Print this page
4818 printf(1) should support n$ width and precision specifiers

*** 1,6 **** --- 1,7 ---- /* + * Copyright 2014 Garrett D'Amore <garrett@damore.org> * Copyright 2010 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without
*** 36,45 **** --- 37,48 ---- #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + #include <alloca.h> + #include <ctype.h> #include <locale.h> #include <note.h> #define warnx1(a, b, c) warnx(a) #define warnx2(a, b, c) warnx(a, b)
*** 49,63 **** #define _(x) gettext(x) #define PF(f, func) do { \ char *b = NULL; \ - int dollar = 0; \ - if (*f == '$') { \ - dollar++; \ - *f = '%'; \ - } \ if (havewidth) \ if (haveprec) \ (void) asprintf(&b, f, fieldwidth, precision, func); \ else \ (void) asprintf(&b, f, fieldwidth, func); \ --- 52,61 ----
*** 67,78 **** (void) asprintf(&b, f, func); \ if (b) { \ (void) fputs(b, stdout); \ free(b); \ } \ - if (dollar) \ - *f = '$'; \ _NOTE(CONSTCOND) } while (0) static int asciicode(void); static char *doformat(char *, int *); static int escape(char *, int, size_t *); --- 65,74 ----
*** 83,95 **** --- 79,94 ---- static const char *getstr(void); static char *mknum(char *, char); static void usage(void); + static const char digits[] = "0123456789"; + static int myargc; static char **myargv; static char **gargv; + static char **maxargv; int main(int argc, char *argv[]) { size_t len;
*** 128,138 **** chopped = escape(fmt, 1, &len); /* backslash interpretation */ rval = end = 0; gargv = ++argv; for (;;) { ! char **maxargv = gargv; myargv = gargv; for (myargc = 0; gargv[myargc]; myargc++) /* nop */; start = fmt; --- 127,137 ---- chopped = escape(fmt, 1, &len); /* backslash interpretation */ rval = end = 0; gargv = ++argv; for (;;) { ! maxargv = gargv; myargv = gargv; for (myargc = 0; gargv[myargc]; myargc++) /* nop */; start = fmt;
*** 172,239 **** /* NOTREACHED */ } static char * ! doformat(char *start, int *rval) { static const char skip1[] = "#'-+ 0"; ! static const char skip2[] = "0123456789"; ! char *fmt; int fieldwidth, haveprec, havewidth, mod_ldbl, precision; char convch, nextch; ! fmt = start + 1; /* look for "n$" field index specifier */ ! fmt += strspn(fmt, skip2); ! if ((*fmt == '$') && (fmt != (start + 1))) { ! int idx = atoi(start + 1); if (idx <= myargc) { gargv = &myargv[idx - 1]; } else { gargv = &myargv[myargc]; } ! start = fmt; ! fmt++; ! } else { ! fmt = start + 1; } /* skip to field width */ ! fmt += strspn(fmt, skip1); if (*fmt == '*') { if (getint(&fieldwidth)) return (NULL); havewidth = 1; ! ++fmt; } else { havewidth = 0; /* skip to possible '.', get following precision */ ! fmt += strspn(fmt, skip2); } if (*fmt == '.') { /* precision present? */ ! ++fmt; if (*fmt == '*') { if (getint(&precision)) return (NULL); haveprec = 1; ! ++fmt; } else { haveprec = 0; /* skip to conversion char */ ! fmt += strspn(fmt, skip2); } } else haveprec = 0; if (!*fmt) { warnx1(_("missing format character"), NULL, NULL); return (NULL); } /* * Look for a length modifier. POSIX doesn't have these, so * we only support them for floating-point conversions, which * are extensions. This is useful because the L modifier can --- 171,298 ---- /* NOTREACHED */ } static char * ! doformat(char *fmt, int *rval) { static const char skip1[] = "#'-+ 0"; ! char **save; int fieldwidth, haveprec, havewidth, mod_ldbl, precision; char convch, nextch; + char *start; + char *dptr; + int l; ! start = alloca(strlen(fmt) + 1); + dptr = start; + *dptr++ = '%'; + *dptr = 0; + + fmt++; + /* look for "n$" field index specifier */ ! l = strspn(fmt, digits); ! if ((l > 0) && (fmt[l] == '$')) { ! int idx = atoi(fmt); if (idx <= myargc) { gargv = &myargv[idx - 1]; } else { gargv = &myargv[myargc]; } ! if (gargv > maxargv) { ! maxargv = gargv; } + fmt += l + 1; + } + save = gargv; + /* skip to field width */ ! while (strchr(skip1, *fmt) != NULL) { ! *dptr++ = *fmt++; ! *dptr = 0; ! } ! if (*fmt == '*') { + + fmt++; + l = strspn(fmt, digits); + if ((l > 0) && (fmt[l] == '$')) { + int idx = atoi(fmt); + if (idx <= myargc) { + gargv = &myargv[idx - 1]; + } else { + gargv = &myargv[myargc]; + } + fmt += l + 1; + } + if (getint(&fieldwidth)) return (NULL); + if (gargv > maxargv) { + maxargv = gargv; + } havewidth = 1; ! ! *dptr++ = '*'; ! *dptr = 0; } else { havewidth = 0; /* skip to possible '.', get following precision */ ! while (isdigit(*fmt)) { ! *dptr++ = *fmt++; ! *dptr = 0; } + } + if (*fmt == '.') { /* precision present? */ ! fmt++; ! *dptr++ = '.'; ! if (*fmt == '*') { + + fmt++; + l = strspn(fmt, digits); + if ((l > 0) && (fmt[l] == '$')) { + int idx = atoi(fmt); + if (idx <= myargc) { + gargv = &myargv[idx - 1]; + } else { + gargv = &myargv[myargc]; + } + fmt += l + 1; + } + if (getint(&precision)) return (NULL); + if (gargv > maxargv) { + maxargv = gargv; + } haveprec = 1; ! *dptr++ = '*'; ! *dptr = 0; } else { haveprec = 0; /* skip to conversion char */ ! while (isdigit(*fmt)) { ! *dptr++ = *fmt++; ! *dptr = 0; } + } } else haveprec = 0; if (!*fmt) { warnx1(_("missing format character"), NULL, NULL); return (NULL); } + *dptr++ = *fmt; + *dptr = 0; /* * Look for a length modifier. POSIX doesn't have these, so * we only support them for floating-point conversions, which * are extensions. This is useful because the L modifier can
*** 252,263 **** --- 311,324 ---- } } else { mod_ldbl = 0; } + gargv = save; convch = *fmt; nextch = *++fmt; + *fmt = '\0'; switch (convch) { case 'b': { size_t len; char *p;