.
[coreutils.git] / src / printf.c
blob7ac13a5d60e0281ad73084abce47ec47a37de962
1 /* printf - format and print data
2 Copyright (C) 90, 91, 92, 93, 94, 95, 1996 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 #ifndef STDC_HEADERS
56 double strtod ();
57 long strtol ();
58 unsigned long strtoul ();
59 #endif
61 #define isodigit(c) ((c) >= '0' && (c) <= '7')
62 #define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
63 #define octtobin(c) ((c) - '0')
65 char *xmalloc ();
67 static double xstrtod __P ((char *s));
68 static int print_esc __P ((char *escstart));
69 static int print_formatted __P ((char *format, int argc, char **argv));
70 static long xstrtol __P ((char *s));
71 static unsigned long xstrtoul __P ((char *s));
72 static void print_direc __P ((char *start, size_t length, int field_width, int precision, char *argument));
73 static void print_esc_char __P ((int c));
74 static void print_esc_string __P ((char *str));
75 static void verify __P ((char *s, char *end));
77 /* The value to return to the calling program. */
78 static int exit_status;
80 /* The name this program was run with. */
81 char *program_name;
83 static void
84 usage (int status)
86 if (status != 0)
87 fprintf (stderr, _("Try `%s --help' for more information.\n"),
88 program_name);
89 else
91 printf (_("\
92 Usage: %s FORMAT [ARGUMENT]...\n\
93 or: %s OPTION\n\
94 "),
95 program_name, program_name);
96 printf (_("\
97 Print ARGUMENT(s) according to FORMAT.\n\
98 \n\
99 --help display this help and exit\n\
100 --version output version information and exit\n\
102 FORMAT controls the output as in C printf. Interpreted sequences are:\n\
104 \\\" double quote\n\
105 \\0NNN character with octal value NNN (0 to 3 digits)\n\
106 \\\\ backslash\n\
107 \\a alert (BEL)\n\
108 \\b backspace\n\
109 \\c produce no further output\n\
110 \\f form feed\n\
111 \\n new line\n\
112 \\r carriage return\n\
113 \\t horizontal tab\n\
114 \\v vertical tab\n\
115 \\xNNN character with hexadecimal value NNN (1 to 3 digits)\n\
117 %%%% a single %%\n\
118 %%b ARGUMENT as a string with `\\' escapes interpreted\n\
120 and all C format specifications ending with one of diouxXfeEgGcs, with\n\
121 ARGUMENTs converted to proper type first. Variable widths are handled.\n\
122 "));
123 puts (_("\nReport bugs to sh-utils-bugs@gnu.ai.mit.edu"));
125 exit (status);
129 main (int argc, char **argv)
131 char *format;
132 int args_used;
134 program_name = argv[0];
135 setlocale (LC_ALL, "");
136 bindtextdomain (PACKAGE, LOCALEDIR);
137 textdomain (PACKAGE);
139 exit_status = 0;
141 /* Don't recognize --help or --version if POSIXLY_CORRECT is set. */
142 if (getenv ("POSIXLY_CORRECT") == NULL)
143 parse_long_options (argc, argv, "printf", GNU_PACKAGE, VERSION, usage);
145 if (argc == 1)
147 fprintf (stderr, _("Usage: %s format [argument...]\n"), program_name);
148 exit (1);
151 format = argv[1];
152 argc -= 2;
153 argv += 2;
157 args_used = print_formatted (format, argc, argv);
158 argc -= args_used;
159 argv += args_used;
161 while (args_used > 0 && argc > 0);
163 if (argc > 0)
164 error (0, 0, _("warning: excess arguments have been ignored"));
166 exit (exit_status);
169 /* Print the text in FORMAT, using ARGV (with ARGC elements) for
170 arguments to any `%' directives.
171 Return the number of elements of ARGV used. */
173 static int
174 print_formatted (char *format, int argc, char **argv)
176 int save_argc = argc; /* Preserve original value. */
177 char *f; /* Pointer into `format'. */
178 char *direc_start; /* Start of % directive. */
179 size_t direc_length; /* Length of % directive. */
180 int field_width; /* Arg to first '*', or -1 if none. */
181 int precision; /* Arg to second '*', or -1 if none. */
183 for (f = format; *f; ++f)
185 switch (*f)
187 case '%':
188 direc_start = f++;
189 direc_length = 1;
190 field_width = precision = -1;
191 if (*f == '%')
193 putchar ('%');
194 break;
196 if (*f == 'b')
198 if (argc > 0)
200 print_esc_string (*argv);
201 ++argv;
202 --argc;
204 break;
206 if (strchr ("-+ #", *f))
208 ++f;
209 ++direc_length;
211 if (*f == '*')
213 ++f;
214 ++direc_length;
215 if (argc > 0)
217 field_width = xstrtoul (*argv);
218 ++argv;
219 --argc;
221 else
222 field_width = 0;
224 else
225 while (ISDIGIT (*f))
227 ++f;
228 ++direc_length;
230 if (*f == '.')
232 ++f;
233 ++direc_length;
234 if (*f == '*')
236 ++f;
237 ++direc_length;
238 if (argc > 0)
240 precision = xstrtoul (*argv);
241 ++argv;
242 --argc;
244 else
245 precision = 0;
247 else
248 while (ISDIGIT (*f))
250 ++f;
251 ++direc_length;
254 if (*f == 'l' || *f == 'L' || *f == 'h')
256 ++f;
257 ++direc_length;
259 if (!strchr ("diouxXfeEgGcs", *f))
260 error (1, 0, _("%%%c: invalid directive"), *f);
261 ++direc_length;
262 if (argc > 0)
264 print_direc (direc_start, direc_length, field_width,
265 precision, *argv);
266 ++argv;
267 --argc;
269 else
270 print_direc (direc_start, direc_length, field_width,
271 precision, "");
272 break;
274 case '\\':
275 f += print_esc (f);
276 break;
278 default:
279 putchar (*f);
283 return save_argc - argc;
286 /* Print a \ escape sequence starting at ESCSTART.
287 Return the number of characters in the escape sequence
288 besides the backslash. */
290 static int
291 print_esc (char *escstart)
293 register char *p = escstart + 1;
294 int esc_value = 0; /* Value of \nnn escape. */
295 int esc_length; /* Length of \nnn escape. */
297 /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
298 if (*p == 'x')
300 for (esc_length = 0, ++p;
301 esc_length < 3 && ISXDIGIT (*p);
302 ++esc_length, ++p)
303 esc_value = esc_value * 16 + hextobin (*p);
304 if (esc_length == 0)
305 error (1, 0, _("missing hexadecimal number in escape"));
306 putchar (esc_value);
308 else if (*p == '0')
310 for (esc_length = 0, ++p;
311 esc_length < 3 && isodigit (*p);
312 ++esc_length, ++p)
313 esc_value = esc_value * 8 + octtobin (*p);
314 putchar (esc_value);
316 else if (strchr ("\"\\abcfnrtv", *p))
317 print_esc_char (*p++);
318 else
319 error (1, 0, _("\\%c: invalid escape"), *p);
320 return p - escstart - 1;
323 /* Output a single-character \ escape. */
325 static void
326 print_esc_char (int c)
328 switch (c)
330 case 'a': /* Alert. */
331 putchar (7);
332 break;
333 case 'b': /* Backspace. */
334 putchar (8);
335 break;
336 case 'c': /* Cancel the rest of the output. */
337 exit (0);
338 break;
339 case 'f': /* Form feed. */
340 putchar (12);
341 break;
342 case 'n': /* New line. */
343 putchar (10);
344 break;
345 case 'r': /* Carriage return. */
346 putchar (13);
347 break;
348 case 't': /* Horizontal tab. */
349 putchar (9);
350 break;
351 case 'v': /* Vertical tab. */
352 putchar (11);
353 break;
354 default:
355 putchar (c);
356 break;
360 /* Print string STR, evaluating \ escapes. */
362 static void
363 print_esc_string (char *str)
365 for (; *str; str++)
366 if (*str == '\\')
367 str += print_esc (str);
368 else
369 putchar (*str);
372 /* Output a % directive. START is the start of the directive,
373 LENGTH is its length, and ARGUMENT is its argument.
374 If FIELD_WIDTH or PRECISION is non-negative, they are args for
375 '*' values in those fields. */
377 static void
378 print_direc (char *start, size_t length, int field_width, int precision, char *argument)
380 char *p; /* Null-terminated copy of % directive. */
382 p = xmalloc ((unsigned) (length + 1));
383 strncpy (p, start, length);
384 p[length] = 0;
386 switch (p[length - 1])
388 case 'd':
389 case 'i':
390 if (field_width < 0)
392 if (precision < 0)
393 printf (p, xstrtol (argument));
394 else
395 printf (p, precision, xstrtol (argument));
397 else
399 if (precision < 0)
400 printf (p, field_width, xstrtol (argument));
401 else
402 printf (p, field_width, precision, xstrtol (argument));
404 break;
406 case 'o':
407 case 'u':
408 case 'x':
409 case 'X':
410 if (field_width < 0)
412 if (precision < 0)
413 printf (p, xstrtoul (argument));
414 else
415 printf (p, precision, xstrtoul (argument));
417 else
419 if (precision < 0)
420 printf (p, field_width, xstrtoul (argument));
421 else
422 printf (p, field_width, precision, xstrtoul (argument));
424 break;
426 case 'f':
427 case 'e':
428 case 'E':
429 case 'g':
430 case 'G':
431 if (field_width < 0)
433 if (precision < 0)
434 printf (p, xstrtod (argument));
435 else
436 printf (p, precision, xstrtod (argument));
438 else
440 if (precision < 0)
441 printf (p, field_width, xstrtod (argument));
442 else
443 printf (p, field_width, precision, xstrtod (argument));
445 break;
447 case 'c':
448 printf (p, *argument);
449 break;
451 case 's':
452 if (field_width < 0)
454 if (precision < 0)
455 printf (p, argument);
456 else
457 printf (p, precision, argument);
459 else
461 if (precision < 0)
462 printf (p, field_width, argument);
463 else
464 printf (p, field_width, precision, argument);
466 break;
469 free (p);
472 static unsigned long
473 xstrtoul (char *s)
475 char *end;
476 unsigned long val;
478 errno = 0;
479 val = strtoul (s, &end, 0);
480 verify (s, end);
481 return val;
484 static long
485 xstrtol (char *s)
487 char *end;
488 long val;
490 errno = 0;
491 val = strtol (s, &end, 0);
492 verify (s, end);
493 return val;
496 static double
497 xstrtod (char *s)
499 char *end;
500 double val;
502 errno = 0;
503 val = strtod (s, &end);
504 verify (s, end);
505 return val;
508 static void
509 verify (char *s, char *end)
511 if (errno)
513 error (0, errno, "%s", s);
514 exit_status = 1;
516 else if (*end)
518 if (s == end)
519 error (0, 0, _("%s: expected a numeric value"), s);
520 else
521 error (0, 0, _("%s: value not completely converted"), s);
522 exit_status = 1;