1 /* $Header: /p/tcsh/cvsroot/tcsh/tc.printf.c,v 3.37 2014/02/28 17:10:31 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.37 2014/02/28 17:10:31 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 int 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, do_ptrdiff_t
= 0;
72 int sign
= 0, count
= 0;
78 if (*f
!= '%') { /* then just out the char */
79 (*addchar
) (((unsigned char)*f
) | attributes
);
85 if (*f
== '-') { /* minus: flush left */
90 if (*f
== '0' || *f
== '.') {
91 /* padding with 0 rather than blank */
95 if (*f
== '*') { /* field width */
96 f_width
= va_arg(ap
, int);
99 else if (isdigit((unsigned char) *f
)) {
101 while (isdigit((unsigned char) *f
))
102 f
++; /* skip the digits */
105 if (*f
== '.') { /* precision */
108 prec
= va_arg(ap
, int);
111 else if (isdigit((unsigned char) *f
)) {
113 while (isdigit((unsigned char) *f
))
114 f
++; /* skip the digits */
118 if (*f
== '#') { /* alternate form */
123 if (*f
== 'l') { /* long format */
131 if (*f
== 'z') { /* size_t format */
135 if (*f
== 't') { /* ptrdiff_t format */
140 fmt
= (unsigned char) *f
;
141 if (fmt
!= 'S' && fmt
!= 'Q' && isupper(fmt
)) {
146 switch (fmt
) { /* do the format */
151 l
= (long) (va_arg(ap
, size_t));
153 l
= (long) (va_arg(ap
, int));
156 #ifndef HAVE_LONG_LONG
159 l
= va_arg(ap
, long);
161 #ifdef HAVE_LONG_LONG
163 l
= va_arg(ap
, long long);
173 *bp
++ = (char) (l
% 10) + '0';
174 } while ((l
/= 10) > 0);
177 f_width
= f_width
- (int) (bp
- buf
);
179 while (f_width
-- > 0) {
180 (*addchar
) (pad
| attributes
);
183 for (bp
--; bp
>= buf
; bp
--) {
184 (*addchar
) (((unsigned char) *bp
) | attributes
);
188 while (f_width
-- > 0) {
189 (*addchar
) (' ' | attributes
);
205 u
= va_arg(ap
, size_t);
206 else if (do_ptrdiff_t
)
207 u
= va_arg(ap
, ptrdiff_t);
209 u
= va_arg(ap
, unsigned int);
212 #ifndef HAVE_LONG_LONG
215 u
= va_arg(ap
, unsigned long);
217 #ifdef HAVE_LONG_LONG
219 u
= va_arg(ap
, unsigned long long);
223 if (fmt
== 'u') { /* unsigned decimal */
225 *bp
++ = (char) (u
% 10) + '0';
226 } while ((u
/= 10) > 0);
228 else if (fmt
== 'o') { /* octal */
230 *bp
++ = (char) (u
% 8) + '0';
231 } while ((u
/= 8) > 0);
235 else if (fmt
== 'x') { /* hex */
241 *bp
++ = i
- 10 + 'a';
242 } while ((u
/= 16) > 0);
248 i
= f_width
- (int) (bp
- buf
);
251 (*addchar
) (pad
| attributes
);
254 for (bp
--; bp
>= buf
; bp
--)
255 (*addchar
) (((unsigned char) *bp
) | attributes
);
258 (*addchar
) (' ' | attributes
);
266 (*addchar
) (i
| attributes
);
273 Bp
= va_arg(ap
, Char
*);
278 f_width
= f_width
- Strlen(Bp
);
280 while (f_width
-- > 0) {
281 (*addchar
) ((int) (pad
| attributes
));
284 for (i
= 0; *Bp
&& i
< prec
; i
++) {
285 char cbuf
[MB_LEN_MAX
];
288 if (fmt
== 'Q' && *Bp
& QUOTE
) {
289 (*addchar
) ('\\' | attributes
);
292 len
= one_wctomb(cbuf
, *Bp
& CHAR
);
293 for (pos
= 0; pos
< len
; pos
++) {
294 (*addchar
) ((unsigned char)cbuf
[pos
] | attributes
295 | (*Bp
& ATTRIBUTES
));
301 while (f_width
-- > 0) {
302 (*addchar
) (' ' | attributes
);
306 #endif /* SHORT_STRINGS */
310 bp
= va_arg(ap
, char *);
314 f_width
= f_width
- strlen(bp
);
316 while (f_width
-- > 0) {
317 (*addchar
) (pad
| attributes
);
320 for (i
= 0; *bp
&& i
< prec
; i
++) {
321 if (fmt
== 'q' && *bp
& QUOTE
) {
322 (*addchar
) ('\\' | attributes
);
325 (*addchar
) (((unsigned char) *bp
& TRIM
) | attributes
);
330 while (f_width
-- > 0) {
331 (*addchar
) (' ' | attributes
);
337 attributes
= va_arg(ap
, int);
341 (*addchar
) ('%' | attributes
);
348 flush_left
= 0, f_width
= 0, prec
= INF
, hash
= 0;
349 do_ptrdiff_t
= 0, do_size_t
= 0, do_long
= 0;
358 static char *xstring
, *xestring
;
362 if (xestring
== xstring
)
365 *xstring
++ = (char) c
;
371 xsnprintf(char *str
, size_t size
, const char *fmt
, ...)
378 xestring
= str
+ size
- 1;
379 count
= doprnt(xaddchar
, fmt
, va
);
387 xprintf(const char *fmt
, ...)
392 count
= doprnt(xputchar
, fmt
, va
);
398 xvprintf(const char *fmt
, va_list va
)
400 return doprnt(xputchar
, fmt
, va
);
404 xvsnprintf(char *str
, size_t size
, const char *fmt
, va_list va
)
408 xestring
= str
+ size
- 1;
409 count
= doprnt(xaddchar
, fmt
, va
);
415 xvasprintf(const char *fmt
, va_list va
)
421 size
= 2048; /* Arbitrary */
425 buf
= xrealloc(buf
, size
);
427 xestring
= buf
+ size
- 1;
429 doprnt(xaddchar
, fmt
, copy
);
431 if (xstring
< xestring
)
436 return xrealloc(buf
, xstring
- buf
);
440 xasprintf(const char *fmt
, ...)
446 ret
= xvasprintf(fmt
, va
);
453 /* Purify uses (some of..) the following functions to output memory-use
454 * debugging info. Given all the messing with file descriptors that
455 * tcsh does, the easiest way I could think of to get it (Purify) to
456 * print anything was by replacing some standard functions with
457 * ones that do tcsh output directly - see dumb hook in doreaddirs()
464 fprintf(FILE *fp
, const char* fmt
, ...)
469 count
= doprnt(xputchar
, fmt
, va
);
475 vfprintf(FILE *fp
, const char *fmt
, va_list va
)
477 return doprnt(xputchar
, fmt
, va
);