*** empty log message ***
[coreutils.git] / src / printf.c
blob57171c38d65b5301716c98e2ed742e7cd7857609
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,
273 int precision, const char *argument)
275 char *p; /* Null-terminated copy of % directive. */
277 p = xmalloc ((unsigned) (length + 1));
278 strncpy (p, start, length);
279 p[length] = 0;
281 switch (p[length - 1])
283 case 'd':
284 case 'i':
285 if (field_width < 0)
287 if (precision < 0)
288 printf (p, xstrtol (argument));
289 else
290 printf (p, precision, xstrtol (argument));
292 else
294 if (precision < 0)
295 printf (p, field_width, xstrtol (argument));
296 else
297 printf (p, field_width, precision, xstrtol (argument));
299 break;
301 case 'o':
302 case 'u':
303 case 'x':
304 case 'X':
305 if (field_width < 0)
307 if (precision < 0)
308 printf (p, xstrtoul (argument));
309 else
310 printf (p, precision, xstrtoul (argument));
312 else
314 if (precision < 0)
315 printf (p, field_width, xstrtoul (argument));
316 else
317 printf (p, field_width, precision, xstrtoul (argument));
319 break;
321 case 'f':
322 case 'e':
323 case 'E':
324 case 'g':
325 case 'G':
326 if (field_width < 0)
328 if (precision < 0)
329 printf (p, xstrtod (argument));
330 else
331 printf (p, precision, xstrtod (argument));
333 else
335 if (precision < 0)
336 printf (p, field_width, xstrtod (argument));
337 else
338 printf (p, field_width, precision, xstrtod (argument));
340 break;
342 case 'c':
343 printf (p, *argument);
344 break;
346 case 's':
347 if (field_width < 0)
349 if (precision < 0)
350 printf (p, argument);
351 else
352 printf (p, precision, argument);
354 else
356 if (precision < 0)
357 printf (p, field_width, argument);
358 else
359 printf (p, field_width, precision, argument);
361 break;
364 free (p);
367 /* Print the text in FORMAT, using ARGV (with ARGC elements) for
368 arguments to any `%' directives.
369 Return the number of elements of ARGV used. */
371 static int
372 print_formatted (const char *format, int argc, char **argv)
374 int save_argc = argc; /* Preserve original value. */
375 const char *f; /* Pointer into `format'. */
376 const char *direc_start; /* Start of % directive. */
377 size_t direc_length; /* Length of % directive. */
378 int field_width; /* Arg to first '*', or -1 if none. */
379 int precision; /* Arg to second '*', or -1 if none. */
381 for (f = format; *f; ++f)
383 switch (*f)
385 case '%':
386 direc_start = f++;
387 direc_length = 1;
388 field_width = precision = -1;
389 if (*f == '%')
391 putchar ('%');
392 break;
394 if (*f == 'b')
396 if (argc > 0)
398 print_esc_string (*argv);
399 ++argv;
400 --argc;
402 break;
404 if (strchr ("-+ #", *f))
406 ++f;
407 ++direc_length;
409 if (*f == '*')
411 ++f;
412 ++direc_length;
413 if (argc > 0)
415 field_width = xstrtoul (*argv);
416 ++argv;
417 --argc;
419 else
420 field_width = 0;
422 else
423 while (ISDIGIT (*f))
425 ++f;
426 ++direc_length;
428 if (*f == '.')
430 ++f;
431 ++direc_length;
432 if (*f == '*')
434 ++f;
435 ++direc_length;
436 if (argc > 0)
438 precision = xstrtoul (*argv);
439 ++argv;
440 --argc;
442 else
443 precision = 0;
445 else
446 while (ISDIGIT (*f))
448 ++f;
449 ++direc_length;
452 if (*f == 'l' || *f == 'L' || *f == 'h')
454 ++f;
455 ++direc_length;
457 if (!strchr ("diouxXfeEgGcs", *f))
458 error (1, 0, _("%%%c: invalid directive"), *f);
459 ++direc_length;
460 if (argc > 0)
462 print_direc (direc_start, direc_length, field_width,
463 precision, *argv);
464 ++argv;
465 --argc;
467 else
468 print_direc (direc_start, direc_length, field_width,
469 precision, "");
470 break;
472 case '\\':
473 f += print_esc (f);
474 break;
476 default:
477 putchar (*f);
481 return save_argc - argc;
485 main (int argc, char **argv)
487 char *format;
488 int args_used;
490 program_name = argv[0];
491 setlocale (LC_ALL, "");
492 bindtextdomain (PACKAGE, LOCALEDIR);
493 textdomain (PACKAGE);
495 exit_status = 0;
497 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
498 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
499 if (!posixly_correct)
500 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
501 AUTHORS, usage);
503 if (argc == 1)
505 fprintf (stderr, _("Usage: %s format [argument...]\n"), program_name);
506 exit (1);
509 format = argv[1];
510 argc -= 2;
511 argv += 2;
515 args_used = print_formatted (format, argc, argv);
516 argc -= args_used;
517 argv += args_used;
519 while (args_used > 0 && argc > 0);
521 if (argc > 0)
522 error (0, 0, _("warning: excess arguments have been ignored"));
524 exit (exit_status);