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