gzip.1 & co.: Please keep DragonFly timeline for .Dd, not FreeBSD's.
[dragonfly.git] / contrib / tcsh-6 / tc.printf.c
blob8db69d5fff9cd13a230fe7368db822db66b3cbc0
1 /* $Header: /p/tcsh/cvsroot/tcsh/tc.printf.c,v 3.35 2006/03/02 18:46:45 christos Exp $ */
2 /*
3 * tc.printf.c: A public-domain, minimal printf/sprintf routine that prints
4 * through the putchar() routine. Feel free to use for
5 * anything... -- 7/17/87 Paul Placeway
6 */
7 /*-
8 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 #include "sh.h"
37 RCSID("$tcsh: tc.printf.c,v 3.35 2006/03/02 18:46:45 christos Exp $")
39 #ifdef lint
40 #undef va_arg
41 #define va_arg(a, b) (a ? (b) 0 : (b) 0)
42 #endif
44 #define INF INT_MAX /* should be bigger than any field to print */
46 static char snil[] = "(nil)";
48 static void xaddchar (int);
49 static void doprnt (void (*) (int), const char *, va_list);
51 static void
52 doprnt(void (*addchar) (int), const char *sfmt, va_list ap)
54 char *bp;
55 const char *f;
56 #ifdef SHORT_STRINGS
57 const Char *Bp;
58 #endif /* SHORT_STRINGS */
59 #ifdef HAVE_LONG_LONG
60 long long l;
61 unsigned long long u;
62 #else
63 long l;
64 unsigned long u;
65 #endif
66 char buf[(CHAR_BIT * sizeof (l) + 2) / 3 + 1]; /* Octal: 3 bits per char */
67 int i;
68 int fmt;
69 unsigned char pad = ' ';
70 int flush_left = 0, f_width = 0, prec = INF, hash = 0;
71 int do_long = 0, do_size_t = 0;
72 int sign = 0;
73 int attributes = 0;
76 f = sfmt;
77 for (; *f; f++) {
78 if (*f != '%') { /* then just out the char */
79 (*addchar) (((unsigned char)*f) | attributes);
81 else {
82 f++; /* skip the % */
84 if (*f == '-') { /* minus: flush left */
85 flush_left = 1;
86 f++;
89 if (*f == '0' || *f == '.') {
90 /* padding with 0 rather than blank */
91 pad = '0';
92 f++;
94 if (*f == '*') { /* field width */
95 f_width = va_arg(ap, int);
96 f++;
98 else if (isdigit((unsigned char) *f)) {
99 f_width = atoi(f);
100 while (isdigit((unsigned char) *f))
101 f++; /* skip the digits */
104 if (*f == '.') { /* precision */
105 f++;
106 if (*f == '*') {
107 prec = va_arg(ap, int);
108 f++;
110 else if (isdigit((unsigned char) *f)) {
111 prec = atoi(f);
112 while (isdigit((unsigned char) *f))
113 f++; /* skip the digits */
117 if (*f == '#') { /* alternate form */
118 hash = 1;
119 f++;
122 if (*f == 'l') { /* long format */
123 do_long++;
124 f++;
125 if (*f == 'l') {
126 do_long++;
127 f++;
130 if (*f == 'z') { /* size_t format */
131 do_size_t++;
132 f++;
135 fmt = (unsigned char) *f;
136 if (fmt != 'S' && fmt != 'Q' && isupper(fmt)) {
137 do_long = 1;
138 fmt = tolower(fmt);
140 bp = buf;
141 switch (fmt) { /* do the format */
142 case 'd':
143 switch (do_long) {
144 case 0:
145 if (do_size_t)
146 l = (long) (va_arg(ap, size_t));
147 else
148 l = (long) (va_arg(ap, int));
149 break;
150 case 1:
151 #ifndef HAVE_LONG_LONG
152 default:
153 #endif
154 l = va_arg(ap, long);
155 break;
156 #ifdef HAVE_LONG_LONG
157 default:
158 l = va_arg(ap, long long);
159 break;
160 #endif
163 if (l < 0) {
164 sign = 1;
165 l = -l;
167 do {
168 *bp++ = (char) (l % 10) + '0';
169 } while ((l /= 10) > 0);
170 if (sign)
171 *bp++ = '-';
172 f_width = f_width - (int) (bp - buf);
173 if (!flush_left)
174 while (f_width-- > 0)
175 (*addchar) (pad | attributes);
176 for (bp--; bp >= buf; bp--)
177 (*addchar) (((unsigned char) *bp) | attributes);
178 if (flush_left)
179 while (f_width-- > 0)
180 (*addchar) (' ' | attributes);
181 break;
183 case 'p':
184 do_long = 1;
185 hash = 1;
186 fmt = 'x';
187 /*FALLTHROUGH*/
188 case 'o':
189 case 'x':
190 case 'u':
191 switch (do_long) {
192 case 0:
193 if (do_size_t)
194 u = va_arg(ap, size_t);
195 else
196 u = va_arg(ap, unsigned int);
197 break;
198 case 1:
199 #ifndef HAVE_LONG_LONG
200 default:
201 #endif
202 u = va_arg(ap, unsigned long);
203 break;
204 #ifdef HAVE_LONG_LONG
205 default:
206 u = va_arg(ap, unsigned long long);
207 break;
208 #endif
210 if (fmt == 'u') { /* unsigned decimal */
211 do {
212 *bp++ = (char) (u % 10) + '0';
213 } while ((u /= 10) > 0);
215 else if (fmt == 'o') { /* octal */
216 do {
217 *bp++ = (char) (u % 8) + '0';
218 } while ((u /= 8) > 0);
219 if (hash)
220 *bp++ = '0';
222 else if (fmt == 'x') { /* hex */
223 do {
224 i = (int) (u % 16);
225 if (i < 10)
226 *bp++ = i + '0';
227 else
228 *bp++ = i - 10 + 'a';
229 } while ((u /= 16) > 0);
230 if (hash) {
231 *bp++ = 'x';
232 *bp++ = '0';
235 i = f_width - (int) (bp - buf);
236 if (!flush_left)
237 while (i-- > 0)
238 (*addchar) (pad | attributes);
239 for (bp--; bp >= buf; bp--)
240 (*addchar) (((unsigned char) *bp) | attributes);
241 if (flush_left)
242 while (i-- > 0)
243 (*addchar) (' ' | attributes);
244 break;
247 case 'c':
248 i = va_arg(ap, int);
249 (*addchar) (i | attributes);
250 break;
252 case 'S':
253 case 'Q':
254 #ifdef SHORT_STRINGS
255 Bp = va_arg(ap, Char *);
256 if (!Bp) {
257 bp = NULL;
258 goto lcase_s;
260 f_width = f_width - Strlen(Bp);
261 if (!flush_left)
262 while (f_width-- > 0)
263 (*addchar) ((int) (pad | attributes));
264 for (i = 0; *Bp && i < prec; i++) {
265 char cbuf[MB_LEN_MAX];
266 size_t pos, len;
268 if (fmt == 'Q' && *Bp & QUOTE)
269 (*addchar) ('\\' | attributes);
270 len = one_wctomb(cbuf, *Bp & CHAR);
271 for (pos = 0; pos < len; pos++)
272 (*addchar) ((unsigned char)cbuf[pos] | attributes
273 | (*Bp & ATTRIBUTES));
274 Bp++;
276 if (flush_left)
277 while (f_width-- > 0)
278 (*addchar) (' ' | attributes);
279 break;
280 #endif /* SHORT_STRINGS */
282 case 's':
283 case 'q':
284 bp = va_arg(ap, char *);
285 lcase_s:
286 if (!bp)
287 bp = snil;
288 f_width = f_width - strlen(bp);
289 if (!flush_left)
290 while (f_width-- > 0)
291 (*addchar) (pad | attributes);
292 for (i = 0; *bp && i < prec; i++) {
293 if (fmt == 'q' && *bp & QUOTE)
294 (*addchar) ('\\' | attributes);
295 (*addchar) (((unsigned char) *bp & TRIM) | attributes);
296 bp++;
298 if (flush_left)
299 while (f_width-- > 0)
300 (*addchar) (' ' | attributes);
301 break;
303 case 'a':
304 attributes = va_arg(ap, int);
305 break;
307 case '%':
308 (*addchar) ('%' | attributes);
309 break;
311 default:
312 break;
314 flush_left = 0, f_width = 0, prec = INF, hash = 0;
315 do_size_t = 0, do_long = 0;
316 sign = 0;
317 pad = ' ';
323 static char *xstring, *xestring;
324 static void
325 xaddchar(int c)
327 if (xestring == xstring)
328 *xstring = '\0';
329 else
330 *xstring++ = (char) c;
334 pret_t
335 /*VARARGS*/
336 xsnprintf(char *str, size_t size, const char *fmt, ...)
338 va_list va;
339 va_start(va, fmt);
341 xstring = str;
342 xestring = str + size - 1;
343 doprnt(xaddchar, fmt, va);
344 va_end(va);
345 *xstring++ = '\0';
346 #ifdef PURIFY
347 return 1;
348 #endif
351 pret_t
352 /*VARARGS*/
353 xprintf(const char *fmt, ...)
355 va_list va;
356 va_start(va, fmt);
357 doprnt(xputchar, fmt, va);
358 va_end(va);
359 #ifdef PURIFY
360 return 1;
361 #endif
365 pret_t
366 xvprintf(const char *fmt, va_list va)
368 doprnt(xputchar, fmt, va);
369 #ifdef PURIFY
370 return 1;
371 #endif
374 pret_t
375 xvsnprintf(char *str, size_t size, const char *fmt, va_list va)
377 xstring = str;
378 xestring = str + size - 1;
379 doprnt(xaddchar, fmt, va);
380 *xstring++ = '\0';
381 #ifdef PURIFY
382 return 1;
383 #endif
386 char *
387 xvasprintf(const char *fmt, va_list va)
389 size_t size;
390 char *buf;
392 buf = NULL;
393 size = 2048; /* Arbitrary */
394 for (;;) {
395 va_list copy;
397 buf = xrealloc(buf, size);
398 xstring = buf;
399 xestring = buf + size - 1;
400 va_copy(copy, va);
401 doprnt(xaddchar, fmt, copy);
402 va_end(copy);
403 if (xstring < xestring)
404 break;
405 size *= 2;
407 *xstring++ = '\0';
408 return xrealloc(buf, xstring - buf);
411 char *
412 xasprintf(const char *fmt, ...)
414 va_list va;
415 char *ret;
417 va_start (va, fmt);
418 ret = xvasprintf(fmt, va);
419 va_end(va);
420 return ret;
424 #ifdef PURIFY
425 /* Purify uses (some of..) the following functions to output memory-use
426 * debugging info. Given all the messing with file descriptors that
427 * tcsh does, the easiest way I could think of to get it (Purify) to
428 * print anything was by replacing some standard functions with
429 * ones that do tcsh output directly - see dumb hook in doreaddirs()
430 * (sh.dir.c) -sg
432 #ifndef FILE
433 #define FILE int
434 #endif
435 int
436 fprintf(FILE *fp, const char* fmt, ...)
438 va_list va;
439 va_start(va, fmt);
440 doprnt(xputchar, fmt, va);
441 va_end(va);
442 return 1;
445 int
446 vfprintf(FILE *fp, const char *fmt, va_list va)
448 doprnt(xputchar, fmt, va);
449 return 1;
452 #endif /* PURIFY */