1/*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
49 *  School of Computer Science
50 *  Carnegie Mellon University
51 *  Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58/*
59 * 	Author: David B. Golub, Carnegie Mellon University
60 *	Date:	7/90
61 */
62
63/*
64 * Printf and character output for debugger.
65 */
66
67#include <mach/boolean.h>
68#include <kern/misc_protos.h>
69#include <stdarg.h>
70#include <machine/db_machdep.h>
71#include <ddb/db_command.h>
72#include <ddb/db_lex.h>
73#include <ddb/db_input.h>
74#include <ddb/db_output.h>
75#include <ddb/db_task_thread.h>
76
77/*
78 *	Character output - tracks position in line.
79 *	To do this correctly, we should know how wide
80 *	the output device is - then we could zero
81 *	the line position when the output device wraps
82 *	around to the start of the next line.
83 *
84 *	Instead, we count the number of spaces printed
85 *	since the last printing character so that we
86 *	don't print trailing spaces.  This avoids most
87 *	of the wraparounds.
88 */
89
90#ifndef	DB_MAX_LINE
91#define	DB_MAX_LINE		43	/* maximum line */
92#define DB_MAX_WIDTH		132	/* maximum width */
93#endif	/* DB_MAX_LINE */
94
95#define DB_MIN_MAX_WIDTH	20	/* minimum max width */
96#define DB_MIN_MAX_LINE		3	/* minimum max line */
97#define CTRL(c)			((c) & 0xff)
98
99int	db_output_position = 0;		/* output column */
100int	db_output_line = 0;		/* output line number */
101int	db_last_non_space = 0;		/* last non-space character */
102int	db_last_gen_return = 0;		/* last character generated return */
103int	db_auto_wrap = 1;		/* auto wrap at end of line ? */
104int	db_tab_stop_width = 8;		/* how wide are tab stops? */
105#define	NEXT_TAB(i) \
106	((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
107int	db_max_line = DB_MAX_LINE;	/* output max lines */
108int	db_max_width = DB_MAX_WIDTH;	/* output line width */
109
110
111/* Prototypes for functions local to this file.  XXX -- should be static!
112 */
113static void db_more(void);
114void db_advance_output_position(int new_output_position,
115				int blank);
116
117
118/*
119 * Force pending whitespace.
120 */
121void
122db_force_whitespace(void)
123{
124	register int last_print, next_tab;
125
126	last_print = db_last_non_space;
127	while (last_print < db_output_position) {
128	    next_tab = NEXT_TAB(last_print);
129	    if (next_tab <= db_output_position) {
130		cnputc('\t');
131		last_print = next_tab;
132	    }
133	    else {
134		cnputc(' ');
135		last_print++;
136	    }
137	}
138	db_last_non_space = db_output_position;
139}
140
141void
142db_reset_more()
143{
144	db_output_line = 0;
145}
146
147static void
148db_more(void)
149{
150	const char *p;
151	boolean_t quit_output = FALSE;
152
153	for (p = "--db_more--"; *p; p++)
154	    cnputc(*p);
155	switch(cngetc()) {
156	case ' ':
157	    db_output_line = 0;
158	    break;
159	case 'q':
160	case CTRL('c'):
161	    db_output_line = 0;
162	    quit_output = TRUE;
163	    break;
164	default:
165	    db_output_line--;
166	    break;
167	}
168	p = "\b\b\b\b\b\b\b\b\b\b\b           \b\b\b\b\b\b\b\b\b\b\b";
169	while (*p)
170	    cnputc(*p++);
171	if (quit_output) {
172	    db_error((char *) 0);
173	    /* NOTREACHED */
174	}
175}
176
177void
178db_advance_output_position(int new_output_position,
179			   int blank)
180{
181	if (db_max_width >= DB_MIN_MAX_WIDTH
182	    && new_output_position >= db_max_width) {
183		/* auto new line */
184		if (!db_auto_wrap || blank)
185		    cnputc('\n');
186		db_output_position = 0;
187		db_last_non_space = 0;
188		db_last_gen_return = 1;
189		db_output_line++;
190	} else {
191		db_output_position = new_output_position;
192	}
193}
194
195boolean_t
196db_reserve_output_position(int increment)
197{
198	if (db_max_width >= DB_MIN_MAX_WIDTH
199	    && db_output_position + increment >= db_max_width) {
200		/* auto new line */
201		if (!db_auto_wrap || db_last_non_space != db_output_position)
202		    cnputc('\n');
203		db_output_position = 0;
204		db_last_non_space = 0;
205		db_last_gen_return = 1;
206		db_output_line++;
207		return TRUE;
208	}
209	return FALSE;
210}
211
212/*
213 * Output character.  Buffer whitespace.
214 */
215void
216db_putchar(char c)
217{
218	if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1)
219	    db_more();
220	if (c > ' ' && c <= '~') {
221	    /*
222	     * Printing character.
223	     * If we have spaces to print, print them first.
224	     * Use tabs if possible.
225	     */
226	    db_force_whitespace();
227	    cnputc(c);
228	    db_last_gen_return = 0;
229	    db_advance_output_position(db_output_position+1, 0);
230	    db_last_non_space = db_output_position;
231	}
232	else if (c == '\n') {
233	    /* Return */
234	    if (db_last_gen_return) {
235		db_last_gen_return = 0;
236	    } else {
237		cnputc(c);
238		db_output_position = 0;
239		db_last_non_space = 0;
240		db_output_line++;
241		db_check_interrupt();
242	    }
243	}
244	else if (c == '\t') {
245	    /* assume tabs every 8 positions */
246	    db_advance_output_position(NEXT_TAB(db_output_position), 1);
247	}
248	else if (c == ' ') {
249	    /* space */
250	    db_advance_output_position(db_output_position+1, 1);
251	}
252	else if (c == '\007') {
253	    /* bell */
254	    cnputc(c);
255	}
256	/* other characters are assumed non-printing */
257}
258
259/*
260 * Return output position
261 */
262int
263db_print_position(void)
264{
265	return (db_output_position);
266}
267
268/*
269 * End line if too long.
270 */
271void
272db_end_line(void)
273{
274	if (db_output_position >= db_max_width-1) {
275	    /* auto new line */
276	    if (!db_auto_wrap)
277		cnputc('\n');
278	    db_output_position = 0;
279	    db_last_non_space = 0;
280	    db_last_gen_return = 1;
281	    db_output_line++;
282	}
283}
284
285/*
286 * Printing
287 */
288
289void
290db_printf(const char *fmt, ...)
291{
292	va_list	listp;
293
294	va_start(listp, fmt);
295	_doprnt(fmt, &listp, db_putchar, db_radix);
296	va_end(listp);
297}
298
299/* alternate name */
300
301void
302kdbprintf(const char *fmt, ...)
303{
304	va_list	listp;
305
306	va_start(listp, fmt);
307	_doprnt(fmt, &listp, db_putchar, db_radix);
308	va_end(listp);
309}
310
311int	db_indent = 0;
312
313/*
314 * Printing (to console) with indentation.
315 */
316void
317iprintf(const char *fmt, ...)
318{
319	va_list listp;
320	register int i;
321
322	for (i = db_indent; i > 0; ){
323	    if (i >= 8) {
324		kdbprintf("\t");
325		i -= 8;
326	    }
327	    else {
328		kdbprintf(" ");
329		i--;
330	    }
331	}
332
333	va_start(listp, fmt);
334	_doprnt(fmt, &listp, db_putchar, db_radix);
335	va_end(listp);
336}
337
338void
339db_output_prompt(void)
340{
341	db_printf("db%s", (db_default_act) ? "t": "");
342	db_printf("{%d}", cpu_number());
343	db_printf("> ");
344}
345
346