tc.printf.c revision 59243
1/* $Header: /src/pub/tcsh/tc.printf.c,v 3.19 1998/10/25 15:10:37 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.
10 *
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. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39#include "sh.h"
40
41RCSID("$Id: tc.printf.c,v 3.19 1998/10/25 15:10:37 christos Exp $")
42
43#ifdef lint
44#undef va_arg
45#define va_arg(a, b) (a ? (b) 0 : (b) 0)
46#endif
47
48#define INF	32766		/* should be bigger than any field to print */
49
50static char buf[128];
51
52static	void	xaddchar	__P((int));
53static	void	doprnt		__P((void (*) __P((int)), const char *, va_list));
54
55static void
56doprnt(addchar, sfmt, ap)
57    void    (*addchar) __P((int));
58    const char   *sfmt;
59    va_list ap;
60{
61    register char *bp;
62    register const char *f;
63#ifdef SHORT_STRINGS
64    register Char *Bp;
65#endif /* SHORT_STRINGS */
66    register long l;
67    register unsigned long u;
68    register int i;
69    register int fmt;
70    register unsigned char pad = ' ';
71    int     flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
72    int     sign = 0;
73    int     attributes = 0;
74
75
76    f = sfmt;
77    for (; *f; f++) {
78	if (*f != '%') {	/* then just out the char */
79	    (*addchar) ((int) (((unsigned char)*f) | attributes));
80	}
81	else {
82	    f++;		/* skip the % */
83
84	    if (*f == '-') {	/* minus: flush left */
85		flush_left = 1;
86		f++;
87	    }
88
89	    if (*f == '0' || *f == '.') {
90		/* padding with 0 rather than blank */
91		pad = '0';
92		f++;
93	    }
94	    if (*f == '*') {	/* field width */
95		f_width = va_arg(ap, int);
96		f++;
97	    }
98	    else if (Isdigit((unsigned char) *f)) {
99		f_width = atoi(f);
100		while (Isdigit((unsigned char) *f))
101		    f++;	/* skip the digits */
102	    }
103
104	    if (*f == '.') {	/* precision */
105		f++;
106		if (*f == '*') {
107		    prec = va_arg(ap, int);
108		    f++;
109		}
110		else if (Isdigit((unsigned char) *f)) {
111		    prec = atoi((char *) f);
112		    while (Isdigit((unsigned char) *f))
113			f++;	/* skip the digits */
114		}
115	    }
116
117	    if (*f == '#') {	/* alternate form */
118		hash = 1;
119		f++;
120	    }
121
122	    if (*f == 'l') {	/* long format */
123		do_long = 1;
124		f++;
125	    }
126
127	    fmt = (unsigned char) *f;
128	    if (fmt != 'S' && fmt != 'Q' && Isupper(fmt)) {
129		do_long = 1;
130		fmt = Tolower(fmt);
131	    }
132	    bp = buf;
133	    switch (fmt) {	/* do the format */
134	    case 'd':
135		if (do_long)
136		    l = va_arg(ap, long);
137		else
138		    l = (long) (va_arg(ap, int));
139		if (l < 0) {
140		    sign = 1;
141		    l = -l;
142		}
143		do {
144		    *bp++ = (char) (l % 10) + '0';
145		} while ((l /= 10) > 0);
146		if (sign)
147		    *bp++ = '-';
148		f_width = f_width - (int) (bp - buf);
149		if (!flush_left)
150		    while (f_width-- > 0)
151			(*addchar) ((int) (pad | attributes));
152		for (bp--; bp >= buf; bp--)
153		    (*addchar) ((int) (((unsigned char) *bp) | attributes));
154		if (flush_left)
155		    while (f_width-- > 0)
156			(*addchar) ((int) (' ' | attributes));
157		break;
158
159	    case 'o':
160	    case 'x':
161	    case 'u':
162		if (do_long)
163		    u = va_arg(ap, unsigned long);
164		else
165		    u = (unsigned long) (va_arg(ap, unsigned int));
166		if (fmt == 'u') {	/* unsigned decimal */
167		    do {
168			*bp++ = (char) (u % 10) + '0';
169		    } while ((u /= 10) > 0);
170		}
171		else if (fmt == 'o') {	/* octal */
172		    do {
173			*bp++ = (char) (u % 8) + '0';
174		    } while ((u /= 8) > 0);
175		    if (hash)
176			*bp++ = '0';
177		}
178		else if (fmt == 'x') {	/* hex */
179		    do {
180			i = (int) (u % 16);
181			if (i < 10)
182			    *bp++ = i + '0';
183			else
184			    *bp++ = i - 10 + 'a';
185		    } while ((u /= 16) > 0);
186		    if (hash) {
187			*bp++ = 'x';
188			*bp++ = '0';
189		    }
190		}
191		i = f_width - (int) (bp - buf);
192		if (!flush_left)
193		    while (i-- > 0)
194			(*addchar) ((int) (pad | attributes));
195		for (bp--; bp >= buf; bp--)
196		    (*addchar) ((int) (((unsigned char) *bp) | attributes));
197		if (flush_left)
198		    while (i-- > 0)
199			(*addchar) ((int) (' ' | attributes));
200		break;
201
202
203	    case 'c':
204		i = va_arg(ap, int);
205		(*addchar) ((int) (i | attributes));
206		break;
207
208	    case 'S':
209	    case 'Q':
210		Bp = va_arg(ap, Char *);
211		if (!Bp) {
212		    bp = NULL;
213		    goto lcase_s;
214	        }
215		f_width = f_width - Strlen(Bp);
216		if (!flush_left)
217		    while (f_width-- > 0)
218			(*addchar) ((int) (pad | attributes));
219		for (i = 0; *Bp && i < prec; i++) {
220		    if (fmt == 'Q' && *Bp & QUOTE)
221			(*addchar) ((int) ('\\' | attributes));
222		    (*addchar) ((int) ((*Bp & TRIM) | attributes));
223		    Bp++;
224		}
225		if (flush_left)
226		    while (f_width-- > 0)
227			(*addchar) ((int) (' ' | attributes));
228		break;
229
230	    case 's':
231	    case 'q':
232		bp = va_arg(ap, char *);
233lcase_s:
234		if (!bp)
235		    bp = "(nil)";
236		f_width = f_width - strlen((char *) bp);
237		if (!flush_left)
238		    while (f_width-- > 0)
239			(*addchar) ((int) (pad | attributes));
240		for (i = 0; *bp && i < prec; i++) {
241		    if (fmt == 'q' && *bp & QUOTE)
242			(*addchar) ((int) ('\\' | attributes));
243		    (*addchar) ((int) (((unsigned char) *bp & TRIM) |
244				   	attributes));
245		    bp++;
246		}
247		if (flush_left)
248		    while (f_width-- > 0)
249			(*addchar) ((int) (' ' | attributes));
250		break;
251
252	    case 'a':
253		attributes = va_arg(ap, int);
254		break;
255
256	    case '%':
257		(*addchar) ((int) ('%' | attributes));
258		break;
259
260	    default:
261		break;
262	    }
263	    flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
264	    sign = 0;
265	    pad = ' ';
266	}
267    }
268}
269
270
271static char *xstring, *xestring;
272static void
273xaddchar(c)
274    int     c;
275{
276    if (xestring == xstring)
277	*xstring = '\0';
278    else
279	*xstring++ = (char) c;
280}
281
282
283pret_t
284/*VARARGS*/
285#ifdef FUNCPROTO
286xsnprintf(char *str, size_t size, const char *fmt, ...)
287#else
288xsnprintf(va_alist)
289    va_dcl
290#endif
291{
292    va_list va;
293#ifdef FUNCPROTO
294    va_start(va, fmt);
295#else
296    char *str, *fmt;
297    size_t size;
298
299    va_start(va);
300    str = va_arg(va, char *);
301    size = va_arg(va, size_t);
302    fmt = va_arg(va, char *);
303#endif
304
305    xstring = str;
306    xestring = str + size - 1;
307    doprnt(xaddchar, fmt, va);
308    va_end(va);
309    *xstring++ = '\0';
310#ifdef PURIFY
311    return 1;
312#endif
313}
314
315pret_t
316/*VARARGS*/
317#ifdef FUNCPROTO
318xprintf(const char *fmt, ...)
319#else
320xprintf(va_alist)
321    va_dcl
322#endif
323{
324    va_list va;
325#ifdef FUNCPROTO
326    va_start(va, fmt);
327#else
328    char   *fmt;
329
330    va_start(va);
331    fmt = va_arg(va, char *);
332#endif
333    doprnt(xputchar, fmt, va);
334    va_end(va);
335#ifdef PURIFY
336    return 1;
337#endif
338}
339
340
341pret_t
342xvprintf(fmt, va)
343    const char   *fmt;
344    va_list va;
345{
346    doprnt(xputchar, fmt, va);
347#ifdef PURIFY
348    return 1;
349#endif
350}
351
352pret_t
353xvsnprintf(str, size, fmt, va)
354    char   *str;
355    size_t size;
356    const char   *fmt;
357    va_list va;
358{
359    xstring = str;
360    xestring = str + size - 1;
361    doprnt(xaddchar, fmt, va);
362    *xstring++ = '\0';
363#ifdef PURIFY
364    return 1;
365#endif
366}
367
368
369
370#ifdef PURIFY
371/* Purify uses (some of..) the following functions to output memory-use
372 * debugging info.  Given all the messing with file descriptors that
373 * tcsh does, the easiest way I could think of to get it (Purify) to
374 * print anything was by replacing some standard functions with
375 * ones that do tcsh output directly - see dumb hook in doreaddirs()
376 * (sh.dir.c) -sg
377 */
378#ifndef FILE
379#define FILE int
380#endif
381int
382#ifdef FUNCPROTO
383fprintf(FILE *fp, const char* fmt, ...)
384#else
385fprintf(va_alist)
386    va_dcl
387#endif
388{
389    va_list va;
390#ifdef FUNCPROTO
391    va_start(va, fmt);
392#else
393    FILE *fp;
394    const char   *fmt;
395
396    va_start(va);
397    fp = va_arg(va, FILE *);
398    fmt = va_arg(va, const char *);
399#endif
400    doprnt(xputchar, fmt, va);
401    va_end(va);
402    return 1;
403}
404
405int
406vfprintf(fp, fmt, va)
407    FILE *fp;
408    const char   *fmt;
409    va_list va;
410{
411    doprnt(xputchar, fmt, va);
412    return 1;
413}
414
415#endif	/* PURIFY */
416