xref: /freebsd/sys/ddb/db_output.c (revision d37ea99837e6ad50837fd9fe1771ddf1c3ba6002)
1 /*
2  * Mach Operating System
3  * Copyright (c) 1991,1990 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie the
24  * rights to redistribute these changes.
25  */
26 /*
27  * 	Author: David B. Golub, Carnegie Mellon University
28  *	Date:	7/90
29  */
30 
31 /*
32  * Printf and character output for debugger.
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/cons.h>
41 #include <sys/kernel.h>
42 #include <sys/sysctl.h>
43 
44 #include <machine/stdarg.h>
45 
46 #include <ddb/ddb.h>
47 #include <ddb/db_output.h>
48 
49 /*
50  *	Character output - tracks position in line.
51  *	To do this correctly, we should know how wide
52  *	the output device is - then we could zero
53  *	the line position when the output device wraps
54  *	around to the start of the next line.
55  *
56  *	Instead, we count the number of spaces printed
57  *	since the last printing character so that we
58  *	don't print trailing spaces.  This avoids most
59  *	of the wraparounds.
60  */
61 static int	db_output_position = 0;		/* output column */
62 static int	db_last_non_space = 0;		/* last non-space character */
63 db_expr_t	db_tab_stop_width = 8;		/* how wide are tab stops? */
64 #define	NEXT_TAB(i) \
65 	((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
66 db_expr_t	db_max_width = 79;		/* output line width */
67 static int	db_newlines;			/* # lines this page */
68 static int	db_maxlines = -1;		/* max lines per page */
69 static db_page_calloutfcn_t *db_page_callout = NULL;
70 static void	*db_page_callout_arg = NULL;
71 static int	ddb_use_printf = 0;
72 SYSCTL_INT(_debug, OID_AUTO, ddb_use_printf, CTLFLAG_RW, &ddb_use_printf, 0,
73     "use printf for all ddb output");
74 
75 static void	db_putchar(int c, void *arg);
76 
77 /*
78  * Force pending whitespace.
79  */
80 void
81 db_force_whitespace()
82 {
83 	register int last_print, next_tab;
84 
85 	last_print = db_last_non_space;
86 	while (last_print < db_output_position) {
87 	    next_tab = NEXT_TAB(last_print);
88 	    if (next_tab <= db_output_position) {
89 		while (last_print < next_tab) { /* DON'T send a tab!!! */
90 			cnputc(' ');
91 			last_print++;
92 		}
93 	    }
94 	    else {
95 		cnputc(' ');
96 		last_print++;
97 	    }
98 	}
99 	db_last_non_space = db_output_position;
100 }
101 
102 /*
103  * Output character.  Buffer whitespace.
104  */
105 static void
106 db_putchar(c, arg)
107 	int	c;		/* character to output */
108 	void *	arg;
109 {
110 
111 	/*
112 	 * If not in the debugger or the user requests it, output data to
113 	 * both the console and the message buffer.
114 	 */
115 	if (!db_active || ddb_use_printf) {
116 		printf("%c", c);
117 		if (!db_active)
118 			return;
119 		if (c == '\r' || c == '\n')
120 			db_check_interrupt();
121 		if (c == '\n' && db_maxlines > 0 && db_page_callout != NULL) {
122 			db_newlines++;
123 			if (db_newlines >= db_maxlines) {
124 				db_maxlines = -1;
125 				db_page_callout(db_page_callout_arg);
126 			}
127 		}
128 		return;
129 	}
130 
131 	/* Otherwise, output data directly to the console. */
132 	if (c > ' ' && c <= '~') {
133 	    /*
134 	     * Printing character.
135 	     * If we have spaces to print, print them first.
136 	     * Use tabs if possible.
137 	     */
138 	    db_force_whitespace();
139 	    cnputc(c);
140 	    db_output_position++;
141 	    db_last_non_space = db_output_position;
142 	}
143 	else if (c == '\n') {
144 	    /* Newline */
145 	    cnputc(c);
146 	    db_output_position = 0;
147 	    db_last_non_space = 0;
148 	    db_check_interrupt();
149 	    if (db_maxlines > 0 && db_page_callout != NULL) {
150 		    db_newlines++;
151 		    if (db_newlines >= db_maxlines) {
152 			    db_maxlines = -1;
153 			    db_page_callout(db_page_callout_arg);
154 		    }
155 	    }
156 	}
157 	else if (c == '\r') {
158 	    /* Return */
159 	    cnputc(c);
160 	    db_output_position = 0;
161 	    db_last_non_space = 0;
162 	    db_check_interrupt();
163 	}
164 	else if (c == '\t') {
165 	    /* assume tabs every 8 positions */
166 	    db_output_position = NEXT_TAB(db_output_position);
167 	}
168 	else if (c == ' ') {
169 	    /* space */
170 	    db_output_position++;
171 	}
172 	else if (c == '\007') {
173 	    /* bell */
174 	    cnputc(c);
175 	}
176 	/* other characters are assumed non-printing */
177 }
178 
179 /*
180  * Register callout for providing a pager for output.
181  */
182 void
183 db_setup_paging(db_page_calloutfcn_t *callout, void *arg, int maxlines)
184 {
185 
186 	db_page_callout = callout;
187 	db_page_callout_arg = arg;
188 	db_maxlines = maxlines;
189 	db_newlines = 0;
190 }
191 
192 /*
193  * A simple paging callout function.  If the argument is not null, it
194  * points to an integer that will be set to 1 if the user asks to quit.
195  */
196 void
197 db_simple_pager(void *arg)
198 {
199 	int c;
200 
201 	db_printf("--More--\r");
202 	for (;;) {
203 		c = cngetc();
204 		switch (c) {
205 		case '\n':
206 			/* Just one more line. */
207 			db_setup_paging(db_simple_pager, arg, 1);
208 			return;
209 		case ' ':
210 			/* Another page. */
211 			db_setup_paging(db_simple_pager, arg,
212 			    DB_LINES_PER_PAGE);
213 			return;
214 		case 'q':
215 		case 'Q':
216 		case 'x':
217 		case 'X':
218 			/* Quit */
219 			if (arg != NULL) {
220 				*(int *)arg = 1;
221 				db_printf("\n");
222 				return;
223 			}
224 #if 0
225 			/* FALLTHROUGH */
226 		default:
227 			cnputc('\007');
228 #endif
229 		}
230 	}
231 }
232 
233 /*
234  * Return output position
235  */
236 int
237 db_print_position()
238 {
239 	return (db_output_position);
240 }
241 
242 /*
243  * Printing
244  */
245 void
246 #if __STDC__
247 db_printf(const char *fmt, ...)
248 #else
249 db_printf(fmt)
250 	const char *fmt;
251 #endif
252 {
253 	va_list	listp;
254 
255 	va_start(listp, fmt);
256 	kvprintf (fmt, db_putchar, NULL, db_radix, listp);
257 	va_end(listp);
258 }
259 
260 int db_indent;
261 
262 void
263 #if __STDC__
264 db_iprintf(const char *fmt,...)
265 #else
266 db_iprintf(fmt)
267 	const char *fmt;
268 #endif
269 {
270 	register int i;
271 	va_list listp;
272 
273 	for (i = db_indent; i >= 8; i -= 8)
274 		db_printf("\t");
275 	while (--i >= 0)
276 		db_printf(" ");
277 	va_start(listp, fmt);
278 	kvprintf (fmt, db_putchar, NULL, db_radix, listp);
279 	va_end(listp);
280 }
281 
282 /*
283  * End line if too long.
284  */
285 void
286 db_end_line()
287 {
288 	if (db_output_position >= db_max_width)
289 	    db_printf("\n");
290 }
291