[comp.sources.misc] v19i024: dmake - dmake version 3.7, Part03/37

dvadura@watdragon.waterloo.edu (Dennis Vadura) (05/10/91)

Submitted-by: Dennis Vadura <dvadura@watdragon.waterloo.edu>
Posting-number: Volume 19, Issue 24
Archive-name: dmake/part03
Supersedes: dmake-3.6: Volume 15, Issue 52-77

---- Cut Here and feed the following to sh ----
#!/bin/sh
# this is dmake.shar.03 (part 3 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file dmake/dbug/dbug/dbug.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 3; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test -f _shar_wnt_.tmp; then
sed 's/^X//' << 'SHAR_EOF' >> 'dmake/dbug/dbug/dbug.c' &&
X *	current process name, current source file name and line number,
X *	and current function nesting depth.
X *
X */
X  
X 
LOCAL VOID DoPrefix (_line_)
int _line_;
{
X    lineno++;
X    if (stack -> flags & NUMBER_ON) {
X	(VOID) fprintf (_db_fp_, "%5d: ", lineno);
X    }
X    if (stack -> flags & PROCESS_ON) {
X	(VOID) fprintf (_db_fp_, "%s: ", _db_process_);
X    }
X    if (stack -> flags & FILE_ON) {
X	(VOID) fprintf (_db_fp_, "%14s: ", file);
X    }
X    if (stack -> flags & LINE_ON) {
X	(VOID) fprintf (_db_fp_, "%5d: ", _line_);
X    }
X    if (stack -> flags & DEPTH_ON) {
X	(VOID) fprintf (_db_fp_, "%4d: ", stack -> level);
X    }
X    (VOID) fflush (_db_fp_);
}
X
X
/*
X *  FUNCTION
X *
X *	OpenFile    open new output stream for debugger output
X *
X *  SYNOPSIS
X *
X *	LOCAL VOID OpenFile (name)
X *	char *name;
X *
X *  DESCRIPTION
X *
X *	Given name of a new file (or "-" for stdout) opens the file
X *	and sets the output stream to the new file.
X *
X */
X
LOCAL VOID OpenFile (name)
char *name;
{
X    REGISTER FILE *fp;
X    REGISTER BOOLEAN newfile;
X
X    if (name != NULL) {
X	if (strcmp (name, "-") == 0) {
X	    _db_fp_ = stdout;
X	    stack -> out_file = _db_fp_;
X	} else {
X	    if (!Writable (name)) {
X		(VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
X		perror ("");
X		(VOID) fflush (_db_fp_);
X		(VOID) XDelay (stack -> delay);
X	    } else {
X		if (EXISTS (name)) {
X		    newfile = FALSE;
X		} else {
X		    newfile = TRUE;
X		}
X		fp = fopen (name, "a");
X		if (fp == NULL) {
X 		    (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
X		    perror ("");
X		    (VOID) fflush (_db_fp_);
X		    (VOID) XDelay (stack -> delay);
X		} else {
X		    _db_fp_ = fp;
X		    stack -> out_file = fp;
X		    if (newfile) {
X			ChangeOwner (name);
X		    }
X		}
X	    }
X	}
X    }
}
X
X
/*
X *  FUNCTION
X *
X *	OpenProfile    open new output stream for profiler output
X *
X *  SYNOPSIS
X *
X *	LOCAL VOID OpenProfile (name)
X *	char *name;
X *
X *  DESCRIPTION
X *
X *	Given name of a new file, opens the file
X *	and sets the profiler output stream to the new file.
X *
X *	It is currently unclear whether the prefered behavior is
X *	to truncate any existing file, or simply append to it.
X *	The latter behavior would be desirable for collecting
X *	accumulated runtime history over a number of separate
X *	runs.  It might take some changes to the analyzer program
X *	though, and the notes that Binayak sent with the profiling
X *	diffs indicated that append was the normal mode, but this
X *	does not appear to agree with the actual code. I haven't
X *	investigated at this time [fnf; 24-Jul-87].
X */
X
LOCAL VOID OpenProfile (name)
char *name;
{
X    REGISTER FILE *fp;
X    REGISTER BOOLEAN newfile;
X
X    if (name != NULL) {
X	if (!Writable (name)) {
X	    (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
X	    perror ("");
X	    (VOID) fflush (_db_fp_);
X	    (VOID) XDelay (stack -> delay);
X	} else {
X	    if (EXISTS (name)) {
X		newfile = FALSE;
X	    } else {
X		newfile = TRUE;
X	    }
X	    fp = fopen (name, "w");
X	    if (fp == NULL) {
X		(VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
X		perror ("");
X		(VOID) fflush (_db_fp_);
X		(VOID) XDelay (stack -> delay);
X	    } else {
X		_db_pfp_ = fp;
X		stack -> prof_file = fp;
X		if (newfile) {
X		    ChangeOwner (name);
X		}
X	    }
X	}
X    }
}
X
X
/*
X *  FUNCTION
X *
X *	CloseFile    close the debug output stream
X *
X *  SYNOPSIS
X *
X *	LOCAL VOID CloseFile (fp)
X *	FILE *fp;
X *
X *  DESCRIPTION
X *
X *	Closes the debug output stream unless it is standard output
X *	or standard error.
X *
X */
X
LOCAL VOID CloseFile (fp)
FILE *fp;
{
X    if (fp != stderr && fp != stdout) {
X	if (fclose (fp) == EOF) {
X	    (VOID) fprintf (stderr, ERR_CLOSE, _db_process_);
X	    perror ("");
X	    (VOID) fflush (stderr);
X	    (VOID) XDelay (stack -> delay);
X	}
X    }
}
X
X
/*
X *  FUNCTION
X *
X *	DbugExit    print error message and exit
X *
X *  SYNOPSIS
X *
X *	LOCAL VOID DbugExit (why)
X *	char *why;
X *
X *  DESCRIPTION
X *
X *	Prints error message using current process name, the reason for
X *	aborting (typically out of memory), and exits with status 1.
X *	This should probably be changed to use a status code
X *	defined in the user's debugger include file.
X *
X */
X 
LOCAL VOID DbugExit (why)
char *why;
{
X    (VOID) fprintf (stderr, ERR_ABORT, _db_process_, why);
X    (VOID) fflush (stderr);
X    (VOID) XDelay (stack -> delay);
X    exit (1);
}
X
X
/*
X *  FUNCTION
X *
X *	DbugMalloc    allocate memory for debugger runtime support
X *
X *  SYNOPSIS
X *
X *	LOCAL char *DbugMalloc (size)
X *	int size;
X *
X *  DESCRIPTION
X *
X *	Allocate more memory for debugger runtime support functions.
X *	Failure to to allocate the requested number of bytes is
X *	immediately fatal to the current process.  This may be
X *	rather unfriendly behavior.  It might be better to simply
X *	print a warning message, freeze the current debugger state,
X *	and continue execution.
X *
X */
X 
LOCAL char *DbugMalloc (size)
int size;
{
X    register char *new;
X
X    new = malloc ( size );
X    if (new == NULL) {
X	DbugExit ("out of memory");
X    }
X    return (new);
}
X
X
/*
X *	This function may be eliminated when strtok is available
X *	in the runtime environment (missing from BSD4.1).
X */
X
LOCAL char *strtok (s1, s2)
char *s1, *s2;
{
X    static char *end = NULL;
X    REGISTER char *rtnval;
X
X    rtnval = NULL;
X    if (s2 != NULL) {
X	if (s1 != NULL) {
X	    end = s1;
X	    rtnval = strtok ((char *) NULL, s2);
X	} else if (end != NULL) {
X	    if (*end != EOS) {
X		rtnval = end;
X		while (*end != *s2 && *end != EOS) {end++;}
X		if (*end != EOS) {
X		    *end++ = EOS;
X		}
X	    }
X	}
X    }
X    return (rtnval);
}
X
X
/*
X *  FUNCTION
X *
X *	BaseName    strip leading pathname components from name
X *
X *  SYNOPSIS
X *
X *	LOCAL char *BaseName (pathname)
X *	char *pathname;
X *
X *  DESCRIPTION
X *
X *	Given pointer to a complete pathname, locates the base file
X *	name at the end of the pathname and returns a pointer to
X *	it.
X *
X */
X
LOCAL char *BaseName (pathname)
char *pathname;
{
X    register char *base;
X
X    base = strrchr (pathname, '/');
X    if (base++ == NULL) {
X	base = pathname;
X    }
X    return (base);
}
X
X
/*
X *  FUNCTION
X *
X *	Writable    test to see if a pathname is writable/creatable
X *
X *  SYNOPSIS
X *
X *	LOCAL BOOLEAN Writable (pathname)
X *	char *pathname;
X *
X *  DESCRIPTION
X *
X *	Because the debugger might be linked in with a program that
X *	runs with the set-uid-bit (suid) set, we have to be careful
X *	about opening a user named file for debug output.  This consists
X *	of checking the file for write access with the real user id,
X *	or checking the directory where the file will be created.
X *
X *	Returns TRUE if the user would normally be allowed write or
X *	create access to the named file.  Returns FALSE otherwise.
X *
X */
X
LOCAL BOOLEAN Writable (pathname)
char *pathname;
{
X    REGISTER BOOLEAN granted;
#ifdef unix
X    REGISTER char *lastslash;
#endif
X
#ifndef unix
X    granted = TRUE;
#else
X    granted = FALSE;
X    if (EXISTS (pathname)) {
X	if (WRITABLE (pathname)) {
X	    granted = TRUE;
X	}
X    } else {
X	lastslash = strrchr (pathname, '/');
X	if (lastslash != NULL) {
X	    *lastslash = EOS;
X	} else {
X	    pathname = ".";
X	}
X	if (WRITABLE (pathname)) {
X	    granted = TRUE;
X	}
X	if (lastslash != NULL) {
X	    *lastslash = '/';
X	}
X    }
#endif
X    return (granted);
}
X
X
/*
X *	This function may be eliminated when strrchr is available
X *	in the runtime environment (missing from BSD4.1).
X *	Alternately, you can use rindex() on BSD systems.
X */
X
LOCAL char *strrchr (s, c)
char *s;
char c;
{
X    REGISTER char *scan;
X
X    for (scan = s; *scan != EOS; scan++) {;}
X    while (scan > s && *--scan != c) {;}
X    if (*scan != c) {
X	scan = NULL;
X    }
X    return (scan);
}
X
X
/*
X *  FUNCTION
X *
X *	ChangeOwner    change owner to real user for suid programs
X *
X *  SYNOPSIS
X *
X *	LOCAL VOID ChangeOwner (pathname)
X *
X *  DESCRIPTION
X *
X *	For unix systems, change the owner of the newly created debug
X *	file to the real owner.  This is strictly for the benefit of
X *	programs that are running with the set-user-id bit set.
X *
X *	Note that at this point, the fact that pathname represents
X *	a newly created file has already been established.  If the
X *	program that the debugger is linked to is not running with
X *	the suid bit set, then this operation is redundant (but
X *	harmless).
X *
X */
X
LOCAL VOID ChangeOwner (pathname)
char *pathname;
{
#ifdef unix
X    if (chown (pathname, getuid (), getgid ()) == -1) {
X	(VOID) fprintf (stderr, ERR_CHOWN, _db_process_, pathname);
X	perror ("");
X	(VOID) fflush (stderr);
X	(VOID) XDelay (stack -> delay);
X    }
#endif
}
X
X
/*
X *  FUNCTION
X *
X *	_db_setjmp_    save debugger environment
X *
X *  SYNOPSIS
X *
X *	VOID _db_setjmp_ ()
X *
X *  DESCRIPTION
X *
X *	Invoked as part of the user's DBUG_SETJMP macro to save
X *	the debugger environment in parallel with saving the user's
X *	environment.
X *
X */
X
VOID _db_setjmp_ ()
{
X   jmplevel = stack -> level;
X   jmpfunc = func;
X   jmpfile = file;
}
X
X
/*
X *  FUNCTION
X *
X *	_db_longjmp_    restore previously saved debugger environment
X *
X *  SYNOPSIS
X *
X *	VOID _db_longjmp_ ()
X *
X *  DESCRIPTION
X *
X *	Invoked as part of the user's DBUG_LONGJMP macro to restore
X *	the debugger environment in parallel with restoring the user's
X *	previously saved environment.
X *
X */
X
VOID _db_longjmp_ ()
{
X    stack -> level = jmplevel;
X    if (jmpfunc) {
X	func = jmpfunc;
X    }
X    if (jmpfile) {
X	file = jmpfile;
X    }
}
X
X
/*
X *  FUNCTION
X *
X *	DelayArg   convert D flag argument to appropriate value
X *
X *  SYNOPSIS
X *
X *	LOCAL int DelayArg (value)
X *	int value;
X *
X *  DESCRIPTION
X *
X *	Converts delay argument, given in tenths of a second, to the
X *	appropriate numerical argument used by the system to delay
X *	that that many tenths of a second.  For example, on the
X *	AMIGA, there is a system call "Delay()" which takes an
X *	argument in ticks (50 per second).  On unix, the sleep
X *	command takes seconds.  Thus a value of "10", for one
X *	second of delay, gets converted to 50 on the amiga, and 1
X *	on unix.  Other systems will need to use a timing loop.
X *
X */
X
LOCAL int DelayArg (value)
int value;
{
X    int delayarg = 0;
X    
#ifdef unix
X    delayarg = value / 10;		/* Delay is in seconds for sleep () */
#endif
#ifdef AMIGA
X    delayarg = (HZ * value) / 10;	/* Delay in ticks for XDelay () */
#endif
X    return (delayarg);
}
X
X
/*
X *	A dummy delay stub for systems that do not support delays.
X *	With a little work, this can be turned into a timing loop.
X */
X
#ifndef unix
#ifndef AMIGA
XXDelay ()
{
}
#endif
#endif
X
X
/*
X *  FUNCTION
X *
X *	perror    perror simulation for systems that don't have it
X *
X *  SYNOPSIS
X *
X *	LOCAL VOID perror (s)
X *	char *s;
X *
X *  DESCRIPTION
X *
X *	Perror produces a message on the standard error stream which
X *	provides more information about the library or system error
X *	just encountered.  The argument string s is printed, followed
X *	by a ':', a blank, and then a message and a newline.
X *
X *	An undocumented feature of the unix perror is that if the string
X *	's' is a null string (NOT a NULL pointer!), then the ':' and
X *	blank are not printed.
X *
X *	This version just complains about an "unknown system error".
X *
X */
X
#if !unix && !(AMIGA || LATTICE || __TURBOC__ )
LOCAL VOID perror (s)
#if __STDC__
const char *s;
#else
char *s;
#endif
{
X    if (s && *s != EOS) {
X	(VOID) fprintf (stderr, "%s: ", s);
X    }
X    (VOID) fprintf (stderr, "<unknown system error>\n");
}
#endif	/* !unix && !(AMIGA && LATTICE) */
X
/*
X * Here we need the definitions of the clock routine.  Add your
X * own for whatever system that you have.
X */
X
#if unix
X
# include <sys/param.h>
# if BSD4_3 || sun
X
/*
X * Definition of the Clock() routine for 4.3 BSD.
X */
X
#include <sys/time.h>
#include <sys/resource.h>
X
/*
X * Returns the user time in milliseconds used by this process so
X * far.
X */
X
LOCAL unsigned long Clock ()
{
X    struct rusage ru;
X
X    (VOID) getrusage (RUSAGE_SELF, &ru);
X    return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000));
}
X
#else
X
LOCAL unsigned long Clock ()
{
X    return (0);
}
X
# endif
X
#else
X
#if AMIGA
X
struct DateStamp {		/* Yes, this is a hack, but doing it right */
X	long ds_Days;		/* is incredibly ugly without splitting this */
X	long ds_Minute;		/* off into a separate file */
X	long ds_Tick;
};
X
static int first_clock = TRUE;
static struct DateStamp begin;
static struct DateStamp elapsed;
X
LOCAL unsigned long Clock ()
{
X    register struct DateStamp *now;
X    register unsigned long millisec = 0;
X    extern VOID *AllocMem ();
X
X    now = (struct DateStamp *) AllocMem ((long) sizeof (struct DateStamp), 0L);
X    if (now != NULL) {
X	if (first_clock == TRUE) {
X	    first_clock = FALSE;
X	    (VOID) DateStamp (now);
X	    begin = *now;
X	}
X	(VOID) DateStamp (now);
X	millisec = 24 * 3600 * (1000 / HZ) * (now -> ds_Days - begin.ds_Days);
X	millisec += 60 * (1000 / HZ) * (now -> ds_Minute - begin.ds_Minute);
X	millisec += (1000 / HZ) * (now -> ds_Tick - begin.ds_Tick);
X	(VOID) FreeMem (now, (long) sizeof (struct DateStamp));
X    }
X    return (millisec);
}
X
#else
X
LOCAL unsigned long Clock ()
{
X    return (0);
}
X
#endif	/* AMIGA */
X
#endif	/* unix */
X
#ifdef AMIGA
XXDelay(x)
int x;
{
X	if (x) Delay(x);	/* fix Delay bug in AmigaDOS */
}
#endif
X
SHAR_EOF
chmod 0640 dmake/dbug/dbug/dbug.c ||
echo 'restore of dmake/dbug/dbug/dbug.c failed'
Wc_c="`wc -c < 'dmake/dbug/dbug/dbug.c'`"
test 44504 -eq "$Wc_c" ||
	echo 'dmake/dbug/dbug/dbug.c: original size 44504, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/dbug/dbug/dbug.h ==============
if test -f 'dmake/dbug/dbug/dbug.h' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/dbug/dbug/dbug.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/dbug/dbug/dbug.h' &&
/******************************************************************************
X *									      *
X *	                           N O T I C E				      *
X *									      *
X *	              Copyright Abandoned, 1987, Fred Fish		      *
X *									      *
X *									      *
X *	This previously copyrighted work has been placed into the  public     *
X *	domain  by  the  author  and  may be freely used for any purpose,     *
X *	private or commercial.						      *
X *									      *
X *	Because of the number of inquiries I was receiving about the  use     *
X *	of this product in commercially developed works I have decided to     *
X *	simply make it public domain to further its unrestricted use.   I     *
X *	specifically  would  be  most happy to see this material become a     *
X *	part of the standard Unix distributions by AT&T and the  Berkeley     *
X *	Computer  Science  Research Group, and a standard part of the GNU     *
X *	system from the Free Software Foundation.			      *
X *									      *
X *	I would appreciate it, as a courtesy, if this notice is  left  in     *
X *	all copies and derivative works.  Thank you.			      *
X *									      *
X *	The author makes no warranty of any kind  with  respect  to  this     *
X *	product  and  explicitly disclaims any implied warranties of mer-     *
X *	chantability or fitness for any particular purpose.		      *
X *									      *
X ******************************************************************************
X */
X
X
/*
X *  FILE
X *
X *	dbug.h    user include file for programs using the dbug package
X *
X *  SYNOPSIS
X *
X *	#include <local/dbug.h>
X *
X *  SCCS ID
X *
X *	@(#)dbug.h	1.11 9/5/87
X *
X *  DESCRIPTION
X *
X *	Programs which use the dbug package must include this file.
X *	It contains the appropriate macros to call support routines
X *	in the dbug runtime library.
X *
X *	To disable compilation of the macro expansions define the
X *	preprocessor symbol "DBUG_OFF".  This will result in null
X *	macros expansions so that the resulting code will be smaller
X *	and faster.  (The difference may be smaller than you think
X *	so this step is recommended only when absolutely necessary).
X *	In general, tradeoffs between space and efficiency are
X *	decided in favor of efficiency since space is seldom a
X *	problem on the new machines).
X *
X *	All externally visible symbol names follow the pattern
X *	"_db_xxx..xx_" to minimize the possibility of a dbug package
X *	symbol colliding with a user defined symbol.
X *	
X *	The DBUG_<N> style macros are obsolete and should not be used
X *	in new code.  Macros to map them to instances of DBUG_PRINT
X *	are provided for compatibility with older code.  They may go
X *	away completely in subsequent releases.
X *
X *  AUTHOR
X *
X *	Fred Fish
X *	(Currently employed by Motorola Computer Division, Tempe, Az.)
X *	hao!noao!mcdsun!fnf
X *	(602) 438-3614
X *
X */
X
X
/*
X *	Internally used dbug variables which must be global.
X */
X
#ifndef DBUG_OFF
X    extern int _db_on_;			/* TRUE if debug currently enabled */
X    extern FILE *_db_fp_;		/* Current debug output stream */
X    extern char *_db_process_;		/* Name of current process */
X    extern int _db_keyword_ ();		/* Accept/reject keyword */
X    extern void _db_push_ ();		/* Push state, set up new state */
X    extern void _db_pop_ ();		/* Pop previous debug state */
X    extern void _db_enter_ ();		/* New user function entered */
X    extern void _db_return_ ();		/* User function return */
X    extern void _db_pargs_ ();		/* Remember args for line */
X    extern void _db_doprnt_ ();		/* Print debug output */
X    extern void _db_setjmp_ ();		/* Save debugger environment */
X    extern void _db_longjmp_ ();	/* Restore debugger environment */
# endif
X
X
/*
X *	These macros provide a user interface into functions in the
X *	dbug runtime support library.  They isolate users from changes
X *	in the MACROS and/or runtime support.
X *
X *	The symbols "__LINE__" and "__FILE__" are expanded by the
X *	preprocessor to the current source file line number and file
X *	name respectively.
X *
X *	WARNING ---  Because the DBUG_ENTER macro allocates space on
X *	the user function's stack, it must precede any executable
X *	statements in the user function.
X *
X */
X
# ifdef DBUG_OFF
#    define DBUG_ENTER(a1)
#    define DBUG_MALLOC(a1)
#    define DBUG_RETURN(a1) return(a1)
#    define DBUG_VOID_RETURN return
#    define DBUG_EXECUTE(keyword,a1)
#    define DBUG_PRINT(keyword,arglist)
#    define DBUG_2(keyword,format)		/* Obsolete */
#    define DBUG_3(keyword,format,a1)		/* Obsolete */
#    define DBUG_4(keyword,format,a1,a2)	/* Obsolete */
#    define DBUG_5(keyword,format,a1,a2,a3)	/* Obsolete */
#    define DBUG_PUSH(a1)
#    define DBUG_POP()
#    define DBUG_PROCESS(a1)
#    define DBUG_FILE (stderr)
#    define DBUG_SETJMP setjmp
#    define DBUG_LONGJMP longjmp
# else
#    define DBUG_ENTER(a) \
X	auto char *_db_func_, *_db_file_; \
X	int _db_level_; \
X	_db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_)
#    define DBUG_MALLOC(a) \
X	auto char *_db_func_, *_db_file_; \
X	int _db_level_; \
X	malloc_init();\
X	_db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_)
#    define DBUG_LEAVE \
X	(_db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_))
#    define DBUG_RETURN(a1) return (DBUG_LEAVE, (a1))
/*   define DBUG_RETURN(a1) {DBUG_LEAVE; return(a1);}  Alternate form */
#    define DBUG_VOID_RETURN DBUG_LEAVE; return
#    define DBUG_EXECUTE(keyword,a1) \
X	{if (_db_on_) {if (_db_keyword_ (keyword)) { a1 }}}
#    define DBUG_PRINT(keyword,arglist) \
X	{if (_db_on_) {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;}}
#    define DBUG_2(keyword,format) \
X	DBUG_PRINT(keyword,(format))		/* Obsolete */
#    define DBUG_3(keyword,format,a1) \
X	DBUG_PRINT(keyword,(format,a1))		/* Obsolete */
#    define DBUG_4(keyword,format,a1,a2) \
X	DBUG_PRINT(keyword,(format,a1,a2))	/* Obsolete */
#    define DBUG_5(keyword,format,a1,a2,a3) \
X	DBUG_PRINT(keyword,(format,a1,a2,a3))	/* Obsolete */
#    define DBUG_PUSH(a1) _db_push_ (a1)
#    define DBUG_POP() _db_pop_ ()
#    define DBUG_PROCESS(a1) (_db_process_ = a1)
#    define DBUG_FILE (_db_fp_)
#    define DBUG_SETJMP(a1) (_db_setjmp_ (), setjmp (a1))
#    define DBUG_LONGJMP(a1,a2) (_db_longjmp_ (), longjmp (a1, a2))
# endif
X
SHAR_EOF
chmod 0640 dmake/dbug/dbug/dbug.h ||
echo 'restore of dmake/dbug/dbug/dbug.h failed'
Wc_c="`wc -c < 'dmake/dbug/dbug/dbug.h'`"
test 6259 -eq "$Wc_c" ||
	echo 'dmake/dbug/dbug/dbug.h: original size 6259, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= dmake/dbug/dbug/dbug.p ==============
if test -f 'dmake/dbug/dbug/dbug.p' -a X"$1" != X"-c"; then
	echo 'x - skipping dmake/dbug/dbug/dbug.p (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
sed 's/^X//' << 'SHAR_EOF' > 'dmake/dbug/dbug/dbug.p' &&
X
X
X
X                                 D B U G
X
X                       C Program Debugging Package
X
X                                    by
X
X                                Fred Fish
X
X
X
X
X       IIIINNNNTTTTRRRROOOODDDDUUUUCCCCTTTTIIIIOOOONNNN
X
X
X            Almost every program development environment worthy  of
X       the  name provides some sort of debugging facility.  Usually
X       this takes the  form  of  a  program  which  is  capable  of
X       controlling  execution  of  other programs and examining the
X       internal state of other executing programs.  These types  of
X       programs will be referred to as external debuggers since the
X       debugger is not part of the executing program.  Examples  of
X       this  type  of  debugger  include  the aaaaddddbbbb and ssssddddbbbb debuggers
X       provided with the UUUUNNNNIIIIXXXX811119 operating system.
X
X
X            One of the problems associated with developing programs
X       in  an  environment  with  good  external  debuggers is that
X       developed programs  tend  to  have  little  or  no  internal
X       instrumentation.   This  is  usually  not  a problem for the
X       developer since he is, or at  least  should  be,  intimately
X       familiar  with  the  internal organization, data structures,
X       and control flow of the program being  debugged.   It  is  a
X       serious   problem   for  maintenance  programmers,  who  are
X       unlikely to have such familiarity  with  the  program  being
X       maintained,  modified, or ported to another environment.  It
X       is also a problem, even for the developer, when the  program
X       is  moved  to  an environment with a primitive or unfamiliar
X       debugger, or even no debugger.
X
X
X            On the other hand, _d_b_u_g is an example  of  an  internal
X       debugger.  Because it requires internal instrumentation of a
X       program, and its  usage  does  not  depend  on  any  special
X       capabilities  of  the  execution  environment,  it is always
X       available and will  execute  in  any  environment  that  the
X       program  itself will execute in.  In addition, since it is a
X       complete  package  with  a  specific  user  interface,   all
X       programs   which  use  it  will  be  provided  with  similar
X       debugging capabilities.  This is in sharp contrast to  other
X
X
X       __________
X
X        1. UNIX is a trademark of AT&T Bell Laboratories.
X
X
X
X
X                                  - 1 -
X
X
X
X
X
X
X
X       DBUG User Manual                            October 29, 1986
X
X
X
X       forms of internal instrumentation where each  developer  has
X       their  own, usually less capable, form of internal debugger.
X       In summary, because _d_b_u_g is an internal debugger it provides
X       consistency across operating environments, and because it is
X       available to all developers it provides  consistency  across
X       all programs in the same environment.
X
X
X            The _d_b_u_g package imposes only a slight speed penalty on
X       executing programs, typically much less than 10 percent, and
X       a modest size penalty,  typically  10  to  20  percent.   By
X       defining  a specific C preprocessor symbol both of these can
X       be reduced to zero with no changes required  to  the  source
X       code.
X
X
X            The  following  list  is  a  quick   summary   of   the
X       capabilities  of  the  _d_b_u_g package.  Each capability can be
X       individually enabled or disabled at the time  a  program  is
X       invoked   by   specifying   the   appropriate  command  line
X       arguments.
X
X               o Execution trace  showing  function  level  control
X                 flow    in   a   semi-graphically   manner   using
X                 indentation to indicate nesting depth.
X
X               o Output the values of all, or any  subset  of,  key
X                 internal variables.
X
X               o Limit  actions  to  a  specific   set   of   named
X                 functions.
X
X               o Limit function trace to a specified nesting depth.
X
X               o Label each output line with source file  name  and
X                 line number.
X
X               o Label  each  output  line  with  name  of  current
X                 process.
X
X               o Push or pop  internal  debugging  state  to  allow
X                 execution with built in debugging defaults.
X
X               o Redirect  the  debug  output  stream  to  standard
X                 output  (stdout)  or  a  named  file.  The default
X                 output stream is  standard  error  (stderr).   The
X                 redirection mechanism is completely independent of
X                 normal command line redirection  to  avoid  output
X                 conflicts.
X
X
X
X
X
X                                  - 2 -
X
X
X
X
X
X
X
X       DBUG User Manual                            October 29, 1986
X
X
X
X       PPPPRRRRIIIIMMMMIIIITTTTIIIIVVVVEEEE DDDDEEEEBBBBUUUUGGGGGGGGIIIINNNNGGGG TTTTEEEECCCCHHHHNNNNIIIIQQQQUUUUEEEESSSS
X
X
X            Internal instrumentation is already a familiar  concept
X       to most programmers, since it is usually the first debugging
X       technique  learned.    Typically,   "print statements"   are
X       inserted  in the source code at interesting points, the code
X       is recompiled and executed,  and  the  resulting  output  is
X       examined in an attempt to determine where the problem is.
X
X       The procedure is iterative,  with  each  iteration  yielding
X       more  and  more  output,  and  hopefully  the  source of the
X       problem is discovered before the output becomes too large to
X       deal  with  or  previously  inserted  statements  need to be
X       removed.  Figure 1 is an example of this type  of  primitive
X       debugging technique.
X
X
X
X                 #include <stdio.h>
X
X                 main (argc, argv)
X                 int argc;
X                 char *argv[];
X                 {
X                     printf ("argv[0] = %d\n", argv[0]);
X                     /*
X                      *  Rest of program
X                      */
X                     printf ("== done ==\n");
X                 }
X
X
X                                   Figure 1
X                         Primitive Debugging Technique
X
X
X
X
X
X            Eventually,  and  usually  after   at   least   several
X       iterations,  the  problem  will  be found and corrected.  At
X       this point, the newly  inserted  print  statements  must  be
X       dealt  with.   One obvious solution is to simply delete them
X       all.  Beginners usually do this a few times until they  have
X       to  repeat  the entire process every time a new bug pops up.
X       The second most obvious solution is to somehow  disable  the
X       output,  either  through  the  source code comment facility,
X       creation of a debug variable to be switched on or off, or by
X       using  the  C  preprocessor.   Figure 2 is an example of all
X       three techniques.
X
X
X
X                                  - 3 -
X
X
X
X
X
X
X
X       DBUG User Manual                            October 29, 1986
X
X
X
X
X
X                 #include <stdio.h>
X
X                 int debug = 0;
X
X                 main (argc, argv)
X                 int argc;
X                 char *argv[];
X                 {
X                     /* printf ("argv = %x\n", argv) */
X                     if (debug) printf ("argv[0] = %d\n", argv[0]);
X                     /*
X                      *  Rest of program
X                      */
X                 #ifdef DEBUG
X                     printf ("== done ==\n");
X                 #endif
X                 }
X
X
X                                   Figure 2
X                           Debug Disable Techniques
X
X
X
X
X
X            Each technique has  its  advantages  and  disadvantages
X       with  respect  to  dynamic vs static activation, source code
X       overhead, recompilation requirements, ease of  use,  program
X       readability,  etc.   Overuse  of  the  preprocessor solution
X       quickly leads to problems with source code  readability  and
X       maintainability  when  multiple  ####iiiiffffddddeeeeffff  symbols  are  to be
X       defined or  undefined  based  on  specific  types  of  debug
X       desired.  The source code can be made slightly more readable
X       by suitable indentation of the ####iiiiffffddddeeeeffff arguments to match the
X       indentation  of  the code, but not all C preprocessors allow
X       this.   The  only  requirement  for  the  standard  UUUUNNNNIIIIXXXX   C
X       preprocessor is for the '#' character to appear in the first
X       column,  but  even  this  seems  like   an   arbitrary   and
X       unreasonable  restriction.   Figure  3 is an example of this
X       usage.
X
X
X
X
X
X
X
X
X
X
X
X                                  - 4 -
X
X
X
X
X
X
X
X       DBUG User Manual                            October 29, 1986
X
X
X
X
X
X                 #include <stdio.h>
X
X                 main (argc, argv)
X                 int argc;
X                 char *argv[];
X                 {
X                 #   ifdef DEBUG
X                     printf ("argv[0] = %d\n", argv[0]);
X                 #   endif
X                     /*
X                      *  Rest of program
X                      */
X                 #   ifdef DEBUG
X                     printf ("== done ==\n");
X                 #   endif
X                 }
X
X
X                                   Figure 3
X                       More Readable Preprocessor Usage
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X                                  - 5 -
X
X
X
X
X
X
X
X       DBUG User Manual                            October 29, 1986
X
X
X
X       FFFFUUUUNNNNCCCCTTTTIIIIOOOONNNN TTTTRRRRAAAACCCCEEEE EEEEXXXXAAAAMMMMPPPPLLLLEEEE
X
X
X            We will start off learning about  the  capabilities  of
X       the  _d_b_u_g  package  by  using  a simple minded program which
X       computes the factorial of a  number.   In  order  to  better
X       demonstrate  the  function  trace mechanism, this program is
X       implemented recursively.  Figure 4 is the main function  for
X       this factorial program.
X
X
X
X                 #include <stdio.h>
X                 /* User programs should use <local/dbug.h> */
X                 #include "dbug.h"
X
X                 main (argc, argv)
X                 int argc;
X                 char *argv[];
X                 {
X                     register int result, ix;
X                     extern int factorial (), atoi ();
X
X                     DBUG_ENTER ("main");
X                     DBUG_PROCESS (argv[0]);
X                     for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
X                         switch (argv[ix][1]) {
X                             case '#':
X                                 DBUG_PUSH (&(argv[ix][2]));
X                                 break;
X                         }
X                     }
X                     for (; ix < argc; ix++) {
X                         DBUG_PRINT ("args", ("argv[%d] = %s", ix, argv[ix]));
X                         result = factorial (atoi (argv[ix]));
X                         printf ("%d\n", result);
X                     }
X                     DBUG_RETURN (0);
X                 }
X
X
X                                   Figure 4
X                          Factorial Program Mainline
X
X
X
X
X
X            The mmmmaaaaiiiinnnn function is  responsible  for  processing  any
X       command   line  option  arguments  and  then  computing  and
X       printing the factorial of each non-option argument.
X
X
X
X                                  - 6 -
X
X
X
X
X
X
X
X       DBUG User Manual                            October 29, 1986
X
X
X
X            First of all, notice that all of the debugger functions
X       are  implemented  via  preprocessor  macros.   This does not
X       detract from the readability of the code and makes disabling
X       all debug compilation trivial (a single preprocessor symbol,
X       DDDDBBBBUUUUGGGG____OOOOFFFFFFFF, forces the macro expansions to be null).
X
X            Also notice the inclusion of  the  header  file  ddddbbbbuuuugggg....hhhh
X       from the local header file directory.  (The version included
X       here is the test version in  the  dbug  source  distribution
X       directory).   This file contains all the definitions for the
X       debugger macros, which all have the form DDDDBBBBUUUUGGGG____XXXXXXXX............XXXXXXXX.
X
X
X            The DDDDBBBBUUUUGGGG____EEEENNNNTTTTEEEERRRR macro informs that debugger that we have
X       entered  the function named mmmmaaaaiiiinnnn.  It must be the very first
X       "executable" line in a function, after all declarations  and
X       before any other executable line.  The DDDDBBBBUUUUGGGG____PPPPRRRROOOOCCCCEEEESSSSSSSS macro is
X       generally used only once per program to inform the  debugger
X       what name the program was invoked with.  The DDDDBBBBUUUUGGGG____PPPPUUUUSSSSHHHH macro
X       modifies the current debugger state by saving  the  previous
X       state  and  setting  a new state based on the control string
X       passed as its argument.  The DDDDBBBBUUUUGGGG____PPPPRRRRIIIINNNNTTTT  macro  is  used  to
X       print  the  values of each argument for which a factorial is
X       to be computed.  The DDDDBBBBUUUUGGGG____RRRREEEETTTTUUUURRRRNNNN macro  tells  the  debugger
X       that  the  end  of the current function has been reached and
X       returns a value to  the  calling  function.   All  of  these
X       macros will be fully explained in subsequent sections.
X
X            To use the debugger, the factorial program  is  invoked
X       with a command line of the form:
X
X                          factorial -#d:t 1 2 3
X
X       The  mmmmaaaaiiiinnnn  function  recognizes  the  "-#d:t"  string  as  a
X       debugger  control  string, and passes the debugger arguments
X       ("d:t")  to  the  _d_b_u_g  runtime  support  routines  via  the
X       DDDDBBBBUUUUGGGG____PPPPUUUUSSSSHHHH macro.  This particular string enables output from
X       the DDDDBBBBUUUUGGGG____PPPPRRRRIIIINNNNTTTT macro with the 'd' flag and enables  function
X       tracing  with  the 't' flag.  The factorial function is then
X       called three times, with the arguments "1",  "2",  and  "3".
X       Note  that  the DBUG_PRINT takes exactly ttttwwwwoooo arguments, with
X       the second argument (a format string and list  of  printable
X       values) enclosed in parenthesis.
X
X            Debug control strings consist of a  header,  the  "-#",
X       followed  by  a  colon separated list of debugger arguments.
X       Each debugger argument is a single character  flag  followed
X       by an optional comma separated list of arguments specific to
X       the given flag.  Some examples are:
X
X
X
X
X
X                                  - 7 -
X
X
X
X
X
X
X
X       DBUG User Manual                            October 29, 1986
X
X
X
X                          -#d:t:o
X                          -#d,in,out:f,main:F:L
X
X       Note  that  previously  enabled  debugger  actions  can   be
X       disabled by the control string "-#".
X
X
X            The definition of the factorial function, symbolized as
X       "N!", is given by:
X
X                         N! = N * N-1 * ... 2 * 1
X
X       Figure 5 is the factorial  function  which  implements  this
X       algorithm  recursively.   Note  that this is not necessarily
X       the best way to  do  factorials  and  error  conditions  are
X       ignored completely.
X
X
X
X                 #include <stdio.h>
X                 /* User programs should use <local/dbug.h> */
X                 #include "dbug.h"
X
X                 int factorial (value)
X                 register int value;
X                 {
X                     DBUG_ENTER ("factorial");
X                     DBUG_PRINT ("find", ("find %d factorial", value));
X                     if (value > 1) {
X                         value *= factorial (value - 1);
X                     }
X                     DBUG_PRINT ("result", ("result is %d", value));
X                     DBUG_RETURN (value);
X                 }
X
X
X                                   Figure 5
X                              Factorial Function
X
X
X
X
X
X            One advantage (some may not consider it  so)  to  using
X       the  _d_b_u_g  package  is  that  it  strongly  encourages fully
X       structured coding with only one entry and one exit point  in
X       each  function.  Multiple exit points, such as early returns
X       to escape a loop, may be used, but each such point  requires
X       the  use  of  an appropriate DDDDBBBBUUUUGGGG____RRRREEEETTTTUUUURRRRNNNN or DDDDBBBBUUUUGGGG____VVVVOOOOIIIIDDDD____RRRREEEETTTTUUUURRRRNNNN
X       macro.
X
X
X
X
X                                  - 8 -
X
X
X
X
X
X
X
X       DBUG User Manual                            October 29, 1986
X
X
X
X            To build  the  factorial  program  on  a  UUUUNNNNIIIIXXXX  system,
X       compile and link with the command:
X
X                cc -o factorial main.c factorial.c -ldbug
X
X       The "-ldbug" argument  tells  the  loader  to  link  in  the
X       runtime support modules for the _d_b_u_g package.  Executing the
X       factorial program with a command of the form:
X
X                           factorial 1 2 3 4 5
X
X       generates the output shown in figure 6.
X
X
X
X                 1
X                 2
X                 6
X                 24
X                 120
X
X
X                                   Figure 6
X                              factorial 1 2 3 4 5
SHAR_EOF
true || echo 'restore of dmake/dbug/dbug/dbug.p failed'
fi
echo 'End of part 3, continue with part 4'
echo 4 > _shar_seq_.tmp
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.