1 /* 2 * Copyright (C) 1996-2005 Paul Mackerras. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 */ 9 #include <linux/string.h> 10 #include <asm/udbg.h> 11 #include <asm/time.h> 12 #include "nonstdio.h" 13 14 static bool paginating, paginate_skipping; 15 static unsigned long paginate_lpp; /* Lines Per Page */ 16 static unsigned long paginate_pos; 17 18 void xmon_start_pagination(void) 19 { 20 paginating = true; 21 paginate_skipping = false; 22 paginate_pos = 0; 23 } 24 25 void xmon_end_pagination(void) 26 { 27 paginating = false; 28 } 29 30 void xmon_set_pagination_lpp(unsigned long lpp) 31 { 32 paginate_lpp = lpp; 33 } 34 35 static int xmon_readchar(void) 36 { 37 if (udbg_getc) 38 return udbg_getc(); 39 return -1; 40 } 41 42 static int xmon_write(const char *ptr, int nb) 43 { 44 int rv = 0; 45 const char *p = ptr, *q; 46 const char msg[] = "[Hit a key (a:all, q:truncate, any:next page)]"; 47 48 if (nb <= 0) 49 return rv; 50 51 if (paginating && paginate_skipping) 52 return nb; 53 54 if (paginate_lpp) { 55 while (paginating && (q = strchr(p, '\n'))) { 56 rv += udbg_write(p, q - p + 1); 57 p = q + 1; 58 paginate_pos++; 59 60 if (paginate_pos >= paginate_lpp) { 61 udbg_write(msg, strlen(msg)); 62 63 switch (xmon_readchar()) { 64 case 'a': 65 paginating = false; 66 break; 67 case 'q': 68 paginate_skipping = true; 69 break; 70 default: 71 /* nothing */ 72 break; 73 } 74 75 paginate_pos = 0; 76 udbg_write("\r\n", 2); 77 78 if (paginate_skipping) 79 return nb; 80 } 81 } 82 } 83 84 return rv + udbg_write(p, nb - (p - ptr)); 85 } 86 87 int xmon_putchar(int c) 88 { 89 char ch = c; 90 91 if (c == '\n') 92 xmon_putchar('\r'); 93 return xmon_write(&ch, 1) == 1? c: -1; 94 } 95 96 static char line[256]; 97 static char *lineptr; 98 static int lineleft; 99 100 static int xmon_getchar(void) 101 { 102 int c; 103 104 if (lineleft == 0) { 105 lineptr = line; 106 for (;;) { 107 c = xmon_readchar(); 108 if (c == -1 || c == 4) 109 break; 110 if (c == '\r' || c == '\n') { 111 *lineptr++ = '\n'; 112 xmon_putchar('\n'); 113 break; 114 } 115 switch (c) { 116 case 0177: 117 case '\b': 118 if (lineptr > line) { 119 xmon_putchar('\b'); 120 xmon_putchar(' '); 121 xmon_putchar('\b'); 122 --lineptr; 123 } 124 break; 125 case 'U' & 0x1F: 126 while (lineptr > line) { 127 xmon_putchar('\b'); 128 xmon_putchar(' '); 129 xmon_putchar('\b'); 130 --lineptr; 131 } 132 break; 133 default: 134 if (lineptr >= &line[sizeof(line) - 1]) 135 xmon_putchar('\a'); 136 else { 137 xmon_putchar(c); 138 *lineptr++ = c; 139 } 140 } 141 } 142 lineleft = lineptr - line; 143 lineptr = line; 144 } 145 if (lineleft == 0) 146 return -1; 147 --lineleft; 148 return *lineptr++; 149 } 150 151 char *xmon_gets(char *str, int nb) 152 { 153 char *p; 154 int c; 155 156 for (p = str; p < str + nb - 1; ) { 157 c = xmon_getchar(); 158 if (c == -1) { 159 if (p == str) 160 return NULL; 161 break; 162 } 163 *p++ = c; 164 if (c == '\n') 165 break; 166 } 167 *p = 0; 168 return str; 169 } 170 171 void xmon_printf(const char *format, ...) 172 { 173 va_list args; 174 static char xmon_outbuf[1024]; 175 int rc, n; 176 177 va_start(args, format); 178 n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args); 179 va_end(args); 180 181 rc = xmon_write(xmon_outbuf, n); 182 183 if (n && rc == 0) { 184 /* No udbg hooks, fallback to printk() - dangerous */ 185 printk("%s", xmon_outbuf); 186 } 187 } 188 189 void xmon_puts(const char *str) 190 { 191 xmon_write(str, strlen(str)); 192 } 193