Add type predicate
The main new finction is is(), which tests the type of a value. There are also constants for each of the possible token types, and one new conversion: number(), which converts a value into the most appropriate number type. This change also reuses the functions in scanner.h for exracting ints, floats, and identifiers from strings, rather than either rewriting the functionality elsewhere, or using the general-purpose scan when only one token type was of interest.
This commit is contained in:
parent
892fdcdb75
commit
6534aec2fd
602
doc/teapot.lyx
602
doc/teapot.lyx
@ -5015,8 +5015,10 @@ y
|
|||||||
.
|
.
|
||||||
As with
|
As with
|
||||||
\family typewriter
|
\family typewriter
|
||||||
|
\series bold
|
||||||
and
|
and
|
||||||
\family default
|
\family default
|
||||||
|
\series default
|
||||||
, this evaluation short-circuits if
|
, this evaluation short-circuits if
|
||||||
\emph on
|
\emph on
|
||||||
x
|
x
|
||||||
@ -5226,17 +5228,17 @@ y
|
|||||||
Note: a string of consecutive relational operators is interpreted as the
|
Note: a string of consecutive relational operators is interpreted as the
|
||||||
conjunction of each consecutive (overlapping) pair.
|
conjunction of each consecutive (overlapping) pair.
|
||||||
Thus
|
Thus
|
||||||
\family typewriter
|
\family sans
|
||||||
2 <= y() <= 10
|
2 <= y() <= 10
|
||||||
\family default
|
\family default
|
||||||
will evaluate to true precisely in rows 2 through 10, inclusive (it is
|
will evaluate to true precisely in rows 2 through 10, inclusive (it is
|
||||||
shorthand for
|
shorthand for
|
||||||
\family typewriter
|
\family sans
|
||||||
2 <= y() and y() <= 10
|
2 <= y() and y() <= 10
|
||||||
\family default
|
\family default
|
||||||
).
|
).
|
||||||
Similarly
|
Similarly
|
||||||
\family typewriter
|
\family sans
|
||||||
@(cell1) == @(cell2) == @(cell3)
|
@(cell1) == @(cell2) == @(cell3)
|
||||||
\family default
|
\family default
|
||||||
will return true exactly when all three cells have the same value.
|
will return true exactly when all three cells have the same value.
|
||||||
@ -5499,13 +5501,15 @@ Functions
|
|||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
This section documents all available functions in alphabetical order.
|
This section documents all available functions in alphabetical order.
|
||||||
The functions are given in a C-like notation, so use
|
The functions are described in a C-like notation; you don't have to write
|
||||||
\family typewriter
|
the types when you use the function in a formula.
|
||||||
|
For example, use
|
||||||
|
\family sans
|
||||||
@(0,0,0)
|
@(0,0,0)
|
||||||
\family default
|
\family default
|
||||||
instead of
|
, not
|
||||||
\family typewriter
|
\family sans
|
||||||
@(integer 0, integer 0, integer 0)
|
@(int 0, int 0, int 0)
|
||||||
\family default
|
\family default
|
||||||
.
|
.
|
||||||
If no type is given for the result of a function, it means the result type
|
If no type is given for the result of a function, it means the result type
|
||||||
@ -5565,7 +5569,8 @@ y
|
|||||||
z
|
z
|
||||||
\emph default
|
\emph default
|
||||||
is specified, that value overrides the corresponding coordinate of the
|
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
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -6436,6 +6441,27 @@ or
|
|||||||
of all the supplied values.
|
of all the supplied values.
|
||||||
\end_layout
|
\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
|
\begin_layout Description
|
||||||
|
|
||||||
\series medium
|
\series medium
|
||||||
@ -6641,6 +6667,24 @@ e
|
|||||||
Note the parentheses are optional.
|
Note the parentheses are optional.
|
||||||
\end_layout
|
\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
|
\begin_layout Description
|
||||||
|
|
||||||
\series medium
|
\series medium
|
||||||
@ -6652,17 +6696,23 @@ error
|
|||||||
\series default
|
\series default
|
||||||
error
|
error
|
||||||
\series medium
|
\series medium
|
||||||
(string
|
[([
|
||||||
\emph on
|
\emph on
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
message
|
message
|
||||||
\emph default
|
\emph default
|
||||||
)
|
])]
|
||||||
\series 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
|
\end_layout
|
||||||
|
|
||||||
@ -6692,6 +6742,19 @@ boolean
|
|||||||
false represents the false Boolean value.
|
false represents the false Boolean value.
|
||||||
\end_layout
|
\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
|
\begin_layout Description
|
||||||
|
|
||||||
\series medium
|
\series medium
|
||||||
@ -6703,7 +6766,7 @@ float
|
|||||||
\series default
|
\series default
|
||||||
float
|
float
|
||||||
\series medium
|
\series medium
|
||||||
(string|int
|
[([float|string|int|empty
|
||||||
\emph on
|
\emph on
|
||||||
|
|
||||||
\begin_inset space ~
|
\begin_inset space ~
|
||||||
@ -6711,9 +6774,20 @@ float
|
|||||||
|
|
||||||
s
|
s
|
||||||
\emph default
|
\emph default
|
||||||
)
|
])]
|
||||||
\series 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
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -6763,14 +6837,32 @@ frac
|
|||||||
|
|
||||||
x
|
x
|
||||||
\emph default
|
\emph default
|
||||||
)
|
)
|
||||||
\series default
|
\series default
|
||||||
evaluates to the fractional part of
|
evaluates to the fractional part of
|
||||||
\emph on
|
\emph on
|
||||||
x
|
x
|
||||||
\emph default
|
\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
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -6789,7 +6881,7 @@ int
|
|||||||
\series default
|
\series default
|
||||||
int
|
int
|
||||||
\series medium
|
\series medium
|
||||||
(float
|
[([int|float|string|empty
|
||||||
\emph on
|
\emph on
|
||||||
|
|
||||||
\begin_inset space ~
|
\begin_inset space ~
|
||||||
@ -6797,263 +6889,185 @@ int
|
|||||||
|
|
||||||
x
|
x
|
||||||
\emph default
|
\emph default
|
||||||
[,integer
|
][,
|
||||||
\emph on
|
\emph on
|
||||||
|
|
||||||
\begin_inset space ~
|
\begin_inset space ~
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
neg
|
direction
|
||||||
\emph default
|
\emph default
|
||||||
,
|
])]
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
integer
|
|
||||||
\emph on
|
|
||||||
|
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
pos
|
|
||||||
\emph default
|
|
||||||
])
|
|
||||||
\series 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
|
\emph on
|
||||||
x
|
x
|
||||||
\emph default
|
\emph default
|
||||||
to an integer value by cutting off the fractional part.
|
is omitted, the value of the current cell is used.
|
||||||
If given, the value of
|
If in addition the parentheses are omitted, acts as a keyword, e.g., for
|
||||||
\emph on
|
value testing with
|
||||||
neg
|
\family sans
|
||||||
\emph default
|
\series bold
|
||||||
and
|
is
|
||||||
\emph on
|
\series default
|
||||||
pos
|
()
|
||||||
\emph default
|
\family default
|
||||||
determines how negative and non-negative numbers will be converted:
|
.
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\begin_layout Quote
|
|
||||||
\begin_inset Tabular
|
|
||||||
<lyxtabular version="3" rows="6" columns="2">
|
|
||||||
<features tabularvalignment="middle">
|
|
||||||
<column alignment="center" valignment="top">
|
|
||||||
<column alignment="left" valignment="top">
|
|
||||||
<row>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
|
|
||||||
\emph on
|
|
||||||
neg
|
|
||||||
\emph default
|
|
||||||
/
|
|
||||||
\emph on
|
|
||||||
pos
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
Result
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
< -1
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
next smaller integer value
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
-1
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
round downward
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
0
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
cut fractional part off (default)
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
1
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
round upward
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
</row>
|
|
||||||
<row>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
> 1
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
|
|
||||||
\begin_inset Text
|
|
||||||
|
|
||||||
\begin_layout Plain Layout
|
|
||||||
next larger integer value
|
|
||||||
\end_layout
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
</cell>
|
|
||||||
</row>
|
|
||||||
</lyxtabular>
|
|
||||||
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
|
is
|
||||||
\series medium
|
\series medium
|
||||||
int
|
[([
|
||||||
|
\emph on
|
||||||
|
x
|
||||||
|
\emph default
|
||||||
|
][,
|
||||||
|
\emph on
|
||||||
|
|
||||||
\begin_inset space ~
|
\begin_inset space ~
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
|
type1,
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
type2
|
||||||
|
\emph default
|
||||||
|
,...])]
|
||||||
\series default
|
\series default
|
||||||
int
|
Boolean-valued type testing.
|
||||||
\series medium
|
Returns true if the given value
|
||||||
(string|float
|
|
||||||
\emph on
|
\emph on
|
||||||
|
x
|
||||||
\begin_inset space ~
|
|
||||||
\end_inset
|
|
||||||
|
|
||||||
s
|
|
||||||
\emph default
|
\emph default
|
||||||
[,
|
is any of the listed types.
|
||||||
\emph on
|
Each type may be any of the keywords
|
||||||
|
\family sans
|
||||||
\begin_inset space ~
|
\series bold
|
||||||
\end_inset
|
bool, empty, error, fident, float, funcall, int
|
||||||
|
\family default
|
||||||
rounding
|
|
||||||
\emph default
|
|
||||||
])
|
|
||||||
\series 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
|
\emph on
|
||||||
s
|
x
|
||||||
\emph default
|
\emph default
|
||||||
to an integer number.
|
)
|
||||||
In case of a floating point argument, there is an optional second argument
|
\family default
|
||||||
which determines which nearby integer will be selected.
|
is a boolean-valued version of
|
||||||
It must be one of the function names
|
\family sans
|
||||||
\begin_inset Quotes eld
|
\series bold
|
||||||
\end_inset
|
n
|
||||||
|
\series default
|
||||||
ceil,
|
(
|
||||||
\begin_inset Quotes erd
|
\emph on
|
||||||
\end_inset
|
x
|
||||||
|
\emph default
|
||||||
|
)
|
||||||
\begin_inset Quotes eld
|
\family default
|
||||||
\end_inset
|
, without the special behavior when
|
||||||
|
\emph on
|
||||||
floor,
|
x
|
||||||
\begin_inset Quotes erd
|
\emph default
|
||||||
\end_inset
|
is a location.) If
|
||||||
|
\emph on
|
||||||
|
x
|
||||||
\begin_inset Quotes eld
|
\emph default
|
||||||
\end_inset
|
is omitted, defaults to the value of the current cell; the parentheses
|
||||||
|
may be omitted as well, so bare
|
||||||
round,
|
\family sans
|
||||||
\begin_inset Quotes erd
|
\series bold
|
||||||
\end_inset
|
is
|
||||||
|
\family default
|
||||||
or
|
\series default
|
||||||
\begin_inset Quotes eld
|
tests whether the current cell is non-empty.
|
||||||
\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.
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -7106,7 +7120,20 @@ s
|
|||||||
s
|
s
|
||||||
\emph default
|
\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
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -7157,7 +7184,25 @@ y
|
|||||||
y
|
y
|
||||||
\emph default
|
\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
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -7449,6 +7494,47 @@ l1
|
|||||||
The second form simply returns the number of its arguments which are nonempty.
|
The second form simply returns the number of its arguments which are nonempty.
|
||||||
\end_layout
|
\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
|
\begin_layout Description
|
||||||
poly
|
poly
|
||||||
\series medium
|
\series medium
|
||||||
@ -7476,7 +7562,7 @@ cn
|
|||||||
\begin_inset space ~
|
\begin_inset space ~
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
...])
|
...])
|
||||||
\series default
|
\series default
|
||||||
evaluates the polynomial
|
evaluates the polynomial
|
||||||
\emph on
|
\emph on
|
||||||
|
@ -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 */ /*{{{*/
|
/* blcnst_func -- common implementation of true/false */ /*{{{*/
|
||||||
static Token blcnst_func(FunctionIdentifier self, int argc, const Token argv[])
|
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 */ /*{{{*/
|
/* string */ /*{{{*/
|
||||||
static Token string_func(FunctionIdentifier self, int argc, const Token argv[])
|
static Token string_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||||
{
|
{
|
||||||
assert(self == FUNC_STRING);
|
|
||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token result;
|
Token result, arg;
|
||||||
const char *usage = _("Usage: string(x[,[int prec][,format_for_floats]])");
|
|
||||||
int precision = def_precision;
|
int precision = def_precision;
|
||||||
bool ff = DEF_FLOATFORM;
|
bool ff = DEF_FLOATFORM;
|
||||||
|
bool bad_args = false;
|
||||||
char staticbuf[4096];
|
char staticbuf[4096];
|
||||||
size_t size;
|
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
if (argc < 1 || argc > 3) return duperror(&result, usage);
|
switch (argc) {
|
||||||
if (argc == 3)
|
case -1: return self_func(self, argc, argv);
|
||||||
{
|
case 0: arg = recompvalue(upd_sheet, upd_l); break;
|
||||||
if (argv[2].type != FIDENT) return duperror(&result, usage);
|
case 3:
|
||||||
switch (argv[2].u.fident)
|
if (argv[2].type != FIDENT) bad_args = true; break;
|
||||||
|
switch (argv[2].u.fident)
|
||||||
{
|
{
|
||||||
case FUNC_DECIMAL: ff = FLT_DECIMAL; break;
|
case FUNC_DECIMAL: ff = FLT_DECIMAL; break;
|
||||||
case FUNC_SCIENTIFIC: ff = FLT_SCIENTIFIC; break;
|
case FUNC_SCIENTIFIC: ff = FLT_SCIENTIFIC; break;
|
||||||
case FUNC_COMPACT: ff = FLT_COMPACT; break;
|
case FUNC_COMPACT: ff = FLT_COMPACT; break;
|
||||||
case FUNC_HEXACT: ff = FLT_HEXACT; break;
|
case FUNC_HEXACT: ff = FLT_HEXACT; break;
|
||||||
default: assert(0);
|
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 (bad_args) {
|
||||||
if (argv[1].type != INT) return duperror(&result, usage);
|
const char *templ =
|
||||||
precision = argv[1].u.integer;
|
_("Usage: %s[([x][,[int prec][,format_for_floats]])]");
|
||||||
|
sprintf(staticbuf, templ, tfunc[self].name);
|
||||||
|
return duperror(&result, staticbuf);
|
||||||
}
|
}
|
||||||
result.type = STRING;
|
result.type = STRING;
|
||||||
size = printtok(staticbuf, sizeof(staticbuf), 0, DIRECT_STRING, ff,
|
size_t size = printtok(staticbuf, sizeof(staticbuf), 0, DIRECT_STRING, ff,
|
||||||
precision, VERBOSE_ERROR, argv);
|
precision, VERBOSE_ERROR, &arg);
|
||||||
|
tfree(&arg);
|
||||||
if (size > sizeof(staticbuf) - 2)
|
if (size > sizeof(staticbuf) - 2)
|
||||||
return duperror(&result, _("string: Overflow of internal buffer"));
|
return duperror(&result, _("string: Overflow of internal buffer"));
|
||||||
result.u.string = strdup(staticbuf);
|
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
|
/* accum_func -- common implementation of functions that accumulate all of
|
||||||
their arguments into a final value.
|
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 */ /*{{{*/
|
/* len */ /*{{{*/
|
||||||
static Token len_func(FunctionIdentifier self, int argc, const Token argv[])
|
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 */ /*{{{*/
|
/* strftime */ /*{{{*/
|
||||||
static Token strftime_func(FunctionIdentifier fi, int argc, const Token argv[])
|
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);
|
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 */ /*{{{*/
|
/* nearby integer (rounding) function */ /*{{{*/
|
||||||
static Token near_func(FunctionIdentifier self, int argc, const Token argv[])
|
static Token near_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||||
{
|
{
|
||||||
@ -1424,7 +1557,6 @@ Tfunc tfunc[]=
|
|||||||
|
|
||||||
/* Evaluation control functions */
|
/* Evaluation control functions */
|
||||||
[FUNC_CLOCK] = { "clock", clock_func, PREFIX_FUNC, FUNCT, 0 },
|
[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 },
|
[FUNC_EVAL] = { "eval", eval_func, PREFIX_FUNC, FUNCT, 0 },
|
||||||
|
|
||||||
/* Boolean functions */
|
/* Boolean functions */
|
||||||
@ -1433,10 +1565,20 @@ Tfunc tfunc[]=
|
|||||||
[FUNC_OR] = { "or", blop_macro, INFIX_BOOL, MACRO, 0 },
|
[FUNC_OR] = { "or", blop_macro, INFIX_BOOL, MACRO, 0 },
|
||||||
[FUNC_TRUE] = { "true", blcnst_func, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_TRUE] = { "true", blcnst_func, PREFIX_FUNC, FUNCT, 0 },
|
||||||
|
|
||||||
/* Type conversion functions */
|
/* Type conversion/testing functions and keywords */
|
||||||
[FUNC_FLOAT] = { "float", float_func, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_BOOL] = { "bool", self_func, PREFIX_FUNC, FUNCT, 0 },
|
||||||
[FUNC_INT] = { "int", int_func, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_EMPTY] = { "empty", empty_func, PREFIX_FUNC, FUNCT, 0 },
|
||||||
[FUNC_STRING] = { "string", string_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 */
|
/* Block operations */
|
||||||
[FUNC_MAX] = { "max", reg_disp, PREFIX_FUNC, FUNCT, 0 },
|
[FUNC_MAX] = { "max", reg_disp, PREFIX_FUNC, FUNCT, 0 },
|
||||||
|
@ -22,7 +22,8 @@ typedef enum
|
|||||||
FUNC_RND, FUNC_SUBSTR, FUNC_STRPTIME, FUNC_TIME, FUNC_BITAND, FUNC_BITOR,
|
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_R, FUNC_D, FUNC_CAP_X, FUNC_X_AMPERSAND, FUNC_NEGATE, FUNC_PLUS_SYMBOL,
|
||||||
FUNC_MINUS_SYMBOL, FUNC_ASTERISK, FUNC_SLASH,
|
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_LESS_EQUAL, FUNC_GREATER_EQUAL, FUNC_LESS_THAN, FUNC_GREATER_THAN,
|
||||||
FUNC_EQUAL_EQUAL, FUNC_TILDE_EQUAL, FUNC_BANG_EQUAL,
|
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_HEXACT, FUNC_RIGHT, FUNC_LEFT, FUNC_DOWN, FUNC_UP, FUNC_BELOW, FUNC_ABOVE,
|
||||||
FUNC_TRUE, FUNC_FALSE, FUNC_AND, FUNC_OR,
|
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
|
N_FUNCTION_IDS
|
||||||
} FunctionIdentifier;
|
} FunctionIdentifier;
|
||||||
|
|
||||||
#define IS_RELATION_FUNC(f) (((f) >= FUNC_LESS_EQUAL) && ((f) <= FUNC_BANG_EQUAL))
|
#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 */
|
/* Forward declaration of Token, since this header is used in scanner.h */
|
||||||
typedef struct Token_struc Token;
|
typedef struct Token_struc Token;
|
||||||
|
@ -89,60 +89,49 @@ void relmoveto(Sheet *sheet, int x, int y, int z)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* line_numedit -- number line editor function */ /*{{{*/
|
/* 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 */ /*{{{*/
|
assert(prompt != NULL);
|
||||||
char buf[20];
|
|
||||||
const char *s;
|
|
||||||
Token **t;
|
|
||||||
int c;
|
|
||||||
/*}}}*/
|
|
||||||
|
|
||||||
/* asserts */ /*{{{*/
|
char buf[20];
|
||||||
assert(prompt!=(char*)0);
|
Token *t = NULLTOKEN;
|
||||||
assert(x!=(size_t*)0);
|
sprintf(buf, "%d", *n);
|
||||||
assert(offx!=(size_t*)0);
|
char *s = buf+strlen(buf);
|
||||||
/*}}}*/
|
|
||||||
t=(Token**)0;
|
|
||||||
sprintf(buf,"%d",*n);
|
|
||||||
s=buf+strlen(buf);
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
tvecfree(t);
|
free(t);
|
||||||
*x=s-buf;
|
size_t x = s - buf;
|
||||||
if ((c=line_edit((Sheet*)0,buf,sizeof(buf),prompt,x,offx))<0) return c;
|
size_t offx = 0;
|
||||||
s=buf;
|
int c = line_edit((Sheet*)0, buf, sizeof(buf), prompt, &x, &offx);
|
||||||
t=scan(&s);
|
if (c < 0) return c;
|
||||||
} while ((*s!='\0' && t==(Token**)0) || !(t!=(Token**)0 && ((*t)==(Token*)0 || ((*t)->type==INT && (*t)->u.integer>=0 && *(t+1)==(Token*)0))));
|
s = buf;
|
||||||
if (t==(Token**)0 || *t==(Token*)0) *n=-1;
|
t = scan_integer(&s);
|
||||||
else *n=(*t)->u.integer;
|
} while (*s != '\0');
|
||||||
tvecfree(t);
|
if (t == NULLTOKEN) *n = -1;
|
||||||
|
else { *n = t->u.integer; free(t); }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* line_lidedit -- label identifier line editor function */ /*{{{*/
|
/* 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)
|
static int line_idedit(char *ident, size_t size, const char *prompt, size_t *x, size_t *offx)
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
Token *t = NULLTOKEN;
|
||||||
const char *s;
|
char *s = ident+strlen(ident);
|
||||||
Token **t;
|
|
||||||
int c;
|
|
||||||
/*}}}*/
|
|
||||||
|
|
||||||
t=(Token**)0;
|
|
||||||
s=ident+strlen(ident);
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
tvecfree(t);
|
free(t);
|
||||||
*x=s-ident;
|
*x = s - ident;
|
||||||
if ((c=line_edit((Sheet*)0,ident,size,prompt,x,offx))<0) return c;
|
int c = line_edit((Sheet*)0, ident, size, prompt, x, offx);
|
||||||
s=ident;
|
if (c < 0) return c;
|
||||||
t=scan(&s);
|
s = ident;
|
||||||
} while ((*s!='\0' && t==(Token**)0) || !(t!=(Token**)0 && ((*t)==(Token*)0 || ((*t)->type==LIDENT && *(t+1)==(Token*)0))));
|
t = scan_ident(&s);
|
||||||
tvecfree(t);
|
} while (*s != '\0' || t == NULLTOKEN || t->type != LIDENT);
|
||||||
|
free(t);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* doanyway -- ask if action should be done despite unsaved changes */ /*{{{*/
|
/* doanyway -- ask if action should be done despite unsaved changes */ /*{{{*/
|
||||||
int doanyway(Sheet *sheet, const char *msg)
|
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 */ /*{{{*/
|
/* 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 */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
const char *s, *prompt;
|
const char *prompt;
|
||||||
|
char *s;
|
||||||
size_t x,offx;
|
size_t x,offx;
|
||||||
Location scur;
|
Location scur;
|
||||||
Token **t;
|
Token **t;
|
||||||
@ -322,23 +312,15 @@ static int do_label(Sheet *sheet)
|
|||||||
/* do_columnwidth -- set the column width */ /*{{{*/
|
/* do_columnwidth -- set the column width */ /*{{{*/
|
||||||
static int do_columnwidth(Sheet *cursheet)
|
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);
|
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 {
|
do {
|
||||||
if ((c=line_numedit(&n,_("Column width:"),&edx,&offx))<0) return c;
|
int c = line_numedit(&n, _("Column width:"));
|
||||||
} while (n<=0);
|
if (c < 0) return c;
|
||||||
|
} while (n <= 0);
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
for (x = cursheet->mark1[X]; x <= cursheet->mark2[X]; ++x)
|
for (int x = cursheet->mark1[X]; x <= cursheet->mark2[X]; ++x)
|
||||||
for (z = cursheet->mark1[Z]; z <= cursheet->mark2[Z]; ++z)
|
for (int z = cursheet->mark1[Z]; z <= cursheet->mark2[Z]; ++z)
|
||||||
setwidth(cursheet,x,z,n);
|
setwidth(cursheet,x,z,n);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -397,7 +379,10 @@ static void do_attribute(Sheet *cursheet, Key action)
|
|||||||
offx=0;
|
offx=0;
|
||||||
ex=0;
|
ex=0;
|
||||||
n = getprecision(fcell);
|
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))
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
||||||
changed = setprecision(cursheet, w, n) || changed;
|
changed = setprecision(cursheet, w, n) || changed;
|
||||||
break;
|
break;
|
||||||
@ -1139,7 +1124,6 @@ static int do_move(Sheet *sheet, int copy, int force)
|
|||||||
static int do_fill(Sheet *sheet)
|
static int do_fill(Sheet *sheet)
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
size_t offx,edx;
|
|
||||||
int cols,rows,layers;
|
int cols,rows,layers;
|
||||||
int x,y,z;
|
int x,y,z;
|
||||||
Location wid, go;
|
Location wid, go;
|
||||||
@ -1152,26 +1136,23 @@ static int do_fill(Sheet *sheet)
|
|||||||
do_mark(sheet, MARKED);
|
do_mark(sheet, MARKED);
|
||||||
cols=rows=layers=1;
|
cols=rows=layers=1;
|
||||||
firstmenu:
|
firstmenu:
|
||||||
offx=0;
|
do {
|
||||||
edx=0;
|
int c = line_numedit(&cols, _("Number of column-wise repetitions:"));
|
||||||
do if ((c=line_numedit(&cols,_("Number of column-wise repetitions:"),&edx,&offx))<0) return c; while (cols<=0);
|
if (c < 0) return c;
|
||||||
|
} while (cols <= 0);
|
||||||
secondmenu:
|
secondmenu:
|
||||||
offx=0;
|
|
||||||
edx=0;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
c=line_numedit(&rows,_("Number of row-wise repetitions:"),&edx,&offx);
|
int c = line_numedit(&rows, _("Number of row-wise repetitions:"));
|
||||||
if (c==-1) return -1;
|
if (c == -1) return -1;
|
||||||
else if (c==-2) goto firstmenu;
|
else if (c == -2) goto firstmenu;
|
||||||
} while (rows<=0);
|
} while (rows <= 0);
|
||||||
offx=0;
|
|
||||||
edx=0;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
c=line_numedit(&layers,_("Number of depth-wise repetitions:"),&edx,&offx);
|
int c = line_numedit(&layers, _("Number of depth-wise repetitions:"));
|
||||||
if (c==-1) return -1;
|
if (c == -1) return -1;
|
||||||
else if (c==-2) goto secondmenu;
|
else if (c == -2) goto secondmenu;
|
||||||
} while (layers<=0);
|
} while (layers <= 0);
|
||||||
LOCATION_GETS(wid, sheet->mark2);
|
LOCATION_GETS(wid, sheet->mark2);
|
||||||
LOCATION_SUB(wid, sheet->mark1);
|
LOCATION_SUB(wid, sheet->mark1);
|
||||||
wid[X]++; wid[Y]++; wid[Z]++;
|
wid[X]++; wid[Y]++; wid[Z]++;
|
||||||
@ -1202,18 +1183,6 @@ void fillwith(Sheet *she)
|
|||||||
/* do_sort -- sort block */ /*{{{*/
|
/* do_sort -- sort block */ /*{{{*/
|
||||||
static int do_sort(Sheet *sheet)
|
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);
|
do_mark(sheet, GET_MARK_ALL);
|
||||||
/* build menus */ /*{{{*/
|
/* build menus */ /*{{{*/
|
||||||
const char* menu1[] =
|
const char* menu1[] =
|
||||||
@ -1224,162 +1193,134 @@ static int do_sort(Sheet *sheet)
|
|||||||
{ _("aA)scending"), _("dD)escending"), NULL };
|
{ _("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 */ /*{{{*/
|
/* 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;
|
||||||
case 0: in_dir=IN_X; break;
|
case 1: in_dir = IN_Y; break;
|
||||||
/*}}}*/
|
case 2: in_dir = IN_Z; break;
|
||||||
/* 1 -- in Y */ /*{{{*/
|
case -2: case -1: return dir;
|
||||||
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 */ /*{{{*/
|
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
/*}}}*/
|
|
||||||
}
|
}
|
||||||
last=0;
|
last=0;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
key=0;
|
Sortkey sk[MAX_SORTKEYS];
|
||||||
|
unsigned int key = 0;
|
||||||
|
bool doit = false;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
/* ask for positions */ /*{{{*/
|
/* ask for positions */ /*{{{*/
|
||||||
one: if (in_dir==IN_X) sk[key].x=0; else /* ask for x position */ /*{{{*/
|
one: if (in_dir==IN_X) sk[key].x=0; else /* ask for x position */ /*{{{*/
|
||||||
{
|
{
|
||||||
x=0;
|
sk[key].x = 0;
|
||||||
offx=0;
|
|
||||||
sk[key].x=0;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
c=line_numedit(&(sk[key].x),_("X position of key vector:"),&x,&offx);
|
int c = line_numedit(&(sk[key].x), _("X position of key vector:"));
|
||||||
if (c==-1) goto greak;
|
if (c == -1) return -1;
|
||||||
else if (c==-2) switch (last)
|
else if (c == -2) switch (last)
|
||||||
{
|
{
|
||||||
case -1: goto greak;
|
case -1: return -2;
|
||||||
case 0: goto zero;
|
case 0: goto zero;
|
||||||
case 2: goto two;
|
case 2: goto two;
|
||||||
case 3: goto three;
|
case 3: goto three;
|
||||||
case 5: goto five;
|
case 5: goto five;
|
||||||
}
|
}
|
||||||
} while (sk[key].x<0);
|
} while (sk[key].x < 0);
|
||||||
last=1;
|
last = 1;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
two: if (in_dir==IN_Y) sk[key].y=0; else /* ask for y position */ /*{{{*/
|
two: if (in_dir==IN_Y) sk[key].y=0; else /* ask for y position */ /*{{{*/
|
||||||
{
|
{
|
||||||
x=0;
|
sk[key].y = 0;
|
||||||
offx=0;
|
|
||||||
sk[key].y=0;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
c=line_numedit(&(sk[key].y),_("Y position of key vector:"),&x,&offx);
|
int c = line_numedit(&(sk[key].y), _("Y position of key vector:"));
|
||||||
if (c==-1) goto greak;
|
if (c == -1) return -1;
|
||||||
else if (c==-2) switch (last)
|
else if (c == -2) switch (last)
|
||||||
{
|
{
|
||||||
case -1: goto greak;
|
case -1: return -2;
|
||||||
case 0: goto zero;
|
case 0: goto zero;
|
||||||
case 1: goto one;
|
case 1: goto one;
|
||||||
case 3: goto three;
|
case 3: goto three;
|
||||||
case 5: goto five;
|
case 5: goto five;
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
}
|
}
|
||||||
} while (sk[key].y<0);
|
} while (sk[key].y < 0);
|
||||||
last=2;
|
last = 2;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
three: if (in_dir==IN_Z) sk[key].z=0; else /* ask for z position */ /*{{{*/
|
three: if (in_dir==IN_Z) sk[key].z=0; else /* ask for z position */ /*{{{*/
|
||||||
{
|
{
|
||||||
x=0;
|
sk[key].z = 0;
|
||||||
offx=0;
|
|
||||||
sk[key].z=0;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
c=line_numedit(&(sk[key].z),_("Z position of key vector:"),&x,&offx);
|
int c = line_numedit(&(sk[key].z), _("Z position of key vector:"));
|
||||||
if (c==-1) goto greak;
|
if (c == -1) return -1;
|
||||||
else if (c==-2) switch (last)
|
else if (c == -2) switch (last)
|
||||||
{
|
{
|
||||||
case -1: goto greak;
|
case -1: return -2;
|
||||||
case 0: goto zero;
|
case 0: goto zero;
|
||||||
case 1: goto one;
|
case 1: goto one;
|
||||||
case 2: goto two;
|
case 2: goto two;
|
||||||
case 5: goto five;
|
case 5: goto five;
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
}
|
}
|
||||||
} while (sk[key].z<0);
|
} while (sk[key].z < 0);
|
||||||
last=3;
|
last = 3;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
/* ask for sort key */ /*{{{*/
|
/* ask for sort key */ /*{{{*/
|
||||||
four: sk[key].sortkey=0;
|
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;
|
||||||
case 0: sk[key].sortkey|=ASCENDING; break;
|
case 1: sk[key].sortkey &= ~ASCENDING; break;
|
||||||
/*}}}*/
|
case -1: return -1;
|
||||||
/* 1 -- descending */ /*{{{*/
|
|
||||||
case 1: sk[key].sortkey&=~ASCENDING; break;
|
|
||||||
/*}}}*/
|
|
||||||
/* -1 -- abort */ /*{{{*/
|
|
||||||
case -1: goto greak;
|
|
||||||
/*}}}*/
|
|
||||||
/* -2 -- go to first menu */ /*{{{*/
|
|
||||||
case -2: switch (last)
|
case -2: switch (last)
|
||||||
{
|
{
|
||||||
case -1: goto greak;
|
case -1: return -2;
|
||||||
case 1: goto one;
|
case 1: goto one;
|
||||||
case 2: goto two;
|
case 2: goto two;
|
||||||
case 3: goto three;
|
case 3: goto three;
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
}
|
}
|
||||||
/*}}}*/
|
|
||||||
/* default -- should not happen */ /*{{{*/
|
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
/*}}}*/
|
|
||||||
}
|
}
|
||||||
last=4;
|
last = 4;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
++key;
|
++key;
|
||||||
five:
|
five:
|
||||||
if (key==MAX_SORTKEYS) /* ask for sort comfirmation */ /*{{{*/
|
if (key == MAX_SORTKEYS) /* ask for sort comfirmation */ /*{{{*/
|
||||||
{
|
{
|
||||||
c=line_ok(_("Sort block:"),0);
|
int c = line_ok(_("Sort block:"),0);
|
||||||
if (c==-1) goto greak;
|
if (c == -1) return -1;
|
||||||
else if (c==-2) goto four;
|
else if (c == -2) goto four;
|
||||||
else if (c==0) doit=1;
|
else if (c == 0) doit = true;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
else /* ask for sort or adding another key */ /*{{{*/
|
else /* ask for sort or adding another key */ /*{{{*/
|
||||||
switch (line_menu(_("Sort block:"), menu2, 0))
|
switch (line_menu(_("Sort block:"), menu2, 0))
|
||||||
{
|
{
|
||||||
/* 0 -- sort it */ /*{{{*/
|
case 0: doit = true; break;
|
||||||
case 0: doit=1; break;
|
case 1: doit = false; break;
|
||||||
/*}}}*/
|
case -1: return -1;
|
||||||
/* 1 -- add another key */ /*{{{*/
|
|
||||||
case 1: doit=0; break;
|
|
||||||
/*}}}*/
|
|
||||||
/* -1 -- abort */ /*{{{*/
|
|
||||||
case -1: goto greak;
|
|
||||||
/*}}}*/
|
|
||||||
case -2: goto four;
|
case -2: goto four;
|
||||||
/* default -- should not happen */ /*{{{*/
|
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
/*}}}*/
|
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
last=5;
|
last = 5;
|
||||||
} while (!doit);
|
} while (!doit);
|
||||||
c=-1;
|
const char *msg =
|
||||||
if ((msg=sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key))!=(const char*)0) line_msg(_("Sort block:"),msg);
|
sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key);
|
||||||
greak:
|
if (msg != NULL) line_msg(_("Sort block:"), msg);
|
||||||
return c;
|
return 0;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
@ -1444,22 +1385,20 @@ static int do_mirror(Sheet *sheet)
|
|||||||
/* do_goto -- go to a specific cell */ /*{{{*/
|
/* do_goto -- go to a specific cell */ /*{{{*/
|
||||||
static int do_goto(Sheet *sheet, const char *expr)
|
static int do_goto(Sheet *sheet, const char *expr)
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
assert(sheet != (Sheet*)0);
|
||||||
char buf[1024];
|
|
||||||
const char *s;
|
|
||||||
size_t x,offx;
|
|
||||||
Token **t;
|
|
||||||
int c;
|
|
||||||
/*}}}*/
|
|
||||||
|
|
||||||
assert(sheet!=(Sheet*)0);
|
size_t x = 0;
|
||||||
|
size_t offx = 0;
|
||||||
|
char buf[1024];
|
||||||
buf[0]='\0';
|
buf[0]='\0';
|
||||||
x=offx=0;
|
|
||||||
if (expr) strcpy(buf,expr);
|
if (expr) strcpy(buf,expr);
|
||||||
else if ((c=line_edit(sheet,buf,sizeof(buf),_("Go to location:"),&x,&offx))<0) return c;
|
else {
|
||||||
s=buf;
|
int c = line_edit(sheet, buf, sizeof(buf), _("Go to location:"), &x, &offx);
|
||||||
t=scan(&s);
|
if (c < 0) return c;
|
||||||
if (t!=(Token**)0)
|
}
|
||||||
|
char *s = buf;
|
||||||
|
Token **t = scan(&s);
|
||||||
|
if (t != EMPTY_TVEC)
|
||||||
{
|
{
|
||||||
Token value;
|
Token value;
|
||||||
|
|
||||||
@ -1467,10 +1406,10 @@ static int do_goto(Sheet *sheet, const char *expr)
|
|||||||
upd_sheet = sheet;
|
upd_sheet = sheet;
|
||||||
value = eval_safe(t, FULL);
|
value = eval_safe(t, FULL);
|
||||||
tvecfree(t);
|
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);
|
movetoloc(sheet, value.u.location);
|
||||||
else
|
else
|
||||||
line_msg(_("Go to location:"),_("Not a valid location"));
|
line_msg(_("Go to location:"), _("Not a valid location"));
|
||||||
tfree(&value);
|
tfree(&value);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
@ -1599,10 +1538,16 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly)
|
|||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
/* ENTER -- edit current cell */ /*{{{*/
|
/* 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 */ /*{{{*/
|
/* 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 */ /*{{{*/
|
/* ", @, digit -- edit current cell with character already in buffer */ /*{{{*/
|
||||||
case K_BACKSPACE:
|
case K_BACKSPACE:
|
||||||
@ -1618,11 +1563,14 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly)
|
|||||||
case '6':
|
case '6':
|
||||||
case '7':
|
case '7':
|
||||||
case '8':
|
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 */ /*{{{*/
|
/* MARK -- toggle block marking */ /*{{{*/
|
||||||
case '.':
|
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 */ /*{{{*/
|
/* _("Save sheet file format:") -- save menu */ /*{{{*/
|
||||||
case K_SAVEMENU: if (moveonly) break; do_save(cursheet); break;
|
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;
|
case K_QUIT: if (moveonly) break; return 1;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
default:
|
default:
|
||||||
if (isalpha(c) && !moveonly) do_edit(cursheet,c,(const char*)0,0);
|
if (isalpha(c) && !moveonly) do_edit(cursheet, c, NULL, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -30,61 +30,19 @@
|
|||||||
#include "utf8.h"
|
#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 */ /*{{{*/
|
/* posorder -- sort two integers */ /*{{{*/
|
||||||
void posorder(int *x, int *y)
|
void posorder(int *x, int *y)
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
assert(x != (int*)0);
|
||||||
int t;
|
assert(*x >= 0);
|
||||||
/*}}}*/
|
assert(y != (int*)0);
|
||||||
|
assert(*y >= 0);
|
||||||
|
|
||||||
assert(x!=(int*)0);
|
if (*x > *y)
|
||||||
assert(*x>=0);
|
|
||||||
assert(y!=(int*)0);
|
|
||||||
assert(*y>=0);
|
|
||||||
if (*x>*y)
|
|
||||||
{
|
{
|
||||||
t=*x;
|
int t = *x;
|
||||||
*x=*y;
|
*x = *y;
|
||||||
*y=t;
|
*y = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
@ -10,7 +10,6 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void posorder(int *x, int *y);
|
void posorder(int *x, int *y);
|
||||||
long int posnumber(const char *s, const char **endptr);
|
|
||||||
const char *dblfinite(FltT x);
|
const char *dblfinite(FltT x);
|
||||||
int fputc_close(char c, FILE *fp);
|
int fputc_close(char c, FILE *fp);
|
||||||
int fputs_close(const char *s, FILE *fp);
|
int fputs_close(const char *s, FILE *fp);
|
||||||
|
@ -245,7 +245,7 @@ const char *loadsc(Sheet *sheet, const char *name)
|
|||||||
|| strncmp(buf, "rightstring ", 12) == 0) /* rightstring/leftstring cell = "string" */ /*{{{*/
|
|| strncmp(buf, "rightstring ", 12) == 0) /* rightstring/leftstring cell = "string" */ /*{{{*/
|
||||||
{
|
{
|
||||||
int x,y;
|
int x,y;
|
||||||
const char *s;
|
char *s;
|
||||||
Token **contents;
|
Token **contents;
|
||||||
|
|
||||||
if (strncmp(buf, "leftstring ", 11) == 0) s = buf+11; else s = buf+12;
|
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 */ /*{{{*/
|
else if (strncmp(buf,"let ",4)==0) /* let cell = expression */ /*{{{*/
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
|
||||||
const char *s;
|
|
||||||
Token **contents;
|
|
||||||
char newbuf[512];
|
char newbuf[512];
|
||||||
/*}}}*/
|
char *s = buf+4;
|
||||||
|
x = *s++-'A'; if (*s >= 'A' && *s <= 'Z') x = x*26 + (*s++-'A');
|
||||||
s=buf+4;
|
y = *s++-'0'; while (*s >= '0' && *s <= '9') y = 10*y + (*s++-'0');
|
||||||
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;
|
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
|
||||||
if (gettok(CELL_ATC(sheet,x,y,0), BASE_CONT).type == EMPTY)
|
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';
|
*s2t_t = '\0';
|
||||||
s = newbuf;
|
s = newbuf;
|
||||||
contents = scan(&s);
|
Token **contents = scan(&s);
|
||||||
if (contents==(Token**)0)
|
if (contents == EMPTY_TVEC)
|
||||||
{
|
{
|
||||||
tvecfree(contents);
|
tvecfree(contents);
|
||||||
sprintf(errbuf,_("Expression syntax error in line %d"),line);
|
sprintf(errbuf,_("Expression syntax error in line %d"),line);
|
||||||
|
@ -99,11 +99,11 @@ Token duperror(Token* tok, const char* erro)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* charstring -- match quoted string and return token */ /*{{{*/
|
/* 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=='"')
|
if (**s=='"')
|
||||||
{
|
{
|
||||||
++(*s);
|
++(*s);
|
||||||
@ -129,57 +129,47 @@ static Token *charstring(const char **s)
|
|||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* integer -- match an unsigned integer and return token */ /*{{{*/
|
/* scan_integer -- match an integer and return token */ /*{{{*/
|
||||||
static Token *integer(const char **s)
|
Token *scan_integer(char **s)
|
||||||
{
|
{
|
||||||
const char *r;
|
char *r = *s;
|
||||||
long i;
|
IntT i = STRTOINT(r, s, 0);
|
||||||
|
if (*s != r && **s != '.' && **s != 'e')
|
||||||
r=*s;
|
|
||||||
i=posnumber(r,s);
|
|
||||||
if (*s!=r && **s!='.' && **s!='e')
|
|
||||||
{
|
{
|
||||||
Token *n;
|
Token *n = malloc(sizeof(Token));
|
||||||
|
n->type = INT;
|
||||||
n=malloc(sizeof(Token));
|
n->u.integer = i;
|
||||||
n->type=INT;
|
|
||||||
n->u.integer=i;
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
else { *s=r; return (Token*)0; }
|
else { *s = r; return NULLTOKEN; }
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* flt -- match a floating point number */ /*{{{*/
|
/* scan_flt -- match a floating point number */ /*{{{*/
|
||||||
static Token *flt(const char **s)
|
Token *scan_flt(char **s)
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
char *t = *s;
|
||||||
const char *t;
|
|
||||||
char *end;
|
char *end;
|
||||||
Token *n;
|
FltT x = STRTOFLT(t, &end);
|
||||||
FltT x;
|
|
||||||
/*}}}*/
|
|
||||||
|
|
||||||
t=*s;
|
|
||||||
x = STRTOFLT(t,&end);
|
|
||||||
*s = end;
|
*s = end;
|
||||||
if (t!=*s && dblfinite(x)==(const char*)0)
|
if (t !=* s && dblfinite(x) == NULL)
|
||||||
{
|
{
|
||||||
n=malloc(sizeof(Token));
|
Token *n = malloc(sizeof(Token));
|
||||||
n->type=FLOAT;
|
n->type = FLOAT;
|
||||||
n->u.flt=x;
|
n->u.flt = x;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*s=t;
|
*s = t;
|
||||||
return (Token*)0;
|
return NULLTOKEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* op -- match an op and return token */ /*{{{*/
|
/* op -- match an op and return token */ /*{{{*/
|
||||||
static Token *op(const char **s)
|
static Token *op(char **s)
|
||||||
{
|
{
|
||||||
Token *n;
|
Token *n;
|
||||||
Operator op;
|
Operator op;
|
||||||
@ -209,8 +199,8 @@ static Token *op(const char **s)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
/* ident -- match an identifier and return token */ /*{{{*/
|
/* scan_ident -- match an identifier and return token */ /*{{{*/
|
||||||
static Token *ident(const char **s)
|
Token *scan_ident(char **s)
|
||||||
{
|
{
|
||||||
const char *begin;
|
const char *begin;
|
||||||
Token *result;
|
Token *result;
|
||||||
@ -251,11 +241,11 @@ static Token *ident(const char **s)
|
|||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* scan -- scan string into tokens */ /*{{{*/
|
/* scan -- scan string into tokens */ /*{{{*/
|
||||||
Token **scan(const char **s)
|
Token **scan(char **s)
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
/* variables */ /*{{{*/
|
||||||
Token **na,*n;
|
Token **na,*n;
|
||||||
const char *r;
|
char *r;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* compute number of tokens */ /*{{{*/
|
/* compute number of tokens */ /*{{{*/
|
||||||
@ -270,9 +260,9 @@ Token **scan(const char **s)
|
|||||||
while (*r == ' ') ++r;
|
while (*r == ' ') ++r;
|
||||||
n = charstring(&r);
|
n = charstring(&r);
|
||||||
if (n == NULLTOKEN) n = op(&r);
|
if (n == NULLTOKEN) n = op(&r);
|
||||||
if (n == NULLTOKEN) n = integer(&r);
|
if (n == NULLTOKEN) n = scan_integer(&r);
|
||||||
if (n == NULLTOKEN) n = flt(&r);
|
if (n == NULLTOKEN) n = scan_flt(&r);
|
||||||
if (n == NULLTOKEN) n = ident(&r);
|
if (n == NULLTOKEN) n = scan_ident(&r);
|
||||||
if (or == r) { *s = r; return EMPTY_TVEC; }
|
if (or == r) { *s = r; return EMPTY_TVEC; }
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -287,9 +277,9 @@ Token **scan(const char **s)
|
|||||||
while (*r == ' ') ++r;
|
while (*r == ' ') ++r;
|
||||||
n = charstring(&r);
|
n = charstring(&r);
|
||||||
if (n == NULLTOKEN) n = op(&r);
|
if (n == NULLTOKEN) n = op(&r);
|
||||||
if (n == NULLTOKEN) n = integer(&r);
|
if (n == NULLTOKEN) n = scan_integer(&r);
|
||||||
if (n == NULLTOKEN) n = flt(&r);
|
if (n == NULLTOKEN) n = scan_flt(&r);
|
||||||
if (n == NULLTOKEN) n = ident(&r);
|
if (n == NULLTOKEN) n = scan_ident(&r);
|
||||||
na[j] = n;
|
na[j] = n;
|
||||||
}
|
}
|
||||||
na[i] = NULLTOKEN;
|
na[i] = NULLTOKEN;
|
||||||
|
@ -38,7 +38,7 @@ typedef enum
|
|||||||
extern const char *Op_Name[];
|
extern const char *Op_Name[];
|
||||||
|
|
||||||
typedef int Location[3]; /* NOTE: Locations are passed by REFERENCE not value */
|
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*
|
const Location*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -172,7 +172,10 @@ typedef struct Token_struc
|
|||||||
|
|
||||||
bool tok_matches(const Token *l, const Token *r);
|
bool tok_matches(const Token *l, const Token *r);
|
||||||
Token duperror(Token* tok, const char* erro);
|
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);
|
void cleartoken(Token* tok);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -1174,27 +1174,19 @@ const char *saveport(Sheet *sheet, const char *name, unsigned int *count)
|
|||||||
/* loadport -- load from portable text */ /*{{{*/
|
/* loadport -- load from portable text */ /*{{{*/
|
||||||
const char *loadport(Sheet *sheet, const char *name)
|
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;
|
Cell loaded;
|
||||||
int width;
|
FILE *fp;
|
||||||
/*}}}*/
|
|
||||||
|
|
||||||
if ((fp=fopen(name,"r")) == (FILE*)0) return strerror(errno);
|
if ((fp=fopen(name,"r")) == (FILE*)0) return strerror(errno);
|
||||||
freesheet(sheet, 0);
|
freesheet(sheet, 0);
|
||||||
err = (const char*)0;
|
|
||||||
line = 1;
|
static char errbuf[80];
|
||||||
while (fgets(buf,sizeof(buf),fp) != (char*)0)
|
const char *err = NULL;
|
||||||
|
int line = 1;
|
||||||
|
char buf[4096];
|
||||||
|
while (fgets(buf, sizeof(buf), fp) != NULL)
|
||||||
{
|
{
|
||||||
/* remove nl */ /*{{{*/
|
/* remove nl */ /*{{{*/
|
||||||
width = strlen(buf);
|
int width = strlen(buf);
|
||||||
if (width > 0 && buf[width-1] == '\n') buf[--width] = '\0';
|
if (width > 0 && buf[width-1] == '\n') buf[--width] = '\0';
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
switch (buf[0])
|
switch (buf[0])
|
||||||
@ -1203,12 +1195,14 @@ const char *loadport(Sheet *sheet, const char *name)
|
|||||||
case 'C':
|
case 'C':
|
||||||
{
|
{
|
||||||
TokVariety rv = BASE_CONT, nextrv = BASE_CONT;
|
TokVariety rv = BASE_CONT, nextrv = BASE_CONT;
|
||||||
|
Location loc;
|
||||||
|
|
||||||
if (width > 0 && buf[width-1]=='\\') { buf[--width]='\0'; ++nextrv; }
|
if (width > 0 && buf[width-1]=='\\') { buf[--width]='\0'; ++nextrv; }
|
||||||
initcellcontents(&loaded);
|
initcellcontents(&loaded);
|
||||||
/* parse x y and z */ /*{{{*/
|
/* parse x y and z */ /*{{{*/
|
||||||
os=ns=buf+1;
|
const char *os = buf + 1;
|
||||||
loc[X] = posnumber(os,&ns);
|
char *ns = buf + 1;
|
||||||
|
loc[X] = strtol(os, &ns, 0);
|
||||||
if (os==ns)
|
if (os==ns)
|
||||||
{
|
{
|
||||||
sprintf(errbuf,_("Parse error for x position in line %d"),line);
|
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;
|
while (*ns==' ') ++ns;
|
||||||
os=ns;
|
os=ns;
|
||||||
loc[Y] = posnumber(os,&ns);
|
loc[Y] = strtol(os, &ns, 0);
|
||||||
if (os==ns)
|
if (os==ns)
|
||||||
{
|
{
|
||||||
sprintf(errbuf,_("Parse error for y position in line %d"),line);
|
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;
|
while (*ns==' ') ++ns;
|
||||||
os=ns;
|
os=ns;
|
||||||
loc[Z] = posnumber(os,&ns);
|
loc[Z] = strtol(os, &ns, 0);
|
||||||
if (os == ns)
|
if (os == ns)
|
||||||
{
|
{
|
||||||
sprintf(errbuf,_("Parse error for z position in line %d"),line);
|
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':
|
case 'P':
|
||||||
{
|
{
|
||||||
os=++ns;
|
os=++ns;
|
||||||
loaded.precision=posnumber(os,&ns);
|
loaded.precision = strtol(os, &ns, 0);
|
||||||
if (os==ns)
|
if (os==ns)
|
||||||
{
|
{
|
||||||
sprintf(errbuf,_("Parse error for precision in line %d"),line);
|
sprintf(errbuf,_("Parse error for precision in line %d"),line);
|
||||||
@ -1304,7 +1298,7 @@ const char *loadport(Sheet *sheet, const char *name)
|
|||||||
case 'H':
|
case 'H':
|
||||||
{
|
{
|
||||||
os = ++ns;
|
os = ++ns;
|
||||||
size_t na = posnumber(os, &ns);
|
size_t na = strtol(os, &ns, 0);
|
||||||
if (os == ns || na > NUM_COLOR_ASPECTS)
|
if (os == ns || na > NUM_COLOR_ASPECTS)
|
||||||
{
|
{
|
||||||
sprintf(errbuf, _("Parse error for number of hues in line %d"),
|
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; }
|
while (*ns && (*ns == ' ')) { ++ns; }
|
||||||
os = ns;
|
os = ns;
|
||||||
loaded.aspect[a] = posnumber(os, &ns);
|
loaded.aspect[a] = strtol(os, &ns, 0);
|
||||||
if (os == ns)
|
if (os == ns)
|
||||||
{
|
{
|
||||||
sprintf(errbuf, _("Parse error in hue %d on line %d"),
|
sprintf(errbuf, _("Parse error in hue %d on line %d"),
|
||||||
@ -1458,8 +1452,9 @@ const char *loadport(Sheet *sheet, const char *name)
|
|||||||
case 'W':
|
case 'W':
|
||||||
{
|
{
|
||||||
/* parse x and z */ /*{{{*/
|
/* parse x and z */ /*{{{*/
|
||||||
os=ns=buf+1;
|
const char *os = buf+1;
|
||||||
cx=posnumber(os,&ns);
|
char *ns = buf+1;
|
||||||
|
int cx = strtol(os, &ns, 0);
|
||||||
if (os==ns)
|
if (os==ns)
|
||||||
{
|
{
|
||||||
sprintf(errbuf,_("Parse error for x position in line %d"),line);
|
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;
|
while (*ns==' ') ++ns;
|
||||||
os=ns;
|
os=ns;
|
||||||
cz=posnumber(os,&ns);
|
int cz = strtol(os, &ns, 0);
|
||||||
if (os==ns)
|
if (os==ns)
|
||||||
{
|
{
|
||||||
sprintf(errbuf,_("Parse error for z position in line %d"),line);
|
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 */ /*{{{*/
|
/* parse width */ /*{{{*/
|
||||||
while (*ns==' ') ++ns;
|
while (*ns==' ') ++ns;
|
||||||
os=ns;
|
os=ns;
|
||||||
width=posnumber(os,&ns);
|
width = strtol(os, &ns, 0);
|
||||||
if (os==ns)
|
if (os==ns)
|
||||||
{
|
{
|
||||||
sprintf(errbuf,_("Parse error for width in line %d"),line);
|
sprintf(errbuf,_("Parse error for width in line %d"),line);
|
||||||
|
Loading…
Reference in New Issue
Block a user