Allow styles to be computed
Needs further testing and documentation, will provide a more detailed commit message when that is checked in.
This commit is contained in:
parent
253062e906
commit
c52219f827
337
doc/teapot.lyx
337
doc/teapot.lyx
@ -4895,14 +4895,36 @@ false,
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
Location Cell labels and the result of the
|
||||
\family typewriter
|
||||
Label Cell labels are of this type, but they generally evaluate to locations
|
||||
(or cause an error if there is no cell with that label), so you don't generally
|
||||
manipulate values of this type.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
Keyword The names of functions and of special arguments to functions, like
|
||||
the
|
||||
\family sans
|
||||
decimal
|
||||
\family default
|
||||
flag to the
|
||||
\family sans
|
||||
float()
|
||||
\family default
|
||||
function.
|
||||
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
Location The values of cell labels and the result of the
|
||||
\family sans
|
||||
&()
|
||||
\family default
|
||||
function have this type, but there are no location constant literals.
|
||||
However,
|
||||
\family sans
|
||||
&(3,2,1)
|
||||
\family typewriter
|
||||
&(3,2,1),
|
||||
,
|
||||
\family default
|
||||
for example, acts very much like a location constant literal.
|
||||
\end_layout
|
||||
@ -4910,16 +4932,30 @@ Location Cell labels and the result of the
|
||||
\begin_layout Description
|
||||
Error Syntactical or semantical (type mismatch) errors cause this value,
|
||||
as well as division by 0 and the function
|
||||
\family typewriter
|
||||
\family sans
|
||||
error()
|
||||
\family default
|
||||
.
|
||||
An error always has an assigned error message.
|
||||
Functions and operators, when applied to a value of the type error, evaluate
|
||||
to just that value.
|
||||
That way, the first error which was found, possibly deep inside a complicated
|
||||
That way, the first error encountered, possibly deep inside a complicated
|
||||
expression, will be shown.
|
||||
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
Expression a teapot formula; some functions (like
|
||||
\family sans
|
||||
find()
|
||||
\family default
|
||||
) take an expression as an argument so that it can be evaluated from the
|
||||
point of view of other cells.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
Style the encapsulated visual/display attributes of a cell.
|
||||
Not many operators/functions apply to Style values, but they are the key
|
||||
to allowing the appearance of a cell to depend on its value.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Subsection
|
||||
@ -5311,6 +5347,9 @@ y
|
||||
\emph default
|
||||
are strings, the result is the concatenated string.
|
||||
If they are locations, this operates componentwise.
|
||||
If they are styles, it means to take any unset components of the left-hand
|
||||
style and fill them in with values from the right-hand style (ignoring
|
||||
the right-hand components that are already set in the left-hand style).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
@ -6380,6 +6419,37 @@ x
|
||||
is given in radians.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
background
|
||||
\series medium
|
||||
(int
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\emph default
|
||||
c)
|
||||
\series default
|
||||
evaluates to a style token with the background color set to
|
||||
\emph on
|
||||
c
|
||||
\emph default
|
||||
(and no other fields set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
below
|
||||
\series medium
|
||||
@ -6478,6 +6548,37 @@ or
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
bold
|
||||
\series medium
|
||||
([bool
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
b
|
||||
\emph default
|
||||
])
|
||||
\series default
|
||||
evaluates to a style token with the bold property set to
|
||||
\emph on
|
||||
b
|
||||
\emph default
|
||||
, which defaults to true (and no other fields set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
bool
|
||||
\begin_inset space ~
|
||||
@ -6543,6 +6644,16 @@ x
|
||||
.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
center keyword used as an argument to
|
||||
\family sans
|
||||
\series bold
|
||||
justify
|
||||
\family default
|
||||
\series default
|
||||
().
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
clock
|
||||
\series medium
|
||||
@ -6570,8 +6681,14 @@ condition
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
compact used as a keyword to the string() function; listed here to record
|
||||
that this identifier may not be used as a cell label.
|
||||
compact used as a keyword to the
|
||||
\family sans
|
||||
\series bold
|
||||
string
|
||||
\family default
|
||||
\series default
|
||||
() function; listed here to record that this identifier may not be used
|
||||
as a cell label.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
@ -6907,6 +7024,26 @@ is
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
floatfmt
|
||||
\series medium
|
||||
(decimal|scientific|compact|hexact)
|
||||
\series default
|
||||
evaluates to a style token with the floating-point format set to the specified
|
||||
format, given as a bare word (and no other fields set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
float
|
||||
\begin_inset space ~
|
||||
@ -6935,6 +7072,37 @@ x
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
foreground
|
||||
\series medium
|
||||
(int
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\emph default
|
||||
c)
|
||||
\series default
|
||||
evaluates to a style token with the foreground color set to
|
||||
\emph on
|
||||
c
|
||||
\emph default
|
||||
(and no other fields set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
float
|
||||
\begin_inset space ~
|
||||
@ -7185,6 +7353,26 @@ is
|
||||
tests whether the current cell is non-empty.
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
justify
|
||||
\series medium
|
||||
(left|right|center)
|
||||
\series default
|
||||
evaluates to a style token with the justification set to the specified
|
||||
direction, given as a bare word (and no other fields set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
left
|
||||
\series medium
|
||||
@ -7693,6 +7881,37 @@ cn
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
precision
|
||||
\series medium
|
||||
(int
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
x
|
||||
\emph default
|
||||
)
|
||||
\series default
|
||||
evaluates to a style token in which the precision is set to
|
||||
\emph on
|
||||
x
|
||||
\emph default
|
||||
(and no other fields are set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
float
|
||||
\begin_inset space ~
|
||||
@ -7801,6 +8020,37 @@ scientific Used as a keyword argument to the string() function; listed here
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
shadowed
|
||||
\series medium
|
||||
([bool
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
b
|
||||
\emph default
|
||||
])
|
||||
\series default
|
||||
evaluates to a style token with the shadowed property set to
|
||||
\emph on
|
||||
b
|
||||
\emph default
|
||||
, which defaults to true (and no other fields set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
float
|
||||
\begin_inset space ~
|
||||
@ -8345,6 +8595,37 @@ status open
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
transparent
|
||||
\series medium
|
||||
([bool
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
b
|
||||
\emph default
|
||||
])
|
||||
\series default
|
||||
evaluates to a style token with the transparent property set to
|
||||
\emph on
|
||||
b
|
||||
\emph default
|
||||
, which defaults to true (and no other fields set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
boolean
|
||||
\begin_inset space ~
|
||||
@ -8390,6 +8671,37 @@ x
|
||||
).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
||||
\series medium
|
||||
style
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
|
||||
\series default
|
||||
\emph default
|
||||
underline
|
||||
\series medium
|
||||
([bool
|
||||
\emph on
|
||||
|
||||
\begin_inset space ~
|
||||
\end_inset
|
||||
|
||||
b
|
||||
\emph default
|
||||
])
|
||||
\series default
|
||||
evaluates to a style token with the underline property set to
|
||||
\emph on
|
||||
b
|
||||
\emph default
|
||||
, which defaults to true (and no other fields set).
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
up
|
||||
\series medium
|
||||
@ -8404,7 +8716,14 @@ l
|
||||
])] displacement by one cell in the negative
|
||||
\series default
|
||||
\emph on
|
||||
y
|
||||
y
|
||||
\emph default
|
||||
direction; see the fuller description at
|
||||
\family sans
|
||||
\series bold
|
||||
above
|
||||
\series default
|
||||
.)
|
||||
\end_layout
|
||||
|
||||
\begin_layout Description
|
||||
|
@ -3,4 +3,4 @@ include_directories("${Teapot_SOURCE_DIR}/src/common")
|
||||
|
||||
link_directories("${Teapot_SOURCE_DIR}/src/common")
|
||||
|
||||
add_library(teapotlib cell.c context.c csv.c eval.c func.c htmlio.c latex.c main.c misc.c parser.c sc.c scanner.c sheet.c utf8.c wk1.c xdr.c)
|
||||
add_library(teapotlib cell.c context.c csv.c eval.c func.c htmlio.c latex.c main.c misc.c parser.c sc.c scanner.c sheet.c style.c token.c utf8.c wk1.c xdr.c)
|
||||
|
@ -6,42 +6,21 @@
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cell.h"
|
||||
#include "default.h"
|
||||
#include "display.h"
|
||||
#include "eval.h"
|
||||
#include "parser.h"
|
||||
#include "main.h"
|
||||
#include "utf8.h"
|
||||
|
||||
const char *Adjust_Name[] =
|
||||
{ [LEFT] = "Left", [RIGHT] = "Right", [CENTER] = "Center",
|
||||
[AUTOADJUST] = "Auto"
|
||||
};
|
||||
|
||||
const char Adjust_Char[] = "lrca";
|
||||
|
||||
const char *FloatFormat_Name[] =
|
||||
{ [FLT_DECIMAL] = "Decimal", [FLT_SCIENTIFIC] = "Scientific",
|
||||
[FLT_COMPACT] = "Compact", [FLT_HEXACT] = "Hexact"
|
||||
};
|
||||
|
||||
const char FloatFormat_Char[] = "dsch";
|
||||
|
||||
const char *ColorAspect_Name[] =
|
||||
{ [FOREGROUND] = "Foreground", [BACKGROUND] = "Background"
|
||||
};
|
||||
const ColorNum DefaultCN[] =
|
||||
{ [FOREGROUND] = 0, [BACKGROUND] = 16, [NUM_COLOR_ASPECTS] = 255 };
|
||||
|
||||
const char *TokVariety_Name[] =
|
||||
{ [BASE_CONT] = "Base Content", [ITER_CONT] = "Iterative Content",
|
||||
[ATTR_REF] = "Attribute Reference", [CURR_VAL] = "Current Value",
|
||||
[RES_VAL] = "Resultant Value", [CONTINGENT] = "Contingent Content"
|
||||
[STYLE_CONT] = "Style Content", [CURR_VAL] = "Current Value",
|
||||
[RES_VAL] = "Resultant Value", [STYLE_VAL] = "Current Style",
|
||||
[CONTINGENT] = "Contingent Content"
|
||||
};
|
||||
|
||||
/* initcellcontents - make a fresh cell into the "empty" one; don't worry
|
||||
@ -51,21 +30,12 @@ void initcellcontents(Cell *fresh)
|
||||
for (TokVariety tv = BASE_CONT; tv < CONTINGENT; ++tv)
|
||||
fresh->tok[tv].type = EMPTY;
|
||||
fresh->label = NULL;
|
||||
fresh->precision = -1;
|
||||
fresh->fform = DEF_FLOATFORM;
|
||||
fresh->adjust = AUTOADJUST;
|
||||
for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a)
|
||||
fresh->aspect[a] = DefaultCN[a];
|
||||
fresh->updated = 0;
|
||||
fresh->shadowed = 0;
|
||||
fresh->locked = 0;
|
||||
fresh->transparent = 0;
|
||||
fresh->ignored = 0;
|
||||
fresh->clock_t0 = 0;
|
||||
fresh->clock_t1 = 0;
|
||||
fresh->clock_t2 = 0;
|
||||
fresh->bold = 0;
|
||||
fresh->underline = 0;
|
||||
fresh->updated = false;
|
||||
fresh->locked = false;
|
||||
fresh->ignored = false;
|
||||
fresh->clock_t0 = false;
|
||||
fresh->clock_t1 = false;
|
||||
fresh->clock_t2 = false;
|
||||
}
|
||||
|
||||
/* getcont -- get contents */
|
||||
@ -80,72 +50,18 @@ Token gettok(const Cell *cell, TokVariety v)
|
||||
return cell->tok[v];
|
||||
}
|
||||
|
||||
/* getadjust -- get cell adjustment */
|
||||
Adjust getadjust(const Cell* cell)
|
||||
{
|
||||
if (cell == NULLCELL) return LEFT;
|
||||
else if (cell->adjust == AUTOADJUST)
|
||||
return (cell->tok[CURR_VAL].type == INT
|
||||
|| cell->tok[CURR_VAL].type == FLOAT) ? RIGHT : LEFT;
|
||||
else return cell->adjust;
|
||||
}
|
||||
|
||||
/* shadowed -- is cell shadowed? */
|
||||
bool shadowed(const Cell *cell)
|
||||
{
|
||||
return (cell != NULLCELL) && cell->shadowed;
|
||||
}
|
||||
|
||||
/* isbold -- is cell bold? */
|
||||
bool isbold(const Cell* cell)
|
||||
{
|
||||
return (cell != NULLCELL) && cell->bold;
|
||||
}
|
||||
|
||||
/* getcolor -- a color associated to cell */
|
||||
ColorNum getcolor(const Cell* cell, ColorAspect aspect)
|
||||
{
|
||||
return cell == NULLCELL ? DefaultCN[aspect] : cell->aspect[aspect];
|
||||
}
|
||||
|
||||
/* isunderline -- is cell underlined? */
|
||||
bool underlined(const Cell *cell)
|
||||
{
|
||||
return (cell != NULLCELL) && cell->underline;
|
||||
}
|
||||
|
||||
/* locked -- is cell locked? */
|
||||
bool locked(const Cell *cell)
|
||||
{
|
||||
return (cell != NULLCELL) && cell->locked;
|
||||
}
|
||||
|
||||
/* transparent -- is cell transparent? */
|
||||
bool transparent(const Cell* cell)
|
||||
{
|
||||
return (cell != NULLCELL) && cell->transparent;
|
||||
}
|
||||
|
||||
/* ignored -- is cell ignored? */
|
||||
bool ignored(const Cell *cell)
|
||||
{
|
||||
return (cell != NULLCELL) && cell->ignored;
|
||||
}
|
||||
|
||||
|
||||
/* getfltformat -- float format for numbers */
|
||||
FloatFormat getfltformat(const Cell *cell )
|
||||
{
|
||||
return (cell == NULLCELL) ? DEF_FLOATFORM : cell->fform;
|
||||
}
|
||||
|
||||
/* getprecision -- get cell precision */
|
||||
int getprecision(const Cell *cell)
|
||||
{
|
||||
if (cell == NULLCELL || cell->precision == -1) return def_precision;
|
||||
return cell->precision;
|
||||
}
|
||||
|
||||
/* getlabel -- get cell label */
|
||||
const char *getlabel(const Cell* cell)
|
||||
{
|
||||
@ -214,374 +130,3 @@ void copycell(Cell *to, const Cell *fromcell, LabelHandling lh)
|
||||
initcellcontents(to);
|
||||
}
|
||||
}
|
||||
|
||||
/* print_fident -- print a field identifier to a dest and return the number
|
||||
of characters written
|
||||
*/ /*{{{*/
|
||||
static int print_fident(char* dest, size_t space, FunctionIdentifier id)
|
||||
{
|
||||
size_t identlen = strlen(tfunc[id].name);
|
||||
if ((identlen+1) < space) strcpy(dest, tfunc[id].name);
|
||||
else {
|
||||
(void)strncpy(dest, tfunc[id].name, space);
|
||||
dest[space-1] = '\0';
|
||||
}
|
||||
return identlen;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* print_string -- print a string value to a dest and return the number of
|
||||
characters written
|
||||
*/ /*{{{*/
|
||||
static int print_string(char* dest, size_t space,
|
||||
const char *str, StringFormat sf)
|
||||
{
|
||||
size_t cur = 0;
|
||||
if (sf == QUOTE_STRING && cur < space) dest[cur++] = '"';
|
||||
for ( ; cur < space && *str != '\0'; ++str)
|
||||
{
|
||||
if (sf == QUOTE_STRING && (*str == '"' || *str=='\\')) dest[cur++] = '\\';
|
||||
if (cur < space) dest[cur++] = *str;
|
||||
}
|
||||
if (sf == QUOTE_STRING && cur < space) dest[cur++] = '"';
|
||||
return cur;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
|
||||
size_t ptokatprec(char* dest, size_t size, size_t field_width, StringFormat sf,
|
||||
FloatFormat ff, int digits, ErrorFormat ef, const Token *tok,
|
||||
FunctionPrecedence atprec)
|
||||
{
|
||||
if (debug_level > 2) {
|
||||
printf("..Entering printtok; bufsize %d, field_width %d, qs %d, ff %s,"
|
||||
"prec %d, verr %d\n",
|
||||
size, field_width, sf, FloatFormat_Name[ff], digits, ef);
|
||||
}
|
||||
if (size > 0 ) *dest = '\0';
|
||||
if (tok == NULLTOKEN || tok->type == EMPTY) return 0;
|
||||
size_t cur = 0;
|
||||
switch (tok->type)
|
||||
{
|
||||
/* STRING */
|
||||
case STRING: cur += print_string(dest, size-cur, tok->u.string, sf); break;
|
||||
/* INT */ /*{{{*/
|
||||
case INT:
|
||||
{
|
||||
char buf[64];
|
||||
size_t buflen;
|
||||
|
||||
buflen = sprintf(buf, INT_T_FMT, tok->u.integer);
|
||||
assert(buflen < sizeof(buf));
|
||||
(void)strncpy(dest+cur,buf,size-cur-1);
|
||||
cur+=buflen;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* FLOAT */ /*{{{*/
|
||||
case FLOAT:
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
char buf[1100], buf2[1100], *use, *p;
|
||||
size_t len, len2;
|
||||
/*}}}*/
|
||||
|
||||
if (digits <= 0) digits += FLT_T_DIG;
|
||||
if (digits > sizeof(buf) - 20) digits = sizeof(buf) - 20;
|
||||
switch (ff) {
|
||||
case FLT_DECIMAL:
|
||||
len = sprintf(buf, FLT_T_STD_FMT, digits, tok->u.flt);
|
||||
use = buf;
|
||||
break;
|
||||
case FLT_SCIENTIFIC:
|
||||
len = sprintf(buf, FLT_T_SCI_FMT, digits, tok->u.flt);
|
||||
use = buf;
|
||||
break;
|
||||
case FLT_COMPACT:
|
||||
len = sprintf(buf, FLT_T_CPT_FMT, digits, tok->u.flt);
|
||||
/* Unfortunately, %g is so clever that sometimes it omits the
|
||||
decimal; it also has a penchant for not switching to scientific
|
||||
notation until the magnitude gets very large. So we try to
|
||||
counteract these bad tendencies here. If there is no decimal,
|
||||
we take the shorter of %.1f and %e with the same number of digits.
|
||||
*/
|
||||
use = buf;
|
||||
if (strchr(buf, '.') == NULL) {
|
||||
len = sprintf(buf, FLT_T_STD_FMT, 1, tok->u.flt);
|
||||
len2 = sprintf(buf2, FLT_T_SCI_FMT, digits, tok->u.flt);
|
||||
/* remove trailing 0s from sci format to be fair */
|
||||
size_t epos = strchr(buf2, 'e') - buf2;
|
||||
size_t tpos = epos;
|
||||
while (tpos > 1 && buf2[tpos-1] == '0' && buf2[tpos-2] != '.') --tpos;
|
||||
if (tpos < epos) {
|
||||
memmove(buf2+tpos, buf2+epos, len2-epos+1);
|
||||
len2 -= epos - tpos;
|
||||
}
|
||||
if (len2 < len) { use = buf2; len = len2; }
|
||||
}
|
||||
break;
|
||||
case FLT_HEXACT:
|
||||
len = sprintf(buf, FLT_T_HEX_FMT, tok->u.flt);
|
||||
use = buf;
|
||||
break;
|
||||
}
|
||||
|
||||
assert(len < sizeof(buf));
|
||||
p = use + len;
|
||||
while (*--p == ' ') { *p = '\0'; --len; }
|
||||
(void)strncpy(dest+cur, use, size-cur-1);
|
||||
cur += len;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* OPERATOR */ /*{{{*/
|
||||
case OPERATOR:
|
||||
{
|
||||
static const char *ops[]={ "+", "-", "*", "/", "(", ")", ",", "<", "<=", ">=", ">", "==", "~=", "!=", "^", "%" };
|
||||
|
||||
if ((size-cur)>1)
|
||||
{
|
||||
dest[cur++]=*ops[tok->u.op];
|
||||
if (*(ops[tok->u.op]+1) && size>cur) dest[cur++]=*(ops[tok->u.op]+1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* LIDENT */ /*{{{*/
|
||||
case LIDENT:
|
||||
{
|
||||
size_t identlen;
|
||||
|
||||
identlen=strlen(tok->u.lident);
|
||||
if ((cur+identlen+1)<=size) strcpy(dest+cur,tok->u.lident);
|
||||
else (void)strncpy(dest+cur,tok->u.lident,size-cur-1);
|
||||
cur+=identlen;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* FIDENT */ /*{{{*/
|
||||
case FIDENT:
|
||||
if (debug_level > 2) {
|
||||
printf("...Found function [%s].\n", tfunc[tok->u.fident].name);
|
||||
}
|
||||
cur += print_fident(dest+cur, size-cur-1, tok->u.fident);
|
||||
break;
|
||||
/*}}}*/
|
||||
/* LOCATION */ /*{{{*/
|
||||
case LOCATION:
|
||||
{
|
||||
char buf[60];
|
||||
|
||||
sprintf(buf,"&(%d,%d,%d)",tok->u.location[0],tok->u.location[1],tok->u.location[2]);
|
||||
(void)strncpy(dest+cur,buf,size-cur-1);
|
||||
cur+=strlen(buf);
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* FUNCALL */ /*{{{*/
|
||||
case FUNCALL:
|
||||
{
|
||||
FunctionIdentifier fid = tok->u.funcall.fident;
|
||||
if (tok->u.funcall.argc <= 0)
|
||||
{
|
||||
cur += print_fident(dest+cur, size-cur-1, fid);
|
||||
if (tok->u.funcall.argc == 0)
|
||||
{
|
||||
if (cur < size - 2) { dest[cur++] = '('; dest[cur++] = ')'; }
|
||||
else cur += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
FunctionPrecedence fp = tfunc[fid].precedence;
|
||||
switch (fp)
|
||||
{
|
||||
case PREFIX_FUNC: {
|
||||
cur += print_fident(dest+cur, size-cur-1, fid);
|
||||
if (cur < size) dest[cur++] = '(';
|
||||
for (size_t ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai)
|
||||
{
|
||||
if (ai > 0 && cur < size) dest[cur++] = ',';
|
||||
/* The commas eliminate the need for precedence worries in arguments*/
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv + ai,
|
||||
NO_PRECEDENCE);
|
||||
}
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
break;
|
||||
}
|
||||
case PREFIX_NEG: {
|
||||
assert(tok->u.funcall.argc == 1);
|
||||
assert(tfunc[fid].display_symbol != NULL);
|
||||
if (fp < atprec && cur < size) dest[cur++] = '(';
|
||||
if (cur < size) {
|
||||
strncpy(dest+cur, tfunc[fid].display_symbol, size-cur-1);
|
||||
cur += strlen(tfunc[fid].display_symbol);
|
||||
}
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv, fp);
|
||||
if (fp < atprec && cur < size) dest[cur++] = ')';
|
||||
break;
|
||||
}
|
||||
default: /* infix argument */
|
||||
assert(tok->u.funcall.argc > 1);
|
||||
if (fp < atprec && cur < size) dest[cur++] = '(';
|
||||
/* Check for the special relation sequence notation */
|
||||
bool specialrel = true;
|
||||
if (fid != FUNC_AND || tok->u.funcall.argc < 2) specialrel = false;
|
||||
else {
|
||||
for (int ai = 0; ai < tok->u.funcall.argc; ++ai) {
|
||||
if (tok->u.funcall.argv[ai].type != FUNCALL
|
||||
|| tok->u.funcall.argv[ai].u.funcall.argc != 2
|
||||
|| !IS_RELATION_FUNC(tok->u.funcall.argv[ai].u.funcall.fident))
|
||||
{
|
||||
specialrel = false;
|
||||
break;
|
||||
}
|
||||
if (ai > 0
|
||||
&& !tok_matches(tok->u.funcall.argv[ai].u.funcall.argv,
|
||||
tok->u.funcall.argv[ai-1].u.funcall.argv+1))
|
||||
{
|
||||
specialrel = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (specialrel) {
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv, INFIX_BOOL);
|
||||
for (int ai = 1; ai < tok->u.funcall.argc && cur < size-1; ++ ai) {
|
||||
dest[cur++] = ' ';
|
||||
const char *use =
|
||||
tfunc[tok->u.funcall.argv[ai].u.funcall.fident].name;
|
||||
strncpy(dest+cur, use, size-cur-1);
|
||||
cur += strlen(use);
|
||||
if (cur < size) dest[cur++] = ' ';
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef,
|
||||
tok->u.funcall.argv[ai].u.funcall.argv + 1,
|
||||
INFIX_REL);
|
||||
}
|
||||
} else {
|
||||
for (int ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai)
|
||||
{
|
||||
bool parenarg = false;
|
||||
if (ai > 0) {
|
||||
if (fp < INFIX_MUL && cur < size) dest[cur++] = ' ';
|
||||
const char *use = tfunc[fid].display_symbol;
|
||||
if (use == NULL) use = tfunc[fid].name;
|
||||
strncpy(dest+cur, use, size-cur-1);
|
||||
cur += strlen(use);
|
||||
if (fp < INFIX_MUL && cur < size) dest[cur++] = ' ';
|
||||
} else if (fp > PREFIX_NEG) {
|
||||
char powbuf[4096];
|
||||
size_t arglen = ptokatprec(powbuf, sizeof(powbuf), 0, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv, fp);
|
||||
assert(arglen < sizeof(powbuf)-1);
|
||||
if (powbuf[0] == '-') {
|
||||
parenarg = true;
|
||||
if (cur < size) dest[cur++] = '(';
|
||||
}
|
||||
}
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv + ai, fp);
|
||||
if (parenarg && cur < size) dest[cur++] = ')';
|
||||
}
|
||||
}
|
||||
if (fp < atprec && cur < size) dest[cur++] = ')';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* BOOL */ /*{{{*/
|
||||
case BOOL:
|
||||
{
|
||||
const char *rep = "false";
|
||||
if (tok->u.bl) rep = "true";
|
||||
strncpy(dest+cur, rep, size-cur-1);
|
||||
cur += strlen(rep);
|
||||
break;
|
||||
}
|
||||
/* EEK */ /*{{{*/
|
||||
case EEK:
|
||||
{
|
||||
if (ef == RESTORE_ERROR) {
|
||||
strncpy(dest + cur, "error(", size-cur-1);
|
||||
cur += 6;
|
||||
if (cur < size - 1)
|
||||
cur += print_string(dest+cur, size-cur-1, tok->u.err, QUOTE_STRING);
|
||||
if (cur < size - 1)
|
||||
dest[cur++] = ')';
|
||||
break;
|
||||
}
|
||||
(void)strncpy(dest+cur, _("ERROR"), size-cur-1);
|
||||
cur += strlen(_("ERROR"));
|
||||
if (ef == VERBOSE_ERROR)
|
||||
{
|
||||
(void)strncpy(dest+cur, ": ", size-cur-1);
|
||||
cur += 2;
|
||||
size_t errlen = strlen(tok->u.err);
|
||||
if ((cur+errlen+1) < size) strcpy(dest+cur, tok->u.err);
|
||||
else (void)strncpy(dest+cur, tok->u.err, size-cur-1);
|
||||
cur += errlen;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* default */ /*{{{*/
|
||||
default: assert(0);
|
||||
/*}}}*/
|
||||
}
|
||||
if (cur<size) dest[cur] = 0;
|
||||
else
|
||||
{
|
||||
dest[size-1] = 0;
|
||||
cur = size;
|
||||
}
|
||||
if (field_width && mbslen(dest) > field_width) {
|
||||
for (cur = 0; cur < field_width; ++cur) dest[cur] = '#';
|
||||
dest[cur] = 0;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
|
||||
size_t printtok(char* dest, size_t size, size_t field_width,
|
||||
StringFormat sf, FloatFormat ff,
|
||||
int digits, ErrorFormat ef, const Token *tok)
|
||||
{
|
||||
return ptokatprec(dest, size, field_width, sf, ff, digits, ef, tok,
|
||||
NO_PRECEDENCE);
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
static char dbgpbuf[4096];
|
||||
|
||||
/* dbgprint -- simple on the fly print for in the debugger */
|
||||
const char *dbgprint(const Token* tok) {
|
||||
size_t used = printtok(dbgpbuf, sizeof(dbgpbuf), 0, QUOTE_STRING, FLT_COMPACT,
|
||||
0, VERBOSE_ERROR, tok);
|
||||
if (used > sizeof(dbgpbuf) - 2) {
|
||||
printf(_("Warning: buffer overflow in dbgprint"));
|
||||
}
|
||||
return dbgpbuf;
|
||||
}
|
||||
|
||||
/* print -- print token sequence */ /*{{{*/
|
||||
void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff,
|
||||
int digits, Token **n)
|
||||
{
|
||||
size_t cur;
|
||||
|
||||
cur=0;
|
||||
if (n != EMPTY_TVEC)
|
||||
for (; cur<size-1 && (*n) != NULLTOKEN; ++n)
|
||||
cur += printtok(s+cur, size-cur, 0, sf, ff, digits, TRUNCATED_ERROR, *n);
|
||||
if (cur<size) s[cur] = 0;
|
||||
else s[size-1] = 0;
|
||||
if (chars && mbslen(s) > chars) {
|
||||
for (cur=0; cur < chars; ++cur) s[cur] = '#';
|
||||
s[cur] = 0;
|
||||
}
|
||||
}
|
||||
/*}}}*/
|
||||
|
@ -2,55 +2,29 @@
|
||||
#define CELL_H
|
||||
|
||||
#include "scanner.h"
|
||||
#include "style.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{ BASE_CONT=0, ITER_CONT, ATTR_REF, MAX_PERSIST_TV = ATTR_REF,
|
||||
CURR_VAL, RES_VAL,
|
||||
{ BASE_CONT=0, ITER_CONT, STYLE_CONT, MAX_PERSIST_TV = STYLE_CONT,
|
||||
CURR_VAL, RES_VAL, STYLE_VAL,
|
||||
CONTINGENT /* Must be last, marks end of many loops */
|
||||
} TokVariety;
|
||||
extern const char *TokVariety_Name[];
|
||||
|
||||
typedef enum { LEFT=0, RIGHT=1, CENTER=2, AUTOADJUST=3 } Adjust;
|
||||
extern const char *Adjust_Name[];
|
||||
#define MAX_ADJUST_NAME_LENGTH 16
|
||||
extern const char Adjust_Char[];
|
||||
|
||||
typedef enum
|
||||
{ FLT_DECIMAL=0, FLT_SCIENTIFIC, FLT_COMPACT, FLT_HEXACT }
|
||||
FloatFormat;
|
||||
extern const char *FloatFormat_Name[];
|
||||
#define MAX_FLOATFORM_NAME_LENGTH 16
|
||||
extern const char FloatFormat_Char[];
|
||||
|
||||
typedef unsigned char ColorNum;
|
||||
#define MAX_MAX_COLORS UCHAR_MAX;
|
||||
|
||||
typedef enum { FOREGROUND = 0, BACKGROUND, NUM_COLOR_ASPECTS } ColorAspect;
|
||||
extern const char *ColorAspect_Name[];
|
||||
extern const ColorNum DefaultCN[];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Token tok[CONTINGENT];
|
||||
char *label;
|
||||
int precision;
|
||||
Adjust adjust;
|
||||
FloatFormat fform;
|
||||
ColorNum aspect[NUM_COLOR_ASPECTS];
|
||||
unsigned int updated:1;
|
||||
unsigned int shadowed:1;
|
||||
unsigned int locked:1;
|
||||
unsigned int transparent:1;
|
||||
unsigned int ignored:1;
|
||||
unsigned int clock_t0:1;
|
||||
unsigned int clock_t1:1;
|
||||
unsigned int clock_t2:1;
|
||||
unsigned int bold:1;
|
||||
unsigned int underline:1;
|
||||
} Cell;
|
||||
|
||||
#define NULLCELL ((Cell*)0)
|
||||
@ -58,28 +32,13 @@ typedef struct
|
||||
typedef enum {ALTER_LABEL, PRESERVE_LABEL} LabelHandling;
|
||||
|
||||
Token gettok(const Cell *cell, TokVariety v);
|
||||
Adjust getadjust(const Cell *cell);
|
||||
bool shadowed(const Cell *cell);
|
||||
bool isbold(const Cell *cell);
|
||||
bool underlined(const Cell *cell);
|
||||
ColorNum getcolor(const Cell *cell, ColorAspect aspect);
|
||||
bool locked(const Cell *cell);
|
||||
bool transparent(const Cell *cell);
|
||||
bool ignored(const Cell *cell);
|
||||
FloatFormat getfltformat(const Cell *cell);
|
||||
int getprecision(const Cell* cell);
|
||||
const char *getlabel(const Cell *cell);
|
||||
void initcellcontents(Cell *cell);
|
||||
void freecellcontents(Cell *cell);
|
||||
void copycell(Cell *to, const Cell *from, LabelHandling lh);
|
||||
|
||||
typedef enum {DIRECT_STRING, QUOTE_STRING} StringFormat;
|
||||
typedef enum {TRUNCATED_ERROR, VERBOSE_ERROR, RESTORE_ERROR} ErrorFormat;
|
||||
size_t printtok(char *dest, size_t size, size_t field_width, StringFormat sf,
|
||||
FloatFormat ff, int digits, ErrorFormat ef, const Token *tok);
|
||||
const char *dbgprint(const Token *tok); /* for use in debugging */
|
||||
void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff,
|
||||
int digits, Token **n);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -34,7 +34,6 @@ const char *savecontext(Sheet *sheet, const char *name, int body,
|
||||
char buf[1024];
|
||||
char num[20];
|
||||
char fullname[PATH_MAX];
|
||||
Cell *cell;
|
||||
/*}}}*/
|
||||
|
||||
/* asserts */ /*{{{*/
|
||||
@ -45,7 +44,7 @@ const char *savecontext(Sheet *sheet, const char *name, int body,
|
||||
w[X] = beg[X];
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
||||
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
||||
if (shadowed(sheet, w)) return _("Shadowed cells in first column");
|
||||
if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
{
|
||||
@ -85,29 +84,31 @@ const char *savecontext(Sheet *sheet, const char *name, int body,
|
||||
{
|
||||
for (w[X]=beg[X]; w[X]<=end[X]; )
|
||||
{
|
||||
int multicols;
|
||||
char *bufp;
|
||||
|
||||
if (w[X] > beg[X] && fputs_close("\\NC",fp)==EOF) return strerror(errno);
|
||||
for (multicols=w[X]+1; multicols<sheet->dimx && SHADOWEDC(sheet,multicols,w[Y],w[Z]); ++multicols);
|
||||
multicols=multicols-w[X];
|
||||
if (multicols>1) fprintf(fp,"\\use{%d}",multicols);
|
||||
cell = CELL_AT(sheet, w);
|
||||
switch (getadjust(cell))
|
||||
if (w[X] > beg[X] && fputs_close("\\NC", fp) == EOF)
|
||||
return strerror(errno);
|
||||
Location mw; LOCATION_GETS(mw, w);
|
||||
for (++(mw[X]); mw[X] < sheet->dimx && shadowed(sheet, mw); ++(mw[X]));
|
||||
int multicols = mw[X] - w[X];
|
||||
if (multicols > 1) fprintf(fp,"\\use{%d}", multicols);
|
||||
Style cs = getstyle(sheet, w);
|
||||
switch (cs.adjust)
|
||||
{
|
||||
case LEFT: if (fputs_close("\\JustLeft ",fp)==EOF) return strerror(errno); break;
|
||||
case RIGHT: if (fputs_close("\\JustRight ",fp)==EOF) return strerror(errno); break;
|
||||
case CENTER: if (fputs_close("\\JustCenter ",fp)==EOF) return strerror(errno); break;
|
||||
case LEFT:
|
||||
if (fputs_close("\\JustLeft ", fp) == EOF) return strerror(errno);
|
||||
case RIGHT:
|
||||
if (fputs_close("\\JustRight ", fp) == EOF) return strerror(errno);
|
||||
case CENTER:
|
||||
if (fputs_close("\\JustCenter ", fp) == EOF) return strerror(errno);
|
||||
default: assert(0);
|
||||
}
|
||||
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell),
|
||||
getprecision(cell), sheet, w);
|
||||
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, cs.fform, cs.precision,
|
||||
sheet, w);
|
||||
/* if (fputs_close("}{",fp)==EOF) return strerror(errno);*/
|
||||
if (transparent(cell))
|
||||
if (cs.transparent)
|
||||
{
|
||||
if (fputs_close(buf,fp)==EOF) return strerror(errno);
|
||||
if (fputs_close(buf,fp) == EOF) return strerror(errno);
|
||||
}
|
||||
else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
|
||||
else for (char *bufp = buf; *bufp; ++bufp) switch (*bufp)
|
||||
{
|
||||
case '%':
|
||||
case '$':
|
||||
|
@ -239,6 +239,39 @@ Token tadd(Token l, Token r)
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
if (l.type == STYLE && r.type == STYLE)
|
||||
/* result fills in any unset fields in l from r */ /*{{{*/
|
||||
{
|
||||
result.type = STYLE;
|
||||
memcpy(&(result.u.style), &(l.u.style), sizeof(Style));
|
||||
if (result.u.style.precision == NO_PRECISION)
|
||||
result.u.style.precision = r.u.style.precision;
|
||||
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
|
||||
if (result.u.style.aspect[ca] == NO_COLOR_SET)
|
||||
result.u.style.aspect[ca] = r.u.style.aspect[ca];
|
||||
if (result.u.style.adjust == AUTOADJUST)
|
||||
result.u.style.adjust = r.u.style.adjust;
|
||||
if (result.u.style.fform == FLT_NO_FORMAT)
|
||||
result.u.style.fform = r.u.style.fform;
|
||||
if (!result.u.style.shadowed_set && r.u.style.shadowed_set) {
|
||||
result.u.style.shadowed = r.u.style.shadowed;
|
||||
result.u.style.shadowed_set = true;
|
||||
}
|
||||
if (!result.u.style.transparent_set && r.u.style.transparent_set) {
|
||||
result.u.style.transparent = r.u.style.transparent;
|
||||
result.u.style.transparent_set = true;
|
||||
}
|
||||
if (!result.u.style.bold_set && r.u.style.bold_set) {
|
||||
result.u.style.bold = r.u.style.bold;
|
||||
result.u.style.bold_set = true;
|
||||
}
|
||||
if (!result.u.style.underline_set && r.u.style.underline_set) {
|
||||
result.u.style.underline = r.u.style.underline;
|
||||
result.u.style.underline_set = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
return operand_type_error(cntxt, l.type, r.type);
|
||||
}
|
||||
/*}}}*/
|
||||
@ -890,6 +923,7 @@ Token teq(Token l, Token r)
|
||||
if (dim < HYPER) result.u.bl = false;
|
||||
return result;
|
||||
}
|
||||
case STYLE: result.u.bl = style_equal(l.u.style, r.u.style); return result;
|
||||
default: break;
|
||||
}
|
||||
return relational_type_mismatch(l.type, r.type);
|
||||
|
@ -766,10 +766,12 @@ static Token int_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||
case -1: return self_func(self, argc, argv);
|
||||
case 0: arg = recompvalue(upd_sheet, upd_l); break;
|
||||
case 2:
|
||||
if (argv[1].type == EEK) return argv[1];
|
||||
if (argv[1].type != FIDENT) return duperror(&result, usage);
|
||||
dir = argv[1].u.fident;
|
||||
/* FALL THROUGH */
|
||||
case 1:
|
||||
if (argv[0].type == EEK) return argv[0];
|
||||
arg = tcopy(argv[0]);
|
||||
break;
|
||||
default: return duperror(&result, usage);
|
||||
@ -891,7 +893,7 @@ static Token string_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||
return duperror(&result, staticbuf);
|
||||
}
|
||||
result.type = STRING;
|
||||
size_t size = printtok(staticbuf, sizeof(staticbuf), 0, DIRECT_STRING, ff,
|
||||
size_t size = printtok(staticbuf, sizeof(staticbuf), -1, DIRECT_STRING, ff,
|
||||
precision, VERBOSE_ERROR, &arg);
|
||||
tfree(&arg);
|
||||
if (size > sizeof(staticbuf) - 2)
|
||||
@ -974,6 +976,104 @@ static Token is_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* precision_func -- create a style with just precision set */ /*{{{*/
|
||||
static Token precision_func(FunctionIdentifier self,
|
||||
int argc, const Token argv[])
|
||||
{
|
||||
assert(self == FUNC_PRECISION);
|
||||
Token result;
|
||||
if (argc != 1 || argv[0].type != INT)
|
||||
return duperror(&result, _("Usage: precision(int)"));
|
||||
result.type = STYLE;
|
||||
clearstyle(&(result.u.style));
|
||||
result.u.style.precision = argv[0].u.integer;
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* aspect_func -- create a style with just a color set */ /*{{{*/
|
||||
static Token aspect_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||
{
|
||||
ColorAspect ca = FOREGROUND;
|
||||
if (self == FUNC_BACKGROUND) ca = BACKGROUND;
|
||||
Token result;
|
||||
if (argc != 1 || argv[0].type != INT) {
|
||||
const char *templ = _("Usage: %s(int)");
|
||||
result.type = EEK;
|
||||
result.u.err = malloc(strlen(templ) + MAX_FUNC_NAME_LENGTH + 1);
|
||||
sprintf(result.u.err, templ, tfunc[self].name);
|
||||
return result;
|
||||
}
|
||||
result.type = STYLE;
|
||||
clearstyle(&(result.u.style));
|
||||
result.u.style.aspect[ca] = argv[0].u.integer;
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* justify_func -- create a style with just a justification */ /*{{{*/
|
||||
static Token justify_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||
{
|
||||
Token result;
|
||||
const char *usage = _("Usage: justify(left|right|center)");
|
||||
if (argc != 1 || (argv[0].type != FIDENT && argv[0].type != LOCATION))
|
||||
return duperror(&result, usage);
|
||||
result.type = STYLE;
|
||||
clearstyle(&(result.u.style));
|
||||
if (argv[0].type == FIDENT)
|
||||
if (argv[0].u.fident == FUNC_CENTER)
|
||||
result.u.style.adjust = CENTER;
|
||||
else return duperror(&result, usage);
|
||||
else /* left or right */
|
||||
if (argv[0].u.location[Y] != 0 || argv[0].u.location[Z] != 0)
|
||||
return duperror(&result, usage);
|
||||
else
|
||||
result.u.style.adjust = (argv[0].u.location[X] < 0) ? LEFT : RIGHT;
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* floatfmt_func -- create a style with just a float format */ /*{{{*/
|
||||
static Token floatfmt_func(FunctionIdentifier self,
|
||||
int argc, const Token argv[])
|
||||
{
|
||||
Token result;
|
||||
const char *usage = _("Usage: floatfmt(decimal|scientific|compact|hexact)");
|
||||
if (argc != 1 || argv[0].type != FIDENT) return duperror(&result, usage);
|
||||
result.type = STYLE;
|
||||
clearstyle(&(result.u.style));
|
||||
switch (argv[0].u.fident) {
|
||||
case FUNC_DECIMAL: result.u.style.fform = FLT_DECIMAL; break;
|
||||
case FUNC_SCIENTIFIC: result.u.style.fform = FLT_SCIENTIFIC; break;
|
||||
case FUNC_COMPACT: result.u.style.fform = FLT_COMPACT; break;
|
||||
case FUNC_HEXACT: result.u.style.fform = FLT_HEXACT; break;
|
||||
default: return duperror(&result, usage);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
#define STYLEFLAGFUNC(field) static Token\
|
||||
field##_func(FunctionIdentifier self, int argc, const Token argv[])\
|
||||
{\
|
||||
Token result;\
|
||||
result.type = STYLE;\
|
||||
clearstyle(&(result.u.style));\
|
||||
result.u.style.field##_set = true;\
|
||||
result.u.style.field = true;\
|
||||
if (argc == 0) return result;\
|
||||
if (argc == 1 && argv[0].type == BOOL) {\
|
||||
result.u.style.field = argv[0].u.bl;\
|
||||
return result;\
|
||||
}\
|
||||
return duperror(&result, _("Usage:" #field "([bool])"));\
|
||||
}
|
||||
|
||||
STYLEFLAGFUNC(shadowed)
|
||||
STYLEFLAGFUNC(transparent)
|
||||
STYLEFLAGFUNC(bold)
|
||||
STYLEFLAGFUNC(underline)
|
||||
|
||||
/* accum_func -- common implementation of functions that accumulate all of
|
||||
their arguments into a final value.
|
||||
*/
|
||||
@ -1368,42 +1468,35 @@ static Token strftime_func(FunctionIdentifier fi, int argc, const Token argv[])
|
||||
/*}}}*/
|
||||
|
||||
/* clock */ /*{{{*/
|
||||
static Token clock_func(FunctionIdentifier self,int argc, const Token argv[])
|
||||
static Token clock_func(FunctionIdentifier self, int argc, const Token argv[])
|
||||
{
|
||||
assert(self == FUNC_CLOCK);
|
||||
/* variables */ /*{{{*/
|
||||
Token result;
|
||||
/*}}}*/
|
||||
|
||||
if (argc==2 && argv[0].type==INT && argv[1].type==LOCATION) /* clock(condition,location) */ /*{{{*/
|
||||
Token result; result.type = EMPTY;
|
||||
char *usage = _("Usage: clock(condition,location[,location])");
|
||||
if (argc < 2) return duperror(&result, usage);
|
||||
if (argv[0].type == EEK) return argv[0];
|
||||
/* Special case: if the first argument is a location, probably forgot the
|
||||
condition */
|
||||
if (argv[0].type == LOCATION) return duperror(&result, usage);
|
||||
if (!(tbool(argv[0]).u.bl)) return result;
|
||||
if (argc == 2 && argv[1].type == LOCATION) clk(upd_sheet, argv[1].u.location);
|
||||
else if (argc == 3 && argv[1].type == LOCATION && argv[2].type == LOCATION) /* clock(condition,location,location) */ /*{{{*/
|
||||
{
|
||||
if (argv[0].u.integer) clk(upd_sheet, argv[1].u.location);
|
||||
result.type=EMPTY;
|
||||
Location w;
|
||||
int x1,y1,z1;
|
||||
int x2,y2,z2;
|
||||
|
||||
x1=argv[1].u.location[0]; x2=argv[2].u.location[0]; posorder(&x1,&x2);
|
||||
y1=argv[1].u.location[1]; y2=argv[2].u.location[1]; posorder(&y1,&y2);
|
||||
z1=argv[1].u.location[2]; z2=argv[2].u.location[2]; posorder(&z1,&z2);
|
||||
|
||||
for (w[X]=x1; w[X]<=x2; ++(w[X]))
|
||||
for (w[Y]=y1; w[Y]<=y2; ++(w[Y]))
|
||||
for (w[Z]=z1; w[Z]<=z2; ++(w[Z]))
|
||||
clk(upd_sheet, w);
|
||||
}
|
||||
/*}}}*/
|
||||
else if (argc==3 && argv[0].type==INT && argv[1].type==LOCATION && argv[2].type==LOCATION) /* clock(condition,location,location) */ /*{{{*/
|
||||
{
|
||||
if (argv[0].u.integer)
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
Location w;
|
||||
int x1,y1,z1;
|
||||
int x2,y2,z2;
|
||||
/*}}}*/
|
||||
|
||||
x1=argv[1].u.location[0]; x2=argv[2].u.location[0]; posorder(&x1,&x2);
|
||||
y1=argv[1].u.location[1]; y2=argv[2].u.location[1]; posorder(&y1,&y2);
|
||||
z1=argv[1].u.location[2]; z2=argv[2].u.location[2]; posorder(&z1,&z2);
|
||||
|
||||
for (w[X]=x1; w[X]<=x2; ++(w[X]))
|
||||
for (w[Y]=y1; w[Y]<=y2; ++(w[Y]))
|
||||
for (w[Z]=z1; w[Z]<=z2; ++(w[Z]))
|
||||
clk(upd_sheet, w);
|
||||
}
|
||||
result.type=EMPTY;
|
||||
}
|
||||
/*}}}*/
|
||||
else duperror(&result, _("Usage: clock(condition,location[,location])"));
|
||||
else duperror(&result, usage);
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1652,6 +1745,18 @@ Tfunc tfunc[]=
|
||||
[FUNC_OPERATOR] = { "operator", self_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_STRING] = { "string", string_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
|
||||
/* Style functions */
|
||||
[FUNC_PRECISION] = { "precision", precision_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_FOREGROUND] = { "foreground", aspect_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_BACKGROUND] = { "background", aspect_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_JUSTIFY] = { "justify", justify_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_FLOATFMT] = { "floatfmt", floatfmt_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_SHADOWED] = { "shadowed", shadowed_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_TRANSPARENT] = { "transparent", transparent_func,PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_BOLD] = { "bold", bold_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_UNDERLINE] = { "underline", underline_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_CENTER] = { "center", self_func, PREFIX_FUNC, FUNCT, 0 },
|
||||
|
||||
/* Block operations */
|
||||
[FUNC_MAX] = { "max", reg_disp, PREFIX_FUNC, FUNCT, 0 },
|
||||
[FUNC_MIN] = { "min", reg_disp, PREFIX_FUNC, FUNCT, 0 },
|
||||
|
@ -1,6 +1,12 @@
|
||||
#ifndef FUNC_H
|
||||
#define FUNC_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_FUNC_NAME_LENGTH 20
|
||||
|
||||
typedef enum
|
||||
@ -37,7 +43,9 @@ typedef enum
|
||||
FUNC_BOOL, FUNC_EMPTY, FUNC_FIDENT,
|
||||
FUNC_FUNCALL, FUNC_LIDENT, FUNC_LOCATION, FUNC_NUMBER, FUNC_OPERATOR,
|
||||
|
||||
FUNC_IS, FUNC_FIND,
|
||||
FUNC_IS, FUNC_FIND, FUNC_PRECISION, FUNC_FOREGROUND, FUNC_BACKGROUND,
|
||||
FUNC_JUSTIFY, FUNC_FLOATFMT, FUNC_SHADOWED, FUNC_TRANSPARENT, FUNC_BOLD,
|
||||
FUNC_UNDERLINE, FUNC_CENTER,
|
||||
|
||||
N_FUNCTION_IDS
|
||||
} FunctionIdentifier;
|
||||
@ -68,4 +76,8 @@ typedef struct
|
||||
FunctionIdentifier identcode(const char *s, size_t len);
|
||||
extern Tfunc tfunc[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -45,7 +45,7 @@ const char *savehtml(Sheet *sheet, const char *name, int body,
|
||||
w[X] = beg[X];
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
||||
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
||||
if (shadowed(sheet, w)) return _("Shadowed cells in first column");
|
||||
if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
{
|
||||
@ -71,28 +71,26 @@ const char *savehtml(Sheet *sheet, const char *name, int body,
|
||||
if (fputs_close("<tr>",fp)==EOF) return strerror(errno);
|
||||
for (w[X]=beg[X]; w[X]<=end[X]; )
|
||||
{
|
||||
int multicols;
|
||||
char *bufp;
|
||||
|
||||
for (multicols=w[X]+1; multicols<sheet->dimx && SHADOWEDC(sheet,multicols,w[Y],w[Z]); ++multicols);
|
||||
multicols = multicols - w[X];
|
||||
if (multicols>1) fprintf(fp,"<td colspan=%d",multicols);
|
||||
Location mw; LOCATION_GETS(mw, w);
|
||||
for (++(mw[X]); mw[X] < sheet->dimx && shadowed(sheet, mw); ++(mw[X]));
|
||||
int multicols = mw[X] - w[X];
|
||||
if (multicols > 1) fprintf(fp,"<td colspan=%d",multicols);
|
||||
else fprintf(fp,"<td");
|
||||
cell = CELL_AT(sheet, w);
|
||||
switch (getadjust(cell))
|
||||
Style cs = getstyle(sheet, w);
|
||||
switch (cs.adjust)
|
||||
{
|
||||
case LEFT: if (fputs_close(" align=left>",fp)==EOF) return strerror(errno); break;
|
||||
case RIGHT: if (fputs_close(" align=right>",fp)==EOF) return strerror(errno); break;
|
||||
case CENTER: if (fputs_close(" align=center>",fp)==EOF) return strerror(errno); break;
|
||||
default: assert(0);
|
||||
}
|
||||
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell),
|
||||
getprecision(cell), sheet, w);
|
||||
if (transparent(cell))
|
||||
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, cs.fform, cs.precision,
|
||||
sheet, w);
|
||||
if (cs.transparent)
|
||||
{
|
||||
if (fputs_close(buf,fp)==EOF) return strerror(errno);
|
||||
if (fputs_close(buf,fp) == EOF) return strerror(errno);
|
||||
}
|
||||
else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
|
||||
else for (char *bufp = buf; *bufp; ++bufp) switch (*bufp)
|
||||
{
|
||||
case '<': if (fputs_close("<",fp)==EOF) return strerror(errno); break;
|
||||
case '>': if (fputs_close(">",fp)==EOF) return strerror(errno); break;
|
||||
@ -110,14 +108,14 @@ const char *savehtml(Sheet *sheet, const char *name, int body,
|
||||
if (fputs_close("</table>\n",fp)==EOF) return strerror(errno);
|
||||
if (body)
|
||||
{
|
||||
if (fclose(fp)==EOF) return strerror(errno);
|
||||
if (fclose(fp) == EOF) return strerror(errno);
|
||||
}
|
||||
}
|
||||
if (!body)
|
||||
{
|
||||
if (fputs_close("</body>\n</html>\n",fp)==EOF) return strerror(errno);
|
||||
if (fclose(fp)==EOF) return strerror(errno);
|
||||
if (fputs_close("</body>\n</html>\n",fp) == EOF) return strerror(errno);
|
||||
if (fclose(fp) == EOF) return strerror(errno);
|
||||
}
|
||||
return (const char*)0;
|
||||
return NULL;
|
||||
}
|
||||
/*}}}*/
|
||||
|
@ -46,7 +46,7 @@ const char *savelatex(Sheet *sheet, const char *name, int body,
|
||||
w[X] = beg[X];
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
||||
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
||||
if (shadowed(sheet, w)) return _("Shadowed cells in first column");
|
||||
if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
{
|
||||
@ -85,29 +85,28 @@ const char *savelatex(Sheet *sheet, const char *name, int body,
|
||||
{
|
||||
for (w[X]=beg[X]; w[X]<=end[X]; )
|
||||
{
|
||||
int multicols;
|
||||
char *bufp;
|
||||
|
||||
if (w[X]>beg[X] && fputc_close('&',fp)==EOF) return strerror(errno);
|
||||
for (multicols = w[X]+1; multicols<sheet->dimx && SHADOWEDC(sheet,multicols,w[Y],w[Z]); ++multicols);
|
||||
multicols = multicols - w[X];
|
||||
fprintf(fp,"\\multicolumn{%d}{",multicols);
|
||||
cell = CELL_AT(sheet, w);
|
||||
switch (getadjust(cell))
|
||||
if (w[X] > beg[X] && fputc_close('&', fp) == EOF)
|
||||
return strerror(errno);
|
||||
Location mw; LOCATION_GETS(mw,w);
|
||||
for (mw[X]++; mw[X] < sheet->dimx && shadowed(sheet, mw); mw[X]++);
|
||||
int multicols = mw[X] - w[X];
|
||||
fprintf(fp, "\\multicolumn{%d}{", multicols);
|
||||
Style cs = getstyle(sheet, w);
|
||||
switch (cs.adjust)
|
||||
{
|
||||
case LEFT: if (fputc_close('l',fp)==EOF) return strerror(errno); break;
|
||||
case RIGHT: if (fputc_close('r',fp)==EOF) return strerror(errno); break;
|
||||
case CENTER: if (fputc_close('c',fp)==EOF) return strerror(errno); break;
|
||||
default: assert(0);
|
||||
}
|
||||
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell),
|
||||
getprecision(cell), sheet, w);
|
||||
if (fputs_close("}{",fp)==EOF) return strerror(errno);
|
||||
if (transparent(cell))
|
||||
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, cs.fform, cs.precision,
|
||||
sheet, w);
|
||||
if (fputs_close("}{", fp) == EOF) return strerror(errno);
|
||||
if (cs.transparent)
|
||||
{
|
||||
if (fputs_close(buf,fp)==EOF) return strerror(errno);
|
||||
}
|
||||
else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
|
||||
else for (char *bufp = buf; *bufp; ++bufp) switch (*bufp)
|
||||
{
|
||||
case '%':
|
||||
case '$':
|
||||
|
@ -50,7 +50,7 @@ extern char *strdup(const char* s);
|
||||
char helpfile[PATH_MAX];
|
||||
bool batch = false;
|
||||
unsigned int batchln=0;
|
||||
int def_precision = DEF_PRECISION;
|
||||
PrecisionLevel def_precision = DEF_PRECISION;
|
||||
StringFormat quote = DIRECT_STRING;
|
||||
bool header = true;
|
||||
bool always_redraw = false;
|
||||
@ -66,7 +66,8 @@ void moveto(Sheet *sheet, int x, int y, int z)
|
||||
if (x >= 0) sheet->cur[X] = x;
|
||||
if (y >= 0) sheet->cur[Y] = y;
|
||||
if (z >= 0) need_redraw++, sheet->cur[Z] = z;
|
||||
while (sheet->cur[X] > 0 && SHADOWED(sheet, sheet->cur)) sheet->cur[X] += xdir;
|
||||
while (sheet->cur[X] > 0 && shadowed(sheet, sheet->cur))
|
||||
sheet->cur[X] += xdir;
|
||||
|
||||
if (getmarkstate(sheet) == MARKING) LOCATION_GETS(sheet->mark2, sheet->cur);
|
||||
|
||||
@ -133,16 +134,10 @@ static int line_idedit(char *ident, size_t size, const char *prompt, size_t *x,
|
||||
/*}}}*/
|
||||
|
||||
/* doanyway -- ask if action should be done despite unsaved changes */ /*{{{*/
|
||||
int doanyway(Sheet *sheet, const char *msg)
|
||||
bool doanyway(Sheet *sheet, const char *msg)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (sheet->changed) {
|
||||
result = line_ok(msg,0);
|
||||
if (result < 0) return 0;
|
||||
return result;
|
||||
}
|
||||
return 1;
|
||||
if (sheet->changed && line_ok(msg, 0) <= 0) return false;
|
||||
return true;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
@ -172,6 +167,7 @@ static int do_edit(Sheet *cursheet, Key c, char *expr, TokVariety tv)
|
||||
t = scan(&s);
|
||||
prompt = _("Cell contents:");
|
||||
if (tv == ITER_CONT) prompt = _("Clocked cell contents");
|
||||
if (tv == STYLE_CONT) prompt = _("Style expression");
|
||||
if (*s != '\0')
|
||||
if (t == EMPTY_TVEC)
|
||||
line_msg(prompt, "XXX invalid expression");
|
||||
@ -190,14 +186,14 @@ static int do_edit(Sheet *cursheet, Key c, char *expr, TokVariety tv)
|
||||
if (c == K_NONE)
|
||||
{
|
||||
cntt = gettok(cell, tv);
|
||||
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, 0,
|
||||
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1,
|
||||
TRUNCATED_ERROR, &cntt);
|
||||
s = buf+strlen(buf);
|
||||
}
|
||||
else if (c == K_BACKSPACE)
|
||||
{
|
||||
cntt = gettok(cell, tv);
|
||||
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, 0,
|
||||
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1,
|
||||
TRUNCATED_ERROR, &cntt);
|
||||
if (strlen(buf)) *mbspos(buf+strlen(buf),-1)='\0';
|
||||
s = buf+strlen(buf);
|
||||
@ -205,7 +201,7 @@ static int do_edit(Sheet *cursheet, Key c, char *expr, TokVariety tv)
|
||||
else if (c == K_DC)
|
||||
{
|
||||
cntt = gettok(cell, tv);
|
||||
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, 0,
|
||||
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1,
|
||||
TRUNCATED_ERROR, &cntt);
|
||||
memmove(buf,mbspos(buf,1),strlen(mbspos(buf,1))+1);
|
||||
s = buf;
|
||||
@ -335,6 +331,7 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
do_mark(cursheet, GET_MARK_CUR);
|
||||
bool onecell = SAME_LOC(cursheet->mark1, cursheet->mark2);
|
||||
Cell *fcell = safe_cell_at(cursheet, cursheet->mark1);
|
||||
Style fs = getstyle(cursheet, cursheet->mark1);
|
||||
bool changed = false;
|
||||
if (action != ADJUST_LOCK && onecell && locked(fcell))
|
||||
{
|
||||
@ -374,7 +371,7 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
/* 5 -- set precision */ /*{{{*/
|
||||
case ADJUST_PRECISION:
|
||||
{
|
||||
int n = getprecision(fcell);
|
||||
int n = fs.precision;
|
||||
const char* prompt = _("Precision for block:");
|
||||
if (onecell) prompt = _("Precision for cell:");
|
||||
int c = line_numedit(&n, prompt);
|
||||
@ -389,7 +386,7 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
ca = BACKGROUND;
|
||||
/* FALL THROUGH */
|
||||
case ADJUST_FOREGROUND: {
|
||||
int n = getcolor(fcell, ca);
|
||||
int n = fs.aspect[ca];
|
||||
const char* prompt = _("%s for block:");
|
||||
if (onecell) prompt = _("%s for cell:");
|
||||
char pbuf[256];
|
||||
@ -406,10 +403,10 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
int n;
|
||||
Location r;
|
||||
LOCATION_GETS(r, cursheet->mark1); ++r[X];
|
||||
if (onecell) n = !SHADOWED(cursheet, r);
|
||||
if (onecell) n = !(fs.shadowed);
|
||||
else n = line_binary(_("Set block to:"),
|
||||
_("uU)nshadowed"), _("sS)hadowed"),
|
||||
!SHADOWED(cursheet, r));
|
||||
!(fs.shadowed));
|
||||
if (cursheet->mark1[X] == 0 && n == 1) {
|
||||
line_msg(_("Shadow cell:"),_("You can not shadow cells in column 0"));
|
||||
break;
|
||||
@ -423,8 +420,8 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
if (n == 0)
|
||||
{
|
||||
LOCATION_GETS(r, w);
|
||||
if (!SHADOWED(cursheet, r)) ++(r[X]);
|
||||
for (; SHADOWED(cursheet, r); ++(r[X]))
|
||||
if (!shadowed(cursheet, r)) ++(r[X]);
|
||||
for (; shadowed(cursheet, r); ++(r[X]))
|
||||
changed = shadow(cursheet, r, false) || changed;
|
||||
}
|
||||
else if (w[X]>0) changed = shadow(cursheet, w, true) || changed;
|
||||
@ -439,10 +436,10 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (onecell) n = !transparent(fcell);
|
||||
if (onecell) n = !(fs.transparent);
|
||||
else n = line_binary(_("Set block to:"),
|
||||
_("pP)rotected"), _("tT)ransparent:"),
|
||||
!transparent(fcell));
|
||||
!(fs.transparent));
|
||||
if (n >= 0)
|
||||
for (ALL_LOCS_IN_REGION(cursheet,w))
|
||||
changed = maketrans(cursheet, w, n) || changed;
|
||||
@ -454,9 +451,9 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (onecell) n = !isbold(fcell);
|
||||
if (onecell) n = !(fs.bold);
|
||||
else n = line_binary(_("Set block weight to:"),
|
||||
_("rR)egular"), _("bB)old"), !isbold(fcell));
|
||||
_("rR)egular"), _("bB)old"), !(fs.bold));
|
||||
if (n >= 0)
|
||||
for (ALL_LOCS_IN_REGION(cursheet,w))
|
||||
changed = bold(cursheet, w, n) || changed;
|
||||
@ -468,9 +465,9 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (onecell) n = !underlined(fcell);
|
||||
if (onecell) n = !(fs.underline);
|
||||
else n = line_binary(_("Set block to:"), _("nN)ot underline"),
|
||||
_("uU)nderline"), !underlined(fcell));
|
||||
_("uU)nderline"), !(fs.underline));
|
||||
if (n >= 0)
|
||||
for (ALL_LOCS_IN_REGION(cursheet,w))
|
||||
changed = underline(cursheet, w, n) || changed;
|
||||
@ -516,11 +513,7 @@ static void do_attribute(Sheet *cursheet, Key action)
|
||||
default: assert(0);
|
||||
/*}}}*/
|
||||
}
|
||||
if (changed) {
|
||||
if (onecell) redraw_cell(cursheet, cursheet->mark1);
|
||||
else redraw_sheet(cursheet);
|
||||
forceupdate(cursheet);
|
||||
}
|
||||
if (changed) forceupdate(cursheet);
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
@ -1435,15 +1428,15 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly)
|
||||
{
|
||||
case K_GOTO: do_goto(cursheet, (const char *)0); break;
|
||||
case K_COLWIDTH: do_columnwidth(cursheet); break;
|
||||
case BLOCK_CLEAR: do_clear(cursheet); redraw_sheet(cursheet); break;
|
||||
case BLOCK_INSERT: do_insert(cursheet); redraw_sheet(cursheet); break;
|
||||
case BLOCK_DELETE: do_delete(cursheet); redraw_sheet(cursheet); break;
|
||||
case BLOCK_MOVE: do_move(cursheet,0,0); redraw_sheet(cursheet); break;
|
||||
case BLOCK_COPY: do_move(cursheet,1,0); redraw_sheet(cursheet); break;
|
||||
case BLOCK_FILL: do_fill(cursheet); redraw_sheet(cursheet); break;
|
||||
case FILL_BLOCK: fillwith(cursheet); redraw_sheet(cursheet); break;
|
||||
case BLOCK_SORT: do_sort(cursheet); redraw_sheet(cursheet); break;
|
||||
case BLOCK_MIRROR: do_mirror(cursheet); redraw_sheet(cursheet); break;
|
||||
case BLOCK_CLEAR: do_clear(cursheet); update(cursheet); break;
|
||||
case BLOCK_INSERT: do_insert(cursheet); update(cursheet); break;
|
||||
case BLOCK_DELETE: do_delete(cursheet); update(cursheet); break;
|
||||
case BLOCK_MOVE: do_move(cursheet,0,0); update(cursheet); break;
|
||||
case BLOCK_COPY: do_move(cursheet,1,0); update(cursheet); break;
|
||||
case BLOCK_FILL: do_fill(cursheet); update(cursheet); break;
|
||||
case FILL_BLOCK: fillwith(cursheet); update(cursheet); break;
|
||||
case BLOCK_SORT: do_sort(cursheet); update(cursheet); break;
|
||||
case BLOCK_MIRROR: do_mirror(cursheet); update(cursheet); break;
|
||||
case ADJUST_LEFT:
|
||||
case ADJUST_RIGHT:
|
||||
case ADJUST_CENTER:
|
||||
@ -1554,13 +1547,18 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly)
|
||||
/* ENTER -- edit current cell */ /*{{{*/
|
||||
case K_ENTER:
|
||||
if (moveonly) break;
|
||||
do_edit(cursheet, '\0', NULL, 0);
|
||||
do_edit(cursheet, '\0', NULL, BASE_CONT);
|
||||
break;
|
||||
/*}}}*/
|
||||
/* MENTER -- edit current clocked cell */ /*{{{*/
|
||||
case K_MENTER:
|
||||
if (moveonly) break;
|
||||
do_edit(cursheet, '\0', NULL, 1);
|
||||
do_edit(cursheet, '\0', NULL, ITER_CONT);
|
||||
break;
|
||||
/*}}}*/
|
||||
case K_EDIT_STYLE_EXPR: /* edit style expression */ /*{{{*/
|
||||
if (moveonly) break;
|
||||
do_edit(cursheet, '\0', NULL, STYLE_CONT);
|
||||
break;
|
||||
/*}}}*/
|
||||
/* ", @, digit -- edit current cell with character already in buffer */ /*{{{*/
|
||||
@ -1579,7 +1577,7 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly)
|
||||
case '8':
|
||||
case '9':
|
||||
if (moveonly) break;
|
||||
do_edit(cursheet, c, NULL, 0);
|
||||
do_edit(cursheet, c, NULL, BASE_CONT);
|
||||
break;
|
||||
/*}}}*/
|
||||
/* MARK -- toggle block marking */ /*{{{*/
|
||||
@ -1714,7 +1712,7 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly)
|
||||
case K_QUIT: if (moveonly) break; return 1;
|
||||
/*}}}*/
|
||||
default:
|
||||
if (isalpha(c) && !moveonly) do_edit(cursheet, c, NULL, 0);
|
||||
if (isalpha(c) && !moveonly) do_edit(cursheet, c, NULL, BASE_CONT);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -12,7 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
extern bool batch;
|
||||
extern int def_precision;
|
||||
extern PrecisionLevel def_precision;
|
||||
extern StringFormat quote;
|
||||
extern bool header;
|
||||
extern int debug_level;
|
||||
@ -87,11 +87,12 @@ typedef enum {
|
||||
ADJUST_COMPACT = -60,
|
||||
ADJUST_HEXACT = -61,
|
||||
ADJUST_FOREGROUND = -62,
|
||||
ADJUST_BACKGROUND = -63
|
||||
ADJUST_BACKGROUND = -63,
|
||||
K_EDIT_STYLE_EXPR = -64
|
||||
} Key;
|
||||
|
||||
extern int do_sheetcmd(Sheet *cursheet, Key c, int moveonly);
|
||||
extern int doanyway(Sheet *sheet, const char *msg);
|
||||
extern bool doanyway(Sheet *sheet, const char *msg);
|
||||
extern void moveto(Sheet *sheet, int x, int y, int z);
|
||||
extern void movetoloc(Sheet *sheet, const Location dest);
|
||||
extern void relmoveto(Sheet *sheet, int x, int y, int z);
|
||||
|
@ -716,6 +716,7 @@ Token evaltoken(Token n, EvalMethod meth)
|
||||
}
|
||||
case LOCATION: return n;
|
||||
case FUNCALL: return full_eval_funcall(&n);
|
||||
case STYLE: return n;
|
||||
case EEK: return tcopy(n);
|
||||
default: assert(0);
|
||||
}
|
||||
|
@ -236,8 +236,11 @@ const char *loadsc(Sheet *sheet, const char *name)
|
||||
OLOCATION(tmp);
|
||||
tmp[X] = col;
|
||||
cell = initcellofsheet(sheet, tmp, NULL);
|
||||
cell->adjust = RIGHT;
|
||||
cell->precision = precision;
|
||||
Style csty;
|
||||
clearstyle(&csty);
|
||||
csty.adjust = RIGHT;
|
||||
csty.precision = precision;
|
||||
overridestyle(sheet, tmp, csty);
|
||||
setwidth(sheet, col, 0, colwidth);
|
||||
}
|
||||
/*}}}*/
|
||||
@ -264,7 +267,10 @@ const char *loadsc(Sheet *sheet, const char *name)
|
||||
}
|
||||
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
|
||||
cell = initcellofsheet(sheet, tmp, NULL);
|
||||
cell->adjust = strncmp(buf, "leftstring ", 11) ? RIGHT : LEFT;
|
||||
Style csty;
|
||||
clearstyle(&csty);
|
||||
csty.adjust = strncmp(buf, "leftstring ", 11) ? RIGHT : LEFT;
|
||||
overridestyle(sheet, tmp, csty);
|
||||
cell->tok[BASE_CONT] = eval_safe(contents, LITERAL);
|
||||
tvecfree(contents);
|
||||
if (cell->tok[BASE_CONT].type == EEK)
|
||||
@ -309,7 +315,6 @@ const char *loadsc(Sheet *sheet, const char *name)
|
||||
}
|
||||
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
|
||||
cell = initcellofsheet(sheet, tmp, NULL);
|
||||
cell->adjust = RIGHT;
|
||||
cell->tok[BASE_CONT] = eval_safe(contents, LITERAL);
|
||||
tvecfree(contents);
|
||||
if (cell->tok[BASE_CONT].type == EEK)
|
||||
@ -327,17 +332,22 @@ const char *loadsc(Sheet *sheet, const char *name)
|
||||
++line;
|
||||
}
|
||||
/* set precisions for each column */ /*{{{*/
|
||||
for (x=0; x<sheet->dimx; ++x)
|
||||
Location colhead;
|
||||
OLOCATION(&colhead);
|
||||
for (; colhead[X] < sheet->dimx; colhead[X]++)
|
||||
{
|
||||
int prec;
|
||||
|
||||
prec=getprecision(CELL_ATC(sheet,x,0,0))==def_precision ? 2 : getprecision(CELL_ATC(sheet,x,0,0));
|
||||
for (y=1; y<sheet->dimy; ++y) if (CELL_ATC(sheet,x,y,0)) CELL_ATC(sheet,x,y,0)->precision=prec;
|
||||
int prec = getprecision(sheet, colhead) == def_precision
|
||||
? 2 : getprecision(sheet, colhead);
|
||||
for (y = 1; y < sheet->dimy; ++y) {
|
||||
Location l; l[X] = x; l[Y] = y; l[Z] = 0;
|
||||
if (CELL_AT(sheet,l))
|
||||
setprecision(sheet, l, prec);
|
||||
}
|
||||
}
|
||||
/*}}}*/
|
||||
eek:
|
||||
if (fclose(fp)==EOF && err==(const char*)0) err=strerror(errno);
|
||||
sheet->changed=0;
|
||||
sheet->changed = false;
|
||||
cachelabels(sheet);
|
||||
forceupdate(sheet);
|
||||
return err;
|
||||
|
@ -12,12 +12,10 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
extern char *strdup(const char* s);
|
||||
extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
|
||||
extern long double strtold(const char *nptr, char **endptr); /* SunOS 4 hack */
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "default.h"
|
||||
#include "func.h"
|
||||
#include "main.h"
|
||||
@ -25,79 +23,6 @@ extern long double strtold(const char *nptr, char **endptr); /* SunOS 4 hack */
|
||||
#include "scanner.h"
|
||||
/*}}}*/
|
||||
|
||||
const char *Type_Name[] =
|
||||
{ [EMPTY] = "EMPTY", [STRING] = "STRING", [FLOAT] = "FLOAT", [INT] = "INT",
|
||||
[OPERATOR] = "OPERATOR", [LIDENT] = "LABEL", [FIDENT] = "FUNCTION",
|
||||
[LOCATION] = "LOCATION", [FUNCALL] = "FUNCTION-CALL", [EEK] = "ERROR",
|
||||
[BOOL] = "BOOL"
|
||||
};
|
||||
|
||||
const char *Op_Name[] =
|
||||
{ [PLUS] = "+", [MINUS] = "-", [MUL] = "*", [DIV] = "/",
|
||||
[OP] = "(", [CP] = ")", [COMMA] = ",",
|
||||
[LT] = "<", [LE] = "<=", [GE] = ">=", [GT] = ">",
|
||||
[ISEQUAL] = "==", [ABOUTEQ] = "~=", [NE] = "!=",
|
||||
[POW] = "^", [MOD] = "%", [LAND] = "and", [LOR] = "or"
|
||||
};
|
||||
|
||||
/* loc_in_box -- returns true if test is in the box determined by b and c */
|
||||
bool loc_in_box(const Location test,
|
||||
const Location b, const Location c)
|
||||
{
|
||||
for (Dimensions dim = X; dim < HYPER; ++dim)
|
||||
{
|
||||
if (test[dim] < b[dim] && test[dim] < c[dim]) return false;
|
||||
if (test[dim] > b[dim] && test[dim] > c[dim]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* cleartoken - Initialize all of the memory of a token */ /*{{{*/
|
||||
void cleartoken(Token* tok)
|
||||
{
|
||||
tok->type = EMPTY;
|
||||
tok->u.flt = 0.0;
|
||||
tok->u.location[0] = 0;
|
||||
tok->u.location[1] = 0;
|
||||
tok->u.location[2] = 0;
|
||||
}
|
||||
|
||||
/* tok_matches - return true if l and r appear to be the same token */ /*{{{*/
|
||||
bool tok_matches(const Token* l, const Token *r)
|
||||
{
|
||||
if (l->type != r->type) return false;
|
||||
switch (l->type) {
|
||||
case EMPTY: return true;
|
||||
case STRING: return l->u.string == r->u.string;
|
||||
case FLOAT: return l->u.flt == r->u.flt;
|
||||
case INT: return l->u.integer == r->u.integer;
|
||||
case OPERATOR: return l->u.op == r->u.op;
|
||||
case LIDENT: return l->u.lident == r->u.lident;
|
||||
case FIDENT: return l->u.fident == r->u.fident;
|
||||
case LOCATION:
|
||||
return l->u.location[X] == r->u.location[X]
|
||||
&& l->u.location[Y] == r->u.location[Y]
|
||||
&& l->u.location[Z] == r->u.location[Z];
|
||||
case EEK: return l->u.err == r->u.err;
|
||||
case FUNCALL:
|
||||
return l->u.funcall.fident == r->u.funcall.fident
|
||||
&& l->u.funcall.argc == r->u.funcall.argc
|
||||
&& l->u.funcall.argv == r->u.funcall.argv;
|
||||
case BOOL:
|
||||
return l->u.bl == r->u.bl;
|
||||
}
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* duperror - Sets tok to an error and strdups the message into place */
|
||||
Token duperror(Token* tok, const char* erro)
|
||||
{
|
||||
tok->type = EEK;
|
||||
tok->u.err = strdup(erro);
|
||||
return *tok;
|
||||
}
|
||||
|
||||
/* charstring -- match quoted string and return token */ /*{{{*/
|
||||
static Token *charstring(char **s)
|
||||
{
|
||||
@ -203,6 +128,7 @@ static Token *op(char **s)
|
||||
return n;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* scan_ident -- match an identifier and return token */ /*{{{*/
|
||||
Token *scan_ident(char **s)
|
||||
{
|
||||
|
@ -2,181 +2,18 @@
|
||||
#define SCANNER_H
|
||||
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "func.h"
|
||||
#include "token.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* TO PRESERVE ABILITY TO READ OLD SAVE FILES, ONLY ADD ITEMS AT END */
|
||||
typedef enum {
|
||||
EMPTY
|
||||
#ifndef __cplusplus
|
||||
, STRING, FLOAT, INT, OPERATOR, LIDENT, FIDENT, LOCATION, EEK,
|
||||
FUNCALL, BOOL
|
||||
#endif
|
||||
} Type;
|
||||
|
||||
#define MAX_TYPE_NAME_LENGTH 16
|
||||
extern const char *Type_Name[];
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PLUS, MINUS, MUL, DIV, OP, CP, COMMA,
|
||||
|
||||
LT, /* Take care with the macros just below */
|
||||
LE, GE, GT, ISEQUAL, ABOUTEQ, NE,
|
||||
|
||||
POW, MOD, LAND, LOR
|
||||
} Operator;
|
||||
|
||||
#define MAX_OP_NAME_LENGTH 3
|
||||
#define IS_RELATION_OP(op) (((op)>= LT) && ((op)<=NE))
|
||||
extern const char *Op_Name[];
|
||||
|
||||
typedef int Location[3]; /* NOTE: Locations are passed by REFERENCE not value */
|
||||
/* I.e., to accept a Location argument, declare the parameter to be of type
|
||||
const Location*
|
||||
*/
|
||||
|
||||
typedef enum { X=0, Y=1, Z=2, HYPER} Dimensions;
|
||||
|
||||
#define OLOCATION(loc) ((void)memset(loc, 0, sizeof(Location)))
|
||||
#define IN_OCTANT(loc) (loc[X]>=0 && loc[Y]>=0 && loc[Z]>=0)
|
||||
#define LOCATION_GETS(la,lb) ((void)memcpy(la, lb, sizeof(Location)))
|
||||
#define SAME_LOC(la,lb) (memcmp(la,lb,sizeof(Location))==0)
|
||||
#define LOCATION_SUB(la,lb) (la)[X]-=(lb)[X]; (la)[Y]-=(lb)[Y]; (la)[Z]-=(lb)[Z];
|
||||
#define LOCATION_ADD(la,lb) (la)[X]+=(lb)[X]; (la)[Y]+=(lb)[Y]; (la)[Z]+=(lb)[Z];
|
||||
|
||||
bool loc_in_box(const Location test,
|
||||
const Location b, const Location c);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FunctionIdentifier fident;
|
||||
int argc;
|
||||
Token *argv;
|
||||
} FunctionCall;
|
||||
|
||||
#define FLT_LONG_DOUBLE
|
||||
#ifdef FLT_LONG_DOUBLE
|
||||
typedef long double FltT;
|
||||
/* To switch the internal type used to store a floating value, it is
|
||||
supposed to suffice to redefine all of the following macros:
|
||||
*/
|
||||
#define FLT_T_STD_FMT "%.*Lf"
|
||||
#define FLT_T_SCI_FMT "%.*Le"
|
||||
#define FLT_T_CPT_FMT "%.*Lg"
|
||||
#define FLT_T_HEX_FMT "%La"
|
||||
#define FLT_T_DIG LDBL_DIG
|
||||
#define FLTEPS LDBL_EPSILON
|
||||
#define FLTMX LDBL_MAX
|
||||
#define STRTOFLT strtold
|
||||
#define ABSFLT fabsl
|
||||
#define LOGFLT logl
|
||||
#define LOG2FLT log2l
|
||||
#define LOG10FLT log10l
|
||||
#define SQRTFLT sqrtl
|
||||
#define POWFLT powl
|
||||
#define FMODFLT fmodl
|
||||
#define MODFFLT modfl
|
||||
#define SINFLT sinl
|
||||
#define COSFLT cosl
|
||||
#define TANFLT tanl
|
||||
#define SINHFLT sinhl
|
||||
#define COSHFLT coshl
|
||||
#define TANHFLT tanhl
|
||||
#define ASINFLT asinl
|
||||
#define ACOSFLT acosl
|
||||
#define ATANFLT atanl
|
||||
#define FLOORFLT floorl
|
||||
#define CEILFLT ceill
|
||||
#define ROUNDFLT rintl
|
||||
#define TRUNCFLT truncl
|
||||
#else
|
||||
typedef double FltT;
|
||||
/* To switch the internal type used to store a floating value, it is
|
||||
supposed to suffice to redefine all of the following macros:
|
||||
*/
|
||||
#define FLT_T_STD_FMT "%.*f"
|
||||
#define FLT_T_SCI_FMT "%.*e"
|
||||
#define FLT_T_CPT_FMT "%.*g"
|
||||
#define FLT_T_HEX_FMT "%a"
|
||||
#define FLT_T_DIG DBL_DIG
|
||||
#define FLTEPS DBL_EPSILON
|
||||
#define FLTMX DBL_MAX
|
||||
#define STRTOFLT strtod
|
||||
#define ABSFLT fabs
|
||||
#define LOGFLT log
|
||||
#define LOG2FLT log2
|
||||
#define LOG10FLT log10
|
||||
#define SQRTFLT sqrt
|
||||
#define POWFLT pow
|
||||
#define FMODFLT fmod
|
||||
#define MODFFLT modf
|
||||
#define SINFLT sin
|
||||
#define COSFLT cos
|
||||
#define TANFLT tan
|
||||
#define SINHFLT sinh
|
||||
#define COSHFLT cosh
|
||||
#define TANHFLT tanh
|
||||
#define ASINFLT asin
|
||||
#define ACOSFLT acos
|
||||
#define ATANFLT atan
|
||||
#define FLOORFLT floor
|
||||
#define CEILFLT ceil
|
||||
#define ROUNDFLT rint
|
||||
#define TRUNCFLT trunc
|
||||
#endif
|
||||
|
||||
typedef long long IntT;
|
||||
/* To switch the internal type used to store an integer value, it is
|
||||
supposed to suffice to redefine all of the following macros and typedefs.
|
||||
*/
|
||||
typedef unsigned long long UIntT;
|
||||
#define INT_T_FMT "%lld"
|
||||
#define STRTOINT strtoll
|
||||
/* This one depends on both the floating point and integer types */
|
||||
#ifdef FLT_LONG_DOUBLE
|
||||
#define ROUNDFLTINT llrintl
|
||||
#else
|
||||
#define ROUNDFLTINT llrint
|
||||
#endif
|
||||
/* End of subtype definitions */
|
||||
|
||||
/* The main type defined here; should this be token.h ?*/
|
||||
typedef struct Token_struc
|
||||
{
|
||||
Type type;
|
||||
union
|
||||
{
|
||||
char *string;
|
||||
FltT flt;
|
||||
IntT integer;
|
||||
Operator op;
|
||||
char *lident;
|
||||
FunctionIdentifier fident;
|
||||
Location location;
|
||||
FunctionCall funcall;
|
||||
char *err;
|
||||
bool bl;
|
||||
} u;
|
||||
} Token;
|
||||
|
||||
#define NULLTOKEN ((Token*)0)
|
||||
#define EMPTY_TVEC ((Token**)0)
|
||||
#define TOKISNUM(t) ((t).type == INT || (t).type == FLOAT || (t).type == EMPTY)
|
||||
|
||||
bool tok_matches(const Token *l, const Token *r);
|
||||
Token duperror(Token* tok, const char* erro);
|
||||
Token *scan_ident(char **s);
|
||||
Token *scan_integer(char **s);
|
||||
Token *scan_flt(char **s);
|
||||
Token **scan(char **s);
|
||||
void cleartoken(Token* tok);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -38,7 +38,7 @@
|
||||
/*}}}*/
|
||||
|
||||
/* variables */ /*{{{*/
|
||||
static int upd_clock; /* evaluate clocked expressions */
|
||||
static bool upd_clock; /* evaluate clocked expressions */
|
||||
/* Used during evaluation of a cell to specify the currently updated cell */
|
||||
Sheet *upd_sheet;
|
||||
Location upd_l;
|
||||
@ -94,27 +94,19 @@ static void dump_cell(Sheet *sheet, int x, int y, int z)
|
||||
printf("TEADUMP of &(%d,%d,%d):\n", x, y, z);
|
||||
for (TokVariety tv = BASE_CONT; tv < CONTINGENT; ++tv)
|
||||
{
|
||||
printf(" %s: ", TokVariety_Name[tv]);
|
||||
printtok(buf, sizeof(buf), 0, 1, 0, -1, 1, c->tok + tv);
|
||||
printf(" %s: (%s)", TokVariety_Name[tv], Type_Name[c->tok[tv].type]);
|
||||
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1,
|
||||
VERBOSE_ERROR, c->tok + tv);
|
||||
printf("%s.\n", buf);
|
||||
}
|
||||
if (c->label == NULL) printf("\n No label.\n");
|
||||
else printf("\n Label: %s.\n", c->label);
|
||||
printf(" Adjustment: %s.\n", Adjust_Name[c->adjust]);
|
||||
printf(" Float format: %s.\n", FloatFormat_Name[c->fform]);
|
||||
printf(" Precision: %d\n Attributes: ", c->precision);
|
||||
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
|
||||
printf(" %s color: %d\n", ColorAspect_Name[ca], c->aspect[ca]);
|
||||
if (c->updated) printf("updated ");
|
||||
if (c->shadowed) printf("shadowed ");
|
||||
if (c->locked) printf("locked ");
|
||||
if (c->transparent) printf("transparent ");
|
||||
if (c->ignored) printf("ignored ");
|
||||
if (c->clock_t0) printf("clock_t0 ");
|
||||
if (c->clock_t1) printf("clock_t1 ");
|
||||
if (c->clock_t2) printf("clock_t2 ");
|
||||
if (c->bold) printf("bold ");
|
||||
if (c->underline) printf("underline ");
|
||||
if (c->updated) printf(" updated ");
|
||||
if (c->locked) printf(" locked ");
|
||||
if (c->ignored) printf(" ignored ");
|
||||
if (c->clock_t0) printf(" clock_t0 ");
|
||||
if (c->clock_t1) printf(" clock_t1 ");
|
||||
if (c->clock_t2) printf(" clock_t2 ");
|
||||
printf("\n\n");
|
||||
}
|
||||
/*}}}*/
|
||||
@ -460,8 +452,10 @@ void forceupdate(Sheet *sheet)
|
||||
assert(sheet!=(Sheet*)0);
|
||||
if (sheet->sheet == (Cell **)0) return;
|
||||
for (ALL_CELLS_IN_SHEET(sheet,i,cell))
|
||||
if (cell != NULLCELL)
|
||||
cell->updated = cell->clock_t0 = cell->clock_t1 = cell->clock_t2 = 0;
|
||||
if (cell != NULLCELL) {
|
||||
cell->updated = cell->clock_t0 = cell->clock_t1 = cell->clock_t2 = false;
|
||||
tfree(&(cell->tok[STYLE_VAL]));
|
||||
}
|
||||
update(sheet);
|
||||
}
|
||||
/*}}}*/
|
||||
@ -510,13 +504,11 @@ bool setwidth(Sheet *sheet, int x, int z, int width)
|
||||
/* cellwidth -- get width of a cell */ /*{{{*/
|
||||
int cellwidth(Sheet *sheet, const Location at)
|
||||
{
|
||||
int width,x;
|
||||
|
||||
if (SHADOWED(sheet,at)) return 0;
|
||||
x = at[X];
|
||||
width = columnwidth(sheet,x,at[Z]);
|
||||
for (++x; SHADOWEDC(sheet,x,at[Y],at[Z]);
|
||||
width += columnwidth(sheet,x,at[Z]), ++x);
|
||||
if (shadowed(sheet,at)) return 0;
|
||||
Location near; LOCATION_GETS(near,at);
|
||||
int width = columnwidth(sheet,at[X],at[Z]);
|
||||
for (near[X]++; shadowed(sheet,near);
|
||||
width += columnwidth(sheet,near[X]++,near[Z]));
|
||||
return width;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -540,7 +532,6 @@ Token recompvalue(Sheet *sheet, const Location at)
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
Token result;
|
||||
int orig_upd_clock;
|
||||
Cell* cell;
|
||||
/*}}}*/
|
||||
|
||||
@ -564,13 +555,13 @@ Token recompvalue(Sheet *sheet, const Location at)
|
||||
cell = CELL_AT(sheet, at);
|
||||
if (!upd_clock && gettok(cell, CONTINGENT).type == EMPTY) return result;
|
||||
/* update value of this cell if needed and return it */ /*{{{*/
|
||||
orig_upd_clock = upd_clock;
|
||||
bool orig_upd_clock = upd_clock;
|
||||
if (cell->ignored)
|
||||
{
|
||||
tfree(cell->tok + CURR_VAL);
|
||||
cell->updated = 1;
|
||||
cell->updated = true;
|
||||
}
|
||||
else if (cell->updated == 0)
|
||||
else if (cell->updated == false)
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
Sheet *old_sheet;
|
||||
@ -585,18 +576,18 @@ Token recompvalue(Sheet *sheet, const Location at)
|
||||
upd_sheet = sheet;
|
||||
LOCATION_GETS(upd_l, at);
|
||||
max_eval = MAX_EVALNEST;
|
||||
if (cell->clock_t1 == 0)
|
||||
if (!(cell->clock_t1))
|
||||
{
|
||||
cell->updated = 1;
|
||||
cell->updated = true;
|
||||
oldvalue = gettok(cell, CURR_VAL);
|
||||
upd_clock = 0;
|
||||
upd_clock = false;
|
||||
cell->tok[CURR_VAL] = evaltoken(gettok(cell, CONTINGENT), FULL);
|
||||
tfree(&oldvalue);
|
||||
}
|
||||
else if (upd_clock)
|
||||
{
|
||||
cell->updated = 1;
|
||||
upd_clock = 0;
|
||||
cell->updated = true;
|
||||
upd_clock = false;
|
||||
oldvalue = gettok(cell, RES_VAL);
|
||||
cell->tok[RES_VAL] = evaltoken(gettok(cell, CONTINGENT), FULL);
|
||||
tfree(&oldvalue);
|
||||
@ -630,35 +621,35 @@ Token evaluate_at(Token t, Sheet *sheet, const Location at)
|
||||
/* update -- update all cells that need it */ /*{{{*/
|
||||
void update(Sheet *sheet)
|
||||
{
|
||||
Location w;
|
||||
Cell *cell;
|
||||
int i,kp,iterating;
|
||||
|
||||
assert(sheet != (Sheet*)0);
|
||||
kp = 0;
|
||||
iterating = 0;
|
||||
do
|
||||
int iterating = 0;
|
||||
bool kp = false;
|
||||
for (sheet->clk = true; sheet->sheet && sheet->clk && !kp; kp = keypressed())
|
||||
{
|
||||
sheet->clk = 0;
|
||||
if (iterating==1)
|
||||
if (iterating == 1)
|
||||
{
|
||||
line_msg((const char*)0,_("Calculating running, press Escape to abort it"));
|
||||
line_msg(NULL, _("Realculation running, press Escape to abort it"));
|
||||
++iterating;
|
||||
}
|
||||
else if (iterating==0) ++iterating;
|
||||
else if (iterating == 0) ++iterating;
|
||||
Cell *cell;
|
||||
int i;
|
||||
for (ALL_CELLS_IN_SHEET(sheet,i,cell))
|
||||
{
|
||||
if (cell && cell->clock_t2)
|
||||
{
|
||||
cell->updated = 0;
|
||||
cell->clock_t0 = 1;
|
||||
cell->clock_t1 = 1;
|
||||
cell->clock_t2 = 0;
|
||||
cell->updated = false;
|
||||
cell->clock_t0 = true;
|
||||
cell->clock_t1 = true;
|
||||
cell->clock_t2 = false;
|
||||
tfree(&(cell->tok[STYLE_VAL]));
|
||||
}
|
||||
}
|
||||
Location w;
|
||||
for (ALL_LOCS_IN_SHEET(sheet,w))
|
||||
{
|
||||
upd_clock = 1;
|
||||
upd_clock = true;
|
||||
recompvalue(sheet, w);
|
||||
}
|
||||
for (ALL_CELLS_IN_SHEET(sheet,i,cell))
|
||||
@ -668,16 +659,18 @@ void update(Sheet *sheet)
|
||||
tfree(&(cell->tok[CURR_VAL]));
|
||||
cell->tok[CURR_VAL] = cell->tok[RES_VAL];;
|
||||
cell->tok[RES_VAL].type = EMPTY;
|
||||
cell->clock_t1 = 0;
|
||||
cell->clock_t1 = false;
|
||||
}
|
||||
}
|
||||
upd_clock = 0;
|
||||
} while (sheet->clk && !(kp=keypressed()));
|
||||
if (iterating == 2) line_msg((const char*)0,kp ? _("Calculation aborted") : _("Calculation finished"));
|
||||
sheet->clk = 0;
|
||||
upd_clock = false;
|
||||
}
|
||||
if (iterating == 2)
|
||||
line_msg(NULL, kp ? _("Calculation aborted") : _("Calculation finished"));
|
||||
sheet->clk = false;
|
||||
redraw_sheet(sheet);
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* geterror -- get malloc()ed error string */ /*{{{*/
|
||||
char *geterror(Sheet *sheet, const Location at)
|
||||
{
|
||||
@ -694,17 +687,150 @@ char *geterror(Sheet *sheet, const Location at)
|
||||
/*}}}*/
|
||||
|
||||
/* printvalue -- get ASCII representation of value */ /*{{{*/
|
||||
void printvalue(char *s, size_t size, size_t chars, StringFormat sf,
|
||||
size_t printvalue(char *s, size_t size, size_t chars, StringFormat sf,
|
||||
FloatFormat ff, int precision, Sheet *sheet, const Location at)
|
||||
{
|
||||
assert(sheet != (Sheet*)0);
|
||||
Token t = recompvalue(sheet, at);
|
||||
printtok(s, size, chars, sf, ff, precision, TRUNCATED_ERROR, &t);
|
||||
size_t retval =
|
||||
printtok(s, size, chars, sf, ff, precision, TRUNCATED_ERROR, &t);
|
||||
tfree(&t);
|
||||
return retval;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* The cell field setters all have nearly identical code, so: */
|
||||
/* getstyle -- get the current style token */
|
||||
Style getstyle(Sheet *sheet, const Location at)
|
||||
{
|
||||
Token res;
|
||||
res.type = STYLE;
|
||||
clearstyle(&(res.u.style));
|
||||
res.u.style.fform = DEF_FLOATFORM;
|
||||
res.u.style.precision = def_precision;
|
||||
if (!IN_OCTANT(at) || !CELL_IS_GOOD(sheet, at)) {
|
||||
res.u.style.adjust = LEFT; return res.u.style;
|
||||
}
|
||||
Cell *cell = CELL_AT(sheet, at);
|
||||
assert(cell->updated);
|
||||
if (cell->tok[STYLE_VAL].type == STYLE) return cell->tok[STYLE_VAL].u.style;
|
||||
Sheet *old_up_sh = upd_sheet;
|
||||
Location old_upd_l; LOCATION_GETS(old_upd_l, upd_l);
|
||||
upd_sheet = sheet;
|
||||
LOCATION_GETS(upd_l, at);
|
||||
Token tsty = evaltoken(cell->tok[STYLE_CONT], FULL);
|
||||
LOCATION_GETS(upd_l, old_upd_l);
|
||||
upd_sheet = old_up_sh;
|
||||
Style sty;
|
||||
switch (tsty.type) {
|
||||
case STYLE: sty = tsty.u.style; break;
|
||||
case EMPTY: sty = res.u.style; break;
|
||||
default: {
|
||||
char buf[4096];
|
||||
const char *msg = _("Produced non-style value ");
|
||||
strcpy(buf, msg);
|
||||
printtok(buf+strlen(msg), sizeof(buf)-strlen(msg)-1, 0, QUOTE_STRING,
|
||||
FLT_COMPACT, -1, VERBOSE_ERROR, &tsty);
|
||||
line_msg(_("Cell style expr:"), msg);
|
||||
sty = res.u.style;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sty.adjust == AUTOADJUST)
|
||||
sty.adjust = TOKISNUM(cell->tok[CURR_VAL]) ? RIGHT : LEFT;
|
||||
if (sty.fform == FLT_NO_FORMAT) sty.fform = DEF_FLOATFORM;
|
||||
if (sty.precision == NO_PRECISION) sty.precision = def_precision;
|
||||
cell->tok[STYLE_VAL].type = STYLE;
|
||||
cell->tok[STYLE_VAL].u.style = sty;
|
||||
return sty;
|
||||
}
|
||||
|
||||
/* getadjust -- get cell adjustment */
|
||||
Adjust getadjust(Sheet *sheet, const Location at)
|
||||
{
|
||||
return getstyle(sheet, at).adjust;
|
||||
}
|
||||
|
||||
/* shadowed -- is cell shadowed? */
|
||||
bool shadowed(Sheet *sheet, const Location at)
|
||||
{
|
||||
return getstyle(sheet, at).shadowed;
|
||||
}
|
||||
|
||||
/* isbold -- is cell bold? */
|
||||
bool isbold(Sheet *sheet, const Location at)
|
||||
{
|
||||
return getstyle(sheet, at).bold;
|
||||
}
|
||||
|
||||
/* getcolor -- a color associated to cell */
|
||||
ColorNum getcolor(Sheet *sheet, const Location at, ColorAspect aspect)
|
||||
{
|
||||
return getstyle(sheet, at).aspect[aspect];
|
||||
}
|
||||
|
||||
/* isunderline -- is cell underlined? */
|
||||
bool underlined(Sheet *sheet, const Location at)
|
||||
{
|
||||
return getstyle(sheet, at).underline;
|
||||
}
|
||||
|
||||
/* transparent -- is cell transparent? */
|
||||
bool transparent(Sheet *sheet, const Location at)
|
||||
{
|
||||
return getstyle(sheet, at).transparent;
|
||||
}
|
||||
|
||||
/* getfltformat -- float format for numbers */
|
||||
FloatFormat getfltformat(Sheet *sheet, const Location at)
|
||||
{
|
||||
return getstyle(sheet, at).fform;
|
||||
}
|
||||
|
||||
/* getprecision -- get cell precision */
|
||||
PrecisionLevel getprecision(Sheet *sheet, const Location at)
|
||||
{
|
||||
return getstyle(sheet, at).precision;
|
||||
}
|
||||
|
||||
/* overridestyle -- coerce the style of a cell to match sty */
|
||||
bool overridestyle(Sheet *sheet, const Location at, Style sty) {
|
||||
Style esty;
|
||||
clearstyle(&esty);
|
||||
if (style_equal(sty, esty)) return false;
|
||||
assert(sheet != (Sheet*)0);
|
||||
bool isnew = false;
|
||||
Cell* thecell = initcellofsheet(sheet, at, &isnew);
|
||||
if (isnew) sheet->changed = true;
|
||||
Token stok = gettok(thecell, STYLE_CONT);
|
||||
switch (stok.type) {
|
||||
case EMPTY:
|
||||
thecell->tok[STYLE_CONT].type = STYLE;
|
||||
thecell->tok[STYLE_CONT].u.style = sty;
|
||||
tfree(&(thecell->tok[STYLE_VAL]));
|
||||
return true;
|
||||
case STYLE: {
|
||||
Token tsty; tsty.type = STYLE; tsty.u.style = sty;
|
||||
thecell->tok[STYLE_CONT] = tadd(tsty, stok);
|
||||
if (style_equal(stok.u.style, thecell->tok[STYLE].u.style)) return false;
|
||||
tfree(&(thecell->tok[STYLE_VAL]));
|
||||
return true;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
/* Create an expression that adds the prior expression to this style */
|
||||
Token tsty; tsty.type = STYLE; tsty.u.style = sty;
|
||||
Token fsty; fsty.type = FUNCALL;
|
||||
fsty.u.funcall.fident = FUNC_PLUS_SYMBOL;
|
||||
fsty.u.funcall.argc = 2;
|
||||
fsty.u.funcall.argv = malloc(fsty.u.funcall.argc*sizeof(Token));
|
||||
fsty.u.funcall.argv[0] = tsty;
|
||||
fsty.u.funcall.argv[1] = stok;
|
||||
thecell->tok[STYLE_CONT] = fsty;
|
||||
tfree(&(thecell->tok[STYLE_VAL]));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The cell field setters used to all have nearly identical code, so: */
|
||||
|
||||
#define DEFSETTER(funcname,argtype,field) bool\
|
||||
funcname(Sheet *sheet, const Location at, argtype arg)\
|
||||
@ -721,29 +847,41 @@ void printvalue(char *s, size_t size, size_t chars, StringFormat sf,
|
||||
return isnew;\
|
||||
}
|
||||
|
||||
DEFSETTER(setadjust, Adjust, adjust);
|
||||
DEFSETTER(shadow, bool, shadowed);
|
||||
DEFSETTER(bold, bool, bold);
|
||||
DEFSETTER(underline, bool, underline);
|
||||
DEFSETTER(lockcell, bool, locked);
|
||||
DEFSETTER(maketrans, bool, transparent);
|
||||
DEFSETTER(igncell, bool, ignored);
|
||||
DEFSETTER(setfltformat, FloatFormat, fform);
|
||||
DEFSETTER(setprecision, int, precision);
|
||||
|
||||
/* sadly color has an extra argument */
|
||||
#define DEFSTYVAL(funcname,argtype,field) bool\
|
||||
funcname(Sheet *sheet, const Location at, argtype arg)\
|
||||
{\
|
||||
Style nsty; clearstyle(&nsty);\
|
||||
nsty.field = arg;\
|
||||
return overridestyle(sheet, at, nsty);\
|
||||
}
|
||||
|
||||
DEFSTYVAL(setadjust, Adjust, adjust);
|
||||
DEFSTYVAL(setfltformat, FloatFormat, fform);
|
||||
DEFSTYVAL(setprecision, PrecisionLevel, precision);
|
||||
|
||||
#define DEFSTYFLAG(funcname,field) bool\
|
||||
funcname(Sheet *sheet, const Location at, bool arg)\
|
||||
{\
|
||||
Style nsty; clearstyle(&nsty);\
|
||||
nsty.field = arg;\
|
||||
nsty.field##_set = true;\
|
||||
return overridestyle(sheet, at, nsty);\
|
||||
}
|
||||
|
||||
DEFSTYFLAG(shadow, shadowed);
|
||||
DEFSTYFLAG(bold, bold);
|
||||
DEFSTYFLAG(underline, underline);
|
||||
DEFSTYFLAG(maketrans, transparent);
|
||||
|
||||
/* setcolor -- force the color of a cell to be as specified */
|
||||
bool setcolor(Sheet *sheet, const Location at, ColorAspect asp, ColorNum col)
|
||||
{
|
||||
assert(sheet != (Sheet*)0);
|
||||
bool isnew = false;
|
||||
Cell* thecell = initcellofsheet(sheet, at, &isnew);
|
||||
if (isnew) sheet->changed = true;
|
||||
if (thecell->aspect[asp] != col) {
|
||||
thecell->aspect[asp] = col;
|
||||
sheet->changed = true;
|
||||
return true;
|
||||
}
|
||||
return isnew;
|
||||
Style nsty; clearstyle(&nsty);
|
||||
nsty.aspect[asp] = col;
|
||||
return overridestyle(sheet, at, nsty);
|
||||
}
|
||||
|
||||
/* clk -- clock cell */ /*{{{*/
|
||||
@ -754,8 +892,8 @@ void clk(Sheet *sheet, const Location at)
|
||||
assert(LOC_WITHIN(sheet,at));
|
||||
if (CELL_AT(sheet,at))
|
||||
{
|
||||
CELL_AT(sheet,at)->clock_t2 = 1;
|
||||
sheet->clk = 1;
|
||||
CELL_AT(sheet,at)->clock_t2 = true;
|
||||
sheet->clk = true;
|
||||
}
|
||||
}
|
||||
/*}}}*/
|
||||
@ -871,7 +1009,6 @@ const char *savetbl(Sheet *sheet, const char *name, int body,
|
||||
char buf[1024];
|
||||
char num[20];
|
||||
char fullname[PATH_MAX];
|
||||
Cell *cw;
|
||||
/*}}}*/
|
||||
|
||||
/* asserts */ /*{{{*/
|
||||
@ -882,7 +1019,7 @@ const char *savetbl(Sheet *sheet, const char *name, int body,
|
||||
w[X] = beg[X];
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
||||
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
||||
if (shadowed(sheet,w)) return _("Shadowed cells in first column");
|
||||
if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
{
|
||||
@ -906,11 +1043,12 @@ const char *savetbl(Sheet *sheet, const char *name, int body,
|
||||
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X]))
|
||||
{
|
||||
if (w[X] > beg [X] && fputc_close(' ',fp)==EOF) return strerror(errno);
|
||||
cw = CELL_AT(sheet,w);
|
||||
if (shadowed(cw) && fputc_close('s',fp)==EOF) return strerror(errno);
|
||||
if (isbold(cw) && fputc_close('b',fp)==EOF) return strerror(errno);
|
||||
if (underlined(cw) && fputc_close('u',fp)==EOF) return strerror(errno);
|
||||
switch (getadjust(cw))
|
||||
Cell *cw = CELL_AT(sheet,w);
|
||||
Style sw = getstyle(sheet,w);
|
||||
if (sw.shadowed && fputc_close('s',fp)==EOF) return strerror(errno);
|
||||
if (sw.bold && fputc_close('b',fp)==EOF) return strerror(errno);
|
||||
if (sw.underline && fputc_close('u',fp)==EOF) return strerror(errno);
|
||||
switch (sw.adjust)
|
||||
{
|
||||
case LEFT: if (fputc_close('l',fp)==EOF) return strerror(errno); break;
|
||||
case RIGHT: if (fputc_close('r',fp)==EOF) return strerror(errno); break;
|
||||
@ -923,21 +1061,22 @@ const char *savetbl(Sheet *sheet, const char *name, int body,
|
||||
/* print contents */ /*{{{*/
|
||||
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X]))
|
||||
{
|
||||
cw = CELL_AT(sheet,w);
|
||||
if (!shadowed(cw))
|
||||
Cell *cw = CELL_AT(sheet,w);
|
||||
Style sw = getstyle(sheet,w);
|
||||
if (!sw.shadowed)
|
||||
{
|
||||
if (w[X] > beg[X] && fputc_close('\t',fp)==EOF) return strerror(errno);
|
||||
if (cw != NULLCELL)
|
||||
{
|
||||
char *bufp;
|
||||
|
||||
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cw),
|
||||
getprecision(cw), sheet, w);
|
||||
if (transparent(cw))
|
||||
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, sw.fform,
|
||||
sw.precision, sheet, w);
|
||||
if (sw.transparent)
|
||||
{
|
||||
if (fputs_close(buf,fp)==EOF) return strerror(errno);
|
||||
}
|
||||
else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
|
||||
else for (char *bufp = buf; *bufp; ++bufp) switch (*bufp)
|
||||
{
|
||||
case '\\':
|
||||
{
|
||||
@ -996,21 +1135,18 @@ const char *savetext(Sheet *sheet, const char *name,
|
||||
const Location beg, const Location end,
|
||||
unsigned int *count)
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
FILE *fp;
|
||||
Location w;
|
||||
Cell *cw;
|
||||
/*}}}*/
|
||||
|
||||
/* asserts */ /*{{{*/
|
||||
assert(sheet != (Sheet*)0);
|
||||
assert(name != (const char*)0);
|
||||
/*}}}*/
|
||||
|
||||
*count=0;
|
||||
Location w;
|
||||
w[X] = beg[X];
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
||||
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
||||
if (shadowed(sheet,w)) return _("Shadowed cells in first column");
|
||||
FILE *fp;
|
||||
if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
{
|
||||
@ -1020,15 +1156,14 @@ const char *savetext(Sheet *sheet, const char *name,
|
||||
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X]))
|
||||
{
|
||||
size = cellwidth(sheet,w);
|
||||
cw = CELL_AT(sheet,w);
|
||||
Cell *cw = CELL_AT(sheet,w);
|
||||
if (cw != NULLCELL)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = malloc(size*UTF8SZ+1);
|
||||
char *buf = malloc(size*UTF8SZ+1);
|
||||
Style sw = getstyle(sheet,w);
|
||||
printvalue(buf, size*UTF8SZ + 1, size, DIRECT_STRING,
|
||||
getfltformat(cw), getprecision(cw), sheet, w);
|
||||
adjust(getadjust(cw), buf, size);
|
||||
sw.fform, sw.precision, sheet, w);
|
||||
adjust(sw.adjust, buf, size);
|
||||
if (fputs_close(buf,fp)==EOF)
|
||||
{
|
||||
free(buf);
|
||||
@ -1061,20 +1196,18 @@ const char *savecsv(Sheet *sheet, const char *name, char sep,
|
||||
const Location beg, const Location end,
|
||||
unsigned int *count)
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
FILE *fp;
|
||||
Location w;
|
||||
/*}}}*/
|
||||
|
||||
/* asserts */ /*{{{*/
|
||||
assert(sheet != (Sheet*)0);
|
||||
assert(name != (const char*)0);
|
||||
/*}}}*/
|
||||
|
||||
*count = 0;
|
||||
Location w;
|
||||
w[X] = beg[X];
|
||||
for (w[Z] = beg[Z]; w[Z] <= end[Z]; ++(w[Z]))
|
||||
for (w[Y] = beg[Y]; w[Y] <= end[Y]; ++(w[Y]))
|
||||
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
||||
if (shadowed(sheet,w)) return _("Shadowed cells in first column");
|
||||
FILE *fp;
|
||||
if ((fp = fopen(name,"w")) == (FILE*)0) return strerror(errno);
|
||||
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
||||
{
|
||||
@ -1090,10 +1223,10 @@ const char *savecsv(Sheet *sheet, const char *name, char sep,
|
||||
static const int bufchar = 511;
|
||||
static const int bufsz = bufchar*UTF8SZ + 1;
|
||||
char *buf = malloc(bufsz);
|
||||
|
||||
printvalue(buf, bufsz, bufchar, DIRECT_STRING, getfltformat(cw),
|
||||
getprecision(cw), sheet, w);
|
||||
bool needquote = !transparent(cw)
|
||||
Style sw = getstyle(sheet, w);
|
||||
printvalue(buf, bufsz, bufchar, DIRECT_STRING, sw.fform,
|
||||
sw.precision, sheet, w);
|
||||
bool needquote = !(sw.transparent)
|
||||
&& (strlen(buf) != strcspn(buf, "\",\n\r"));
|
||||
if (needquote && fputc_close('"',fp) == EOF)
|
||||
{
|
||||
@ -1124,7 +1257,7 @@ const char *savecsv(Sheet *sheet, const char *name, char sep,
|
||||
/*}}}*/
|
||||
|
||||
static const char *saveport_contentleader[] =
|
||||
{ [BASE_CONT] = ":", [ITER_CONT] = "\\\n", [ATTR_REF] = "\\\n"
|
||||
{ [BASE_CONT] = ":", [ITER_CONT] = "\\\n", [STYLE_CONT] = "\\\n"
|
||||
};
|
||||
|
||||
/* saveport -- save as portable text */ /*{{{*/
|
||||
@ -1153,28 +1286,8 @@ const char *saveport(Sheet *sheet, const char *name, unsigned int *count)
|
||||
if (cell != NULLCELL)
|
||||
{
|
||||
fprintf(fp,"C%d %d %d ",x,y,z);
|
||||
if (cell->adjust != AUTOADJUST)
|
||||
fprintf(fp, "A%c ", Adjust_Char[cell->adjust]);
|
||||
if (cell->label) fprintf(fp, "L%s ", cell->label);
|
||||
if (cell->precision != -1)
|
||||
fprintf(fp,"P%d ", cell->precision);
|
||||
if (cell->fform != DEF_FLOATFORM)
|
||||
fprintf(fp,"F%c ", FloatFormat_Char[cell->fform]);
|
||||
bool needscolor = false;
|
||||
for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a)
|
||||
if (cell->aspect[a] != DefaultCN[a])
|
||||
{ needscolor = true; break; }
|
||||
if (needscolor)
|
||||
{
|
||||
fprintf(fp, "H%d ", NUM_COLOR_ASPECTS);
|
||||
for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a)
|
||||
fprintf(fp, "%d ", (int)cell->aspect[a]);
|
||||
}
|
||||
if (cell->shadowed) fprintf(fp,"S ");
|
||||
if (cell->bold) fprintf(fp,"B ");
|
||||
if (cell->underline) fprintf(fp,"U ");
|
||||
if (cell->locked) fprintf(fp, "K ");
|
||||
if (cell->transparent) fprintf(fp,"T ");
|
||||
if (cell->ignored) fprintf(fp, "I ");
|
||||
TokVariety lastv = MAX_PERSIST_TV;
|
||||
while (lastv > BASE_CONT && cell->tok[lastv].type == EMPTY) --lastv;
|
||||
@ -1260,6 +1373,7 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
}
|
||||
/*}}}*/
|
||||
/* parse optional attributes */ /*{{{*/
|
||||
cleartoken(&(loaded.tok[STYLE_CONT]));
|
||||
do
|
||||
{
|
||||
while (*ns==' ') ++ns;
|
||||
@ -1272,7 +1386,9 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
const char *found = strchr(Adjust_Char, *ns);
|
||||
if (found != NULL)
|
||||
{
|
||||
loaded.adjust = (Adjust)(found - Adjust_Char);
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
loaded.tok[STYLE_CONT].u.style.adjust =
|
||||
(Adjust)(found - Adjust_Char);
|
||||
++ns;
|
||||
break;
|
||||
}
|
||||
@ -1288,7 +1404,9 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
const char* found = strchr(FloatFormat_Char, *ns);
|
||||
if (found != NULL)
|
||||
{
|
||||
loaded.fform = (FloatFormat)(found - FloatFormat_Char);
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
loaded.tok[STYLE_CONT].u.style.fform =
|
||||
(FloatFormat)(found - FloatFormat_Char);
|
||||
++ns;
|
||||
break;
|
||||
}
|
||||
@ -1315,7 +1433,8 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
case 'P':
|
||||
{
|
||||
os=++ns;
|
||||
loaded.precision = strtol(os, &ns, 0);
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
loaded.tok[STYLE_CONT].u.style.precision = strtol(os, &ns, 0);
|
||||
if (os==ns)
|
||||
{
|
||||
sprintf(errbuf,_("Parse error for precision in line %d"),line);
|
||||
@ -1337,11 +1456,12 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
err = errbuf;
|
||||
goto eek;
|
||||
}
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
for (size_t a = 0; a < na; ++a)
|
||||
{
|
||||
while (*ns && (*ns == ' ')) { ++ns; }
|
||||
os = ns;
|
||||
loaded.aspect[a] = strtol(os, &ns, 0);
|
||||
loaded.tok[STYLE_CONT].u.style.aspect[a] = strtol(os, &ns, 0);
|
||||
if (os == ns)
|
||||
{
|
||||
sprintf(errbuf, _("Parse error in hue %d on line %d"),
|
||||
@ -1364,37 +1484,29 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
goto eek;
|
||||
}
|
||||
++ns;
|
||||
loaded.shadowed=1;
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
loaded.tok[STYLE_CONT].u.style.shadowed = true;
|
||||
loaded.tok[STYLE_CONT].u.style.shadowed_set = true;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* U -- underline */ /*{{{*/
|
||||
case 'U':
|
||||
{
|
||||
if (loc[X]==0)
|
||||
{
|
||||
sprintf(errbuf,_("Trying to underline cell (%d,%d,%d) in line %d"),
|
||||
loc[X],loc[Y],loc[Z],line);
|
||||
err=errbuf;
|
||||
goto eek;
|
||||
}
|
||||
++ns;
|
||||
loaded.underline=1;
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
loaded.tok[STYLE_CONT].u.style.underline = true;
|
||||
loaded.tok[STYLE_CONT].u.style.underline_set = true;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* B -- bold */ /*{{{*/
|
||||
case 'B':
|
||||
{
|
||||
if (loc[X]==0)
|
||||
{
|
||||
sprintf(errbuf,_("Trying to bold cell (%d,%d,%d) in line %d"),
|
||||
loc[X], loc[Y], loc[Z], line);
|
||||
err=errbuf;
|
||||
goto eek;
|
||||
}
|
||||
++ns;
|
||||
loaded.bold=1;
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
loaded.tok[STYLE_CONT].u.style.bold = true;
|
||||
loaded.tok[STYLE_CONT].u.style.bold_set = true;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1402,7 +1514,8 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
case 'E':
|
||||
{
|
||||
++ns;
|
||||
loaded.fform = FLT_SCIENTIFIC;
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
loaded.tok[STYLE_CONT].u.style.fform = FLT_SCIENTIFIC;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1419,7 +1532,9 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
case 'T':
|
||||
{
|
||||
++ns;
|
||||
loaded.transparent=1;
|
||||
loaded.tok[STYLE_CONT].type = STYLE;
|
||||
loaded.tok[STYLE_CONT].u.style.transparent = true;
|
||||
loaded.tok[STYLE_CONT].u.style.transparent_set = true;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1468,9 +1583,12 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
if (fgets(buf, sizeof(buf), fp) == (char*)0) break;
|
||||
++line;
|
||||
width = strlen(buf);
|
||||
if (width>0 && buf[width-1]=='\n') buf[width-1]='\0';
|
||||
if (width > 0 && buf[width-1] == '\n') buf[--width] = '\0';
|
||||
/* More content? */
|
||||
if (width > 0 && buf[width-1]=='\\') { buf[--width]='\0'; ++nextrv; }
|
||||
if (width > 0 && buf[width-1] == '\\') {
|
||||
buf[--width] = '\0';
|
||||
++nextrv;
|
||||
}
|
||||
ns = buf;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1539,7 +1657,6 @@ const char *loadport(Sheet *sheet, const char *name)
|
||||
}
|
||||
cachelabels(sheet);
|
||||
forceupdate(sheet);
|
||||
redraw_sheet(sheet);
|
||||
return err;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -1892,7 +2009,7 @@ const char *sortblock(Sheet *sheet, const Location beg, const Location end,
|
||||
} while (work);
|
||||
cachelabels(sheet);
|
||||
forceupdate(sheet);
|
||||
sheet->changed=1;
|
||||
sheet->changed = true;
|
||||
if (norel) return _("uncomparable elements");
|
||||
else return (const char*)0;
|
||||
}
|
||||
|
@ -61,8 +61,6 @@ typedef struct
|
||||
#define CELL_IS_NULL(s,l) (CELL_AT(s,l) == NULLCELL)
|
||||
#define CELL_IS_GOODC(s,x,y,z) (LOC_WITHINC(s,x,y,z) && !CELL_IS_NULLC(s,x,y,z))
|
||||
#define CELL_IS_GOOD(s,l) (LOC_WITHIN(s,l) && !CELL_IS_NULL(s,l))
|
||||
#define SHADOWEDC(s,x,y,z) (CELL_IS_GOODC(s,x,y,z) && CELL_ATC(s,x,y,z)->shadowed)
|
||||
#define SHADOWED(s,l) (CELL_IS_GOOD(s,l) && CELL_AT(s,l)->shadowed)
|
||||
#define ALL_COORDS_IN_SHEETC(s,x,y,z) x=0; x<(s)->dimx; ++x) for (y=0; y<(s)->dimy; ++y) for (z=0; z<(s)->dimz; ++z
|
||||
#define ALL_LOCS_IN_SHEET(s,l) l[Z]=0; l[Z]<(s)->dimz; ++(l[Z])) for (l[Y]=0; l[Y]<(s)->dimy; ++(l[Y])) for (l[X]=0; l[X]<(s)->dimx; ++(l[X])
|
||||
#define ALL_LOCS_IN_REGION(s,l) l[Z]=(s)->mark1[Z]; l[Z]<=(s)->mark2[Z]; ++(l[Z])) for (l[Y]=(s)->mark1[Y]; l[Y]<=(s)->mark2[Y]; ++(l[Y])) for (l[X]=(s)->mark1[X]; l[X]<=(s)->mark2[X]; ++(l[X])
|
||||
@ -94,8 +92,18 @@ Token recompvalue(Sheet *sheet, const Location at);
|
||||
Token evaluate_at(Token t, Sheet *sheet, const Location at);
|
||||
void update(Sheet *sheet);
|
||||
char *geterror(Sheet *sheet, const Location at);
|
||||
void printvalue(char *s, size_t size, size_t chars, StringFormat sf,
|
||||
size_t printvalue(char *s, size_t size, size_t chars, StringFormat sf,
|
||||
FloatFormat ff, int precision, Sheet *sheet, const Location at);
|
||||
Style getstyle(Sheet *sheet, const Location at);
|
||||
Adjust getadjust(Sheet *sheet, const Location at);
|
||||
bool shadowed(Sheet *sheet, const Location at);
|
||||
bool isbold(Sheet *sheet, const Location at);
|
||||
bool underlined(Sheet *sheet, const Location at);
|
||||
ColorNum getcolor(Sheet *sheet, const Location at, ColorAspect aspect);
|
||||
bool transparent(Sheet *sheet, const Location at);
|
||||
FloatFormat getfltformat(Sheet *sheet, const Location at);
|
||||
PrecisionLevel getprecision(Sheet *sheet, const Location at);
|
||||
bool overridestyle(Sheet *sheet, const Location at, Style sty);
|
||||
bool setadjust(Sheet *sheet, const Location at, Adjust adjust);
|
||||
bool shadow(Sheet *sheet, const Location at, bool yep);
|
||||
bool bold(Sheet *sheet, const Location at, bool yep);
|
||||
@ -106,7 +114,7 @@ bool maketrans(Sheet *sheet, const Location at, bool yep);
|
||||
bool igncell(Sheet *sheet, const Location at, bool yep);
|
||||
void clk(Sheet *sheet, const Location at);
|
||||
bool setfltformat(Sheet *sheet, const Location at, FloatFormat ff);
|
||||
bool setprecision(Sheet *sheet, const Location at, int precision);
|
||||
bool setprecision(Sheet *sheet, const Location at, PrecisionLevel precision);
|
||||
void setlabel(Sheet *sheet, const Location at, const char *buf, int update);
|
||||
Token findlabel(Sheet *sheet, const char *label);
|
||||
void relabel(Sheet* sheet, const Location at,
|
||||
|
56
src/common/style.c
Normal file
56
src/common/style.c
Normal file
@ -0,0 +1,56 @@
|
||||
#include <style.h>
|
||||
|
||||
const char *Adjust_Name[] =
|
||||
{ [AUTOADJUST] = "Auto",
|
||||
[LEFT] = "left", [RIGHT] = "right", [CENTER] = "center"
|
||||
};
|
||||
|
||||
const char Adjust_Char[] = "alrc";
|
||||
|
||||
const char *FloatFormat_Name[] =
|
||||
{ [FLT_NO_FORMAT] = "NO_FORMAT",
|
||||
[FLT_DECIMAL] = "decimal", [FLT_SCIENTIFIC] = "scientific",
|
||||
[FLT_COMPACT] = "compact", [FLT_HEXACT] = "hexact"
|
||||
};
|
||||
|
||||
const char FloatFormat_Char[] = "Ndsch";
|
||||
|
||||
const char *ColorAspect_Name[] =
|
||||
{ [FOREGROUND] = "foreground", [BACKGROUND] = "background"
|
||||
};
|
||||
const ColorNum DefaultCN[] =
|
||||
{ [FOREGROUND] = 0, [BACKGROUND] = 16, [NUM_COLOR_ASPECTS] = 255 };
|
||||
|
||||
/* clearstyle -- zero out a style */
|
||||
void clearstyle(Style* s) {
|
||||
s->precision = NO_PRECISION;
|
||||
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
|
||||
s->aspect[ca] = NO_COLOR_SET;
|
||||
s->adjust = AUTOADJUST;
|
||||
s->fform = FLT_NO_FORMAT;
|
||||
s->shadowed = false;
|
||||
s->shadowed_set = false;
|
||||
s->transparent = false;
|
||||
s->transparent_set = false;
|
||||
s->bold = false;
|
||||
s->bold_set = false;
|
||||
s->underline = false;
|
||||
s->underline_set = false;
|
||||
}
|
||||
|
||||
/* style_equal -- return true if styles are equal */
|
||||
bool style_equal(Style l, Style r) {
|
||||
if (l.precision != r.precision) return false;
|
||||
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
|
||||
if (l.aspect[ca] != r.aspect[ca]) return false;
|
||||
if (l.adjust != r.adjust) return false;
|
||||
if (l.fform != r.fform) return false;
|
||||
if (l.shadowed_set != r.shadowed_set) return false;
|
||||
if (l.shadowed_set && (l.shadowed != r.shadowed)) return false;
|
||||
if (l.transparent_set != r.transparent_set) return false;
|
||||
if (l.transparent_set && (l.transparent != r.transparent)) return false;
|
||||
if (l.bold_set != r.bold_set) return false;
|
||||
if (l.bold_set && (l.bold != r.bold)) return false;
|
||||
if (l.underline_set != r.underline_set) return false;
|
||||
if (l.underline_set && (l.underline != r.underline)) return false;
|
||||
}
|
57
src/common/style.h
Normal file
57
src/common/style.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef STYLE_H
|
||||
#define STYLE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef short PrecisionLevel;
|
||||
#define NO_PRECISION 0
|
||||
|
||||
/* Note AUTOADJUST is treated exactly as though no Adjust value is set. */
|
||||
typedef enum { AUTOADJUST = 0, LEFT, RIGHT, CENTER } Adjust;
|
||||
extern const char *Adjust_Name[];
|
||||
#define MAX_ADJUST_NAME_LENGTH 16
|
||||
extern const char Adjust_Char[];
|
||||
|
||||
typedef enum
|
||||
{ FLT_NO_FORMAT = 0, FLT_DECIMAL, FLT_SCIENTIFIC, FLT_COMPACT, FLT_HEXACT }
|
||||
FloatFormat;
|
||||
extern const char *FloatFormat_Name[];
|
||||
#define MAX_FLOATFORM_NAME_LENGTH 16
|
||||
extern const char FloatFormat_Char[];
|
||||
|
||||
typedef unsigned char ColorNum;
|
||||
#define NO_COLOR_SET 0
|
||||
#define MAX_MAX_COLORS UCHAR_MAX
|
||||
|
||||
typedef enum { FOREGROUND = 0, BACKGROUND, NUM_COLOR_ASPECTS } ColorAspect;
|
||||
extern const char *ColorAspect_Name[];
|
||||
extern const ColorNum DefaultCN[];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PrecisionLevel precision;
|
||||
ColorNum aspect[NUM_COLOR_ASPECTS];
|
||||
Adjust adjust:3;
|
||||
FloatFormat fform:3;
|
||||
unsigned int shadowed:1;
|
||||
unsigned int shadowed_set:1;
|
||||
unsigned int transparent:1;
|
||||
unsigned int transparent_set:1;
|
||||
unsigned int bold:1;
|
||||
unsigned int bold_set:1;
|
||||
unsigned int underline:1;
|
||||
unsigned int underline_set:1;
|
||||
} Style;
|
||||
|
||||
void clearstyle(Style* s);
|
||||
bool style_equal(Style l, Style r);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
518
src/common/token.c
Normal file
518
src/common/token.c
Normal file
@ -0,0 +1,518 @@
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "default.h"
|
||||
#include "main.h"
|
||||
#include "style.h"
|
||||
#include "token.h"
|
||||
#include "utf8.h"
|
||||
|
||||
const char *Type_Name[] =
|
||||
{ [EMPTY] = "EMPTY", [STRING] = "STRING", [FLOAT] = "FLOAT", [INT] = "INT",
|
||||
[OPERATOR] = "OPERATOR", [LIDENT] = "LABEL", [FIDENT] = "FUNCTION",
|
||||
[LOCATION] = "LOCATION", [FUNCALL] = "FUNCTION-CALL", [EEK] = "ERROR",
|
||||
[BOOL] = "BOOL", [STYLE] = "STYLE"
|
||||
};
|
||||
|
||||
const char *Op_Name[] =
|
||||
{ [PLUS] = "+", [MINUS] = "-", [MUL] = "*", [DIV] = "/",
|
||||
[OP] = "(", [CP] = ")", [COMMA] = ",",
|
||||
[LT] = "<", [LE] = "<=", [GE] = ">=", [GT] = ">",
|
||||
[ISEQUAL] = "==", [ABOUTEQ] = "~=", [NE] = "!=",
|
||||
[POW] = "^", [MOD] = "%", [LAND] = "and", [LOR] = "or"
|
||||
};
|
||||
|
||||
/* loc_in_box -- returns true if test is in the box determined by b and c */
|
||||
bool loc_in_box(const Location test,
|
||||
const Location b, const Location c)
|
||||
{
|
||||
for (Dimensions dim = X; dim < HYPER; ++dim)
|
||||
{
|
||||
if (test[dim] < b[dim] && test[dim] < c[dim]) return false;
|
||||
if (test[dim] > b[dim] && test[dim] > c[dim]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* cleartoken - Initialize all of the memory of a token */ /*{{{*/
|
||||
void cleartoken(Token* tok)
|
||||
{
|
||||
tok->type = EMPTY;
|
||||
clearstyle(&(tok->u.style));
|
||||
tok->u.flt = 0.0;
|
||||
tok->u.location[0] = 0;
|
||||
tok->u.location[1] = 0;
|
||||
tok->u.location[2] = 0;
|
||||
}
|
||||
|
||||
/* tok_matches - return true if l and r appear to be the same token */ /*{{{*/
|
||||
bool tok_matches(const Token* l, const Token *r)
|
||||
{
|
||||
if (l->type != r->type) return false;
|
||||
switch (l->type) {
|
||||
case EMPTY: return true;
|
||||
case STRING: return l->u.string == r->u.string;
|
||||
case FLOAT: return l->u.flt == r->u.flt;
|
||||
case INT: return l->u.integer == r->u.integer;
|
||||
case OPERATOR: return l->u.op == r->u.op;
|
||||
case LIDENT: return l->u.lident == r->u.lident;
|
||||
case FIDENT: return l->u.fident == r->u.fident;
|
||||
case LOCATION:
|
||||
return l->u.location[X] == r->u.location[X]
|
||||
&& l->u.location[Y] == r->u.location[Y]
|
||||
&& l->u.location[Z] == r->u.location[Z];
|
||||
case EEK: return l->u.err == r->u.err;
|
||||
case FUNCALL:
|
||||
return l->u.funcall.fident == r->u.funcall.fident
|
||||
&& l->u.funcall.argc == r->u.funcall.argc
|
||||
&& l->u.funcall.argv == r->u.funcall.argv;
|
||||
case BOOL:
|
||||
return l->u.bl == r->u.bl;
|
||||
case STYLE:
|
||||
return style_equal(l->u.style, r->u.style);
|
||||
}
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* duperror - Sets tok to an error and strdups the message into place */
|
||||
Token duperror(Token* tok, const char* erro)
|
||||
{
|
||||
tok->type = EEK;
|
||||
tok->u.err = strdup(erro);
|
||||
return *tok;
|
||||
}
|
||||
|
||||
|
||||
/* print_fident -- print a field identifier to a dest and return the number
|
||||
of characters written
|
||||
*/ /*{{{*/
|
||||
static int print_fident(char* dest, size_t space, FunctionIdentifier id)
|
||||
{
|
||||
size_t identlen = strlen(tfunc[id].name);
|
||||
if ((identlen+1) < space) strcpy(dest, tfunc[id].name);
|
||||
else {
|
||||
(void)strncpy(dest, tfunc[id].name, space);
|
||||
dest[space-1] = '\0';
|
||||
}
|
||||
return identlen;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* print_string -- print a string value to a dest and return the number of
|
||||
characters written
|
||||
*/ /*{{{*/
|
||||
static int print_string(char* dest, size_t space,
|
||||
const char *str, StringFormat sf)
|
||||
{
|
||||
size_t cur = 0;
|
||||
if (sf == QUOTE_STRING && cur < space) dest[cur++] = '"';
|
||||
for ( ; cur < space && *str != '\0'; ++str)
|
||||
{
|
||||
if (sf == QUOTE_STRING && (*str == '"' || *str=='\\')) dest[cur++] = '\\';
|
||||
if (cur < space) dest[cur++] = *str;
|
||||
}
|
||||
if (sf == QUOTE_STRING && cur < space) dest[cur++] = '"';
|
||||
return cur;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
static int print_chars(char* d, size_t l, const char *s)
|
||||
{
|
||||
return print_string(d, l, s, DIRECT_STRING);
|
||||
}
|
||||
|
||||
/* print_int -- print an int value */ /*{{{*/
|
||||
size_t print_int(char *dest, size_t size, IntT val)
|
||||
{
|
||||
char buf[64];
|
||||
size_t buflen = sprintf(buf, INT_T_FMT, val);
|
||||
assert(buflen < sizeof(buf));
|
||||
(void)strncpy(dest, buf, size);
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
|
||||
size_t ptokatprec(char *dest, size_t size, size_t field_width, StringFormat sf,
|
||||
FloatFormat ff, int digits, ErrorFormat ef, const Token *tok,
|
||||
FunctionPrecedence atprec)
|
||||
{
|
||||
if (debug_level > 2) {
|
||||
printf("..Entering printtok; bufsize %d, field_width %d, qs %d, ff %s,"
|
||||
"prec %d, verr %d\n",
|
||||
size, field_width, sf, FloatFormat_Name[ff], digits, ef);
|
||||
}
|
||||
if (size > 0 ) *dest = '\0';
|
||||
if (tok == NULLTOKEN || tok->type == EMPTY) return 0;
|
||||
size_t cur = 0;
|
||||
switch (tok->type)
|
||||
{
|
||||
case STRING: cur += print_string(dest, size, tok->u.string, sf); break;
|
||||
case INT: cur += print_int(dest, size, tok->u.integer); break;
|
||||
case FLOAT: /*{{{*/
|
||||
{
|
||||
/* variables */ /*{{{*/
|
||||
char buf[1100], buf2[1100], *use, *p;
|
||||
size_t len, len2;
|
||||
/*}}}*/
|
||||
|
||||
if (digits == 0) digits = def_precision;
|
||||
else if (digits < 0) digits += FLT_T_DIG + 1;
|
||||
if (digits > sizeof(buf) - 20) digits = sizeof(buf) - 20;
|
||||
switch (ff) {
|
||||
case FLT_DECIMAL:
|
||||
len = sprintf(buf, FLT_T_STD_FMT, digits, tok->u.flt);
|
||||
use = buf;
|
||||
break;
|
||||
case FLT_SCIENTIFIC:
|
||||
len = sprintf(buf, FLT_T_SCI_FMT, digits, tok->u.flt);
|
||||
use = buf;
|
||||
break;
|
||||
case FLT_COMPACT:
|
||||
len = sprintf(buf, FLT_T_CPT_FMT, digits, tok->u.flt);
|
||||
/* Unfortunately, %g is so clever that sometimes it omits the
|
||||
decimal; it also has a penchant for not switching to scientific
|
||||
notation until the magnitude gets very large. So we try to
|
||||
counteract these bad tendencies here. If there is no decimal,
|
||||
we take the shorter of %.1f and %e with the same number of digits.
|
||||
*/
|
||||
use = buf;
|
||||
if (strchr(buf, '.') == NULL) {
|
||||
len = sprintf(buf, FLT_T_STD_FMT, 1, tok->u.flt);
|
||||
len2 = sprintf(buf2, FLT_T_SCI_FMT, digits, tok->u.flt);
|
||||
/* remove trailing 0s from sci format to be fair */
|
||||
size_t epos = strchr(buf2, 'e') - buf2;
|
||||
size_t tpos = epos;
|
||||
while (tpos > 1 && buf2[tpos-1] == '0' && buf2[tpos-2] != '.') --tpos;
|
||||
if (tpos < epos) {
|
||||
memmove(buf2+tpos, buf2+epos, len2-epos+1);
|
||||
len2 -= epos - tpos;
|
||||
}
|
||||
if (len2 < len) { use = buf2; len = len2; }
|
||||
}
|
||||
break;
|
||||
case FLT_HEXACT:
|
||||
len = sprintf(buf, FLT_T_HEX_FMT, tok->u.flt);
|
||||
use = buf;
|
||||
break;
|
||||
}
|
||||
|
||||
assert(len < sizeof(buf));
|
||||
p = use + len;
|
||||
while (*--p == ' ') { *p = '\0'; --len; }
|
||||
(void)strncpy(dest, use, size);
|
||||
cur += len;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
case OPERATOR: /*{{{*/
|
||||
{
|
||||
static const char *ops[]={ "+", "-", "*", "/", "(", ")", ",", "<", "<=", ">=", ">", "==", "~=", "!=", "^", "%" };
|
||||
|
||||
if (size >1)
|
||||
{
|
||||
dest[cur++]=*ops[tok->u.op];
|
||||
if (*(ops[tok->u.op]+1) && size > cur) dest[cur++]=*(ops[tok->u.op]+1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
case LIDENT:
|
||||
cur += print_chars(dest, size, tok->u.lident); break;
|
||||
case FIDENT: cur += print_fident(dest, size, tok->u.fident); break;
|
||||
case LOCATION: /*{{{*/
|
||||
{
|
||||
char buf[128];
|
||||
sprintf(buf, "&(%d,%d,%d)",
|
||||
tok->u.location[X], tok->u.location[Y], tok->u.location[Z]);
|
||||
cur += print_chars(dest, size, buf);
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
case FUNCALL: /*{{{*/
|
||||
{
|
||||
FunctionIdentifier fid = tok->u.funcall.fident;
|
||||
if (tok->u.funcall.argc <= 0)
|
||||
{
|
||||
cur += print_fident(dest+cur, size-cur-1, fid);
|
||||
if (tok->u.funcall.argc == 0)
|
||||
{
|
||||
if (cur < size - 2) { dest[cur++] = '('; dest[cur++] = ')'; }
|
||||
else cur += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
FunctionPrecedence fp = tfunc[fid].precedence;
|
||||
switch (fp)
|
||||
{
|
||||
case PREFIX_FUNC: {
|
||||
cur += print_fident(dest+cur, size-cur-1, fid);
|
||||
if (cur < size) dest[cur++] = '(';
|
||||
for (size_t ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai)
|
||||
{
|
||||
if (ai > 0 && cur < size) dest[cur++] = ',';
|
||||
/* The commas eliminate the need for precedence worries in arguments*/
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv + ai,
|
||||
NO_PRECEDENCE);
|
||||
}
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
break;
|
||||
}
|
||||
case PREFIX_NEG: {
|
||||
assert(tok->u.funcall.argc == 1);
|
||||
assert(tfunc[fid].display_symbol != NULL);
|
||||
if (fp < atprec && cur < size) dest[cur++] = '(';
|
||||
cur += print_chars(dest+cur, size-cur-1, tfunc[fid].display_symbol);
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv, fp);
|
||||
if (fp < atprec && cur < size) dest[cur++] = ')';
|
||||
break;
|
||||
}
|
||||
default: /* infix argument */
|
||||
assert(tok->u.funcall.argc > 1);
|
||||
if (fp < atprec && cur < size) dest[cur++] = '(';
|
||||
/* Check for the special relation sequence notation */
|
||||
bool specialrel = true;
|
||||
if (fid != FUNC_AND || tok->u.funcall.argc < 2) specialrel = false;
|
||||
else {
|
||||
for (int ai = 0; ai < tok->u.funcall.argc; ++ai) {
|
||||
if (tok->u.funcall.argv[ai].type != FUNCALL
|
||||
|| tok->u.funcall.argv[ai].u.funcall.argc != 2
|
||||
|| !IS_RELATION_FUNC(tok->u.funcall.argv[ai].u.funcall.fident))
|
||||
{
|
||||
specialrel = false;
|
||||
break;
|
||||
}
|
||||
if (ai > 0
|
||||
&& !tok_matches(tok->u.funcall.argv[ai].u.funcall.argv,
|
||||
tok->u.funcall.argv[ai-1].u.funcall.argv+1))
|
||||
{
|
||||
specialrel = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (specialrel) {
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv, INFIX_BOOL);
|
||||
for (int ai = 1; ai < tok->u.funcall.argc && cur < size-1; ++ ai) {
|
||||
dest[cur++] = ' ';
|
||||
const char *use =
|
||||
tfunc[tok->u.funcall.argv[ai].u.funcall.fident].name;
|
||||
cur += print_chars(dest+cur, size-cur-1, use);
|
||||
if (cur < size) dest[cur++] = ' ';
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef,
|
||||
tok->u.funcall.argv[ai].u.funcall.argv + 1,
|
||||
INFIX_REL);
|
||||
}
|
||||
} else {
|
||||
for (int ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai)
|
||||
{
|
||||
bool parenarg = false;
|
||||
if (ai > 0) {
|
||||
if (fp < INFIX_MUL && cur < size) dest[cur++] = ' ';
|
||||
const char *use = tfunc[fid].display_symbol;
|
||||
if (use == NULL) use = tfunc[fid].name;
|
||||
cur += print_chars(dest+cur, size-cur-1, use);
|
||||
if (fp < INFIX_MUL && cur < size) dest[cur++] = ' ';
|
||||
} else if (fp > PREFIX_NEG) {
|
||||
char powbuf[4096];
|
||||
size_t arglen = ptokatprec(powbuf, sizeof(powbuf), 0, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv, fp);
|
||||
assert(arglen < sizeof(powbuf)-1);
|
||||
if (powbuf[0] == '-') {
|
||||
parenarg = true;
|
||||
if (cur < size) dest[cur++] = '(';
|
||||
}
|
||||
}
|
||||
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
||||
digits, ef, tok->u.funcall.argv + ai, fp);
|
||||
if (parenarg && cur < size) dest[cur++] = ')';
|
||||
}
|
||||
}
|
||||
if (fp < atprec && cur < size) dest[cur++] = ')';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BOOL:
|
||||
cur += print_chars(dest, size, (tok->u.bl) ? "true" : "false"); break;
|
||||
case STYLE: /*{{{*/
|
||||
{
|
||||
const char *emptyrep = "background(0)";
|
||||
size_t nfields = 0;
|
||||
if (tok->u.style.precision != NO_PRECISION) ++nfields;
|
||||
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
|
||||
if (tok->u.style.aspect[ca] != NO_COLOR_SET) ++nfields;
|
||||
if (tok->u.style.adjust != AUTOADJUST) ++nfields;
|
||||
if (tok->u.style.fform != FLT_NO_FORMAT) ++nfields;
|
||||
if (tok->u.style.shadowed_set) ++nfields;
|
||||
if (tok->u.style.transparent_set) ++nfields;
|
||||
if (tok->u.style.bold_set) ++nfields;
|
||||
if (tok->u.style.underline_set) ++nfields;
|
||||
if (nfields == 0) cur += print_chars(dest, size, emptyrep);
|
||||
else {
|
||||
if (nfields > 1) cur += print_chars(dest, size, "+(");
|
||||
size_t shownfields = 0;
|
||||
if (tok->u.style.precision != NO_PRECISION) {
|
||||
cur += print_chars(dest+cur, size-cur-1, "precision(");
|
||||
cur += print_int(dest+cur, size-cur-1, tok->u.style.precision);
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
++shownfields;
|
||||
}
|
||||
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
|
||||
if (tok->u.style.aspect[ca] != NO_COLOR_SET) {
|
||||
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
||||
cur += print_chars(dest+cur, size-cur-1, ColorAspect_Name[ca]);
|
||||
if (cur < size) dest[cur++] = '(';
|
||||
cur += print_int(dest+cur, size-cur-1, tok->u.style.aspect[ca]);
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
++shownfields;
|
||||
}
|
||||
if (tok->u.style.adjust != AUTOADJUST) {
|
||||
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
||||
cur += print_chars(dest+cur, size-cur-1, "justify(");
|
||||
cur += print_chars(dest+cur, size-cur-1,
|
||||
Adjust_Name[tok->u.style.adjust]);
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
++shownfields;
|
||||
}
|
||||
if (tok->u.style.fform != FLT_NO_FORMAT) {
|
||||
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
||||
cur += print_chars(dest+cur, size-cur-1, "floatfmt(");
|
||||
cur += print_chars(dest+cur, size-cur-1,
|
||||
FloatFormat_Name[tok->u.style.fform]);
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
++shownfields;
|
||||
}
|
||||
if (tok->u.style.shadowed_set) {
|
||||
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
||||
cur += print_chars(dest+cur, size-cur-1, "shadowed(");
|
||||
cur += print_chars(dest+cur, size-cur-1,
|
||||
(tok->u.style.shadowed) ? "" : "false");
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
++shownfields;
|
||||
}
|
||||
if (tok->u.style.transparent_set) {
|
||||
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
||||
cur += print_chars(dest+cur, size-cur-1, "transparent(");
|
||||
cur += print_chars(dest+cur, size-cur-1,
|
||||
(tok->u.style.transparent) ? "" : "false");
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
++shownfields;
|
||||
}
|
||||
if (tok->u.style.bold_set) {
|
||||
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
||||
cur += print_chars(dest+cur, size-cur-1, "bold(");
|
||||
cur += print_chars(dest+cur, size-cur-1,
|
||||
(tok->u.style.bold) ? "" : "false");
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
++shownfields;
|
||||
}
|
||||
if (tok->u.style.underline_set) {
|
||||
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
||||
cur += print_chars(dest+cur, size-cur-1, "underline(");
|
||||
cur += print_chars(dest+cur, size-cur-1,
|
||||
(tok->u.style.underline) ? "" : "false");
|
||||
if (cur < size) dest[cur++] = ')';
|
||||
++shownfields;
|
||||
}
|
||||
if (nfields > 1 && cur < size) dest[cur++] = ')';
|
||||
}
|
||||
break;
|
||||
} /*}}}*/
|
||||
case EEK: /*{{{*/
|
||||
{
|
||||
if (ef == RESTORE_ERROR) {
|
||||
strncpy(dest + cur, "error(", size-cur-1);
|
||||
cur += 6;
|
||||
if (cur < size - 1)
|
||||
cur += print_string(dest+cur, size-cur-1, tok->u.err, QUOTE_STRING);
|
||||
if (cur < size - 1)
|
||||
dest[cur++] = ')';
|
||||
break;
|
||||
}
|
||||
(void)strncpy(dest+cur, _("ERROR"), size-cur-1);
|
||||
cur += strlen(_("ERROR"));
|
||||
if (ef == VERBOSE_ERROR)
|
||||
{
|
||||
(void)strncpy(dest+cur, ": ", size-cur-1);
|
||||
cur += 2;
|
||||
size_t errlen = strlen(tok->u.err);
|
||||
if ((cur+errlen+1) < size) strcpy(dest+cur, tok->u.err);
|
||||
else (void)strncpy(dest+cur, tok->u.err, size-cur-1);
|
||||
cur += errlen;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
/* default */ /*{{{*/
|
||||
default: assert(0);
|
||||
/*}}}*/
|
||||
}
|
||||
if (cur<size) dest[cur] = 0;
|
||||
else
|
||||
{
|
||||
dest[size-1] = 0;
|
||||
cur = size;
|
||||
}
|
||||
int mlen = mbslen(dest);
|
||||
if (field_width && mlen > field_width) {
|
||||
if (field_width < 6) {
|
||||
for (cur = 0; cur < field_width; ++cur) dest[cur] = '#';
|
||||
dest[cur] = 0;
|
||||
} else {
|
||||
char *ov = mbspos(dest+cur, -5);
|
||||
cur = ov - dest;
|
||||
cur += print_chars(dest+cur, size-cur-1, "...##");
|
||||
}
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
|
||||
size_t printtok(char* dest, size_t size, size_t field_width,
|
||||
StringFormat sf, FloatFormat ff,
|
||||
int digits, ErrorFormat ef, const Token *tok)
|
||||
{
|
||||
return ptokatprec(dest, size, field_width, sf, ff, digits, ef, tok,
|
||||
NO_PRECEDENCE);
|
||||
}
|
||||
/*}}}*/
|
||||
|
||||
static char dbgpbuf[4096];
|
||||
|
||||
/* dbgprint -- simple on the fly print for in the debugger */
|
||||
const char *dbgprint(const Token* tok) {
|
||||
size_t used = printtok(dbgpbuf, sizeof(dbgpbuf), 0, QUOTE_STRING, FLT_COMPACT,
|
||||
-1, VERBOSE_ERROR, tok);
|
||||
if (used > sizeof(dbgpbuf) - 2) {
|
||||
printf(_("Warning: buffer overflow in dbgprint"));
|
||||
}
|
||||
return dbgpbuf;
|
||||
}
|
||||
|
||||
/* print -- print token sequence */ /*{{{*/
|
||||
void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff,
|
||||
int digits, Token **n)
|
||||
{
|
||||
size_t cur;
|
||||
|
||||
cur=0;
|
||||
if (n != EMPTY_TVEC)
|
||||
for (; cur<size-1 && (*n) != NULLTOKEN; ++n)
|
||||
cur += printtok(s+cur, size-cur, 0, sf, ff, digits, TRUNCATED_ERROR, *n);
|
||||
if (cur<size) s[cur] = 0;
|
||||
else s[size-1] = 0;
|
||||
if (chars && mbslen(s) > chars) {
|
||||
for (cur=0; cur < chars; ++cur) s[cur] = '#';
|
||||
s[cur] = 0;
|
||||
}
|
||||
}
|
||||
/*}}}*/
|
189
src/common/token.h
Normal file
189
src/common/token.h
Normal file
@ -0,0 +1,189 @@
|
||||
#ifndef TOKEN_H
|
||||
#define TOKEN_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "func.h"
|
||||
#include "style.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* TO PRESERVE ABILITY TO READ OLD SAVE FILES, ONLY ADD ITEMS AT END */
|
||||
typedef enum {
|
||||
EMPTY
|
||||
#ifndef __cplusplus
|
||||
, STRING, FLOAT, INT, OPERATOR, LIDENT, FIDENT, LOCATION, EEK,
|
||||
FUNCALL, BOOL, STYLE
|
||||
#endif
|
||||
} Type;
|
||||
|
||||
#define MAX_TYPE_NAME_LENGTH 16
|
||||
extern const char *Type_Name[];
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PLUS, MINUS, MUL, DIV, OP, CP, COMMA,
|
||||
|
||||
LT, /* Take care with the macros just below */
|
||||
LE, GE, GT, ISEQUAL, ABOUTEQ, NE,
|
||||
|
||||
POW, MOD, LAND, LOR
|
||||
} Operator;
|
||||
|
||||
#define MAX_OP_NAME_LENGTH 3
|
||||
#define IS_RELATION_OP(op) (((op)>= LT) && ((op)<=NE))
|
||||
extern const char *Op_Name[];
|
||||
|
||||
typedef int Location[3]; /* NOTE: Locations are passed by REFERENCE not value */
|
||||
/* I.e., to accept a Location argument, declare the parameter to be of type
|
||||
const Location*
|
||||
*/
|
||||
|
||||
typedef enum { X=0, Y=1, Z=2, HYPER} Dimensions;
|
||||
|
||||
#define OLOCATION(loc) ((void)memset(loc, 0, sizeof(Location)))
|
||||
#define IN_OCTANT(loc) (loc[X]>=0 && loc[Y]>=0 && loc[Z]>=0)
|
||||
#define LOCATION_GETS(la,lb) ((void)memcpy(la, lb, sizeof(Location)))
|
||||
#define SAME_LOC(la,lb) (memcmp(la,lb,sizeof(Location))==0)
|
||||
#define LOCATION_SUB(la,lb) (la)[X]-=(lb)[X]; (la)[Y]-=(lb)[Y]; (la)[Z]-=(lb)[Z];
|
||||
#define LOCATION_ADD(la,lb) (la)[X]+=(lb)[X]; (la)[Y]+=(lb)[Y]; (la)[Z]+=(lb)[Z];
|
||||
|
||||
bool loc_in_box(const Location test,
|
||||
const Location b, const Location c);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FunctionIdentifier fident;
|
||||
int argc;
|
||||
Token *argv;
|
||||
} FunctionCall;
|
||||
|
||||
#define FLT_LONG_DOUBLE
|
||||
#ifdef FLT_LONG_DOUBLE
|
||||
typedef long double FltT;
|
||||
/* To switch the internal type used to store a floating value, it is
|
||||
supposed to suffice to redefine all of the following macros:
|
||||
*/
|
||||
#define FLT_T_STD_FMT "%.*Lf"
|
||||
#define FLT_T_SCI_FMT "%.*Le"
|
||||
#define FLT_T_CPT_FMT "%.*Lg"
|
||||
#define FLT_T_HEX_FMT "%La"
|
||||
#define FLT_T_DIG LDBL_DIG
|
||||
#define FLTEPS LDBL_EPSILON
|
||||
#define FLTMX LDBL_MAX
|
||||
#define STRTOFLT strtold
|
||||
#define ABSFLT fabsl
|
||||
#define LOGFLT logl
|
||||
#define LOG2FLT log2l
|
||||
#define LOG10FLT log10l
|
||||
#define SQRTFLT sqrtl
|
||||
#define POWFLT powl
|
||||
#define FMODFLT fmodl
|
||||
#define MODFFLT modfl
|
||||
#define SINFLT sinl
|
||||
#define COSFLT cosl
|
||||
#define TANFLT tanl
|
||||
#define SINHFLT sinhl
|
||||
#define COSHFLT coshl
|
||||
#define TANHFLT tanhl
|
||||
#define ASINFLT asinl
|
||||
#define ACOSFLT acosl
|
||||
#define ATANFLT atanl
|
||||
#define FLOORFLT floorl
|
||||
#define CEILFLT ceill
|
||||
#define ROUNDFLT rintl
|
||||
#define TRUNCFLT truncl
|
||||
#else
|
||||
typedef double FltT;
|
||||
/* To switch the internal type used to store a floating value, it is
|
||||
supposed to suffice to redefine all of the following macros:
|
||||
*/
|
||||
#define FLT_T_STD_FMT "%.*f"
|
||||
#define FLT_T_SCI_FMT "%.*e"
|
||||
#define FLT_T_CPT_FMT "%.*g"
|
||||
#define FLT_T_HEX_FMT "%a"
|
||||
#define FLT_T_DIG DBL_DIG
|
||||
#define FLTEPS DBL_EPSILON
|
||||
#define FLTMX DBL_MAX
|
||||
#define STRTOFLT strtod
|
||||
#define ABSFLT fabs
|
||||
#define LOGFLT log
|
||||
#define LOG2FLT log2
|
||||
#define LOG10FLT log10
|
||||
#define SQRTFLT sqrt
|
||||
#define POWFLT pow
|
||||
#define FMODFLT fmod
|
||||
#define MODFFLT modf
|
||||
#define SINFLT sin
|
||||
#define COSFLT cos
|
||||
#define TANFLT tan
|
||||
#define SINHFLT sinh
|
||||
#define COSHFLT cosh
|
||||
#define TANHFLT tanh
|
||||
#define ASINFLT asin
|
||||
#define ACOSFLT acos
|
||||
#define ATANFLT atan
|
||||
#define FLOORFLT floor
|
||||
#define CEILFLT ceil
|
||||
#define ROUNDFLT rint
|
||||
#define TRUNCFLT trunc
|
||||
#endif
|
||||
|
||||
typedef long long IntT;
|
||||
/* To switch the internal type used to store an integer value, it is
|
||||
supposed to suffice to redefine all of the following macros and typedefs.
|
||||
*/
|
||||
typedef unsigned long long UIntT;
|
||||
#define INT_T_FMT "%lld"
|
||||
#define STRTOINT strtoll
|
||||
/* This one depends on both the floating point and integer types */
|
||||
#ifdef FLT_LONG_DOUBLE
|
||||
#define ROUNDFLTINT llrintl
|
||||
#else
|
||||
#define ROUNDFLTINT llrint
|
||||
#endif
|
||||
/* End of subtype definitions */
|
||||
|
||||
/* The main type defined here */
|
||||
typedef struct Token_struc
|
||||
{
|
||||
Type type;
|
||||
union
|
||||
{
|
||||
char *string;
|
||||
FltT flt;
|
||||
IntT integer;
|
||||
Operator op;
|
||||
char *lident;
|
||||
FunctionIdentifier fident;
|
||||
Location location;
|
||||
FunctionCall funcall;
|
||||
char *err;
|
||||
bool bl;
|
||||
Style style;
|
||||
} u;
|
||||
} Token;
|
||||
|
||||
#define NULLTOKEN ((Token*)0)
|
||||
#define EMPTY_TVEC ((Token**)0)
|
||||
#define TOKISNUM(t) ((t).type == INT || (t).type == FLOAT || (t).type == EMPTY)
|
||||
|
||||
bool tok_matches(const Token *l, const Token *r);
|
||||
Token duperror(Token* tok, const char* erro);
|
||||
void cleartoken(Token* tok);
|
||||
|
||||
typedef enum {DIRECT_STRING, QUOTE_STRING} StringFormat;
|
||||
typedef enum {TRUNCATED_ERROR, VERBOSE_ERROR, RESTORE_ERROR} ErrorFormat;
|
||||
size_t printtok(char *dest, size_t size, size_t field_width, StringFormat sf,
|
||||
FloatFormat ff, int digits, ErrorFormat ef, const Token *tok);
|
||||
const char *dbgprint(const Token *tok); /* for use in debugging */
|
||||
void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff,
|
||||
int digits, Token **n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -89,37 +89,39 @@ static void format(unsigned char s, Cell *cell)
|
||||
fprintf(se,", format 0x%02x",s);
|
||||
if (s&0x80) fprintf(se,", locked");
|
||||
#endif
|
||||
cleartoken(&(cell->tok[STYLE_CONT]));
|
||||
cell->tok[STYLE_CONT].type = STYLE;
|
||||
switch (((unsigned int)(s&0x70))>>4)
|
||||
{
|
||||
case 0: /* fixed with given precision */ /*{{{*/
|
||||
{
|
||||
cell->precision = s&0x0f;
|
||||
cell->fform = FLT_DECIMAL;
|
||||
cell->tok[STYLE_CONT].u.style.precision = s&0x0f;
|
||||
cell->tok[STYLE_CONT].u.style.fform = FLT_DECIMAL;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
case 1: /* scientifix with given presision */ /*{{{*/
|
||||
{
|
||||
cell->precision = s&0x0f;
|
||||
cell->fform = FLT_SCIENTIFIC;
|
||||
cell->tok[STYLE_CONT].u.style.precision = s&0x0f;
|
||||
cell->tok[STYLE_CONT].u.style.fform = FLT_SCIENTIFIC;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
case 2: /* currency with given precision */ /*{{{*/
|
||||
{
|
||||
cell->precision=s&0x0f;
|
||||
cell->tok[STYLE_CONT].u.style.precision=s&0x0f;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
case 3: /* percent with given precision */ /*{{{*/
|
||||
{
|
||||
cell->precision=s&0x0f;
|
||||
cell->tok[STYLE_CONT].u.style.precision=s&0x0f;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
case 4: /* comma with given precision */ /*{{{*/
|
||||
{
|
||||
cell->precision=s&0x0f;
|
||||
cell->tok[STYLE_CONT].u.style.precision=s&0x0f;
|
||||
break;
|
||||
}
|
||||
/*}}}*/
|
||||
|
@ -236,12 +236,20 @@ bool_t xdr_cell(XDR *xdrs, Cell *cell)
|
||||
cell->tok[tv] = tok;
|
||||
}
|
||||
if (xdr_mystring(xdrs, &(cell->label))==0) return 0;
|
||||
x = cell->adjust;
|
||||
/* x = cell->adjust; ONLY DECODING */
|
||||
result = xdr_int(xdrs, &x);
|
||||
cell->adjust = x;
|
||||
cleartoken(cell->tok + STYLE_CONT);
|
||||
Adjust a = x;
|
||||
if (a != AUTOADJUST) {
|
||||
cell->tok[STYLE_CONT].type = STYLE;
|
||||
cell->tok[STYLE_CONT].u.style.adjust = a;
|
||||
}
|
||||
if (result==0) return 0;
|
||||
if (xdr_int(xdrs, &(cell->precision))==0) return 0;
|
||||
x = 0;
|
||||
if (xdr_int(xdrs, &x)==0) return 0;
|
||||
if (x != NO_PRECISION) {
|
||||
cell->tok[STYLE_CONT].type = STYLE;
|
||||
cell->tok[STYLE_CONT].u.style.precision = (PrecisionLevel)x;
|
||||
}
|
||||
/* Since we only decode, we do not need to do this any more; it is
|
||||
just kept for documentation purposes:
|
||||
|
||||
@ -252,13 +260,32 @@ bool_t xdr_cell(XDR *xdrs, Cell *cell)
|
||||
*/
|
||||
result = xdr_int(xdrs, &x);
|
||||
/* cell->updated = ((x&(1))!=0); # Makes no sense to restore this */
|
||||
cell->shadowed = ((x & (1<<1)) != 0);
|
||||
if ((x & (1<<2)) !=0 ) cell->fform = FLT_SCIENTIFIC;
|
||||
if ((x & (1<<1)) != 0) {
|
||||
cell->tok[STYLE_CONT].type = STYLE;
|
||||
cell->tok[STYLE_CONT].u.style.shadowed = true;
|
||||
cell->tok[STYLE_CONT].u.style.shadowed_set = true;
|
||||
}
|
||||
if ((x & (1<<2)) !=0 ) {
|
||||
cell->tok[STYLE_CONT].type = STYLE;
|
||||
cell->tok[STYLE_CONT].u.style.fform = FLT_SCIENTIFIC;
|
||||
}
|
||||
cell->locked = ((x & (1<<3)) != 0);
|
||||
cell->transparent = ((x & (1<<4)) != 0);
|
||||
if ((x & (1<<4)) != 0) {
|
||||
cell->tok[STYLE_CONT].type = STYLE;
|
||||
cell->tok[STYLE_CONT].u.style.transparent = true;
|
||||
cell->tok[STYLE_CONT].u.style.transparent_set = true;
|
||||
}
|
||||
cell->ignored = ((x & (1<<5)) != 0);
|
||||
cell->bold = ((x & (1<<6)) != 0);
|
||||
cell->underline = ((x & (1<<7)) != 0);
|
||||
if ((x & (1<<6)) != 0) {
|
||||
cell->tok[STYLE_CONT].type = STYLE;
|
||||
cell->tok[STYLE_CONT].u.style.bold = true;
|
||||
cell->tok[STYLE_CONT].u.style.bold_set = true;
|
||||
}
|
||||
if ((x & (1<<7)) != 0) {
|
||||
cell->tok[STYLE_CONT].type = STYLE;
|
||||
cell->tok[STYLE_CONT].u.style.underline = true;
|
||||
cell->tok[STYLE_CONT].u.style.underline_set = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/*}}}*/
|
||||
@ -428,7 +455,6 @@ const char *loadxdr(Sheet *sheet, const char *name)
|
||||
sheet->changed=0;
|
||||
cachelabels(sheet);
|
||||
forceupdate(sheet);
|
||||
redraw_sheet(sheet);
|
||||
return (const char*)0;
|
||||
return NULL;
|
||||
}
|
||||
/*}}}*/
|
||||
|
@ -61,6 +61,7 @@ static int do_attribute(Sheet *cursheet)
|
||||
{
|
||||
int c;
|
||||
Cell *cc = curcell(cursheet);
|
||||
Style sc = getstyle(cursheet, cursheet->cur);
|
||||
do
|
||||
{
|
||||
MarkState ms = getmarkstate(cursheet);
|
||||
@ -86,7 +87,7 @@ static int do_attribute(Sheet *cursheet)
|
||||
{
|
||||
const char *justifymenu[] =
|
||||
{ _("lL)eft"), _("rR)ight"), _("cC)entered"), NULL };
|
||||
switch (c = line_menu(prompt, justifymenu, getadjust(cc)))
|
||||
switch (c = line_menu(prompt, justifymenu, sc.adjust))
|
||||
{
|
||||
case -2: case -1: c = K_INVALID; break;
|
||||
case 0: c = ADJUST_LEFT; break;
|
||||
@ -102,7 +103,7 @@ static int do_attribute(Sheet *cursheet)
|
||||
{ _("dD)ecimal"), _("sS)cientific"), _("cC)ompact"),
|
||||
_("hH)exact"), _("pP)recision"), NULL
|
||||
};
|
||||
switch (c = line_menu(prompt, floatmenu, getfltformat(cc)))
|
||||
switch (c = line_menu(prompt, floatmenu, sc.fform))
|
||||
{
|
||||
case -2: case -1: c = K_INVALID; break;
|
||||
case 0: c = ADJUST_DECIMAL; break;
|
||||
@ -346,9 +347,9 @@ void display_main(Sheet *cursheet)
|
||||
do
|
||||
{
|
||||
quit = 0;
|
||||
redraw_sheet(cursheet);
|
||||
k=wgetc();
|
||||
wmove(stdscr,LINES-1,0);
|
||||
update(cursheet);
|
||||
k = wgetc();
|
||||
wmove(stdscr, LINES-1, 0);
|
||||
wclrtoeol(stdscr);
|
||||
switch ((int)k)
|
||||
{
|
||||
@ -358,7 +359,8 @@ void display_main(Sheet *cursheet)
|
||||
case KEY_F(0):
|
||||
case KEY_F(10): k = show_menu(cursheet); break;
|
||||
}
|
||||
} while (k == K_INVALID || !do_sheetcmd(cursheet,k,0) || doanyway(cursheet,_("Sheet modified, leave anyway?"))!=1);
|
||||
} while (k == K_INVALID || !do_sheetcmd(cursheet, k, 0)
|
||||
|| !doanyway(cursheet,_("Sheet modified, leave anyway?")));
|
||||
}
|
||||
|
||||
#define CHANNEL_MAX 1000
|
||||
@ -404,7 +406,7 @@ void display_end(Sheet* sheet)
|
||||
|
||||
void redraw_cell(Sheet *sheet, const Location at )
|
||||
{
|
||||
redraw_sheet(sheet);
|
||||
update(sheet);
|
||||
}
|
||||
|
||||
/* redraw_sheet -- draw a sheet with cell cursor */
|
||||
@ -428,7 +430,7 @@ void redraw_sheet(Sheet *sheet)
|
||||
assert(sheet->offy>=0);
|
||||
|
||||
/* correct offsets to keep cursor visible */
|
||||
while (shadowed(curcell(sheet)))
|
||||
while (shadowed(sheet, sheet->cur))
|
||||
{
|
||||
--(sheet->cur[X]);
|
||||
assert(sheet->cur[X] >= 0);
|
||||
@ -508,23 +510,29 @@ void redraw_sheet(Sheet *sheet)
|
||||
|
||||
realx = x;
|
||||
cutoff = 0;
|
||||
if (x == sheet->offx)
|
||||
while (SHADOWEDC(sheet,realx,y-header+sheet->offy,sheet->cur[Z]))
|
||||
{
|
||||
--realx;
|
||||
cutoff+=columnwidth(sheet, realx, sheet->cur[Z]);
|
||||
if (x == sheet->offx) {
|
||||
Location fil;
|
||||
fil[X] = realx;
|
||||
fil[Y] = y - header + sheet->offy;
|
||||
fil[Z] = sheet->cur[Z];
|
||||
while (shadowed(sheet, fil)) {
|
||||
--realx; fil[X] = realx;
|
||||
cutoff += columnwidth(sheet, realx, sheet->cur[Z]);
|
||||
}
|
||||
}
|
||||
tmp[X] = realx; tmp[Y] = y - header + sheet->offy;
|
||||
tmp[Z] = sheet->cur[Z]; cell = safe_cell_at(sheet, tmp);
|
||||
tmp[Z] = sheet->cur[Z];
|
||||
cell = safe_cell_at(sheet, tmp);
|
||||
Style sc = getstyle(sheet, tmp);
|
||||
if ((size = cellwidth(sheet, tmp)))
|
||||
{
|
||||
bool invert;
|
||||
|
||||
if (bufsz < (size*UTF8SZ+1))
|
||||
buf = realloc(buf, bufsz=(size*UTF8SZ+1));
|
||||
printvalue(buf, (size*UTF8SZ + 1), size, quote, getfltformat(cell),
|
||||
getprecision(cell), sheet, tmp);
|
||||
adjust(getadjust(cell), buf, size);
|
||||
printvalue(buf, (size*UTF8SZ + 1), size, quote, sc.fform,
|
||||
sc.precision, sheet, tmp);
|
||||
adjust(sc.adjust, buf, size);
|
||||
assert(size>=cutoff);
|
||||
if (width+((int)(size-cutoff)) >= sheet->maxx)
|
||||
{
|
||||
@ -534,8 +542,10 @@ void redraw_sheet(Sheet *sheet)
|
||||
else realsize=size;
|
||||
ms = getmarkstate(sheet);
|
||||
int usecp = 0;
|
||||
ColorNum fg = getcolor(cell, FOREGROUND);
|
||||
ColorNum bg = getcolor(cell, BACKGROUND);
|
||||
ColorNum fg = sc.aspect[FOREGROUND];
|
||||
if (fg == NO_COLOR_SET) fg = DefaultCN[FOREGROUND];
|
||||
ColorNum bg = sc.aspect[BACKGROUND];
|
||||
if (bg == NO_COLOR_SET) bg = DefaultCN[BACKGROUND];
|
||||
while (usecp < curcp) {
|
||||
unsigned short pfg, pbg;
|
||||
pair_content(usecp, &pfg, &pbg);
|
||||
@ -549,8 +559,8 @@ void redraw_sheet(Sheet *sheet)
|
||||
if (x == sheet->cur[X] && (y-header+sheet->offy) == sheet->cur[Y])
|
||||
invert = (ms == MARKING) ? true : !invert;
|
||||
if (invert) (void)wattron(stdscr,DEF_CELLCURSOR);
|
||||
if (isbold(cell)) wattron(stdscr,A_BOLD);
|
||||
if (underlined(cell)) wattron(stdscr,A_UNDERLINE);
|
||||
if (sc.bold) wattron(stdscr,A_BOLD);
|
||||
if (sc.underline) wattron(stdscr,A_UNDERLINE);
|
||||
(void)mvwaddstr(stdscr,sheet->oriy+y,sheet->orix+width,buf+cutoff);
|
||||
for (fill=mbslen(buf+cutoff); fill<realsize; ++fill)
|
||||
(void)waddch(stdscr,(chtype)(unsigned char)' ');
|
||||
@ -581,13 +591,13 @@ void redraw_sheet(Sheet *sheet)
|
||||
cell = curcell(sheet);
|
||||
Token bc = gettok(cell, BASE_CONT);
|
||||
printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING,
|
||||
FLT_COMPACT, 0, TRUNCATED_ERROR, &bc);
|
||||
FLT_COMPACT, -1, TRUNCATED_ERROR, &bc);
|
||||
Token ic = gettok(cell, ITER_CONT);
|
||||
if (ic.type != EMPTY && mbslen(buf) < (size_t)(sheet->maxx+1-4))
|
||||
{
|
||||
strcat(buf," -> ");
|
||||
printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING,
|
||||
FLT_COMPACT, 0, TRUNCATED_ERROR, &ic);
|
||||
FLT_COMPACT, -1, TRUNCATED_ERROR, &ic);
|
||||
}
|
||||
}
|
||||
*mbspos(buf, sheet->maxx) = 0;
|
||||
@ -996,19 +1006,12 @@ void show_text(const char *text)
|
||||
}
|
||||
|
||||
/* keypressed -- get keypress, if there is one */
|
||||
int keypressed(void)
|
||||
bool keypressed(void)
|
||||
{
|
||||
(void)nodelay(stdscr,TRUE);
|
||||
if (getch()==ERR)
|
||||
{
|
||||
(void)nodelay(stdscr,FALSE);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)nodelay(stdscr,FALSE);
|
||||
return 1;
|
||||
}
|
||||
(void)nodelay(stdscr, TRUE);
|
||||
bool result = (getch() != ERR);
|
||||
nodelay(stdscr, FALSE);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -1125,6 +1128,9 @@ static Key wgetc(void)
|
||||
case '\r':
|
||||
case '\n': return K_MENTER;
|
||||
|
||||
/* M-s -- edit style expression */
|
||||
case 's': return K_EDIT_STYLE_EXPR;
|
||||
|
||||
/* M-z -- SAVEQUIT */
|
||||
case 'z': return K_SAVEQUIT;
|
||||
|
||||
|
@ -18,7 +18,7 @@ int line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *
|
||||
int line_ok(const char *prompt, int curx);
|
||||
int line_binary(const char *prompt, const char* op1, const char* op2, int curx);
|
||||
void line_msg(const char *prompt, const char *msg);
|
||||
int keypressed(void);
|
||||
bool keypressed(void);
|
||||
void show_text(const char *text);
|
||||
|
||||
Key show_menu(Sheet *cursheet);
|
||||
|
@ -8,6 +8,7 @@ decl {\#include <FL/Fl_Select_Browser.H>} {public global}
|
||||
decl {\#include <FL/Fl_Sys_Menu_Bar.H>} {public global}
|
||||
|
||||
decl {\#include "display.h"} {public global}
|
||||
decl {\#include "utf8.h"} {public global}
|
||||
|
||||
decl {\#include <unistd.h>} {private global}
|
||||
decl {\#include <stdint.h>} {private global}
|
||||
@ -126,12 +127,14 @@ class TeapotTable {open : {public Fl_Table}}
|
||||
}
|
||||
|
||||
case CONTEXT_CELL: {
|
||||
while (SHADOWEDC(cursheet, C, R, cursheet->cur[Z]))
|
||||
xx -= W = col_width(--C);
|
||||
int x = C+1;
|
||||
while (SHADOWEDC(cursheet, x, R, cursheet->cur[Z]))
|
||||
W += col_width(x), x++;
|
||||
|
||||
Location crz; crz[X] = C; crz[Y] = R; crz[Z] = cursheet->cur[Z];
|
||||
while (shadowed(cursheet, crz)) {
|
||||
crz[X] = --C;
|
||||
xx -= W = col_width(C);
|
||||
}
|
||||
crz[X]++;
|
||||
while (shadowed(cursheet, crz))
|
||||
W += col_width(crz[X]++);
|
||||
fl_push_clip(xx, yy, W, H);
|
||||
bool selected = false;
|
||||
MarkState ms = getmarkstate(cursheet);
|
||||
@ -141,8 +144,10 @@ class TeapotTable {open : {public Fl_Table}}
|
||||
selected = loc_in_box(test, cursheet->mark1, cursheet->mark2);
|
||||
bool iscurrent = (C == cursheet->cur[X] && R == cursheet->cur[Y]);
|
||||
Cell *cell = safe_cell_at(cursheet, test);
|
||||
Fl_Color cellbg =
|
||||
((Fl_Color *)(cursheet->palette))[getcolor(cell, BACKGROUND)];
|
||||
Style sc = getstyle(cursheet, test);
|
||||
ColorNum bgcn = sc.aspect[BACKGROUND];
|
||||
if (bgcn == NO_COLOR_SET) bgcn = DefaultCN[BACKGROUND];
|
||||
Fl_Color cellbg = ((Fl_Color *)(cursheet->palette))[bgcn];
|
||||
if (selected) cellbg = tpt_selection_version(cellbg);
|
||||
if (!LOC_WITHIN(cursheet,test))
|
||||
cellbg = fl_color_average(cellbg, FL_BLACK, 0.97);
|
||||
@ -153,24 +158,39 @@ class TeapotTable {open : {public Fl_Table}}
|
||||
fl_pop_clip();
|
||||
|
||||
fl_push_clip(xx+3, yy+3, W-6, H-6);
|
||||
Fl_Color cellfg =
|
||||
((Fl_Color *)(cursheet->palette))[getcolor(cell, FOREGROUND)];
|
||||
ColorNum fgcn = sc.aspect[FOREGROUND];
|
||||
if (fgcn == NO_COLOR_SET) fgcn = DefaultCN[FOREGROUND];
|
||||
Fl_Color cellfg = ((Fl_Color *)(cursheet->palette))[fgcn];
|
||||
fl_color(cellfg);
|
||||
fl_font(FL_HELVETICA | (isbold(cell) ? FL_BOLD : 0), 14);
|
||||
|
||||
printvalue(s, sizeof(s), 0, quote, getfltformat(cell),
|
||||
getprecision(cell), cursheet, test);
|
||||
fl_font(FL_HELVETICA | (sc.bold ? FL_BOLD : 0), 14);
|
||||
|
||||
size_t len = printvalue(s, sizeof(s), 0, quote, sc.fform,
|
||||
sc.precision, cursheet, test);
|
||||
size_t nlen = len;
|
||||
int ww = 0, hh = 0;
|
||||
fl_measure(s, ww, hh, 0);
|
||||
if (ww > W-6) for (int i = 0; s[i]; i++) s[i] = '\#';
|
||||
|
||||
Adjust adj = getadjust(cell);
|
||||
while (ww > W-6) {
|
||||
char *dc = mbspos(s+nlen-1, -1);
|
||||
nlen = dc - s;
|
||||
s[nlen] = (char)0;
|
||||
ww = 0;
|
||||
fl_measure(s, ww, hh, 0);
|
||||
}
|
||||
if (nlen < len) {
|
||||
if (nlen < 1) { s[0] = '\#'; s[1] = (char)0; }
|
||||
else if (nlen < 6) for (int i = 0; s[i]; i++) s[i] = '\#';
|
||||
else {
|
||||
char *ov = mbspos(s+nlen-1, -5);
|
||||
if (ov < s) ov = s;
|
||||
strncpy(ov, "...\#\#", sizeof(s) - nlen);
|
||||
}
|
||||
}
|
||||
Adjust adj = sc.adjust;
|
||||
fl_draw(s, xx+3, yy+3, W-6, H-6,
|
||||
adj == RIGHT ? FL_ALIGN_RIGHT :
|
||||
adj == LEFT ? FL_ALIGN_LEFT : FL_ALIGN_CENTER,
|
||||
NULL, 0);
|
||||
if (underlined(cell)) fl_xyline(xx, yy+H-7, xx+W);
|
||||
if (sc.underline) fl_xyline(xx, yy+H-7, xx+W);
|
||||
fl_pop_clip();
|
||||
|
||||
return;
|
||||
@ -266,7 +286,9 @@ class TeapotTable {open : {public Fl_Table}}
|
||||
case FL_F+10: k = (Key)'/'; break;
|
||||
case FL_Tab: if (shift) { k = K_CLOCK; break; }
|
||||
case FL_Enter:
|
||||
case FL_KP_Enter: k = alt?K_MENTER:K_ENTER; break;
|
||||
case FL_KP_Enter:
|
||||
k = alt ? (shift ? K_EDIT_STYLE_EXPR : K_MENTER) : K_ENTER;
|
||||
break;
|
||||
case 'c':
|
||||
if (ctrl) {
|
||||
do_mark(cursheet, GET_MARK_CUR);
|
||||
@ -688,37 +710,38 @@ class MainWindow {open}
|
||||
} else {
|
||||
Token t = gettok(curcell(sheet), BASE_CONT);
|
||||
printtok(val, sizeof(val), 0, QUOTE_STRING,
|
||||
FLT_COMPACT, 0, VERBOSE_ERROR, &t);
|
||||
FLT_COMPACT, -1, VERBOSE_ERROR, &t);
|
||||
}
|
||||
Token t = gettok(curcell(sheet), ITER_CONT);
|
||||
if (t.type != EMPTY) {
|
||||
snprintf(val+strlen(val),sizeof(val)-strlen(val), " -> ");
|
||||
printtok(val+strlen(val), sizeof(val)-strlen(val), 0,
|
||||
QUOTE_STRING, FLT_COMPACT, 0, VERBOSE_ERROR, &t);
|
||||
QUOTE_STRING, FLT_COMPACT, -1, VERBOSE_ERROR, &t);
|
||||
}
|
||||
|
||||
line_edit(sheet, val, 0, buf, 0, 0);
|
||||
Cell *cell = curcell(sheet);
|
||||
switch (getadjust(cell)) {
|
||||
Style sc = getstyle(sheet, sheet->cur);
|
||||
switch (sc.adjust) {
|
||||
case LEFT: left->setonly(); break;
|
||||
case RIGHT: right->setonly(); break;
|
||||
case CENTER: center->setonly(); break;
|
||||
}
|
||||
if (SHADOWEDC(sheet,
|
||||
sheet->cur[X]+1, sheet->cur[Y], sheet->cur[Z]))
|
||||
Location nb; LOCATION_GETS(nb, sheet->cur); nb[X]++;
|
||||
if (shadowed(sheet, nb))
|
||||
shadow->set();
|
||||
else shadow->clear();
|
||||
if (::transparent(cell)) transparent->set();
|
||||
if (sc.transparent) transparent->set();
|
||||
else transparent->clear();
|
||||
if (locked(cell)) lock->set();
|
||||
else lock->clear();
|
||||
if (ignored(cell)) ignore->set();
|
||||
else ignore->clear();
|
||||
if (isbold(cell)) bold->set();
|
||||
if (sc.bold) bold->set();
|
||||
else bold->clear();
|
||||
if (underlined(cell)) underline->set();
|
||||
if (sc.underline) underline->set();
|
||||
else underline->clear();
|
||||
switch (getfltformat(cell)) {
|
||||
switch (sc.fform) {
|
||||
case FLT_DECIMAL: dec->setonly(); break;
|
||||
case FLT_SCIENTIFIC: sci->setonly(); break;
|
||||
case FLT_COMPACT: cpt->setonly(); break;
|
||||
@ -870,10 +893,10 @@ Function
|
||||
MainWindow::current->line_msg(prompt, msg);
|
||||
} {} }
|
||||
|
||||
Function {keypressed()} {open C return_type int} {code
|
||||
Function {keypressed()} {open C return_type bool} {code
|
||||
{
|
||||
while (Fl::wait(.01)) if (Fl::event_key(FL_Escape)) return 1;
|
||||
return 0;
|
||||
while (Fl::wait(.01)) if (Fl::event_key(FL_Escape)) return true;
|
||||
return false;
|
||||
} {} }
|
||||
|
||||
Function
|
||||
@ -927,7 +950,7 @@ Function
|
||||
{redraw_cell(Sheet *sheet, const Location /* at */)} {C return_type void}
|
||||
{ code
|
||||
{
|
||||
redraw_sheet(sheet);
|
||||
update(sheet);
|
||||
} {} }
|
||||
|
||||
Function
|
||||
@ -949,6 +972,7 @@ Function
|
||||
palt[DefaultCN[FOREGROUND]] = FL_FOREGROUND_COLOR;
|
||||
palt[DefaultCN[BACKGROUND]] = FL_BACKGROUND2_COLOR;
|
||||
ColorNum c = 0; SKIPDEFCOLS(c);
|
||||
palt[c++] = FL_FOREGROUND_COLOR; SKIPDEFCOLS(c);
|
||||
palt[c++] = FL_BACKGROUND_COLOR; SKIPDEFCOLS(c);
|
||||
palt[c++] = FL_INACTIVE_COLOR; SKIPDEFCOLS(c);
|
||||
palt[c++] = FL_SELECTION_COLOR; SKIPDEFCOLS(c);
|
||||
|
Loading…
Reference in New Issue
Block a user