1 | /* $NetBSD: db_output.c,v 1.33 2012/09/01 01:13:51 matt 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 | #ifdef _KERNEL_OPT |
34 | #include "opt_ddbparam.h" |
35 | #endif |
36 | |
37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: db_output.c,v 1.33 2012/09/01 01:13:51 matt Exp $" ); |
39 | |
40 | #include <sys/param.h> |
41 | #include <sys/systm.h> |
42 | #include <sys/stdarg.h> |
43 | |
44 | #include <dev/cons.h> |
45 | |
46 | #include <ddb/ddb.h> |
47 | |
48 | /* |
49 | * Character output - tracks position in line. |
50 | * To do this correctly, we should know how wide |
51 | * the output device is - then we could zero |
52 | * the line position when the output device wraps |
53 | * around to the start of the next line. |
54 | * |
55 | * Instead, we count the number of spaces printed |
56 | * since the last printing character so that we |
57 | * don't print trailing spaces. This avoids most |
58 | * of the wraparounds. |
59 | */ |
60 | |
61 | #ifndef DB_MAX_LINE |
62 | #define DB_MAX_LINE 24 /* maximum line */ |
63 | #endif /* DB_MAX_LINE */ |
64 | #ifndef DB_MAX_WIDTH |
65 | #define DB_MAX_WIDTH 80 /* maximum width */ |
66 | #endif /* DB_MAX_WIDTH */ |
67 | |
68 | #define DB_MIN_MAX_WIDTH 20 /* minimum max width */ |
69 | #define DB_MIN_MAX_LINE 3 /* minimum max line */ |
70 | #define CTRL(c) ((c) & 0xff) |
71 | |
72 | int db_output_line = 0; /* output line number */ |
73 | int db_tab_stop_width = 8; /* how wide are tab stops? */ |
74 | int db_max_line = DB_MAX_LINE; /* output max lines */ |
75 | int db_max_width = DB_MAX_WIDTH; /* output line width */ |
76 | |
77 | static int db_output_position = 0; /* output column */ |
78 | static int db_last_non_space = 0; /* last non-space character */ |
79 | |
80 | static void db_more(void); |
81 | |
82 | /* |
83 | * Force pending whitespace. |
84 | */ |
85 | void |
86 | db_force_whitespace(void) |
87 | { |
88 | int last_print, next_tab; |
89 | |
90 | last_print = db_last_non_space; |
91 | while (last_print < db_output_position) { |
92 | next_tab = DB_NEXT_TAB(last_print); |
93 | if (next_tab <= db_output_position) { |
94 | while (last_print < next_tab) { /* DON'T send a tab!! */ |
95 | cnputc(' '); |
96 | last_print++; |
97 | } |
98 | } else { |
99 | cnputc(' '); |
100 | last_print++; |
101 | } |
102 | } |
103 | db_last_non_space = db_output_position; |
104 | } |
105 | |
106 | static void |
107 | db_more(void) |
108 | { |
109 | const char *p; |
110 | int quit_output = 0; |
111 | |
112 | for (p = "--db_more--" ; *p; p++) |
113 | cnputc(*p); |
114 | switch(cngetc()) { |
115 | case ' ': |
116 | db_output_line = 0; |
117 | break; |
118 | case 'q': |
119 | case CTRL('c'): |
120 | db_output_line = 0; |
121 | quit_output = 1; |
122 | break; |
123 | default: |
124 | db_output_line--; |
125 | break; |
126 | } |
127 | p = "\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b" ; |
128 | while (*p) |
129 | cnputc(*p++); |
130 | if (quit_output) { |
131 | db_error(0); |
132 | /* NOTREACHED */ |
133 | } |
134 | } |
135 | |
136 | /* |
137 | * Output character. Buffer whitespace. |
138 | */ |
139 | void |
140 | db_putchar(int c) |
141 | { |
142 | if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1) |
143 | db_more(); |
144 | if (c > ' ' && c <= '~') { |
145 | /* |
146 | * Printing character. |
147 | * If we have spaces to print, print them first. |
148 | * Use tabs if possible. |
149 | */ |
150 | db_force_whitespace(); |
151 | cnputc(c); |
152 | db_output_position++; |
153 | if (db_max_width >= DB_MIN_MAX_WIDTH |
154 | && db_output_position >= db_max_width) { |
155 | /* auto new line */ |
156 | cnputc('\n'); |
157 | db_output_position = 0; |
158 | db_last_non_space = 0; |
159 | db_output_line++; |
160 | } |
161 | db_last_non_space = db_output_position; |
162 | } else if (c == '\n') { |
163 | /* Return */ |
164 | cnputc(c); |
165 | db_output_position = 0; |
166 | db_last_non_space = 0; |
167 | db_output_line++; |
168 | db_check_interrupt(); |
169 | } else if (c == '\t') { |
170 | /* assume tabs every 8 positions */ |
171 | db_output_position = DB_NEXT_TAB(db_output_position); |
172 | } else if (c == ' ') { |
173 | /* space */ |
174 | db_output_position++; |
175 | } else if (c == '\007') { |
176 | /* bell */ |
177 | cnputc(c); |
178 | } |
179 | /* other characters are assumed non-printing */ |
180 | } |
181 | |
182 | /* |
183 | * Return output position |
184 | */ |
185 | int |
186 | db_print_position(void) |
187 | { |
188 | |
189 | return (db_output_position); |
190 | } |
191 | |
192 | /* |
193 | * End line if too long. |
194 | */ |
195 | void |
196 | db_end_line(void) |
197 | { |
198 | |
199 | if (db_output_position >= db_max_width) |
200 | db_printf("\n" ); |
201 | } |
202 | |
203 | /* |
204 | * Replacement for old '%r' kprintf format. |
205 | */ |
206 | void |
207 | db_format_radix(char *buf, size_t bufsiz, quad_t val, int altflag) |
208 | { |
209 | const char *fmt; |
210 | |
211 | if (db_radix == 16) { |
212 | db_format_hex(buf, bufsiz, val, altflag); |
213 | return; |
214 | } |
215 | |
216 | if (db_radix == 8) |
217 | fmt = altflag ? "-%#qo" : "-%qo" ; |
218 | else |
219 | fmt = altflag ? "-%#qu" : "-%qu" ; |
220 | |
221 | if (val < 0) |
222 | val = -val; |
223 | else |
224 | ++fmt; |
225 | |
226 | snprintf(buf, bufsiz, fmt, val); |
227 | } |
228 | |
229 | /* |
230 | * Replacement for old '%z' kprintf format. |
231 | */ |
232 | void |
233 | db_format_hex(char *buf, size_t bufsiz, quad_t val, int altflag) |
234 | { |
235 | /* Only use alternate form if val is nonzero. */ |
236 | const char *fmt = (altflag && val) ? "-%#qx" : "-%qx" ; |
237 | |
238 | if (val < 0) |
239 | val = -val; |
240 | else |
241 | ++fmt; |
242 | |
243 | snprintf(buf, bufsiz, fmt, val); |
244 | } |
245 | |