*	Convergent Technologies  System V  May 1986	*
ident	@()runtime.c	6.2 :sourcecmdctraces.runtime.c 1987 14:29:56

*	ctrace  C program debugging tool
 *
 *	runtime package of trace functions
 *
 *
include <stdlib.h>
include <string.h>

typedef 
	union	{		* var value *
		char	*vs_ct_;* string *
		int		vi_ct_;	* int *
		long	vl_ct_;	* long *
		double	vd_ct_;	* double *
	} u_ct_val_;
typedef void (*PF)();
extern PF set_fault_handler(PF);

ifndef B_CT_

* signal catching function used by u_ct_ *
static jmp_buf sj_ct_;
void f_ct_(void)
{
	longjmp(sj_ct_, 1);
}
endif

ifdef LM_CT_
define I_CT_(x)	((x + LM_CT_)  LM_CT_)

* global data used by loop detection code *
static	int	ts_ct_ = 0;	* trace state *
endif

* global data used by duplicate variable trace code *
static	int	vc_ct_ = 0;	* var trace count within statement *

static	struct	{	* var values within statement *
	char	*vn_ct_;	* var name *
	int	vt_ct_;		* var type (0 is string, > 0 is size) *
	union	{		* var value *
		char	*vs_ct_;* string *
		int	vi_ct_;	* int *
		long	vl_ct_;	* long *
		double	vd_ct_;	* double *
	} vv_ct_;
} v_ct_[VM_CT_];

* trace onoff control *
int	tr_ct_ = 1;

void ctron(void)
{
	tr_ct_ = 1;
	PF_CT_ \b\n    * trace on * \b);
}

void ctroff(void)
{
	tr_ct_ = 0;
	PF_CT_ \b\n    * trace off * \b);
}
* print the statement text *

void t_ct_(register char *text)
{
ifdef LM_CT_
	static	int	loop_start = 0, next_stmt = 0;
	static	char	*stmt[LM_CT_];
	static	long	loops = 0;
	register int	i = 0;
	register char	*s;
	register char	c = 0;
endif

	* return if tracing is off *
	if (tr_ct_) {
		return;
	}
ifdef LM_CT_
	if (ts_ct_ == 2)	* if not tracing *
		if (strcmp(text, stmt[next_stmt]) == 0) {
			if (strcmp(text, stmt[loop_start]) == 0) {
				++loops;
				if (loops  1000 == 0)
					PF_CT_ \b\n    * still repeating after ld times * \b, loops);
				next_stmt = loop_start;
			}
			next_stmt = I_CT_(next_stmt + 1);
			vc_ct_ = 0;	* reset the var count *
			return;
		}
		else {	* doesn't match next statement *
			if (loops == 0)
				PF_CT_ \b\n    * repeated < 1 time * \b);
			else
				PF_CT_ \b\n    * repeated ld times * \b, loops);
			loops = 0;
			PF_CT_ \bs \b, stmt[I_CT_(next_stmt  1)]); * print last statement *
			ts_ct_ = 4;	* force var printing *
			for (i = 0; i < vc_ct_; ++i) * print its vars *
				if (v_ct_[i].vt_ct_ == 0) * string? *
					s_ct_(v_ct_[i].vn_ct_, v_ct_[i].vv_ct_.vs_ct_); * yes *
				else
					u_ct_(v_ct_[i].vn_ct_, v_ct_[i].vt_ct_, v_ct_[i].vv_ct_);
			ts_ct_ = 0;	* start tracing *
		}
endif
	vc_ct_ = 0;	* reset the var count *

ifdef LM_CT_
	if (ts_ct_ == 0) {	* if looking for the start of a loop *
		* if statement in list *
		for (i = I_CT_(next_stmt  2); i = I_CT_(next_stmt  1); i = I_CT_(i  1))
			if ((s = stmt[i]) = 0 	* saved text could be null *
			    strcmp(text, s) == 0 	* if text matches *
			    (c = s[strlen(s)  1]) = '{'  c = '}') { * and is not a brace *
				ts_ct_ = 1;	* look for the loop end *
				loop_start = i;
				next_stmt = I_CT_(loop_start + 1);
				goto print_stmt;
			}
	}
	else	* if looking for the loop end *
		if (strcmp(text, stmt[loop_start]) == 0) { * if start stmt *
			ts_ct_ = 2;			* stop tracing *
			PF_CT_ \b\n    * repeating * \b);
			stmt[next_stmt] = text;	* save as end marker *
			next_stmt = I_CT_(loop_start + 1);
			return;
		}
		else
			if ((s = stmt[next_stmt]) = 0 	* saved text could be null *
			    strcmp(text, s) == 0 )	* if not next stmt *
			ts_ct_ = 0; * look for the start of a loop *
	stmt[next_stmt] = text;	* save this statement *
	next_stmt = I_CT_(next_stmt + 1); * inc the pointer *
print_stmt:
endif
	PF_CT_ \bs \b, text); * print this statement *
ifndef B_CT_
	fflush(stdout);		* flush the output buffer *
endif
}
* dump a string variable *

void s_ct_(register char *name, register char *value)
{
	* return if tracing is off *
	if (tr_ct_) {
		return;
	}
ifdef LM_CT_
	* save the var name and value *
	if (ts_ct_ = 4) {	* if not forcing var printing *
		v_ct_[vc_ct_].vn_ct_ = name;
		v_ct_[vc_ct_].vt_ct_ = 0;	* var type is string *
		v_ct_[vc_ct_].vv_ct_.vs_ct_ = value;
		++vc_ct_;
	}

	if (ts_ct_ == 2)	* if not tracing *
		return;
endif

	PF_CT_ \b\n    s == \, name);
	* flush before printing the string because it may cause an
	   abort if it is not null terminated *
ifndef B_CT_
	fflush(stdout);
endif
	PF_CT_s\ * \b, value);
ifndef B_CT_
	fflush(stdout);
endif
}
* dump a variable of an unknown type *

void u_ct_(char *name, register int _size, void  *pvalue)
		* size is a macro in <macros.h> *
{
ifndef isprint
include <ctype.h>
endif
	register int	i = 0;
	register char	*s;
	register char	c;

	u_ct_val_		value;

	* return if tracing is off *
	if (tr_ct_) {
		return;
	}
	
	value = *(u_ct_val_ *)pvalue;
	
	* normalize the size (pointer and float are the same size as either int or long) *
	if (_size == sizeof(char) || _size == sizeof(short))
		_size = sizeof(int);
	else if (_size = sizeof(int)  _size = sizeof(long)  _size = sizeof(double))
		* this is an extern pointer (size=0), or array or struct address *
		_size = sizeof(char *);
ifdef LM_CT_
	if (ts_ct_ = 4) {	* if not forcing var printing *
endif
		* don't dump the variable if its value is the same *
		for (i = 0; i < vc_ct_; ++i)
			if (_size == v_ct_[i].vt_ct_  strcmp(name, v_ct_[i].vn_ct_) == 0)
				if (_size == sizeof(int)) {
					if (value.vi_ct_ == v_ct_[i].vv_ct_.vi_ct_)
						return;
				}
				else if (_size == sizeof(long)) {
					if (value.vl_ct_ == v_ct_[i].vv_ct_.vl_ct_)
						return;
				}
				else * double *
					if (value.vd_ct_ == v_ct_[i].vv_ct_.vd_ct_)
						return;
	
		* save the var name and value *
		v_ct_[vc_ct_].vn_ct_ = name;
		v_ct_[vc_ct_].vt_ct_ = _size;
		if (_size == sizeof(int)) {
			v_ct_[vc_ct_].vv_ct_.vi_ct_ = value.vi_ct_;
		}
		else if (_size == sizeof(long)) {
			v_ct_[vc_ct_].vv_ct_.vl_ct_ = value.vl_ct_;
		}
		else * double *
			v_ct_[vc_ct_].vv_ct_.vd_ct_ = value.vd_ct_;
		++vc_ct_;
ifdef LM_CT_
	}

	if (ts_ct_ == 2)	* if not tracing *
		return;
endif
	* determine the variable type and print it *
	PF_CT_ \b\n    s == , name);
	if (_size == sizeof(int)) {
		PF_CT_d, value.vi_ct_);	* decimal *
ifdef O_CT_
		if ((unsigned) value.vi_ct_ > 7)	* octal *
			PF_CT_ or 0o, value.vi_ct_);
endif
ifdef X_CT_
		if ((unsigned) value.vi_ct_ > 9)	* hexadecimal *
			PF_CT_ or 0Xx, value.vi_ct_);
endif
ifdef U_CT_
		if (value.vi_ct_ < 0)		* unsigned *
			PF_CT_ or u, value.vi_ct_);
endif
ifdef E_CT_
		if (_size == sizeof(float))	* float *
			PF_CT_ or E, value.vi_ct_);
endif
		if ((unsigned) value.vi_ct_ <= 255) * character *
			if (isprint(value.vi_ct_))
				PF_CT_ or 'c', value.vi_ct_);
			else if (iscntrl(value.vi_ct_)) {
				switch (value.vi_ct_) {
					case '\n': c = 'n'; break;
					case '\t': c = 't'; break;
					case '\b': c = 'b'; break;
					case '\r': c = 'r'; break;
					case '\f': c = 'f'; break;
					case '\v': c = 'v'; break;
					default:    c = '\0';
				}
				if (c = '\0')
					PF_CT_ or '\\c', c);
			}
	}
	else if (_size == sizeof(long)) {
		PF_CT_ld, value.vl_ct_);	* decimal *
ifdef O_CT_
		if ((unsigned) value.vl_ct_ > 7)	* octal *
			PF_CT_ or 0lo, value.vl_ct_);
endif
ifdef X_CT_
	if ((unsigned) value.vl_ct_ > 9)	* hexadecimal *
			PF_CT_ or 0Xlx, value.vl_ct_);
endif
ifdef U_CT_
		if (value.vl_ct_ < 0)		* unsigned *
			PF_CT_ or lu, value.vl_ct_);
endif
ifdef E_CT_
		if (_size == sizeof(float))	* float *
			PF_CT_ or E, value.vl_ct_);
endif
	}
	else if (_size == sizeof(double))	* double *
		PF_CT_E, value.vd_ct_);
ifndef B_CT_
	* check for a possible nonnull pointer *
	if (_size == sizeof(char *)  value.vs_ct_ = 0) {
		* see if this is a nonnull string *
		if (setjmp(sj_ct_) == 0) {
			set_fault_handler(f_ct_);
			if (*value.vs_ct_ = '\0')
				for (s = value.vs_ct_; ; ++s) {
					if ((c = *s) == '\0') {
						PF_CT_ or \s\, value.vs_ct_);
						break;
					}
					* don't use isspace(3) because \v and others will not print properly *
					if (isprint(c)  c = '\t'  c = '\n')
						break;	* not string *
				}
		}
		set_fault_handler(0);
	}
endif
	PF_CT_ * \b);
ifndef B_CT_
	fflush(stdout);
endif
}
