/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: str_debug.c 1.14 89/08/07 $"

/* $Log:	str_debug.c,v $
*/

/*
 * stream flavoured debuging
 *
 * Q and q flavours cycled though all modules
 * R and r set the debug level for the current module
 * str_debug(id,level)  interrogates this
 */

#ifdef DEBUG

#include "sys/types.h"
#include "sys/param.h"
#include "sys/mutex.h"
#include "sys/intctl.h"
#include "sys/sysmacros.h"
#include "sys/stropts.h"
#include "sys/session.h"
#include "sys/stream.h"
#include "sys/strstat.h"
#include "sys/conf.h"
#include "sys/var.h"
#include "sys/debug.h"

#define STRL_MAX 40
#define STR_LIM 4

#define STR_MOD	1
#define STR_DRV	2
#define STR_HD	3

static	int	n_mod;			/* actual number found (1 based)*/
static	int	cur_mod;		/* current setting */
static struct str_l {
	struct	streamtab	*sl_str;	/* current stream tab */
	char			*sl_name; 	/* mod or dev */
	dev_t			sl_dminor;	/* device dminor */
	int			sl_level;	/* debug level */
	int			sl_flag;	/* type of module */
	int			sl_id;		/* id number */
} str_l[STRL_MAX];

extern int	strdebug;	/* stream head debug flag */
static int	first=0;
static int	last_id;
static int	last_level;

/*
 * str_nextmod -  find next or last module
 * called from dinfo from ^FQ or  ^Fq
 */
str_nextmod( up )
int	up;
{
	/*
	 * fisrt time scan cstrtab and fmodsw
	 * otherwise use table
	 */
	if (first == 0) {
		scan();
	} else {
		/*
		 * increment or decrement "cur_mod".
		 */
		if (up) {
			if (++cur_mod > n_mod)
				cur_mod = 0;
		} else {
			if (--cur_mod < 0)
				cur_mod = n_mod;
		}
	}
}

	
/*
 * form a table (str_l[]) of all stream drivers and stream modules.
 */
static
scan()
{
	extern	int	cstrcnt;
	extern	int	fmodcnt;
	extern	struct	streamtab	*cstrtab[];
	struct	streamtab	*str;
	struct	str_l		*sl;
	int			i;

	first=1;
	/*
	 * The stream head is always entry 0.
	 */
	str_l[0].sl_name = "stream head";
	str_l[0].sl_level = strdebug;
	str_l[0].sl_flag = STR_HD;
	str_l[0].sl_id = -1;
	n_mod = 1;
	sl = &str_l[1];
	/*
	 * next scan cstrtab (cdevsw) for stream drivers.
	 */
	printf("scanning cstrtab and fmodsw\n");
	for (i=0; i<cstrcnt; i++) {
		if ( cstrtab[i] ) {
			str = cstrtab[i];
			sl->sl_str = str;
			sl->sl_name = str->st_rdinit->qi_minfo->mi_idname;
			sl->sl_id = str->st_rdinit->qi_minfo->mi_idnum;
			sl->sl_dminor = i;
			sl->sl_level = 0;
			sl->sl_flag = STR_DRV;
			if (!sl->sl_name)
				printf("Error cstrtab[%d] has no name\n",i);
			if (check_id(sl->sl_id) != -1) {
				printf("duplicate stream id %d \"%s\" \"%s\" \n",
				sl->sl_id,sl->sl_name,str_l[check_id(sl->sl_id)].sl_name);
			}
			if ( n_mod++ > STRL_MAX) 
				printf("INCREASE STRL_MAX in str_debug\n");
			else
				sl++;
		}
	}
	/*
	 * now scan fmodsw[] for stream modules.
	 */
	for (i=0; i<fmodcnt; i++) {
		str = fmodsw[i].f_str;
		sl->sl_str = str;
		sl->sl_name = fmodsw[i].f_name;
		sl->sl_level = 0;
		sl->sl_flag = STR_MOD;
		sl->sl_id = str->st_rdinit->qi_minfo->mi_idnum;
		if (!sl->sl_name)
			printf("Error fmodsw[%d] has no name\n",i);
		if (check_id(sl->sl_id) != -1) {
			printf("duplicate stream id %d \"%s\" \"%s\" \n",
			sl->sl_id,sl->sl_name,str_l[check_id(sl->sl_id)].sl_name);
		}
		if ( n_mod++ > STRL_MAX) 
			printf("INCREASE STRL_MAX in str_debug\n");
		else
			sl++;
	}
	printf("scan table set up %d modules found\n",n_mod);
	if (n_mod > STRL_MAX)
		n_mod = STRL_MAX;
	/*
	 * set "cur_mod" to stream head
	 */
	cur_mod = 0;
	n_mod -= 1;
	last_id = -1;
}


/*
 * str_prmod - display info structure
 * called from dinfo
 */
str_prmod()
{
	struct	streamtab	*str;
	/*
	 * display information about module
	 * (for now just print name).
	 */
	str = str_l[cur_mod].sl_str;
	switch(str_l[cur_mod].sl_flag) {
	case STR_MOD:
		printf("module:\"%s\" m_info:#%d \"%s\"\n",str_l[cur_mod].sl_name,
			str->st_rdinit->qi_minfo->mi_idnum,
	        	str->st_rdinit->qi_minfo->mi_idname);
		break;
	case STR_DRV:
		printf("driver:(%d) m_info:#%d \"%s\"\n",str_l[cur_mod].sl_dminor,
			str->st_rdinit->qi_minfo->mi_idnum,
	        	str->st_rdinit->qi_minfo->mi_idname);
		break;
	case STR_HD:
		printf("stream head\n");
		break;
	}
}

/*
 * str_bumpdebug - change the current debug level.
 * level goes from 0 to STR_LIM and then 0 again
 * called from dinfo
 */
str_bumpdebug()
{
	register struct	str_l	*sl;

	if (first == 0) 
		scan();
	sl = &str_l[cur_mod];
	if (++(sl->sl_level) > STR_LIM)
		sl->sl_level = 0;
	if ( sl->sl_flag == STR_HD )
		strdebug = sl->sl_level;
	last_id = -1;
	printf("str:\"%s\" %d level %d\n", sl->sl_name,sl->sl_id,sl->sl_level);
}

/*
 * str_bumpdebug - change the current debug level.
 * level goes from STR_LIM to 0 and then STR_LIM again
 * called from dinfo
 */
str_decdebug()
{
	register struct	str_l	*sl;

	if (first == 0) 
		scan();
	sl = &str_l[cur_mod];
	if (--(sl->sl_level) < 0)
		sl->sl_level = STR_LIM;
	if (sl->sl_flag == STR_HD)
		strdebug = sl->sl_level;
	printf("str:\"%s\" %d level %d\n", sl->sl_name,sl->sl_id,sl->sl_level);
	last_id = -1;
}

/*
 * str_debug - return if this module id is being debugged at level n
 * that is if STR_LIM is 4
 * str_debug( X, 0 ) will always be true. debug = 0,1,2,3 or 4
 * str_debug( X, 1 ) will only be true if debug =   1,2,3 or 4
 * str_debug( X, 2 ) will only be true if debug =     2,3 or 4
 * str_debug( X, 3 ) will only be true if debug =       3 or 4
 * str_debug( X, 4 ) will only be true if debug =            4
 * called from modules.
 * or conversly if debug = 4 you get evrything
 *                 debug = 1 you only get the str_debug( X, 1);
 */

str_debug( id, level )
int	id;
int	level;
{
	register struct	str_l *sl;

	/*
	 * cache last look-up.
	 */
	if ( last_id == id ) {
		return (level <= last_level);
	}
	for (sl = &str_l[1]; sl<&str_l[n_mod]; sl++) {
		if (sl->sl_id == id) {
			last_level = sl->sl_level;
			last_id = id;
			return (level <= sl->sl_level);
		}
	}
	/*
	 * print error once
	 */
	if ( last_id == -1 )
		printf("stream id %d not found in str_debug\n",id);
	last_id = id;
	last_level = 0;
	return (0);
}

/*
 * validate unique stream ids.
 */
static
check_id(id)
{
	register int	i;

	for (i=1; i<n_mod; i++) {
		if (str_l[i].sl_id == id) {
			return (i);
		}
	}
	return -1;
}

#endif /*DEBUG*/
