diff --git a/doc/teapot.lyx b/doc/teapot.lyx index f7dce0a..6fe71d2 100644 --- a/doc/teapot.lyx +++ b/doc/teapot.lyx @@ -4895,14 +4895,36 @@ false, \end_layout \begin_layout Description -Location Cell labels and the result of the -\family typewriter +Label Cell labels are of this type, but they generally evaluate to locations + (or cause an error if there is no cell with that label), so you don't generally + manipulate values of this type. +\end_layout + +\begin_layout Description +Keyword The names of functions and of special arguments to functions, like + the +\family sans +decimal +\family default + flag to the +\family sans +float() +\family default + function. + +\end_layout + +\begin_layout Description +Location The values of cell labels and the result of the +\family sans &() \family default function have this type, but there are no location constant literals. However, +\family sans +&(3,2,1) \family typewriter -&(3,2,1), +, \family default for example, acts very much like a location constant literal. \end_layout @@ -4910,16 +4932,30 @@ Location Cell labels and the result of the \begin_layout Description Error Syntactical or semantical (type mismatch) errors cause this value, as well as division by 0 and the function -\family typewriter +\family sans error() \family default . An error always has an assigned error message. Functions and operators, when applied to a value of the type error, evaluate to just that value. - That way, the first error which was found, possibly deep inside a complicated + That way, the first error encountered, possibly deep inside a complicated expression, will be shown. - +\end_layout + +\begin_layout Description +Expression a teapot formula; some functions (like +\family sans +find() +\family default +) take an expression as an argument so that it can be evaluated from the + point of view of other cells. +\end_layout + +\begin_layout Description +Style the encapsulated visual/display attributes of a cell. + Not many operators/functions apply to Style values, but they are the key + to allowing the appearance of a cell to depend on its value. \end_layout \begin_layout Subsection @@ -5311,6 +5347,9 @@ y \emph default are strings, the result is the concatenated string. If they are locations, this operates componentwise. + If they are styles, it means to take any unset components of the left-hand + style and fill them in with values from the right-hand style (ignoring + the right-hand components that are already set in the left-hand style). \end_layout \begin_layout Description @@ -6380,6 +6419,37 @@ x is given in radians. \end_layout +\begin_layout Description + +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +background +\series medium +(int +\emph on + +\begin_inset space ~ +\end_inset + + +\emph default +c) +\series default + evaluates to a style token with the background color set to +\emph on +c +\emph default + (and no other fields set). +\end_layout + \begin_layout Description below \series medium @@ -6478,6 +6548,37 @@ or \begin_layout Description +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +bold +\series medium +([bool +\emph on + +\begin_inset space ~ +\end_inset + +b +\emph default +]) +\series default + evaluates to a style token with the bold property set to +\emph on +b +\emph default +, which defaults to true (and no other fields set). +\end_layout + +\begin_layout Description + \series medium bool \begin_inset space ~ @@ -6543,6 +6644,16 @@ x . \end_layout +\begin_layout Description +center keyword used as an argument to +\family sans +\series bold +justify +\family default +\series default +(). +\end_layout + \begin_layout Description clock \series medium @@ -6570,8 +6681,14 @@ condition \end_layout \begin_layout Description -compact used as a keyword to the string() function; listed here to record - that this identifier may not be used as a cell label. +compact used as a keyword to the +\family sans +\series bold +string +\family default +\series default +() function; listed here to record that this identifier may not be used + as a cell label. \end_layout \begin_layout Description @@ -6907,6 +7024,26 @@ is \begin_layout Description +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +floatfmt +\series medium +(decimal|scientific|compact|hexact) +\series default + evaluates to a style token with the floating-point format set to the specified + format, given as a bare word (and no other fields set). +\end_layout + +\begin_layout Description + \series medium float \begin_inset space ~ @@ -6935,6 +7072,37 @@ x \begin_layout Description +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +foreground +\series medium +(int +\emph on + +\begin_inset space ~ +\end_inset + + +\emph default +c) +\series default + evaluates to a style token with the foreground color set to +\emph on +c +\emph default + (and no other fields set). +\end_layout + +\begin_layout Description + \series medium float \begin_inset space ~ @@ -7185,6 +7353,26 @@ is tests whether the current cell is non-empty. \end_layout +\begin_layout Description + +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +justify +\series medium +(left|right|center) +\series default + evaluates to a style token with the justification set to the specified + direction, given as a bare word (and no other fields set). +\end_layout + \begin_layout Description left \series medium @@ -7693,6 +7881,37 @@ cn \begin_layout Description +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +precision +\series medium +(int +\emph on + +\begin_inset space ~ +\end_inset + +x +\emph default +) +\series default + evaluates to a style token in which the precision is set to +\emph on +x +\emph default + (and no other fields are set). +\end_layout + +\begin_layout Description + \series medium float \begin_inset space ~ @@ -7801,6 +8020,37 @@ scientific Used as a keyword argument to the string() function; listed here \begin_layout Description +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +shadowed +\series medium +([bool +\emph on + +\begin_inset space ~ +\end_inset + +b +\emph default +]) +\series default + evaluates to a style token with the shadowed property set to +\emph on +b +\emph default +, which defaults to true (and no other fields set). +\end_layout + +\begin_layout Description + \series medium float \begin_inset space ~ @@ -8345,6 +8595,37 @@ status open \begin_layout Description +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +transparent +\series medium +([bool +\emph on + +\begin_inset space ~ +\end_inset + +b +\emph default +]) +\series default + evaluates to a style token with the transparent property set to +\emph on +b +\emph default +, which defaults to true (and no other fields set). +\end_layout + +\begin_layout Description + \series medium boolean \begin_inset space ~ @@ -8390,6 +8671,37 @@ x ). \end_layout +\begin_layout Description + +\series medium +style +\emph on + +\begin_inset space ~ +\end_inset + + +\series default +\emph default +underline +\series medium +([bool +\emph on + +\begin_inset space ~ +\end_inset + +b +\emph default +]) +\series default + evaluates to a style token with the underline property set to +\emph on +b +\emph default +, which defaults to true (and no other fields set). +\end_layout + \begin_layout Description up \series medium @@ -8404,7 +8716,14 @@ l ])] displacement by one cell in the negative \series default \emph on -y +y +\emph default +direction; see the fuller description at +\family sans +\series bold +above +\series default +.) \end_layout \begin_layout Description diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 86f49c3..7759984 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -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) diff --git a/src/common/cell.c b/src/common/cell.c index cfeb7c9..b5a2acc 100644 --- a/src/common/cell.c +++ b/src/common/cell.c @@ -6,42 +6,21 @@ #endif #include -#include #include -#include -#include #include #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 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 chars) { - for (cur=0; cur < chars; ++cur) s[cur] = '#'; - s[cur] = 0; - } -} -/*}}}*/ diff --git a/src/common/cell.h b/src/common/cell.h index 997b21a..ed4aac5 100644 --- a/src/common/cell.h +++ b/src/common/cell.h @@ -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 diff --git a/src/common/context.c b/src/common/context.c index e577e62..fb4f2c1 100644 --- a/src/common/context.c +++ b/src/common/context.c @@ -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; multicolsdimx && 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 '$': diff --git a/src/common/eval.c b/src/common/eval.c index 448654c..1ba2ce8 100644 --- a/src/common/eval.c +++ b/src/common/eval.c @@ -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); diff --git a/src/common/func.c b/src/common/func.c index 52bd696..75900a5 100644 --- a/src/common/func.c +++ b/src/common/func.c @@ -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 }, diff --git a/src/common/func.h b/src/common/func.h index ee4128e..f494dca 100644 --- a/src/common/func.h +++ b/src/common/func.h @@ -1,6 +1,12 @@ #ifndef FUNC_H #define FUNC_H +#include + +#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 diff --git a/src/common/htmlio.c b/src/common/htmlio.c index 83167f8..cc310c5 100644 --- a/src/common/htmlio.c +++ b/src/common/htmlio.c @@ -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("",fp)==EOF) return strerror(errno); for (w[X]=beg[X]; w[X]<=end[X]; ) { - int multicols; - char *bufp; - - for (multicols=w[X]+1; multicolsdimx && SHADOWEDC(sheet,multicols,w[Y],w[Z]); ++multicols); - multicols = multicols - w[X]; - if (multicols>1) fprintf(fp,"dimx && shadowed(sheet, mw); ++(mw[X])); + int multicols = mw[X] - w[X]; + if (multicols > 1) fprintf(fp,"",fp)==EOF) return strerror(errno); break; case RIGHT: if (fputs_close(" align=right>",fp)==EOF) return strerror(errno); break; case CENTER: if (fputs_close(" align=center>",fp)==EOF) return strerror(errno); break; default: assert(0); } - printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell), - getprecision(cell), sheet, w); - if (transparent(cell)) + printvalue(buf, sizeof(buf), 0, DIRECT_STRING, cs.fform, cs.precision, + sheet, w); + if (cs.transparent) { - if (fputs_close(buf,fp)==EOF) return strerror(errno); + if (fputs_close(buf,fp) == EOF) return strerror(errno); } - else for (bufp=buf; *bufp; ++bufp) switch (*bufp) + else for (char *bufp = buf; *bufp; ++bufp) switch (*bufp) { case '<': if (fputs_close("<",fp)==EOF) return strerror(errno); break; case '>': if (fputs_close(">",fp)==EOF) return strerror(errno); break; @@ -110,14 +108,14 @@ const char *savehtml(Sheet *sheet, const char *name, int body, if (fputs_close("\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("\n\n",fp)==EOF) return strerror(errno); - if (fclose(fp)==EOF) return strerror(errno); + if (fputs_close("\n\n",fp) == EOF) return strerror(errno); + if (fclose(fp) == EOF) return strerror(errno); } - return (const char*)0; + return NULL; } /*}}}*/ diff --git a/src/common/latex.c b/src/common/latex.c index 2d79ded..10d7c15 100644 --- a/src/common/latex.c +++ b/src/common/latex.c @@ -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; multicolsdimx && 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 '$': diff --git a/src/common/main.c b/src/common/main.c index abeb242..e374b2d 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -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; diff --git a/src/common/main.h b/src/common/main.h index 84d9cb5..c2e2f06 100644 --- a/src/common/main.h +++ b/src/common/main.h @@ -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); diff --git a/src/common/parser.c b/src/common/parser.c index 1fc738d..9cb7a51 100644 --- a/src/common/parser.c +++ b/src/common/parser.c @@ -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); } diff --git a/src/common/sc.c b/src/common/sc.c index 85f01d8..1dbc44b 100644 --- a/src/common/sc.c +++ b/src/common/sc.c @@ -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; xdimx; ++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; ydimy; ++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; diff --git a/src/common/scanner.c b/src/common/scanner.c index 7a44d4c..92ef1e4 100644 --- a/src/common/scanner.c +++ b/src/common/scanner.c @@ -12,12 +12,10 @@ #include #include -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 - #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) { diff --git a/src/common/scanner.h b/src/common/scanner.h index e1783d9..d80a2de 100644 --- a/src/common/scanner.h +++ b/src/common/scanner.h @@ -2,181 +2,18 @@ #define SCANNER_H #include -#include #include -#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 } diff --git a/src/common/sheet.c b/src/common/sheet.c index bc8520d..5515b87 100644 --- a/src/common/sheet.c +++ b/src/common/sheet.c @@ -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; } diff --git a/src/common/sheet.h b/src/common/sheet.h index 6c63018..6063e02 100644 --- a/src/common/sheet.h +++ b/src/common/sheet.h @@ -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, diff --git a/src/common/style.c b/src/common/style.c new file mode 100644 index 0000000..34bf55b --- /dev/null +++ b/src/common/style.c @@ -0,0 +1,56 @@ +#include + +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; +} diff --git a/src/common/style.h b/src/common/style.h new file mode 100644 index 0000000..71860f6 --- /dev/null +++ b/src/common/style.h @@ -0,0 +1,57 @@ +#ifndef STYLE_H +#define STYLE_H + +#include + +#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 diff --git a/src/common/token.c b/src/common/token.c new file mode 100644 index 0000000..5cdad97 --- /dev/null +++ b/src/common/token.c @@ -0,0 +1,518 @@ +#include +#include +#include +#include +#include + +#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 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 chars) { + for (cur=0; cur < chars; ++cur) s[cur] = '#'; + s[cur] = 0; + } +} +/*}}}*/ diff --git a/src/common/token.h b/src/common/token.h new file mode 100644 index 0000000..01a4dca --- /dev/null +++ b/src/common/token.h @@ -0,0 +1,189 @@ +#ifndef TOKEN_H +#define TOKEN_H + +#include + +#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 diff --git a/src/common/wk1.c b/src/common/wk1.c index 7eca9e3..bf5b7c3 100644 --- a/src/common/wk1.c +++ b/src/common/wk1.c @@ -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; } /*}}}*/ diff --git a/src/common/xdr.c b/src/common/xdr.c index 3970a9e..450e4e5 100644 --- a/src/common/xdr.c +++ b/src/common/xdr.c @@ -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; } /*}}}*/ diff --git a/src/display.c b/src/display.c index deb28ec..3c29149 100644 --- a/src/display.c +++ b/src/display.c @@ -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); fillmaxx+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; diff --git a/src/display.h b/src/display.h index f750d6d..9cd8c85 100644 --- a/src/display.h +++ b/src/display.h @@ -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); diff --git a/src/fteapot.fl b/src/fteapot.fl index 5c0ff6a..e864213 100644 --- a/src/fteapot.fl +++ b/src/fteapot.fl @@ -8,6 +8,7 @@ decl {\#include } {public global} decl {\#include } {public global} decl {\#include "display.h"} {public global} +decl {\#include "utf8.h"} {public global} decl {\#include } {private global} decl {\#include } {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);