Implement a relative reference robust to source and reference moving
The new function is X(SRC,REF), which briefly for a cell in the neighborhood of REF returns the corresponding cell in the neighborhood in SRC. For further details, see the updated documention. In developing and documenting this function, I refined some of the existing error messages (e.g. showing the coordinates when there is an attempt to obtain a cell with a negative coordinate) and improved the error propagation to increase the chance that the innermost error will percolate to the top level.
This commit is contained in:
parent
ab1a2fbb5a
commit
341b12ba04
421
doc/teapot.lyx
421
doc/teapot.lyx
@ -4625,7 +4625,7 @@ save-tbl
|
|||||||
file
|
file
|
||||||
\series default
|
\series default
|
||||||
\emph default
|
\emph default
|
||||||
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -4642,7 +4642,7 @@ save-csv
|
|||||||
file
|
file
|
||||||
\series default
|
\series default
|
||||||
\emph default
|
\emph default
|
||||||
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -4659,7 +4659,7 @@ save-latex
|
|||||||
file
|
file
|
||||||
\series default
|
\series default
|
||||||
\emph default
|
\emph default
|
||||||
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -4676,7 +4676,7 @@ save-context
|
|||||||
file
|
file
|
||||||
\series default
|
\series default
|
||||||
\emph default
|
\emph default
|
||||||
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -4855,6 +4855,11 @@ Location Cell labels and the
|
|||||||
&()
|
&()
|
||||||
\family default
|
\family default
|
||||||
function have this type, but there are no location constant literals.
|
function have this type, but there are no location constant literals.
|
||||||
|
However,
|
||||||
|
\family typewriter
|
||||||
|
&(3,2,1),
|
||||||
|
\family default
|
||||||
|
for example, acts very much like a location constant literal.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -5041,7 +5046,7 @@ y
|
|||||||
x
|
x
|
||||||
\family typewriter
|
\family typewriter
|
||||||
\emph default
|
\emph default
|
||||||
=
|
~=
|
||||||
\family default
|
\family default
|
||||||
\emph on
|
\emph on
|
||||||
y
|
y
|
||||||
@ -5489,7 +5494,8 @@ y
|
|||||||
z
|
z
|
||||||
\emph default
|
\emph default
|
||||||
is omitted, the coordinate of the cell is used.
|
is omitted, the coordinate of the cell is used.
|
||||||
The second form is in fact a no-op, but it is allowed for convenience
|
The second form is in fact a no-op, but it is allowed for convenience and
|
||||||
|
consistency of expressions.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -5515,8 +5521,21 @@ relative.
|
|||||||
\begin_inset Quotes erd
|
\begin_inset Quotes erd
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
Thus R(-1) returns the value of the cell immediately to the left of this
|
Thus
|
||||||
one.
|
\family sans
|
||||||
|
\series bold
|
||||||
|
R
|
||||||
|
\series default
|
||||||
|
(-1)
|
||||||
|
\family default
|
||||||
|
returns the value of the cell immediately to the left of this one, and
|
||||||
|
\family sans
|
||||||
|
\series bold
|
||||||
|
R
|
||||||
|
\series default
|
||||||
|
(,,1)
|
||||||
|
\family default
|
||||||
|
returns the same cell as this one but on the following layer.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -5541,8 +5560,181 @@ displaced (by).
|
|||||||
\begin_inset Quotes erd
|
\begin_inset Quotes erd
|
||||||
\end_inset
|
\end_inset
|
||||||
|
|
||||||
Thus, D(-1) returns the location of the cell immediately to the left of
|
Thus,
|
||||||
this one.
|
\family sans
|
||||||
|
\series bold
|
||||||
|
D
|
||||||
|
\series default
|
||||||
|
(-1)
|
||||||
|
\family default
|
||||||
|
returns the location of the cell immediately to the left of this one, and
|
||||||
|
\family sans
|
||||||
|
\series bold
|
||||||
|
D
|
||||||
|
\series default
|
||||||
|
(,2,1)
|
||||||
|
\family default
|
||||||
|
returns the location of the cell two below this one on the following layer.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Description
|
||||||
|
X(
|
||||||
|
\series medium
|
||||||
|
label
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
to,
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\emph default
|
||||||
|
label
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
from,
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\emph default
|
||||||
|
[bool
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
fix_x
|
||||||
|
\emph default
|
||||||
|
]
|
||||||
|
\emph on
|
||||||
|
,
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\emph default
|
||||||
|
[bool
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
fix_y
|
||||||
|
\emph default
|
||||||
|
]
|
||||||
|
\emph on
|
||||||
|
,
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\emph default
|
||||||
|
[bool
|
||||||
|
\emph on
|
||||||
|
|
||||||
|
\begin_inset space ~
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
fix_z
|
||||||
|
\emph default
|
||||||
|
]
|
||||||
|
\series default
|
||||||
|
)
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
Excel reference
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
: returns the value of the cell at a computed target location.
|
||||||
|
This target location is the one reached from the current cell via the same
|
||||||
|
offset as the cell with label
|
||||||
|
\emph on
|
||||||
|
to
|
||||||
|
\emph default
|
||||||
|
has from label
|
||||||
|
\emph on
|
||||||
|
from.
|
||||||
|
|
||||||
|
\emph default
|
||||||
|
The idea is that if you label the source of data you want to reference,
|
||||||
|
say with
|
||||||
|
\family sans
|
||||||
|
SRC
|
||||||
|
\family default
|
||||||
|
, and the location of some place you want to start referring to it with
|
||||||
|
|
||||||
|
\family sans
|
||||||
|
REF
|
||||||
|
\family default
|
||||||
|
, then you can use
|
||||||
|
\family sans
|
||||||
|
\series bold
|
||||||
|
X
|
||||||
|
\series default
|
||||||
|
(SRC,REF)
|
||||||
|
\family default
|
||||||
|
to refer to the source data, and fill this formula to neighboring cells
|
||||||
|
to refer to the neighbors of the source, and it will all continue to work
|
||||||
|
if either the source or the reference is moved around in the sheet.
|
||||||
|
|
||||||
|
\begin_inset Newline newline
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
If the
|
||||||
|
\emph on
|
||||||
|
fix_DIM
|
||||||
|
\emph default
|
||||||
|
argument is present and positive, then the corresponding coordinate of
|
||||||
|
the target cell is set to match that of
|
||||||
|
\emph on
|
||||||
|
to
|
||||||
|
\emph default
|
||||||
|
.
|
||||||
|
This corresponds to fixing the row or column (or layer) of the reference,
|
||||||
|
as with a
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
$
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
character in Excel.
|
||||||
|
Thus
|
||||||
|
\family sans
|
||||||
|
\series bold
|
||||||
|
X
|
||||||
|
\series default
|
||||||
|
(SRC,REF,1,1,1)
|
||||||
|
\family default
|
||||||
|
is identical to
|
||||||
|
\family sans
|
||||||
|
@(SRC)
|
||||||
|
\family default
|
||||||
|
, but you should certainly prefer the latter for clarity of expression.
|
||||||
|
\begin_inset Newline newline
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
There is a corresponding location function
|
||||||
|
\family sans
|
||||||
|
X&()
|
||||||
|
\family default
|
||||||
|
as well, which takes exactly the same arguments with the same meanings,
|
||||||
|
but it is rarely needed.
|
||||||
|
It is provided for completeness.
|
||||||
|
\begin_inset Newline newline
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
See the FAQ below for further discussion of cell references.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Description
|
\begin_layout Description
|
||||||
@ -5904,7 +6096,7 @@ clock
|
|||||||
|
|
||||||
condition
|
condition
|
||||||
\emph default
|
\emph default
|
||||||
,[location[,location])
|
,[location[,location])
|
||||||
\series default
|
\series default
|
||||||
conditionally clocks the specified cell if the condition is not 0.
|
conditionally clocks the specified cell if the condition is not 0.
|
||||||
If two locations are given, all cells in that range will be clocked.
|
If two locations are given, all cells in that range will be clocked.
|
||||||
@ -7264,8 +7456,22 @@ z
|
|||||||
position of the given location, of the currently updated cell if none is
|
position of the given location, of the currently updated cell if none is
|
||||||
given.
|
given.
|
||||||
These functions are usually used in combination with the @ function for
|
These functions are usually used in combination with the @ function for
|
||||||
relative relations to other cells.
|
relative relations to other cell, but see also the convenience functions
|
||||||
|
|
||||||
|
\family sans
|
||||||
|
\series bold
|
||||||
|
R
|
||||||
|
\series default
|
||||||
|
()
|
||||||
|
\family default
|
||||||
|
and
|
||||||
|
\family sans
|
||||||
|
\series bold
|
||||||
|
D
|
||||||
|
\series default
|
||||||
|
()
|
||||||
|
\family default
|
||||||
|
for relative references.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Subsection
|
\begin_layout Subsection
|
||||||
@ -7763,11 +7969,13 @@ X
|
|||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Quote
|
\begin_layout Quote
|
||||||
eval(&((@(X)>=0)+x(BAD),y(BAD),z(BAD)))
|
eval(BAD + &((@(X)>=0),0,0))
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Standard
|
\begin_layout Standard
|
||||||
The cell labelled
|
Note this is making use of the fact that you can add locations in the natural
|
||||||
|
way.
|
||||||
|
The cell labelled
|
||||||
\family typewriter
|
\family typewriter
|
||||||
BAD
|
BAD
|
||||||
\family default
|
\family default
|
||||||
@ -7786,5 +7994,190 @@ BAD
|
|||||||
|
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Subsection
|
||||||
|
But my references don't do the right thing when I move or copy them!
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
If you are used to other spreadsheets, you have probably noticed that references
|
||||||
|
like
|
||||||
|
\family sans
|
||||||
|
@(0,1,0)
|
||||||
|
\family default
|
||||||
|
(for the start of the second row) or
|
||||||
|
\family sans
|
||||||
|
@(MYDATA)
|
||||||
|
\family default
|
||||||
|
(for a location) are
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
absolute
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
– they always refer to the same location no matter where in the spreadsheet
|
||||||
|
they occur.
|
||||||
|
And of course sometimes it is convenient, for example when making a column
|
||||||
|
of consecutive numbers, to refer to nearby cells in a relative manner,
|
||||||
|
either with say
|
||||||
|
\family sans
|
||||||
|
@(x(),y()-1,z())+1
|
||||||
|
\family default
|
||||||
|
or
|
||||||
|
\family sans
|
||||||
|
@(&()+&(0,-1,0))+1
|
||||||
|
\family default
|
||||||
|
or just
|
||||||
|
\family sans
|
||||||
|
R(,-1)+1
|
||||||
|
\family default
|
||||||
|
to add one to the value of the cell just above.
|
||||||
|
Then you can fill that expression down and get your column of consecutive
|
||||||
|
numbers.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
But these sorts of relative expressions only keep working if the cells move
|
||||||
|
together with the cells they refer to.
|
||||||
|
If for example you have a row of cells that are all referring to the row
|
||||||
|
above with a relative reference (like
|
||||||
|
\family sans
|
||||||
|
R(,-1)
|
||||||
|
\family default
|
||||||
|
) and you insert another row in between them, your references will be all
|
||||||
|
messed up.
|
||||||
|
There is value to
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
Excel-style
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
references that can be used to fill and which also can move around while
|
||||||
|
still just
|
||||||
|
\begin_inset Quotes eld
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
referring to what you want.
|
||||||
|
\begin_inset Quotes erd
|
||||||
|
\end_inset
|
||||||
|
|
||||||
|
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
To provide for this need, teapot has a function
|
||||||
|
\family sans
|
||||||
|
X(SRC, REF)
|
||||||
|
\family default
|
||||||
|
to retrieve the value of the cell labeled
|
||||||
|
\family sans
|
||||||
|
SRC
|
||||||
|
\family default
|
||||||
|
|
||||||
|
\bar under
|
||||||
|
from
|
||||||
|
\bar default
|
||||||
|
the cell labeled
|
||||||
|
\family sans
|
||||||
|
REF
|
||||||
|
\family default
|
||||||
|
.
|
||||||
|
If the so-labeled cells move around (either the source or the reference)
|
||||||
|
it will still work.
|
||||||
|
This is not particularly useful in and of itself; what makes it useful
|
||||||
|
is that from a cell other than
|
||||||
|
\family sans
|
||||||
|
REF
|
||||||
|
\family default
|
||||||
|
, it gives you the value of the cell that stands in the same relation to
|
||||||
|
|
||||||
|
\family sans
|
||||||
|
SRC
|
||||||
|
\family default
|
||||||
|
as that cell stands to
|
||||||
|
\family sans
|
||||||
|
REF
|
||||||
|
\family default
|
||||||
|
.
|
||||||
|
So in the cell to the right of
|
||||||
|
\family sans
|
||||||
|
REF
|
||||||
|
\family default
|
||||||
|
, it will give you the value of the cell to the right of
|
||||||
|
\family sans
|
||||||
|
SRC
|
||||||
|
\family default
|
||||||
|
; in the cell below, it gives you the cell below
|
||||||
|
\family sans
|
||||||
|
SRC
|
||||||
|
\family default
|
||||||
|
, etc.
|
||||||
|
Now you can fill a block of cells around
|
||||||
|
\family sans
|
||||||
|
REF
|
||||||
|
\family default
|
||||||
|
with formulas contaning
|
||||||
|
\family sans
|
||||||
|
X(SRC,REF)
|
||||||
|
\family default
|
||||||
|
and they will refer to the analogous block of cells around
|
||||||
|
\family sans
|
||||||
|
SRC
|
||||||
|
\family default
|
||||||
|
.
|
||||||
|
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
Sometimes you want to make this kind of reference but fix one of the coordinates
|
||||||
|
but not the others;
|
||||||
|
\family sans
|
||||||
|
X()
|
||||||
|
\family default
|
||||||
|
has optional flags for this, as well, so that
|
||||||
|
\family sans
|
||||||
|
X(SRC,REF,,,1)
|
||||||
|
\family default
|
||||||
|
will always be on the same layer as
|
||||||
|
\family sans
|
||||||
|
SRC
|
||||||
|
\family default
|
||||||
|
regardless of what layer it is called from or what layer
|
||||||
|
\family sans
|
||||||
|
REF
|
||||||
|
\family default
|
||||||
|
is on.
|
||||||
|
Thus
|
||||||
|
\family sans
|
||||||
|
X(SRC,REF,1,1,1)
|
||||||
|
\family default
|
||||||
|
is just
|
||||||
|
\family sans
|
||||||
|
@(SRC)
|
||||||
|
\family default
|
||||||
|
, but the intent of the latter is much clearer.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
You might ask as a follow-up question: Isnt
|
||||||
|
\family sans
|
||||||
|
X(SRC, REF)
|
||||||
|
\family default
|
||||||
|
much more cumbersome than just referring to cells by coordinate and then
|
||||||
|
letting Excel just do the right thing as you copy and move either that
|
||||||
|
formula or the referred-to data? The response to this is that in a typical
|
||||||
|
spreadsheet, there are only a small number of fundamental references, and
|
||||||
|
all other references derive from them in this way.
|
||||||
|
So you generally only need a few labels, and by taking just a little extra
|
||||||
|
time to apply those labels and refer to them in initial formulas, you are
|
||||||
|
making the semantics of your references much clearer and in essence documenting
|
||||||
|
them within your spreadsheet.
|
||||||
|
This extra effort will therefore be repaid in an easier-to-use, easier-to-under
|
||||||
|
stand, and easier-to-maintain and update spreadsheet.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
\end_body
|
\end_body
|
||||||
\end_document
|
\end_document
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
extern char *strdup(const char* s);
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
@ -44,26 +45,40 @@ Token tcopy(Token n)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* tfree -- free dynamic data of token */ /*{{{*/
|
/* tfree -- free dynamic data of token */ /*{{{*/
|
||||||
void tfree(Token *n)
|
void tfree(Token *n)
|
||||||
{
|
{
|
||||||
if (n->type==STRING)
|
Token fake;
|
||||||
|
fake.type = INT;
|
||||||
|
tfree_protected(n, fake);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
/* tfree_protected -- free dynamic data of token but not if same as protected */ /*{{{*/
|
||||||
|
void tfree_protected(Token *n, const Token dontfree)
|
||||||
|
{
|
||||||
|
if (n->type == STRING &&
|
||||||
|
(dontfree.type != STRING || n->u.string != dontfree.u.string))
|
||||||
{
|
{
|
||||||
free(n->u.string);
|
free(n->u.string);
|
||||||
n->u.string=(char*)0;
|
n->u.string=(char*)0;
|
||||||
}
|
}
|
||||||
else if (n->type==EEK)
|
else if (n->type == EEK &&
|
||||||
|
(dontfree.type != EEK || n->u.err != dontfree.u.err))
|
||||||
{
|
{
|
||||||
free(n->u.err);
|
free(n->u.err);
|
||||||
n->u.err=(char*)0;
|
n->u.err=(char*)0;
|
||||||
}
|
}
|
||||||
else if (n->type==LIDENT)
|
else if (n->type==LIDENT &&
|
||||||
|
(dontfree.type != LIDENT || n->u.lident != dontfree.u.lident))
|
||||||
{
|
{
|
||||||
free(n->u.lident);
|
free(n->u.lident);
|
||||||
n->u.lident=(char*)0;
|
n->u.lident=(char*)0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* tvecfreetoks -- free the tokens in vector of pointer to tokens */ /*{{{*/
|
/* tvecfreetoks -- free the tokens in vector of pointer to tokens */ /*{{{*/
|
||||||
void tvecfreetoks(Token **tvec)
|
void tvecfreetoks(Token **tvec)
|
||||||
{
|
{
|
||||||
@ -177,7 +192,7 @@ Token tadd(Token l, Token r)
|
|||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
len = strlen(_("wrong types for + operator"));
|
len = strlen(_("wrong types for + operator"));
|
||||||
buf = malloc(len + 128);
|
buf = malloc(len + 5 + 2*MAX_TYPE_NAME_LENGTH + 1);
|
||||||
strcpy(buf, _("wrong types for + operator"));
|
strcpy(buf, _("wrong types for + operator"));
|
||||||
snprintf(buf + len, 128, ": %s + %s", Type_Name[l.type], Type_Name[r.type]);
|
snprintf(buf + len, 128, ": %s + %s", Type_Name[l.type], Type_Name[r.type]);
|
||||||
result.u.err = buf;
|
result.u.err = buf;
|
||||||
@ -706,6 +721,17 @@ Token tfuncall(Token *ident, int argc, Token argv[])
|
|||||||
return tfunc[ident->u.fident].func(argc, argv);
|
return tfunc[ident->u.fident].func(argc, argv);
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
|
static Token relational_type_mismatch(Type l, Type r)
|
||||||
|
{
|
||||||
|
Token mismatch;
|
||||||
|
mismatch.type = EEK;
|
||||||
|
char *templ = _("Type mismatch: cannot compare %s and %s");
|
||||||
|
mismatch.u.err = malloc(strlen(templ) + 2*MAX_TYPE_NAME_LENGTH + 1);
|
||||||
|
sprintf(mismatch.u.err, templ, Type_Name[l], Type_Name[r]);
|
||||||
|
return mismatch;
|
||||||
|
}
|
||||||
|
|
||||||
/* tlt -- < operator */ /*{{{*/
|
/* tlt -- < operator */ /*{{{*/
|
||||||
Token tlt(Token l, Token r)
|
Token tlt(Token l, Token r)
|
||||||
{
|
{
|
||||||
@ -787,12 +813,7 @@ Token tlt(Token l, Token r)
|
|||||||
if (len < 3) result.u.integer = 0;
|
if (len < 3) result.u.integer = 0;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
else /* return < type error */ /*{{{*/
|
else return relational_type_mismatch(l.type, r.type);
|
||||||
{
|
|
||||||
result.type=EEK;
|
|
||||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -881,12 +902,7 @@ Token tle(Token l, Token r)
|
|||||||
if (len < 3) result.u.integer = 0;
|
if (len < 3) result.u.integer = 0;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
else /* result is <= type error */ /*{{{*/
|
else return relational_type_mismatch(l.type, r.type);
|
||||||
{
|
|
||||||
result.type=EEK;
|
|
||||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -969,12 +985,7 @@ Token tge(Token l, Token r)
|
|||||||
if (len < 3) result.u.integer = 0;
|
if (len < 3) result.u.integer = 0;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
else /* return >= type error */ /*{{{*/
|
else return relational_type_mismatch(l.type, r.type);
|
||||||
{
|
|
||||||
result.type=EEK;
|
|
||||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -1058,12 +1069,7 @@ Token tgt(Token l, Token r)
|
|||||||
else if (r.u.location[len] < l.u.location[len]) ++result.u.integer;
|
else if (r.u.location[len] < l.u.location[len]) ++result.u.integer;
|
||||||
if (len < 3) result.u.integer = 0;
|
if (len < 3) result.u.integer = 0;
|
||||||
}
|
}
|
||||||
/*}}}*/ else /* result is relation op type error */ /*{{{*/
|
else return relational_type_mismatch(l.type, r.type);
|
||||||
{
|
|
||||||
result.type=EEK;
|
|
||||||
result.u.err=mystrmalloc(_("type mismatch for relational operator"));
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -1148,14 +1154,11 @@ Token teq(Token l, Token r)
|
|||||||
if (len < 3) result.u.integer = 0;
|
if (len < 3) result.u.integer = 0;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
else
|
else return relational_type_mismatch(l.type, r.type);
|
||||||
{
|
|
||||||
result.type=EEK;
|
|
||||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* tabouteq -- ~= operator */ /*{{{*/
|
/* tabouteq -- ~= operator */ /*{{{*/
|
||||||
Token tabouteq(Token l, Token r)
|
Token tabouteq(Token l, Token r)
|
||||||
{
|
{
|
||||||
@ -1195,7 +1198,7 @@ Token tabouteq(Token l, Token r)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
result.u.err = strdup(_("Usage: ~= only compares float values"));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1278,11 +1281,7 @@ Token tne(Token l, Token r)
|
|||||||
for (len = 0; len < 3 && l.u.location[len] == r.u.location[len]; ++len);
|
for (len = 0; len < 3 && l.u.location[len] == r.u.location[len]; ++len);
|
||||||
if (len < 3) result.u.integer = 1;
|
if (len < 3) result.u.integer = 1;
|
||||||
}
|
}
|
||||||
else
|
else return relational_type_mismatch(l.type, r.type);
|
||||||
{
|
|
||||||
result.type=EEK;
|
|
||||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
Token tcopy(Token n);
|
Token tcopy(Token n);
|
||||||
void tfree(Token *n);
|
void tfree(Token *n);
|
||||||
|
void tfree_protected(Token *n, const Token dontfree);
|
||||||
void tvecfreetoks(Token **tvec);
|
void tvecfreetoks(Token **tvec);
|
||||||
void tvecfree(Token **tvec);
|
void tvecfree(Token **tvec);
|
||||||
size_t tveclen(Token **tvec);
|
size_t tveclen(Token **tvec);
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
|
extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
extern char *strdup(const char* s);
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@ -303,7 +304,9 @@ static double deg2rad(double x)
|
|||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
typedef enum {ABSOLUTE, RELATIVE} LocConvention;
|
typedef enum {ABSOLUTE, RELATIVE, EXCEL} LocConvention;
|
||||||
|
|
||||||
|
static Token excel_adr_func(int argc, const Token argv[]);
|
||||||
|
|
||||||
/* & */ /*{{{*/
|
/* & */ /*{{{*/
|
||||||
static Token adr_func(int argc, const Token argv[], LocConvention lcon)
|
static Token adr_func(int argc, const Token argv[], LocConvention lcon)
|
||||||
@ -314,20 +317,23 @@ static Token adr_func(int argc, const Token argv[], LocConvention lcon)
|
|||||||
size_t i;
|
size_t i;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
|
if (lcon == EXCEL) return excel_adr_func(argc, argv);
|
||||||
|
|
||||||
/* asserts */ /*{{{*/
|
/* asserts */ /*{{{*/
|
||||||
assert(argv != (Token*)0);
|
assert(argv != (Token*)0);
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
LOCATION_GETS(result.u.location, upd_l);
|
LOCATION_GETS(result.u.location, upd_l);
|
||||||
if (argc == 1 && argv[0].type == LOCATION)
|
if (argc == 1 && argv[0].type == LOCATION)
|
||||||
if (lcon == ABSOLUTE) return argv[0];
|
if (lcon == ABSOLUTE) return argv[0];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOCATION_ADD(result.u.location, argv[0].u.location);
|
LOCATION_ADD(result.u.location, argv[0].u.location);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
for (i = 0; i < argc && i < HYPER; ++i)
|
for (i = 0; i < argc && i < HYPER; ++i)
|
||||||
{
|
{
|
||||||
|
if (argv[0].type == EEK) return argv[0];
|
||||||
if (argv[i].type == INT)
|
if (argv[i].type == INT)
|
||||||
if (lcon == ABSOLUTE) result.u.location[i] = argv[i].u.integer;
|
if (lcon == ABSOLUTE) result.u.location[i] = argv[i].u.integer;
|
||||||
else result.u.location[i] += argv[i].u.integer;
|
else result.u.location[i] += argv[i].u.integer;
|
||||||
@ -355,9 +361,15 @@ static Token at_func(int argc, const Token argv[], LocConvention lcon)
|
|||||||
Token result;
|
Token result;
|
||||||
result.type = EEK;
|
result.type = EEK;
|
||||||
char *pref = _("Inside @: ");
|
char *pref = _("Inside @: ");
|
||||||
|
if (lcon == RELATIVE) pref = _("Inside R(): ");
|
||||||
|
if (lcon == EXCEL) pref = _("Inside X(): ");
|
||||||
result.u.err = malloc(strlen(location.u.err) + strlen(pref) + 1);
|
result.u.err = malloc(strlen(location.u.err) + strlen(pref) + 1);
|
||||||
strcpy(result.u.err, pref);
|
strcpy(result.u.err, pref);
|
||||||
strcat(result.u.err, location.u.err);
|
strcat(result.u.err, location.u.err);
|
||||||
|
/* don't free the location if it is the same as an argument, because
|
||||||
|
those get freed later: */
|
||||||
|
for (size_t i = 0; i < argc; ++i)
|
||||||
|
if (argv[i].type == EEK & argv[i].u.err == location.u.err) return result;
|
||||||
tfree(&location);
|
tfree(&location);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -384,106 +396,104 @@ static Token rel_at_func(int argc, const Token argv[])
|
|||||||
return at_func(argc, argv, RELATIVE);
|
return at_func(argc, argv, RELATIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* x */ /*{{{*/
|
static Token excel_at_func(int argc, const Token argv[])
|
||||||
static Token x_func(int argc, const Token argv[])
|
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
return at_func(argc, argv, EXCEL);
|
||||||
Token result;
|
}
|
||||||
/*}}}*/
|
|
||||||
|
|
||||||
if (argc==0)
|
#define INTPATIBLE(t) (t.type == INT || t.type == EMPTY)
|
||||||
/* result is currently updated x position */ /*{{{*/
|
|
||||||
{
|
static Token excel_adr_func(int argc, const Token argv[])
|
||||||
result.type = INT;
|
{
|
||||||
result.u.integer = upd_l[X];
|
Token result;
|
||||||
|
char *usage = _("Usage: X&(THERE_LABEL, HERE_LABEL, [fix_x], [fix_y], [fix_z])");
|
||||||
|
if (argc < 2) {
|
||||||
|
result.type = EEK;
|
||||||
|
result.u.err = strdup(usage);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
if (argv[0].type == EEK) return argv[0];
|
||||||
else if (argc==1 && argv[0].type==LOCATION)
|
if (argv[1].type == EEK) return argv[1];
|
||||||
/* return x component of location */ /*{{{*/
|
if (argv[0].type != LOCATION || argv[1].type != LOCATION)
|
||||||
{
|
{
|
||||||
result.type = INT;
|
result.type = EEK;
|
||||||
result.u.integer = argv[0].u.location[X];
|
result.u.err = strdup(usage);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
|
||||||
else
|
LOCATION_GETS(result.u.location, upd_l);
|
||||||
/* x type error */ /*{{{*/
|
|
||||||
|
for (Dimensions dim = X; dim < HYPER; ++dim)
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
int i = dim + 2;
|
||||||
result.u.err=strcpy(malloc(strlen(_("Usage: x([location])"))+1),_("Usage: x([location])"));
|
bool fixed = false;
|
||||||
|
if (i < argc)
|
||||||
|
{
|
||||||
|
if (argv[i].type == EEK) return argv[i];
|
||||||
|
if (!INTPATIBLE(argv[i]))
|
||||||
|
{
|
||||||
|
result.type = EEK;
|
||||||
|
result.u.err = strdup(usage);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (argv[i].type == INT && argv[i].u.integer > 0) fixed = true;
|
||||||
|
}
|
||||||
|
if (fixed) result.u.location[dim] = argv[0].u.location[dim];
|
||||||
|
else result.u.location[dim] +=
|
||||||
|
argv[0].u.location[dim] - argv[1].u.location[dim];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dim_func -- common implementation of the coordinate functions */ /*{{{*/
|
||||||
|
static Token dim_func(int argc, const Token argv[], Dimensions dim)
|
||||||
|
{
|
||||||
|
Token result;
|
||||||
|
result.type = INT;
|
||||||
|
|
||||||
|
if (argc == 0)
|
||||||
|
/* result is currently updated coordinate along dim */ /*{{{*/
|
||||||
|
result.u.integer = upd_l[dim];
|
||||||
|
/*}}}*/
|
||||||
|
else if (argc == 1 && argv[0].type == LOCATION)
|
||||||
|
/* return dim coordinate of location */ /*{{{*/
|
||||||
|
result.u.integer = argv[0].u.location[dim];
|
||||||
|
else /* type error */ /*{{{*/
|
||||||
|
{
|
||||||
|
result.type = EEK;
|
||||||
|
char *templ = _("Usage: %c([location])");
|
||||||
|
const char *DIMS = "xyz";
|
||||||
|
result.u.err = malloc(strlen(templ)+1);
|
||||||
|
sprintf(result.u.err, templ, DIMS[dim]);
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
/*}}}/
|
||||||
|
|
||||||
|
/* x */ /*{{{*/
|
||||||
|
static Token x_func(int argc, const Token argv[])
|
||||||
|
{
|
||||||
|
return dim_func(argc, argv, X);
|
||||||
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* y */ /*{{{*/
|
/* y */ /*{{{*/
|
||||||
static Token y_func(int argc, const Token argv[])
|
static Token y_func(int argc, const Token argv[])
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
return dim_func(argc, argv, Y);
|
||||||
Token result;
|
|
||||||
/*}}}*/
|
|
||||||
|
|
||||||
if (argc==0)
|
|
||||||
/* result is currently updated y position */ /*{{{*/
|
|
||||||
{
|
|
||||||
result.type = INT;
|
|
||||||
result.u.integer = upd_l[Y];
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
else if (argc==1 && argv[0].type==LOCATION)
|
|
||||||
/* return y component of location */ /*{{{*/
|
|
||||||
{
|
|
||||||
result.type = INT;
|
|
||||||
result.u.integer = argv[0].u.location[Y];
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
else
|
|
||||||
/* y type error */ /*{{{*/
|
|
||||||
{
|
|
||||||
result.type=EEK;
|
|
||||||
result.u.err=strcpy(malloc(strlen(_("Usage: y([location])"))+1),_("Usage: y([location])"));
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
/* z */ /*{{{*/
|
/* z */ /*{{{*/
|
||||||
static Token z_func(int argc, const Token argv[])
|
static Token z_func(int argc, const Token argv[])
|
||||||
{
|
{
|
||||||
/* variables */ /*{{{*/
|
return dim_func(argc, argv, Z);
|
||||||
Token result;
|
|
||||||
/*}}}*/
|
|
||||||
|
|
||||||
if (argc==0)
|
|
||||||
/* result is currently updated z position */ /*{{{*/
|
|
||||||
{
|
|
||||||
result.type = INT;
|
|
||||||
result.u.integer = upd_l[Z];
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
else if (argc == 1 && argv[0].type == LOCATION)
|
|
||||||
/* return z component of location */ /*{{{*/
|
|
||||||
{
|
|
||||||
result.type = INT;
|
|
||||||
result.u.integer = argv[0].u.location[Z];
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
else
|
|
||||||
/* result is z type error */ /*{{{*/
|
|
||||||
{
|
|
||||||
result.type=EEK;
|
|
||||||
result.u.err=mystrmalloc(_("Usage: z([location])"));
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
typedef enum { LOG_AND, LOG_OR } LogicalFunction;
|
typedef enum { LOG_AND, LOG_OR } LogicalFunction;
|
||||||
|
|
||||||
#define INTPATIBLE(t) (t.type == INT || t.type == EMPTY)
|
|
||||||
|
|
||||||
static Token bitwise_func(int argc, const Token argv[], LogicalFunction lop)
|
static Token bitwise_func(int argc, const Token argv[], LogicalFunction lop)
|
||||||
{
|
{
|
||||||
Token result;
|
Token result;
|
||||||
@ -495,7 +505,7 @@ static Token bitwise_func(int argc, const Token argv[], LogicalFunction lop)
|
|||||||
{
|
{
|
||||||
result.type = EEK;
|
result.type = EEK;
|
||||||
result.u.err =
|
result.u.err =
|
||||||
mystrmalloc(_("Bitwise functions operate only on integers."));
|
strdup(_("Bitwise functions operate only on integers."));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
int val = 0;
|
int val = 0;
|
||||||
@ -534,7 +544,7 @@ static Token e_func(int argc, const Token argv[])
|
|||||||
else /* result is e type error */ /*{{{*/
|
else /* result is e type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: e()"));
|
result.u.err=strdup(_("Usage: e()"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
@ -552,7 +562,7 @@ static Token eval_func(int argc, const Token argv[])
|
|||||||
/* nesting error */ /*{{{*/
|
/* nesting error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("nested eval()"));
|
result.u.err=strdup(_("nested eval()"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
else if (argc==1 && argv[0].type==LOCATION)
|
else if (argc==1 && argv[0].type==LOCATION)
|
||||||
@ -806,12 +816,12 @@ static Token int_func(int argc, const Token argv[])
|
|||||||
if (s==(char*)0 || *s)
|
if (s==(char*)0 || *s)
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("int(string): invalid string"));
|
result.u.err=strdup(_("int(string): invalid string"));
|
||||||
}
|
}
|
||||||
else if (errno==ERANGE && (result.u.integer==LONG_MAX || result.u.integer==LONG_MIN))
|
else if (errno==ERANGE && (result.u.integer==LONG_MAX || result.u.integer==LONG_MIN))
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("int(string): domain error"));
|
result.u.err=strdup(_("int(string): domain error"));
|
||||||
}
|
}
|
||||||
else result.type=INT;
|
else result.type=INT;
|
||||||
}
|
}
|
||||||
@ -869,7 +879,7 @@ static Token len_func(int argc, const Token argv[])
|
|||||||
/* result is frac type error */ /*{{{*/
|
/* result is frac type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: len(string)"));
|
result.u.err=strdup(_("Usage: len(string)"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
@ -912,7 +922,7 @@ static Token log_func(int argc, const Token argv[])
|
|||||||
else /* result is log type error */ /*{{{*/
|
else /* result is log type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: log(float[,float])"));
|
result.u.err=strdup(_("Usage: log(float[,float])"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
@ -998,7 +1008,7 @@ static Token minmax_func(int argc, const Token argv[], int min)
|
|||||||
/* result is min/max type error */ /*{{{*/
|
/* result is min/max type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(min ? _("Usage: min(location,location) or min(val1, val2,...)") : _("Usage: max(location,location) or max(val1,val2,...)"));
|
result.u.err=strdup(min ? _("Usage: min(location,location) or min(val1, val2,...)") : _("Usage: max(location,location) or max(val1,val2,...)"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -1041,7 +1051,7 @@ static Token abs_func(int argc, const Token argv[])
|
|||||||
/* result is abs type error */ /*{{{*/
|
/* result is abs type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: abs(float|integer)"));
|
result.u.err=strdup(_("Usage: abs(float|integer)"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
@ -1060,12 +1070,12 @@ static Token env_func(int argc, const Token argv[])
|
|||||||
|
|
||||||
if ((e=getenv(argv[0].u.string))==(char*)0) e="";
|
if ((e=getenv(argv[0].u.string))==(char*)0) e="";
|
||||||
result.type=STRING;
|
result.type=STRING;
|
||||||
result.u.string=mystrmalloc(e);
|
result.u.string=strdup(e);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: $(string)"));
|
result.u.err=strdup(_("Usage: $(string)"));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1088,7 +1098,7 @@ static Token float_func(int argc, const Token argv[])
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Not a (finite) floating point number"));
|
result.u.err=strdup(_("Not a (finite) floating point number"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -1096,7 +1106,7 @@ static Token float_func(int argc, const Token argv[])
|
|||||||
/* float type error */ /*{{{*/
|
/* float type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: float(string)"));
|
result.u.err=strdup(_("Usage: float(string)"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
@ -1119,7 +1129,7 @@ static Token strftime_func(int argc, const Token argv[])
|
|||||||
tm=localtime(&t);
|
tm=localtime(&t);
|
||||||
strftime(s,sizeof(s),argv[0].u.string,tm);
|
strftime(s,sizeof(s),argv[0].u.string,tm);
|
||||||
s[sizeof(s)-1]='\0';
|
s[sizeof(s)-1]='\0';
|
||||||
result.u.string=mystrmalloc(s);
|
result.u.string=strdup(s);
|
||||||
result.type=STRING;
|
result.type=STRING;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -1133,14 +1143,14 @@ static Token strftime_func(int argc, const Token argv[])
|
|||||||
tm=localtime(&t);
|
tm=localtime(&t);
|
||||||
strftime(s,sizeof(s),argv[0].u.string,tm);
|
strftime(s,sizeof(s),argv[0].u.string,tm);
|
||||||
s[sizeof(s)-1]='\0';
|
s[sizeof(s)-1]='\0';
|
||||||
result.u.string=mystrmalloc(s);
|
result.u.string=strdup(s);
|
||||||
result.type=STRING;
|
result.type=STRING;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
else /* strftime type error */ /*{{{*/
|
else /* strftime type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: strftime(string[,integer])"));
|
result.u.err=strdup(_("Usage: strftime(string[,integer])"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
@ -1184,7 +1194,7 @@ static Token clock_func(int argc, const Token argv[])
|
|||||||
else /* wrong usage */ /*{{{*/
|
else /* wrong usage */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: clock(condition,location[,location])"));
|
result.u.err=strdup(_("Usage: clock(condition,location[,location])"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
@ -1322,7 +1332,7 @@ static Token rnd_func(int argc, const Token argv[])
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: rnd()"));
|
result.u.err=strdup(_("Usage: rnd()"));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1351,7 +1361,7 @@ static Token substr_func(int argc, const Token argv[])
|
|||||||
ss[n] = '\0';
|
ss[n] = '\0';
|
||||||
strncpy(ss, argv[0].u.string + b, n);
|
strncpy(ss, argv[0].u.string + b, n);
|
||||||
result.type=STRING;
|
result.type=STRING;
|
||||||
result.u.string=mystrmalloc(ss);
|
result.u.string=strdup(ss);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result.type=EMPTY;
|
result.type=EMPTY;
|
||||||
@ -1360,7 +1370,7 @@ static Token substr_func(int argc, const Token argv[])
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: substr(string,integer,integer)"));
|
result.u.err=strdup(_("Usage: substr(string,integer,integer)"));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1387,7 +1397,7 @@ static Token strptime_func(int argc, const Token argv[])
|
|||||||
else /* strftime type error */ /*{{{*/
|
else /* strftime type error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: strptime(string,string)"));
|
result.u.err=strdup(_("Usage: strptime(string,string)"));
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
return result;
|
return result;
|
||||||
@ -1406,7 +1416,7 @@ static Token time_func(int argc, const Token argv[])
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Usage: time()"));
|
result.u.err=strdup(_("Usage: time()"));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1460,8 +1470,10 @@ Tfunc tfunc[]=
|
|||||||
{ "time", time_func },
|
{ "time", time_func },
|
||||||
{ "bitand", bitand_func },
|
{ "bitand", bitand_func },
|
||||||
{ "bitor", bitor_func },
|
{ "bitor", bitor_func },
|
||||||
{ "D", rel_adr_func },
|
|
||||||
{ "R", rel_at_func },
|
{ "R", rel_at_func },
|
||||||
|
{ "D", rel_adr_func },
|
||||||
|
{ "X", excel_at_func },
|
||||||
|
{ "X&", excel_adr_func },
|
||||||
{ "", (Token (*)(int, const Token[]))0 }
|
{ "", (Token (*)(int, const Token[]))0 }
|
||||||
};
|
};
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind,opterr,optopt;
|
extern int optind,opterr,optopt;
|
||||||
int getopt(int argc, char * const *argv, const char *optstring);
|
int getopt(int argc, char * const *argv, const char *optstring);
|
||||||
|
extern char *strdup(const char* s);
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -680,9 +681,9 @@ static int do_savecsv(Sheet *cursheet, const char *name)
|
|||||||
MenuChoice menu[4];
|
MenuChoice menu[4];
|
||||||
name = cursheet->name;
|
name = cursheet->name;
|
||||||
|
|
||||||
menu[0].str=mystrmalloc(_("cC)omma (,)")); menu[0].c='\0';
|
menu[0].str=strdup(_("cC)omma (,)")); menu[0].c='\0';
|
||||||
menu[1].str=mystrmalloc(_("sS)emicolon (;)")); menu[1].c='\0';
|
menu[1].str=strdup(_("sS)emicolon (;)")); menu[1].c='\0';
|
||||||
menu[2].str=mystrmalloc(_("tT)ab (\\t)")); menu[2].c='\0';
|
menu[2].str=strdup(_("tT)ab (\\t)")); menu[2].c='\0';
|
||||||
menu[3].str=(char*)0;
|
menu[3].str=(char*)0;
|
||||||
sep=line_menu(_("Choose separator:"),menu,0);
|
sep=line_menu(_("Choose separator:"),menu,0);
|
||||||
if (sep < 0) return sep;
|
if (sep < 0) return sep;
|
||||||
@ -912,9 +913,9 @@ static int do_insert(Sheet *sheet)
|
|||||||
{
|
{
|
||||||
MenuChoice menu[4];
|
MenuChoice menu[4];
|
||||||
|
|
||||||
menu[0].str=mystrmalloc(_("cC)olumn")); menu[0].c='\0';
|
menu[0].str=strdup(_("cC)olumn")); menu[0].c='\0';
|
||||||
menu[1].str=mystrmalloc(_("rR)ow")); menu[1].c='\0';
|
menu[1].str=strdup(_("rR)ow")); menu[1].c='\0';
|
||||||
menu[2].str=mystrmalloc(_("dD)epth")); menu[2].c='\0';
|
menu[2].str=strdup(_("dD)epth")); menu[2].c='\0';
|
||||||
menu[3].str=(char*)0;
|
menu[3].str=(char*)0;
|
||||||
reply=line_menu(_("Insert:"),menu,0);
|
reply=line_menu(_("Insert:"),menu,0);
|
||||||
free(menu[0].str);
|
free(menu[0].str);
|
||||||
@ -938,12 +939,12 @@ static int do_insert(Sheet *sheet)
|
|||||||
/* show menu */ /*{{{*/
|
/* show menu */ /*{{{*/
|
||||||
switch (reply)
|
switch (reply)
|
||||||
{
|
{
|
||||||
case 0: menu[0].str=mystrmalloc(_("wW)hole column")); break;
|
case 0: menu[0].str=strdup(_("wW)hole column")); break;
|
||||||
case 1: menu[0].str=mystrmalloc(_("wW)hole line")); break;
|
case 1: menu[0].str=strdup(_("wW)hole line")); break;
|
||||||
case 2: menu[0].str=mystrmalloc(_("wW)hole sheet")); break;
|
case 2: menu[0].str=strdup(_("wW)hole sheet")); break;
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
}
|
}
|
||||||
menu[1].str=mystrmalloc(_("sS)ingle cell")); menu[1].c='\0';
|
menu[1].str=strdup(_("sS)ingle cell")); menu[1].c='\0';
|
||||||
menu[2].str=(char*)0;
|
menu[2].str=(char*)0;
|
||||||
r=line_menu(_("Insert:"),menu,0);
|
r=line_menu(_("Insert:"),menu,0);
|
||||||
free(menu[0].str);
|
free(menu[0].str);
|
||||||
@ -1029,9 +1030,9 @@ static int do_delete(Sheet *sheet)
|
|||||||
{
|
{
|
||||||
MenuChoice menu[4];
|
MenuChoice menu[4];
|
||||||
|
|
||||||
menu[0].str=mystrmalloc(_("cC)olumn")); menu[0].c='\0';
|
menu[0].str=strdup(_("cC)olumn")); menu[0].c='\0';
|
||||||
menu[1].str=mystrmalloc(_("rR)ow")); menu[1].c='\0';
|
menu[1].str=strdup(_("rR)ow")); menu[1].c='\0';
|
||||||
menu[2].str=mystrmalloc(_("dD)epth")); menu[2].c='\0';
|
menu[2].str=strdup(_("dD)epth")); menu[2].c='\0';
|
||||||
menu[3].str=(char*)0;
|
menu[3].str=(char*)0;
|
||||||
reply=line_menu(_("Delete:"),menu,0);
|
reply=line_menu(_("Delete:"),menu,0);
|
||||||
free(menu[0].str);
|
free(menu[0].str);
|
||||||
@ -1056,12 +1057,12 @@ static int do_delete(Sheet *sheet)
|
|||||||
/* show menu */ /*{{{*/
|
/* show menu */ /*{{{*/
|
||||||
switch (reply)
|
switch (reply)
|
||||||
{
|
{
|
||||||
case 0: menu[0].str=mystrmalloc(_("wW)hole column")); break;
|
case 0: menu[0].str=strdup(_("wW)hole column")); break;
|
||||||
case 1: menu[0].str=mystrmalloc(_("wW)hole line")); break;
|
case 1: menu[0].str=strdup(_("wW)hole line")); break;
|
||||||
case 2: menu[0].str=mystrmalloc(_("wW)hole sheet")); break;
|
case 2: menu[0].str=strdup(_("wW)hole sheet")); break;
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
}
|
}
|
||||||
menu[1].str=mystrmalloc(_("sS)ingle cell")); menu[1].c='\0';
|
menu[1].str=strdup(_("sS)ingle cell")); menu[1].c='\0';
|
||||||
menu[2].str=(char*)0;
|
menu[2].str=(char*)0;
|
||||||
r=line_menu(_("Delete:"),menu,0);
|
r=line_menu(_("Delete:"),menu,0);
|
||||||
free(menu[0].str);
|
free(menu[0].str);
|
||||||
@ -1233,15 +1234,15 @@ static int do_sort(Sheet *sheet)
|
|||||||
|
|
||||||
do_mark(sheet, GET_MARK_ALL);
|
do_mark(sheet, GET_MARK_ALL);
|
||||||
/* build menues */ /*{{{*/
|
/* build menues */ /*{{{*/
|
||||||
menu1[0].str=mystrmalloc(_("cC)olumn")); menu1[0].c='\0';
|
menu1[0].str=strdup(_("cC)olumn")); menu1[0].c='\0';
|
||||||
menu1[1].str=mystrmalloc(_("rR)ow")); menu1[1].c='\0';
|
menu1[1].str=strdup(_("rR)ow")); menu1[1].c='\0';
|
||||||
menu1[2].str=mystrmalloc(_("dD)epth")); menu1[2].c='\0';
|
menu1[2].str=strdup(_("dD)epth")); menu1[2].c='\0';
|
||||||
menu1[3].str=(char*)0;
|
menu1[3].str=(char*)0;
|
||||||
menu2[0].str=mystrmalloc(_("sS)ort region")); menu2[0].c='\0';
|
menu2[0].str=strdup(_("sS)ort region")); menu2[0].c='\0';
|
||||||
menu2[1].str=mystrmalloc(_("aA)dd key")); menu2[1].c='\0';
|
menu2[1].str=strdup(_("aA)dd key")); menu2[1].c='\0';
|
||||||
menu2[2].str=(char*)0;
|
menu2[2].str=(char*)0;
|
||||||
menu3[0].str=mystrmalloc(_("aA)scending")); menu3[0].c='\0';
|
menu3[0].str=strdup(_("aA)scending")); menu3[0].c='\0';
|
||||||
menu3[1].str=mystrmalloc(_("dD)escending")); menu3[0].c='\0';
|
menu3[1].str=strdup(_("dD)escending")); menu3[0].c='\0';
|
||||||
menu3[2].str=(char*)0;
|
menu3[2].str=(char*)0;
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
|
||||||
@ -1453,9 +1454,9 @@ static int do_mirror(Sheet *sheet)
|
|||||||
{
|
{
|
||||||
MenuChoice menu[4];
|
MenuChoice menu[4];
|
||||||
|
|
||||||
menu[0].str=mystrmalloc(_("lL)eft-right")); menu[0].c='\0';
|
menu[0].str=strdup(_("lL)eft-right")); menu[0].c='\0';
|
||||||
menu[1].str=mystrmalloc(_("uU)pside-down")); menu[1].c='\0';
|
menu[1].str=strdup(_("uU)pside-down")); menu[1].c='\0';
|
||||||
menu[2].str=mystrmalloc(_("fF)ront-back")); menu[2].c='\0';
|
menu[2].str=strdup(_("fF)ront-back")); menu[2].c='\0';
|
||||||
menu[3].str=(char*)0;
|
menu[3].str=(char*)0;
|
||||||
reply=line_menu(_("Mirror block:"),menu,0);
|
reply=line_menu(_("Mirror block:"),menu,0);
|
||||||
free(menu[0].str);
|
free(menu[0].str);
|
||||||
@ -1882,7 +1883,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
|
||||||
cursheet->name=mystrmalloc(loadfile);
|
cursheet->name=strdup(loadfile);
|
||||||
if (usexdr)
|
if (usexdr)
|
||||||
{
|
{
|
||||||
if ((msg=loadxdr(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from XDR file:"),msg);
|
if ((msg=loadxdr(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from XDR file:"),msg);
|
||||||
|
@ -88,12 +88,7 @@ void posorder(int *x, int *y)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
/* mystrmalloc -- return malloced copy of string */ /*{{{*/
|
|
||||||
char *mystrmalloc(const char *str)
|
|
||||||
{
|
|
||||||
return (strcpy(malloc(strlen(str)+1),str));
|
|
||||||
}
|
|
||||||
/*}}}*/
|
|
||||||
/* finite -- return error message about number or null */ /*{{{*/
|
/* finite -- return error message about number or null */ /*{{{*/
|
||||||
static volatile int caughtfpe;
|
static volatile int caughtfpe;
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ extern "C" {
|
|||||||
|
|
||||||
void posorder(int *x, int *y);
|
void posorder(int *x, int *y);
|
||||||
long int posnumber(const char *s, const char **endptr);
|
long int posnumber(const char *s, const char **endptr);
|
||||||
char *mystrmalloc(const char *str);
|
|
||||||
const char *dblfinite(double x);
|
const char *dblfinite(double 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);
|
||||||
|
@ -12,8 +12,10 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <float.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
extern char *strdup(const char* s);
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
@ -89,7 +91,7 @@ static Token primary(Token *n[], int *i)
|
|||||||
/* return error, value expected */ /*{{{*/
|
/* return error, value expected */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("value expected"));
|
result.u.err=strdup(_("value expected"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -153,8 +155,10 @@ static Token primary(Token *n[], int *i)
|
|||||||
/* eval function */ /*{{{*/
|
/* eval function */ /*{{{*/
|
||||||
{
|
{
|
||||||
++(*i);
|
++(*i);
|
||||||
result=tfuncall(ident,argc,argv);
|
result = tfuncall(ident,argc,argv);
|
||||||
for (j=0; j<argc; ++j) tfree(&argv[j]);
|
/* To allow a function to return one of its arguments, we need
|
||||||
|
to be sure not to free that argument: */
|
||||||
|
for (j=0; j<argc; ++j) tfree_protected(&argv[j], result);
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
else
|
else
|
||||||
@ -171,7 +175,7 @@ static Token primary(Token *n[], int *i)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("( expected"));
|
result.u.err=strdup(_("( expected"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +183,7 @@ static Token primary(Token *n[], int *i)
|
|||||||
default: ; /* fall through */
|
default: ; /* fall through */
|
||||||
}
|
}
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("value expected"));
|
result.u.err=strdup(_("value expected"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
@ -15,6 +15,7 @@ typedef enum {
|
|||||||
#endif
|
#endif
|
||||||
} Type;
|
} Type;
|
||||||
|
|
||||||
|
#define MAX_TYPE_NAME_LENGTH 16
|
||||||
extern const char *Type_Name[];
|
extern const char *Type_Name[];
|
||||||
|
|
||||||
typedef enum { PLUS, MINUS, MUL, DIV, OP, CP, COMMA, LT, LE, GE, GT, ISEQUAL, ABOUTEQ, NE, POW, MOD } Operator;
|
typedef enum { PLUS, MINUS, MUL, DIV, OP, CP, COMMA, LT, LE, GE, GT, ISEQUAL, ABOUTEQ, NE, POW, MOD } Operator;
|
||||||
|
@ -538,7 +538,9 @@ Token getvalue(Sheet *sheet, const Location at)
|
|||||||
/* return error */ /*{{{*/
|
/* return error */ /*{{{*/
|
||||||
{
|
{
|
||||||
result.type=EEK;
|
result.type=EEK;
|
||||||
result.u.err=mystrmalloc(_("Negative index"));
|
char *templ = _("Attempt to access cell at (%d,%d,%d) with negative index");
|
||||||
|
result.u.err = malloc(strlen(templ)+32);
|
||||||
|
sprintf(result.u.err, templ, at[X], at[Y], at[Z]);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -831,7 +833,10 @@ Token findlabel(Sheet *sheet, const char *label)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.type = EEK;
|
result.type = EEK;
|
||||||
result.u.err = mystrmalloc(_("No such label"));
|
char *pref = _("No such label: ");
|
||||||
|
result.u.err = malloc(strlen(pref) + strlen(label) + 1);
|
||||||
|
strcpy(result.u.err, pref);
|
||||||
|
strcat(result.u.err, label);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -860,7 +865,7 @@ void relabel(Sheet *sheet, const Location at,
|
|||||||
if ((*run)->type==LIDENT && strcmp((*run)->u.lident, oldlabel)==0)
|
if ((*run)->type==LIDENT && strcmp((*run)->u.lident, oldlabel)==0)
|
||||||
{
|
{
|
||||||
free((*run)->u.lident);
|
free((*run)->u.lident);
|
||||||
(*run)->u.lident = mystrmalloc(newlabel);
|
(*run)->u.lident = strdup(newlabel);
|
||||||
}
|
}
|
||||||
cachelabels(sheet);
|
cachelabels(sheet);
|
||||||
forceupdate(sheet);
|
forceupdate(sheet);
|
||||||
@ -1337,7 +1342,7 @@ const char *loadport(Sheet *sheet, const char *name)
|
|||||||
++ns;
|
++ns;
|
||||||
while (*ns && *ns!=' ') { *p=*ns; ++p; ++ns; }
|
while (*ns && *ns!=' ') { *p=*ns; ++p; ++ns; }
|
||||||
*p='\0';
|
*p='\0';
|
||||||
loaded.label=mystrmalloc(buf);
|
loaded.label=strdup(buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
@ -1683,7 +1688,7 @@ const char *loadcsv(Sheet *sheet, const char *name)
|
|||||||
if (s!=cend) /* ok, it is a string */ /*{{{*/
|
if (s!=cend) /* ok, it is a string */ /*{{{*/
|
||||||
{
|
{
|
||||||
t[0]->type=STRING;
|
t[0]->type=STRING;
|
||||||
t[0]->u.string=mystrmalloc(str);
|
t[0]->u.string=strdup(str);
|
||||||
putcont(sheet, where, t, BASE);
|
putcont(sheet, where, t, BASE);
|
||||||
}
|
}
|
||||||
/*}}}*/
|
/*}}}*/
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
extern char *strdup(const char *s);
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifdef OLD_REALLOC
|
#ifdef OLD_REALLOC
|
||||||
#define realloc(s,l) myrealloc(s,l)
|
#define realloc(s,l) myrealloc(s,l)
|
||||||
@ -891,7 +892,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
|
|||||||
t[0]=malloc(sizeof(Token));
|
t[0]=malloc(sizeof(Token));
|
||||||
t[1]=(Token*)0;
|
t[1]=(Token*)0;
|
||||||
t[0]->type=STRING;
|
t[0]->type=STRING;
|
||||||
t[0]->u.string=mystrmalloc(body+6);
|
t[0]->u.string=strdup(body+6);
|
||||||
putcont(sheet, tmp, t, BASE);
|
putcont(sheet, tmp, t, BASE);
|
||||||
format((unsigned char)body[0], cell);
|
format((unsigned char)body[0], cell);
|
||||||
break;
|
break;
|
||||||
@ -1098,7 +1099,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
|
|||||||
t[0]=malloc(sizeof(Token));
|
t[0]=malloc(sizeof(Token));
|
||||||
t[1]=(Token*)0;
|
t[1]=(Token*)0;
|
||||||
t[0]->type=STRING;
|
t[0]->type=STRING;
|
||||||
t[0]->u.string=mystrmalloc(body+5);
|
t[0]->u.string=strdup(body+5);
|
||||||
putcont(sheet, tmp, t, BASE);
|
putcont(sheet, tmp, t, BASE);
|
||||||
format((unsigned char)body[0], cell);
|
format((unsigned char)body[0], cell);
|
||||||
break;
|
break;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
extern char *strdup(const char* s);
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#ifdef NEED_BCOPY
|
#ifdef NEED_BCOPY
|
||||||
@ -66,21 +67,21 @@ static int do_attribute(Sheet *cursheet)
|
|||||||
int c;
|
int c;
|
||||||
|
|
||||||
/* create menus */
|
/* create menus */
|
||||||
adjmenu[0].str=mystrmalloc(_("lL)eft")); adjmenu[0].c='\0';
|
adjmenu[0].str=strdup(_("lL)eft")); adjmenu[0].c='\0';
|
||||||
adjmenu[1].str=mystrmalloc(_("rR)ight")); adjmenu[1].c='\0';
|
adjmenu[1].str=strdup(_("rR)ight")); adjmenu[1].c='\0';
|
||||||
adjmenu[2].str=mystrmalloc(_("cC)entered")); adjmenu[2].c='\0';
|
adjmenu[2].str=strdup(_("cC)entered")); adjmenu[2].c='\0';
|
||||||
adjmenu[3].str=mystrmalloc(_("11).23e1 <-> 12.3")); adjmenu[3].c='\0';
|
adjmenu[3].str=strdup(_("11).23e1 <-> 12.3")); adjmenu[3].c='\0';
|
||||||
adjmenu[4].str=mystrmalloc(_("pP)recision")); adjmenu[4].c='\0';
|
adjmenu[4].str=strdup(_("pP)recision")); adjmenu[4].c='\0';
|
||||||
adjmenu[5].str=mystrmalloc(_("sS)hadow")); adjmenu[5].c='\0';
|
adjmenu[5].str=strdup(_("sS)hadow")); adjmenu[5].c='\0';
|
||||||
adjmenu[6].str=mystrmalloc(_("bB)old")); adjmenu[6].c='\0';
|
adjmenu[6].str=strdup(_("bB)old")); adjmenu[6].c='\0';
|
||||||
adjmenu[7].str=mystrmalloc(_("uU)nderline")); adjmenu[7].c='\0';
|
adjmenu[7].str=strdup(_("uU)nderline")); adjmenu[7].c='\0';
|
||||||
adjmenu[8].str=mystrmalloc(_("oO)utput special characters")); adjmenu[8].c='\0';
|
adjmenu[8].str=strdup(_("oO)utput special characters")); adjmenu[8].c='\0';
|
||||||
adjmenu[9].str=(char*)0;
|
adjmenu[9].str=(char*)0;
|
||||||
|
|
||||||
mainmenu[0].str=mystrmalloc(_("rR)epresentation")); mainmenu[0].c='\0';
|
mainmenu[0].str=strdup(_("rR)epresentation")); mainmenu[0].c='\0';
|
||||||
mainmenu[1].str=mystrmalloc(_("lL)abel")); mainmenu[1].c='\0';
|
mainmenu[1].str=strdup(_("lL)abel")); mainmenu[1].c='\0';
|
||||||
mainmenu[2].str=mystrmalloc(_("oLo)ck")); mainmenu[2].c='\0';
|
mainmenu[2].str=strdup(_("oLo)ck")); mainmenu[2].c='\0';
|
||||||
mainmenu[3].str=mystrmalloc(_("iI)gnore")); mainmenu[3].c='\0';
|
mainmenu[3].str=strdup(_("iI)gnore")); mainmenu[3].c='\0';
|
||||||
mainmenu[4].str=(char*)0;
|
mainmenu[4].str=(char*)0;
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -155,9 +156,9 @@ static int do_file(Sheet *cursheet)
|
|||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
|
||||||
menu[0].str=mystrmalloc(_("lL)oad")); menu[0].c='\0';
|
menu[0].str=strdup(_("lL)oad")); menu[0].c='\0';
|
||||||
menu[1].str=mystrmalloc(_("sS)ave")); menu[1].c='\0';
|
menu[1].str=strdup(_("sS)ave")); menu[1].c='\0';
|
||||||
menu[2].str=mystrmalloc(_("nN)ame")); menu[2].c='\0';
|
menu[2].str=strdup(_("nN)ame")); menu[2].c='\0';
|
||||||
menu[3].str=(char*)0;
|
menu[3].str=(char*)0;
|
||||||
c=0;
|
c=0;
|
||||||
do
|
do
|
||||||
@ -257,14 +258,14 @@ static int do_block(Sheet *cursheet)
|
|||||||
MenuChoice block[9];
|
MenuChoice block[9];
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
block[0].str=mystrmalloc(_("ecle)ar")); block[0].c='\0';
|
block[0].str=strdup(_("ecle)ar")); block[0].c='\0';
|
||||||
block[1].str=mystrmalloc(_("iI)nsert")); block[1].c='\0';
|
block[1].str=strdup(_("iI)nsert")); block[1].c='\0';
|
||||||
block[2].str=mystrmalloc(_("dD)elete")); block[2].c='\0';
|
block[2].str=strdup(_("dD)elete")); block[2].c='\0';
|
||||||
block[3].str=mystrmalloc(_("mM)ove")); block[3].c='\0';
|
block[3].str=strdup(_("mM)ove")); block[3].c='\0';
|
||||||
block[4].str=mystrmalloc(_("cC)opy")); block[4].c='\0';
|
block[4].str=strdup(_("cC)opy")); block[4].c='\0';
|
||||||
block[5].str=mystrmalloc(_("fF)ill")); block[5].c='\0';
|
block[5].str=strdup(_("fF)ill")); block[5].c='\0';
|
||||||
block[6].str=mystrmalloc(_("sS)ort")); block[6].c='\0';
|
block[6].str=strdup(_("sS)ort")); block[6].c='\0';
|
||||||
block[7].str=mystrmalloc(_("rMir)ror")); block[7].c='\0';
|
block[7].str=strdup(_("rMir)ror")); block[7].c='\0';
|
||||||
block[8].str=(char*)0;
|
block[8].str=(char*)0;
|
||||||
c=0;
|
c=0;
|
||||||
do
|
do
|
||||||
@ -303,14 +304,14 @@ int show_menu(Sheet *cursheet)
|
|||||||
int c = K_INVALID;
|
int c = K_INVALID;
|
||||||
|
|
||||||
|
|
||||||
menu[0].str=mystrmalloc(_("aA)ttributes")); menu[0].c='\0';
|
menu[0].str=strdup(_("aA)ttributes")); menu[0].c='\0';
|
||||||
menu[1].str=mystrmalloc(_("wW)idth")); menu[1].c='\0';
|
menu[1].str=strdup(_("wW)idth")); menu[1].c='\0';
|
||||||
menu[2].str=mystrmalloc(_("bB)lock")); menu[2].c='\0';
|
menu[2].str=strdup(_("bB)lock")); menu[2].c='\0';
|
||||||
menu[3].str=mystrmalloc(_("fF)ile")); menu[3].c='\0';
|
menu[3].str=strdup(_("fF)ile")); menu[3].c='\0';
|
||||||
menu[4].str=mystrmalloc(_("gG)oto")); menu[4].c='\0';
|
menu[4].str=strdup(_("gG)oto")); menu[4].c='\0';
|
||||||
menu[5].str=mystrmalloc(_("sS)hell")); menu[5].c='\0';
|
menu[5].str=strdup(_("sS)hell")); menu[5].c='\0';
|
||||||
menu[6].str=mystrmalloc(_("vV)ersion")); menu[6].c='\0';
|
menu[6].str=strdup(_("vV)ersion")); menu[6].c='\0';
|
||||||
menu[7].str=mystrmalloc(_("qQ)uit")); menu[7].c='\0';
|
menu[7].str=strdup(_("qQ)uit")); menu[7].c='\0';
|
||||||
menu[8].str=(char*)0;
|
menu[8].str=(char*)0;
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -838,8 +839,8 @@ int line_ok(const char *prompt, int curx)
|
|||||||
|
|
||||||
assert(curx==0 || curx==1);
|
assert(curx==0 || curx==1);
|
||||||
|
|
||||||
menu[0].str=mystrmalloc(_("nN)o")); menu[0].c='\0';
|
menu[0].str=strdup(_("nN)o")); menu[0].c='\0';
|
||||||
menu[1].str=mystrmalloc(_("yY)es")); menu[1].c='\0';
|
menu[1].str=strdup(_("yY)es")); menu[1].c='\0';
|
||||||
menu[2].str=(char*)0;
|
menu[2].str=(char*)0;
|
||||||
result=line_menu(prompt,menu,curx);
|
result=line_menu(prompt,menu,curx);
|
||||||
free(menu[0].str);
|
free(menu[0].str);
|
||||||
|
Loading…
Reference in New Issue
Block a user