Remove declaration of statfs.
[coreutils.git] / src / printf.c
blob8c1ba1755b59d96ec998c3307959b378ef4ab37b
1 /* printf - format and print data
2 Copyright (C) 1990-2002, 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 \xhh = hexadecimal number (hhh is 1 to 2 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. */
83 static char *const cfcc_msg =
84 N_("warning: %s: character(s) following character constant have been ignored");
86 /* The name this program was run with. */
87 char *program_name;
89 void
90 usage (int status)
92 if (status != 0)
93 fprintf (stderr, _("Try `%s --help' for more information.\n"),
94 program_name);
95 else
97 printf (_("\
98 Usage: %s FORMAT [ARGUMENT]...\n\
99 or: %s OPTION\n\
101 program_name, program_name);
102 fputs (_("\
103 Print ARGUMENT(s) according to FORMAT.\n\
105 "), stdout);
106 fputs (HELP_OPTION_DESCRIPTION, stdout);
107 fputs (VERSION_OPTION_DESCRIPTION, stdout);
108 fputs (_("\
110 FORMAT controls the output as in C printf. Interpreted sequences are:\n\
112 \\\" double quote\n\
113 \\0NNN character with octal value NNN (0 to 3 digits)\n\
114 \\\\ backslash\n\
115 "), stdout);
116 fputs (_("\
117 \\a alert (BEL)\n\
118 \\b backspace\n\
119 \\c produce no further output\n\
120 \\f form feed\n\
121 "), stdout);
122 fputs (_("\
123 \\n new line\n\
124 \\r carriage return\n\
125 \\t horizontal tab\n\
126 \\v vertical tab\n\
127 "), stdout);
128 fputs (_("\
129 \\xNN byte with hexadecimal value NN (1 to 2 digits)\n\
131 \\uNNNN character with hexadecimal value NNNN (4 digits)\n\
132 \\UNNNNNNNN character with hexadecimal value NNNNNNNN (8 digits)\n\
133 "), stdout);
134 fputs (_("\
135 %% a single %\n\
136 %b ARGUMENT as a string with `\\' escapes interpreted\n\
138 and all C format specifications ending with one of diouxXfeEgGcs, with\n\
139 ARGUMENTs converted to proper type first. Variable widths are handled.\n\
140 "), stdout);
141 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
143 exit (status);
146 static void
147 verify (const char *s, const char *end)
149 if (errno)
151 error (0, errno, "%s", s);
152 exit_status = 1;
154 else if (*end)
156 if (s == end)
157 error (0, 0, _("%s: expected a numeric value"), s);
158 else
159 error (0, 0, _("%s: value not completely converted"), s);
160 exit_status = 1;
164 #define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR) \
165 static TYPE \
166 FUNC_NAME (s) \
167 const char *s; \
169 char *end; \
170 TYPE val; \
172 if (*s == '\"' || *s == '\'') \
174 val = *(unsigned char *) ++s; \
175 /* If POSIXLY_CORRECT is not set, then give a warning that there \
176 are characters following the character constant and that GNU \
177 printf is ignoring those characters. If POSIXLY_CORRECT *is* \
178 set, then don't give the warning. */ \
179 if (*++s != 0 && !posixly_correct) \
180 error (0, 0, _(cfcc_msg), s); \
182 else \
184 errno = 0; \
185 val = LIB_FUNC_EXPR; \
186 verify (s, end); \
188 return val; \
191 STRTOX (unsigned long int, xstrtoul, (strtoul (s, &end, 0)))
192 STRTOX (long int, xstrtol, (strtol (s, &end, 0)))
193 STRTOX (double, xstrtod, (strtod (s, &end)))
195 /* Output a single-character \ escape. */
197 static void
198 print_esc_char (int c)
200 switch (c)
202 case 'a': /* Alert. */
203 putchar (7);
204 break;
205 case 'b': /* Backspace. */
206 putchar (8);
207 break;
208 case 'c': /* Cancel the rest of the output. */
209 exit (EXIT_SUCCESS);
210 break;
211 case 'f': /* Form feed. */
212 putchar (12);
213 break;
214 case 'n': /* New line. */
215 putchar (10);
216 break;
217 case 'r': /* Carriage return. */
218 putchar (13);
219 break;
220 case 't': /* Horizontal tab. */
221 putchar (9);
222 break;
223 case 'v': /* Vertical tab. */
224 putchar (11);
225 break;
226 default:
227 putchar (c);
228 break;
232 /* Print a \ escape sequence starting at ESCSTART.
233 Return the number of characters in the escape sequence
234 besides the backslash. */
236 static int
237 print_esc (const char *escstart)
239 register const char *p = escstart + 1;
240 int esc_value = 0; /* Value of \nnn escape. */
241 int esc_length; /* Length of \nnn escape. */
243 if (*p == 'x')
245 /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */
246 for (esc_length = 0, ++p;
247 esc_length < 2 && ISXDIGIT (*p);
248 ++esc_length, ++p)
249 esc_value = esc_value * 16 + hextobin (*p);
250 if (esc_length == 0)
251 error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));
252 putchar (esc_value);
254 else if (*p == '0')
256 /* An octal \0ooo escape sequence has 0 to 3 octal digits
257 after the leading \0. */
258 for (esc_length = 0, ++p;
259 esc_length < 3 && isodigit (*p);
260 ++esc_length, ++p)
261 esc_value = esc_value * 8 + octtobin (*p);
262 putchar (esc_value);
264 else if (strchr ("\"\\abcfnrtv", *p))
265 print_esc_char (*p++);
266 else if (!posixly_correct && (*p == 'u' || *p == 'U'))
268 char esc_char = *p;
269 unsigned int uni_value;
271 uni_value = 0;
272 for (esc_length = (esc_char == 'u' ? 4 : 8), ++p;
273 esc_length > 0;
274 --esc_length, ++p)
276 if (!ISXDIGIT (*p))
277 error (EXIT_FAILURE, 0, _("missing hexadecimal number in escape"));
278 uni_value = uni_value * 16 + hextobin (*p);
281 /* A universal character name shall not specify a character short
282 identifier in the range 00000000 through 00000020, 0000007F through
283 0000009F, or 0000D800 through 0000DFFF inclusive. A universal
284 character name shall not designate a character in the required
285 character set. */
286 if ((uni_value >= 0x00 && uni_value <= 0x9f
287 && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60)
288 || (uni_value >= 0xd800 && uni_value <= 0xdfff))
289 error (EXIT_FAILURE, 0, _("invalid universal character name \\%c%0*x"),
290 esc_char, (esc_char == 'u' ? 4 : 8), uni_value);
292 print_unicode_char (stdout, uni_value, 0);
294 else
295 error (EXIT_FAILURE, 0, _("\\%c: invalid escape"), *p);
296 return p - escstart - 1;
299 /* Print string STR, evaluating \ escapes. */
301 static void
302 print_esc_string (const char *str)
304 for (; *str; str++)
305 if (*str == '\\')
306 str += print_esc (str);
307 else
308 putchar (*str);
311 /* Output a % directive. START is the start of the directive,
312 LENGTH is its length, and ARGUMENT is its argument.
313 If FIELD_WIDTH or PRECISION is non-negative, they are args for
314 '*' values in those fields. */
316 static void
317 print_direc (const char *start, size_t length, int field_width,
318 int precision, const char *argument)
320 char *p; /* Null-terminated copy of % directive. */
322 p = xmalloc ((unsigned) (length + 1));
323 strncpy (p, start, length);
324 p[length] = 0;
326 switch (p[length - 1])
328 case 'd':
329 case 'i':
330 if (field_width < 0)
332 if (precision < 0)
333 printf (p, xstrtol (argument));
334 else
335 printf (p, precision, xstrtol (argument));
337 else
339 if (precision < 0)
340 printf (p, field_width, xstrtol (argument));
341 else
342 printf (p, field_width, precision, xstrtol (argument));
344 break;
346 case 'o':
347 case 'u':
348 case 'x':
349 case 'X':
350 if (field_width < 0)
352 if (precision < 0)
353 printf (p, xstrtoul (argument));
354 else
355 printf (p, precision, xstrtoul (argument));
357 else
359 if (precision < 0)
360 printf (p, field_width, xstrtoul (argument));
361 else
362 printf (p, field_width, precision, xstrtoul (argument));
364 break;
366 case 'f':
367 case 'e':
368 case 'E':
369 case 'g':
370 case 'G':
371 if (field_width < 0)
373 if (precision < 0)
374 printf (p, xstrtod (argument));
375 else
376 printf (p, precision, xstrtod (argument));
378 else
380 if (precision < 0)
381 printf (p, field_width, xstrtod (argument));
382 else
383 printf (p, field_width, precision, xstrtod (argument));
385 break;
387 case 'c':
388 printf (p, *argument);
389 break;
391 case 's':
392 if (field_width < 0)
394 if (precision < 0)
395 printf (p, argument);
396 else
397 printf (p, precision, argument);
399 else
401 if (precision < 0)
402 printf (p, field_width, argument);
403 else
404 printf (p, field_width, precision, argument);
406 break;
409 free (p);
412 /* Print the text in FORMAT, using ARGV (with ARGC elements) for
413 arguments to any `%' directives.
414 Return the number of elements of ARGV used. */
416 static int
417 print_formatted (const char *format, int argc, char **argv)
419 int save_argc = argc; /* Preserve original value. */
420 const char *f; /* Pointer into `format'. */
421 const char *direc_start; /* Start of % directive. */
422 size_t direc_length; /* Length of % directive. */
423 int field_width; /* Arg to first '*', or -1 if none. */
424 int precision; /* Arg to second '*', or -1 if none. */
426 for (f = format; *f; ++f)
428 switch (*f)
430 case '%':
431 direc_start = f++;
432 direc_length = 1;
433 field_width = precision = -1;
434 if (*f == '%')
436 putchar ('%');
437 break;
439 if (*f == 'b')
441 if (argc > 0)
443 print_esc_string (*argv);
444 ++argv;
445 --argc;
447 break;
449 if (strchr ("-+ #", *f))
451 ++f;
452 ++direc_length;
454 if (*f == '*')
456 ++f;
457 ++direc_length;
458 if (argc > 0)
460 field_width = xstrtoul (*argv);
461 ++argv;
462 --argc;
464 else
465 field_width = 0;
467 else
468 while (ISDIGIT (*f))
470 ++f;
471 ++direc_length;
473 if (*f == '.')
475 ++f;
476 ++direc_length;
477 if (*f == '*')
479 ++f;
480 ++direc_length;
481 if (argc > 0)
483 precision = xstrtoul (*argv);
484 ++argv;
485 --argc;
487 else
488 precision = 0;
490 else
491 while (ISDIGIT (*f))
493 ++f;
494 ++direc_length;
497 if (*f == 'l' || *f == 'L' || *f == 'h')
499 ++f;
500 ++direc_length;
502 if (!strchr ("diouxXfeEgGcs", *f))
503 error (EXIT_FAILURE, 0, _("%%%c: invalid directive"), *f);
504 ++direc_length;
505 if (argc > 0)
507 print_direc (direc_start, direc_length, field_width,
508 precision, *argv);
509 ++argv;
510 --argc;
512 else
513 print_direc (direc_start, direc_length, field_width,
514 precision, "");
515 break;
517 case '\\':
518 f += print_esc (f);
519 break;
521 default:
522 putchar (*f);
526 return save_argc - argc;
530 main (int argc, char **argv)
532 char *format;
533 int args_used;
535 program_name = argv[0];
536 setlocale (LC_ALL, "");
537 bindtextdomain (PACKAGE, LOCALEDIR);
538 textdomain (PACKAGE);
540 atexit (close_stdout);
542 exit_status = 0;
544 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
545 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
546 if (!posixly_correct)
547 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
548 AUTHORS, usage);
550 /* The above handles --help and --version.
551 Since there is no other invocation of getopt, handle `--' here. */
552 if (1 < argc && STREQ (argv[1], "--"))
554 --argc;
555 ++argv;
558 if (argc == 1)
560 fprintf (stderr, _("Usage: %s format [argument...]\n"), program_name);
561 exit (EXIT_FAILURE);
564 format = argv[1];
565 argc -= 2;
566 argv += 2;
570 args_used = print_formatted (format, argc, argv);
571 argc -= args_used;
572 argv += args_used;
574 while (args_used > 0 && argc > 0);
576 if (argc > 0)
577 error (0, 0,
578 _("warning: ignoring excess arguments, starting with `%s'"),
579 argv[0]);
581 exit (exit_status);