]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcsh/tc.printf.c
This commit was generated by cvs2svn to compensate for changes in r161863,
[FreeBSD/FreeBSD.git] / contrib / tcsh / tc.printf.c
1 /* $Header: /src/pub/tcsh/tc.printf.c,v 3.27 2005/01/05 16:06:15 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. 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
37 RCSID("$Id: tc.printf.c,v 3.27 2005/01/05 16:06:15 christos 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
46 static char buf[128];
47 static char snil[] = "(nil)";
48
49 static  void    xaddchar        __P((int));
50 static  void    doprnt          __P((void (*) __P((int)), const char *, va_list));
51
52 static void
53 doprnt(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 *);
277 lcase_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
315 static char *xstring, *xestring;
316 static void
317 xaddchar(c)
318     int     c;
319 {
320     if (xestring == xstring)
321         *xstring = '\0';
322     else
323         *xstring++ = (char) c;
324 }
325
326
327 pret_t
328 /*VARARGS*/
329 #ifdef PROTOTYPES
330 xsnprintf(char *str, size_t size, const char *fmt, ...)
331 #else
332 xsnprintf(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
359 pret_t
360 /*VARARGS*/
361 #ifdef PROTOTYPES
362 xprintf(const char *fmt, ...)
363 #else
364 xprintf(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
385 pret_t
386 xvprintf(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
396 pret_t
397 xvsnprintf(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
425 int 
426 #ifdef PROTOTYPES
427 fprintf(FILE *fp, const char* fmt, ...)
428 #else
429 fprintf(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
449 int 
450 vfprintf(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 */