1838 lines
50 KiB
C
1838 lines
50 KiB
C
#ifdef DMALLOC
|
|
#include "dmalloc.h"
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <float.h>
|
|
#include <limits.h>
|
|
#include <locale.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
|
|
#include "default.h"
|
|
#include "display.h"
|
|
#include "eval.h"
|
|
#include "htmlio.h"
|
|
#include "latex.h"
|
|
#include "context.h"
|
|
#include "main.h"
|
|
#include "misc.h"
|
|
#include "sc.h"
|
|
#include "scanner.h"
|
|
#include "utf8.h"
|
|
#include "parser.h"
|
|
#include "sheet.h"
|
|
#include "wk1.h"
|
|
#include "xdr.h"
|
|
|
|
/* variables */ /*{{{*/
|
|
char helpfile[PATH_MAX];
|
|
bool batch = false;
|
|
unsigned int batchln=0;
|
|
PrecisionLevel def_precision = DEF_PRECISION;
|
|
StringFormat quote = DIRECT_STRING;
|
|
bool header = true;
|
|
int fontsize = 14;
|
|
bool always_redraw = false;
|
|
int debug_level = 0;
|
|
static bool usexdr = false;
|
|
/*}}}*/
|
|
|
|
void moveto(Sheet *sheet, CoordT x, CoordT y, CoordT z)
|
|
{
|
|
bool need_redraw = false;
|
|
bool need_cell = false;
|
|
CoordT xdir = x > sheet->cur[X] ? 1 : -1;
|
|
|
|
if (x >= 0 && x != sheet->cur[X]) { need_cell = true; sheet->cur[X] = x; }
|
|
if (y >= 0 && y != sheet->cur[Y]) { need_cell = true; sheet->cur[Y] = y; }
|
|
if (z >= 0 && z != sheet->cur[Z]) { need_redraw = true; sheet->cur[Z] = z; }
|
|
|
|
while (sheet->cur[X] > 0 && shadowed(sheet, sheet->cur))
|
|
sheet->cur[X] += xdir;
|
|
|
|
if (getmarkstate(sheet) == MARKING) LOCATION_GETS(sheet->mark2, sheet->cur);
|
|
|
|
if (sheet->cur[X] <= sheet->offx && sheet->offx > 0) {
|
|
need_redraw = true;
|
|
sheet->offx = (sheet->cur[X] > 0) ? sheet->cur[X]-1 : 0;
|
|
}
|
|
if (sheet->cur[Y] <= sheet->offy && sheet->offy > 0) {
|
|
need_redraw = true;
|
|
sheet->offy = (sheet->cur[Y] > 0) ? sheet->cur[Y]-1 : 0;
|
|
}
|
|
if (sheet->cur[X] >= sheet->offx + (CoordT)sheet->maxx) {
|
|
need_redraw = true;
|
|
sheet->offx = sheet->cur[X] - (CoordT)sheet->maxx + 2;
|
|
}
|
|
if (sheet->cur[Y] >= sheet->offy + (CoordT)sheet->maxy) {
|
|
need_redraw = true;
|
|
sheet->offy = sheet->cur[Y] - (CoordT)sheet->maxy + 2;
|
|
}
|
|
if (need_redraw) redraw_sheet(sheet);
|
|
else if (need_cell) redraw_cell(sheet, sheet->cur);
|
|
}
|
|
|
|
void movetoloc(Sheet *sheet, const Location dest) {
|
|
moveto(sheet, dest[X], dest[Y], dest[Z]);
|
|
}
|
|
|
|
void relmoveto(Sheet *sheet, CoordT x, CoordT y, CoordT z)
|
|
{
|
|
moveto(sheet, sheet->cur[X]+x, sheet->cur[Y]+y, (z?sheet->cur[Z]+z:-1));
|
|
}
|
|
|
|
/* line_numedit -- number line editor function */ /*{{{*/
|
|
static int line_numedit(int *n, const char *prompt)
|
|
{
|
|
assert(prompt != NULL);
|
|
|
|
char buf[20];
|
|
Token *t = NULLTOKEN;
|
|
sprintf(buf, "%d", *n);
|
|
char *s = buf + strlen(buf);
|
|
do
|
|
{
|
|
free(t);
|
|
size_t x = (size_t)(s - buf);
|
|
size_t offx = 0;
|
|
int c = line_edit((Sheet*)0, buf, sizeof(buf), prompt, &x, &offx);
|
|
if (c < 0) return c;
|
|
s = buf;
|
|
t = scan_integer(&s);
|
|
} while (*s != '\0');
|
|
if (t == NULLTOKEN) *n = -1;
|
|
else { *n = (int)(t->u.integer); free(t); }
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* line_lidedit -- label identifier line editor function */ /*{{{*/
|
|
static int line_idedit(char *ident, size_t size, const char *prompt,
|
|
size_t *x, size_t *offx)
|
|
{
|
|
Token *t = NULLTOKEN;
|
|
char *s = ident + strlen(ident);
|
|
do
|
|
{
|
|
free(t);
|
|
*x = (size_t)(s - ident);
|
|
int c = line_edit((Sheet*)0, ident, size, prompt, x, offx);
|
|
if (c < 0) return c;
|
|
s = ident;
|
|
t = scan_ident(&s);
|
|
} while (*s != '\0' || t == NULLTOKEN || t->type != LIDENT);
|
|
free(t);
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* doanyway -- ask if action should be done despite unsaved changes */ /*{{{*/
|
|
bool doanyway(Sheet *sheet, const char *msg)
|
|
{
|
|
if (sheet->changed && line_ok(msg, 0) <= 0) return false;
|
|
return true;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_edit -- set or modify cell contents */ /*{{{*/
|
|
static int do_edit(Sheet *cursheet, Key c, char *expr, TokVariety tv)
|
|
{
|
|
const char *promptfor[] = { [BASE_CONT] = _("Cell contents"),
|
|
[ITER_CONT] = _("Clocked cell contents"),
|
|
[STYLE_CONT] = _("Style expression")
|
|
};
|
|
Location scur;
|
|
Cell *cell = curcell(cursheet);
|
|
Token newcont;
|
|
if (locked(cell)) line_msg(_("Edit cell:"),_("Cell is locked"));
|
|
else
|
|
{
|
|
newcont.type = EMPTY;
|
|
LOCATION_GETS(scur, cursheet->cur);
|
|
if (expr)
|
|
{
|
|
char *s = expr;
|
|
Token **t = scan(&s);
|
|
if (*s != '\0') {
|
|
if (t == EMPTY_TVEC)
|
|
line_msg(promptfor[tv], "XXX invalid expression");
|
|
else {
|
|
newcont = eval_safe(t, LITERAL);
|
|
if (newcont.type == EEK)
|
|
line_msg(promptfor[tv], "XXX unparseable expression");
|
|
}
|
|
}
|
|
tvecfree(t);
|
|
}
|
|
else
|
|
{
|
|
Token cntt;
|
|
size_t offx = 0;
|
|
char buf[1024];
|
|
char *s = NULL;
|
|
if (c == K_NONE)
|
|
{
|
|
cntt = gettok(cell, tv);
|
|
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1,
|
|
TRUNCATED_ERROR, &cntt);
|
|
s = buf+strlen(buf);
|
|
}
|
|
else if (c == K_BACKSPACE)
|
|
{
|
|
cntt = gettok(cell, tv);
|
|
printtok(buf, sizeof(buf), 0, QUOTE_STRING, FLT_COMPACT, -1,
|
|
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, QUOTE_STRING, FLT_COMPACT, -1,
|
|
TRUNCATED_ERROR, &cntt);
|
|
memmove(buf,mbspos(buf,1),strlen(mbspos(buf,1))+1);
|
|
s = buf;
|
|
}
|
|
else if (isalpha(c))
|
|
{
|
|
buf[0] = '"';
|
|
buf[1] = (char)c;
|
|
buf[2] = 0;
|
|
s=buf+2;
|
|
}
|
|
else
|
|
{
|
|
if (c < 256) buf[0] = (char)c;
|
|
else buf[0] = 0;
|
|
buf[1]='\0';
|
|
s=buf+1;
|
|
}
|
|
do
|
|
{
|
|
tfree(&newcont);
|
|
newcont.type = EEK;
|
|
newcont.u.err = (char *)0;
|
|
size_t x = mbslen(buf)-mbslen(s);
|
|
int r = line_edit(cursheet, buf, sizeof(buf), promptfor[tv], &x, &offx);
|
|
if (r < 0) return r;
|
|
s = buf;
|
|
if (buf[0] == '"' && buf[strlen(buf)-1] != '"'
|
|
&& strlen(buf)+1 < sizeof(buf))
|
|
{
|
|
buf[strlen(buf)+1] = 0;
|
|
buf[strlen(buf)] = '"';
|
|
}
|
|
Token **t = scan(&s);
|
|
if (t != EMPTY_TVEC) {
|
|
newcont = eval_safe(t, LITERAL);
|
|
}
|
|
tvecfree(t);
|
|
} while (*s != '\0' && newcont.type == EEK);
|
|
}
|
|
movetoloc(cursheet, scur);
|
|
puttok(cursheet, cursheet->cur, newcont, tv);
|
|
forceupdate(cursheet);
|
|
}
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_label -- modify cell label */ /*{{{*/
|
|
static int do_label(Sheet *sheet)
|
|
{
|
|
/* variables */ /*{{{*/
|
|
char buf[1024],oldlabel[1024];
|
|
size_t edx,offx,ok;
|
|
Token t;
|
|
Location w;
|
|
int tried;
|
|
int c;
|
|
/*}}}*/
|
|
|
|
assert(sheet != (Sheet*)0);
|
|
do_mark(sheet, GET_MARK_ALL);
|
|
if (SAME_LOC(sheet->mark1,sheet->mark2) &&
|
|
locked(CELL_AT(sheet, sheet->mark1)))
|
|
{
|
|
line_msg(_("Cell label:"),_("Cell is locked"));
|
|
}
|
|
else
|
|
{
|
|
ok=edx=offx=0;
|
|
(void)strcpy(buf, getlabel(curcell(sheet)));
|
|
(void)strcpy(oldlabel, buf);
|
|
tried = 0;
|
|
do
|
|
{
|
|
if (tried) {
|
|
line_msg(_("Cell label:"), _("Label already in use"));
|
|
}
|
|
if ((c=line_idedit(buf,sizeof(buf),_("Cell label:"),&edx,&offx))<0) return c;
|
|
tried = 1;
|
|
if (buf[0]=='\0') ok=1;
|
|
else
|
|
{
|
|
ok=((t=findlabel(sheet,buf)).type==EEK ||
|
|
(t.type == LOCATION && SAME_LOC(t.u.location, sheet->cur)));
|
|
tfree(&t);
|
|
}
|
|
} while (!ok);
|
|
setlabel(sheet, sheet->cur, buf,1);
|
|
if (buf[0] != '\0' && oldlabel[0] != '\0')
|
|
for (ALL_LOCS_IN_REGION(sheet,w))
|
|
relabel(sheet, w, oldlabel, buf);
|
|
cachelabels(sheet);
|
|
forceupdate(sheet);
|
|
}
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_columnwidth -- set the column width */ /*{{{*/
|
|
static int do_columnwidth(Sheet *cursheet)
|
|
{
|
|
do_mark(cursheet, GET_MARK_CUR);
|
|
int n = (int)columnwidth(cursheet, cursheet->mark1[X], cursheet->mark1[Z]);
|
|
do {
|
|
int c = line_numedit(&n, _("Column width:"));
|
|
if (c < 0) return c;
|
|
} while (n <= 0);
|
|
/*}}}*/
|
|
for (int x = cursheet->mark1[X]; x <= cursheet->mark2[X]; ++x)
|
|
for (int z = cursheet->mark1[Z]; z <= cursheet->mark2[Z]; ++z)
|
|
setwidth(cursheet,x,z,(ColWidT)n);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_rowheight -- set the row height */ /*{{{*/
|
|
static int do_rowheight(Sheet *cursheet)
|
|
{
|
|
do_mark(cursheet, GET_MARK_CUR);
|
|
int n = (int)rowheight(cursheet, cursheet->mark1[Y], cursheet->mark1[Z]);
|
|
do {
|
|
int c = line_numedit(&n, _("Row height:"));
|
|
if (c < 0) return c;
|
|
} while (n <= 0);
|
|
RowHgtT rh = (RowHgtT)n;
|
|
for (int y = cursheet->mark1[Y]; y <= cursheet->mark2[Y]; ++y)
|
|
for (int z = cursheet->mark1[Z]; z <= cursheet->mark2[Z]; ++z)
|
|
setheight(cursheet, y, z, rh);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_attribute -- set cell attributes */ /*{{{*/
|
|
static void do_attribute(Sheet *cursheet, Key action)
|
|
{
|
|
Location w;
|
|
Adjust adj = LEFT;
|
|
FloatFormat ff = FLT_DECIMAL;
|
|
do_mark(cursheet, GET_MARK_CUR);
|
|
bool onecell = SAME_LOC(cursheet->mark1, cursheet->mark2);
|
|
Cell *fcell = safe_cell_at(cursheet, cursheet->mark1);
|
|
Style fs = getstyle(cursheet, cursheet->mark1);
|
|
bool changed = false;
|
|
if (action != ADJUST_LOCK && onecell && locked(fcell))
|
|
{
|
|
line_msg(_("Cell attribute:"),_("Cell is locked"));
|
|
return;
|
|
}
|
|
ColorAspect ca = FOREGROUND;
|
|
switch ((int)action)
|
|
{
|
|
case ADJUST_CENTER: ++adj; /* FALL THROUGH */
|
|
case ADJUST_RIGHT: ++adj; /* FALL THROUGH */
|
|
case ADJUST_LEFT:
|
|
{
|
|
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))
|
|
changed = setadjust(cursheet, w, adj) || changed;
|
|
break;
|
|
}
|
|
/* set float format */ /*{{{*/
|
|
case ADJUST_HEXACT: ++ff; /* FALL THROUGH */
|
|
case ADJUST_COMPACT: ++ff; /* FALL THROUGH */
|
|
case ADJUST_SCIENTIFIC: ++ff; /* FALL THROUGH */
|
|
case ADJUST_DECIMAL:
|
|
{
|
|
const char* templ = _("Change float format of block to %s?");
|
|
char *prompt = malloc(strlen(templ) + MAX_FLOATFORM_NAME_LENGTH +1);
|
|
sprintf(prompt, templ, FloatFormat_Name[ff]);
|
|
if (!onecell && line_ok(prompt, 0) <= 0) break;
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = setfltformat(cursheet, w, ff) || changed;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* 5 -- set precision */ /*{{{*/
|
|
case ADJUST_PRECISION:
|
|
{
|
|
int n = fs.precision;
|
|
const char* prompt = _("Precision for block:");
|
|
if (onecell) prompt = _("Precision for cell:");
|
|
int c = line_numedit(&n, prompt);
|
|
if (c < 0) return;
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = setprecision(cursheet, w, (PrecisionLevel)n) || changed;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* Set a color */ /*{{{*/
|
|
case ADJUST_BACKGROUND:
|
|
ca = BACKGROUND;
|
|
/* FALL THROUGH */
|
|
case ADJUST_FOREGROUND: {
|
|
int n = fs.aspect[ca];
|
|
const char* prompt = _("%s for block:");
|
|
if (onecell) prompt = _("%s for cell:");
|
|
char pbuf[256];
|
|
sprintf(pbuf, prompt, ColorAspect_Name[ca]);
|
|
int c = line_numedit(&n, pbuf);
|
|
if (c < 0) return;
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = setcolor(cursheet, w, ca, (ColorNum)n) || changed;
|
|
break;
|
|
}
|
|
/* 6 -- shadow */ /*{{{*/
|
|
case ADJUST_SHADOW:
|
|
{
|
|
Location rt;
|
|
LOCATION_GETS(rt, cursheet->mark1); ++rt[X];
|
|
int n = 0;
|
|
if (!(fs.shadowed) && !shadowed(cursheet, rt)) n = 1;
|
|
if (!onecell) n = line_binary(_("Set block to:"),
|
|
_("uU)nshadowed"), _("sS)hadowed"), n);
|
|
if (cursheet->mark1[X] == 0 && n == 1) {
|
|
line_msg(_("Shadow cell:"),_("You can not shadow cells in column 0"));
|
|
break;
|
|
}
|
|
|
|
if (n >= 0) {
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
{
|
|
Location assoc;
|
|
|
|
if (n == 0)
|
|
{
|
|
LOCATION_GETS(assoc, w);
|
|
if (!shadowed(cursheet, assoc)) assoc[X]++;
|
|
for (; shadowed(cursheet, assoc); assoc[X]++)
|
|
changed = shadow(cursheet, assoc, false) || changed;
|
|
}
|
|
else if (w[X] > 0) changed = shadow(cursheet, w, true) || changed;
|
|
}
|
|
}
|
|
if (n > 0) do_mark(cursheet, UNMARKED);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* 7 -- transparent */ /*{{{*/
|
|
case ADJUST_TRANSPARENT:
|
|
{
|
|
int n;
|
|
|
|
if (onecell) n = !(fs.transparent);
|
|
else n = line_binary(_("Set block to:"),
|
|
_("pP)rotected"), _("tT)ransparent:"),
|
|
!(fs.transparent));
|
|
if (n >= 0)
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = maketrans(cursheet, w, n) || changed;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
case ADJUST_DIM: /*{{{*/
|
|
{
|
|
int n = !(fs.dim);
|
|
if (!onecell) n = line_binary(_("Set block brightness to:"),
|
|
_("rR)egular"), _("dD)im"), n);
|
|
if (n >= 0)
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = makedim(cursheet, w, n) || changed;
|
|
break;
|
|
} /*}}}*/
|
|
case ADJUST_BOLD: /*{{{*/
|
|
{
|
|
int n = !(fs.bold);
|
|
if (!onecell) n = line_binary(_("Set block weight to:"),
|
|
_("rR)egular"), _("bB)old"), n);
|
|
if (n >= 0)
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = embolden(cursheet, w, n) || changed;
|
|
break;
|
|
} /*}}}*/
|
|
case ADJUST_ITALIC: /*{{{*/
|
|
{
|
|
int n = !(fs.italic);
|
|
if (!onecell) n = line_binary(_("Set block font to:"),
|
|
_("rR)oman"), _("iI)talic"), n);
|
|
if (n >= 0)
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = italicize(cursheet, w, n) || changed;
|
|
break;
|
|
} /*}}}*/
|
|
/* 9 -- underline */ /*{{{*/
|
|
case ADJUST_UNDERLINE:
|
|
{
|
|
int n;
|
|
|
|
if (onecell) n = !(fs.underline);
|
|
else n = line_binary(_("Set block to:"), _("nN)ot underline"),
|
|
_("uU)nderline"), !(fs.underline));
|
|
if (n >= 0)
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = underline(cursheet, w, n) || changed;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* 1 -- edit label and goto end */ /*{{{*/
|
|
case ADJUST_LABEL:
|
|
{
|
|
do_label(cursheet);
|
|
return;
|
|
}
|
|
/*}}}*/
|
|
/* 2 -- lock */ /*{{{*/
|
|
case ADJUST_LOCK:
|
|
{
|
|
int n;
|
|
|
|
if (onecell) n = !locked(fcell);
|
|
else n = line_binary(_("Set block to:"), _("uU)nlocked"), _("lL)ocked"),
|
|
!locked(fcell));
|
|
if (n >= 0)
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = lockcell(cursheet, w, n) || changed;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* 3 -- ignore */ /*{{{*/
|
|
case ADJUST_IGNORE:
|
|
{
|
|
int n;
|
|
|
|
if (onecell) n = !ignored(fcell);
|
|
else n = line_binary(_("Set block to:"), _("cC)omputed"), _("iI)gnored"),
|
|
!ignored(fcell));
|
|
if (n >= 0)
|
|
for (ALL_LOCS_IN_REGION(cursheet,w))
|
|
changed = igncell(cursheet, w, n) || changed;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* default -- should not happen */ /*{{{*/
|
|
default: assert(0);
|
|
/*}}}*/
|
|
}
|
|
if (changed) forceupdate(cursheet);
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_saveport -- save sheet as portable ASCII file */ /*{{{*/
|
|
static int do_saveport(Sheet *cursheet, const char *name)
|
|
{
|
|
char buf[PATH_MAX];
|
|
const char *msg;
|
|
unsigned int count;
|
|
|
|
if (!name) name = cursheet->name;
|
|
|
|
if ((msg = saveport(cursheet, name, &count))) {
|
|
line_msg(_("Save sheet to ASCII file:"),msg);
|
|
return -2;
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf), _("%u cells written"), count);
|
|
if (!batch) line_msg(_("Save sheet to ASCII file:"),buf);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_savetbl -- save sheet as tbl file */ /*{{{*/
|
|
static int do_savetbl(Sheet *cursheet, const char *name)
|
|
{
|
|
char buf[PATH_MAX];
|
|
const char *msg;
|
|
int standalone=0;
|
|
unsigned int count;
|
|
|
|
do_mark(cursheet, GET_MARK_ALL);
|
|
if (!name) {
|
|
name = cursheet->name;
|
|
if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone;
|
|
}
|
|
|
|
if ((msg = savetbl(cursheet, name, !standalone,
|
|
cursheet->mark1, cursheet->mark2, &count))) {
|
|
line_msg(_("Save in tbl format to file:"),msg);
|
|
return -2;
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf), _("%u cells written"), count);
|
|
if (!batch) line_msg(_("Save in tbl format to file:"), buf);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_savelatex -- save sheet as LaTeX file */ /*{{{*/
|
|
static int do_savelatex(Sheet *cursheet, const char *name)
|
|
{
|
|
char buf[PATH_MAX];
|
|
const char *msg;
|
|
int standalone=0;
|
|
unsigned int count;
|
|
|
|
do_mark(cursheet, GET_MARK_ALL);
|
|
if (!name) {
|
|
name = cursheet->name;
|
|
if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone;
|
|
}
|
|
|
|
if ((msg = savelatex(cursheet, name, !standalone,
|
|
cursheet->mark1, cursheet->mark2, &count))) {
|
|
line_msg(_("Save in LaTeX format to file:"),msg);
|
|
return -2;
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf), _("%u cells written"), count);
|
|
if (!batch) line_msg(_("Save in LaTeX format to file:"), buf);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_savecontext -- save sheet as ConTeXt file */ /*{{{*/
|
|
static int do_savecontext(Sheet *cursheet, const char *name)
|
|
{
|
|
char buf[PATH_MAX];
|
|
const char *msg;
|
|
int standalone=0;
|
|
unsigned int count;
|
|
|
|
do_mark(cursheet, GET_MARK_ALL);
|
|
if (!name)
|
|
{
|
|
name = cursheet->name;
|
|
if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone;
|
|
}
|
|
|
|
if ((msg = savecontext(cursheet, name, !standalone,
|
|
cursheet->mark1, cursheet->mark2, &count)))
|
|
{
|
|
line_msg(_("Save in ConTeXt format to file:"),msg);
|
|
return -2;
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf), _("%u cells written"), count);
|
|
if (!batch) line_msg(_("Save in ConTeXt format to file:"), buf);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_savehtml -- save sheet as HTML file */ /*{{{*/
|
|
static int do_savehtml(Sheet *cursheet, const char *name)
|
|
{
|
|
char buf[PATH_MAX];
|
|
const char *msg;
|
|
int standalone=0;
|
|
unsigned int count;
|
|
|
|
do_mark(cursheet, GET_MARK_ALL);
|
|
if (!name) {
|
|
name = cursheet->name;
|
|
if ((standalone=line_ok(_("Save as stand-alone document:"),1))<0) return standalone;
|
|
}
|
|
|
|
if ((msg = savehtml(cursheet, name, !standalone,
|
|
cursheet->mark1, cursheet->mark2, &count))) {
|
|
line_msg(_("Save in HTML format to file:"),msg);
|
|
return -2;
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf), _("%u cells written"), count);
|
|
if (!batch) line_msg(_("Save in HTML format to file:"), buf);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_savetext -- save sheet as formatted text file */ /*{{{*/
|
|
static int do_savetext(Sheet *cursheet, const char *name)
|
|
{
|
|
char buf[PATH_MAX];
|
|
const char *msg;
|
|
unsigned int count;
|
|
|
|
do_mark(cursheet, GET_MARK_ALL);
|
|
if (!name) name = cursheet->name;
|
|
|
|
if ((msg = savetext(cursheet, name,
|
|
cursheet->mark1, cursheet->mark2, &count))) {
|
|
line_msg(_("Save in plain text format to file:"),msg);
|
|
return -2;
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf), _("%u cells written"), count);
|
|
if (!batch) line_msg(_("Save in plain text format to file:"), buf);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_savecsv -- save sheet as CSV file */ /*{{{*/
|
|
static int do_savecsv(Sheet *cursheet, const char *name)
|
|
{
|
|
do_mark(cursheet, GET_MARK_ALL);
|
|
if (!name) name = cursheet->name;
|
|
const char *menu[] =
|
|
{ _("cC)omma (,)"), _("sS)emicolon (;)"), _("tT)ab (\\t)"), NULL };
|
|
const char seps[4] = ",;\t";
|
|
int sep = line_menu(_("Choose separator:"), menu, 0);
|
|
if (sep < 0) return sep;
|
|
|
|
unsigned int count;
|
|
const char *msg;
|
|
if ((msg = savecsv(cursheet, name, seps[sep],
|
|
cursheet->mark1, cursheet->mark2, &count)))
|
|
{
|
|
line_msg(_("Save in CSV format to file:"), msg);
|
|
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;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_loadxdr -- load sheet from XDR file */ /*{{{*/
|
|
static int do_loadxdr(Sheet *cursheet)
|
|
{
|
|
const char *msg;
|
|
|
|
if ((msg=loadxdr(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from XDR file:"),msg);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_loadport -- load sheet from portable ASCII file */ /*{{{*/
|
|
static int do_loadport(Sheet *cursheet)
|
|
{
|
|
const char *msg;
|
|
/*}}}*/
|
|
|
|
if ((msg=loadport(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from ASCII file:"),msg);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
/* do_loadsc -- load sheet from SC file */ /*{{{*/
|
|
static int do_loadsc(Sheet *cursheet)
|
|
{
|
|
const char *msg;
|
|
|
|
if ((msg=loadsc(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from SC file:"),msg);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
/* do_loadwk1 -- load sheet from WK1 file */ /*{{{*/
|
|
static int do_loadwk1(Sheet *cursheet)
|
|
{
|
|
const char *msg;
|
|
|
|
if ((msg=loadwk1(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from WK1 file:"),msg);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
/* do_loadcsv -- load/merge sheet from CSV file */ /*{{{*/
|
|
static int do_loadcsv(Sheet *cursheet)
|
|
{
|
|
const char *msg;
|
|
|
|
if ((msg=loadcsv(cursheet,cursheet->name))!=(const char*)0) line_msg(_("Load sheet from CSV file:"),msg);
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_mark -- set mark */ /*{{{*/
|
|
void do_mark(Sheet *cursheet, MarkState ms)
|
|
{
|
|
MarkState ps = getmarkstate(cursheet);
|
|
|
|
if (ms == MARK_CYCLE)
|
|
{
|
|
if (ps == UNMARKED) ms = MARKING;
|
|
else ms = ps + 1;
|
|
}
|
|
if (ps == ms) return;
|
|
switch (ms)
|
|
{
|
|
case MARKING:
|
|
{
|
|
LOCATION_GETS(cursheet->mark1, cursheet->cur);
|
|
LOCATION_GETS(cursheet->mark2, cursheet->cur);
|
|
break;
|
|
}
|
|
case UNMARKED:
|
|
break;
|
|
case MARKED:
|
|
case GET_MARK_CUR:
|
|
case GET_MARK_ALL:
|
|
{
|
|
switch (ps)
|
|
{
|
|
case MARKED: {
|
|
ms = MARKED;
|
|
break;
|
|
}
|
|
case MARKING:
|
|
{
|
|
poscorners(cursheet->mark1, cursheet->mark2);
|
|
ms = MARKED;
|
|
break;
|
|
}
|
|
case UNMARKED:
|
|
{
|
|
if (ms == GET_MARK_CUR)
|
|
{
|
|
LOCATION_GETS(cursheet->mark1, cursheet->cur);
|
|
LOCATION_GETS(cursheet->mark2, cursheet->cur);
|
|
ms = UNMARKED;
|
|
}
|
|
else if (ms == GET_MARK_ALL)
|
|
{
|
|
OLOCATION(cursheet->mark1);
|
|
for (Dimensions dd = X; dd < HYPER; ++dd)
|
|
cursheet->mark2[dd] = (CoordT)(cursheet->dim[dd] - 1);
|
|
ms = UNMARKED;
|
|
}
|
|
else assert(ms == MARKED);
|
|
break;
|
|
}
|
|
default: assert(0);
|
|
}
|
|
break;
|
|
}
|
|
default: assert(0);
|
|
}
|
|
cursheet->marking = ms;
|
|
}
|
|
/*}}}*/
|
|
|
|
static int do_name(Sheet *cursheet);
|
|
|
|
/* do_save -- save sheet */ /*{{{*/
|
|
static int do_save(Sheet *cursheet)
|
|
{
|
|
const char *ext = cursheet->name;
|
|
if (ext==(char*)0) return do_name(cursheet);
|
|
|
|
ext += strlen(ext)-1;
|
|
|
|
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_saveport(cursheet, NULL);
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_name -- (re)name sheet */ /*{{{*/
|
|
static int do_name(Sheet *cursheet)
|
|
{
|
|
const char *name;
|
|
|
|
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);
|
|
cursheet->name=strdup(name);
|
|
return do_save(cursheet);
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_load -- load sheet */ /*{{{*/
|
|
static int do_load(Sheet *cursheet)
|
|
{
|
|
const char *name, *ext;
|
|
|
|
if (doanyway(cursheet, _("Sheet modified, load new file anyway?")) != 1) return -1;
|
|
|
|
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-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_loadport(cursheet);
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_clear -- clear block */ /*{{{*/
|
|
static int do_clear(Sheet *sheet)
|
|
{
|
|
/* variables */ /*{{{*/
|
|
Location w;
|
|
bool onecell;
|
|
int c;
|
|
/*}}}*/
|
|
|
|
do_mark(sheet, GET_MARK_CUR);
|
|
onecell = SAME_LOC(sheet->mark1, sheet->mark2);
|
|
if (onecell && locked(CELL_AT(sheet, sheet->mark1)))
|
|
line_msg(_("Clear cell:"),_("Cell is locked"));
|
|
else
|
|
{
|
|
if (!onecell)
|
|
{
|
|
if ((c=line_ok(_("Clear block:"),0))<0) return c;
|
|
else if (c!=1) return -1;
|
|
}
|
|
|
|
for (ALL_LOCS_IN_REGION(sheet, w)) freecellofsheet(sheet, w);
|
|
cachelabels(sheet);
|
|
forceupdate(sheet);
|
|
}
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_insert -- insert block */ /*{{{*/
|
|
static int do_insert(Sheet *sheet)
|
|
{
|
|
const char* menu[] =
|
|
{ [X] = _("cC)olumn"), [Y] = _("rR)ow"),[Z] = _("lL)ayer"), NULL };
|
|
int repl = line_menu(_("Insert:"), menu, 0);
|
|
if (repl < 0) return repl;
|
|
assert(repl < HYPER);
|
|
Dimensions reply = (Dimensions)repl;
|
|
|
|
do_mark(sheet, GET_MARK_CUR);
|
|
Location beg, end;
|
|
LOCATION_GETS(beg, sheet->mark1);
|
|
LOCATION_GETS(end, sheet->mark2);
|
|
bool onecell = SAME_LOC(beg, end);
|
|
if (onecell)
|
|
/* ask if current cell or whole dimension should be used */ /*{{{*/
|
|
{
|
|
const char *menu2[3];
|
|
/* show menu */ /*{{{*/
|
|
switch (reply)
|
|
{
|
|
case X: menu2[0] = _("wW)hole column"); break;
|
|
case Y: menu2[0] = _("wW)hole line"); break;
|
|
case Z: menu2[0] = _("wW)hole layer"); break;
|
|
case HYPER: assert(0);
|
|
}
|
|
menu2[1] = _("sS)ingle cell");
|
|
menu2[2] = NULL;
|
|
int r = line_menu(_("Insert:"), menu2, 0);
|
|
/*}}}*/
|
|
switch (r)
|
|
{
|
|
case 0: /* use whole dimension */ /*{{{*/
|
|
{
|
|
switch (reply)
|
|
{
|
|
case X: /* use whole column */
|
|
beg[Y] = 0; end[Y] = (CoordT)(sheet->dim[Y]); break;
|
|
case Y: /* use whole line */
|
|
beg[X] = 0; end[X] = (CoordT)(sheet->dim[X]); break;
|
|
case Z: /* use whole layer */
|
|
beg[X] = 0; end[X] = (CoordT)(sheet->dim[X]);
|
|
beg[Y] = 0; end[Y] = (CoordT)(sheet->dim[Y]);
|
|
break;
|
|
case HYPER: assert(0);
|
|
}
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
case 1: /* use current cell */
|
|
break;
|
|
/* -2,-1 -- go up or abort */
|
|
case -2: case -1: return r;
|
|
/* default -- should not happen */
|
|
default: assert(0);
|
|
}
|
|
/*}}}*/
|
|
}
|
|
/*}}}*/
|
|
insertcube(sheet, beg, end, reply);
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_delete -- delete block */ /*{{{*/
|
|
static int do_delete(Sheet *sheet)
|
|
{
|
|
firstmenu: /* ask for direction of deletion */ /*{{{*/
|
|
assert(sheet != (Sheet*)0);
|
|
const char* menu[] =
|
|
{ [X] = _("cC)olumn"), [Y] = _("rR)ow"), [Z] = _("lL)ayer"), NULL };
|
|
int repl = line_menu(_("Delete:"), menu, 0);
|
|
if (repl < 0) return repl;
|
|
assert(repl < HYPER);
|
|
Dimensions reply = (Dimensions)repl;
|
|
/*}}}*/
|
|
|
|
do_mark(sheet, GET_MARK_CUR);
|
|
Location beg, end;
|
|
LOCATION_GETS(beg, sheet->mark1);
|
|
LOCATION_GETS(end, sheet->mark2);
|
|
bool onecell = SAME_LOC(beg, end);
|
|
if (onecell)
|
|
/* ask if range is the current cell or whole dimension should be used */ /*{{{*/
|
|
{
|
|
const char *menu2[3];
|
|
/* show menu */ /*{{{*/
|
|
switch (reply)
|
|
{
|
|
case X: menu2[0] = _("wW)hole column"); break;
|
|
case Y: menu2[0] = _("wW)hole line"); break;
|
|
case Z: menu2[0] = _("wW)hole layer"); break;
|
|
case HYPER: assert(0);
|
|
}
|
|
menu2[1] = _("sS)ingle cell");
|
|
menu2[2] = NULL;
|
|
int r = line_menu(_("Delete:"), menu2, 0);
|
|
/*}}}*/
|
|
switch (r)
|
|
{
|
|
/* 0 -- use whole dimension */ /*{{{*/
|
|
case 0:
|
|
{
|
|
switch (reply)
|
|
{
|
|
case X: /* use whole column */
|
|
beg[Y] = 0; end[Y] = (CoordT)(sheet->dim[Y]); break;
|
|
case Y: /* use whole line */
|
|
beg[X] = 0; end[X] = (CoordT)(sheet->dim[X]); break;
|
|
case 2: /* use whole layer */
|
|
beg[X] = 0; end[X] = (CoordT)(sheet->dim[X]);
|
|
beg[Y] = 0; end[Y] = (CoordT)(sheet->dim[Y]);
|
|
break;
|
|
case HYPER: assert(0);
|
|
}
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
case 1: /* use current cell */
|
|
break;
|
|
case -1: /* abort */
|
|
return -1;
|
|
case -2: goto firstmenu;
|
|
default: assert(0);
|
|
}
|
|
/*}}}*/
|
|
}
|
|
/*}}}*/
|
|
deletecube(sheet, beg, end, reply);
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_move -- copy or move a block */ /*{{{*/
|
|
static int do_move(Sheet *sheet, int copy, int force)
|
|
{
|
|
int c;
|
|
|
|
c=-1;
|
|
|
|
if (getmarkstate(sheet) == UNMARKED) line_msg(copy ? _("Copy block:") : _("Move block:"),_("No block marked"));
|
|
else if (force || (c=line_ok(copy ? _("Copy block:") : _("Move block:"),0))==1)
|
|
{
|
|
do_mark(sheet, MARKED);
|
|
moveblock(sheet, sheet->mark1, sheet->mark2, sheet->cur, copy);
|
|
if (!copy) sheet->marking = UNMARKED;
|
|
}
|
|
if (c<0) return c; else return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_fill -- fill a block */ /*{{{*/
|
|
static int do_fill(Sheet *sheet)
|
|
{
|
|
if (getmarkstate(sheet) == UNMARKED)
|
|
line_msg(_("Fill block:"), _("No block marked"));
|
|
else
|
|
{
|
|
do_mark(sheet, MARKED);
|
|
int cols = 1, rows = 1, layers = 1;
|
|
firstmenu:
|
|
do {
|
|
int c = line_numedit(&cols, _("Number of column-wise repetitions:"));
|
|
if (c < 0) return c;
|
|
} while (cols <= 0);
|
|
secondmenu:
|
|
do
|
|
{
|
|
int c = line_numedit(&rows, _("Number of row-wise repetitions:"));
|
|
if (c == -1) return -1;
|
|
else if (c == -2) goto firstmenu;
|
|
} while (rows <= 0);
|
|
do
|
|
{
|
|
int c = line_numedit(&layers, _("Number of depth-wise repetitions:"));
|
|
if (c == -1) return -1;
|
|
else if (c == -2) goto secondmenu;
|
|
} while (layers <= 0);
|
|
Location wid;
|
|
LOCATION_GETS(wid, sheet->mark2);
|
|
LOCATION_SUB(wid, sheet->mark1);
|
|
wid[X]++; wid[Y]++; wid[Z]++;
|
|
Location go;
|
|
go[Z] = sheet->cur[Z];
|
|
for (int z = 0; z < layers; ++z, go[Z] += wid[Z]) {
|
|
go[Y] = sheet->cur[Y];
|
|
for (int y = 0; y < rows; ++y, go[Y] += wid[Y]) {
|
|
go[X] = sheet->cur[X];
|
|
for (int x = 0; x < cols; ++x, go[X] += wid[X])
|
|
moveblock(sheet, sheet->mark1, sheet->mark2, go, 1);
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* fill the entire marked region using the current cell */
|
|
void fillwith(Sheet *she)
|
|
{
|
|
do_mark(she, GET_MARK_ALL);
|
|
Cell *src = curcell(she);
|
|
Location dest;
|
|
bool scan_labels = (src != NULLCELL && getlabel(src) != (const char*)0);
|
|
/* the following is safe since we have handled copying a cell to itself */
|
|
for (ALL_LOCS_IN_REGION(she, dest))
|
|
copycelltosheet(src, she, dest, ALTER_LABEL);
|
|
if (scan_labels) cachelabels(she);
|
|
forceupdate(she);
|
|
}
|
|
|
|
/* do_sort -- sort block */ /*{{{*/
|
|
static int do_sort(Sheet *sheet)
|
|
{
|
|
do_mark(sheet, GET_MARK_ALL);
|
|
/* build menus */ /*{{{*/
|
|
const char* menu1[] =
|
|
{ [X] = _("cC)olumn"), [Y] = _("rR)ow"), [Z] = _("dD)epth"), NULL };
|
|
const char* menu2[] =
|
|
{ _("sS)ort region"), _("aA)dd key"), NULL };
|
|
const char* menu3[] =
|
|
{ _("aA)scending"), _("dD)escending"), NULL };
|
|
/*}}}*/
|
|
|
|
Dimensions in_dir = HYPER;
|
|
int dir;
|
|
/* ask for sort direction */ /*{{{*/
|
|
zero:
|
|
dir = line_menu(_("Sort block:"), menu1, 0);
|
|
if (dir < 0) return dir;
|
|
assert(dir < HYPER);
|
|
in_dir = (Dimensions)dir;
|
|
int last = 0;
|
|
/*}}}*/
|
|
Sortkey sk[MAX_SORTKEYS];
|
|
unsigned int key = 0;
|
|
bool doit = false;
|
|
do
|
|
{
|
|
/* ask for positions */ /*{{{*/
|
|
one:
|
|
sk[key].soff[X] = 0;
|
|
if (in_dir != X) do {
|
|
int c = line_numedit(&(sk[key].soff[X]), _("X position of key vector:"));
|
|
if (c == -1) return -1;
|
|
else if (c == -2) switch (last) {
|
|
case -1: return -2;
|
|
case 0: goto zero;
|
|
case 2: goto two;
|
|
case 3: goto three;
|
|
case 5: goto five;
|
|
}
|
|
} while (sk[key].soff[X] < 0);
|
|
last = 1;
|
|
|
|
two:
|
|
sk[key].soff[Y] = 0;
|
|
if (in_dir != Y) do {
|
|
int c = line_numedit(&(sk[key].soff[Y]), _("Y position of key vector:"));
|
|
if (c == -1) return -1;
|
|
else if (c == -2) switch (last) {
|
|
case -1: return -2;
|
|
case 0: goto zero;
|
|
case 1: goto one;
|
|
case 3: goto three;
|
|
case 5: goto five;
|
|
default: assert(0);
|
|
}
|
|
} while (sk[key].soff[Y] < 0);
|
|
last = 2;
|
|
|
|
three:
|
|
sk[key].soff[Z] = 0;
|
|
if (in_dir != Z) do {
|
|
int c = line_numedit(&(sk[key].soff[Y]), _("Z position of key vector:"));
|
|
if (c == -1) return -1;
|
|
else if (c == -2) switch (last) {
|
|
case -1: return -2;
|
|
case 0: goto zero;
|
|
case 1: goto one;
|
|
case 2: goto two;
|
|
case 5: goto five;
|
|
default: assert(0);
|
|
}
|
|
} while (sk[key].soff[Z] < 0);
|
|
last = 3;
|
|
/*}}}*/
|
|
/* ask for sort key */ /*{{{*/
|
|
four:
|
|
sk[key].sortkey=0;
|
|
int ckey = line_menu(_("Sort block:"), menu3, 0);
|
|
switch (ckey)
|
|
{
|
|
case 0: sk[key].sortkey |= ASCENDING; break;
|
|
case 1: sk[key].sortkey &= ~ASCENDING; break;
|
|
case -1: return -1;
|
|
case -2: switch (last)
|
|
{
|
|
case -1: return -2;
|
|
case 1: goto one;
|
|
case 2: goto two;
|
|
case 3: goto three;
|
|
default: assert(0);
|
|
}
|
|
default: assert(0);
|
|
}
|
|
last = 4;
|
|
/*}}}*/
|
|
++key;
|
|
|
|
five:
|
|
if (key == MAX_SORTKEYS) /* ask for sort comfirmation */ /*{{{*/
|
|
{
|
|
int c = line_ok(_("Sort block:"), 0);
|
|
if (c == -1) return -1;
|
|
else if (c == -2) goto four;
|
|
else if (c == 0) doit = true;
|
|
}
|
|
/*}}}*/
|
|
else /* ask for sort or adding another key */ /*{{{*/
|
|
switch (line_menu(_("Sort block:"), menu2, 0))
|
|
{
|
|
case 0: doit = true; break;
|
|
case 1: doit = false; break;
|
|
case -1: return -1;
|
|
case -2: goto four;
|
|
default: assert(0);
|
|
}
|
|
/*}}}*/
|
|
last = 5;
|
|
} while (!doit);
|
|
const char *msg =
|
|
sortblock(sheet, sheet->mark1, sheet->mark2, in_dir, sk, key);
|
|
if (msg != NULL) { line_msg(_("Sort block:"), msg); return -1; }
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_batchsort -- sort block in a batch*/ /*{{{*/
|
|
static void do_batchsort(Sheet *sheet, Dimensions dm, char* arg)
|
|
{
|
|
Sortkey sk[MAX_SORTKEYS];
|
|
unsigned int key = 0;
|
|
char* next;
|
|
while( *arg != '\0' )
|
|
{
|
|
while (isspace((int)*arg)) arg++;
|
|
OLOCATION(sk[key].soff);
|
|
sk[key].sortkey = 0;
|
|
switch (*arg)
|
|
{
|
|
case 'a': sk[key].sortkey |= ASCENDING; arg++; break;
|
|
case 'd': sk[key].sortkey &= ~ASCENDING; arg++; break;
|
|
}
|
|
if ( *arg != '\0' && dm != X ) {
|
|
sk[key].soff[X] = (CoordT)strtol(arg, &next, 10); arg = next;
|
|
}
|
|
if ( *arg != '\0' && dm != Y ) {
|
|
sk[key].soff[Y] = (CoordT)strtol(arg, &next, 10); arg = next;
|
|
}
|
|
if ( *arg != '\0' && dm != Z ) {
|
|
sk[key].soff[Z] = (CoordT)strtol(arg, &next, 10); arg = next;
|
|
}
|
|
++key;
|
|
}
|
|
do_mark(sheet, GET_MARK_ALL);
|
|
sortblock(sheet, sheet->mark1, sheet->mark2, dm, sk, key);
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_mirror -- mirror block */ /*{{{*/
|
|
static int do_mirror(Sheet *sheet)
|
|
{
|
|
do_mark(sheet, GET_MARK_ALL);
|
|
/* ask for direction of mirroring */ /*{{{*/
|
|
const char *menu[] =
|
|
{ [X] = _("lL)eft-right"), [Y] = _("uU)pside-down"),
|
|
[Z] = _("aA)bove-below"), NULL};
|
|
int reply = line_menu(_("Mirror block:"), menu, 0);
|
|
if (reply < 0) return reply;
|
|
assert(reply < HYPER);
|
|
/*}}}*/
|
|
mirrorblock(sheet, sheet->mark1, sheet->mark2, (Dimensions)reply);
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_goto -- go to a specific cell */ /*{{{*/
|
|
static int do_goto(Sheet *sheet, const char *expr)
|
|
{
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
size_t x = 0;
|
|
size_t offx = 0;
|
|
char buf[1024];
|
|
buf[0]='\0';
|
|
if (expr) strcpy(buf,expr);
|
|
else {
|
|
int c = line_edit(sheet, buf, sizeof(buf), _("Go to location:"), &x, &offx);
|
|
if (c < 0) return c;
|
|
}
|
|
char *s = buf;
|
|
Token **t = scan(&s);
|
|
if (t != EMPTY_TVEC)
|
|
{
|
|
Token value;
|
|
|
|
LOCATION_GETS(upd_l, sheet->cur);
|
|
upd_sheet = sheet;
|
|
value = eval_safe(t, FULL);
|
|
tvecfree(t);
|
|
if (value.type == LOCATION && IN_OCTANT(value.u.location))
|
|
movetoloc(sheet, value.u.location);
|
|
else
|
|
line_msg(_("Go to location:"), _("Not a valid location"));
|
|
tfree(&value);
|
|
}
|
|
return -1;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* do_sheetcmd -- process one key press */ /*{{{*/
|
|
int do_sheetcmd(Sheet *cursheet, Key c, bool moveonly)
|
|
{
|
|
switch ((int)c)
|
|
{
|
|
case K_GOTO: do_goto(cursheet, (const char *)0); break;
|
|
case K_COLWIDTH: do_columnwidth(cursheet); break;
|
|
case K_ROWHEIGHT: do_rowheight(cursheet); break;
|
|
case BLOCK_CLEAR: do_clear(cursheet); update(cursheet); break;
|
|
case BLOCK_INSERT: do_insert(cursheet); update(cursheet); break;
|
|
case BLOCK_DELETE: do_delete(cursheet); update(cursheet); break;
|
|
case BLOCK_MOVE: do_move(cursheet,0,0); update(cursheet); break;
|
|
case BLOCK_COPY: do_move(cursheet,1,0); update(cursheet); break;
|
|
case BLOCK_FILL: do_fill(cursheet); update(cursheet); break;
|
|
case FILL_BLOCK: fillwith(cursheet); update(cursheet); break;
|
|
case BLOCK_SORT: do_sort(cursheet); update(cursheet); break;
|
|
case BLOCK_MIRROR: do_mirror(cursheet); update(cursheet); break;
|
|
case ADJUST_LEFT:
|
|
case ADJUST_RIGHT:
|
|
case ADJUST_CENTER:
|
|
case ADJUST_DECIMAL:
|
|
case ADJUST_SCIENTIFIC:
|
|
case ADJUST_COMPACT:
|
|
case ADJUST_HEXACT:
|
|
case ADJUST_PRECISION:
|
|
case ADJUST_SHADOW:
|
|
case ADJUST_DIM:
|
|
case ADJUST_BOLD:
|
|
case ADJUST_ITALIC:
|
|
case ADJUST_UNDERLINE:
|
|
case ADJUST_FOREGROUND:
|
|
case ADJUST_BACKGROUND:
|
|
case ADJUST_TRANSPARENT:
|
|
case ADJUST_LABEL:
|
|
case ADJUST_LOCK:
|
|
case ADJUST_IGNORE: do_attribute(cursheet, c); break;
|
|
/* UP -- move up */ /*{{{*/
|
|
case K_UP:
|
|
{
|
|
relmoveto(cursheet, 0, -1, 0);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* DOWN -- move down */ /*{{{*/
|
|
case K_DOWN:
|
|
{
|
|
relmoveto(cursheet, 0, 1, 0);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* LEFT -- move left */ /*{{{*/
|
|
case K_LEFT:
|
|
{
|
|
relmoveto(cursheet, -1, 0, 0);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* RIGHT -- move right */ /*{{{*/
|
|
case K_RIGHT:
|
|
{
|
|
relmoveto(cursheet, 1, 0, 0);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* FIRSTL -- move to first line */ /*{{{*/
|
|
case K_FIRSTL:
|
|
case '<':
|
|
{
|
|
moveto(cursheet, -1, 0, -1);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* LASTL -- move to last line */ /*{{{*/
|
|
case K_LASTL:
|
|
case '>':
|
|
{
|
|
moveto(cursheet,
|
|
-1, ((cursheet->dim[Y] > 0) ? (CoordT)(cursheet->dim[Y]-1) : 0), -1);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* HOME -- move to beginning of line */ /*{{{*/
|
|
case K_HOME:
|
|
{
|
|
moveto(cursheet, 0, -1, -1);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* END -- move to end of line */ /*{{{*/
|
|
case K_END:
|
|
{
|
|
moveto(cursheet,
|
|
((cursheet->dim[X] > 0) ? (CoordT)(cursheet->dim[X]-1) : 0), -1, -1);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* + -- move one layer down */ /*{{{*/
|
|
case K_NSHEET:
|
|
case '+':
|
|
{
|
|
relmoveto(cursheet, 0, 0, 1);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* - -- move one layer up */ /*{{{*/
|
|
case K_PSHEET:
|
|
case '-':
|
|
{
|
|
relmoveto(cursheet, 0, 0, -1);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* * -- move to bottom layer */ /*{{{*/
|
|
case K_LSHEET:
|
|
case '*':
|
|
{
|
|
moveto(cursheet,
|
|
-1, -1, ((cursheet->dim[Z] > 0) ? (CoordT)(cursheet->dim[Z]-1) : 0));
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* _ -- move to top layer */ /*{{{*/
|
|
case K_FSHEET:
|
|
case '_':
|
|
{
|
|
moveto(cursheet, -1, -1, 0);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* ENTER -- edit current cell */ /*{{{*/
|
|
case K_ENTER:
|
|
if (moveonly) break;
|
|
do_edit(cursheet, '\0', NULL, BASE_CONT);
|
|
break;
|
|
/*}}}*/
|
|
/* MENTER -- edit current clocked cell */ /*{{{*/
|
|
case K_MENTER:
|
|
if (moveonly) break;
|
|
do_edit(cursheet, '\0', NULL, ITER_CONT);
|
|
break;
|
|
/*}}}*/
|
|
case K_EDIT_STYLE_EXPR: /* edit style expression */ /*{{{*/
|
|
if (moveonly) break;
|
|
do_edit(cursheet, '\0', NULL, STYLE_CONT);
|
|
break;
|
|
/*}}}*/
|
|
/* ", @, digit -- edit current cell with character already in buffer */ /*{{{*/
|
|
case K_BACKSPACE:
|
|
case K_DC:
|
|
case '"':
|
|
case '@':
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
if (moveonly) break;
|
|
do_edit(cursheet, c, NULL, BASE_CONT);
|
|
break;
|
|
/*}}}*/
|
|
/* MARK -- toggle block marking */ /*{{{*/
|
|
case '.':
|
|
case K_MARK: if (moveonly) break; do_mark(cursheet, 0); break;
|
|
/*}}}*/
|
|
/* _("Save sheet file format:") -- save menu */ /*{{{*/
|
|
case K_SAVEMENU: if (moveonly) break; do_save(cursheet); break;
|
|
/*}}}*/
|
|
/* _("Load sheet file format:") -- load menu */ /*{{{*/
|
|
case K_LOAD:
|
|
case K_LOADMENU: if (moveonly) break; do_load(cursheet); break;
|
|
/*}}}*/
|
|
/* _("nN)ame") -- set name */ /*{{{*/
|
|
case K_NAME: if (moveonly) break; do_name(cursheet); break;
|
|
/*}}}*/
|
|
#ifdef ENABLE_HELP
|
|
case K_HELP: show_text(helpfile); break;
|
|
#else
|
|
case K_HELP: show_text(_("Sorry, manual is not installed.")); break;
|
|
#endif
|
|
case K_DUMPCELL: dump_current_cell(cursheet); break;
|
|
case K_ABOUT: show_text(_("<html><head><title>About teapot</title></head><body><center><pre>\n\n"
|
|
" ` ',` ' ' \n"
|
|
" ` ' ` ' ' \n"
|
|
" `' ' '`' \n"
|
|
" ' ` ' '` \n"
|
|
" ' '` ' ` '`` ` \n"
|
|
" `. Table Editor And Planner, or: \n"
|
|
" , . , , . . \n"
|
|
" ` ' ` ' ' \n"
|
|
" `::\\ /:::::::::::::::::\\ ___ \n"
|
|
" `::\\ /:::::::::::::::::::\\,'::::\\ \n"
|
|
" :::\\/:::::::::::::::::::::\\/ \\:\\ \n"
|
|
" :::::::::::::::::::::::::::\\ ::: \n"
|
|
" ::::::::::::::::::::::::::::; /:;' \n"
|
|
" `::::::::::::::::::::::::::::_/:;' \n"
|
|
" `::::::::::::::::::::::::::::' \n"
|
|
" `////////////////////////' \n"
|
|
" `:::::::::::::::::::::' \n"
|
|
"</pre>\n"
|
|
"<p>Teapot " VERSION "</p>\n"
|
|
"\n"
|
|
"<p>Original Version: Michael Haardt<br>\n"
|
|
"Current Maintainer: Joerg Walter<br>\n"
|
|
"Contributions by: Glen Whitney<br>\b"
|
|
"Home Page: <a href='http://www.syntax-k.de/projekte/teapot/'>http://www.syntax-k.de/projekte/teapot/</a></p>\n"
|
|
"This distribution: <a href='https://code.studioinfinity.org/glen/teapot-spreadsheet/'>https://code.studioinfinity.org/glen/teapot-spreadsheet/</a></p>\n"
|
|
"\n"
|
|
"<p>Copyright 1995-2006 Michael Haardt,<br>\n"
|
|
"Copyright 2009-2010 Joerg Walter (<a href='mailto:info@syntax-k.de'>info@syntax-k.de</a>)<br>"
|
|
"Copyright 2019,2023 Glen Whitney</p></center>\n"
|
|
"\f"
|
|
"<p>This program is free software: you can redistribute it and/or modify\n"
|
|
"it under the terms of the GNU General Public License as published by\n"
|
|
"the Free Software Foundation, either version 3 of the License, or\n"
|
|
"(at your option) any later version.</p>\n"
|
|
"\n"
|
|
"<p>This program is distributed in the hope that it will be useful,\n"
|
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
|
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
|
"GNU General Public License for more details.</p>\n"
|
|
"\n"
|
|
"<p>You should have received a copy of the GNU General Public License\n"
|
|
"along with this program. If not, see <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.</p>"
|
|
"</body></html>"));
|
|
break;
|
|
/* MENU, / -- main menu */ /*{{{*/
|
|
case '/': if (!moveonly && do_sheetcmd(cursheet, show_menu(cursheet), 0)) return 1; break;
|
|
/*}}}*/
|
|
/* _("sS)ave") -- save in current native format */ /*{{{*/
|
|
case K_SAVE: do_save(cursheet); break;
|
|
/*}}}*/
|
|
/* _("cC)opy") -- copy block */ /*{{{*/
|
|
case K_COPY: if (moveonly) break; do_move(cursheet,1,1); break;
|
|
/*}}}*/
|
|
/* RECALC -- recalculate */ /*{{{*/
|
|
case K_RECALC: if (moveonly) break; forceupdate(cursheet); break;
|
|
/*}}}*/
|
|
/* _("Usage: clock(condition,location[,location])") -- clock */ /*{{{*/
|
|
case K_CLOCK:
|
|
{
|
|
Location w;
|
|
|
|
for (ALL_LOCS_IN_SHEET(cursheet, w))
|
|
clk(cursheet, w);
|
|
update(cursheet);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* NPAGE -- page down */ /*{{{*/
|
|
case K_NPAGE:
|
|
{
|
|
cursheet->offy += ((CoordT)(cursheet->maxy)-3);
|
|
relmoveto(cursheet, 0, (CoordT)(cursheet->maxy)-3, 0);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* PPAGE -- page up */ /*{{{*/
|
|
case K_PPAGE:
|
|
{
|
|
cursheet->offy =
|
|
cursheet->offy >= (CoordT)(cursheet->maxy) - 3
|
|
? cursheet->offy - (CoordT)(cursheet->maxy) + 3 : 0;
|
|
relmoveto(cursheet, 0,
|
|
cursheet->cur[Y] >= ((CoordT)(cursheet->maxy) - 3)
|
|
? -((CoordT)(cursheet->maxy) - 3) : -cursheet->cur[Y],
|
|
0);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* FPAGE -- page right */ /*{{{*/
|
|
case K_FPAGE:
|
|
{
|
|
cursheet->offx += (CoordT)cursheet->width;
|
|
relmoveto(cursheet, (CoordT)(cursheet->width), 0, 0);
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* BPAGE -- page left */ /*{{{*/
|
|
case K_BPAGE:
|
|
cursheet->offx = (size_t)(cursheet->offx) >= cursheet->width
|
|
? cursheet->offx - (CoordT)(cursheet->width) : 0;
|
|
relmoveto(cursheet,
|
|
((size_t)(cursheet->cur[X]) >= cursheet->width
|
|
? -((CoordT)(cursheet->width)) : -cursheet->cur[X]),
|
|
0, 0);
|
|
break;
|
|
/*}}}*/
|
|
/* SAVEQUIT -- save and quit */ /*{{{*/
|
|
case K_SAVEQUIT:
|
|
{
|
|
if (moveonly) break;
|
|
if (do_save(cursheet)!=-2) return 1;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* _("qQ)uit") -- quit */ /*{{{*/
|
|
case K_QUIT: if (moveonly) break; return 1;
|
|
/*}}}*/
|
|
default:
|
|
if (isalpha(c) && !moveonly) do_edit(cursheet, c, NULL, BASE_CONT);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* main */ /*{{{*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
/* variables */ /*{{{*/
|
|
Sheet sheet,*cursheet;
|
|
int o;
|
|
const char *loadfile;
|
|
char ln[1024];
|
|
/*}}}*/
|
|
|
|
setlocale(LC_ALL, "");
|
|
find_helpfile(helpfile, sizeof(helpfile), argv[0]);
|
|
|
|
/* parse options */ /*{{{*/
|
|
while ((o=getopt(argc,argv,"bdhnrqHp:F:?"))!=EOF) switch (o)
|
|
{
|
|
/* b -- run batch */ /*{{{*/
|
|
case 'b': batch = true; break;
|
|
/*}}}*/
|
|
/* d -- increase debug level */ /*{{{*/
|
|
case 'd': ++debug_level; break;
|
|
/*}}}*/
|
|
/* n -- no quoted strings */ /*{{{*/
|
|
case 'n': quote = DIRECT_STRING; break;
|
|
/*}}}*/
|
|
/* q -- force quoted strings */ /*{{{*/
|
|
case 'q': quote = QUOTE_STRING; break;
|
|
/*}}}*/
|
|
/* H -- no row/column headers */ /*{{{*/
|
|
case 'H': header = false; break;
|
|
/*}}}*/
|
|
/* r -- always redraw */ /*{{{*/
|
|
case 'r':
|
|
{
|
|
always_redraw = true;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* p -- precision */ /*{{{*/
|
|
case 'p':
|
|
{
|
|
long n;
|
|
char *end;
|
|
|
|
n = strtol(optarg,&end,0);
|
|
if (*end || n < 0 || n > FLT_T_DIG)
|
|
{
|
|
fprintf(stderr,
|
|
_("teapot: default precision must be between 0 and %d.\n"),
|
|
FLT_T_DIG);
|
|
exit(1);
|
|
}
|
|
def_precision = (PrecisionLevel)n;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* F -- font size */ /*{{{*/
|
|
case 'F':
|
|
{
|
|
long f;
|
|
char *end;
|
|
|
|
f = strtol(optarg, &end, 0);
|
|
if (*end || f < 1) {
|
|
fprintf(stderr, _("teapot: font size must be positive.\n"));
|
|
exit(1);
|
|
}
|
|
fontsize = (int)f;
|
|
break;
|
|
}
|
|
/*}}}*/
|
|
/* default -- includes ? and h */ /*{{{*/
|
|
default:
|
|
{
|
|
fprintf(stderr,_(
|
|
"Usage: %s [-abFhHr] [-d]* [-n|-q] [-p digits] [file]\n"
|
|
" -a: use ASCII file format as default\n"
|
|
" -b: batch mode\n"
|
|
" -d: increase debug level, once for each occurrence\n"
|
|
" -F nn: set font size to nn\n"
|
|
" -h: print this message and exit\n"
|
|
" -H: hide row/column headers\n"
|
|
" -n|-q: DO NOT or DO display strings in quotes, respectively\n"
|
|
" -p nn: set decimal precision to nn\n"
|
|
" -r: redraw more often\n"
|
|
), argv[0]);
|
|
exit(1);
|
|
}
|
|
/*}}}*/
|
|
}
|
|
loadfile = (optind<argc ? argv[optind] : (const char*)0);
|
|
/*}}}*/
|
|
cursheet = &sheet;
|
|
initialize_sheet(cursheet);
|
|
if (loadfile) /* load given sheet */ /*{{{*/
|
|
{
|
|
const char *msg;
|
|
|
|
cursheet->name=strdup(loadfile);
|
|
if (usexdr)
|
|
{
|
|
if ((msg=loadxdr(cursheet, cursheet->name)) != NULL)
|
|
line_msg(_("Load sheet from XDR file:"), msg);
|
|
}
|
|
else
|
|
if ((msg=loadport(cursheet, cursheet->name)) != NULL)
|
|
line_msg(_("Load sheet from ASCII file:"),msg);
|
|
}
|
|
/*}}}*/
|
|
if (batch) /* process batch */ /*{{{*/
|
|
while (fgets(ln,sizeof(ln),stdin)!=(char*)0)
|
|
{
|
|
/* variables */ /*{{{*/
|
|
size_t len;
|
|
char *cmd,*arg;
|
|
/*}}}*/
|
|
|
|
/* set cmd and arg */ /*{{{*/
|
|
++batchln;
|
|
len=strlen(ln);
|
|
if (len && ln[len-1]=='\n') ln[len-1]='\0';
|
|
cmd=ln; while (isspace((int)*cmd)) ++cmd;
|
|
arg=cmd;
|
|
while (*arg && !isspace((int)*arg)) ++arg;
|
|
while (isspace((int)*arg)) *arg++='\0';
|
|
/*}}}*/
|
|
|
|
/* goto location */ /*{{{*/
|
|
if (strcmp(cmd,"goto")==0) do_goto(cursheet,arg);
|
|
/*}}}*/
|
|
/* from location */ /*{{{*/
|
|
else if (strcmp(cmd,"from")==0)
|
|
{
|
|
do_goto(cursheet,arg);
|
|
do_mark(cursheet,1);
|
|
}
|
|
/*}}}*/
|
|
/* to location */ /*{{{*/
|
|
else if (strcmp(cmd,"to")==0)
|
|
{
|
|
do_goto(cursheet,arg);
|
|
do_mark(cursheet,2);
|
|
}
|
|
/*}}}*/
|
|
/* save-tbl file */ /*{{{*/
|
|
else if (strcmp(cmd,"save-tbl")==0) do_savetbl(cursheet,arg);
|
|
/*}}}*/
|
|
/* save-latex file */ /*{{{*/
|
|
else if (strcmp(cmd,"save-latex")==0) do_savelatex(cursheet,arg);
|
|
/*}}}*/
|
|
/* save-context file */ /*{{{*/
|
|
else if (strcmp(cmd,"save-context")==0) do_savecontext(cursheet,arg);
|
|
/*}}}*/
|
|
/* save-csv file */ /*{{{*/
|
|
else if (strcmp(cmd,"save-csv")==0) do_savecsv(cursheet,arg);
|
|
/*}}}*/
|
|
/* save-html file */ /*{{{*/
|
|
else if (strcmp(cmd,"save-html")==0) do_savehtml(cursheet,arg);
|
|
/*}}}*/
|
|
/* load-csv file */ /*{{{*/
|
|
else if (strcmp(cmd,"load-csv")==0) { loadcsv(cursheet,arg); forceupdate(cursheet); }
|
|
/*}}}*/
|
|
/* sort in x direction */ /*{{{*/
|
|
else if (strcmp(cmd,"sort-x")==0) do_batchsort(cursheet, X, arg);
|
|
/*}}}*/
|
|
/* sort in y direction */ /*{{{*/
|
|
else if (strcmp(cmd,"sort-y")==0) do_batchsort(cursheet, Y, arg);
|
|
/*}}}*/
|
|
/* sort in z direction */ /*{{{*/
|
|
else if (strcmp(cmd,"sort-z")==0) do_batchsort(cursheet, Z, arg);
|
|
/*}}}*/
|
|
/* this is an unknown command */ /*{{{*/
|
|
else line_msg(_("Unknown batch command:"),cmd);
|
|
/*}}}*/
|
|
}
|
|
/*}}}*/
|
|
else /* process interactive input */ /*{{{*/
|
|
display_main(cursheet);
|
|
/*}}}*/
|
|
freesheet(cursheet,1);
|
|
fclose(stdin);
|
|
return 0;
|
|
}
|
|
/*}}}*/
|