Main Page Namespace List Class Hierarchy Alphabetical List Compound List File List Namespace Members Compound Members File Members Related Pages

vmdconsole.c

Go to the documentation of this file.
00001 /***************************************************************************
00002 *cr
00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the
00004 *cr University of Illinois
00005 *cr All Rights Reserved
00006 *cr
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 * RCS INFORMATION:
00011 *
00012 * $RCSfile: vmdconsole.c,v $
00013 * $Author: johns $ $Locker: $ $State: Exp $
00014 * $Revision: 1.13 $ $Date: 2019年01月17日 21:21:03 $
00015 *
00016 ***************************************************************************
00017 * DESCRIPTION:
00018 *
00019 * vmd console redirector
00020 * (c) 2006-2009 Axel Kohlmeyer <akohlmey@cmm.chem.upenn.edu>
00021 * 
00022 ***************************************************************************/
00023 
00024 #if defined(VMDTKCON)
00025 
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <stdarg.h>
00029 #include <string.h>
00030 #include <errno.h>
00031 
00032 #include "vmdconsole.h"
00033 #include "WKFThreads.h"
00034 
00035 #ifdef __cplusplus
00036 extern "C" {
00037 #endif
00038 
00039 /* structure for linked list of pending messages. */
00040 struct vmdcon_msg 
00041 {
00042 char *txt;
00043 int lvl;
00044 struct vmdcon_msg *next;
00045 };
00046 
00047 static struct vmdcon_msg *vmdcon_pending=NULL;
00048 static struct vmdcon_msg *vmdcon_lastmsg=NULL;
00049 
00050 static struct vmdcon_msg *vmdcon_logmsgs=NULL;
00051 static struct vmdcon_msg *vmdcon_lastlog=NULL;
00052 static int vmdcon_max_loglen=2000;
00053 static int vmdcon_loglen=0;
00054 
00055 /* static buffer size for vmdcon_printf */
00056 static const int vmdcon_bufsz=4092;
00057 
00058 /* path to console text widget */
00059 static char *vmdcon_wpath=NULL;
00060 
00061 /* current insertion mark */
00062 static char *vmdcon_mark=NULL;
00063 
00064 /* opaque pointer to the current tcl interpreter */
00065 static void *vmdcon_interp=NULL;
00066 
00067 /* output destination status. */
00068 static int vmdcon_status=VMDCON_UNDEF;
00069 
00070 /* output loglevel. default to print all.*/
00071 static int vmdcon_loglvl=VMDCON_ALL;
00072 
00073 /* mutex to lock access to status variables */
00074 static wkf_mutex_t vmdcon_status_lock;
00075 static wkf_mutex_t vmdcon_output_lock;
00076 
00077 /* initialize vmdcon */
00078 void vmdcon_init(void) 
00079 {
00080 wkf_mutex_init(&vmdcon_status_lock);
00081 wkf_mutex_init(&vmdcon_output_lock);
00082 vmdcon_set_status(VMDCON_NONE, NULL);
00083 }
00084 
00085 /* report current vmdcon status */
00086 int vmdcon_get_status(void)
00087 {
00088 return vmdcon_status;
00089 }
00090 
00091 /* set current vmdcon status */
00092 void vmdcon_set_status(int status, void *interp)
00093 {
00094 wkf_mutex_lock(&vmdcon_status_lock);
00095 if (interp != NULL) vmdcon_interp=interp;
00096 vmdcon_status=status;
00097 tcl_vmdcon_set_status_var(vmdcon_interp, status);
00098 wkf_mutex_unlock(&vmdcon_status_lock);
00099 }
00100 
00101 /* set current vmdcon log level */
00102 void vmdcon_set_loglvl(int lvl)
00103 {
00104 wkf_mutex_lock(&vmdcon_status_lock);
00105 vmdcon_loglvl=lvl;
00106 wkf_mutex_unlock(&vmdcon_status_lock);
00107 }
00108 
00109 /* set current vmdcon log level */
00110 int vmdcon_get_loglvl(void)
00111 {
00112 return vmdcon_loglvl;
00113 }
00114 
00115 /* turn on text mode processing */
00116 void vmdcon_use_text(void *interp) 
00117 {
00118 vmdcon_set_status(VMDCON_TEXT, interp);
00119 }
00120 
00121 /* turn on tk text widget mode processing */
00122 void vmdcon_use_widget(void *interp) 
00123 {
00124 vmdcon_set_status(VMDCON_WIDGET, interp);
00125 }
00126 
00127 /* register a tk/tcl widget to be the console window.
00128 * we get the widget path directly from tcl, 
00129 * so we have to create a copy (and free it later).
00130 * we also need a pointer to the tcl interpreter.
00131 */
00132 int vmdcon_register(const char *w_path, const char *mark, void *interp)
00133 {
00134 wkf_mutex_lock(&vmdcon_status_lock);
00135 vmdcon_interp=interp;
00136 
00137 /* unregister current console widget */
00138 if(w_path == NULL) {
00139 if (vmdcon_wpath != NULL) {
00140 free(vmdcon_wpath);
00141 free(vmdcon_mark);
00142 }
00143 vmdcon_wpath=NULL;
00144 vmdcon_mark=NULL;
00145 /* we have to indicate that no console is available */
00146 if (vmdcon_status == VMDCON_WIDGET) vmdcon_status=VMDCON_NONE;
00147 } else {
00148 int len;
00149 
00150 if (vmdcon_wpath != NULL) {
00151 free(vmdcon_wpath);
00152 free(vmdcon_mark);
00153 }
00154 
00155 len=strlen(w_path);
00156 vmdcon_wpath=(char*)malloc(len+1);
00157 strcpy(vmdcon_wpath, w_path);
00158 len=strlen(mark);
00159 vmdcon_mark=(char*)malloc(len+1);
00160 strcpy(vmdcon_mark, mark);
00161 }
00162 wkf_mutex_unlock(&vmdcon_status_lock);
00163 
00164 /* try to flush pending console log text. */
00165 return vmdcon_purge();
00166 }
00167 
00168 /* append text from to console log buffer to queue. */
00169 int vmdcon_showlog(void)
00170 {
00171 struct vmdcon_msg *log, *msg;
00172 
00173 wkf_mutex_lock(&vmdcon_output_lock);
00174 log=vmdcon_logmsgs;
00175 do {
00176 /* append to message queue. */
00177 msg=(struct vmdcon_msg *)malloc(sizeof(struct vmdcon_msg));
00178 msg->txt=(char *) malloc(strlen(log->txt)+1);
00179 msg->lvl=VMDCON_ALWAYS;
00180 strcpy(msg->txt,log->txt);
00181 msg->next=NULL;
00182 
00183 if (vmdcon_pending == NULL) {
00184 vmdcon_pending=msg;
00185 vmdcon_lastmsg=msg;
00186 } else {
00187 vmdcon_lastmsg->next=msg;
00188 vmdcon_lastmsg=msg;
00189 }
00190 log=log->next;
00191 } while (log->next != NULL);
00192 
00193 /* terminate the dmesg output with a newline */
00194 msg=(struct vmdcon_msg *)malloc(sizeof(struct vmdcon_msg));
00195 msg->txt=(char *) malloc(strlen("\n")+1);
00196 msg->lvl=VMDCON_ALWAYS;
00197 strcpy(msg->txt,"\n");
00198 msg->next=NULL;
00199 
00200 if (vmdcon_pending == NULL) {
00201 vmdcon_pending=msg;
00202 vmdcon_lastmsg=msg;
00203 } else {
00204 vmdcon_lastmsg->next=msg;
00205 vmdcon_lastmsg=msg;
00206 }
00207 log=log->next;
00208 
00209 wkf_mutex_unlock(&vmdcon_output_lock);
00210 return vmdcon_purge();
00211 }
00212 
00213 /* append text to console log queue.
00214 * we have to make copies as we might get handed 
00215 * a tcl object or a pointer to some larger buffer. */
00216 int vmdcon_append(int level, const char *txt, int len) 
00217 {
00218 struct vmdcon_msg *msg;
00219 char *buf;
00220 
00221 /* len=0: don't print. len=-1, autodetect. */
00222 if (len == 0 ) return 0;
00223 if (len < 0) {
00224 len=strlen(txt);
00225 }
00226 
00227 wkf_mutex_lock(&vmdcon_output_lock);
00228 
00229 /* append to message queue. */
00230 /* but don't print stuff below the current loglevel */
00231 if (level >= vmdcon_loglvl) {
00232 /* create copy of text. gets free'd after it has been 'printed'. */
00233 buf=(char *)calloc(len+1,1);
00234 strncpy(buf,txt,len);
00235 
00236 msg=(struct vmdcon_msg *)malloc(sizeof(struct vmdcon_msg));
00237 msg->txt=buf;
00238 msg->lvl=level;
00239 msg->next=NULL;
00240 
00241 if (vmdcon_pending == NULL) {
00242 vmdcon_pending=msg;
00243 vmdcon_lastmsg=msg;
00244 } else {
00245 vmdcon_lastmsg->next=msg;
00246 vmdcon_lastmsg=msg;
00247 }
00248 }
00249 
00250 /* messages are added to the log regardless of loglevel.
00251 * this way we can silence the log window and still retrieve
00252 * useful information with 'vmdcon -dmesg'. */
00253 buf=(char *)calloc(len+1,1);
00254 strncpy(buf,txt,len);
00255 
00256 /* append to log message list. */
00257 msg=(struct vmdcon_msg *)malloc(sizeof(struct vmdcon_msg));
00258 msg->txt=buf;
00259 msg->lvl=level;
00260 msg->next=NULL;
00261 
00262 if (vmdcon_logmsgs == NULL) {
00263 vmdcon_logmsgs=msg;
00264 vmdcon_lastlog=msg;
00265 ++vmdcon_loglen;
00266 } else {
00267 vmdcon_lastlog->next=msg;
00268 vmdcon_lastlog=msg;
00269 ++vmdcon_loglen;
00270 }
00271 
00272 /* remove message from the front of the queue
00273 * in case we have too long a list */
00274 while (vmdcon_loglen > vmdcon_max_loglen) {
00275 msg=vmdcon_logmsgs;
00276 vmdcon_logmsgs=msg->next;
00277 free(msg->txt);
00278 free(msg);
00279 --vmdcon_loglen;
00280 }
00281 
00282 wkf_mutex_unlock(&vmdcon_output_lock);
00283 
00284 return 0;
00285 }
00286 
00287 /* flush current message queue to a registered 
00288 * console widget, if such a thing exists.
00289 * since vmdcon_append() allocates the storage,
00290 * for everything, we have to free the msg structs
00291 * and the strings. */
00292 int vmdcon_purge(void) 
00293 {
00294 struct vmdcon_msg *msg;
00295 const char *res;
00296 
00297 wkf_mutex_lock(&vmdcon_status_lock);
00298 /* purge message queue only if we have a working console window */
00299 if ( ! ((vmdcon_status == VMDCON_UNDEF) || (vmdcon_status == VMDCON_NONE)
00300 || ((vmdcon_status == VMDCON_WIDGET) &&
00301 ((vmdcon_interp == NULL) || (vmdcon_wpath == NULL))) ) ) {
00302 
00303 wkf_mutex_lock(&vmdcon_output_lock);
00304 while (vmdcon_pending != NULL) {
00305 msg=vmdcon_pending;
00306 
00307 switch (vmdcon_status) {
00308 case VMDCON_TEXT:
00309 fputs(msg->txt,stdout);
00310 break;
00311 
00312 case VMDCON_WIDGET: 
00313 res = tcl_vmdcon_insert(vmdcon_interp, vmdcon_wpath, 
00314 vmdcon_mark, msg->txt);
00315 /* handle errors writing to a tcl console window.
00316 * unregister widget, don't free current message 
00317 * and append error message into holding buffer. */
00318 if (res) {
00319 wkf_mutex_unlock(&vmdcon_status_lock);
00320 vmdcon_register(NULL, NULL, vmdcon_interp);
00321 wkf_mutex_unlock(&vmdcon_output_lock);
00322 vmdcon_printf(VMDCON_ERROR,
00323 "Problem writing to text widget: %s\n", res);
00324 return 1;
00325 }
00326 break;
00327 
00328 default:
00329 /* unknown console type */
00330 return 1;
00331 }
00332 free(msg->txt);
00333 vmdcon_pending=msg->next;
00334 free(msg);
00335 
00336 }
00337 if (vmdcon_status == VMDCON_TEXT) 
00338 fflush(stdout);
00339 
00340 wkf_mutex_unlock(&vmdcon_output_lock);
00341 }
00342 wkf_mutex_unlock(&vmdcon_status_lock);
00343 return 0;
00344 }
00345 
00346 /* emulate printf. unfortunately, we cannot rely on 
00347 * snprintf being available, so we have to write to
00348 * a very large buffer and then free it. :-( */
00349 int vmdcon_printf(const int lvl, const char *fmt, ...) 
00350 {
00351 va_list ap;
00352 char *buf;
00353 int len;
00354 
00355 /* expand formated output into a single string */
00356 buf = (char *)malloc(vmdcon_bufsz);
00357 va_start(ap, fmt);
00358 len = vsprintf(buf, fmt, ap);
00359 
00360 /* check result. we may get a segfault, but if not
00361 * let the user know that he/she is in trouble. */
00362 if (len >= vmdcon_bufsz) {
00363 fprintf(stderr,"WARNING! buffer overflow in vmdcon_printf. %d vs %d.\n",
00364 len, vmdcon_bufsz);
00365 free(buf);
00366 errno=ERANGE;
00367 return -1;
00368 }
00369 
00370 /* prefix message with info level... or not. */
00371 switch (lvl) {
00372 case VMDCON_INFO:
00373 vmdcon_append(lvl, "Info) ", 6);
00374 break;
00375 
00376 case VMDCON_WARN:
00377 vmdcon_append(lvl, "Warning) ", 9);
00378 break;
00379 
00380 case VMDCON_ERROR:
00381 vmdcon_append(lvl, "ERROR) ", 7);
00382 break;
00383 
00384 default: 
00385 break;
00386 }
00387 
00388 vmdcon_append(lvl, buf, len);
00389 vmdcon_purge();
00390 
00391 free(buf);
00392 return 0; 
00393 }
00394 
00395 /* emulate fputs for console. */
00396 int vmdcon_fputs(const int lvl, const char *string) 
00397 {
00398 /* prefix message with info level... or not. */
00399 switch (lvl) {
00400 case VMDCON_INFO:
00401 vmdcon_append(lvl, "Info) ", 6);
00402 break;
00403 
00404 case VMDCON_WARN:
00405 vmdcon_append(lvl, "Warning) ", 9);
00406 break;
00407 
00408 case VMDCON_ERROR:
00409 vmdcon_append(lvl, "ERROR) ", 7);
00410 break;
00411 
00412 default: 
00413 break;
00414 }
00415 
00416 vmdcon_append(lvl, string, -1);
00417 vmdcon_purge();
00418 
00419 return 0; 
00420 }
00421 
00422 #ifdef __cplusplus
00423 }
00424 #endif
00425 
00426 #endif

Generated on Mon Nov 17 02:47:23 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /