diff --git a/doc/teapot.lyx b/doc/teapot.lyx index cec4e05..141df62 100644 --- a/doc/teapot.lyx +++ b/doc/teapot.lyx @@ -1948,7 +1948,7 @@ status open \begin_layout Plain Layout \begin_inset Tabular - + @@ -2562,35 +2562,6 @@ Set column width \begin_inset Text -\begin_layout Plain Layout -{Meta-S} -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Set cell/block scientific notation -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - \begin_layout Plain Layout {Meta-E} \end_layout @@ -3359,9 +3330,43 @@ The precision for the output of floating point values. \end_layout \begin_layout Itemize -Whether floating point numbers should be printed in scientific notation - (0.123e1) or as decimal number (1.23). - It only affects the output, if the cell value is a floating point number. +The format for floating point numbers when they are printed. + This can be +\begin_inset Quotes eld +\end_inset + +decimal +\begin_inset Quotes erd +\end_inset + + (12.34), +\begin_inset Quotes eld +\end_inset + +scientific +\begin_inset Quotes erd +\end_inset + + (1.234e1), +\begin_inset Quotes eld +\end_inset + +compact +\begin_inset Quotes erd +\end_inset + + (a mix of these to produce a compact notation depending on thethe magnitude + of the value; this is the default), or +\begin_inset Quotes eld +\end_inset + +hexact +\begin_inset Quotes erd +\end_inset + + (a specialized hexadecimal format used for exact round trips to ASCII format, + rarely used for dispaly.) It only affects the output if the cell value is + a floating point number. \end_layout @@ -4034,7 +4039,25 @@ File Formats \end_layout \begin_layout Paragraph -XDR (.tp) +ASCII (.tpa) +\end_layout + +\begin_layout Standard +The ASCII file format allows easy generation/modification of saved sheets + by shell scripts. + Note that when reading a .tpa file, either ordinary decimal or scientific + formats for floating point number are recognized, as well as the exact + hex floating point format used by default when saving. + The default extension is +\family typewriter +. +\family default +tpa. + +\end_layout + +\begin_layout Paragraph +Legacy XDR (.tp) \end_layout \begin_layout Standard @@ -4043,28 +4066,31 @@ XDR (eXternal Data Representation) is a standard invented by Sun Microsystems media. Its advantage is that it is widely available and that it defines a portable floating point number format. - The native teapot file format uses XDR so it is portable across different - machine architectures and operating systems. - The advantage of this over the portable ASCII format is that due to the + The native teapot file format formerly used XDR so it is portable across + different machine architectures and operating systems. + The advantage of this over the portable ASCII format was that due to the (usually) missing conversion calculations any floating point constants will be saved/loaded exactly without conversion errors. -\end_layout + It was discontinued because the ASCII format was made exact by virtue of + the exact hexadecimal +\begin_inset Quotes eld +\end_inset -\begin_layout Paragraph -ASCII (.tpa) -\end_layout +%a +\begin_inset Quotes erd +\end_inset -\begin_layout Standard -The ASCII file format allows easy generation/modification of saved sheets - by shell scripts. - Due to binary/ASCII conversion, there may be conversion errors in floating - point constants. - The default extension is -\family typewriter -. -\family default -tpa. - + style ( +\begin_inset Quotes eld +\end_inset + +hexact +\begin_inset Quotes erd +\end_inset + +) of representing floating point values, and so there was no need for a + specialized binary format. + Old .tp files may be read, but teapot no longer writes files in this format. \end_layout \begin_layout Paragraph @@ -6254,6 +6280,11 @@ condition expression to avoid recalculation becoming stuck in an infinite loop, however. \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. +\end_layout + \begin_layout Description \series medium @@ -6344,7 +6375,7 @@ deg2rad x \emph default -) +) \series default evaluates to the degrees that are equivalent to \emph on @@ -6495,6 +6526,11 @@ x \end_layout +\begin_layout Description +hexact used as a keyword to the string() function; listed here to record + that this identifier may not be used as a cell label. +\end_layout + \begin_layout Description \series medium @@ -7458,20 +7494,24 @@ precision \begin_inset space ~ \end_inset -integer + \emph on - -\begin_inset space ~ -\end_inset - -scientific +format \emph default ]]) \series default evaluates to the string representation of its first argument. The optional second argument gives the precision used for converting floating point numbers to string form. - The optional third argument may either be the keyword + The optional third argument may be one of the keywords +\begin_inset Quotes eld +\end_inset + +decimal +\begin_inset Quotes erd +\end_inset + +, \begin_inset Quotes eld \end_inset @@ -7479,16 +7519,24 @@ scientific \begin_inset Quotes erd \end_inset - or +, \begin_inset Quotes eld \end_inset -decimal, +compact \begin_inset Quotes erd \end_inset - controlling the type of notation used for converting floating point numbers - to string form. +, or +\begin_inset Quotes eld +\end_inset + +hexact +\begin_inset Quotes erd +\end_inset + +, controlling the format for converting floating point numbers to string + form. If the optional arguments are not specified, current defaults are used. \end_layout diff --git a/src/common/cell.c b/src/common/cell.c index a435624..a0b18a3 100644 --- a/src/common/cell.c +++ b/src/common/cell.c @@ -1,11 +1,36 @@ -#include "cell.h" +#ifndef NO_POSIX_SOURCE +#undef _POSIX_SOURCE +#define _POSIX_SOURCE 1 +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 2 +#endif #include +#include +#include +#include +#include #include +#include "cell.h" #include "default.h" #include "eval.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" @@ -27,12 +52,12 @@ void initcellcontents(Cell *fresh) 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->scientific = DEF_SCIENTIFIC; fresh->locked = 0; fresh->transparent = 0; fresh->ignored = 0; @@ -108,10 +133,10 @@ bool ignored(const Cell *cell) } -/* getscientific -- should value be displayed in scientific notation? */ -bool getscientific(const Cell *cell ) +/* getfltformat -- float format for numbers */ +FloatFormat getfltformat(const Cell *cell ) { - return (cell == NULLCELL) ? DEF_SCIENTIFIC : cell->scientific; + return (cell == NULLCELL) ? DEF_FLOATFORM : cell->fform; } /* getprecision -- get cell precision */ @@ -189,3 +214,246 @@ 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 printtok(char* dest, size_t size, size_t field_width, + StringFormat sf, FloatFormat ff, + int digits, ErrorFormat ef, const Token *tok) +{ + 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: + { + cur += print_fident(dest+cur, size-cur-1, tok->u.funcall.fident); + if (tok->u.funcall.argc >= 0 && cur + 2 < size) /* -1 args is bare func */ + { + dest[cur++] = '\('; + for (size_t ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai) + { + if (ai > 0 && cur < size) dest[cur++] = ','; + cur += printtok(dest+cur, size-cur-1, field_width-cur, sf, ff, + digits, ef, tok->u.funcall.argv + ai); + } + if (cur < size) dest[cur++] = ')'; + } + 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; +} +/*}}}*/ + +/* 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 4fec95a..c54e5b6 100644 --- a/src/common/cell.h +++ b/src/common/cell.h @@ -7,8 +7,6 @@ extern "C" { #endif -typedef enum { LEFT=0, RIGHT=1, CENTER=2, AUTOADJUST=3 } Adjust; - typedef enum { BASE_CONT=0, ITER_CONT, ATTR_REF, MAX_PERSIST_TV = ATTR_REF, CURR_VAL, RES_VAL, @@ -16,6 +14,18 @@ typedef enum } 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; @@ -29,10 +39,10 @@ typedef struct char *label; int precision; Adjust adjust; + FloatFormat fform; ColorNum aspect[NUM_COLOR_ASPECTS]; unsigned int updated:1; unsigned int shadowed:1; - unsigned int scientific:1; unsigned int locked:1; unsigned int transparent:1; unsigned int ignored:1; @@ -56,13 +66,19 @@ ColorNum getcolor(const Cell *cell, ColorAspect aspect); bool locked(const Cell *cell); bool transparent(const Cell *cell); bool ignored(const Cell *cell); -bool getscientific(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); +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); +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 59561ee..e577e62 100644 --- a/src/common/context.c +++ b/src/common/context.c @@ -100,7 +100,7 @@ const char *savecontext(Sheet *sheet, const char *name, int body, case CENTER: if (fputs_close("\\JustCenter ",fp)==EOF) return strerror(errno); break; default: assert(0); } - printvalue(buf, sizeof(buf), 0, 0, getscientific(cell), + printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell), getprecision(cell), sheet, w); /* if (fputs_close("}{",fp)==EOF) return strerror(errno);*/ if (transparent(cell)) diff --git a/src/common/default.h b/src/common/default.h index 90777e0..cd5725a 100644 --- a/src/common/default.h +++ b/src/common/default.h @@ -7,10 +7,13 @@ #define DEF_COLUMNWIDTH 12 /* default precision of a printed value */ -#define DEF_PRECISION 2 +/* Since the default format now counts significant figures + rather than digits after the decimal, bumping this to 3 +*/ +#define DEF_PRECISION 3 -/* default is no scientific notation for numbers */ -#define DEF_SCIENTIFIC 0 +/* default is compact notation for floating point numbers */ +#define DEF_FLOATFORM FLT_COMPACT /* character attribute for cell and row numbers */ #define DEF_NUMBER A_BOLD diff --git a/src/common/eval.c b/src/common/eval.c index 2a65935..ffbfd21 100644 --- a/src/common/eval.c +++ b/src/common/eval.c @@ -246,14 +246,15 @@ Token tconcat(Token l, Token r) if (l.type == EEK) return tcopy(l); if (r.type == EEK) return tcopy(r); - len = printtok(buf, conc_buf_len, 0, 0, DEF_SCIENTIFIC, def_precision, 0, &l); + len = printtok(buf, conc_buf_len, 0, DIRECT_STRING, + DEF_FLOATFORM, def_precision, TRUNCATED_ERROR, &l); if (len > conc_buf_len - 2) { duperror(&result, buferr); return result; } - len += printtok(buf + len, conc_buf_len - len - 1, 0, 0, - DEF_SCIENTIFIC, def_precision, 0, &r); + len += printtok(buf + len, conc_buf_len - len - 1, 0, DIRECT_STRING, + DEF_FLOATFORM, def_precision, TRUNCATED_ERROR, &r); if (len > conc_buf_len - 2) { duperror(&result, buferr); diff --git a/src/common/func.c b/src/common/func.c index 8e7f304..9a135c4 100644 --- a/src/common/func.c +++ b/src/common/func.c @@ -617,9 +617,9 @@ static Token string_func(int argc, const Token argv[]) { /* variables */ /*{{{*/ Token result; - const char *usage = _("Usage: string(x[,[int prec][,decimal|scientific]])"); + const char *usage = _("Usage: string(x[,[int prec][,format_for_floats]])"); int precision = def_precision; - bool use_sci = DEF_SCIENTIFIC; + bool ff = DEF_FLOATFORM; char staticbuf[4096]; size_t size; /*}}}*/ @@ -630,8 +630,10 @@ static Token string_func(int argc, const Token argv[]) if (argv[2].type != FIDENT) return duperror(&result, usage); switch (argv[2].u.fident) { - case FUNC_DECIMAL: use_sci = false; break; - case FUNC_SCIENTIFIC: use_sci = true; break; + case FUNC_DECIMAL: ff = FLT_DECIMAL; break; + case FUNC_SCIENTIFIC: ff = FLT_SCIENTIFIC; break; + case FUNC_COMPACT: ff = FLT_COMPACT; break; + case FUNC_HEXACT: ff = FLT_HEXACT; break; default: assert(0); } } @@ -641,8 +643,8 @@ static Token string_func(int argc, const Token argv[]) precision = argv[1].u.integer; } result.type = STRING; - size = printtok(staticbuf, sizeof(staticbuf), 0, false, use_sci, precision, - true, argv); + size = printtok(staticbuf, sizeof(staticbuf), 0, DIRECT_STRING, ff, + precision, VERBOSE_ERROR, argv); if (size > sizeof(staticbuf) - 2) return duperror(&result, _("string: Overflow of internal buffer")); result.u.string = strdup(staticbuf); @@ -1417,6 +1419,20 @@ static Token decimal_func(int argc, const Token argv[]) } /*}}}*/ +/* compact keyword */ /*{{{*/ +static Token compact_func(int argc, const Token argv[]) +{ + return self_func(argc, argv, FUNC_COMPACT); +} +/*}}}*/ + +/* hexact keyword */ /*{{{*/ +static Token hexact_func(int argc, const Token argv[]) +{ + return self_func(argc, argv, FUNC_HEXACT); +} +/*}}}*/ + /* scientific keyword */ /*{{{*/ static Token scientific_func(int argc, const Token argv[]) { @@ -1659,7 +1675,10 @@ Tfunc tfunc[]= /* Miscellaneous other functions/keywords */ [FUNC_DOLLAR_SIGN] = { "$", env_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_COMPACT] = { "compact", compact_func, PREFIX_FUNC, FUNCT, 0 }, [FUNC_DECIMAL] = { "decimal", decimal_func, PREFIX_FUNC, FUNCT, 0 }, + [FUNC_HEXACT] = { "hexact", hexact_func, PREFIX_FUNC, FUNCT, 0 }, [FUNC_SCIENTIFIC] = { "scientific", scientific_func, PREFIX_FUNC, FUNCT, 0 }, + }; /*}}}*/ diff --git a/src/common/func.h b/src/common/func.h index 95ff17f..a34958c 100644 --- a/src/common/func.h +++ b/src/common/func.h @@ -25,7 +25,8 @@ typedef enum FUNC_LESS_EQUAL, FUNC_GREATER_EQUAL, FUNC_LESS_THAN, FUNC_GREATER_THAN, FUNC_EQUAL_EQUAL, FUNC_TILDE_EQUAL, FUNC_BANG_EQUAL, FUNC_CARET, FUNC_PER_CENT, FUNC_CONCAT, FUNC_TAU, FUNC_SQRT, FUNC_FLOOR, FUNC_CEIL, - FUNC_TRUNC, FUNC_ROUND, FUNC_DECIMAL, FUNC_SCIENTIFIC, + FUNC_TRUNC, FUNC_ROUND, FUNC_DECIMAL, FUNC_SCIENTIFIC, FUNC_COMPACT, + FUNC_HEXACT, N_FUNCTION_IDS } FunctionIdentifier; diff --git a/src/common/htmlio.c b/src/common/htmlio.c index c8bee89..83167f8 100644 --- a/src/common/htmlio.c +++ b/src/common/htmlio.c @@ -86,7 +86,7 @@ const char *savehtml(Sheet *sheet, const char *name, int body, case CENTER: if (fputs_close(" align=center>",fp)==EOF) return strerror(errno); break; default: assert(0); } - printvalue(buf, sizeof(buf), 0, 0, getscientific(cell), + printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell), getprecision(cell), sheet, w); if (transparent(cell)) { diff --git a/src/common/latex.c b/src/common/latex.c index e9ce2ed..2d79ded 100644 --- a/src/common/latex.c +++ b/src/common/latex.c @@ -100,7 +100,7 @@ const char *savelatex(Sheet *sheet, const char *name, int body, case CENTER: if (fputc_close('c',fp)==EOF) return strerror(errno); break; default: assert(0); } - printvalue(buf, sizeof(buf), 0, 0, getscientific(cell), + printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell), getprecision(cell), sheet, w); if (fputs_close("}{",fp)==EOF) return strerror(errno); if (transparent(cell)) diff --git a/src/common/main.c b/src/common/main.c index 2e8aeb6..4d92afc 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -51,11 +51,11 @@ char helpfile[PATH_MAX]; bool batch = false; unsigned int batchln=0; int def_precision = DEF_PRECISION; -bool quote = false; +StringFormat quote = DIRECT_STRING; bool header = true; bool always_redraw = false; int debug_level = 0; -static bool usexdr = true; +static bool usexdr = false; /*}}}*/ void moveto(Sheet *sheet, int x, int y, int z) @@ -197,23 +197,26 @@ static int do_edit(Sheet *cursheet, Key c, const char *expr, TokVariety tv) { Token cntt; offx=0; - if (c==K_NONE) + if (c == K_NONE) { cntt = gettok(cell, tv); - printtok(buf, sizeof(buf), 0, 1, getscientific(cell), -1, 0, &cntt); + printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, 0, + TRUNCATED_ERROR, &cntt); s = buf+strlen(buf); } - else if (c==K_BACKSPACE) + else if (c == K_BACKSPACE) { cntt = gettok(cell, tv); - printtok(buf, sizeof(buf), 0, 1, getscientific(cell), -1, 0, &cntt); + printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, 0, + TRUNCATED_ERROR, &cntt); if (strlen(buf)) *mbspos(buf+strlen(buf),-1)='\0'; s = buf+strlen(buf); } - else if (c==K_DC) + else if (c == K_DC) { cntt = gettok(cell, tv); - printtok(buf, sizeof(buf), 0, 1, getscientific(cell), -1, 0, &cntt); + printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, 0, + TRUNCATED_ERROR, &cntt); memmove(buf,mbspos(buf,1),strlen(mbspos(buf,1))+1); s = buf; } @@ -344,18 +347,13 @@ static int do_columnwidth(Sheet *cursheet) /* do_attribute -- set cell attributes */ /*{{{*/ static void do_attribute(Sheet *cursheet, Key action) { - /* variables */ /*{{{*/ Location w; - Adjust adj; - bool onecell; - Cell *fcell; - int c = 0; - /*}}}*/ - - adj = LEFT; + Adjust adj = LEFT; + FloatFormat ff = FLT_DECIMAL; do_mark(cursheet, GET_MARK_CUR); - onecell = SAME_LOC(cursheet->mark1, cursheet->mark2); - fcell = safe_cell_at(cursheet, cursheet->mark1); + bool onecell = SAME_LOC(cursheet->mark1, cursheet->mark2); + Cell *fcell = safe_cell_at(cursheet, cursheet->mark1); + bool changed = false; if (action != ADJUST_LOCK && onecell && locked(fcell)) { line_msg(_("Cell attribute:"),_("Cell is locked")); @@ -364,32 +362,29 @@ static void do_attribute(Sheet *cursheet, Key action) switch ((int)action) { case ADJUST_CENTER: ++adj; /* drop through */ - case ADJUST_RIGHT: ++adj; + case ADJUST_RIGHT: ++adj; /* drop through */ case ADJUST_LEFT: { - const char *templ = _("Change adjustment of block to "); - char *prompt = malloc(strlen(templ) + 64); - const char *way = _("center?"); - if (action == ADJUST_RIGHT) way = _("right?"); - else if (action == ADJUST_LEFT) way = _("left?"); - strcpy(prompt, templ); strcat(prompt, way); + const char *templ = _("Change adjustment of block to %s?"); + char *prompt = malloc(strlen(templ) + MAX_ADJUST_NAME_LENGTH + 1); + sprintf(prompt, templ, Adjust_Name[adj]); if (!onecell && line_ok(prompt, 0) <= 0) break; for (ALL_LOCS_IN_REGION(cursheet,w)) - setadjust(cursheet, w, adj); + changed = setadjust(cursheet, w, adj) || changed; break; } - /* 3 -- set scientific notation flag */ /*{{{*/ - case ADJUST_SCIENTIFIC: + /* set float format */ /*{{{*/ + case ADJUST_HEXACT: ++ff; /* drop through */ + case ADJUST_COMPACT: ++ff; /* drop through */ + case ADJUST_SCIENTIFIC: ++ff; /* drop through */ + case ADJUST_DECIMAL: { - int n; - - if (onecell) n = !getscientific(fcell); - else n = line_binary(_("Make block notation:"), - _("dD)ecimal"), _("sS)cientific"), - !getscientific(fcell)); - if (n >= 0) - for (ALL_LOCS_IN_REGION(cursheet,w)) - setscientific(cursheet, w, n); + const char* templ = _("Change float format of block to %s?"); + char *prompt = malloc(strlen(templ) + MAX_FLOATFORM_NAME_LENGTH +1); + sprintf(prompt, templ, FloatFormat_Name[ff]); + if (!onecell && line_ok(prompt, 0) <= 0) break; + for (ALL_LOCS_IN_REGION(cursheet,w)) + changed = setfltformat(cursheet, w, ff) || changed; break; } /*}}}*/ @@ -403,7 +398,8 @@ static void do_attribute(Sheet *cursheet, Key action) ex=0; n = getprecision(fcell); do if (line_numedit(&n, onecell ? _("Precision for cell:") : _("Precision for block:"),&ex,&offx)==-1) return; while (n!=-1 && (n==0 || n>20)); - for (ALL_LOCS_IN_REGION(cursheet,w)) setprecision(cursheet, w, n); + for (ALL_LOCS_IN_REGION(cursheet,w)) + changed = setprecision(cursheet, w, n) || changed; break; } /*}}}*/ @@ -427,14 +423,14 @@ static void do_attribute(Sheet *cursheet, Key action) { Location r; - if (n==0) + if (n == 0) { LOCATION_GETS(r, w); if (!SHADOWED(cursheet, r)) ++(r[X]); for (; SHADOWED(cursheet, r); ++(r[X])) - shadow(cursheet, r, 0); + changed = shadow(cursheet, r, false) || changed; } - else if (w[X]>0) shadow(cursheet, w, 1); + else if (w[X]>0) changed = shadow(cursheet, w, true) || changed; } } if (n>0) do_mark(cursheet, UNMARKED); @@ -451,7 +447,8 @@ static void do_attribute(Sheet *cursheet, Key action) _("pP)rotected"), _("tT)ransparent:"), !transparent(fcell)); if (n >= 0) - for (ALL_LOCS_IN_REGION(cursheet,w)) maketrans(cursheet, w, n); + for (ALL_LOCS_IN_REGION(cursheet,w)) + changed = maketrans(cursheet, w, n) || changed; break; } /*}}}*/ @@ -464,7 +461,8 @@ static void do_attribute(Sheet *cursheet, Key action) else n = line_binary(_("Set block weight to:"), _("rR)egular"), _("bB)old"), !isbold(fcell)); if (n >= 0) - for (ALL_LOCS_IN_REGION(cursheet,w)) bold(cursheet, w, n); + for (ALL_LOCS_IN_REGION(cursheet,w)) + changed = bold(cursheet, w, n) || changed; break; } /*}}}*/ @@ -477,7 +475,8 @@ static void do_attribute(Sheet *cursheet, Key action) else n = line_binary(_("Set block to:"), _("nN)ot underline"), _("uU)nderline"), !underlined(fcell)); if (n >= 0) - for (ALL_LOCS_IN_REGION(cursheet,w)) underline(cursheet, w, n); + for (ALL_LOCS_IN_REGION(cursheet,w)) + changed = underline(cursheet, w, n) || changed; break; } /*}}}*/ @@ -497,7 +496,8 @@ static void do_attribute(Sheet *cursheet, Key action) else n = line_binary(_("Set block to:"), _("uU)nlocked"), _("lL)ocked"), !locked(fcell)); if (n >= 0) - for (ALL_LOCS_IN_REGION(cursheet,w)) lockcell(cursheet, w, n); + for (ALL_LOCS_IN_REGION(cursheet,w)) + changed = lockcell(cursheet, w, n) || changed; break; } /*}}}*/ @@ -510,7 +510,8 @@ static void do_attribute(Sheet *cursheet, Key action) else n = line_binary(_("Set block to:"), _("cC)omputed"), _("iI)gnored"), !ignored(fcell)); if (n >= 0) - for (ALL_LOCS_IN_REGION(cursheet,w)) igncell(cursheet, w, n); + for (ALL_LOCS_IN_REGION(cursheet,w)) + changed = igncell(cursheet, w, n) || changed; break; } /*}}}*/ @@ -518,42 +519,14 @@ static void do_attribute(Sheet *cursheet, Key action) default: assert(0); /*}}}*/ } - if (c>=0) - { + if (changed) { if (onecell) redraw_cell(cursheet, cursheet->mark1); else redraw_sheet(cursheet); + forceupdate(cursheet); } - forceupdate(cursheet); - return; } /*}}}*/ -/* do_savexdr -- save sheet as XDR file */ /*{{{*/ -static int do_savexdr(Sheet *cursheet, const char *name) -{ - char buf[PATH_MAX]; - const char *msg; - unsigned int count; - - if (!name) { - name = cursheet->name; - - if (strcmp(name+strlen(name)-3,".tp")) { - snprintf(buf, sizeof(buf), "%s.tp", name); - name = buf; - } - } - - if ((msg = savexdr(cursheet, name, &count))) { - line_msg(_("Save sheet to XDR file:"), msg); - return -2; - } - - snprintf(buf, sizeof(buf), _("%u cells written"), count); - if (!batch) line_msg(_("Save sheet to XDR file:"),buf); - return -1; -} -/*}}}*/ /* do_saveport -- save sheet as portable ASCII file */ /*{{{*/ static int do_saveport(Sheet *cursheet, const char *name) { @@ -708,32 +681,24 @@ static int do_savetext(Sheet *cursheet, const char *name) /* do_savecsv -- save sheet as CSV file */ /*{{{*/ static int do_savecsv(Sheet *cursheet, const char *name) { - char buf[PATH_MAX]; - const char *msg; - int x1,y1,z1,x2,y2,z2; - unsigned int count; - int sep = 0; - const char seps[4] = ",;\t"; - do_mark(cursheet, GET_MARK_ALL); - if (!name) { - MenuChoice menu[4]; - name = cursheet->name; - - menu[0].str=strdup(_("cC)omma (,)")); menu[0].c='\0'; - menu[1].str=strdup(_("sS)emicolon (;)")); menu[1].c='\0'; - menu[2].str=strdup(_("tT)ab (\\t)")); menu[2].c='\0'; - menu[3].str=(char*)0; - sep=line_menu(_("Choose separator:"),menu,0); - if (sep < 0) return sep; - } + if (!name) name = cursheet->name; + const char *menu[] = + { _("cC)omma (,)"), _("sS)emicolon (;)"), _("tT)ab (\\t)"), NULL }; + const char seps[4] = ",;\t"; + int sep = line_menu(_("Choose separator:"), menu, 0); + if (sep < 0) return sep; + unsigned int count; + const char *msg; if ((msg = savecsv(cursheet, name, seps[sep], - cursheet->mark1, cursheet->mark2, &count))) { - line_msg(_("Save in CSV format to file:"),msg); + cursheet->mark1, cursheet->mark2, &count))) + { + line_msg(_("Save in CSV format to file:"), msg); return -2; } + char buf[1024]; snprintf(buf, sizeof(buf), _("%u cells written"), count); if (!batch) line_msg(_("Save in CSV format to file:"), buf); return -1; @@ -749,6 +714,7 @@ static int do_loadxdr(Sheet *cursheet) return -1; } /*}}}*/ + /* do_loadport -- load sheet from portable ASCII file */ /*{{{*/ static int do_loadport(Sheet *cursheet) { @@ -858,6 +824,7 @@ void do_mark(Sheet *cursheet, MarkState ms) /*}}}*/ static int do_name(Sheet *cursheet); + /* do_save -- save sheet */ /*{{{*/ static int do_save(Sheet *cursheet) { @@ -866,22 +833,22 @@ static int do_save(Sheet *cursheet) ext += strlen(ext)-1; - if (!strcmp(ext-3, ".tpa")) return do_saveport(cursheet, NULL); if (!strcmp(ext-3, ".tbl")) return do_savetbl(cursheet, NULL); if (!strcmp(ext-5, ".latex")) return do_savelatex(cursheet, NULL); if (!strcmp(ext-4, ".html")) return do_savehtml(cursheet, NULL); if (!strcmp(ext-3, ".csv")) return do_savecsv(cursheet, NULL); if (!strcmp(ext-3, ".txt")) return do_savetext(cursheet, NULL); if (!strcmp(ext-3, ".tex")) return do_savecontext(cursheet, NULL); - return do_savexdr(cursheet, NULL); + return do_saveport(cursheet, NULL); } /*}}}*/ + /* do_name -- (re)name sheet */ /*{{{*/ static int do_name(Sheet *cursheet) { const char *name; - name = line_file(cursheet->name, _("Teapot \t*.tp\nTeapot ASCII \t*.tpa\ntbl \t*.tbl\nLaTeX \t*.latex\nHTML \t*.html\nCSV \t*.csv\nFormatted ASCII \t*.txt\nConTeXt \t*.tex"), _("New file name:"), 1); + name = line_file(cursheet->name, _("Teapot ASCII \t*.tpa\ntbl \t*.tbl\nLaTeX \t*.latex\nHTML \t*.html\nCSV \t*.csv\nFormatted ASCII \t*.txt\nConTeXt \t*.tex"), _("New file name:"), 1); if (!name) return -1; if (cursheet->name!=(char*)0) free(cursheet->name); @@ -889,6 +856,7 @@ static int do_name(Sheet *cursheet) return do_save(cursheet); } /*}}}*/ + /* do_load -- load sheet */ /*{{{*/ static int do_load(Sheet *cursheet) { @@ -896,17 +864,23 @@ static int do_load(Sheet *cursheet) if (doanyway(cursheet, _("Sheet modified, load new file anyway?")) != 1) return -1; - name = line_file(cursheet->name, _("Teapot \t*.tp\nTeapot ASCII \t*.tpa\nSC Spreadsheet Calculator \t*.sc\nLotus 1-2-3 \t*.wk1\nCSV \t*.csv"), _("Load sheet:"), 0); + name = line_file(cursheet->name, + _("Teapot ASCII \t*.tpa\n" + "CSV \t*.csv\n" + "Legacy binary Teapot \t*.tp\n" + "SC Spreadsheet Calculator \t*.sc\n" + "Lotus 1-2-3 \t*.wk1\n" + ), _("Load sheet:"), 0); if (!name) return -1; if (cursheet->name!=(char*)0) free(cursheet->name); cursheet->name=strdup(name); ext = name+strlen(name)-1; - if (!strcmp(ext-3, ".tpa")) return do_loadport(cursheet); + if (!strcmp(ext-2, ".tp")) return do_loadxdr(cursheet); if (!strcmp(ext-2, ".sc")) return do_loadsc(cursheet); if (!strcmp(ext-3, ".wk1")) return do_loadwk1(cursheet); if (!strcmp(ext-3, ".csv")) return do_loadcsv(cursheet); - return do_loadxdr(cursheet); + return do_loadport(cursheet); } /*}}}*/ @@ -942,47 +916,35 @@ static int do_clear(Sheet *sheet) /* do_insert -- insert block */ /*{{{*/ static int do_insert(Sheet *sheet) { - /* variables */ /*{{{*/ int reply; - bool onecell; - Location beg, end; - /*}}}*/ - /* ask for direction of insertion */ /*{{{*/ { - MenuChoice menu[4]; - - menu[0].str = _("cC)olumn"); menu[0].c='\0'; - menu[1].str = _("rR)ow"); menu[1].c='\0'; - menu[2].str = _("dD)epth"); menu[2].c='\0'; - menu[3].str=(char*)0; - reply=line_menu(_("Insert:"),menu,0); + const char* menu[] = + { _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL }; + reply = line_menu(_("Insert:"), menu, 0); if (reply<0) return reply; } /*}}}*/ do_mark(sheet, GET_MARK_CUR); + Location beg, end; LOCATION_GETS(beg, sheet->mark1); LOCATION_GETS(end, sheet->mark2); - onecell = SAME_LOC(beg, end); + bool onecell = SAME_LOC(beg, end); if (onecell) /* ask if current cell or whole dimension should be used */ /*{{{*/ { - /* variables */ /*{{{*/ - MenuChoice menu[3]; - int r; - /*}}}*/ - + const char *menu[3]; /* show menu */ /*{{{*/ switch (reply) { - case 0: menu[0].str = _("wW)hole column"); break; - case 1: menu[0].str = _("wW)hole line"); break; - case 2: menu[0].str = _("wW)hole sheet"); break; + case 0: menu[0] = _("wW)hole column"); break; + case 1: menu[0] = _("wW)hole line"); break; + case 2: menu[0] = _("wW)hole sheet"); break; default: assert(0); } - menu[1].str = _("sS)ingle cell"); menu[1].c='\0'; - menu[2].str = (char*)0; - r=line_menu(_("Insert:"),menu,0); + menu[1] = _("sS)ingle cell"); + menu[2] = NULL; + int r = line_menu(_("Insert:"), menu, 0); /*}}}*/ switch (r) { @@ -1053,49 +1015,39 @@ static int do_insert(Sheet *sheet) /* do_delete -- delete block */ /*{{{*/ static int do_delete(Sheet *sheet) { - /* variables */ /*{{{*/ int reply; - bool onecell; - Location beg, end; - /*}}}*/ firstmenu: /* ask for direction of deletion */ /*{{{*/ { - MenuChoice menu[4]; - - menu[0].str = _("cC)olumn"); menu[0].c='\0'; - menu[1].str = _("rR)ow"); menu[1].c='\0'; - menu[2].str = _("dD)epth"); menu[2].c='\0'; - menu[3].str = (char*)0; - reply=line_menu(_("Delete:"),menu,0); - if (reply<0) return reply; + const char* menu[] = + { _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL }; + reply = line_menu(_("Delete:"), menu, 0); + if (reply < 0) return reply; } /*}}}*/ do_mark(sheet, GET_MARK_CUR); + Location beg, end; LOCATION_GETS(beg, sheet->mark1); LOCATION_GETS(end, sheet->mark2); - onecell = SAME_LOC(beg, end); + bool onecell = SAME_LOC(beg, end); if (onecell) /* ask if range is the current cell or whole dimension should be used */ /*{{{*/ { - /* variables */ /*{{{*/ - MenuChoice menu[3]; - int r; - /*}}}*/ + const char *menu[3]; /* show menu */ /*{{{*/ switch (reply) { - case 0: menu[0].str = _("wW)hole column"); break; - case 1: menu[0].str = _("wW)hole line"); break; - case 2: menu[0].str = _("wW)hole sheet"); break; + case 0: menu[0] = _("wW)hole column"); break; + case 1: menu[0] = _("wW)hole line"); break; + case 2: menu[0] = _("wW)hole sheet"); break; default: assert(0); } - menu[1].str = _("sS)ingle cell"); menu[1].c='\0'; - menu[2].str=(char*)0; - r=line_menu(_("Delete:"),menu,0); + menu[1] = _("sS)ingle cell"); + menu[2] = NULL; + int r = line_menu(_("Delete:"), menu, 0); /*}}}*/ switch (r) { @@ -1164,6 +1116,7 @@ static int do_delete(Sheet *sheet) return -1; } /*}}}*/ + /* do_move -- copy or move a block */ /*{{{*/ static int do_move(Sheet *sheet, int copy, int force) { @@ -1250,7 +1203,6 @@ void fillwith(Sheet *she) static int do_sort(Sheet *sheet) { /* variables */ /*{{{*/ - MenuChoice menu1[4],menu2[3],menu3[3]; Sortkey sk[MAX_SORTKEYS]; unsigned int key; size_t x,offx; @@ -1263,22 +1215,18 @@ static int do_sort(Sheet *sheet) /*}}}*/ do_mark(sheet, GET_MARK_ALL); - /* build menues */ /*{{{*/ - menu1[0].str=strdup(_("cC)olumn")); menu1[0].c='\0'; - menu1[1].str=strdup(_("rR)ow")); menu1[1].c='\0'; - menu1[2].str=strdup(_("dD)epth")); menu1[2].c='\0'; - menu1[3].str=(char*)0; - menu2[0].str=strdup(_("sS)ort region")); menu2[0].c='\0'; - menu2[1].str=strdup(_("aA)dd key")); menu2[1].c='\0'; - menu2[2].str=(char*)0; - menu3[0].str=strdup(_("aA)scending")); menu3[0].c='\0'; - menu3[1].str=strdup(_("dD)escending")); menu3[0].c='\0'; - menu3[2].str=(char*)0; + /* build menus */ /*{{{*/ + const char* menu1[] = + { _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL }; + const char* menu2[] = + { _("sS)ort region"), _("aA)dd key"), NULL }; + const char* menu3[] = + { _("aA)scending"), _("dD)escending"), NULL }; /*}}}*/ - last=-1; + last = -1; /* ask for sort direction */ /*{{{*/ - zero: switch (c=line_menu(_("Sort block:"),menu1,0)) + zero: switch (c = line_menu(_("Sort block:"), menu1, 0)) { /* 0 -- in X */ /*{{{*/ case 0: in_dir=IN_X; break; @@ -1371,7 +1319,7 @@ static int do_sort(Sheet *sheet) /*}}}*/ /* ask for sort key */ /*{{{*/ four: sk[key].sortkey=0; - switch (c=line_menu(_("Sort block:"),menu3,0)) + switch (c = line_menu(_("Sort block:"), menu3, 0)) { /* 0 -- ascending */ /*{{{*/ case 0: sk[key].sortkey|=ASCENDING; break; @@ -1409,7 +1357,7 @@ static int do_sort(Sheet *sheet) } /*}}}*/ else /* ask for sort or adding another key */ /*{{{*/ - switch (line_menu(_("Sort block:"),menu2,0)) + switch (line_menu(_("Sort block:"), menu2, 0)) { /* 0 -- sort it */ /*{{{*/ case 0: doit=1; break; @@ -1431,17 +1379,6 @@ static int do_sort(Sheet *sheet) c=-1; if ((msg=sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key))!=(const char*)0) line_msg(_("Sort block:"),msg); greak: - /* free menues */ /*{{{*/ - free((char*)menu1[0].str); - free((char*)menu1[1].str); - free((char*)menu1[2].str); - free((char*)menu2[0].str); - free((char*)menu2[1].str); - free((char*)menu2[2].str); - free((char*)menu3[0].str); - free((char*)menu3[1].str); - free((char*)menu3[2].str); - /*}}}*/ return c; } /*}}}*/ @@ -1482,14 +1419,10 @@ static int do_mirror(Sheet *sheet) do_mark(sheet, GET_MARK_ALL); /* ask for direction of mirroring */ /*{{{*/ { - MenuChoice menu[4]; - - menu[0].str = _("lL)eft-right"); menu[0].c='\0'; - menu[1].str = _("uU)pside-down"); menu[1].c='\0'; - menu[2].str = _("fF)ront-back"); menu[2].c='\0'; - menu[3].str = (char*)0; - reply=line_menu(_("Mirror block:"),menu,0); - if (reply<0) return reply; + const char *menu[] = + { _("lL)eft-right"), _("uU)pside-down"), _("fF)ront-back"), NULL}; + reply = line_menu(_("Mirror block:"), menu, 0); + if (reply < 0) return reply; } /*}}}*/ switch (reply) @@ -1563,7 +1496,10 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly) case ADJUST_LEFT: case ADJUST_RIGHT: case ADJUST_CENTER: + case ADJUST_DECIMAL: case ADJUST_SCIENTIFIC: + case ADJUST_COMPACT: + case ADJUST_HEXACT: case ADJUST_PRECISION: case ADJUST_SHADOW: case ADJUST_BOLD: @@ -1837,15 +1773,8 @@ int main(int argc, char *argv[]) find_helpfile(helpfile, sizeof(helpfile), argv[0]); /* parse options */ /*{{{*/ - while ((o=getopt(argc,argv,"abdhnrqHp:?"))!=EOF) switch (o) + while ((o=getopt(argc,argv,"bdhnrqHp:?"))!=EOF) switch (o) { - /* a -- use ascii as default */ /*{{{*/ - case 'a': - { - usexdr = false; - break; - } - /*}}}*/ /* b -- run batch */ /*{{{*/ case 'b': batch = true; break; /*}}}*/ @@ -1853,10 +1782,10 @@ int main(int argc, char *argv[]) case 'd': ++debug_level; break; /*}}}*/ /* n -- no quoted strings */ /*{{{*/ - case 'n': quote = false; break; + case 'n': quote = DIRECT_STRING; break; /*}}}*/ /* q -- force quoted strings */ /*{{{*/ - case 'q': quote = true; break; + case 'q': quote = QUOTE_STRING; break; /*}}}*/ /* H -- no row/column headers */ /*{{{*/ case 'H': header = false; break; @@ -1914,12 +1843,12 @@ int main(int argc, char *argv[]) cursheet->name=strdup(loadfile); if (usexdr) { - if ((msg=loadxdr(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from XDR file:"),msg); + if ((msg=loadxdr(cursheet, cursheet->name)) != NULL) + line_msg(_("Load sheet from XDR file:"), msg); } else - { - if ((msg=loadport(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from ASCII file:"),msg); - } + if ((msg=loadport(cursheet, cursheet->name)) != NULL) + line_msg(_("Load sheet from ASCII file:"),msg); } /*}}}*/ if (batch) /* process batch */ /*{{{*/ diff --git a/src/common/main.h b/src/common/main.h index 17da764..7915cd3 100644 --- a/src/common/main.h +++ b/src/common/main.h @@ -13,7 +13,7 @@ extern "C" { extern bool batch; extern int def_precision; -extern bool quote; +extern StringFormat quote; extern bool header; extern int debug_level; extern bool always_redraw; @@ -82,7 +82,10 @@ typedef enum { K_HELP = -55, K_DUMPCELL = -56, ADJUST_UNDERLINE = -57, - FILL_BLOCK = -58 + FILL_BLOCK = -58, + ADJUST_DECIMAL = -59, + ADJUST_COMPACT = -60, + ADJUST_HEXACT = -61 } Key; extern int do_sheetcmd(Sheet *cursheet, Key c, int moveonly); diff --git a/src/common/sc.c b/src/common/sc.c index 33f1eec..096845e 100644 --- a/src/common/sc.c +++ b/src/common/sc.c @@ -235,7 +235,7 @@ const char *loadsc(Sheet *sheet, const char *name) col=(colstr[0]-'A'); if (colstr[1]) col=col*26+(colstr[1]-'A'); OLOCATION(tmp); tmp[X] = col; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); cell->adjust = RIGHT; cell->precision = precision; setwidth(sheet, col, 0, colwidth); @@ -263,7 +263,7 @@ const char *loadsc(Sheet *sheet, const char *name) goto eek; } tmp[X] = x; tmp[Y] = y; tmp[Z] = 0; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); cell->adjust = strncmp(buf, "leftstring ", 11) ? RIGHT : LEFT; cell->tok[BASE_CONT] = eval_safe(contents, LITERAL); tvecfree(contents); @@ -313,7 +313,7 @@ const char *loadsc(Sheet *sheet, const char *name) goto eek; } tmp[X] = x; tmp[Y] = y; tmp[Z] = 0; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); cell->adjust = RIGHT; cell->tok[BASE_CONT] = eval_safe(contents, LITERAL); tvecfree(contents); diff --git a/src/common/scanner.c b/src/common/scanner.c index a9f6bd6..9401d2a 100644 --- a/src/common/scanner.c +++ b/src/common/scanner.c @@ -12,10 +12,6 @@ #include #include -#include -#include -#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 */ @@ -26,7 +22,6 @@ extern long double strtold(const char *nptr, char **endptr); /* SunOS 4 hack */ #include "func.h" #include "main.h" #include "misc.h" -#include "utf8.h" #include "scanner.h" /*}}}*/ @@ -262,197 +257,3 @@ Token **scan(const char **s) return na; } /*}}}*/ - -static int print_fident(char* dest, size_t space, int 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; -} - -/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/ -size_t printtok(char* dest, size_t size, size_t field_width, - bool quote_strings, bool use_scientific, - int precision, bool verbose_error, const Token *tok) -{ - if (debug_level > 2) { - printf("..Entering printtok; bufsize %d, field_width %d, qs %d, us %d, prec %d, verr %d\n", size, field_width, quote_strings, use_scientific, precision, verbose_error); - } - if (size > 0 ) *dest = '\0'; - if (tok == NULLTOKEN || tok->type == EMPTY) return 0; - size_t cur = 0; - switch (tok->type) - { - /* STRING */ /*{{{*/ - case STRING: - { - char *str = tok->u.string; - - if (quote_strings && curu.integer); - assert(buflen < sizeof(buf)); - (void)strncpy(dest+cur,buf,size-cur-1); - cur+=buflen; - break; - } - /*}}}*/ - /* FLOAT */ /*{{{*/ - case FLOAT: - { - /* variables */ /*{{{*/ - char buf[1024],*p; - size_t len; - /*}}}*/ - - bool use_sci = use_scientific - || (int)ABSFLT(LOG10FLT(tok->u.flt)) > FLT_T_DIG; - - len = sprintf(buf, use_sci ? FLT_T_SCI_FMT : FLT_T_STD_FMT, - precision == -1 ? FLT_T_DIG-2 : precision, - tok->u.flt); - assert(lenbuf && *p == '0' && *(p-1) != '.') { *p = '\0'; --p; --len; } - } - p = buf+len; - while (*--p == ' ') { *p = '\0'; --len; } - (void)strncpy(dest+cur,buf,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: - { - cur += print_fident(dest+cur, size-cur-1, tok->u.funcall.fident); - if (tok->u.funcall.argc >= 0 && cur + 2 < size) /* -1 args is bare func */ - { - dest[cur++] = '\('; - for (size_t ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai) - { - if (ai > 0 && cur < size) dest[cur++] = ','; - cur += printtok(dest+cur, size-cur-1, field_width-cur, quote_strings, - use_scientific, precision, verbose_error, - tok->u.funcall.argv + ai); - } - if (cur < size) dest[cur++] = ')'; - } - break; - } - /* EEK */ /*{{{*/ - case EEK: - { - size_t errlen; - - (void)strncpy(dest+cur,_("ERROR"),size-cur-1); - cur += strlen(_("ERROR")); - if (verbose_error) - { - (void)strncpy(dest+cur, ": ", size-cur-1); - cur += 2; - 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; -} -/*}}}*/ -/* print -- print token sequence */ /*{{{*/ -void print(char *s, size_t size, size_t chars, int quote, int scientific, int precision, 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/scanner.h b/src/common/scanner.h index f820d56..c72f0d4 100644 --- a/src/common/scanner.h +++ b/src/common/scanner.h @@ -66,6 +66,8 @@ typedef long double FltT; */ #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 @@ -98,6 +100,8 @@ typedef double FltT; */ #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 @@ -165,10 +169,6 @@ typedef struct Token_struc Token duperror(Token* tok, const char* erro); Token **scan(const char **s); void cleartoken(Token* tok); -size_t printtok(char *dest, size_t size, size_t field_width, - bool quote_strings, bool use_scientific, - int precision, bool verbose_error, const Token *tok); -void print(char *s, size_t size, size_t chars, int quote, int scientific, int precision, Token **n); #ifdef __cplusplus } diff --git a/src/common/sheet.c b/src/common/sheet.c index dfd5a3d..3ceb956 100644 --- a/src/common/sheet.c +++ b/src/common/sheet.c @@ -57,8 +57,8 @@ void copycelltosheet(const Cell *fromcell, Sheet *sheet2, if (fromcell != NULLCELL) /* copy first cell to second */ /*{{{*/ { - sheet2->changed = 1; - Cell *alsotocell = initcellofsheet(sheet2, to); + sheet2->changed = true; + Cell *alsotocell = initcellofsheet(sheet2, to, NULL); assert(tocell == NULLCELL || tocell == alsotocell); copycell(alsotocell, fromcell, lh); } @@ -100,18 +100,13 @@ static void dump_cell(Sheet *sheet, int x, int y, int z) } if (c->label == NULL) printf("\n No label.\n"); else printf("\n Label: %s.\n", c->label); - switch (c->adjust) { - case LEFT: printf("LEFT\n"); break; - case RIGHT: printf("RIGHT\n"); break; - case CENTER: printf("CENTER\n"); break; - case AUTOADJUST: printf("AUTO\n"); break; - } + 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->scientific) printf("scientific "); if (c->locked) printf("locked "); if (c->transparent) printf("transparent "); if (c->ignored) printf("ignored "); @@ -139,8 +134,8 @@ static void swapblock(Sheet *sheet1, int x1, int y1, int z1, Sheet *sheet2, int assert(sheet1!=(Sheet*)0); assert(sheet2!=(Sheet*)0); - resize(sheet1,x1+xdist-1,y1+ydist-1,z1+zdist-1); - resize(sheet2,x2+xdist-1,y2+ydist-1,z2+zdist-1); + resize(sheet1, x1+xdist-1, y1+ydist-1, z1+zdist-1, NULL); + resize(sheet2, x2+xdist-1, y2+ydist-1, z2+zdist-1, NULL); for (xoff=0; xoffchanged=1; - sheet2->changed=1; + sheet1->changed = true; + sheet2->changed = true; } /*}}}*/ @@ -257,7 +252,7 @@ void initialize_sheet(Sheet *sheet) { /*}}}*/ /* resize -- check if sheet needs to be resized in any dimension */ /*{{{*/ -void resize(Sheet *sheet, int x, int y, int z) +void resize(Sheet *sheet, int x, int y, int z, bool *qextended) { assert(x>=0); assert(y>=0); @@ -270,7 +265,8 @@ void resize(Sheet *sheet, int x, int y, int z) Sheet dummy; /*}}}*/ - sheet->changed=1; + sheet->changed = true; + if (qextended) *qextended = true; dummy.dimx = (x >= sheet->dimx ? x+1 : sheet->dimx); dummy.dimy = (y >= sheet->dimy ? y+1 : sheet->dimy); dummy.dimz = (z >= sheet->dimz ? z+1 : sheet->dimz); @@ -306,16 +302,17 @@ void resize(Sheet *sheet, int x, int y, int z) /*}}}*/ /* initcellofsheet -- initialise new cell, if it does not exist yet */ /*{{{*/ -Cell *initcellofsheet(Sheet *sheet, const Location at) +Cell *initcellofsheet(Sheet *sheet, const Location at, bool *qnew) { Cell *nc; assert(IN_OCTANT(at)); - resize(sheet, at[X], at[Y], at[Z]); + resize(sheet, at[X], at[Y], at[Z], qnew); nc = CELL_AT(sheet,at); if (nc == NULLCELL) { - sheet->changed = 1; + sheet->changed = true; + if (qnew) *qnew = true; nc = malloc(sizeof(Cell)); CELL_AT(sheet,at) = nc; initcellcontents(nc); @@ -492,15 +489,24 @@ int columnwidth(Sheet *sheet, int x, int z) else return DEF_COLUMNWIDTH; } /*}}}*/ + /* setwidth -- set width of column */ /*{{{*/ -void setwidth(Sheet *sheet, int x, int z, int width) +bool setwidth(Sheet *sheet, int x, int z, int width) { assert(sheet!=(Sheet*)0); - resize(sheet,x,1,z); - sheet->changed=1; - *(sheet->column+x*sheet->dimz+z)=width; + bool isbigger = false; + resize(sheet, x, 1, z, &isbigger); + if (isbigger) sheet->changed = true; + int *storage = sheet->column + x*sheet->dimz + z; + if (*storage != width) { + *storage = width; + sheet->changed = true; + return true; + } + return isbigger; } /*}}}*/ + /* cellwidth -- get width of a cell */ /*{{{*/ int cellwidth(Sheet *sheet, const Location at) { @@ -522,7 +528,7 @@ void puttok(Sheet *sheet, const Location at, Token t, TokVariety v) assert(sheet != (Sheet*)0); sheet->changed = 1; - cell = initcellofsheet(sheet, at); + cell = initcellofsheet(sheet, at, NULL); tfree(&(cell->tok[v])); cell->tok[v] = t; redraw_cell(sheet, at); @@ -672,77 +678,42 @@ char *geterror(Sheet *sheet, const Location at) /*}}}*/ /* printvalue -- get ASCII representation of value */ /*{{{*/ -void printvalue(char *s, size_t size, size_t chars, int quote, int scientific, int precision, Sheet *sheet, const Location at) +void 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, quote, scientific, precision, 0, &t); + printtok(s, size, chars, sf, ff, precision, TRUNCATED_ERROR, &t); tfree(&t); } /*}}}*/ -/* setadjust -- set cell adjustment */ /*{{{*/ -void setadjust(Sheet *sheet, const Location at, Adjust adjust) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet, at)->adjust = adjust; -} -/*}}}*/ +/* The cell field setters all have nearly identical code, so: */ -/* shadow -- shadow cell by left neighbour */ /*{{{*/ -void shadow(Sheet *sheet, const Location at, int yep) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet, at)->shadowed = yep; +#define DEFSETTER(funcname,argtype,field) bool\ + funcname(Sheet *sheet, const Location at, argtype arg)\ +{\ + assert(sheet != (Sheet*)0);\ + bool isnew = false;\ + Cell* thecell = initcellofsheet(sheet, at, &isnew);\ + if (isnew) sheet->changed = true;\ + if (thecell->field != arg) {\ + thecell->field = arg;\ + sheet->changed = true;\ + return true;\ + }\ + return isnew;\ } -/*}}}*/ -/* bold -- bold font */ /*{{{*/ -void bold(Sheet *sheet, const Location at, int yep) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet,at)->bold = yep; -} -/*}}}*/ - -/* underline -- underline */ /*{{{*/ -void underline(Sheet *sheet, const Location at, int yep) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet,at)->underline = yep; -} -/*}}}*/ - -/* lockcell -- lock cell */ /*{{{*/ -void lockcell(Sheet *sheet, const Location at, int yep) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet,at)->locked = yep; -} -/*}}}*/ - -/* maketrans -- make cell transparent */ /*{{{*/ -void maketrans(Sheet *sheet, const Location at, int yep) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet,at)->transparent = yep; -} -/*}}}*/ - -/* igncell -- ignore cell */ /*{{{*/ -void igncell(Sheet *sheet, const Location at, int yep) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet,at)->ignored = yep; -} -/*}}}*/ +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); /* clk -- clock cell */ /*{{{*/ void clk(Sheet *sheet, const Location at) @@ -758,24 +729,6 @@ void clk(Sheet *sheet, const Location at) } /*}}}*/ -/* setscientific -- cell value should be displayed in scientific notation */ /*{{{*/ -void setscientific(Sheet *sheet, const Location at, int yep) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet,at)->scientific = yep; -} -/*}}}*/ - -/* setprecision -- set cell precision */ /*{{{*/ -void setprecision(Sheet *sheet, const Location at, int precision) -{ - assert(sheet != (Sheet*)0); - sheet->changed = 1; - initcellofsheet(sheet,at)->precision = precision; -} -/*}}}*/ - /* getmarkstate -- find out where in the marking cycle the sheet is */ /*{{{*/ MarkState getmarkstate(Sheet *sheet) { if (sheet == (Sheet*)0) return MARK_CYCLE; @@ -789,7 +742,7 @@ void setlabel(Sheet *sheet, const Location at, const char *buf, int update) assert(sheet != (Sheet*)0); sheet->changed = 1; - cell = initcellofsheet(sheet, at); + cell = initcellofsheet(sheet, at, NULL); if (cell->label != (char*)0) free(cell->label); if (*buf == '\0') cell->label = (char*)0; else cell->label = strcpy(malloc(strlen(buf)+1), buf); @@ -947,7 +900,7 @@ const char *savetbl(Sheet *sheet, const char *name, int body, { char *bufp; - printvalue(buf, sizeof(buf), 0, 0, getscientific(cw), + printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cw), getprecision(cw), sheet, w); if (transparent(cw)) { @@ -1042,8 +995,8 @@ const char *savetext(Sheet *sheet, const char *name, char *buf; buf = malloc(size*UTF8SZ+1); - printvalue(buf, size*UTF8SZ+1, size, 0, getscientific(cw), - getprecision(cw), sheet, w); + printvalue(buf, size*UTF8SZ + 1, size, DIRECT_STRING, + getfltformat(cw), getprecision(cw), sheet, w); adjust(getadjust(cw), buf, size); if (fputs_close(buf,fp)==EOF) { @@ -1103,10 +1056,11 @@ const char *savecsv(Sheet *sheet, const char *name, char sep, Cell *cw = CELL_AT(sheet,w); if (cw != NULLCELL) { - static const int bufsz = 511*UTF8SZ + 1; + static const int bufchar = 511; + static const int bufsz = bufchar*UTF8SZ + 1; char *buf = malloc(bufsz); - printvalue(buf, bufsz, 255, 0, getscientific(cw), + printvalue(buf, bufsz, bufchar, DIRECT_STRING, getfltformat(cw), getprecision(cw), sheet, w); bool needquote = !transparent(cw) && (strlen(buf) != strcspn(buf, "\",\n\r")); @@ -1169,10 +1123,12 @@ const char *saveport(Sheet *sheet, const char *name, unsigned int *count) { fprintf(fp,"C%d %d %d ",x,y,z); if (cell->adjust != AUTOADJUST) - fprintf(fp,"A%c ","lrc"[cell->adjust]); - if (cell->label) fprintf(fp,"L%s ", cell->label); + 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]) @@ -1186,7 +1142,6 @@ const char *saveport(Sheet *sheet, const char *name, unsigned int *count) if (cell->shadowed) fprintf(fp,"S "); if (cell->bold) fprintf(fp,"B "); if (cell->underline) fprintf(fp,"U "); - if (cell->scientific != DEF_SCIENTIFIC) fprintf(fp,"E "); if (cell->locked) fprintf(fp, "K "); if (cell->transparent) fprintf(fp,"T "); if (cell->ignored) fprintf(fp, "I "); @@ -1195,19 +1150,23 @@ const char *saveport(Sheet *sheet, const char *name, unsigned int *count) for (TokVariety v = BASE_CONT; v <= lastv; ++v) { if (v == BASE_CONT && cell->tok[v].type == EMPTY) continue; - char buf[4096]; + static const size_t bl = 4096; + char buf[bl]; if (fputs_close(saveport_contentleader[v], fp) == EOF) return strerror(errno); - printtok(buf, sizeof(buf), 0, 1, cell->scientific, - cell->precision, 0, cell->tok + v); + size_t used = printtok(buf, bl, 0, QUOTE_STRING, FLT_HEXACT, + -1, RESTORE_ERROR, cell->tok + v); + if (used > bl - 3) return _("Internal buffer overrun in saveport"); if (fputs_close(buf, fp) == EOF) return strerror(errno); } if (fputc_close('\n', fp) == EOF) return strerror(errno); + ++(*count); } } } } if (fclose(fp) == EOF) return strerror(errno); + sheet->changed = false; return (const char*)0; } /*}}}*/ @@ -1285,16 +1244,35 @@ const char *loadport(Sheet *sheet, const char *name) case 'A': { ++ns; - switch (*ns) - { - case 'l': loaded.adjust=LEFT; ++ns; break; - case 'r': loaded.adjust=RIGHT; ++ns; break; - case 'c': loaded.adjust=CENTER; ++ns; break; - default: sprintf(errbuf,_("Parse error for adjustment in line %d"),line); err=errbuf; goto eek; - } - break; + const char *found = strchr(Adjust_Char, *ns); + if (found != NULL) + { + loaded.adjust = (Adjust)(found - Adjust_Char); + ++ns; + break; + } + sprintf(errbuf, _("Parse error for adjustment in line %d"), line); + err = errbuf; + goto eek; } /*}}}*/ + /* F -- float format */ /*{{{*/ + case 'F': + { + ++ns; + const char* found = strchr(FloatFormat_Char, *ns); + if (found != NULL) + { + loaded.fform = (FloatFormat)(found - FloatFormat_Char); + ++ns; + break; + } + sprintf(errbuf, + _("Parse error for float format in line %d"), line); + err = errbuf; + goto eek; + } + /*}}}*/ /* L -- label */ /*{{{*/ case 'L': { @@ -1395,11 +1373,11 @@ const char *loadport(Sheet *sheet, const char *name) break; } /*}}}*/ - /* E -- scientific */ /*{{{*/ + /* E -- scientific, for backward compatibility */ /*{{{*/ case 'E': { ++ns; - loaded.scientific=1; + loaded.fform = FLT_SCIENTIFIC; break; } /*}}}*/ @@ -1528,10 +1506,14 @@ const char *loadport(Sheet *sheet, const char *name) ++line; } eek: - if (fclose(fp)==EOF && err==(const char*)0) err=strerror(errno); - sheet->changed=0; + if (fclose(fp) == EOF) { + if (err == (const char*)0) err=strerror(errno); + } else { + sheet->changed = false; + } cachelabels(sheet); forceupdate(sheet); + redraw_sheet(sheet); return err; } /*}}}*/ @@ -1641,7 +1623,7 @@ void insertcube(Sheet *sheet, const Location beg, const Location end, right=sheet->dimx+end[X]-beg[X]; for (z=beg[Z]; z<=end[Z]; ++z) for (y=beg[Y]; y<=end[Y]; ++y) for (x=right; x>end[X]; --x) { - resize(sheet,x,y,z); + resize(sheet, x, y, z, NULL); CELL_ATC(sheet,x,y,z) = CELL_ATC(sheet,x-(end[X]-beg[X]+1),y,z); CELL_ATC(sheet,x-(end[X]-beg[X]+1),y,z) = NULLCELL; } @@ -1656,7 +1638,7 @@ void insertcube(Sheet *sheet, const Location beg, const Location end, down=sheet->dimy+end[Y]-beg[Y]; for (z=beg[Z]; z<=end[Z]; ++z) for (x=beg[X]; x<=end[X]; ++x) for (y=down; y>end[Y]; --y) { - resize(sheet,x,y,z); + resize(sheet, x, y, z, NULL); CELL_ATC(sheet,x,y,z) = CELL_ATC(sheet,x,y-(end[Y]-beg[Y]+1),z); CELL_ATC(sheet,x,y-(end[Y]-beg[Y]+1),z) = NULLCELL; } @@ -1671,7 +1653,7 @@ void insertcube(Sheet *sheet, const Location beg, const Location end, bottom=sheet->dimz+end[Z]-beg[Z]; for (y=beg[Y]; y<=end[Y]; ++y) for (x=beg[X]; x<=end[X]; ++x) for (z=bottom; z>end[Z]; --z) { - resize(sheet,x,y,z); + resize(sheet, x, y, z, NULL); CELL_ATC(sheet,x,y,z) = CELL_ATC(sheet,x,y,z-(end[Z]-beg[Z]+1)); CELL_ATC(sheet,x,y,z-(end[Z]-beg[Z]+1)) = NULLCELL; } @@ -1799,12 +1781,12 @@ void moveblock(Sheet *sheet, const Location beg, const Location end, copycelltosheet(CELL_AT(sheet, get), sheet, go, ALTER_LABEL); else { - resize(sheet, go[X], go[Y], go[Z]); + resize(sheet, go[X], go[Y], go[Z], NULL); CELL_AT(sheet, go) = CELL_AT(sheet, get); CELL_AT(sheet, get) = NULLCELL; } } - sheet->changed=1; + sheet->changed = TRUE; cachelabels(sheet); forceupdate(sheet); } diff --git a/src/common/sheet.h b/src/common/sheet.h index 58e9223..35ca5c5 100644 --- a/src/common/sheet.h +++ b/src/common/sheet.h @@ -73,8 +73,8 @@ extern Location upd_l; extern int max_eval; void initialize_sheet(Sheet *sheet); -void resize(Sheet *sheet, int x, int y, int z); -Cell *initcellofsheet(Sheet *sheet, const Location at); +void resize(Sheet *sheet, int x, int y, int z, bool *qextended); +Cell *initcellofsheet(Sheet *sheet, const Location at, bool *qnew); void copycelltosheet(const Cell *fromcell, Sheet *sheet2, const Location to, LabelHandling lh); Cell *safe_cell_at(Sheet *sheet, const Location at); @@ -87,23 +87,24 @@ MarkState getmarkstate(Sheet *sheet); void dump_current_cell(Sheet *sheet); void freecellofsheet(Sheet *sheet, const Location at); int columnwidth(Sheet *sheet, int x, int z); -void setwidth(Sheet *sheet, int x, int z, int width); +bool setwidth(Sheet *sheet, int x, int z, int width); int cellwidth(Sheet *sheet, const Location at); void puttok(Sheet *sheet, const Location at, Token t, TokVariety v); Token recompvalue(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, int quote, int scientific, int precision, Sheet *sheet, const Location at); -void setadjust(Sheet *sheet, const Location at, Adjust adjust); -void shadow(Sheet *sheet, const Location at, int yep); -void bold(Sheet *sheet, const Location at, int yep); -void underline(Sheet *sheet, const Location at, int yep); -void lockcell(Sheet *sheet, const Location at, int yep); -void maketrans(Sheet *sheet, const Location at, int yep); -void igncell(Sheet *sheet, const Location at, int yep); +void printvalue(char *s, size_t size, size_t chars, StringFormat sf, + FloatFormat ff, int precision, Sheet *sheet, const Location at); +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); +bool underline(Sheet *sheet, const Location at, bool yep); +bool lockcell(Sheet *sheet, const Location at, bool yep); +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); -void setscientific(Sheet *sheet, const Location at, int yep); -void setprecision(Sheet *sheet, const Location at, int precision); +bool setfltformat(Sheet *sheet, const Location at, FloatFormat ff); +bool setprecision(Sheet *sheet, const Location at, int 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/wk1.c b/src/common/wk1.c index 34446e8..7eca9e3 100644 --- a/src/common/wk1.c +++ b/src/common/wk1.c @@ -93,15 +93,15 @@ static void format(unsigned char s, Cell *cell) { case 0: /* fixed with given precision */ /*{{{*/ { - cell->precision=s&0x0f; - cell->scientific=0; + cell->precision = s&0x0f; + cell->fform = FLT_DECIMAL; break; } /*}}}*/ case 1: /* scientifix with given presision */ /*{{{*/ { - cell->precision=s&0x0f; - cell->scientific=1; + cell->precision = s&0x0f; + cell->fform = FLT_SCIENTIFIC; break; } /*}}}*/ @@ -797,7 +797,7 @@ const char *loadwk1(Sheet *sheet, const char *name) case 0x6: { if (bodylen!=8) { err=_("Invalid record body length"); goto ouch; } - resize(sheet,it(body+4),it(body+6),0); + resize(sheet, it(body+4), it(body+6), 0, NULL); /* range is from &(it(body),it(body+2)) to &(it(body+4),it(body+6)) */ break; } @@ -843,7 +843,7 @@ const char *loadwk1(Sheet *sheet, const char *name) { if (bodylen!=5) { err=_("Invalid record body length"); goto ouch; } tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); format((unsigned char)body[0], cell); break; } @@ -855,7 +855,7 @@ const char *loadwk1(Sheet *sheet, const char *name) assert(bodylen == 7); tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); t.type = INT; t.u.integer = it(body+5); puttok(sheet, tmp, t, BASE_CONT); @@ -870,7 +870,7 @@ const char *loadwk1(Sheet *sheet, const char *name) assert(bodylen == 13); tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); t.type = FLOAT; t.u.flt = dbl((unsigned char*)body+5); puttok(sheet, tmp, t, BASE_CONT); @@ -885,7 +885,7 @@ const char *loadwk1(Sheet *sheet, const char *name) assert(bodylen >= 6 && bodylen <= 245); tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); t.type = STRING; t.u.string = strdup(body+6); puttok(sheet, tmp, t, BASE_CONT); @@ -985,7 +985,7 @@ const char *loadwk1(Sheet *sheet, const char *name) #endif free(offset); tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); cell->tok[CURR_VAL].type = FLOAT; cell->tok[CURR_VAL].u.flt = dbl((unsigned char*)body+5); puttok(sheet, tmp, tok, BASE_CONT); @@ -1103,7 +1103,7 @@ const char *loadwk1(Sheet *sheet, const char *name) assert(bodylen>=6 && bodylen<=245); tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; - cell = initcellofsheet(sheet, tmp); + cell = initcellofsheet(sheet, tmp, NULL); t.type = STRING; t.u.string = strdup(body+5); puttok(sheet, tmp, t, BASE_CONT); diff --git a/src/common/xdr.c b/src/common/xdr.c index 5e27e64..3970a9e 100644 --- a/src/common/xdr.c +++ b/src/common/xdr.c @@ -236,21 +236,29 @@ bool_t xdr_cell(XDR *xdrs, Cell *cell) cell->tok[tv] = tok; } if (xdr_mystring(xdrs, &(cell->label))==0) return 0; - x=cell->adjust; - result=xdr_int(xdrs, &x); - cell->adjust=x; + x = cell->adjust; + result = xdr_int(xdrs, &x); + cell->adjust = x; if (result==0) return 0; if (xdr_int(xdrs, &(cell->precision))==0) return 0; - x=(cell->updated&1)|((cell->shadowed&1)<<1)|((cell->scientific&1)<<2)|((cell->locked&1)<<3)|((cell->transparent&1)<<4)|((cell->ignored&1)<<5)|((cell->bold&1)<<6)|((cell->underline&1)<<7); - result=xdr_int(xdrs, &x); - cell->updated=((x&(1))!=0); - cell->shadowed=((x&(1<<1))!=0); - cell->scientific=((x&(1<<2))!=0); - cell->locked=((x&(1<<3))!=0); - cell->transparent=((x&(1<<4))!=0); - cell->ignored=((x&(1<<5))!=0); - cell->bold=((x&(1<<6))!=0); - cell->underline=((x&(1<<7))!=0); + x = 0; + /* Since we only decode, we do not need to do this any more; it is + just kept for documentation purposes: + + x = (cell->updated & 1) | ((cell->shadowed & 1)<<1) + | ((cell->scientific & 1)<<2) | ((cell->locked & 1)<<3) + | ((cell->transparent & 1)<<4) | ((cell->ignored & 1)<<5) + | ((cell->bold & 1)<<6) | ((cell->underline & 1)<<7); + */ + 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; + cell->locked = ((x & (1<<3)) != 0); + cell->transparent = ((x & (1<<4)) != 0); + cell->ignored = ((x & (1<<5)) != 0); + cell->bold = ((x & (1<<6)) != 0); + cell->underline = ((x & (1<<7)) != 0); return result; } /*}}}*/ @@ -391,7 +399,7 @@ const char *loadxdr(Sheet *sheet, const char *name) (void)fclose(fp); return strerror(olderror); } - nc = initcellofsheet(sheet, w); + nc = initcellofsheet(sheet, w, NULL); if (xdr_cell(&xdrs, nc)==0) { freecellofsheet(sheet, w); diff --git a/src/display.c b/src/display.c index 02ec5e7..aa701e3 100644 --- a/src/display.c +++ b/src/display.c @@ -59,71 +59,92 @@ static void redraw(void) /* do_attribute -- set cell attributes */ static int do_attribute(Sheet *cursheet) { - - MenuChoice mainmenu[5]; - MenuChoice adjmenu[11]; - MarkState ms; - const char *prompt; int c; - - /* create menus */ - adjmenu[0].str = _("lL)eft"); adjmenu[0].c='\0'; - adjmenu[1].str = _("rR)ight"); adjmenu[1].c='\0'; - adjmenu[2].str = _("cC)entered"); adjmenu[2].c='\0'; - adjmenu[3].str = _("11).23e1 <-> 12.3"); adjmenu[3].c='\0'; - adjmenu[4].str = _("pP)recision"); adjmenu[4].c='\0'; - adjmenu[5].str = _("sS)hadow"); adjmenu[5].c='\0'; - adjmenu[6].str = _("bB)old"); adjmenu[6].c='\0'; - adjmenu[7].str = _("uU)nderline"); adjmenu[7].c='\0'; - adjmenu[8].str = _("oO)utput special characters"); adjmenu[8].c='\0'; - adjmenu[9].str = (char*)0; - - mainmenu[0].str = _("rR)epresentation"); mainmenu[0].c='\0'; - mainmenu[1].str = _("lL)abel"); mainmenu[1].c='\0'; - mainmenu[2].str = _("oLo)ck"); mainmenu[2].c='\0'; - mainmenu[3].str = _("iI)gnore"); mainmenu[3].c='\0'; - mainmenu[4].str = (char*)0; - + Cell *cc = curcell(cursheet); do { - ms = getmarkstate(cursheet); + MarkState ms = getmarkstate(cursheet); + const char* prompt = _("Block attribute"); if (ms == UNMARKED) prompt = _("Cell attribute"); - else prompt = _("Block attribute"); + const char *mainmenu[] = + { _("jJ)ustify"), _("fF)loats"), _("tT)ypeface"), + _("mM)isc"), _("lL)abel"), _("kLock)"), NULL + }; c = line_menu(prompt, mainmenu, 0); - /* There is a magic number "2" in the next line, presumably it represents + /* There is a magic number "5" in the next line, presumably it represents the selection of the lock attribute in the list of items above, in which - lock does indeed appear at index 2 + lock does indeed appear at index 5 */ - if (ms == UNMARKED && c != 2 && locked(curcell(cursheet))) - line_msg(_("Cell attribute:"),_("Cell is locked")); + if (ms == UNMARKED && c != 5 && locked(cc)) + line_msg(_("Cell attribute:"), _("Cell is locked")); else { switch (c) { - case -2: - case -1: c = KEY_CANCEL; break; + case -2: case -1: c = KEY_CANCEL; break; case 0: { - switch (c = line_menu(prompt, adjmenu,0)) + const char *justifymenu[] = + { _("lL)eft"), _("rR)ight"), _("cC)entered"), NULL }; + switch (c = line_menu(prompt, justifymenu, getadjust(cc))) { - case -2: - case -1: c = K_INVALID; break; + case -2: case -1: c = K_INVALID; break; case 0: c = ADJUST_LEFT; break; case 1: c = ADJUST_RIGHT; break; case 2: c = ADJUST_CENTER; break; - case 3: c = ADJUST_SCIENTIFIC; break; - case 4: c = ADJUST_PRECISION; break; - case 5: c = ADJUST_SHADOW; break; - case 6: c = ADJUST_BOLD; break; - case 7: c = ADJUST_UNDERLINE; break; - case 8: c = ADJUST_TRANSPARENT; break; default: assert(0); } break; } - case 1: c = ADJUST_LABEL; break; - case 2: c = ADJUST_LOCK; break; - case 3: c = ADJUST_IGNORE; break; + case 1: + { + const char *floatmenu[] = + { _("dD)ecimal"), _("sS)cientific"), _("cC)ompact"), + _("hH)exact"), _("pP)recision"), NULL + }; + switch (c = line_menu(prompt, floatmenu, getfltformat(cc))) + { + case -2: case -1: c = K_INVALID; break; + case 0: c = ADJUST_DECIMAL; break; + case 1: c = ADJUST_SCIENTIFIC; break; + case 2: c = ADJUST_COMPACT; break; + case 3: c = ADJUST_HEXACT; break; + case 4: c = ADJUST_PRECISION; break; + default: assert(0); + } + break; + } + case 2: + { + const char *typemenu[] = + { _("bB)old"), _("uU)nderline"), NULL }; + switch (c = line_menu(prompt, typemenu, 0)) + { + case -2: case -1: c = K_INVALID; break; + case 0: c = ADJUST_BOLD; break; + case 1: c = ADJUST_UNDERLINE; break; + default: assert(0); + } + break; + } + case 3: + { + const char *miscmenu[] = + { _("sS)hadow"), _("iI)gnore"), + _("oO)utput special characters"), NULL + }; + switch (c = line_menu(prompt, miscmenu, 0)) + { + case -2: case -1: c = K_INVALID; break; + case 0: c = ADJUST_SHADOW; break; + case 1: c = ADJUST_IGNORE; break; + case 2: c = ADJUST_TRANSPARENT; break; + default: assert(0); + } + break; + } + case 4: c = ADJUST_LABEL; break; + case 5: c = ADJUST_LOCK; break; default: assert(0); } } @@ -136,19 +157,13 @@ static int do_attribute(Sheet *cursheet) /* do_file -- file menu */ static int do_file(Sheet *cursheet) { + int c = 0; - MenuChoice menu[4]; - int c; - - - menu[0].str = _("lL)oad"); menu[0].c='\0'; - menu[1].str = _("sS)ave"); menu[1].c='\0'; - menu[2].str = _("nN)ame"); menu[2].c='\0'; - menu[3].str = (char*)0; - c=0; do { - switch (c=line_menu(_("File:"),menu,0)) + const char *menu[] = + { _("lL)oad"), _("sS)ave"), _("nN)ame"), NULL }; + switch (c = line_menu(_("File:"), menu, 0)) { case -2: case -1: c = KEY_CANCEL; break; @@ -237,22 +252,15 @@ static int do_shell(void) /* do_block -- block menu */ static int do_block(Sheet *cursheet) { - MenuChoice block[9]; - int c; + int c = 0; - block[0].str = _("ecle)ar"); block[0].c='\0'; - block[1].str = _("iI)nsert"); block[1].c='\0'; - block[2].str = _("dD)elete"); block[2].c='\0'; - block[3].str = _("mM)ove"); block[3].c='\0'; - block[4].str = _("cC)opy"); block[4].c='\0'; - block[5].str = _("fF)ill"); block[5].c='\0'; - block[6].str = _("sS)ort"); block[6].c='\0'; - block[7].str = _("rMir)ror"); block[7].c='\0'; - block[8].str = (char*)0; - c=0; do { - switch (c=line_menu(_("Block menu:"),block,0)) + const char* block[] = + { _("ecle)ar"), _("iI)nsert"), _("dD)elete"), _("mM)ove"), + _("cC)opy"), _("fF)ill"), _("sS)ort"), _("rMir)ror"), NULL + }; + switch (c = line_menu(_("Block menu:"), block, 0)) { case -2: case -1: c = KEY_CANCEL; break; @@ -273,23 +281,14 @@ static int do_block(Sheet *cursheet) int show_menu(Sheet *cursheet) { - - MenuChoice menu[9]; int c = K_INVALID; - - menu[0].str = _("aA)ttributes"); menu[0].c='\0'; - menu[1].str = _("wW)idth"); menu[1].c='\0'; - menu[2].str = _("bB)lock"); menu[2].c='\0'; - menu[3].str = _("fF)ile"); menu[3].c='\0'; - menu[4].str = _("gG)oto"); menu[4].c='\0'; - menu[5].str = _("sS)hell"); menu[5].c='\0'; - menu[6].str = _("vV)ersion"); menu[6].c='\0'; - menu[7].str = _("qQ)uit"); menu[7].c='\0'; - menu[8].str = (char*)0; - do { + const char* menu[] = + { _("aA)ttributes"), _("wW)idth"), _("bB)lock"), _("fF)ile"), + _("gG)oto"), _("sS)hell"), _("vV)ersion"), _("qQ)uit"), NULL + }; switch (c=line_menu(_("Main menu:"),menu,0)) { case -2: @@ -520,7 +519,7 @@ void redraw_sheet(Sheet *sheet) if (bufsz < (size*UTF8SZ+1)) buf = realloc(buf, bufsz=(size*UTF8SZ+1)); - printvalue(buf, (size*UTF8SZ+1), size, quote, getscientific(cell), + printvalue(buf, (size*UTF8SZ + 1), size, quote, getfltformat(cell), getprecision(cell), sheet, tmp); adjust(getadjust(cell), buf, size); assert(size>=cutoff); @@ -566,14 +565,14 @@ void redraw_sheet(Sheet *sheet) { cell = curcell(sheet); Token bc = gettok(cell, BASE_CONT); - printtok(buf+strlen(buf), bufsz-strlen(buf), 0, 1, getscientific(cell), - -1, false, &bc); + printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING, + FLT_COMPACT, 0, TRUNCATED_ERROR, &bc); Token ic = gettok(cell, ITER_CONT); if (ic.type != EMPTY && mbslen(buf) < (size_t)(sheet->maxx+1-4)) { strcat(buf," -> "); - printtok(buf+strlen(buf), bufsz-strlen(buf), 0, 1, - getscientific(cell), -1, false, &ic); + printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING, + FLT_COMPACT, 0, TRUNCATED_ERROR, &ic); } } *mbspos(buf, sheet->maxx) = 0; @@ -643,9 +642,8 @@ int line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t * case 'v': { char valbuf[1024]; - printvalue(valbuf, sizeof(valbuf), 0, 1, - getscientific(curcell(sheet)), -1, - sheet, sheet->cur); + printvalue(valbuf, sizeof(valbuf), 0, QUOTE_STRING, + FLT_COMPACT, 0, sheet, sheet->cur); if (strlen(buf)+strlen(valbuf) >= (size-1)) break; (void)memmove(src+strlen(valbuf), src, strlen(src)); (void)memcpy(src, valbuf, strlen(valbuf)); @@ -817,30 +815,20 @@ int line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t * /* line_ok -- one line yes/no menu */ int line_ok(const char *prompt, int curx) { + assert(curx == 0 || curx == 1); - MenuChoice menu[3]; - - assert(curx==0 || curx==1); - - menu[0].str = _("nN)o"); menu[0].c='\0'; - menu[1].str = _("yY)es"); menu[1].c='\0'; - menu[2].str=(char*)0; + const char* menu[] = { _("nN)o"), _("yY)es"), NULL }; return line_menu(prompt, menu, curx); } /* line_binary -- two choices with cancel */ int line_binary(const char *prompt, const char* op1, const char* op2, int curx) { - - MenuChoice menu[4]; int result; - assert(curx==0 || curx==1); + assert(curx == 0 || curx == 1); - menu[0].str = _("cC)ancel"); - menu[1].str = op1; menu[0].c='\0'; - menu[2].str = op2; menu[1].c='\0'; - menu[3].str = (char*)0; + const char* menu[] = { _("cC)ancel"), op1, op2, NULL }; return line_menu(prompt, menu, curx+1) - 1; } @@ -855,75 +843,75 @@ function key to work. */ -int line_menu(const char *prompt, const MenuChoice *choice, int curx) +int line_menu(const char *prompt, const char **choice, int curx) { - - int maxx,x,width,offx; - chtype c; - size_t promptlen; - - - - assert(prompt!=(const char*)0); - assert(choice!=(const MenuChoice*)0); - assert(curx>=0); + assert(prompt != NULL); + assert(choice != (const char **)0); + assert(curx >= 0); mvwaddstr(stdscr,LINES-1,0,prompt); - promptlen = mbslen(prompt); - for (maxx=0; (choice+maxx)->str!=(const char*)0; ++maxx); - offx=0; + + size_t promptlen = mbslen(prompt); + int maxx = 0; + while (choice[maxx] != NULL) ++maxx; + int offx = 0; + chtype c; do { - (void)wmove(stdscr,LINES-1,(int)promptlen); + int x, width; + (void)wmove(stdscr, LINES-1, (int)promptlen); /* correct offset so choice is visible */ - if (curx<=offx) offx=curx; + if (curx <= offx) offx = curx; else do { - for (width=promptlen,x=offx; xstr+1))+1<=COLS; width+=((int)(mbslen((choice+x)->str)))+1,++x); + width = promptlen; + x = offx; + while (x < maxx && width + ((int)mbslen(choice[x]+1)) + 1 <= COLS) + { + width += (int)(mbslen(choice[x]+1)) + 1; + ++x; + } --x; - if (xstr+1))+1<=COLS; width+=mbslen((choice+x)->str+1)+1,++x) + for (width = promptlen, x = offx; + x < maxx && width + ((int)mbslen(choice[x]+1)) + 1 <= COLS; + width += mbslen(choice[x]+1) + 1, ++x) { - (void)waddch(stdscr,(chtype)(unsigned char)' '); - if (x==curx) (void)wattron(stdscr,DEF_MENU); - (void)waddstr(stdscr,(char*)(choice+x)->str+1); - if (x==curx) (void)wattroff(stdscr,DEF_MENU); + (void)waddch(stdscr, (chtype)(unsigned char)' '); + if (x == curx) (void)wattron(stdscr, DEF_MENU); + (void)waddstr(stdscr, (char*)(choice[x]+1)); + if (x == curx) (void)wattroff(stdscr,DEF_MENU); } - if (width0) --curx; else curx=maxx-1; break; + case K_LEFT: if (curx > 0) --curx; else curx = maxx-1; break; /* Space, Tab, KEY_RIGHT -- move to next item */ case ' ': case '\t': - case K_RIGHT: if (curx<(maxx-1)) ++curx; else curx=0; break; + case K_RIGHT: if (curx < (maxx-1)) ++curx; else curx = 0; break; /* default -- search choice keys */ default: { - int i; - - for (i=0; (choice+i)->str!=(const char*)0; ++i) - { - if ((c<256 && tolower(c)==*((choice+i)->str)) || (choice+i)->c==c) + for (int i = 0; i < maxx; ++i) + if (c < 256 && tolower(c) == choice[i][0]) { - c=K_ENTER; - curx=i; + c = K_ENTER; + curx = i; } - } } - } } - while (c!=K_ENTER && c!=K_DOWN && c!=KEY_CANCEL && c!=K_UP); - (void)wmove(stdscr,LINES-1,0); + while (c != K_ENTER && c != K_DOWN && c != KEY_CANCEL && c != K_UP); + (void)wmove(stdscr, LINES-1, 0); (void)wclrtoeol(stdscr); switch (c) { diff --git a/src/display.h b/src/display.h index 48a9e21..f750d6d 100644 --- a/src/display.h +++ b/src/display.h @@ -8,12 +8,6 @@ extern "C" { #endif -typedef struct -{ - Key c; - const char *str; -} MenuChoice; - void display_main(Sheet *cursheet); void display_init(Sheet *cursheet, int always_redraw); void display_end(Sheet *sheet); @@ -28,7 +22,7 @@ int keypressed(void); void show_text(const char *text); Key show_menu(Sheet *cursheet); -int line_menu(const char *prompt, const MenuChoice *choice, int curx); +int line_menu(const char *prompt, const char **choice, int curx); void find_helpfile(char *buf, int size, const char *argv0); #ifdef __cplusplus diff --git a/src/fteapot.fl b/src/fteapot.fl index 59240b2..bfca0bd 100644 --- a/src/fteapot.fl +++ b/src/fteapot.fl @@ -18,7 +18,6 @@ decl {\#define SKIPDEFCOLS(c) while (c == DefaultCN[FOREGROUND] || c == DefaultC {private global} decl {\#define shadow _shadow} {private global} decl {\#define transparent _transparent} {private global} -decl {\#define MenuChoice _MenuChoice} {private global} decl {\#define Cell _Cell} {private global} decl {\#include } {private local} @@ -29,7 +28,6 @@ decl {\#include } {private global} decl {\#undef shadow} {private global} decl {\#undef transparent} {private global} -decl {\#undef MenuChoice} {private global} decl {\#undef Cell} {private global} decl {\#include "tpt_choose.h"} {private global} @@ -160,7 +158,7 @@ class TeapotTable {open : {public Fl_Table}} fl_color(cellfg); fl_font(FL_HELVETICA | (isbold(cell) ? FL_BOLD : 0), 14); - printvalue(s, sizeof(s), 0, 0, getscientific(cell), + printvalue(s, sizeof(s), 0, quote, getfltformat(cell), getprecision(cell), cursheet, test); int ww = 0, hh = 0; @@ -558,11 +556,29 @@ class MainWindow {open} user_data ADJUST_PRECISION xywh {0 0 36 21} shortcut 0x80070 divider } + menuitem dec { + label {&Decimal} + user_data ADJUST_DECIMAL + protected xywh {0 0 36 21} + code0 {o->flags |= FL_MENU_RADIO;} + } MenuItem sci { label {&Scientific} user_data ADJUST_SCIENTIFIC protected xywh {0 0 36 21} shortcut 0x80073 - code0 {o->flags |= FL_MENU_TOGGLE;} + code0 {o->flags |= FL_MENU_RADIO;} + } + MenuItem cpt { + label {Co&mpact} + user_data ADJUST_COMPACT + protected xywh {0 0 36 21} + code0 {o->flags |= FL_MENU_RADIO;} + } + MenuItem hex { + label {He&xact} + user_data ADJUST_COMPACT + protected xywh {0 0 36 21} divider + code0 {o->flags |= FL_MENU_RADIO;} } MenuItem shadow { label {Shadow&ed} @@ -644,9 +660,8 @@ class MainWindow {open} sprintf(valbuf, "(%i,%i,%i)", sheet->cur[X], sheet->cur[Y], sheet->cur[Z]); else if (Fl::event_key() == 'v') - printvalue(valbuf, sizeof(valbuf), 0, 1, - getscientific(curcell(sheet)), - -1, sheet, sheet->cur); + printvalue(valbuf, sizeof(valbuf), 0, QUOTE_STRING, + FLT_COMPACT, 0, sheet, sheet->cur); else if (Fl::event_key(FL_Tab)) line_input->take_focus(); if (valbuf[0]) { line_input->insert(valbuf); @@ -662,23 +677,23 @@ class MainWindow {open} val[sizeof(val)-1] = 0; } else { Token t = gettok(curcell(sheet), BASE_CONT); - printtok(val, sizeof(val), 0, 1, getscientific(curcell(sheet)), - -1, true, &t); - 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, 1, - getscientific(curcell(sheet)), -1, true, &t); - } + printtok(val, sizeof(val), 0, QUOTE_STRING, + FLT_COMPACT, 0, 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); + } line_edit(sheet, val, 0, buf, 0, 0); Cell *cell = curcell(sheet); - int adj = getadjust(cell); - if (adj == LEFT) left->setonly(); - else if (adj == RIGHT) right->setonly(); - else if (adj == CENTER) center->setonly(); + switch (getadjust(cell)) { + 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])) shadow->set(); @@ -693,11 +708,16 @@ class MainWindow {open} else bold->clear(); if (underlined(cell)) underline->set(); else underline->clear(); - if (getscientific(cell)) sci->set(); - else sci->clear();} + switch (getfltformat(cell)) { + case FLT_DECIMAL: dec->setonly(); break; + case FLT_SCIENTIFIC: sci->setonly(); break; + case FLT_COMPACT: cpt->setonly(); break; + case FLT_HEXACT: hex->setonly(); break; + } + } protected xywh {0 50 800 525} box DOWN_FRAME labeltype NO_LABEL resizable - code0 {table->sheet(sheet);} + code0 { table->sheet(sheet); } class TeapotTable } Fl_Box status { @@ -847,7 +867,7 @@ Function {keypressed()} {open C return_type int} {code } {} } Function -{line_menu(const char *prompt, const MenuChoice *choice, int curx)} +{line_menu(const char *prompt, const char **choice, int curx)} {C return_type int} { Fl_Window line_menu_menu { @@ -874,8 +894,8 @@ Function } code { line_menu_browser->clear(); - while (choice->str) { - line_menu_browser->add(choice->str+1); + while (*choice) { + line_menu_browser->add(*choice + 1); choice++; } @@ -909,8 +929,8 @@ Function Fl_File_Icon::load_system_icons(); \#endif Fl::scheme("gtk+"); - int ch = sheet->changed; - resize(sheet, 1, 1, 1); + bool ch = sheet->changed; + resize(sheet, 1, 1, 1, NULL); sheet->changed = ch; new MainWindow(sheet); /* allocate and initialize the palette */