
#include "V.h"
#include "sys_varargs.h"
/*
* This is a routine for checking out the debug function stack.  The  stack  is
* actually  represented  by  a linked list of structs declared in the Fenter()
* macro, and linked into a list starting at Vfcts.  We do a test  that  this
* list doesn't have a loop, and ends at the Vfctroot struct. There is a real
* risk here caused by the fact that if a routine fails  to  call  Fexit,  then
* Vfcts ends up pointing to a stack area that has been recycled.
*/

Vchkstk(df,file,line)
	V_f *df;	/* Should be the top of the stack */
	char*file;	/* File we were called from */
	int  line;	/* Line number */
{	int   r=0;
	V_f *dp, *lp, *xp;
	Flag  par=0;
extern V_f Vfctroot;

	if (Une(Vfcts,df)) {
		P2 "### Debug stack screwup Vfcts=%08X should be %08X [corrected] file %s line %d.",
			Vfcts,df,file,line D;
		Vfcts = df;
	}
	if (!(dp = lp = xp = Vfcts)) {
		V3 "+++ Vfcts is null." D;
		++r;
		Done;
	}
	P7 "Function stack:" D;
	while (dp) {
		P7 "\t\"%s\"",NulC(dp->name) D;
		lp = dp;		/* Note the last one */
		dp = dp->list;	/* Advance to the next one */
		if (par)		/* Advance xp every other time */
			xp = xp->list;
		par = 1 - par;
		if (dp == xp) {	/* Is there a loop? */
			P3 "### Loop in function stack at \"%s\"",NulC(xp->name) D;
			++r;
			Done;
		}
	}
	if (Une(lp,&Vfctroot)) {
		P3 "+++ Warning: Function stack ends at \"%s\", not at Vfctroot",
			NulC(lp->name) D;
		++r;
	}
done:
	return r;
}

/*
* Here's a routine to count the length of the longest string of  nulls
* in  a  block  of  chars.  This is used for error checking in various
* places where things have turned up null  that  shouldn't.   We  only
* count  nulls strings of at least Vmaxnull bytes, to try to prevent
* spurious warnings for short (usually binary) null chunks..
*/
Vcntnulls(b,n)
	byte* b;
	int   n;
{	int   r=0;
	int   i, nulls=0;
extern Flag Vchknull;		/* If true, check for nulls */
extern int  Vmaxnull;		/* If true, max length string of nulls */
extern int  Vlennull;		/* Longest string of nulls so far */
	for (i=0; i<n; i++) {
		if (b[i]) {
			if (nulls > Vmaxnull) {
				r = Max(r,nulls);
				Vlennull = Max(Vlennull,nulls);
			}
			nulls = 0;
		} else {
			++nulls;
		}
	}
	if (nulls > Vmaxnull) {
		r = Max(r,nulls);
		Vlennull = Max(Vlennull,nulls);
	}
	return r;
}

/*
* This is an internal dump module for the V package.  You might want
* to  call  the  Vdmpft()  routine  to  get  a  symbolic dump of the
* open-file table. Of course, it only knows about files that have been
* opened by the V package's wrapper routines.
*/
struct openfileflag { int f; char *v; } openfileflag[] = {
	{File_OPEN," OPEN" }, /* File is open */
	{File_SOCK," SOCK" }, /* File is a socket */
	{File_PIPE," PIPE" }, /* File is a pipe */
	{File_PNI ," PNI"  }, /* File is a PNI device */
	{File_TERM," TERM" }, /* File is a tty or pty */
	{File_MBOX," MBOX" }, /* File is a mailbox */
	{0}
};

char *
Vfileflags(v)
{	int f, x;
static char *buf=0;
	Fenter("Vfileflags");
	if (!buf)
		if (!(buf = (CP)Malloc(BUFSIZ)))
			Fail;
	*buf = 0;
	if (v) {
		for (f=0; (x = openfileflag[f].f); f++)
			if ((x & v) == x)
				strcat(buf,openfileflag[f].v);
		if (!*buf)
			sprintf(buf,"[%08X]",v);
	} else
		strcat(buf," CLOSED");
fail:

	V7 "Return \"%s\"",N(buf) D;
	Fexit;
	return buf;
}

/*
* Here is the routine to produce a dump of the openfile list. The dump
* is written to the Vout stream, of course.  The return value is the
* number of open files.
*/
Vdmpft()
{	int f, r=0;
	File *fp;
	char *np;
	Fenter("Vdmpft");
	for (f=0, fp=openfiles; fp; f++, fp = fp->next) {
		if (fp->flgs)
			++r;	/* Count the open files */
		P1 "File%3d ---" D;
		fflush(Vout);
		if (!(np = fp->name.v)) np = null;
		if (fp->port || fp->ipad) {
			P1 "File%3d:%s\t\"%s\" %s.%u."
				,f
				,Vfileflags(fp->flgs)
				,np
				,IPdot(&fp->ipad)
				,fp->port
			D;
		} else {	/* No network address attached */
			P1 "file%3d: lfd=%d flgs=%s\t\"%s\""
				,f
				,fp->lfd
				,Vfileflags(fp->flgs)
				,np
			D;
		}
		fflush(Vout);
	}
	Fexit;
	return r;
}

/*
* Debug dump of the open-file table.
*/
void
Vshowfiles()
{	int   f=0;
	File* fp;
	fprintf(Vout,"We have %d open files:\n",openfilemax+1);
	for (fp=openfiles; fp; f++) {
		fprintf(Vout,"F%3d: %08lX\n",f,fp);
		fprintf(Vout,"F%3d: lfd=%d rfd=%d..\n",f,fp->lfd,fp->rfd);
		fprintf(Vout,"F%3d: name.l=%d.\n",f,fp->name.l);
		fprintf(Vout,"F%3d: name.m=%d.\n",f,fp->name.m);
		fprintf(Vout,"F%3d: name.v=%08lX=\"%s\"\n",f,fp->name.v,N(fp->name.v));
		fprintf(Vout,"F%3d: name.p=%08lX=\"%s\"\n",f,fp->name.p,N(fp->name.p));
		fprintf(Vout,"F%3d: next=%08lX.\n",f,fp->next);
		fp = fp->next;
	}
}

/*
* This routine tests a lot of symbols for being defined, and tells us which
* ones are defined.  Perhaps we should add some code to show the definitions.
*/
Vshowdefs()
{

#ifdef USE_varargs
	V5 "defined: USE_varargs=%d.",USE_varargs D;
#endif
#if defined(BIGENDIAN)
	V5 "defined: BIGENDIAN" D;
#endif
#if defined(BSD)
	V5 "defined: BSD" D;
#endif
#if defined(DEBUG)
	V5 "defined: DEBUG=%d.",DEBUG D;
#endif
#if defined(ENDIAN)
	V5 "defined: ENDIAN" D;
#endif
#if defined(LITTLENDIAN)
	V5 "defined: LITTLENDIAN" D;
#endif
#if defined(MIXEDENDIAN)
	V5 "defined: MIXEDENDIAN" D;
#endif
#if defined(NOTNEEDED)
	V5 "defined: NOTNEEDED" D;
#endif
#if defined(SYS5)
	V5 "defined: SYS5" D;
#endif
#if defined(SYSLOG)
	V5 "defined: SYSLOG" D;
#endif
#if defined(SYS_close)
	V5 "defined: SYS_close" D;
#endif
#if defined(SYS_lseek)
	V5 "defined: SYS_lseek" D;
#endif
#if defined(SYS_open)
	V5 "defined: SYS_open" D;
#endif
#if defined(SYS_read)
	V5 "defined: SYS_read" D;
#endif
#if defined(SYS_write)
	V5 "defined: SYS_write" D;
#endif
#if defined(ULTRIX)
	V5 "defined: ULTRIX" D;
#endif
#if defined(ULTRIX)
	V5 "defined: ULTRIX" D;
#endif

}
