Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / misc / __dprintf.c
blob31454f4c2b07dcf6e65c28a182121e6b05558a2f
1 /* Debugging printf, for debugging the library itself.
3 We don't assume stdio is working.
4 We do assume _write_r is working.
5 */
7 #include <_ansi.h>
8 #include "ctype.h"
9 #include "reent.h"
10 #include "string.h"
11 #include "unctrl.h"
13 #ifdef __STDC__
14 #include "stdarg.h"
15 #else
16 #include "varargs.h"
17 #endif
19 #if 0
20 static char *parse_number ();
21 #endif
23 static long get_number (char *, long, int);
24 static void print_number (int, int, long);
25 static void write_char (char c);
26 static void write_string (const char *s);
28 /* Non-zero for big-endian systems. */
29 static int big_endian_p;
31 /* For now hardcode 2 (stderr) as the console file descriptor.
32 May wish to let the caller pass in a file descriptor or some such but
33 this is only for debugging purposes anyway. */
34 #define CONSOLE_FD 2
36 /* Standalone printf routine.
38 The format string has been enhanced so that multiple values can be dumped
39 without having to have a %-field for each one (say if you want to dump
40 20 words at a certain address). A modifier of `N' says the next argument
41 is a count, and the one after that is a pointer.
43 Example: __dprintf ("%Nx\n", 20, p); /-* print 20 ints at `p' *-/
45 Supported formats are: c d u x s p.
47 All ints are retrieved a byte at a time so alignment issues are not
48 a problem.
50 This routine is used in situations where the only debugging capability
51 is console output and was written to aid debugging newlib itself. We don't
52 use printf ourselves as we may be debugging it. We do assume _write_r is
53 working.
56 void
57 #ifdef __STDC__
58 __dprintf (const char *fmt, ...)
59 #else
60 __dprintf (fmt, va_alist)
61 char *fmt;
62 va_dcl
63 #endif
65 va_list args;
67 /* Which endian are we? */
69 short tmp = 1;
70 big_endian_p = *(char *) &tmp == 0;
73 #ifdef __STDC__
74 va_start (args, fmt);
75 #else
76 va_start (args);
77 #endif
79 while (*fmt)
81 char c, *p;
82 int count;
83 long l;
85 if (*fmt != '%' || *++fmt == '%')
87 write_char (*fmt++);
88 continue;
91 if (*fmt == 'N')
93 count = va_arg (args, int);
94 p = va_arg (args, char *);
95 ++fmt;
96 c = *fmt++;
98 while (--count >= 0)
100 switch (c)
102 case 'c' :
103 write_string (unctrl (*p++));
104 break;
105 case 'p' :
106 print_number (16, 1, get_number (p, sizeof (char *), 1));
107 p += sizeof (char *);
108 break;
109 case 'd' :
110 case 'u' :
111 case 'x' :
112 print_number (c == 'x' ? 16 : 10, c != 'd',
113 get_number (p, sizeof (int), c != 'd'));
114 p += sizeof (int);
115 break;
116 case 's' :
117 write_string (*(char **) p);
118 p += sizeof (char *);
119 break;
121 if (count > 0)
122 write_char (' ');
125 else
127 switch (c = *fmt++)
129 case 'c' :
130 c = va_arg (args, int);
131 write_string (unctrl (c));
132 break;
133 case 'p' :
134 l = (_POINTER_INT) va_arg (args, char *);
135 print_number (16, 1, l);
136 break;
137 case 'd' :
138 case 'u' :
139 case 'x' :
140 l = va_arg (args, int);
141 print_number (c == 'x' ? 16 : 10, c != 'd', l);
142 break;
143 case 's' :
144 p = va_arg (args, char *);
145 write_string (p);
146 break;
151 va_end (args);
154 #if 0
155 /* Parse a positive decimal integer at S.
156 FIXME: Was used in earlier version, but not currently used.
157 Keep for now. */
159 static char *
160 parse_number (s, p)
161 char *s;
162 long *p;
164 long x = 0;
166 while (isdigit (*s))
168 x = (x * 10) + (*s - '0');
169 ++s;
172 *p = x;
173 return s;
175 #endif
177 /* Fetch the number at S of SIZE bytes. */
179 static long
180 get_number (char *s,
181 long size,
182 int unsigned_p)
184 long x;
185 unsigned char *p = (unsigned char *) s;
187 switch (size)
189 case 1 :
190 x = *p;
191 if (!unsigned_p)
192 x = (x ^ 0x80) - 0x80;
193 return x;
194 case 2 :
195 if (big_endian_p)
196 x = (p[0] << 8) | p[1];
197 else
198 x = (p[1] << 8) | p[0];
199 if (!unsigned_p)
200 x = (x ^ 0x8000) - 0x8000;
201 return x;
202 case 4 :
203 if (big_endian_p)
204 x = ((long)p[0] << 24) | ((long)p[1] << 16) | (p[2] << 8) | p[3];
205 else
206 x = ((long)p[3] << 24) | ((long)p[2] << 16) | (p[1] << 8) | p[0];
207 if (!unsigned_p)
208 x = (x ^ 0x80000000L) - 0x80000000L;
209 return x;
210 #if 0 /* FIXME: Is there a standard mechanism for knowing if
211 long longs exist? */
212 case 8 :
213 #endif
214 default :
215 return 0;
219 /* Print X in base BASE. */
221 static void
222 print_number (int base,
223 int unsigned_p,
224 long n)
226 static char chars[16] = "0123456789abcdef";
227 char *p, buf[32];
228 unsigned long x;
230 if (!unsigned_p && n < 0)
232 write_char ('-');
233 x = -n;
235 else
236 x = n;
238 p = buf + sizeof (buf);
239 *--p = '\0';
242 *--p = chars[x % base];
243 x /= base;
245 while (x != 0);
247 write_string (p);
250 /* Write C to the console.
251 We go through the file descriptor directly because we can't assume
252 stdio is working. */
254 static void
255 write_char (char c)
257 _write_r (_REENT, CONSOLE_FD, &c, 1);
260 /* Write S to the console.
261 We go through the file descriptor directly because we can't assume
262 stdio is working. */
264 static void
265 write_string (const char *s)
267 _write_r (_REENT, CONSOLE_FD, s, strlen (s));