summaryrefslogtreecommitdiff
path: root/Src/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/builtin.c')
-rw-r--r--Src/builtin.c134
1 files changed, 97 insertions, 37 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index 113c5931e..038e1a199 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2892,10 +2892,11 @@ mod_export LinkList bufstack;
int
bin_print(char *name, char **args, char *ops, int func)
{
- int flen, width, prec, type, argc, n, nnl = 0, ret = 0;
+ int flen, width, prec, type, argc, n, narg;
+ int nnl = 0, ret = 0, maxarg = 0;
int flags[5], *len;
char *start, *endptr, *c, *d, *flag, spec[11], *fmt = NULL;
- char **first, *flagch = "0+- #", save, nullstr = '\0';
+ char **first, *curarg, *flagch = "0+- #", save, nullstr = '\0';
zlong count = 0;
FILE *fout = stdout;
@@ -3095,6 +3096,11 @@ bin_print(char *name, char **args, char *ops, int func)
/* printf style output */
*spec='%';
do {
+ if (maxarg) {
+ first += maxarg;
+ argc -= maxarg;
+ maxarg = 0;
+ }
for (c = fmt;c-fmt < flen;c++) {
if (*c != '%') {
putc(*c, fout);
@@ -3111,11 +3117,29 @@ bin_print(char *name, char **args, char *ops, int func)
type = prec = -1;
width = 0;
+ curarg = NULL;
d = spec + 1;
+ if (*c >= '1' && *c <= '9') {
+ narg = strtoul(c, &endptr, 0);
+ if (*endptr == '$') {
+ c = endptr + 1;
+ DPUTS(narg <= 0, "specified zero or negative arg");
+ if (narg > argc) {
+ zwarnnam(name, "%d: argument specifier out of range",
+ 0, narg);
+ return 1;
+ } else {
+ if (narg > maxarg) maxarg = narg;
+ curarg = *(first + narg - 1);
+ }
+ }
+ }
+
+
/* copy only one of each flag as spec has finite size */
memset(flags, 0, sizeof(flags));
- while (flag = strchr(flagch, *c)) {
+ while ((flag = strchr(flagch, *c))) {
if (!flags[flag - flagch]) {
flags[flag - flagch] = 1;
*d++ = *c;
@@ -3123,28 +3147,60 @@ bin_print(char *name, char **args, char *ops, int func)
c++;
}
- if (*c == '*') {
- if (*args) width = (int)mathevali(*args++);
- if (errflag) {
- errflag = 0;
- ret = 1;
- }
- c++;
- } else if (idigit(*c)) {
+ if (idigit(*c)) {
width = strtoul(c, &endptr, 0);
c = endptr;
+ } else if (*c == '*') {
+ if (idigit(*++c)) {
+ narg = strtoul(c, &endptr, 0);
+ if (*endptr == '$') {
+ c = endptr + 1;
+ if (narg > argc || narg <= 0) {
+ zwarnnam(name,
+ "%d: argument specifier out of range",
+ 0, narg);
+ return 1;
+ } else {
+ if (narg > maxarg) maxarg = narg;
+ args = first + narg - 1;
+ }
+ }
+ }
+ if (*args) {
+ width = (int)mathevali(*args++);
+ if (errflag) {
+ errflag = 0;
+ ret = 1;
+ }
+ }
}
*d++ = '*';
if (*c == '.') {
- c++;
- if (*c == '*') {
- prec = (*args) ? (int)mathevali(*args++) : 0;
- if (errflag) {
- errflag = 0;
- ret = 1;
+ if (*++c == '*') {
+ if (idigit(*++c)) {
+ narg = strtoul(c, &endptr, 0);
+ if (*endptr == '$') {
+ c = endptr + 1;
+ if (narg > argc || narg <= 0) {
+ zwarnnam(name,
+ "%d: argument specifier out of range",
+ 0, narg);
+ return 1;
+ } else {
+ if (narg > maxarg) maxarg = narg;
+ args = first + narg - 1;
+ }
+ }
+ }
+
+ if (*args) {
+ prec = (int)mathevali(*args++);
+ if (errflag) {
+ errflag = 0;
+ ret = 1;
+ }
}
- c++;
} else if (idigit(*c)) {
prec = strtoul(c, &endptr, 0);
c = endptr;
@@ -3155,30 +3211,30 @@ bin_print(char *name, char **args, char *ops, int func)
/* ignore any size modifier */
if (*c == 'l' || *c == 'L' || *c == 'h') c++;
+ if (!curarg && *args) curarg = *args++;
d[1] = '\0';
switch (*d = *c) {
case 'c':
- if (*args) {
- intval = **args;
- args++;
+ if (curarg) {
+ intval = *curarg;
} else
intval = 0;
print_val(intval);
break;
case 's':
- stringval = *args ? *args++ : &nullstr;
+ stringval = curarg ? curarg : &nullstr;
print_val(stringval);
break;
case 'b':
- if (*args) {
+ if (curarg) {
int l;
- char *b = getkeystring(*args++, &l, ops['b'] ? 2 : 0, &nnl);
+ char *b = getkeystring(curarg, &l, ops['b'] ? 2 : 0, &nnl);
fwrite(b, l, 1, fout);
count += l;
}
break;
case 'q':
- stringval = *args ? bslashquote(*args++, NULL, 0) : &nullstr;
+ stringval = curarg ? bslashquote(curarg, NULL, 0) : &nullstr;
*d = 's';
print_val(stringval);
break;
@@ -3200,7 +3256,7 @@ bin_print(char *name, char **args, char *ops, int func)
type=3;
break;
case 'n':
- if (*args) setiparam(*args++, count);
+ if (curarg) setiparam(curarg, count);
break;
default:
if (*c) {
@@ -3208,20 +3264,21 @@ bin_print(char *name, char **args, char *ops, int func)
c[1] = '\0';
}
zwarnnam(name, "%s: invalid directive", start, 0);
- ret = 1;
if (*c) c[1] = save;
+ if (fout != stdout)
+ fclose(fout);
+ return 1;
}
if (type > 0) {
- if (*args && (**args == '\'' || **args == '"' )) {
+ if (curarg && (*curarg == '\'' || *curarg == '"' )) {
if (type == 2) {
- doubleval = (unsigned char)(*args)[1];
+ doubleval = (unsigned char)curarg[1];
print_val(doubleval);
} else {
- intval = (unsigned char)(*args)[1];
+ intval = (unsigned char)curarg[1];
print_val(intval);
}
- args++;
} else {
switch (type) {
case 1:
@@ -3229,7 +3286,7 @@ bin_print(char *name, char **args, char *ops, int func)
*d++ = 'l';
#endif
*d++ = 'l', *d++ = *c, *d = '\0';
- zlongval = (*args) ? mathevali(*args++) : 0;
+ zlongval = (curarg) ? mathevali(curarg) : 0;
if (errflag) {
zlongval = 0;
errflag = 0;
@@ -3238,8 +3295,8 @@ bin_print(char *name, char **args, char *ops, int func)
print_val(zlongval)
break;
case 2:
- if (*args) {
- mnumval = matheval(*args++);
+ if (curarg) {
+ mnumval = matheval(curarg);
doubleval = (mnumval.type & MN_FLOAT) ?
mnumval.u.d : (double)mnumval.u.l;
} else doubleval = 0;
@@ -3255,9 +3312,9 @@ bin_print(char *name, char **args, char *ops, int func)
*d++ = 'l';
#endif
*d++ = 'l', *d++ = *c, *d = '\0';
- zulongval = (*args) ? mathevali(*args++) : 0;
+ zulongval = (curarg) ? mathevali(curarg) : 0;
if (errflag) {
- doubleval = 0;
+ zulongval = 0;
errflag = 0;
ret = 1;
}
@@ -3265,10 +3322,13 @@ bin_print(char *name, char **args, char *ops, int func)
}
}
}
+ if (maxarg && (args - first > maxarg))
+ maxarg = args - first;
}
+ if (maxarg) args = first + maxarg;
/* if there are remaining args, reuse format string */
- } while (*args && args != first);
+ } while (*args && args != first && !ops['r']);
if (fout != stdout)
fclose(fout);