1/*	$NetBSD: db_output.c,v 1.30 2009/03/07 22:02:17 ad Exp $	*/
2
3/*
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
6 * All Rights Reserved.
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
13 *
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21 *  School of Computer Science
22 *  Carnegie Mellon University
23 *  Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
27 */
28
29/*
30 * Printf and character output for debugger.
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: db_output.c,v 1.30 2009/03/07 22:02:17 ad Exp $");
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/stdarg.h>
39
40#include <dev/cons.h>
41
42#include <ddb/ddb.h>
43
44/*
45 *	Character output - tracks position in line.
46 *	To do this correctly, we should know how wide
47 *	the output device is - then we could zero
48 *	the line position when the output device wraps
49 *	around to the start of the next line.
50 *
51 *	Instead, we count the number of spaces printed
52 *	since the last printing character so that we
53 *	don't print trailing spaces.  This avoids most
54 *	of the wraparounds.
55 */
56
57#ifndef	DB_MAX_LINE
58#define	DB_MAX_LINE		24	/* maximum line */
59#endif	/* DB_MAX_LINE */
60#ifndef	DB_MAX_WIDTH
61#define DB_MAX_WIDTH		80	/* maximum width */
62#endif	/* DB_MAX_WIDTH */
63
64#define DB_MIN_MAX_WIDTH	20	/* minimum max width */
65#define DB_MIN_MAX_LINE		3	/* minimum max line */
66#define CTRL(c)			((c) & 0xff)
67
68int	db_output_line = 0;			/* output line number */
69int	db_tab_stop_width = 8;			/* how wide are tab stops? */
70int	db_max_line = DB_MAX_LINE;		/* output max lines */
71int	db_max_width = DB_MAX_WIDTH;		/* output line width */
72
73static int	db_output_position = 0;		/* output column */
74static int	db_last_non_space = 0;		/* last non-space character */
75
76static void db_more(void);
77
78/*
79 * Force pending whitespace.
80 */
81void
82db_force_whitespace(void)
83{
84	int last_print, next_tab;
85
86	last_print = db_last_non_space;
87	while (last_print < db_output_position) {
88		next_tab = DB_NEXT_TAB(last_print);
89		if (next_tab <= db_output_position) {
90			while (last_print < next_tab) { /* DON'T send a tab!! */
91				cnputc(' ');
92				last_print++;
93			}
94		} else {
95			cnputc(' ');
96			last_print++;
97		}
98	}
99	db_last_non_space = db_output_position;
100}
101
102static void
103db_more(void)
104{
105	const char *p;
106	int quit_output = 0;
107
108	for (p = "--db_more--"; *p; p++)
109		cnputc(*p);
110	switch(cngetc()) {
111	case ' ':
112		db_output_line = 0;
113		break;
114	case 'q':
115	case CTRL('c'):
116		db_output_line = 0;
117		quit_output = 1;
118		break;
119	default:
120		db_output_line--;
121		break;
122	}
123	p = "\b\b\b\b\b\b\b\b\b\b\b           \b\b\b\b\b\b\b\b\b\b\b";
124	while (*p)
125		cnputc(*p++);
126	if (quit_output) {
127		db_error(0);
128		/* NOTREACHED */
129	}
130}
131
132/*
133 * Output character.  Buffer whitespace.
134 */
135void
136db_putchar(int c)
137{
138	if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
139		db_more();
140	if (c > ' ' && c <= '~') {
141		/*
142		 * Printing character.
143		 * If we have spaces to print, print them first.
144		 * Use tabs if possible.
145		 */
146		db_force_whitespace();
147		cnputc(c);
148		db_output_position++;
149		if (db_max_width >= DB_MIN_MAX_WIDTH
150		    && db_output_position >= db_max_width) {
151			/* auto new line */
152			cnputc('\n');
153			db_output_position = 0;
154			db_last_non_space = 0;
155			db_output_line++;
156		}
157		db_last_non_space = db_output_position;
158	} else if (c == '\n') {
159		/* Return */
160		cnputc(c);
161		db_output_position = 0;
162		db_last_non_space = 0;
163		db_output_line++;
164		db_check_interrupt();
165	} else if (c == '\t') {
166		/* assume tabs every 8 positions */
167		db_output_position = DB_NEXT_TAB(db_output_position);
168	} else if (c == ' ') {
169		/* space */
170		db_output_position++;
171	} else if (c == '\007') {
172		/* bell */
173		cnputc(c);
174	}
175	/* other characters are assumed non-printing */
176}
177
178/*
179 * Return output position
180 */
181int
182db_print_position(void)
183{
184
185	return (db_output_position);
186}
187
188/*
189 * End line if too long.
190 */
191void
192db_end_line(void)
193{
194
195	if (db_output_position >= db_max_width)
196		db_printf("\n");
197}
198
199/*
200 * Replacement for old '%r' kprintf format.
201 */
202void
203db_format_radix(char *buf, size_t bufsiz, quad_t val, int altflag)
204{
205	const char *fmt;
206
207	if (db_radix == 16) {
208		db_format_hex(buf, bufsiz, val, altflag);
209		return;
210	}
211
212	if (db_radix == 8)
213		fmt = altflag ? "-%#qo" : "-%qo";
214	else
215		fmt = altflag ? "-%#qu" : "-%qu";
216
217	if (val < 0)
218		val = -val;
219	else
220		++fmt;
221
222	snprintf(buf, bufsiz, fmt, val);
223}
224
225/*
226 * Replacement for old '%z' kprintf format.
227 */
228void
229db_format_hex(char *buf, size_t bufsiz, quad_t val, int altflag)
230{
231	/* Only use alternate form if val is nonzero. */
232	const char *fmt = (altflag && val) ? "-%#qx" : "-%qx";
233
234	if (val < 0)
235		val = -val;
236	else
237		++fmt;
238
239	snprintf(buf, bufsiz, fmt, val);
240}
241