/* emulate fputs for console. */ int vmdcon_fputs(const int lvl, const char *string) { /* prefix message with info level... or not. */ switch (lvl) { case VMDCON_INFO: vmdcon_append(lvl, "Info) ", 6); break; case VMDCON_WARN: vmdcon_append(lvl, "Warning) ", 9); break; case VMDCON_ERROR: vmdcon_append(lvl, "ERROR) ", 7); break; default: break; } vmdcon_append(lvl, string, -1); vmdcon_purge(); return 0; }
/* register a tk/tcl widget to be the console window. * we get the widget path directly from tcl, * so we have to create a copy (and free it later). * we also need a pointer to the tcl interpreter. */ int vmdcon_register(const char *w_path, const char *mark, void *interp) { wkf_mutex_lock(&vmdcon_status_lock); vmdcon_interp=interp; /* unregister current console widget */ if(w_path == NULL) { if (vmdcon_wpath != NULL) { free(vmdcon_wpath); free(vmdcon_mark); } vmdcon_wpath=NULL; vmdcon_mark=NULL; /* we have to indicate that no console is available */ if (vmdcon_status == VMDCON_WIDGET) vmdcon_status=VMDCON_NONE; } else { int len; if (vmdcon_wpath != NULL) { free(vmdcon_wpath); free(vmdcon_mark); } len=strlen(w_path); vmdcon_wpath=(char*)malloc(len+1); strcpy(vmdcon_wpath, w_path); len=strlen(mark); vmdcon_mark=(char*)malloc(len+1); strcpy(vmdcon_mark, mark); } wkf_mutex_unlock(&vmdcon_status_lock); /* try to flush pending console log text. */ return vmdcon_purge(); }
Inform& sendmsg(Inform& inform) { Inform& rc = inform.send(); #if defined(VMDTKCON) vmdcon_purge(); #else fflush(stdout); // force standard output to be flushed here, otherwise output // from Inform, stdio, Tcl, and Python can be weirdly // buffered, resulting in jumbled output from batch runs #endif return rc; }
/* emulate printf. unfortunately, we cannot rely on * snprintf being available, so we have to write to * a very large buffer and then free it. :-( */ int vmdcon_printf(const int lvl, const char *fmt, ...) { va_list ap; char *buf; int len; /* expand formated output into a single string */ buf = (char *)malloc(vmdcon_bufsz); va_start(ap, fmt); len = vsprintf(buf, fmt, ap); /* check result. we may get a segfault, but if not * let the user know that he/she is in trouble. */ if (len >= vmdcon_bufsz) { fprintf(stderr,"WARNING! buffer overflow in vmdcon_printf. %d vs %d.\n", len, vmdcon_bufsz); free(buf); errno=ERANGE; return -1; } /* prefix message with info level... or not. */ switch (lvl) { case VMDCON_INFO: vmdcon_append(lvl, "Info) ", 6); break; case VMDCON_WARN: vmdcon_append(lvl, "Warning) ", 9); break; case VMDCON_ERROR: vmdcon_append(lvl, "ERROR) ", 7); break; default: break; } vmdcon_append(lvl, buf, len); vmdcon_purge(); free(buf); return 0; }
/* append text from to console log buffer to queue. */ int vmdcon_showlog(void) { struct vmdcon_msg *log, *msg; wkf_mutex_lock(&vmdcon_output_lock); log=vmdcon_logmsgs; do { /* append to message queue. */ msg=(struct vmdcon_msg *)malloc(sizeof(struct vmdcon_msg)); msg->txt=(char *) malloc(strlen(log->txt)+1); msg->lvl=VMDCON_ALWAYS; strcpy(msg->txt,log->txt); msg->next=NULL; if (vmdcon_pending == NULL) { vmdcon_pending=msg; vmdcon_lastmsg=msg; } else { vmdcon_lastmsg->next=msg; vmdcon_lastmsg=msg; } log=log->next; } while (log->next != NULL); /* terminate the dmesg output with a newline */ msg=(struct vmdcon_msg *)malloc(sizeof(struct vmdcon_msg)); msg->txt=(char *) malloc(strlen("\n")+1); msg->lvl=VMDCON_ALWAYS; strcpy(msg->txt,"\n"); msg->next=NULL; if (vmdcon_pending == NULL) { vmdcon_pending=msg; vmdcon_lastmsg=msg; } else { vmdcon_lastmsg->next=msg; vmdcon_lastmsg=msg; } log=log->next; wkf_mutex_unlock(&vmdcon_output_lock); return vmdcon_purge(); }
int TclTextInterp::evalString(const char *s) { #if defined(VMD_NANOHUB) if (Tcl_Eval(interp, s) != TCL_OK) { #else if (Tcl_RecordAndEval(interp, s, 0) != TCL_OK) { #endif // Don't print error message if there's nothing to show. if (strlen(Tcl_GetStringResult(interp))) msgErr << Tcl_GetStringResult(interp) << sendmsg; return FALSE; } return TRUE; } void TclTextInterp::setString(const char *name, const char *val) { if (interp) Tcl_SetVar(interp, name, val, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG); } void TclTextInterp::setMap(const char *name, const char *key, const char *val) { if (interp) Tcl_SetVar2(interp, name, key, val, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG); } // There's a fair amount of code duplication between doEvent and evalFile, // maybe these could be combined somehow, say by having TclTextInterp keep // track of its Tcl_Channel objects. // // Side note: Reading line-by-line gives different Tcl semantics than // just calling Tcl_EvalFile. Shell commands (e.g., stty) are properly // parsed when read line-by-line and passed to Tcl_RecordAndEval, but are // unrecognized when contained in a file read by Tcl_EvalFile. I would // consider this a bug. int TclTextInterp::evalFile(const char *fname) { Tcl_Channel inchannel = Tcl_OpenFileChannel(interp, fname, "r", 0644); Tcl_Channel outchannel = Tcl_GetStdChannel(TCL_STDOUT); if (inchannel == NULL) { msgErr << "Error opening file " << fname << sendmsg; msgErr << Tcl_GetStringResult(interp) << sendmsg; return 1; } Tcl_Obj *cmdPtr = Tcl_NewObj(); Tcl_IncrRefCount(cmdPtr); int length = 0; while ((length = Tcl_GetsObj(inchannel, cmdPtr)) >= 0) { Tcl_AppendToObj(cmdPtr, "\n", 1); char *stringrep = Tcl_GetStringFromObj(cmdPtr, NULL); if (!Tcl_CommandComplete(stringrep)) { continue; } // check if "exit" was called if (app->exitFlag) break; #if defined(VMD_NANOHUB) Tcl_EvalObjEx(interp, cmdPtr, 0); #else Tcl_RecordAndEvalObj(interp, cmdPtr, 0); #endif #if TCL_MINOR_VERSION >= 4 Tcl_DecrRefCount(cmdPtr); cmdPtr = Tcl_NewObj(); Tcl_IncrRefCount(cmdPtr); #else // XXX this crashes Tcl 8.5.[46] with an internal panic Tcl_SetObjLength(cmdPtr, 0); #endif // XXX this makes sure the display is updated // after each line read from the file or pipe // So, this is also where we'd optimise reading multiple // lines at once // // In VR modes (CAVE, FreeVR, VR Juggler) the draw method will // not be called from app->display_update(), so multiple lines // of input could be combined in one frame, if possible app->display_update(); Tcl_Obj *resultPtr = Tcl_GetObjResult(interp); char *bytes = Tcl_GetStringFromObj(resultPtr, &length); #if defined(VMDTKCON) if (length > 0) { vmdcon_append(VMDCON_ALWAYS, bytes,length); vmdcon_append(VMDCON_ALWAYS, "\n", 1); } vmdcon_purge(); #else if (length > 0) { #if TCL_MINOR_VERSION >= 4 Tcl_WriteChars(outchannel, bytes, length); Tcl_WriteChars(outchannel, "\n", 1); #else Tcl_Write(outchannel, bytes, length); Tcl_Write(outchannel, "\n", 1); #endif } Tcl_Flush(outchannel); #endif } Tcl_Close(interp, inchannel); Tcl_DecrRefCount(cmdPtr); return 0; }
void TclTextInterp::doEvent() { if (!done_waiting()) return; // no recursive calls to TclEvalObj; this prevents // display update ui from messing up Tcl. if (callLevel) return; Tcl_Channel inChannel = Tcl_GetStdChannel(TCL_STDIN); Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT); if (needPrompt && consoleisatty) { #if TCL_MINOR_VERSION >= 4 if (gotPartial) { Tcl_WriteChars(outChannel, "? ", -1); } else { Tcl_WriteChars(outChannel, VMD_CMD_PROMPT, -1); } #else if (gotPartial) { Tcl_Write(outChannel, "? ", -1); } else { Tcl_Write(outChannel, VMD_CMD_PROMPT, -1); } #endif #if defined(VMDTKCON) vmdcon_purge(); #endif Tcl_Flush(outChannel); needPrompt = 0; } #if defined(VMD_NANOHUB) return; #endif // // MPI builds of VMD cannot try to read any command input from the // console because it creates shutdown problems, at least with MPICH. // File-based command input is fine however. // // For the time being, the Android builds won't attempt to get any // console input. Any input we're going to get is going to come via // some means other than stdin, such as a network socket, text box, etc. // if (ignorestdin) return; if (!vmd_check_stdin()) return; // // event loop based on tclMain.c // // According to the Tcl docs, GetsObj returns -1 on error or EOF. int length = Tcl_GetsObj(inChannel, commandPtr); if (length < 0) { if (Tcl_Eof(inChannel)) { // exit if we're not a tty, or if eofexit is set if ((!consoleisatty) || app->get_eofexit()) app->VMDexit("", 0, 0); } else { msgErr << "Error reading Tcl input: " << Tcl_ErrnoMsg(Tcl_GetErrno()) << sendmsg; } return; } needPrompt = 1; // add the newline removed by Tcl_GetsObj Tcl_AppendToObj(commandPtr, "\n", 1); char *stringrep = Tcl_GetStringFromObj(commandPtr, NULL); if (!Tcl_CommandComplete(stringrep)) { gotPartial = 1; return; } gotPartial = 0; callLevel++; #if defined(VMD_NANOHUB) Tcl_EvalObjEx(interp, commandPtr, 0); #else Tcl_RecordAndEvalObj(interp, commandPtr, 0); #endif callLevel--; #if TCL_MINOR_VERSION >= 4 Tcl_DecrRefCount(commandPtr); commandPtr = Tcl_NewObj(); Tcl_IncrRefCount(commandPtr); #else // XXX this crashes Tcl 8.5.[46] with an internal panic Tcl_SetObjLength(commandPtr, 0); #endif // if ok, send to stdout; if not, send to stderr Tcl_Obj *resultPtr = Tcl_GetObjResult(interp); char *bytes = Tcl_GetStringFromObj(resultPtr, &length); #if defined(VMDTKCON) if (length > 0) { vmdcon_append(VMDCON_ALWAYS, bytes,length); vmdcon_append(VMDCON_ALWAYS, "\n", 1); } vmdcon_purge(); #else if (length > 0) { #if TCL_MINOR_VERSION >= 4 Tcl_WriteChars(outChannel, bytes, length); Tcl_WriteChars(outChannel, "\n", 1); #else Tcl_Write(outChannel, bytes, length); Tcl_Write(outChannel, "\n", 1); #endif } Tcl_Flush(outChannel); #endif }
int VMDinitialize(int *argc, char ***argv) { int i; #if defined VMDMPI // hack to fix up env vars if necessary for (i=0; i<(*argc); i++) { if(!strupcmp((*argv)[i], "-vmddir")) { if((*argc) > (i + 1)) { setenv("VMDDIR", (*argv)[++i], 1); } else { msgErr << "-vmddir must specify a fully qualified path." << sendmsg; } } } vmd_mpi_init(argc, argv); // initialize MPI, fix up env vars, etc. #endif #if defined(_MSC_VER) && !defined(VMDSEPARATESTARTUP) win32vmdstart(); // get registry info etc #endif #if !defined(VMDNOMACBUNDLE) && defined(__APPLE__) macosxvmdstart(*argc, *argv); // get env variables etc #endif // Tell Tcl where the executable is located const char *argv0 = vmd_initialize_tcl((*argv)[0]); #ifdef VMDTCL // register signal handler tclhandler = Tcl_AsyncCreate(VMDTclAsyncProc, (ClientData)NULL); signal(SIGINT, (sighandler_t) VMDTclSigHandler); #endif // Let people know who we are. VMDtitle(); // Tell the user what we think about the hardware we're running on. // If VMD is compiled for MPI, then we don't print any of the normal // standalone startup messages and instead we use the special MPI-specific // node scan startup messages only. #if !defined(VMDMPI) #if defined(VMDTHREADS) int vmdnumcpus = wkf_thread_numprocessors(); msgInfo << "Multithreading available, " << vmdnumcpus << ((vmdnumcpus > 1) ? " CPUs" : " CPU") << " detected." << sendmsg; #endif long vmdcorefree = vmd_get_avail_physmem_mb(); if (vmdcorefree >= 0) { long vmdcorepcnt = vmd_get_avail_physmem_percent(); msgInfo << "Free system memory: " << vmdcorefree << "MB (" << vmdcorepcnt << "%)" << sendmsg; } #endif // Read environment variables and command line options. // Initialize customArgv with just argv0 to avoid problems with // Tcl extension. customArgv.append((char *)argv0); VMDGetOptions(*argc, *argv); #if (!defined(__APPLE__) && !defined(_MSC_VER)) && (defined(VMDOPENGL) || defined(VMDFLTK)) // If we're using X-windows, we autodetect if the DISPLAY environment // variable is unset, and automatically switch back to text mode without // requiring the user to pass the "-dispdev text" command line parameters if ((which_display == DISPLAY_WIN) && (getenv("DISPLAY") == NULL)) { which_display = DISPLAY_TEXT; } #endif #if defined(VMDTKCON) vmdcon_init(); msgInfo << "Using VMD Console redirection interface." << sendmsg; // we default to a widget mode console, unless text mode is requested. // we don't have an tcl interpreter registered yet, so it is set to NULL. // flushing pending messages to the screen, is only in text mode possible. if ((which_display == DISPLAY_TEXT) || just_print_help) { vmdcon_use_text(NULL); vmdcon_purge(); } else { vmdcon_use_widget(NULL); } #endif #ifdef VMDFLTK // Do various special FLTK initialization stuff here if ((which_display != DISPLAY_TEXT)) { // Cause FLTK to to use 24-bit color for all windows if possible // This must be done before any FLTK windows are shown for the first time. if (!Fl::visual(FL_DOUBLE | FL_RGB8)) { if (!Fl::visual(FL_RGB8)) { Fl::visual(FL_RGB); } } // Disable the use of the arrow keys for navigating buttons and other // non-text widgets, we'll try it out and see how it pans out Fl::visible_focus(0); // Disable Drag 'n Drop since the only text field in VMD is the // atomselection input and DND severely gets in the way there. Fl::dnd_text_ops(0); } #endif // Quit now if the user just wanted a list of command line options. if (just_print_help) { vmd_sleep(10); // This is here so that the user can see the message // before the terminal/shell exits... return 0; } // Set up default allocators; these may be overridden by cave or freevr. vmd_alloc = malloc; // system malloc() in the default case vmd_dealloc = free; // system free() in the default case vmd_realloc = realloc; // system realloc(), set to NULL when not available // check for a CAVE display if (DISPLAY_USES_CAVE(which_display)) { #ifdef VMDCAVE // allocate shared memory pool used to communicate with child renderers int megs = 2048; if (getenv("VMDCAVEMEM") != NULL) { megs = atoi(getenv("VMDCAVEMEM")); } msgInfo << "Attempting to get " << megs << "MB of CAVE Shared Memory" << sendmsg; grab_CAVE_memory(megs); CAVEConfigure(argc, *argv, NULL); // configure cave walls and memory use // point VMD shared memory allocators to CAVE routines vmd_alloc = malloc_from_CAVE_memory; vmd_dealloc = free_to_CAVE_memory; vmd_realloc = NULL; // no realloc() functionality is available presently #else msgErr << "Not compiled with the CAVE options set." << sendmsg; which_display = DISPLAY_WIN; #endif } // check for a FreeVR display if (DISPLAY_USES_FREEVR(which_display)) { #ifdef VMDFREEVR int megs = 2048; if (getenv("VMDFREEVRMEM") != NULL) { megs = atoi(getenv("VMDFREEVRMEM")); } msgInfo << "Attempting to get " << megs << "MB of FreeVR Shared Memory" << sendmsg; grab_FreeVR_memory(megs); // have to do this *before* vrConfigure() if // we want more than the default shared mem. vrConfigure(NULL, NULL, NULL); // configure FreeVR walls // point shared memory allocators to FreeVR routines vmd_alloc = malloc_from_FreeVR_memory; vmd_dealloc = free_to_FreeVR_memory; vmd_realloc = NULL; // no realloc() functionality is available presently #else msgErr << "Not compiled with the FREEVR options set." << sendmsg; which_display = DISPLAY_WIN; #endif } // return custom argc/argv *argc = customArgv.num(); for (i=0; i<customArgv.num(); i++) { (*argv)[i] = customArgv[i]; } return 1; // successful startup }