home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 355_01 / slk1.exe / SHERLOCK / SHERLOCK.C < prev    next >
C/C++ Source or Header  |  1991-06-09  |  48KB  |  2,316 lines

  1. /*
  2.     Sherlock run-time routines.
  3.  
  4.     bug fix: 10/18/88: sl_visit().
  5.     bug fix: 2/10/89:  sl_lout().
  6.     added:   2/10/89:  sl_uiout() and sl_ulout().
  7.     bug fix: 4/19/89:  sl_set().
  8.     bug fix: 6/27/89:  sl_check().
  9.     lib fix: 6/30/89:  ltoa, itoa redefined.
  10.     added:   8/3/89:   sl_adjust().  Used only by sl_dump().
  11.     bug fix: 4/17/90:  sl_level made a global var as in manual.
  12.  
  13.     Mark I  version started: September 26, 1985
  14.     Mark II version started: September 8, 1986
  15.  
  16.     Source:   sherlock.c
  17.     Versions:
  18.  
  19.         0.6a    June 8, 1988
  20.         0.7    June 21, 1988
  21.         0.7c    June 28, 1988
  22.         0.8    July 14, 1988
  23.         1.0    July 21, 1988
  24.         1.1    February 14, 1989
  25.         1.2    February 27, 1989
  26.         1.3    April 19, 1989
  27.         1.4    June 27, 1989
  28.         1.5    August 4, 1989
  29.         1.6    April 17, 1990
  30.         1.7 June 15, 1991    First Public Domain Version
  31.  
  32.  
  33.     PUBLIC DOMAIN SOFTWARE
  34.  
  35.     Sherlock, including the SPP, SDEL and SDIF programs, was placed in
  36.     the public domain on June 15, 1991, by its author,
  37.  
  38.         Edward K. Ream
  39.         166 North Prospect Ave.
  40.         Madison, WI 53705.
  41.         (608) 257-0802
  42.  
  43.     Sherlock may be used for any commercial or non-commercial purpose.
  44.  
  45.  
  46.     DISCLAIMER OF WARRANTIES
  47.  
  48.     Edward K. Ream (Ream) specifically disclaims all warranties,
  49.     expressed or implied, with respect to this computer software,
  50.     including but not limited to implied warranties of merchantability
  51.     and fitness for a particular purpose.  In no event shall Ream be
  52.     liable for any loss of profit or any commercial damage, including
  53.     but not limited to special, incidental consequential or other damages.
  54.  
  55.  
  56.     This file has the following parts:
  57.     1.  Data structures and definitions.
  58.     2.  Internal (static) routines.
  59.     3.  Externally visible routines common to Mark I and Mark I versions.
  60.     4.  Mark I  versions of routines.
  61.     5.  Mark II versions of routines.
  62.     6.  Output routines
  63. */
  64.  
  65. #include <stdio.h>
  66. #include <stdlib.h>
  67. #include <process.h>
  68. #include <string.h>
  69. #include <ctype.h>
  70.  
  71. /* most Compilers don't have itoa() or ltoa */
  72. #define    itoa(a, b, c)    sprintf(b, "%d", a);
  73. #define    ltoa(a, b, c)    sprintf(b, "%ld", a);
  74.  
  75. #define SL_VERSION_NAME "1.7"
  76.  
  77. #define STAT_FLAG    TRUE
  78. #define NO_STAT_FLAG    FALSE
  79. #define ENTRY_FLAG    TRUE
  80. #define NO_ENTRY_FLAG    FALSE
  81.  
  82. /*
  83.     Define this constant if your compiler allows function prototypes.
  84. */
  85. #define HAS_ANSI_PROTOTYPE 1
  86.  
  87. /*
  88.     Select which version of the macros to define.
  89.  
  90.     The Mark I versions call sl_find() EVERY time to determine whether
  91.     the tracepoint has been enabled.  The Mark II versions call
  92.     sl_find() only on the initial encounter with the tracepoint.
  93.  
  94.     The difference in speed between the Mark I and Mark II versions can
  95.     be large.  Use the Mark I version of the routines only if you are
  96.     forced to do so by problems with the compiler you are using. All 
  97.     standard C compilers should be able to handle the Mark II version.
  98. */
  99.  
  100. #define MARKI 1
  101. #define MARKII 1
  102.  
  103. /*
  104.     ========== PART 1 ==========
  105.     Data structures and definitions.
  106. */
  107.  
  108. /*
  109.     Define constants that enable output for debugging the Sherlock code
  110.     itself.  Normally, these constants should be commented out.
  111.  
  112.     BUG_STATS:    enables printing of internal statistics by sl_dump().
  113.     BUG_HASH_DUMP:    enables printing of internal statistics relating to
  114.             the hash table.
  115.     BUG_DEBUG:    enables printing of internal tracing messages.
  116.  
  117.     The STATS macro is for use ONLY within this file.  It expands the
  118.     statement supplied as its actual parameter only if BUG_STATS variable
  119.     is defined.  Typically, the actual parameter is a statement which bumps
  120.     an internal tracing statistic.
  121.  
  122.     The DEBUG macro is for use ONLY within this file.  It expands the
  123.     statement supplied as its actual parameter only if the BUG_DEBUG 
  124.     variable is defined.  Typically, the actual parameter is a printf()
  125.     statement used to trace the internal workings of the routines on this
  126.     file.
  127. */
  128.  
  129. /* -----
  130. #define BUG_STATS 1
  131. #define BUG_DEBUG 1
  132. ----- */
  133.  
  134. #ifdef BUG_STATS
  135. #define STATS(statement) statement
  136. #else
  137. #define STATS(statement)
  138. #endif
  139.  
  140. #ifdef BUG_DEBUG
  141. #define DEBUG(statement) statement
  142. #else
  143. #define DEBUG(statement)
  144. #endif
  145.  
  146. /*
  147.     Define various constants.
  148. */
  149. #define TRUE        (1)
  150. #define FALSE         (0)
  151. #define BAD_EXIT     (1)
  152.  
  153. /*
  154.     Define the format of statistics nodes.
  155.  
  156.     These nodes are used to keep all information related to tracepoints.
  157.     There is exactly one node per tracepoint, regardless of how many
  158.     times a tracepoint name appears throughout the code.
  159. */
  160. static struct stat {
  161.     struct stat * next;    /* pointer to next bucket.    */
  162.     struct stat * alpha;    /* alphabetical list.        */
  163.     char *    name;        /* pointer to checkpoint name.    */
  164.     long    n_stat;        /* # of calls to macros.    */
  165.     long    n_disable;    /* # of prints to skip or 0.    */
  166.     long    n_times;    /* # of profiler ticks.        */
  167.     long    n_2times;    /* Cumulative ticks.        */
  168.     int    trace;        /* trace flag.            */
  169. };
  170.  
  171. /*
  172.     Define a dummy node used as a target for statistics gathering
  173.     before the first Sherlock macro is seen.
  174.  
  175.     The dummy node also is used as the list header when the nodes are
  176.     alphabetized by sl_dump().
  177. */
  178. static struct stat a_list;
  179.  
  180. /*
  181.     Define a (fixed size) array of statistics nodes. All stat nodes are
  182.     allocated from this array. We do NOT call dynamic storage allocation,
  183.     (such as malloc() or calloc()) to get node storage so as not to
  184.     disturb memory while tracing.
  185.  
  186.     The sl__nodes [] array holds all the nodes.
  187.     The cur_stat variable counts how many entries in sl__nodes [] have
  188.     already been allocated.
  189. */
  190.  
  191. #define MAX_STAT 500
  192. static struct stat sl__nodes [MAX_STAT];    /* Static node table.    */
  193. static int cur_stat = 0;
  194.  
  195. /*
  196.     Define a (fixed size) array used to keep track of nesting of Sherlock
  197.     macros.  ENTER macros push pointers to stat nodes on the stack.  EXITxx
  198.     macros pop entries from the stack.  Non-cumulative timing statistics
  199.     only increment the top of the stack.  Cumulative timing statistics 
  200.     increment all entries on the stack.
  201.  
  202.     The sl_level variable does double duty.  It keeps track of the top 
  203.     entry on the call_stack and it is used to indent output to reflect the
  204.     current nesting level.
  205. */
  206. #define MAX_BUG_LEVEL 100
  207. static struct stat * call_stack [MAX_BUG_LEVEL];
  208.  
  209. /* This is a global variable. */
  210. int sl_level = 0;
  211.  
  212. /*
  213.     Define the hash table used to speed the search of statistics nodes.
  214.  
  215.     The 'next' field of each stat node chains together all nodes with
  216.     the same hash value.
  217. */
  218.  
  219. #define MAX_HASH 241
  220. static struct stat * hash_tab [MAX_HASH];
  221.  
  222. /*
  223.     Define the list of names of wildcards which have been enabled from
  224.     the command line or via calls to sl_on or sl_off().  This list is
  225.     used by sl_new() to determine whether tracing is enabled or not.
  226.  
  227.     As wildcards are seen, they are added to the HEAD of the list, which
  228.     essentially means that the list is searched in REVERSE order for 
  229.     matches.  This is best, since the scan of the list can stop with the
  230.     first match found, rather than having to scan the whole list.
  231. */
  232. static struct stat * wildcard = NULL;    /* Head of wildcard list.    */
  233.  
  234. /*
  235.     The troff variable suppress the operation of all STAT, TICK, TRACE
  236.     TRACEP and RETURN_xxx macros.    The troff variable is set if "--trace"
  237.     is seen on the command line or if sl_off("trace") is seen.
  238.  
  239.     The only way of re-enabling Sherlock's macros after troff becomes
  240.     TRUE is to execute sl_on("trace").  Note that the call to sl_on()
  241.     must not occur inside a TRACE or TRACEP macro!!
  242. */
  243. static int troff = FALSE;     /* TRUE if all tracing disabled.    */
  244.  
  245. /*
  246.     The check_s variable contains of the name of the macro currently 
  247.     executing.  It is made global so as to avoid the overhead of passing
  248.     extra parameters to sl_set() and sl_check().
  249. */
  250. static char * check_s = NULL;    /* Name of current macro.        */
  251.  
  252. /*
  253.     Define local and global "disable counts."
  254.  
  255.     The disable variable contains a disable count which is associated
  256.     with a single variable.  The g_disable variable contains the global
  257.     disable count.  Both disable and g_disable are set by sl_set() and
  258.     used by sl_new() when new nodes are created.
  259.  
  260.     Local disable counts are set by preceeding the name of a tracpoint by
  261.     a number.  For example,  --100xyz sets the local disable count of xyz
  262.     to 100.  The single global disable count is set by following a prefix
  263.     by a number alone.  For example, --100 sets the global disable count
  264.     to 100.
  265.  
  266.     Disable counts suppress the operation of all tracing macros.
  267.     Each time such a macro is encounted, a check is made of both the
  268.     global disable count and the local disable count associated with the
  269.     tracepoint.  Both global and local counts are decremented as long as
  270.     either or both are non-zero.
  271. */
  272. static long    disable      = 0;        /* Local disable count.         */
  273. static long    g_disable = 0;        /* Global disable printing counter. */
  274.  
  275. /*
  276.     Define globals used to communicate with the Interrupt Handler.
  277.  
  278.     The interrupt handler allows Sherlock macros to gather timing 
  279.     statistics.  The interrupt handler code (in PRF.ASM) is required
  280.     only if the TIME_STATS variable is defined.
  281.  
  282.     WARNING:    By necessity, the interrupt handler contains
  283.             MACHINE DEPENDENT CODE.  Using this code is not
  284.             guarranteed to work and may cause your system to
  285.             crash.  See further warnings in file PRF.ASM.
  286.  
  287.     TIME_STATS    enables code which gathers timing statistics.
  288.  
  289.     sl_count    a global variable which is incremented each time
  290.             the interrupt handle is executed.
  291.  
  292.     sl_speed    The 'speed-up factor' used to speed up the system
  293.             timer to acheive speeds greater than the default
  294.             speed of 18.2 clock ticks per second.
  295.  
  296.             As you can imagine, increasing the speed of the system
  297.             clock is potentially a MACHINE DEPENDENT OPERATION.
  298.             However, the interrupt handler masks the speedup from
  299.             the rest of the system by passing only selected ticks
  300.             on to the old tick routine.
  301.  
  302.             A setting of 55 for sl_speed gives about
  303.             1 time/tick per msec. (assuming 18.2 clock ticks/sec.)
  304. */
  305.  
  306. /* comment out -----
  307. #define TIME_STATS 1
  308. ----- end comment out */
  309.  
  310. unsigned long        sl_count    = 0;    /* Timing count.    */
  311. unsigned int        sl_speed    = 55;    /* Default clock speed.    */
  312.  
  313. /*
  314.     Define internal tracing variables.
  315.  
  316.     The variables whose names begin with t_ are used only if BUG_STATS
  317.     defined.  They count how many times Sherlock's routines are called.
  318.  
  319.     The bin array is used to count the number of hash chains of there are
  320.     of a given length.  bin [i] counts the number of chains in the hash
  321.     table with length i.  bin [10] counts the number of chains with length
  322.     10 or more. Very few chains typically contain two or more elements, so
  323.     this small array gives acceptable statistics.
  324. */
  325.  
  326. /* -----
  327. #define BUG_HASH_DUMP 1
  328. ----- */
  329.  
  330. #ifdef BUG_HASH_DUMP
  331. static    int bin[10];
  332. #endif
  333.  
  334. #ifdef BUG_STATS
  335.  
  336. static long t_buffer    = 0;
  337. static long t_check    = 0;
  338. static long t_cmp    = 0;
  339. static long t_eq    = 0;
  340. static long t_find    = 0;
  341. static long t_hash    = 0;
  342. static long t_init    = 0;
  343. static long t_match    = 0;
  344. static long t_new    = 0;
  345. static long t_on    = 0;
  346. static long t_off    = 0;
  347.  
  348. static long t_bstat    = 0;
  349. static long t_btick    = 0;
  350. static long t_btrace    = 0;
  351. static long t_ntick    = 0;
  352. static long t_ntrace    = 0;
  353. static long t_ptrace    = 0;
  354. static long t_pbtrace    = 0;
  355. static long t_pntrace    = 0;
  356. static long t_pxtrace    = 0;
  357. static long t_set    = 0;
  358. static long t_stat    = 0;
  359. static long t_tick    = 0;
  360. static long t_trace    = 0;
  361. static long t_xtrace    = 0;
  362. static long t_wild    = 0;
  363.  
  364. #endif
  365.  
  366. /*
  367.     Forward declarations of external routines.
  368.     They are needed because sl.h is not #include'd in this file.
  369.  
  370.     sl_von() is not mentioned in sl.h.  It is defined in PRF.ASM.
  371.  
  372.     Note that Microsoft version 4.00 does not allow dummy names in
  373.     these function prototypes.
  374. */
  375. #ifdef HAS_ANSI_PROTOTYPE
  376.  
  377. void    sl_bout    (int);
  378. void    sl_cout    (char);
  379. void    sl_dout    (double);
  380. void    sl_fout    (double);    /* Floats are passed as doubles. */
  381. void    sl_iout    (int);
  382. void    sl_lout    (long);
  383. void    sl_pout (void *);
  384. char *    sl_sbout(int);
  385. void    sl_sout (char *);
  386. void    sl_uiout(unsigned int);
  387. void    sl_ulout(unsigned long);
  388.  
  389. int    sl_ret    (char *);
  390. void    sl_off    (char *);
  391. void    sl_on    (char *);
  392. void    sl_von    (void);
  393.  
  394. #else
  395.  
  396. void    sl_bout();
  397. void    sl_cout();
  398. void    sl_dout();
  399. void    sl_fout();
  400. void    sl_iout();
  401. void    sl_lout();
  402. void    sl_pout();
  403. void    sl_sbout();
  404. void    sl_sout();
  405.  
  406. int    sl_ret();
  407. void    sl_off();
  408. void    sl_on();
  409. void    sl_von();
  410.  
  411. #endif /* HAS_ANSI_PROTOTYPE */
  412.  
  413. /*
  414.     Declarations of internal routines.
  415. */
  416.  
  417. #ifdef HAS_ANSI_PROTOTYPE
  418.  
  419. static long    sl_adjust    (struct stat *, long);
  420. static void    sl_check    (char *);
  421. static struct stat *
  422.         sl_find        (char *, char *);
  423. static int    sl_hash        (char *);
  424. static int    prefix        (char *, char *);
  425. static struct stat *
  426.         sl_new        (char *);
  427. static void    sl_set        (char *, int);
  428. static void    sl_s2out    (char *, char *);
  429. static void    sl_s3out    (char *, char *, char *);
  430. static void    sl_slout    (int, char *);
  431. static int    sl_visit    (struct stat *, int, int);
  432. static int    has_wild    (char *);
  433. static int    is_match    (char *, char *);
  434. static void    print_dots    (int);
  435. static int    strcmp_        (char *, char *);
  436. static int    streq_        (char *, char *);
  437.  
  438. #else
  439.  
  440. static long    sl_adjust();
  441. static void    sl_check();
  442. static struct stat *
  443.         sl_find();
  444. static int    sl_hash();
  445. static int    prefix();
  446. static struct stat *
  447.         sl_new();
  448. static void    sl_set();
  449. static void    sl_s2out();
  450. static void    sl_s3out();
  451. static void    sl_slout();
  452. static int    sl_visit();
  453. static int    has_wild();
  454. static int    is_match();
  455. static void    print_dots();
  456. static int    strcmp_();
  457. static int    streq_();
  458.  
  459. #endif /* HAS_ANSI_PROTOTYPE */
  460.  
  461. /*
  462.     ========== PART 2 ==========
  463.     Internal (static) routines.
  464. */
  465.  
  466. /*
  467.     This routine defines the meaning of the TIME_ADJUST constant.
  468.     Adjust the value of val by subtracting ((p->n_stat/1000)*TIME_ADJUST).
  469.  
  470.     The following code is complicated because only integer division is
  471.     used.  The division is done first to avoid overflow.  If you know that
  472.     overflow will not occur, you could simply define sl_adjust as:
  473.  
  474.     #define sl_adjust(p, val) (val-((p->n_stat * TIME_ADJUST) / 1000))
  475. */
  476.  
  477. #ifndef TIME_ADJUST
  478. #define TIME_ADJUST 0
  479. #endif
  480.  
  481. #define ADJ_1000(n)  ( ((n)/1000)       * TIME_ADJUST        )
  482. #define ADJ_100(n)   ( (((n)%1000)/100) * (TIME_ADJUST/10)   )
  483. #define ADJ_10(n)    ( (((n)%100)/10)   * (TIME_ADJUST/100)  )
  484. #define ADJ_1(n)     ( ((n)%10)         * (TIME_ADJUST/1000) )
  485.  
  486. #if TIME_ADJUST == 0
  487.  
  488. #define sl_adjust(p, val) (val)
  489.  
  490. #else /* TIME_ADJUST > 0 */
  491.  
  492. static long
  493. sl_adjust(p, val)
  494. struct stat *p;
  495. long val;
  496. {
  497.     long n;
  498.  
  499.     /*
  500.         This series of conditional statements eliminates warnings
  501.         about "code has no effect" from the Turboc C compiler.
  502.     */
  503.  
  504. #if TIME_ADJUST > 1000
  505.     n = val - ADJ_1000(p->n_stat) - ADJ_100(p->n_stat) -
  506.         ADJ_10(p->n_stat) - ADJ_1(p->n_stat);
  507. #elif TIME_ADJUST > 100
  508.     n = val - ADJ_1000(p->n_stat) - ADJ_100(p->n_stat) -
  509.         ADJ_10(p->n_stat);
  510. #elif TIME_ADJUST > 10
  511.     n = val - ADJ_1000(p->n_stat) - ADJ_100(p->n_stat);
  512. #elif TIME_ADJUST > 0
  513.     n = val - ADJ_1000(p->n_stat);
  514. #else
  515.     n = val;
  516. #endif
  517.  
  518.     return (n > 0) ? n : 0;
  519. }
  520.  
  521. #endif /* TIME_ADJUST > 0 */
  522.  
  523. #undef ADJ_1000
  524. #undef ADJ_100
  525. #undef ADJ_10
  526. #undef ADJ_1
  527.  
  528. /*
  529.     Check the string arguments to a tracing function.
  530.  
  531.     The check_s global variable points to a string containing the
  532.     name of the macro responsible for invoking the check.
  533. */
  534. static void
  535. sl_check(register char *s)
  536. {
  537.     register char c;
  538.     register int i;
  539.     char sbuf [40];
  540.     char *old_s;
  541.  
  542.     STATS(t_check++);
  543.     DEBUG(printf("sl_check(%s)\n", s));
  544.  
  545.     old_s = s;
  546.  
  547.     /* Check for null string. */
  548.     if (!*s) {
  549.         /* Write the error message. */
  550.         sprintf(sbuf, "%p", s);
  551.         sl_s3out("sl_check: ", check_s, ": null string @ ");
  552.         sl_s2out(sbuf, "\n");
  553.         exit(BAD_EXIT);
  554.     }
  555.  
  556.     /* 6/27/89: allow up to 31 character names. */
  557.     for (i = 0; i < 31; i++) {
  558.         c = *s++;
  559.         if (c == '\0') {
  560.             return ;
  561.         }
  562.  
  563.         /* Allow only identifiers and wild cards. */
  564.         if (!isalnum(c) && c != '_' && c != '*' && c != '?') {
  565.             sprintf(sbuf, "%p", s);
  566.             sl_s3out("sl_check: ", check_s, ": bad character: ");
  567.             sl_cout(c);
  568.             sl_s3out(" in ", old_s, " @ ");
  569.             sl_s2out(sbuf, "\n");
  570.             exit(BAD_EXIT);
  571.         }
  572.     }
  573.     sprintf(sbuf, "%p", s);
  574.     sl_s3out("sl_check: ", check_s, ": run on argument: ");
  575.     sl_s3out(old_s, " @ ", sbuf);
  576.     sl_sout("\n");
  577.     exit(BAD_EXIT);
  578. }
  579.  
  580. /*
  581.     Return a pointer to the node for s.
  582.     Set the global check_s to macro_type.
  583. */
  584. static struct stat *
  585. sl_find(char *macro_type, char *s)
  586. {
  587.     register int i;
  588.     register struct stat *p, *q, *node;
  589.     register int hash;
  590.  
  591.     struct stat * sl_new();
  592.  
  593.     STATS(t_find++);
  594.     DEBUG(printf("sl_find(%s, %s)\n", macro_type, s));
  595.  
  596.     /* Update global error string. */
  597.     check_s = macro_type;
  598.  
  599.     /* Search the proper index table. */
  600.     hash = sl_hash(s);
  601.     p = hash_tab [hash];
  602.     if (p != NULL) {
  603.         i = strcmp_(s, p -> name);
  604.         if (i == 0) {
  605.             DEBUG(printf("sl_find: returns %p\n", p));
  606.             return p;
  607.         }
  608.     }
  609.         if (p == NULL || i < 0) {
  610.         sl_check(s);
  611.         node = sl_new(s);
  612.         hash_tab [hash] = node;
  613.         node -> next  = p;
  614.         node -> n_disable = disable;
  615.         DEBUG(printf("sl_find: returns %p\n", node));
  616.         return node;
  617.     }
  618.         
  619.     /* Search the list for the node. */
  620.     for (q = p, p = p -> next; p; q = p, p = p -> next) {
  621.         i = strcmp_(s, p -> name);
  622.         if (i == 0) {
  623.             return p;
  624.         }
  625.         else if (i < 0) {
  626.             break;
  627.         }
  628.     }
  629.  
  630.     /* Not found. */
  631.     sl_check(s);
  632.     node = sl_new(s);
  633.     q -> next    = node;
  634.     node -> next = p;
  635.     node -> n_disable = disable;
  636.     DEBUG(printf("sl_find: returns %p\n", node));
  637.     return node;
  638. }
  639.  
  640. /*
  641.     Compute hash code for the string s.
  642. */
  643. static int
  644. sl_hash(register char *s)
  645. {
  646.     register unsigned int hash;
  647.  
  648.     STATS(t_hash++);
  649.  
  650.     for (hash = 0; *s; ) {
  651.         hash += hash + hash + (unsigned int) *s++;
  652.         hash %= MAX_HASH;
  653.     }
  654.     return (int) hash;
  655. }
  656.  
  657. /*
  658.     Allocate a new node for tracepoint s from the static node table.
  659.  
  660.     If a match is found from the wildcard list, use that value for tracing.
  661.     Otherwise, set the tracing field to zero (FALSE).
  662. */
  663. static struct stat *
  664. sl_new(char *s)
  665. {
  666.     register struct stat * node, *p;
  667.  
  668.     STATS(t_new++);
  669.     DEBUG(printf("sl_new(%s)\n", s));
  670.  
  671.     /* Not found. Point node at a new node. */
  672.     if (cur_stat >= MAX_STAT) {
  673.         sl_sout("sl_new: trace table overflow\n");
  674.         exit(BAD_EXIT);
  675.     }
  676.  
  677.     /* Create the new node. */
  678.     node = sl__nodes + cur_stat;
  679.     cur_stat++;
  680.     node -> name  = s;
  681.     node -> n_stat = 0;
  682.     node -> n_disable = disable;
  683.  
  684.     /*
  685.         Search the wildcard list for a node which matches s.
  686.         If found.  Set trace field.
  687.     */
  688.     for (p = wildcard; p; p = p -> next) {
  689.         if (is_match(p -> name, s)) {
  690.             node -> trace = p -> trace;
  691.             return node;
  692.         }
  693.     }
  694.  
  695.     /* No match. */
  696.     node -> trace = 0;
  697.     DEBUG(printf("sl_new: returns %p\n", node));
  698.     return node;
  699. }
  700.  
  701. /*
  702.     Update the tracing status for string s and set the disable flags.
  703.     Enable tracing if flag is TRUE.
  704.  
  705.     If s contains a wildcard, ALL nodes matching s have their enable
  706.     field set to flag and a new entry for s is added to the wild card list.
  707.     Otherwise, the single node (if it exists) which matches s has its
  708.     enable field set to flag.
  709. */
  710. static void
  711. sl_set(char *s, int flag)
  712. {
  713.     register struct stat * p;
  714.     register char c;
  715.     register int i;
  716.  
  717.     STATS(t_set++);
  718.     DEBUG(printf("sl_set(%s, %d)\n", s, flag));
  719.  
  720.     /* Skip over the initial disable count. */
  721.     disable = 0;
  722.     while (*s >= '0' && *s <= '9') {
  723.         c = *s++;
  724.         disable = disable * 10 + (long)c - '0';
  725.     }
  726.     if (*s == '\0') {
  727.         /* Global suppress. */
  728.         g_disable = disable;
  729.         disable   = 0;
  730.         return;
  731.     }
  732.  
  733.     sl_check(s);
  734.     if (!has_wild(s)) {
  735.  
  736.         /* No wild card.  Just set one flag. */
  737.         p = sl_find("SL_ON, SL_OFF or SL_PARSE", s);
  738.         p -> trace = flag;
  739.         if (flag == 0 && p -> n_disable != 0) {
  740.             /* Ignore leading count. */
  741.             p -> n_disable = 0;
  742.             sl_sout("disable count ignored after off prefix\n");
  743.         }
  744.         disable = 0;
  745.         return;
  746.     }
  747.  
  748.     /* Search ALL hash lists. */
  749.     for (i = 0; i < MAX_HASH; i++) {
  750.         for (p = hash_tab [i]; p; p = p -> next) {
  751.             /* Bug fix: 4/19/89
  752.                 wildcards possible only in first arg. */
  753.             if (is_match(s, p -> name)) {
  754.                 p -> trace = flag;
  755.             }
  756.         }
  757.     }
  758.  
  759.     /*
  760.         Add new element at the head of the wildcard list.
  761.         This will supercede any previous conflicting entries.
  762.     */
  763.     p          = sl_new(s);
  764.     p -> next  = wildcard;
  765.     wildcard   = p;
  766.     p -> trace = flag;
  767.     if (p -> n_disable != 0) {
  768.         /* Ignore leading count. */
  769.         p -> n_disable = 0;
  770.         sl_sout("disable count ignored in wildcard\n");
  771.     }
  772.     disable = 0;
  773.     return;
  774. }
  775.  
  776. /*
  777.     Visit node p.
  778.     Update statistics if stat_flag is TRUE.
  779.     Enter a section of timing code if entry_flag is TRUE.
  780.     Return TRUE if the node is currently enabled.
  781.  
  782.     Bug fix: New code marked with 10/18/88
  783.  
  784.     The old code updated statistics and reset sl_count only in sl_ret(),
  785.     but that clearly can not be correct.
  786.  
  787.     The old code added time since the beginning of the deepest item on the
  788.     stack to all entries on the stack. Example:
  789.         f:
  790.             a LOT of processing
  791.             g:
  792.                 h:
  793.                 h exits;
  794.  
  795.     The bug updated h and g with f's time, which is wrong.
  796. */
  797. static int
  798. sl_visit(struct stat *p, int stat_flag, int entry_flag)
  799. {
  800.     int i;                /* bug fix: 10/18/88 */
  801.     struct stat *p1;        /* bug fix: 10/18/88 */
  802.     char *p2;            /* bug fix: 10/18/88 */
  803.     unsigned long old_count;    /* bug fix: 10/18/88 */
  804.  
  805.     if (troff || p == NULL) {
  806.         return FALSE;
  807.     }
  808.  
  809.     /* Update statistics if requested. */
  810.     if (stat_flag) {
  811.         p -> n_stat++;
  812.     }        
  813.  
  814.     /* Make an entry in the call stack for entry macros. */
  815.     if (entry_flag && sl_level < MAX_BUG_LEVEL) {
  816.  
  817.         old_count = sl_count;
  818.  
  819.         /* bug fix: 10/18/88
  820.             The following code is essentially
  821.             identical to the code in sl_ret.
  822.         */
  823.  
  824.         /* Update both timing statistics for the top of stack. */
  825.         if (sl_level > 0) {
  826.             p1 = call_stack [sl_level - 1];
  827.             p1 -> n_times += old_count;
  828.             p1 -> n_2times += old_count;
  829.  
  830.             /*
  831.                 Update the cumulative statistics of all outer
  832.                 routines EXCEPT recursive calls to the same
  833.                 function.
  834.             */
  835.             p2 = p1 -> name;
  836.             for(i = 0; i < sl_level-1; i++) {
  837.                 p1 = call_stack[i];
  838.                 if (p1 -> name != p2) {
  839.                     p1 -> n_2times += old_count;
  840.                     }
  841.             }
  842.         }
  843.         call_stack[sl_level++] = p;
  844.     }
  845.     /* bug fix: 10/18/88 */
  846.     sl_count = 0;
  847.     
  848.     /* Return TRUE if macro should be enabled. */
  849.     if (g_disable > 0) {
  850.         g_disable--;
  851.         if (p -> n_disable > 0) {
  852.             p -> n_disable--;
  853.         }
  854.         return FALSE;
  855.     }
  856.     else if (p -> n_disable > 0) {
  857.         p -> n_disable--;
  858.         return FALSE;
  859.     }
  860.     else {
  861.         return p -> trace;
  862.     }
  863. }
  864.  
  865. /*
  866.     Return TRUE if string s1 contains a wildcard character, i.e., an
  867.     asterisk or a question mark.
  868. */
  869. static int
  870. has_wild(register char *s)
  871. {
  872.     register char c;
  873.  
  874.     STATS(t_wild++);
  875.     DEBUG(printf("has_wild(%s)\n", s));
  876.  
  877.     for (;;) {
  878.         c = *s++;
  879.         if (c == '\0') {
  880.             return FALSE;
  881.         }
  882.         else if (c == '*' || c == '?') {
  883.             return TRUE;
  884.         }
  885.     }
  886. }
  887.  
  888. /*
  889.     Return TRUE if string s1 matches string s2 with wildcards possible in
  890.     string s1.
  891. */
  892. static int
  893. is_match(register char *s1, register char *s2)
  894. {
  895.     register char c;
  896.  
  897.     STATS(t_match++);
  898.     DEBUG(printf("is_match(%s, %s)\n", s1, s2));
  899.  
  900.     for (;;) {
  901.         c = *s1++;
  902.         if (c == '\0') {
  903.             return !*s2;
  904.         }
  905.         else if (c == '*') {
  906.             /* Matches zero or more characters. */
  907.             return TRUE;
  908.         }
  909.         else if (c == '?') {
  910.             /* Matches exactly one character. */
  911.             if (*s2 == '\0') {
  912.                 return FALSE;
  913.             }
  914.             else {
  915.                 s2++;
  916.             }
  917.         }
  918.         else if (c != *s2++) {
  919.             return FALSE;
  920.         }
  921.     }
  922. }
  923.  
  924. /*
  925.     Return TRUE if string p is a prefix of string s.
  926. */
  927. static int
  928. prefix(char *p, char *s)
  929. {
  930.     while (*p) {
  931.         if (*p++ != *s++) {
  932.             return FALSE;
  933.         }
  934.     }
  935.     return TRUE;
  936. }
  937.  
  938. /*
  939.     Print out n-1 periods.
  940. */
  941. static void
  942. print_dots(int n)
  943. {
  944.     int i;
  945.  
  946.     for(i = 1; i < n; i++) {
  947.         sl_cout('.');
  948.     }
  949. }
  950.  
  951. /*
  952.     Compare s1 and s2.
  953.     Return <0  ==0  >0
  954.  
  955.     WARNING:  This routine MUST NOT call any Sherlock macro.
  956.           (Calling STATS and DEBUG is permitted.)
  957. */
  958. static int
  959. strcmp_(register char *s1, register char *s2)
  960. {
  961.     STATS(t_cmp++);
  962.     DEBUG(printf("strcmp_(%s, %s)\n", s1, s2));
  963.  
  964.     while (*s1 == *s2) {
  965.         if (*s1 == '\0') {
  966.             return 0;
  967.         }
  968.         else {
  969.             s1++;
  970.             s2++;
  971.         }
  972.     }
  973.     return ((int) *s1) - ((int) *s2);
  974. }
  975.  
  976. /*
  977.     Return TRUE if s1 == s2
  978.  
  979.     WARNING:  This routine MUST NOT call any Sherlock macro.
  980.           (Calling STATS and DEBUG is permitted.)
  981. */
  982. static int
  983. streq_(register char *s1, register char *s2)
  984. {
  985.     STATS(t_eq++);
  986.     DEBUG(printf("streq_(%s, %s)\n", s1, s2));
  987.  
  988.     while(*s1) {
  989.         if (*s1++ != *s2++) {
  990.             return FALSE;
  991.         }
  992.     }
  993.     return !*s2;
  994. }
  995.  
  996. /*
  997.     ========== PART 3 ==========
  998.     External routines common to both Mark I and Mark II versions.
  999. */
  1000.  
  1001. /*
  1002.     SL_CLEAR macro--Clear all statistics.
  1003. */
  1004. void
  1005. sl_clear(void)
  1006. {
  1007.     int i;
  1008.     struct stat * p;
  1009.  
  1010.     for (i = 0; i < MAX_HASH; i++) {
  1011.         for (p = hash_tab[i]; p; p = p -> next) {
  1012.             p -> n_times =  0;
  1013.             p -> n_2times = 0;
  1014.             p -> n_stat  =  0;
  1015.         }
  1016.     }
  1017. }
  1018.  
  1019. /*
  1020.     SL_DUMP macro--Print all statistics.
  1021. */
  1022.  
  1023. void
  1024. sl_dump(void)
  1025. {
  1026.     struct stat *p, *q, *q1;
  1027.     char *pname;
  1028.     int i;
  1029.     long tot_stats, percent, totp_stats;
  1030.     char sbuf1 [40], sbuf2 [40];
  1031. #ifdef TIME_STATS
  1032.     long tot_times, tpercent, totp_times;
  1033.     long tot_2times, t2percent, totp_2times;
  1034. #endif
  1035.  
  1036. #ifdef BUG_HASH_DUMP
  1037.     int bucket_count;
  1038. #endif
  1039.  
  1040.     sl_sout("\n\nReport of statistics:\n\n");
  1041.  
  1042.     /* Calculate grand total times. */
  1043.     tot_stats = 0;
  1044. #ifdef TIME_STATS
  1045.     tot_times = 0;
  1046.     tot_2times = 0;
  1047. #endif
  1048.  
  1049.     /* Scan all buckets. */
  1050.     for (i = 0; i < MAX_HASH; i++) {
  1051.  
  1052. #ifdef BUG_HASH_DUMP
  1053.     bucket_count = 0;
  1054. #endif
  1055.  
  1056.     for (p = hash_tab[i]; p; p = p -> next) {
  1057.  
  1058.         tot_stats  += p -> n_stat;
  1059. #ifdef TIME_STATS
  1060.         tot_times  += sl_adjust(p, p->n_times);    /* 8/3/89 */
  1061.         tot_2times += sl_adjust(p, p -> n_2times); /* 8/3/89 */
  1062. #endif
  1063.  
  1064. #ifdef BUG_HASH_DUMP
  1065.         bucket_count++;
  1066. #endif
  1067.  
  1068.         /*
  1069.             Sort all and only those entries that will be printed.
  1070.             The sorting is done by creating a list in the alpha
  1071.             field of the stat nodes.
  1072.         */
  1073.         if (    p -> n_stat || p -> n_times ||
  1074.             p -> n_2times || p -> trace
  1075.            ) {
  1076.             pname = p -> name;
  1077.             for (    q1 = &a_list, q = q1 -> alpha;
  1078.                 ;
  1079.                 q1 = q, q = q -> alpha
  1080.                 ) {
  1081.                 
  1082.                 if (    q == NULL ||
  1083.                     strcmp_(pname, q -> name) < 0
  1084.                    ) {
  1085.                     q1 -> alpha = p;                
  1086.                     p  -> alpha = q;
  1087.                     break;
  1088.                 }
  1089.             }
  1090.         }
  1091.  
  1092. #ifdef BUG_HASH_DUMP
  1093.         if (bucket_count >= 9) {
  1094.             bin[9]++;
  1095.         }
  1096.         else {
  1097.             bin[bucket_count]++;
  1098.         }
  1099. #endif
  1100.  
  1101.     }}
  1102.  
  1103.     /* Print the table in alphabetical order. */
  1104.     sl_slout(20, "tracepoints");
  1105.     sl_cout(' ');
  1106.     sl_slout(12, "ticks");
  1107.     sl_slout(5,  " ");
  1108.  
  1109. #ifdef TIME_STATS
  1110.     sl_slout(12, "times1");
  1111.     sl_slout(5,  " ");
  1112.     sl_slout(10, "times2");
  1113.     sl_slout(5,  " ");
  1114. #endif
  1115.  
  1116.     sl_sout("tracing\n\n");
  1117.  
  1118.     totp_stats = 0;
  1119. #ifdef TIME_STATS
  1120.     totp_times = 0;
  1121.     totp_2times = 0;
  1122. #endif
  1123.  
  1124.     for (p = a_list.alpha; p; p = p -> alpha) {
  1125.         if (p -> n_stat || p -> n_times || p -> trace) {
  1126.             /* Print breakpoint name. */
  1127.             sl_slout(20, p -> name);
  1128.             sl_cout(' ');
  1129.  
  1130.             /* Print statistics. */
  1131.             if (tot_stats == 0) {
  1132.                 percent = 0;
  1133.             }
  1134.             else {
  1135.                 percent = ((p -> n_stat * 100) / tot_stats);
  1136.                 totp_stats += percent;
  1137.             }
  1138. #ifdef TIME_STATS
  1139.             if (tot_times == 0) {
  1140.                 tpercent = 0;
  1141.             }
  1142.             else {
  1143.                 tpercent =
  1144.                   /* 8/3/89 */
  1145.                   ((sl_adjust(p, p->n_times)*100) / tot_times);
  1146.                 totp_times += tpercent;
  1147.             }
  1148.             if (tot_2times == 0) {
  1149.                 t2percent = 0;
  1150.             }
  1151.             else {
  1152.                 t2percent =
  1153.                   /* 8/3/89 */
  1154.                   ((sl_adjust(p, p->n_2times)*100) / tot_2times);
  1155.                 totp_2times += t2percent;
  1156.             }
  1157. #endif
  1158.  
  1159.             ltoa(p -> n_stat, sbuf1, 10);
  1160.             ltoa(percent, sbuf2, 10);
  1161.             sl_slout(8, sbuf1);
  1162.             sl_sout(" = ");
  1163.             sl_slout(3, sbuf2);
  1164.             sl_sout("% ");
  1165.             
  1166. #ifdef TIME_STATS
  1167.             ltoa(sl_adjust(p,p->n_times), sbuf1, 10); /* 8/3/89 */
  1168.             ltoa(tpercent, sbuf2, 10);
  1169.             sl_slout(8, sbuf1);
  1170.             sl_sout(" = ");
  1171.             sl_slout(3, sbuf2);
  1172.             sl_sout("% ");
  1173.  
  1174.             ltoa(sl_adjust(p,p->n_2times), sbuf1, 10); /* 8/3/89 */
  1175.             ltoa(t2percent, sbuf2, 10);
  1176.             sl_slout(8, sbuf1);
  1177.             sl_sout(" = ");
  1178.             sl_slout(3, sbuf2);
  1179.             sl_sout("% ");
  1180. #endif
  1181.  
  1182.             /* Indicate whether tracing was enabled. */
  1183.             if (p -> trace) {
  1184.                 sl_slout(9, "ON\n");
  1185.             }
  1186.             else {
  1187.                 sl_slout(9, "OFF\n");
  1188.             }
  1189.         }
  1190.     }
  1191.  
  1192.     /* Print the totals. */
  1193.     ltoa(tot_stats, sbuf1, 10);
  1194.     ltoa(totp_stats, sbuf2, 10);
  1195.     sl_slout(20, "TOTALS:");
  1196.     sl_sout(" ");
  1197.     sl_slout(8, sbuf1);
  1198.     sl_sout("   ");
  1199.     sl_slout(3, sbuf2);
  1200.     sl_sout("%");
  1201.  
  1202. #ifdef TIME_STATS
  1203.     ltoa(tot_times, sbuf1, 10);
  1204.     ltoa(totp_times, sbuf2, 10);
  1205.     sl_sout(" ");
  1206.     sl_slout(8, sbuf1);
  1207.     sl_sout("   ");
  1208.     sl_slout(3, sbuf2);
  1209.  
  1210.     sl_sout("%");
  1211.  
  1212.     ltoa(tot_2times, sbuf1, 10);
  1213.     ltoa(totp_2times, sbuf2, 10);
  1214.     sl_sout(" ");
  1215.     sl_slout(8, sbuf1);
  1216.     sl_sout("   ");
  1217.     sl_slout(3, sbuf2);
  1218.     sl_sout("%\n\n");
  1219.  
  1220. #endif
  1221.  
  1222.     /* Print the TIME_ADJUST Factor. */
  1223.     sl_sout("TIME_ADJUST is ");
  1224.     itoa(TIME_ADJUST, sbuf1, 10);
  1225.     sl_sout(sbuf1);
  1226.     sl_sout("\n\n");
  1227.  
  1228.     /* Print wildcard table. */
  1229.     sl_slout(20, "Wildcards");
  1230.     sl_sout("  tracing\n\n");
  1231.  
  1232.     for (p = wildcard; p; p = p -> next) {
  1233.         sl_slout(20, p -> name);
  1234.         sl_sout("  ");
  1235.         if (p -> trace) {
  1236.             sl_slout(8, "ON\n");
  1237.         }
  1238.         else {
  1239.             sl_slout(8, "OFF\n");
  1240.         }
  1241.     }
  1242.  
  1243. #ifdef BUG_HASH_DUMP
  1244.     printf("\nHash statistics\n\n");
  1245.     for (i = 0; i < 10; i++) {
  1246.         printf("bin[%d] = %d\n", i, bin[i]);
  1247.     }
  1248. #endif
  1249.  
  1250. #ifdef BUG_STATS
  1251.  
  1252.     printf("\nInternal Variables\n\n");
  1253.  
  1254.     printf("t_buffer  = %ld\n", t_buffer);
  1255.     printf("t_check      = %ld\n", t_check);
  1256.     printf("t_cmp      = %ld\n", t_cmp);
  1257.     printf("t_eq      = %ld\n", t_eq);
  1258.     printf("t_find      = %ld\n", t_find);
  1259.     printf("t_hash      = %ld\n", t_hash);
  1260.     printf("t_init      = %ld\n", t_init);
  1261.     printf("t_match      = %ld\n", t_match);
  1262.     printf("t_new      = %ld\n", t_new);
  1263.     printf("t_off      = %ld\n", t_off);
  1264.     printf("t_on      = %ld\n", t_on);
  1265.     printf("t_set      = %ld\n", t_set);
  1266.     printf("t_wild      = %ld\n\n", t_wild);
  1267.  
  1268.     printf("t_btick      = %ld\n", t_btick);
  1269.     printf("t_btrace  = %ld\n", t_btrace);
  1270.     printf("t_ntick      = %ld\n", t_ntick);
  1271.     printf("t_ntrace  = %ld\n", t_ntrace);
  1272.     printf("t_ptrace  = %ld\n", t_ptrace);
  1273.     printf("t_pbtrace = %ld\n", t_pbtrace);
  1274.     printf("t_pntrace = %ld\n", t_pntrace);
  1275.     printf("t_pxtrace = %ld\n", t_pxtrace);
  1276.     printf("t_stat      = %ld\n", t_stat);
  1277.     printf("t_tick      = %ld\n", t_tick);
  1278.     printf("t_trace      = %ld\n", t_trace);
  1279.     printf("t_xtrace  = %ld\n\n", t_xtrace);
  1280.  
  1281. #endif
  1282.  
  1283. }
  1284.  
  1285.  
  1286. /*
  1287.     SL_INIT macro--Initialize the statistics routines.
  1288. */
  1289. void
  1290. sl_init(char * version)
  1291. {
  1292.     int i;
  1293.  
  1294.     STATS(t_init++);
  1295.     DEBUG(printf("sl_init()\n"));
  1296.  
  1297.     sl_s3out("Sherlock support routines version ", SL_VERSION_NAME, "\n");
  1298.  
  1299.     if (strcmp(version, SL_VERSION_NAME) != 0) {
  1300.         sl_s2out("sl_init: Header version ", version);
  1301.         sl_sout(" does not match version of support routines.\n");
  1302.         exit(BAD_EXIT);
  1303.     }
  1304.  
  1305.     /* Initialize the hash table. */
  1306.     for (i = 0; i < MAX_HASH; i++) {
  1307.         hash_tab [i] = NULL;
  1308.     }
  1309.     a_list.alpha = NULL;
  1310.     a_list.next  = NULL;
  1311.     a_list.name  = NULL;
  1312.  
  1313. #ifdef TIME_STATS
  1314.     /* Initialize the interrupt vectors. See. prf.asm */
  1315.     sl_von();
  1316.     DEBUG(sl_sout("Trap vectors installed.\n"));
  1317. #endif
  1318.  
  1319. }
  1320.  
  1321. /*
  1322.     SL_OFF macro.
  1323.     Turn tracing off for one variable or a class of variables.
  1324. */
  1325. void
  1326. sl_off(char *s)
  1327. {
  1328.     STATS(t_off++);
  1329.     DEBUG(printf("sl_off(%s)\n", s));
  1330.  
  1331.     if (streq_(s, "trace")) {
  1332.         sl_sout("Disabling ALL tracing...\n");
  1333.         troff = TRUE;
  1334.         return;
  1335.     }
  1336.     sl_s3out("Disabling trace of ", s, "\n");
  1337.  
  1338.     check_s = "TRACE_OFF";
  1339.     sl_set(s, 0);
  1340. }
  1341.  
  1342. /*
  1343.     SL_ON macro.
  1344.     Turn tracing on for one variable or a class of variables.
  1345. */
  1346. void
  1347. sl_on(char *s)
  1348. {
  1349.     STATS(t_on++);
  1350.     DEBUG(printf("sl_on(%s)\n", s));
  1351.  
  1352.     if (streq_(s, "trace")) {
  1353.         sl_sout("Enabling ALL tracing...\n");
  1354.         troff = FALSE;
  1355.         return;
  1356.     }
  1357.     sl_s3out("Enabling trace of ", s, "\n");
  1358.  
  1359.     check_s = "TRACE_ON";
  1360.     sl_set(s, 1);
  1361. }
  1362.  
  1363. /*
  1364.     SL_PARSE macro--Parse the command list.
  1365.     argcp points to the argc count.
  1366.     argv contains pointers to the arguments.
  1367.     on_str and off_str are the on_prefix and off_prefix respectively.
  1368. */
  1369. void
  1370. sl_parse(int *argcp, char **argv, char *on_str, char *off_str)
  1371. {
  1372.     char ** base;
  1373.     char * arg;
  1374.     int argc;
  1375.     int on_len, off_len;
  1376.  
  1377.     on_len  = strlen(on_str);
  1378.     off_len = strlen(off_str);
  1379.  
  1380.     argc = *argcp;
  1381.     argc--;
  1382.     argv++;
  1383.     base = argv;
  1384.     while (argc-- > 0) {
  1385.         arg = *argv++;
  1386.  
  1387.         if (prefix(on_str, arg)) {
  1388.             if (!*(arg + on_len)) {
  1389.                 sl_s3out("Lone '", on_str, "'\n");
  1390.                 exit(BAD_EXIT);
  1391.             }
  1392.             sl_on(arg + on_len);
  1393.  
  1394.             /* One less argument for the program. */
  1395.             (*argcp)--;
  1396.         }
  1397.         else if (prefix(off_str, arg)) {
  1398.             if (!*(arg + off_len)) {
  1399.                 sl_s3out("Lone '", off_str, "'\n");
  1400.                 exit(BAD_EXIT);
  1401.             }
  1402.             sl_off(arg + off_len);
  1403.  
  1404.             /* One less argument for the program. */
  1405.             (*argcp)--;
  1406.             
  1407.         }
  1408.         else {
  1409.             /* Compact original argv vector. */
  1410.             *base++ = arg;
  1411.         }
  1412.     }
  1413. }
  1414.  
  1415. /*
  1416.     The following macros are the same in both versions because there
  1417.     is no need to pass a handle to the support routine--the proper handle
  1418.     should be on top of the call stack.
  1419. */
  1420.  
  1421. /*
  1422.     TRACEPX macro.
  1423. */
  1424. int
  1425. sl_pxtrace(char *s)
  1426. {
  1427.     STATS(t_pxtrace++);
  1428.     DEBUG(printf("sl1pxtrace(%s)\n", s));
  1429.  
  1430.     if (sl_ret(s)) {
  1431.         print_dots(sl_level);
  1432.         sl_s2out(s, ": ");
  1433.         return TRUE;
  1434.     }
  1435.     else {
  1436.         return FALSE;
  1437.     }
  1438. }
  1439.  
  1440. /*
  1441.     Check for proper stack alignment using the entry name s.
  1442.     Return TRUE if tracing is enabled.
  1443. */
  1444. int
  1445. sl_ret(char *s)
  1446. {
  1447.     register int i;
  1448.     register struct stat *p, *p1;
  1449.     char *p2;
  1450.     unsigned long old_count;
  1451.  
  1452.     if (troff) {
  1453.         return FALSE;
  1454.     }
  1455.     else if (sl_level <= 0) {
  1456.         sl_s3out(
  1457.             "Sherlock call stack underflow at exit point ", s, "\n");
  1458.         return FALSE;
  1459.     }
  1460.  
  1461.     p = call_stack [sl_level-1];
  1462.     if (!streq_(p -> name, s)) {
  1463.         sl_s3out("sl_ret: Entry/Exit mismatch at exit point ", s, "\n");
  1464.         sl_sout("Check for missing or misnamed exit macros.\n");
  1465.         sl_sout("Dump of call stack: \n\n");
  1466.         for (i = sl_level - 1; i >= 0; i--) {
  1467.             sl_s2out(call_stack [i] -> name, "\n");
  1468.         }
  1469.         sl_sout("\n");
  1470.         exit(1);
  1471.     }
  1472.     else {
  1473.         old_count = sl_count;
  1474.         /* Update both timing statistic. */
  1475.         p1 = call_stack [sl_level - 1];
  1476.         p1 -> n_times += old_count;
  1477.         p1 -> n_2times += old_count;
  1478.  
  1479.         /*
  1480.             Update the cumulative statistics of all nested routines
  1481.             EXCEPT recursive calls to the same function.
  1482.         */
  1483.         p2 = p1 -> name;
  1484.         for(i = 0; i < sl_level-1; i++) {
  1485.             p1 = call_stack[i];
  1486.             if (p1 -> name != p2) {
  1487.                 p1 -> n_2times += old_count;
  1488.         
  1489.             DEBUG(printf("sl_ret: add %ld to cumulative for %s\n",
  1490.                 old_count, p1 -> name));
  1491.  
  1492.             }
  1493.         }
  1494.         sl_count = 0;
  1495.         sl_level--;
  1496.     }
  1497.  
  1498.     /* Return TRUE if we should enable the macro. */
  1499.     if (g_disable > 0) {
  1500.         g_disable--;
  1501.         if (p -> n_disable > 0) {
  1502.             p -> n_disable--;
  1503.         }
  1504.         return FALSE;
  1505.     }
  1506.     else if (p -> n_disable > 0) {
  1507.         p -> n_disable--;
  1508.         return FALSE;
  1509.     }
  1510.     else {
  1511.         return p -> trace;
  1512.     }
  1513. }
  1514.  
  1515. /*
  1516.     TICKX macro--Exit a nesting level and print s.
  1517. */
  1518. void
  1519. sl_x(char *s)
  1520. {
  1521.     if (sl_ret(s)) {
  1522.         print_dots(sl_level);
  1523.         sl_s2out(s, ": exits\n");
  1524.     }
  1525. }
  1526.  
  1527. /*
  1528.     RETURN_BOOL macro.
  1529.     Exit a nesting sl_level and print a boolean (int).
  1530. */
  1531. int
  1532. sl_xb(char *s, int b)
  1533. {
  1534.     if (sl_ret(s)) {
  1535.         print_dots(sl_level);
  1536.         if (b) {
  1537.             sl_s2out(s, ": returns TRUE\n");
  1538.         }
  1539.         else {
  1540.             sl_s2out(s, ": returns FALSE\n");
  1541.         }
  1542.     }
  1543.     return b;
  1544. }
  1545.  
  1546. /*
  1547.     RETURN_CHAR macro.
  1548.     Exit a nesting level and print a character.
  1549. */
  1550. char
  1551. sl_xc(char *s, char c)
  1552. {
  1553.     char buffer[2];
  1554.  
  1555.     if (sl_ret(s)) {
  1556.         print_dots(sl_level);
  1557.         buffer[0] = c;
  1558.         buffer[1] = '\0';
  1559.         sl_s3out(s, ": returns ", buffer);
  1560.         sl_sout("\n");
  1561.     }
  1562.     return c;
  1563. }
  1564.  
  1565. /*
  1566.     EXIT_DOUBLE macro.
  1567.     Exit a nesting sl_level and print a double.
  1568. */
  1569. double
  1570. sl_xd(char *s, double d)
  1571. {
  1572.     char buffer [100];
  1573.  
  1574.     if (sl_ret(s)) {
  1575.         print_dots(sl_level);
  1576.         sprintf(buffer, "%f", d);
  1577.         sl_s3out(s, ": returns ", buffer);
  1578.         sl_sout("\n");
  1579.     }
  1580.     return d;
  1581. }
  1582.  
  1583. /*
  1584.     RETURN_INT macro.
  1585.     Exit a nesting level and print an int.
  1586. */
  1587. int
  1588. sl_xi(char *s, int n)
  1589. {
  1590.     char buffer [40];
  1591.  
  1592.     if (sl_ret(s)) {
  1593.         print_dots(sl_level);
  1594.         itoa(n, buffer, 10);
  1595.         sl_s2out(s, ": returns ");
  1596.         sl_s2out(buffer, "\n");
  1597.     }
  1598.     return n;
  1599. }
  1600.  
  1601. /*
  1602.     RETURN_LONG macro.
  1603.     Exit a nesting level and print a long.
  1604. */
  1605. long
  1606. sl_xl(char *s, long l)
  1607. {
  1608.     char buffer [40];
  1609.  
  1610.     if (sl_ret(s)) {
  1611.         print_dots(sl_level);
  1612.         ltoa(l, buffer, 10);
  1613.         sl_s2out(s, ": returns ");
  1614.         sl_s2out(buffer, "\n");
  1615.     }
  1616.     return l;
  1617. }
  1618.  
  1619. /*
  1620.     RETURN_PTR macro.
  1621.     Exit a nesting level and print a pointer.
  1622. */
  1623. void *
  1624. sl_xp(char *s, void *pv)
  1625. {
  1626.     char buffer [100];
  1627.  
  1628.     if (sl_ret(s)) {
  1629.         print_dots(sl_level);
  1630.         sprintf(buffer, "%p", pv);
  1631.         sl_s3out(s, ": returns ptr: ", buffer);
  1632.         sl_sout("\n");
  1633.     }
  1634.     return pv;
  1635. }
  1636.  
  1637. /*
  1638.     RETURN_sTRING macro.
  1639.     Exit a nesting level and print a string.
  1640. */
  1641. char *
  1642. sl_xs(char *s1, char *s2)
  1643. {
  1644.     if(sl_ret(s1)) {
  1645.         print_dots(sl_level);
  1646.         sl_s3out(s1, ": returns ", s2);
  1647.         sl_sout("\n");
  1648.     }
  1649.     return s2;
  1650. }
  1651.  
  1652. /*
  1653.     TRACEX macro.
  1654. */
  1655. int
  1656. sl_xtrace(char *s)
  1657. {
  1658.     STATS(t_xtrace++);
  1659.     DEBUG(printf("sl_xtrace(%s)\n", s));
  1660.  
  1661.     return sl_ret(s);
  1662. }
  1663.  
  1664. /*
  1665.     RETURN_UINT macro.
  1666.     Exit a nesting level and print an unsigned int.
  1667. */
  1668. unsigned int
  1669. sl_xui(char *s1, unsigned int ui)
  1670. {
  1671.     char buffer [100];
  1672.  
  1673.     if(sl_ret(s1)) {
  1674.         print_dots(sl_level);
  1675.         sprintf(buffer, "(unsigned) %u", ui);
  1676.         sl_s3out(s1, ": returns ", buffer);
  1677.         sl_sout("\n");
  1678.     }
  1679.     return ui;
  1680. }
  1681.  
  1682. /*
  1683.     RETURN_ULONG macro.
  1684.     Exit a nesting level and print an unsigned int.
  1685. */
  1686. unsigned long
  1687. sl_xul(char *s1, unsigned long ul)
  1688. {
  1689.     char buffer [100];
  1690.  
  1691.     if(sl_ret(s1)) {
  1692.         print_dots(sl_level);
  1693.         sprintf(buffer, "(unsigned) %lu", ul);
  1694.         sl_s3out(s1, ": returns ", buffer);
  1695.         sl_sout("\n");
  1696.     }
  1697.     return ul;
  1698. }
  1699.  
  1700. /*
  1701.     RETURN_VOID macro--Exit a nesting level and print void.
  1702. */
  1703. void
  1704. sl_xv(char *s)
  1705. {
  1706.     if (sl_ret(s)) {
  1707.         print_dots(sl_level);
  1708.         sl_s2out(s, ": returns void\n");
  1709.     }
  1710. }
  1711.  
  1712. /*
  1713.     ========== PART 4 ==========
  1714.     Mark I versions of routines.
  1715. */
  1716. #ifdef MARKI
  1717.  
  1718. /*
  1719.     STATB macro--Enter a new nesting level.
  1720.     (Mark I Version.)
  1721. */
  1722. void
  1723. sl1bstat(char *s)
  1724. {
  1725.     STATS(t_bstat++);
  1726.     DEBUG(printf("sl1bstat(%s)\n", s));
  1727.  
  1728.     sl_visit(sl_find("STATB", s), STAT_FLAG, ENTRY_FLAG);
  1729. }
  1730.  
  1731. /*
  1732.     BTICK and ENTER macros--Enter a new nesting level.
  1733.     (Mark I Version.)
  1734. */
  1735. void
  1736. sl1btick(char *s)
  1737. {
  1738.     STATS(t_btick++);
  1739.     DEBUG(printf("sl1btick(%s)\n", s));
  1740.  
  1741.     if (sl_visit(sl_find("TICKB", s) , STAT_FLAG, ENTRY_FLAG)) {
  1742.         print_dots(sl_level-1);
  1743.         sl_s2out(s, ":\n");
  1744.     }
  1745. }
  1746.  
  1747. /*
  1748.     TRACEB macros.
  1749.     Enter a new nesting level.
  1750.     (Mark I Version.)
  1751. */
  1752. int
  1753. sl1btrace(char *s)
  1754. {
  1755.     STATS(t_btrace++);
  1756.     DEBUG(printf("sl1btrace(%s)\n", s));
  1757.  
  1758.     return sl_visit(sl_find("TRACEB", s), STAT_FLAG, ENTRY_FLAG);
  1759. }
  1760.  
  1761. /*
  1762.     TICKN macro--TICK with no statistics.
  1763.     (Mark I Version.)
  1764. */
  1765. void
  1766. sl1ntick(char *s)
  1767. {
  1768.     STATS(t_ntick++);
  1769.     DEBUG(printf("sl1ntick(%s)\n", s));
  1770.  
  1771.     if (sl_visit(sl_find("TICKN", s), NO_STAT_FLAG, NO_ENTRY_FLAG)) {
  1772.         print_dots(sl_level-1);
  1773.         sl_s2out(s, ":\n");
  1774.     }
  1775. }
  1776.  
  1777. /*
  1778.     TRACEN macro--TRACE with no statistics.
  1779.     (Mark I Version.)
  1780. */
  1781. int
  1782. sl1ntrace(char *s)
  1783. {
  1784.     STATS(t_ntrace++);
  1785.     DEBUG(printf("sl1ntrace(%s)\n", s));
  1786.  
  1787.     return sl_visit(sl_find("TRACEN", s), NO_STAT_FLAG, NO_ENTRY_FLAG);
  1788. }
  1789.  
  1790. /*
  1791.     TRACEPB and ENTER_TRACE macros.
  1792.     Enter a new nesting level.
  1793.     (Mark I Version.)
  1794. */
  1795. int
  1796. sl1pbtrace(char *s)
  1797. {
  1798.     STATS(t_pbtrace++);
  1799.     DEBUG(printf("sl1pbtrace(%s)\n", s));
  1800.  
  1801.     if (sl_visit(sl_find("TRACEPB", s), STAT_FLAG, ENTRY_FLAG)) {
  1802.         print_dots(sl_level - 1);
  1803.         sl_s2out(s, ": ");
  1804.         return TRUE;
  1805.     }
  1806.     else {
  1807.         return FALSE;
  1808.     }
  1809. }
  1810.  
  1811. /*
  1812.     TRACEPN--TRACEP with no statistics.
  1813.     (Mark I Version.)
  1814. */
  1815. int
  1816. sl1pntrace(char *s)
  1817. {
  1818.     STATS(t_pntrace++);
  1819.     DEBUG(printf("sl1pntrace(%s)\n", s));
  1820.  
  1821.     if (sl_visit(sl_find("TRACEPN", s), NO_STAT_FLAG, NO_ENTRY_FLAG)) {
  1822.         print_dots(sl_level-1);
  1823.         sl_s2out(s, ": ");
  1824.         return TRUE;
  1825.     }
  1826.     else {
  1827.         return FALSE;
  1828.     }
  1829. }
  1830.  
  1831. /*
  1832.     TRACEP macro--TRACE with printing of tracepoint's name.
  1833.     (Mark I Version.)
  1834. */
  1835. int
  1836. sl1ptrace(char *s)
  1837. {
  1838.     STATS(t_ptrace++);
  1839.     DEBUG(printf("sl1ptrace(%s)\n", s));
  1840.  
  1841.     if (sl_visit(sl_find("TRACEP", s), STAT_FLAG, NO_ENTRY_FLAG)) {
  1842.         print_dots(sl_level-1);
  1843.         sl_s2out(s, ": ");
  1844.         return TRUE;
  1845.     }
  1846.     else {
  1847.         return FALSE;
  1848.     }
  1849. }
  1850.  
  1851. /*
  1852.     STAT macro--Update one statistic.
  1853.     (Mark I Version.)
  1854. */
  1855. void
  1856. sl1stat(char *s)
  1857. {
  1858.     STATS(t_stat++);
  1859.     DEBUG(printf("sl1stat(%s)\n", s));
  1860.  
  1861.     sl_visit(sl_find("STAT", s), STAT_FLAG, NO_ENTRY_FLAG);
  1862. }
  1863.  
  1864. /*
  1865.     TICK macro--Update one statistic and print the tracepoint name.
  1866.     (Mark I Version.)
  1867. */
  1868. void
  1869. sl1tick(char *s)
  1870. {
  1871.     STATS(t_tick++);
  1872.     DEBUG(printf("sl1tick(%s)\n", s));
  1873.  
  1874.     if (sl_visit(sl_find("TICK", s), STAT_FLAG, NO_ENTRY_FLAG)) {
  1875.         print_dots(sl_level - 1);
  1876.         sl_s2out(s, ":\n");
  1877.     }
  1878. }
  1879.  
  1880. /*
  1881.     TRACE macro--Return TRUE if tracing s.
  1882.     (Mark I Version.)
  1883. */
  1884. int
  1885. sl1trace(char *s)
  1886. {
  1887.     STATS(t_trace++);
  1888.     DEBUG(printf("sl1trace(%s)\n", s));
  1889.  
  1890.     return sl_visit(sl_find("TRACE", s), STAT_FLAG, NO_ENTRY_FLAG);
  1891. }
  1892.  
  1893.  
  1894. #endif /* MARKI */
  1895.  
  1896. /*
  1897.     ========== PART 5 ==========
  1898.     Mark II versions of routines.
  1899. */
  1900. #ifdef MARKII
  1901.  
  1902. /*
  1903.     STATB macro--Enter a new nesting level.
  1904.     (Mark II Version).
  1905. */
  1906. void
  1907. sl2bstat(struct stat **pp, char *s)
  1908. {
  1909.     STATS(t_bstat++);
  1910.     DEBUG(printf("sl2bstat(%s)\n", s));
  1911.  
  1912.     if (*pp == NULL) {
  1913.         *pp = sl_find("TICKB", s);
  1914.     }
  1915.     sl_visit(*pp, STAT_FLAG, ENTRY_FLAG);
  1916. }
  1917.  
  1918. /*
  1919.     TICKB or ENTER macros--Enter a new nesting level.
  1920.     (Mark II Version).
  1921. */
  1922. void
  1923. sl2btick(struct stat **pp, char *s)
  1924. {
  1925.     STATS(t_btick++);
  1926.     DEBUG(printf("sl2btick(%s)\n", s));
  1927.  
  1928.     if (*pp == NULL) {
  1929.         *pp = sl_find("TICKB", s);
  1930.     }
  1931.  
  1932.     if (sl_visit(*pp, STAT_FLAG, ENTRY_FLAG)) {
  1933.         print_dots(sl_level-1);
  1934.         sl_s2out(s, ":\n");
  1935.     }
  1936. }
  1937.  
  1938. /*
  1939.     TRACEB macro--Enter a new nesting level.
  1940.     (Mark II Version).
  1941. */
  1942. int
  1943. sl2btrace(struct stat **pp, char *s)
  1944. {
  1945.     STATS(t_btrace++);
  1946.     DEBUG(printf("sl2btrace(%s)\n", s));
  1947.  
  1948.     if (*pp == NULL) {
  1949.         *pp = sl_find("TRACEB", s);
  1950.     }
  1951.     return sl_visit(*pp, STAT_FLAG, ENTRY_FLAG);
  1952. }
  1953.  
  1954. /*
  1955.     TICKN macro.
  1956.     (Mark II Version.)
  1957. */
  1958. void
  1959. sl2ntick(struct stat **pp, char * s)
  1960. {
  1961.     STATS(t_ntick++);
  1962.     DEBUG(printf("sl2ntick(%s)\n", s));
  1963.  
  1964.     if (*pp == NULL) {
  1965.         *pp = sl_find("TICKN", s);
  1966.     }
  1967.  
  1968.     if (sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG)) {
  1969.         print_dots(sl_level-1);
  1970.         sl_s2out(s, ":\n");
  1971.     }
  1972. }
  1973.  
  1974. /*
  1975.     TRACEN macro.
  1976.     (Mark II Version.)
  1977. */
  1978. int
  1979. sl2ntrace(struct stat **pp, char *s)
  1980. {
  1981.     STATS(t_ntrace++);
  1982.     DEBUG(printf("sl2ntrace(%s)\n", s));
  1983.  
  1984.     if (*pp == NULL) {
  1985.         *pp = sl_find("TRACEN", s);
  1986.     }
  1987.     return sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG);
  1988. }
  1989.  
  1990. /*
  1991.     TRACEPB and ENTER_TRACE macros--Enter a new nesting level.
  1992.     (Mark II Version).
  1993. */
  1994. int
  1995. sl2pbtrace(struct stat **pp, char *s)
  1996. {
  1997.     STATS(t_pbtrace++);
  1998.     DEBUG(printf("sl2pbtrace(%s)\n", s));
  1999.  
  2000.     /* Find the proper node.  Allocate one if needed. */
  2001.     if (*pp == NULL) {
  2002.         *pp = sl_find("TRACEPB", s);
  2003.     }
  2004.     if (sl_visit(*pp, STAT_FLAG, ENTRY_FLAG)) {
  2005.         print_dots(sl_level-1);
  2006.         sl_s2out(s, ": ");
  2007.         return TRUE;
  2008.     }
  2009.     else {
  2010.         return FALSE;
  2011.     }
  2012. }
  2013.  
  2014. /*
  2015.     TRACEPN macro.
  2016.     (Mark II Version.)
  2017. */
  2018. int
  2019. sl2pntrace(struct stat **pp, char *s)
  2020. {
  2021.     STATS(t_pntrace++);
  2022.     DEBUG(printf("sl2pntrace(%s)\n", s));
  2023.  
  2024.     if (*pp == NULL) {
  2025.         *pp = sl_find("TRACEPN", s);
  2026.     }
  2027.     if (sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG)) {
  2028.         print_dots(sl_level-1);
  2029.         sl_s2out(s, ": ");
  2030.         return TRUE;
  2031.     }
  2032.     else {
  2033.         return FALSE;
  2034.     }
  2035. }
  2036.  
  2037. /*
  2038.     TRACEP macro--TRACE with printing of tracepoint's name.
  2039.     (Mark II Version.)
  2040. */
  2041. int
  2042. sl2ptrace(struct stat **pp, char *s)
  2043. {
  2044.     STATS(t_ptrace++);
  2045.     DEBUG(printf("sl2ptrace(%s)\n", s));
  2046.  
  2047.     if (*pp == NULL) {
  2048.         *pp = sl_find("TRACEP", s);
  2049.     }
  2050.     if (sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG)) {
  2051.         print_dots(sl_level-1);
  2052.         sl_s2out(s, ": ");
  2053.         return TRUE;
  2054.     }
  2055.     else {
  2056.         return FALSE;
  2057.     }
  2058. }
  2059.  
  2060. /*
  2061.     STAT macro--Update one statistic.
  2062.     (Mark II Version.)
  2063. */
  2064. void
  2065. sl2stat(struct stat **pp, char * s)
  2066. {
  2067.     STATS(t_stat++);
  2068.     DEBUG(printf("sl2stat(%s)\n", s));
  2069.  
  2070.     if (*pp == NULL) {
  2071.         *pp = sl_find("STAT", s);
  2072.     }
  2073.     sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG);
  2074. }
  2075.  
  2076. /*
  2077.     TICK macro--Update one statistic and print tracepoint's name.
  2078.     (Mark II Version.)
  2079. */
  2080. void
  2081. sl2tick(struct stat **pp, char * s)
  2082. {
  2083.     STATS(t_tick++);
  2084.     DEBUG(printf("sl2tick(%s)\n", s));
  2085.  
  2086.     /* Find the proper node.  Allocate one if needed. */
  2087.     if (*pp == NULL) {
  2088.         *pp = sl_find("TICK", s);
  2089.     }
  2090.     if (sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG)) {
  2091.         print_dots(sl_level-1);
  2092.         sl_s2out(s, ":\n");
  2093.     }
  2094. }
  2095.  
  2096. /*
  2097.     TRACE macro--Return TRUE if tracing s.
  2098.     (Mark II Version.)
  2099. */
  2100. int
  2101. sl2trace(struct stat **pp, char *s)
  2102. {
  2103.     STATS(t_trace++);
  2104.     DEBUG(printf("sl2trace(%s)\n", s));
  2105.  
  2106.     if (*pp == NULL) {
  2107.         *pp = sl_find("TRACE", s);
  2108.     }
  2109.     return sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG);
  2110. }
  2111.  
  2112. #endif /* MARKII */
  2113.  
  2114. /*
  2115.     ========== PART 6 ==========
  2116.     Output routines.
  2117. */
  2118.  
  2119. /*
  2120.     Output a character to the standard place.
  2121.  
  2122.     This is the only routine you should change in order to use different
  2123.     routines for output.  All output eventually goes through this routine.
  2124. */
  2125. void
  2126. sl_cout(char c)
  2127. {
  2128.     putchar(c);
  2129. }
  2130.  
  2131. /*
  2132.     Output a comma, followed by a space.
  2133.     SPP generates a call to this routine to save space.
  2134. */
  2135. void
  2136. sl_csout(void)
  2137. {
  2138.     sl_sout(", ");
  2139. }
  2140.  
  2141.  
  2142. /*
  2143.     Output a bool.
  2144. */
  2145. void
  2146. sl_bout(int b)
  2147. {
  2148.     if (b) {
  2149.         sl_sout("TRUE");
  2150.     }
  2151.     else {
  2152.         sl_sout("FALSE");
  2153.     }
  2154. }
  2155.  
  2156. /*
  2157.     Output a double.
  2158. */
  2159. void
  2160. sl_dout(double d)
  2161. {
  2162.     char buf [100];
  2163.  
  2164.     sprintf(buf, "%f", d);
  2165.     sl_sout(buf);
  2166. }
  2167.  
  2168. /*
  2169.     Output a float. (Floats are converted to double.)
  2170. */
  2171. void
  2172. sl_fout(double f)
  2173. {
  2174.     char buf [100];
  2175.  
  2176.     sprintf(buf, "%f", f);
  2177.     sl_sout(buf);
  2178. }
  2179.  
  2180. /*
  2181.     Output an integer.
  2182. */
  2183. void
  2184. sl_iout(int i)
  2185. {
  2186.     char buf [100];
  2187.  
  2188.     sprintf(buf, "%d", i);
  2189.     sl_sout(buf);
  2190. }
  2191.  
  2192. /*
  2193.     Output a left (open) parenthesis.
  2194.     SPP generates a call to this routine to save space.
  2195. */
  2196. void
  2197. sl_lpout(void)
  2198. {
  2199.     sl_cout('(');
  2200. }
  2201.  
  2202. /*
  2203.     Output a long.
  2204. */
  2205. void
  2206. sl_lout(long l)
  2207. {
  2208.     char buf [100];
  2209.  
  2210.     sprintf(buf, "(long) %ld", l);    /* bug fix: 2/10/89 */
  2211.     sl_sout(buf);
  2212. }
  2213.  
  2214. /*
  2215.     Output a pointer.
  2216. */
  2217. void
  2218. sl_pout(void *p)
  2219. {
  2220.     char buf [100];
  2221.  
  2222.     sprintf(buf, "(pointer) %p", p);
  2223.     sl_sout(buf);
  2224. }
  2225.  
  2226. /*
  2227.     Output a right parenthesis and a newline.
  2228.     SPP generates a call to this routine to save space.
  2229. */
  2230. void
  2231. sl_rpout(void)
  2232. {
  2233.     sl_sout(")\n");
  2234. }
  2235.  
  2236. /*
  2237.     Return a pointer to a string corresponding to a bool.
  2238. */
  2239. char *
  2240. sl_sbout(int b)
  2241. {
  2242.     return (b ? "TRUE" : "FALSE");
  2243. }
  2244.  
  2245. /*
  2246.     Output a string.
  2247. */
  2248. void
  2249. sl_sout(char *s)
  2250. {
  2251.     while (*s) {
  2252.         sl_cout(*s++);
  2253.     }
  2254. }
  2255.  
  2256. /*
  2257.     Output two strings.
  2258. */
  2259. static void
  2260. sl_s2out(char *s1, char *s2)
  2261. {
  2262.     sl_sout(s1);
  2263.     sl_sout(s2);
  2264. }
  2265.  
  2266. /*
  2267.     Output three strings.
  2268. */
  2269. static void
  2270. sl_s3out(char *s1, char *s2, char *s3)
  2271. {
  2272.     sl_sout(s1);
  2273.     sl_sout(s2);
  2274.     sl_sout(s3);
  2275. }
  2276.  
  2277. /*
  2278.     Output string s right justified in a field of size n.
  2279. */
  2280. static void
  2281. sl_slout(int n, char *s)
  2282. {
  2283.     int pad;
  2284.  
  2285.     for (pad = n - strlen(s); pad > 0; pad--) {
  2286.         sl_cout(' ');
  2287.     }
  2288.     sl_sout(s);
  2289. }
  2290.  
  2291. /*    2/10/89
  2292.  
  2293.     Output an unsigned int.
  2294. */
  2295. void
  2296. sl_uiout(unsigned u)
  2297. {
  2298.     char buf [100];
  2299.  
  2300.     sprintf(buf, "(unsigned) %u", u);
  2301.     sl_sout(buf);
  2302. }
  2303.  
  2304. /*    2/10/89
  2305.  
  2306.     Output an unsigned int.
  2307. */
  2308. void
  2309. sl_ulout(unsigned long u)
  2310. {
  2311.     char buf [100];
  2312.  
  2313.     sprintf(buf, "(unsigned long) %lu", u);
  2314.     sl_sout(buf);
  2315. }
  2316.