]>
git.saurik.com Git - apple/shell_cmds.git/blob - printf/printf.c
1 /* $NetBSD: printf.c,v 1.19 1998/02/03 03:10:15 perry Exp $ */
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. 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
36 #include <sys/cdefs.h>
38 #if !defined(BUILTIN) && !defined(SHELL)
39 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
40 The Regents of the University of California. All rights reserved.\n");
46 static char sccsid
[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95";
48 __RCSID("$NetBSD: printf.c,v 1.19 1998/02/03 03:10:15 perry Exp $");
52 #include <sys/types.h>
65 static int print_escape_str
__P((const char *));
66 static size_t print_escape
__P((const char *));
68 static int getchr
__P((void));
69 static double getdouble
__P((void));
70 static int getint
__P((void));
71 static long getlong
__P((void));
72 static unsigned long getulong
__P ((void));
73 static char *getstr
__P((void));
74 static char *mklong
__P((const char *, int));
75 static void check_conversion
__P((const char *, const char *));
76 static void usage
__P((void));
82 int progprintf
__P((int, char **));
84 int main
__P((int, char **));
87 #define isodigit(c) ((c) >= '0' && (c) <= '7')
88 #define octtobin(c) ((c) - '0')
89 #define hextobin(c) ((c) >= 'A' && (c) <= 'F' ? c - 'A' + 10 : (c) >= 'a' && (c) <= 'f' ? c - 'a' + 10 : c - '0')
92 #define main printfcmd
94 #include "bltin/bltin.h"
96 #include "../../bin/sh/bltin/bltin.h"
105 static void warnx
__P((const char *fmt
, ...));
109 warnx(const char *fmt
, ...)
125 vsprintf(buf
, fmt
, ap
);
132 #define PF(f, func) { \
135 (void)printf(f, fieldwidth, precision, func); \
137 (void)printf(f, fieldwidth, func); \
138 else if (precision) \
139 (void)printf(f, precision, func); \
141 (void)printf(f, func); \
146 progprintf(argc
, argv
)
154 int fieldwidth
, precision
;
159 #if !defined(SHELL) && !defined(BUILTIN)
160 (void)setlocale (LC_ALL
, "");
163 while ((ch
= getopt(argc
, argv
, "")) != -1) {
182 #define SKIP1 "#-+ 0"
183 #define SKIP2 "*0123456789"
186 * Basic algorithm is to scan the format string for conversion
187 * specifications -- once one is found, find out if the field
188 * width or precision is a '*'; if it is, gather up value.
189 * Note, format strings are reused as necessary to use up the
190 * provided arguments, arguments of zero/null string are
191 * provided to use up the format string.
194 /* find next format specification */
195 for (fmt
= format
; *fmt
; fmt
++) {
203 } else if (*fmt
== 'b') {
205 if (print_escape_str(p
)) {
211 /* skip to field width */
212 for (; strchr(SKIP1
, *fmt
); ++fmt
) ;
213 fieldwidth
= *fmt
== '*' ? getint() : 0;
215 /* skip to possible '.', get following precision */
216 for (; strchr(SKIP2
, *fmt
); ++fmt
) ;
219 precision
= *fmt
== '*' ? getint() : 0;
221 for (; strchr(SKIP2
, *fmt
); ++fmt
) ;
223 warnx ("missing format character");
243 char *f
= mklong(start
, convch
);
252 char *f
= mklong(start
, convch
);
253 unsigned long p
= getulong();
262 double p
= getdouble();
267 warnx ("%s: invalid directive", start
);
274 fmt
+= print_escape(fmt
);
282 } while (gargv
> argv
&& *gargv
);
289 * Print SysV echo(1) style escape string
290 * Halts processing string and returns 1 if a \c escape is encountered.
293 print_escape_str(str
)
303 * %b string octal constants are not like those in C.
304 * They start with a \0, and are followed by 0, 1, 2,
309 for (c
= 3, value
= 0; c
-- && isodigit(*str
); str
++) {
311 value
+= octtobin(*str
);
313 (void)putchar(value
);
315 } else if (*str
== 'c') {
319 str
+= print_escape(str
);
331 * Print "standard" escape characters
337 const char *start
= str
;
344 case '0': case '1': case '2': case '3':
345 case '4': case '5': case '6': case '7':
346 for (c
= 3, value
= 0; c
-- && isodigit(*str
); str
++) {
348 value
+= octtobin(*str
);
350 (void)putchar(value
);
351 return str
- start
- 1;
356 for (value
= 0; isxdigit(*str
); str
++) {
358 value
+= hextobin(*str
);
360 if (value
> UCHAR_MAX
) {
361 warnx ("escape sequence out of range for character");
364 (void)putchar (value
);
365 return str
- start
- 1;
368 case '\\': /* backslash */
372 case '\'': /* single quote */
376 case '"': /* double quote */
380 case 'a': /* alert */
388 case 'b': /* backspace */
392 case 'e': /* escape */
400 case 'f': /* form-feed */
404 case 'n': /* newline */
408 case 'r': /* carriage-return */
416 case 'v': /* vertical-tab */
422 warnx("unknown escape sequence `\\%c'", *str
);
435 static char copy
[64];
438 len
= strlen(str
) + 2;
439 (void)memmove(copy
, str
, len
- 3);
442 copy
[len
- 1] = '\0';
451 return ((int)**gargv
++);
462 static char *Number
= "+-.0123456789";
469 if (strchr(Number
, **gargv
))
470 return(atoi(*gargv
++));
484 if (**gargv
== '\"' || **gargv
== '\'')
485 return (long) *((*gargv
++)+1);
488 val
= strtol (*gargv
, &ep
, 0);
489 check_conversion(*gargv
++, ep
);
502 if (**gargv
== '\"' || **gargv
== '\'')
503 return (unsigned long) *((*gargv
++)+1);
506 val
= strtoul (*gargv
, &ep
, 0);
507 check_conversion(*gargv
++, ep
);
520 if (**gargv
== '\"' || **gargv
== '\'')
521 return (double) *((*gargv
++)+1);
524 val
= strtod (*gargv
, &ep
);
525 check_conversion(*gargv
++, ep
);
530 check_conversion(s
, ep
)
536 warnx ("%s: expected numeric value", s
);
538 warnx ("%s: not completely converted", s
);
540 } else if (errno
== ERANGE
) {
541 warnx ("%s: %s", s
, strerror(ERANGE
));
549 (void)fprintf(stderr
, "usage: printf format [arg ...]\n");