75 static int getchr(void);
76 static int getfloating(long double *, int);
77 static int getint(int *);
78 static int getnum(intmax_t *, uintmax_t *, int);
79 static const char
80 *getstr(void);
81 static char *mknum(char *, char);
82 static void usage(void);
83
84 static const char digits[] = "0123456789";
85
86 static int myargc;
87 static char **myargv;
88 static char **gargv;
89 static char **maxargv;
90
91 int
92 main(int argc, char *argv[])
93 {
94 size_t len;
95 int chopped, end, rval;
96 char *format, *fmt, *start;
97
98 (void) setlocale(LC_ALL, "");
99
100 argv++;
101 argc--;
102
103 /*
104 * POSIX says: Standard utilities that do not accept options,
105 * but that do accept operands, shall recognize "--" as a
106 * first argument to be discarded.
107 */
108 if (argc && strcmp(argv[0], "--") == 0) {
109 argc--;
110 argv++;
111 }
112
113 if (argc < 1) {
114 usage();
115 return (1);
116 }
117
118 /*
119 * Basic algorithm is to scan the format string for conversion
120 * specifications -- once one is found, find out if the field
121 * width or precision is a '*'; if it is, gather up value. Note,
122 * format strings are reused as necessary to use up the provided
123 * arguments, arguments of zero/null string are provided to use
124 * up the format string.
125 */
126 fmt = format = *argv;
127 chopped = escape(fmt, 1, &len); /* backslash interpretation */
128 rval = end = 0;
129 gargv = ++argv;
130
131 for (;;) {
132 maxargv = gargv;
133
134 myargv = gargv;
135 for (myargc = 0; gargv[myargc]; myargc++)
136 /* nop */;
137 start = fmt;
138 while (fmt < format + len) {
139 if (fmt[0] == '%') {
140 (void) fwrite(start, 1, PTRDIFF(fmt, start),
141 stdout);
142 if (fmt[1] == '%') {
143 /* %% prints a % */
144 (void) putchar('%');
145 fmt += 2;
146 } else {
147 fmt = doformat(fmt, &rval);
148 if (fmt == NULL)
149 return (1);
150 end = 0;
151 }
152 start = fmt;
153 } else
154 fmt++;
155 if (gargv > maxargv)
156 maxargv = gargv;
157 }
158 gargv = maxargv;
159
160 if (end == 1) {
161 warnx1(_("missing format character"), NULL, NULL);
162 return (1);
163 }
164 (void) fwrite(start, 1, PTRDIFF(fmt, start), stdout);
165 if (chopped || !*gargv)
166 return (rval);
167 /* Restart at the beginning of the format string. */
168 fmt = format;
169 end = 1;
170 }
171 /* NOTREACHED */
172 }
173
174
175 static char *
176 doformat(char *fmt, int *rval)
177 {
178 static const char skip1[] = "#'-+ 0";
179 int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
180 char convch, nextch;
181 char *start;
182 char **fargv;
183 char *dptr;
184 int l;
185
321 if (fargv != NULL) {
322 gargv = fargv;
323 }
324
325 convch = *fmt;
326 nextch = *++fmt;
327
328 *fmt = '\0';
329 switch (convch) {
330 case 'b': {
331 size_t len;
332 char *p;
333 int getout;
334
335 p = strdup(getstr());
336 if (p == NULL) {
337 warnx2("%s", strerror(ENOMEM), NULL);
338 return (NULL);
339 }
340 getout = escape(p, 0, &len);
341 *(fmt - 1) = 's';
342 PF(start, p);
343 *(fmt - 1) = 'b';
344 free(p);
345
346 if (getout)
347 return (fmt);
348 break;
349 }
350 case 'c': {
351 char p;
352
353 p = getchr();
354 PF(start, p);
355 break;
356 }
357 case 's': {
358 const char *p;
359
360 p = getstr();
361 PF(start, p);
362 break;
363 }
364 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
365 char *f;
366 intmax_t val;
367 uintmax_t uval;
439 *store = c;
440 continue;
441 }
442 switch (*++fmt) {
443 case '\0': /* EOS, user error */
444 *store = '\\';
445 *++store = '\0';
446 *len = PTRDIFF(store, save);
447 return (0);
448 case '\\': /* backslash */
449 case '\'': /* single quote */
450 *store = *fmt;
451 break;
452 case 'a': /* bell/alert */
453 *store = '\a';
454 break;
455 case 'b': /* backspace */
456 *store = '\b';
457 break;
458 case 'c':
459 *store = '\0';
460 *len = PTRDIFF(store, save);
461 return (1);
462 case 'f': /* form-feed */
463 *store = '\f';
464 break;
465 case 'n': /* newline */
466 *store = '\n';
467 break;
468 case 'r': /* carriage-return */
469 *store = '\r';
470 break;
471 case 't': /* horizontal tab */
472 *store = '\t';
473 break;
474 case 'v': /* vertical tab */
475 *store = '\v';
476 break;
477 /* octal constant */
478 case '0': case '1': case '2': case '3':
479 case '4': case '5': case '6': case '7':
480 c = (!percent && *fmt == '0') ? 4 : 3;
481 for (value = 0;
|
75 static int getchr(void);
76 static int getfloating(long double *, int);
77 static int getint(int *);
78 static int getnum(intmax_t *, uintmax_t *, int);
79 static const char
80 *getstr(void);
81 static char *mknum(char *, char);
82 static void usage(void);
83
84 static const char digits[] = "0123456789";
85
86 static int myargc;
87 static char **myargv;
88 static char **gargv;
89 static char **maxargv;
90
91 int
92 main(int argc, char *argv[])
93 {
94 size_t len;
95 int end, rval;
96 char *format, *fmt, *start;
97
98 (void) setlocale(LC_ALL, "");
99
100 argv++;
101 argc--;
102
103 /*
104 * POSIX says: Standard utilities that do not accept options,
105 * but that do accept operands, shall recognize "--" as a
106 * first argument to be discarded.
107 */
108 if (argc && strcmp(argv[0], "--") == 0) {
109 argc--;
110 argv++;
111 }
112
113 if (argc < 1) {
114 usage();
115 return (1);
116 }
117
118 /*
119 * Basic algorithm is to scan the format string for conversion
120 * specifications -- once one is found, find out if the field
121 * width or precision is a '*'; if it is, gather up value. Note,
122 * format strings are reused as necessary to use up the provided
123 * arguments, arguments of zero/null string are provided to use
124 * up the format string.
125 */
126 fmt = format = *argv;
127 (void) escape(fmt, 1, &len); /* backslash interpretation */
128 rval = end = 0;
129 gargv = ++argv;
130
131 for (;;) {
132 maxargv = gargv;
133
134 myargv = gargv;
135 for (myargc = 0; gargv[myargc]; myargc++)
136 /* nop */;
137 start = fmt;
138 while (fmt < format + len) {
139 if (fmt[0] == '%') {
140 (void) fwrite(start, 1, PTRDIFF(fmt, start),
141 stdout);
142 if (fmt[1] == '%') {
143 /* %% prints a % */
144 (void) putchar('%');
145 fmt += 2;
146 } else {
147 fmt = doformat(fmt, &rval);
148 if (fmt == NULL)
149 return (1);
150 end = 0;
151 }
152 start = fmt;
153 } else
154 fmt++;
155 if (gargv > maxargv)
156 maxargv = gargv;
157 }
158 gargv = maxargv;
159
160 if (end == 1) {
161 warnx1(_("missing format character"), NULL, NULL);
162 return (1);
163 }
164 (void) fwrite(start, 1, PTRDIFF(fmt, start), stdout);
165 if (!*gargv)
166 return (rval);
167 /* Restart at the beginning of the format string. */
168 fmt = format;
169 end = 1;
170 }
171 /* NOTREACHED */
172 }
173
174
175 static char *
176 doformat(char *fmt, int *rval)
177 {
178 static const char skip1[] = "#'-+ 0";
179 int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
180 char convch, nextch;
181 char *start;
182 char **fargv;
183 char *dptr;
184 int l;
185
321 if (fargv != NULL) {
322 gargv = fargv;
323 }
324
325 convch = *fmt;
326 nextch = *++fmt;
327
328 *fmt = '\0';
329 switch (convch) {
330 case 'b': {
331 size_t len;
332 char *p;
333 int getout;
334
335 p = strdup(getstr());
336 if (p == NULL) {
337 warnx2("%s", strerror(ENOMEM), NULL);
338 return (NULL);
339 }
340 getout = escape(p, 0, &len);
341 (void) fputs(p, stdout);
342 free(p);
343
344 if (getout)
345 exit(*rval);
346 break;
347 }
348 case 'c': {
349 char p;
350
351 p = getchr();
352 PF(start, p);
353 break;
354 }
355 case 's': {
356 const char *p;
357
358 p = getstr();
359 PF(start, p);
360 break;
361 }
362 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
363 char *f;
364 intmax_t val;
365 uintmax_t uval;
437 *store = c;
438 continue;
439 }
440 switch (*++fmt) {
441 case '\0': /* EOS, user error */
442 *store = '\\';
443 *++store = '\0';
444 *len = PTRDIFF(store, save);
445 return (0);
446 case '\\': /* backslash */
447 case '\'': /* single quote */
448 *store = *fmt;
449 break;
450 case 'a': /* bell/alert */
451 *store = '\a';
452 break;
453 case 'b': /* backspace */
454 *store = '\b';
455 break;
456 case 'c':
457 if (!percent) {
458 *store = '\0';
459 *len = PTRDIFF(store, save);
460 return (1);
461 }
462 *store = 'c';
463 break;
464 case 'f': /* form-feed */
465 *store = '\f';
466 break;
467 case 'n': /* newline */
468 *store = '\n';
469 break;
470 case 'r': /* carriage-return */
471 *store = '\r';
472 break;
473 case 't': /* horizontal tab */
474 *store = '\t';
475 break;
476 case 'v': /* vertical tab */
477 *store = '\v';
478 break;
479 /* octal constant */
480 case '0': case '1': case '2': case '3':
481 case '4': case '5': case '6': case '7':
482 c = (!percent && *fmt == '0') ? 4 : 3;
483 for (value = 0;
|