diff --git a/doc/teapot.lyx b/doc/teapot.lyx index a429083..daa22c1 100644 --- a/doc/teapot.lyx +++ b/doc/teapot.lyx @@ -5015,8 +5015,10 @@ y . As with \family typewriter +\series bold and \family default +\series default , this evaluation short-circuits if \emph on x @@ -5226,17 +5228,17 @@ y Note: a string of consecutive relational operators is interpreted as the conjunction of each consecutive (overlapping) pair. Thus -\family typewriter +\family sans 2 <= y() <= 10 \family default will evaluate to true precisely in rows 2 through 10, inclusive (it is shorthand for -\family typewriter +\family sans 2 <= y() and y() <= 10 \family default ). Similarly -\family typewriter +\family sans @(cell1) == @(cell2) == @(cell3) \family default will return true exactly when all three cells have the same value. @@ -5499,13 +5501,15 @@ Functions \begin_layout Standard This section documents all available functions in alphabetical order. - The functions are given in a C-like notation, so use -\family typewriter + The functions are described in a C-like notation; you don't have to write + the types when you use the function in a formula. + For example, use +\family sans @(0,0,0) \family default - instead of -\family typewriter -@(integer 0, integer 0, integer 0) +, not +\family sans +@(int 0, int 0, int 0) \family default . If no type is given for the result of a function, it means the result type @@ -5565,7 +5569,8 @@ y z \emph default is specified, that value overrides the corresponding coordinate of the - given location, which defaults to the location of the current cell. + given location, which defaults to the location of the current cell if it + is omitted. \end_layout \begin_layout Description @@ -6436,6 +6441,27 @@ or of all the supplied values. \end_layout +\begin_layout Description +bool currently only acts as a keyword to +\family sans +\series bold +is +\series default +(); +\family default +there are not currently any conversions to boolean type. + Use e.g. + +\family sans + +\shape italic +expr +\shape default + != 0 +\family default +to obtain a boolean value from a numerical expression. +\end_layout + \begin_layout Description \series medium @@ -6641,6 +6667,24 @@ e Note the parentheses are optional. \end_layout +\begin_layout Description +empty +\series medium +[( +\shape italic +args +\shape default +)] +\series default + ignores all of its arguments and returns the empty value. + Without parentheses, acts as a keyword, typically for +\family sans +\series bold +is +\series default +(). +\end_layout + \begin_layout Description \series medium @@ -6652,17 +6696,23 @@ error \series default error \series medium -(string +[([ \emph on - -\begin_inset space ~ -\end_inset - message \emph default -) +])] \series default - evaluates to an error with the specified message. + converts its argument to a string just as with the string() function, and + then returns an error with that string as the message. + Without parentheses, acts as a keyword, e.g. + for +\family sans +\series bold +is +\series default +() +\family default +. \end_layout @@ -6692,6 +6742,19 @@ boolean false represents the false Boolean value. \end_layout +\begin_layout Description +fident a keyword indicating the token type of +\begin_inset Quotes eld +\end_inset + +function identifier, +\begin_inset Quotes erd +\end_inset + + provided for the sake of completeness. + There is probably little practical call for this type. +\end_layout + \begin_layout Description \series medium @@ -6703,7 +6766,7 @@ float \series default float \series medium -(string|int +[([float|string|int|empty \emph on \begin_inset space ~ @@ -6711,9 +6774,20 @@ float s \emph default -) +])] \series default - converts the given string or int into a floating point number. + converts into a floating point number the given float, string, int, or + empty value (the latter converts to 0.0). + If the argument is omitted, the value of the current cell is used. + If the parentheses are omitted, acts as a keyword, e.g., for type testing + with +\family sans +\series bold +is +\series default +() +\family default +. \end_layout \begin_layout Description @@ -6763,14 +6837,32 @@ frac x \emph default -) +) \series default evaluates to the fractional part of \emph on x \emph default . - +\end_layout + +\begin_layout Description +funcall a keyword indicating the +\begin_inset Quotes eld +\end_inset + +funcall +\begin_inset Quotes erd +\end_inset + + token type used to encode expressions as tokens; may be used with +\family sans +\series bold +is +\series default +() +\family default + for example. \end_layout \begin_layout Description @@ -6789,7 +6881,7 @@ int \series default int \series medium -(float +[([int|float|string|empty \emph on \begin_inset space ~ @@ -6797,263 +6889,185 @@ int x \emph default -[,integer +][, \emph on \begin_inset space ~ \end_inset -neg +direction \emph default -, -\begin_inset space ~ -\end_inset - -integer -\emph on - -\begin_inset space ~ -\end_inset - -pos -\emph default -]) +])] \series default -converts +converts to an +\emph on + +\emph default +integer the given integer, float, string, or empty value +\emph on +x. + +\emph default +(The latter converts to 0.) The optional second argument must be the name + of one of the functions that produces a floating point integral value from + a float, i.e., +\family sans +\series bold +ceil +\family default +\series default +, +\family sans +\series bold +floor +\family default +\series default +, +\family sans +\series bold +round +\family default +\series default +, or +\family sans +\series bold +trunc +\family default +\series default +, and it directs how to convert floating point values to an integer. + (The default is +\family sans +\series bold +trunc +\family default +\series default +, see the documentation of the corresponding functions for a description + of the conversion behavior.) If \emph on x \emph default - to an integer value by cutting off the fractional part. - If given, the value of -\emph on -neg -\emph default - and -\emph on -pos -\emph default - determines how negative and non-negative numbers will be converted: -\end_layout - -\begin_layout Quote -\begin_inset Tabular - - - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\emph on -neg -\emph default -/ -\emph on -pos -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Result -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -< -1 -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -next smaller integer value -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout --1 -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -round downward -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -0 -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -cut fractional part off (default) -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -1 -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -round upward -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -> 1 -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -next larger integer value -\end_layout - -\end_inset - - - - -\end_inset - - + is omitted, the value of the current cell is used. + If in addition the parentheses are omitted, acts as a keyword, e.g., for + value testing with +\family sans +\series bold +is +\series default +() +\family default +. \end_layout \begin_layout Description - +is \series medium -int +[([ +\emph on +x +\emph default +][, +\emph on + \begin_inset space ~ \end_inset +type1, +\begin_inset space ~ +\end_inset +type2 +\emph default +,...])] \series default -int -\series medium -(string|float + Boolean-valued type testing. + Returns true if the given value \emph on - -\begin_inset space ~ -\end_inset - -s +x \emph default -[, -\emph on - -\begin_inset space ~ -\end_inset - -rounding -\emph default -]) + is any of the listed types. + Each type may be any of the keywords +\family sans +\series bold +bool, empty, error, fident, float, funcall, int +\family default \series default - converts +, +\family sans +\series bold +lident, location, number, operator, +\family default +\series default +or +\family sans +\series bold +string +\family default +\series default +. + Each of these identifies a single type, except +\family sans +\series bold +number +\family default +\series default +, which is a shorthand for +\family sans +\series bold +empty +\family default +\series default +, +\family sans +\series bold + float +\family default +\series default +, +\family sans +\series bold + int +\family default +\series default +. + If no types are specified, returns true for any non-empty value. + (In other words, +\family sans +\series bold +is +\series default +( \emph on -s +x \emph default - to an integer number. - In case of a floating point argument, there is an optional second argument - which determines which nearby integer will be selected. - It must be one of the function names -\begin_inset Quotes eld -\end_inset - -ceil, -\begin_inset Quotes erd -\end_inset - - -\begin_inset Quotes eld -\end_inset - -floor, -\begin_inset Quotes erd -\end_inset - - -\begin_inset Quotes eld -\end_inset - -round, -\begin_inset Quotes erd -\end_inset - - or -\begin_inset Quotes eld -\end_inset - -trunc, -\begin_inset Quotes erd -\end_inset - - and the integer corresponding to the value that function would select is - returned. - (See the documentation of each of these functions.) If the second argument - is omitted, the -\begin_inset Quotes eld -\end_inset - -trunc -\begin_inset Quotes erd -\end_inset - - value is returned. +) +\family default + is a boolean-valued version of +\family sans +\series bold +n +\series default +( +\emph on +x +\emph default +) +\family default +, without the special behavior when +\emph on +x +\emph default + is a location.) If +\emph on +x +\emph default + is omitted, defaults to the value of the current cell; the parentheses + may be omitted as well, so bare +\family sans +\series bold +is +\family default +\series default + tests whether the current cell is non-empty. \end_layout \begin_layout Description @@ -7106,7 +7120,20 @@ s s \emph default . - +\end_layout + +\begin_layout Description +lident a keyword indicating the +\begin_inset Quotes eld +\end_inset + +label identifier +\begin_inset Quotes erd +\end_inset + + token type. + This type is not generally accessible, as labels always evaluate to their + locations (or error if there is no such label). \end_layout \begin_layout Description @@ -7157,7 +7184,25 @@ y y \emph default . - +\end_layout + +\begin_layout Description +location currently this is only a keyword, e.g., for use with +\family sans +\series bold +is +\series default +() +\family default +. + Use +\family sans +\series bold +& +\series default +() +\family default + to convert three integers to a location. \end_layout \begin_layout Description @@ -7449,6 +7494,47 @@ l1 The second form simply returns the number of its arguments which are nonempty. \end_layout +\begin_layout Description +number +\series medium +[([bool|empty|int|float|string +\emph on + +\begin_inset space ~ +\end_inset + +x +\emph default +])] +\series default + Converts its argument, which defaults to the value of the current cell, + to the most appropriate number type. + Thus, it leaves ints and floats alone, converts boolean values to integers + 1 or 0, converts empty to integer 0, and converts numeric strings to ints + if they don't have a decimal point and floats if they do. + Without parentheses, acts as a keyword for +\family sans +\series bold +is +\series default +() +\family default +, abbreviating the combination of float, int, and empty. +\end_layout + +\begin_layout Description +operator A keyword indicating the +\begin_inset Quotes eld +\end_inset + +operator +\begin_inset Quotes erd +\end_inset + + token type, representing symbols like parentheses, plus signs, commas, + etc. +\end_layout + \begin_layout Description poly \series medium @@ -7476,7 +7562,7 @@ cn \begin_inset space ~ \end_inset -...]) +...]) \series default evaluates the polynomial \emph on diff --git a/src/common/func.c b/src/common/func.c index 3d2c430..dae1ff9 100644 --- a/src/common/func.c +++ b/src/common/func.c @@ -581,24 +581,6 @@ static Token eval_func(FunctionIdentifier self, int argc, const Token argv[]) } /*}}}*/ -/* error */ /*{{{*/ -static Token error_func(FunctionIdentifier self, int argc, const Token argv[]) -{ - assert(self == FUNC_ERROR); - /* variables */ /*{{{*/ - Token result; - /*}}}*/ - - /* asserts */ /*{{{*/ - assert(argv!=(Token*)0); - /*}}}*/ - if (argc != 1 || argv[0].type != STRING) - duperror(&result, _("Usage: error(string message)")); - else duperror(&result, argv[0].u.string); - return result; -} -/*}}}*/ - /* blcnst_func -- common implementation of true/false */ /*{{{*/ static Token blcnst_func(FunctionIdentifier self, int argc, const Token argv[]) { @@ -637,40 +619,219 @@ static Token blop_macro(FunctionIdentifier self, int argc, const Token argv[]) } /*}}}*/ +/* self function, typically used for keywords */ /*{{{*/ +static Token self_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + Token result; + if (argc == -1) + { + result.type = FIDENT; + result.u.fident = self; + return result; + } + const char *templ = _("%s may only be used as a bare identifier"); + result.type = EEK; + result.u.err = malloc(strlen(templ) + MAX_FUNC_NAME_LENGTH + 1); + sprintf(result.u.err, templ, tfunc[self].name); + return result; +} +/*}}}*/ + +/* empty -- ignores arguments and returns empty value */ /*{{{*/ +static Token empty_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + assert(self == FUNC_EMPTY); + if (argc == -1) return self_func(self, argc, argv); + Token emp; + emp.type = EMPTY; + return emp; +} +/*}}}*/ + +/* float */ /*{{{*/ +static Token float_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + assert(self == FUNC_FLOAT); + Token arg, result; + result.type = FLOAT; + result.u.flt = 0.0; + const char *usage = _("Usage: float[([float|string|int|empty])]"); + + switch (argc) { + case -1: return self_func(self, argc, argv); + case 0: arg = recompvalue(upd_sheet, upd_l); break; + case 1: arg = tcopy(argv[0]); break; + default: return duperror(&result, usage); + } + switch (arg.type) + { + case FLOAT: return arg; + case STRING: { + char *p = arg.u.string; + Token *sf = scan_flt(&p); + if (sf == NULLTOKEN || *p != '\0') + duperror(&result, _("Not a (finite) floating point number")); + else result = *sf; + free(sf); + tfree(&arg); + return result; + } + case INT: + result.u.flt = (FltT)arg.u.integer; + /* fall through */ + case EMPTY: + return result; + default: break; + } + tfree(&arg); + return duperror(&result, usage); +} +/*}}}*/ + +/* number -- convert to most appropriate number type */ /*{{{*/ +static Token number_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + assert(self == FUNC_NUMBER); + const char *usage = _("Usage: number[([bool|empty|int|float|string x])]"); + Token result, arg; + result.type = INT; + result.u.integer = 0; + + switch (argc) { + case -1: return self_func(self, argc, argv); + case 0: arg = recompvalue(upd_sheet, upd_l); break; + case 1: arg = tcopy(argv[0]); break; + default: return duperror(&result, usage); + } + switch (arg.type) { + case INT: return arg; + case FLOAT: return arg; + case BOOL: if (arg.u.bl) result.u.integer = 1; /* FALL THROUGH */ + case EMPTY: return result; + case STRING: { + char *p = arg.u.string; + Token *st = scan_integer(&p); + if (st != NULLTOKEN && *p == '\0') result = *st; + else { + p = arg.u.string; + st = scan_flt(&p); + if (st == NULLTOKEN || *p != '\0') + duperror(&result, _("string does not represent a number")); + else result = *st; + } + free(st); + tfree(&arg); + return result; + } + default: break; + } + tfree(&arg); + return duperror(&result, usage); +} +/*}}}*/ + +/* int */ /*{{{*/ +static Token int_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + assert(self == FUNC_INT); + const char *usage = + _("Usage: int[([int|string|bool|float|empty][,rounding_function])]"); + Token result, arg; + result.type = INT; + result.u.integer = 0; + FunctionIdentifier dir = FUNC_TRUNC; + + switch (argc) { + case -1: return self_func(self, argc, argv); + case 0: arg = recompvalue(upd_sheet, upd_l); break; + case 2: + if (argv[1].type != FIDENT) return duperror(&result, usage); + dir = argv[1].u.fident; + /* FALL THROUGH */ + case 1: + arg = tcopy(argv[0]); + break; + default: return duperror(&result, usage); + } + switch (arg.type) { + case INT: return arg; + case FLOAT: + switch (dir) { + case FUNC_TRUNC: result.u.integer = (IntT)arg.u.flt; break; + case FUNC_ROUND: result.u.integer = ROUNDFLTINT(arg.u.flt); break; + case FUNC_FLOOR: result.u.integer = (IntT)FLOORFLT(arg.u.flt); break; + case FUNC_CEIL: result.u.integer = (IntT) CEILFLT(arg.u.flt); break; + default: assert(0); + } + return result; + case STRING: { + char *s = arg.u.string; + Token *si = scan_integer(&s); + if (si == NULLTOKEN || *s != '\0') + duperror(&result, _("int(string): invalid string")); + else result = *si; + free(si); + tfree(&arg); + return result; + } + case BOOL: + if (arg.u.bl) result.u.integer = 1; + /* fall through */ + case EMPTY: + return result; + default: break; + } + tfree(&arg); + return duperror(&result, usage); +} +/*}}}*/ + + /* string */ /*{{{*/ static Token string_func(FunctionIdentifier self, int argc, const Token argv[]) { - assert(self == FUNC_STRING); /* variables */ /*{{{*/ - Token result; - const char *usage = _("Usage: string(x[,[int prec][,format_for_floats]])"); + Token result, arg; int precision = def_precision; bool ff = DEF_FLOATFORM; + bool bad_args = false; char staticbuf[4096]; - size_t size; /*}}}*/ - if (argc < 1 || argc > 3) return duperror(&result, usage); - if (argc == 3) - { - if (argv[2].type != FIDENT) return duperror(&result, usage); - switch (argv[2].u.fident) + switch (argc) { + case -1: return self_func(self, argc, argv); + case 0: arg = recompvalue(upd_sheet, upd_l); break; + case 3: + if (argv[2].type != FIDENT) bad_args = true; break; + switch (argv[2].u.fident) { - case FUNC_DECIMAL: ff = FLT_DECIMAL; break; - case FUNC_SCIENTIFIC: ff = FLT_SCIENTIFIC; break; - case FUNC_COMPACT: ff = FLT_COMPACT; break; - case FUNC_HEXACT: ff = FLT_HEXACT; break; - default: assert(0); + case FUNC_DECIMAL: ff = FLT_DECIMAL; break; + case FUNC_SCIENTIFIC: ff = FLT_SCIENTIFIC; break; + case FUNC_COMPACT: ff = FLT_COMPACT; break; + case FUNC_HEXACT: ff = FLT_HEXACT; break; + default: assert(0); } + /* FALL THROUGH */ + case 2: + if (argv[1].type == INT) precision = argv[1].u.integer; + else if (argv[1].type != EMPTY) bad_args = true; break; + /* FALL THROUGH */ + case 1: + arg = tcopy(argv[0]); + break; + default: bad_args = true; } - if (argc >= 2 & argv[1].type != EMPTY) - { - if (argv[1].type != INT) return duperror(&result, usage); - precision = argv[1].u.integer; + + if (bad_args) { + const char *templ = + _("Usage: %s[([x][,[int prec][,format_for_floats]])]"); + sprintf(staticbuf, templ, tfunc[self].name); + return duperror(&result, staticbuf); } result.type = STRING; - size = printtok(staticbuf, sizeof(staticbuf), 0, DIRECT_STRING, ff, - precision, VERBOSE_ERROR, argv); + size_t size = printtok(staticbuf, sizeof(staticbuf), 0, DIRECT_STRING, ff, + precision, VERBOSE_ERROR, &arg); + tfree(&arg); if (size > sizeof(staticbuf) - 2) return duperror(&result, _("string: Overflow of internal buffer")); result.u.string = strdup(staticbuf); @@ -678,6 +839,79 @@ static Token string_func(FunctionIdentifier self, int argc, const Token argv[]) } /*}}}*/ +/* error */ /*{{{*/ +static Token error_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + assert(self == FUNC_ERROR); + if (argc == -1) return self_func(self, argc, argv); + Token tmsg = string_func(self, argc, argv); + if (tmsg.type == EEK) return tmsg; + assert(tmsg.type == STRING); + char *msg = tmsg.u.string; + tmsg.type = EEK; + tmsg.u.err = msg; + return tmsg; +} +/*}}}*/ + +/* is_func -- test the type of a value */ /*{{{*/ +static Token is_func(FunctionIdentifier self, int argc, const Token argv[]) +{ + assert(self == FUNC_IS); + Token val; + val.type = EMPTY; + bool need_value = true; + bool tested_something = false; + Token result; + result.type = BOOL; + result.u.bl = false; + + for (int ai = 0; ai < argc; ++ai) { + if (argv[ai].type == FIDENT && IS_TYPE_FUNC(argv[ai].u.fident)) { + /* OK, test this type */ + tested_something = true; + if (need_value) { + val = recompvalue(upd_sheet, upd_l); + need_value = false; + } + switch (argv[ai].u.fident) { + case FUNC_EMPTY: result.u.bl = (val.type == EMPTY); break; + case FUNC_STRING: result.u.bl = (val.type == STRING); break; + case FUNC_FLOAT: result.u.bl = (val.type == FLOAT); break; + case FUNC_INT: result.u.bl = (val.type == INT); break; + case FUNC_OPERATOR: result.u.bl = (val.type == OPERATOR); break; + case FUNC_LIDENT: result.u.bl = (val.type == LIDENT); break; + case FUNC_FIDENT: result.u.bl = (val.type == FIDENT); break; + case FUNC_LOCATION: result.u.bl = (val.type == LOCATION); break; + case FUNC_ERROR: result.u.bl = (val.type == EEK); break; + case FUNC_FUNCALL: result.u.bl = (val.type == FUNCALL); break; + case FUNC_BOOL: result.u.bl = (val.type == BOOL); break; + case FUNC_NUMBER: + result.u.bl = val.type==FLOAT || val.type==INT || val.type==EMPTY; + break; + default: assert(0); + } + if (result.u.bl) { + tfree(&val); + return result; + } + } else if (need_value) { + val = tcopy(argv[ai]); + need_value = false; + } else { + tfree(&val); + const char* usage = _("Usage: is([x][,type1, type2, ...])"); + return duperror(&result, usage); + } + } + if (tested_something) { tfree(&val); return result; } + if (need_value) val = recompvalue(upd_sheet, upd_l); + result.u.bl = (val.type != EMPTY); + tfree(&val); + return result; +} +/*}}}*/ + /* accum_func -- common implementation of functions that accumulate all of their arguments into a final value. */ @@ -912,58 +1146,6 @@ static Token binop_func(FunctionIdentifier self, int argc, const Token argv[]) } /*}}}*/ -/* int */ /*{{{*/ -static Token int_func(FunctionIdentifier self, int argc, const Token argv[]) -{ - assert(self == FUNC_INT); - const char *usage = _("Usage: int(string|bool|float[,rounding_function])"); - Token result; - result.type = INT; - if (argc < 1 || argc > 2) return duperror(&result, usage); - switch (argv[0].type) { - case FLOAT: - if (argc == 1) { - result.u.integer = (IntT)argv[0].u.flt; - return result; - } else { /* result is integer with given conversion */ /*{{{*/ - switch (argv[1].u.fident) - { - case FUNC_TRUNC: - result.u.integer = (IntT)argv[0].u.flt; break; - case FUNC_ROUND: - result.u.integer = ROUNDFLTINT(argv[0].u.flt); break; - case FUNC_FLOOR: - result.u.integer = (IntT)FLOORFLT(argv[0].u.flt); break; - case FUNC_CEIL: - result.u.integer = (IntT) CEILFLT(argv[0].u.flt); break; - default: assert(0); - } - return result; - } - case STRING: - { - char *s; - if (argc > 1) return duperror(&result, usage); - errno=0; - result.u.integer = STRTOINT(argv[0].u.string, &s, 10); - if (s==(char*)0 || *s) - return duperror(&result, _("int(string): invalid string")); - if (errno==ERANGE && - (result.u.integer==LONG_MAX || result.u.integer==LONG_MIN)) - return duperror(&result, _("int(string): domain error")); - return result; - } - case BOOL: - if (argc > 1) return duperror(&result, usage); - if (argv[0].u.bl) result.u.integer = 1; - else result.u.integer = 0; - return result; - default: break; - } - return duperror(&result, usage); -} -/*}}}*/ - /* len */ /*{{{*/ static Token len_func(FunctionIdentifier self, int argc, const Token argv[]) { @@ -1073,36 +1255,6 @@ static Token env_func(FunctionIdentifier self, int argc, const Token argv[]) } /*}}}*/ -/* float */ /*{{{*/ -static Token float_func(FunctionIdentifier self, int argc, const Token argv[]) -{ - assert(self == FUNC_FLOAT); - Token result; - const char *usage = _("Usage: float(string|int)"); - - if (argc != 1) return duperror(&result, usage); - switch (argv[0].type) - { - case STRING: { - char *p; - - result.u.flt = STRTOFLT(argv[0].u.string, &p); - if (p != argv[0].u.string && *p=='\0' - && dblfinite(result.u.flt) == (const char*)0) - result.type = FLOAT; - else duperror(&result, _("Not a (finite) floating point number")); - return result; - } - case INT: - result.type = FLOAT; - result.u.flt = (FltT)argv[0].u.integer; - return result; - } - return duperror(&result, usage); - return result; -} -/*}}}*/ - /* strftime */ /*{{{*/ static Token strftime_func(FunctionIdentifier fi, int argc, const Token argv[]) { @@ -1238,25 +1390,6 @@ static Token sci_disp(FunctionIdentifier self, int argc, const Token argv[]) return sci_func(argc, argv, fsci, tfunc[self].name); } - -/* self function, typically used for keywords */ /*{{{*/ -static Token self_func(FunctionIdentifier self, int argc, const Token argv[]) -{ - Token result; - if (argc == -1) - { - result.type = FIDENT; - result.u.fident = self; - return result; - } - const char *templ = _("%s may only be used as a bare identifier"); - result.type = EEK; - result.u.err = malloc(strlen(templ) + MAX_FUNC_NAME_LENGTH + 1); - sprintf(result.u.err, templ, tfunc[self].name); - return result; -} -/*}}}*/ - /* nearby integer (rounding) function */ /*{{{*/ static Token near_func(FunctionIdentifier self, int argc, const Token argv[]) { @@ -1424,7 +1557,6 @@ Tfunc tfunc[]= /* Evaluation control functions */ [FUNC_CLOCK] = { "clock", clock_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_ERROR] = { "error", error_func, PREFIX_FUNC, FUNCT, 0 }, [FUNC_EVAL] = { "eval", eval_func, PREFIX_FUNC, FUNCT, 0 }, /* Boolean functions */ @@ -1433,10 +1565,20 @@ Tfunc tfunc[]= [FUNC_OR] = { "or", blop_macro, INFIX_BOOL, MACRO, 0 }, [FUNC_TRUE] = { "true", blcnst_func, PREFIX_FUNC, FUNCT, 0 }, - /* Type conversion functions */ - [FUNC_FLOAT] = { "float", float_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_INT] = { "int", int_func, PREFIX_FUNC, FUNCT, 0 }, - [FUNC_STRING] = { "string", string_func, PREFIX_FUNC, FUNCT, 0 }, + /* Type conversion/testing functions and keywords */ + [FUNC_BOOL] = { "bool", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_EMPTY] = { "empty", empty_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_ERROR] = { "error", error_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_FIDENT] = { "fident", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_FLOAT] = { "float", float_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_FUNCALL] = { "funcall", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_INT] = { "int", int_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_IS] = { "is", is_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_LIDENT] = { "lident", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_LOCATION] = { "location", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_NUMBER] = { "number", number_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_OPERATOR] = { "operator", self_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_STRING] = { "string", string_func, PREFIX_FUNC, FUNCT, 0 }, /* Block operations */ [FUNC_MAX] = { "max", reg_disp, PREFIX_FUNC, FUNCT, 0 }, diff --git a/src/common/func.h b/src/common/func.h index fdba1ea..4166580 100644 --- a/src/common/func.h +++ b/src/common/func.h @@ -22,7 +22,8 @@ typedef enum FUNC_RND, FUNC_SUBSTR, FUNC_STRPTIME, FUNC_TIME, FUNC_BITAND, FUNC_BITOR, FUNC_R, FUNC_D, FUNC_CAP_X, FUNC_X_AMPERSAND, FUNC_NEGATE, FUNC_PLUS_SYMBOL, FUNC_MINUS_SYMBOL, FUNC_ASTERISK, FUNC_SLASH, - /* Note use of thes in the macro below */ + + /* Note use of these in the macro below */ FUNC_LESS_EQUAL, FUNC_GREATER_EQUAL, FUNC_LESS_THAN, FUNC_GREATER_THAN, FUNC_EQUAL_EQUAL, FUNC_TILDE_EQUAL, FUNC_BANG_EQUAL, @@ -32,10 +33,17 @@ typedef enum FUNC_HEXACT, FUNC_RIGHT, FUNC_LEFT, FUNC_DOWN, FUNC_UP, FUNC_BELOW, FUNC_ABOVE, FUNC_TRUE, FUNC_FALSE, FUNC_AND, FUNC_OR, + /* Note use of these in the macro below */ + FUNC_BOOL, FUNC_EMPTY, FUNC_FIDENT, + FUNC_FUNCALL, FUNC_LIDENT, FUNC_LOCATION, FUNC_NUMBER, FUNC_OPERATOR, + + FUNC_IS, + N_FUNCTION_IDS } FunctionIdentifier; #define IS_RELATION_FUNC(f) (((f) >= FUNC_LESS_EQUAL) && ((f) <= FUNC_BANG_EQUAL)) +#define IS_TYPE_FUNC(f) (((f) >= FUNC_BOOL && ((f) <= FUNC_OPERATOR)) || (f)==FUNC_ERROR || (f)==FUNC_FLOAT || (f)==FUNC_INT || (f)==FUNC_STRING) /* Forward declaration of Token, since this header is used in scanner.h */ typedef struct Token_struc Token; diff --git a/src/common/main.c b/src/common/main.c index 4d92afc..fd8da52 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -89,60 +89,49 @@ void relmoveto(Sheet *sheet, int x, int y, int z) } /* line_numedit -- number line editor function */ /*{{{*/ -static int line_numedit(int *n, const char *prompt, size_t *x, size_t *offx) +static int line_numedit(int *n, const char *prompt) { - /* variables */ /*{{{*/ - char buf[20]; - const char *s; - Token **t; - int c; - /*}}}*/ + assert(prompt != NULL); - /* asserts */ /*{{{*/ - assert(prompt!=(char*)0); - assert(x!=(size_t*)0); - assert(offx!=(size_t*)0); - /*}}}*/ - t=(Token**)0; - sprintf(buf,"%d",*n); - s=buf+strlen(buf); + char buf[20]; + Token *t = NULLTOKEN; + sprintf(buf, "%d", *n); + char *s = buf+strlen(buf); do { - tvecfree(t); - *x=s-buf; - if ((c=line_edit((Sheet*)0,buf,sizeof(buf),prompt,x,offx))<0) return c; - s=buf; - t=scan(&s); - } while ((*s!='\0' && t==(Token**)0) || !(t!=(Token**)0 && ((*t)==(Token*)0 || ((*t)->type==INT && (*t)->u.integer>=0 && *(t+1)==(Token*)0)))); - if (t==(Token**)0 || *t==(Token*)0) *n=-1; - else *n=(*t)->u.integer; - tvecfree(t); + free(t); + size_t x = s - buf; + size_t offx = 0; + int c = line_edit((Sheet*)0, buf, sizeof(buf), prompt, &x, &offx); + if (c < 0) return c; + s = buf; + t = scan_integer(&s); + } while (*s != '\0'); + if (t == NULLTOKEN) *n = -1; + else { *n = t->u.integer; free(t); } return 0; } /*}}}*/ + /* line_lidedit -- label identifier line editor function */ /*{{{*/ static int line_idedit(char *ident, size_t size, const char *prompt, size_t *x, size_t *offx) { - /* variables */ /*{{{*/ - const char *s; - Token **t; - int c; - /*}}}*/ - - t=(Token**)0; - s=ident+strlen(ident); + Token *t = NULLTOKEN; + char *s = ident+strlen(ident); do { - tvecfree(t); - *x=s-ident; - if ((c=line_edit((Sheet*)0,ident,size,prompt,x,offx))<0) return c; - s=ident; - t=scan(&s); - } while ((*s!='\0' && t==(Token**)0) || !(t!=(Token**)0 && ((*t)==(Token*)0 || ((*t)->type==LIDENT && *(t+1)==(Token*)0)))); - tvecfree(t); + free(t); + *x = s - ident; + int c = line_edit((Sheet*)0, ident, size, prompt, x, offx); + if (c < 0) return c; + s = ident; + t = scan_ident(&s); + } while (*s != '\0' || t == NULLTOKEN || t->type != LIDENT); + free(t); return 0; } /*}}}*/ + /* doanyway -- ask if action should be done despite unsaved changes */ /*{{{*/ int doanyway(Sheet *sheet, const char *msg) { @@ -158,11 +147,12 @@ int doanyway(Sheet *sheet, const char *msg) /*}}}*/ /* do_edit -- set or modify cell contents */ /*{{{*/ -static int do_edit(Sheet *cursheet, Key c, const char *expr, TokVariety tv) +static int do_edit(Sheet *cursheet, Key c, char *expr, TokVariety tv) { /* variables */ /*{{{*/ char buf[1024]; - const char *s, *prompt; + const char *prompt; + char *s; size_t x,offx; Location scur; Token **t; @@ -322,23 +312,15 @@ static int do_label(Sheet *sheet) /* do_columnwidth -- set the column width */ /*{{{*/ static int do_columnwidth(Sheet *cursheet) { - /* variables */ /*{{{*/ - size_t edx,offx; - int n; - int x, z; - int c; - /*}}}*/ - - offx=0; - edx=0; do_mark(cursheet, GET_MARK_CUR); - n = columnwidth(cursheet, cursheet->mark1[X], cursheet->mark1[Z]); + int n = columnwidth(cursheet, cursheet->mark1[X], cursheet->mark1[Z]); do { - if ((c=line_numedit(&n,_("Column width:"),&edx,&offx))<0) return c; - } while (n<=0); + int c = line_numedit(&n, _("Column width:")); + if (c < 0) return c; + } while (n <= 0); /*}}}*/ - for (x = cursheet->mark1[X]; x <= cursheet->mark2[X]; ++x) - for (z = cursheet->mark1[Z]; z <= cursheet->mark2[Z]; ++z) + for (int x = cursheet->mark1[X]; x <= cursheet->mark2[X]; ++x) + for (int z = cursheet->mark1[Z]; z <= cursheet->mark2[Z]; ++z) setwidth(cursheet,x,z,n); return -1; } @@ -397,7 +379,10 @@ static void do_attribute(Sheet *cursheet, Key action) offx=0; ex=0; n = getprecision(fcell); - do if (line_numedit(&n, onecell ? _("Precision for cell:") : _("Precision for block:"),&ex,&offx)==-1) return; while (n!=-1 && (n==0 || n>20)); + const char* prompt = _("Precision for block:"); + if (onecell) prompt = _("Precision for cell:"); + int c = line_numedit(&n, prompt); + if (c < 0) return; for (ALL_LOCS_IN_REGION(cursheet,w)) changed = setprecision(cursheet, w, n) || changed; break; @@ -1139,7 +1124,6 @@ static int do_move(Sheet *sheet, int copy, int force) static int do_fill(Sheet *sheet) { /* variables */ /*{{{*/ - size_t offx,edx; int cols,rows,layers; int x,y,z; Location wid, go; @@ -1152,26 +1136,23 @@ static int do_fill(Sheet *sheet) do_mark(sheet, MARKED); cols=rows=layers=1; firstmenu: - offx=0; - edx=0; - do if ((c=line_numedit(&cols,_("Number of column-wise repetitions:"),&edx,&offx))<0) return c; while (cols<=0); + do { + int c = line_numedit(&cols, _("Number of column-wise repetitions:")); + if (c < 0) return c; + } while (cols <= 0); secondmenu: - offx=0; - edx=0; do { - c=line_numedit(&rows,_("Number of row-wise repetitions:"),&edx,&offx); - if (c==-1) return -1; - else if (c==-2) goto firstmenu; - } while (rows<=0); - offx=0; - edx=0; + int c = line_numedit(&rows, _("Number of row-wise repetitions:")); + if (c == -1) return -1; + else if (c == -2) goto firstmenu; + } while (rows <= 0); do { - c=line_numedit(&layers,_("Number of depth-wise repetitions:"),&edx,&offx); - if (c==-1) return -1; - else if (c==-2) goto secondmenu; - } while (layers<=0); + int c = line_numedit(&layers, _("Number of depth-wise repetitions:")); + if (c == -1) return -1; + else if (c == -2) goto secondmenu; + } while (layers <= 0); LOCATION_GETS(wid, sheet->mark2); LOCATION_SUB(wid, sheet->mark1); wid[X]++; wid[Y]++; wid[Z]++; @@ -1202,18 +1183,6 @@ void fillwith(Sheet *she) /* do_sort -- sort block */ /*{{{*/ static int do_sort(Sheet *sheet) { - /* variables */ /*{{{*/ - Sortkey sk[MAX_SORTKEYS]; - unsigned int key; - size_t x,offx; - const char *msg; - Direction in_dir=(Direction)-2; /* cause run time error */ - int x1,y1,z1,x2,y2,z2; - int doit=-1; - int c; - int last; - /*}}}*/ - do_mark(sheet, GET_MARK_ALL); /* build menus */ /*{{{*/ const char* menu1[] = @@ -1224,162 +1193,134 @@ static int do_sort(Sheet *sheet) { _("aA)scending"), _("dD)escending"), NULL }; /*}}}*/ - last = -1; + int last = -1; + Direction in_dir = (Direction)-2; /* cause run time error */ + int dir; /* ask for sort direction */ /*{{{*/ - zero: switch (c = line_menu(_("Sort block:"), menu1, 0)) + zero: + dir = line_menu(_("Sort block:"), menu1, 0); + switch (dir) { - /* 0 -- in X */ /*{{{*/ - case 0: in_dir=IN_X; break; - /*}}}*/ - /* 1 -- in Y */ /*{{{*/ - case 1: in_dir=IN_Y; break; - /*}}}*/ - /* 2 -- in Z */ /*{{{*/ - case 2: in_dir=IN_Z; break; - /*}}}*/ - /* -2,-1 -- abort */ /*{{{*/ - case -2: - case -1: goto greak; - /*}}}*/ - /* default -- should not happen */ /*{{{*/ + case 0: in_dir = IN_X; break; + case 1: in_dir = IN_Y; break; + case 2: in_dir = IN_Z; break; + case -2: case -1: return dir; default: assert(0); - /*}}}*/ } last=0; /*}}}*/ - key=0; + Sortkey sk[MAX_SORTKEYS]; + unsigned int key = 0; + bool doit = false; do { /* ask for positions */ /*{{{*/ one: if (in_dir==IN_X) sk[key].x=0; else /* ask for x position */ /*{{{*/ { - x=0; - offx=0; - sk[key].x=0; + sk[key].x = 0; do { - c=line_numedit(&(sk[key].x),_("X position of key vector:"),&x,&offx); - if (c==-1) goto greak; - else if (c==-2) switch (last) + int c = line_numedit(&(sk[key].x), _("X position of key vector:")); + if (c == -1) return -1; + else if (c == -2) switch (last) { - case -1: goto greak; + case -1: return -2; case 0: goto zero; case 2: goto two; case 3: goto three; case 5: goto five; } - } while (sk[key].x<0); - last=1; + } while (sk[key].x < 0); + last = 1; } /*}}}*/ two: if (in_dir==IN_Y) sk[key].y=0; else /* ask for y position */ /*{{{*/ { - x=0; - offx=0; - sk[key].y=0; + sk[key].y = 0; do { - c=line_numedit(&(sk[key].y),_("Y position of key vector:"),&x,&offx); - if (c==-1) goto greak; - else if (c==-2) switch (last) + int c = line_numedit(&(sk[key].y), _("Y position of key vector:")); + if (c == -1) return -1; + else if (c == -2) switch (last) { - case -1: goto greak; + case -1: return -2; case 0: goto zero; case 1: goto one; case 3: goto three; case 5: goto five; default: assert(0); } - } while (sk[key].y<0); - last=2; + } while (sk[key].y < 0); + last = 2; } /*}}}*/ three: if (in_dir==IN_Z) sk[key].z=0; else /* ask for z position */ /*{{{*/ { - x=0; - offx=0; - sk[key].z=0; + sk[key].z = 0; do { - c=line_numedit(&(sk[key].z),_("Z position of key vector:"),&x,&offx); - if (c==-1) goto greak; - else if (c==-2) switch (last) + int c = line_numedit(&(sk[key].z), _("Z position of key vector:")); + if (c == -1) return -1; + else if (c == -2) switch (last) { - case -1: goto greak; + case -1: return -2; case 0: goto zero; case 1: goto one; case 2: goto two; case 5: goto five; default: assert(0); } - } while (sk[key].z<0); - last=3; + } while (sk[key].z < 0); + last = 3; } /*}}}*/ /*}}}*/ /* ask for sort key */ /*{{{*/ four: sk[key].sortkey=0; - switch (c = line_menu(_("Sort block:"), menu3, 0)) + int ckey = line_menu(_("Sort block:"), menu3, 0); + switch (ckey) { - /* 0 -- ascending */ /*{{{*/ - case 0: sk[key].sortkey|=ASCENDING; break; - /*}}}*/ - /* 1 -- descending */ /*{{{*/ - case 1: sk[key].sortkey&=~ASCENDING; break; - /*}}}*/ - /* -1 -- abort */ /*{{{*/ - case -1: goto greak; - /*}}}*/ - /* -2 -- go to first menu */ /*{{{*/ + case 0: sk[key].sortkey |= ASCENDING; break; + case 1: sk[key].sortkey &= ~ASCENDING; break; + case -1: return -1; case -2: switch (last) { - case -1: goto greak; + case -1: return -2; case 1: goto one; case 2: goto two; case 3: goto three; default: assert(0); } - /*}}}*/ - /* default -- should not happen */ /*{{{*/ default: assert(0); - /*}}}*/ } - last=4; + last = 4; /*}}}*/ ++key; five: - if (key==MAX_SORTKEYS) /* ask for sort comfirmation */ /*{{{*/ + if (key == MAX_SORTKEYS) /* ask for sort comfirmation */ /*{{{*/ { - c=line_ok(_("Sort block:"),0); - if (c==-1) goto greak; - else if (c==-2) goto four; - else if (c==0) doit=1; + int c = line_ok(_("Sort block:"),0); + if (c == -1) return -1; + else if (c == -2) goto four; + else if (c == 0) doit = true; } /*}}}*/ else /* ask for sort or adding another key */ /*{{{*/ switch (line_menu(_("Sort block:"), menu2, 0)) { - /* 0 -- sort it */ /*{{{*/ - case 0: doit=1; break; - /*}}}*/ - /* 1 -- add another key */ /*{{{*/ - case 1: doit=0; break; - /*}}}*/ - /* -1 -- abort */ /*{{{*/ - case -1: goto greak; - /*}}}*/ + case 0: doit = true; break; + case 1: doit = false; break; + case -1: return -1; case -2: goto four; - /* default -- should not happen */ /*{{{*/ default: assert(0); - /*}}}*/ } /*}}}*/ - last=5; + last = 5; } while (!doit); - c=-1; - if ((msg=sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key))!=(const char*)0) line_msg(_("Sort block:"),msg); - greak: - return c; + const char *msg = + sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key); + if (msg != NULL) line_msg(_("Sort block:"), msg); + return 0; } /*}}}*/ @@ -1444,22 +1385,20 @@ static int do_mirror(Sheet *sheet) /* do_goto -- go to a specific cell */ /*{{{*/ static int do_goto(Sheet *sheet, const char *expr) { - /* variables */ /*{{{*/ - char buf[1024]; - const char *s; - size_t x,offx; - Token **t; - int c; - /*}}}*/ + assert(sheet != (Sheet*)0); - assert(sheet!=(Sheet*)0); + size_t x = 0; + size_t offx = 0; + char buf[1024]; buf[0]='\0'; - x=offx=0; if (expr) strcpy(buf,expr); - else if ((c=line_edit(sheet,buf,sizeof(buf),_("Go to location:"),&x,&offx))<0) return c; - s=buf; - t=scan(&s); - if (t!=(Token**)0) + else { + int c = line_edit(sheet, buf, sizeof(buf), _("Go to location:"), &x, &offx); + if (c < 0) return c; + } + char *s = buf; + Token **t = scan(&s); + if (t != EMPTY_TVEC) { Token value; @@ -1467,10 +1406,10 @@ static int do_goto(Sheet *sheet, const char *expr) upd_sheet = sheet; value = eval_safe(t, FULL); tvecfree(t); - if (value.type==LOCATION && IN_OCTANT(value.u.location)) + if (value.type == LOCATION && IN_OCTANT(value.u.location)) movetoloc(sheet, value.u.location); else - line_msg(_("Go to location:"),_("Not a valid location")); + line_msg(_("Go to location:"), _("Not a valid location")); tfree(&value); } return -1; @@ -1599,10 +1538,16 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly) } /*}}}*/ /* ENTER -- edit current cell */ /*{{{*/ - case K_ENTER: if (moveonly) break; do_edit(cursheet,'\0',(const char*)0,0); break; + case K_ENTER: + if (moveonly) break; + do_edit(cursheet, '\0', NULL, 0); + break; /*}}}*/ /* MENTER -- edit current clocked cell */ /*{{{*/ - case K_MENTER: if (moveonly) break; do_edit(cursheet,'\0',(const char*)0,1); break; + case K_MENTER: + if (moveonly) break; + do_edit(cursheet, '\0', NULL, 1); + break; /*}}}*/ /* ", @, digit -- edit current cell with character already in buffer */ /*{{{*/ case K_BACKSPACE: @@ -1618,11 +1563,14 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly) case '6': case '7': case '8': - case '9': if (moveonly) break; do_edit(cursheet,c,(const char*)0,0); break; + case '9': + if (moveonly) break; + do_edit(cursheet, c, NULL, 0); + break; /*}}}*/ /* MARK -- toggle block marking */ /*{{{*/ case '.': - case K_MARK: if (moveonly) break; do_mark(cursheet,0); break; + case K_MARK: if (moveonly) break; do_mark(cursheet, 0); break; /*}}}*/ /* _("Save sheet file format:") -- save menu */ /*{{{*/ case K_SAVEMENU: if (moveonly) break; do_save(cursheet); break; @@ -1752,7 +1700,7 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly) case K_QUIT: if (moveonly) break; return 1; /*}}}*/ default: - if (isalpha(c) && !moveonly) do_edit(cursheet,c,(const char*)0,0); + if (isalpha(c) && !moveonly) do_edit(cursheet, c, NULL, 0); break; } return 0; diff --git a/src/common/misc.c b/src/common/misc.c index 3df4441..e097ec3 100644 --- a/src/common/misc.c +++ b/src/common/misc.c @@ -30,61 +30,19 @@ #include "utf8.h" /*}}}*/ -/* posnumber -- match positive integer */ /*{{{*/ -long int posnumber(const char *s, const char **endptr) -{ - unsigned int base=10; - unsigned char c; - register const char *nptr = s; - long int result = 0L; - int saw_a_digit = 0; - - if (*nptr == '0') - { - if ((c = *++nptr) == 'x' || c == 'X') - { - ++nptr; - base = 16; - } - else - { - saw_a_digit = 1; - base = 8; - } - } - - --nptr; - while ((c=*++nptr)!='\0') - { - if (isdigit(c)) c -= '0'; - else if (isupper(c)) c -= ('A'-10); - else if (islower(c)) c -= ('a'-10); - else break; - if (c>=base) break; - saw_a_digit = 1; - result = result*base+c; - } - - *endptr=(saw_a_digit ? nptr : s); - return result; -} -/*}}}*/ /* posorder -- sort two integers */ /*{{{*/ void posorder(int *x, int *y) { - /* variables */ /*{{{*/ - int t; - /*}}}*/ + assert(x != (int*)0); + assert(*x >= 0); + assert(y != (int*)0); + assert(*y >= 0); - assert(x!=(int*)0); - assert(*x>=0); - assert(y!=(int*)0); - assert(*y>=0); - if (*x>*y) + if (*x > *y) { - t=*x; - *x=*y; - *y=t; + int t = *x; + *x = *y; + *y = t; } } /*}}}*/ diff --git a/src/common/misc.h b/src/common/misc.h index 46535dd..c9e58b3 100644 --- a/src/common/misc.h +++ b/src/common/misc.h @@ -10,7 +10,6 @@ extern "C" { #endif void posorder(int *x, int *y); -long int posnumber(const char *s, const char **endptr); const char *dblfinite(FltT x); int fputc_close(char c, FILE *fp); int fputs_close(const char *s, FILE *fp); diff --git a/src/common/sc.c b/src/common/sc.c index 096845e..85f01d8 100644 --- a/src/common/sc.c +++ b/src/common/sc.c @@ -245,7 +245,7 @@ const char *loadsc(Sheet *sheet, const char *name) || strncmp(buf, "rightstring ", 12) == 0) /* rightstring/leftstring cell = "string" */ /*{{{*/ { int x,y; - const char *s; + char *s; Token **contents; if (strncmp(buf, "leftstring ", 11) == 0) s = buf+11; else s = buf+12; @@ -279,15 +279,10 @@ const char *loadsc(Sheet *sheet, const char *name) /*}}}*/ else if (strncmp(buf,"let ",4)==0) /* let cell = expression */ /*{{{*/ { - /* variables */ /*{{{*/ - const char *s; - Token **contents; char newbuf[512]; - /*}}}*/ - - s=buf+4; - x=*s++-'A'; if (*s>='A' && *s<='Z') x=x*26+(*s++-'A'); - y=*s++-'0'; while (*s>='0' && *s<='9') y=10*y+(*s++-'0'); + char *s = buf+4; + x = *s++-'A'; if (*s >= 'A' && *s <= 'Z') x = x*26 + (*s++-'A'); + y = *s++-'0'; while (*s >= '0' && *s <= '9') y = 10*y + (*s++-'0'); tmp[X] = x; tmp[Y] = y; tmp[Z] = 0; if (gettok(CELL_ATC(sheet,x,y,0), BASE_CONT).type == EMPTY) { @@ -304,8 +299,8 @@ const char *loadsc(Sheet *sheet, const char *name) } *s2t_t = '\0'; s = newbuf; - contents = scan(&s); - if (contents==(Token**)0) + Token **contents = scan(&s); + if (contents == EMPTY_TVEC) { tvecfree(contents); sprintf(errbuf,_("Expression syntax error in line %d"),line); diff --git a/src/common/scanner.c b/src/common/scanner.c index 0d9b392..bfd2c33 100644 --- a/src/common/scanner.c +++ b/src/common/scanner.c @@ -99,11 +99,11 @@ Token duperror(Token* tok, const char* erro) } /* charstring -- match quoted string and return token */ /*{{{*/ -static Token *charstring(const char **s) +static Token *charstring(char **s) { - const char *r; + char *r; - r=*s; + r = *s; if (**s=='"') { ++(*s); @@ -129,57 +129,47 @@ static Token *charstring(const char **s) } /*}}}*/ -/* integer -- match an unsigned integer and return token */ /*{{{*/ -static Token *integer(const char **s) +/* scan_integer -- match an integer and return token */ /*{{{*/ +Token *scan_integer(char **s) { - const char *r; - long i; - - r=*s; - i=posnumber(r,s); - if (*s!=r && **s!='.' && **s!='e') + char *r = *s; + IntT i = STRTOINT(r, s, 0); + if (*s != r && **s != '.' && **s != 'e') { - Token *n; - - n=malloc(sizeof(Token)); - n->type=INT; - n->u.integer=i; + Token *n = malloc(sizeof(Token)); + n->type = INT; + n->u.integer = i; return n; } - else { *s=r; return (Token*)0; } + else { *s = r; return NULLTOKEN; } } /*}}}*/ -/* flt -- match a floating point number */ /*{{{*/ -static Token *flt(const char **s) +/* scan_flt -- match a floating point number */ /*{{{*/ +Token *scan_flt(char **s) { - /* variables */ /*{{{*/ - const char *t; + char *t = *s; char *end; - Token *n; - FltT x; - /*}}}*/ + FltT x = STRTOFLT(t, &end); - t=*s; - x = STRTOFLT(t,&end); *s = end; - if (t!=*s && dblfinite(x)==(const char*)0) + if (t !=* s && dblfinite(x) == NULL) { - n=malloc(sizeof(Token)); - n->type=FLOAT; - n->u.flt=x; + Token *n = malloc(sizeof(Token)); + n->type = FLOAT; + n->u.flt = x; return n; } else { - *s=t; - return (Token*)0; + *s = t; + return NULLTOKEN; } } /*}}}*/ /* op -- match an op and return token */ /*{{{*/ -static Token *op(const char **s) +static Token *op(char **s) { Token *n; Operator op; @@ -209,8 +199,8 @@ static Token *op(const char **s) return n; } /*}}}*/ -/* ident -- match an identifier and return token */ /*{{{*/ -static Token *ident(const char **s) +/* scan_ident -- match an identifier and return token */ /*{{{*/ +Token *scan_ident(char **s) { const char *begin; Token *result; @@ -251,11 +241,11 @@ static Token *ident(const char **s) /*}}}*/ /* scan -- scan string into tokens */ /*{{{*/ -Token **scan(const char **s) +Token **scan(char **s) { /* variables */ /*{{{*/ Token **na,*n; - const char *r; + char *r; /*}}}*/ /* compute number of tokens */ /*{{{*/ @@ -270,9 +260,9 @@ Token **scan(const char **s) while (*r == ' ') ++r; n = charstring(&r); if (n == NULLTOKEN) n = op(&r); - if (n == NULLTOKEN) n = integer(&r); - if (n == NULLTOKEN) n = flt(&r); - if (n == NULLTOKEN) n = ident(&r); + if (n == NULLTOKEN) n = scan_integer(&r); + if (n == NULLTOKEN) n = scan_flt(&r); + if (n == NULLTOKEN) n = scan_ident(&r); if (or == r) { *s = r; return EMPTY_TVEC; } } /*}}}*/ @@ -287,9 +277,9 @@ Token **scan(const char **s) while (*r == ' ') ++r; n = charstring(&r); if (n == NULLTOKEN) n = op(&r); - if (n == NULLTOKEN) n = integer(&r); - if (n == NULLTOKEN) n = flt(&r); - if (n == NULLTOKEN) n = ident(&r); + if (n == NULLTOKEN) n = scan_integer(&r); + if (n == NULLTOKEN) n = scan_flt(&r); + if (n == NULLTOKEN) n = scan_ident(&r); na[j] = n; } na[i] = NULLTOKEN; diff --git a/src/common/scanner.h b/src/common/scanner.h index b932a15..e1783d9 100644 --- a/src/common/scanner.h +++ b/src/common/scanner.h @@ -38,7 +38,7 @@ typedef enum extern const char *Op_Name[]; typedef int Location[3]; /* NOTE: Locations are passed by REFERENCE not value */ - /* I.e., to accapt a Location argument, declare the parameter to be of type + /* I.e., to accept a Location argument, declare the parameter to be of type const Location* */ @@ -172,7 +172,10 @@ typedef struct Token_struc bool tok_matches(const Token *l, const Token *r); Token duperror(Token* tok, const char* erro); -Token **scan(const char **s); +Token *scan_ident(char **s); +Token *scan_integer(char **s); +Token *scan_flt(char **s); +Token **scan(char **s); void cleartoken(Token* tok); #ifdef __cplusplus diff --git a/src/common/sheet.c b/src/common/sheet.c index 3ceb956..5ca7f6b 100644 --- a/src/common/sheet.c +++ b/src/common/sheet.c @@ -1174,27 +1174,19 @@ const char *saveport(Sheet *sheet, const char *name, unsigned int *count) /* loadport -- load from portable text */ /*{{{*/ const char *loadport(Sheet *sheet, const char *name) { - /* variables */ /*{{{*/ - static char errbuf[80]; - FILE *fp; - Location loc; - int cx, cz; - char buf[4096]; - int line; - const char *ns,*os; - const char *err; Cell loaded; - int width; - /*}}}*/ - + FILE *fp; if ((fp=fopen(name,"r")) == (FILE*)0) return strerror(errno); freesheet(sheet, 0); - err = (const char*)0; - line = 1; - while (fgets(buf,sizeof(buf),fp) != (char*)0) + + static char errbuf[80]; + const char *err = NULL; + int line = 1; + char buf[4096]; + while (fgets(buf, sizeof(buf), fp) != NULL) { /* remove nl */ /*{{{*/ - width = strlen(buf); + int width = strlen(buf); if (width > 0 && buf[width-1] == '\n') buf[--width] = '\0'; /*}}}*/ switch (buf[0]) @@ -1203,12 +1195,14 @@ const char *loadport(Sheet *sheet, const char *name) case 'C': { TokVariety rv = BASE_CONT, nextrv = BASE_CONT; - + Location loc; + if (width > 0 && buf[width-1]=='\\') { buf[--width]='\0'; ++nextrv; } initcellcontents(&loaded); /* parse x y and z */ /*{{{*/ - os=ns=buf+1; - loc[X] = posnumber(os,&ns); + const char *os = buf + 1; + char *ns = buf + 1; + loc[X] = strtol(os, &ns, 0); if (os==ns) { sprintf(errbuf,_("Parse error for x position in line %d"),line); @@ -1217,7 +1211,7 @@ const char *loadport(Sheet *sheet, const char *name) } while (*ns==' ') ++ns; os=ns; - loc[Y] = posnumber(os,&ns); + loc[Y] = strtol(os, &ns, 0); if (os==ns) { sprintf(errbuf,_("Parse error for y position in line %d"),line); @@ -1226,7 +1220,7 @@ const char *loadport(Sheet *sheet, const char *name) } while (*ns==' ') ++ns; os=ns; - loc[Z] = posnumber(os,&ns); + loc[Z] = strtol(os, &ns, 0); if (os == ns) { sprintf(errbuf,_("Parse error for z position in line %d"),line); @@ -1290,7 +1284,7 @@ const char *loadport(Sheet *sheet, const char *name) case 'P': { os=++ns; - loaded.precision=posnumber(os,&ns); + loaded.precision = strtol(os, &ns, 0); if (os==ns) { sprintf(errbuf,_("Parse error for precision in line %d"),line); @@ -1304,7 +1298,7 @@ const char *loadport(Sheet *sheet, const char *name) case 'H': { os = ++ns; - size_t na = posnumber(os, &ns); + size_t na = strtol(os, &ns, 0); if (os == ns || na > NUM_COLOR_ASPECTS) { sprintf(errbuf, _("Parse error for number of hues in line %d"), @@ -1316,7 +1310,7 @@ const char *loadport(Sheet *sheet, const char *name) { while (*ns && (*ns == ' ')) { ++ns; } os = ns; - loaded.aspect[a] = posnumber(os, &ns); + loaded.aspect[a] = strtol(os, &ns, 0); if (os == ns) { sprintf(errbuf, _("Parse error in hue %d on line %d"), @@ -1458,8 +1452,9 @@ const char *loadport(Sheet *sheet, const char *name) case 'W': { /* parse x and z */ /*{{{*/ - os=ns=buf+1; - cx=posnumber(os,&ns); + const char *os = buf+1; + char *ns = buf+1; + int cx = strtol(os, &ns, 0); if (os==ns) { sprintf(errbuf,_("Parse error for x position in line %d"),line); @@ -1468,7 +1463,7 @@ const char *loadport(Sheet *sheet, const char *name) } while (*ns==' ') ++ns; os=ns; - cz=posnumber(os,&ns); + int cz = strtol(os, &ns, 0); if (os==ns) { sprintf(errbuf,_("Parse error for z position in line %d"),line); @@ -1479,7 +1474,7 @@ const char *loadport(Sheet *sheet, const char *name) /* parse width */ /*{{{*/ while (*ns==' ') ++ns; os=ns; - width=posnumber(os,&ns); + width = strtol(os, &ns, 0); if (os==ns) { sprintf(errbuf,_("Parse error for width in line %d"),line);