FreeBSD-5.3/sys/ddb/db_output.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * 	Author: David B. Golub, Carnegie Mellon University
 *	Date:	7/90
 */

/*
 * Printf and character output for debugger.
 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/ddb/db_output.c,v 1.31 2004/07/10 23:47:18 marcel Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/cons.h>
#include <sys/kdb.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>

#include <machine/stdarg.h>

#include <ddb/ddb.h>
#include <ddb/db_output.h>

/*
 *	Character output - tracks position in line.
 *	To do this correctly, we should know how wide
 *	the output device is - then we could zero
 *	the line position when the output device wraps
 *	around to the start of the next line.
 *
 *	Instead, we count the number of spaces printed
 *	since the last printing character so that we
 *	don't print trailing spaces.  This avoids most
 *	of the wraparounds.
 */
static int	db_output_position = 0;		/* output column */
static int	db_last_non_space = 0;		/* last non-space character */
db_expr_t	db_tab_stop_width = 8;		/* how wide are tab stops? */
#define	NEXT_TAB(i) \
	((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
db_expr_t	db_max_width = 79;		/* output line width */
static int	db_newlines;			/* # lines this page */
static int	db_maxlines = -1;		/* max lines per page */
static db_page_calloutfcn_t *db_page_callout = NULL;
static void	*db_page_callout_arg = NULL;
static int	ddb_use_printf = 0;
SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0,
    "use printf for all ddb output");

static void	db_putchar(int c, void *arg);

/*
 * Force pending whitespace.
 */
void
db_force_whitespace()
{
	register int last_print, next_tab;

	last_print = db_last_non_space;
	while (last_print < db_output_position) {
	    next_tab = NEXT_TAB(last_print);
	    if (next_tab <= db_output_position) {
		while (last_print < next_tab) { /* DON'T send a tab!!! */
			cnputc(' ');
			last_print++;
		}
	    }
	    else {
		cnputc(' ');
		last_print++;
	    }
	}
	db_last_non_space = db_output_position;
}

/*
 * Output character.  Buffer whitespace.
 */
static void
db_putchar(c, arg)
	int	c;		/* character to output */
	void *	arg;
{

	/*
	 * If not in the debugger or the user requests it, output data to
	 * both the console and the message buffer.
	 */
	if (!kdb_active || ddb_use_printf) {
		printf("%c", c);
		if (!kdb_active)
			return;
		if (c == '\r' || c == '\n')
			db_check_interrupt();
		if (c == '\n' && db_maxlines > 0 && db_page_callout != NULL) {
			db_newlines++;
			if (db_newlines >= db_maxlines) {
				db_maxlines = -1;
				db_page_callout(db_page_callout_arg);
			}
		}
		return;
	}

	/* Otherwise, output data directly to the console. */
	if (c > ' ' && c <= '~') {
	    /*
	     * Printing character.
	     * If we have spaces to print, print them first.
	     * Use tabs if possible.
	     */
	    db_force_whitespace();
	    cnputc(c);
	    db_output_position++;
	    db_last_non_space = db_output_position;
	}
	else if (c == '\n') {
	    /* Newline */
	    cnputc(c);
	    db_output_position = 0;
	    db_last_non_space = 0;
	    db_check_interrupt();
	    if (db_maxlines > 0 && db_page_callout != NULL) {
		    db_newlines++;
		    if (db_newlines >= db_maxlines) {
			    db_maxlines = -1;
			    db_page_callout(db_page_callout_arg);
		    }
	    }
	}
	else if (c == '\r') {
	    /* Return */
	    cnputc(c);
	    db_output_position = 0;
	    db_last_non_space = 0;
	    db_check_interrupt();
	}
	else if (c == '\t') {
	    /* assume tabs every 8 positions */
	    db_output_position = NEXT_TAB(db_output_position);
	}
	else if (c == ' ') {
	    /* space */
	    db_output_position++;
	}
	else if (c == '\007') {
	    /* bell */
	    cnputc(c);
	}
	/* other characters are assumed non-printing */
}

/*
 * Register callout for providing a pager for output.
 */
void
db_setup_paging(db_page_calloutfcn_t *callout, void *arg, int maxlines)
{

	db_page_callout = callout;
	db_page_callout_arg = arg;
	db_maxlines = maxlines;
	db_newlines = 0;
}

/*
 * A simple paging callout function.  If the argument is not null, it
 * points to an integer that will be set to 1 if the user asks to quit.
 */
void
db_simple_pager(void *arg)
{
	int c;

	db_printf("--More--\r");
	for (;;) {
		c = cngetc();
		switch (c) {
		case '\n':
			/* Just one more line. */
			db_setup_paging(db_simple_pager, arg, 1);
			return;
		case ' ':
			/* Another page. */
			db_setup_paging(db_simple_pager, arg,
			    DB_LINES_PER_PAGE);
			return;
		case 'q':
		case 'Q':
		case 'x':
		case 'X':
			/* Quit */
			if (arg != NULL) {
				*(int *)arg = 1;
				db_printf("\n");
				return;
			}
#if 0
			/* FALLTHROUGH */
		default:
			cnputc('\007');
#endif
		}
	}
}

/*
 * Return output position
 */
int
db_print_position()
{
	return (db_output_position);
}

/*
 * Printing
 */
void
#if __STDC__
db_printf(const char *fmt, ...)
#else
db_printf(fmt)
	const char *fmt;
#endif
{
	va_list	listp;

	va_start(listp, fmt);
	kvprintf (fmt, db_putchar, NULL, db_radix, listp);
	va_end(listp);
}

int db_indent;

void
#if __STDC__
db_iprintf(const char *fmt,...)
#else
db_iprintf(fmt)
	const char *fmt;
#endif
{
	register int i;
	va_list listp;

	for (i = db_indent; i >= 8; i -= 8)
		db_printf("\t");
	while (--i >= 0)
		db_printf(" ");
	va_start(listp, fmt);
	kvprintf (fmt, db_putchar, NULL, db_radix, listp);
	va_end(listp);
}

/*
 * End line if too long.
 */
void
db_end_line()
{
	if (db_output_position >= db_max_width)
	    db_printf("\n");
}