(jm_FILE_SYSTEM_USAGE): Add `[]' between use of
[coreutils.git] / src / printf.c
blob75b662fe63a9aea8daa3a41e3f7103dce7f39281
1 /* printf - format and print data
2 Copyright (C) 1990-2000, Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Usage: printf format [argument...]
20 A front end to the printf function that lets it be used from the shell.
22 Backslash escapes:
24 \" = double quote
25 \\ = backslash
26 \a = alert (bell)
27 \b = backspace
28 \c = produce no further output
29 \f = form feed
30 \n = new line
31 \r = carriage return
32 \t = horizontal tab
33 \v = vertical tab
34 \0ooo = octal number (ooo is 0 to 3 digits)
35 \xhhh = hexadecimal number (hhh is 1 to 3 digits)
36 \uhhhh = 16-bit Unicode character (hhhh is 4 digits)
37 \Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits)
39 Additional directive:
41 %b = print an argument string, interpreting backslash escapes
43 The `format' argument is re-used as many times as necessary
44 to convert all of the given arguments.
46 David MacKenzie <djm@gnu.ai.mit.edu> */
48 #include <config.h>
49 #include <stdio.h>
50 #include <sys/types.h>
51 #include <getopt.h>
53 #include "system.h"
54 #include "long-options.h"
55 #include "error.h"
56 #include "closeout.h"
57 #include "unicodeio.h"
59 /* The official name of this program (e.g., no `g' prefix). */
60 #define PROGRAM_NAME "printf"
62 #define AUTHORS "David MacKenzie"
64 #ifndef STDC_HEADERS
65 double strtod ();
66 long int strtol ();
67 unsigned long int strtoul ();
68 #endif
70 #define isodigit(c) ((c) >= '0' && (c) <= '7')
71 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
72 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
73 #define octtobin(c) ((c) - '0')
75 /* The value to return to the calling program. */
76 static int exit_status;
78 /* Non-zero if the POSIXLY_CORRECT environment variable is set. */
79 static int posixly_correct;
81 /* This message appears in N_() here rather than just in _() below because
82 the sole use would have been in a #define, and xgettext doesn't look for
83 strings in cpp directives. */
84 static char *const cfcc_msg =
85 N_("warning: %s: character(s) following character constant have been ignored");
87 /* The name this program was run with. */
88 char *program_name;
90 void
91 usage (int status)
93 if (status != 0)
94 fprintf (stderr, _("Try `%s --help' for more information.\n"),
95 program_name);
96 else
98 printf (_("\
99 Usage: %s FORMAT [ARGUMENT]...\n\
100 or: %s OPTION\n\
102 program_name, program_name);
103 printf (_("\
104 Print ARGUMENT(s) according to FORMAT.\n\
106 --help display this help and exit\n\
107 --version output version information and exit\n\
109 FORMAT controls the output as in C printf. Interpreted sequences are:\n\
111 \\\" double quote\n\
112 \\0NNN character with octal value NNN (0 to 3 digits)\n\
113 \\\\ backslash\n\
114 \\a alert (BEL)\n\
115 \\b backspace\n\
116 \\c produce no further output\n\
117 \\f form feed\n\
118 \\n new line\n\
119 \\r carriage return\n\
120 \\t horizontal tab\n\
121 \\v vertical tab\n\
122 \\xNNN byte with hexadecimal value NNN (1 to 3 digits)\n\
124 \\uNNNN character with hexadecimal value NNNN (4 digits)\n\
125 \\UNNNNNNNN character with hexadecimal value NNNNNNNN (8 digits)\n\
126 %%%% a single %%\n\
127 %%b ARGUMENT as a string with `\\' escapes interpreted\n\
129 and all C format specifications ending with one of diouxXfeEgGcs, with\n\
130 ARGUMENTs converted to proper type first. Variable widths are handled.\n\
131 "));
132 puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
134 exit (status);
137 static void
138 verify (const char *s, const char *end)
140 if (errno)
142 error (0, errno, "%s", s);
143 exit_status = 1;
145 else if (*end)
147 if (s == end)
148 error (0, 0, _("%s: expected a numeric value"), s);
149 else
150 error (0, 0, _("%s: value not completely converted"), s);
151 exit_status = 1;
155 #define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR) \
156 static TYPE \
157 FUNC_NAME (s) \
158 const char *s; \
160 char *end; \
161 TYPE val; \
163 if (*s == '\"' || *s == '\'') \
165 val = *(unsigned char *) ++s; \
166 /* If POSIXLY_CORRECT is not set, then give a warning that there \
167 are characters following the character constant and that GNU \
168 printf is ignoring those characters. If POSIXLY_CORRECT *is* \
169 set, then don't give the warning. */ \
170 if (*++s != 0 && !posixly_correct) \
171 error (0, 0, _(cfcc_msg), s); \
173 else \
175 errno = 0; \
176 val = LIB_FUNC_EXPR; \
177 verify (s, end); \
179 return val; \
182 STRTOX (unsigned long int, xstrtoul, (strtoul (s, &end, 0)))
183 STRTOX (long int, xstrtol, (strtol (s, &end, 0)))
184 STRTOX (double, xstrtod, (strtod (s, &end)))
186 /* Output a single-character \ escape. */
188 static void
189 print_esc_char (int c)
191 switch (c)
193 case 'a': /* Alert. */
194 putchar (7);
195 break;
196 case 'b': /* Backspace. */
197 putchar (8);
198 break;
199 case 'c': /* Cancel the rest of the output. */
200 exit (0);
201 break;
202 case 'f': /* Form feed. */
203 putchar (12);
204 break;
205 case 'n': /* New line. */
206 putchar (10);
207 break;
208 case 'r': /* Carriage return. */
209 putchar (13);
210 break;
211 case 't': /* Horizontal tab. */
212 putchar (9);
213 break;
214 case 'v': /* Vertical tab. */
215 putchar (11);
216 break;
217 default:
218 putchar (c);
219 break;
223 /* Print a \ escape sequence starting at ESCSTART.
224 Return the number of characters in the escape sequence
225 besides the backslash. */
227 static int
228 print_esc (const char *escstart)
230 register const char *p = escstart + 1;
231 int esc_value = 0; /* Value of \nnn escape. */
232 int esc_length; /* Length of \nnn escape. */
234 /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
235 if (*p == 'x')
237 for (esc_length = 0, ++p;
238 esc_length < 3 && ISXDIGIT (*p);
239 ++esc_length, ++p)
240 esc_value = esc_value * 16 + hextobin (*p);
241 if (esc_length == 0)
242 error (1, 0, _("missing hexadecimal number in escape"));
243 putchar (esc_value);
245 else if (*p == '0')
247 for (esc_length = 0, ++p;
248 esc_length < 3 && isodigit (*p);
249 ++esc_length, ++p)
250 esc_value = esc_value * 8 + octtobin (*p);
251 putchar (esc_value);
253 else if (strchr ("\"\\abcfnrtv", *p))
254 print_esc_char (*p++);
255 else if (!posixly_correct && (*p == 'u' || *p == 'U'))
257 char esc_char = *p;
258 unsigned int uni_value;
260 uni_value = 0;
261 for (esc_length = (esc_char == 'u' ? 4 : 8), ++p;
262 esc_length > 0;
263 --esc_length, ++p)
265 if (!ISXDIGIT (*p))
266 error (1, 0, _("missing hexadecimal number in escape"));
267 uni_value = uni_value * 16 + hextobin (*p);
270 /* A universal character name shall not specify a character short
271 identifier in the range 00000000 through 00000020, 0000007F through
272 0000009F, or 0000D800 through 0000DFFF inclusive. A universal
273 character name shall not designate a character in the required
274 character set. */
275 if ((uni_value >= 0x00 && uni_value <= 0x9f
276 && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60)
277 || (uni_value >= 0xd800 && uni_value <= 0xdfff))
278 error (1, 0, _("invalid universal character name \\%c%0*x"),
279 esc_char, (esc_char == 'u' ? 4 : 8), uni_value);
281 print_unicode_char (stdout, uni_value);
283 else
284 error (1, 0, _("\\%c: invalid escape"), *p);
285 return p - escstart - 1;
288 /* Print string STR, evaluating \ escapes. */
290 static void
291 print_esc_string (const char *str)
293 for (; *str; str++)
294 if (*str == '\\')
295 str += print_esc (str);
296 else
297 putchar (*str);
300 /* Output a % directive. START is the start of the directive,
301 LENGTH is its length, and ARGUMENT is its argument.
302 If FIELD_WIDTH or PRECISION is non-negative, they are args for
303 '*' values in those fields. */
305 static void
306 print_direc (const char *start, size_t length, int field_width,
307 int precision, const char *argument)
309 char *p; /* Null-terminated copy of % directive. */
311 p = xmalloc ((unsigned) (length + 1));
312 strncpy (p, start, length);
313 p[length] = 0;
315 switch (p[length - 1])
317 case 'd':
318 case 'i':
319 if (field_width < 0)
321 if (precision < 0)
322 printf (p, xstrtol (argument));
323 else
324 printf (p, precision, xstrtol (argument));
326 else
328 if (precision < 0)
329 printf (p, field_width, xstrtol (argument));
330 else
331 printf (p, field_width, precision, xstrtol (argument));
333 break;
335 case 'o':
336 case 'u':
337 case 'x':
338 case 'X':
339 if (field_width < 0)
341 if (precision < 0)
342 printf (p, xstrtoul (argument));
343 else
344 printf (p, precision, xstrtoul (argument));
346 else
348 if (precision < 0)
349 printf (p, field_width, xstrtoul (argument));
350 else
351 printf (p, field_width, precision, xstrtoul (argument));
353 break;
355 case 'f':
356 case 'e':
357 case 'E':
358 case 'g':
359 case 'G':
360 if (field_width < 0)
362 if (precision < 0)
363 printf (p, xstrtod (argument));
364 else
365 printf (p, precision, xstrtod (argument));
367 else
369 if (precision < 0)
370 printf (p, field_width, xstrtod (argument));
371 else
372 printf (p, field_width, precision, xstrtod (argument));
374 break;
376 case 'c':
377 printf (p, *argument);
378 break;
380 case 's':
381 if (field_width < 0)
383 if (precision < 0)
384 printf (p, argument);
385 else
386 printf (p, precision, argument);
388 else
390 if (precision < 0)
391 printf (p, field_width, argument);
392 else
393 printf (p, field_width, precision, argument);
395 break;
398 free (p);
401 /* Print the text in FORMAT, using ARGV (with ARGC elements) for
402 arguments to any `%' directives.
403 Return the number of elements of ARGV used. */
405 static int
406 print_formatted (const char *format, int argc, char **argv)
408 int save_argc = argc; /* Preserve original value. */
409 const char *f; /* Pointer into `format'. */
410 const char *direc_start; /* Start of % directive. */
411 size_t direc_length; /* Length of % directive. */
412 int field_width; /* Arg to first '*', or -1 if none. */
413 int precision; /* Arg to second '*', or -1 if none. */
415 for (f = format; *f; ++f)
417 switch (*f)
419 case '%':
420 direc_start = f++;
421 direc_length = 1;
422 field_width = precision = -1;
423 if (*f == '%')
425 putchar ('%');
426 break;
428 if (*f == 'b')
430 if (argc > 0)
432 print_esc_string (*argv);
433 ++argv;
434 --argc;
436 break;
438 if (strchr ("-+ #", *f))
440 ++f;
441 ++direc_length;
443 if (*f == '*')
445 ++f;
446 ++direc_length;
447 if (argc > 0)
449 field_width = xstrtoul (*argv);
450 ++argv;
451 --argc;
453 else
454 field_width = 0;
456 else
457 while (ISDIGIT (*f))
459 ++f;
460 ++direc_length;
462 if (*f == '.')
464 ++f;
465 ++direc_length;
466 if (*f == '*')
468 ++f;
469 ++direc_length;
470 if (argc > 0)
472 precision = xstrtoul (*argv);
473 ++argv;
474 --argc;
476 else
477 precision = 0;
479 else
480 while (ISDIGIT (*f))
482 ++f;
483 ++direc_length;
486 if (*f == 'l' || *f == 'L' || *f == 'h')
488 ++f;
489 ++direc_length;
491 if (!strchr ("diouxXfeEgGcs", *f))
492 error (1, 0, _("%%%c: invalid directive"), *f);
493 ++direc_length;
494 if (argc > 0)
496 print_direc (direc_start, direc_length, field_width,
497 precision, *argv);
498 ++argv;
499 --argc;
501 else
502 print_direc (direc_start, direc_length, field_width,
503 precision, "");
504 break;
506 case '\\':
507 f += print_esc (f);
508 break;
510 default:
511 putchar (*f);
515 return save_argc - argc;
519 main (int argc, char **argv)
521 char *format;
522 int args_used;
524 program_name = argv[0];
525 setlocale (LC_ALL, "");
526 bindtextdomain (PACKAGE, LOCALEDIR);
527 textdomain (PACKAGE);
529 atexit (close_stdout);
531 exit_status = 0;
533 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
534 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
535 if (!posixly_correct)
536 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
537 AUTHORS, usage);
539 if (argc == 1)
541 fprintf (stderr, _("Usage: %s format [argument...]\n"), program_name);
542 exit (1);
545 format = argv[1];
546 argc -= 2;
547 argv += 2;
551 args_used = print_formatted (format, argc, argv);
552 argc -= args_used;
553 argv += args_used;
555 while (args_used > 0 && argc > 0);
557 if (argc > 0)
558 error (0, 0, _("warning: excess arguments have been ignored"));
560 exit (exit_status);