diff options
author | Oliver Kiddle <opk@users.sourceforge.net> | 2001-10-08 10:47:46 +0000 |
---|---|---|
committer | Oliver Kiddle <opk@users.sourceforge.net> | 2001-10-08 10:47:46 +0000 |
commit | 648d1c275613f7e43d01278fb3ffb5bca34640e2 (patch) | |
tree | a1f9616537f0836eebca8157ea836e414a8dba74 /Src | |
parent | 0ca8bb74f02b1291786f80d9e9f3f884f4ae0fa8 (diff) | |
download | zsh-648d1c275613f7e43d01278fb3ffb5bca34640e2.tar.gz zsh-648d1c275613f7e43d01278fb3ffb5bca34640e2.tar.xz zsh-648d1c275613f7e43d01278fb3ffb5bca34640e2.zip |
add print -f option, %n format specifier and tests for print/printf (15973)
Diffstat (limited to 'Src')
-rw-r--r-- | Src/builtin.c | 171 | ||||
-rw-r--r-- | Src/hashtable.h | 1 |
2 files changed, 91 insertions, 81 deletions
diff --git a/Src/builtin.c b/Src/builtin.c index 4ccc26314..a04b57163 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -91,8 +91,8 @@ static struct builtin builtins[] = #endif BUILTIN("popd", 0, bin_cd, 0, 2, BIN_POPD, NULL, NULL), - BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "RDPbnrslzNu0123456789pioOcm-", NULL), - BUILTIN("printf", 0, bin_printf, 1, -1, 0, NULL, NULL), + BUILTIN("print", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, "RDPbnrsflzNu0123456789pioOcm-", NULL), + BUILTIN("printf", 0, bin_print, 1, -1, BIN_PRINTF, NULL, NULL), BUILTIN("pushd", 0, bin_cd, 0, 2, BIN_PUSHD, NULL, NULL), BUILTIN("pushln", BINF_PRINTOPTS, bin_print, 0, -1, BIN_PRINT, NULL, "-nz"), BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL), @@ -296,10 +296,19 @@ execbuiltin(LinkList args, Builtin bn) } arg = (char *) ugetnode(args); /* for the "print" builtin, the options after -R are treated as - options to "echo" */ - if ((flags & BINF_PRINTOPTS) && ops['R']) { - optstr = "ne"; - flags |= BINF_ECHOPTS; + options to "echo" and -f takes an extra argument */ + if (flags & BINF_PRINTOPTS) { + if (ops['R'] && !ops['f']) { + optstr = "ne"; + flags |= BINF_ECHOPTS; + } else if (execop == 'f') { + if (!arg) { + zwarnnam(name, "-f: format argument expected", NULL, 0); + return 1; + } + auxdata = arg; + arg = (char *) ugetnode(args); + } } /* the option -- indicates the end of the options */ if (ops['-']) @@ -2871,17 +2880,42 @@ bin_false(char *name, char **argv, char *ops, int func) /**/ mod_export LinkList bufstack; -/* echo, print, pushln */ +/* echo, print, printf, pushln */ + +#define print_val(VAL) \ + if (width >= 0) { \ + if (prec >= 0) \ + count += fprintf(fout, start, width, prec, VAL); \ + else \ + count += fprintf(fout, start, width, VAL); \ + } else { \ + if (prec >= 0) \ + count += fprintf(fout, start, prec, VAL); \ + else \ + count += fprintf(fout, start, VAL); \ + } /**/ int bin_print(char *name, char **args, char *ops, int func) { - int nnl = 0, fd, argc, n; + int flen, width, prec, type, argc, n, nnl = 0, ret = 0; int *len; - Histent ent; + char *start, *endptr, *c, *fmt = NULL; + char **first, nullstr = '\0', save = '\0'; + zlong count = 0; FILE *fout = stdout; + double doubleval; + int intval; + unsigned int uintval; + char *stringval; + + if (func == BIN_PRINTF) auxdata = *args++; + if (auxdata) + fmt = getkeystring(auxdata, &flen, ops['b'] ? 2 : 0, &nnl); + first = args; + /* -m option -- treat the first argument as a pattern and remove * arguments not matching */ if (ops['m']) { @@ -2894,16 +2928,19 @@ bin_print(char *name, char **args, char *ops, int func) zwarnnam(name, "bad pattern : %s", *args, 0); return 1; } - for (p = ++args; *p; p++) - if (!pattry(pprog, *p)) - for (t = p--; (*t = t[1]); t++); + for (t = p = ++args; *p; p++) + if (pattry(pprog, *p)) + *t++ = *p; + *t = NULL; + first = args; + if (fmt && !*args) return 0; } /* compute lengths, and interpret according to -P, -D, -e, etc. */ argc = arrlen(args); len = (int *) hcalloc(argc * sizeof(int)); for(n = 0; n < argc; n++) { /* first \ sequences */ - if (!ops['e'] && (ops['R'] || ops['r'] || ops['E'])) + if (fmt || !ops['e'] && (ops['R'] || ops['r'] || ops['E'])) unmetafy(args[n], &len[n]); else args[n] = getkeystring(args[n], &len[n], ops['b'] ? 2 : @@ -2948,6 +2985,7 @@ bin_print(char *name, char **args, char *ops, int func) if (ops['s']) { int nwords = 0, nlen, iwords; char **pargs = args; + Histent ent; queue_signals(); ent = prepnexthistent(); @@ -2971,8 +3009,11 @@ bin_print(char *name, char **args, char *ops, int func) unqueue_signals(); return 0; } + /* -u and -p -- output to other than standard output */ if (ops['u'] || ops['p']) { + int fd; + if (ops['u']) { for (fd = 0; fd < 10; fd++) if (ops[fd + '0']) @@ -2993,15 +3034,15 @@ bin_print(char *name, char **args, char *ops, int func) /* -o and -O -- sort the arguments */ if (ops['o']) { + if (fmt && !*args) return 0; if (ops['i']) qsort(args, arrlen(args), sizeof(char *), cstrpcmp); - else qsort(args, arrlen(args), sizeof(char *), strpcmp); } else if (ops['O']) { + if (fmt && !*args) return 0; if (ops['i']) qsort(args, arrlen(args), sizeof(char *), invcstrpcmp); - else qsort(args, arrlen(args), sizeof(char *), invstrpcmp); } @@ -3041,62 +3082,37 @@ bin_print(char *name, char **args, char *ops, int func) fclose(fout); return 0; } + /* normal output */ - for (; *args; args++, len++) { - fwrite(*args, *len, 1, fout); - if (args[1]) - fputc(ops['l'] ? '\n' : ops['N'] ? '\0' : ' ', fout); + if (!fmt) { + for (; *args; args++, len++) { + fwrite(*args, *len, 1, fout); + if (args[1]) + fputc(ops['l'] ? '\n' : ops['N'] ? '\0' : ' ', fout); + } + if (!(ops['n'] || nnl)) + fputc(ops['N'] ? '\0' : '\n', fout); + if (fout != stdout) + fclose(fout); + return 0; } - if (!(ops['n'] || nnl)) - fputc(ops['N'] ? '\0' : '\n', fout); - if (fout != stdout) - fclose(fout); - return 0; -} - -/* printf */ - -#define print_val(VAL) \ - if (width >= 0) { \ - if (prec >= 0) \ - printf(start, width, prec, VAL); \ - else \ - printf(start, width, VAL); \ - } else { \ - if (prec >= 0) \ - printf(start, prec, VAL); \ - else \ - printf(start, VAL); \ - } - -/**/ -int -bin_printf(char *name, char **args, char *ops, int func) -{ - int len, nnl, width, prec, type, ret = 0; - char *start, *endptr, *c, *fmt = getkeystring(*args, &len, 0, &nnl); - char **first = ++args, nullstr = '\0', save = '\0'; - - double doubleval; - int intval; - unsigned int uintval; - char *stringval; - + + /* printf style output */ do { - - for (c = fmt;c-fmt < len;c++) { - type = prec = width = -1; - + for (c = fmt;c-fmt < flen;c++) { if (*c != '%') { - putchar(*c); + putc(*c, fout); + ++count; continue; } start = c++; if (*c == '%') { putchar('%'); + ++count; continue; } + type = prec = width = -1; if (strchr("+- #", *c)) c++; @@ -3126,34 +3142,26 @@ bin_printf(char *name, char **args, char *ops, int func) switch (*c) { case 'c': if (*args) { - if (**args == Meta) - intval = (*args)[1] ^ 32; - else - intval = **args; + intval = **args; args++; } else intval = 0; print_val(intval); break; case 's': - if (*args) - stringval = unmetafy(*args++, NULL); - else - stringval = &nullstr; + stringval = *args ? *args++ : &nullstr; print_val(stringval); break; case 'b': if (*args) { int l; - char *b = getkeystring(*args++, &l, 0, &nnl); - fwrite(b, l, 1, stdout); + char *b = getkeystring(*args++, &l, ops['b'] ? 2 : 0, &nnl); + fwrite(b, l, 1, fout); + count += l; } - continue; + break; case 'q': - if (*args) - stringval = bslashquote(unmetafy(*args++, NULL), NULL, 0); - else - stringval = &nullstr; + stringval = *args ? bslashquote(*args++, NULL, 0) : &nullstr; *c = 's'; print_val(stringval); break; @@ -3174,6 +3182,9 @@ bin_printf(char *name, char **args, char *ops, int func) case 'X': type=3; break; + case 'n': + if (*args) setiparam(*args++, count); + break; default: zerrnam(name, "%s: invalid directive", start, 0); ret = 1; @@ -3185,12 +3196,12 @@ bin_printf(char *name, char **args, char *ops, int func) doubleval = (*args)[1]; print_val(doubleval); } else { - intval = (*args)[1]; + intval = (*args)[1]; print_val(intval); } args++; } else { - switch (type) { + switch (type) { case 1: intval = (*args) ? strtol(*args, &endptr, 0) : 0; print_val(intval); @@ -3224,6 +3235,8 @@ bin_printf(char *name, char **args, char *ops, int func) /* if there are remaining args, reuse format string */ } while (*args && args != first); + if (fout != stdout) + fclose(fout); return ret; } @@ -3429,16 +3442,12 @@ bin_break(char *name, char **argv, char *ops, int func) } /*FALLTHROUGH*/ case BIN_EXIT: - if (locallevel > forklevel) { + if (locallevel) { /* * We don't exit directly from functions to allow tidying * up, in particular EXIT traps. We still need to perform * the usual interactive tests to see if we can exit at * all, however. - * - * The forklevel test means we *do* exit from a subshell - * inside a function when we reach the level of the - * function itself. */ if (stopmsg || (zexit(0,2), !stopmsg)) { retflag = 1; diff --git a/Src/hashtable.h b/Src/hashtable.h index 5b78c9c18..aa12ad3cb 100644 --- a/Src/hashtable.h +++ b/Src/hashtable.h @@ -56,6 +56,7 @@ #define BIN_ECHO 22 #define BIN_DISABLE 23 #define BIN_ENABLE 24 +#define BIN_PRINTF 25 /* These currently depend on being 0 and 1. */ #define BIN_SETOPT 0 |