(open_maybe_create): New function.
[coreutils.git] / src / printf.c
blobab3ae2d6a3ff3ec8a567e5a0507eb1e8e6a439b0
1 /* printf - format and print data
2 Copyright (C) 1990-1998, 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)
37 Additional directive:
39 %b = print an argument string, interpreting backslash escapes
41 The `format' argument is re-used as many times as necessary
42 to convert all of the given arguments.
44 David MacKenzie <djm@gnu.ai.mit.edu> */
46 #include <config.h>
47 #include <stdio.h>
48 #include <sys/types.h>
49 #include <getopt.h>
51 #include "system.h"
52 #include "long-options.h"
53 #include "error.h"
55 /* The official name of this program (e.g., no `g' prefix). */
56 #define PROGRAM_NAME "printf"
58 #define AUTHORS "David MacKenzie"
60 #ifndef STDC_HEADERS
61 double strtod ();
62 long int strtol ();
63 unsigned long int strtoul ();
64 #endif
66 #define isodigit(c) ((c) >= '0' && (c) <= '7')
67 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
68 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
69 #define octtobin(c) ((c) - '0')
71 /* The value to return to the calling program. */
72 static int exit_status;
74 /* Non-zero if the POSIXLY_CORRECT environment variable is set. */
75 static int posixly_correct;
77 /* This message appears in N_() here rather than just in _() below because
78 the sole use would have been in a #define, and xgettext doesn't look for
79 strings in cpp directives. */
80 static char *const cfcc_msg =
81 N_("warning: %s: character(s) following character constant have been ignored");
83 /* The name this program was run with. */
84 char *program_name;
86 void
87 usage (int status)
89 if (status != 0)
90 fprintf (stderr, _("Try `%s --help' for more information.\n"),
91 program_name);
92 else
94 printf (_("\
95 Usage: %s FORMAT [ARGUMENT]...\n\
96 or: %s OPTION\n\
97 "),
98 program_name, program_name);
99 printf (_("\
100 Print ARGUMENT(s) according to FORMAT.\n\
102 --help display this help and exit\n\
103 --version output version information and exit\n\
105 FORMAT controls the output as in C printf. Interpreted sequences are:\n\
107 \\\" double quote\n\
108 \\0NNN character with octal value NNN (0 to 3 digits)\n\
109 \\\\ backslash\n\
110 \\a alert (BEL)\n\
111 \\b backspace\n\
112 \\c produce no further output\n\
113 \\f form feed\n\
114 \\n new line\n\
115 \\r carriage return\n\
116 \\t horizontal tab\n\
117 \\v vertical tab\n\
118 \\xNNN character with hexadecimal value NNN (1 to 3 digits)\n\
120 %%%% a single %%\n\
121 %%b ARGUMENT as a string with `\\' escapes interpreted\n\
123 and all C format specifications ending with one of diouxXfeEgGcs, with\n\
124 ARGUMENTs converted to proper type first. Variable widths are handled.\n\
125 "));
126 puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
128 exit (status);
131 static void
132 verify (const char *s, const char *end)
134 if (errno)
136 error (0, errno, "%s", s);
137 exit_status = 1;
139 else if (*end)
141 if (s == end)
142 error (0, 0, _("%s: expected a numeric value"), s);
143 else
144 error (0, 0, _("%s: value not completely converted"), s);
145 exit_status = 1;
149 #define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR) \
150 static TYPE \
151 FUNC_NAME (s) \
152 const char *s; \
154 char *end; \
155 TYPE val; \
157 if (*s == '\"' || *s == '\'') \
159 val = *(unsigned char *) ++s; \
160 /* If POSIXLY_CORRECT is not set, then give a warning that there \
161 are characters following the character constant and that GNU \
162 printf is ignoring those characters. If POSIXLY_CORRECT *is* \
163 set, then don't give the warning. */ \
164 if (*++s != 0 && !posixly_correct) \
165 error (0, 0, _(cfcc_msg), s); \
167 else \
169 errno = 0; \
170 val = LIB_FUNC_EXPR; \
171 verify (s, end); \
173 return val; \
176 STRTOX (unsigned long int, xstrtoul, (strtoul (s, &end, 0)))
177 STRTOX (long int, xstrtol, (strtol (s, &end, 0)))
178 STRTOX (double, xstrtod, (strtod (s, &end)))
180 /* Output a single-character \ escape. */
182 static void
183 print_esc_char (int c)
185 switch (c)
187 case 'a': /* Alert. */
188 putchar (7);
189 break;
190 case 'b': /* Backspace. */
191 putchar (8);
192 break;
193 case 'c': /* Cancel the rest of the output. */
194 exit (0);
195 break;
196 case 'f': /* Form feed. */
197 putchar (12);
198 break;
199 case 'n': /* New line. */
200 putchar (10);
201 break;
202 case 'r': /* Carriage return. */
203 putchar (13);
204 break;
205 case 't': /* Horizontal tab. */
206 putchar (9);
207 break;
208 case 'v': /* Vertical tab. */
209 putchar (11);
210 break;
211 default:
212 putchar (c);
213 break;
217 /* Print a \ escape sequence starting at ESCSTART.
218 Return the number of characters in the escape sequence
219 besides the backslash. */
221 static int
222 print_esc (const char *escstart)
224 register const char *p = escstart + 1;
225 int esc_value = 0; /* Value of \nnn escape. */
226 int esc_length; /* Length of \nnn escape. */
228 /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
229 if (*p == 'x')
231 for (esc_length = 0, ++p;
232 esc_length < 3 && ISXDIGIT (*p);
233 ++esc_length, ++p)
234 esc_value = esc_value * 16 + hextobin (*p);
235 if (esc_length == 0)
236 error (1, 0, _("missing hexadecimal number in escape"));
237 putchar (esc_value);
239 else if (*p == '0')
241 for (esc_length = 0, ++p;
242 esc_length < 3 && isodigit (*p);
243 ++esc_length, ++p)
244 esc_value = esc_value * 8 + octtobin (*p);
245 putchar (esc_value);
247 else if (strchr ("\"\\abcfnrtv", *p))
248 print_esc_char (*p++);
249 else
250 error (1, 0, _("\\%c: invalid escape"), *p);
251 return p - escstart - 1;
254 /* Print string STR, evaluating \ escapes. */
256 static void
257 print_esc_string (const char *str)
259 for (; *str; str++)
260 if (*str == '\\')
261 str += print_esc (str);
262 else
263 putchar (*str);
266 /* Output a % directive. START is the start of the directive,
267 LENGTH is its length, and ARGUMENT is its argument.
268 If FIELD_WIDTH or PRECISION is non-negative, they are args for
269 '*' values in those fields. */
271 static void
272 print_direc (const char *start, size_t length, int field_width, int precision, const char *argument)
274 char *p; /* Null-terminated copy of % directive. */
276 p = xmalloc ((unsigned) (length + 1));
277 strncpy (p, start, length);
278 p[length] = 0;
280 switch (p[length - 1])
282 case 'd':
283 case 'i':
284 if (field_width < 0)
286 if (precision < 0)
287 printf (p, xstrtol (argument));
288 else
289 printf (p, precision, xstrtol (argument));
291 else
293 if (precision < 0)
294 printf (p, field_width, xstrtol (argument));
295 else
296 printf (p, field_width, precision, xstrtol (argument));
298 break;
300 case 'o':
301 case 'u':
302 case 'x':
303 case 'X':
304 if (field_width < 0)
306 if (precision < 0)
307 printf (p, xstrtoul (argument));
308 else
309 printf (p, precision, xstrtoul (argument));
311 else
313 if (precision < 0)
314 printf (p, field_width, xstrtoul (argument));
315 else
316 printf (p, field_width, precision, xstrtoul (argument));
318 break;
320 case 'f':
321 case 'e':
322 case 'E':
323 case 'g':
324 case 'G':
325 if (field_width < 0)
327 if (precision < 0)
328 printf (p, xstrtod (argument));
329 else
330 printf (p, precision, xstrtod (argument));
332 else
334 if (precision < 0)
335 printf (p, field_width, xstrtod (argument));
336 else
337 printf (p, field_width, precision, xstrtod (argument));
339 break;
341 case 'c':
342 printf (p, *argument);
343 break;
345 case 's':
346 if (field_width < 0)
348 if (precision < 0)
349 printf (p, argument);
350 else
351 printf (p, precision, argument);
353 else
355 if (precision < 0)
356 printf (p, field_width, argument);
357 else
358 printf (p, field_width, precision, argument);
360 break;
363 free (p);
366 /* Print the text in FORMAT, using ARGV (with ARGC elements) for
367 arguments to any `%' directives.
368 Return the number of elements of ARGV used. */
370 static int
371 print_formatted (const char *format, int argc, char **argv)
373 int save_argc = argc; /* Preserve original value. */
374 const char *f; /* Pointer into `format'. */
375 const char *direc_start; /* Start of % directive. */
376 size_t direc_length; /* Length of % directive. */
377 int field_width; /* Arg to first '*', or -1 if none. */
378 int precision; /* Arg to second '*', or -1 if none. */
380 for (f = format; *f; ++f)
382 switch (*f)
384 case '%':
385 direc_start = f++;
386 direc_length = 1;
387 field_width = precision = -1;
388 if (*f == '%')
390 putchar ('%');
391 break;
393 if (*f == 'b')
395 if (argc > 0)
397 print_esc_string (*argv);
398 ++argv;
399 --argc;
401 break;
403 if (strchr ("-+ #", *f))
405 ++f;
406 ++direc_length;
408 if (*f == '*')
410 ++f;
411 ++direc_length;
412 if (argc > 0)
414 field_width = xstrtoul (*argv);
415 ++argv;
416 --argc;
418 else
419 field_width = 0;
421 else
422 while (ISDIGIT (*f))
424 ++f;
425 ++direc_length;
427 if (*f == '.')
429 ++f;
430 ++direc_length;
431 if (*f == '*')
433 ++f;
434 ++direc_length;
435 if (argc > 0)
437 precision = xstrtoul (*argv);
438 ++argv;
439 --argc;
441 else
442 precision = 0;
444 else
445 while (ISDIGIT (*f))
447 ++f;
448 ++direc_length;
451 if (*f == 'l' || *f == 'L' || *f == 'h')
453 ++f;
454 ++direc_length;
456 if (!strchr ("diouxXfeEgGcs", *f))
457 error (1, 0, _("%%%c: invalid directive"), *f);
458 ++direc_length;
459 if (argc > 0)
461 print_direc (direc_start, direc_length, field_width,
462 precision, *argv);
463 ++argv;
464 --argc;
466 else
467 print_direc (direc_start, direc_length, field_width,
468 precision, "");
469 break;
471 case '\\':
472 f += print_esc (f);
473 break;
475 default:
476 putchar (*f);
480 return save_argc - argc;
484 main (int argc, char **argv)
486 char *format;
487 int args_used;
489 program_name = argv[0];
490 setlocale (LC_ALL, "");
491 bindtextdomain (PACKAGE, LOCALEDIR);
492 textdomain (PACKAGE);
494 exit_status = 0;
496 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
497 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
498 if (!posixly_correct)
499 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
500 AUTHORS, usage);
502 if (argc == 1)
504 fprintf (stderr, _("Usage: %s format [argument...]\n"), program_name);
505 exit (1);
508 format = argv[1];
509 argc -= 2;
510 argv += 2;
514 args_used = print_formatted (format, argc, argv);
515 argc -= args_used;
516 argv += args_used;
518 while (args_used > 0 && argc > 0);
520 if (argc > 0)
521 error (0, 0, _("warning: excess arguments have been ignored"));
523 exit (exit_status);