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