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