source: trunk/third/tcsh/tc.printf.c @ 22036

Revision 22036, 9.7 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22035, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/tc.printf.c,v 1.1.1.3 2005-06-03 14:35:13 ghudson 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. 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.
22 *
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.
34 */
35#include "sh.h"
36
37RCSID("$Id: tc.printf.c,v 1.1.1.3 2005-06-03 14:35:13 ghudson Exp $")
38
39#ifdef lint
40#undef va_arg
41#define va_arg(a, b) (a ? (b) 0 : (b) 0)
42#endif
43
44#define INF     32766           /* should be bigger than any field to print */
45
46static char buf[128];
47static char snil[] = "(nil)";
48
49static  void    xaddchar        __P((int));
50static  void    doprnt          __P((void (*) __P((int)), const char *, va_list));
51
52static void
53doprnt(addchar, sfmt, ap)
54    void    (*addchar) __P((int));
55    const char   *sfmt;
56    va_list ap;
57{
58    char *bp;
59    const char *f;
60#ifdef SHORT_STRINGS
61    Char *Bp;
62#endif /* SHORT_STRINGS */
63#ifdef HAVE_LONG_LONG
64    long long l;
65    unsigned long long u;
66#else
67    long l;
68    unsigned long u;
69#endif
70    int i;
71    int fmt;
72    unsigned char pad = ' ';
73    int     flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
74    int     sign = 0;
75    int     attributes = 0;
76
77
78    f = sfmt;
79    for (; *f; f++) {
80        if (*f != '%') {        /* then just out the char */
81            (*addchar) ((int) (((unsigned char)*f) | attributes));
82        }
83        else {
84            f++;                /* skip the % */
85
86            if (*f == '-') {    /* minus: flush left */
87                flush_left = 1;
88                f++;
89            }
90
91            if (*f == '0' || *f == '.') {
92                /* padding with 0 rather than blank */
93                pad = '0';
94                f++;
95            }
96            if (*f == '*') {    /* field width */
97                f_width = va_arg(ap, int);
98                f++;
99            }
100            else if (isdigit((unsigned char) *f)) {
101                f_width = atoi(f);
102                while (isdigit((unsigned char) *f))
103                    f++;        /* skip the digits */
104            }
105
106            if (*f == '.') {    /* precision */
107                f++;
108                if (*f == '*') {
109                    prec = va_arg(ap, int);
110                    f++;
111                }
112                else if (isdigit((unsigned char) *f)) {
113                    prec = atoi(f);
114                    while (isdigit((unsigned char) *f))
115                        f++;    /* skip the digits */
116                }
117            }
118
119            if (*f == '#') {    /* alternate form */
120                hash = 1;
121                f++;
122            }
123
124            if (*f == 'l') {    /* long format */
125                do_long++;
126                f++;
127                if (*f == 'l') {
128                    do_long++;
129                    f++;
130                }
131            }
132
133            fmt = (unsigned char) *f;
134            if (fmt != 'S' && fmt != 'Q' && isupper(fmt)) {
135                do_long = 1;
136                fmt = tolower(fmt);
137            }
138            bp = buf;
139            switch (fmt) {      /* do the format */
140            case 'd':
141                switch (do_long) {
142                case 0:
143                    l = (long) (va_arg(ap, int));
144                    break;
145                case 1:
146#ifndef HAVE_LONG_LONG
147                default:
148#endif
149                    l = va_arg(ap, long);
150                    break;
151#ifdef HAVE_LONG_LONG
152                default:
153                    l = va_arg(ap, long long);
154                    break;
155#endif
156                }
157
158                if (l < 0) {
159                    sign = 1;
160                    l = -l;
161                }
162                do {
163                    *bp++ = (char) (l % 10) + '0';
164                } while ((l /= 10) > 0);
165                if (sign)
166                    *bp++ = '-';
167                f_width = f_width - (int) (bp - buf);
168                if (!flush_left)
169                    while (f_width-- > 0)
170                        (*addchar) ((int) (pad | attributes));
171                for (bp--; bp >= buf; bp--)
172                    (*addchar) ((int) (((unsigned char) *bp) | attributes));
173                if (flush_left)
174                    while (f_width-- > 0)
175                        (*addchar) ((int) (' ' | attributes));
176                break;
177
178            case 'p':
179                do_long = 1;
180                hash = 1;
181                fmt = 'x';
182                /*FALLTHROUGH*/
183            case 'o':
184            case 'x':
185            case 'u':
186                switch (do_long) {
187                case 0:
188                    u = (unsigned long) (va_arg(ap, unsigned int));
189                    break;
190                case 1:
191#ifndef HAVE_LONG_LONG
192                default:
193#endif
194                    u = va_arg(ap, unsigned long);
195                    break;
196#ifdef HAVE_LONG_LONG
197                default:
198                    u = va_arg(ap, unsigned long long);
199                    break;
200#endif
201                }
202                if (fmt == 'u') {       /* unsigned decimal */
203                    do {
204                        *bp++ = (char) (u % 10) + '0';
205                    } while ((u /= 10) > 0);
206                }
207                else if (fmt == 'o') {  /* octal */
208                    do {
209                        *bp++ = (char) (u % 8) + '0';
210                    } while ((u /= 8) > 0);
211                    if (hash)
212                        *bp++ = '0';
213                }
214                else if (fmt == 'x') {  /* hex */
215                    do {
216                        i = (int) (u % 16);
217                        if (i < 10)
218                            *bp++ = i + '0';
219                        else
220                            *bp++ = i - 10 + 'a';
221                    } while ((u /= 16) > 0);
222                    if (hash) {
223                        *bp++ = 'x';
224                        *bp++ = '0';
225                    }
226                }
227                i = f_width - (int) (bp - buf);
228                if (!flush_left)
229                    while (i-- > 0)
230                        (*addchar) ((int) (pad | attributes));
231                for (bp--; bp >= buf; bp--)
232                    (*addchar) ((int) (((unsigned char) *bp) | attributes));
233                if (flush_left)
234                    while (i-- > 0)
235                        (*addchar) ((int) (' ' | attributes));
236                break;
237
238
239            case 'c':
240                i = va_arg(ap, int);
241                (*addchar) ((int) (i | attributes));
242                break;
243
244            case 'S':
245            case 'Q':
246#ifdef SHORT_STRINGS
247                Bp = va_arg(ap, Char *);
248                if (!Bp) {
249                    bp = NULL;
250                    goto lcase_s;
251                }
252                f_width = f_width - Strlen(Bp);
253                if (!flush_left)
254                    while (f_width-- > 0)
255                        (*addchar) ((int) (pad | attributes));
256                for (i = 0; *Bp && i < prec; i++) {
257                    char cbuf[MB_LEN_MAX];
258                    size_t pos, len;
259
260                    if (fmt == 'Q' && *Bp & QUOTE)
261                        (*addchar) ((int) ('\\' | attributes));
262                    len = one_wctomb(cbuf, *Bp & CHAR);
263                    for (pos = 0; pos < len; pos++)
264                        (*addchar) ((int) ((unsigned char)cbuf[pos]
265                                           | attributes | (*Bp & ATTRIBUTES)));
266                    Bp++;
267                }
268                if (flush_left)
269                    while (f_width-- > 0)
270                        (*addchar) ((int) (' ' | attributes));
271                break;
272#endif /* SHORT_STRINGS */
273
274            case 's':
275            case 'q':
276                bp = va_arg(ap, char *);
277lcase_s:
278                if (!bp)
279                    bp = snil;
280                f_width = f_width - strlen((char *) bp);
281                if (!flush_left)
282                    while (f_width-- > 0)
283                        (*addchar) ((int) (pad | attributes));
284                for (i = 0; *bp && i < prec; i++) {
285                    if (fmt == 'q' && *bp & QUOTE)
286                        (*addchar) ((int) ('\\' | attributes));
287                    (*addchar) ((int) (((unsigned char) *bp & TRIM) |
288                                        attributes));
289                    bp++;
290                }
291                if (flush_left)
292                    while (f_width-- > 0)
293                        (*addchar) ((int) (' ' | attributes));
294                break;
295
296            case 'a':
297                attributes = va_arg(ap, int);
298                break;
299
300            case '%':
301                (*addchar) ((int) ('%' | attributes));
302                break;
303
304            default:
305                break;
306            }
307            flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
308            sign = 0;
309            pad = ' ';
310        }
311    }
312}
313
314
315static char *xstring, *xestring;
316static void
317xaddchar(c)
318    int     c;
319{
320    if (xestring == xstring)
321        *xstring = '\0';
322    else
323        *xstring++ = (char) c;
324}
325
326
327pret_t
328/*VARARGS*/
329#ifdef PROTOTYPES
330xsnprintf(char *str, size_t size, const char *fmt, ...)
331#else
332xsnprintf(va_alist)
333    va_dcl
334#endif
335{
336    va_list va;
337#ifdef PROTOTYPES
338    va_start(va, fmt);
339#else
340    char *str, *fmt;
341    size_t size;
342
343    va_start(va);
344    str = va_arg(va, char *);
345    size = va_arg(va, size_t);
346    fmt = va_arg(va, char *);
347#endif
348
349    xstring = str;
350    xestring = str + size - 1;
351    doprnt(xaddchar, fmt, va);
352    va_end(va);
353    *xstring++ = '\0';
354#ifdef PURIFY
355    return 1;
356#endif
357}
358
359pret_t
360/*VARARGS*/
361#ifdef PROTOTYPES
362xprintf(const char *fmt, ...)
363#else
364xprintf(va_alist)
365    va_dcl
366#endif
367{
368    va_list va;
369#ifdef PROTOTYPES
370    va_start(va, fmt);
371#else
372    char   *fmt;
373
374    va_start(va);
375    fmt = va_arg(va, char *);
376#endif
377    doprnt(xputchar, fmt, va);
378    va_end(va);
379#ifdef PURIFY
380    return 1;
381#endif
382}
383
384
385pret_t
386xvprintf(fmt, va)
387    const char   *fmt;
388    va_list va;
389{
390    doprnt(xputchar, fmt, va);
391#ifdef PURIFY
392    return 1;
393#endif
394}
395
396pret_t
397xvsnprintf(str, size, fmt, va)
398    char   *str;
399    size_t size;
400    const char   *fmt;
401    va_list va;
402{
403    xstring = str;
404    xestring = str + size - 1;
405    doprnt(xaddchar, fmt, va);
406    *xstring++ = '\0';
407#ifdef PURIFY
408    return 1;
409#endif
410}
411
412
413
414#ifdef PURIFY
415/* Purify uses (some of..) the following functions to output memory-use
416 * debugging info.  Given all the messing with file descriptors that
417 * tcsh does, the easiest way I could think of to get it (Purify) to
418 * print anything was by replacing some standard functions with
419 * ones that do tcsh output directly - see dumb hook in doreaddirs()
420 * (sh.dir.c) -sg
421 */
422#ifndef FILE
423#define FILE int
424#endif
425int
426#ifdef PROTOTYPES
427fprintf(FILE *fp, const char* fmt, ...)
428#else
429fprintf(va_alist)
430    va_dcl
431#endif
432{
433    va_list va;
434#ifdef PROTOTYPES
435    va_start(va, fmt);
436#else
437    FILE *fp;
438    const char   *fmt;
439
440    va_start(va);
441    fp = va_arg(va, FILE *);
442    fmt = va_arg(va, const char *);
443#endif
444    doprnt(xputchar, fmt, va);
445    va_end(va);
446    return 1;
447}
448
449int
450vfprintf(fp, fmt, va)
451    FILE *fp;
452    const char   *fmt;
453    va_list va;
454{
455    doprnt(xputchar, fmt, va);
456    return 1;
457}
458
459#endif  /* PURIFY */
Note: See TracBrowser for help on using the repository browser.