/********************************************************************** * File: debugwin.cpp * Description: Portable debug window class. * Author: Ray Smith * Created: Wed Feb 21 15:36:59 MST 1996 * * (C) Copyright 1996, Hewlett-Packard Co. ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** http://www.apache.org/licenses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. * **********************************************************************/ #include "mfcpch.h" //precompiled headers #include #include "debugwin.h" DLLSYM INT_VAR (debug_lines, 256, "Number of lines in debug window"); #ifndef GRAPHICS_DISABLED #ifdef __MAC__ #include #include //#include #define scrl_SCROLLER 101 #define text_FLOWED 100 static LCommander *pCommander = NULL; #endif //NT implementation #if defined(__MSW32__) && !defined(_CONSOLE) #include #define ID_DEBUG_MSG 32779 /********************************************************************** * DEBUG_WIN::DEBUG_WIN * * Create a debug window with size according to the arguments. **********************************************************************/ DEBUG_WIN::DEBUG_WIN( //constructor const char *title, //of window inT32 xpos, //initial position inT32 ypos, //in pixels inT32 xsize, //initial size inT32 ysize, //in pixels inT32 buflines //default scroll size ) { char cmd[1024]; int parm; //output from scrolrwin STARTUPINFO start_info; //process control PROCESS_INFORMATION proc_info; //process ids SECURITY_ATTRIBUTES security; //for handles handle = NULL; shm_hand = NULL; shm_mem = NULL; msg_end = NULL; dbg_process = NULL; //save handles dbg_thread = NULL; security.nLength = sizeof (security); security.lpSecurityDescriptor = NULL; security.bInheritHandle = TRUE;//make it inheritable //anonymous shm_hand = CreateFileMapping ((HANDLE) 0xffffffff, &security, PAGE_READWRITE, 0, 4096, NULL); if (shm_hand == NULL) return; //failed shm_mem = (char *) MapViewOfFile (shm_hand, FILE_MAP_WRITE, 0, 0, 0); if (shm_mem == NULL) return; shm_mem[5] = 0; sprintf (cmd, "scrolwin.exe %d %d", buflines, shm_hand); GetStartupInfo(&start_info); //clone our stuff if (!CreateProcess (NULL, cmd, NULL, NULL, TRUE, CREATE_NO_WINDOW | DETACHED_PROCESS | CREATE_SUSPENDED, NULL, NULL, &start_info, &proc_info)) return; //save handles dbg_process = proc_info.hProcess; dbg_thread = proc_info.hThread; if (ResumeThread (dbg_thread) != 1) return; do Sleep (100); while (shm_mem[5] == 0); //wait for handle parm = ((((uinT8) shm_mem[4] << 8) + (uinT8) shm_mem[3] << 8) + (uinT8) shm_mem[2] << 8) + (uinT8) shm_mem[1]; handle = (HWND) parm; if (handle != NULL) { //setup window ::SetWindowText (handle, title); ::MoveWindow (handle, xpos, ypos, xsize, ysize, TRUE); ::ShowWindow (handle, SW_SHOW); } } /********************************************************************** * DEBUG_WIN::DEBUG_WIN * * Destroy a debug window. **********************************************************************/ DEBUG_WIN::~DEBUG_WIN ( //destructor ) { if (IsWindow (handle)) ::SendMessage (handle, WM_COMMAND, IDOK, 0); if (shm_mem != NULL) UnmapViewOfFile(shm_mem); if (shm_hand != NULL) CloseHandle(shm_hand); if (dbg_thread != NULL) CloseHandle(dbg_thread); if (dbg_process == NULL) CloseHandle(dbg_process); } /********************************************************************** * dprintf * * Print a message to the debug window. * Like printf, this function can cope with messages which do not end * in newline, but nothing is printed until the newline is received. **********************************************************************/ void DEBUG_WIN::dprintf ( //debug printf const char *format, ... //special message ) { va_list args; //variable args char *msg_start; //for printing if (!IsWindow (handle)) return; //destroyed if (msg_end == NULL) msg_end = shm_mem + 1; va_start(args, format); //variable list //Format into msg vsprintf(msg_end, format, args); va_end(args); if (*msg_end == '\0') return; msg_start = shm_mem + 1; do { //end of line msg_end = strchr (msg_start, '\n'); if (msg_end == NULL) { if (msg_start != shm_mem + 1) //bring to front strcpy (shm_mem + 1, msg_start); //current end msg_end = shm_mem + 1 + strlen (shm_mem + 1); return; } *msg_end = '\0'; while (IsWindow (handle) && shm_mem[0]) Sleep (500); if (IsWindow (handle)) { //Visual C++2.0 macro ::SendMessage (handle, WM_COMMAND, ID_DEBUG_MSG, (DWORD) (msg_start - shm_mem)); } msg_start = msg_end + 1; } while (*msg_start != '\0'); msg_end = shm_mem + 1; //buffer empty } /********************************************************************** * await_destruction * * Wait for the user to close the debug window. Then return. **********************************************************************/ void DEBUG_WIN::await_destruction() { //wait for user to close WaitForSingleObject (dbg_process, (unsigned long) -1); } #endif //NT Implmentation //UNIX implementation #if defined(__UNIX__) || defined(_CONSOLE) #ifdef __UNIX__ #include #include #endif //#include "basefile.h" /********************************************************************** * DEBUG_WIN::DEBUG_WIN * * Create a debug window with size according to the arguments. * Create an hpterm window with a pipe connected to it. **********************************************************************/ DEBUG_WIN::DEBUG_WIN( //constructor const char *title, //of window inT32 xpos, //initial position inT32 ypos, //in pixels inT32 xsize, //initial size inT32 ysize, //in pixels inT32 buflines //default scroll size ) { #ifdef __UNIX__ inT32 length; /*length of name */ char command[MAX_PATH]; /*pipe command */ pid_t pid; /*process id */ char host[MAX_PATH]; //remote host BOOL8 remote; //remote host // remote=remote_display(host); //check remote host remote = FALSE; if (remote) //do it remotely length = sprintf (command, "remsh %s 'DISPLAY=%s;export DISPLAY;", host, getenv ("DISPLAY")); else length = 0; length += sprintf (command + length, "trap \"\" 1 2 3 13 15\n"); length += sprintf (command + length, "/usr/bin/xterm -sb -sl " INT32FORMAT " -geometry " INT32FORMAT "x" INT32FORMAT "", buflines, xsize / 8, ysize / 16); if (xpos >= 0) command[length++] = '+'; length += sprintf (command + length, INT32FORMAT, xpos); if (ypos >= 0) command[length++] = '+'; length += sprintf (command + length, INT32FORMAT " -title \"%s\" -n \"%s\" -e /bin/sh -c ", ypos, title, title); pid = getpid (); /*random number */ length += sprintf (command + length, "\"stty opost; tty >/tmp/debug%d; while [ -s /tmp/debug%d ]\ndo\nsleep 1\ndone\" &\n", pid, pid); length += sprintf (command + length, "trap \"rm -f /tmp/debug%d; kill -9 $!\" 0\n", pid); length += sprintf (command + length, "trap \"exit\" 1 2 3 13 15\n"); length += sprintf (command + length, "while [ ! -s /tmp/debug%d ]\ndo\nsleep 1\ndone\n", pid); length += sprintf (command + length, "trap \"\" 1 2 3 13 15\n"); length += sprintf (command + length, "ofile=`cat /tmp/debug%d`\n", pid); length += sprintf (command + length, "cat -u - >$ofile; rm /tmp/debug%d\n", pid); if (remote) { command[length++] = '\''; //terminate remsh command[length] = '\0'; } fp = popen (command, "w"); /*create window */ if (fp != NULL) { /*set no buffering */ if (setvbuf (fp, NULL, _IONBF, BUFSIZ)) { pclose(fp); fp = NULL; } } #endif } /********************************************************************** * DEBUG_WIN::DEBUG_WIN * * Close the file and destroy the window. **********************************************************************/ DEBUG_WIN::~DEBUG_WIN ( //destructor ) { #ifdef __UNIX__ pclose(fp); #endif } /********************************************************************** * dprintf * * Print a message to the debug window. * Like printf, this function can cope with messages which do not end * in newline, but nothing is printed until the newline is received. **********************************************************************/ void DEBUG_WIN::dprintf ( //debug printf const char *format, ... //special message ) { va_list args; //variable args va_start(args, format); //variable list #ifdef __UNIX__ vfprintf(fp, format, args); //Format into msg #else //Format into msg vfprintf(stderr, format, args); #endif va_end(args); } /********************************************************************** * await_destruction * * Wait for the user to close the debug window. Then return. **********************************************************************/ void DEBUG_WIN::await_destruction() { //wait for user to close #ifdef __UNIX__ signal(SIGPIPE, SIG_IGN); while (!ferror (fp)) { sleep (1); fputc (0, fp); //send nulls until error } #endif } #endif //UNIX Implmentation #ifdef __MAC__ //NT implementation #include //#include "textwindow.h" #include #include "ipcbase.h" //must be last include // Until I can figure a way to do this without linking in PowerPlant, // the debug window will just have empty functions so compilation can take place. /********************************************************************** * DEBUG_WIN::SetCommander * * Mac-specific function to set the commander for the next debug window **********************************************************************/ void DEBUG_WIN::SetCommander(LCommander *pNew) { pCommander = pNew; } /********************************************************************** * DEBUG_WIN::DEBUG_WIN * * Create a debug window with size according to the arguments. * Create an hpterm window with a pipe connected to it. **********************************************************************/ DEBUG_WIN::DEBUG_WIN( //constructor const char *title, //of window inT32 xpos, //initial position inT32 ypos, //in pixels inT32 xsize, //initial size inT32 ysize, //in pixels inT32 buflines //default scroll size ) { inT32 length; /*length of name */ // don't replace this DebugStr() with a call to DEBUG_WIN! //if (pCommander==NULL) DebugStr("\pDEBUG_WIN::DEBUG_WIN(), Commander not set"); // create the window //pWindow=LWindow::CreateWindow(2700,pCommander); } /********************************************************************** * DEBUG_WIN::DEBUG_WIN * * Close the file and destroy the window. **********************************************************************/ DEBUG_WIN::~DEBUG_WIN ( //destructor ) { } /********************************************************************** * dprintf * * Print a message to the debug window. * Like printf, this function can cope with messages which do not end * in newline, but nothing is printed until the newline is received. **********************************************************************/ void DEBUG_WIN::dprintf ( //debug printf const char *format, ... //special message ) { #if 0 LTextEdit *pTextEdit; va_list args; //variable args static char msg[1024]; inT32 i; inT32 OriginalLength; inT32 NewLength; TEHandle hTextEdit; char *pTempBuffer; CharsHandle hChar; char *pOriginalText; inT32 StringLength; pTextEdit = (LTextEdit *) pWindow->FindPaneByID (text_FLOWED); if (pTextEdit == NULL) DebugStr ("\pwhoops"); // get a C String from the format and args passed in va_start(args, format); //variable list vsprintf(msg, format, args); //Format into msg va_end(args); StringLength = strlen (msg); // get the handle for the text hTextEdit = pTextEdit->GetMacTEH (); if (hTextEdit == NULL) DebugStr ("\pDEBUG_WIN,WriteCharsToConsole()"); // get a pointer to the characters and the length of the character stream hChar = TEGetText (hTextEdit); if (hChar == NULL) DebugStr ("\pDEBUG_WIN,WriteCharsToConsole()"); pOriginalText = *hChar; // get pointer to existing text // get the length of the original data OriginalLength = (*hTextEdit)->teLength; // setup a temporary buffer for the new text NewLength = OriginalLength + StringLength; pTempBuffer = NewPtr (NewLength); if (pTempBuffer == NULL) DebugStr ("\pDEBUG_WIN,WriteCharsToConsole()"); // copy the original data into the new buffer for (i = 0; i < OriginalLength; i++) pTempBuffer[i] = pOriginalText[i]; // append the new data onto the end of the original buffer for (i = 0; i < StringLength; i++) { if (msg[i] == '\n') pTempBuffer[i + OriginalLength] = '\r'; else pTempBuffer[i + OriginalLength] = msg[i]; } // put the new text into the text edit item TESetText(pTempBuffer, NewLength, hTextEdit); // clean up DisposePtr(pTempBuffer); #endif } #endif //Mac Implmentation #else // Non graphical debugger DEBUG_WIN::DEBUG_WIN( const char*, inT32, inT32, inT32, inT32, inT32 ) { } DEBUG_WIN::~DEBUG_WIN () { } void DEBUG_WIN::dprintf (const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } void await_destruction() { } #endif