1 /*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29 /* Debugging printf, for debugging the library itself.
30
31 We don't assume stdio is working.
32 We do assume _write_r is working.
33 */
34
35 #include <_ansi.h>
36 #include <unistd.h>
37 #include "ctype.h"
38 #include "string.h"
39 #include "unctrl.h"
40
41 #ifdef __STDC__
42 #include "stdarg.h"
43 #else
44 #include "varargs.h"
45 #endif
46
47 #if 0
48 static char *parse_number ();
49 #endif
50
51 static long get_number (char *, long, int);
52 static void print_number (int, int, long);
53 static void write_char (char c);
54 static void write_string (const char *s);
55
56 /* Non-zero for big-endian systems. */
57 static int big_endian_p;
58
59 /* For now hardcode 2 (stderr) as the console file descriptor.
60 May wish to let the caller pass in a file descriptor or some such but
61 this is only for debugging purposes anyway. */
62 #define CONSOLE_FD 2
63
64 /* Standalone printf routine.
65
66 The format string has been enhanced so that multiple values can be dumped
67 without having to have a %-field for each one (say if you want to dump
68 20 words at a certain address). A modifier of `N' says the next argument
69 is a count, and the one after that is a pointer.
70
71 Example: __dprintf ("%Nx\n", 20, p); /-* print 20 ints at `p' *-/
72
73 Supported formats are: c d u x s p.
74
75 All ints are retrieved a byte at a time so alignment issues are not
76 a problem.
77
78 This routine is used in situations where the only debugging capability
79 is console output and was written to aid debugging newlib itself. We don't
80 use printf ourselves as we may be debugging it. We do assume _write_r is
81 working.
82 */
83
84 void
85 #ifdef __STDC__
__dprintf(const char * fmt,...)86 __dprintf (const char *fmt, ...)
87 #else
88 __dprintf (fmt, va_alist)
89 char *fmt;
90 va_dcl
91 #endif
92 {
93 va_list args;
94
95 /* Which endian are we? */
96 {
97 short tmp = 1;
98 big_endian_p = *(char *) &tmp == 0;
99 }
100
101 #ifdef __STDC__
102 va_start (args, fmt);
103 #else
104 va_start (args);
105 #endif
106
107 while (*fmt)
108 {
109 char c, *p;
110 int count;
111 long l;
112
113 if (*fmt != '%' || *++fmt == '%')
114 {
115 write_char (*fmt++);
116 continue;
117 }
118
119 if (*fmt == 'N')
120 {
121 count = va_arg (args, int);
122 p = va_arg (args, char *);
123 ++fmt;
124 c = *fmt++;
125
126 while (--count >= 0)
127 {
128 switch (c)
129 {
130 case 'c' :
131 write_string (unctrl (*p++));
132 break;
133 case 'p' :
134 print_number (16, 1, get_number (p, sizeof (char *), 1));
135 p += sizeof (char *);
136 break;
137 case 'd' :
138 case 'u' :
139 case 'x' :
140 print_number (c == 'x' ? 16 : 10, c != 'd',
141 get_number (p, sizeof (int), c != 'd'));
142 p += sizeof (int);
143 break;
144 case 's' :
145 write_string (*(char **) p);
146 p += sizeof (char *);
147 break;
148 }
149 if (count > 0)
150 write_char (' ');
151 }
152 }
153 else
154 {
155 switch (c = *fmt++)
156 {
157 case 'c' :
158 c = va_arg (args, int);
159 write_string (unctrl (c));
160 break;
161 case 'p' :
162 l = (_POINTER_INT) va_arg (args, char *);
163 print_number (16, 1, l);
164 break;
165 case 'd' :
166 case 'u' :
167 case 'x' :
168 l = va_arg (args, int);
169 print_number (c == 'x' ? 16 : 10, c != 'd', l);
170 break;
171 case 's' :
172 p = va_arg (args, char *);
173 write_string (p);
174 break;
175 }
176 }
177 }
178
179 va_end (args);
180 }
181
182 #if 0
183 /* Parse a positive decimal integer at S.
184 FIXME: Was used in earlier version, but not currently used.
185 Keep for now. */
186
187 static char *
188 parse_number (s, p)
189 char *s;
190 long *p;
191 {
192 long x = 0;
193
194 while (isdigit (*s))
195 {
196 x = (x * 10) + (*s - '0');
197 ++s;
198 }
199
200 *p = x;
201 return s;
202 }
203 #endif
204
205 /* Fetch the number at S of SIZE bytes. */
206
207 static long
get_number(char * s,long size,int unsigned_p)208 get_number (char *s,
209 long size,
210 int unsigned_p)
211 {
212 long x;
213 unsigned char *p = (unsigned char *) s;
214
215 switch (size)
216 {
217 case 1 :
218 x = *p;
219 if (!unsigned_p)
220 x = (x ^ 0x80) - 0x80;
221 return x;
222 case 2 :
223 if (big_endian_p)
224 x = (p[0] << 8) | p[1];
225 else
226 x = (p[1] << 8) | p[0];
227 if (!unsigned_p)
228 x = (x ^ 0x8000) - 0x8000;
229 return x;
230 case 4 :
231 if (big_endian_p)
232 x = ((long)p[0] << 24) | ((long)p[1] << 16) | (p[2] << 8) | p[3];
233 else
234 x = ((long)p[3] << 24) | ((long)p[2] << 16) | (p[1] << 8) | p[0];
235 if (!unsigned_p)
236 x = (x ^ 0x80000000L) - 0x80000000L;
237 return x;
238 #if 0 /* FIXME: Is there a standard mechanism for knowing if
239 long longs exist? */
240 case 8 :
241 #endif
242 default :
243 return 0;
244 }
245 }
246
247 /* Print X in base BASE. */
248
249 static void
print_number(int base,int unsigned_p,long n)250 print_number (int base,
251 int unsigned_p,
252 long n)
253 {
254 static char chars[16] = "0123456789abcdef";
255 char *p, buf[32];
256 unsigned long x;
257
258 if (!unsigned_p && n < 0)
259 {
260 write_char ('-');
261 x = -n;
262 }
263 else
264 x = n;
265
266 p = buf + sizeof (buf);
267 *--p = '\0';
268 do
269 {
270 *--p = chars[x % base];
271 x /= base;
272 }
273 while (x != 0);
274
275 write_string (p);
276 }
277
278 /* Write C to the console.
279 We go through the file descriptor directly because we can't assume
280 stdio is working. */
281
282 static void
write_char(char c)283 write_char (char c)
284 {
285 write (CONSOLE_FD, &c, 1);
286 }
287
288 /* Write S to the console.
289 We go through the file descriptor directly because we can't assume
290 stdio is working. */
291
292 static void
write_string(const char * s)293 write_string (const char *s)
294 {
295 write (CONSOLE_FD, s, strlen (s));
296 }
297