1 /* $Header: /p/tcsh/cvsroot/tcsh/tc.printf.c,v 3.35 2006/03/02 18:46:45 christos Exp $ */
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
8 * Copyright (c) 1980, 1991 The Regents of the University of California.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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
37 RCSID("$tcsh: tc.printf.c,v 3.35 2006/03/02 18:46:45 christos Exp $")
41 #define va_arg(a, b) (a ? (b) 0 : (b) 0)
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);
52 doprnt(void (*addchar
) (int), const char *sfmt
, va_list ap
)
58 #endif /* SHORT_STRINGS */
66 char buf
[(CHAR_BIT
* sizeof (l
) + 2) / 3 + 1]; /* Octal: 3 bits per char */
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;
78 if (*f
!= '%') { /* then just out the char */
79 (*addchar
) (((unsigned char)*f
) | attributes
);
84 if (*f
== '-') { /* minus: flush left */
89 if (*f
== '0' || *f
== '.') {
90 /* padding with 0 rather than blank */
94 if (*f
== '*') { /* field width */
95 f_width
= va_arg(ap
, int);
98 else if (isdigit((unsigned char) *f
)) {
100 while (isdigit((unsigned char) *f
))
101 f
++; /* skip the digits */
104 if (*f
== '.') { /* precision */
107 prec
= va_arg(ap
, int);
110 else if (isdigit((unsigned char) *f
)) {
112 while (isdigit((unsigned char) *f
))
113 f
++; /* skip the digits */
117 if (*f
== '#') { /* alternate form */
122 if (*f
== 'l') { /* long format */
130 if (*f
== 'z') { /* size_t format */
135 fmt
= (unsigned char) *f
;
136 if (fmt
!= 'S' && fmt
!= 'Q' && isupper(fmt
)) {
141 switch (fmt
) { /* do the format */
146 l
= (long) (va_arg(ap
, size_t));
148 l
= (long) (va_arg(ap
, int));
151 #ifndef HAVE_LONG_LONG
154 l
= va_arg(ap
, long);
156 #ifdef HAVE_LONG_LONG
158 l
= va_arg(ap
, long long);
168 *bp
++ = (char) (l
% 10) + '0';
169 } while ((l
/= 10) > 0);
172 f_width
= f_width
- (int) (bp
- buf
);
174 while (f_width
-- > 0)
175 (*addchar
) (pad
| attributes
);
176 for (bp
--; bp
>= buf
; bp
--)
177 (*addchar
) (((unsigned char) *bp
) | attributes
);
179 while (f_width
-- > 0)
180 (*addchar
) (' ' | attributes
);
194 u
= va_arg(ap
, size_t);
196 u
= va_arg(ap
, unsigned int);
199 #ifndef HAVE_LONG_LONG
202 u
= va_arg(ap
, unsigned long);
204 #ifdef HAVE_LONG_LONG
206 u
= va_arg(ap
, unsigned long long);
210 if (fmt
== 'u') { /* unsigned decimal */
212 *bp
++ = (char) (u
% 10) + '0';
213 } while ((u
/= 10) > 0);
215 else if (fmt
== 'o') { /* octal */
217 *bp
++ = (char) (u
% 8) + '0';
218 } while ((u
/= 8) > 0);
222 else if (fmt
== 'x') { /* hex */
228 *bp
++ = i
- 10 + 'a';
229 } while ((u
/= 16) > 0);
235 i
= f_width
- (int) (bp
- buf
);
238 (*addchar
) (pad
| attributes
);
239 for (bp
--; bp
>= buf
; bp
--)
240 (*addchar
) (((unsigned char) *bp
) | attributes
);
243 (*addchar
) (' ' | attributes
);
249 (*addchar
) (i
| attributes
);
255 Bp
= va_arg(ap
, Char
*);
260 f_width
= f_width
- Strlen(Bp
);
262 while (f_width
-- > 0)
263 (*addchar
) ((int) (pad
| attributes
));
264 for (i
= 0; *Bp
&& i
< prec
; i
++) {
265 char cbuf
[MB_LEN_MAX
];
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
));
277 while (f_width
-- > 0)
278 (*addchar
) (' ' | attributes
);
280 #endif /* SHORT_STRINGS */
284 bp
= va_arg(ap
, char *);
288 f_width
= f_width
- strlen(bp
);
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
);
299 while (f_width
-- > 0)
300 (*addchar
) (' ' | attributes
);
304 attributes
= va_arg(ap
, int);
308 (*addchar
) ('%' | attributes
);
314 flush_left
= 0, f_width
= 0, prec
= INF
, hash
= 0;
315 do_size_t
= 0, do_long
= 0;
323 static char *xstring
, *xestring
;
327 if (xestring
== xstring
)
330 *xstring
++ = (char) c
;
336 xsnprintf(char *str
, size_t size
, const char *fmt
, ...)
342 xestring
= str
+ size
- 1;
343 doprnt(xaddchar
, fmt
, va
);
353 xprintf(const char *fmt
, ...)
357 doprnt(xputchar
, fmt
, va
);
366 xvprintf(const char *fmt
, va_list va
)
368 doprnt(xputchar
, fmt
, va
);
375 xvsnprintf(char *str
, size_t size
, const char *fmt
, va_list va
)
378 xestring
= str
+ size
- 1;
379 doprnt(xaddchar
, fmt
, va
);
387 xvasprintf(const char *fmt
, va_list va
)
393 size
= 2048; /* Arbitrary */
397 buf
= xrealloc(buf
, size
);
399 xestring
= buf
+ size
- 1;
401 doprnt(xaddchar
, fmt
, copy
);
403 if (xstring
< xestring
)
408 return xrealloc(buf
, xstring
- buf
);
412 xasprintf(const char *fmt
, ...)
418 ret
= xvasprintf(fmt
, va
);
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()
436 fprintf(FILE *fp
, const char* fmt
, ...)
440 doprnt(xputchar
, fmt
, va
);
446 vfprintf(FILE *fp
, const char *fmt
, va_list va
)
448 doprnt(xputchar
, fmt
, va
);