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 >
Wrap
C/C++ Source or Header
|
1991-06-09
|
48KB
|
2,316 lines
/*
Sherlock run-time routines.
bug fix: 10/18/88: sl_visit().
bug fix: 2/10/89: sl_lout().
added: 2/10/89: sl_uiout() and sl_ulout().
bug fix: 4/19/89: sl_set().
bug fix: 6/27/89: sl_check().
lib fix: 6/30/89: ltoa, itoa redefined.
added: 8/3/89: sl_adjust(). Used only by sl_dump().
bug fix: 4/17/90: sl_level made a global var as in manual.
Mark I version started: September 26, 1985
Mark II version started: September 8, 1986
Source: sherlock.c
Versions:
0.6a June 8, 1988
0.7 June 21, 1988
0.7c June 28, 1988
0.8 July 14, 1988
1.0 July 21, 1988
1.1 February 14, 1989
1.2 February 27, 1989
1.3 April 19, 1989
1.4 June 27, 1989
1.5 August 4, 1989
1.6 April 17, 1990
1.7 June 15, 1991 First Public Domain Version
PUBLIC DOMAIN SOFTWARE
Sherlock, including the SPP, SDEL and SDIF programs, was placed in
the public domain on June 15, 1991, by its author,
Edward K. Ream
166 North Prospect Ave.
Madison, WI 53705.
(608) 257-0802
Sherlock may be used for any commercial or non-commercial purpose.
DISCLAIMER OF WARRANTIES
Edward K. Ream (Ream) specifically disclaims all warranties,
expressed or implied, with respect to this computer software,
including but not limited to implied warranties of merchantability
and fitness for a particular purpose. In no event shall Ream be
liable for any loss of profit or any commercial damage, including
but not limited to special, incidental consequential or other damages.
This file has the following parts:
1. Data structures and definitions.
2. Internal (static) routines.
3. Externally visible routines common to Mark I and Mark I versions.
4. Mark I versions of routines.
5. Mark II versions of routines.
6. Output routines
*/
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <string.h>
#include <ctype.h>
/* most Compilers don't have itoa() or ltoa */
#define itoa(a, b, c) sprintf(b, "%d", a);
#define ltoa(a, b, c) sprintf(b, "%ld", a);
#define SL_VERSION_NAME "1.7"
#define STAT_FLAG TRUE
#define NO_STAT_FLAG FALSE
#define ENTRY_FLAG TRUE
#define NO_ENTRY_FLAG FALSE
/*
Define this constant if your compiler allows function prototypes.
*/
#define HAS_ANSI_PROTOTYPE 1
/*
Select which version of the macros to define.
The Mark I versions call sl_find() EVERY time to determine whether
the tracepoint has been enabled. The Mark II versions call
sl_find() only on the initial encounter with the tracepoint.
The difference in speed between the Mark I and Mark II versions can
be large. Use the Mark I version of the routines only if you are
forced to do so by problems with the compiler you are using. All
standard C compilers should be able to handle the Mark II version.
*/
#define MARKI 1
#define MARKII 1
/*
========== PART 1 ==========
Data structures and definitions.
*/
/*
Define constants that enable output for debugging the Sherlock code
itself. Normally, these constants should be commented out.
BUG_STATS: enables printing of internal statistics by sl_dump().
BUG_HASH_DUMP: enables printing of internal statistics relating to
the hash table.
BUG_DEBUG: enables printing of internal tracing messages.
The STATS macro is for use ONLY within this file. It expands the
statement supplied as its actual parameter only if BUG_STATS variable
is defined. Typically, the actual parameter is a statement which bumps
an internal tracing statistic.
The DEBUG macro is for use ONLY within this file. It expands the
statement supplied as its actual parameter only if the BUG_DEBUG
variable is defined. Typically, the actual parameter is a printf()
statement used to trace the internal workings of the routines on this
file.
*/
/* -----
#define BUG_STATS 1
#define BUG_DEBUG 1
----- */
#ifdef BUG_STATS
#define STATS(statement) statement
#else
#define STATS(statement)
#endif
#ifdef BUG_DEBUG
#define DEBUG(statement) statement
#else
#define DEBUG(statement)
#endif
/*
Define various constants.
*/
#define TRUE (1)
#define FALSE (0)
#define BAD_EXIT (1)
/*
Define the format of statistics nodes.
These nodes are used to keep all information related to tracepoints.
There is exactly one node per tracepoint, regardless of how many
times a tracepoint name appears throughout the code.
*/
static struct stat {
struct stat * next; /* pointer to next bucket. */
struct stat * alpha; /* alphabetical list. */
char * name; /* pointer to checkpoint name. */
long n_stat; /* # of calls to macros. */
long n_disable; /* # of prints to skip or 0. */
long n_times; /* # of profiler ticks. */
long n_2times; /* Cumulative ticks. */
int trace; /* trace flag. */
};
/*
Define a dummy node used as a target for statistics gathering
before the first Sherlock macro is seen.
The dummy node also is used as the list header when the nodes are
alphabetized by sl_dump().
*/
static struct stat a_list;
/*
Define a (fixed size) array of statistics nodes. All stat nodes are
allocated from this array. We do NOT call dynamic storage allocation,
(such as malloc() or calloc()) to get node storage so as not to
disturb memory while tracing.
The sl__nodes [] array holds all the nodes.
The cur_stat variable counts how many entries in sl__nodes [] have
already been allocated.
*/
#define MAX_STAT 500
static struct stat sl__nodes [MAX_STAT]; /* Static node table. */
static int cur_stat = 0;
/*
Define a (fixed size) array used to keep track of nesting of Sherlock
macros. ENTER macros push pointers to stat nodes on the stack. EXITxx
macros pop entries from the stack. Non-cumulative timing statistics
only increment the top of the stack. Cumulative timing statistics
increment all entries on the stack.
The sl_level variable does double duty. It keeps track of the top
entry on the call_stack and it is used to indent output to reflect the
current nesting level.
*/
#define MAX_BUG_LEVEL 100
static struct stat * call_stack [MAX_BUG_LEVEL];
/* This is a global variable. */
int sl_level = 0;
/*
Define the hash table used to speed the search of statistics nodes.
The 'next' field of each stat node chains together all nodes with
the same hash value.
*/
#define MAX_HASH 241
static struct stat * hash_tab [MAX_HASH];
/*
Define the list of names of wildcards which have been enabled from
the command line or via calls to sl_on or sl_off(). This list is
used by sl_new() to determine whether tracing is enabled or not.
As wildcards are seen, they are added to the HEAD of the list, which
essentially means that the list is searched in REVERSE order for
matches. This is best, since the scan of the list can stop with the
first match found, rather than having to scan the whole list.
*/
static struct stat * wildcard = NULL; /* Head of wildcard list. */
/*
The troff variable suppress the operation of all STAT, TICK, TRACE
TRACEP and RETURN_xxx macros. The troff variable is set if "--trace"
is seen on the command line or if sl_off("trace") is seen.
The only way of re-enabling Sherlock's macros after troff becomes
TRUE is to execute sl_on("trace"). Note that the call to sl_on()
must not occur inside a TRACE or TRACEP macro!!
*/
static int troff = FALSE; /* TRUE if all tracing disabled. */
/*
The check_s variable contains of the name of the macro currently
executing. It is made global so as to avoid the overhead of passing
extra parameters to sl_set() and sl_check().
*/
static char * check_s = NULL; /* Name of current macro. */
/*
Define local and global "disable counts."
The disable variable contains a disable count which is associated
with a single variable. The g_disable variable contains the global
disable count. Both disable and g_disable are set by sl_set() and
used by sl_new() when new nodes are created.
Local disable counts are set by preceeding the name of a tracpoint by
a number. For example, --100xyz sets the local disable count of xyz
to 100. The single global disable count is set by following a prefix
by a number alone. For example, --100 sets the global disable count
to 100.
Disable counts suppress the operation of all tracing macros.
Each time such a macro is encounted, a check is made of both the
global disable count and the local disable count associated with the
tracepoint. Both global and local counts are decremented as long as
either or both are non-zero.
*/
static long disable = 0; /* Local disable count. */
static long g_disable = 0; /* Global disable printing counter. */
/*
Define globals used to communicate with the Interrupt Handler.
The interrupt handler allows Sherlock macros to gather timing
statistics. The interrupt handler code (in PRF.ASM) is required
only if the TIME_STATS variable is defined.
WARNING: By necessity, the interrupt handler contains
MACHINE DEPENDENT CODE. Using this code is not
guarranteed to work and may cause your system to
crash. See further warnings in file PRF.ASM.
TIME_STATS enables code which gathers timing statistics.
sl_count a global variable which is incremented each time
the interrupt handle is executed.
sl_speed The 'speed-up factor' used to speed up the system
timer to acheive speeds greater than the default
speed of 18.2 clock ticks per second.
As you can imagine, increasing the speed of the system
clock is potentially a MACHINE DEPENDENT OPERATION.
However, the interrupt handler masks the speedup from
the rest of the system by passing only selected ticks
on to the old tick routine.
A setting of 55 for sl_speed gives about
1 time/tick per msec. (assuming 18.2 clock ticks/sec.)
*/
/* comment out -----
#define TIME_STATS 1
----- end comment out */
unsigned long sl_count = 0; /* Timing count. */
unsigned int sl_speed = 55; /* Default clock speed. */
/*
Define internal tracing variables.
The variables whose names begin with t_ are used only if BUG_STATS
defined. They count how many times Sherlock's routines are called.
The bin array is used to count the number of hash chains of there are
of a given length. bin [i] counts the number of chains in the hash
table with length i. bin [10] counts the number of chains with length
10 or more. Very few chains typically contain two or more elements, so
this small array gives acceptable statistics.
*/
/* -----
#define BUG_HASH_DUMP 1
----- */
#ifdef BUG_HASH_DUMP
static int bin[10];
#endif
#ifdef BUG_STATS
static long t_buffer = 0;
static long t_check = 0;
static long t_cmp = 0;
static long t_eq = 0;
static long t_find = 0;
static long t_hash = 0;
static long t_init = 0;
static long t_match = 0;
static long t_new = 0;
static long t_on = 0;
static long t_off = 0;
static long t_bstat = 0;
static long t_btick = 0;
static long t_btrace = 0;
static long t_ntick = 0;
static long t_ntrace = 0;
static long t_ptrace = 0;
static long t_pbtrace = 0;
static long t_pntrace = 0;
static long t_pxtrace = 0;
static long t_set = 0;
static long t_stat = 0;
static long t_tick = 0;
static long t_trace = 0;
static long t_xtrace = 0;
static long t_wild = 0;
#endif
/*
Forward declarations of external routines.
They are needed because sl.h is not #include'd in this file.
sl_von() is not mentioned in sl.h. It is defined in PRF.ASM.
Note that Microsoft version 4.00 does not allow dummy names in
these function prototypes.
*/
#ifdef HAS_ANSI_PROTOTYPE
void sl_bout (int);
void sl_cout (char);
void sl_dout (double);
void sl_fout (double); /* Floats are passed as doubles. */
void sl_iout (int);
void sl_lout (long);
void sl_pout (void *);
char * sl_sbout(int);
void sl_sout (char *);
void sl_uiout(unsigned int);
void sl_ulout(unsigned long);
int sl_ret (char *);
void sl_off (char *);
void sl_on (char *);
void sl_von (void);
#else
void sl_bout();
void sl_cout();
void sl_dout();
void sl_fout();
void sl_iout();
void sl_lout();
void sl_pout();
void sl_sbout();
void sl_sout();
int sl_ret();
void sl_off();
void sl_on();
void sl_von();
#endif /* HAS_ANSI_PROTOTYPE */
/*
Declarations of internal routines.
*/
#ifdef HAS_ANSI_PROTOTYPE
static long sl_adjust (struct stat *, long);
static void sl_check (char *);
static struct stat *
sl_find (char *, char *);
static int sl_hash (char *);
static int prefix (char *, char *);
static struct stat *
sl_new (char *);
static void sl_set (char *, int);
static void sl_s2out (char *, char *);
static void sl_s3out (char *, char *, char *);
static void sl_slout (int, char *);
static int sl_visit (struct stat *, int, int);
static int has_wild (char *);
static int is_match (char *, char *);
static void print_dots (int);
static int strcmp_ (char *, char *);
static int streq_ (char *, char *);
#else
static long sl_adjust();
static void sl_check();
static struct stat *
sl_find();
static int sl_hash();
static int prefix();
static struct stat *
sl_new();
static void sl_set();
static void sl_s2out();
static void sl_s3out();
static void sl_slout();
static int sl_visit();
static int has_wild();
static int is_match();
static void print_dots();
static int strcmp_();
static int streq_();
#endif /* HAS_ANSI_PROTOTYPE */
/*
========== PART 2 ==========
Internal (static) routines.
*/
/*
This routine defines the meaning of the TIME_ADJUST constant.
Adjust the value of val by subtracting ((p->n_stat/1000)*TIME_ADJUST).
The following code is complicated because only integer division is
used. The division is done first to avoid overflow. If you know that
overflow will not occur, you could simply define sl_adjust as:
#define sl_adjust(p, val) (val-((p->n_stat * TIME_ADJUST) / 1000))
*/
#ifndef TIME_ADJUST
#define TIME_ADJUST 0
#endif
#define ADJ_1000(n) ( ((n)/1000) * TIME_ADJUST )
#define ADJ_100(n) ( (((n)%1000)/100) * (TIME_ADJUST/10) )
#define ADJ_10(n) ( (((n)%100)/10) * (TIME_ADJUST/100) )
#define ADJ_1(n) ( ((n)%10) * (TIME_ADJUST/1000) )
#if TIME_ADJUST == 0
#define sl_adjust(p, val) (val)
#else /* TIME_ADJUST > 0 */
static long
sl_adjust(p, val)
struct stat *p;
long val;
{
long n;
/*
This series of conditional statements eliminates warnings
about "code has no effect" from the Turboc C compiler.
*/
#if TIME_ADJUST > 1000
n = val - ADJ_1000(p->n_stat) - ADJ_100(p->n_stat) -
ADJ_10(p->n_stat) - ADJ_1(p->n_stat);
#elif TIME_ADJUST > 100
n = val - ADJ_1000(p->n_stat) - ADJ_100(p->n_stat) -
ADJ_10(p->n_stat);
#elif TIME_ADJUST > 10
n = val - ADJ_1000(p->n_stat) - ADJ_100(p->n_stat);
#elif TIME_ADJUST > 0
n = val - ADJ_1000(p->n_stat);
#else
n = val;
#endif
return (n > 0) ? n : 0;
}
#endif /* TIME_ADJUST > 0 */
#undef ADJ_1000
#undef ADJ_100
#undef ADJ_10
#undef ADJ_1
/*
Check the string arguments to a tracing function.
The check_s global variable points to a string containing the
name of the macro responsible for invoking the check.
*/
static void
sl_check(register char *s)
{
register char c;
register int i;
char sbuf [40];
char *old_s;
STATS(t_check++);
DEBUG(printf("sl_check(%s)\n", s));
old_s = s;
/* Check for null string. */
if (!*s) {
/* Write the error message. */
sprintf(sbuf, "%p", s);
sl_s3out("sl_check: ", check_s, ": null string @ ");
sl_s2out(sbuf, "\n");
exit(BAD_EXIT);
}
/* 6/27/89: allow up to 31 character names. */
for (i = 0; i < 31; i++) {
c = *s++;
if (c == '\0') {
return ;
}
/* Allow only identifiers and wild cards. */
if (!isalnum(c) && c != '_' && c != '*' && c != '?') {
sprintf(sbuf, "%p", s);
sl_s3out("sl_check: ", check_s, ": bad character: ");
sl_cout(c);
sl_s3out(" in ", old_s, " @ ");
sl_s2out(sbuf, "\n");
exit(BAD_EXIT);
}
}
sprintf(sbuf, "%p", s);
sl_s3out("sl_check: ", check_s, ": run on argument: ");
sl_s3out(old_s, " @ ", sbuf);
sl_sout("\n");
exit(BAD_EXIT);
}
/*
Return a pointer to the node for s.
Set the global check_s to macro_type.
*/
static struct stat *
sl_find(char *macro_type, char *s)
{
register int i;
register struct stat *p, *q, *node;
register int hash;
struct stat * sl_new();
STATS(t_find++);
DEBUG(printf("sl_find(%s, %s)\n", macro_type, s));
/* Update global error string. */
check_s = macro_type;
/* Search the proper index table. */
hash = sl_hash(s);
p = hash_tab [hash];
if (p != NULL) {
i = strcmp_(s, p -> name);
if (i == 0) {
DEBUG(printf("sl_find: returns %p\n", p));
return p;
}
}
if (p == NULL || i < 0) {
sl_check(s);
node = sl_new(s);
hash_tab [hash] = node;
node -> next = p;
node -> n_disable = disable;
DEBUG(printf("sl_find: returns %p\n", node));
return node;
}
/* Search the list for the node. */
for (q = p, p = p -> next; p; q = p, p = p -> next) {
i = strcmp_(s, p -> name);
if (i == 0) {
return p;
}
else if (i < 0) {
break;
}
}
/* Not found. */
sl_check(s);
node = sl_new(s);
q -> next = node;
node -> next = p;
node -> n_disable = disable;
DEBUG(printf("sl_find: returns %p\n", node));
return node;
}
/*
Compute hash code for the string s.
*/
static int
sl_hash(register char *s)
{
register unsigned int hash;
STATS(t_hash++);
for (hash = 0; *s; ) {
hash += hash + hash + (unsigned int) *s++;
hash %= MAX_HASH;
}
return (int) hash;
}
/*
Allocate a new node for tracepoint s from the static node table.
If a match is found from the wildcard list, use that value for tracing.
Otherwise, set the tracing field to zero (FALSE).
*/
static struct stat *
sl_new(char *s)
{
register struct stat * node, *p;
STATS(t_new++);
DEBUG(printf("sl_new(%s)\n", s));
/* Not found. Point node at a new node. */
if (cur_stat >= MAX_STAT) {
sl_sout("sl_new: trace table overflow\n");
exit(BAD_EXIT);
}
/* Create the new node. */
node = sl__nodes + cur_stat;
cur_stat++;
node -> name = s;
node -> n_stat = 0;
node -> n_disable = disable;
/*
Search the wildcard list for a node which matches s.
If found. Set trace field.
*/
for (p = wildcard; p; p = p -> next) {
if (is_match(p -> name, s)) {
node -> trace = p -> trace;
return node;
}
}
/* No match. */
node -> trace = 0;
DEBUG(printf("sl_new: returns %p\n", node));
return node;
}
/*
Update the tracing status for string s and set the disable flags.
Enable tracing if flag is TRUE.
If s contains a wildcard, ALL nodes matching s have their enable
field set to flag and a new entry for s is added to the wild card list.
Otherwise, the single node (if it exists) which matches s has its
enable field set to flag.
*/
static void
sl_set(char *s, int flag)
{
register struct stat * p;
register char c;
register int i;
STATS(t_set++);
DEBUG(printf("sl_set(%s, %d)\n", s, flag));
/* Skip over the initial disable count. */
disable = 0;
while (*s >= '0' && *s <= '9') {
c = *s++;
disable = disable * 10 + (long)c - '0';
}
if (*s == '\0') {
/* Global suppress. */
g_disable = disable;
disable = 0;
return;
}
sl_check(s);
if (!has_wild(s)) {
/* No wild card. Just set one flag. */
p = sl_find("SL_ON, SL_OFF or SL_PARSE", s);
p -> trace = flag;
if (flag == 0 && p -> n_disable != 0) {
/* Ignore leading count. */
p -> n_disable = 0;
sl_sout("disable count ignored after off prefix\n");
}
disable = 0;
return;
}
/* Search ALL hash lists. */
for (i = 0; i < MAX_HASH; i++) {
for (p = hash_tab [i]; p; p = p -> next) {
/* Bug fix: 4/19/89
wildcards possible only in first arg. */
if (is_match(s, p -> name)) {
p -> trace = flag;
}
}
}
/*
Add new element at the head of the wildcard list.
This will supercede any previous conflicting entries.
*/
p = sl_new(s);
p -> next = wildcard;
wildcard = p;
p -> trace = flag;
if (p -> n_disable != 0) {
/* Ignore leading count. */
p -> n_disable = 0;
sl_sout("disable count ignored in wildcard\n");
}
disable = 0;
return;
}
/*
Visit node p.
Update statistics if stat_flag is TRUE.
Enter a section of timing code if entry_flag is TRUE.
Return TRUE if the node is currently enabled.
Bug fix: New code marked with 10/18/88
The old code updated statistics and reset sl_count only in sl_ret(),
but that clearly can not be correct.
The old code added time since the beginning of the deepest item on the
stack to all entries on the stack. Example:
f:
a LOT of processing
g:
h:
h exits;
The bug updated h and g with f's time, which is wrong.
*/
static int
sl_visit(struct stat *p, int stat_flag, int entry_flag)
{
int i; /* bug fix: 10/18/88 */
struct stat *p1; /* bug fix: 10/18/88 */
char *p2; /* bug fix: 10/18/88 */
unsigned long old_count; /* bug fix: 10/18/88 */
if (troff || p == NULL) {
return FALSE;
}
/* Update statistics if requested. */
if (stat_flag) {
p -> n_stat++;
}
/* Make an entry in the call stack for entry macros. */
if (entry_flag && sl_level < MAX_BUG_LEVEL) {
old_count = sl_count;
/* bug fix: 10/18/88
The following code is essentially
identical to the code in sl_ret.
*/
/* Update both timing statistics for the top of stack. */
if (sl_level > 0) {
p1 = call_stack [sl_level - 1];
p1 -> n_times += old_count;
p1 -> n_2times += old_count;
/*
Update the cumulative statistics of all outer
routines EXCEPT recursive calls to the same
function.
*/
p2 = p1 -> name;
for(i = 0; i < sl_level-1; i++) {
p1 = call_stack[i];
if (p1 -> name != p2) {
p1 -> n_2times += old_count;
}
}
}
call_stack[sl_level++] = p;
}
/* bug fix: 10/18/88 */
sl_count = 0;
/* Return TRUE if macro should be enabled. */
if (g_disable > 0) {
g_disable--;
if (p -> n_disable > 0) {
p -> n_disable--;
}
return FALSE;
}
else if (p -> n_disable > 0) {
p -> n_disable--;
return FALSE;
}
else {
return p -> trace;
}
}
/*
Return TRUE if string s1 contains a wildcard character, i.e., an
asterisk or a question mark.
*/
static int
has_wild(register char *s)
{
register char c;
STATS(t_wild++);
DEBUG(printf("has_wild(%s)\n", s));
for (;;) {
c = *s++;
if (c == '\0') {
return FALSE;
}
else if (c == '*' || c == '?') {
return TRUE;
}
}
}
/*
Return TRUE if string s1 matches string s2 with wildcards possible in
string s1.
*/
static int
is_match(register char *s1, register char *s2)
{
register char c;
STATS(t_match++);
DEBUG(printf("is_match(%s, %s)\n", s1, s2));
for (;;) {
c = *s1++;
if (c == '\0') {
return !*s2;
}
else if (c == '*') {
/* Matches zero or more characters. */
return TRUE;
}
else if (c == '?') {
/* Matches exactly one character. */
if (*s2 == '\0') {
return FALSE;
}
else {
s2++;
}
}
else if (c != *s2++) {
return FALSE;
}
}
}
/*
Return TRUE if string p is a prefix of string s.
*/
static int
prefix(char *p, char *s)
{
while (*p) {
if (*p++ != *s++) {
return FALSE;
}
}
return TRUE;
}
/*
Print out n-1 periods.
*/
static void
print_dots(int n)
{
int i;
for(i = 1; i < n; i++) {
sl_cout('.');
}
}
/*
Compare s1 and s2.
Return <0 ==0 >0
WARNING: This routine MUST NOT call any Sherlock macro.
(Calling STATS and DEBUG is permitted.)
*/
static int
strcmp_(register char *s1, register char *s2)
{
STATS(t_cmp++);
DEBUG(printf("strcmp_(%s, %s)\n", s1, s2));
while (*s1 == *s2) {
if (*s1 == '\0') {
return 0;
}
else {
s1++;
s2++;
}
}
return ((int) *s1) - ((int) *s2);
}
/*
Return TRUE if s1 == s2
WARNING: This routine MUST NOT call any Sherlock macro.
(Calling STATS and DEBUG is permitted.)
*/
static int
streq_(register char *s1, register char *s2)
{
STATS(t_eq++);
DEBUG(printf("streq_(%s, %s)\n", s1, s2));
while(*s1) {
if (*s1++ != *s2++) {
return FALSE;
}
}
return !*s2;
}
/*
========== PART 3 ==========
External routines common to both Mark I and Mark II versions.
*/
/*
SL_CLEAR macro--Clear all statistics.
*/
void
sl_clear(void)
{
int i;
struct stat * p;
for (i = 0; i < MAX_HASH; i++) {
for (p = hash_tab[i]; p; p = p -> next) {
p -> n_times = 0;
p -> n_2times = 0;
p -> n_stat = 0;
}
}
}
/*
SL_DUMP macro--Print all statistics.
*/
void
sl_dump(void)
{
struct stat *p, *q, *q1;
char *pname;
int i;
long tot_stats, percent, totp_stats;
char sbuf1 [40], sbuf2 [40];
#ifdef TIME_STATS
long tot_times, tpercent, totp_times;
long tot_2times, t2percent, totp_2times;
#endif
#ifdef BUG_HASH_DUMP
int bucket_count;
#endif
sl_sout("\n\nReport of statistics:\n\n");
/* Calculate grand total times. */
tot_stats = 0;
#ifdef TIME_STATS
tot_times = 0;
tot_2times = 0;
#endif
/* Scan all buckets. */
for (i = 0; i < MAX_HASH; i++) {
#ifdef BUG_HASH_DUMP
bucket_count = 0;
#endif
for (p = hash_tab[i]; p; p = p -> next) {
tot_stats += p -> n_stat;
#ifdef TIME_STATS
tot_times += sl_adjust(p, p->n_times); /* 8/3/89 */
tot_2times += sl_adjust(p, p -> n_2times); /* 8/3/89 */
#endif
#ifdef BUG_HASH_DUMP
bucket_count++;
#endif
/*
Sort all and only those entries that will be printed.
The sorting is done by creating a list in the alpha
field of the stat nodes.
*/
if ( p -> n_stat || p -> n_times ||
p -> n_2times || p -> trace
) {
pname = p -> name;
for ( q1 = &a_list, q = q1 -> alpha;
;
q1 = q, q = q -> alpha
) {
if ( q == NULL ||
strcmp_(pname, q -> name) < 0
) {
q1 -> alpha = p;
p -> alpha = q;
break;
}
}
}
#ifdef BUG_HASH_DUMP
if (bucket_count >= 9) {
bin[9]++;
}
else {
bin[bucket_count]++;
}
#endif
}}
/* Print the table in alphabetical order. */
sl_slout(20, "tracepoints");
sl_cout(' ');
sl_slout(12, "ticks");
sl_slout(5, " ");
#ifdef TIME_STATS
sl_slout(12, "times1");
sl_slout(5, " ");
sl_slout(10, "times2");
sl_slout(5, " ");
#endif
sl_sout("tracing\n\n");
totp_stats = 0;
#ifdef TIME_STATS
totp_times = 0;
totp_2times = 0;
#endif
for (p = a_list.alpha; p; p = p -> alpha) {
if (p -> n_stat || p -> n_times || p -> trace) {
/* Print breakpoint name. */
sl_slout(20, p -> name);
sl_cout(' ');
/* Print statistics. */
if (tot_stats == 0) {
percent = 0;
}
else {
percent = ((p -> n_stat * 100) / tot_stats);
totp_stats += percent;
}
#ifdef TIME_STATS
if (tot_times == 0) {
tpercent = 0;
}
else {
tpercent =
/* 8/3/89 */
((sl_adjust(p, p->n_times)*100) / tot_times);
totp_times += tpercent;
}
if (tot_2times == 0) {
t2percent = 0;
}
else {
t2percent =
/* 8/3/89 */
((sl_adjust(p, p->n_2times)*100) / tot_2times);
totp_2times += t2percent;
}
#endif
ltoa(p -> n_stat, sbuf1, 10);
ltoa(percent, sbuf2, 10);
sl_slout(8, sbuf1);
sl_sout(" = ");
sl_slout(3, sbuf2);
sl_sout("% ");
#ifdef TIME_STATS
ltoa(sl_adjust(p,p->n_times), sbuf1, 10); /* 8/3/89 */
ltoa(tpercent, sbuf2, 10);
sl_slout(8, sbuf1);
sl_sout(" = ");
sl_slout(3, sbuf2);
sl_sout("% ");
ltoa(sl_adjust(p,p->n_2times), sbuf1, 10); /* 8/3/89 */
ltoa(t2percent, sbuf2, 10);
sl_slout(8, sbuf1);
sl_sout(" = ");
sl_slout(3, sbuf2);
sl_sout("% ");
#endif
/* Indicate whether tracing was enabled. */
if (p -> trace) {
sl_slout(9, "ON\n");
}
else {
sl_slout(9, "OFF\n");
}
}
}
/* Print the totals. */
ltoa(tot_stats, sbuf1, 10);
ltoa(totp_stats, sbuf2, 10);
sl_slout(20, "TOTALS:");
sl_sout(" ");
sl_slout(8, sbuf1);
sl_sout(" ");
sl_slout(3, sbuf2);
sl_sout("%");
#ifdef TIME_STATS
ltoa(tot_times, sbuf1, 10);
ltoa(totp_times, sbuf2, 10);
sl_sout(" ");
sl_slout(8, sbuf1);
sl_sout(" ");
sl_slout(3, sbuf2);
sl_sout("%");
ltoa(tot_2times, sbuf1, 10);
ltoa(totp_2times, sbuf2, 10);
sl_sout(" ");
sl_slout(8, sbuf1);
sl_sout(" ");
sl_slout(3, sbuf2);
sl_sout("%\n\n");
#endif
/* Print the TIME_ADJUST Factor. */
sl_sout("TIME_ADJUST is ");
itoa(TIME_ADJUST, sbuf1, 10);
sl_sout(sbuf1);
sl_sout("\n\n");
/* Print wildcard table. */
sl_slout(20, "Wildcards");
sl_sout(" tracing\n\n");
for (p = wildcard; p; p = p -> next) {
sl_slout(20, p -> name);
sl_sout(" ");
if (p -> trace) {
sl_slout(8, "ON\n");
}
else {
sl_slout(8, "OFF\n");
}
}
#ifdef BUG_HASH_DUMP
printf("\nHash statistics\n\n");
for (i = 0; i < 10; i++) {
printf("bin[%d] = %d\n", i, bin[i]);
}
#endif
#ifdef BUG_STATS
printf("\nInternal Variables\n\n");
printf("t_buffer = %ld\n", t_buffer);
printf("t_check = %ld\n", t_check);
printf("t_cmp = %ld\n", t_cmp);
printf("t_eq = %ld\n", t_eq);
printf("t_find = %ld\n", t_find);
printf("t_hash = %ld\n", t_hash);
printf("t_init = %ld\n", t_init);
printf("t_match = %ld\n", t_match);
printf("t_new = %ld\n", t_new);
printf("t_off = %ld\n", t_off);
printf("t_on = %ld\n", t_on);
printf("t_set = %ld\n", t_set);
printf("t_wild = %ld\n\n", t_wild);
printf("t_btick = %ld\n", t_btick);
printf("t_btrace = %ld\n", t_btrace);
printf("t_ntick = %ld\n", t_ntick);
printf("t_ntrace = %ld\n", t_ntrace);
printf("t_ptrace = %ld\n", t_ptrace);
printf("t_pbtrace = %ld\n", t_pbtrace);
printf("t_pntrace = %ld\n", t_pntrace);
printf("t_pxtrace = %ld\n", t_pxtrace);
printf("t_stat = %ld\n", t_stat);
printf("t_tick = %ld\n", t_tick);
printf("t_trace = %ld\n", t_trace);
printf("t_xtrace = %ld\n\n", t_xtrace);
#endif
}
/*
SL_INIT macro--Initialize the statistics routines.
*/
void
sl_init(char * version)
{
int i;
STATS(t_init++);
DEBUG(printf("sl_init()\n"));
sl_s3out("Sherlock support routines version ", SL_VERSION_NAME, "\n");
if (strcmp(version, SL_VERSION_NAME) != 0) {
sl_s2out("sl_init: Header version ", version);
sl_sout(" does not match version of support routines.\n");
exit(BAD_EXIT);
}
/* Initialize the hash table. */
for (i = 0; i < MAX_HASH; i++) {
hash_tab [i] = NULL;
}
a_list.alpha = NULL;
a_list.next = NULL;
a_list.name = NULL;
#ifdef TIME_STATS
/* Initialize the interrupt vectors. See. prf.asm */
sl_von();
DEBUG(sl_sout("Trap vectors installed.\n"));
#endif
}
/*
SL_OFF macro.
Turn tracing off for one variable or a class of variables.
*/
void
sl_off(char *s)
{
STATS(t_off++);
DEBUG(printf("sl_off(%s)\n", s));
if (streq_(s, "trace")) {
sl_sout("Disabling ALL tracing...\n");
troff = TRUE;
return;
}
sl_s3out("Disabling trace of ", s, "\n");
check_s = "TRACE_OFF";
sl_set(s, 0);
}
/*
SL_ON macro.
Turn tracing on for one variable or a class of variables.
*/
void
sl_on(char *s)
{
STATS(t_on++);
DEBUG(printf("sl_on(%s)\n", s));
if (streq_(s, "trace")) {
sl_sout("Enabling ALL tracing...\n");
troff = FALSE;
return;
}
sl_s3out("Enabling trace of ", s, "\n");
check_s = "TRACE_ON";
sl_set(s, 1);
}
/*
SL_PARSE macro--Parse the command list.
argcp points to the argc count.
argv contains pointers to the arguments.
on_str and off_str are the on_prefix and off_prefix respectively.
*/
void
sl_parse(int *argcp, char **argv, char *on_str, char *off_str)
{
char ** base;
char * arg;
int argc;
int on_len, off_len;
on_len = strlen(on_str);
off_len = strlen(off_str);
argc = *argcp;
argc--;
argv++;
base = argv;
while (argc-- > 0) {
arg = *argv++;
if (prefix(on_str, arg)) {
if (!*(arg + on_len)) {
sl_s3out("Lone '", on_str, "'\n");
exit(BAD_EXIT);
}
sl_on(arg + on_len);
/* One less argument for the program. */
(*argcp)--;
}
else if (prefix(off_str, arg)) {
if (!*(arg + off_len)) {
sl_s3out("Lone '", off_str, "'\n");
exit(BAD_EXIT);
}
sl_off(arg + off_len);
/* One less argument for the program. */
(*argcp)--;
}
else {
/* Compact original argv vector. */
*base++ = arg;
}
}
}
/*
The following macros are the same in both versions because there
is no need to pass a handle to the support routine--the proper handle
should be on top of the call stack.
*/
/*
TRACEPX macro.
*/
int
sl_pxtrace(char *s)
{
STATS(t_pxtrace++);
DEBUG(printf("sl1pxtrace(%s)\n", s));
if (sl_ret(s)) {
print_dots(sl_level);
sl_s2out(s, ": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
Check for proper stack alignment using the entry name s.
Return TRUE if tracing is enabled.
*/
int
sl_ret(char *s)
{
register int i;
register struct stat *p, *p1;
char *p2;
unsigned long old_count;
if (troff) {
return FALSE;
}
else if (sl_level <= 0) {
sl_s3out(
"Sherlock call stack underflow at exit point ", s, "\n");
return FALSE;
}
p = call_stack [sl_level-1];
if (!streq_(p -> name, s)) {
sl_s3out("sl_ret: Entry/Exit mismatch at exit point ", s, "\n");
sl_sout("Check for missing or misnamed exit macros.\n");
sl_sout("Dump of call stack: \n\n");
for (i = sl_level - 1; i >= 0; i--) {
sl_s2out(call_stack [i] -> name, "\n");
}
sl_sout("\n");
exit(1);
}
else {
old_count = sl_count;
/* Update both timing statistic. */
p1 = call_stack [sl_level - 1];
p1 -> n_times += old_count;
p1 -> n_2times += old_count;
/*
Update the cumulative statistics of all nested routines
EXCEPT recursive calls to the same function.
*/
p2 = p1 -> name;
for(i = 0; i < sl_level-1; i++) {
p1 = call_stack[i];
if (p1 -> name != p2) {
p1 -> n_2times += old_count;
DEBUG(printf("sl_ret: add %ld to cumulative for %s\n",
old_count, p1 -> name));
}
}
sl_count = 0;
sl_level--;
}
/* Return TRUE if we should enable the macro. */
if (g_disable > 0) {
g_disable--;
if (p -> n_disable > 0) {
p -> n_disable--;
}
return FALSE;
}
else if (p -> n_disable > 0) {
p -> n_disable--;
return FALSE;
}
else {
return p -> trace;
}
}
/*
TICKX macro--Exit a nesting level and print s.
*/
void
sl_x(char *s)
{
if (sl_ret(s)) {
print_dots(sl_level);
sl_s2out(s, ": exits\n");
}
}
/*
RETURN_BOOL macro.
Exit a nesting sl_level and print a boolean (int).
*/
int
sl_xb(char *s, int b)
{
if (sl_ret(s)) {
print_dots(sl_level);
if (b) {
sl_s2out(s, ": returns TRUE\n");
}
else {
sl_s2out(s, ": returns FALSE\n");
}
}
return b;
}
/*
RETURN_CHAR macro.
Exit a nesting level and print a character.
*/
char
sl_xc(char *s, char c)
{
char buffer[2];
if (sl_ret(s)) {
print_dots(sl_level);
buffer[0] = c;
buffer[1] = '\0';
sl_s3out(s, ": returns ", buffer);
sl_sout("\n");
}
return c;
}
/*
EXIT_DOUBLE macro.
Exit a nesting sl_level and print a double.
*/
double
sl_xd(char *s, double d)
{
char buffer [100];
if (sl_ret(s)) {
print_dots(sl_level);
sprintf(buffer, "%f", d);
sl_s3out(s, ": returns ", buffer);
sl_sout("\n");
}
return d;
}
/*
RETURN_INT macro.
Exit a nesting level and print an int.
*/
int
sl_xi(char *s, int n)
{
char buffer [40];
if (sl_ret(s)) {
print_dots(sl_level);
itoa(n, buffer, 10);
sl_s2out(s, ": returns ");
sl_s2out(buffer, "\n");
}
return n;
}
/*
RETURN_LONG macro.
Exit a nesting level and print a long.
*/
long
sl_xl(char *s, long l)
{
char buffer [40];
if (sl_ret(s)) {
print_dots(sl_level);
ltoa(l, buffer, 10);
sl_s2out(s, ": returns ");
sl_s2out(buffer, "\n");
}
return l;
}
/*
RETURN_PTR macro.
Exit a nesting level and print a pointer.
*/
void *
sl_xp(char *s, void *pv)
{
char buffer [100];
if (sl_ret(s)) {
print_dots(sl_level);
sprintf(buffer, "%p", pv);
sl_s3out(s, ": returns ptr: ", buffer);
sl_sout("\n");
}
return pv;
}
/*
RETURN_sTRING macro.
Exit a nesting level and print a string.
*/
char *
sl_xs(char *s1, char *s2)
{
if(sl_ret(s1)) {
print_dots(sl_level);
sl_s3out(s1, ": returns ", s2);
sl_sout("\n");
}
return s2;
}
/*
TRACEX macro.
*/
int
sl_xtrace(char *s)
{
STATS(t_xtrace++);
DEBUG(printf("sl_xtrace(%s)\n", s));
return sl_ret(s);
}
/*
RETURN_UINT macro.
Exit a nesting level and print an unsigned int.
*/
unsigned int
sl_xui(char *s1, unsigned int ui)
{
char buffer [100];
if(sl_ret(s1)) {
print_dots(sl_level);
sprintf(buffer, "(unsigned) %u", ui);
sl_s3out(s1, ": returns ", buffer);
sl_sout("\n");
}
return ui;
}
/*
RETURN_ULONG macro.
Exit a nesting level and print an unsigned int.
*/
unsigned long
sl_xul(char *s1, unsigned long ul)
{
char buffer [100];
if(sl_ret(s1)) {
print_dots(sl_level);
sprintf(buffer, "(unsigned) %lu", ul);
sl_s3out(s1, ": returns ", buffer);
sl_sout("\n");
}
return ul;
}
/*
RETURN_VOID macro--Exit a nesting level and print void.
*/
void
sl_xv(char *s)
{
if (sl_ret(s)) {
print_dots(sl_level);
sl_s2out(s, ": returns void\n");
}
}
/*
========== PART 4 ==========
Mark I versions of routines.
*/
#ifdef MARKI
/*
STATB macro--Enter a new nesting level.
(Mark I Version.)
*/
void
sl1bstat(char *s)
{
STATS(t_bstat++);
DEBUG(printf("sl1bstat(%s)\n", s));
sl_visit(sl_find("STATB", s), STAT_FLAG, ENTRY_FLAG);
}
/*
BTICK and ENTER macros--Enter a new nesting level.
(Mark I Version.)
*/
void
sl1btick(char *s)
{
STATS(t_btick++);
DEBUG(printf("sl1btick(%s)\n", s));
if (sl_visit(sl_find("TICKB", s) , STAT_FLAG, ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ":\n");
}
}
/*
TRACEB macros.
Enter a new nesting level.
(Mark I Version.)
*/
int
sl1btrace(char *s)
{
STATS(t_btrace++);
DEBUG(printf("sl1btrace(%s)\n", s));
return sl_visit(sl_find("TRACEB", s), STAT_FLAG, ENTRY_FLAG);
}
/*
TICKN macro--TICK with no statistics.
(Mark I Version.)
*/
void
sl1ntick(char *s)
{
STATS(t_ntick++);
DEBUG(printf("sl1ntick(%s)\n", s));
if (sl_visit(sl_find("TICKN", s), NO_STAT_FLAG, NO_ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ":\n");
}
}
/*
TRACEN macro--TRACE with no statistics.
(Mark I Version.)
*/
int
sl1ntrace(char *s)
{
STATS(t_ntrace++);
DEBUG(printf("sl1ntrace(%s)\n", s));
return sl_visit(sl_find("TRACEN", s), NO_STAT_FLAG, NO_ENTRY_FLAG);
}
/*
TRACEPB and ENTER_TRACE macros.
Enter a new nesting level.
(Mark I Version.)
*/
int
sl1pbtrace(char *s)
{
STATS(t_pbtrace++);
DEBUG(printf("sl1pbtrace(%s)\n", s));
if (sl_visit(sl_find("TRACEPB", s), STAT_FLAG, ENTRY_FLAG)) {
print_dots(sl_level - 1);
sl_s2out(s, ": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
TRACEPN--TRACEP with no statistics.
(Mark I Version.)
*/
int
sl1pntrace(char *s)
{
STATS(t_pntrace++);
DEBUG(printf("sl1pntrace(%s)\n", s));
if (sl_visit(sl_find("TRACEPN", s), NO_STAT_FLAG, NO_ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
TRACEP macro--TRACE with printing of tracepoint's name.
(Mark I Version.)
*/
int
sl1ptrace(char *s)
{
STATS(t_ptrace++);
DEBUG(printf("sl1ptrace(%s)\n", s));
if (sl_visit(sl_find("TRACEP", s), STAT_FLAG, NO_ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
STAT macro--Update one statistic.
(Mark I Version.)
*/
void
sl1stat(char *s)
{
STATS(t_stat++);
DEBUG(printf("sl1stat(%s)\n", s));
sl_visit(sl_find("STAT", s), STAT_FLAG, NO_ENTRY_FLAG);
}
/*
TICK macro--Update one statistic and print the tracepoint name.
(Mark I Version.)
*/
void
sl1tick(char *s)
{
STATS(t_tick++);
DEBUG(printf("sl1tick(%s)\n", s));
if (sl_visit(sl_find("TICK", s), STAT_FLAG, NO_ENTRY_FLAG)) {
print_dots(sl_level - 1);
sl_s2out(s, ":\n");
}
}
/*
TRACE macro--Return TRUE if tracing s.
(Mark I Version.)
*/
int
sl1trace(char *s)
{
STATS(t_trace++);
DEBUG(printf("sl1trace(%s)\n", s));
return sl_visit(sl_find("TRACE", s), STAT_FLAG, NO_ENTRY_FLAG);
}
#endif /* MARKI */
/*
========== PART 5 ==========
Mark II versions of routines.
*/
#ifdef MARKII
/*
STATB macro--Enter a new nesting level.
(Mark II Version).
*/
void
sl2bstat(struct stat **pp, char *s)
{
STATS(t_bstat++);
DEBUG(printf("sl2bstat(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("TICKB", s);
}
sl_visit(*pp, STAT_FLAG, ENTRY_FLAG);
}
/*
TICKB or ENTER macros--Enter a new nesting level.
(Mark II Version).
*/
void
sl2btick(struct stat **pp, char *s)
{
STATS(t_btick++);
DEBUG(printf("sl2btick(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("TICKB", s);
}
if (sl_visit(*pp, STAT_FLAG, ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ":\n");
}
}
/*
TRACEB macro--Enter a new nesting level.
(Mark II Version).
*/
int
sl2btrace(struct stat **pp, char *s)
{
STATS(t_btrace++);
DEBUG(printf("sl2btrace(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("TRACEB", s);
}
return sl_visit(*pp, STAT_FLAG, ENTRY_FLAG);
}
/*
TICKN macro.
(Mark II Version.)
*/
void
sl2ntick(struct stat **pp, char * s)
{
STATS(t_ntick++);
DEBUG(printf("sl2ntick(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("TICKN", s);
}
if (sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ":\n");
}
}
/*
TRACEN macro.
(Mark II Version.)
*/
int
sl2ntrace(struct stat **pp, char *s)
{
STATS(t_ntrace++);
DEBUG(printf("sl2ntrace(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("TRACEN", s);
}
return sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG);
}
/*
TRACEPB and ENTER_TRACE macros--Enter a new nesting level.
(Mark II Version).
*/
int
sl2pbtrace(struct stat **pp, char *s)
{
STATS(t_pbtrace++);
DEBUG(printf("sl2pbtrace(%s)\n", s));
/* Find the proper node. Allocate one if needed. */
if (*pp == NULL) {
*pp = sl_find("TRACEPB", s);
}
if (sl_visit(*pp, STAT_FLAG, ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
TRACEPN macro.
(Mark II Version.)
*/
int
sl2pntrace(struct stat **pp, char *s)
{
STATS(t_pntrace++);
DEBUG(printf("sl2pntrace(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("TRACEPN", s);
}
if (sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
TRACEP macro--TRACE with printing of tracepoint's name.
(Mark II Version.)
*/
int
sl2ptrace(struct stat **pp, char *s)
{
STATS(t_ptrace++);
DEBUG(printf("sl2ptrace(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("TRACEP", s);
}
if (sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
STAT macro--Update one statistic.
(Mark II Version.)
*/
void
sl2stat(struct stat **pp, char * s)
{
STATS(t_stat++);
DEBUG(printf("sl2stat(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("STAT", s);
}
sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG);
}
/*
TICK macro--Update one statistic and print tracepoint's name.
(Mark II Version.)
*/
void
sl2tick(struct stat **pp, char * s)
{
STATS(t_tick++);
DEBUG(printf("sl2tick(%s)\n", s));
/* Find the proper node. Allocate one if needed. */
if (*pp == NULL) {
*pp = sl_find("TICK", s);
}
if (sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG)) {
print_dots(sl_level-1);
sl_s2out(s, ":\n");
}
}
/*
TRACE macro--Return TRUE if tracing s.
(Mark II Version.)
*/
int
sl2trace(struct stat **pp, char *s)
{
STATS(t_trace++);
DEBUG(printf("sl2trace(%s)\n", s));
if (*pp == NULL) {
*pp = sl_find("TRACE", s);
}
return sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG);
}
#endif /* MARKII */
/*
========== PART 6 ==========
Output routines.
*/
/*
Output a character to the standard place.
This is the only routine you should change in order to use different
routines for output. All output eventually goes through this routine.
*/
void
sl_cout(char c)
{
putchar(c);
}
/*
Output a comma, followed by a space.
SPP generates a call to this routine to save space.
*/
void
sl_csout(void)
{
sl_sout(", ");
}
/*
Output a bool.
*/
void
sl_bout(int b)
{
if (b) {
sl_sout("TRUE");
}
else {
sl_sout("FALSE");
}
}
/*
Output a double.
*/
void
sl_dout(double d)
{
char buf [100];
sprintf(buf, "%f", d);
sl_sout(buf);
}
/*
Output a float. (Floats are converted to double.)
*/
void
sl_fout(double f)
{
char buf [100];
sprintf(buf, "%f", f);
sl_sout(buf);
}
/*
Output an integer.
*/
void
sl_iout(int i)
{
char buf [100];
sprintf(buf, "%d", i);
sl_sout(buf);
}
/*
Output a left (open) parenthesis.
SPP generates a call to this routine to save space.
*/
void
sl_lpout(void)
{
sl_cout('(');
}
/*
Output a long.
*/
void
sl_lout(long l)
{
char buf [100];
sprintf(buf, "(long) %ld", l); /* bug fix: 2/10/89 */
sl_sout(buf);
}
/*
Output a pointer.
*/
void
sl_pout(void *p)
{
char buf [100];
sprintf(buf, "(pointer) %p", p);
sl_sout(buf);
}
/*
Output a right parenthesis and a newline.
SPP generates a call to this routine to save space.
*/
void
sl_rpout(void)
{
sl_sout(")\n");
}
/*
Return a pointer to a string corresponding to a bool.
*/
char *
sl_sbout(int b)
{
return (b ? "TRUE" : "FALSE");
}
/*
Output a string.
*/
void
sl_sout(char *s)
{
while (*s) {
sl_cout(*s++);
}
}
/*
Output two strings.
*/
static void
sl_s2out(char *s1, char *s2)
{
sl_sout(s1);
sl_sout(s2);
}
/*
Output three strings.
*/
static void
sl_s3out(char *s1, char *s2, char *s3)
{
sl_sout(s1);
sl_sout(s2);
sl_sout(s3);
}
/*
Output string s right justified in a field of size n.
*/
static void
sl_slout(int n, char *s)
{
int pad;
for (pad = n - strlen(s); pad > 0; pad--) {
sl_cout(' ');
}
sl_sout(s);
}
/* 2/10/89
Output an unsigned int.
*/
void
sl_uiout(unsigned u)
{
char buf [100];
sprintf(buf, "(unsigned) %u", u);
sl_sout(buf);
}
/* 2/10/89
Output an unsigned int.
*/
void
sl_ulout(unsigned long u)
{
char buf [100];
sprintf(buf, "(unsigned long) %lu", u);
sl_sout(buf);
}