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