mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-11 13:01:28 +02:00
add printf builtin (15851, 15948)
This commit is contained in:
parent
aac666130c
commit
a5890553e8
3 changed files with 197 additions and 0 deletions
|
@ -1,3 +1,8 @@
|
|||
2001-10-05 Oliver Kiddle <opk@zsh.org>
|
||||
|
||||
* 15851, 15948: Src/builtin.c, Doc/Zsh/builtins.yo: add printf
|
||||
builtin with basic POSIX functionality
|
||||
|
||||
2001-10-05 Sven Wischnowsky <wischnow@zsh.org>
|
||||
|
||||
* 15946: Src/Zle/compresult.c: fix calculation of number of
|
||||
|
|
|
@ -716,6 +716,24 @@ ifnzman(noderef(Prompt Expansion))\
|
|||
)
|
||||
enditem()
|
||||
)
|
||||
findex(printf)
|
||||
item(tt(printf) var(format) [ var(arg) ... ])(
|
||||
Print the arguments according to the format specification. Formatting
|
||||
rules are the same as used in C. The same escape sequences as for tt(echo)
|
||||
are recognised in the format. All C format specifications ending in one of
|
||||
csdiouxXeEfgG are handled. In addition to this, `tt(%b)' can be used
|
||||
instead of `tt(%s)' to cause escape sequences in the argument to be
|
||||
recognised and `tt(%q)' can be used to quote the argument in such a way
|
||||
that allows it to be reused as shell input. With the numeric format
|
||||
specifiers, if the corresponding argument starts with a quote character,
|
||||
the numeric value of the following character is used as the number to
|
||||
print.
|
||||
|
||||
If arguments remain unused after formatting, the format string is reused
|
||||
until all arguments have been consumed. If more arguments are required by
|
||||
the format than have been specified, the behaviour is as if zero or an
|
||||
empty string had been specified as the argument.
|
||||
)
|
||||
findex(pushd)
|
||||
pindex(PUSHD_TO_HOME, use of)
|
||||
pindex(PUSHD_MINUS, use of)
|
||||
|
|
174
Src/builtin.c
174
Src/builtin.c
|
@ -92,6 +92,7 @@ static struct builtin builtins[] =
|
|||
|
||||
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("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),
|
||||
|
@ -3053,6 +3054,179 @@ bin_print(char *name, char **args, char *ops, int func)
|
|||
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;
|
||||
|
||||
do {
|
||||
|
||||
for (c = fmt;c-fmt < len;c++) {
|
||||
type = prec = width = -1;
|
||||
|
||||
if (*c != '%') {
|
||||
putchar(*c);
|
||||
continue;
|
||||
}
|
||||
|
||||
start = c++;
|
||||
if (*c == '%') {
|
||||
putchar('%');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strchr("+- #", *c)) c++;
|
||||
|
||||
if (*c == '*') {
|
||||
width = (*args) ? strtoul(*args++, NULL, 0) : 0;
|
||||
c++;
|
||||
} else {
|
||||
while (idigit(*c)) c++;
|
||||
}
|
||||
|
||||
if (*c == '.') {
|
||||
c++;
|
||||
if (*c == '*') {
|
||||
prec = (*args) ? strtoul(*args++, NULL, 0) : 0;
|
||||
c++;
|
||||
} else {
|
||||
while (idigit(*c)) c++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*c == 'l' || *c == 'L' || *c == 'h') c++;
|
||||
|
||||
if (*c) {
|
||||
save = c[1];
|
||||
c[1] = '\0';
|
||||
}
|
||||
switch (*c) {
|
||||
case 'c':
|
||||
if (*args) {
|
||||
if (**args == Meta)
|
||||
intval = (*args)[1] ^ 32;
|
||||
else
|
||||
intval = **args;
|
||||
args++;
|
||||
} else
|
||||
intval = 0;
|
||||
print_val(intval);
|
||||
break;
|
||||
case 's':
|
||||
if (*args)
|
||||
stringval = unmetafy(*args++, NULL);
|
||||
else
|
||||
stringval = &nullstr;
|
||||
print_val(stringval);
|
||||
break;
|
||||
case 'b':
|
||||
if (*args) {
|
||||
int l;
|
||||
char *b = getkeystring(*args++, &l, 0, &nnl);
|
||||
fwrite(b, l, 1, stdout);
|
||||
}
|
||||
continue;
|
||||
case 'q':
|
||||
if (*args)
|
||||
stringval = bslashquote(unmetafy(*args++, NULL), NULL, 0);
|
||||
else
|
||||
stringval = &nullstr;
|
||||
*c = 's';
|
||||
print_val(stringval);
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
type=1;
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
type=2;
|
||||
break;
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
type=3;
|
||||
break;
|
||||
default:
|
||||
zerrnam(name, "%s: invalid directive", start, 0);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (type > 0) {
|
||||
if (*args && (**args == '\'' || **args == '"' )) {
|
||||
if (type == 2) {
|
||||
doubleval = (*args)[1];
|
||||
print_val(doubleval);
|
||||
} else {
|
||||
intval = (*args)[1];
|
||||
print_val(intval);
|
||||
}
|
||||
args++;
|
||||
} else {
|
||||
switch (type) {
|
||||
case 1:
|
||||
intval = (*args) ? strtol(*args, &endptr, 0) : 0;
|
||||
print_val(intval);
|
||||
break;
|
||||
case 2:
|
||||
doubleval = (*args) ? strtod(*args, &endptr) : 0;
|
||||
print_val(doubleval);
|
||||
break;
|
||||
case 3:
|
||||
uintval = (*args) ? strtoul(*args, &endptr, 0) : 0;
|
||||
print_val(uintval);
|
||||
}
|
||||
if (*args) {
|
||||
if (errno == ERANGE) {
|
||||
zerrnam(name, "`%s' arithmetic overflow", *args, 0);
|
||||
ret = 1;
|
||||
} else if (**args && endptr == *args) {
|
||||
zerrnam(name, "`%s' expected numeric value", endptr, 0);
|
||||
ret = 1;
|
||||
} else if (*endptr) {
|
||||
zerrnam(name, "`%s' not completely converted", *args, 0);
|
||||
ret = 1;
|
||||
}
|
||||
args++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*c) c[1] = save;
|
||||
}
|
||||
|
||||
/* if there are remaining args, reuse format string */
|
||||
} while (*args && args != first);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* shift builtin */
|
||||
|
||||
/**/
|
||||
|
|
Loading…
Reference in a new issue