mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-02 22:11:54 +02:00
manual/7915
This commit is contained in:
parent
77c1b9a3d4
commit
d0f024f152
12 changed files with 812 additions and 354 deletions
|
@ -6,12 +6,13 @@ sect(Arithmetic Evaluation)
|
|||
cindex(arithmetic evaluation)
|
||||
cindex(evaluation, arithmetic)
|
||||
findex(let, use of)
|
||||
The shell can perform integer arithmetic, either using the builtin tt(let),
|
||||
or via a substitution of the form tt($((...))). The shell is usually
|
||||
compiled to use 8-byte precision where this is available, otherwise
|
||||
precision is 4 bytes. This can be tested, for example, by giving the
|
||||
command `tt(print - $(( 12345678901 )))'; if the number appears unchanged,
|
||||
the precision is at least 8 bytes.
|
||||
The shell can perform integer and floating point arithmetic, either using
|
||||
the builtin tt(let), or via a substitution of the form tt($((...))). For
|
||||
integers, the shell is usually compiled to use 8-byte precision where this
|
||||
is available, otherwise precision is 4 bytes. This can be tested, for
|
||||
example, by giving the command `tt(print - $(( 12345678901 )))'; if the
|
||||
number appears unchanged, the precision is at least 8 bytes. Floating
|
||||
point arithmetic is always double precision.
|
||||
|
||||
The tt(let) builtin command takes arithmetic expressions as arguments; each
|
||||
is evaluated separately. Since many of the arithmetic operators, as well
|
||||
|
@ -32,9 +33,9 @@ both assigning the value 3 to the shell variable tt(foo) and returning a
|
|||
zero status.
|
||||
|
||||
cindex(bases, in arithmetic)
|
||||
Numbers can be in bases other than 10.
|
||||
Integers can be in bases other than 10.
|
||||
A leading `tt(0x)' or `tt(0X)' denotes hexadecimal.
|
||||
Numbers may also be of the form `var(base)tt(#)var(n)',
|
||||
Integers may also be of the form `var(base)tt(#)var(n)',
|
||||
where var(base) is a decimal number between two and thirty-six
|
||||
representing the arithmetic base and var(n)
|
||||
is a number in that base (for example, `tt(16#ff)' is 255 in hexadecimal).
|
||||
|
@ -42,6 +43,11 @@ The var(base)tt(#) may also be omitted, in which case
|
|||
base 10 is used. For backwards compatibility the form
|
||||
`tt([)var(base)tt(])var(n)' is also accepted.
|
||||
|
||||
Floating point constants are recognized by the presence of a decimal point
|
||||
or an exponent. The decimal point may be the first character of the
|
||||
constant, but the exponent character tt(e) or tt(E) may not, as it will be
|
||||
taken for a parameter name.
|
||||
|
||||
cindex(arithmetic operators)
|
||||
cindex(operators, arithmetic)
|
||||
An arithmetic expression uses nearly the same syntax, precedence, and
|
||||
|
@ -67,9 +73,9 @@ sitem(tt(= PLUS()= -= *= /= %= &= ^= |= <<= >>= &&= ||= ^^= **=))(assignment)
|
|||
sitem(tt(,))(comma operator)
|
||||
endsitem()
|
||||
|
||||
The operators `tt(&&)', `tt(||)', `tt(&&=)', and `tt(||=)' are short-circuiting,
|
||||
and only one of the latter two expressions in a ternary operator
|
||||
is evaluated. Note the precedence of the bitwise AND, OR,
|
||||
The operators `tt(&&)', `tt(||)', `tt(&&=)', and `tt(||=)' are
|
||||
short-circuiting, and only one of the latter two expressions in a ternary
|
||||
operator is evaluated. Note the precedence of the bitwise AND, OR,
|
||||
and XOR operators.
|
||||
|
||||
An expression of the form `tt(#\)var(x)' where var(x) is any character
|
||||
|
@ -95,4 +101,41 @@ cindex(integer parameters)
|
|||
findex(integer, use of)
|
||||
Arithmetic evaluation is performed on the value of each
|
||||
assignment to a named parameter declared integer
|
||||
in this manner.
|
||||
in this manner. Assigning a floating point number to an integer results in
|
||||
rounding down to the next integer.
|
||||
|
||||
cindex(parameters, floating point)
|
||||
cindex(floating point parameters)
|
||||
findex(float, use of)
|
||||
Likewise, floating point numbers can be declared with the tt(float)
|
||||
builtin; there are two types, differing only in their output format, as
|
||||
described for the tt(typeset) builtin. The output format can be bypassed
|
||||
by using arithmetic substitution instead of the parameter substitution,
|
||||
i.e. `tt(${)var(float)tt(})' uses the defined format, but
|
||||
`tt($LPAR()LPAR())var(float)tt(RPAR()RPAR())' uses a generic floating point
|
||||
format.
|
||||
|
||||
Promotion of integer to floating point values is performed where
|
||||
necessary. In addition, if any operator which requires an integer
|
||||
(`tt(~)', `tt(&)', `tt(|)', `tt(^)', `tt(%)', `tt(<<)', `tt(>>)' and their
|
||||
equivalents with assignment) is given a floating point argument, it will be
|
||||
silently rounded down to the next integer.
|
||||
|
||||
Scalar variables can hold integer or floating point values at different
|
||||
times; there is no memory of the numeric type in this case.
|
||||
|
||||
If a variable is first assigned in a numeric context without previously
|
||||
being declared, it will be implicitly typed as tt(integer) or tt(float) and
|
||||
retain that type either until the type is explicitly changed or until the
|
||||
end of the scope. This can have unforeseen consequences. For example, in
|
||||
the loop
|
||||
|
||||
example(for (( f = 0; f < 1; f += 0.1 )); do;
|
||||
# use $f
|
||||
done)
|
||||
|
||||
if tt(f) has not already been declared, the first assignment will cause it
|
||||
to be created as an integer, and consequently the operation `tt(f += 0.1)'
|
||||
will always cause the result to be truncated to zero, so that the loop will
|
||||
fail. A simple fix would be to turn the initialization into `tt(f = 0.0)'.
|
||||
It is therefore best to declare numeric variables with explicit types.
|
||||
|
|
|
@ -347,6 +347,11 @@ item(var(job) ...)(
|
|||
Bring each specified var(job) in turn to the foreground.
|
||||
If no var(job) is specified, resume the current job.
|
||||
)
|
||||
findex(float)
|
||||
item(tt(float) [ {tt(PLUE())|tt(-)}tt(EFghlrtux) ] [ var(name)[tt(=)var(value)] ... ])(
|
||||
Equivalent to tt(typeset -E), except that options irrelevant to floating
|
||||
point numbers are not permitted.
|
||||
)
|
||||
findex(functions)
|
||||
item(tt(functions) [ {tt(PLUS())|tt(-)}tt(tum) ] [ var(name) ... ])(
|
||||
Equivalent to tt(typeset -f).
|
||||
|
@ -533,7 +538,7 @@ sitem([var(mm)tt(:)]var(ss))(minutes and seconds)
|
|||
endsitem()
|
||||
)
|
||||
findex(local)
|
||||
item(tt(local) [ {tt(PLUS())|tt(-)}tt(ALRUZahilrtu) [var(n)]] [ var(name)[tt(=)var(value)] ] ...)(
|
||||
item(tt(local) [ {tt(PLUS())|tt(-)}tt(AEFLRUZahilrtu) [var(n)]] [ var(name)[tt(=)var(value)] ] ...)(
|
||||
Same as tt(typeset), except that the options tt(-g), tt(-x) and
|
||||
tt(-f) are not permitted.
|
||||
)
|
||||
|
@ -922,7 +927,7 @@ Equivalent to tt(whence -v).
|
|||
findex(typeset)
|
||||
cindex(parameters, setting)
|
||||
cindex(parameters, declaring)
|
||||
xitem(tt(typeset) [ {tt(PLUS())|tt(-)}tt(ALRUZafghilrtuxm) [var(n)]] [ \
|
||||
xitem(tt(typeset) [ {tt(PLUS())|tt(-)}tt(AEFLRUZafghilrtuxm) [var(n)]] [ \
|
||||
var(name)[tt(=)var(value)] ... ])
|
||||
item(tt(typeset) -T [ {tt(PLUS()|tt(-))}tt(LRUZrux) ] \
|
||||
var(SCALAR)[tt(=)var(value)] var(array))(
|
||||
|
@ -1061,6 +1066,18 @@ Use an internal integer representation. If var(n) is nonzero it
|
|||
defines the output arithmetic base, otherwise it is determined by the
|
||||
first assignment.
|
||||
)
|
||||
item(tt(-E))(
|
||||
Use an internal double-precision floating point representation. On output
|
||||
the variable will be converted to scientific notation. If var(n) is
|
||||
nonzero it defines the number of significant figures to display; the
|
||||
default is ten.
|
||||
)
|
||||
item(tt(-F))(
|
||||
Use an internal double-precision floating point representation. On output
|
||||
the variable will be converted to fixed-point decimal notation. If var(n)
|
||||
is nonzero it defines the number of digits to display after the decimal
|
||||
point; the default is ten.
|
||||
)
|
||||
item(tt(-l))(
|
||||
Convert the result to lower case whenever the parameter is expanded.
|
||||
The value is em(not) converted when assigned.
|
||||
|
|
|
@ -90,6 +90,8 @@ paramtypestr(Param pm)
|
|||
case PM_SCALAR: val = "scalar"; break;
|
||||
case PM_ARRAY: val = "array"; break;
|
||||
case PM_INTEGER: val = "integer"; break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT: val = "float"; break;
|
||||
case PM_HASHED: val = "association"; break;
|
||||
}
|
||||
DPUTS(!val, "BUG: type not handled in parameter");
|
||||
|
|
|
@ -50,7 +50,7 @@ static struct builtin builtins[] =
|
|||
BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL),
|
||||
BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL),
|
||||
BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL),
|
||||
BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafghilrtux", NULL),
|
||||
BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFLRTUZafghilrtux", NULL),
|
||||
BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL),
|
||||
BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL),
|
||||
BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
|
||||
|
@ -60,10 +60,11 @@ static struct builtin builtins[] =
|
|||
BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL),
|
||||
BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
|
||||
BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
|
||||
BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRTUZafhilrtu", "xg"),
|
||||
BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "EFLRTUZafhilrtu", "xg"),
|
||||
BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
|
||||
BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", NULL),
|
||||
BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
|
||||
BUILTIN("float", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "EFghlrtux", "E"),
|
||||
BUILTIN("functions", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "mtuU", NULL),
|
||||
BUILTIN("getln", 0, bin_read, 0, -1, 0, "ecnAlE", "zr"),
|
||||
BUILTIN("getopts", 0, bin_getopts, 2, -1, 0, NULL, NULL),
|
||||
|
@ -78,7 +79,7 @@ static struct builtin builtins[] =
|
|||
BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL),
|
||||
BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL),
|
||||
BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
|
||||
BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZahilrtu", NULL),
|
||||
BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFLRTUZahilrtu", NULL),
|
||||
BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
|
||||
BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL),
|
||||
|
||||
|
@ -97,7 +98,7 @@ static struct builtin builtins[] =
|
|||
BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL),
|
||||
BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL),
|
||||
BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL),
|
||||
BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafghiltux", "r"),
|
||||
BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFLRTUZafghiltux", "r"),
|
||||
BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"),
|
||||
BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL),
|
||||
BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL),
|
||||
|
@ -111,7 +112,7 @@ static struct builtin builtins[] =
|
|||
BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL),
|
||||
BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL),
|
||||
BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"),
|
||||
BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRTUZafghilrtuxm", NULL),
|
||||
BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFLRTUZafghilrtuxm", NULL),
|
||||
BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL),
|
||||
BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"),
|
||||
BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"),
|
||||
|
@ -215,6 +216,7 @@ execbuiltin(LinkList args, Builtin bn)
|
|||
LinkNode n;
|
||||
char ops[MAX_OPS], *arg, *pp, *name, **argv, **oargv, *optstr;
|
||||
char *oxarg, *xarg = NULL;
|
||||
char typenumstr[] = TYPESET_OPTNUM;
|
||||
int flags, sense, argc = 0, execop, xtr = isset(XTRACE), lxarg = 0;
|
||||
|
||||
/* initialise some static variables */
|
||||
|
@ -289,8 +291,7 @@ execbuiltin(LinkList args, Builtin bn)
|
|||
/* "typeset" may take a numeric argument *
|
||||
* at the tail of the options */
|
||||
if (idigit(*arg) && (flags & BINF_TYPEOPT) &&
|
||||
(arg[-1] == 'L' || arg[-1] == 'R' ||
|
||||
arg[-1] == 'Z' || arg[-1] == 'i'))
|
||||
strchr(typenumstr, arg[-1]))
|
||||
auxlen = (int)zstrtol(arg, &arg, 10);
|
||||
/* The above loop may have exited on an invalid option. (We *
|
||||
* assume that any option requiring metafication is invalid.) */
|
||||
|
@ -315,9 +316,9 @@ execbuiltin(LinkList args, Builtin bn)
|
|||
auxdata = arg;
|
||||
arg = (char *) ugetnode(args);
|
||||
}
|
||||
/* for "typeset", -L, -R, -Z and -i take a numeric extra argument */
|
||||
if ((flags & BINF_TYPEOPT) && (execop == 'L' || execop == 'R' ||
|
||||
execop == 'Z' || execop == 'i') && arg && idigit(*arg)) {
|
||||
/* some "typeset" options take a numeric extra argument */
|
||||
if ((flags & BINF_TYPEOPT) && strchr(typenumstr, execop) &&
|
||||
arg && idigit(*arg)) {
|
||||
auxlen = atoi(arg);
|
||||
arg = (char *) ugetnode(args);
|
||||
}
|
||||
|
@ -1571,10 +1572,15 @@ typeset_single(char *cname, char *pname, Param pm, int func,
|
|||
}
|
||||
|
||||
/* attempting a type conversion, or making a tied colonarray? */
|
||||
if ((tc = (usepm || newspecial)
|
||||
&& (((off & pm->flags) | (on & ~pm->flags)) &
|
||||
(PM_INTEGER|PM_HASHED|PM_ARRAY|PM_TIED|PM_AUTOLOAD))))
|
||||
usepm = 0;
|
||||
tc = 0;
|
||||
if (usepm || newspecial) {
|
||||
int chflags = ((off & pm->flags) | (on & ~pm->flags)) &
|
||||
(PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED|
|
||||
PM_ARRAY|PM_TIED|PM_AUTOLOAD);
|
||||
/* keep the parameter if just switching between floating types */
|
||||
if ((tc = chflags && chflags != (PM_EFLOAT|PM_FFLOAT)))
|
||||
usepm = 0;
|
||||
}
|
||||
if (tc && (pm->flags & PM_SPECIAL)) {
|
||||
zerrnam(cname, "%s: can't change type of a special parameter",
|
||||
pname, 0);
|
||||
|
@ -1615,7 +1621,8 @@ typeset_single(char *cname, char *pname, Param pm, int func,
|
|||
}
|
||||
pm->flags = (pm->flags | on) & ~off;
|
||||
/* This auxlen/pm->ct stuff is a nasty hack. */
|
||||
if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) &&
|
||||
if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER |
|
||||
PM_EFLOAT | PM_FFLOAT)) &&
|
||||
auxlen)
|
||||
pm->ct = auxlen;
|
||||
if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
|
||||
|
@ -1711,7 +1718,8 @@ typeset_single(char *cname, char *pname, Param pm, int func,
|
|||
* Final tweak: if we've turned on one of the flags with
|
||||
* numbers, we should use the appropriate integer.
|
||||
*/
|
||||
if (on & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z|PM_INTEGER))
|
||||
if (on & (PM_LEFT|PM_RIGHT_B|PM_RIGHT_Z|PM_INTEGER|
|
||||
PM_EFLOAT|PM_FFLOAT))
|
||||
pm->ct = auxlen;
|
||||
else
|
||||
pm->ct = 0;
|
||||
|
@ -1756,6 +1764,10 @@ typeset_single(char *cname, char *pname, Param pm, int func,
|
|||
case PM_INTEGER:
|
||||
pm->sets.ifn(pm, 0);
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
pm->sets.ffn(pm, 0.0);
|
||||
break;
|
||||
case PM_ARRAY:
|
||||
pm->sets.afn(pm, mkarray(NULL));
|
||||
break;
|
||||
|
@ -1785,7 +1797,7 @@ bin_typeset(char *name, char **argv, char *ops, int func)
|
|||
Param pm;
|
||||
Asgment asg;
|
||||
Patprog pprog;
|
||||
char *optstr = "aiALRZlurtxUhT";
|
||||
char *optstr = TYPESET_OPTSTR;
|
||||
int on = 0, off = 0, roff, bit = PM_ARRAY;
|
||||
int i;
|
||||
int returnval = 0, printflags = 0;
|
||||
|
@ -1805,14 +1817,24 @@ bin_typeset(char *name, char **argv, char *ops, int func)
|
|||
roff = off;
|
||||
|
||||
/* Sanity checks on the options. Remove conficting options. */
|
||||
if (on & PM_FFLOAT) {
|
||||
off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY
|
||||
| PM_INTEGER | PM_EFLOAT;
|
||||
/* Allow `float -F' to work even though float sets -E by default */
|
||||
on &= ~PM_EFLOAT;
|
||||
}
|
||||
if (on & PM_EFLOAT)
|
||||
off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY
|
||||
| PM_INTEGER | PM_FFLOAT;
|
||||
if (on & PM_INTEGER)
|
||||
off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY;
|
||||
off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
|
||||
PM_EFLOAT | PM_FFLOAT;
|
||||
if (on & PM_LEFT)
|
||||
off |= PM_RIGHT_B | PM_INTEGER;
|
||||
off |= PM_RIGHT_B | PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
|
||||
if (on & PM_RIGHT_B)
|
||||
off |= PM_LEFT | PM_INTEGER;
|
||||
off |= PM_LEFT | PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
|
||||
if (on & PM_RIGHT_Z)
|
||||
off |= PM_INTEGER;
|
||||
off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
|
||||
if (on & PM_UPPER)
|
||||
off |= PM_LOWER;
|
||||
if (on & PM_LOWER)
|
||||
|
@ -1820,7 +1842,7 @@ bin_typeset(char *name, char **argv, char *ops, int func)
|
|||
if (on & PM_HASHED)
|
||||
off |= PM_ARRAY;
|
||||
if (on & PM_TIED)
|
||||
off |= PM_INTEGER | PM_ARRAY | PM_HASHED;
|
||||
off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED;
|
||||
|
||||
on &= ~off;
|
||||
|
||||
|
@ -2900,7 +2922,7 @@ bin_shift(char *name, char **argv, char *ops, int func)
|
|||
|
||||
/* optional argument can be either numeric or an array */
|
||||
if (*argv && !getaparam(*argv))
|
||||
num = matheval(*argv++);
|
||||
num = mathevali(*argv++);
|
||||
|
||||
if (num < 0) {
|
||||
zwarnnam(name, "argument to shift must be non-negative", NULL, 0);
|
||||
|
@ -3042,7 +3064,7 @@ bin_break(char *name, char **argv, char *ops, int func)
|
|||
|
||||
/* handle one optional numeric argument */
|
||||
if (*argv) {
|
||||
num = matheval(*argv++);
|
||||
num = mathevali(*argv++);
|
||||
nump = 1;
|
||||
}
|
||||
|
||||
|
@ -3857,7 +3879,7 @@ bin_let(char *name, char **argv, char *ops, int func)
|
|||
zlong val = 0;
|
||||
|
||||
while (*argv)
|
||||
val = matheval(*argv++);
|
||||
val = mathevali(*argv++);
|
||||
/* Errors in math evaluation in let are non-fatal. */
|
||||
errflag = 0;
|
||||
return !val;
|
||||
|
|
55
Src/cond.c
55
Src/cond.c
|
@ -127,6 +127,45 @@ evalcond(Cond c)
|
|||
fprintf(stderr, " -%c %s", c->type, (char *)left);
|
||||
}
|
||||
|
||||
if (c->type >= COND_EQ && c->type <= COND_GE) {
|
||||
mnumber mn1, mn2;
|
||||
mn1 = matheval(left);
|
||||
mn2 = matheval(right);
|
||||
|
||||
if (((mn1.type|mn2.type) & (MN_INTEGER|MN_FLOAT)) ==
|
||||
(MN_INTEGER|MN_FLOAT)) {
|
||||
/* promote to float */
|
||||
if (mn1.type & MN_INTEGER) {
|
||||
mn1.type = MN_FLOAT;
|
||||
mn1.u.d = (double)mn1.u.l;
|
||||
}
|
||||
if (mn2.type & MN_INTEGER) {
|
||||
mn2.type = MN_FLOAT;
|
||||
mn2.u.d = (double)mn2.u.l;
|
||||
}
|
||||
}
|
||||
switch(c->type) {
|
||||
case COND_EQ:
|
||||
return (mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) :
|
||||
(mn1.u.l == mn2.u.l);
|
||||
case COND_NE:
|
||||
return (mn1.type & MN_FLOAT) ? (mn1.u.d != mn2.u.d) :
|
||||
(mn1.u.l != mn2.u.l);
|
||||
case COND_LT:
|
||||
return (mn1.type & MN_FLOAT) ? (mn1.u.d < mn2.u.d) :
|
||||
(mn1.u.l < mn2.u.l);
|
||||
case COND_GT:
|
||||
return (mn1.type & MN_FLOAT) ? (mn1.u.d > mn2.u.d) :
|
||||
(mn1.u.l > mn2.u.l);
|
||||
case COND_LE:
|
||||
return (mn1.type & MN_FLOAT) ? (mn1.u.d <= mn2.u.d) :
|
||||
(mn1.u.l <= mn2.u.l);
|
||||
case COND_GE:
|
||||
return (mn1.type & MN_FLOAT) ? (mn1.u.d >= mn2.u.d) :
|
||||
(mn1.u.l >= mn2.u.l);
|
||||
}
|
||||
}
|
||||
|
||||
switch (c->type) {
|
||||
case COND_STREQ:
|
||||
return matchpat(left, right);
|
||||
|
@ -185,19 +224,7 @@ evalcond(Cond c)
|
|||
case 'N':
|
||||
return ((st = getstat(left)) && st->st_atime <= st->st_mtime);
|
||||
case 't':
|
||||
return isatty(matheval(left));
|
||||
case COND_EQ:
|
||||
return matheval(left) == matheval(right);
|
||||
case COND_NE:
|
||||
return matheval(left) != matheval(right);
|
||||
case COND_LT:
|
||||
return matheval(left) < matheval(right);
|
||||
case COND_GT:
|
||||
return matheval(left) > matheval(right);
|
||||
case COND_LE:
|
||||
return matheval(left) <= matheval(right);
|
||||
case COND_GE:
|
||||
return matheval(left) >= matheval(right);
|
||||
return isatty(mathevali(left));
|
||||
case COND_NT:
|
||||
case COND_OT:
|
||||
{
|
||||
|
@ -323,7 +350,7 @@ cond_val(char **args, int num)
|
|||
singsub(&s);
|
||||
untokenize(s);
|
||||
|
||||
return matheval(s);
|
||||
return mathevali(s);
|
||||
}
|
||||
|
||||
/**/
|
||||
|
|
|
@ -2182,6 +2182,10 @@ restore_params(LinkList restorelist, LinkList removelist)
|
|||
case PM_INTEGER:
|
||||
tpm->sets.ifn(tpm, pm->u.val);
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
tpm->sets.ffn(tpm, pm->u.dval);
|
||||
break;
|
||||
case PM_ARRAY:
|
||||
tpm->sets.afn(tpm, pm->u.arr);
|
||||
break;
|
||||
|
@ -2757,7 +2761,7 @@ execarith(Cmd cmd, LinkList args, int flags)
|
|||
while ((e = (char *) ugetnode(args))) {
|
||||
if (isset(XTRACE))
|
||||
fprintf(stderr, " %s", e);
|
||||
val = matheval(e);
|
||||
val = mathevali(e);
|
||||
}
|
||||
if (isset(XTRACE)) {
|
||||
fprintf(stderr, " ))\n");
|
||||
|
|
588
Src/math.c
588
Src/math.c
|
@ -30,6 +30,8 @@
|
|||
#include "zsh.mdh"
|
||||
#include "math.pro"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* nonzero means we are not evaluating, just parsing */
|
||||
|
||||
/**/
|
||||
|
@ -42,7 +44,7 @@ int lastbase;
|
|||
|
||||
static char *ptr;
|
||||
|
||||
static zlong yyval;
|
||||
static mnumber yyval;
|
||||
static LV yylval;
|
||||
|
||||
static int mlevel = 0;
|
||||
|
@ -53,12 +55,27 @@ static int unary = 1;
|
|||
|
||||
/* LR = left-to-right associativity *
|
||||
* RL = right-to-left associativity *
|
||||
* BOO = short-circuiting boolean */
|
||||
* BOOL = short-circuiting boolean */
|
||||
|
||||
#define LR 0
|
||||
#define RL 1
|
||||
#define BOOL 2
|
||||
|
||||
#define MTYPE(x) ((x) & 3)
|
||||
|
||||
/*
|
||||
* OP_A2 2 argument
|
||||
* OP_A2IR 2 argument with return type integer
|
||||
* OP_A2IO 2 arguments, must be integer, returning integer
|
||||
* OP_E2 2 argument with assignment
|
||||
* OP_E2IO 2 arguments with assignment, must be integer, return integer
|
||||
*/
|
||||
#define OP_A2 4
|
||||
#define OP_A2IR 8
|
||||
#define OP_A2IO 16
|
||||
#define OP_E2 32
|
||||
#define OP_E2IO 64
|
||||
|
||||
#define M_INPAR 0
|
||||
#define M_OUTPAR 1
|
||||
#define NOT 2
|
||||
|
@ -135,17 +152,17 @@ static int prec[TOKCOUNT] =
|
|||
|
||||
static int type[TOKCOUNT] =
|
||||
{
|
||||
LR, LR, RL, RL, RL,
|
||||
RL, RL, RL, LR, LR,
|
||||
LR, LR, LR, LR, LR,
|
||||
LR, LR, LR, LR, LR,
|
||||
LR, LR, LR, LR, BOOL,
|
||||
BOOL, LR, RL, RL, RL,
|
||||
RL, RL, RL, RL, RL,
|
||||
RL, RL, RL, RL, RL,
|
||||
BOOL, BOOL, RL, RL, RL,
|
||||
RL, RL, LR, LR, RL,
|
||||
LR, RL
|
||||
/* 0 */ LR, LR, RL, RL, RL,
|
||||
/* 5 */ RL, RL, RL, LR|OP_A2IO, LR|OP_A2IO,
|
||||
/* 10 */ LR|OP_A2IO, LR|OP_A2, LR|OP_A2, LR|OP_A2IO, LR|OP_A2,
|
||||
/* 15 */ LR|OP_A2, LR|OP_A2IO, LR|OP_A2IO, LR|OP_A2IR, LR|OP_A2IR,
|
||||
/* 20 */ LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, BOOL|OP_A2IO,
|
||||
/* 25 */ BOOL|OP_A2IO, LR|OP_A2IO, RL, RL, RL|OP_E2,
|
||||
/* 30 */ RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2IO,
|
||||
/* 35 */ RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO,
|
||||
/* 40 */ BOOL|OP_E2IO, BOOL|OP_E2IO, RL|OP_A2IO, RL|OP_A2, RL,
|
||||
/* 45 */ RL, RL, LR, LR, RL|OP_A2,
|
||||
/* 50 */ LR, RL|OP_E2
|
||||
};
|
||||
|
||||
#define LVCOUNT 32
|
||||
|
@ -162,6 +179,7 @@ zzlex(void)
|
|||
{
|
||||
int cct = 0;
|
||||
|
||||
yyval.type = MN_INTEGER;
|
||||
for (;; cct = 0)
|
||||
switch (*ptr++) {
|
||||
case '+':
|
||||
|
@ -302,11 +320,11 @@ zzlex(void)
|
|||
return EQ;
|
||||
case '$':
|
||||
unary = 0;
|
||||
yyval = mypid;
|
||||
yyval.u.l = mypid;
|
||||
return NUM;
|
||||
case '?':
|
||||
if (unary) {
|
||||
yyval = lastval;
|
||||
yyval.u.l = lastval;
|
||||
unary = 0;
|
||||
return NUM;
|
||||
}
|
||||
|
@ -329,7 +347,7 @@ zzlex(void)
|
|||
|
||||
if (*ptr == ']')
|
||||
ptr++;
|
||||
yyval = zstrtol(ptr, &ptr, lastbase = base);
|
||||
yyval.u.l = zstrtol(ptr, &ptr, lastbase = base);
|
||||
return NUM;
|
||||
}
|
||||
case ' ':
|
||||
|
@ -340,18 +358,33 @@ zzlex(void)
|
|||
if (*ptr == 'x' || *ptr == 'X') {
|
||||
unary = 0;
|
||||
/* Should we set lastbase here? */
|
||||
yyval = zstrtol(++ptr, &ptr, lastbase = 16);
|
||||
yyval.u.l = zstrtol(++ptr, &ptr, lastbase = 16);
|
||||
return NUM;
|
||||
}
|
||||
/* Fall through! */
|
||||
default:
|
||||
if (idigit(*--ptr)) {
|
||||
if (idigit(*--ptr) || *ptr == '.') {
|
||||
char *nptr;
|
||||
unary = 0;
|
||||
yyval = zstrtol(ptr, &ptr, 10);
|
||||
for (nptr = ptr; idigit(*nptr); nptr++);
|
||||
|
||||
if (*ptr == '#') {
|
||||
ptr++;
|
||||
yyval = zstrtol(ptr, &ptr, lastbase = yyval);
|
||||
if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') {
|
||||
/* it's a float */
|
||||
yyval.type = MN_FLOAT;
|
||||
yyval.u.d = strtod(ptr, &nptr);
|
||||
if (ptr == nptr || *nptr == '.') {
|
||||
zerr("bad floating point constant", NULL, 0);
|
||||
return EOI;
|
||||
}
|
||||
ptr = nptr;
|
||||
} else {
|
||||
/* it's an integer */
|
||||
yyval.u.l = zstrtol(ptr, &ptr, 10);
|
||||
|
||||
if (*ptr == '#') {
|
||||
ptr++;
|
||||
yyval.u.l = zstrtol(ptr, &ptr, lastbase = yyval.u.l);
|
||||
}
|
||||
}
|
||||
return NUM;
|
||||
}
|
||||
|
@ -361,7 +394,7 @@ zzlex(void)
|
|||
|
||||
ptr++;
|
||||
ptr = getkeystring(ptr, NULL, 6, &v);
|
||||
yyval = v;
|
||||
yyval.u.l = v;
|
||||
unary = 0;
|
||||
return NUM;
|
||||
}
|
||||
|
@ -395,7 +428,7 @@ zzlex(void)
|
|||
return cct ? CID : ID;
|
||||
}
|
||||
else if (cct) {
|
||||
yyval = poundgetfn(NULL);
|
||||
yyval.u.l = poundgetfn(NULL);
|
||||
unary = 0;
|
||||
return NUM;
|
||||
}
|
||||
|
@ -411,14 +444,14 @@ static int sp = -1; /* stack pointer */
|
|||
|
||||
struct mathvalue {
|
||||
LV lval;
|
||||
zlong val;
|
||||
mnumber val;
|
||||
};
|
||||
|
||||
static struct mathvalue *stack;
|
||||
|
||||
/**/
|
||||
static void
|
||||
push(zlong val, LV lval)
|
||||
push(mnumber val, LV lval)
|
||||
{
|
||||
if (sp == STACKSZ - 1)
|
||||
zerr("stack overflow", NULL, 0);
|
||||
|
@ -430,275 +463,308 @@ push(zlong val, LV lval)
|
|||
|
||||
|
||||
/**/
|
||||
static zlong
|
||||
static mnumber
|
||||
getcvar(LV s)
|
||||
{
|
||||
char *t;
|
||||
mnumber mn;
|
||||
mn.type = MN_INTEGER;
|
||||
|
||||
if (!(t = getsparam(lvals[s])))
|
||||
return 0;
|
||||
return STOUC(*t == Meta ? t[1] ^ 32 : *t);
|
||||
mn.u.l = 0;
|
||||
else
|
||||
mn.u.l = STOUC(*t == Meta ? t[1] ^ 32 : *t);
|
||||
return mn;
|
||||
}
|
||||
|
||||
|
||||
/**/
|
||||
static zlong
|
||||
setvar(LV s, zlong v)
|
||||
static mnumber
|
||||
setvar(LV s, mnumber v)
|
||||
{
|
||||
if (s == -1 || s >= lvc) {
|
||||
zerr("lvalue required", NULL, 0);
|
||||
return 0;
|
||||
v.type = MN_INTEGER;
|
||||
v.u.l = 0;
|
||||
}
|
||||
if (noeval)
|
||||
return v;
|
||||
setiparam(lvals[s], v);
|
||||
setnparam(lvals[s], v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/**/
|
||||
static int
|
||||
notzero(zlong a)
|
||||
notzero(mnumber a)
|
||||
{
|
||||
if (a == 0) {
|
||||
if ((a.type & MN_INTEGER) ? a.u.l == 0 : a.u.d == 0.0) {
|
||||
zerr("division by zero", NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* macro to pop two values off the value stack */
|
||||
#define pop2() { \
|
||||
if (sp < 1) { \
|
||||
zerr("bad math expression: unbalanced stack", NULL, 0); \
|
||||
return; \
|
||||
} \
|
||||
b = stack[sp--].val; \
|
||||
a = stack[sp--].val; \
|
||||
}
|
||||
|
||||
/* macro to pop three values off the value stack */
|
||||
#define pop3() { \
|
||||
if (sp < 2) { \
|
||||
zerr("bad math expression: unbalanced stack", NULL, 0); \
|
||||
return; \
|
||||
} \
|
||||
c = stack[sp--].val; \
|
||||
b = stack[sp--].val; \
|
||||
a = stack[sp--].val; \
|
||||
}
|
||||
|
||||
#define nolval() {stack[sp].lval= -1;}
|
||||
#define pushv(X) { push(X,-1); }
|
||||
#define pop2lv() { pop2() lv = stack[sp+1].lval; }
|
||||
#define set(X) { push(setvar(lv,X),lv); }
|
||||
|
||||
|
||||
/**/
|
||||
void
|
||||
op(int what)
|
||||
{
|
||||
zlong a, b, c;
|
||||
mnumber a, b, c, *spval;
|
||||
LV lv;
|
||||
int tp = type[what];
|
||||
|
||||
if (sp < 0) {
|
||||
zerr("bad math expression: stack empty", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tp & (OP_A2|OP_A2IR|OP_A2IO|OP_E2|OP_E2IO)) {
|
||||
if (sp < 1) {
|
||||
zerr("bad math expression: unbalanced stack", NULL, 0); \
|
||||
return;
|
||||
}
|
||||
b = stack[sp--].val;
|
||||
a = stack[sp--].val;
|
||||
|
||||
if (tp & (OP_A2IO|OP_E2IO)) {
|
||||
/* coerce to integers */
|
||||
if (a.type & MN_FLOAT) {
|
||||
a.type = MN_INTEGER;
|
||||
a.u.l = (zlong)a.u.d;
|
||||
}
|
||||
if (b.type & MN_FLOAT) {
|
||||
b.type = MN_INTEGER;
|
||||
b.u.l = (zlong)b.u.d;
|
||||
}
|
||||
} else if (a.type != b.type && what != COMMA) {
|
||||
/*
|
||||
* Different types, so coerce to float.
|
||||
* It may happen during an assigment that the LHS
|
||||
* variable is actually an integer, but there's still
|
||||
* no harm in doing the arithmetic in floating point;
|
||||
* the assignment will do the correct conversion.
|
||||
* This way, if the parameter is actually a scalar, but
|
||||
* used to contain an integer, we can write a float into it.
|
||||
*/
|
||||
if (a.type & MN_INTEGER) {
|
||||
a.type = MN_FLOAT;
|
||||
a.u.d = (double)a.u.l;
|
||||
}
|
||||
if (b.type & MN_INTEGER) {
|
||||
b.type = MN_FLOAT;
|
||||
b.u.d = (double)b.u.l;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* type for operation: usually same as operands, but e.g.
|
||||
* (a == b) returns int.
|
||||
*/
|
||||
c.type = (tp & OP_A2IR) ? MN_INTEGER : a.type;
|
||||
|
||||
switch(what) {
|
||||
case AND:
|
||||
case ANDEQ:
|
||||
c.u.l = a.u.l & b.u.l;
|
||||
break;
|
||||
case XOR:
|
||||
case XOREQ:
|
||||
c.u.l = a.u.l ^ b.u.l;
|
||||
break;
|
||||
case OR:
|
||||
case OREQ:
|
||||
c.u.l = a.u.l | b.u.l;
|
||||
break;
|
||||
case MUL:
|
||||
case MULEQ:
|
||||
if (c.type == MN_FLOAT)
|
||||
c.u.d = a.u.d * b.u.d;
|
||||
else
|
||||
c.u.l = a.u.l * b.u.l;
|
||||
break;
|
||||
case DIV:
|
||||
case DIVEQ:
|
||||
if (!notzero(b))
|
||||
return;
|
||||
if (c.type == MN_FLOAT)
|
||||
c.u.d = a.u.d / b.u.d;
|
||||
else
|
||||
c.u.l = a.u.l / b.u.l;
|
||||
break;
|
||||
case MOD:
|
||||
case MODEQ:
|
||||
if (!notzero(b))
|
||||
return;
|
||||
c.u.l = a.u.l % b.u.l;
|
||||
break;
|
||||
case PLUS:
|
||||
case PLUSEQ:
|
||||
if (c.type == MN_FLOAT)
|
||||
c.u.d = a.u.d + b.u.d;
|
||||
else
|
||||
c.u.l = a.u.l + b.u.l;
|
||||
break;
|
||||
case MINUS:
|
||||
case MINUSEQ:
|
||||
if (c.type == MN_FLOAT)
|
||||
c.u.d = a.u.d - b.u.d;
|
||||
else
|
||||
c.u.l = a.u.l - b.u.l;
|
||||
break;
|
||||
case SHLEFT:
|
||||
case SHLEFTEQ:
|
||||
c.u.l = a.u.l << b.u.l;
|
||||
break;
|
||||
case SHRIGHT:
|
||||
case SHRIGHTEQ:
|
||||
c.u.l = a.u.l >> b.u.l;
|
||||
break;
|
||||
case LES:
|
||||
c.u.l = (zlong)
|
||||
(a.type == MN_FLOAT ? (a.u.d < b.u.d) : (a.u.l < b.u.l));
|
||||
break;
|
||||
case LEQ:
|
||||
c.u.l = (zlong)
|
||||
(a.type == MN_FLOAT ? (a.u.d <= b.u.d) : (a.u.l <= b.u.l));
|
||||
break;
|
||||
case GRE:
|
||||
c.u.l = (zlong)
|
||||
(a.type == MN_FLOAT ? (a.u.d > b.u.d) : (a.u.l > b.u.l));
|
||||
break;
|
||||
case GEQ:
|
||||
c.u.l = (zlong)
|
||||
(a.type == MN_FLOAT ? (a.u.d >= b.u.d) : (a.u.l >= b.u.l));
|
||||
break;
|
||||
case DEQ:
|
||||
c.u.l = (zlong)
|
||||
(a.type == MN_FLOAT ? (a.u.d == b.u.d) : (a.u.l == b.u.l));
|
||||
break;
|
||||
case NEQ:
|
||||
c.u.l = (zlong)
|
||||
(a.type == MN_FLOAT ? (a.u.d != b.u.d) : (a.u.l != b.u.l));
|
||||
break;
|
||||
case DAND:
|
||||
case DANDEQ:
|
||||
c.u.l = (zlong)(a.u.l && b.u.l);
|
||||
break;
|
||||
case DOR:
|
||||
case DOREQ:
|
||||
c.u.l = (zlong)(a.u.l || b.u.l);
|
||||
break;
|
||||
case DXOR:
|
||||
case DXOREQ:
|
||||
c.u.l = (zlong)((a.u.l && !b.u.l) || (!a.u.l && b.u.l));
|
||||
break;
|
||||
case COMMA:
|
||||
c = b;
|
||||
break;
|
||||
case POWER:
|
||||
case POWEREQ:
|
||||
if (c.type == MN_INTEGER && b.u.l < 0) {
|
||||
/* produces a real result, so cast to real. */
|
||||
a.type = b.type = c.type = MN_FLOAT;
|
||||
a.u.d = (double) a.u.l;
|
||||
b.u.d = (double) b.u.l;
|
||||
}
|
||||
if (c.type == MN_INTEGER) {
|
||||
for (c.u.l = 1; b.u.l--; c.u.l *= a.u.l);
|
||||
} else {
|
||||
if (b.u.d <= 0 && !notzero(a))
|
||||
return;
|
||||
if (a.u.d < 0) {
|
||||
/* Error if (-num ** b) and b is not an integer */
|
||||
double tst = (double)(zlong)b.u.d;
|
||||
if (tst != b.u.d) {
|
||||
zerr("imaginary power", NULL, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
c.u.d = pow(a.u.d, b.u.d);
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
c = b;
|
||||
break;
|
||||
}
|
||||
if (tp & (OP_E2|OP_E2IO)) {
|
||||
lv = stack[sp+1].lval;
|
||||
push(setvar(lv,c), lv);
|
||||
} else
|
||||
push(c,-1);
|
||||
return;
|
||||
}
|
||||
|
||||
spval = &stack[sp].val;
|
||||
switch (what) {
|
||||
case NOT:
|
||||
stack[sp].val = !stack[sp].val;
|
||||
nolval();
|
||||
if (spval->type & MN_FLOAT) {
|
||||
spval->u.l = !spval->u.d;
|
||||
spval->type = MN_INTEGER;
|
||||
} else
|
||||
spval->u.l = !spval->u.l;
|
||||
stack[sp].lval = -1;
|
||||
break;
|
||||
case COMP:
|
||||
stack[sp].val = ~stack[sp].val;
|
||||
nolval();
|
||||
if (spval->type & MN_FLOAT) {
|
||||
spval->u.l = ~((zlong)spval->u.d);
|
||||
spval->type = MN_INTEGER;
|
||||
} else
|
||||
spval->u.l = ~spval->u.l;
|
||||
stack[sp].lval = -1;
|
||||
break;
|
||||
case POSTPLUS:
|
||||
(void)setvar(stack[sp].lval, stack[sp].val + 1);
|
||||
a = *spval;
|
||||
if (spval->type & MN_FLOAT)
|
||||
a.u.d++;
|
||||
else
|
||||
a.u.l++;
|
||||
(void)setvar(stack[sp].lval, a);
|
||||
break;
|
||||
case POSTMINUS:
|
||||
(void)setvar(stack[sp].lval, stack[sp].val - 1);
|
||||
a = *spval;
|
||||
if (spval->type & MN_FLOAT)
|
||||
a.u.d--;
|
||||
else
|
||||
a.u.l--;
|
||||
(void)setvar(stack[sp].lval, a);
|
||||
break;
|
||||
case UPLUS:
|
||||
nolval();
|
||||
stack[sp].lval = -1;
|
||||
break;
|
||||
case UMINUS:
|
||||
stack[sp].val = -stack[sp].val;
|
||||
nolval();
|
||||
break;
|
||||
case AND:
|
||||
pop2();
|
||||
pushv(a & b);
|
||||
break;
|
||||
case XOR:
|
||||
pop2();
|
||||
pushv(a ^ b);
|
||||
break;
|
||||
case OR:
|
||||
pop2();
|
||||
pushv(a | b);
|
||||
break;
|
||||
case MUL:
|
||||
pop2();
|
||||
pushv(a * b);
|
||||
break;
|
||||
case DIV:
|
||||
pop2();
|
||||
if (notzero(b))
|
||||
pushv(a / b);
|
||||
break;
|
||||
case MOD:
|
||||
pop2();
|
||||
if (notzero(b))
|
||||
pushv(a % b);
|
||||
break;
|
||||
case PLUS:
|
||||
pop2();
|
||||
pushv(a + b);
|
||||
break;
|
||||
case MINUS:
|
||||
pop2();
|
||||
pushv(a - b);
|
||||
break;
|
||||
case SHLEFT:
|
||||
pop2();
|
||||
pushv(a << b);
|
||||
break;
|
||||
case SHRIGHT:
|
||||
pop2();
|
||||
pushv(a >> b);
|
||||
break;
|
||||
case LES:
|
||||
pop2();
|
||||
pushv((zlong)(a < b));
|
||||
break;
|
||||
case LEQ:
|
||||
pop2();
|
||||
pushv((zlong)(a <= b));
|
||||
break;
|
||||
case GRE:
|
||||
pop2();
|
||||
pushv((zlong)(a > b));
|
||||
break;
|
||||
case GEQ:
|
||||
pop2();
|
||||
pushv((zlong)(a >= b));
|
||||
break;
|
||||
case DEQ:
|
||||
pop2();
|
||||
pushv((zlong)(a == b));
|
||||
break;
|
||||
case NEQ:
|
||||
pop2();
|
||||
pushv((zlong)(a != b));
|
||||
break;
|
||||
case DAND:
|
||||
pop2();
|
||||
pushv((zlong)(a && b));
|
||||
break;
|
||||
case DOR:
|
||||
pop2();
|
||||
pushv((zlong)(a || b));
|
||||
break;
|
||||
case DXOR:
|
||||
pop2();
|
||||
pushv((zlong)((a && !b) || (!a && b)));
|
||||
if (spval->type & MN_FLOAT)
|
||||
spval->u.d = -spval->u.d;
|
||||
else
|
||||
spval->u.l = -spval->u.l;
|
||||
stack[sp].lval = -1;
|
||||
break;
|
||||
case QUEST:
|
||||
pop3();
|
||||
pushv((a) ? b : c);
|
||||
if (sp < 2) {
|
||||
zerr("bad math expression: unbalanced stack", NULL, 0);
|
||||
return;
|
||||
}
|
||||
c = stack[sp--].val;
|
||||
b = stack[sp--].val;
|
||||
a = stack[sp--].val;
|
||||
/* b and c can stay different types in this case. */
|
||||
push(((a.type & MN_FLOAT) ? a.u.d : a.u.l) ? b : c, -1);
|
||||
break;
|
||||
case COLON:
|
||||
break;
|
||||
case EQ:
|
||||
pop2();
|
||||
lv = stack[sp + 1].lval;
|
||||
set(b);
|
||||
break;
|
||||
case PLUSEQ:
|
||||
pop2lv();
|
||||
set(a + b);
|
||||
break;
|
||||
case MINUSEQ:
|
||||
pop2lv();
|
||||
set(a - b);
|
||||
break;
|
||||
case MULEQ:
|
||||
pop2lv();
|
||||
set(a * b);
|
||||
break;
|
||||
case DIVEQ:
|
||||
pop2lv();
|
||||
if (notzero(b))
|
||||
set(a / b);
|
||||
break;
|
||||
case MODEQ:
|
||||
pop2lv();
|
||||
if (notzero(b))
|
||||
set(a % b);
|
||||
break;
|
||||
case ANDEQ:
|
||||
pop2lv();
|
||||
set(a & b);
|
||||
break;
|
||||
case XOREQ:
|
||||
pop2lv();
|
||||
set(a ^ b);
|
||||
break;
|
||||
case OREQ:
|
||||
pop2lv();
|
||||
set(a | b);
|
||||
break;
|
||||
case SHLEFTEQ:
|
||||
pop2lv();
|
||||
set(a << b);
|
||||
break;
|
||||
case SHRIGHTEQ:
|
||||
pop2lv();
|
||||
set(a >> b);
|
||||
break;
|
||||
case DANDEQ:
|
||||
pop2lv();
|
||||
set((zlong)(a && b));
|
||||
break;
|
||||
case DOREQ:
|
||||
pop2lv();
|
||||
set((zlong)(a || b));
|
||||
break;
|
||||
case DXOREQ:
|
||||
pop2lv();
|
||||
set((zlong)((a && !b) || (!a && b)));
|
||||
break;
|
||||
case COMMA:
|
||||
pop2();
|
||||
pushv(b);
|
||||
break;
|
||||
case PREPLUS:
|
||||
stack[sp].val = setvar(stack[sp].lval,
|
||||
stack[sp].val + 1);
|
||||
if (spval->type & MN_FLOAT)
|
||||
spval->u.d++;
|
||||
else
|
||||
spval->u.l++;
|
||||
setvar(stack[sp].lval, *spval);
|
||||
break;
|
||||
case PREMINUS:
|
||||
stack[sp].val = setvar(stack[sp].lval,
|
||||
stack[sp].val - 1);
|
||||
break;
|
||||
case POWER:
|
||||
pop2();
|
||||
if (b < 0) {
|
||||
zerr("can't handle negative exponents", NULL, 0);
|
||||
return;
|
||||
}
|
||||
for (c = 1; b--; c *= a);
|
||||
pushv(c);
|
||||
break;
|
||||
case POWEREQ:
|
||||
pop2lv();
|
||||
if (b < 0) {
|
||||
zerr("can't handle negative exponents", NULL, 0);
|
||||
return;
|
||||
}
|
||||
for (c = 1; b--; c *= a);
|
||||
set(c);
|
||||
if (spval->type & MN_FLOAT)
|
||||
spval->u.d--;
|
||||
else
|
||||
spval->u.l--;
|
||||
setvar(stack[sp].lval, *spval);
|
||||
break;
|
||||
default:
|
||||
zerr("out of integers", NULL, 0);
|
||||
|
@ -711,15 +777,18 @@ op(int what)
|
|||
static void
|
||||
bop(int tk)
|
||||
{
|
||||
mnumber *spval = &stack[sp].val;
|
||||
int tst = (spval->type & MN_FLOAT) ? (zlong)spval->u.d : spval->u.l;
|
||||
|
||||
switch (tk) {
|
||||
case DAND:
|
||||
case DANDEQ:
|
||||
if (!stack[sp].val)
|
||||
if (!tst)
|
||||
noeval++;
|
||||
break;
|
||||
case DOR:
|
||||
case DOREQ:
|
||||
if (stack[sp].val)
|
||||
if (tst)
|
||||
noeval++;
|
||||
break;
|
||||
};
|
||||
|
@ -727,21 +796,19 @@ bop(int tk)
|
|||
|
||||
|
||||
/**/
|
||||
static zlong
|
||||
static mnumber
|
||||
mathevall(char *s, int prek, char **ep)
|
||||
{
|
||||
int t0;
|
||||
int xlastbase, xnoeval, xunary, xlvc;
|
||||
char *xptr;
|
||||
zlong xyyval;
|
||||
mnumber xyyval;
|
||||
LV xyylval;
|
||||
char **xlvals = 0, *nlvals[LVCOUNT];
|
||||
int xsp;
|
||||
struct mathvalue *xstack = 0, nstack[STACKSZ];
|
||||
zlong ret;
|
||||
mnumber ret;
|
||||
|
||||
xlastbase = xnoeval = xunary = xlvc = xyyval = xyylval = xsp = 0;
|
||||
xptr = NULL;
|
||||
if (mlevel++) {
|
||||
xlastbase = lastbase;
|
||||
xnoeval = noeval;
|
||||
|
@ -754,6 +821,11 @@ mathevall(char *s, int prek, char **ep)
|
|||
|
||||
xsp = sp;
|
||||
xstack = stack;
|
||||
} else {
|
||||
xlastbase = xnoeval = xunary = xlvc = xyylval = xsp = 0;
|
||||
xyyval.type = MN_INTEGER;
|
||||
xyyval.u.l = 0;
|
||||
xptr = NULL;
|
||||
}
|
||||
stack = nstack;
|
||||
lastbase = -1;
|
||||
|
@ -790,15 +862,18 @@ mathevall(char *s, int prek, char **ep)
|
|||
|
||||
|
||||
/**/
|
||||
zlong
|
||||
mnumber
|
||||
matheval(char *s)
|
||||
{
|
||||
char *junk;
|
||||
zlong x;
|
||||
mnumber x;
|
||||
int xmtok = mtok;
|
||||
|
||||
if (!*s)
|
||||
return 0;
|
||||
if (!*s) {
|
||||
x.type = MN_INTEGER;
|
||||
x.u.l = 0;
|
||||
return x;
|
||||
}
|
||||
x = mathevall(s, TOPPREC, &junk);
|
||||
mtok = xmtok;
|
||||
if (*junk)
|
||||
|
@ -806,19 +881,27 @@ matheval(char *s)
|
|||
return x;
|
||||
}
|
||||
|
||||
/**/
|
||||
zlong
|
||||
mathevali(char *s)
|
||||
{
|
||||
mnumber x = matheval(s);
|
||||
return (x.type & MN_FLOAT) ? (zlong)x.u.d : x.u.l;
|
||||
}
|
||||
|
||||
|
||||
/**/
|
||||
zlong
|
||||
mathevalarg(char *s, char **ss)
|
||||
{
|
||||
zlong x;
|
||||
mnumber x;
|
||||
int xmtok = mtok;
|
||||
|
||||
x = mathevall(s, ARGPREC, ss);
|
||||
if (mtok == COMMA)
|
||||
(*ss)--;
|
||||
mtok = xmtok;
|
||||
return x;
|
||||
return (x.type & MN_FLOAT) ? (zlong)x.u.d : x.u.l;
|
||||
}
|
||||
|
||||
|
||||
|
@ -842,7 +925,7 @@ mathparse(int pc)
|
|||
push(yyval, -1);
|
||||
break;
|
||||
case ID:
|
||||
push(getiparam(lvals[yylval]), yylval);
|
||||
push(getnparam(lvals[yylval]), yylval);
|
||||
break;
|
||||
case CID:
|
||||
push(getcvar(yylval), yylval);
|
||||
|
@ -856,7 +939,8 @@ mathparse(int pc)
|
|||
}
|
||||
break;
|
||||
case QUEST:
|
||||
q = stack[sp].val;
|
||||
q = (stack[sp].val.type == MN_FLOAT) ? (zlong)stack[sp].val.u.d :
|
||||
stack[sp].val.u.l;
|
||||
|
||||
if (!q)
|
||||
noeval++;
|
||||
|
@ -873,9 +957,9 @@ mathparse(int pc)
|
|||
default:
|
||||
otok = mtok;
|
||||
onoeval = noeval;
|
||||
if (type[otok] == BOOL)
|
||||
if (MTYPE(type[otok]) == BOOL)
|
||||
bop(otok);
|
||||
mathparse(prec[otok] - (type[otok] != RL));
|
||||
mathparse(prec[otok] - (MTYPE(type[otok]) != RL));
|
||||
noeval = onoeval;
|
||||
op(otok);
|
||||
continue;
|
||||
|
|
46
Src/mem.c
46
Src/mem.c
|
@ -96,7 +96,13 @@ static int h_m[1025], h_push, h_pop, h_free;
|
|||
|
||||
#endif
|
||||
|
||||
#define H_ISIZE sizeof(zlong)
|
||||
/* Make sure we align to the longest fundamental type. */
|
||||
union mem_align {
|
||||
zlong l;
|
||||
double d;
|
||||
};
|
||||
|
||||
#define H_ISIZE sizeof(union mem_align)
|
||||
#define HEAPSIZE (16384 - H_ISIZE)
|
||||
#define HEAP_ARENA_SIZE (HEAPSIZE - sizeof(struct heap))
|
||||
#define HEAPFREE (16384 - H_ISIZE)
|
||||
|
@ -514,13 +520,12 @@ ztrdup(const char *s)
|
|||
/*
|
||||
Below is a simple segment oriented memory allocator for systems on
|
||||
which it is better than the system's one. Memory is given in blocks
|
||||
aligned to an integer multiple of sizeof(zlong) (4 bytes on most machines,
|
||||
but 8 bytes on e.g. a dec alpha; it will be 8 bytes if we are using
|
||||
long long's or equivalent). Each block is preceded by a header
|
||||
which contains the length of the data part (in bytes). In allocated
|
||||
blocks only this field of the structure m_hdr is senseful. In free
|
||||
blocks the second field (next) is a pointer to the next free segment
|
||||
on the free list.
|
||||
aligned to an integer multiple of sizeof(union mem_align), which will
|
||||
probably be 64-bit as it is the longer of zlong or double. Each block is
|
||||
preceded by a header which contains the length of the data part (in
|
||||
bytes). In allocated blocks only this field of the structure m_hdr is
|
||||
senseful. In free blocks the second field (next) is a pointer to the next
|
||||
free segment on the free list.
|
||||
|
||||
On top of this simple allocator there is a second allocator for small
|
||||
chunks of data. It should be both faster and less space-consuming than
|
||||
|
@ -576,7 +581,7 @@ ztrdup(const char *s)
|
|||
|
||||
struct m_shdr {
|
||||
struct m_shdr *next; /* next one on free list */
|
||||
#ifdef ZSH_64_BIT_TYPE
|
||||
#ifdef PAD_64_BIT
|
||||
/* dummy to make this 64-bit aligned */
|
||||
struct m_shdr *dummy;
|
||||
#endif
|
||||
|
@ -584,18 +589,25 @@ struct m_shdr {
|
|||
|
||||
struct m_hdr {
|
||||
zlong len; /* length of memory block */
|
||||
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
|
||||
/* either 1 or 2 zlong's, whichever makes up 64 bits. */
|
||||
zlong dummy1;
|
||||
#endif
|
||||
struct m_hdr *next; /* if free: next on free list
|
||||
if block of small blocks: next one with
|
||||
small blocks of same size*/
|
||||
struct m_shdr *free; /* if block of small blocks: free list */
|
||||
zlong used; /* if block of small blocks: number of used
|
||||
blocks */
|
||||
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
|
||||
zlong dummy2;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* alignment for memory blocks */
|
||||
|
||||
#define M_ALIGN (sizeof(zlong))
|
||||
#define M_ALIGN (sizeof(union mem_align))
|
||||
|
||||
/* length of memory header, length of first field of memory header and
|
||||
minimal size of a block left free (if we allocate memory and take a
|
||||
|
@ -604,7 +616,11 @@ struct m_hdr {
|
|||
the free list) */
|
||||
|
||||
#define M_HSIZE (sizeof(struct m_hdr))
|
||||
#define M_ISIZE (sizeof(zlong))
|
||||
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
|
||||
# define M_ISIZE (2*sizeof(zlong))
|
||||
#else
|
||||
# define M_ISIZE (sizeof(zlong))
|
||||
#endif
|
||||
#define M_MIN (2 * M_ISIZE)
|
||||
|
||||
/* M_FREE is the number of bytes that have to be free before memory is
|
||||
|
@ -649,10 +665,18 @@ static char *m_high, *m_low;
|
|||
#define M_SIDX(S) ((S) / M_ISIZE)
|
||||
#define M_SNUM 128
|
||||
#define M_SLEN(M) ((M)->len / M_SNUM)
|
||||
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
|
||||
/* Include the dummy in the alignment */
|
||||
#define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) + \
|
||||
2*sizeof(zlong) + sizeof(struct m_hdr *))
|
||||
#define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) - \
|
||||
2*sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
|
||||
#else
|
||||
#define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) + \
|
||||
sizeof(zlong) + sizeof(struct m_hdr *))
|
||||
#define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) - \
|
||||
sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
|
||||
#endif
|
||||
#define M_NSMALL 13
|
||||
|
||||
static struct m_hdr *m_small[M_NSMALL];
|
||||
|
|
213
Src/params.c
213
Src/params.c
|
@ -557,6 +557,11 @@ assigngetset(Param pm)
|
|||
pm->sets.ifn = intsetfn;
|
||||
pm->gets.ifn = intgetfn;
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
pm->sets.ffn = floatsetfn;
|
||||
pm->gets.ffn = floatgetfn;
|
||||
break;
|
||||
case PM_ARRAY:
|
||||
pm->sets.afn = arrsetfn;
|
||||
pm->gets.afn = arrgetfn;
|
||||
|
@ -651,6 +656,10 @@ copyparam(Param tpm, Param pm, int toplevel)
|
|||
case PM_INTEGER:
|
||||
tpm->u.val = pm->gets.ifn(pm);
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
tpm->u.dval = pm->gets.ffn(pm);
|
||||
break;
|
||||
case PM_ARRAY:
|
||||
tpm->u.arr = arrdup(pm->gets.afn(pm));
|
||||
break;
|
||||
|
@ -1242,7 +1251,7 @@ char *
|
|||
getstrvalue(Value v)
|
||||
{
|
||||
char *s, **ss;
|
||||
static char buf[(sizeof(zlong) * 8) + 4];
|
||||
char buf[(sizeof(zlong) * 8) + 4];
|
||||
|
||||
if (!v)
|
||||
return hcalloc(1);
|
||||
|
@ -1276,6 +1285,11 @@ getstrvalue(Value v)
|
|||
convbase(buf, v->pm->gets.ifn(v->pm), v->pm->ct);
|
||||
s = dupstring(buf);
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
s = convfloat(v->pm->gets.ffn(v->pm), v->pm->ct,
|
||||
v->pm->flags, NULL);
|
||||
break;
|
||||
case PM_SCALAR:
|
||||
s = v->pm->gets.cfn(v->pm);
|
||||
break;
|
||||
|
@ -1349,7 +1363,30 @@ getintvalue(Value v)
|
|||
return v->a;
|
||||
if (PM_TYPE(v->pm->flags) == PM_INTEGER)
|
||||
return v->pm->gets.ifn(v->pm);
|
||||
return matheval(getstrvalue(v));
|
||||
if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT))
|
||||
return (zlong)v->pm->gets.ffn(v->pm);
|
||||
return mathevali(getstrvalue(v));
|
||||
}
|
||||
|
||||
/**/
|
||||
mnumber
|
||||
getnumvalue(Value v)
|
||||
{
|
||||
mnumber mn;
|
||||
mn.type = MN_INTEGER;
|
||||
|
||||
if (!v || v->isarr) {
|
||||
mn.u.l = 0;
|
||||
} else if (v->inv) {
|
||||
mn.u.l = v->a;
|
||||
} else if (PM_TYPE(v->pm->flags) == PM_INTEGER) {
|
||||
mn.u.l = v->pm->gets.ifn(v->pm);
|
||||
} else if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT)) {
|
||||
mn.type = MN_FLOAT;
|
||||
mn.u.d = v->pm->gets.ffn(v->pm);
|
||||
} else
|
||||
return matheval(getstrvalue(v));
|
||||
return mn;
|
||||
}
|
||||
|
||||
/**/
|
||||
|
@ -1405,12 +1442,21 @@ setstrvalue(Value v, char *val)
|
|||
break;
|
||||
case PM_INTEGER:
|
||||
if (val) {
|
||||
(v->pm->sets.ifn) (v->pm, matheval(val));
|
||||
(v->pm->sets.ifn) (v->pm, mathevali(val));
|
||||
zsfree(val);
|
||||
}
|
||||
if (!v->pm->ct && lastbase != -1)
|
||||
v->pm->ct = lastbase;
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
if (val) {
|
||||
mnumber mn = matheval(val);
|
||||
(v->pm->sets.ffn) (v->pm, (mn.type & MN_FLOAT) ? mn.u.d :
|
||||
(double)mn.u.l);
|
||||
zsfree(val);
|
||||
}
|
||||
break;
|
||||
case PM_ARRAY:
|
||||
MUSTUSEHEAP("setstrvalue");
|
||||
{
|
||||
|
@ -1428,6 +1474,9 @@ setstrvalue(Value v, char *val)
|
|||
return;
|
||||
if (PM_TYPE(v->pm->flags) == PM_INTEGER)
|
||||
convbase(val = buf, v->pm->gets.ifn(v->pm), v->pm->ct);
|
||||
else if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT))
|
||||
val = convfloat(v->pm->gets.ffn(v->pm), v->pm->ct,
|
||||
v->pm->flags, NULL);
|
||||
else
|
||||
val = v->pm->gets.cfn(v->pm);
|
||||
if (v->pm->env)
|
||||
|
@ -1440,9 +1489,9 @@ setstrvalue(Value v, char *val)
|
|||
|
||||
/**/
|
||||
static void
|
||||
setintvalue(Value v, zlong val)
|
||||
setnumvalue(Value v, mnumber val)
|
||||
{
|
||||
char buf[DIGBUFSIZE];
|
||||
char buf[DIGBUFSIZE], *p;
|
||||
|
||||
if (v->pm->flags & PM_READONLY) {
|
||||
zerr("read-only variable: %s", v->pm->nam, 0);
|
||||
|
@ -1455,11 +1504,21 @@ setintvalue(Value v, zlong val)
|
|||
switch (PM_TYPE(v->pm->flags)) {
|
||||
case PM_SCALAR:
|
||||
case PM_ARRAY:
|
||||
convbase(buf, val, 0);
|
||||
setstrvalue(v, ztrdup(buf));
|
||||
if (val.type & MN_INTEGER)
|
||||
convbase(p = buf, val.u.l, 0);
|
||||
else
|
||||
p = convfloat(val.u.d, 0, 0, NULL);
|
||||
setstrvalue(v, ztrdup(p));
|
||||
break;
|
||||
case PM_INTEGER:
|
||||
(v->pm->sets.ifn) (v->pm, val);
|
||||
(v->pm->sets.ifn) (v->pm, (val.type & MN_INTEGER) ? val.u.l :
|
||||
(zlong) val.u.d);
|
||||
setstrvalue(v, NULL);
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
(v->pm->sets.ffn) (v->pm, (val.type & MN_INTEGER) ?
|
||||
(double)val.u.l : val.u.d);
|
||||
setstrvalue(v, NULL);
|
||||
break;
|
||||
}
|
||||
|
@ -1544,6 +1603,22 @@ getiparam(char *s)
|
|||
return getintvalue(v);
|
||||
}
|
||||
|
||||
/* Retrieve a numerical parameter, either integer or floating */
|
||||
|
||||
/**/
|
||||
mnumber
|
||||
getnparam(char *s)
|
||||
{
|
||||
Value v;
|
||||
if (!(v = getvalue(&s, 1))) {
|
||||
mnumber mn;
|
||||
mn.type = MN_INTEGER;
|
||||
mn.u.l = 0;
|
||||
return mn;
|
||||
}
|
||||
return getnumvalue(v);
|
||||
}
|
||||
|
||||
/* Retrieve a scalar (string) parameter */
|
||||
|
||||
/**/
|
||||
|
@ -1709,6 +1784,7 @@ setiparam(char *s, zlong val)
|
|||
Value v;
|
||||
char *t = s;
|
||||
Param pm;
|
||||
mnumber mnval;
|
||||
|
||||
if (!isident(s)) {
|
||||
zerr("not an identifier: %s", s, 0);
|
||||
|
@ -1721,7 +1797,41 @@ setiparam(char *s, zlong val)
|
|||
pm->u.val = val;
|
||||
return pm;
|
||||
}
|
||||
setintvalue(v, val);
|
||||
mnval.type = MN_INTEGER;
|
||||
mnval.u.l = val;
|
||||
setnumvalue(v, mnval);
|
||||
return v->pm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like setiparam(), but can take an mnumber which can be integer or
|
||||
* floating.
|
||||
*/
|
||||
|
||||
/**/
|
||||
Param
|
||||
setnparam(char *s, mnumber val)
|
||||
{
|
||||
Value v;
|
||||
char *t = s;
|
||||
Param pm;
|
||||
|
||||
if (!isident(s)) {
|
||||
zerr("not an identifier: %s", s, 0);
|
||||
errflag = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (!(v = getvalue(&s, 1))) {
|
||||
pm = createparam(t, (val.type & MN_INTEGER) ? PM_INTEGER
|
||||
: PM_FFLOAT);
|
||||
DPUTS(!pm, "BUG: parameter not created");
|
||||
if (val.type & MN_INTEGER)
|
||||
pm->u.val = val.u.l;
|
||||
else
|
||||
pm->u.dval = val.u.d;
|
||||
return pm;
|
||||
}
|
||||
setnumvalue(v, val);
|
||||
return v->pm;
|
||||
}
|
||||
|
||||
|
@ -1834,6 +1944,24 @@ intsetfn(Param pm, zlong x)
|
|||
pm->u.val = x;
|
||||
}
|
||||
|
||||
/* Function to get value of a floating point parameter */
|
||||
|
||||
/**/
|
||||
static double
|
||||
floatgetfn(Param pm)
|
||||
{
|
||||
return pm->u.dval;
|
||||
}
|
||||
|
||||
/* Function to set value of an integer parameter */
|
||||
|
||||
/**/
|
||||
static void
|
||||
floatsetfn(Param pm, double x)
|
||||
{
|
||||
pm->u.dval = x;
|
||||
}
|
||||
|
||||
/* Function to get value of a scalar (string) parameter */
|
||||
|
||||
/**/
|
||||
|
@ -2680,6 +2808,62 @@ convbase(char *s, zlong v, int base)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a floating point value for output.
|
||||
* Unlike convbase(), this has its own internal storage and returns
|
||||
* a value from the heap;
|
||||
*/
|
||||
|
||||
/**/
|
||||
char *
|
||||
convfloat(double dval, int digits, int flags, FILE *fout)
|
||||
{
|
||||
char fmt[] = "%.*e";
|
||||
|
||||
MUSTUSEHEAP("convfloat");
|
||||
/*
|
||||
* The difficulty with the buffer size is that a %f conversion
|
||||
* prints all digits before the decimal point: with 64 bit doubles,
|
||||
* that's around 310. We can't check without doing some quite
|
||||
* serious floating point operations we'd like to avoid.
|
||||
* Then we are liable to get all the digits
|
||||
* we asked for after the decimal point, or we should at least
|
||||
* bargain for it. So we just allocate 512 + digits. This
|
||||
* should work until somebody decides on 128-bit doubles.
|
||||
*/
|
||||
if (!(flags & (PM_EFLOAT|PM_FFLOAT))) {
|
||||
/*
|
||||
* Conversion from a floating point expression without using
|
||||
* a variable. The best bet in this case just seems to be
|
||||
* to use the general %g format with something like the maximum
|
||||
* double precision.
|
||||
*/
|
||||
fmt[3] = 'g';
|
||||
if (!digits)
|
||||
digits = 17;
|
||||
} else {
|
||||
if (flags & PM_FFLOAT)
|
||||
fmt[3] = 'f';
|
||||
if (digits <= 0)
|
||||
digits = 10;
|
||||
if (flags & PM_EFLOAT) {
|
||||
/*
|
||||
* Here, we are given the number of significant figures, but
|
||||
* %e wants the number of decimal places (unlike %g)
|
||||
*/
|
||||
digits--;
|
||||
}
|
||||
}
|
||||
if (fout) {
|
||||
fprintf(fout, fmt, digits, dval);
|
||||
return NULL;
|
||||
} else {
|
||||
VARARR(char, buf, 512 + digits);
|
||||
sprintf(buf, fmt, digits, dval);
|
||||
return dupstring(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Start a parameter scope */
|
||||
|
||||
/**/
|
||||
|
@ -2733,6 +2917,10 @@ scanendscope(HashNode hn, int flags)
|
|||
case PM_INTEGER:
|
||||
pm->sets.ifn(pm, tpm->u.val);
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
pm->sets.ffn(pm, tpm->u.dval);
|
||||
break;
|
||||
case PM_ARRAY:
|
||||
pm->sets.afn(pm, tpm->u.arr);
|
||||
break;
|
||||
|
@ -2786,6 +2974,8 @@ printparamnode(HashNode hn, int printflags)
|
|||
printf("undefined ");
|
||||
if (p->flags & PM_INTEGER)
|
||||
printf("integer ");
|
||||
if (p->flags & (PM_EFLOAT|PM_FFLOAT))
|
||||
printf("float ");
|
||||
else if (p->flags & PM_ARRAY)
|
||||
printf("array ");
|
||||
else if (p->flags & PM_HASHED)
|
||||
|
@ -2843,6 +3033,11 @@ printparamnode(HashNode hn, int printflags)
|
|||
printf("%ld", p->gets.ifn(p));
|
||||
#endif
|
||||
break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT:
|
||||
/* float */
|
||||
convfloat(p->gets.ffn(p), p->ct, p->flags, stdout);
|
||||
break;
|
||||
case PM_ARRAY:
|
||||
/* array */
|
||||
if (!(printflags & PRINT_KV_PAIR))
|
||||
|
|
14
Src/subst.c
14
Src/subst.c
|
@ -685,7 +685,7 @@ get_intarg(char **s)
|
|||
singsub(&p);
|
||||
if (errflag)
|
||||
return -1;
|
||||
ret = matheval(p);
|
||||
ret = mathevali(p);
|
||||
if (errflag)
|
||||
return -1;
|
||||
if (ret < 0)
|
||||
|
@ -1045,6 +1045,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
|
|||
case PM_SCALAR: val = "scalar"; break;
|
||||
case PM_ARRAY: val = "array"; break;
|
||||
case PM_INTEGER: val = "integer"; break;
|
||||
case PM_EFLOAT:
|
||||
case PM_FFLOAT: val = "float"; break;
|
||||
case PM_HASHED: val = "association"; break;
|
||||
}
|
||||
val = dupstring(val);
|
||||
|
@ -1823,12 +1825,16 @@ arithsubst(char *a, char **bptr, char *rest)
|
|||
{
|
||||
char *s = *bptr, *t;
|
||||
char buf[DIGBUFSIZE], *b = buf;
|
||||
zlong v;
|
||||
mnumber v;
|
||||
|
||||
singsub(&a);
|
||||
v = matheval(a);
|
||||
convbase(buf, v, 0);
|
||||
t = *bptr = (char *)ncalloc(strlen(*bptr) + strlen(buf) + strlen(rest) + 1);
|
||||
if (v.type & MN_FLOAT)
|
||||
b = convfloat(v.u.d, 0, 0, NULL);
|
||||
else
|
||||
convbase(buf, v.u.l, 0);
|
||||
t = *bptr = (char *)ncalloc(strlen(*bptr) + strlen(b) +
|
||||
strlen(rest) + 1);
|
||||
t--;
|
||||
while ((*++t = *s++));
|
||||
t--;
|
||||
|
|
80
Src/zsh.h
80
Src/zsh.h
|
@ -57,7 +57,26 @@ typedef long zlong;
|
|||
typedef unsigned long zulong;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Double float support requires 64-bit alignment, so if longs and
|
||||
* pointers are less we need to pad out.
|
||||
*/
|
||||
#ifndef LONG_IS_64_BIT
|
||||
# define PAD_64_BIT 1
|
||||
#endif
|
||||
|
||||
/* math.c */
|
||||
typedef struct {
|
||||
union {
|
||||
zlong l;
|
||||
double d;
|
||||
} u;
|
||||
int type;
|
||||
} mnumber;
|
||||
|
||||
#define MN_INTEGER 1 /* mnumber is integer */
|
||||
#define MN_FLOAT 2 /* mnumber is floating point */
|
||||
|
||||
typedef int LV;
|
||||
|
||||
/* Character tokens are sometimes casted to (unsigned char)'s. *
|
||||
|
@ -953,6 +972,8 @@ struct param {
|
|||
char **arr; /* value if declared array (PM_ARRAY) */
|
||||
char *str; /* value if declared string (PM_SCALAR) */
|
||||
zlong val; /* value if declared integer (PM_INTEGER) */
|
||||
double dval; /* value if declared float
|
||||
(PM_EFLOAT|PM_FFLOAT) */
|
||||
HashTable hash; /* value if declared assoc (PM_HASHED) */
|
||||
} u;
|
||||
|
||||
|
@ -960,6 +981,7 @@ struct param {
|
|||
union {
|
||||
void (*cfn) _((Param, char *));
|
||||
void (*ifn) _((Param, zlong));
|
||||
void (*ffn) _((Param, double));
|
||||
void (*afn) _((Param, char **));
|
||||
void (*hfn) _((Param, HashTable));
|
||||
} sets;
|
||||
|
@ -968,6 +990,7 @@ struct param {
|
|||
union {
|
||||
char *(*cfn) _((Param));
|
||||
zlong (*ifn) _((Param));
|
||||
double (*ffn) _((Param));
|
||||
char **(*afn) _((Param));
|
||||
HashTable (*hfn) _((Param));
|
||||
} gets;
|
||||
|
@ -988,41 +1011,50 @@ struct param {
|
|||
#define PM_SCALAR 0 /* scalar */
|
||||
#define PM_ARRAY (1<<0) /* array */
|
||||
#define PM_INTEGER (1<<1) /* integer */
|
||||
#define PM_HASHED (1<<2) /* association */
|
||||
#define PM_EFLOAT (1<<2) /* double with %e output */
|
||||
#define PM_FFLOAT (1<<3) /* double with %f output */
|
||||
#define PM_HASHED (1<<4) /* association */
|
||||
|
||||
#define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY|PM_HASHED))
|
||||
#define PM_TYPE(X) \
|
||||
(X & (PM_SCALAR|PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_ARRAY|PM_HASHED))
|
||||
|
||||
#define PM_LEFT (1<<3) /* left justify, remove leading blanks */
|
||||
#define PM_RIGHT_B (1<<4) /* right justify, fill with leading blanks */
|
||||
#define PM_RIGHT_Z (1<<5) /* right justify, fill with leading zeros */
|
||||
#define PM_LOWER (1<<6) /* all lower case */
|
||||
#define PM_LEFT (1<<5) /* left justify, remove leading blanks */
|
||||
#define PM_RIGHT_B (1<<6) /* right justify, fill with leading blanks */
|
||||
#define PM_RIGHT_Z (1<<7) /* right justify, fill with leading zeros */
|
||||
#define PM_LOWER (1<<8) /* all lower case */
|
||||
|
||||
/* The following are the same since they *
|
||||
* both represent -u option to typeset */
|
||||
#define PM_UPPER (1<<7) /* all upper case */
|
||||
#define PM_UNDEFINED (1<<7) /* undefined (autoloaded) shell function */
|
||||
#define PM_UPPER (1<<9) /* all upper case */
|
||||
#define PM_UNDEFINED (1<<9) /* undefined (autoloaded) shell function */
|
||||
|
||||
#define PM_READONLY (1<<8) /* readonly */
|
||||
#define PM_TAGGED (1<<9) /* tagged */
|
||||
#define PM_EXPORTED (1<<10) /* exported */
|
||||
#define PM_READONLY (1<<10) /* readonly */
|
||||
#define PM_TAGGED (1<<11) /* tagged */
|
||||
#define PM_EXPORTED (1<<12) /* exported */
|
||||
|
||||
/* The following are the same since they *
|
||||
* both represent -U option to typeset */
|
||||
#define PM_UNIQUE (1<<11) /* remove duplicates */
|
||||
#define PM_UNALIASED (1<<11) /* do not expand aliases when autoloading */
|
||||
#define PM_UNIQUE (1<<13) /* remove duplicates */
|
||||
#define PM_UNALIASED (1<<13) /* do not expand aliases when autoloading */
|
||||
|
||||
#define PM_HIDE (1<<12) /* Special behaviour hidden by local */
|
||||
#define PM_TIED (1<<13) /* array tied to colon-path or v.v. */
|
||||
#define PM_HIDE (1<<14) /* Special behaviour hidden by local */
|
||||
#define PM_TIED (1<<15) /* array tied to colon-path or v.v. */
|
||||
|
||||
/* Remaining flags do not correspond directly to command line arguments */
|
||||
#define PM_LOCAL (1<<14) /* this parameter will be made local */
|
||||
#define PM_SPECIAL (1<<15) /* special builtin parameter */
|
||||
#define PM_DONTIMPORT (1<<16) /* do not import this variable */
|
||||
#define PM_RESTRICTED (1<<17) /* cannot be changed in restricted mode */
|
||||
#define PM_UNSET (1<<18) /* has null value */
|
||||
#define PM_REMOVABLE (1<<19) /* special can be removed from paramtab */
|
||||
#define PM_AUTOLOAD (1<<20) /* autoloaded from module */
|
||||
#define PM_NORESTORE (1<<21) /* do not restore value of local special */
|
||||
#define PM_LOCAL (1<<16) /* this parameter will be made local */
|
||||
#define PM_SPECIAL (1<<17) /* special builtin parameter */
|
||||
#define PM_DONTIMPORT (1<<18) /* do not import this variable */
|
||||
#define PM_RESTRICTED (1<<19) /* cannot be changed in restricted mode */
|
||||
#define PM_UNSET (1<<20) /* has null value */
|
||||
#define PM_REMOVABLE (1<<21) /* special can be removed from paramtab */
|
||||
#define PM_AUTOLOAD (1<<22) /* autoloaded from module */
|
||||
#define PM_NORESTORE (1<<23) /* do not restore value of local special */
|
||||
|
||||
/* The option string corresponds to the first of the variables above */
|
||||
#define TYPESET_OPTSTR "aiEFALRZlurtxUhT"
|
||||
|
||||
/* These typeset options take an optional numeric argument */
|
||||
#define TYPESET_OPTNUM "LRZiEF"
|
||||
|
||||
/* Flags for extracting elements of arrays and associative arrays */
|
||||
#define SCANPM_WANTVALS (1<<0)
|
||||
|
@ -1481,7 +1513,7 @@ struct heap {
|
|||
struct heap *next; /* next one */
|
||||
size_t used; /* bytes used from the heap */
|
||||
struct heapstack *sp; /* used by pushheap() to save the value used */
|
||||
#ifdef ZSH_64_BIT_TYPE
|
||||
#ifdef PAD_64_BIT
|
||||
size_t dummy; /* Make sure sizeof(heap) is a multiple of 8 */
|
||||
#endif
|
||||
#define arena(X) ((char *) (X) + sizeof(struct heap))
|
||||
|
|
|
@ -458,6 +458,8 @@ dnl in case they require objects that exist only in the static version
|
|||
dnl and might not be compiled into the zsh executable.
|
||||
AC_CHECK_LIB(c, printf)
|
||||
|
||||
AC_CHECK_LIB(m, pow)
|
||||
|
||||
dnl Prefer BSD termcap library to SysV curses library, except on certain
|
||||
dnl versions of AIX and HP-UX.
|
||||
case "$host_os" in
|
||||
|
|
Loading…
Reference in a new issue