Add width and precision specifiers to printf(1) %n$.
This actually completes r264743 so that width and precision specifiers work properly with %n$. These keeps consistency with ksh93 and zsh. Requested by: jilles Obtained from: Garrett D'Amore (Illumos) MFC after: 4 days
This commit is contained in:
parent
4d6bab2606
commit
f8a6c905bf
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=265592
@ -1,4 +1,5 @@
|
|||||||
/*-
|
/*-
|
||||||
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org>
|
||||||
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
|
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
|
||||||
* Copyright (c) 1989, 1993
|
* Copyright (c) 1989, 1993
|
||||||
* The Regents of the University of California. All rights reserved.
|
* The Regents of the University of California. All rights reserved.
|
||||||
@ -50,6 +51,7 @@ static const char rcsid[] =
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
@ -70,11 +72,6 @@ static const char rcsid[] =
|
|||||||
|
|
||||||
#define PF(f, func) do { \
|
#define PF(f, func) do { \
|
||||||
char *b = NULL; \
|
char *b = NULL; \
|
||||||
int dollar = 0; \
|
|
||||||
if (*f == '$') { \
|
|
||||||
dollar++; \
|
|
||||||
*f = '%'; \
|
|
||||||
} \
|
|
||||||
if (havewidth) \
|
if (havewidth) \
|
||||||
if (haveprec) \
|
if (haveprec) \
|
||||||
(void)asprintf(&b, f, fieldwidth, precision, func); \
|
(void)asprintf(&b, f, fieldwidth, precision, func); \
|
||||||
@ -88,8 +85,6 @@ static const char rcsid[] =
|
|||||||
(void)fputs(b, stdout); \
|
(void)fputs(b, stdout); \
|
||||||
free(b); \
|
free(b); \
|
||||||
} \
|
} \
|
||||||
if (dollar) \
|
|
||||||
*f = '$'; \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int asciicode(void);
|
static int asciicode(void);
|
||||||
@ -104,9 +99,12 @@ static const char
|
|||||||
static char *mknum(char *, char);
|
static char *mknum(char *, char);
|
||||||
static void usage(void);
|
static void usage(void);
|
||||||
|
|
||||||
|
static const char digits[] = "0123456789";
|
||||||
|
|
||||||
static int myargc;
|
static int myargc;
|
||||||
static char **myargv;
|
static char **myargv;
|
||||||
static char **gargv;
|
static char **gargv;
|
||||||
|
static char **maxargv;
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
@ -158,7 +156,7 @@ main(int argc, char *argv[])
|
|||||||
gargv = ++argv;
|
gargv = ++argv;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char **maxargv = gargv;
|
maxargv = gargv;
|
||||||
|
|
||||||
myargv = gargv;
|
myargv = gargv;
|
||||||
for (myargc = 0; gargv[myargc]; myargc++)
|
for (myargc = 0; gargv[myargc]; myargc++)
|
||||||
@ -212,57 +210,115 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
printf_doformat(char *start, int *rval)
|
printf_doformat(char *fmt, int *rval)
|
||||||
{
|
{
|
||||||
static const char skip1[] = "#'-+ 0";
|
static const char skip1[] = "#'-+ 0";
|
||||||
static const char skip2[] = "0123456789";
|
|
||||||
char *fmt;
|
|
||||||
int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
|
int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
|
||||||
char convch, nextch;
|
char convch, nextch;
|
||||||
|
char *start;
|
||||||
|
char **fargv;
|
||||||
|
char *dptr;
|
||||||
|
int l;
|
||||||
|
|
||||||
fmt = start + 1;
|
start = alloca(strlen(fmt) + 1);
|
||||||
|
|
||||||
|
dptr = start;
|
||||||
|
*dptr++ = '%';
|
||||||
|
*dptr = 0;
|
||||||
|
|
||||||
|
fmt++;
|
||||||
|
|
||||||
/* look for "n$" field index specifier */
|
/* look for "n$" field index specifier */
|
||||||
fmt += strspn(fmt, skip2);
|
l = strspn(fmt, digits);
|
||||||
if ((*fmt == '$') && (fmt != (start + 1))) {
|
if ((l > 0) && (fmt[l] == '$')) {
|
||||||
int idx = atoi(start + 1);
|
int idx = atoi(fmt);
|
||||||
if (idx <= myargc) {
|
if (idx <= myargc) {
|
||||||
gargv = &myargv[idx - 1];
|
gargv = &myargv[idx - 1];
|
||||||
} else {
|
} else {
|
||||||
gargv = &myargv[myargc];
|
gargv = &myargv[myargc];
|
||||||
}
|
}
|
||||||
start = fmt;
|
if (gargv > maxargv)
|
||||||
fmt++;
|
maxargv = gargv;
|
||||||
|
fmt += l + 1;
|
||||||
|
|
||||||
|
/* save format argument */
|
||||||
|
fargv = gargv;
|
||||||
} else {
|
} else {
|
||||||
fmt = start + 1;
|
fargv = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* skip to field width */
|
/* skip to field width */
|
||||||
fmt += strspn(fmt, skip1);
|
while (strchr(skip1, *fmt) != NULL) {
|
||||||
|
*dptr++ = *fmt++;
|
||||||
|
*dptr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (*fmt == '*') {
|
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))
|
if (getint(&fieldwidth))
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
if (gargv > maxargv)
|
||||||
|
maxargv = gargv;
|
||||||
havewidth = 1;
|
havewidth = 1;
|
||||||
++fmt;
|
|
||||||
|
*dptr++ = '*';
|
||||||
|
*dptr = 0;
|
||||||
} else {
|
} else {
|
||||||
havewidth = 0;
|
havewidth = 0;
|
||||||
|
|
||||||
/* skip to possible '.', get following precision */
|
/* skip to possible '.', get following precision */
|
||||||
fmt += strspn(fmt, skip2);
|
while (isdigit(*fmt)) {
|
||||||
|
*dptr++ = *fmt++;
|
||||||
|
*dptr = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*fmt == '.') {
|
if (*fmt == '.') {
|
||||||
/* precision present? */
|
/* precision present? */
|
||||||
++fmt;
|
fmt++;
|
||||||
|
*dptr++ = '.';
|
||||||
|
|
||||||
if (*fmt == '*') {
|
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))
|
if (getint(&precision))
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
if (gargv > maxargv)
|
||||||
|
maxargv = gargv;
|
||||||
haveprec = 1;
|
haveprec = 1;
|
||||||
++fmt;
|
*dptr++ = '*';
|
||||||
|
*dptr = 0;
|
||||||
} else {
|
} else {
|
||||||
haveprec = 0;
|
haveprec = 0;
|
||||||
|
|
||||||
/* skip to conversion char */
|
/* skip to conversion char */
|
||||||
fmt += strspn(fmt, skip2);
|
while (isdigit(*fmt)) {
|
||||||
|
*dptr++ = *fmt++;
|
||||||
|
*dptr = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
haveprec = 0;
|
haveprec = 0;
|
||||||
@ -270,6 +326,8 @@ printf_doformat(char *start, int *rval)
|
|||||||
warnx("missing format character");
|
warnx("missing format character");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
*dptr++ = *fmt;
|
||||||
|
*dptr = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for a length modifier. POSIX doesn't have these, so
|
* Look for a length modifier. POSIX doesn't have these, so
|
||||||
@ -292,8 +350,14 @@ printf_doformat(char *start, int *rval)
|
|||||||
mod_ldbl = 0;
|
mod_ldbl = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* save the current arg offset, and set to the format arg */
|
||||||
|
if (fargv != NULL) {
|
||||||
|
gargv = fargv;
|
||||||
|
}
|
||||||
|
|
||||||
convch = *fmt;
|
convch = *fmt;
|
||||||
nextch = *++fmt;
|
nextch = *++fmt;
|
||||||
|
|
||||||
*fmt = '\0';
|
*fmt = '\0';
|
||||||
switch (convch) {
|
switch (convch) {
|
||||||
case 'b': {
|
case 'b': {
|
||||||
@ -365,6 +429,7 @@ printf_doformat(char *start, int *rval)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
*fmt = nextch;
|
*fmt = nextch;
|
||||||
|
/* return the gargv to the next element */
|
||||||
return (fmt);
|
return (fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,7 +573,7 @@ getnum(intmax_t *ip, uintmax_t *uip, int signedconv)
|
|||||||
int rval;
|
int rval;
|
||||||
|
|
||||||
if (!*gargv) {
|
if (!*gargv) {
|
||||||
*ip = *uip = 0;
|
*ip = 0;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (**gargv == '"' || **gargv == '\'') {
|
if (**gargv == '"' || **gargv == '\'') {
|
||||||
|
Loading…
Reference in New Issue
Block a user