~ubuntu-branches/ubuntu/hardy/klibc/hardy-updates

« back to all changes in this revision

Viewing changes to ash/bltin/printf.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-01-04 20:24:52 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104202452-ec4v3n829rymukuv
Tags: 1.1.15-0ubuntu1
* New upstream version.

* Patch to fix compilation on parisc64 kernels.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*      $NetBSD: printf.c,v 1.28 2003/06/25 12:56:59 dsl Exp $  */
2
 
 
3
 
/*
4
 
 * Copyright (c) 1989, 1993
5
 
 *      The Regents of the University of California.  All rights reserved.
6
 
 *
7
 
 * Redistribution and use in source and binary forms, with or without
8
 
 * modification, are permitted provided that the following conditions
9
 
 * are met:
10
 
 * 1. Redistributions of source code must retain the above copyright
11
 
 *    notice, this list of conditions and the following disclaimer.
12
 
 * 2. Redistributions in binary form must reproduce the above copyright
13
 
 *    notice, this list of conditions and the following disclaimer in the
14
 
 *    documentation and/or other materials provided with the distribution.
15
 
 * 3. Neither the name of the University nor the names of its contributors
16
 
 *    may be used to endorse or promote products derived from this software
17
 
 *    without specific prior written permission.
18
 
 *
19
 
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 
 * SUCH DAMAGE.
30
 
 */
31
 
 
32
 
#ifndef __KLIBC__
33
 
#include <sys/cdefs.h>
34
 
#endif
35
 
#ifndef __RCSID
36
 
#define __RCSID(arg)
37
 
#endif
38
 
#ifndef lint
39
 
#if !defined(BUILTIN) && !defined(SHELL)
40
 
__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
41
 
        The Regents of the University of California.  All rights reserved.\n");
42
 
#endif
43
 
#endif
44
 
 
45
 
#ifndef lint
46
 
#if 0
47
 
static char sccsid[] = "@(#)printf.c    8.2 (Berkeley) 3/22/95";
48
 
#else
49
 
__RCSID("$NetBSD: printf.c,v 1.28 2003/06/25 12:56:59 dsl Exp $");
50
 
#endif
51
 
#endif /* not lint */
52
 
 
53
 
#include <sys/types.h>
54
 
 
55
 
#include <ctype.h>
56
 
#ifndef __KLIBC__
57
 
#include <err.h>
58
 
#endif
59
 
#include <errno.h>
60
 
#include <inttypes.h>
61
 
#include <limits.h>
62
 
#ifdef HAVE_LOCALE_H
63
 
#include <locale.h>
64
 
#endif
65
 
#include <stdarg.h>
66
 
#include <stdio.h>
67
 
#include <stdlib.h>
68
 
#include <string.h>
69
 
#include <unistd.h>
70
 
 
71
 
#ifdef __linux__
72
 
#include "compat_linux.h"
73
 
#endif
74
 
 
75
 
#ifdef __GNUC__
76
 
#define ESCAPE '\e'
77
 
#else
78
 
#define ESCAPE 033
79
 
#endif
80
 
 
81
 
static void      conv_escape_str(char *, void (*)(int));
82
 
static char     *conv_escape(char *, char *);
83
 
static char     *conv_expand(const char *);
84
 
static int       getchr(void);
85
 
#ifndef __KLIBC__
86
 
static double    getdouble(void);
87
 
#endif
88
 
static int       getwidth(void);
89
 
static intmax_t  getintmax(void);
90
 
static uintmax_t getuintmax(void);
91
 
static char     *getstr(void);
92
 
static char     *mklong(const char *, int);
93
 
static void      check_conversion(const char *, const char *);
94
 
static void      usage(void); 
95
 
 
96
 
static void     b_count(int);
97
 
static void     b_output(int);
98
 
static int      b_length;
99
 
static char     *b_fmt;
100
 
 
101
 
static int      rval;
102
 
static char  **gargv;
103
 
 
104
 
#ifdef BUILTIN          /* csh builtin */
105
 
#define main progprintf
106
 
#endif
107
 
 
108
 
#ifdef SHELL            /* sh (aka ash) builtin */
109
 
#define main printfcmd
110
 
#include "bltin/bltin.h"
111
 
#endif /* SHELL */
112
 
 
113
 
#define PF(f, func) { \
114
 
        if (fieldwidth != -1) { \
115
 
                if (precision != -1) \
116
 
                        (void)printf(f, fieldwidth, precision, func); \
117
 
                else \
118
 
                        (void)printf(f, fieldwidth, func); \
119
 
        } else if (precision != -1) \
120
 
                (void)printf(f, precision, func); \
121
 
        else \
122
 
                (void)printf(f, func); \
123
 
}
124
 
 
125
 
#define APF(cpp, f, func) { \
126
 
        if (fieldwidth != -1) { \
127
 
                if (precision != -1) \
128
 
                        (void)asprintf(cpp, f, fieldwidth, precision, func); \
129
 
                else \
130
 
                        (void)asprintf(cpp, f, fieldwidth, func); \
131
 
        } else if (precision != -1) \
132
 
                (void)asprintf(cpp, f, precision, func); \
133
 
        else \
134
 
                (void)asprintf(cpp, f, func); \
135
 
}
136
 
 
137
 
int main(int, char **);
138
 
int main(int argc, char *argv[])
139
 
{
140
 
        char *fmt, *start;
141
 
        int fieldwidth, precision;
142
 
        char nextch;
143
 
        char *format;
144
 
        int ch;
145
 
 
146
 
#if !defined(SHELL) && !defined(BUILTIN)
147
 
        (void)setlocale (LC_ALL, "");
148
 
#endif
149
 
 
150
 
        while ((ch = getopt(argc, argv, "")) != -1) {
151
 
                switch (ch) {
152
 
                case '?':
153
 
                default:
154
 
                        usage();
155
 
                        return (1);
156
 
                }
157
 
        }
158
 
        argc -= optind;
159
 
        argv += optind;
160
 
 
161
 
        if (argc < 1) {
162
 
                usage();
163
 
                return (1);
164
 
        }
165
 
 
166
 
        format = *argv;
167
 
        gargv = ++argv;
168
 
 
169
 
#define SKIP1   "#-+ 0"
170
 
#define SKIP2   "*0123456789"
171
 
        do {
172
 
                /*
173
 
                 * Basic algorithm is to scan the format string for conversion
174
 
                 * specifications -- once one is found, find out if the field
175
 
                 * width or precision is a '*'; if it is, gather up value. 
176
 
                 * Note, format strings are reused as necessary to use up the
177
 
                 * provided arguments, arguments of zero/null string are 
178
 
                 * provided to use up the format string.
179
 
                 */
180
 
 
181
 
                /* find next format specification */
182
 
                for (fmt = format; (ch = *fmt++) ;) {
183
 
                        if (ch == '\\') {
184
 
                                char c_ch;
185
 
                                fmt = conv_escape(fmt, &c_ch);
186
 
                                putchar(c_ch);
187
 
                                continue;
188
 
                        }
189
 
                        if (ch != '%' || (*fmt == '%' && ++fmt)) {
190
 
                                (void)putchar(ch);
191
 
                                continue;
192
 
                        }
193
 
 
194
 
                        /* Ok - we've found a format specification,
195
 
                           Save its address for a later printf(). */
196
 
                        start = fmt - 1;
197
 
 
198
 
                        /* skip to field width */
199
 
                        fmt += strspn(fmt, SKIP1);
200
 
                        fieldwidth = *fmt == '*' ? getwidth() : -1;
201
 
 
202
 
                        /* skip to possible '.', get following precision */
203
 
                        fmt += strspn(fmt, SKIP2);
204
 
                        if (*fmt == '.')
205
 
                                ++fmt;
206
 
                        precision = *fmt == '*' ? getwidth() : -1;
207
 
 
208
 
                        fmt += strspn(fmt, SKIP2);
209
 
 
210
 
                        ch = *fmt;
211
 
                        if (!ch) {
212
 
                                warnx("missing format character");
213
 
                                return (1);
214
 
                        }
215
 
                        /* null terminate format string to we can use it
216
 
                           as an argument to printf. */
217
 
                        nextch = fmt[1];
218
 
                        fmt[1] = 0;
219
 
                        switch (ch) {
220
 
 
221
 
                        case 'B': {
222
 
                                const char *p = conv_expand(getstr());
223
 
                                *fmt = 's';
224
 
                                PF(start, p);
225
 
                                break;
226
 
                        }
227
 
                        case 'b': {
228
 
                                /* There has to be a better way to do this,
229
 
                                 * but the string we generate might have
230
 
                                 * embedded nulls. */
231
 
                                static char *a, *t;
232
 
                                char *cp = getstr();
233
 
                                /* Free on entry in case shell longjumped out */
234
 
                                if (a != NULL)
235
 
                                        free(a);
236
 
                                a = NULL;
237
 
                                if (t != NULL)
238
 
                                        free(t);
239
 
                                t = NULL;
240
 
                                /* Count number of bytes we want to output */
241
 
                                b_length = 0;
242
 
                                conv_escape_str(cp, b_count);
243
 
                                t = malloc(b_length + 1);
244
 
                                if (t == NULL)
245
 
                                        break;
246
 
                                memset(t, 'x', b_length);
247
 
                                t[b_length] = 0;
248
 
                                /* Get printf to calculate the lengths */
249
 
                                *fmt = 's';
250
 
                                APF(&a, start, t);
251
 
                                b_fmt = a;
252
 
                                /* Output leading spaces and data bytes */
253
 
                                conv_escape_str(cp, b_output);
254
 
                                /* Add any trailing spaces */
255
 
                                printf("%s", b_fmt);
256
 
                                break;
257
 
                        }
258
 
                        case 'c': {
259
 
                                char p = getchr();
260
 
                                PF(start, p);
261
 
                                break;
262
 
                        }
263
 
                        case 's': {
264
 
                                char *p = getstr();
265
 
                                PF(start, p);
266
 
                                break;
267
 
                        }
268
 
                        case 'd':
269
 
                        case 'i': {
270
 
                                intmax_t p = getintmax();
271
 
                                char *f = mklong(start, ch);
272
 
                                PF(f, p);
273
 
                                break;
274
 
                        }
275
 
                        case 'o':
276
 
                        case 'u':
277
 
                        case 'x':
278
 
                        case 'X': {
279
 
                                uintmax_t p = getuintmax();
280
 
                                char *f = mklong(start, ch);
281
 
                                PF(f, p);
282
 
                                break;
283
 
                        }
284
 
#ifndef __KLIBC__
285
 
                        case 'e':
286
 
                        case 'E':
287
 
                        case 'f':
288
 
                        case 'g':
289
 
                        case 'G': {
290
 
                                double p = getdouble();
291
 
                                PF(start, p);
292
 
                                break;
293
 
                        }
294
 
#endif
295
 
                        default:
296
 
                                warnx("%s: invalid directive", start);
297
 
                                return (1);
298
 
                        }
299
 
                        *fmt++ = ch;
300
 
                        *fmt = nextch;
301
 
                        /* escape if a \c was encountered */
302
 
                        if (rval & 0x100)
303
 
                                return (rval & ~0x100);
304
 
                }
305
 
        } while (gargv != argv && *gargv);
306
 
 
307
 
        return (rval);
308
 
}
309
 
 
310
 
/* helper functions for conv_escape_str */
311
 
 
312
 
static void
313
 
b_count(int ch)
314
 
{
315
 
        b_length++;
316
 
}
317
 
 
318
 
/* Output one converted character for every 'x' in the 'format' */
319
 
 
320
 
static void
321
 
b_output(int ch)
322
 
{
323
 
        for (;;) {
324
 
                switch (*b_fmt++) {
325
 
                case 0:
326
 
                        b_fmt--;
327
 
                        return;
328
 
                case ' ':
329
 
                        putchar(' ');
330
 
                        break;
331
 
                default:
332
 
                        putchar(ch);
333
 
                        return;
334
 
                }
335
 
        }
336
 
}
337
 
 
338
 
 
339
 
/*
340
 
 * Print SysV echo(1) style escape string 
341
 
 *      Halts processing string if a \c escape is encountered.
342
 
 */
343
 
static void
344
 
conv_escape_str(char *str, void (*do_putchar)(int))
345
 
{
346
 
        int value;
347
 
        int ch;
348
 
        char c;
349
 
 
350
 
        while ((ch = *str++)) {
351
 
                if (ch != '\\') {
352
 
                        do_putchar(ch);
353
 
                        continue;
354
 
                }
355
 
 
356
 
                ch = *str++;
357
 
                if (ch == 'c') {
358
 
                        /* \c as in SYSV echo - abort all processing.... */
359
 
                        rval |= 0x100;
360
 
                        break;
361
 
                }
362
 
 
363
 
                /* 
364
 
                 * %b string octal constants are not like those in C.
365
 
                 * They start with a \0, and are followed by 0, 1, 2, 
366
 
                 * or 3 octal digits. 
367
 
                 */
368
 
                if (ch == '0') {
369
 
                        char octnum[4], *oct_end;
370
 
                        octnum[0] = str[0];
371
 
                        octnum[1] = str[1];
372
 
                        octnum[2] = str[2];
373
 
                        octnum[3] = 0;
374
 
                        do_putchar(strtoul(octnum, &oct_end, 8));
375
 
                        str += oct_end - octnum;
376
 
                        continue;
377
 
                }
378
 
 
379
 
                /* \[M][^|-]C as defined by vis(3) */
380
 
                if (ch == 'M' && *str == '-') {
381
 
                        do_putchar(0200 | str[1]);
382
 
                        str += 2;
383
 
                        continue;
384
 
                }
385
 
                if (ch == 'M' && *str == '^') {
386
 
                        str++;
387
 
                        value = 0200;
388
 
                        ch = '^';
389
 
                } else
390
 
                        value = 0;
391
 
                if (ch == '^') {
392
 
                        ch = *str++;
393
 
                        if (ch == '?')
394
 
                                value |= 0177;
395
 
                        else
396
 
                                value |= ch & 037;
397
 
                        do_putchar(value);
398
 
                        continue;
399
 
                }
400
 
 
401
 
                /* Finally test for sequences valid in the format string */
402
 
                str = conv_escape(str - 1, &c);
403
 
                do_putchar(c);
404
 
        }
405
 
}
406
 
 
407
 
/*
408
 
 * Print "standard" escape characters 
409
 
 */
410
 
static char *
411
 
conv_escape(char *str, char *conv_ch)
412
 
{
413
 
        int value;
414
 
        int ch;
415
 
        char num_buf[4], *num_end;
416
 
 
417
 
        ch = *str++;
418
 
 
419
 
        switch (ch) {
420
 
        case '0': case '1': case '2': case '3':
421
 
        case '4': case '5': case '6': case '7':
422
 
                num_buf[0] = ch;
423
 
                ch = str[0];
424
 
                num_buf[1] = ch;
425
 
                num_buf[2] = ch ? str[1] : 0;
426
 
                num_buf[3] = 0;
427
 
                value = strtoul(num_buf, &num_end, 8);
428
 
                str += num_end  - (num_buf + 1);
429
 
                break;
430
 
 
431
 
        case 'x':
432
 
                /* Hexadecimal character constants are not required to be
433
 
                   supported (by SuS v1) because there is no consistent
434
 
                   way to detect the end of the constant.
435
 
                   Supporting 2 byte constants is a compromise. */
436
 
                ch = str[0];
437
 
                num_buf[0] = ch;
438
 
                num_buf[1] = ch ? str[1] : 0;
439
 
                num_buf[2] = 0;
440
 
                value = strtoul(num_buf, &num_end, 16);
441
 
                str += num_end - num_buf;
442
 
                break;
443
 
 
444
 
        case '\\':      value = '\\';   break;  /* backslash */
445
 
        case '\'':      value = '\'';   break;  /* single quote */
446
 
        case '"':       value = '"';    break;  /* double quote */
447
 
        case 'a':       value = '\a';   break;  /* alert */
448
 
        case 'b':       value = '\b';   break;  /* backspace */
449
 
        case 'e':       value = ESCAPE; break;  /* escape */
450
 
        case 'f':       value = '\f';   break;  /* form-feed */
451
 
        case 'n':       value = '\n';   break;  /* newline */
452
 
        case 'r':       value = '\r';   break;  /* carriage-return */
453
 
        case 't':       value = '\t';   break;  /* tab */
454
 
        case 'v':       value = '\v';   break;  /* vertical-tab */
455
 
 
456
 
        default:
457
 
                warnx("unknown escape sequence `\\%c'", ch);
458
 
                rval = 1;
459
 
                value = ch;
460
 
                break;
461
 
        }
462
 
 
463
 
        *conv_ch = value;
464
 
        return str;
465
 
}
466
 
 
467
 
/* expand a string so that everything is printable */
468
 
 
469
 
static char *
470
 
conv_expand(const char *str)
471
 
{
472
 
        static char *conv_str;
473
 
        char *cp;
474
 
        int ch;
475
 
 
476
 
        if (conv_str)
477
 
                free(conv_str);
478
 
        /* get a buffer that is definitely large enough.... */
479
 
        conv_str = malloc(4 * strlen(str) + 1);
480
 
        if (!conv_str)
481
 
                return "<no memory>";
482
 
        cp = conv_str;
483
 
 
484
 
        while ((ch = *(unsigned char *)str++)) {
485
 
                switch (ch) {
486
 
                /* Use C escapes for expected control characters */
487
 
                case '\\':      ch = '\\';      break;  /* backslash */
488
 
                case '\'':      ch = '\'';      break;  /* single quote */
489
 
                case '"':       ch = '"';       break;  /* double quote */
490
 
                case '\a':      ch = 'a';       break;  /* alert */
491
 
                case '\b':      ch = 'b';       break;  /* backspace */
492
 
                case ESCAPE:    ch = 'e';       break;  /* escape */
493
 
                case '\f':      ch = 'f';       break;  /* form-feed */
494
 
                case '\n':      ch = 'n';       break;  /* newline */
495
 
                case '\r':      ch = 'r';       break;  /* carriage-return */
496
 
                case '\t':      ch = 't';       break;  /* tab */
497
 
                case '\v':      ch = 'v';       break;  /* vertical-tab */
498
 
                default:
499
 
                        /* Copy anything printable */
500
 
                        if (isprint(ch)) {
501
 
                                *cp++ = ch;
502
 
                                continue;
503
 
                        }
504
 
                        /* Use vis(3) encodings for the rest */
505
 
                        *cp++ = '\\';
506
 
                        if (ch & 0200) {
507
 
                                *cp++ = 'M';
508
 
                                ch &= ~0200;
509
 
                        }
510
 
                        if (ch == 0177) {
511
 
                                *cp++ = '^';
512
 
                                *cp++ = '?';
513
 
                                continue;
514
 
                        }
515
 
                        if (ch < 040) {
516
 
                                *cp++ = '^';
517
 
                                *cp++ = ch | 0100;
518
 
                                continue;
519
 
                        }
520
 
                        *cp++ = '-';
521
 
                        *cp++ = ch;
522
 
                        continue;
523
 
                }
524
 
                *cp++ = '\\';
525
 
                *cp++ = ch;
526
 
        }
527
 
 
528
 
        *cp = 0;
529
 
        return conv_str;
530
 
}
531
 
 
532
 
static char *
533
 
mklong(const char *str, int ch)
534
 
{
535
 
        static char copy[64];
536
 
        size_t len;     
537
 
 
538
 
        len = strlen(str) + 2;
539
 
        if (len > sizeof copy) {
540
 
                warnx("format %s too complex\n", str);
541
 
                len = 4;
542
 
        }
543
 
        (void)memmove(copy, str, len - 3);
544
 
        copy[len - 3] = 'j';
545
 
        copy[len - 2] = ch;
546
 
        copy[len - 1] = '\0';
547
 
        return (copy);  
548
 
}
549
 
 
550
 
static int
551
 
getchr(void)
552
 
{
553
 
        if (!*gargv)
554
 
                return ('\0');
555
 
        return ((int)**gargv++);
556
 
}
557
 
 
558
 
static char *
559
 
getstr(void)
560
 
{
561
 
        if (!*gargv)
562
 
                return ("");
563
 
        return (*gargv++);
564
 
}
565
 
 
566
 
static int
567
 
getwidth(void)
568
 
{
569
 
        long val;
570
 
        char *s, *ep;
571
 
 
572
 
        s = *gargv;
573
 
        if (!*gargv)
574
 
                return (0);
575
 
        gargv++;
576
 
 
577
 
        errno = 0;
578
 
        val = strtoul(s, &ep, 0);
579
 
        check_conversion(s, ep);
580
 
 
581
 
        /* Arbitrarily 'restrict' field widths to 1Mbyte */
582
 
        if (val < 0 || val > 1 << 20) {
583
 
                warnx("%s: invalid field width", s);
584
 
                return 0;
585
 
        }
586
 
 
587
 
        return val;
588
 
}
589
 
 
590
 
static intmax_t
591
 
getintmax(void)
592
 
{
593
 
        intmax_t val;
594
 
        char *cp, *ep;
595
 
 
596
 
        cp = *gargv;
597
 
        if (cp == NULL)
598
 
                return 0;
599
 
        gargv++;
600
 
 
601
 
        if (*cp == '\"' || *cp == '\'')
602
 
                return *(cp+1);
603
 
 
604
 
        errno = 0;
605
 
        val = strtoimax(cp, &ep, 0);
606
 
        check_conversion(cp, ep);
607
 
        return val;
608
 
}
609
 
 
610
 
static uintmax_t
611
 
getuintmax(void)
612
 
{
613
 
        uintmax_t val;
614
 
        char *cp, *ep;
615
 
 
616
 
        cp = *gargv;
617
 
        if (cp == NULL)
618
 
                return 0;
619
 
        gargv++;
620
 
 
621
 
        if (*cp == '\"' || *cp == '\'')
622
 
                return *(cp+1);
623
 
 
624
 
        /* strtoumax won't error -ve values */
625
 
        while (isspace(*(unsigned char *)cp))
626
 
                cp++;
627
 
        if (*cp == '-') {
628
 
                warnx("%s: expected positive numeric value", cp);
629
 
                rval = 1;
630
 
                return 0;
631
 
        }
632
 
 
633
 
        errno = 0;
634
 
        val = strtoumax(cp, &ep, 0);
635
 
        check_conversion(cp, ep);
636
 
        return val;
637
 
}
638
 
 
639
 
#ifndef __KLIBC__
640
 
static double
641
 
getdouble(void)
642
 
{
643
 
        double val;
644
 
        char *ep;
645
 
 
646
 
        if (!*gargv)
647
 
                return (0.0);
648
 
 
649
 
        if (**gargv == '\"' || **gargv == '\'')
650
 
                return (double) *((*gargv++)+1);
651
 
 
652
 
        errno = 0;
653
 
        val = strtod(*gargv, &ep);
654
 
        check_conversion(*gargv++, ep);
655
 
        return val;
656
 
}
657
 
#endif
658
 
 
659
 
static void
660
 
check_conversion(const char *s, const char *ep)
661
 
{
662
 
        if (*ep) {
663
 
                if (ep == s)
664
 
                        warnx("%s: expected numeric value", s);
665
 
                else
666
 
                        warnx("%s: not completely converted", s);
667
 
                rval = 1;
668
 
        } else if (errno == ERANGE) {
669
 
                warnx("%s: %s", s, strerror(ERANGE));
670
 
                rval = 1;
671
 
        }
672
 
}
673
 
 
674
 
static void
675
 
usage(void)
676
 
{
677
 
        (void)fprintf(stderr, "usage: printf format [arg ...]\n");
678
 
}