[444] | 1 | /* Debugging printf, for debugging the library itself. |
---|
| 2 | |
---|
| 3 | We don't assume stdio is working. |
---|
| 4 | We do assume _write_r is working. |
---|
| 5 | */ |
---|
| 6 | |
---|
| 7 | #include <_ansi.h> |
---|
| 8 | #include "ctype.h" |
---|
| 9 | #include "reent.h" |
---|
| 10 | #include "string.h" |
---|
| 11 | #include "unctrl.h" |
---|
| 12 | |
---|
| 13 | #ifdef __STDC__ |
---|
| 14 | #include "stdarg.h" |
---|
| 15 | #else |
---|
| 16 | #include "varargs.h" |
---|
| 17 | #endif |
---|
| 18 | |
---|
| 19 | #if 0 |
---|
| 20 | static char *parse_number (); |
---|
| 21 | #endif |
---|
| 22 | |
---|
| 23 | static long get_number (char *, long, int); |
---|
| 24 | static void print_number (int, int, long); |
---|
| 25 | static void write_char (char c); |
---|
| 26 | static void write_string (const char *s); |
---|
| 27 | |
---|
| 28 | /* Non-zero for big-endian systems. */ |
---|
| 29 | static int big_endian_p; |
---|
| 30 | |
---|
| 31 | /* For now hardcode 2 (stderr) as the console file descriptor. |
---|
| 32 | May wish to let the caller pass in a file descriptor or some such but |
---|
| 33 | this is only for debugging purposes anyway. */ |
---|
| 34 | #define CONSOLE_FD 2 |
---|
| 35 | |
---|
| 36 | /* Standalone printf routine. |
---|
| 37 | |
---|
| 38 | The format string has been enhanced so that multiple values can be dumped |
---|
| 39 | without having to have a %-field for each one (say if you want to dump |
---|
| 40 | 20 words at a certain address). A modifier of `N' says the next argument |
---|
| 41 | is a count, and the one after that is a pointer. |
---|
| 42 | |
---|
| 43 | Example: __dprintf ("%Nx\n", 20, p); /-* print 20 ints at `p' *-/ |
---|
| 44 | |
---|
| 45 | Supported formats are: c d u x s p. |
---|
| 46 | |
---|
| 47 | All ints are retrieved a byte at a time so alignment issues are not |
---|
| 48 | a problem. |
---|
| 49 | |
---|
| 50 | This routine is used in situations where the only debugging capability |
---|
| 51 | is console output and was written to aid debugging newlib itself. We don't |
---|
| 52 | use printf ourselves as we may be debugging it. We do assume _write_r is |
---|
| 53 | working. |
---|
| 54 | */ |
---|
| 55 | |
---|
| 56 | void |
---|
| 57 | #ifdef __STDC__ |
---|
| 58 | __dprintf (const char *fmt, ...) |
---|
| 59 | #else |
---|
| 60 | __dprintf (fmt, va_alist) |
---|
| 61 | char *fmt; |
---|
| 62 | va_dcl |
---|
| 63 | #endif |
---|
| 64 | { |
---|
| 65 | va_list args; |
---|
| 66 | |
---|
| 67 | /* Which endian are we? */ |
---|
| 68 | { |
---|
| 69 | short tmp = 1; |
---|
| 70 | big_endian_p = *(char *) &tmp == 0; |
---|
| 71 | } |
---|
| 72 | |
---|
| 73 | #ifdef __STDC__ |
---|
| 74 | va_start (args, fmt); |
---|
| 75 | #else |
---|
| 76 | va_start (args); |
---|
| 77 | #endif |
---|
| 78 | |
---|
| 79 | while (*fmt) |
---|
| 80 | { |
---|
| 81 | char c, *p; |
---|
| 82 | int count; |
---|
| 83 | long l; |
---|
| 84 | |
---|
| 85 | if (*fmt != '%' || *++fmt == '%') |
---|
| 86 | { |
---|
| 87 | write_char (*fmt++); |
---|
| 88 | continue; |
---|
| 89 | } |
---|
| 90 | |
---|
| 91 | if (*fmt == 'N') |
---|
| 92 | { |
---|
| 93 | count = va_arg (args, int); |
---|
| 94 | p = va_arg (args, char *); |
---|
| 95 | ++fmt; |
---|
| 96 | c = *fmt++; |
---|
| 97 | |
---|
| 98 | while (--count >= 0) |
---|
| 99 | { |
---|
| 100 | switch (c) |
---|
| 101 | { |
---|
| 102 | case 'c' : |
---|
| 103 | write_string (unctrl (*p++)); |
---|
| 104 | break; |
---|
| 105 | case 'p' : |
---|
| 106 | print_number (16, 1, get_number (p, sizeof (char *), 1)); |
---|
| 107 | p += sizeof (char *); |
---|
| 108 | break; |
---|
| 109 | case 'd' : |
---|
| 110 | case 'u' : |
---|
| 111 | case 'x' : |
---|
| 112 | print_number (c == 'x' ? 16 : 10, c != 'd', |
---|
| 113 | get_number (p, sizeof (int), c != 'd')); |
---|
| 114 | p += sizeof (int); |
---|
| 115 | break; |
---|
| 116 | case 's' : |
---|
| 117 | write_string (*(char **) p); |
---|
| 118 | p += sizeof (char *); |
---|
| 119 | break; |
---|
| 120 | } |
---|
| 121 | if (count > 0) |
---|
| 122 | write_char (' '); |
---|
| 123 | } |
---|
| 124 | } |
---|
| 125 | else |
---|
| 126 | { |
---|
| 127 | switch (c = *fmt++) |
---|
| 128 | { |
---|
| 129 | case 'c' : |
---|
| 130 | c = va_arg (args, int); |
---|
| 131 | write_string (unctrl (c)); |
---|
| 132 | break; |
---|
| 133 | case 'p' : |
---|
| 134 | l = (_POINTER_INT) va_arg (args, char *); |
---|
| 135 | print_number (16, 1, l); |
---|
| 136 | break; |
---|
| 137 | case 'd' : |
---|
| 138 | case 'u' : |
---|
| 139 | case 'x' : |
---|
| 140 | l = va_arg (args, int); |
---|
| 141 | print_number (c == 'x' ? 16 : 10, c != 'd', l); |
---|
| 142 | break; |
---|
| 143 | case 's' : |
---|
| 144 | p = va_arg (args, char *); |
---|
| 145 | write_string (p); |
---|
| 146 | break; |
---|
| 147 | } |
---|
| 148 | } |
---|
| 149 | } |
---|
| 150 | |
---|
| 151 | va_end (args); |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | #if 0 |
---|
| 155 | /* Parse a positive decimal integer at S. |
---|
| 156 | FIXME: Was used in earlier version, but not currently used. |
---|
| 157 | Keep for now. */ |
---|
| 158 | |
---|
| 159 | static char * |
---|
| 160 | parse_number (s, p) |
---|
| 161 | char *s; |
---|
| 162 | long *p; |
---|
| 163 | { |
---|
| 164 | long x = 0; |
---|
| 165 | |
---|
| 166 | while (isdigit (*s)) |
---|
| 167 | { |
---|
| 168 | x = (x * 10) + (*s - '0'); |
---|
| 169 | ++s; |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | *p = x; |
---|
| 173 | return s; |
---|
| 174 | } |
---|
| 175 | #endif |
---|
| 176 | |
---|
| 177 | /* Fetch the number at S of SIZE bytes. */ |
---|
| 178 | |
---|
| 179 | static long |
---|
| 180 | get_number (char *s, |
---|
| 181 | long size, |
---|
| 182 | int unsigned_p) |
---|
| 183 | { |
---|
| 184 | long x; |
---|
| 185 | unsigned char *p = (unsigned char *) s; |
---|
| 186 | |
---|
| 187 | switch (size) |
---|
| 188 | { |
---|
| 189 | case 1 : |
---|
| 190 | x = *p; |
---|
| 191 | if (!unsigned_p) |
---|
| 192 | x = (x ^ 0x80) - 0x80; |
---|
| 193 | return x; |
---|
| 194 | case 2 : |
---|
| 195 | if (big_endian_p) |
---|
| 196 | x = (p[0] << 8) | p[1]; |
---|
| 197 | else |
---|
| 198 | x = (p[1] << 8) | p[0]; |
---|
| 199 | if (!unsigned_p) |
---|
| 200 | x = (x ^ 0x8000) - 0x8000; |
---|
| 201 | return x; |
---|
| 202 | case 4 : |
---|
| 203 | if (big_endian_p) |
---|
| 204 | x = ((long)p[0] << 24) | ((long)p[1] << 16) | (p[2] << 8) | p[3]; |
---|
| 205 | else |
---|
| 206 | x = ((long)p[3] << 24) | ((long)p[2] << 16) | (p[1] << 8) | p[0]; |
---|
| 207 | if (!unsigned_p) |
---|
| 208 | x = (x ^ 0x80000000L) - 0x80000000L; |
---|
| 209 | return x; |
---|
| 210 | #if 0 /* FIXME: Is there a standard mechanism for knowing if |
---|
| 211 | long longs exist? */ |
---|
| 212 | case 8 : |
---|
| 213 | #endif |
---|
| 214 | default : |
---|
| 215 | return 0; |
---|
| 216 | } |
---|
| 217 | } |
---|
| 218 | |
---|
| 219 | /* Print X in base BASE. */ |
---|
| 220 | |
---|
| 221 | static void |
---|
| 222 | print_number (int base, |
---|
| 223 | int unsigned_p, |
---|
| 224 | long n) |
---|
| 225 | { |
---|
| 226 | static char chars[16] = "0123456789abcdef"; |
---|
| 227 | char *p, buf[32]; |
---|
| 228 | unsigned long x; |
---|
| 229 | |
---|
| 230 | if (!unsigned_p && n < 0) |
---|
| 231 | { |
---|
| 232 | write_char ('-'); |
---|
| 233 | x = -n; |
---|
| 234 | } |
---|
| 235 | else |
---|
| 236 | x = n; |
---|
| 237 | |
---|
| 238 | p = buf + sizeof (buf); |
---|
| 239 | *--p = '\0'; |
---|
| 240 | do |
---|
| 241 | { |
---|
| 242 | *--p = chars[x % base]; |
---|
| 243 | x /= base; |
---|
| 244 | } |
---|
| 245 | while (x != 0); |
---|
| 246 | |
---|
| 247 | write_string (p); |
---|
| 248 | } |
---|
| 249 | |
---|
| 250 | /* Write C to the console. |
---|
| 251 | We go through the file descriptor directly because we can't assume |
---|
| 252 | stdio is working. */ |
---|
| 253 | |
---|
| 254 | static void |
---|
| 255 | write_char (char c) |
---|
| 256 | { |
---|
| 257 | _write_r (_REENT, CONSOLE_FD, &c, 1); |
---|
| 258 | } |
---|
| 259 | |
---|
| 260 | /* Write S to the console. |
---|
| 261 | We go through the file descriptor directly because we can't assume |
---|
| 262 | stdio is working. */ |
---|
| 263 | |
---|
| 264 | static void |
---|
| 265 | write_string (const char *s) |
---|
| 266 | { |
---|
| 267 | _write_r (_REENT, CONSOLE_FD, s, strlen (s)); |
---|
| 268 | } |
---|