2019-07-22 20:32:33 +00:00
|
|
|
/* #includes */ /*{{{C}}}*//*{{{*/
|
|
|
|
#ifdef DMALLOC
|
|
|
|
#include "dmalloc.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
2019-07-27 04:14:26 +00:00
|
|
|
#include <stdbool.h>
|
2019-07-22 20:32:33 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "csv.h"
|
|
|
|
#include "default.h"
|
|
|
|
#include "display.h"
|
|
|
|
#include "eval.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "parser.h"
|
|
|
|
#include "scanner.h"
|
|
|
|
#include "sheet.h"
|
|
|
|
#include "utf8.h"
|
|
|
|
#include "xdr.h"
|
|
|
|
|
|
|
|
/*}}}*/
|
|
|
|
/* #defines */ /*{{{*/
|
|
|
|
#define HASH(x,s) \
|
|
|
|
{ \
|
|
|
|
const unsigned char *S=(const unsigned char*)s; \
|
|
|
|
\
|
|
|
|
x=0; \
|
|
|
|
while (*S) { x=(x<<5)+((x>>27)^*S); ++S; } \
|
|
|
|
x%=LABEL_CACHE; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
static int upd_clock; /* evaluate clocked expressions */
|
|
|
|
/* Used during evaluation of a cell to specify the currently updated cell */
|
|
|
|
Sheet *upd_sheet;
|
2019-07-27 04:14:26 +00:00
|
|
|
Location upd_l;
|
2019-07-22 20:32:33 +00:00
|
|
|
int max_eval;
|
|
|
|
/*}}}*/
|
|
|
|
|
2019-07-27 07:00:03 +00:00
|
|
|
/* copycelltosheet -- copy a cell into a sheet*/ /*{{{*/
|
|
|
|
static void copycelltosheet(const Cell *fromcell,
|
|
|
|
Sheet *sheet2, const Location to)
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet2 != (Sheet*)0);
|
|
|
|
|
2019-07-27 07:00:03 +00:00
|
|
|
freecellofsheet(sheet2, to);
|
2019-07-27 04:14:26 +00:00
|
|
|
if (fromcell != NULLCELL)
|
|
|
|
/* copy first cell to second */ /*{{{*/
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
sheet2->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
Cell *tocell = initcellofsheet(sheet2, to);
|
|
|
|
copycell(tocell, fromcell);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
/*}}}*/
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
/* dump_cell -- write internal contents of cell to standard out */ /*{{{*/
|
|
|
|
static void dump_cell(Sheet *sheet, int x, int y, int z)
|
|
|
|
{
|
|
|
|
Cell* c;
|
|
|
|
char buf[2048];
|
|
|
|
|
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
if (x < 0 || y < 0 || z < 0)
|
|
|
|
{
|
|
|
|
printf("TEADUMP: Requested cell &(%d,%d,%d) has negative coordinates.\n",
|
|
|
|
x, y, z);
|
|
|
|
return;
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
if (!LOC_WITHINC(sheet, x, y, z))
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
{
|
|
|
|
printf("TEADUMP: Requested cell &(%d,%d,%d) outside sheet dims %d,%d,%d.\n",
|
|
|
|
x, y, z, sheet->dimx, sheet->dimy, sheet->dimz);
|
|
|
|
return;
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
c = CELL_ATC(sheet, x, y, z);
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (c == NULLCELL)
|
|
|
|
{
|
|
|
|
printf("TEADUMP: Cell at &(%d,%d,%d) is empty.\n", x, y, z);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
printf("TEADUMP of &(%d,%d,%d):\n", x, y, z);
|
2019-07-27 04:14:26 +00:00
|
|
|
print(buf, sizeof(buf), 0, 1, 0, -1, c->contents[BASE]);
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
printf(" Base expr: %s.\n", buf);
|
2019-07-27 04:14:26 +00:00
|
|
|
print(buf, sizeof(buf), 0, 1, 0, -1, c->contents[ITERATIVE]);
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
printf(" Update expr: %s.\n", buf);
|
|
|
|
if (c->label == (char *)0) printf("\n No label.\n");
|
|
|
|
else printf("\n Label: %s.\n", c->label);
|
|
|
|
printtok(buf, sizeof(buf), 0, 1, 0, -1, 1, &(c->value));
|
|
|
|
printf(" Current value: %s.\n", buf);
|
|
|
|
printtok(buf, sizeof(buf), 0, 1, 0, -1, 1, &(c->resvalue));
|
|
|
|
printf(" Stored result value: %s.\n Adjustment: ", buf);
|
|
|
|
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(" Precision: %d\n Attributes: ", c->precision);
|
|
|
|
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 ");
|
|
|
|
if (c->clock_t0) printf("clock_t0 ");
|
|
|
|
if (c->clock_t1) printf("clock_t1 ");
|
|
|
|
if (c->clock_t2) printf("clock_t2 ");
|
|
|
|
if (c->bold) printf("bold ");
|
|
|
|
if (c->underline) printf("underline ");
|
|
|
|
printf("\n\n");
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
/* dump_current_cell -- dump_cell of the current_cell */ /*{{{*/
|
|
|
|
void dump_current_cell(Sheet *sheet)
|
|
|
|
{
|
|
|
|
assert(sheet != (Sheet *)0);
|
2019-07-27 04:14:26 +00:00
|
|
|
dump_cell(sheet, sheet->cur[X], sheet->cur[Y], sheet->cur[Z]);
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* swapblock -- swap two non-overlapping blocks of cells */ /*{{{*/
|
|
|
|
static void swapblock(Sheet *sheet1, int x1, int y1, int z1, Sheet *sheet2, int x2, int y2, int z2, int xdist, int ydist, int zdist)
|
|
|
|
{
|
|
|
|
int xoff, yoff, zoff;
|
|
|
|
|
|
|
|
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);
|
|
|
|
for (xoff=0; xoff<xdist; ++xoff)
|
|
|
|
for (yoff=0; yoff<ydist; ++yoff)
|
|
|
|
for (zoff=0; zoff<zdist; ++zoff)
|
|
|
|
{
|
|
|
|
Cell *t;
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
t = CELL_ATC(sheet1,x1+xoff,y1+yoff,z1+zoff);
|
|
|
|
CELL_ATC(sheet1,x1+xoff,y1+yoff,z1+zoff) = CELL_ATC(sheet2,x2+xoff,y2+yoff,z2+zoff);
|
|
|
|
CELL_ATC(sheet2,x2+xoff,y2+yoff,z2+zoff) = t;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
sheet1->changed=1;
|
|
|
|
sheet2->changed=1;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* cmpcell -- compare to cells with given order flags */ /*{{{*/
|
|
|
|
/* Notes */ /*{{{*/
|
|
|
|
/*
|
|
|
|
Compare the _values_ of two cells. The result is -1 if first is smaller
|
|
|
|
than second, 0 if they are equal and 1 if the first is bigger than the
|
|
|
|
second. A result of 2 means they are not comparable.
|
|
|
|
*/
|
|
|
|
/*}}}*/
|
|
|
|
static int cmpcell(Sheet *sheet1, int x1, int y1, int z1, Sheet *sheet2, int x2, int y2, int z2, int sortkey)
|
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
Cell *leftcell, *rightcell;
|
2019-07-22 20:32:33 +00:00
|
|
|
assert(sheet1!=(Sheet*)0);
|
|
|
|
assert(sheet2!=(Sheet*)0);
|
|
|
|
/* empty cells are smaller than any non-empty cell */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
if (!CELL_IS_GOODC(sheet1,x1,y1,z1) || CELL_ATC(sheet1,x1,y1,z1)->value.type==EMPTY)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (!CELL_IS_GOODC(sheet2,x2,y2,z2) || CELL_ATC(sheet2,x2,y2,z2)->value.type==EMPTY) return 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
else return (sortkey&ASCENDING ? -1 : 1);
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
if (!CELL_IS_GOODC(sheet2,x2,y2,z2) || CELL_ATC(sheet2,x2,y2,z2)->value.type==EMPTY) return (sortkey&ASCENDING ? 1 : -1);
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
leftcell = CELL_ATC(sheet1,x1,y1,z1);
|
|
|
|
rightcell = CELL_ATC(sheet2,x2,y2,z2);
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
switch (leftcell->value.type)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* STRING */ /*{{{*/
|
|
|
|
case STRING:
|
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (rightcell->value.type==STRING)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
r=strcmp(leftcell->value.u.string, rightcell->value.u.string);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (r<0) return (sortkey&ASCENDING ? -1 : 1);
|
|
|
|
else if (r==0) return 0;
|
|
|
|
else return (sortkey&ASCENDING ? 1 : -1);
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* FLOAT */ /*{{{*/
|
|
|
|
case FLOAT:
|
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (rightcell->value.type==FLOAT)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (leftcell->value.u.flt<rightcell->value.u.flt) return (sortkey&ASCENDING ? -1 : 1);
|
|
|
|
else if (leftcell->value.u.flt==rightcell->value.u.flt) return 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
else return (sortkey&ASCENDING ? 1 : -1);
|
|
|
|
}
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (rightcell->value.type==INT)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (leftcell->value.u.flt<rightcell->value.u.integer) return (sortkey&ASCENDING ? -1 : 1);
|
|
|
|
else if (leftcell->value.u.flt==rightcell->value.u.integer) return 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
else return (sortkey&ASCENDING ? 1 : -1);
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* INT */ /*{{{*/
|
|
|
|
case INT:
|
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (rightcell->value.type==INT)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (leftcell->value.u.integer<rightcell->value.u.integer) return (sortkey&ASCENDING ? -1 : 1);
|
|
|
|
else if (leftcell->value.u.integer==rightcell->value.u.integer) return 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
else return (sortkey&ASCENDING ? 1 : -1);
|
|
|
|
}
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (rightcell->value.type==FLOAT)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
if (leftcell->value.u.integer<rightcell->value.u.flt) return (sortkey&ASCENDING ? -1 : 1);
|
|
|
|
else if (leftcell->value.u.integer==rightcell->value.u.flt) return 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
else return (sortkey&ASCENDING ? 1 : -1);
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
default: return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
/* initialize_sheet -- fill in fields of a newly allocated Sheet */ /*{{{*/
|
|
|
|
void initialize_sheet(Sheet *sheet) {
|
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
OLOCATION(sheet->cur);
|
|
|
|
sheet->offx = sheet->offy = 0;
|
|
|
|
sheet->dimx = sheet->dimy = sheet->dimz = 0;
|
|
|
|
sheet->sheet = (Cell**)0;
|
|
|
|
sheet->column = (int*)0;
|
|
|
|
sheet->orix = sheet->oriy = 0;
|
|
|
|
sheet->maxx = sheet->maxy = 0;
|
|
|
|
sheet->name = (char*)0;
|
|
|
|
OLOCATION(sheet->mark1);
|
|
|
|
OLOCATION(sheet->mark2);
|
|
|
|
sheet->marking = UNMARKED;
|
|
|
|
sheet->changed = 0;
|
|
|
|
sheet->moveonly = 0;
|
|
|
|
sheet->clk = 0;
|
|
|
|
(void)memset(sheet->labelcache, 0, sizeof(sheet->labelcache));
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* resize -- check if sheet needs to be resized in any dimension */ /*{{{*/
|
|
|
|
void resize(Sheet *sheet, int x, int y, int z)
|
|
|
|
{
|
|
|
|
assert(x>=0);
|
|
|
|
assert(y>=0);
|
|
|
|
assert(z>=0);
|
|
|
|
assert(sheet!=(Sheet*)0);
|
2019-07-27 04:14:26 +00:00
|
|
|
|
|
|
|
if (!LOC_WITHINC(sheet,x,y,z))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
Sheet dummy;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
sheet->changed=1;
|
2019-07-27 04:14:26 +00:00
|
|
|
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);
|
2019-07-22 20:32:33 +00:00
|
|
|
/* allocate new sheet */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
dummy.sheet = malloc(dummy.dimx*dummy.dimy*dummy.dimz*sizeof(Cell*));
|
|
|
|
for (ALL_COORDS_IN_SHEETC(&dummy,x,y,z))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (LOC_WITHINC(sheet,x,y,z)) CELL_ATC(&dummy,x,y,z) = CELL_ATC(sheet,x,y,z);
|
|
|
|
else CELL_ATC(&dummy,x,y,z) = NULLCELL;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
if (sheet->sheet!=(Cell**)0) free(sheet->sheet);
|
2019-07-27 04:14:26 +00:00
|
|
|
sheet->sheet = dummy.sheet;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
/* allocate new columns */ /*{{{*/
|
|
|
|
if (x>sheet->dimx || z>=sheet->dimz)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
dummy.column=malloc(dummy.dimx*dummy.dimz*sizeof(int));
|
|
|
|
for (x=0; x<dummy.dimx; ++x) for (z=0; z<dummy.dimz; ++z)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (x<sheet->dimx && z<sheet->dimz)
|
|
|
|
*(dummy.column+x*dummy.dimz+z)=*(sheet->column+x*sheet->dimz+z);
|
|
|
|
else *(dummy.column+x*dummy.dimz+z)=DEF_COLUMNWIDTH;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
if (sheet->column!=(int*)0) free(sheet->column);
|
2019-07-27 04:14:26 +00:00
|
|
|
sheet->column = dummy.column;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
sheet->dimx = dummy.dimx;
|
|
|
|
sheet->dimy = dummy.dimy;
|
|
|
|
sheet->dimz = dummy.dimz;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-27 07:00:03 +00:00
|
|
|
/* initcellofsheet -- initialise new cell, if it does not exist yet */ /*{{{*/
|
|
|
|
Cell *initcellofsheet(Sheet *sheet, const Location at)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
Cell *nc;
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(IN_OCTANT(at));
|
|
|
|
resize(sheet, at[X], at[Y], at[Z]);
|
|
|
|
nc = CELL_AT(sheet,at);
|
|
|
|
if (nc == NULLCELL)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
sheet->changed = 1;
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
nc = malloc(sizeof(Cell));
|
2019-07-27 04:14:26 +00:00
|
|
|
CELL_AT(sheet,at) = nc;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellcontents(nc);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
return nc;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
|
|
|
/* safe_cell_at -- returns pointer to the cell at the given location,
|
|
|
|
even in the face of various edge conditions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
Cell *safe_cell_at(Sheet *sheet, const Location at)
|
|
|
|
{
|
|
|
|
if (sheet == (Sheet*)0) return NULLCELL;
|
|
|
|
if (sheet->sheet == (Cell **)0) return NULLCELL;
|
|
|
|
if (!LOC_WITHIN(sheet, at)) return NULLCELL;
|
|
|
|
return CELL_AT(sheet, at);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* curcell -- return pointer to the current cell */ /*{{{*/
|
|
|
|
Cell *curcell(Sheet *sheet)
|
|
|
|
{
|
|
|
|
return safe_cell_at(sheet, sheet->cur);
|
|
|
|
}
|
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* cachelabels -- create new label cache */ /*{{{*/
|
|
|
|
void cachelabels(Sheet *sheet)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
int i;
|
|
|
|
Location w;
|
2019-07-22 20:32:33 +00:00
|
|
|
|
|
|
|
if (sheet==(Sheet*)0) return;
|
|
|
|
for (i=0; i<LABEL_CACHE; ++i) /* free bucket */ /*{{{*/
|
|
|
|
{
|
|
|
|
struct Label *run;
|
|
|
|
|
|
|
|
for (run=sheet->labelcache[i]; run!=(struct Label*)0;)
|
|
|
|
{
|
|
|
|
struct Label *runnext;
|
|
|
|
|
|
|
|
runnext=run->next;
|
|
|
|
free(run);
|
|
|
|
run=runnext;
|
|
|
|
}
|
|
|
|
sheet->labelcache[i]=(struct Label*)0;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
for (ALL_LOCS_IN_SHEET(sheet,w))
|
2019-07-22 20:32:33 +00:00
|
|
|
/* cache all labels */ /*{{{*/
|
|
|
|
{
|
|
|
|
const char *l;
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
l = getlabel(CELL_AT(sheet,w));
|
2019-07-22 20:32:33 +00:00
|
|
|
if (*l)
|
|
|
|
{
|
|
|
|
unsigned long hx;
|
|
|
|
struct Label **run;
|
|
|
|
|
|
|
|
HASH(hx,l);
|
|
|
|
for (run=&sheet->labelcache[(unsigned int)hx]; *run!=(struct Label*)0 && strcmp(l,(*run)->label); run=&((*run)->next));
|
|
|
|
if (*run==(struct Label*)0)
|
|
|
|
{
|
|
|
|
*run=malloc(sizeof(struct Label));
|
|
|
|
(*run)->next=(struct Label*)0;
|
|
|
|
(*run)->label=l;
|
2019-07-27 04:14:26 +00:00
|
|
|
LOCATION_GETS((*run)->location,w);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/* else we have a duplicate label, which _can_ happen under */
|
|
|
|
/* unfortunate conditions. Don't tell anybody. */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* freesheet -- free all cells of an entire spread sheet */ /*{{{*/
|
|
|
|
void freesheet(Sheet *sheet, int all)
|
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
Location w;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
assert(sheet!=(Sheet*)0);
|
|
|
|
sheet->changed=0;
|
2019-07-27 04:14:26 +00:00
|
|
|
for (ALL_LOCS_IN_SHEET(sheet,w))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 07:00:03 +00:00
|
|
|
freecellofsheet(sheet,w);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
if (all)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<LABEL_CACHE; ++i) /* free all buckets */ /*{{{*/
|
|
|
|
{
|
|
|
|
struct Label *run;
|
|
|
|
|
|
|
|
for (run=sheet->labelcache[i]; run!=(struct Label*)0;)
|
|
|
|
{
|
|
|
|
struct Label *runnext;
|
|
|
|
|
|
|
|
runnext=run->next;
|
|
|
|
free(run);
|
|
|
|
run=runnext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
if (sheet->sheet) free(sheet->sheet);
|
|
|
|
if (sheet->column) free(sheet->column);
|
|
|
|
if (sheet->name) free(sheet->name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
int x,z;
|
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
for (x=0; x<sheet->dimx; ++x) for (z=0; z<sheet->dimz; ++z)
|
|
|
|
{
|
|
|
|
*(sheet->column+x*sheet->dimz+z)=DEF_COLUMNWIDTH;
|
|
|
|
}
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* forceupdate -- clear all clock and update flags */ /*{{{*/
|
|
|
|
void forceupdate(Sheet *sheet)
|
|
|
|
{
|
|
|
|
int i;
|
2019-07-27 04:14:26 +00:00
|
|
|
Cell *cell;
|
2019-07-22 20:32:33 +00:00
|
|
|
|
|
|
|
assert(sheet!=(Sheet*)0);
|
2019-07-27 04:14:26 +00:00
|
|
|
for (ALL_CELLS_IN_SHEET(sheet,i,cell))
|
|
|
|
if (cell != NULLCELL)
|
|
|
|
cell->updated = cell->clock_t0 = cell->clock_t1 = cell->clock_t2 = 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
update(sheet);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-27 07:00:03 +00:00
|
|
|
/* freecellofsheet -- free one cell */ /*{{{*/
|
|
|
|
void freecellofsheet(Sheet *sheet, const Location at)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
if (sheet->sheet != (Cell**)0 && CELL_IS_GOOD(sheet,at))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 07:00:03 +00:00
|
|
|
Cell *c = CELL_AT(sheet,at);
|
|
|
|
freecellcontents(c);
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
free(c);
|
2019-07-27 04:14:26 +00:00
|
|
|
CELL_AT(sheet,at) = NULLCELL;
|
|
|
|
sheet->changed = 1;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* columnwidth -- get width of column */ /*{{{*/
|
|
|
|
int columnwidth(Sheet *sheet, int x, int z)
|
|
|
|
{
|
|
|
|
assert(sheet!=(Sheet*)0);
|
|
|
|
if (x<sheet->dimx && z<sheet->dimz) return (*(sheet->column+x*sheet->dimz+z));
|
|
|
|
else return DEF_COLUMNWIDTH;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* setwidth -- set width of column */ /*{{{*/
|
|
|
|
void 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;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* cellwidth -- get width of a cell */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
int cellwidth(Sheet *sheet, const Location at)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
int width,x;
|
2019-07-22 20:32:33 +00:00
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
if (SHADOWED(sheet,at)) return 0;
|
|
|
|
x = at[X];
|
|
|
|
width = columnwidth(sheet,x,at[Z]);
|
|
|
|
for (++x; SHADOWEDC(sheet,x,at[Y],at[Z]);
|
|
|
|
width += columnwidth(sheet,x,at[Z]), ++x);
|
2019-07-22 20:32:33 +00:00
|
|
|
return width;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* putcont -- assign new contents */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void putcont(Sheet *sheet, const Location at, Token **t, ContentVariety v)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
Cell *cell;
|
|
|
|
|
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
cell = initcellofsheet(sheet, at);
|
2019-07-27 04:14:26 +00:00
|
|
|
tvecfree(cell->contents[v]);
|
|
|
|
cell->contents[v] = t;
|
|
|
|
redraw_cell(sheet, at);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* getvalue -- get tcopy()ed value */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
Token getvalue(Sheet *sheet, const Location at)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
Token result;
|
|
|
|
int orig_upd_clock;
|
2019-07-27 04:14:26 +00:00
|
|
|
Cell* cell;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
assert(sheet!=(Sheet*)0);
|
2019-07-27 04:14:26 +00:00
|
|
|
if (!IN_OCTANT(at))
|
2019-07-22 20:32:33 +00:00
|
|
|
/* return error */ /*{{{*/
|
|
|
|
{
|
|
|
|
result.type=EEK;
|
|
|
|
result.u.err=mystrmalloc(_("Negative index"));
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
return result;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
result.type = EMPTY;
|
|
|
|
/* Can always short-circuit an out-of-bounds or empty cell */
|
2019-07-27 04:14:26 +00:00
|
|
|
if (!CELL_IS_GOOD(sheet,at)) return result;
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
/* only short-circuit on empty contents of a good cell if we are NOT
|
|
|
|
depending on this call to update the current value
|
|
|
|
*/
|
2019-07-27 04:14:26 +00:00
|
|
|
cell = CELL_AT(sheet, at);
|
|
|
|
if (!upd_clock && getcont(cell,2) == EMPTY_TVEC) return result;
|
2019-07-22 20:32:33 +00:00
|
|
|
/* update value of this cell if needed and return it */ /*{{{*/
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
orig_upd_clock = upd_clock;
|
2019-07-27 04:14:26 +00:00
|
|
|
if (cell->ignored)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
/* variables */ /*{{{*/
|
|
|
|
Token oldvalue;
|
|
|
|
/*}}}*/
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
oldvalue = cell->value;
|
|
|
|
cell->updated = 1;
|
|
|
|
cell->value.type = EMPTY;
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
tfree(&oldvalue);
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
else if (cell->updated == 0)
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
Sheet *old_sheet;
|
2019-07-27 04:14:26 +00:00
|
|
|
Location old_l;
|
|
|
|
int old_max_eval;
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
Token oldvalue;
|
|
|
|
/*}}}*/
|
2019-07-22 20:32:33 +00:00
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
old_sheet = upd_sheet;
|
|
|
|
LOCATION_GETS(old_l, upd_l);
|
|
|
|
old_max_eval = max_eval;
|
|
|
|
upd_sheet = sheet;
|
|
|
|
LOCATION_GETS(upd_l, at);
|
|
|
|
max_eval = MAX_EVALNEST;
|
|
|
|
if (cell->clock_t1 == 0)
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
cell->updated = 1;
|
|
|
|
oldvalue = cell->value;
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
upd_clock = 0;
|
2019-07-27 04:14:26 +00:00
|
|
|
cell->value = eval_safe(getcont(cell, 2));
|
2019-07-22 20:32:33 +00:00
|
|
|
tfree(&oldvalue);
|
|
|
|
}
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
else if (upd_clock)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
cell->updated = 1;
|
|
|
|
upd_clock = 0;
|
|
|
|
oldvalue = cell->resvalue;
|
|
|
|
cell->resvalue = eval_safe(getcont(cell,2));
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
tfree(&oldvalue);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
upd_sheet = old_sheet;
|
|
|
|
LOCATION_GETS(upd_l, old_l);
|
|
|
|
max_eval = old_max_eval;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
if (!orig_upd_clock) result = tcopy(cell->value);
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* update -- update all cells that need it */ /*{{{*/
|
|
|
|
void update(Sheet *sheet)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
Location w;
|
|
|
|
Cell *cell;
|
|
|
|
int i,kp,iterating;
|
2019-07-22 20:32:33 +00:00
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
kp = 0;
|
|
|
|
iterating = 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
do
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
sheet->clk = 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
if (iterating==1)
|
|
|
|
{
|
|
|
|
line_msg((const char*)0,_("Calculating running, press Escape to abort it"));
|
|
|
|
++iterating;
|
|
|
|
}
|
|
|
|
else if (iterating==0) ++iterating;
|
2019-07-27 04:14:26 +00:00
|
|
|
for (ALL_CELLS_IN_SHEET(sheet,i,cell))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (cell && cell->clock_t2)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
cell->updated = 0;
|
|
|
|
cell->clock_t0 = 1;
|
|
|
|
cell->clock_t1 = 1;
|
|
|
|
cell->clock_t2 = 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
for (ALL_LOCS_IN_SHEET(sheet,w))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
upd_clock = 1;
|
|
|
|
getvalue(sheet, w);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
for (ALL_CELLS_IN_SHEET(sheet,i,cell))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (cell && cell->clock_t1)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
tfree(&(cell->value));
|
|
|
|
cell->value = cell->resvalue;
|
|
|
|
cell->resvalue.type = EMPTY;
|
|
|
|
cell->clock_t1 = 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
upd_clock = 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
} while (sheet->clk && !(kp=keypressed()));
|
2019-07-27 04:14:26 +00:00
|
|
|
if (iterating == 2) line_msg((const char*)0,kp ? _("Calculation aborted") : _("Calculation finished"));
|
|
|
|
sheet->clk = 0;
|
2019-07-22 20:32:33 +00:00
|
|
|
redraw_sheet(sheet);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* geterror -- get malloc()ed error string */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
char *geterror(Sheet *sheet, const Location at)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
Token v;
|
|
|
|
|
|
|
|
assert(sheet!=(Sheet*)0);
|
2019-07-27 04:14:26 +00:00
|
|
|
if ((v = getvalue(sheet,at)).type != EEK)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
tfree(&v);
|
|
|
|
return (char*)0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return (v.u.err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* printvalue -- get ASCII representation of value */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void printvalue(char *s, size_t size, size_t chars, int quote, int scientific, int precision, Sheet *sheet, const Location at)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
Prevent phantom values when clocking, resetting, and clocking again
In the end it turned out that the cause of the phantom values was
short-cutting in getvalue() when the contents of a cell were empty,
preventing the update of the internal cache of the value of the cell.
However, tracking this down (and getting the associated memory management
correct) necessitated implementing a debugging mode in which I could
dump the internal states of cells and print various other stuff to standard
output. It also involved understanding the meaning of various pointers in
the code, in the process of which I renamed some commonly used macros,
particularly the former SHEET(s,x,y,z) which was not returning a Sheet at
all but rather a pointer to a Cell. So this macro is now called CELL_AT. I
also replaced several very repeatedly used patterns of checking the validity
of locations and pointers with macros, now defined in sheet.h.
Therefore, unfortunately the (relatively small in the end) bugfix for this
major issue is entangled with numerous textual changes to the code made
in tracking it down.
Fixes #18.
Closes #19.
2019-07-24 17:47:39 +00:00
|
|
|
Token t;
|
2019-07-22 20:32:33 +00:00
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
t = getvalue(sheet, at);
|
|
|
|
printtok(s, size, chars, quote, scientific, precision, 0, &t);
|
2019-07-22 20:32:33 +00:00
|
|
|
tfree(&t);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* setadjust -- set cell adjustment */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void setadjust(Sheet *sheet, const Location at, Adjust adjust)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet, at)->adjust = adjust;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* shadow -- shadow cell by left neighbour */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void shadow(Sheet *sheet, const Location at, int yep)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet, at)->shadowed = yep;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* bold -- bold font */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void bold(Sheet *sheet, const Location at, int yep)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet,at)->bold = yep;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* underline -- underline */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void underline(Sheet *sheet, const Location at, int yep)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet,at)->underline = yep;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* lockcell -- lock cell */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void lockcell(Sheet *sheet, const Location at, int yep)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet,at)->locked = yep;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* maketrans -- make cell transparent */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void maketrans(Sheet *sheet, const Location at, int yep)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet,at)->transparent = yep;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* igncell -- ignore cell */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void igncell(Sheet *sheet, const Location at, int yep)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet,at)->ignored = yep;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* clk -- clock cell */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void clk(Sheet *sheet, const Location at)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
assert(IN_OCTANT(at));
|
|
|
|
assert(LOC_WITHIN(sheet,at));
|
|
|
|
if (CELL_AT(sheet,at))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
CELL_AT(sheet,at)->clock_t2 = 1;
|
|
|
|
sheet->clk = 1;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* setscientific -- cell value should be displayed in scientific notation */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void setscientific(Sheet *sheet, const Location at, int yep)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet,at)->scientific = yep;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* setprecision -- set cell precision */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void setprecision(Sheet *sheet, const Location at, int precision)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellofsheet(sheet,at)->precision = precision;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
|
|
|
/* getmarkstate -- find out where in the marking cycle the sheet is */ /*{{{*/
|
|
|
|
MarkState getmarkstate(Sheet *sheet) {
|
|
|
|
if (sheet == (Sheet*)0) return MARK_CYCLE;
|
|
|
|
return sheet->marking;
|
|
|
|
}
|
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* setlabel -- set cell label */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void setlabel(Sheet *sheet, const Location at, const char *buf, int update)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
Cell *cell;
|
|
|
|
|
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
sheet->changed = 1;
|
2019-07-27 07:00:03 +00:00
|
|
|
cell = initcellofsheet(sheet, at);
|
2019-07-27 04:14:26 +00:00
|
|
|
if (cell->label != (char*)0) free(cell->label);
|
|
|
|
if (*buf == '\0') cell->label = (char*)0;
|
|
|
|
else cell->label = strcpy(malloc(strlen(buf)+1), buf);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (update)
|
|
|
|
{
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* findlabel -- return cell location for a given label */ /*{{{*/
|
|
|
|
Token findlabel(Sheet *sheet, const char *label)
|
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
Token result;
|
|
|
|
unsigned long hx;
|
|
|
|
struct Label *run;
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
assert(sheet!=(Sheet*)0);
|
|
|
|
/*
|
|
|
|
if (sheet==(Sheet*)0) run=(struct Label*)0;
|
|
|
|
else
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
HASH(hx,label);
|
|
|
|
for (run=sheet->labelcache[(unsigned int)hx]; run!=(struct Label*)0 && strcmp(label,run->label); run=run->next);
|
|
|
|
}
|
|
|
|
if (run)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
result.type = LOCATION;
|
|
|
|
LOCATION_GETS(result.u.location, run->location);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
result.type = EEK;
|
|
|
|
result.u.err = mystrmalloc(_("No such label"));
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* relabel -- search and replace for labels */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void relabel(Sheet *sheet, const Location at,
|
|
|
|
const char *oldlabel, const char *newlabel)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
Token **run;
|
2019-07-27 04:14:26 +00:00
|
|
|
ContentVariety v;
|
|
|
|
Cell *cell;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* asserts */ /*{{{*/
|
|
|
|
assert(oldlabel!=(const char*)0);
|
|
|
|
assert(newlabel!=(const char*)0);
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
if (!LOC_WITHIN(sheet, at)) return;
|
|
|
|
cell = CELL_AT(sheet, at);
|
|
|
|
if (cell != NULLCELL)
|
|
|
|
for (v = BASE; v <= ITERATIVE; ++v)
|
|
|
|
if (cell->contents[v] != EMPTY_TVEC)
|
|
|
|
for (run = cell->contents[v]; *run != NULLTOKEN; ++run)
|
|
|
|
if ((*run)->type==LIDENT && strcmp((*run)->u.lident, oldlabel)==0)
|
|
|
|
{
|
|
|
|
free((*run)->u.lident);
|
|
|
|
(*run)->u.lident = mystrmalloc(newlabel);
|
|
|
|
}
|
2019-07-22 20:32:33 +00:00
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* savexdr -- save a spread sheet in XDR */ /*{{{*/
|
|
|
|
const char *savexdr(Sheet *sheet, const char *name, unsigned int *count)
|
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
FILE *fp;
|
|
|
|
XDR xdrs;
|
|
|
|
int x,y,z;
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
*count=0;
|
|
|
|
if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
|
|
|
xdrstdio_create(&xdrs,fp,XDR_ENCODE);
|
|
|
|
if (!xdr_magic(&xdrs))
|
|
|
|
{
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
(void)fclose(fp);
|
|
|
|
return strerror(errno);
|
|
|
|
}
|
|
|
|
for (x=sheet->dimx-1; x>=0; --x) for (z=sheet->dimz-1; z>=0; --z)
|
|
|
|
{
|
|
|
|
int width;
|
|
|
|
int u;
|
|
|
|
|
|
|
|
width=columnwidth(sheet,x,z);
|
|
|
|
if (width!=DEF_COLUMNWIDTH)
|
|
|
|
{
|
|
|
|
u=0;
|
|
|
|
if (xdr_int(&xdrs,&u)==0 || xdr_column(&xdrs,&x,&z,&width)==0)
|
|
|
|
{
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
(void)fclose(fp);
|
|
|
|
return strerror(errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (y=sheet->dimy-1; y>=0; --y)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (CELL_ATC(sheet,x,y,z)!=NULLCELL)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
u=1;
|
2019-07-27 04:14:26 +00:00
|
|
|
if (xdr_int(&xdrs,&u)==0 || xdr_int(&xdrs,&x)==0 || xdr_int(&xdrs,&y)==0 || xdr_int(&xdrs,&z)==0 || xdr_cell(&xdrs,CELL_ATC(sheet,x,y,z))==0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
(void)fclose(fp);
|
|
|
|
return strerror(errno);
|
|
|
|
}
|
|
|
|
++*count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
if (fclose(fp)==EOF) return strerror(errno);
|
|
|
|
sheet->changed=0;
|
|
|
|
return (const char*)0;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* savetbl -- save as tbl tyble */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
const char *savetbl(Sheet *sheet, const char *name, int body,
|
|
|
|
const Location beg, const Location end,
|
|
|
|
unsigned int *count)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
FILE *fp=(FILE*)0; /* cause run time error */
|
2019-07-27 04:14:26 +00:00
|
|
|
Location w;
|
2019-07-22 20:32:33 +00:00
|
|
|
char buf[1024];
|
|
|
|
char num[20];
|
|
|
|
char fullname[PATH_MAX];
|
2019-07-27 04:14:26 +00:00
|
|
|
Cell *cw;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* asserts */ /*{{{*/
|
|
|
|
assert(sheet!=(Sheet*)0);
|
|
|
|
assert(name!=(const char*)0);
|
|
|
|
/*}}}*/
|
|
|
|
*count=0;
|
2019-07-27 04:14:26 +00:00
|
|
|
w[X] = beg[X];
|
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
|
|
|
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
2019-07-22 20:32:33 +00:00
|
|
|
if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
if (body)
|
|
|
|
/* open new file */ /*{{{*/
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
sprintf(num, ".%d", w[Z]);
|
2019-07-22 20:32:33 +00:00
|
|
|
fullname[sizeof(fullname)-strlen(num)-1]='\0';
|
|
|
|
(void)strncpy(fullname,name,sizeof(fullname)-strlen(num)-1);
|
|
|
|
fullname[sizeof(fullname)-1]='\0';
|
|
|
|
(void)strncat(fullname,num,sizeof(fullname)-strlen(num)-1);
|
|
|
|
fullname[sizeof(fullname)-1]='\0';
|
|
|
|
if ((fp=fopen(fullname,"w"))==(FILE*)0) return strerror(errno);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
else if (fputs_close(".TS\n",fp)==EOF) return strerror(errno);
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* print format */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[Y] > beg[Y] && fputs_close(".T&\n",fp)==EOF) return strerror(errno);
|
|
|
|
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[X] > beg [X] && fputc_close(' ',fp)==EOF) return strerror(errno);
|
|
|
|
cw = CELL_AT(sheet,w);
|
|
|
|
if (shadowed(cw) && fputc_close('s',fp)==EOF) return strerror(errno);
|
|
|
|
if (isbold(cw) && fputc_close('b',fp)==EOF) return strerror(errno);
|
|
|
|
if (underlined(cw) && fputc_close('u',fp)==EOF) return strerror(errno);
|
|
|
|
switch (getadjust(cw))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
case LEFT: if (fputc_close('l',fp)==EOF) return strerror(errno); break;
|
|
|
|
case RIGHT: if (fputc_close('r',fp)==EOF) return strerror(errno); break;
|
|
|
|
case CENTER: if (fputc_close('c',fp)==EOF) return strerror(errno); break;
|
|
|
|
default: assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fputs_close(".\n",fp)==EOF) return strerror(errno);
|
|
|
|
/*}}}*/
|
|
|
|
/* print contents */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
cw = CELL_AT(sheet,w);
|
|
|
|
if (!shadowed(cw))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[X] > beg[X] && fputc_close('\t',fp)==EOF) return strerror(errno);
|
|
|
|
if (cw != NULLCELL)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
char *bufp;
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
printvalue(buf, sizeof(buf), 0, 0, getscientific(cw),
|
|
|
|
getprecision(cw), sheet, w);
|
|
|
|
if (transparent(cw))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
if (fputs_close(buf,fp)==EOF) return strerror(errno);
|
|
|
|
}
|
|
|
|
else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
|
|
|
|
{
|
|
|
|
case '\\':
|
|
|
|
{
|
|
|
|
if (fputc_close('\\',fp)==EOF || fputc_close('e',fp)==EOF) return strerror(errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '_':
|
|
|
|
{
|
|
|
|
if (fputc_close('\\',fp)==EOF || fputc_close('&',fp)==EOF || fputc_close('_',fp)==EOF) return strerror(errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '.':
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[X] == beg[X] && bufp==buf && (fputc_close('\\',fp)==EOF || fputc_close('&',fp)==EOF)) return strerror(errno);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (fputc_close('.',fp)==EOF) return strerror(errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '\'':
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[X] == beg[X] && bufp==buf && (fputc_close('\\',fp)==EOF || fputc_close('&',fp)==EOF)) return strerror(errno);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (fputc_close('\'',fp)==EOF) return strerror(errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '-':
|
|
|
|
{
|
|
|
|
if (*(bufp+1)=='-')
|
|
|
|
{
|
|
|
|
if (fputc_close('-',fp)==EOF) return strerror(errno);
|
|
|
|
else ++bufp;
|
|
|
|
}
|
|
|
|
else if (fputs_close("\\-",fp)==EOF) return strerror(errno);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: if (fputc_close(*bufp,fp)==EOF) return strerror(errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fputc_close('\n',fp)==EOF) return strerror(errno);
|
|
|
|
/*}}}*/
|
|
|
|
++*count;
|
|
|
|
}
|
|
|
|
if (!body)
|
|
|
|
{
|
|
|
|
if (fputs_close(".TE\n",fp)==EOF) return strerror(errno);
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[Z] < end[Z] && fputs_close(".bp\n",fp)==EOF) return strerror(errno);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
if (body && fclose(fp)==EOF) return strerror(errno);
|
|
|
|
}
|
|
|
|
if (!body && fclose(fp)==EOF) return strerror(errno);
|
|
|
|
return (const char*)0;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* savetext -- save as text */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
const char *savetext(Sheet *sheet, const char *name,
|
|
|
|
const Location beg, const Location end,
|
|
|
|
unsigned int *count)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
FILE *fp;
|
2019-07-27 04:14:26 +00:00
|
|
|
Location w;
|
|
|
|
Cell *cw;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* asserts */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
assert(name != (const char*)0);
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
*count=0;
|
2019-07-27 04:14:26 +00:00
|
|
|
w[X] = beg[X];
|
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
|
|
|
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
2019-07-22 20:32:33 +00:00
|
|
|
if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
size_t size,fill;
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
size = cellwidth(sheet,w);
|
|
|
|
cw = CELL_AT(sheet,w);
|
|
|
|
if (cw != NULLCELL)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
char *buf;
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
buf = malloc(size*UTF8SZ+1);
|
|
|
|
printvalue(buf, size*UTF8SZ+1, size, 0, getscientific(cw),
|
|
|
|
getprecision(cw), sheet, w);
|
|
|
|
adjust(getadjust(cw), buf, size);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (fputs_close(buf,fp)==EOF)
|
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
return strerror(errno);
|
|
|
|
}
|
|
|
|
for (fill=strlen(buf); fill<size; ++fill) if (fputc_close(' ',fp)==EOF)
|
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
return strerror(errno);
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (fill=0; fill<size; ++fill) if (fputc_close(' ',fp)==EOF) return strerror(errno);
|
|
|
|
}
|
|
|
|
++*count;
|
|
|
|
}
|
|
|
|
if (fputc_close('\n',fp)==EOF) return strerror(errno);
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[Z] < end[Z] && fputs_close("\f",fp)==EOF) return strerror(errno);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
if (fclose(fp)==EOF) return strerror(errno);
|
|
|
|
return (const char*)0;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* savecsv -- save as CSV */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
const char *savecsv(Sheet *sheet, const char *name, char sep,
|
|
|
|
const Location beg, const Location end,
|
|
|
|
unsigned int *count)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
FILE *fp;
|
2019-07-27 04:14:26 +00:00
|
|
|
Location w;
|
|
|
|
Cell *cw;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* asserts */ /*{{{*/
|
|
|
|
assert(sheet!=(Sheet*)0);
|
|
|
|
assert(name!=(const char*)0);
|
|
|
|
/*}}}*/
|
|
|
|
*count=0;
|
2019-07-27 04:14:26 +00:00
|
|
|
w[X] = beg[X];
|
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
|
|
|
if (shadowed(CELL_AT(sheet,w))) return _("Shadowed cells in first column");
|
2019-07-22 20:32:33 +00:00
|
|
|
if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++(w[Z]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++(w[Y]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[X]=beg[X]; w[X]<=end[X]; ++(w[X]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[X]>beg[X]) if (fputc_close(sep,fp)==EOF) return strerror(errno);
|
|
|
|
cw = CELL_AT(sheet,w);
|
|
|
|
if (cw != NULLCELL)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
char *buf,*s;
|
|
|
|
|
|
|
|
buf=malloc(255*UTF8SZ+1);
|
2019-07-27 04:14:26 +00:00
|
|
|
printvalue(buf, 255*UTF8SZ+1, 255, 0, getscientific(cw),
|
|
|
|
getprecision(cw), sheet, w);
|
|
|
|
if (cw->value.type == STRING && fputc_close('"',fp)==EOF)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
return strerror(errno);
|
|
|
|
}
|
|
|
|
for (s=buf; *s; ++s)
|
|
|
|
{
|
|
|
|
if (fputc_close(*s,fp)==EOF || (*s=='"' && fputc_close(*s,fp)==EOF))
|
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
return strerror(errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(buf);
|
2019-07-27 04:14:26 +00:00
|
|
|
if (cw->value.type==STRING && fputc_close('"',fp)==EOF) return strerror(errno);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
++*count;
|
|
|
|
}
|
|
|
|
if (fputc_close('\n',fp)==EOF) return strerror(errno);
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
if (w[Z] < end[Z] && fputs_close("\f",fp)==EOF) return strerror(errno);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
if (fclose(fp)==EOF) return strerror(errno);
|
|
|
|
return (const char*)0;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
|
|
|
static const char *saveport_contentleader[] =
|
|
|
|
{ [BASE] = ":", [ITERATIVE] = "\\\n"
|
|
|
|
};
|
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* saveport -- save as portable text */ /*{{{*/
|
|
|
|
const char *saveport(Sheet *sheet, const char *name, unsigned int *count)
|
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
FILE *fp;
|
|
|
|
int x,y,z;
|
2019-07-27 04:14:26 +00:00
|
|
|
Cell *cell;
|
|
|
|
ContentVariety v;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* asserts */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
assert(sheet != (Sheet*)0);
|
|
|
|
assert(name != (const char*)0);
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
*count = 0;
|
|
|
|
if ((fp=fopen(name,"w")) == (FILE*)0) return strerror(errno);
|
2019-07-22 20:32:33 +00:00
|
|
|
fprintf(fp,"# This is a work sheet generated with teapot %s.\n",VERSION);
|
|
|
|
for (z=sheet->dimz-1; z>=0; --z)
|
|
|
|
{
|
|
|
|
for (y=sheet->dimy-1; y>=0; --y)
|
|
|
|
{
|
|
|
|
for (x=sheet->dimx-1; x>=0; --x)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (y == 0 && columnwidth(sheet,x,z) != DEF_COLUMNWIDTH)
|
|
|
|
fprintf(fp,"W%d %d %d\n",x,z,columnwidth(sheet,x,z));
|
|
|
|
cell = CELL_ATC(sheet,x,y,z);
|
|
|
|
if (cell != NULLCELL)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
fprintf(fp,"C%d %d %d ",x,y,z);
|
2019-07-27 04:14:26 +00:00
|
|
|
if (cell->adjust != AUTOADJUST)
|
|
|
|
fprintf(fp,"A%c ","lrc"[cell->adjust]);
|
|
|
|
if (cell->label) fprintf(fp,"L%s ", cell->label);
|
|
|
|
if (cell->precision != -1)
|
|
|
|
fprintf(fp,"P%d ", cell->precision);
|
|
|
|
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,"C ");
|
|
|
|
if (cell->transparent) fprintf(fp,"T ");
|
|
|
|
for (v = BASE; v <= ITERATIVE; ++v)
|
|
|
|
if (cell->contents[v])
|
|
|
|
{
|
|
|
|
char buf[4096];
|
2019-07-22 20:32:33 +00:00
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
if (fputs_close(saveport_contentleader[v], fp) == EOF)
|
|
|
|
return strerror(errno);
|
|
|
|
print(buf, sizeof(buf), 0, 1, cell->scientific, cell->precision,
|
|
|
|
cell->contents[v]);
|
|
|
|
if (fputs_close(buf, fp) == EOF) return strerror(errno);
|
|
|
|
}
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
if (fclose(fp) == EOF) return strerror(errno);
|
2019-07-22 20:32:33 +00:00
|
|
|
return (const char*)0;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* loadport -- load from portable text */ /*{{{*/
|
|
|
|
const char *loadport(Sheet *sheet, const char *name)
|
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
static char errbuf[80];
|
|
|
|
FILE *fp;
|
2019-07-27 04:14:26 +00:00
|
|
|
Location loc;
|
|
|
|
int cx, cz;
|
2019-07-22 20:32:33 +00:00
|
|
|
char buf[4096];
|
|
|
|
int line;
|
|
|
|
const char *ns,*os;
|
|
|
|
const char *err;
|
2019-07-27 04:14:26 +00:00
|
|
|
Cell loaded;
|
2019-07-22 20:32:33 +00:00
|
|
|
int width;
|
|
|
|
/*}}}*/
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
if ((fp=fopen(name,"r")) == (FILE*)0) return strerror(errno);
|
|
|
|
freesheet(sheet, 0);
|
|
|
|
err = (const char*)0;
|
|
|
|
line = 1;
|
|
|
|
while (fgets(buf,sizeof(buf),fp) != (char*)0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* remove nl */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
width = strlen(buf);
|
|
|
|
if (width>0 && buf[width-1]=='\n') buf[--width] = '\0';
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
switch (buf[0])
|
|
|
|
{
|
|
|
|
/* C -- parse cell */ /*{{{*/
|
|
|
|
case 'C':
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
ContentVariety cv = BASE, nextcv = BASE;
|
|
|
|
|
|
|
|
if (width > 0 && buf[width-1]=='\\') { buf[--width]='\0'; ++nextcv; }
|
2019-07-27 07:00:03 +00:00
|
|
|
initcellcontents(&loaded);
|
2019-07-22 20:32:33 +00:00
|
|
|
/* parse x y and z */ /*{{{*/
|
|
|
|
os=ns=buf+1;
|
2019-07-27 04:14:26 +00:00
|
|
|
loc[X] = posnumber(os,&ns);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (os==ns)
|
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Parse error for x position in line %d"),line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
while (*ns==' ') ++ns;
|
|
|
|
os=ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loc[Y] = posnumber(os,&ns);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (os==ns)
|
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Parse error for y position in line %d"),line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
while (*ns==' ') ++ns;
|
|
|
|
os=ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loc[Z] = posnumber(os,&ns);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (os==ns)
|
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Parse error for z position in line %d"),line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* parse optional attributes */ /*{{{*/
|
|
|
|
do
|
|
|
|
{
|
|
|
|
while (*ns==' ') ++ns;
|
|
|
|
switch (*ns)
|
|
|
|
{
|
|
|
|
/* A -- adjustment */ /*{{{*/
|
|
|
|
case 'A':
|
|
|
|
{
|
|
|
|
++ns;
|
|
|
|
switch (*ns)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
case 'l': loaded.adjust=LEFT; ++ns; break;
|
|
|
|
case 'r': loaded.adjust=RIGHT; ++ns; break;
|
|
|
|
case 'c': loaded.adjust=CENTER; ++ns; break;
|
2019-07-22 20:32:33 +00:00
|
|
|
default: sprintf(errbuf,_("Parse error for adjustment in line %d"),line); err=errbuf; goto eek;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* L -- label */ /*{{{*/
|
|
|
|
case 'L':
|
|
|
|
{
|
|
|
|
char buf[1024],*p;
|
|
|
|
|
|
|
|
p=buf;
|
|
|
|
++ns;
|
|
|
|
while (*ns && *ns!=' ') { *p=*ns; ++p; ++ns; }
|
|
|
|
*p='\0';
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.label=mystrmalloc(buf);
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* P -- precision */ /*{{{*/
|
|
|
|
case 'P':
|
|
|
|
{
|
|
|
|
os=++ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.precision=posnumber(os,&ns);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (os==ns)
|
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Parse error for precision in line %d"),line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* S -- shadowed */ /*{{{*/
|
|
|
|
case 'S':
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (loc[X]==0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
sprintf(errbuf,_("Trying to shadow cell (%d,%d,%d) in line %d"),
|
|
|
|
loc[X],loc[Y],loc[Z],line);
|
2019-07-22 20:32:33 +00:00
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
++ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.shadowed=1;
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* U -- underline */ /*{{{*/
|
|
|
|
case 'U':
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (loc[X]==0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
sprintf(errbuf,_("Trying to underline cell (%d,%d,%d) in line %d"),
|
|
|
|
loc[X],loc[Y],loc[Z],line);
|
2019-07-22 20:32:33 +00:00
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
++ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.underline=1;
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* B -- bold */ /*{{{*/
|
|
|
|
case 'B':
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (loc[X]==0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
sprintf(errbuf,_("Trying to bold cell (%d,%d,%d) in line %d"),
|
|
|
|
loc[X], loc[Y], loc[Z], line);
|
2019-07-22 20:32:33 +00:00
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
++ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.bold=1;
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* E -- scientific */ /*{{{*/
|
|
|
|
case 'E':
|
|
|
|
{
|
|
|
|
++ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.scientific=1;
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* O -- locked */ /*{{{*/
|
|
|
|
case 'O':
|
|
|
|
{
|
|
|
|
++ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.locked=1;
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* T -- transparent */ /*{{{*/
|
|
|
|
case 'T':
|
|
|
|
{
|
|
|
|
++ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.transparent=1;
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* I -- ignored */ /*{{{*/
|
|
|
|
case 'I':
|
|
|
|
{
|
|
|
|
++ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.ignored=1;
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* : \0 -- do nothing */ /*{{{*/
|
|
|
|
case ':':
|
|
|
|
case '\0': break;
|
|
|
|
/*}}}*/
|
|
|
|
/* default -- error */ /*{{{*/
|
|
|
|
default: sprintf(errbuf,_("Invalid option %c in line %d"),*ns,line); err=errbuf; goto eek;
|
|
|
|
/*}}}*/
|
|
|
|
}
|
|
|
|
} while (*ns!=':' && *ns!='\0');
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
if (*ns) ++ns;
|
|
|
|
/* convert remaining string(s) into token sequence */ /*{{{*/
|
|
|
|
while (true)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
loaded.contents[cv] = scan(&ns);
|
|
|
|
if (loaded.contents[cv]==(Token**)0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Expression syntax error in line %d"),line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
if (nextcv == cv) break;
|
|
|
|
cv = nextcv;
|
|
|
|
if (fgets(buf, sizeof(buf), fp) == (char*)0) break;
|
|
|
|
++line;
|
|
|
|
width = strlen(buf);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (width>0 && buf[width-1]=='\n') buf[width-1]='\0';
|
2019-07-27 04:14:26 +00:00
|
|
|
/* More content? */
|
|
|
|
if (width > 0 && buf[width-1]=='\\') { buf[--width]='\0'; ++nextcv; }
|
|
|
|
ns = buf;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-27 07:00:03 +00:00
|
|
|
copycelltosheet(&loaded, sheet, loc);
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* W -- column width */ /*{{{*/
|
|
|
|
case 'W':
|
|
|
|
{
|
|
|
|
/* parse x and z */ /*{{{*/
|
|
|
|
os=ns=buf+1;
|
2019-07-27 04:14:26 +00:00
|
|
|
cx=posnumber(os,&ns);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (os==ns)
|
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Parse error for x position in line %d"),line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
while (*ns==' ') ++ns;
|
|
|
|
os=ns;
|
2019-07-27 04:14:26 +00:00
|
|
|
cz=posnumber(os,&ns);
|
2019-07-22 20:32:33 +00:00
|
|
|
if (os==ns)
|
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Parse error for z position in line %d"),line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* parse width */ /*{{{*/
|
|
|
|
while (*ns==' ') ++ns;
|
|
|
|
os=ns;
|
|
|
|
width=posnumber(os,&ns);
|
|
|
|
if (os==ns)
|
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Parse error for width in line %d"),line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
setwidth(sheet,cx,cz,width);
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* # -- comment */ /*{{{*/
|
|
|
|
case '#': break;
|
|
|
|
/*}}}*/
|
|
|
|
/* default -- error */ /*{{{*/
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
sprintf(errbuf,_("Unknown tag %c in line %d"),buf[0],line);
|
|
|
|
err=errbuf;
|
|
|
|
goto eek;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
}
|
|
|
|
++line;
|
|
|
|
}
|
|
|
|
eek:
|
|
|
|
if (fclose(fp)==EOF && err==(const char*)0) err=strerror(errno);
|
|
|
|
sheet->changed=0;
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* loadxdr -- load a spread sheet in XDR */ /*{{{*/
|
|
|
|
const char *loadxdr(Sheet *sheet, const char *name)
|
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
FILE *fp;
|
|
|
|
XDR xdrs;
|
2019-07-27 04:14:26 +00:00
|
|
|
Location w;
|
2019-07-22 20:32:33 +00:00
|
|
|
int width;
|
|
|
|
int u;
|
|
|
|
int olderror;
|
2019-07-27 04:14:26 +00:00
|
|
|
Cell *nc;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
if ((fp=fopen(name,"r"))==(FILE*)0) return strerror(errno);
|
|
|
|
xdrstdio_create(&xdrs,fp,XDR_DECODE);
|
|
|
|
if (!xdr_magic(&xdrs))
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
fclose(fp);
|
|
|
|
return _("This is not a teapot worksheet in XDR format");
|
|
|
|
#else
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
rewind(fp);
|
|
|
|
xdrstdio_create(&xdrs,fp,XDR_DECODE);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
freesheet(sheet,0);
|
|
|
|
while (xdr_int(&xdrs,&u)) switch (u)
|
|
|
|
{
|
|
|
|
/* 0 -- column width element */ /*{{{*/
|
|
|
|
case 0:
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (xdr_column(&xdrs,&(w[X]),&(w[Z]),&width)==0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
olderror=errno;
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
(void)fclose(fp);
|
|
|
|
return strerror(olderror);
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
setwidth(sheet,w[X],w[Z],width);
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* 1 -- cell element */ /*{{{*/
|
|
|
|
case 1:
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
if (xdr_int(&xdrs,&(w[X]))==0 ||
|
|
|
|
xdr_int(&xdrs,&(w[Y]))==0 ||
|
|
|
|
xdr_int(&xdrs,&(w[Z]))==0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
olderror=errno;
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
(void)fclose(fp);
|
|
|
|
return strerror(olderror);
|
|
|
|
}
|
2019-07-27 07:00:03 +00:00
|
|
|
nc = initcellofsheet(sheet, w);
|
2019-07-27 04:14:26 +00:00
|
|
|
if (xdr_cell(&xdrs, nc)==0)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 07:00:03 +00:00
|
|
|
freecellofsheet(sheet, w);
|
2019-07-22 20:32:33 +00:00
|
|
|
olderror=errno;
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
(void)fclose(fp);
|
|
|
|
return strerror(olderror);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* default -- should not happen */ /*{{{*/
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
fclose(fp);
|
|
|
|
sheet->changed=0;
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
return _("Invalid record, loading aborted");
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
}
|
|
|
|
xdr_destroy(&xdrs);
|
|
|
|
if (fclose(fp)==EOF) return strerror(errno);
|
|
|
|
sheet->changed=0;
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
redraw_sheet(sheet);
|
|
|
|
return (const char*)0;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* loadcsv -- load/merge CSVs */ /*{{{*/
|
|
|
|
const char *loadcsv(Sheet *sheet, const char *name)
|
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
FILE *fp;
|
|
|
|
Token **t;
|
|
|
|
const char *err;
|
2019-07-27 04:14:26 +00:00
|
|
|
Location where;
|
2019-07-22 20:32:33 +00:00
|
|
|
char ln[4096];
|
|
|
|
const char *str;
|
|
|
|
double value;
|
|
|
|
long lvalue;
|
|
|
|
int separator = 0;
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
if ((fp=fopen(name,"r"))==(FILE*)0) return strerror(errno);
|
|
|
|
err=(const char*)0;
|
2019-07-27 04:14:26 +00:00
|
|
|
LOCATION_GETS(where, sheet->cur);
|
|
|
|
for (; fgets(ln,sizeof(ln),fp); ++(where[Y]))
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
const char *s;
|
|
|
|
const char *cend;
|
|
|
|
|
|
|
|
if (!separator) { /* FIXME: find a better way to autodetect */
|
|
|
|
int ccnt = 0, scnt = 0;
|
|
|
|
char *pos = ln;
|
|
|
|
while ((pos = strchr(pos, ','))) pos++, ccnt++;
|
|
|
|
pos = ln;
|
|
|
|
while ((pos = strchr(pos, ';'))) pos++, scnt++;
|
|
|
|
if (ccnt || scnt) separator = 1;
|
|
|
|
csv_setopt(scnt > ccnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
s=cend=ln;
|
2019-07-27 04:14:26 +00:00
|
|
|
where[X] = sheet->cur[X];
|
2019-07-22 20:32:33 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
t=malloc(2*sizeof(Token*));
|
|
|
|
t[0]=malloc(sizeof(Token));
|
|
|
|
t[1]=(Token*)0;
|
|
|
|
lvalue=csv_long(s,&cend);
|
|
|
|
if (s!=cend) /* ok, it is a integer */ /*{{{*/
|
|
|
|
{
|
|
|
|
t[0]->type=INT;
|
|
|
|
t[0]->u.integer=lvalue;
|
2019-07-27 04:14:26 +00:00
|
|
|
putcont(sheet, where, t, BASE);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value=csv_double(s,&cend);
|
|
|
|
if (s!=cend) /* ok, it is a double */ /*{{{*/
|
|
|
|
{
|
|
|
|
t[0]->type=FLOAT;
|
|
|
|
t[0]->u.flt=value;
|
2019-07-27 04:14:26 +00:00
|
|
|
putcont(sheet, where, t, BASE);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
str=csv_string(s,&cend);
|
|
|
|
if (s!=cend) /* ok, it is a string */ /*{{{*/
|
|
|
|
{
|
|
|
|
t[0]->type=STRING;
|
|
|
|
t[0]->u.string=mystrmalloc(str);
|
2019-07-27 04:14:26 +00:00
|
|
|
putcont(sheet, where, t, BASE);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tvecfree(t);
|
|
|
|
csv_separator(s,&cend);
|
|
|
|
while (s==cend && *s && *s!='\n')
|
|
|
|
{
|
|
|
|
err=_("unknown values ignored");
|
|
|
|
csv_separator(++s,&cend);
|
|
|
|
}
|
|
|
|
/* else it is nothing, which does not need to be stored :) */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-27 04:14:26 +00:00
|
|
|
} while (s!=cend ? s=cend,++(where[X]),1 : 0);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* insertcube -- insert a block */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void insertcube(Sheet *sheet, const Location beg, const Location end,
|
|
|
|
Direction ins)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
|
|
|
int x,y,z;
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
switch (ins)
|
|
|
|
{
|
|
|
|
/* IN_X */ /*{{{*/
|
|
|
|
case IN_X:
|
|
|
|
{
|
|
|
|
int right;
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
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)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
resize(sheet,x,y,z);
|
2019-07-27 04:14:26 +00:00
|
|
|
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;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* IN_Y */ /*{{{*/
|
|
|
|
case IN_Y:
|
|
|
|
{
|
|
|
|
int down;
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
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)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
resize(sheet,x,y,z);
|
2019-07-27 04:14:26 +00:00
|
|
|
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;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* IN_Z */ /*{{{*/
|
|
|
|
case IN_Z:
|
|
|
|
{
|
|
|
|
int bottom;
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
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)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
resize(sheet,x,y,z);
|
2019-07-27 04:14:26 +00:00
|
|
|
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;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* default */ /*{{{*/
|
|
|
|
default: assert(0);
|
|
|
|
/*}}}*/
|
|
|
|
}
|
|
|
|
sheet->changed=1;
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* deletecube -- delete a block */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void deletecube(Sheet *sheet, const Location beg, const Location end,
|
|
|
|
Direction del)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
Location w;
|
|
|
|
Location fm;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* free cells in marked block */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[X]=beg[X]; w[X]<=end[X]; ++w[X])
|
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++w[Y])
|
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++w[Z])
|
2019-07-27 07:00:03 +00:00
|
|
|
freecellofsheet(sheet, w);
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
switch (del)
|
|
|
|
{
|
|
|
|
/* IN_X */ /*{{{*/
|
|
|
|
case IN_X:
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++w[Z])
|
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++w[Y])
|
|
|
|
for (w[X]=beg[X]; w[X]<=sheet->dimx-(end[X]-beg[X]+1); ++w[X])
|
|
|
|
{
|
|
|
|
LOCATION_GETS(fm, w);
|
|
|
|
fm[X] += end[X]-beg[X]+1;
|
|
|
|
if (LOC_WITHIN(sheet,fm))
|
|
|
|
{
|
|
|
|
CELL_AT(sheet,w) = CELL_AT(sheet,fm);
|
|
|
|
CELL_AT(sheet,fm) = NULLCELL;
|
|
|
|
}
|
|
|
|
}
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* IN_Y */ /*{{{*/
|
|
|
|
case IN_Y:
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Z]=beg[Z]; w[Z]<=end[Z]; ++w[Z])
|
|
|
|
for (w[X]=beg[X]; w[X]<=end[X]; ++w[X])
|
|
|
|
for (w[Y]=beg[Y]; w[Y]<=sheet->dimy-(end[Y]-beg[Y]+1); ++w[Y])
|
|
|
|
{
|
|
|
|
LOCATION_GETS(fm, w);
|
|
|
|
fm[Y] += end[Y]-beg[Y]+1;
|
|
|
|
if (LOC_WITHIN(sheet,fm))
|
|
|
|
{
|
|
|
|
CELL_AT(sheet,w) = CELL_AT(sheet,fm);
|
|
|
|
CELL_AT(sheet,fm) = NULLCELL;
|
|
|
|
}
|
|
|
|
}
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* IN_Z */ /*{{{*/
|
|
|
|
case IN_Z:
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
for (w[Y]=beg[Y]; w[Y]<=end[Y]; ++w[Y])
|
|
|
|
for (w[X]=beg[X]; w[X]<=end[X]; ++w[X])
|
|
|
|
for (w[Z]=beg[Z]; w[Z]<=sheet->dimz-(end[Z]-beg[Z]+1); ++w[Z])
|
|
|
|
{
|
|
|
|
LOCATION_GETS(fm, w);
|
|
|
|
fm[Z] += end[Z]-beg[Z]+1;
|
|
|
|
if (LOC_WITHIN(sheet,fm))
|
|
|
|
{
|
|
|
|
CELL_AT(sheet,w) = CELL_AT(sheet,fm);
|
|
|
|
CELL_AT(sheet,fm) = NULLCELL;
|
|
|
|
}
|
|
|
|
}
|
2019-07-22 20:32:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* default */ /*{{{*/
|
|
|
|
default: assert(0);
|
|
|
|
/*}}}*/
|
|
|
|
}
|
|
|
|
sheet->changed=1;
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* moveblock -- move a block */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void moveblock(Sheet *sheet, const Location beg, const Location end,
|
|
|
|
const Location dest, int copy)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
Location wid, dir, fm, to, get, go;
|
|
|
|
Dimensions dim;
|
2019-07-22 20:32:33 +00:00
|
|
|
/*}}}*/
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
if (SAME_LOC(beg, dest)) return;
|
|
|
|
LOCATION_GETS(wid, end);
|
|
|
|
LOCATION_SUB(wid, beg);
|
|
|
|
for (dim = X; dim < HYPER; ++dim) {
|
|
|
|
if (dest[dim] > beg[dim])
|
|
|
|
{ dir[dim] = -1; fm[dim] = wid[dim]; to[dim] = beg[dim]-1; }
|
|
|
|
else
|
|
|
|
{ dir[dim] = 1; fm[dim] = 0; to[dim] = beg[dim]+wid[dim]+1; }
|
|
|
|
}
|
|
|
|
for (get[Z] = beg[Z]+fm[Z], go[Z] = dest[Z]+fm[Z];
|
|
|
|
get[Z] != to[Z]; get[Z] += dir[Z], go[Z] += dir[Z])
|
|
|
|
for (get[Y] = beg[Y]+fm[Y], go[Y] = dest[Y]+fm[Y];
|
|
|
|
get[Y] != to[Y]; get[Y] += dir[Y], go[Y] += dir[Y])
|
|
|
|
for (get[X] = beg[X]+fm[X], go[X] = dest[X]+fm[X];
|
|
|
|
get[X] != to[X]; get[X] += dir[X], go[X] += dir[X])
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
2019-07-27 07:00:03 +00:00
|
|
|
if (!LOC_WITHIN(sheet, get)) freecellofsheet(sheet, go);
|
|
|
|
else if (copy) { copycelltosheet(CELL_AT(sheet, get), sheet, go); }
|
2019-07-22 20:32:33 +00:00
|
|
|
else
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
resize(sheet, go[X], go[Y], go[Z]);
|
|
|
|
CELL_AT(sheet, go) = CELL_AT(sheet, get);
|
|
|
|
CELL_AT(sheet, get) = NULLCELL;
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
sheet->changed=1;
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* sortblock -- sort a block */ /*{{{*/
|
|
|
|
/* Notes */ /*{{{*/
|
|
|
|
/*
|
|
|
|
The idea is to sort a block of cells in one direction by swapping the
|
|
|
|
planes which are canonical to the sort key vectors. An example is to
|
|
|
|
sort a two dimensional block line-wise with one column as sort key.
|
|
|
|
You can have multiple sort keys which all have the same direction and
|
|
|
|
you can sort a cube plane-wise.
|
|
|
|
*/
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
const char *sortblock(Sheet *sheet, const Location beg, const Location end,
|
|
|
|
Direction dir, Sortkey *sk, size_t sklen)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
/* variables */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
int x1, y1, z1, x2, y2, z2;
|
2019-07-22 20:32:33 +00:00
|
|
|
int x,y,z;
|
|
|
|
int incx=0,incy=0,incz=0;
|
|
|
|
int distx,disty,distz;
|
|
|
|
int i,r=-3,norel,work;
|
|
|
|
/*}}}*/
|
|
|
|
|
2019-07-27 04:14:26 +00:00
|
|
|
/* unpack corners */
|
|
|
|
x1 = beg[X]; y1 = beg[Y]; z1 = beg[Z];
|
|
|
|
x2 = end[X]; y2 = end[Y]; z2 = end[Z];
|
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* asserts */ /*{{{*/
|
|
|
|
assert(sklen>0);
|
|
|
|
assert(x1>=0);
|
|
|
|
assert(x2>=0);
|
|
|
|
assert(y1>=0);
|
|
|
|
assert(y2>=0);
|
|
|
|
assert(z1>=0);
|
|
|
|
assert(z2>=0);
|
|
|
|
/*}}}*/
|
|
|
|
norel=0;
|
|
|
|
posorder(&x1,&x2);
|
|
|
|
posorder(&y1,&y2);
|
|
|
|
posorder(&z1,&z2);
|
|
|
|
distx=(x2-x1+1);
|
|
|
|
disty=(y2-y1+1);
|
|
|
|
distz=(z2-z1+1);
|
|
|
|
switch (dir)
|
|
|
|
{
|
|
|
|
case IN_X: incx=1; --x2; incy=0; incz=0; distx=1; break;
|
|
|
|
case IN_Y: incx=0; incy=1; --y2; incz=0; disty=1; break;
|
|
|
|
case IN_Z: incx=0; incy=0; incz=1; --z2; distz=1; break;
|
|
|
|
default: assert(0);
|
|
|
|
}
|
|
|
|
assert(incx || incy || incz);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
work=0;
|
|
|
|
for (x=x1,y=y1,z=z1; x<=x2&&y<=y2&&z<=z2; x+=incx,y+=incy,z+=incz)
|
|
|
|
{
|
|
|
|
for (i=0; i<sklen; ++i)
|
|
|
|
{
|
|
|
|
r=cmpcell(sheet,x+sk[i].x,y+sk[i].y,z+sk[i].z,sheet,x+incx+sk[i].x,y+incy+sk[i].y,z+incz+sk[i].z,sk[i].sortkey);
|
|
|
|
if (r==2) norel=1;
|
|
|
|
else if (r==-1 || r==1) break;
|
|
|
|
else assert(r==0);
|
|
|
|
}
|
|
|
|
if (r==1)
|
|
|
|
{
|
|
|
|
swapblock(sheet,dir==IN_X ? x : x1,dir==IN_Y ? y : y1,dir==IN_Z ? z : z1,sheet,dir==IN_X ? x+incx : x1,dir==IN_Y ? y+incy : y1,dir==IN_Z ? z+incz : z1,distx,disty,distz);
|
|
|
|
work=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x2-=incx;
|
|
|
|
y2-=incy;
|
|
|
|
z2-=incz;
|
|
|
|
} while (work);
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
sheet->changed=1;
|
|
|
|
if (norel) return _("uncomparable elements");
|
|
|
|
else return (const char*)0;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
2019-07-27 04:14:26 +00:00
|
|
|
|
2019-07-22 20:32:33 +00:00
|
|
|
/* mirrorblock -- mirror a block */ /*{{{*/
|
2019-07-27 04:14:26 +00:00
|
|
|
void mirrorblock(Sheet *sheet, const Location beg, const Location end,
|
|
|
|
Direction dir)
|
2019-07-22 20:32:33 +00:00
|
|
|
{
|
|
|
|
switch (dir)
|
|
|
|
{
|
|
|
|
case IN_X: /* left-right */ /*{{{*/
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
int x,middle=(end[X]-beg[X]+1)/2;
|
2019-07-22 20:32:33 +00:00
|
|
|
for (x=0; x<middle; ++x)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
swapblock(sheet,beg[X]+x,beg[Y],beg[Z],sheet,end[X]-x,beg[Y],beg[Z], 1,end[Y]-beg[Y]+1,end[Z]-beg[Z]+1);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
case IN_Y: /* upside-down */ /*{{{*/
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
int y,middle=(end[Y]-beg[Y]+1)/2;
|
2019-07-22 20:32:33 +00:00
|
|
|
for (y=0; y<middle; ++y)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
swapblock(sheet,beg[X],beg[Y]+y,beg[Z],sheet,beg[X],end[Y]-y,beg[Z], end[X]-beg[X]+1,1,end[Z]-beg[Z]+1);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
case IN_Z: /* front-back */ /*{{{*/
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
int z,middle=(end[Z]-beg[Z]+1)/2;
|
2019-07-22 20:32:33 +00:00
|
|
|
for (z=0; z<middle; ++z)
|
|
|
|
{
|
2019-07-27 04:14:26 +00:00
|
|
|
swapblock(sheet,beg[X],beg[Y],beg[Z]+z,sheet,beg[X],beg[Y],end[Z]-z, end[X]-beg[X]+1,end[Y]-beg[Y]+1,1);
|
2019-07-22 20:32:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
default: assert(0);
|
|
|
|
}
|
|
|
|
sheet->changed=1;
|
|
|
|
cachelabels(sheet);
|
|
|
|
forceupdate(sheet);
|
|
|
|
}
|
|
|
|
/*}}}*/
|