Make tpa the default file format for Teapot

There turned out to be one blocking technical issue for full adpotion of
  tpa format, and that was the fact that the printed representation of
  floating values inside the tpa file might not reproduce the same double
  when read. This change therefore introduces the "hexact" floating point
  format, based on the the %La format string, which produces a hex
  representation with exact round trips. While working on this, it was
  convenient to add a new representation "compact" which is basically the
  shorter of decimal and scientific representations, without trailing zeros.
  This is now the default float format, but of course one can select decimal
  or scientific formats to restore prior appearance. However, full-precision
  compact format is now the (only) format for editing cell contents, as it
  is accurate and efficient. Of course you can enter floating point values
  in any format you like when typing in a formula.

  The addition of several new floating point options overloaded the menus
  in terminal teapot, so this change also revamps those menus slightly,
  including eliminating the unused MenuChoice struct, and just specifying menus
  with an array of strings.

  Closes #63.
This commit is contained in:
Glen Whitney 2019-08-24 09:58:46 -07:00
parent 364ef2c0ea
commit 96079b210e
22 changed files with 923 additions and 841 deletions

View File

@ -1948,7 +1948,7 @@ status open
\begin_layout Plain Layout \begin_layout Plain Layout
\begin_inset Tabular \begin_inset Tabular
<lyxtabular version="3" rows="26" columns="3"> <lyxtabular version="3" rows="25" columns="3">
<features tabularvalignment="middle"> <features tabularvalignment="middle">
<column alignment="left" valignment="top" width="5cm"> <column alignment="left" valignment="top" width="5cm">
<column alignment="left" valignment="top"> <column alignment="left" valignment="top">
@ -2562,35 +2562,6 @@ Set column width
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none"> <cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text \begin_inset Text
\begin_layout Plain Layout
{Meta-S}
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
Set cell/block scientific notation
\end_layout
\end_inset
</cell>
</row>
<row>
<cell alignment="left" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout
\end_layout
\end_inset
</cell>
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\begin_inset Text
\begin_layout Plain Layout \begin_layout Plain Layout
{Meta-E} {Meta-E}
\end_layout \end_layout
@ -3359,9 +3330,43 @@ The precision for the output of floating point values.
\end_layout \end_layout
\begin_layout Itemize \begin_layout Itemize
Whether floating point numbers should be printed in scientific notation The format for floating point numbers when they are printed.
(0.123e1) or as decimal number (1.23). This can be
It only affects the output, if the cell value is a floating point number. \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 \end_layout
@ -4034,7 +4039,25 @@ File Formats
\end_layout \end_layout
\begin_layout Paragraph \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 \end_layout
\begin_layout Standard \begin_layout Standard
@ -4043,28 +4066,31 @@ XDR (eXternal Data Representation) is a standard invented by Sun Microsystems
media. media.
Its advantage is that it is widely available and that it defines a portable Its advantage is that it is widely available and that it defines a portable
floating point number format. floating point number format.
The native teapot file format uses XDR so it is portable across different The native teapot file format formerly used XDR so it is portable across
machine architectures and operating systems. different machine architectures and operating systems.
The advantage of this over the portable ASCII format is that due to the The advantage of this over the portable ASCII format was that due to the
(usually) missing conversion calculations any floating point constants (usually) missing conversion calculations any floating point constants
will be saved/loaded exactly without conversion errors. 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 %a
ASCII (.tpa) \begin_inset Quotes erd
\end_layout \end_inset
\begin_layout Standard style (
The ASCII file format allows easy generation/modification of saved sheets \begin_inset Quotes eld
by shell scripts. \end_inset
Due to binary/ASCII conversion, there may be conversion errors in floating
point constants.
The default extension is
\family typewriter
.
\family default
tpa.
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 \end_layout
\begin_layout Paragraph \begin_layout Paragraph
@ -6254,6 +6280,11 @@ condition
expression to avoid recalculation becoming stuck in an infinite loop, however. expression to avoid recalculation becoming stuck in an infinite loop, however.
\end_layout \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 \begin_layout Description
\series medium \series medium
@ -6495,6 +6526,11 @@ x
\end_layout \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 \begin_layout Description
\series medium \series medium
@ -7458,20 +7494,24 @@ precision
\begin_inset space ~ \begin_inset space ~
\end_inset \end_inset
integer
\emph on \emph on
format
\begin_inset space ~
\end_inset
scientific
\emph default \emph default
]]) ]])
\series default \series default
evaluates to the string representation of its first argument. evaluates to the string representation of its first argument.
The optional second argument gives the precision used for converting floating The optional second argument gives the precision used for converting floating
point numbers to string form. 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 \begin_inset Quotes eld
\end_inset \end_inset
@ -7479,16 +7519,24 @@ scientific
\begin_inset Quotes erd \begin_inset Quotes erd
\end_inset \end_inset
or ,
\begin_inset Quotes eld \begin_inset Quotes eld
\end_inset \end_inset
decimal, compact
\begin_inset Quotes erd \begin_inset Quotes erd
\end_inset \end_inset
controlling the type of notation used for converting floating point numbers , or
to string form. \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. If the optional arguments are not specified, current defaults are used.
\end_layout \end_layout

View File

@ -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 <assert.h> #include <assert.h>
#include <float.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include "cell.h"
#include "default.h" #include "default.h"
#include "eval.h" #include "eval.h"
#include "main.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[] = const char *ColorAspect_Name[] =
{ [FOREGROUND] = "Foreground", [BACKGROUND] = "Background" { [FOREGROUND] = "Foreground", [BACKGROUND] = "Background"
@ -27,12 +52,12 @@ void initcellcontents(Cell *fresh)
fresh->tok[tv].type = EMPTY; fresh->tok[tv].type = EMPTY;
fresh->label = NULL; fresh->label = NULL;
fresh->precision = -1; fresh->precision = -1;
fresh->fform = DEF_FLOATFORM;
fresh->adjust = AUTOADJUST; fresh->adjust = AUTOADJUST;
for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a) for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a)
fresh->aspect[a] = DefaultCN[a]; fresh->aspect[a] = DefaultCN[a];
fresh->updated = 0; fresh->updated = 0;
fresh->shadowed = 0; fresh->shadowed = 0;
fresh->scientific = DEF_SCIENTIFIC;
fresh->locked = 0; fresh->locked = 0;
fresh->transparent = 0; fresh->transparent = 0;
fresh->ignored = 0; fresh->ignored = 0;
@ -108,10 +133,10 @@ bool ignored(const Cell *cell)
} }
/* getscientific -- should value be displayed in scientific notation? */ /* getfltformat -- float format for numbers */
bool getscientific(const Cell *cell ) FloatFormat getfltformat(const Cell *cell )
{ {
return (cell == NULLCELL) ? DEF_SCIENTIFIC : cell->scientific; return (cell == NULLCELL) ? DEF_FLOATFORM : cell->fform;
} }
/* getprecision -- get cell precision */ /* getprecision -- get cell precision */
@ -189,3 +214,246 @@ void copycell(Cell *to, const Cell *fromcell, LabelHandling lh)
initcellcontents(to); 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<size) dest[cur] = 0;
else
{
dest[size-1] = 0;
cur = size;
}
if (field_width && mbslen(dest) > field_width) {
for (cur = 0; cur < field_width; ++cur) dest[cur] = '#';
dest[cur] = 0;
}
return cur;
}
/*}}}*/
/* print -- print token sequence */ /*{{{*/
void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff,
int digits, Token **n)
{
size_t cur;
cur=0;
if (n != EMPTY_TVEC)
for (; cur<size-1 && (*n) != NULLTOKEN; ++n)
cur += printtok(s+cur, size-cur, 0, sf, ff, digits, TRUNCATED_ERROR, *n);
if (cur<size) s[cur] = 0;
else s[size-1] = 0;
if (chars && mbslen(s) > chars) {
for (cur=0; cur < chars; ++cur) s[cur] = '#';
s[cur] = 0;
}
}
/*}}}*/

View File

@ -7,8 +7,6 @@
extern "C" { extern "C" {
#endif #endif
typedef enum { LEFT=0, RIGHT=1, CENTER=2, AUTOADJUST=3 } Adjust;
typedef enum typedef enum
{ BASE_CONT=0, ITER_CONT, ATTR_REF, MAX_PERSIST_TV = ATTR_REF, { BASE_CONT=0, ITER_CONT, ATTR_REF, MAX_PERSIST_TV = ATTR_REF,
CURR_VAL, RES_VAL, CURR_VAL, RES_VAL,
@ -16,6 +14,18 @@ typedef enum
} TokVariety; } TokVariety;
extern const char *TokVariety_Name[]; 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; typedef unsigned char ColorNum;
#define MAX_MAX_COLORS UCHAR_MAX; #define MAX_MAX_COLORS UCHAR_MAX;
@ -29,10 +39,10 @@ typedef struct
char *label; char *label;
int precision; int precision;
Adjust adjust; Adjust adjust;
FloatFormat fform;
ColorNum aspect[NUM_COLOR_ASPECTS]; ColorNum aspect[NUM_COLOR_ASPECTS];
unsigned int updated:1; unsigned int updated:1;
unsigned int shadowed:1; unsigned int shadowed:1;
unsigned int scientific:1;
unsigned int locked:1; unsigned int locked:1;
unsigned int transparent:1; unsigned int transparent:1;
unsigned int ignored:1; unsigned int ignored:1;
@ -56,13 +66,19 @@ ColorNum getcolor(const Cell *cell, ColorAspect aspect);
bool locked(const Cell *cell); bool locked(const Cell *cell);
bool transparent(const Cell *cell); bool transparent(const Cell *cell);
bool ignored(const Cell *cell); bool ignored(const Cell *cell);
bool getscientific(const Cell *cell); FloatFormat getfltformat(const Cell *cell);
int getprecision(const Cell* cell); int getprecision(const Cell* cell);
const char *getlabel(const Cell *cell); const char *getlabel(const Cell *cell);
void initcellcontents(Cell *cell); void initcellcontents(Cell *cell);
void freecellcontents(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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -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; case CENTER: if (fputs_close("\\JustCenter ",fp)==EOF) return strerror(errno); break;
default: assert(0); default: assert(0);
} }
printvalue(buf, sizeof(buf), 0, 0, getscientific(cell), printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell),
getprecision(cell), sheet, w); getprecision(cell), sheet, w);
/* if (fputs_close("}{",fp)==EOF) return strerror(errno);*/ /* if (fputs_close("}{",fp)==EOF) return strerror(errno);*/
if (transparent(cell)) if (transparent(cell))

View File

@ -7,10 +7,13 @@
#define DEF_COLUMNWIDTH 12 #define DEF_COLUMNWIDTH 12
/* default precision of a printed value */ /* 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 */ /* default is compact notation for floating point numbers */
#define DEF_SCIENTIFIC 0 #define DEF_FLOATFORM FLT_COMPACT
/* character attribute for cell and row numbers */ /* character attribute for cell and row numbers */
#define DEF_NUMBER A_BOLD #define DEF_NUMBER A_BOLD

View File

@ -246,14 +246,15 @@ Token tconcat(Token l, Token r)
if (l.type == EEK) return tcopy(l); if (l.type == EEK) return tcopy(l);
if (r.type == EEK) return tcopy(r); 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) if (len > conc_buf_len - 2)
{ {
duperror(&result, buferr); duperror(&result, buferr);
return result; return result;
} }
len += printtok(buf + len, conc_buf_len - len - 1, 0, 0, len += printtok(buf + len, conc_buf_len - len - 1, 0, DIRECT_STRING,
DEF_SCIENTIFIC, def_precision, 0, &r); DEF_FLOATFORM, def_precision, TRUNCATED_ERROR, &r);
if (len > conc_buf_len - 2) if (len > conc_buf_len - 2)
{ {
duperror(&result, buferr); duperror(&result, buferr);

View File

@ -617,9 +617,9 @@ static Token string_func(int argc, const Token argv[])
{ {
/* variables */ /*{{{*/ /* variables */ /*{{{*/
Token result; 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; int precision = def_precision;
bool use_sci = DEF_SCIENTIFIC; bool ff = DEF_FLOATFORM;
char staticbuf[4096]; char staticbuf[4096];
size_t size; 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); if (argv[2].type != FIDENT) return duperror(&result, usage);
switch (argv[2].u.fident) switch (argv[2].u.fident)
{ {
case FUNC_DECIMAL: use_sci = false; break; case FUNC_DECIMAL: ff = FLT_DECIMAL; break;
case FUNC_SCIENTIFIC: use_sci = true; 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); default: assert(0);
} }
} }
@ -641,8 +643,8 @@ static Token string_func(int argc, const Token argv[])
precision = argv[1].u.integer; precision = argv[1].u.integer;
} }
result.type = STRING; result.type = STRING;
size = printtok(staticbuf, sizeof(staticbuf), 0, false, use_sci, precision, size = printtok(staticbuf, sizeof(staticbuf), 0, DIRECT_STRING, ff,
true, argv); precision, VERBOSE_ERROR, argv);
if (size > sizeof(staticbuf) - 2) if (size > sizeof(staticbuf) - 2)
return duperror(&result, _("string: Overflow of internal buffer")); return duperror(&result, _("string: Overflow of internal buffer"));
result.u.string = strdup(staticbuf); 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 */ /*{{{*/ /* scientific keyword */ /*{{{*/
static Token scientific_func(int argc, const Token argv[]) static Token scientific_func(int argc, const Token argv[])
{ {
@ -1659,7 +1675,10 @@ Tfunc tfunc[]=
/* Miscellaneous other functions/keywords */ /* Miscellaneous other functions/keywords */
[FUNC_DOLLAR_SIGN] = { "$", env_func, PREFIX_FUNC, FUNCT, 0 }, [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_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 }, [FUNC_SCIENTIFIC] = { "scientific", scientific_func, PREFIX_FUNC, FUNCT, 0 },
}; };
/*}}}*/ /*}}}*/

View File

@ -25,7 +25,8 @@ typedef enum
FUNC_LESS_EQUAL, FUNC_GREATER_EQUAL, FUNC_LESS_THAN, FUNC_GREATER_THAN, FUNC_LESS_EQUAL, FUNC_GREATER_EQUAL, FUNC_LESS_THAN, FUNC_GREATER_THAN,
FUNC_EQUAL_EQUAL, FUNC_TILDE_EQUAL, FUNC_BANG_EQUAL, FUNC_CARET, 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_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 N_FUNCTION_IDS
} FunctionIdentifier; } FunctionIdentifier;

View File

@ -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; case CENTER: if (fputs_close(" align=center>",fp)==EOF) return strerror(errno); break;
default: assert(0); default: assert(0);
} }
printvalue(buf, sizeof(buf), 0, 0, getscientific(cell), printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell),
getprecision(cell), sheet, w); getprecision(cell), sheet, w);
if (transparent(cell)) if (transparent(cell))
{ {

View File

@ -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; case CENTER: if (fputc_close('c',fp)==EOF) return strerror(errno); break;
default: assert(0); default: assert(0);
} }
printvalue(buf, sizeof(buf), 0, 0, getscientific(cell), printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell),
getprecision(cell), sheet, w); getprecision(cell), sheet, w);
if (fputs_close("}{",fp)==EOF) return strerror(errno); if (fputs_close("}{",fp)==EOF) return strerror(errno);
if (transparent(cell)) if (transparent(cell))

View File

@ -51,11 +51,11 @@ char helpfile[PATH_MAX];
bool batch = false; bool batch = false;
unsigned int batchln=0; unsigned int batchln=0;
int def_precision = DEF_PRECISION; int def_precision = DEF_PRECISION;
bool quote = false; StringFormat quote = DIRECT_STRING;
bool header = true; bool header = true;
bool always_redraw = false; bool always_redraw = false;
int debug_level = 0; int debug_level = 0;
static bool usexdr = true; static bool usexdr = false;
/*}}}*/ /*}}}*/
void moveto(Sheet *sheet, int x, int y, int z) void moveto(Sheet *sheet, int x, int y, int z)
@ -200,20 +200,23 @@ static int do_edit(Sheet *cursheet, Key c, const char *expr, TokVariety tv)
if (c == K_NONE) if (c == K_NONE)
{ {
cntt = gettok(cell, tv); 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); s = buf+strlen(buf);
} }
else if (c == K_BACKSPACE) else if (c == K_BACKSPACE)
{ {
cntt = gettok(cell, tv); 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'; if (strlen(buf)) *mbspos(buf+strlen(buf),-1)='\0';
s = buf+strlen(buf); s = buf+strlen(buf);
} }
else if (c == K_DC) else if (c == K_DC)
{ {
cntt = gettok(cell, tv); 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); memmove(buf,mbspos(buf,1),strlen(mbspos(buf,1))+1);
s = buf; s = buf;
} }
@ -344,18 +347,13 @@ static int do_columnwidth(Sheet *cursheet)
/* do_attribute -- set cell attributes */ /*{{{*/ /* do_attribute -- set cell attributes */ /*{{{*/
static void do_attribute(Sheet *cursheet, Key action) static void do_attribute(Sheet *cursheet, Key action)
{ {
/* variables */ /*{{{*/
Location w; Location w;
Adjust adj; Adjust adj = LEFT;
bool onecell; FloatFormat ff = FLT_DECIMAL;
Cell *fcell;
int c = 0;
/*}}}*/
adj = LEFT;
do_mark(cursheet, GET_MARK_CUR); do_mark(cursheet, GET_MARK_CUR);
onecell = SAME_LOC(cursheet->mark1, cursheet->mark2); bool onecell = SAME_LOC(cursheet->mark1, cursheet->mark2);
fcell = safe_cell_at(cursheet, cursheet->mark1); Cell *fcell = safe_cell_at(cursheet, cursheet->mark1);
bool changed = false;
if (action != ADJUST_LOCK && onecell && locked(fcell)) if (action != ADJUST_LOCK && onecell && locked(fcell))
{ {
line_msg(_("Cell attribute:"),_("Cell is locked")); line_msg(_("Cell attribute:"),_("Cell is locked"));
@ -364,32 +362,29 @@ static void do_attribute(Sheet *cursheet, Key action)
switch ((int)action) switch ((int)action)
{ {
case ADJUST_CENTER: ++adj; /* drop through */ case ADJUST_CENTER: ++adj; /* drop through */
case ADJUST_RIGHT: ++adj; case ADJUST_RIGHT: ++adj; /* drop through */
case ADJUST_LEFT: case ADJUST_LEFT:
{ {
const char *templ = _("Change adjustment of block to "); const char *templ = _("Change adjustment of block to %s?");
char *prompt = malloc(strlen(templ) + 64); char *prompt = malloc(strlen(templ) + MAX_ADJUST_NAME_LENGTH + 1);
const char *way = _("center?"); sprintf(prompt, templ, Adjust_Name[adj]);
if (action == ADJUST_RIGHT) way = _("right?");
else if (action == ADJUST_LEFT) way = _("left?");
strcpy(prompt, templ); strcat(prompt, way);
if (!onecell && line_ok(prompt, 0) <= 0) break; if (!onecell && line_ok(prompt, 0) <= 0) break;
for (ALL_LOCS_IN_REGION(cursheet,w)) for (ALL_LOCS_IN_REGION(cursheet,w))
setadjust(cursheet, w, adj); changed = setadjust(cursheet, w, adj) || changed;
break; break;
} }
/* 3 -- set scientific notation flag */ /*{{{*/ /* set float format */ /*{{{*/
case ADJUST_SCIENTIFIC: case ADJUST_HEXACT: ++ff; /* drop through */
case ADJUST_COMPACT: ++ff; /* drop through */
case ADJUST_SCIENTIFIC: ++ff; /* drop through */
case ADJUST_DECIMAL:
{ {
int n; const char* templ = _("Change float format of block to %s?");
char *prompt = malloc(strlen(templ) + MAX_FLOATFORM_NAME_LENGTH +1);
if (onecell) n = !getscientific(fcell); sprintf(prompt, templ, FloatFormat_Name[ff]);
else n = line_binary(_("Make block notation:"), if (!onecell && line_ok(prompt, 0) <= 0) break;
_("dD)ecimal"), _("sS)cientific"),
!getscientific(fcell));
if (n >= 0)
for (ALL_LOCS_IN_REGION(cursheet,w)) for (ALL_LOCS_IN_REGION(cursheet,w))
setscientific(cursheet, w, n); changed = setfltformat(cursheet, w, ff) || changed;
break; break;
} }
/*}}}*/ /*}}}*/
@ -403,7 +398,8 @@ static void do_attribute(Sheet *cursheet, Key action)
ex=0; ex=0;
n = getprecision(fcell); 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)); 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; break;
} }
/*}}}*/ /*}}}*/
@ -432,9 +428,9 @@ static void do_attribute(Sheet *cursheet, Key action)
LOCATION_GETS(r, w); LOCATION_GETS(r, w);
if (!SHADOWED(cursheet, r)) ++(r[X]); if (!SHADOWED(cursheet, r)) ++(r[X]);
for (; 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); if (n>0) do_mark(cursheet, UNMARKED);
@ -451,7 +447,8 @@ static void do_attribute(Sheet *cursheet, Key action)
_("pP)rotected"), _("tT)ransparent:"), _("pP)rotected"), _("tT)ransparent:"),
!transparent(fcell)); !transparent(fcell));
if (n >= 0) 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; break;
} }
/*}}}*/ /*}}}*/
@ -464,7 +461,8 @@ static void do_attribute(Sheet *cursheet, Key action)
else n = line_binary(_("Set block weight to:"), else n = line_binary(_("Set block weight to:"),
_("rR)egular"), _("bB)old"), !isbold(fcell)); _("rR)egular"), _("bB)old"), !isbold(fcell));
if (n >= 0) 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; break;
} }
/*}}}*/ /*}}}*/
@ -477,7 +475,8 @@ static void do_attribute(Sheet *cursheet, Key action)
else n = line_binary(_("Set block to:"), _("nN)ot underline"), else n = line_binary(_("Set block to:"), _("nN)ot underline"),
_("uU)nderline"), !underlined(fcell)); _("uU)nderline"), !underlined(fcell));
if (n >= 0) 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; break;
} }
/*}}}*/ /*}}}*/
@ -497,7 +496,8 @@ static void do_attribute(Sheet *cursheet, Key action)
else n = line_binary(_("Set block to:"), _("uU)nlocked"), _("lL)ocked"), else n = line_binary(_("Set block to:"), _("uU)nlocked"), _("lL)ocked"),
!locked(fcell)); !locked(fcell));
if (n >= 0) 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; break;
} }
/*}}}*/ /*}}}*/
@ -510,7 +510,8 @@ static void do_attribute(Sheet *cursheet, Key action)
else n = line_binary(_("Set block to:"), _("cC)omputed"), _("iI)gnored"), else n = line_binary(_("Set block to:"), _("cC)omputed"), _("iI)gnored"),
!ignored(fcell)); !ignored(fcell));
if (n >= 0) 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; break;
} }
/*}}}*/ /*}}}*/
@ -518,42 +519,14 @@ static void do_attribute(Sheet *cursheet, Key action)
default: assert(0); default: assert(0);
/*}}}*/ /*}}}*/
} }
if (c>=0) if (changed) {
{
if (onecell) redraw_cell(cursheet, cursheet->mark1); if (onecell) redraw_cell(cursheet, cursheet->mark1);
else redraw_sheet(cursheet); 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 */ /*{{{*/ /* do_saveport -- save sheet as portable ASCII file */ /*{{{*/
static int do_saveport(Sheet *cursheet, const char *name) 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 */ /*{{{*/ /* do_savecsv -- save sheet as CSV file */ /*{{{*/
static int do_savecsv(Sheet *cursheet, const char *name) 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); do_mark(cursheet, GET_MARK_ALL);
if (!name) { if (!name) name = cursheet->name;
MenuChoice menu[4]; const char *menu[] =
name = cursheet->name; { _("cC)omma (,)"), _("sS)emicolon (;)"), _("tT)ab (\\t)"), NULL };
const char seps[4] = ",;\t";
menu[0].str=strdup(_("cC)omma (,)")); menu[0].c='\0'; int sep = line_menu(_("Choose separator:"), menu, 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 (sep < 0) return sep;
}
unsigned int count;
const char *msg;
if ((msg = savecsv(cursheet, name, seps[sep], if ((msg = savecsv(cursheet, name, seps[sep],
cursheet->mark1, cursheet->mark2, &count))) { cursheet->mark1, cursheet->mark2, &count)))
{
line_msg(_("Save in CSV format to file:"), msg); line_msg(_("Save in CSV format to file:"), msg);
return -2; return -2;
} }
char buf[1024];
snprintf(buf, sizeof(buf), _("%u cells written"), count); snprintf(buf, sizeof(buf), _("%u cells written"), count);
if (!batch) line_msg(_("Save in CSV format to file:"), buf); if (!batch) line_msg(_("Save in CSV format to file:"), buf);
return -1; return -1;
@ -749,6 +714,7 @@ static int do_loadxdr(Sheet *cursheet)
return -1; return -1;
} }
/*}}}*/ /*}}}*/
/* do_loadport -- load sheet from portable ASCII file */ /*{{{*/ /* do_loadport -- load sheet from portable ASCII file */ /*{{{*/
static int do_loadport(Sheet *cursheet) static int do_loadport(Sheet *cursheet)
{ {
@ -858,6 +824,7 @@ void do_mark(Sheet *cursheet, MarkState ms)
/*}}}*/ /*}}}*/
static int do_name(Sheet *cursheet); static int do_name(Sheet *cursheet);
/* do_save -- save sheet */ /*{{{*/ /* do_save -- save sheet */ /*{{{*/
static int do_save(Sheet *cursheet) static int do_save(Sheet *cursheet)
{ {
@ -866,22 +833,22 @@ static int do_save(Sheet *cursheet)
ext += strlen(ext)-1; 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-3, ".tbl")) return do_savetbl(cursheet, NULL);
if (!strcmp(ext-5, ".latex")) return do_savelatex(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-4, ".html")) return do_savehtml(cursheet, NULL);
if (!strcmp(ext-3, ".csv")) return do_savecsv(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, ".txt")) return do_savetext(cursheet, NULL);
if (!strcmp(ext-3, ".tex")) return do_savecontext(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 */ /*{{{*/ /* do_name -- (re)name sheet */ /*{{{*/
static int do_name(Sheet *cursheet) static int do_name(Sheet *cursheet)
{ {
const char *name; 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 (!name) return -1;
if (cursheet->name!=(char*)0) free(cursheet->name); if (cursheet->name!=(char*)0) free(cursheet->name);
@ -889,6 +856,7 @@ static int do_name(Sheet *cursheet)
return do_save(cursheet); return do_save(cursheet);
} }
/*}}}*/ /*}}}*/
/* do_load -- load sheet */ /*{{{*/ /* do_load -- load sheet */ /*{{{*/
static int do_load(Sheet *cursheet) 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; 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 (!name) return -1;
if (cursheet->name!=(char*)0) free(cursheet->name); if (cursheet->name!=(char*)0) free(cursheet->name);
cursheet->name=strdup(name); cursheet->name=strdup(name);
ext = name+strlen(name)-1; 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-2, ".sc")) return do_loadsc(cursheet);
if (!strcmp(ext-3, ".wk1")) return do_loadwk1(cursheet); if (!strcmp(ext-3, ".wk1")) return do_loadwk1(cursheet);
if (!strcmp(ext-3, ".csv")) return do_loadcsv(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 */ /*{{{*/ /* do_insert -- insert block */ /*{{{*/
static int do_insert(Sheet *sheet) static int do_insert(Sheet *sheet)
{ {
/* variables */ /*{{{*/
int reply; int reply;
bool onecell;
Location beg, end;
/*}}}*/
/* ask for direction of insertion */ /*{{{*/ /* ask for direction of insertion */ /*{{{*/
{ {
MenuChoice menu[4]; const char* menu[] =
{ _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL };
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); reply = line_menu(_("Insert:"), menu, 0);
if (reply<0) return reply; if (reply<0) return reply;
} }
/*}}}*/ /*}}}*/
do_mark(sheet, GET_MARK_CUR); do_mark(sheet, GET_MARK_CUR);
Location beg, end;
LOCATION_GETS(beg, sheet->mark1); LOCATION_GETS(beg, sheet->mark1);
LOCATION_GETS(end, sheet->mark2); LOCATION_GETS(end, sheet->mark2);
onecell = SAME_LOC(beg, end); bool onecell = SAME_LOC(beg, end);
if (onecell) if (onecell)
/* ask if current cell or whole dimension should be used */ /*{{{*/ /* ask if current cell or whole dimension should be used */ /*{{{*/
{ {
/* variables */ /*{{{*/ const char *menu[3];
MenuChoice menu[3];
int r;
/*}}}*/
/* show menu */ /*{{{*/ /* show menu */ /*{{{*/
switch (reply) switch (reply)
{ {
case 0: menu[0].str = _("wW)hole column"); break; case 0: menu[0] = _("wW)hole column"); break;
case 1: menu[0].str = _("wW)hole line"); break; case 1: menu[0] = _("wW)hole line"); break;
case 2: menu[0].str = _("wW)hole sheet"); break; case 2: menu[0] = _("wW)hole sheet"); break;
default: assert(0); default: assert(0);
} }
menu[1].str = _("sS)ingle cell"); menu[1].c='\0'; menu[1] = _("sS)ingle cell");
menu[2].str = (char*)0; menu[2] = NULL;
r=line_menu(_("Insert:"),menu,0); int r = line_menu(_("Insert:"), menu, 0);
/*}}}*/ /*}}}*/
switch (r) switch (r)
{ {
@ -1053,49 +1015,39 @@ static int do_insert(Sheet *sheet)
/* do_delete -- delete block */ /*{{{*/ /* do_delete -- delete block */ /*{{{*/
static int do_delete(Sheet *sheet) static int do_delete(Sheet *sheet)
{ {
/* variables */ /*{{{*/
int reply; int reply;
bool onecell;
Location beg, end;
/*}}}*/
firstmenu: firstmenu:
/* ask for direction of deletion */ /*{{{*/ /* ask for direction of deletion */ /*{{{*/
{ {
MenuChoice menu[4]; const char* menu[] =
{ _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL };
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); reply = line_menu(_("Delete:"), menu, 0);
if (reply < 0) return reply; if (reply < 0) return reply;
} }
/*}}}*/ /*}}}*/
do_mark(sheet, GET_MARK_CUR); do_mark(sheet, GET_MARK_CUR);
Location beg, end;
LOCATION_GETS(beg, sheet->mark1); LOCATION_GETS(beg, sheet->mark1);
LOCATION_GETS(end, sheet->mark2); LOCATION_GETS(end, sheet->mark2);
onecell = SAME_LOC(beg, end); bool onecell = SAME_LOC(beg, end);
if (onecell) if (onecell)
/* ask if range is the current cell or whole dimension should be used */ /*{{{*/ /* ask if range is the current cell or whole dimension should be used */ /*{{{*/
{ {
/* variables */ /*{{{*/ const char *menu[3];
MenuChoice menu[3];
int r;
/*}}}*/
/* show menu */ /*{{{*/ /* show menu */ /*{{{*/
switch (reply) switch (reply)
{ {
case 0: menu[0].str = _("wW)hole column"); break; case 0: menu[0] = _("wW)hole column"); break;
case 1: menu[0].str = _("wW)hole line"); break; case 1: menu[0] = _("wW)hole line"); break;
case 2: menu[0].str = _("wW)hole sheet"); break; case 2: menu[0] = _("wW)hole sheet"); break;
default: assert(0); default: assert(0);
} }
menu[1].str = _("sS)ingle cell"); menu[1].c='\0'; menu[1] = _("sS)ingle cell");
menu[2].str=(char*)0; menu[2] = NULL;
r=line_menu(_("Delete:"),menu,0); int r = line_menu(_("Delete:"), menu, 0);
/*}}}*/ /*}}}*/
switch (r) switch (r)
{ {
@ -1164,6 +1116,7 @@ static int do_delete(Sheet *sheet)
return -1; return -1;
} }
/*}}}*/ /*}}}*/
/* do_move -- copy or move a block */ /*{{{*/ /* do_move -- copy or move a block */ /*{{{*/
static int do_move(Sheet *sheet, int copy, int force) static int do_move(Sheet *sheet, int copy, int force)
{ {
@ -1250,7 +1203,6 @@ void fillwith(Sheet *she)
static int do_sort(Sheet *sheet) static int do_sort(Sheet *sheet)
{ {
/* variables */ /*{{{*/ /* variables */ /*{{{*/
MenuChoice menu1[4],menu2[3],menu3[3];
Sortkey sk[MAX_SORTKEYS]; Sortkey sk[MAX_SORTKEYS];
unsigned int key; unsigned int key;
size_t x,offx; size_t x,offx;
@ -1263,17 +1215,13 @@ static int do_sort(Sheet *sheet)
/*}}}*/ /*}}}*/
do_mark(sheet, GET_MARK_ALL); do_mark(sheet, GET_MARK_ALL);
/* build menues */ /*{{{*/ /* build menus */ /*{{{*/
menu1[0].str=strdup(_("cC)olumn")); menu1[0].c='\0'; const char* menu1[] =
menu1[1].str=strdup(_("rR)ow")); menu1[1].c='\0'; { _("cC)olumn"), _("rR)ow"), _("dD)epth"), NULL };
menu1[2].str=strdup(_("dD)epth")); menu1[2].c='\0'; const char* menu2[] =
menu1[3].str=(char*)0; { _("sS)ort region"), _("aA)dd key"), NULL };
menu2[0].str=strdup(_("sS)ort region")); menu2[0].c='\0'; const char* menu3[] =
menu2[1].str=strdup(_("aA)dd key")); menu2[1].c='\0'; { _("aA)scending"), _("dD)escending"), NULL };
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;
/*}}}*/ /*}}}*/
last = -1; last = -1;
@ -1431,17 +1379,6 @@ static int do_sort(Sheet *sheet)
c=-1; c=-1;
if ((msg=sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key))!=(const char*)0) line_msg(_("Sort block:"),msg); if ((msg=sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key))!=(const char*)0) line_msg(_("Sort block:"),msg);
greak: 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; return c;
} }
/*}}}*/ /*}}}*/
@ -1482,12 +1419,8 @@ static int do_mirror(Sheet *sheet)
do_mark(sheet, GET_MARK_ALL); do_mark(sheet, GET_MARK_ALL);
/* ask for direction of mirroring */ /*{{{*/ /* ask for direction of mirroring */ /*{{{*/
{ {
MenuChoice menu[4]; const char *menu[] =
{ _("lL)eft-right"), _("uU)pside-down"), _("fF)ront-back"), NULL};
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); reply = line_menu(_("Mirror block:"), menu, 0);
if (reply < 0) return reply; if (reply < 0) return reply;
} }
@ -1563,7 +1496,10 @@ int do_sheetcmd(Sheet *cursheet, Key c, int moveonly)
case ADJUST_LEFT: case ADJUST_LEFT:
case ADJUST_RIGHT: case ADJUST_RIGHT:
case ADJUST_CENTER: case ADJUST_CENTER:
case ADJUST_DECIMAL:
case ADJUST_SCIENTIFIC: case ADJUST_SCIENTIFIC:
case ADJUST_COMPACT:
case ADJUST_HEXACT:
case ADJUST_PRECISION: case ADJUST_PRECISION:
case ADJUST_SHADOW: case ADJUST_SHADOW:
case ADJUST_BOLD: case ADJUST_BOLD:
@ -1837,15 +1773,8 @@ int main(int argc, char *argv[])
find_helpfile(helpfile, sizeof(helpfile), argv[0]); find_helpfile(helpfile, sizeof(helpfile), argv[0]);
/* parse options */ /*{{{*/ /* 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 */ /*{{{*/ /* b -- run batch */ /*{{{*/
case 'b': batch = true; break; case 'b': batch = true; break;
/*}}}*/ /*}}}*/
@ -1853,10 +1782,10 @@ int main(int argc, char *argv[])
case 'd': ++debug_level; break; case 'd': ++debug_level; break;
/*}}}*/ /*}}}*/
/* n -- no quoted strings */ /*{{{*/ /* n -- no quoted strings */ /*{{{*/
case 'n': quote = false; break; case 'n': quote = DIRECT_STRING; break;
/*}}}*/ /*}}}*/
/* q -- force quoted strings */ /*{{{*/ /* q -- force quoted strings */ /*{{{*/
case 'q': quote = true; break; case 'q': quote = QUOTE_STRING; break;
/*}}}*/ /*}}}*/
/* H -- no row/column headers */ /*{{{*/ /* H -- no row/column headers */ /*{{{*/
case 'H': header = false; break; case 'H': header = false; break;
@ -1914,12 +1843,12 @@ int main(int argc, char *argv[])
cursheet->name=strdup(loadfile); cursheet->name=strdup(loadfile);
if (usexdr) 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 else
{ if ((msg=loadport(cursheet, cursheet->name)) != NULL)
if ((msg=loadport(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from ASCII file:"),msg); line_msg(_("Load sheet from ASCII file:"),msg);
}
} }
/*}}}*/ /*}}}*/
if (batch) /* process batch */ /*{{{*/ if (batch) /* process batch */ /*{{{*/

View File

@ -13,7 +13,7 @@ extern "C" {
extern bool batch; extern bool batch;
extern int def_precision; extern int def_precision;
extern bool quote; extern StringFormat quote;
extern bool header; extern bool header;
extern int debug_level; extern int debug_level;
extern bool always_redraw; extern bool always_redraw;
@ -82,7 +82,10 @@ typedef enum {
K_HELP = -55, K_HELP = -55,
K_DUMPCELL = -56, K_DUMPCELL = -56,
ADJUST_UNDERLINE = -57, ADJUST_UNDERLINE = -57,
FILL_BLOCK = -58 FILL_BLOCK = -58,
ADJUST_DECIMAL = -59,
ADJUST_COMPACT = -60,
ADJUST_HEXACT = -61
} Key; } Key;
extern int do_sheetcmd(Sheet *cursheet, Key c, int moveonly); extern int do_sheetcmd(Sheet *cursheet, Key c, int moveonly);

View File

@ -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'); col=(colstr[0]-'A'); if (colstr[1]) col=col*26+(colstr[1]-'A');
OLOCATION(tmp); OLOCATION(tmp);
tmp[X] = col; tmp[X] = col;
cell = initcellofsheet(sheet, tmp); cell = initcellofsheet(sheet, tmp, NULL);
cell->adjust = RIGHT; cell->adjust = RIGHT;
cell->precision = precision; cell->precision = precision;
setwidth(sheet, col, 0, colwidth); setwidth(sheet, col, 0, colwidth);
@ -263,7 +263,7 @@ const char *loadsc(Sheet *sheet, const char *name)
goto eek; goto eek;
} }
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0; 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->adjust = strncmp(buf, "leftstring ", 11) ? RIGHT : LEFT;
cell->tok[BASE_CONT] = eval_safe(contents, LITERAL); cell->tok[BASE_CONT] = eval_safe(contents, LITERAL);
tvecfree(contents); tvecfree(contents);
@ -313,7 +313,7 @@ const char *loadsc(Sheet *sheet, const char *name)
goto eek; goto eek;
} }
tmp[X] = x; tmp[Y] = y; tmp[Z] = 0; tmp[X] = x; tmp[Y] = y; tmp[Z] = 0;
cell = initcellofsheet(sheet, tmp); cell = initcellofsheet(sheet, tmp, NULL);
cell->adjust = RIGHT; cell->adjust = RIGHT;
cell->tok[BASE_CONT] = eval_safe(contents, LITERAL); cell->tok[BASE_CONT] = eval_safe(contents, LITERAL);
tvecfree(contents); tvecfree(contents);

View File

@ -12,10 +12,6 @@
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <float.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
extern char *strdup(const char* s); extern char *strdup(const char* s);
extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */ extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
extern long double strtold(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 "func.h"
#include "main.h" #include "main.h"
#include "misc.h" #include "misc.h"
#include "utf8.h"
#include "scanner.h" #include "scanner.h"
/*}}}*/ /*}}}*/
@ -262,197 +257,3 @@ Token **scan(const char **s)
return na; 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 && cur<size) dest[cur++] = '"';
for (;cur<size && *str != '\0'; ++str)
{
if (quote_strings && (*str == '"' || *str=='\\')) dest[cur++] = '\\';
if (cur<size) dest[cur++]=*str;
}
if (quote_strings && cur<size) dest[cur++] = '"';
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[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(len<sizeof(buf));
if (!use_sci)
{
p=&buf[len-1];
while (p>buf && *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<size) dest[cur] = 0;
else
{
dest[size-1] = 0;
cur = size;
}
if (field_width && mbslen(dest) > field_width) {
for (cur = 0; cur < field_width; ++cur) dest[cur] = '#';
dest[cur] = 0;
}
return cur;
}
/*}}}*/
/* 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<size-1 && (*n) != NULLTOKEN; ++n)
cur += printtok(s+cur, size-cur, 0, quote, scientific, precision, 0, *n);
if (cur<size) s[cur] = 0;
else s[size-1] = 0;
if (chars && mbslen(s) > chars) {
for (cur=0; cur < chars; ++cur) s[cur] = '#';
s[cur] = 0;
}
}
/*}}}*/

View File

@ -66,6 +66,8 @@ typedef long double FltT;
*/ */
#define FLT_T_STD_FMT "%.*Lf" #define FLT_T_STD_FMT "%.*Lf"
#define FLT_T_SCI_FMT "%.*Le" #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 FLT_T_DIG LDBL_DIG
#define FLTEPS LDBL_EPSILON #define FLTEPS LDBL_EPSILON
#define FLTMX LDBL_MAX #define FLTMX LDBL_MAX
@ -98,6 +100,8 @@ typedef double FltT;
*/ */
#define FLT_T_STD_FMT "%.*f" #define FLT_T_STD_FMT "%.*f"
#define FLT_T_SCI_FMT "%.*e" #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 FLT_T_DIG DBL_DIG
#define FLTEPS DBL_EPSILON #define FLTEPS DBL_EPSILON
#define FLTMX DBL_MAX #define FLTMX DBL_MAX
@ -165,10 +169,6 @@ typedef struct Token_struc
Token duperror(Token* tok, const char* erro); Token duperror(Token* tok, const char* erro);
Token **scan(const char **s); Token **scan(const char **s);
void cleartoken(Token* tok); 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 #ifdef __cplusplus
} }

View File

@ -57,8 +57,8 @@ void copycelltosheet(const Cell *fromcell, Sheet *sheet2,
if (fromcell != NULLCELL) if (fromcell != NULLCELL)
/* copy first cell to second */ /*{{{*/ /* copy first cell to second */ /*{{{*/
{ {
sheet2->changed = 1; sheet2->changed = true;
Cell *alsotocell = initcellofsheet(sheet2, to); Cell *alsotocell = initcellofsheet(sheet2, to, NULL);
assert(tocell == NULLCELL || tocell == alsotocell); assert(tocell == NULLCELL || tocell == alsotocell);
copycell(alsotocell, fromcell, lh); 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"); if (c->label == NULL) printf("\n No label.\n");
else printf("\n Label: %s.\n", c->label); else printf("\n Label: %s.\n", c->label);
switch (c->adjust) { printf(" Adjustment: %s.\n", Adjust_Name[c->adjust]);
case LEFT: printf("LEFT\n"); break; printf(" Float format: %s.\n", FloatFormat_Name[c->fform]);
case RIGHT: printf("RIGHT\n"); break;
case CENTER: printf("CENTER\n"); break;
case AUTOADJUST: printf("AUTO\n"); break;
}
printf(" Precision: %d\n Attributes: ", c->precision); printf(" Precision: %d\n Attributes: ", c->precision);
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca) for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
printf(" %s color: %d\n", ColorAspect_Name[ca], c->aspect[ca]); printf(" %s color: %d\n", ColorAspect_Name[ca], c->aspect[ca]);
if (c->updated) printf("updated "); if (c->updated) printf("updated ");
if (c->shadowed) printf("shadowed "); if (c->shadowed) printf("shadowed ");
if (c->scientific) printf("scientific ");
if (c->locked) printf("locked "); if (c->locked) printf("locked ");
if (c->transparent) printf("transparent "); if (c->transparent) printf("transparent ");
if (c->ignored) printf("ignored "); 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(sheet1!=(Sheet*)0);
assert(sheet2!=(Sheet*)0); assert(sheet2!=(Sheet*)0);
resize(sheet1,x1+xdist-1,y1+ydist-1,z1+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); resize(sheet2, x2+xdist-1, y2+ydist-1, z2+zdist-1, NULL);
for (xoff=0; xoff<xdist; ++xoff) for (xoff=0; xoff<xdist; ++xoff)
for (yoff=0; yoff<ydist; ++yoff) for (yoff=0; yoff<ydist; ++yoff)
for (zoff=0; zoff<zdist; ++zoff) for (zoff=0; zoff<zdist; ++zoff)
@ -151,8 +146,8 @@ static void swapblock(Sheet *sheet1, int x1, int y1, int z1, Sheet *sheet2, int
CELL_ATC(sheet1,x1+xoff,y1+yoff,z1+zoff) = CELL_ATC(sheet2,x2+xoff,y2+yoff,z2+zoff); CELL_ATC(sheet1,x1+xoff,y1+yoff,z1+zoff) = CELL_ATC(sheet2,x2+xoff,y2+yoff,z2+zoff);
CELL_ATC(sheet2,x2+xoff,y2+yoff,z2+zoff) = t; CELL_ATC(sheet2,x2+xoff,y2+yoff,z2+zoff) = t;
} }
sheet1->changed=1; sheet1->changed = true;
sheet2->changed=1; sheet2->changed = true;
} }
/*}}}*/ /*}}}*/
@ -257,7 +252,7 @@ void initialize_sheet(Sheet *sheet) {
/*}}}*/ /*}}}*/
/* resize -- check if sheet needs to be resized in any dimension */ /*{{{*/ /* 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(x>=0);
assert(y>=0); assert(y>=0);
@ -270,7 +265,8 @@ void resize(Sheet *sheet, int x, int y, int z)
Sheet dummy; Sheet dummy;
/*}}}*/ /*}}}*/
sheet->changed=1; sheet->changed = true;
if (qextended) *qextended = true;
dummy.dimx = (x >= sheet->dimx ? x+1 : sheet->dimx); dummy.dimx = (x >= sheet->dimx ? x+1 : sheet->dimx);
dummy.dimy = (y >= sheet->dimy ? y+1 : sheet->dimy); dummy.dimy = (y >= sheet->dimy ? y+1 : sheet->dimy);
dummy.dimz = (z >= sheet->dimz ? z+1 : sheet->dimz); 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 */ /*{{{*/ /* 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; Cell *nc;
assert(IN_OCTANT(at)); 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); nc = CELL_AT(sheet,at);
if (nc == NULLCELL) if (nc == NULLCELL)
{ {
sheet->changed = 1; sheet->changed = true;
if (qnew) *qnew = true;
nc = malloc(sizeof(Cell)); nc = malloc(sizeof(Cell));
CELL_AT(sheet,at) = nc; CELL_AT(sheet,at) = nc;
initcellcontents(nc); initcellcontents(nc);
@ -492,15 +489,24 @@ int columnwidth(Sheet *sheet, int x, int z)
else return DEF_COLUMNWIDTH; else return DEF_COLUMNWIDTH;
} }
/*}}}*/ /*}}}*/
/* setwidth -- set width of column */ /*{{{*/ /* 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); assert(sheet!=(Sheet*)0);
resize(sheet,x,1,z); bool isbigger = false;
sheet->changed=1; resize(sheet, x, 1, z, &isbigger);
*(sheet->column+x*sheet->dimz+z)=width; 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 */ /*{{{*/ /* cellwidth -- get width of a cell */ /*{{{*/
int cellwidth(Sheet *sheet, const Location at) 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); assert(sheet != (Sheet*)0);
sheet->changed = 1; sheet->changed = 1;
cell = initcellofsheet(sheet, at); cell = initcellofsheet(sheet, at, NULL);
tfree(&(cell->tok[v])); tfree(&(cell->tok[v]));
cell->tok[v] = t; cell->tok[v] = t;
redraw_cell(sheet, at); redraw_cell(sheet, at);
@ -672,77 +678,42 @@ char *geterror(Sheet *sheet, const Location at)
/*}}}*/ /*}}}*/
/* printvalue -- get ASCII representation of value */ /*{{{*/ /* 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); assert(sheet != (Sheet*)0);
Token t = recompvalue(sheet, at); 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); tfree(&t);
} }
/*}}}*/ /*}}}*/
/* setadjust -- set cell adjustment */ /*{{{*/ /* The cell field setters all have nearly identical code, so: */
void setadjust(Sheet *sheet, const Location at, Adjust adjust)
{
assert(sheet != (Sheet*)0);
sheet->changed = 1;
initcellofsheet(sheet, at)->adjust = adjust;
}
/*}}}*/
/* shadow -- shadow cell by left neighbour */ /*{{{*/ #define DEFSETTER(funcname,argtype,field) bool\
void shadow(Sheet *sheet, const Location at, int yep) funcname(Sheet *sheet, const Location at, argtype arg)\
{ {\
assert(sheet != (Sheet*)0); assert(sheet != (Sheet*)0);\
sheet->changed = 1; bool isnew = false;\
initcellofsheet(sheet, at)->shadowed = yep; 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 */ /*{{{*/ DEFSETTER(setadjust, Adjust, adjust);
void bold(Sheet *sheet, const Location at, int yep) DEFSETTER(shadow, bool, shadowed);
{ DEFSETTER(bold, bool, bold);
assert(sheet != (Sheet*)0); DEFSETTER(underline, bool, underline);
sheet->changed = 1; DEFSETTER(lockcell, bool, locked);
initcellofsheet(sheet,at)->bold = yep; DEFSETTER(maketrans, bool, transparent);
} DEFSETTER(igncell, bool, ignored);
/*}}}*/ DEFSETTER(setfltformat, FloatFormat, fform);
DEFSETTER(setprecision, int, precision);
/* 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;
}
/*}}}*/
/* clk -- clock cell */ /*{{{*/ /* clk -- clock cell */ /*{{{*/
void clk(Sheet *sheet, const Location at) 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 */ /*{{{*/ /* getmarkstate -- find out where in the marking cycle the sheet is */ /*{{{*/
MarkState getmarkstate(Sheet *sheet) { MarkState getmarkstate(Sheet *sheet) {
if (sheet == (Sheet*)0) return MARK_CYCLE; 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); assert(sheet != (Sheet*)0);
sheet->changed = 1; sheet->changed = 1;
cell = initcellofsheet(sheet, at); cell = initcellofsheet(sheet, at, NULL);
if (cell->label != (char*)0) free(cell->label); if (cell->label != (char*)0) free(cell->label);
if (*buf == '\0') cell->label = (char*)0; if (*buf == '\0') cell->label = (char*)0;
else cell->label = strcpy(malloc(strlen(buf)+1), buf); 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; char *bufp;
printvalue(buf, sizeof(buf), 0, 0, getscientific(cw), printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cw),
getprecision(cw), sheet, w); getprecision(cw), sheet, w);
if (transparent(cw)) if (transparent(cw))
{ {
@ -1042,8 +995,8 @@ const char *savetext(Sheet *sheet, const char *name,
char *buf; char *buf;
buf = malloc(size*UTF8SZ+1); buf = malloc(size*UTF8SZ+1);
printvalue(buf, size*UTF8SZ+1, size, 0, getscientific(cw), printvalue(buf, size*UTF8SZ + 1, size, DIRECT_STRING,
getprecision(cw), sheet, w); getfltformat(cw), getprecision(cw), sheet, w);
adjust(getadjust(cw), buf, size); adjust(getadjust(cw), buf, size);
if (fputs_close(buf,fp)==EOF) 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); Cell *cw = CELL_AT(sheet,w);
if (cw != NULLCELL) 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); char *buf = malloc(bufsz);
printvalue(buf, bufsz, 255, 0, getscientific(cw), printvalue(buf, bufsz, bufchar, DIRECT_STRING, getfltformat(cw),
getprecision(cw), sheet, w); getprecision(cw), sheet, w);
bool needquote = !transparent(cw) bool needquote = !transparent(cw)
&& (strlen(buf) != strcspn(buf, "\",\n\r")); && (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); fprintf(fp,"C%d %d %d ",x,y,z);
if (cell->adjust != AUTOADJUST) if (cell->adjust != AUTOADJUST)
fprintf(fp,"A%c ","lrc"[cell->adjust]); fprintf(fp, "A%c ", Adjust_Char[cell->adjust]);
if (cell->label) fprintf(fp, "L%s ", cell->label); if (cell->label) fprintf(fp, "L%s ", cell->label);
if (cell->precision != -1) if (cell->precision != -1)
fprintf(fp,"P%d ", cell->precision); fprintf(fp,"P%d ", cell->precision);
if (cell->fform != DEF_FLOATFORM)
fprintf(fp,"F%c ", FloatFormat_Char[cell->fform]);
bool needscolor = false; bool needscolor = false;
for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a) for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a)
if (cell->aspect[a] != DefaultCN[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->shadowed) fprintf(fp,"S ");
if (cell->bold) fprintf(fp,"B "); if (cell->bold) fprintf(fp,"B ");
if (cell->underline) fprintf(fp,"U "); if (cell->underline) fprintf(fp,"U ");
if (cell->scientific != DEF_SCIENTIFIC) fprintf(fp,"E ");
if (cell->locked) fprintf(fp, "K "); if (cell->locked) fprintf(fp, "K ");
if (cell->transparent) fprintf(fp,"T "); if (cell->transparent) fprintf(fp,"T ");
if (cell->ignored) fprintf(fp, "I "); 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) for (TokVariety v = BASE_CONT; v <= lastv; ++v)
{ {
if (v == BASE_CONT && cell->tok[v].type == EMPTY) continue; 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) if (fputs_close(saveport_contentleader[v], fp) == EOF)
return strerror(errno); return strerror(errno);
printtok(buf, sizeof(buf), 0, 1, cell->scientific, size_t used = printtok(buf, bl, 0, QUOTE_STRING, FLT_HEXACT,
cell->precision, 0, cell->tok + v); -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 (fputs_close(buf, fp) == EOF) return strerror(errno);
} }
if (fputc_close('\n', fp) == EOF) return strerror(errno); if (fputc_close('\n', fp) == EOF) return strerror(errno);
++(*count);
} }
} }
} }
} }
if (fclose(fp) == EOF) return strerror(errno); if (fclose(fp) == EOF) return strerror(errno);
sheet->changed = false;
return (const char*)0; return (const char*)0;
} }
/*}}}*/ /*}}}*/
@ -1285,15 +1244,34 @@ const char *loadport(Sheet *sheet, const char *name)
case 'A': case 'A':
{ {
++ns; ++ns;
switch (*ns) const char *found = strchr(Adjust_Char, *ns);
if (found != NULL)
{ {
case 'l': loaded.adjust=LEFT; ++ns; break; loaded.adjust = (Adjust)(found - Adjust_Char);
case 'r': loaded.adjust=RIGHT; ++ns; break; ++ns;
case 'c': loaded.adjust=CENTER; ++ns; break;
default: sprintf(errbuf,_("Parse error for adjustment in line %d"),line); err=errbuf; goto eek;
}
break; 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 */ /*{{{*/ /* L -- label */ /*{{{*/
case 'L': case 'L':
@ -1395,11 +1373,11 @@ const char *loadport(Sheet *sheet, const char *name)
break; break;
} }
/*}}}*/ /*}}}*/
/* E -- scientific */ /*{{{*/ /* E -- scientific, for backward compatibility */ /*{{{*/
case 'E': case 'E':
{ {
++ns; ++ns;
loaded.scientific=1; loaded.fform = FLT_SCIENTIFIC;
break; break;
} }
/*}}}*/ /*}}}*/
@ -1528,10 +1506,14 @@ const char *loadport(Sheet *sheet, const char *name)
++line; ++line;
} }
eek: eek:
if (fclose(fp)==EOF && err==(const char*)0) err=strerror(errno); if (fclose(fp) == EOF) {
sheet->changed=0; if (err == (const char*)0) err=strerror(errno);
} else {
sheet->changed = false;
}
cachelabels(sheet); cachelabels(sheet);
forceupdate(sheet); forceupdate(sheet);
redraw_sheet(sheet);
return err; return err;
} }
/*}}}*/ /*}}}*/
@ -1641,7 +1623,7 @@ void insertcube(Sheet *sheet, const Location beg, const Location end,
right=sheet->dimx+end[X]-beg[X]; 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) 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,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; 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]; 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) 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,z) = CELL_ATC(sheet,x,y-(end[Y]-beg[Y]+1),z);
CELL_ATC(sheet,x,y-(end[Y]-beg[Y]+1),z) = NULLCELL; 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]; 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) 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) = CELL_ATC(sheet,x,y,z-(end[Z]-beg[Z]+1));
CELL_ATC(sheet,x,y,z-(end[Z]-beg[Z]+1)) = NULLCELL; 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); copycelltosheet(CELL_AT(sheet, get), sheet, go, ALTER_LABEL);
else 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, go) = CELL_AT(sheet, get);
CELL_AT(sheet, get) = NULLCELL; CELL_AT(sheet, get) = NULLCELL;
} }
} }
sheet->changed=1; sheet->changed = TRUE;
cachelabels(sheet); cachelabels(sheet);
forceupdate(sheet); forceupdate(sheet);
} }

View File

@ -73,8 +73,8 @@ extern Location upd_l;
extern int max_eval; extern int max_eval;
void initialize_sheet(Sheet *sheet); void initialize_sheet(Sheet *sheet);
void resize(Sheet *sheet, int x, int y, int z); void resize(Sheet *sheet, int x, int y, int z, bool *qextended);
Cell *initcellofsheet(Sheet *sheet, const Location at); Cell *initcellofsheet(Sheet *sheet, const Location at, bool *qnew);
void copycelltosheet(const Cell *fromcell, Sheet *sheet2, void copycelltosheet(const Cell *fromcell, Sheet *sheet2,
const Location to, LabelHandling lh); const Location to, LabelHandling lh);
Cell *safe_cell_at(Sheet *sheet, const Location at); Cell *safe_cell_at(Sheet *sheet, const Location at);
@ -87,23 +87,24 @@ MarkState getmarkstate(Sheet *sheet);
void dump_current_cell(Sheet *sheet); void dump_current_cell(Sheet *sheet);
void freecellofsheet(Sheet *sheet, const Location at); void freecellofsheet(Sheet *sheet, const Location at);
int columnwidth(Sheet *sheet, int x, int z); 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); int cellwidth(Sheet *sheet, const Location at);
void puttok(Sheet *sheet, const Location at, Token t, TokVariety v); void puttok(Sheet *sheet, const Location at, Token t, TokVariety v);
Token recompvalue(Sheet *sheet, const Location at); Token recompvalue(Sheet *sheet, const Location at);
void update(Sheet *sheet); void update(Sheet *sheet);
char *geterror(Sheet *sheet, const Location at); 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 printvalue(char *s, size_t size, size_t chars, StringFormat sf,
void setadjust(Sheet *sheet, const Location at, Adjust adjust); FloatFormat ff, int precision, Sheet *sheet, const Location at);
void shadow(Sheet *sheet, const Location at, int yep); bool setadjust(Sheet *sheet, const Location at, Adjust adjust);
void bold(Sheet *sheet, const Location at, int yep); bool shadow(Sheet *sheet, const Location at, bool yep);
void underline(Sheet *sheet, const Location at, int yep); bool bold(Sheet *sheet, const Location at, bool yep);
void lockcell(Sheet *sheet, const Location at, int yep); bool underline(Sheet *sheet, const Location at, bool yep);
void maketrans(Sheet *sheet, const Location at, int yep); bool lockcell(Sheet *sheet, const Location at, bool yep);
void igncell(Sheet *sheet, const Location at, int 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 clk(Sheet *sheet, const Location at);
void setscientific(Sheet *sheet, const Location at, int yep); bool setfltformat(Sheet *sheet, const Location at, FloatFormat ff);
void setprecision(Sheet *sheet, const Location at, int precision); bool setprecision(Sheet *sheet, const Location at, int precision);
void setlabel(Sheet *sheet, const Location at, const char *buf, int update); void setlabel(Sheet *sheet, const Location at, const char *buf, int update);
Token findlabel(Sheet *sheet, const char *label); Token findlabel(Sheet *sheet, const char *label);
void relabel(Sheet* sheet, const Location at, void relabel(Sheet* sheet, const Location at,

View File

@ -94,14 +94,14 @@ static void format(unsigned char s, Cell *cell)
case 0: /* fixed with given precision */ /*{{{*/ case 0: /* fixed with given precision */ /*{{{*/
{ {
cell->precision = s&0x0f; cell->precision = s&0x0f;
cell->scientific=0; cell->fform = FLT_DECIMAL;
break; break;
} }
/*}}}*/ /*}}}*/
case 1: /* scientifix with given presision */ /*{{{*/ case 1: /* scientifix with given presision */ /*{{{*/
{ {
cell->precision = s&0x0f; cell->precision = s&0x0f;
cell->scientific=1; cell->fform = FLT_SCIENTIFIC;
break; break;
} }
/*}}}*/ /*}}}*/
@ -797,7 +797,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
case 0x6: case 0x6:
{ {
if (bodylen!=8) { err=_("Invalid record body length"); goto ouch; } 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)) */ /* range is from &(it(body),it(body+2)) to &(it(body+4),it(body+6)) */
break; break;
} }
@ -843,7 +843,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
{ {
if (bodylen!=5) { err=_("Invalid record body length"); goto ouch; } if (bodylen!=5) { err=_("Invalid record body length"); goto ouch; }
tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; 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); format((unsigned char)body[0], cell);
break; break;
} }
@ -855,7 +855,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
assert(bodylen == 7); assert(bodylen == 7);
tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; 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.type = INT;
t.u.integer = it(body+5); t.u.integer = it(body+5);
puttok(sheet, tmp, t, BASE_CONT); puttok(sheet, tmp, t, BASE_CONT);
@ -870,7 +870,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
assert(bodylen == 13); assert(bodylen == 13);
tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; 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.type = FLOAT;
t.u.flt = dbl((unsigned char*)body+5); t.u.flt = dbl((unsigned char*)body+5);
puttok(sheet, tmp, t, BASE_CONT); puttok(sheet, tmp, t, BASE_CONT);
@ -885,7 +885,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
assert(bodylen >= 6 && bodylen <= 245); assert(bodylen >= 6 && bodylen <= 245);
tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; 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.type = STRING;
t.u.string = strdup(body+6); t.u.string = strdup(body+6);
puttok(sheet, tmp, t, BASE_CONT); puttok(sheet, tmp, t, BASE_CONT);
@ -985,7 +985,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
#endif #endif
free(offset); free(offset);
tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; 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].type = FLOAT;
cell->tok[CURR_VAL].u.flt = dbl((unsigned char*)body+5); cell->tok[CURR_VAL].u.flt = dbl((unsigned char*)body+5);
puttok(sheet, tmp, tok, BASE_CONT); puttok(sheet, tmp, tok, BASE_CONT);
@ -1103,7 +1103,7 @@ const char *loadwk1(Sheet *sheet, const char *name)
assert(bodylen>=6 && bodylen<=245); assert(bodylen>=6 && bodylen<=245);
tmp[X] = it(body+1); tmp[Y] = it(body+3); tmp[Z] = 0; 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.type = STRING;
t.u.string = strdup(body+5); t.u.string = strdup(body+5);
puttok(sheet, tmp, t, BASE_CONT); puttok(sheet, tmp, t, BASE_CONT);

View File

@ -241,11 +241,19 @@ bool_t xdr_cell(XDR *xdrs, Cell *cell)
cell->adjust = x; cell->adjust = x;
if (result==0) return 0; if (result==0) return 0;
if (xdr_int(xdrs, &(cell->precision))==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); 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); result = xdr_int(xdrs, &x);
cell->updated=((x&(1))!=0); /* cell->updated = ((x&(1))!=0); # Makes no sense to restore this */
cell->shadowed = ((x & (1<<1)) != 0); cell->shadowed = ((x & (1<<1)) != 0);
cell->scientific=((x&(1<<2))!=0); if ((x & (1<<2)) !=0 ) cell->fform = FLT_SCIENTIFIC;
cell->locked = ((x & (1<<3)) != 0); cell->locked = ((x & (1<<3)) != 0);
cell->transparent = ((x & (1<<4)) != 0); cell->transparent = ((x & (1<<4)) != 0);
cell->ignored = ((x & (1<<5)) != 0); cell->ignored = ((x & (1<<5)) != 0);
@ -391,7 +399,7 @@ const char *loadxdr(Sheet *sheet, const char *name)
(void)fclose(fp); (void)fclose(fp);
return strerror(olderror); return strerror(olderror);
} }
nc = initcellofsheet(sheet, w); nc = initcellofsheet(sheet, w, NULL);
if (xdr_cell(&xdrs, nc)==0) if (xdr_cell(&xdrs, nc)==0)
{ {
freecellofsheet(sheet, w); freecellofsheet(sheet, w);

View File

@ -59,71 +59,92 @@ static void redraw(void)
/* do_attribute -- set cell attributes */ /* do_attribute -- set cell attributes */
static int do_attribute(Sheet *cursheet) static int do_attribute(Sheet *cursheet)
{ {
MenuChoice mainmenu[5];
MenuChoice adjmenu[11];
MarkState ms;
const char *prompt;
int c; int c;
Cell *cc = curcell(cursheet);
/* 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;
do do
{ {
ms = getmarkstate(cursheet); MarkState ms = getmarkstate(cursheet);
const char* prompt = _("Block attribute");
if (ms == UNMARKED) prompt = _("Cell 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); 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 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))) if (ms == UNMARKED && c != 5 && locked(cc))
line_msg(_("Cell attribute:"), _("Cell is locked")); line_msg(_("Cell attribute:"), _("Cell is locked"));
else else
{ {
switch (c) switch (c)
{ {
case -2: case -2: case -1: c = KEY_CANCEL; break;
case -1: c = KEY_CANCEL; break;
case 0: 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 -2: case -1: c = K_INVALID; break;
case -1: c = K_INVALID; break;
case 0: c = ADJUST_LEFT; break; case 0: c = ADJUST_LEFT; break;
case 1: c = ADJUST_RIGHT; break; case 1: c = ADJUST_RIGHT; break;
case 2: c = ADJUST_CENTER; 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); default: assert(0);
} }
break; break;
} }
case 1: c = ADJUST_LABEL; break; case 1:
case 2: c = ADJUST_LOCK; break; {
case 3: c = ADJUST_IGNORE; break; 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); default: assert(0);
} }
} }
@ -136,18 +157,12 @@ static int do_attribute(Sheet *cursheet)
/* do_file -- file menu */ /* do_file -- file menu */
static int do_file(Sheet *cursheet) 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 do
{ {
const char *menu[] =
{ _("lL)oad"), _("sS)ave"), _("nN)ame"), NULL };
switch (c = line_menu(_("File:"), menu, 0)) switch (c = line_menu(_("File:"), menu, 0))
{ {
case -2: case -2:
@ -237,21 +252,14 @@ static int do_shell(void)
/* do_block -- block menu */ /* do_block -- block menu */
static int do_block(Sheet *cursheet) static int do_block(Sheet *cursheet)
{ {
MenuChoice block[9]; int c = 0;
int c;
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 do
{ {
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)) switch (c = line_menu(_("Block menu:"), block, 0))
{ {
case -2: case -2:
@ -273,23 +281,14 @@ static int do_block(Sheet *cursheet)
int show_menu(Sheet *cursheet) int show_menu(Sheet *cursheet)
{ {
MenuChoice menu[9];
int c = K_INVALID; 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 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)) switch (c=line_menu(_("Main menu:"),menu,0))
{ {
case -2: case -2:
@ -520,7 +519,7 @@ void redraw_sheet(Sheet *sheet)
if (bufsz < (size*UTF8SZ+1)) if (bufsz < (size*UTF8SZ+1))
buf = realloc(buf, 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); getprecision(cell), sheet, tmp);
adjust(getadjust(cell), buf, size); adjust(getadjust(cell), buf, size);
assert(size>=cutoff); assert(size>=cutoff);
@ -566,14 +565,14 @@ void redraw_sheet(Sheet *sheet)
{ {
cell = curcell(sheet); cell = curcell(sheet);
Token bc = gettok(cell, BASE_CONT); Token bc = gettok(cell, BASE_CONT);
printtok(buf+strlen(buf), bufsz-strlen(buf), 0, 1, getscientific(cell), printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING,
-1, false, &bc); FLT_COMPACT, 0, TRUNCATED_ERROR, &bc);
Token ic = gettok(cell, ITER_CONT); Token ic = gettok(cell, ITER_CONT);
if (ic.type != EMPTY && mbslen(buf) < (size_t)(sheet->maxx+1-4)) if (ic.type != EMPTY && mbslen(buf) < (size_t)(sheet->maxx+1-4))
{ {
strcat(buf," -> "); strcat(buf," -> ");
printtok(buf+strlen(buf), bufsz-strlen(buf), 0, 1, printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING,
getscientific(cell), -1, false, &ic); FLT_COMPACT, 0, TRUNCATED_ERROR, &ic);
} }
} }
*mbspos(buf, sheet->maxx) = 0; *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': { case 'v': {
char valbuf[1024]; char valbuf[1024];
printvalue(valbuf, sizeof(valbuf), 0, 1, printvalue(valbuf, sizeof(valbuf), 0, QUOTE_STRING,
getscientific(curcell(sheet)), -1, FLT_COMPACT, 0, sheet, sheet->cur);
sheet, sheet->cur);
if (strlen(buf)+strlen(valbuf) >= (size-1)) break; if (strlen(buf)+strlen(valbuf) >= (size-1)) break;
(void)memmove(src+strlen(valbuf), src, strlen(src)); (void)memmove(src+strlen(valbuf), src, strlen(src));
(void)memcpy(src, valbuf, strlen(valbuf)); (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 */ /* line_ok -- one line yes/no menu */
int line_ok(const char *prompt, int curx) int line_ok(const char *prompt, int curx)
{ {
MenuChoice menu[3];
assert(curx == 0 || curx == 1); assert(curx == 0 || curx == 1);
menu[0].str = _("nN)o"); menu[0].c='\0'; const char* menu[] = { _("nN)o"), _("yY)es"), NULL };
menu[1].str = _("yY)es"); menu[1].c='\0';
menu[2].str=(char*)0;
return line_menu(prompt, menu, curx); return line_menu(prompt, menu, curx);
} }
/* line_binary -- two choices with cancel */ /* line_binary -- two choices with cancel */
int line_binary(const char *prompt, const char* op1, const char* op2, int curx) int line_binary(const char *prompt, const char* op1, const char* op2, int curx)
{ {
MenuChoice menu[4];
int result; int result;
assert(curx == 0 || curx == 1); assert(curx == 0 || curx == 1);
menu[0].str = _("cC)ancel"); const char* menu[] = { _("cC)ancel"), op1, op2, NULL };
menu[1].str = op1; menu[0].c='\0';
menu[2].str = op2; menu[1].c='\0';
menu[3].str = (char*)0;
return line_menu(prompt, menu, curx+1) - 1; return line_menu(prompt, menu, curx+1) - 1;
} }
@ -855,41 +843,46 @@ 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)
{ {
assert(prompt != NULL);
int maxx,x,width,offx; assert(choice != (const char **)0);
chtype c;
size_t promptlen;
assert(prompt!=(const char*)0);
assert(choice!=(const MenuChoice*)0);
assert(curx >= 0); assert(curx >= 0);
mvwaddstr(stdscr,LINES-1,0,prompt); mvwaddstr(stdscr,LINES-1,0,prompt);
promptlen = mbslen(prompt);
for (maxx=0; (choice+maxx)->str!=(const char*)0; ++maxx); size_t promptlen = mbslen(prompt);
offx=0; int maxx = 0;
while (choice[maxx] != NULL) ++maxx;
int offx = 0;
chtype c;
do do
{ {
int x, width;
(void)wmove(stdscr, LINES-1, (int)promptlen); (void)wmove(stdscr, LINES-1, (int)promptlen);
/* correct offset so choice is visible */ /* correct offset so choice is visible */
if (curx <= offx) offx = curx; if (curx <= offx) offx = curx;
else do else do
{ {
for (width=promptlen,x=offx; x<maxx && width+((int)mbslen((choice+x)->str+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; --x;
if (x < curx) ++offx; if (x < curx) ++offx;
} while (x < curx); } while (x < curx);
/* show visible choices */ /* show visible choices */
for (width=promptlen,x=offx; x<maxx && width+((int)mbslen((choice+x)->str+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)' '); (void)waddch(stdscr, (chtype)(unsigned char)' ');
if (x == curx) (void)wattron(stdscr, DEF_MENU); if (x == curx) (void)wattron(stdscr, DEF_MENU);
(void)waddstr(stdscr,(char*)(choice+x)->str+1); (void)waddstr(stdscr, (char*)(choice[x]+1));
if (x == curx) (void)wattroff(stdscr,DEF_MENU); if (x == curx) (void)wattroff(stdscr,DEF_MENU);
} }
@ -908,19 +901,14 @@ int line_menu(const char *prompt, const MenuChoice *choice, int curx)
/* default -- search choice keys */ /* default -- search choice keys */
default: default:
{ {
int i; for (int i = 0; i < maxx; ++i)
if (c < 256 && tolower(c) == choice[i][0])
for (i=0; (choice+i)->str!=(const char*)0; ++i)
{
if ((c<256 && tolower(c)==*((choice+i)->str)) || (choice+i)->c==c)
{ {
c = K_ENTER; c = K_ENTER;
curx = i; curx = i;
} }
} }
} }
}
} }
while (c != K_ENTER && c != K_DOWN && c != KEY_CANCEL && c != K_UP); while (c != K_ENTER && c != K_DOWN && c != KEY_CANCEL && c != K_UP);
(void)wmove(stdscr, LINES-1, 0); (void)wmove(stdscr, LINES-1, 0);

View File

@ -8,12 +8,6 @@
extern "C" { extern "C" {
#endif #endif
typedef struct
{
Key c;
const char *str;
} MenuChoice;
void display_main(Sheet *cursheet); void display_main(Sheet *cursheet);
void display_init(Sheet *cursheet, int always_redraw); void display_init(Sheet *cursheet, int always_redraw);
void display_end(Sheet *sheet); void display_end(Sheet *sheet);
@ -28,7 +22,7 @@ int keypressed(void);
void show_text(const char *text); void show_text(const char *text);
Key show_menu(Sheet *cursheet); 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); void find_helpfile(char *buf, int size, const char *argv0);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -18,7 +18,6 @@ decl {\#define SKIPDEFCOLS(c) while (c == DefaultCN[FOREGROUND] || c == DefaultC
{private global} {private global}
decl {\#define shadow _shadow} {private global} decl {\#define shadow _shadow} {private global}
decl {\#define transparent _transparent} {private global} decl {\#define transparent _transparent} {private global}
decl {\#define MenuChoice _MenuChoice} {private global}
decl {\#define Cell _Cell} {private global} decl {\#define Cell _Cell} {private global}
decl {\#include <FL/fl_message.H>} {private local} decl {\#include <FL/fl_message.H>} {private local}
@ -29,7 +28,6 @@ decl {\#include <FL/filename.H>} {private global}
decl {\#undef shadow} {private global} decl {\#undef shadow} {private global}
decl {\#undef transparent} {private global} decl {\#undef transparent} {private global}
decl {\#undef MenuChoice} {private global}
decl {\#undef Cell} {private global} decl {\#undef Cell} {private global}
decl {\#include "tpt_choose.h"} {private global} decl {\#include "tpt_choose.h"} {private global}
@ -160,7 +158,7 @@ class TeapotTable {open : {public Fl_Table}}
fl_color(cellfg); fl_color(cellfg);
fl_font(FL_HELVETICA | (isbold(cell) ? FL_BOLD : 0), 14); 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); getprecision(cell), cursheet, test);
int ww = 0, hh = 0; int ww = 0, hh = 0;
@ -558,11 +556,29 @@ class MainWindow {open}
user_data ADJUST_PRECISION user_data ADJUST_PRECISION
xywh {0 0 36 21} shortcut 0x80070 divider 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 { MenuItem sci {
label {&Scientific} label {&Scientific}
user_data ADJUST_SCIENTIFIC user_data ADJUST_SCIENTIFIC
protected xywh {0 0 36 21} shortcut 0x80073 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 { MenuItem shadow {
label {Shadow&ed} label {Shadow&ed}
@ -644,9 +660,8 @@ class MainWindow {open}
sprintf(valbuf, "(%i,%i,%i)", sprintf(valbuf, "(%i,%i,%i)",
sheet->cur[X], sheet->cur[Y], sheet->cur[Z]); sheet->cur[X], sheet->cur[Y], sheet->cur[Z]);
else if (Fl::event_key() == 'v') else if (Fl::event_key() == 'v')
printvalue(valbuf, sizeof(valbuf), 0, 1, printvalue(valbuf, sizeof(valbuf), 0, QUOTE_STRING,
getscientific(curcell(sheet)), FLT_COMPACT, 0, sheet, sheet->cur);
-1, sheet, sheet->cur);
else if (Fl::event_key(FL_Tab)) line_input->take_focus(); else if (Fl::event_key(FL_Tab)) line_input->take_focus();
if (valbuf[0]) { if (valbuf[0]) {
line_input->insert(valbuf); line_input->insert(valbuf);
@ -662,23 +677,23 @@ class MainWindow {open}
val[sizeof(val)-1] = 0; val[sizeof(val)-1] = 0;
} else { } else {
Token t = gettok(curcell(sheet), BASE_CONT); Token t = gettok(curcell(sheet), BASE_CONT);
printtok(val, sizeof(val), 0, 1, getscientific(curcell(sheet)), printtok(val, sizeof(val), 0, QUOTE_STRING,
-1, true, &t); FLT_COMPACT, 0, VERBOSE_ERROR, &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);
} }
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); line_edit(sheet, val, 0, buf, 0, 0);
Cell *cell = curcell(sheet); Cell *cell = curcell(sheet);
int adj = getadjust(cell); switch (getadjust(cell)) {
if (adj == LEFT) left->setonly(); case LEFT: left->setonly(); break;
else if (adj == RIGHT) right->setonly(); case RIGHT: right->setonly(); break;
else if (adj == CENTER) center->setonly(); case CENTER: center->setonly(); break;
}
if (SHADOWEDC(sheet, if (SHADOWEDC(sheet,
sheet->cur[X]+1, sheet->cur[Y], sheet->cur[Z])) sheet->cur[X]+1, sheet->cur[Y], sheet->cur[Z]))
shadow->set(); shadow->set();
@ -693,8 +708,13 @@ class MainWindow {open}
else bold->clear(); else bold->clear();
if (underlined(cell)) underline->set(); if (underlined(cell)) underline->set();
else underline->clear(); else underline->clear();
if (getscientific(cell)) sci->set(); switch (getfltformat(cell)) {
else sci->clear();} 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 protected xywh {0 50 800 525} box DOWN_FRAME
labeltype NO_LABEL resizable labeltype NO_LABEL resizable
code0 { table->sheet(sheet); } code0 { table->sheet(sheet); }
@ -847,7 +867,7 @@ Function {keypressed()} {open C return_type int} {code
} {} } } {} }
Function 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} {C return_type int}
{ {
Fl_Window line_menu_menu { Fl_Window line_menu_menu {
@ -874,8 +894,8 @@ Function
} code } code
{ {
line_menu_browser->clear(); line_menu_browser->clear();
while (choice->str) { while (*choice) {
line_menu_browser->add(choice->str+1); line_menu_browser->add(*choice + 1);
choice++; choice++;
} }
@ -909,8 +929,8 @@ Function
Fl_File_Icon::load_system_icons(); Fl_File_Icon::load_system_icons();
\#endif \#endif
Fl::scheme("gtk+"); Fl::scheme("gtk+");
int ch = sheet->changed; bool ch = sheet->changed;
resize(sheet, 1, 1, 1); resize(sheet, 1, 1, 1, NULL);
sheet->changed = ch; sheet->changed = ch;
new MainWindow(sheet); new MainWindow(sheet);
/* allocate and initialize the palette */ /* allocate and initialize the palette */