%b = print an argument string, interpreting backslash escapes
- The `format' argument is re-used as many times as necessary
+ The 'format' argument is re-used as many times as necessary
to convert all of the given arguments.
David MacKenzie <djm@gnu.ai.mit.edu> */
// 19990508 Busy Boxed! Dave Cinege
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <assert.h>
#include "busybox.h"
-static int print_formatted __P((char *format, int argc, char **argv));
-static void print_direc __P( (char *start, size_t length,
- int field_width, int precision, char *argument));
+typedef void (*converter)(const char *arg, void *result);
-typedef int (*converter)(char *arg, void *result);
-void multiconvert(char *arg, void *result, converter convert)
+static void multiconvert(const char *arg, void *result, converter convert)
{
- char s[16];
+ char s[sizeof(int)*3 + 2];
+
if (*arg == '"' || *arg == '\'') {
- sprintf(s,"%d",(unsigned)*(++arg));
- arg=s;
+ sprintf(s, "%d", (unsigned char)arg[1]);
+ arg = s;
}
- if(convert(arg,result)) fprintf(stderr, "%s", arg);
+ convert(arg, result);
+ /* if there was conversion error, print unconverted string */
+ if (errno)
+ fputs(arg, stderr);
}
-
-static unsigned long xstrtoul(char *arg)
+
+static void conv_strtoul(const char *arg, void *result)
{
- unsigned long result;
+ *(unsigned long*)result = bb_strtoul(arg, NULL, 0);
+}
+static void conv_strtol(const char *arg, void *result)
+{
+ *(long*)result = bb_strtol(arg, NULL, 0);
+}
+static void conv_strtod(const char *arg, void *result)
+{
+ char *end;
+ /* Well, this one allows leading whitespace... so what */
+ /* What I like much less is that "-" is accepted too! :( */
+ *(double*)result = strtod(arg, &end);
+ if (end[0]) errno = ERANGE;
+}
- multiconvert(arg,&result, (converter)safe_strtoul);
+static unsigned long my_xstrtoul(const char *arg)
+{
+ unsigned long result;
+ multiconvert(arg, &result, conv_strtoul);
return result;
}
-static long xstrtol(char *arg)
+static long my_xstrtol(const char *arg)
{
long result;
- multiconvert(arg, &result, (converter)safe_strtol);
+ multiconvert(arg, &result, conv_strtol);
return result;
}
-static double xstrtod(char *arg)
+static double my_xstrtod(const char *arg)
{
double result;
- multiconvert(arg, &result, (converter)safe_strtod);
+ multiconvert(arg, &result, conv_strtod);
return result;
}
}
}
-int printf_main(int argc, char **argv)
+static void print_direc(char *start, size_t length, int field_width, int precision,
+ const char *argument)
{
- char *format;
- int args_used;
-
- if (argc <= 1 || **(argv + 1) == '-') {
- bb_show_usage();
- }
+ char *p; /* Null-terminated copy of % directive. */
- format = argv[1];
- argc -= 2;
- argv += 2;
+ p = xmalloc((unsigned) (length + 1));
+ strncpy(p, start, length);
+ p[length] = 0;
- do {
- args_used = print_formatted(format, argc, argv);
- argc -= args_used;
- argv += args_used;
+ switch (p[length - 1]) {
+ case 'd':
+ case 'i':
+ if (field_width < 0) {
+ if (precision < 0)
+ printf(p, my_xstrtol(argument));
+ else
+ printf(p, precision, my_xstrtol(argument));
+ } else {
+ if (precision < 0)
+ printf(p, field_width, my_xstrtol(argument));
+ else
+ printf(p, field_width, precision, my_xstrtol(argument));
+ }
+ break;
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (field_width < 0) {
+ if (precision < 0)
+ printf(p, my_xstrtoul(argument));
+ else
+ printf(p, precision, my_xstrtoul(argument));
+ } else {
+ if (precision < 0)
+ printf(p, field_width, my_xstrtoul(argument));
+ else
+ printf(p, field_width, precision, my_xstrtoul(argument));
+ }
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ if (field_width < 0) {
+ if (precision < 0)
+ printf(p, my_xstrtod(argument));
+ else
+ printf(p, precision, my_xstrtod(argument));
+ } else {
+ if (precision < 0)
+ printf(p, field_width, my_xstrtod(argument));
+ else
+ printf(p, field_width, precision, my_xstrtod(argument));
+ }
+ break;
+ case 'c':
+ printf(p, *argument);
+ break;
+ case 's':
+ if (field_width < 0) {
+ if (precision < 0)
+ printf(p, argument);
+ else
+ printf(p, precision, argument);
+ } else {
+ if (precision < 0)
+ printf(p, field_width, argument);
+ else
+ printf(p, field_width, precision, argument);
+ }
+ break;
}
- while (args_used > 0 && argc > 0);
-
-/*
- if (argc > 0)
- fprintf(stderr, "excess args ignored");
-*/
- return EXIT_SUCCESS;
+ free(p);
}
/* Print the text in FORMAT, using ARGV (with ARGC elements) for
- arguments to any `%' directives.
+ arguments to any '%' directives.
Return the number of elements of ARGV used. */
static int print_formatted(char *format, int argc, char **argv)
{
- int save_argc = argc; /* Preserve original value. */
- char *f; /* Pointer into `format'. */
- char *direc_start; /* Start of % directive. */
- size_t direc_length; /* Length of % directive. */
- int field_width; /* Arg to first '*', or -1 if none. */
- int precision; /* Arg to second '*', or -1 if none. */
+ int save_argc = argc; /* Preserve original value. */
+ char *f; /* Pointer into 'format'. */
+ char *direc_start; /* Start of % directive. */
+ size_t direc_length; /* Length of % directive. */
+ int field_width; /* Arg to first '*', or -1 if none. */
+ int precision; /* Arg to second '*', or -1 if none. */
for (f = format; *f; ++f) {
switch (*f) {
++f;
++direc_length;
if (argc > 0) {
- field_width = xstrtoul(*argv);
+ field_width = my_xstrtoul(*argv);
++argv;
--argc;
} else
field_width = 0;
- } else
+ } else {
while (isdigit(*f)) {
++f;
++direc_length;
}
+ }
if (*f == '.') {
++f;
++direc_length;
++f;
++direc_length;
if (argc > 0) {
- precision = xstrtoul(*argv);
+ precision = my_xstrtoul(*argv);
++argv;
--argc;
} else
++direc_length;
}
/*
- if (!strchr ("diouxXfeEgGcs", *f))
- fprintf(stderr, "%%%c: invalid directive", *f);
- */
+ if (!strchr ("diouxXfeEgGcs", *f))
+ fprintf(stderr, "%%%c: invalid directive", *f);
+ */
++direc_length;
if (argc > 0) {
print_direc(direc_start, direc_length, field_width,
print_direc(direc_start, direc_length, field_width,
precision, "");
break;
-
case '\\':
if (*++f == 'c')
exit(0);
putchar(bb_process_escape_sequence((const char **)&f));
f--;
break;
-
default:
putchar(*f);
}
return save_argc - argc;
}
-static void
-print_direc(char *start, size_t length, int field_width, int precision,
- char *argument)
+int printf_main(int argc, char **argv);
+int printf_main(int argc, char **argv)
{
- char *p; /* Null-terminated copy of % directive. */
-
- p = xmalloc((unsigned) (length + 1));
- strncpy(p, start, length);
- p[length] = 0;
-
- switch (p[length - 1]) {
- case 'd':
- case 'i':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtol(argument));
- else
- printf(p, precision, xstrtol(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtol(argument));
- else
- printf(p, field_width, precision, xstrtol(argument));
- }
- break;
+ char *format;
+ int args_used;
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtoul(argument));
- else
- printf(p, precision, xstrtoul(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtoul(argument));
- else
- printf(p, field_width, precision, xstrtoul(argument));
- }
- break;
+ if (argc <= 1 || argv[1][0] == '-') {
+ bb_show_usage();
+ }
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtod(argument));
- else
- printf(p, precision, xstrtod(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtod(argument));
- else
- printf(p, field_width, precision, xstrtod(argument));
- }
- break;
+ format = argv[1];
+ argc -= 2;
+ argv += 2;
- case 'c':
- printf(p, *argument);
- break;
+ do {
+ args_used = print_formatted(format, argc, argv);
+ argc -= args_used;
+ argv += args_used;
+ } while (args_used > 0 && argc > 0);
- case 's':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, argument);
- else
- printf(p, precision, argument);
- } else {
- if (precision < 0)
- printf(p, field_width, argument);
- else
- printf(p, field_width, precision, argument);
- }
- break;
- }
+/* if (argc > 0)
+ fprintf(stderr, "excess args ignored");
+*/
- free(p);
+ return EXIT_SUCCESS;
}