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 | } |
---|