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_inset Tabular
<lyxtabular version="3" rows="26" columns="3">
<lyxtabular version="3" rows="25" columns="3">
<features tabularvalignment="middle">
<column alignment="left" valignment="top" width="5cm">
<column alignment="left" valignment="top">
@ -2562,35 +2562,6 @@ Set column width
<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
\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
{Meta-E}
\end_layout
@ -3359,9 +3330,43 @@ The precision for the output of floating point values.
\end_layout
\begin_layout Itemize
Whether floating point numbers should be printed in scientific notation
(0.123e1) or as decimal number (1.23).
It only affects the output, if the cell value is a floating point number.
The format for floating point numbers when they are printed.
This can be
\begin_inset Quotes eld
\end_inset
decimal
\begin_inset Quotes erd
\end_inset
(12.34),
\begin_inset Quotes eld
\end_inset
scientific
\begin_inset Quotes erd
\end_inset
(1.234e1),
\begin_inset Quotes eld
\end_inset
compact
\begin_inset Quotes erd
\end_inset
(a mix of these to produce a compact notation depending on thethe magnitude
of the value; this is the default), or
\begin_inset Quotes eld
\end_inset
hexact
\begin_inset Quotes erd
\end_inset
(a specialized hexadecimal format used for exact round trips to ASCII format,
rarely used for dispaly.) It only affects the output if the cell value is
a floating point number.
\end_layout
@ -4034,7 +4039,25 @@ File Formats
\end_layout
\begin_layout Paragraph
XDR (.tp)
ASCII (.tpa)
\end_layout
\begin_layout Standard
The ASCII file format allows easy generation/modification of saved sheets
by shell scripts.
Note that when reading a .tpa file, either ordinary decimal or scientific
formats for floating point number are recognized, as well as the exact
hex floating point format used by default when saving.
The default extension is
\family typewriter
.
\family default
tpa.
\end_layout
\begin_layout Paragraph
Legacy XDR (.tp)
\end_layout
\begin_layout Standard
@ -4043,28 +4066,31 @@ XDR (eXternal Data Representation) is a standard invented by Sun Microsystems
media.
Its advantage is that it is widely available and that it defines a portable
floating point number format.
The native teapot file format uses XDR so it is portable across different
machine architectures and operating systems.
The advantage of this over the portable ASCII format is that due to the
The native teapot file format formerly used XDR so it is portable across
different machine architectures and operating systems.
The advantage of this over the portable ASCII format was that due to the
(usually) missing conversion calculations any floating point constants
will be saved/loaded exactly without conversion errors.
\end_layout
It was discontinued because the ASCII format was made exact by virtue of
the exact hexadecimal
\begin_inset Quotes eld
\end_inset
\begin_layout Paragraph
ASCII (.tpa)
\end_layout
%a
\begin_inset Quotes erd
\end_inset
\begin_layout Standard
The ASCII file format allows easy generation/modification of saved sheets
by shell scripts.
Due to binary/ASCII conversion, there may be conversion errors in floating
point constants.
The default extension is
\family typewriter
.
\family default
tpa.
style (
\begin_inset Quotes eld
\end_inset
hexact
\begin_inset Quotes erd
\end_inset
) of representing floating point values, and so there was no need for a
specialized binary format.
Old .tp files may be read, but teapot no longer writes files in this format.
\end_layout
\begin_layout Paragraph
@ -6254,6 +6280,11 @@ condition
expression to avoid recalculation becoming stuck in an infinite loop, however.
\end_layout
\begin_layout Description
compact used as a keyword to the string() function; listed here to record
that this identifier may not be used as a cell label.
\end_layout
\begin_layout Description
\series medium
@ -6495,6 +6526,11 @@ x
\end_layout
\begin_layout Description
hexact used as a keyword to the string() function; listed here to record
that this identifier may not be used as a cell label.
\end_layout
\begin_layout Description
\series medium
@ -7458,20 +7494,24 @@ precision
\begin_inset space ~
\end_inset
integer
\emph on
\begin_inset space ~
\end_inset
scientific
format
\emph default
]])
\series default
evaluates to the string representation of its first argument.
The optional second argument gives the precision used for converting floating
point numbers to string form.
The optional third argument may either be the keyword
The optional third argument may be one of the keywords
\begin_inset Quotes eld
\end_inset
decimal
\begin_inset Quotes erd
\end_inset
,
\begin_inset Quotes eld
\end_inset
@ -7479,16 +7519,24 @@ scientific
\begin_inset Quotes erd
\end_inset
or
,
\begin_inset Quotes eld
\end_inset
decimal,
compact
\begin_inset Quotes erd
\end_inset
controlling the type of notation used for converting floating point numbers
to string form.
, or
\begin_inset Quotes eld
\end_inset
hexact
\begin_inset Quotes erd
\end_inset
, controlling the format for converting floating point numbers to string
form.
If the optional arguments are not specified, current defaults are used.
\end_layout

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 <float.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cell.h"
#include "default.h"
#include "eval.h"
#include "main.h"
#include "utf8.h"
const char *Adjust_Name[] =
{ [LEFT] = "Left", [RIGHT] = "Right", [CENTER] = "Center",
[AUTOADJUST] = "Auto"
};
const char Adjust_Char[] = "lrca";
const char *FloatFormat_Name[] =
{ [FLT_DECIMAL] = "Decimal", [FLT_SCIENTIFIC] = "Scientific",
[FLT_COMPACT] = "Compact", [FLT_HEXACT] = "Hexact"
};
const char FloatFormat_Char[] = "dsch";
const char *ColorAspect_Name[] =
{ [FOREGROUND] = "Foreground", [BACKGROUND] = "Background"
@ -27,12 +52,12 @@ void initcellcontents(Cell *fresh)
fresh->tok[tv].type = EMPTY;
fresh->label = NULL;
fresh->precision = -1;
fresh->fform = DEF_FLOATFORM;
fresh->adjust = AUTOADJUST;
for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a)
fresh->aspect[a] = DefaultCN[a];
fresh->updated = 0;
fresh->shadowed = 0;
fresh->scientific = DEF_SCIENTIFIC;
fresh->locked = 0;
fresh->transparent = 0;
fresh->ignored = 0;
@ -108,10 +133,10 @@ bool ignored(const Cell *cell)
}
/* getscientific -- should value be displayed in scientific notation? */
bool getscientific(const Cell *cell )
/* getfltformat -- float format for numbers */
FloatFormat getfltformat(const Cell *cell )
{
return (cell == NULLCELL) ? DEF_SCIENTIFIC : cell->scientific;
return (cell == NULLCELL) ? DEF_FLOATFORM : cell->fform;
}
/* getprecision -- get cell precision */
@ -189,3 +214,246 @@ void copycell(Cell *to, const Cell *fromcell, LabelHandling lh)
initcellcontents(to);
}
}
/* print_fident -- print a field identifier to a dest and return the number
of characters written
*/ /*{{{*/
static int print_fident(char* dest, size_t space, FunctionIdentifier id)
{
size_t identlen = strlen(tfunc[id].name);
if ((identlen+1) < space) strcpy(dest, tfunc[id].name);
else {
(void)strncpy(dest, tfunc[id].name, space);
dest[space-1] = '\0';
}
return identlen;
}
/*}}}*/
/* print_string -- print a string value to a dest and return the number of
characters written
*/ /*{{{*/
static int print_string(char* dest, size_t space,
const char *str, StringFormat sf)
{
size_t cur = 0;
if (sf == QUOTE_STRING && cur < space) dest[cur++] = '"';
for ( ; cur < space && *str != '\0'; ++str)
{
if (sf == QUOTE_STRING && (*str == '"' || *str=='\\')) dest[cur++] = '\\';
if (cur < space) dest[cur++] = *str;
}
if (sf == QUOTE_STRING && cur < space) dest[cur++] = '"';
return cur;
}
/*}}}*/
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
size_t printtok(char* dest, size_t size, size_t field_width,
StringFormat sf, FloatFormat ff,
int digits, ErrorFormat ef, const Token *tok)
{
if (debug_level > 2) {
printf("..Entering printtok; bufsize %d, field_width %d, qs %d, ff %s,"
"prec %d, verr %d\n",
size, field_width, sf, FloatFormat_Name[ff], digits, ef);
}
if (size > 0 ) *dest = '\0';
if (tok == NULLTOKEN || tok->type == EMPTY) return 0;
size_t cur = 0;
switch (tok->type)
{
/* STRING */
case STRING: cur += print_string(dest, size-cur, tok->u.string, sf); break;
/* INT */ /*{{{*/
case INT:
{
char buf[64];
size_t buflen;
buflen = sprintf(buf, INT_T_FMT, tok->u.integer);
assert(buflen < sizeof(buf));
(void)strncpy(dest+cur,buf,size-cur-1);
cur+=buflen;
break;
}
/*}}}*/
/* FLOAT */ /*{{{*/
case FLOAT:
{
/* variables */ /*{{{*/
char buf[1100], buf2[1100], *use, *p;
size_t len, len2;
/*}}}*/
if (digits <= 0) digits += FLT_T_DIG;
if (digits > sizeof(buf) - 20) digits = sizeof(buf) - 20;
switch (ff) {
case FLT_DECIMAL:
len = sprintf(buf, FLT_T_STD_FMT, digits, tok->u.flt);
use = buf;
break;
case FLT_SCIENTIFIC:
len = sprintf(buf, FLT_T_SCI_FMT, digits, tok->u.flt);
use = buf;
break;
case FLT_COMPACT:
len = sprintf(buf, FLT_T_CPT_FMT, digits, tok->u.flt);
/* Unfortunately, %g is so clever that sometimes it omits the
decimal; it also has a penchant for not switching to scientific
notation until the magnitude gets very large. So we try to
counteract these bad tendencies here. If there is no decimal,
we take the shorter of %.1f and %e with the same number of digits.
*/
use = buf;
if (strchr(buf, '.') == NULL) {
len = sprintf(buf, FLT_T_STD_FMT, 1, tok->u.flt);
len2 = sprintf(buf2, FLT_T_SCI_FMT, digits, tok->u.flt);
/* remove trailing 0s from sci format to be fair */
size_t epos = strchr(buf2, 'e') - buf2;
size_t tpos = epos;
while (tpos > 1 && buf2[tpos-1] == '0' && buf2[tpos-2] != '.') --tpos;
if (tpos < epos) {
memmove(buf2+tpos, buf2+epos, len2-epos+1);
len2 -= epos - tpos;
}
if (len2 < len) { use = buf2; len = len2; }
}
break;
case FLT_HEXACT:
len = sprintf(buf, FLT_T_HEX_FMT, tok->u.flt);
use = buf;
break;
}
assert(len < sizeof(buf));
p = use + len;
while (*--p == ' ') { *p = '\0'; --len; }
(void)strncpy(dest+cur, use, size-cur-1);
cur += len;
break;
}
/*}}}*/
/* OPERATOR */ /*{{{*/
case OPERATOR:
{
static const char *ops[]={ "+", "-", "*", "/", "(", ")", ",", "<", "<=", ">=", ">", "==", "~=", "!=", "^", "%" };
if ((size-cur)>1)
{
dest[cur++]=*ops[tok->u.op];
if (*(ops[tok->u.op]+1) && size>cur) dest[cur++]=*(ops[tok->u.op]+1);
}
break;
}
/*}}}*/
/* LIDENT */ /*{{{*/
case LIDENT:
{
size_t identlen;
identlen=strlen(tok->u.lident);
if ((cur+identlen+1)<=size) strcpy(dest+cur,tok->u.lident);
else (void)strncpy(dest+cur,tok->u.lident,size-cur-1);
cur+=identlen;
break;
}
/*}}}*/
/* FIDENT */ /*{{{*/
case FIDENT:
if (debug_level > 2) {
printf("...Found function [%s].\n", tfunc[tok->u.fident].name);
}
cur += print_fident(dest+cur, size-cur-1, tok->u.fident);
break;
/*}}}*/
/* LOCATION */ /*{{{*/
case LOCATION:
{
char buf[60];
sprintf(buf,"&(%d,%d,%d)",tok->u.location[0],tok->u.location[1],tok->u.location[2]);
(void)strncpy(dest+cur,buf,size-cur-1);
cur+=strlen(buf);
break;
}
/*}}}*/
/* FUNCALL */ /*{{{*/
case FUNCALL:
{
cur += print_fident(dest+cur, size-cur-1, tok->u.funcall.fident);
if (tok->u.funcall.argc >= 0 && cur + 2 < size) /* -1 args is bare func */
{
dest[cur++] = '\(';
for (size_t ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai)
{
if (ai > 0 && cur < size) dest[cur++] = ',';
cur += printtok(dest+cur, size-cur-1, field_width-cur, sf, ff,
digits, ef, tok->u.funcall.argv + ai);
}
if (cur < size) dest[cur++] = ')';
}
break;
}
/* EEK */ /*{{{*/
case EEK:
{
if (ef == RESTORE_ERROR) {
strncpy(dest + cur, "error(", size-cur-1);
cur += 6;
if (cur < size - 1)
cur += print_string(dest+cur, size-cur-1, tok->u.err, QUOTE_STRING);
if (cur < size - 1)
dest[cur++] = ')';
break;
}
(void)strncpy(dest+cur, _("ERROR"), size-cur-1);
cur += strlen(_("ERROR"));
if (ef == VERBOSE_ERROR)
{
(void)strncpy(dest+cur, ": ", size-cur-1);
cur += 2;
size_t errlen = strlen(tok->u.err);
if ((cur+errlen+1) < size) strcpy(dest+cur, tok->u.err);
else (void)strncpy(dest+cur, tok->u.err, size-cur-1);
cur += errlen;
}
break;
}
/*}}}*/
/* default */ /*{{{*/
default: assert(0);
/*}}}*/
}
if (cur<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" {
#endif
typedef enum { LEFT=0, RIGHT=1, CENTER=2, AUTOADJUST=3 } Adjust;
typedef enum
{ BASE_CONT=0, ITER_CONT, ATTR_REF, MAX_PERSIST_TV = ATTR_REF,
CURR_VAL, RES_VAL,
@ -16,6 +14,18 @@ typedef enum
} TokVariety;
extern const char *TokVariety_Name[];
typedef enum { LEFT=0, RIGHT=1, CENTER=2, AUTOADJUST=3 } Adjust;
extern const char *Adjust_Name[];
#define MAX_ADJUST_NAME_LENGTH 16
extern const char Adjust_Char[];
typedef enum
{ FLT_DECIMAL=0, FLT_SCIENTIFIC, FLT_COMPACT, FLT_HEXACT }
FloatFormat;
extern const char *FloatFormat_Name[];
#define MAX_FLOATFORM_NAME_LENGTH 16
extern const char FloatFormat_Char[];
typedef unsigned char ColorNum;
#define MAX_MAX_COLORS UCHAR_MAX;
@ -29,10 +39,10 @@ typedef struct
char *label;
int precision;
Adjust adjust;
FloatFormat fform;
ColorNum aspect[NUM_COLOR_ASPECTS];
unsigned int updated:1;
unsigned int shadowed:1;
unsigned int scientific:1;
unsigned int locked:1;
unsigned int transparent:1;
unsigned int ignored:1;
@ -56,13 +66,19 @@ ColorNum getcolor(const Cell *cell, ColorAspect aspect);
bool locked(const Cell *cell);
bool transparent(const Cell *cell);
bool ignored(const Cell *cell);
bool getscientific(const Cell *cell);
FloatFormat getfltformat(const Cell *cell);
int getprecision(const Cell* cell);
const char *getlabel(const Cell *cell);
void initcellcontents(Cell *cell);
void freecellcontents(Cell *cell);
void copycell(Cell *to, const Cell *from, LabelHandling lh);
typedef enum {DIRECT_STRING, QUOTE_STRING} StringFormat;
typedef enum {TRUNCATED_ERROR, VERBOSE_ERROR, RESTORE_ERROR} ErrorFormat;
size_t printtok(char *dest, size_t size, size_t field_width, StringFormat sf,
FloatFormat ff, int digits, ErrorFormat ef, const Token *tok);
void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff,
int digits, Token **n);
#ifdef __cplusplus
}
#endif

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

View File

@ -7,10 +7,13 @@
#define DEF_COLUMNWIDTH 12
/* default precision of a printed value */
#define DEF_PRECISION 2
/* Since the default format now counts significant figures
rather than digits after the decimal, bumping this to 3
*/
#define DEF_PRECISION 3
/* default is no scientific notation for numbers */
#define DEF_SCIENTIFIC 0
/* default is compact notation for floating point numbers */
#define DEF_FLOATFORM FLT_COMPACT
/* character attribute for cell and row numbers */
#define DEF_NUMBER A_BOLD

View File

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

View File

@ -617,9 +617,9 @@ static Token string_func(int argc, const Token argv[])
{
/* variables */ /*{{{*/
Token result;
const char *usage = _("Usage: string(x[,[int prec][,decimal|scientific]])");
const char *usage = _("Usage: string(x[,[int prec][,format_for_floats]])");
int precision = def_precision;
bool use_sci = DEF_SCIENTIFIC;
bool ff = DEF_FLOATFORM;
char staticbuf[4096];
size_t size;
/*}}}*/
@ -630,8 +630,10 @@ static Token string_func(int argc, const Token argv[])
if (argv[2].type != FIDENT) return duperror(&result, usage);
switch (argv[2].u.fident)
{
case FUNC_DECIMAL: use_sci = false; break;
case FUNC_SCIENTIFIC: use_sci = true; break;
case FUNC_DECIMAL: ff = FLT_DECIMAL; break;
case FUNC_SCIENTIFIC: ff = FLT_SCIENTIFIC; break;
case FUNC_COMPACT: ff = FLT_COMPACT; break;
case FUNC_HEXACT: ff = FLT_HEXACT; break;
default: assert(0);
}
}
@ -641,8 +643,8 @@ static Token string_func(int argc, const Token argv[])
precision = argv[1].u.integer;
}
result.type = STRING;
size = printtok(staticbuf, sizeof(staticbuf), 0, false, use_sci, precision,
true, argv);
size = printtok(staticbuf, sizeof(staticbuf), 0, DIRECT_STRING, ff,
precision, VERBOSE_ERROR, argv);
if (size > sizeof(staticbuf) - 2)
return duperror(&result, _("string: Overflow of internal buffer"));
result.u.string = strdup(staticbuf);
@ -1417,6 +1419,20 @@ static Token decimal_func(int argc, const Token argv[])
}
/*}}}*/
/* compact keyword */ /*{{{*/
static Token compact_func(int argc, const Token argv[])
{
return self_func(argc, argv, FUNC_COMPACT);
}
/*}}}*/
/* hexact keyword */ /*{{{*/
static Token hexact_func(int argc, const Token argv[])
{
return self_func(argc, argv, FUNC_HEXACT);
}
/*}}}*/
/* scientific keyword */ /*{{{*/
static Token scientific_func(int argc, const Token argv[])
{
@ -1659,7 +1675,10 @@ Tfunc tfunc[]=
/* Miscellaneous other functions/keywords */
[FUNC_DOLLAR_SIGN] = { "$", env_func, PREFIX_FUNC, FUNCT, 0 },
[FUNC_COMPACT] = { "compact", compact_func, PREFIX_FUNC, FUNCT, 0 },
[FUNC_DECIMAL] = { "decimal", decimal_func, PREFIX_FUNC, FUNCT, 0 },
[FUNC_HEXACT] = { "hexact", hexact_func, PREFIX_FUNC, FUNCT, 0 },
[FUNC_SCIENTIFIC] = { "scientific", scientific_func, PREFIX_FUNC, FUNCT, 0 },
};
/*}}}*/

View File

@ -25,7 +25,8 @@ typedef enum
FUNC_LESS_EQUAL, FUNC_GREATER_EQUAL, FUNC_LESS_THAN, FUNC_GREATER_THAN,
FUNC_EQUAL_EQUAL, FUNC_TILDE_EQUAL, FUNC_BANG_EQUAL, FUNC_CARET,
FUNC_PER_CENT, FUNC_CONCAT, FUNC_TAU, FUNC_SQRT, FUNC_FLOOR, FUNC_CEIL,
FUNC_TRUNC, FUNC_ROUND, FUNC_DECIMAL, FUNC_SCIENTIFIC,
FUNC_TRUNC, FUNC_ROUND, FUNC_DECIMAL, FUNC_SCIENTIFIC, FUNC_COMPACT,
FUNC_HEXACT,
N_FUNCTION_IDS
} FunctionIdentifier;

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;
default: assert(0);
}
printvalue(buf, sizeof(buf), 0, 0, getscientific(cell),
printvalue(buf, sizeof(buf), 0, DIRECT_STRING, getfltformat(cell),
getprecision(cell), sheet, w);
if (transparent(cell))
{

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

View File

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

View File

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

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

View File

@ -12,10 +12,6 @@
#include <assert.h>
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
extern char *strdup(const char* s);
extern double strtod(const char *nptr, char **endptr); /* SunOS 4 hack */
extern long double strtold(const char *nptr, char **endptr); /* SunOS 4 hack */
@ -26,7 +22,6 @@ extern long double strtold(const char *nptr, char **endptr); /* SunOS 4 hack */
#include "func.h"
#include "main.h"
#include "misc.h"
#include "utf8.h"
#include "scanner.h"
/*}}}*/
@ -262,197 +257,3 @@ Token **scan(const char **s)
return na;
}
/*}}}*/
static int print_fident(char* dest, size_t space, int id)
{
size_t identlen = strlen(tfunc[id].name);
if ((identlen+1) < space) strcpy(dest, tfunc[id].name);
else {
(void)strncpy(dest, tfunc[id].name, space);
dest[space-1] = '\0';
}
return identlen;
}
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
size_t printtok(char* dest, size_t size, size_t field_width,
bool quote_strings, bool use_scientific,
int precision, bool verbose_error, const Token *tok)
{
if (debug_level > 2) {
printf("..Entering printtok; bufsize %d, field_width %d, qs %d, us %d, prec %d, verr %d\n", size, field_width, quote_strings, use_scientific, precision, verbose_error);
}
if (size > 0 ) *dest = '\0';
if (tok == NULLTOKEN || tok->type == EMPTY) return 0;
size_t cur = 0;
switch (tok->type)
{
/* STRING */ /*{{{*/
case STRING:
{
char *str = tok->u.string;
if (quote_strings && 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_SCI_FMT "%.*Le"
#define FLT_T_CPT_FMT "%.*Lg"
#define FLT_T_HEX_FMT "%La"
#define FLT_T_DIG LDBL_DIG
#define FLTEPS LDBL_EPSILON
#define FLTMX LDBL_MAX
@ -98,6 +100,8 @@ typedef double FltT;
*/
#define FLT_T_STD_FMT "%.*f"
#define FLT_T_SCI_FMT "%.*e"
#define FLT_T_CPT_FMT "%.*g"
#define FLT_T_HEX_FMT "%a"
#define FLT_T_DIG DBL_DIG
#define FLTEPS DBL_EPSILON
#define FLTMX DBL_MAX
@ -165,10 +169,6 @@ typedef struct Token_struc
Token duperror(Token* tok, const char* erro);
Token **scan(const char **s);
void cleartoken(Token* tok);
size_t printtok(char *dest, size_t size, size_t field_width,
bool quote_strings, bool use_scientific,
int precision, bool verbose_error, const Token *tok);
void print(char *s, size_t size, size_t chars, int quote, int scientific, int precision, Token **n);
#ifdef __cplusplus
}

View File

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

View File

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

View File

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

View File

@ -241,11 +241,19 @@ bool_t xdr_cell(XDR *xdrs, Cell *cell)
cell->adjust = x;
if (result==0) return 0;
if (xdr_int(xdrs, &(cell->precision))==0) return 0;
x=(cell->updated&1)|((cell->shadowed&1)<<1)|((cell->scientific&1)<<2)|((cell->locked&1)<<3)|((cell->transparent&1)<<4)|((cell->ignored&1)<<5)|((cell->bold&1)<<6)|((cell->underline&1)<<7);
x = 0;
/* Since we only decode, we do not need to do this any more; it is
just kept for documentation purposes:
x = (cell->updated & 1) | ((cell->shadowed & 1)<<1)
| ((cell->scientific & 1)<<2) | ((cell->locked & 1)<<3)
| ((cell->transparent & 1)<<4) | ((cell->ignored & 1)<<5)
| ((cell->bold & 1)<<6) | ((cell->underline & 1)<<7);
*/
result = xdr_int(xdrs, &x);
cell->updated=((x&(1))!=0);
/* cell->updated = ((x&(1))!=0); # Makes no sense to restore this */
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->transparent = ((x & (1<<4)) != 0);
cell->ignored = ((x & (1<<5)) != 0);
@ -391,7 +399,7 @@ const char *loadxdr(Sheet *sheet, const char *name)
(void)fclose(fp);
return strerror(olderror);
}
nc = initcellofsheet(sheet, w);
nc = initcellofsheet(sheet, w, NULL);
if (xdr_cell(&xdrs, nc)==0)
{
freecellofsheet(sheet, w);

View File

@ -59,71 +59,92 @@ static void redraw(void)
/* do_attribute -- set cell attributes */
static int do_attribute(Sheet *cursheet)
{
MenuChoice mainmenu[5];
MenuChoice adjmenu[11];
MarkState ms;
const char *prompt;
int c;
/* create menus */
adjmenu[0].str = _("lL)eft"); adjmenu[0].c='\0';
adjmenu[1].str = _("rR)ight"); adjmenu[1].c='\0';
adjmenu[2].str = _("cC)entered"); adjmenu[2].c='\0';
adjmenu[3].str = _("11).23e1 <-> 12.3"); adjmenu[3].c='\0';
adjmenu[4].str = _("pP)recision"); adjmenu[4].c='\0';
adjmenu[5].str = _("sS)hadow"); adjmenu[5].c='\0';
adjmenu[6].str = _("bB)old"); adjmenu[6].c='\0';
adjmenu[7].str = _("uU)nderline"); adjmenu[7].c='\0';
adjmenu[8].str = _("oO)utput special characters"); adjmenu[8].c='\0';
adjmenu[9].str = (char*)0;
mainmenu[0].str = _("rR)epresentation"); mainmenu[0].c='\0';
mainmenu[1].str = _("lL)abel"); mainmenu[1].c='\0';
mainmenu[2].str = _("oLo)ck"); mainmenu[2].c='\0';
mainmenu[3].str = _("iI)gnore"); mainmenu[3].c='\0';
mainmenu[4].str = (char*)0;
Cell *cc = curcell(cursheet);
do
{
ms = getmarkstate(cursheet);
MarkState ms = getmarkstate(cursheet);
const char* prompt = _("Block attribute");
if (ms == UNMARKED) prompt = _("Cell attribute");
else prompt = _("Block attribute");
const char *mainmenu[] =
{ _("jJ)ustify"), _("fF)loats"), _("tT)ypeface"),
_("mM)isc"), _("lL)abel"), _("kLock)"), NULL
};
c = line_menu(prompt, mainmenu, 0);
/* There is a magic number "2" in the next line, presumably it represents
/* There is a magic number "5" in the next line, presumably it represents
the selection of the lock attribute in the list of items above, in which
lock does indeed appear at index 2
lock does indeed appear at index 5
*/
if (ms == UNMARKED && c != 2 && locked(curcell(cursheet)))
if (ms == UNMARKED && c != 5 && locked(cc))
line_msg(_("Cell attribute:"), _("Cell is locked"));
else
{
switch (c)
{
case -2:
case -1: c = KEY_CANCEL; break;
case -2: case -1: c = KEY_CANCEL; break;
case 0:
{
switch (c = line_menu(prompt, adjmenu,0))
const char *justifymenu[] =
{ _("lL)eft"), _("rR)ight"), _("cC)entered"), NULL };
switch (c = line_menu(prompt, justifymenu, getadjust(cc)))
{
case -2:
case -1: c = K_INVALID; break;
case -2: case -1: c = K_INVALID; break;
case 0: c = ADJUST_LEFT; break;
case 1: c = ADJUST_RIGHT; break;
case 2: c = ADJUST_CENTER; break;
case 3: c = ADJUST_SCIENTIFIC; break;
case 4: c = ADJUST_PRECISION; break;
case 5: c = ADJUST_SHADOW; break;
case 6: c = ADJUST_BOLD; break;
case 7: c = ADJUST_UNDERLINE; break;
case 8: c = ADJUST_TRANSPARENT; break;
default: assert(0);
}
break;
}
case 1: c = ADJUST_LABEL; break;
case 2: c = ADJUST_LOCK; break;
case 3: c = ADJUST_IGNORE; break;
case 1:
{
const char *floatmenu[] =
{ _("dD)ecimal"), _("sS)cientific"), _("cC)ompact"),
_("hH)exact"), _("pP)recision"), NULL
};
switch (c = line_menu(prompt, floatmenu, getfltformat(cc)))
{
case -2: case -1: c = K_INVALID; break;
case 0: c = ADJUST_DECIMAL; break;
case 1: c = ADJUST_SCIENTIFIC; break;
case 2: c = ADJUST_COMPACT; break;
case 3: c = ADJUST_HEXACT; break;
case 4: c = ADJUST_PRECISION; break;
default: assert(0);
}
break;
}
case 2:
{
const char *typemenu[] =
{ _("bB)old"), _("uU)nderline"), NULL };
switch (c = line_menu(prompt, typemenu, 0))
{
case -2: case -1: c = K_INVALID; break;
case 0: c = ADJUST_BOLD; break;
case 1: c = ADJUST_UNDERLINE; break;
default: assert(0);
}
break;
}
case 3:
{
const char *miscmenu[] =
{ _("sS)hadow"), _("iI)gnore"),
_("oO)utput special characters"), NULL
};
switch (c = line_menu(prompt, miscmenu, 0))
{
case -2: case -1: c = K_INVALID; break;
case 0: c = ADJUST_SHADOW; break;
case 1: c = ADJUST_IGNORE; break;
case 2: c = ADJUST_TRANSPARENT; break;
default: assert(0);
}
break;
}
case 4: c = ADJUST_LABEL; break;
case 5: c = ADJUST_LOCK; break;
default: assert(0);
}
}
@ -136,18 +157,12 @@ static int do_attribute(Sheet *cursheet)
/* do_file -- file menu */
static int do_file(Sheet *cursheet)
{
int c = 0;
MenuChoice menu[4];
int c;
menu[0].str = _("lL)oad"); menu[0].c='\0';
menu[1].str = _("sS)ave"); menu[1].c='\0';
menu[2].str = _("nN)ame"); menu[2].c='\0';
menu[3].str = (char*)0;
c=0;
do
{
const char *menu[] =
{ _("lL)oad"), _("sS)ave"), _("nN)ame"), NULL };
switch (c = line_menu(_("File:"), menu, 0))
{
case -2:
@ -237,21 +252,14 @@ static int do_shell(void)
/* do_block -- block menu */
static int do_block(Sheet *cursheet)
{
MenuChoice block[9];
int c;
int c = 0;
block[0].str = _("ecle)ar"); block[0].c='\0';
block[1].str = _("iI)nsert"); block[1].c='\0';
block[2].str = _("dD)elete"); block[2].c='\0';
block[3].str = _("mM)ove"); block[3].c='\0';
block[4].str = _("cC)opy"); block[4].c='\0';
block[5].str = _("fF)ill"); block[5].c='\0';
block[6].str = _("sS)ort"); block[6].c='\0';
block[7].str = _("rMir)ror"); block[7].c='\0';
block[8].str = (char*)0;
c=0;
do
{
const char* block[] =
{ _("ecle)ar"), _("iI)nsert"), _("dD)elete"), _("mM)ove"),
_("cC)opy"), _("fF)ill"), _("sS)ort"), _("rMir)ror"), NULL
};
switch (c = line_menu(_("Block menu:"), block, 0))
{
case -2:
@ -273,23 +281,14 @@ static int do_block(Sheet *cursheet)
int show_menu(Sheet *cursheet)
{
MenuChoice menu[9];
int c = K_INVALID;
menu[0].str = _("aA)ttributes"); menu[0].c='\0';
menu[1].str = _("wW)idth"); menu[1].c='\0';
menu[2].str = _("bB)lock"); menu[2].c='\0';
menu[3].str = _("fF)ile"); menu[3].c='\0';
menu[4].str = _("gG)oto"); menu[4].c='\0';
menu[5].str = _("sS)hell"); menu[5].c='\0';
menu[6].str = _("vV)ersion"); menu[6].c='\0';
menu[7].str = _("qQ)uit"); menu[7].c='\0';
menu[8].str = (char*)0;
do
{
const char* menu[] =
{ _("aA)ttributes"), _("wW)idth"), _("bB)lock"), _("fF)ile"),
_("gG)oto"), _("sS)hell"), _("vV)ersion"), _("qQ)uit"), NULL
};
switch (c=line_menu(_("Main menu:"),menu,0))
{
case -2:
@ -520,7 +519,7 @@ void redraw_sheet(Sheet *sheet)
if (bufsz < (size*UTF8SZ+1))
buf = realloc(buf, bufsz=(size*UTF8SZ+1));
printvalue(buf, (size*UTF8SZ+1), size, quote, getscientific(cell),
printvalue(buf, (size*UTF8SZ + 1), size, quote, getfltformat(cell),
getprecision(cell), sheet, tmp);
adjust(getadjust(cell), buf, size);
assert(size>=cutoff);
@ -566,14 +565,14 @@ void redraw_sheet(Sheet *sheet)
{
cell = curcell(sheet);
Token bc = gettok(cell, BASE_CONT);
printtok(buf+strlen(buf), bufsz-strlen(buf), 0, 1, getscientific(cell),
-1, false, &bc);
printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING,
FLT_COMPACT, 0, TRUNCATED_ERROR, &bc);
Token ic = gettok(cell, ITER_CONT);
if (ic.type != EMPTY && mbslen(buf) < (size_t)(sheet->maxx+1-4))
{
strcat(buf," -> ");
printtok(buf+strlen(buf), bufsz-strlen(buf), 0, 1,
getscientific(cell), -1, false, &ic);
printtok(buf+strlen(buf), bufsz-strlen(buf), 0, QUOTE_STRING,
FLT_COMPACT, 0, TRUNCATED_ERROR, &ic);
}
}
*mbspos(buf, sheet->maxx) = 0;
@ -643,9 +642,8 @@ int line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *
case 'v': {
char valbuf[1024];
printvalue(valbuf, sizeof(valbuf), 0, 1,
getscientific(curcell(sheet)), -1,
sheet, sheet->cur);
printvalue(valbuf, sizeof(valbuf), 0, QUOTE_STRING,
FLT_COMPACT, 0, sheet, sheet->cur);
if (strlen(buf)+strlen(valbuf) >= (size-1)) break;
(void)memmove(src+strlen(valbuf), src, strlen(src));
(void)memcpy(src, valbuf, strlen(valbuf));
@ -817,30 +815,20 @@ int line_edit(Sheet *sheet, char *buf, size_t size, const char *prompt, size_t *
/* line_ok -- one line yes/no menu */
int line_ok(const char *prompt, int curx)
{
MenuChoice menu[3];
assert(curx == 0 || curx == 1);
menu[0].str = _("nN)o"); menu[0].c='\0';
menu[1].str = _("yY)es"); menu[1].c='\0';
menu[2].str=(char*)0;
const char* menu[] = { _("nN)o"), _("yY)es"), NULL };
return line_menu(prompt, menu, curx);
}
/* line_binary -- two choices with cancel */
int line_binary(const char *prompt, const char* op1, const char* op2, int curx)
{
MenuChoice menu[4];
int result;
assert(curx == 0 || curx == 1);
menu[0].str = _("cC)ancel");
menu[1].str = op1; menu[0].c='\0';
menu[2].str = op2; menu[1].c='\0';
menu[3].str = (char*)0;
const char* menu[] = { _("cC)ancel"), op1, op2, NULL };
return line_menu(prompt, menu, curx+1) - 1;
}
@ -855,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)
{
int maxx,x,width,offx;
chtype c;
size_t promptlen;
assert(prompt!=(const char*)0);
assert(choice!=(const MenuChoice*)0);
assert(prompt != NULL);
assert(choice != (const char **)0);
assert(curx >= 0);
mvwaddstr(stdscr,LINES-1,0,prompt);
promptlen = mbslen(prompt);
for (maxx=0; (choice+maxx)->str!=(const char*)0; ++maxx);
offx=0;
size_t promptlen = mbslen(prompt);
int maxx = 0;
while (choice[maxx] != NULL) ++maxx;
int offx = 0;
chtype c;
do
{
int x, width;
(void)wmove(stdscr, LINES-1, (int)promptlen);
/* correct offset so choice is visible */
if (curx <= offx) offx = curx;
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;
if (x < curx) ++offx;
} while (x < curx);
/* 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)' ');
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);
}
@ -908,19 +901,14 @@ int line_menu(const char *prompt, const MenuChoice *choice, int curx)
/* default -- search choice keys */
default:
{
int i;
for (i=0; (choice+i)->str!=(const char*)0; ++i)
{
if ((c<256 && tolower(c)==*((choice+i)->str)) || (choice+i)->c==c)
for (int i = 0; i < maxx; ++i)
if (c < 256 && tolower(c) == choice[i][0])
{
c = K_ENTER;
curx = i;
}
}
}
}
}
while (c != K_ENTER && c != K_DOWN && c != KEY_CANCEL && c != K_UP);
(void)wmove(stdscr, LINES-1, 0);

View File

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

View File

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