1 /**********************************************************************
2 * File: debugwin.cpp
3 * Description: Portable debug window class.
4 * Author: Ray Smith
5 * Created: Wed Feb 21 15:36:59 MST 1996
6 *
7 * (C) Copyright 1996, Hewlett-Packard Co.
8 ** Licensed under the Apache License, Version 2.0 (the "License");
9 ** you may not use this file except in compliance with the License.
10 ** You may obtain a copy of the License at
11 ** http://www.apache.org/licenses/LICENSE-2.0
12 ** Unless required by applicable law or agreed to in writing, software
13 ** distributed under the License is distributed on an "AS IS" BASIS,
14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 ** See the License for the specific language governing permissions and
16 ** limitations under the License.
17 *
18 **********************************************************************/
19
20 #include "mfcpch.h" //precompiled headers
21 #include <stdarg.h>
22 #include "debugwin.h"
23
24 DLLSYM INT_VAR (debug_lines, 256, "Number of lines in debug window");
25
26 #ifndef GRAPHICS_DISABLED
27
28 #ifdef __MAC__
29 #include <ltextedit.h>
30 #include <lwindow.h>
31 //#include <console.h>
32
33 #define scrl_SCROLLER 101
34 #define text_FLOWED 100
35
36 static LCommander *pCommander = NULL;
37 #endif
38
39 //NT implementation
40 #if defined(__MSW32__) && !defined(_CONSOLE)
41
42 #define ID_DEBUG_MSG 32779
43
44 /**********************************************************************
45 * DEBUG_WIN::DEBUG_WIN
46 *
47 * Create a debug window with size according to the arguments.
48 **********************************************************************/
49
DEBUG_WIN(const char * title,inT32 xpos,inT32 ypos,inT32 xsize,inT32 ysize,inT32 buflines)50 DEBUG_WIN::DEBUG_WIN( //constructor
51 const char *title, //of window
52 inT32 xpos, //initial position
53 inT32 ypos, //in pixels
54 inT32 xsize, //initial size
55 inT32 ysize, //in pixels
56 inT32 buflines //default scroll size
57 ) {
58 char cmd[1024];
59 int parm; //output from scrolrwin
60 STARTUPINFO start_info; //process control
61 PROCESS_INFORMATION proc_info; //process ids
62 SECURITY_ATTRIBUTES security; //for handles
63
64 handle = NULL;
65 shm_hand = NULL;
66 shm_mem = NULL;
67 msg_end = NULL;
68 dbg_process = NULL; //save handles
69 dbg_thread = NULL;
70 security.nLength = sizeof (security);
71 security.lpSecurityDescriptor = NULL;
72 security.bInheritHandle = TRUE;//make it inheritable
73 //anonymous
74 shm_hand = CreateFileMapping ((HANDLE) 0xffffffff, &security, PAGE_READWRITE, 0, 4096, NULL);
75 if (shm_hand == NULL)
76 return; //failed
77 shm_mem = (char *) MapViewOfFile (shm_hand, FILE_MAP_WRITE, 0, 0, 0);
78 if (shm_mem == NULL)
79 return;
80 shm_mem[5] = 0;
81 sprintf (cmd, "scrolwin.exe %d %d", buflines, shm_hand);
82 GetStartupInfo(&start_info); //clone our stuff
83 if (!CreateProcess (NULL, cmd, NULL, NULL, TRUE,
84 CREATE_NO_WINDOW | DETACHED_PROCESS | CREATE_SUSPENDED,
85 NULL, NULL, &start_info, &proc_info))
86 return;
87
88 //save handles
89 dbg_process = proc_info.hProcess;
90 dbg_thread = proc_info.hThread;
91 if (ResumeThread (dbg_thread) != 1)
92 return;
93 do
94 Sleep (100);
95 while (shm_mem[5] == 0); //wait for handle
96 parm = ((((uinT8) shm_mem[4] << 8) + (uinT8) shm_mem[3] << 8)
97 + (uinT8) shm_mem[2] << 8) + (uinT8) shm_mem[1];
98 handle = (HWND) parm;
99 if (handle != NULL) {
100 //setup window
101 ::SetWindowText (handle, title);
102 ::MoveWindow (handle, xpos, ypos, xsize, ysize, TRUE);
103 ::ShowWindow (handle, SW_SHOW);
104 }
105 }
106
107
108 /**********************************************************************
109 * DEBUG_WIN::DEBUG_WIN
110 *
111 * Destroy a debug window.
112 **********************************************************************/
113
~DEBUG_WIN()114 DEBUG_WIN::~DEBUG_WIN (
115 //destructor
116 ) {
117 if (IsWindow (handle))
118 ::SendMessage (handle, WM_COMMAND, IDOK, 0);
119 if (shm_mem != NULL)
120 UnmapViewOfFile(shm_mem);
121 if (shm_hand != NULL)
122 CloseHandle(shm_hand);
123 if (dbg_thread != NULL)
124 CloseHandle(dbg_thread);
125 if (dbg_process == NULL)
126 CloseHandle(dbg_process);
127
128 }
129
130
131 /**********************************************************************
132 * dprintf
133 *
134 * Print a message to the debug window.
135 * Like printf, this function can cope with messages which do not end
136 * in newline, but nothing is printed until the newline is received.
137 **********************************************************************/
138
139 void
dprintf(const char * format,...)140 DEBUG_WIN::dprintf ( //debug printf
141 const char *format, ... //special message
142 ) {
143 va_list args; //variable args
144 char *msg_start; //for printing
145
146 if (!IsWindow (handle))
147 return; //destroyed
148 if (msg_end == NULL)
149 msg_end = shm_mem + 1;
150 va_start(args, format); //variable list
151 //Format into msg
152 vsprintf(msg_end, format, args);
153 va_end(args);
154 if (*msg_end == '\0')
155 return;
156 msg_start = shm_mem + 1;
157 do {
158 //end of line
159 msg_end = strchr (msg_start, '\n');
160 if (msg_end == NULL) {
161 if (msg_start != shm_mem + 1)
162 //bring to front
163 strcpy (shm_mem + 1, msg_start);
164 //current end
165 msg_end = shm_mem + 1 + strlen (shm_mem + 1);
166 return;
167 }
168 *msg_end = '\0';
169 while (IsWindow (handle) && shm_mem[0])
170 Sleep (500);
171 if (IsWindow (handle)) {
172 //Visual C++2.0 macro
173 ::SendMessage (handle, WM_COMMAND, ID_DEBUG_MSG, (DWORD) (msg_start - shm_mem));
174 }
175 msg_start = msg_end + 1;
176 }
177 while (*msg_start != '\0');
178 msg_end = shm_mem + 1; //buffer empty
179 }
180
181
182 /**********************************************************************
183 * await_destruction
184 *
185 * Wait for the user to close the debug window. Then return.
186 **********************************************************************/
187
await_destruction()188 void DEBUG_WIN::await_destruction() { //wait for user to close
189 WaitForSingleObject (dbg_process, (unsigned long) -1);
190 }
191 #endif //NT Implmentation
192
193 //UNIX implementation
194 #if defined(__UNIX__) || defined(_CONSOLE)
195 #ifdef __UNIX__
196 #include <unistd.h>
197 #include <signal.h>
198 #endif
199 //#include "basefile.h"
200
201 /**********************************************************************
202 * DEBUG_WIN::DEBUG_WIN
203 *
204 * Create a debug window with size according to the arguments.
205 * Create an hpterm window with a pipe connected to it.
206 **********************************************************************/
207
DEBUG_WIN(const char * title,inT32 xpos,inT32 ypos,inT32 xsize,inT32 ysize,inT32 buflines)208 DEBUG_WIN::DEBUG_WIN( //constructor
209 const char *title, //of window
210 inT32 xpos, //initial position
211 inT32 ypos, //in pixels
212 inT32 xsize, //initial size
213 inT32 ysize, //in pixels
214 inT32 buflines //default scroll size
215 ) {
216 #ifdef __UNIX__
217 inT32 length; /*length of name */
218 char command[MAX_PATH]; /*pipe command */
219 pid_t pid; /*process id */
220 char host[MAX_PATH]; //remote host
221 BOOL8 remote; //remote host
222
223 // remote=remote_display(host); //check remote host
224 remote = FALSE;
225 if (remote)
226 //do it remotely
227 length = sprintf (command, "remsh %s 'DISPLAY=%s;export DISPLAY;", host, getenv ("DISPLAY"));
228 else
229 length = 0;
230 length += sprintf (command + length, "trap \"\" 1 2 3 13 15\n");
231 length +=
232 sprintf (command + length,
233 "/usr/bin/xterm -sb -sl " INT32FORMAT " -geometry "
234 INT32FORMAT "x" INT32FORMAT "", buflines, xsize / 8, ysize / 16);
235 if (xpos >= 0)
236 command[length++] = '+';
237 length += sprintf (command + length, INT32FORMAT, xpos);
238 if (ypos >= 0)
239 command[length++] = '+';
240 length +=
241 sprintf (command + length,
242 INT32FORMAT " -title \"%s\" -n \"%s\" -e /bin/sh -c ", ypos,
243 title, title);
244 pid = getpid (); /*random number */
245 length +=
246 sprintf (command + length,
247 "\"stty opost; tty >/tmp/debug%d; while [ -s /tmp/debug%d ]\ndo\nsleep 1\ndone\" &\n",
248 pid, pid);
249 length +=
250 sprintf (command + length, "trap \"rm -f /tmp/debug%d; kill -9 $!\" 0\n",
251 pid);
252 length += sprintf (command + length, "trap \"exit\" 1 2 3 13 15\n");
253 length +=
254 sprintf (command + length,
255 "while [ ! -s /tmp/debug%d ]\ndo\nsleep 1\ndone\n", pid);
256 length += sprintf (command + length, "trap \"\" 1 2 3 13 15\n");
257 length += sprintf (command + length, "ofile=`cat /tmp/debug%d`\n", pid);
258 length +=
259 sprintf (command + length, "cat -u - >$ofile; rm /tmp/debug%d\n", pid);
260 if (remote) {
261 command[length++] = '\''; //terminate remsh
262 command[length] = '\0';
263 }
264 fp = popen (command, "w"); /*create window */
265 if (fp != NULL) {
266 /*set no buffering */
267 if (setvbuf (fp, NULL, _IONBF, BUFSIZ)) {
268 pclose(fp);
269 fp = NULL;
270 }
271 }
272 #endif
273 }
274
275
276 /**********************************************************************
277 * DEBUG_WIN::DEBUG_WIN
278 *
279 * Close the file and destroy the window.
280 **********************************************************************/
281
~DEBUG_WIN()282 DEBUG_WIN::~DEBUG_WIN (
283 //destructor
284 ) {
285 #ifdef __UNIX__
286 pclose(fp);
287 #endif
288 }
289
290
291 /**********************************************************************
292 * dprintf
293 *
294 * Print a message to the debug window.
295 * Like printf, this function can cope with messages which do not end
296 * in newline, but nothing is printed until the newline is received.
297 **********************************************************************/
298
299 void
dprintf(const char * format,...)300 DEBUG_WIN::dprintf ( //debug printf
301 const char *format, ... //special message
302 ) {
303 va_list args; //variable args
304
305 va_start(args, format); //variable list
306 #ifdef __UNIX__
307 vfprintf(fp, format, args); //Format into msg
308 #else
309 //Format into msg
310 vfprintf(stderr, format, args);
311 #endif
312 va_end(args);
313 }
314
315
316 /**********************************************************************
317 * await_destruction
318 *
319 * Wait for the user to close the debug window. Then return.
320 **********************************************************************/
321
await_destruction()322 void DEBUG_WIN::await_destruction() { //wait for user to close
323 #ifdef __UNIX__
324 signal(SIGPIPE, SIG_IGN);
325 while (!ferror (fp)) {
326 sleep (1);
327 fputc (0, fp); //send nulls until error
328 }
329 #endif
330 }
331 #endif //UNIX Implmentation
332
333 #ifdef __MAC__ //NT implementation
334 #include <stdio.h>
335 //#include "textwindow.h"
336 #include <lwindow.h>
337 #include "ipcbase.h" //must be last include
338
339 // Until I can figure a way to do this without linking in PowerPlant,
340 // the debug window will just have empty functions so compilation can take place.
341
342 /**********************************************************************
343 * DEBUG_WIN::SetCommander
344 *
345 * Mac-specific function to set the commander for the next debug window
346 **********************************************************************/
SetCommander(LCommander * pNew)347 void DEBUG_WIN::SetCommander(LCommander *pNew) {
348 pCommander = pNew;
349 }
350
351
352 /**********************************************************************
353 * DEBUG_WIN::DEBUG_WIN
354 *
355 * Create a debug window with size according to the arguments.
356 * Create an hpterm window with a pipe connected to it.
357 **********************************************************************/
358
DEBUG_WIN(const char * title,inT32 xpos,inT32 ypos,inT32 xsize,inT32 ysize,inT32 buflines)359 DEBUG_WIN::DEBUG_WIN( //constructor
360 const char *title, //of window
361 inT32 xpos, //initial position
362 inT32 ypos, //in pixels
363 inT32 xsize, //initial size
364 inT32 ysize, //in pixels
365 inT32 buflines //default scroll size
366 ) {
367 inT32 length; /*length of name */
368
369 // don't replace this DebugStr() with a call to DEBUG_WIN!
370
371 //if (pCommander==NULL) DebugStr("\pDEBUG_WIN::DEBUG_WIN(), Commander not set");
372
373 // create the window
374
375 //pWindow=LWindow::CreateWindow(2700,pCommander);
376 }
377
378
379 /**********************************************************************
380 * DEBUG_WIN::DEBUG_WIN
381 *
382 * Close the file and destroy the window.
383 **********************************************************************/
384
~DEBUG_WIN()385 DEBUG_WIN::~DEBUG_WIN (
386 //destructor
387 ) {
388 }
389
390
391 /**********************************************************************
392 * dprintf
393 *
394 * Print a message to the debug window.
395 * Like printf, this function can cope with messages which do not end
396 * in newline, but nothing is printed until the newline is received.
397 **********************************************************************/
398
399 void
dprintf(const char * format,...)400 DEBUG_WIN::dprintf ( //debug printf
401 const char *format, ... //special message
402 ) {
403 #if 0
404 LTextEdit *pTextEdit;
405 va_list args; //variable args
406 static char msg[1024];
407
408 inT32 i;
409 inT32 OriginalLength;
410 inT32 NewLength;
411 TEHandle hTextEdit;
412 char *pTempBuffer;
413 CharsHandle hChar;
414 char *pOriginalText;
415 inT32 StringLength;
416
417 pTextEdit = (LTextEdit *) pWindow->FindPaneByID (text_FLOWED);
418 if (pTextEdit == NULL)
419 DebugStr ("\pwhoops");
420
421 // get a C String from the format and args passed in
422
423 va_start(args, format); //variable list
424 vsprintf(msg, format, args); //Format into msg
425 va_end(args);
426
427 StringLength = strlen (msg);
428
429 // get the handle for the text
430
431 hTextEdit = pTextEdit->GetMacTEH ();
432 if (hTextEdit == NULL)
433 DebugStr ("\pDEBUG_WIN,WriteCharsToConsole()");
434
435 // get a pointer to the characters and the length of the character stream
436
437 hChar = TEGetText (hTextEdit);
438 if (hChar == NULL)
439 DebugStr ("\pDEBUG_WIN,WriteCharsToConsole()");
440
441 pOriginalText = *hChar; // get pointer to existing text
442
443 // get the length of the original data
444 OriginalLength = (*hTextEdit)->teLength;
445
446 // setup a temporary buffer for the new text
447
448 NewLength = OriginalLength + StringLength;
449
450 pTempBuffer = NewPtr (NewLength);
451 if (pTempBuffer == NULL)
452 DebugStr ("\pDEBUG_WIN,WriteCharsToConsole()");
453
454 // copy the original data into the new buffer
455
456 for (i = 0; i < OriginalLength; i++)
457 pTempBuffer[i] = pOriginalText[i];
458
459 // append the new data onto the end of the original buffer
460
461 for (i = 0; i < StringLength; i++) {
462 if (msg[i] == '\n')
463 pTempBuffer[i + OriginalLength] = '\r';
464 else
465 pTempBuffer[i + OriginalLength] = msg[i];
466 }
467
468 // put the new text into the text edit item
469
470 TESetText(pTempBuffer, NewLength, hTextEdit);
471
472 // clean up
473
474 DisposePtr(pTempBuffer);
475 #endif
476 }
477 #endif //Mac Implmentation
478
479 #else // Non graphical debugger
480
DEBUG_WIN(const char *,inT32,inT32,inT32,inT32,inT32)481 DEBUG_WIN::DEBUG_WIN( const char*, inT32, inT32, inT32, inT32, inT32 ) {
482 }
483
~DEBUG_WIN()484 DEBUG_WIN::~DEBUG_WIN () {
485 }
486
dprintf(const char * format,...)487 void DEBUG_WIN::dprintf (const char *format, ...) {
488 va_list ap;
489 va_start(ap, format);
490 vfprintf(stderr, format, ap);
491 va_end(ap);
492 }
493
await_destruction()494 void await_destruction() {
495 }
496
497
498 #endif
499
500