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:
Glen Whitney 2019-09-03 01:41:37 -07:00
parent 253062e906
commit c52219f827
27 changed files with 1902 additions and 1154 deletions

View File

@ -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

View File

@ -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)

View File

@ -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;
}
}
/*}}}*/

View File

@ -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

View File

@ -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 '$':

View File

@ -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);

View File

@ -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 },

View File

@ -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

View File

@ -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("&lt;",fp)==EOF) return strerror(errno); break;
case '>': if (fputs_close("&gt;",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;
}
/*}}}*/

View File

@ -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 '$':

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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
}

View File

@ -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;
}

View File

@ -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
View 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
View 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
View 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
View 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

View File

@ -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;
}
/*}}}*/

View File

@ -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;
}
/*}}}*/

View File

@ -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;

View File

@ -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);

View File

@ -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);