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