/*- * 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 __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include struct dbputchar_arg { size_t da_nbufr; size_t da_remain; char *da_pbufr; char *da_pnext; }; /* * 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 */ db_expr_t db_lines_per_page = 20; /* lines per page */ volatile int db_pager_quit; /* user requested quit */ static int db_newlines; /* # lines this page */ static int db_maxlines; /* max lines/page when paging */ 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_putc(int c); static void db_puts(const char *str); static void db_putchar(int c, void *arg); static void db_pager(void); /* * Force pending whitespace. */ void db_force_whitespace(void) { 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(' '); db_capture_writech(' '); last_print++; } } else { cnputc(' '); db_capture_writech(' '); last_print++; } } db_last_non_space = db_output_position; } /* * Output character. Buffer whitespace. */ static void db_putchar(int c, void *arg) { struct dbputchar_arg *dap = arg; if (dap->da_pbufr == NULL) { /* No bufferized output is provided. */ db_putc(c); } else { *dap->da_pnext++ = c; dap->da_remain--; /* Leave always the buffer 0 terminated. */ *dap->da_pnext = '\0'; /* Check if the buffer needs to be flushed. */ if (dap->da_remain < 2 || c == '\n') { db_puts(dap->da_pbufr); dap->da_pnext = dap->da_pbufr; dap->da_remain = dap->da_nbufr; *dap->da_pnext = '\0'; } } } static void db_putc(int c) { /* * 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_newlines++; if (db_newlines >= db_maxlines) db_pager(); } 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_capture_writech(c); db_output_position++; db_last_non_space = db_output_position; } else if (c == '\n') { /* Newline */ cnputc(c); db_capture_writech(c); db_output_position = 0; db_last_non_space = 0; db_check_interrupt(); if (db_maxlines > 0) { db_newlines++; if (db_newlines >= db_maxlines) db_pager(); } } else if (c == '\r') { /* Return */ cnputc(c); db_capture_writech(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); /* No need to beep in a log: db_capture_writech(c); */ } /* other characters are assumed non-printing */ } static void db_puts(const char *str) { int i; for (i = 0; str[i] != '\0'; i++) db_putc(str[i]); } /* * Turn on the pager. */ void db_enable_pager(void) { if (db_maxlines == 0) { db_maxlines = db_lines_per_page; db_newlines = 0; db_pager_quit = 0; } } /* * Turn off the pager. */ void db_disable_pager(void) { db_maxlines = 0; } /* * A simple paging callout function. It supports several simple more(1)-like * commands as well as a quit command that sets db_pager_quit which db * commands can poll to see if they should terminate early. */ void db_pager(void) { int c, done; db_capture_enterpager(); db_printf("--More--\r"); done = 0; while (!done) { c = cngetc(); switch (c) { case 'e': case 'j': case '\n': /* Just one more line. */ db_maxlines = 1; done++; break; case 'd': /* Half a page. */ db_maxlines = db_lines_per_page / 2; done++; break; case 'f': case ' ': /* Another page. */ db_maxlines = db_lines_per_page; done++; break; case 'q': case 'Q': case 'x': case 'X': /* Quit */ db_maxlines = 0; db_pager_quit = 1; done++; break; #if 0 /* FALLTHROUGH */ default: cnputc('\007'); #endif } } db_printf(" "); db_force_whitespace(); db_printf("\r"); db_newlines = 0; db_capture_exitpager(); } /* * Return output position */ int db_print_position(void) { return (db_output_position); } /* * Printing */ int db_printf(const char *fmt, ...) { #ifdef DDB_BUFR_SIZE char bufr[DDB_BUFR_SIZE]; #endif struct dbputchar_arg dca; va_list listp; int retval; #ifdef DDB_BUFR_SIZE dca.da_pbufr = bufr; dca.da_pnext = dca.da_pbufr; dca.da_nbufr = sizeof(bufr); dca.da_remain = sizeof(bufr); *dca.da_pnext = '\0'; #else dca.da_pbufr = NULL; #endif va_start(listp, fmt); retval = kvprintf (fmt, db_putchar, &dca, db_radix, listp); va_end(listp); #ifdef DDB_BUFR_SIZE if (*dca.da_pbufr != '\0') db_puts(dca.da_pbufr); #endif return (retval); } int db_indent; void db_iprintf(const char *fmt,...) { #ifdef DDB_BUFR_SIZE char bufr[DDB_BUFR_SIZE]; #endif struct dbputchar_arg dca; register int i; va_list listp; for (i = db_indent; i >= 8; i -= 8) db_printf("\t"); while (--i >= 0) db_printf(" "); #ifdef DDB_BUFR_SIZE dca.da_pbufr = bufr; dca.da_pnext = dca.da_pbufr; dca.da_nbufr = sizeof(bufr); dca.da_remain = sizeof(bufr); *dca.da_pnext = '\0'; #else dca.da_pbufr = NULL; #endif va_start(listp, fmt); kvprintf (fmt, db_putchar, &dca, db_radix, listp); va_end(listp); #ifdef DDB_BUFR_SIZE if (*dca.da_pbufr != '\0') db_puts(dca.da_pbufr); #endif } /* * End line if too long. */ void db_end_line(int field_width) { if (db_output_position + field_width > db_max_width) db_printf("\n"); }