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
411
doc/teapot.lyx
411
doc/teapot.lyx
@ -4855,6 +4855,11 @@ Location Cell labels and the
|
||||
&()
|
||||
\family default
|
||||
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
|
||||
|
||||
\begin_layout Description
|
||||
@ -5041,7 +5046,7 @@ y
|
||||
x
|
||||
\family typewriter
|
||||
\emph default
|
||||
=
|
||||
~=
|
||||
\family default
|
||||
\emph on
|
||||
y
|
||||
@ -5489,7 +5494,8 @@ y
|
||||
z
|
||||
\emph default
|
||||
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
|
||||
|
||||
\begin_layout Description
|
||||
@ -5515,8 +5521,21 @@ relative.
|
||||
\begin_inset Quotes erd
|
||||
\end_inset
|
||||
|
||||
Thus R(-1) returns the value of the cell immediately to the left of this
|
||||
one.
|
||||
Thus
|
||||
\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
|
||||
|
||||
\begin_layout Description
|
||||
@ -5541,8 +5560,181 @@ displaced (by).
|
||||
\begin_inset Quotes erd
|
||||
\end_inset
|
||||
|
||||
Thus, D(-1) returns the location of the cell immediately to the left of
|
||||
this one.
|
||||
Thus,
|
||||
\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
|
||||
|
||||
\begin_layout Description
|
||||
@ -7264,8 +7456,22 @@ z
|
||||
position of the given location, of the currently updated cell if none is
|
||||
given.
|
||||
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
|
||||
|
||||
\begin_layout Subsection
|
||||
@ -7763,11 +7969,13 @@ X
|
||||
\end_layout
|
||||
|
||||
\begin_layout Quote
|
||||
eval(&((@(X)>=0)+x(BAD),y(BAD),z(BAD)))
|
||||
eval(BAD + &((@(X)>=0),0,0))
|
||||
\end_layout
|
||||
|
||||
\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
|
||||
BAD
|
||||
\family default
|
||||
@ -7786,5 +7994,190 @@ BAD
|
||||
|
||||
\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_document
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
extern char *strdup(const char* s);
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@ -44,26 +45,40 @@ Token tcopy(Token n)
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* tfree -- free dynamic data of token */ /*{{{*/
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
n->u.lident=(char*)0;
|
||||
}
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* tvecfreetoks -- free the tokens in vector of pointer to tokens */ /*{{{*/
|
||||
void tvecfreetoks(Token **tvec)
|
||||
{
|
||||
@ -177,7 +192,7 @@ Token tadd(Token l, Token r)
|
||||
{
|
||||
result.type=EEK;
|
||||
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"));
|
||||
snprintf(buf + len, 128, ": %s + %s", Type_Name[l.type], Type_Name[r.type]);
|
||||
result.u.err = buf;
|
||||
@ -706,6 +721,17 @@ Token tfuncall(Token *ident, int argc, Token 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 */ /*{{{*/
|
||||
Token tlt(Token l, Token r)
|
||||
{
|
||||
@ -787,12 +813,7 @@ Token tlt(Token l, Token r)
|
||||
if (len < 3) result.u.integer = 0;
|
||||
}
|
||||
/*}}}*/
|
||||
else /* return < type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
||||
}
|
||||
/*}}}*/
|
||||
else return relational_type_mismatch(l.type, r.type);
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -881,12 +902,7 @@ Token tle(Token l, Token r)
|
||||
if (len < 3) result.u.integer = 0;
|
||||
}
|
||||
/*}}}*/
|
||||
else /* result is <= type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
||||
}
|
||||
/*}}}*/
|
||||
else return relational_type_mismatch(l.type, r.type);
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -969,12 +985,7 @@ Token tge(Token l, Token r)
|
||||
if (len < 3) result.u.integer = 0;
|
||||
}
|
||||
/*}}}*/
|
||||
else /* return >= type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
||||
}
|
||||
/*}}}*/
|
||||
else return relational_type_mismatch(l.type, r.type);
|
||||
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;
|
||||
if (len < 3) result.u.integer = 0;
|
||||
}
|
||||
/*}}}*/ else /* result is relation op type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("type mismatch for relational operator"));
|
||||
}
|
||||
/*}}}*/
|
||||
else return relational_type_mismatch(l.type, r.type);
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1148,14 +1154,11 @@ Token teq(Token l, Token r)
|
||||
if (len < 3) result.u.integer = 0;
|
||||
}
|
||||
/*}}}*/
|
||||
else
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
||||
}
|
||||
else return relational_type_mismatch(l.type, r.type);
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* tabouteq -- ~= operator */ /*{{{*/
|
||||
Token tabouteq(Token l, Token r)
|
||||
{
|
||||
@ -1195,7 +1198,7 @@ Token tabouteq(Token l, Token r)
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -1278,11 +1281,7 @@ Token tne(Token l, Token r)
|
||||
for (len = 0; len < 3 && l.u.location[len] == r.u.location[len]; ++len);
|
||||
if (len < 3) result.u.integer = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=strcpy(malloc(strlen(_("type mismatch for relational operator"))+1),_("type mismatch for relational operator"));
|
||||
}
|
||||
else return relational_type_mismatch(l.type, r.type);
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
Token tcopy(Token n);
|
||||
void tfree(Token *n);
|
||||
void tfree_protected(Token *n, const Token dontfree);
|
||||
void tvecfreetoks(Token **tvec);
|
||||
void tvecfree(Token **tvec);
|
||||
size_t tveclen(Token **tvec);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <stdlib.h>
|
||||
extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
|
||||
#include <stdio.h>
|
||||
extern char *strdup(const char* s);
|
||||
#include <string.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)
|
||||
@ -314,6 +317,8 @@ static Token adr_func(int argc, const Token argv[], LocConvention lcon)
|
||||
size_t i;
|
||||
/*}}}*/
|
||||
|
||||
if (lcon == EXCEL) return excel_adr_func(argc, argv);
|
||||
|
||||
/* asserts */ /*{{{*/
|
||||
assert(argv != (Token*)0);
|
||||
/*}}}*/
|
||||
@ -328,6 +333,7 @@ static Token adr_func(int argc, const Token argv[], LocConvention lcon)
|
||||
}
|
||||
for (i = 0; i < argc && i < HYPER; ++i)
|
||||
{
|
||||
if (argv[0].type == EEK) return argv[0];
|
||||
if (argv[i].type == INT)
|
||||
if (lcon == ABSOLUTE) 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;
|
||||
result.type = EEK;
|
||||
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);
|
||||
strcpy(result.u.err, pref);
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
@ -384,106 +396,104 @@ static Token rel_at_func(int argc, const Token argv[])
|
||||
return at_func(argc, argv, RELATIVE);
|
||||
}
|
||||
|
||||
/* x */ /*{{{*/
|
||||
static Token x_func(int argc, const Token argv[])
|
||||
static Token excel_at_func(int argc, const Token argv[])
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
Token result;
|
||||
/*}}}*/
|
||||
return at_func(argc, argv, EXCEL);
|
||||
}
|
||||
|
||||
if (argc==0)
|
||||
/* result is currently updated x position */ /*{{{*/
|
||||
{
|
||||
result.type = INT;
|
||||
result.u.integer = upd_l[X];
|
||||
#define INTPATIBLE(t) (t.type == INT || t.type == EMPTY)
|
||||
|
||||
static Token excel_adr_func(int argc, const Token argv[])
|
||||
{
|
||||
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;
|
||||
}
|
||||
/*}}}*/
|
||||
else if (argc==1 && argv[0].type==LOCATION)
|
||||
/* return x component of location */ /*{{{*/
|
||||
if (argv[0].type == EEK) return argv[0];
|
||||
if (argv[1].type == EEK) return argv[1];
|
||||
if (argv[0].type != LOCATION || argv[1].type != LOCATION)
|
||||
{
|
||||
result.type = INT;
|
||||
result.u.integer = argv[0].u.location[X];
|
||||
result.type = EEK;
|
||||
result.u.err = strdup(usage);
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
else
|
||||
/* x type error */ /*{{{*/
|
||||
|
||||
LOCATION_GETS(result.u.location, upd_l);
|
||||
|
||||
for (Dimensions dim = X; dim < HYPER; ++dim)
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=strcpy(malloc(strlen(_("Usage: x([location])"))+1),_("Usage: x([location])"));
|
||||
int i = dim + 2;
|
||||
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;
|
||||
}
|
||||
/*}}}/
|
||||
|
||||
/* x */ /*{{{*/
|
||||
static Token x_func(int argc, const Token argv[])
|
||||
{
|
||||
return dim_func(argc, argv, X);
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* y */ /*{{{*/
|
||||
static Token y_func(int argc, const Token argv[])
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
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;
|
||||
return dim_func(argc, argv, Y);
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* z */ /*{{{*/
|
||||
static Token z_func(int argc, const Token argv[])
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
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;
|
||||
return dim_func(argc, argv, Z);
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
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)
|
||||
{
|
||||
Token result;
|
||||
@ -495,7 +505,7 @@ static Token bitwise_func(int argc, const Token argv[], LogicalFunction lop)
|
||||
{
|
||||
result.type = EEK;
|
||||
result.u.err =
|
||||
mystrmalloc(_("Bitwise functions operate only on integers."));
|
||||
strdup(_("Bitwise functions operate only on integers."));
|
||||
return result;
|
||||
}
|
||||
int val = 0;
|
||||
@ -534,7 +544,7 @@ static Token e_func(int argc, const Token argv[])
|
||||
else /* result is e type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: e()"));
|
||||
result.u.err=strdup(_("Usage: e()"));
|
||||
}
|
||||
/*}}}*/
|
||||
return result;
|
||||
@ -552,7 +562,7 @@ static Token eval_func(int argc, const Token argv[])
|
||||
/* nesting error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("nested eval()"));
|
||||
result.u.err=strdup(_("nested eval()"));
|
||||
}
|
||||
/*}}}*/
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("int(string): domain error"));
|
||||
result.u.err=strdup(_("int(string): domain error"));
|
||||
}
|
||||
else result.type=INT;
|
||||
}
|
||||
@ -869,7 +879,7 @@ static Token len_func(int argc, const Token argv[])
|
||||
/* result is frac type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: len(string)"));
|
||||
result.u.err=strdup(_("Usage: len(string)"));
|
||||
}
|
||||
/*}}}*/
|
||||
return result;
|
||||
@ -912,7 +922,7 @@ static Token log_func(int argc, const Token argv[])
|
||||
else /* result is log type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: log(float[,float])"));
|
||||
result.u.err=strdup(_("Usage: log(float[,float])"));
|
||||
}
|
||||
/*}}}*/
|
||||
return result;
|
||||
@ -998,7 +1008,7 @@ static Token minmax_func(int argc, const Token argv[], int min)
|
||||
/* result is min/max type error */ /*{{{*/
|
||||
{
|
||||
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;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1041,7 +1051,7 @@ static Token abs_func(int argc, const Token argv[])
|
||||
/* result is abs type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: abs(float|integer)"));
|
||||
result.u.err=strdup(_("Usage: abs(float|integer)"));
|
||||
}
|
||||
/*}}}*/
|
||||
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="";
|
||||
result.type=STRING;
|
||||
result.u.string=mystrmalloc(e);
|
||||
result.u.string=strdup(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: $(string)"));
|
||||
result.u.err=strdup(_("Usage: $(string)"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1088,7 +1098,7 @@ static Token float_func(int argc, const Token argv[])
|
||||
else
|
||||
{
|
||||
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 */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: float(string)"));
|
||||
result.u.err=strdup(_("Usage: float(string)"));
|
||||
}
|
||||
/*}}}*/
|
||||
return result;
|
||||
@ -1119,7 +1129,7 @@ static Token strftime_func(int argc, const Token argv[])
|
||||
tm=localtime(&t);
|
||||
strftime(s,sizeof(s),argv[0].u.string,tm);
|
||||
s[sizeof(s)-1]='\0';
|
||||
result.u.string=mystrmalloc(s);
|
||||
result.u.string=strdup(s);
|
||||
result.type=STRING;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1133,14 +1143,14 @@ static Token strftime_func(int argc, const Token argv[])
|
||||
tm=localtime(&t);
|
||||
strftime(s,sizeof(s),argv[0].u.string,tm);
|
||||
s[sizeof(s)-1]='\0';
|
||||
result.u.string=mystrmalloc(s);
|
||||
result.u.string=strdup(s);
|
||||
result.type=STRING;
|
||||
}
|
||||
/*}}}*/
|
||||
else /* strftime type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: strftime(string[,integer])"));
|
||||
result.u.err=strdup(_("Usage: strftime(string[,integer])"));
|
||||
}
|
||||
/*}}}*/
|
||||
return result;
|
||||
@ -1184,7 +1194,7 @@ static Token clock_func(int argc, const Token argv[])
|
||||
else /* wrong usage */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: clock(condition,location[,location])"));
|
||||
result.u.err=strdup(_("Usage: clock(condition,location[,location])"));
|
||||
}
|
||||
/*}}}*/
|
||||
return result;
|
||||
@ -1322,7 +1332,7 @@ static Token rnd_func(int argc, const Token argv[])
|
||||
else
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: rnd()"));
|
||||
result.u.err=strdup(_("Usage: rnd()"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1351,7 +1361,7 @@ static Token substr_func(int argc, const Token argv[])
|
||||
ss[n] = '\0';
|
||||
strncpy(ss, argv[0].u.string + b, n);
|
||||
result.type=STRING;
|
||||
result.u.string=mystrmalloc(ss);
|
||||
result.u.string=strdup(ss);
|
||||
}
|
||||
else {
|
||||
result.type=EMPTY;
|
||||
@ -1360,7 +1370,7 @@ static Token substr_func(int argc, const Token argv[])
|
||||
else
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: substr(string,integer,integer)"));
|
||||
result.u.err=strdup(_("Usage: substr(string,integer,integer)"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1387,7 +1397,7 @@ static Token strptime_func(int argc, const Token argv[])
|
||||
else /* strftime type error */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: strptime(string,string)"));
|
||||
result.u.err=strdup(_("Usage: strptime(string,string)"));
|
||||
}
|
||||
/*}}}*/
|
||||
return result;
|
||||
@ -1406,7 +1416,7 @@ static Token time_func(int argc, const Token argv[])
|
||||
else
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("Usage: time()"));
|
||||
result.u.err=strdup(_("Usage: time()"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1460,8 +1470,10 @@ Tfunc tfunc[]=
|
||||
{ "time", time_func },
|
||||
{ "bitand", bitand_func },
|
||||
{ "bitor", bitor_func },
|
||||
{ "D", rel_adr_func },
|
||||
{ "R", rel_at_func },
|
||||
{ "D", rel_adr_func },
|
||||
{ "X", excel_at_func },
|
||||
{ "X&", excel_adr_func },
|
||||
{ "", (Token (*)(int, const Token[]))0 }
|
||||
};
|
||||
/*}}}*/
|
||||
|
@ -24,6 +24,7 @@
|
||||
extern char *optarg;
|
||||
extern int optind,opterr,optopt;
|
||||
int getopt(int argc, char * const *argv, const char *optstring);
|
||||
extern char *strdup(const char* s);
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -680,9 +681,9 @@ static int do_savecsv(Sheet *cursheet, const char *name)
|
||||
MenuChoice menu[4];
|
||||
name = cursheet->name;
|
||||
|
||||
menu[0].str=mystrmalloc(_("cC)omma (,)")); menu[0].c='\0';
|
||||
menu[1].str=mystrmalloc(_("sS)emicolon (;)")); menu[1].c='\0';
|
||||
menu[2].str=mystrmalloc(_("tT)ab (\\t)")); menu[2].c='\0';
|
||||
menu[0].str=strdup(_("cC)omma (,)")); menu[0].c='\0';
|
||||
menu[1].str=strdup(_("sS)emicolon (;)")); menu[1].c='\0';
|
||||
menu[2].str=strdup(_("tT)ab (\\t)")); menu[2].c='\0';
|
||||
menu[3].str=(char*)0;
|
||||
sep=line_menu(_("Choose separator:"),menu,0);
|
||||
if (sep < 0) return sep;
|
||||
@ -912,9 +913,9 @@ static int do_insert(Sheet *sheet)
|
||||
{
|
||||
MenuChoice menu[4];
|
||||
|
||||
menu[0].str=mystrmalloc(_("cC)olumn")); menu[0].c='\0';
|
||||
menu[1].str=mystrmalloc(_("rR)ow")); menu[1].c='\0';
|
||||
menu[2].str=mystrmalloc(_("dD)epth")); menu[2].c='\0';
|
||||
menu[0].str=strdup(_("cC)olumn")); menu[0].c='\0';
|
||||
menu[1].str=strdup(_("rR)ow")); menu[1].c='\0';
|
||||
menu[2].str=strdup(_("dD)epth")); menu[2].c='\0';
|
||||
menu[3].str=(char*)0;
|
||||
reply=line_menu(_("Insert:"),menu,0);
|
||||
free(menu[0].str);
|
||||
@ -938,12 +939,12 @@ static int do_insert(Sheet *sheet)
|
||||
/* show menu */ /*{{{*/
|
||||
switch (reply)
|
||||
{
|
||||
case 0: menu[0].str=mystrmalloc(_("wW)hole column")); break;
|
||||
case 1: menu[0].str=mystrmalloc(_("wW)hole line")); break;
|
||||
case 2: menu[0].str=mystrmalloc(_("wW)hole sheet")); break;
|
||||
case 0: menu[0].str=strdup(_("wW)hole column")); break;
|
||||
case 1: menu[0].str=strdup(_("wW)hole line")); break;
|
||||
case 2: menu[0].str=strdup(_("wW)hole sheet")); break;
|
||||
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;
|
||||
r=line_menu(_("Insert:"),menu,0);
|
||||
free(menu[0].str);
|
||||
@ -1029,9 +1030,9 @@ static int do_delete(Sheet *sheet)
|
||||
{
|
||||
MenuChoice menu[4];
|
||||
|
||||
menu[0].str=mystrmalloc(_("cC)olumn")); menu[0].c='\0';
|
||||
menu[1].str=mystrmalloc(_("rR)ow")); menu[1].c='\0';
|
||||
menu[2].str=mystrmalloc(_("dD)epth")); menu[2].c='\0';
|
||||
menu[0].str=strdup(_("cC)olumn")); menu[0].c='\0';
|
||||
menu[1].str=strdup(_("rR)ow")); menu[1].c='\0';
|
||||
menu[2].str=strdup(_("dD)epth")); menu[2].c='\0';
|
||||
menu[3].str=(char*)0;
|
||||
reply=line_menu(_("Delete:"),menu,0);
|
||||
free(menu[0].str);
|
||||
@ -1056,12 +1057,12 @@ static int do_delete(Sheet *sheet)
|
||||
/* show menu */ /*{{{*/
|
||||
switch (reply)
|
||||
{
|
||||
case 0: menu[0].str=mystrmalloc(_("wW)hole column")); break;
|
||||
case 1: menu[0].str=mystrmalloc(_("wW)hole line")); break;
|
||||
case 2: menu[0].str=mystrmalloc(_("wW)hole sheet")); break;
|
||||
case 0: menu[0].str=strdup(_("wW)hole column")); break;
|
||||
case 1: menu[0].str=strdup(_("wW)hole line")); break;
|
||||
case 2: menu[0].str=strdup(_("wW)hole sheet")); break;
|
||||
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;
|
||||
r=line_menu(_("Delete:"),menu,0);
|
||||
free(menu[0].str);
|
||||
@ -1233,15 +1234,15 @@ static int do_sort(Sheet *sheet)
|
||||
|
||||
do_mark(sheet, GET_MARK_ALL);
|
||||
/* build menues */ /*{{{*/
|
||||
menu1[0].str=mystrmalloc(_("cC)olumn")); menu1[0].c='\0';
|
||||
menu1[1].str=mystrmalloc(_("rR)ow")); menu1[1].c='\0';
|
||||
menu1[2].str=mystrmalloc(_("dD)epth")); menu1[2].c='\0';
|
||||
menu1[0].str=strdup(_("cC)olumn")); menu1[0].c='\0';
|
||||
menu1[1].str=strdup(_("rR)ow")); menu1[1].c='\0';
|
||||
menu1[2].str=strdup(_("dD)epth")); menu1[2].c='\0';
|
||||
menu1[3].str=(char*)0;
|
||||
menu2[0].str=mystrmalloc(_("sS)ort region")); menu2[0].c='\0';
|
||||
menu2[1].str=mystrmalloc(_("aA)dd key")); menu2[1].c='\0';
|
||||
menu2[0].str=strdup(_("sS)ort region")); menu2[0].c='\0';
|
||||
menu2[1].str=strdup(_("aA)dd key")); menu2[1].c='\0';
|
||||
menu2[2].str=(char*)0;
|
||||
menu3[0].str=mystrmalloc(_("aA)scending")); menu3[0].c='\0';
|
||||
menu3[1].str=mystrmalloc(_("dD)escending")); menu3[0].c='\0';
|
||||
menu3[0].str=strdup(_("aA)scending")); menu3[0].c='\0';
|
||||
menu3[1].str=strdup(_("dD)escending")); menu3[0].c='\0';
|
||||
menu3[2].str=(char*)0;
|
||||
/*}}}*/
|
||||
|
||||
@ -1453,9 +1454,9 @@ static int do_mirror(Sheet *sheet)
|
||||
{
|
||||
MenuChoice menu[4];
|
||||
|
||||
menu[0].str=mystrmalloc(_("lL)eft-right")); menu[0].c='\0';
|
||||
menu[1].str=mystrmalloc(_("uU)pside-down")); menu[1].c='\0';
|
||||
menu[2].str=mystrmalloc(_("fF)ront-back")); menu[2].c='\0';
|
||||
menu[0].str=strdup(_("lL)eft-right")); menu[0].c='\0';
|
||||
menu[1].str=strdup(_("uU)pside-down")); menu[1].c='\0';
|
||||
menu[2].str=strdup(_("fF)ront-back")); menu[2].c='\0';
|
||||
menu[3].str=(char*)0;
|
||||
reply=line_menu(_("Mirror block:"),menu,0);
|
||||
free(menu[0].str);
|
||||
@ -1882,7 +1883,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
cursheet->name=mystrmalloc(loadfile);
|
||||
cursheet->name=strdup(loadfile);
|
||||
if (usexdr)
|
||||
{
|
||||
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 */ /*{{{*/
|
||||
static volatile int caughtfpe;
|
||||
|
||||
|
@ -11,7 +11,6 @@ extern "C" {
|
||||
|
||||
void posorder(int *x, int *y);
|
||||
long int posnumber(const char *s, const char **endptr);
|
||||
char *mystrmalloc(const char *str);
|
||||
const char *dblfinite(double x);
|
||||
int fputc_close(char c, FILE *fp);
|
||||
int fputs_close(const char *s, FILE *fp);
|
||||
|
@ -12,8 +12,10 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
extern char *strdup(const char* s);
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@ -89,7 +91,7 @@ static Token primary(Token *n[], int *i)
|
||||
/* return error, value expected */ /*{{{*/
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("value expected"));
|
||||
result.u.err=strdup(_("value expected"));
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -153,8 +155,10 @@ static Token primary(Token *n[], int *i)
|
||||
/* eval function */ /*{{{*/
|
||||
{
|
||||
++(*i);
|
||||
result=tfuncall(ident,argc,argv);
|
||||
for (j=0; j<argc; ++j) tfree(&argv[j]);
|
||||
result = tfuncall(ident,argc,argv);
|
||||
/* 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
|
||||
@ -171,7 +175,7 @@ static Token primary(Token *n[], int *i)
|
||||
else
|
||||
{
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("( expected"));
|
||||
result.u.err=strdup(_("( expected"));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -179,7 +183,7 @@ static Token primary(Token *n[], int *i)
|
||||
default: ; /* fall through */
|
||||
}
|
||||
result.type=EEK;
|
||||
result.u.err=mystrmalloc(_("value expected"));
|
||||
result.u.err=strdup(_("value expected"));
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
|
@ -15,6 +15,7 @@ typedef enum {
|
||||
#endif
|
||||
} Type;
|
||||
|
||||
#define MAX_TYPE_NAME_LENGTH 16
|
||||
extern const char *Type_Name[];
|
||||
|
||||
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 */ /*{{{*/
|
||||
{
|
||||
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;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -831,7 +833,10 @@ Token findlabel(Sheet *sheet, const char *label)
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -860,7 +865,7 @@ void relabel(Sheet *sheet, const Location at,
|
||||
if ((*run)->type==LIDENT && strcmp((*run)->u.lident, oldlabel)==0)
|
||||
{
|
||||
free((*run)->u.lident);
|
||||
(*run)->u.lident = mystrmalloc(newlabel);
|
||||
(*run)->u.lident = strdup(newlabel);
|
||||
}
|
||||
cachelabels(sheet);
|
||||
forceupdate(sheet);
|
||||
@ -1337,7 +1342,7 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
++ns;
|
||||
while (*ns && *ns!=' ') { *p=*ns; ++p; ++ns; }
|
||||
*p='\0';
|
||||
loaded.label=mystrmalloc(buf);
|
||||
loaded.label=strdup(buf);
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1683,7 +1688,7 @@ const char *loadcsv(Sheet *sheet, const char *name)
|
||||
if (s!=cend) /* ok, it is a string */ /*{{{*/
|
||||
{
|
||||
t[0]->type=STRING;
|
||||
t[0]->u.string=mystrmalloc(str);
|
||||
t[0]->u.string=strdup(str);
|
||||
putcont(sheet, where, t, BASE);
|
||||
}
|
||||
/*}}}*/
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
extern char *strdup(const char *s);
|
||||
#include <string.h>
|
||||
#ifdef OLD_REALLOC
|
||||
#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[1]=(Token*)0;
|
||||
t[0]->type=STRING;
|
||||
t[0]->u.string=mystrmalloc(body+6);
|
||||
t[0]->u.string=strdup(body+6);
|
||||
putcont(sheet, tmp, t, BASE);
|
||||
format((unsigned char)body[0], cell);
|
||||
break;
|
||||
@ -1098,7 +1099,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
|
||||
t[0]=malloc(sizeof(Token));
|
||||
t[1]=(Token*)0;
|
||||
t[0]->type=STRING;
|
||||
t[0]->u.string=mystrmalloc(body+5);
|
||||
t[0]->u.string=strdup(body+5);
|
||||
putcont(sheet, tmp, t, BASE);
|
||||
format((unsigned char)body[0], cell);
|
||||
break;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
extern char *strdup(const char* s);
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef NEED_BCOPY
|
||||
@ -66,21 +67,21 @@ static int do_attribute(Sheet *cursheet)
|
||||
int c;
|
||||
|
||||
/* create menus */
|
||||
adjmenu[0].str=mystrmalloc(_("lL)eft")); adjmenu[0].c='\0';
|
||||
adjmenu[1].str=mystrmalloc(_("rR)ight")); adjmenu[1].c='\0';
|
||||
adjmenu[2].str=mystrmalloc(_("cC)entered")); adjmenu[2].c='\0';
|
||||
adjmenu[3].str=mystrmalloc(_("11).23e1 <-> 12.3")); adjmenu[3].c='\0';
|
||||
adjmenu[4].str=mystrmalloc(_("pP)recision")); adjmenu[4].c='\0';
|
||||
adjmenu[5].str=mystrmalloc(_("sS)hadow")); adjmenu[5].c='\0';
|
||||
adjmenu[6].str=mystrmalloc(_("bB)old")); adjmenu[6].c='\0';
|
||||
adjmenu[7].str=mystrmalloc(_("uU)nderline")); adjmenu[7].c='\0';
|
||||
adjmenu[8].str=mystrmalloc(_("oO)utput special characters")); adjmenu[8].c='\0';
|
||||
adjmenu[0].str=strdup(_("lL)eft")); adjmenu[0].c='\0';
|
||||
adjmenu[1].str=strdup(_("rR)ight")); adjmenu[1].c='\0';
|
||||
adjmenu[2].str=strdup(_("cC)entered")); adjmenu[2].c='\0';
|
||||
adjmenu[3].str=strdup(_("11).23e1 <-> 12.3")); adjmenu[3].c='\0';
|
||||
adjmenu[4].str=strdup(_("pP)recision")); adjmenu[4].c='\0';
|
||||
adjmenu[5].str=strdup(_("sS)hadow")); adjmenu[5].c='\0';
|
||||
adjmenu[6].str=strdup(_("bB)old")); adjmenu[6].c='\0';
|
||||
adjmenu[7].str=strdup(_("uU)nderline")); adjmenu[7].c='\0';
|
||||
adjmenu[8].str=strdup(_("oO)utput special characters")); adjmenu[8].c='\0';
|
||||
adjmenu[9].str=(char*)0;
|
||||
|
||||
mainmenu[0].str=mystrmalloc(_("rR)epresentation")); mainmenu[0].c='\0';
|
||||
mainmenu[1].str=mystrmalloc(_("lL)abel")); mainmenu[1].c='\0';
|
||||
mainmenu[2].str=mystrmalloc(_("oLo)ck")); mainmenu[2].c='\0';
|
||||
mainmenu[3].str=mystrmalloc(_("iI)gnore")); mainmenu[3].c='\0';
|
||||
mainmenu[0].str=strdup(_("rR)epresentation")); mainmenu[0].c='\0';
|
||||
mainmenu[1].str=strdup(_("lL)abel")); mainmenu[1].c='\0';
|
||||
mainmenu[2].str=strdup(_("oLo)ck")); mainmenu[2].c='\0';
|
||||
mainmenu[3].str=strdup(_("iI)gnore")); mainmenu[3].c='\0';
|
||||
mainmenu[4].str=(char*)0;
|
||||
|
||||
do
|
||||
@ -155,9 +156,9 @@ static int do_file(Sheet *cursheet)
|
||||
int c;
|
||||
|
||||
|
||||
menu[0].str=mystrmalloc(_("lL)oad")); menu[0].c='\0';
|
||||
menu[1].str=mystrmalloc(_("sS)ave")); menu[1].c='\0';
|
||||
menu[2].str=mystrmalloc(_("nN)ame")); menu[2].c='\0';
|
||||
menu[0].str=strdup(_("lL)oad")); menu[0].c='\0';
|
||||
menu[1].str=strdup(_("sS)ave")); menu[1].c='\0';
|
||||
menu[2].str=strdup(_("nN)ame")); menu[2].c='\0';
|
||||
menu[3].str=(char*)0;
|
||||
c=0;
|
||||
do
|
||||
@ -257,14 +258,14 @@ static int do_block(Sheet *cursheet)
|
||||
MenuChoice block[9];
|
||||
int c;
|
||||
|
||||
block[0].str=mystrmalloc(_("ecle)ar")); block[0].c='\0';
|
||||
block[1].str=mystrmalloc(_("iI)nsert")); block[1].c='\0';
|
||||
block[2].str=mystrmalloc(_("dD)elete")); block[2].c='\0';
|
||||
block[3].str=mystrmalloc(_("mM)ove")); block[3].c='\0';
|
||||
block[4].str=mystrmalloc(_("cC)opy")); block[4].c='\0';
|
||||
block[5].str=mystrmalloc(_("fF)ill")); block[5].c='\0';
|
||||
block[6].str=mystrmalloc(_("sS)ort")); block[6].c='\0';
|
||||
block[7].str=mystrmalloc(_("rMir)ror")); block[7].c='\0';
|
||||
block[0].str=strdup(_("ecle)ar")); block[0].c='\0';
|
||||
block[1].str=strdup(_("iI)nsert")); block[1].c='\0';
|
||||
block[2].str=strdup(_("dD)elete")); block[2].c='\0';
|
||||
block[3].str=strdup(_("mM)ove")); block[3].c='\0';
|
||||
block[4].str=strdup(_("cC)opy")); block[4].c='\0';
|
||||
block[5].str=strdup(_("fF)ill")); block[5].c='\0';
|
||||
block[6].str=strdup(_("sS)ort")); block[6].c='\0';
|
||||
block[7].str=strdup(_("rMir)ror")); block[7].c='\0';
|
||||
block[8].str=(char*)0;
|
||||
c=0;
|
||||
do
|
||||
@ -303,14 +304,14 @@ int show_menu(Sheet *cursheet)
|
||||
int c = K_INVALID;
|
||||
|
||||
|
||||
menu[0].str=mystrmalloc(_("aA)ttributes")); menu[0].c='\0';
|
||||
menu[1].str=mystrmalloc(_("wW)idth")); menu[1].c='\0';
|
||||
menu[2].str=mystrmalloc(_("bB)lock")); menu[2].c='\0';
|
||||
menu[3].str=mystrmalloc(_("fF)ile")); menu[3].c='\0';
|
||||
menu[4].str=mystrmalloc(_("gG)oto")); menu[4].c='\0';
|
||||
menu[5].str=mystrmalloc(_("sS)hell")); menu[5].c='\0';
|
||||
menu[6].str=mystrmalloc(_("vV)ersion")); menu[6].c='\0';
|
||||
menu[7].str=mystrmalloc(_("qQ)uit")); menu[7].c='\0';
|
||||
menu[0].str=strdup(_("aA)ttributes")); menu[0].c='\0';
|
||||
menu[1].str=strdup(_("wW)idth")); menu[1].c='\0';
|
||||
menu[2].str=strdup(_("bB)lock")); menu[2].c='\0';
|
||||
menu[3].str=strdup(_("fF)ile")); menu[3].c='\0';
|
||||
menu[4].str=strdup(_("gG)oto")); menu[4].c='\0';
|
||||
menu[5].str=strdup(_("sS)hell")); menu[5].c='\0';
|
||||
menu[6].str=strdup(_("vV)ersion")); menu[6].c='\0';
|
||||
menu[7].str=strdup(_("qQ)uit")); menu[7].c='\0';
|
||||
menu[8].str=(char*)0;
|
||||
|
||||
do
|
||||
@ -838,8 +839,8 @@ int line_ok(const char *prompt, int curx)
|
||||
|
||||
assert(curx==0 || curx==1);
|
||||
|
||||
menu[0].str=mystrmalloc(_("nN)o")); menu[0].c='\0';
|
||||
menu[1].str=mystrmalloc(_("yY)es")); menu[1].c='\0';
|
||||
menu[0].str=strdup(_("nN)o")); menu[0].c='\0';
|
||||
menu[1].str=strdup(_("yY)es")); menu[1].c='\0';
|
||||
menu[2].str=(char*)0;
|
||||
result=line_menu(prompt,menu,curx);
|
||||
free(menu[0].str);
|
||||
|
Loading…
Reference in New Issue
Block a user