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