skyrope-mit-merge-hell-20040226
[openafs.git] / src / WINNT / afsclass / c_debug.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include <windows.h>
16 #include <stdlib.h>
17 #include <memory.h>
18 #include <string.h>
19 #include <stdarg.h>
20 #include <WINNT/c_debug.h>
21
22 #ifdef DEBUG
23
24 #ifndef THIS_HINST
25 #define THIS_HINST (GetModuleHandle (NULL))
26 #endif
27
28 #define WM_OUTSTRING  (WM_USER + 0x99)
29
30
31
32 /*
33  * VARIABLES __________________________________________________________________
34  *
35  */
36
37                Debugstr    debug;
38
39                int         Debugstr::fRegistered = 0;
40                int         Debugstr::fInit = 0;
41                HWND        Debugstr::hwnd  = 0;
42
43                ushort      Debugstr::gx;
44                ushort      Debugstr::gy;
45                ushort      Debugstr::gcX;
46                ushort      Debugstr::gcY;
47                char        Debugstr::gdata[ yMAX ][ xMAX ];
48
49                BOOL        Debugstr::fAngles = FALSE;
50
51                ushort      nRefr;
52
53                ushort      cxAvgWidth    (void);
54
55
56 /*
57  * ROUTINES ___________________________________________________________________
58  *
59  */
60
61 int AssertFn (int b, char *expr, int line, char *name)
62 {
63    char  szLine1[ 256 ];
64    char  szLine2[ 256 ];
65
66    if (b)
67       return 1;
68
69    wsprintf (szLine1, "Assertion failed: \"%s\"", expr);
70    wsprintf (szLine2, "Line %u of module %s.", line, name);
71
72 #ifdef DEBUG
73 debug << szLine1 << "\n";
74 debug << szLine2 << "\n";
75 #endif
76
77    MessageBox (NULL, szLine1, szLine2, MB_ICONEXCLAMATION);
78    return 0;
79 }
80
81
82 /*
83  * OPERATORS __________________________________________________________________
84  *
85  */
86
87 Debugstr & Debugstr::operator<< (char *str)
88 {
89    if (! strcmp (str, ANGLES_ON))
90       fAngles = TRUE;
91    else if (! strcmp (str, ANGLES_OFF))
92       fAngles = FALSE;
93    else if (! strcmp (str, LASTERROR))
94       {
95       LPVOID lp;
96
97       FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
98                      NULL, GetLastError(),
99                      MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
100                      (LPTSTR)&lp, 0, NULL);
101
102       (*this) << "#" << (LONG)GetLastError();
103       (*this) << " (" << (char *)lp << ")";
104
105       LocalFree (lp);
106       }
107    else
108       {
109       Register();       // does nothing unless first time
110       Initialize();     // does nothing unless first time
111
112       char *strToSend = (char *)Allocate(1+strlen(str));
113       strcpy (strToSend, str);
114
115       PostMessage (Debugstr::hwnd, WM_OUTSTRING, 0, (LPARAM)strToSend);
116       }
117    return (*this);
118 }
119
120 Debugstr & Debugstr::operator<< (void *addr)
121 {
122    char  szTemp[40];
123    if (HIWORD(addr) == 0x0000)
124       wsprintf (szTemp, "0x%04X", (ushort)LOWORD(addr));
125    else
126       wsprintf (szTemp, "0x%08lX", (LONG)addr);
127    return (*this << szTemp);
128 }
129
130 Debugstr & Debugstr::operator<< (uchar ch)
131 {
132    char  szTemp[2];
133    szTemp[0] = ch;
134    szTemp[1] = 0;
135    return (*this << szTemp);
136 }
137
138 Debugstr & Debugstr::operator<< (char ch)
139 {
140    char  szTemp[2];
141    szTemp[0] = ch;
142    szTemp[1] = 0;
143    return (*this << szTemp);
144 }
145
146 Debugstr & Debugstr::operator<< (size_t l)
147 {
148    char  szTemp[40];
149    _ltoa (l, szTemp, 10);
150    return (*this << szTemp);
151 }
152
153 Debugstr & Debugstr::operator<< (long l)
154 {
155    char  szTemp[40];
156    _ltoa (l, szTemp, 10);
157    return (*this << szTemp);
158 }
159
160 Debugstr & Debugstr::operator<< (ushort s)
161 {
162    char  szTemp[40];
163    _itoa (s, szTemp, 10);
164    return (*this << szTemp);
165 }
166
167 Debugstr & Debugstr::operator<< (short s)
168 {
169    char  szTemp[40];
170    _itoa (s, szTemp, 10);
171    return (*this << szTemp);
172 }
173
174 Debugstr & Debugstr::operator<< (double f)
175 {
176    char *psz;   // (may cross segments)
177    char  szTemp[ 64 ];
178    long  l;
179
180    if (fAngles)
181       {
182       f *= 180.0 / 3.1415926535897;
183       while (f >= 360)
184          f -= 360;
185       while (f < 0)
186          f += 360;
187       }
188
189    l = (long)f;
190    *this << l;
191
192    f -= (double)l;
193    f *= 1000000.0;      // add 6 zeroes...
194    l = (long)f;
195
196    wsprintf (szTemp, "%06ld", l);
197
198    for (psz = &szTemp[ strlen(szTemp)-1 ]; psz >= szTemp; psz--)
199       {
200       if (*psz != '0')
201          break;
202       }
203    *(1+psz) = 0;
204
205    if (szTemp[0] != 0)
206       {
207       *this << "." << szTemp;
208       }
209
210    return *this;
211 }
212
213 Debugstr & Debugstr::operator<< (RECT r)
214 {
215    *this << "{ x=" << (LONG)r.left << ".." << (LONG)r.right;
216    *this << ", y=" << (LONG)r.top << ".." << (LONG)r.bottom << " }";
217    return (*this);
218 }
219
220 Debugstr & Debugstr::operator<< (LPIDENT lpi)
221 {
222    if (!lpi)
223       {
224       *this << "{ invalid ident }";
225       }
226    else if (lpi->fIsCell())
227       {
228       TCHAR szCell[ cchNAME ];
229       lpi->GetCellName (szCell);
230       *this << "{ cell " << szCell << " }";
231       }
232    else if (lpi->fIsServer())
233       {
234       TCHAR szServer[ cchNAME ];
235       lpi->GetServerName (szServer);
236       *this << "{ server " << szServer << " }";
237       }
238    else if (lpi->fIsAggregate())
239       {
240       TCHAR szServer[ cchNAME ];
241       lpi->GetServerName (szServer);
242       TCHAR szAggregate[ cchNAME ];
243       lpi->GetAggregateName (szAggregate);
244       *this << "{ aggregate " << szServer << ":" << szAggregate << " }";
245       }
246    else if (lpi->fIsFileset())
247       {
248       TCHAR szServer[ cchNAME ];
249       lpi->GetServerName (szServer);
250       TCHAR szAggregate[ cchNAME ];
251       lpi->GetAggregateName (szAggregate);
252       TCHAR szFileset[ cchNAME ];
253       lpi->GetFilesetName (szFileset);
254       *this << "{ fileset " << szFileset << " on " << szServer << ":" << szAggregate << " }";
255       }
256    else if (lpi->fIsServer())
257       {
258       TCHAR szServer[ cchNAME ];
259       lpi->GetServerName (szServer);
260       TCHAR szService[ cchNAME ];
261       lpi->GetServiceName (szService);
262       *this << "{ service " << szServer << ":" << szService << " }";
263       }
264    return (*this);
265 }
266
267
268 /*
269  * STATICS ____________________________________________________________________
270  *
271  */
272
273 Debugstr::Debugstr (void)
274 {
275    hfNew = NULL;
276    brBack = NULL;
277 }
278
279 Debugstr::~Debugstr (void)
280 {
281    if (hfNew != NULL)
282       {
283       DeleteObject (hfNew);
284       hfNew = NULL;
285       }
286
287    if (brBack != NULL)
288       {
289       DeleteObject (brBack);
290       brBack = NULL;
291       }
292 }
293
294
295 #define szDebugCLASS  "DebugClass"
296
297 void Debugstr::Register (void)
298 {
299    WNDCLASS  wc;
300
301    if (fRegistered)
302       return;
303    fRegistered = TRUE;
304
305    wc.style         = CS_HREDRAW | CS_VREDRAW;
306    wc.lpfnWndProc   = DebugWndProc;
307    wc.cbClsExtra    = 0;
308    wc.cbWndExtra    = 0;
309    wc.hInstance     = THIS_HINST;
310    wc.hIcon         = LoadIcon(NULL, IDI_EXCLAMATION);
311    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
312    wc.hbrBackground = CreateSolidBrush( GetSysColor( COLOR_BTNFACE ));
313    wc.lpszMenuName  = NULL;
314    wc.lpszClassName = szDebugCLASS;
315
316    (void)RegisterClass(&wc);
317 }
318
319
320 void Debugstr::Initialize (void)
321 {
322    HWND       hWnd;
323    int        x, y, w, h;
324
325    if (fInit)
326       return;
327    fInit = TRUE;
328
329    w = cxAvgWidth() * 58;
330 // w = cxAvgWidth() * 160;
331    h = GetSystemMetrics (SM_CYSCREEN);
332    x = GetSystemMetrics (SM_CXSCREEN) - w;
333    y = 0;
334
335    hWnd = CreateWindow(
336               szDebugCLASS,
337               "debug++",        // Title
338               WS_OVERLAPPEDWINDOW |     // Window style
339                  WS_THICKFRAME,
340               x,        // Default horizontal position
341               y +35,    // Default vertical position
342               w,        // Default width
343               h -70,    // Default height
344               NULL,     // Overlapped windows have no parent
345               NULL,     // Use the window class menu
346               THIS_HINST,       // This instance owns this window
347               NULL      // Pointer not needed
348               );
349
350    if (!hWnd)
351       return;
352
353           /*
354            * Make the window visible and update its client area.
355            *
356            */
357
358    for (y = 0; y < yMAX; y++)
359       gdata[y][0] = 0;
360
361    gx  = minX;
362    gy  = minY;
363    gcX = 0;
364    gcY = 0;
365    nRefr = 0;
366
367    ShowWindow (hWnd, SW_SHOWNOACTIVATE);
368    UpdateWindow (hWnd);
369
370    Debugstr::hwnd = hWnd;
371 }
372
373
374 /*** OutString - Translates "\n" 's, and calls Output to display text
375  *
376  * ENTRY:     char   *str     - string to display
377  *            BOOL    fRecord - FALSE if inside WM_PAINT message
378  *
379  * EXIT:      none
380  *
381  */
382
383 void Debugstr::OutString (char *str, BOOL fRecord)
384 {
385    char      *psz, *pch;
386    HDC        hdc;
387    DWORD      fg, bk;
388    RECT       r;
389    RECT       r2;
390    HFONT      hfOld;
391    LOGFONT    lf;
392    SIZE       siz;
393
394    Register();  // does nothing unless first time
395    Initialize();        // does nothing unless first time
396
397    if (str == NULL)
398       str = "(null)";
399
400    OutputDebugString (str);
401
402    if (Debugstr::hwnd == NULL)
403       return;
404
405    if ((hdc = GetDC (Debugstr::hwnd)) == NULL)
406       return;
407
408    fg = SetTextColor (hdc, GetSysColor( COLOR_BTNTEXT ));
409    bk = SetBkColor (hdc, GetSysColor( COLOR_BTNFACE ));
410
411    if (brBack == NULL)
412       {
413       brBack = CreateSolidBrush (GetBkColor(hdc));
414       }
415
416    if (hfNew == NULL)
417       {
418       memset (&lf, 0, sizeof(lf));
419
420       lf.lfWeight = FW_NORMAL;
421       lf.lfHeight = -MulDiv (8, GetDeviceCaps(hdc, LOGPIXELSY), 72);
422       strcpy (lf.lfFaceName, "Arial");
423
424       hfNew = CreateFontIndirect(&lf);
425       }
426
427    hfOld = (HFONT)SelectObject(hdc, hfNew);
428    GetTextMetrics (hdc, &tm);
429
430    GetClientRect (Debugstr::hwnd, &r);
431
432    if (!strcmp (str, "CLS"))
433       {
434       gx  = 0;
435       gy  = minY;
436       gcX = 0;
437       gcY = 0;
438       gdata[gcY][0] = 0;
439       gdata[gcY+1][0] = 0;
440
441       FillRect (hdc, &r, brBack);
442       }
443    else for (psz = str; *psz; )
444       {
445       if ((pch = strchr(psz, '\n')) == NULL)
446          {
447          Output (hdc, psz, fRecord);
448          break;
449          }
450
451       *pch = 0;
452       Output (hdc, psz, fRecord);
453
454       gy += (ushort)tm.tmHeight;
455       gcY++;
456       gx  = minX;
457       gcX = 0;
458
459       if (fRecord)
460          {
461          if ((gy + tm.tmHeight) > (ushort)r.bottom)
462             {
463             gy = minY;
464             gcY = 0;
465
466             GetTextExtentPoint (hdc, gdata[gcY], strlen(gdata[gcY]), &siz);
467
468             r2.top = gy;
469             r2.bottom = gy + tm.tmHeight;
470             r2.left = gx -1;
471             r2.right = siz.cx;
472             r2.right += gx;
473             FillRect (hdc, &r2, brBack);
474
475             gdata[gcY][0] = 0;
476             }
477          }
478
479       nRefr = max( nRefr, gcY );
480
481       *pch = '\n';
482       psz = 1+pch;
483
484       if (fRecord)
485          {
486          GetTextExtentPoint (hdc, gdata[gcY+1], strlen(gdata[gcY+1]), &siz);
487
488          r2.top = gy +tm.tmHeight;
489          r2.bottom = gy +tm.tmHeight +tm.tmHeight;
490          r2.left = gx;
491          r2.right = siz.cx;
492          r2.right += gx;
493          FillRect (hdc, &r2, brBack);
494
495          gdata[gcY+1][0] = 0;
496          }
497       }
498
499    SelectObject (hdc, hfOld);
500    SetTextColor (hdc, fg);
501    SetBkColor   (hdc, bk);
502    ReleaseDC    (Debugstr::hwnd, hdc);
503 }
504
505
506 void Debugstr::Output (HDC hdc, char *psz, BOOL fRec)
507 {
508    SIZE   siz;
509
510    TextOut (hdc, gx, gy, psz, strlen(psz));
511
512    if (fRec)
513       strcat (gdata[gcY], psz);
514
515    GetTextExtentPoint (hdc, psz, strlen(psz), &siz);
516
517    gx += (ushort)siz.cx;
518    gcX += strlen(psz);
519 }
520
521
522
523 /*** DebugWndProc - Main window callback
524  *
525  * ENTRY:  
526  * EXIT:      As WNDPROC
527  *
528  * MESSAGES:  WM_COMMAND    - application menu (About dialog box)
529  *            WM_DESTROY    - destroy window
530  *
531  */
532
533 LONG APIENTRY Debugstr::DebugWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
534 {
535    ushort   x, y, cX, cY;
536
537    switch (message)
538       {
539       case WM_COMMAND:
540            break;
541
542       case WM_DESTROY:
543             if (Debugstr::hwnd != 0)
544                {
545                CloseWindow (Debugstr::hwnd);
546                Debugstr::hwnd = 0;      // Turn off debugging--no window!
547                }
548            break;
549
550       case WM_OUTSTRING:
551             {
552             char *str = (char*)lParam;
553             debug.OutString (str, TRUE);
554             Free (str);
555             }
556            break;
557
558       case WM_PAINT:
559             {
560             PAINTSTRUCT ps;
561             HDC         hdc;
562             hdc = BeginPaint (hWnd, &ps);
563             EndPaint (hWnd, &ps);
564
565             x = gx; y = gy; cX = gcX; cY = gcY;
566
567             gx = minX;
568             gy = minY;
569             gcX = 0;
570             gcY = 0;
571
572             for (gcY = 0; gcY < nRefr; )
573                {
574                TCHAR szLine[] = TEXT("\n");
575                debug.OutString (gdata[gcY], FALSE);
576                debug.OutString (szLine, FALSE);
577                }
578             debug.OutString (gdata[gcY], FALSE);
579
580             gx = x; gy = y; gcX = cX; gcY = cY;
581             return 0;
582             }
583            break;
584
585       default:
586            break;
587       }
588
589    return (DefWindowProc(hWnd, message, wParam, lParam));
590 }
591
592
593 /*** cxAvgWidth - Returns the average width of the chars in Arial/8point.
594  *
595  * ENTRY:     none
596  *
597  * EXIT:      ushort pels
598  *
599  * ERROR:     returns 8
600  *
601  */
602
603 ushort cxAvgWidth (void)
604 {
605    HFONT      hfnt, hfntOld = NULL;
606    LOGFONT    lf;
607    TEXTMETRIC tm;
608    HDC        hdc;
609
610
611    hdc = GetDC( GetDesktopWindow() );
612
613    memset (&lf, 0, sizeof(lf));
614    lf.lfHeight = -MulDiv (8, GetDeviceCaps(hdc, LOGPIXELSY), 72);
615    strcpy (lf.lfFaceName, "Arial");
616
617    if ((hfnt = CreateFontIndirect(&lf)) != NULL)
618       {
619       hfntOld = (HFONT)SelectObject(hdc, hfnt);
620       }
621
622    if (! GetTextMetrics (hdc, &tm))
623       return 8;
624
625    if (hfntOld != NULL)
626       {
627       SelectObject (hdc, hfntOld);
628       DeleteObject (hfnt);
629       }
630
631    ReleaseDC (GetDesktopWindow(), hdc);
632
633    return (ushort)tm.tmAveCharWidth;
634 }
635
636
637 /*
638  * LOG ROUTINES
639  *
640  */
641
642 #define LONG_TYPE    0x0001
643 #define SHORT_TYPE   0x0002
644 #define INT_TYPE     0x0004
645 #define CHAR_TYPE    0x0008
646 #define STRING_TYPE  0x0010
647 #define FLOAT_TYPE   0x0020
648 #define COMMA_TYPE   0x0040
649 #define MSG_TYPE     0x0080
650
651 cdecl LogOut::LogOut (char *psz, ...)
652 {
653    char     *pch;
654    ushort    n;
655    BOOL      fBreak;
656    va_list   arg;
657    va_start (arg, psz);
658
659    strcpy (pszFormat, psz);
660    nArgs = 0;
661
662    for (pch = psz; *pch; pch++)
663       {
664       if (*pch != '%')
665          continue;
666
667       n = 0;
668       fBreak = FALSE;
669
670       while (!fBreak)
671          {
672          if (!* (++pch))
673             break;
674
675          switch (*pch)
676             {
677             case 'F':    n |= LONG_TYPE;    break;
678             case 'l':    n |= LONG_TYPE;    break;
679             case 'h':    n |= SHORT_TYPE;   break;
680             case 'X':    n |= INT_TYPE;     break;
681             case 'x':    n |= INT_TYPE;     break;
682             case 'O':    n |= INT_TYPE;     break;
683             case 'o':    n |= INT_TYPE;     break;
684             case 'd':    n |= INT_TYPE;     break;
685             case 'u':    n |= INT_TYPE;     break;
686             case 'c':    n |= CHAR_TYPE;    break;
687             case 's':    n |= STRING_TYPE;  break;
688             default:     fBreak = TRUE;     break;
689             }
690          }
691
692       if (nArgs == MAX_ARGS)
693          break;
694
695       aPtr[nArgs] = va_arg (arg, char *);
696
697       nArgs++;
698
699       if (! *pch)
700          break;
701       }
702 }
703
704 LogOut::~LogOut (void)
705 {
706    char      tmpfmt[ 64 ];
707    char      text[ 256 ];
708    char     *pszOut;
709    char     *pszTmpFmt;
710    char     *pszFmt;
711    char     *pch;
712    ushort    i = 0;
713    ushort    n;
714    BOOL      fBreak;
715
716    pszOut = text;
717
718    for (pszFmt = pszFormat; *pszFmt; pszFmt++)
719       {
720       if (*pszFmt != '%')
721          {
722          *pszOut++ = *pszFmt;
723          continue;
724          }
725
726       n = 0;
727       fBreak = FALSE;
728
729       for (pszTmpFmt = tmpfmt; !fBreak; )
730          {
731          *pszTmpFmt++ = *pszFmt;
732
733          if (!* (++pszFmt))
734             break;
735
736          switch (*pszFmt)
737             {
738             case 'F':    n |= LONG_TYPE;    break;   // (far)
739             case 'l':    n |= LONG_TYPE;    break;
740             case 'h':    n |= SHORT_TYPE;   break;
741             case 'X':    n |= INT_TYPE;     break;
742             case 'x':    n |= INT_TYPE;     break;
743             case 'O':    n |= INT_TYPE;     break;
744             case 'o':    n |= INT_TYPE;     break;
745             case 'd':    n |= INT_TYPE;     break;
746             case 'u':    n |= INT_TYPE;     break;
747             case 'c':    n |= CHAR_TYPE;    break;
748             case 's':    n |= STRING_TYPE;  break;
749             default:     fBreak = TRUE;     break;
750             }
751          }
752
753       *pszTmpFmt = 0;
754
755       pch = aPtr[ i ];
756       i++;
757
758
759       if (n & STRING_TYPE)
760          {
761          wsprintf (pszOut, tmpfmt, (char far *)pch);
762          }
763       else if (n & LONG_TYPE)
764          wsprintf (pszOut, tmpfmt, *(long *)pch);
765       else if (n & SHORT_TYPE)
766          wsprintf (pszOut, tmpfmt, *(short *)pch);
767       else if (n & INT_TYPE)
768          wsprintf (pszOut, tmpfmt, *(int *)pch);
769       else if (n & CHAR_TYPE)
770          wsprintf (pszOut, tmpfmt, (char)*(char *)pch);
771       else
772          *pszOut = 0;
773
774       pszOut = &pszOut[ strlen(pszOut) ];
775
776       if (! *pszFmt)
777          break;
778       }
779
780    *pszOut = 0;
781
782    debug << text << "\n";
783 }
784
785 #endif // DEBUG