home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / Goodies / CDiagnostic.c next >
Encoding:
C/C++ Source or Header  |  1990-12-02  |  4.7 KB  |  209 lines  |  [TEXT/KAHL]

  1. /*    A diagnostic display (a Director). */
  2.  
  3. #include <TCL>
  4. #include "GLOBAL.h"
  5. #include "commands.h"
  6. #include "CDiagnostic.h"
  7. #include "CUtility.h"
  8. #include "CPanelMenus.h"
  9. #include "CLoader.h"
  10. #include "WIND.h"
  11. #include "SCPN.h"
  12. #include "STTX.h"
  13. #include "STR.h"
  14. #include "sizes.h"
  15. #include "chars.h"
  16. #include <stdio.h>
  17. #include <string.h>
  18.  
  19. #define    BUFFSIZE     1000            /*    Max characters of text buffered. We have
  20.                                         a fixed size buffer (handle). */
  21.  
  22. LOCAL enum {
  23.     NOT_INITIALISED,
  24.     RUNNING,
  25.     DISABLED,
  26.     TERMINATED
  27. } theState = NOT_INITIALISED;
  28.  
  29. LOCAL CDiagnostic *theDiagnostic;
  30.  
  31. NEW void CDiagnostic::IDiagnostic()
  32. {
  33.     Str255 buff;
  34.     int size;
  35.     Handle han;
  36.  
  37.     inherited::IDirector(gApplication);
  38.  
  39.   /*Create and initialise the director's window. */
  40.     itsWindow = new(CWindow);
  41.     itsWindow->IWindow(DIAGNOSTIC_wind, FALSE, gDesktop, this);
  42.  
  43.   /*We don't use the decorator for this window: we want it placed at the
  44.     bottom right of the screen, as per the WIND resource. */
  45.  
  46.   /*Create and set up the scroll-pane. */
  47.     itsScrollPane = new(CScrollPane);
  48.     itsScrollPane->IViewRes('ScPn', DIAGNOSTIC_scpn, itsWindow, gApplication);
  49.                                     /*    The enclosure is the diagnostic window.
  50.                                         The supervisor (to which we pass
  51.                                         everything) is the application. */
  52.  
  53.     itsScrollPane->FitToEnclFrame(TRUE, TRUE);
  54.     
  55.     itsStaticText = new(CStaticText);
  56.     itsStaticText->IViewRes('StTx', DIAGNOSTIC_sttx, itsScrollPane, gApplication);
  57.  
  58.     itsStaticText->FitToEnclosure(TRUE, TRUE);
  59.     itsScrollPane->InstallPanorama(itsStaticText);
  60.  
  61.     gUtility->GetFontAndSize(DIAGNOSTIC_index, buff, &size);
  62.     itsStaticText->SetFontName(buff);
  63.     itsStaticText->SetFontSize(size);
  64.  
  65.   /*Allocate the buffer for the text. */
  66.     han = gUtility->MustNewHandle(BUFFSIZE);
  67.     itsTextHan = han;
  68.     itsTextInUse = 0L;
  69.  
  70.   /*Force the first refresh. */
  71.     needUpdate = TRUE;
  72.     Update();
  73.     
  74.     itsWindow->Show();
  75.     itsWindow->Select();
  76. }
  77.  
  78. /*    Dispose() clears down the state flag so that any trailing diagnostics
  79.     are discarded. */
  80.  
  81. OVERRIDE void CDiagnostic::Dispose()
  82. {
  83.     theState = TERMINATED;
  84.     inherited::Dispose();
  85. }
  86.  
  87. OVERRIDE void CDiagnostic::UpdateMenus()
  88. {
  89.     inherited::UpdateMenus();
  90.     gBartender->DisableCmd(cmdClose);
  91. }
  92.  
  93. /*    FlushLine - get rid of the leading line of text in the buffer, copying
  94.                 all the following stuff down. */
  95.  
  96. PRIVATE void CDiagnostic::FlushLine()
  97. {
  98.     char *p0, *p;
  99.  
  100.     HLock(itsTextHan);
  101.  
  102.     gUtility->Assert("CDiagnostic::FlushLine", itsTextInUse > 0L);
  103.  
  104.   /*Point p0 at the start, advance p to the start of the second line.*/
  105.     p0 = *itsTextHan;
  106.     p = p0;
  107.     
  108.     while (*p != '\r')  p++;
  109.     p++;
  110.  
  111.   /*Move the text we want (everything except the stuff between p0 and p) down
  112.     to p0:*/
  113.     BlockMove(p, p0, itsTextInUse - (p - p0));
  114.     
  115.     itsTextInUse -= (p - p0);
  116.  
  117.     HUnlock(itsTextHan);
  118. }
  119.  
  120. PRIVATE void CDiagnostic::AppendText(char *text)    /*    text is a C string. */
  121. {
  122.     char *p;
  123.     Size len = strlen(text);
  124.     
  125.     HLock(itsTextHan);
  126.  
  127.     p = (char *)(*itsTextHan) + itsTextInUse;    /*    p := free space. */
  128.     
  129.     if (itsTextInUse > 0L) {
  130.         *p++ = '\r';                            /*    CR after previous line. */
  131.         itsTextInUse++;
  132.     }
  133.  
  134.     BlockMove(text, p, len);                    /*    p[1...] := text. */
  135.     itsTextInUse += len;
  136.  
  137.     HUnlock(itsTextHan);
  138. }
  139.  
  140. NEW void CDiagnostic::Update()
  141. {
  142.     if (needUpdate) {
  143.         HLock(itsTextHan);
  144.         itsStaticText->SetTextPtr(*itsTextHan, itsTextInUse);
  145.         HUnlock(itsTextHan);
  146.  
  147.         itsStaticText->ScrollToSelection();
  148.         
  149.         needUpdate = FALSE;
  150.     }
  151. }
  152.  
  153. /*    The main method: Diagnose takes arguments just like printf(), and sends them
  154.     to the diagnostic window. */
  155.  
  156. NEW void CDiagnostic::Diagnose(char *text)
  157. {
  158.     Size thisLen = strlen(text);
  159.     
  160.     while (itsTextInUse + thisLen >= BUFFSIZE)
  161.                         /*    Don't forget that we need space for separating CR
  162.                             (except if this is the first message). */
  163.         FlushLine();
  164.  
  165.     AppendText(text);
  166.     needUpdate = TRUE;
  167. }
  168.  
  169. /*    Vanilla procedures for the outside world. Note the local CDiagnostic object
  170.     and the locally-remembered state of the diagnostic machinery. */
  171.  
  172. GLOBAL void g_Diagnostic(format, a, b, c, d, e, f, g)
  173. char *format;
  174. {
  175.     char buffer[256];
  176.  
  177.     switch (theState) {
  178.         case NOT_INITIALISED:
  179.             if (Count1Resources('CODE') == 0) {        /*    Under THINK C. */
  180.                 theState = DISABLED;    /*    ARGH! Creating the diagnostic window
  181.                                             might generate diagnostics from
  182.                                             another director (e.g. dashboard). */
  183.                 theDiagnostic = new(CDiagnostic);
  184.                 theDiagnostic->IDiagnostic();
  185.                 theState = RUNNING;
  186.             } else {                                /*    We're a compiled app. */
  187.                 theState = DISABLED;
  188.                 return;
  189.             }
  190.  
  191.             break;
  192.  
  193.         case RUNNING:
  194.             break;                /*    No problem. */
  195.  
  196.         case DISABLED:
  197.         case TERMINATED:
  198.             return;                /*    Can't do any diagnostics. */
  199.     }
  200.  
  201.     sprintf(buffer, format, a, b, c, d, e, f, g);
  202.     theDiagnostic->Diagnose(buffer);
  203. }
  204.  
  205. GLOBAL void g_UpdateDiags()
  206. {
  207.     if (theState == RUNNING)  theDiagnostic->Update();
  208. }
  209.