1 /* #includes */ /*{{{C}}}*//*{{{*/
2 #ifdef DMALLOC
3 #include "dmalloc.h"
4 #endif
5 
6 #include <assert.h>
7 #include <errno.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 
14 #include "csv.h"
15 #include "default.h"
16 #include "display.h"
17 #include "eval.h"
18 #include "main.h"
19 #include "misc.h"
20 #include "parser.h"
21 #include "scanner.h"
22 #include "sheet.h"
23 #include "utf8.h"
24 #include "xdr.h"
25 
26 /*}}}*/
27 /* #defines */ /*{{{*/
28 #define SHEET(s,x,y,z) (*(s->sheet+(x)*s->dimz*s->dimy+(y)*s->dimz+(z)))
29 
30 #define HASH(x,s) \
31 { \
32   const unsigned char *S=(const unsigned char*)s; \
33   \
34   x=0; \
35   while (*S) { x=(x<<5)+((x>>27)^*S); ++S; } \
36   x%=LABEL_CACHE; \
37 }
38 
39 #define SHADOWED(sheet,x,y,z) (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0 && SHEET(sheet,x,y,z)->shadowed)
40 /*}}}*/
41 
42 /* variables */ /*{{{*/
43 static int upd_clock; /* evaluate clocked expressions */
44 /* Used during evaluation of a cell to specify the currently updated cell */
45 Sheet *upd_sheet;
46 int upd_x;
47 int upd_y;
48 int upd_z;
49 int max_eval;
50 /*}}}*/
51 
52 /* copycell      -- copy a cell */ /*{{{*/
copycell(Sheet * sheet1,int x1,int y1,int z1,Sheet * sheet2,int x2,int y2,int z2)53 static void copycell(Sheet *sheet1, int x1, int y1, int z1, Sheet *sheet2, int x2, int y2, int z2)
54 {
55   /* variables */ /*{{{*/
56   Token **run;
57   int i,len;
58   /*}}}*/
59 
60   assert(sheet1!=(Sheet*)0);
61   assert(sheet2!=(Sheet*)0);
62   if (x1<sheet1->dimx && y1<sheet1->dimy && z1<sheet1->dimz)
63   {
64     sheet2->changed=1;
65     if (SHEET(sheet1,x1,y1,z1)==(Cell*)0) freecell(sheet2,x2,y2,z2);
66     else
67     /* copy first cell to second */ /*{{{*/
68     {
69       freecell(sheet2,x2,y2,z2);
70       initcell(sheet2,x2,y2,z2);
71       memcpy(SHEET(sheet2,x2,y2,z2),SHEET(sheet1,x1,y1,z1),sizeof(Cell));
72       if (SHEET(sheet1,x1,y1,z1)->contents!=(Token**)0)
73       {
74         for (len=1,run=SHEET(sheet1,x1,y1,z1)->contents; *run!=(Token*)0; ++len,++run);
75         SHEET(sheet2,x2,y2,z2)->contents=malloc(len*sizeof(Token*));
76         for (i=0; i<len; ++i)
77         {
78           if (*(SHEET(sheet1,x1,y1,z1)->contents+i)==(Token*)0) *(SHEET(sheet2,x2,y2,z2)->contents+i)=(Token*)0;
79           else
80           {
81             *(SHEET(sheet2,x2,y2,z2)->contents+i)=malloc(sizeof(Token));
82             **(SHEET(sheet2,x2,y2,z2)->contents+i)=tcopy(**(SHEET(sheet1,x1,y1,z1)->contents+i));
83           }
84         }
85       }
86       if (SHEET(sheet1,x1,y1,z1)->ccontents!=(Token**)0)
87       {
88         for (len=1,run=SHEET(sheet1,x1,y1,z1)->ccontents; *run!=(Token*)0; ++len,++run);
89         SHEET(sheet2,x2,y2,z2)->ccontents=malloc(len*sizeof(Token*));
90         for (i=0; i<len; ++i)
91         {
92           if (*(SHEET(sheet1,x1,y1,z1)->ccontents+i)==(Token*)0) *(SHEET(sheet2,x2,y2,z2)->ccontents+i)=(Token*)0;
93           else
94           {
95             *(SHEET(sheet2,x2,y2,z2)->ccontents+i)=malloc(sizeof(Token));
96             **(SHEET(sheet2,x2,y2,z2)->ccontents+i)=tcopy(**(SHEET(sheet1,x1,y1,z1)->ccontents+i));
97           }
98         }
99       }
100       if (SHEET(sheet1,x1,y1,z1)->label!=(char*)0) SHEET(sheet2,x2,y2,z2)->label=strcpy(malloc(strlen(SHEET(sheet1,x1,y1,z1)->label)+1),SHEET(sheet1,x1,y1,z1)->label);
101       SHEET(sheet2,x2,y2,z2)->value.type=EMPTY;
102     }
103     /*}}}*/
104   }
105   else freecell(sheet2,x2,y2,z2);
106 }
107 /*}}}*/
108 /* swapblock     -- swap two non-overlapping blocks of cells */ /*{{{*/
swapblock(Sheet * sheet1,int x1,int y1,int z1,Sheet * sheet2,int x2,int y2,int z2,int xdist,int ydist,int zdist)109 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)
110 {
111   int xoff, yoff, zoff;
112 
113   assert(sheet1!=(Sheet*)0);
114   assert(sheet2!=(Sheet*)0);
115   resize(sheet1,x1+xdist-1,y1+ydist-1,z1+zdist-1);
116   resize(sheet2,x2+xdist-1,y2+ydist-1,z2+zdist-1);
117   for (xoff=0; xoff<xdist; ++xoff)
118   for (yoff=0; yoff<ydist; ++yoff)
119   for (zoff=0; zoff<zdist; ++zoff)
120   {
121     Cell *t;
122 
123     t=SHEET(sheet1,x1+xoff,y1+yoff,z1+zoff);
124     SHEET(sheet1,x1+xoff,y1+yoff,z1+zoff)=SHEET(sheet2,x2+xoff,y2+yoff,z2+zoff);
125     SHEET(sheet2,x2+xoff,y2+yoff,z2+zoff)=t;
126   }
127   sheet1->changed=1;
128   sheet2->changed=1;
129 }
130 /*}}}*/
131 /* cmpcell       -- compare to cells with given order flags */ /*{{{*/
132 /* Notes */ /*{{{*/
133 /*
134 Compare the _values_ of two cells.  The result is -1 if first is smaller
135 than second, 0 if they are equal and 1 if the first is bigger than the
136 second.  A result of 2 means they are not comparable.
137 */
138 /*}}}*/
cmpcell(Sheet * sheet1,int x1,int y1,int z1,Sheet * sheet2,int x2,int y2,int z2,int sortkey)139 static int cmpcell(Sheet *sheet1, int x1, int y1, int z1, Sheet *sheet2, int x2, int y2, int z2, int sortkey)
140 {
141   assert(sheet1!=(Sheet*)0);
142   assert(sheet2!=(Sheet*)0);
143   /* empty cells are smaller than any non-empty cell */ /*{{{*/
144   if (x1>=sheet1->dimx || y1>=sheet1->dimy || z1>=sheet1->dimz || SHEET(sheet1,x1,y1,z1)==(Cell*)0 || SHEET(sheet1,x1,y1,z1)->value.type==EMPTY)
145   {
146     if (x2>=sheet2->dimx || y2>=sheet2->dimy || z2>=sheet2->dimz || SHEET(sheet2,x2,y2,z2)==(Cell*)0 || SHEET(sheet2,x2,y2,z2)->value.type==EMPTY) return 0;
147     else return (sortkey&ASCENDING ? -1 : 1);
148   }
149   if (x2>=sheet2->dimx || y2>=sheet2->dimy || z2>=sheet2->dimz || SHEET(sheet2,x2,y2,z2)==(Cell*)0 || SHEET(sheet2,x2,y2,z2)->value.type==EMPTY) return (sortkey&ASCENDING ? 1 : -1);
150   /*}}}*/
151   switch (SHEET(sheet1,x1,y1,z1)->value.type)
152   {
153     /* STRING */ /*{{{*/
154     case STRING:
155     {
156       if (SHEET(sheet2,x2,y2,z2)->value.type==STRING)
157       {
158         int r;
159 
160         r=strcmp(SHEET(sheet1,x1,y1,z1)->value.u.string,SHEET(sheet2,x2,y2,z2)->value.u.string);
161         if (r<0) return (sortkey&ASCENDING ? -1 : 1);
162         else if (r==0) return 0;
163         else return (sortkey&ASCENDING ? 1 : -1);
164       }
165       return 2;
166     }
167     /*}}}*/
168     /* FLOAT */ /*{{{*/
169     case FLOAT:
170     {
171       if (SHEET(sheet2,x2,y2,z2)->value.type==FLOAT)
172       {
173         if (SHEET(sheet1,x1,y1,z1)->value.u.flt<SHEET(sheet2,x2,y2,z2)->value.u.flt) return (sortkey&ASCENDING ? -1 : 1);
174         else if (SHEET(sheet1,x1,y1,z1)->value.u.flt==SHEET(sheet2,x2,y2,z2)->value.u.flt) return 0;
175         else return (sortkey&ASCENDING ? 1 : -1);
176       }
177       if (SHEET(sheet2,x2,y2,z2)->value.type==INT)
178       {
179         if (SHEET(sheet1,x1,y1,z1)->value.u.flt<SHEET(sheet2,x2,y2,z2)->value.u.integer) return (sortkey&ASCENDING ? -1 : 1);
180         else if (SHEET(sheet1,x1,y1,z1)->value.u.flt==SHEET(sheet2,x2,y2,z2)->value.u.integer) return 0;
181         else return (sortkey&ASCENDING ? 1 : -1);
182       }
183       return 2;
184     }
185     /*}}}*/
186     /* INT */ /*{{{*/
187     case INT:
188     {
189       if (SHEET(sheet2,x2,y2,z2)->value.type==INT)
190       {
191         if (SHEET(sheet1,x1,y1,z1)->value.u.integer<SHEET(sheet2,x2,y2,z2)->value.u.integer) return (sortkey&ASCENDING ? -1 : 1);
192         else if (SHEET(sheet1,x1,y1,z1)->value.u.integer==SHEET(sheet2,x2,y2,z2)->value.u.integer) return 0;
193         else return (sortkey&ASCENDING ? 1 : -1);
194       }
195       if (SHEET(sheet2,x2,y2,z2)->value.type==FLOAT)
196       {
197         if (SHEET(sheet1,x1,y1,z1)->value.u.integer<SHEET(sheet2,x2,y2,z2)->value.u.flt) return (sortkey&ASCENDING ? -1 : 1);
198         else if (SHEET(sheet1,x1,y1,z1)->value.u.integer==SHEET(sheet2,x2,y2,z2)->value.u.flt) return 0;
199         else return (sortkey&ASCENDING ? 1 : -1);
200       }
201       return 2;
202     }
203     /*}}}*/
204     default: return 2;
205   }
206 }
207 /*}}}*/
208 
209 /* resize        -- check if sheet needs to be resized in any dimension */ /*{{{*/
resize(Sheet * sheet,int x,int y,int z)210 void resize(Sheet *sheet, int x, int y, int z)
211 {
212   assert(x>=0);
213   assert(y>=0);
214   assert(z>=0);
215   assert(sheet!=(Sheet*)0);
216   if (x>=sheet->dimx || y>=sheet->dimy || z>=sheet->dimz)
217   {
218     /* variables */ /*{{{*/
219     Cell **newsheet;
220     int *newcolumn;
221     unsigned int ndimx,ndimy,ndimz;
222     /*}}}*/
223 
224     sheet->changed=1;
225     ndimx=(x>=sheet->dimx ? x+1 : sheet->dimx);
226     ndimy=(y>=sheet->dimy ? y+1 : sheet->dimy);
227     ndimz=(z>=sheet->dimz ? z+1 : sheet->dimz);
228     /* allocate new sheet */ /*{{{*/
229     newsheet=malloc(ndimx*ndimy*ndimz*sizeof(Cell*));
230     for (x=0; x<ndimx; ++x) for (y=0; y<ndimy; ++y) for (z=0; z<ndimz; ++z)
231     {
232       if (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz) *(newsheet+x*ndimz*ndimy+y*ndimz+z)=SHEET(sheet,x,y,z);
233       else *(newsheet+x*ndimz*ndimy+y*ndimz+z)=(Cell*)0;
234     }
235     if (sheet->sheet!=(Cell**)0) free(sheet->sheet);
236     sheet->sheet=newsheet;
237     /*}}}*/
238     /* allocate new columns */ /*{{{*/
239     if (x>sheet->dimx || z>=sheet->dimz)
240     {
241       newcolumn=malloc(ndimx*ndimz*sizeof(int));
242       for (x=0; x<ndimx; ++x) for (z=0; z<ndimz; ++z)
243       {
244         if (x<sheet->dimx && z<sheet->dimz) *(newcolumn+x*ndimz+z)=*(sheet->column+x*sheet->dimz+z);
245         else *(newcolumn+x*ndimz+z)=DEF_COLUMNWIDTH;
246       }
247       if (sheet->column!=(int*)0) free(sheet->column);
248       sheet->column=newcolumn;
249     }
250     /*}}}*/
251     sheet->dimx=ndimx;
252     sheet->dimy=ndimy;
253     sheet->dimz=ndimz;
254   }
255 }
256 /*}}}*/
257 /* initcell      -- initialise new cell, if it does not exist yet */ /*{{{*/
initcell(Sheet * sheet,int x,int y,int z)258 void initcell(Sheet *sheet, int x, int y, int z)
259 {
260   assert(x>=0);
261   assert(y>=0);
262   assert(z>=0);
263   resize(sheet,x,y,z);
264   if (SHEET(sheet,x,y,z)==(Cell*)0)
265   {
266     sheet->changed=1;
267     SHEET(sheet,x,y,z)=malloc(sizeof(Cell));
268     SHEET(sheet,x,y,z)->contents=(Token**)0;
269     SHEET(sheet,x,y,z)->ccontents=(Token**)0;
270     SHEET(sheet,x,y,z)->label=(char*)0;
271     SHEET(sheet,x,y,z)->adjust=AUTOADJUST;
272     SHEET(sheet,x,y,z)->precision=-1;
273     SHEET(sheet,x,y,z)->shadowed=0;
274     SHEET(sheet,x,y,z)->bold=0;
275     SHEET(sheet,x,y,z)->underline=0;
276     SHEET(sheet,x,y,z)->scientific=DEF_SCIENTIFIC;
277     SHEET(sheet,x,y,z)->value.type=EMPTY;
278     SHEET(sheet,x,y,z)->resvalue.type=EMPTY;
279     SHEET(sheet,x,y,z)->locked=0;
280     SHEET(sheet,x,y,z)->ignored=0;
281     SHEET(sheet,x,y,z)->clock_t0=0;
282     SHEET(sheet,x,y,z)->clock_t1=0;
283     SHEET(sheet,x,y,z)->clock_t2=0;
284   }
285 }
286 /*}}}*/
287 /* cachelabels   -- create new label cache */ /*{{{*/
cachelabels(Sheet * sheet)288 void cachelabels(Sheet *sheet)
289 {
290   int i,x,y,z;
291 
292   if (sheet==(Sheet*)0) return;
293   for (i=0; i<LABEL_CACHE; ++i) /* free bucket */ /*{{{*/
294   {
295     struct Label *run;
296 
297     for (run=sheet->labelcache[i]; run!=(struct Label*)0;)
298     {
299       struct Label *runnext;
300 
301       runnext=run->next;
302       free(run);
303       run=runnext;
304     }
305     sheet->labelcache[i]=(struct Label*)0;
306   }
307   /*}}}*/
308   for (x=0; x<sheet->dimx; ++x) for (y=0; y<sheet->dimy; ++y) for (z=0; z<sheet->dimz; ++z)
309   /* cache all labels */ /*{{{*/
310   {
311     const char *l;
312 
313     l=getlabel(sheet,x,y,z);
314     if (*l)
315     {
316       unsigned long hx;
317       struct Label **run;
318 
319       HASH(hx,l);
320       for (run=&sheet->labelcache[(unsigned int)hx]; *run!=(struct Label*)0 && strcmp(l,(*run)->label); run=&((*run)->next));
321       if (*run==(struct Label*)0)
322       {
323         *run=malloc(sizeof(struct Label));
324         (*run)->next=(struct Label*)0;
325         (*run)->label=l;
326         (*run)->x=x;
327         (*run)->y=y;
328         (*run)->z=z;
329       }
330       /* else we have a duplicate label, which _can_ happen under */
331       /* unfortunate conditions.  Don't tell anybody. */
332     }
333   }
334   /*}}}*/
335 }
336 /*}}}*/
337 /* freesheet     -- free all cells of an entire spread sheet */ /*{{{*/
freesheet(Sheet * sheet,int all)338 void freesheet(Sheet *sheet, int all)
339 {
340   /* variables */ /*{{{*/
341   int x,y,z;
342   /*}}}*/
343 
344   assert(sheet!=(Sheet*)0);
345   sheet->changed=0;
346   for (x=0; x<sheet->dimx; ++x) for (y=0; y<sheet->dimy; ++y) for (z=0; z<sheet->dimz; ++z)
347   {
348     freecell(sheet,x,y,z);
349   }
350   if (all)
351   {
352     int i;
353 
354     for (i=0; i<LABEL_CACHE; ++i) /* free all buckets */ /*{{{*/
355     {
356       struct Label *run;
357 
358       for (run=sheet->labelcache[i]; run!=(struct Label*)0;)
359       {
360         struct Label *runnext;
361 
362         runnext=run->next;
363         free(run);
364         run=runnext;
365       }
366     }
367     /*}}}*/
368     if (sheet->sheet) free(sheet->sheet);
369     if (sheet->column) free(sheet->column);
370     if (sheet->name) free(sheet->name);
371   }
372   else
373   {
374     for (x=0; x<sheet->dimx; ++x) for (z=0; z<sheet->dimz; ++z)
375     {
376       *(sheet->column+x*sheet->dimz+z)=DEF_COLUMNWIDTH;
377     }
378     cachelabels(sheet);
379     forceupdate(sheet);
380   }
381 }
382 /*}}}*/
383 /* forceupdate   -- clear all clock and update flags */ /*{{{*/
forceupdate(Sheet * sheet)384 void forceupdate(Sheet *sheet)
385 {
386   int i;
387 
388   assert(sheet!=(Sheet*)0);
389   for (i=0; i<sheet->dimx*sheet->dimy*sheet->dimz; ++i) if (*(sheet->sheet+i)!=(Cell*)0)
390   {
391     (*(sheet->sheet+i))->updated=0;
392     (*(sheet->sheet+i))->clock_t0=0;
393     (*(sheet->sheet+i))->clock_t1=0;
394     (*(sheet->sheet+i))->clock_t2=0;
395   }
396   update(sheet);
397 }
398 /*}}}*/
399 /* freecell      -- free one cell */ /*{{{*/
freecell(Sheet * sheet,int x,int y,int z)400 void freecell(Sheet *sheet, int x, int y, int z)
401 {
402   assert(sheet!=(Sheet*)0);
403   if (sheet->sheet!=(Cell**)0 && x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0)
404   {
405     tvecfree(SHEET(sheet,x,y,z)->contents);
406     tvecfree(SHEET(sheet,x,y,z)->ccontents);
407     tfree(&(SHEET(sheet,x,y,z)->value));
408     free(SHEET(sheet,x,y,z));
409     SHEET(sheet,x,y,z)=(Cell*)0;
410     sheet->changed=1;
411   }
412 }
413 /*}}}*/
414 /* columnwidth   -- get width of column */ /*{{{*/
columnwidth(Sheet * sheet,int x,int z)415 int columnwidth(Sheet *sheet, int x, int z)
416 {
417   assert(sheet!=(Sheet*)0);
418   if (x<sheet->dimx && z<sheet->dimz) return (*(sheet->column+x*sheet->dimz+z));
419   else return DEF_COLUMNWIDTH;
420 }
421 /*}}}*/
422 /* setwidth      -- set width of column */ /*{{{*/
setwidth(Sheet * sheet,int x,int z,int width)423 void setwidth(Sheet *sheet, int x, int z, int width)
424 {
425   assert(sheet!=(Sheet*)0);
426   resize(sheet,x,1,z);
427   sheet->changed=1;
428   *(sheet->column+x*sheet->dimz+z)=width;
429 }
430 /*}}}*/
431 /* cellwidth     -- get width of a cell */ /*{{{*/
cellwidth(Sheet * sheet,int x,int y,int z)432 int cellwidth(Sheet *sheet, int x, int y, int z)
433 {
434   int width;
435 
436   if (SHADOWED(sheet,x,y,z)) return 0;
437   width=columnwidth(sheet,x,z);
438   for (++x; SHADOWED(sheet,x,y,z); width+=columnwidth(sheet,x,z),++x);
439   return width;
440 }
441 /*}}}*/
442 /* putcont       -- assign new contents */ /*{{{*/
putcont(Sheet * sheet,int x,int y,int z,Token ** t,int c)443 void putcont(Sheet *sheet, int x, int y, int z, Token **t, int c)
444 {
445   assert(sheet!=(Sheet*)0);
446   sheet->changed=1;
447   resize(sheet,x,y,z);
448   initcell(sheet,x,y,z);
449   if (c)
450   {
451     tvecfree(SHEET(sheet,x,y,z)->ccontents);
452     SHEET(sheet,x,y,z)->ccontents=t;
453   }
454   else
455   {
456     tvecfree(SHEET(sheet,x,y,z)->contents);
457     SHEET(sheet,x,y,z)->contents=t;
458   }
459   redraw_cell(sheet, x, y, z);
460 }
461 /*}}}*/
462 /* getcont       -- get contents */ /*{{{*/
getcont(Sheet * sheet,int x,int y,int z,int c)463 Token **getcont(Sheet *sheet, int x, int y, int z, int c)
464 {
465   if (x>=sheet->dimx || y>=sheet->dimy || z>=sheet->dimz) return (Token**)0;
466   else if (SHEET(sheet,x,y,z)==(Cell*)0) return (Token**)0;
467   else if (c==2) return (SHEET(sheet,x,y,z)->clock_t0 && SHEET(sheet,x,y,z)->ccontents ? SHEET(sheet,x,y,z)->ccontents : SHEET(sheet,x,y,z)->contents);
468   else return (c ? SHEET(sheet,x,y,z)->ccontents : SHEET(sheet,x,y,z)->contents);
469 }
470 /*}}}*/
471 /* getvalue      -- get tcopy()ed value */ /*{{{*/
getvalue(Sheet * sheet,int x,int y,int z)472 Token getvalue(Sheet *sheet, int x, int y, int z)
473 {
474   /* variables */ /*{{{*/
475   Token result;
476   int orig_upd_clock;
477   /*}}}*/
478 
479   assert(sheet!=(Sheet*)0);
480   if (x<0 || y<0 || z<0)
481   /* return error */ /*{{{*/
482   {
483     result.type=EEK;
484     result.u.err=mystrmalloc(_("Negative index"));
485   }
486   /*}}}*/
487   else if (getcont(sheet,x,y,z,2)==(Token**)0)
488   /* return empty value */ /*{{{*/
489   result.type=EMPTY;
490   /*}}}*/
491   else
492   /* update value of this cell if needed and return it */ /*{{{*/
493   {
494     orig_upd_clock=upd_clock;
495     if (SHEET(sheet,x,y,z)->ignored)
496     {
497       /* variables */ /*{{{*/
498       Token oldvalue;
499       /*}}}*/
500 
501       oldvalue=SHEET(sheet,x,y,z)->value;
502       SHEET(sheet,x,y,z)->updated=1;
503       SHEET(sheet,x,y,z)->value.type=EMPTY;
504       tfree(&oldvalue);
505     }
506     else if (SHEET(sheet,x,y,z)->updated==0)
507     {
508       /* variables */ /*{{{*/
509       Sheet *old_sheet;
510       int old_x,old_y,old_z,old_max_eval;
511       Token oldvalue;
512       /*}}}*/
513 
514       old_sheet=upd_sheet;
515       old_x=upd_x;
516       old_y=upd_y;
517       old_z=upd_z;
518       old_max_eval=max_eval;
519       upd_sheet=sheet;
520       upd_x=x;
521       upd_y=y;
522       upd_z=z;
523       max_eval=MAX_EVALNEST;
524       if (SHEET(sheet,x,y,z)->clock_t1==0)
525       {
526         SHEET(sheet,x,y,z)->updated=1;
527         oldvalue=SHEET(sheet,x,y,z)->value;
528         upd_clock=0;
529         SHEET(sheet,x,y,z)->value=eval(getcont(sheet,x,y,z,2));
530         tfree(&oldvalue);
531       }
532       else if (upd_clock)
533       {
534         SHEET(sheet,x,y,z)->updated=1;
535         upd_clock=0;
536         SHEET(sheet,x,y,z)->resvalue=eval(getcont(sheet,x,y,z,2));
537       }
538       upd_sheet=old_sheet;
539       upd_x=old_x;
540       upd_y=old_y;
541       upd_z=old_z;
542       max_eval=old_max_eval;
543     }
544     if (!orig_upd_clock) result=tcopy(SHEET(sheet,x,y,z)->value);
545   }
546   /*}}}*/
547   return result;
548 }
549 /*}}}*/
550 /* update        -- update all cells that need it */ /*{{{*/
update(Sheet * sheet)551 void update(Sheet *sheet)
552 {
553   int x,y,z,kp,iterating;
554 
555   assert(sheet!=(Sheet*)0);
556   kp=0;
557   iterating=0;
558   do
559   {
560     sheet->clk=0;
561     if (iterating==1)
562     {
563       line_msg((const char*)0,_("Calculating running, press Escape to abort it"));
564       ++iterating;
565     }
566     else if (iterating==0) ++iterating;
567     for (x=0; x<sheet->dimx; ++x) for (y=0; y<sheet->dimy; ++y) for (z=0; z<sheet->dimz; ++z)
568     {
569       if (SHEET(sheet,x,y,z) && SHEET(sheet,x,y,z)->clock_t2)
570       {
571         SHEET(sheet,x,y,z)->updated=0;
572         SHEET(sheet,x,y,z)->clock_t0=1;
573         SHEET(sheet,x,y,z)->clock_t1=1;
574         SHEET(sheet,x,y,z)->clock_t2=0;
575       }
576     }
577     for (x=0; x<sheet->dimx; ++x) for (y=0; y<sheet->dimy; ++y) for (z=0; z<sheet->dimz; ++z)
578     {
579       upd_clock=1;
580       getvalue(sheet,x,y,z);
581     }
582     for (x=0; x<sheet->dimx; ++x) for (y=0; y<sheet->dimy; ++y) for (z=0; z<sheet->dimz; ++z)
583     {
584       if (SHEET(sheet,x,y,z) && SHEET(sheet,x,y,z)->clock_t1)
585       {
586         tfree(&(SHEET(sheet,x,y,z)->value));
587         SHEET(sheet,x,y,z)->value=SHEET(sheet,x,y,z)->resvalue;
588         SHEET(sheet,x,y,z)->clock_t1=0;
589       }
590     }
591     upd_clock=0;
592   } while (sheet->clk && !(kp=keypressed()));
593   if (iterating==2) line_msg((const char*)0,kp ? _("Calculation aborted") : _("Calculation finished"));
594   sheet->clk=0;
595   redraw_sheet(sheet);
596 }
597 /*}}}*/
598 /* geterror      -- get malloc()ed error string */ /*{{{*/
geterror(Sheet * sheet,int x,int y,int z)599 char *geterror(Sheet *sheet, int x, int y, int z)
600 {
601   Token v;
602 
603   assert(sheet!=(Sheet*)0);
604   if ((v=getvalue(sheet,x,y,z)).type!=EEK)
605   {
606     tfree(&v);
607     return (char*)0;
608   }
609   else
610   {
611     return (v.u.err);
612   }
613 }
614 /*}}}*/
615 /* printvalue    -- get ASCII representation of value */ /*{{{*/
printvalue(char * s,size_t size,size_t chars,int quote,int scientific,int precision,Sheet * sheet,int x,int y,int z)616 void printvalue(char *s, size_t size, size_t chars, int quote, int scientific, int precision, Sheet *sheet, int x, int y, int z)
617 {
618   Token *tv[2],t;
619 
620   assert(sheet!=(Sheet*)0);
621   t=getvalue(sheet,x,y,z); tv[0]=&t;
622   tv[1]=(Token*)0;
623   print(s,size,chars,quote,scientific,precision,tv);
624   tfree(&t);
625 }
626 /*}}}*/
627 /* getadjust     -- get cell adjustment */ /*{{{*/
getadjust(Sheet * sheet,int x,int y,int z)628 Adjust getadjust(Sheet *sheet, int x, int y, int z)
629 {
630   assert(sheet!=(Sheet*)0);
631   if (x>=sheet->dimx || y>=sheet->dimy || z>=sheet->dimz || SHEET(sheet,x,y,z)==(Cell*)0)
632   {
633     return LEFT;
634   }
635   else if (SHEET(sheet,x,y,z)->adjust==AUTOADJUST) return (SHEET(sheet,x,y,z)->value.type==INT || SHEET(sheet,x,y,z)->value.type==FLOAT ? RIGHT : LEFT);
636   else return (SHEET(sheet,x,y,z)->adjust);
637 }
638 /*}}}*/
639 /* setadjust     -- set cell adjustment */ /*{{{*/
setadjust(Sheet * sheet,int x,int y,int z,Adjust adjust)640 void setadjust(Sheet *sheet, int x, int y, int z, Adjust adjust)
641 {
642   assert(sheet!=(Sheet*)0);
643   sheet->changed=1;
644   resize(sheet,x,y,z);
645   initcell(sheet,x,y,z);
646   SHEET(sheet,x,y,z)->adjust=adjust;
647 }
648 /*}}}*/
649 
650 /* shadow        -- shadow cell by left neighbour */ /*{{{*/
shadow(Sheet * sheet,int x,int y,int z,int yep)651 void shadow(Sheet *sheet, int x, int y, int z, int yep)
652 {
653   sheet->changed=1;
654   initcell(sheet,x,y,z);
655   SHEET(sheet,x,y,z)->shadowed=yep;
656 }
657 /*}}}*/
658 /* shadowed      -- is cell shadowed? */ /*{{{*/
shadowed(Sheet * sheet,int x,int y,int z)659 int shadowed(Sheet *sheet, int x, int y, int z)
660 {
661   return (SHADOWED(sheet,x,y,z));
662 }
663 /*}}}*/
664 /* bold        -- bold font */ /*{{{*/
bold(Sheet * sheet,int x,int y,int z,int yep)665 void bold(Sheet *sheet, int x, int y, int z, int yep)
666 {
667   sheet->changed=1;
668   initcell(sheet,x,y,z);
669   SHEET(sheet,x,y,z)->bold=yep;
670 }
671 /*}}}*/
672 /* isbold      -- is cell bold? */ /*{{{*/
isbold(Sheet * sheet,int x,int y,int z)673 int isbold(Sheet *sheet, int x, int y, int z)
674 {
675   return (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0 && SHEET(sheet,x,y,z)->bold);
676 }
677 /*}}}*/
678 /* underline        -- underline */ /*{{{*/
underline(Sheet * sheet,int x,int y,int z,int yep)679 void underline(Sheet *sheet, int x, int y, int z, int yep)
680 {
681   sheet->changed=1;
682   initcell(sheet,x,y,z);
683   SHEET(sheet,x,y,z)->underline=yep;
684 }
685 /*}}}*/
686 /* isunderline      -- is cell underlined? */ /*{{{*/
underlined(Sheet * sheet,int x,int y,int z)687 int underlined(Sheet *sheet, int x, int y, int z)
688 {
689   return (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0 && SHEET(sheet,x,y,z)->underline);
690 }
691 /*}}}*/
692 /* lockcell      -- lock cell */ /*{{{*/
lockcell(Sheet * sheet,int x,int y,int z,int yep)693 void lockcell(Sheet *sheet, int x, int y, int z, int yep)
694 {
695   sheet->changed=1;
696   initcell(sheet,x,y,z);
697   SHEET(sheet,x,y,z)->locked=yep;
698 }
699 /*}}}*/
700 /* locked        -- is cell locked? */ /*{{{*/
locked(Sheet * sheet,int x,int y,int z)701 int locked(Sheet *sheet, int x, int y, int z)
702 {
703   return (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0 && SHEET(sheet,x,y,z)->locked);
704 }
705 /*}}}*/
706 /* transparent   -- is cell transparent? */ /*{{{*/
transparent(Sheet * sheet,int x,int y,int z)707 int transparent(Sheet *sheet, int x, int y, int z)
708 {
709   return (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0 && SHEET(sheet,x,y,z)->transparent);
710 }
711 /*}}}*/
712 /* maketrans     -- make cell transparent */ /*{{{*/
maketrans(Sheet * sheet,int x,int y,int z,int yep)713 void maketrans(Sheet *sheet, int x, int y, int z, int yep)
714 {
715   sheet->changed=1;
716   initcell(sheet,x,y,z);
717   SHEET(sheet,x,y,z)->transparent=yep;
718 }
719 /*}}}*/
720 /* igncell       -- ignore cell */ /*{{{*/
igncell(Sheet * sheet,int x,int y,int z,int yep)721 void igncell(Sheet *sheet, int x, int y, int z, int yep)
722 {
723   sheet->changed=1;
724   initcell(sheet,x,y,z);
725   SHEET(sheet,x,y,z)->ignored=yep;
726 }
727 /*}}}*/
728 /* ignored       -- is cell ignored? */ /*{{{*/
ignored(Sheet * sheet,int x,int y,int z)729 int ignored(Sheet *sheet, int x, int y, int z)
730 {
731   return (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0 && SHEET(sheet,x,y,z)->ignored);
732 }
733 /*}}}*/
734 /* clk           -- clock cell */ /*{{{*/
clk(Sheet * sheet,int x,int y,int z)735 void clk(Sheet *sheet, int x, int y, int z)
736 {
737   assert(sheet!=(Sheet*)0);
738   assert(x>=0 && x<sheet->dimx);
739   assert(y>=0 && y<sheet->dimy);
740   assert(z>=0 && z<sheet->dimz);
741   if (SHEET(sheet,x,y,z))
742   {
743     SHEET(sheet,x,y,z)->clock_t2=1;
744     sheet->clk=1;
745   }
746 }
747 /*}}}*/
748 /* setscientific -- cell value should be displayed in scientific notation */ /*{{{*/
setscientific(Sheet * sheet,int x,int y,int z,int yep)749 void setscientific(Sheet *sheet, int x, int y, int z, int yep)
750 {
751   sheet->changed=1;
752   resize(sheet,x,y,z);
753   initcell(sheet,x,y,z);
754   SHEET(sheet,x,y,z)->scientific=yep;
755 }
756 /*}}}*/
757 /* getscientific -- should value be displayed in scientific notation? */ /*{{{*/
getscientific(Sheet * sheet,int x,int y,int z)758 int getscientific(Sheet *sheet, int x, int y, int z)
759 {
760   if (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0) return SHEET(sheet,x,y,z)->scientific;
761   else return DEF_SCIENTIFIC;
762 }
763 /*}}}*/
764 /* setprecision  -- set cell precision */ /*{{{*/
setprecision(Sheet * sheet,int x,int y,int z,int precision)765 void setprecision(Sheet *sheet, int x, int y, int z, int precision)
766 {
767   sheet->changed=1;
768   resize(sheet,x,y,z);
769   initcell(sheet,x,y,z);
770   SHEET(sheet,x,y,z)->precision=precision;
771 }
772 /*}}}*/
773 /* getprecision  -- get cell precision */ /*{{{*/
getprecision(Sheet * sheet,int x,int y,int z)774 int getprecision(Sheet *sheet, int x, int y, int z)
775 {
776   if (x<sheet->dimx && y<sheet->dimy && z<sheet->dimz && SHEET(sheet,x,y,z)!=(Cell*)0) return (SHEET(sheet,x,y,z)->precision==-1 ? def_precision : SHEET(sheet,x,y,z)->precision);
777   else return def_precision;
778 }
779 /*}}}*/
780 /* getlabel      -- get cell label */ /*{{{*/
getlabel(Sheet * sheet,int x,int y,int z)781 const char *getlabel(Sheet *sheet, int x, int y, int z)
782 {
783   if (x>=sheet->dimx || y>=sheet->dimy || z>=sheet->dimz || SHEET(sheet,x,y,z)==(Cell*)0 || SHEET(sheet,x,y,z)->label==(char*)0) return "";
784   else return (SHEET(sheet,x,y,z)->label);
785 }
786 /*}}}*/
787 /* setlabel      -- set cell label */ /*{{{*/
setlabel(Sheet * sheet,int x,int y,int z,const char * buf,int update)788 void setlabel(Sheet *sheet, int x, int y, int z, const char *buf, int update)
789 {
790   sheet->changed=1;
791   resize(sheet,x,y,z);
792   initcell(sheet,x,y,z);
793   if (SHEET(sheet,x,y,z)->label!=(char*)0) free(SHEET(sheet,x,y,z)->label);
794   if (*buf!='\0') SHEET(sheet,x,y,z)->label=strcpy(malloc(strlen(buf)+1),buf);
795   else SHEET(sheet,x,y,z)->label=(char*)0;
796   if (update)
797   {
798     cachelabels(sheet);
799     forceupdate(sheet);
800   }
801 }
802 /*}}}*/
803 /* findlabel     -- return cell location for a given label */ /*{{{*/
findlabel(Sheet * sheet,const char * label)804 Token findlabel(Sheet *sheet, const char *label)
805 {
806   /* variables */ /*{{{*/
807   Token result;
808   unsigned long hx;
809   struct Label *run;
810   /*}}}*/
811 
812   assert(sheet!=(Sheet*)0);
813 /*
814   if (sheet==(Sheet*)0) run=(struct Label*)0;
815   else
816 */
817   {
818     HASH(hx,label);
819     for (run=sheet->labelcache[(unsigned int)hx]; run!=(struct Label*)0 && strcmp(label,run->label); run=run->next);
820   }
821   if (run)
822   {
823     result.type=LOCATION;
824     result.u.location[0]=run->x;
825     result.u.location[1]=run->y;
826     result.u.location[2]=run->z;
827   }
828   else
829   {
830     result.type=EEK;
831     result.u.err=mystrmalloc(_("No such label"));
832   }
833   return result;
834 }
835 /*}}}*/
836 /* relabel       -- search and replace for labels */ /*{{{*/
relabel(Sheet * sheet,const char * oldlabel,const char * newlabel,int x,int y,int z)837 void relabel(Sheet *sheet, const char *oldlabel, const char *newlabel, int x, int y, int z)
838 {
839   /* variables */ /*{{{*/
840   Token **run;
841   /*}}}*/
842 
843   /* asserts */ /*{{{*/
844   assert(sheet!=(Sheet*)0);
845   assert(oldlabel!=(const char*)0);
846   assert(newlabel!=(const char*)0);
847   assert(x>=0);
848   assert(y>=0);
849   assert(z>=0);
850   /*}}}*/
851   if (!(x>=sheet->dimx || y>=sheet->dimy || z>=sheet->dimz || SHEET(sheet,x,y,z)==(Cell*)0 || SHEET(sheet,x,y,z)->contents==(Token**)0))
852   {
853     for (run=SHEET(sheet,x,y,z)->contents; *run!=(Token*)0; ++run)
854     {
855       if ((*run)->type==LIDENT && strcmp((*run)->u.lident,oldlabel)==0)
856       {
857         free((*run)->u.lident);
858         (*run)->u.lident=mystrmalloc(newlabel);
859       }
860     }
861   }
862   if (!(x>=sheet->dimx || y>=sheet->dimy || z>=sheet->dimz || SHEET(sheet,x,y,z)==(Cell*)0 || SHEET(sheet,x,y,z)->ccontents==(Token**)0))
863   {
864     for (run=SHEET(sheet,x,y,z)->ccontents; *run!=(Token*)0; ++run)
865     {
866       if ((*run)->type==LIDENT && strcmp((*run)->u.lident,oldlabel)==0)
867       {
868         free((*run)->u.lident);
869         (*run)->u.lident=mystrmalloc(newlabel);
870       }
871     }
872   }
873   cachelabels(sheet);
874   forceupdate(sheet);
875 }
876 /*}}}*/
877 /* savexdr       -- save a spread sheet in XDR */ /*{{{*/
savexdr(Sheet * sheet,const char * name,unsigned int * count)878 const char *savexdr(Sheet *sheet, const char *name, unsigned int *count)
879 {
880   /* variables */ /*{{{*/
881   FILE *fp;
882   XDR xdrs;
883   int x,y,z;
884   /*}}}*/
885 
886   *count=0;
887   if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
888   xdrstdio_create(&xdrs,fp,XDR_ENCODE);
889   if (!xdr_magic(&xdrs))
890   {
891     xdr_destroy(&xdrs);
892     (void)fclose(fp);
893     return strerror(errno);
894   }
895   for (x=sheet->dimx-1; x>=0; --x) for (z=sheet->dimz-1; z>=0; --z)
896   {
897     int width;
898     int u;
899 
900     width=columnwidth(sheet,x,z);
901     if (width!=DEF_COLUMNWIDTH)
902     {
903       u=0;
904       if (xdr_int(&xdrs,&u)==0 || xdr_column(&xdrs,&x,&z,&width)==0)
905       {
906         xdr_destroy(&xdrs);
907         (void)fclose(fp);
908         return strerror(errno);
909       }
910     }
911     for (y=sheet->dimy-1; y>=0; --y)
912     {
913       if (SHEET(sheet,x,y,z)!=(Cell*)0)
914       {
915         u=1;
916         if (xdr_int(&xdrs,&u)==0 || xdr_int(&xdrs,&x)==0 || xdr_int(&xdrs,&y)==0 || xdr_int(&xdrs,&z)==0 || xdr_cell(&xdrs,SHEET(sheet,x,y,z))==0)
917         {
918           xdr_destroy(&xdrs);
919           (void)fclose(fp);
920           return strerror(errno);
921         }
922         ++*count;
923       }
924     }
925   }
926   xdr_destroy(&xdrs);
927   if (fclose(fp)==EOF) return strerror(errno);
928   sheet->changed=0;
929   return (const char*)0;
930 }
931 /*}}}*/
932 /* savetbl       -- save as tbl tyble */ /*{{{*/
savetbl(Sheet * sheet,const char * name,int body,int x1,int y1,int z1,int x2,int y2,int z2,unsigned int * count)933 const char *savetbl(Sheet *sheet, const char *name, int body, int x1, int y1, int z1, int x2, int y2, int z2, unsigned int *count)
934 {
935   /* variables */ /*{{{*/
936   FILE *fp=(FILE*)0; /* cause run time error */
937   int x,y,z;
938   char buf[1024];
939   char num[20];
940   char fullname[PATH_MAX];
941   /*}}}*/
942 
943   /* asserts */ /*{{{*/
944   assert(sheet!=(Sheet*)0);
945   assert(name!=(const char*)0);
946   /*}}}*/
947   *count=0;
948   for (z=z1; z<=z2; ++z) for (y=y1; y<=y2; ++y) if (shadowed(sheet,x1,y,z)) return _("Shadowed cells in first column");
949   if (!body && (fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
950   for (z=z1; z<=z2; ++z)
951   {
952     if (body)
953     /* open new file */ /*{{{*/
954     {
955       sprintf(num,".%d",z);
956       fullname[sizeof(fullname)-strlen(num)-1]='\0';
957       (void)strncpy(fullname,name,sizeof(fullname)-strlen(num)-1);
958       fullname[sizeof(fullname)-1]='\0';
959       (void)strncat(fullname,num,sizeof(fullname)-strlen(num)-1);
960       fullname[sizeof(fullname)-1]='\0';
961       if ((fp=fopen(fullname,"w"))==(FILE*)0) return strerror(errno);
962     }
963     /*}}}*/
964     else if (fputs_close(".TS\n",fp)==EOF) return strerror(errno);
965     for (y=y1; y<=y2; ++y)
966     {
967       /* print format */ /*{{{*/
968       if (y>y1 && fputs_close(".T&\n",fp)==EOF) return strerror(errno);
969       for (x=x1; x<=x2; ++x)
970       {
971         if (x>x1 && fputc_close(' ',fp)==EOF) return strerror(errno);
972         if (shadowed(sheet,x,y,z))
973         {
974           if (fputc_close('s',fp)==EOF) return strerror(errno);
975         }
976         if (isbold(sheet,x,y,z))
977         {
978           if (fputc_close('b',fp)==EOF) return strerror(errno);
979         }
980         if (underlined(sheet,x,y,z))
981         {
982           if (fputc_close('u',fp)==EOF) return strerror(errno);
983         }
984         else switch (getadjust(sheet,x,y,z))
985         {
986           case LEFT: if (fputc_close('l',fp)==EOF) return strerror(errno); break;
987           case RIGHT: if (fputc_close('r',fp)==EOF) return strerror(errno); break;
988           case CENTER: if (fputc_close('c',fp)==EOF) return strerror(errno); break;
989           default: assert(0);
990         }
991       }
992       if (fputs_close(".\n",fp)==EOF) return strerror(errno);
993       /*}}}*/
994       /* print contents */ /*{{{*/
995       for (x=x1; x<=x2; ++x)
996       {
997         if (!shadowed(sheet,x,y,z))
998         {
999           if (x>x1 && fputc_close('\t',fp)==EOF) return strerror(errno);
1000           if (SHEET(sheet,x,y,z)!=(Cell*)0)
1001           {
1002             char *bufp;
1003 
1004             printvalue(buf,sizeof(buf),0,0,getscientific(sheet,x,y,z),getprecision(sheet,x,y,z),sheet,x,y,z);
1005             if (transparent(sheet,x,y,z))
1006             {
1007               if (fputs_close(buf,fp)==EOF) return strerror(errno);
1008             }
1009             else for (bufp=buf; *bufp; ++bufp) switch (*bufp)
1010             {
1011               case '\\':
1012               {
1013                 if (fputc_close('\\',fp)==EOF || fputc_close('e',fp)==EOF) return strerror(errno);
1014                 break;
1015               }
1016               case '_':
1017               {
1018                 if (fputc_close('\\',fp)==EOF || fputc_close('&',fp)==EOF || fputc_close('_',fp)==EOF) return strerror(errno);
1019                 break;
1020               }
1021               case '.':
1022               {
1023                 if (x==x1 && bufp==buf && (fputc_close('\\',fp)==EOF || fputc_close('&',fp)==EOF)) return strerror(errno);
1024                 if (fputc_close('.',fp)==EOF) return strerror(errno);
1025                 break;
1026               }
1027               case '\'':
1028               {
1029                 if (x==x1 && bufp==buf && (fputc_close('\\',fp)==EOF || fputc_close('&',fp)==EOF)) return strerror(errno);
1030                 if (fputc_close('\'',fp)==EOF) return strerror(errno);
1031                 break;
1032               }
1033               case '-':
1034               {
1035                 if (*(bufp+1)=='-')
1036                 {
1037                   if (fputc_close('-',fp)==EOF) return strerror(errno);
1038                   else ++bufp;
1039                 }
1040                 else if (fputs_close("\\-",fp)==EOF) return strerror(errno);
1041                 break;
1042               }
1043               default: if (fputc_close(*bufp,fp)==EOF) return strerror(errno);
1044             }
1045           }
1046         }
1047       }
1048       if (fputc_close('\n',fp)==EOF) return strerror(errno);
1049       /*}}}*/
1050       ++*count;
1051     }
1052     if (!body)
1053     {
1054       if (fputs_close(".TE\n",fp)==EOF) return strerror(errno);
1055       if (z<z2 && fputs_close(".bp\n",fp)==EOF) return strerror(errno);
1056     }
1057     if (body && fclose(fp)==EOF) return strerror(errno);
1058   }
1059   if (!body && fclose(fp)==EOF) return strerror(errno);
1060   return (const char*)0;
1061 }
1062 /*}}}*/
1063 /* savetext      -- save as text */ /*{{{*/
savetext(Sheet * sheet,const char * name,int x1,int y1,int z1,int x2,int y2,int z2,unsigned int * count)1064 const char *savetext(Sheet *sheet, const char *name, int x1, int y1, int z1, int x2, int y2, int z2, unsigned int *count)
1065 {
1066   /* variables */ /*{{{*/
1067   FILE *fp;
1068   int x,y,z;
1069   /*}}}*/
1070 
1071   /* asserts */ /*{{{*/
1072   assert(sheet!=(Sheet*)0);
1073   assert(name!=(const char*)0);
1074   /*}}}*/
1075   *count=0;
1076   for (z=z1; z<=z2; ++z) for (y=y1; y<=y2; ++y) if (shadowed(sheet,x1,y,z)) return _("Shadowed cells in first column");
1077   if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
1078   for (z=z1; z<=z2; ++z)
1079   {
1080     for (y=y1; y<=y2; ++y)
1081     {
1082       size_t size,fill;
1083 
1084       for (x=x1; x<=x2; ++x)
1085       {
1086         size=cellwidth(sheet,x,y,z);
1087         if (SHEET(sheet,x,y,z)!=(Cell*)0)
1088         {
1089           char *buf;
1090 
1091           buf=malloc(size*UTF8SZ+1);
1092           printvalue(buf,size*UTF8SZ+1,size,0,getscientific(sheet,x,y,z),getprecision(sheet,x,y,z),sheet,x,y,z);
1093           adjust(getadjust(sheet,x,y,z),buf,size);
1094           if (fputs_close(buf,fp)==EOF)
1095           {
1096             free(buf);
1097             return strerror(errno);
1098           }
1099           for (fill=strlen(buf); fill<size; ++fill) if (fputc_close(' ',fp)==EOF)
1100           {
1101             free(buf);
1102             return strerror(errno);
1103           }
1104           free(buf);
1105         }
1106         else
1107         {
1108           for (fill=0; fill<size; ++fill) if (fputc_close(' ',fp)==EOF) return strerror(errno);
1109         }
1110         ++*count;
1111       }
1112       if (fputc_close('\n',fp)==EOF) return strerror(errno);
1113     }
1114     if (z<z2 && fputs_close("\f",fp)==EOF) return strerror(errno);
1115   }
1116   if (fclose(fp)==EOF) return strerror(errno);
1117   return (const char*)0;
1118 }
1119 /*}}}*/
1120 /* savecsv       -- save as CSV */ /*{{{*/
savecsv(Sheet * sheet,const char * name,char sep,int x1,int y1,int z1,int x2,int y2,int z2,unsigned int * count)1121 const char *savecsv(Sheet *sheet, const char *name, char sep, int x1, int y1, int z1, int x2, int y2, int z2, unsigned int *count)
1122 {
1123   /* variables */ /*{{{*/
1124   FILE *fp;
1125   int x,y,z;
1126   /*}}}*/
1127 
1128   /* asserts */ /*{{{*/
1129   assert(sheet!=(Sheet*)0);
1130   assert(name!=(const char*)0);
1131   /*}}}*/
1132   *count=0;
1133   for (z=z1; z<=z2; ++z) for (y=y1; y<=y2; ++y) if (shadowed(sheet,x1,y,z)) return _("Shadowed cells in first column");
1134   if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
1135   for (z=z1; z<=z2; ++z)
1136   {
1137     for (y=y1; y<=y2; ++y)
1138     {
1139       for (x=x1; x<=x2; ++x)
1140       {
1141         if (x>x1) if (fputc_close(sep,fp)==EOF) return strerror(errno);
1142         if (SHEET(sheet,x,y,z)!=(Cell*)0)
1143         {
1144           char *buf,*s;
1145 
1146           buf=malloc(255*UTF8SZ+1);
1147           printvalue(buf,255*UTF8SZ+1,255,0,getscientific(sheet,x,y,z),getprecision(sheet,x,y,z),sheet,x,y,z);
1148           if (SHEET(sheet,x,y,z)->value.type==STRING && fputc_close('"',fp)==EOF)
1149           {
1150             free(buf);
1151             return strerror(errno);
1152           }
1153           for (s=buf; *s; ++s)
1154           {
1155             if (fputc_close(*s,fp)==EOF || (*s=='"' && fputc_close(*s,fp)==EOF))
1156             {
1157               free(buf);
1158               return strerror(errno);
1159             }
1160           }
1161           free(buf);
1162           if (SHEET(sheet,x,y,z)->value.type==STRING && fputc_close('"',fp)==EOF) return strerror(errno);
1163         }
1164         ++*count;
1165       }
1166       if (fputc_close('\n',fp)==EOF) return strerror(errno);
1167     }
1168     if (z<z2 && fputs_close("\f",fp)==EOF) return strerror(errno);
1169   }
1170   if (fclose(fp)==EOF) return strerror(errno);
1171   return (const char*)0;
1172 }
1173 /*}}}*/
1174 /* saveport      -- save as portable text */ /*{{{*/
saveport(Sheet * sheet,const char * name,unsigned int * count)1175 const char *saveport(Sheet *sheet, const char *name, unsigned int *count)
1176 {
1177   /* variables */ /*{{{*/
1178   FILE *fp;
1179   int x,y,z;
1180   /*}}}*/
1181 
1182   /* asserts */ /*{{{*/
1183   assert(sheet!=(Sheet*)0);
1184   assert(name!=(const char*)0);
1185   /*}}}*/
1186   *count=0;
1187   if ((fp=fopen(name,"w"))==(FILE*)0) return strerror(errno);
1188   fprintf(fp,"# This is a work sheet generated with teapot %s.\n",VERSION);
1189   for (z=sheet->dimz-1; z>=0; --z)
1190   {
1191     for (y=sheet->dimy-1; y>=0; --y)
1192     {
1193       for (x=sheet->dimx-1; x>=0; --x)
1194       {
1195         if (y==0) if (columnwidth(sheet,x,z)!=DEF_COLUMNWIDTH) fprintf(fp,"W%d %d %d\n",x,z,columnwidth(sheet,x,z));
1196         if (SHEET(sheet,x,y,z)!=(Cell*)0)
1197         {
1198           fprintf(fp,"C%d %d %d ",x,y,z);
1199           if (SHEET(sheet,x,y,z)->adjust!=AUTOADJUST) fprintf(fp,"A%c ","lrc"[SHEET(sheet,x,y,z)->adjust]);
1200           if (SHEET(sheet,x,y,z)->label) fprintf(fp,"L%s ",SHEET(sheet,x,y,z)->label);
1201           if (SHEET(sheet,x,y,z)->precision!=-1) fprintf(fp,"P%d ",SHEET(sheet,x,y,z)->precision);
1202           if (SHEET(sheet,x,y,z)->shadowed) fprintf(fp,"S ");
1203           if (SHEET(sheet,x,y,z)->bold) fprintf(fp,"B ");
1204           if (SHEET(sheet,x,y,z)->underline) fprintf(fp,"U ");
1205           if (SHEET(sheet,x,y,z)->scientific!=DEF_SCIENTIFIC) fprintf(fp,"E ");
1206           if (SHEET(sheet,x,y,z)->locked) fprintf(fp,"C ");
1207           if (SHEET(sheet,x,y,z)->transparent) fprintf(fp,"T ");
1208           if (SHEET(sheet,x,y,z)->contents)
1209           {
1210             char buf[4096];
1211 
1212             if (fputc_close(':',fp)==EOF) return strerror(errno);
1213             print(buf,sizeof(buf),0,1,SHEET(sheet,x,y,z)->scientific,SHEET(sheet,x,y,z)->precision,SHEET(sheet,x,y,z)->contents);
1214             if (fputs_close(buf,fp)==EOF) return strerror(errno);
1215           }
1216           if (SHEET(sheet,x,y,z)->ccontents)
1217           {
1218             char buf[4096];
1219 
1220             if (fputs_close("\\\n",fp)==EOF) return strerror(errno);
1221             print(buf,sizeof(buf),0,1,SHEET(sheet,x,y,z)->scientific,SHEET(sheet,x,y,z)->precision,SHEET(sheet,x,y,z)->ccontents);
1222             if (fputs_close(buf,fp)==EOF) return strerror(errno);
1223           }
1224           if (fputc_close('\n',fp)==EOF) return strerror(errno);
1225           ++*count;
1226         }
1227       }
1228     }
1229   }
1230   if (fclose(fp)==EOF) return strerror(errno);
1231   return (const char*)0;
1232 }
1233 /*}}}*/
1234 /* loadport      -- load from portable text */ /*{{{*/
loadport(Sheet * sheet,const char * name)1235 const char *loadport(Sheet *sheet, const char *name)
1236 {
1237   /* variables */ /*{{{*/
1238   static char errbuf[80];
1239   FILE *fp;
1240   int x,y,z;
1241   char buf[4096];
1242   int line;
1243   const char *ns,*os;
1244   const char *err;
1245   int precision;
1246   char *label;
1247   Adjust adjust;
1248   int shadowed;
1249   int bold;
1250   int underline;
1251   int scientific;
1252   int locked;
1253   int transparent;
1254   int ignored;
1255   Token **contents,**ccontents;
1256   int width;
1257   /*}}}*/
1258 
1259   if ((fp=fopen(name,"r"))==(FILE*)0) return strerror(errno);
1260   freesheet(sheet,0);
1261   err=(const char*)0;
1262   line=1;
1263   while (fgets(buf,sizeof(buf),fp)!=(char*)0)
1264   {
1265     /* remove nl */ /*{{{*/
1266     width=strlen(buf);
1267     if (width>0 && buf[width-1]=='\n') buf[--width]='\0';
1268     /*}}}*/
1269     switch (buf[0])
1270     {
1271       /* C       -- parse cell */ /*{{{*/
1272       case 'C':
1273       {
1274         int cc=0;
1275 
1276         if (width>0 && buf[width-1]=='\\') { buf[--width]='\0'; cc=1; }
1277         adjust=AUTOADJUST;
1278         precision=-1;
1279         label=(char*)0;
1280         contents=(Token**)0;
1281         ccontents=(Token**)0;
1282         shadowed=0;
1283         bold=0;
1284         underline=0;
1285         scientific=DEF_SCIENTIFIC;
1286         locked=0;
1287         transparent=0;
1288         ignored=0;
1289         /* parse x y and z */ /*{{{*/
1290         os=ns=buf+1;
1291         x=posnumber(os,&ns);
1292         if (os==ns)
1293         {
1294           sprintf(errbuf,_("Parse error for x position in line %d"),line);
1295           err=errbuf;
1296           goto eek;
1297         }
1298         while (*ns==' ') ++ns;
1299         os=ns;
1300         y=posnumber(os,&ns);
1301         if (os==ns)
1302         {
1303           sprintf(errbuf,_("Parse error for y position in line %d"),line);
1304           err=errbuf;
1305           goto eek;
1306         }
1307         while (*ns==' ') ++ns;
1308         os=ns;
1309         z=posnumber(os,&ns);
1310         if (os==ns)
1311         {
1312           sprintf(errbuf,_("Parse error for z position in line %d"),line);
1313           err=errbuf;
1314           goto eek;
1315         }
1316         /*}}}*/
1317         /* parse optional attributes */ /*{{{*/
1318         do
1319         {
1320           while (*ns==' ') ++ns;
1321           switch (*ns)
1322           {
1323             /* A       -- adjustment */ /*{{{*/
1324             case 'A':
1325             {
1326               ++ns;
1327               switch (*ns)
1328               {
1329                 case 'l': adjust=LEFT; ++ns; break;
1330                 case 'r': adjust=RIGHT; ++ns; break;
1331                 case 'c': adjust=CENTER; ++ns; break;
1332                 default:  sprintf(errbuf,_("Parse error for adjustment in line %d"),line); err=errbuf; goto eek;
1333               }
1334               break;
1335             }
1336             /*}}}*/
1337             /* L       -- label */ /*{{{*/
1338             case 'L':
1339             {
1340               char buf[1024],*p;
1341 
1342               p=buf;
1343               ++ns;
1344               while (*ns && *ns!=' ') { *p=*ns; ++p; ++ns; }
1345               *p='\0';
1346               label=mystrmalloc(buf);
1347               break;
1348             }
1349             /*}}}*/
1350             /* P       -- precision */ /*{{{*/
1351             case 'P':
1352             {
1353               os=++ns;
1354               precision=posnumber(os,&ns);
1355               if (os==ns)
1356               {
1357                 sprintf(errbuf,_("Parse error for precision in line %d"),line);
1358                 err=errbuf;
1359                 goto eek;
1360               }
1361               break;
1362             }
1363             /*}}}*/
1364             /* S       -- shadowed */ /*{{{*/
1365             case 'S':
1366             {
1367               if (x==0)
1368               {
1369                 sprintf(errbuf,_("Trying to shadow cell (%d,%d,%d) in line %d"),x,y,z,line);
1370                 err=errbuf;
1371                 goto eek;
1372               }
1373               ++ns;
1374               shadowed=1;
1375               break;
1376             }
1377             /*}}}*/
1378             /* U       -- underline */ /*{{{*/
1379             case 'U':
1380             {
1381               if (x==0)
1382               {
1383                 sprintf(errbuf,_("Trying to underline cell (%d,%d,%d) in line %d"),x,y,z,line);
1384                 err=errbuf;
1385                 goto eek;
1386               }
1387               ++ns;
1388               underline=1;
1389               break;
1390             }
1391             /*}}}*/
1392             /* B       -- bold */ /*{{{*/
1393             case 'B':
1394             {
1395               if (x==0)
1396               {
1397                 sprintf(errbuf,_("Trying to bold cell (%d,%d,%d) in line %d"),x,y,z,line);
1398                 err=errbuf;
1399                 goto eek;
1400               }
1401               ++ns;
1402               bold=1;
1403               break;
1404             }
1405             /*}}}*/
1406             /* E       -- scientific */ /*{{{*/
1407             case 'E':
1408             {
1409               ++ns;
1410               scientific=1;
1411               break;
1412             }
1413             /*}}}*/
1414             /* O       -- locked */ /*{{{*/
1415             case 'O':
1416             {
1417               ++ns;
1418               locked=1;
1419               break;
1420             }
1421             /*}}}*/
1422             /* T       -- transparent */ /*{{{*/
1423             case 'T':
1424             {
1425               ++ns;
1426               transparent=1;
1427               break;
1428             }
1429             /*}}}*/
1430             /* I       -- ignored */ /*{{{*/
1431             case 'I':
1432             {
1433               ++ns;
1434               ignored=1;
1435               break;
1436             }
1437             /*}}}*/
1438             /* : \0    -- do nothing */ /*{{{*/
1439             case ':':
1440             case '\0': break;
1441             /*}}}*/
1442             /* default -- error */ /*{{{*/
1443             default: sprintf(errbuf,_("Invalid option %c in line %d"),*ns,line); err=errbuf; goto eek;
1444             /*}}}*/
1445           }
1446         } while (*ns!=':' && *ns!='\0');
1447         /*}}}*/
1448         /* convert remaining string into token sequence  */ /*{{{*/
1449         if (*ns)
1450         {
1451           ++ns;
1452           contents=scan(&ns);
1453           if (contents==(Token**)0)
1454           {
1455             tvecfree(contents);
1456             sprintf(errbuf,_("Expression syntax error in line %d"),line);
1457             err=errbuf;
1458             goto eek;
1459           }
1460         }
1461         /*}}}*/
1462         /* convert remaining string into token sequence */ /*{{{*/
1463         if (cc && fgets(buf,sizeof(buf),fp)!=(char*)0)
1464         {
1465           ++line;
1466           /* remove nl */ /*{{{*/
1467           width=strlen(buf);
1468           if (width>0 && buf[width-1]=='\n') buf[width-1]='\0';
1469           /*}}}*/
1470           ns=buf;
1471           ccontents=scan(&ns);
1472           if (ccontents==(Token**)0)
1473           {
1474             tvecfree(ccontents);
1475             sprintf(errbuf,_("Expression syntax error in line %d"),line);
1476             err=errbuf;
1477             goto eek;
1478           }
1479         }
1480         /*}}}*/
1481         initcell(sheet,x,y,z);
1482         SHEET(sheet,x,y,z)->adjust=adjust;
1483         SHEET(sheet,x,y,z)->label=label;
1484         SHEET(sheet,x,y,z)->precision=precision;
1485         SHEET(sheet,x,y,z)->shadowed=shadowed;
1486         SHEET(sheet,x,y,z)->bold=bold;
1487         SHEET(sheet,x,y,z)->underline=underline;
1488         SHEET(sheet,x,y,z)->scientific=scientific;
1489         SHEET(sheet,x,y,z)->locked=locked;
1490         SHEET(sheet,x,y,z)->transparent=transparent;
1491         SHEET(sheet,x,y,z)->ignored=ignored;
1492         SHEET(sheet,x,y,z)->contents=contents;
1493         SHEET(sheet,x,y,z)->ccontents=ccontents;
1494         break;
1495       }
1496       /*}}}*/
1497       /* W       -- column width */ /*{{{*/
1498       case 'W':
1499       {
1500         /* parse x and z */ /*{{{*/
1501         os=ns=buf+1;
1502         x=posnumber(os,&ns);
1503         if (os==ns)
1504         {
1505           sprintf(errbuf,_("Parse error for x position in line %d"),line);
1506           err=errbuf;
1507           goto eek;
1508         }
1509         while (*ns==' ') ++ns;
1510         os=ns;
1511         z=posnumber(os,&ns);
1512         if (os==ns)
1513         {
1514           sprintf(errbuf,_("Parse error for z position in line %d"),line);
1515           err=errbuf;
1516           goto eek;
1517         }
1518         /*}}}*/
1519         /* parse width */ /*{{{*/
1520         while (*ns==' ') ++ns;
1521         os=ns;
1522         width=posnumber(os,&ns);
1523         if (os==ns)
1524         {
1525           sprintf(errbuf,_("Parse error for width in line %d"),line);
1526           err=errbuf;
1527           goto eek;
1528         }
1529         /*}}}*/
1530         setwidth(sheet,x,z,width);
1531         break;
1532       }
1533       /*}}}*/
1534       /* #       -- comment */ /*{{{*/
1535       case '#': break;
1536       /*}}}*/
1537       /* default -- error */ /*{{{*/
1538       default:
1539       {
1540         sprintf(errbuf,_("Unknown tag %c in line %d"),buf[0],line);
1541         err=errbuf;
1542         goto eek;
1543       }
1544       /*}}}*/
1545     }
1546     ++line;
1547   }
1548   eek:
1549   if (fclose(fp)==EOF && err==(const char*)0) err=strerror(errno);
1550   sheet->changed=0;
1551   cachelabels(sheet);
1552   forceupdate(sheet);
1553   return err;
1554 }
1555 /*}}}*/
1556 /* loadxdr       -- load a spread sheet in XDR */ /*{{{*/
loadxdr(Sheet * sheet,const char * name)1557 const char *loadxdr(Sheet *sheet, const char *name)
1558 {
1559   /* variables */ /*{{{*/
1560   FILE *fp;
1561   XDR xdrs;
1562   int x,y,z;
1563   int width;
1564   int u;
1565   int olderror;
1566   /*}}}*/
1567 
1568   if ((fp=fopen(name,"r"))==(FILE*)0) return strerror(errno);
1569   xdrstdio_create(&xdrs,fp,XDR_DECODE);
1570   if (!xdr_magic(&xdrs))
1571   {
1572 #if 0
1573     xdr_destroy(&xdrs);
1574     fclose(fp);
1575     return _("This is not a teapot worksheet in XDR format");
1576 #else
1577     xdr_destroy(&xdrs);
1578     rewind(fp);
1579     xdrstdio_create(&xdrs,fp,XDR_DECODE);
1580 #endif
1581   }
1582   freesheet(sheet,0);
1583   while (xdr_int(&xdrs,&u)) switch (u)
1584   {
1585     /* 0       -- column width element */ /*{{{*/
1586     case 0:
1587     {
1588       if (xdr_column(&xdrs,&x,&z,&width)==0)
1589       {
1590         olderror=errno;
1591         xdr_destroy(&xdrs);
1592         (void)fclose(fp);
1593         return strerror(olderror);
1594       }
1595       setwidth(sheet,x,z,width);
1596       break;
1597     }
1598     /*}}}*/
1599     /* 1       -- cell element */ /*{{{*/
1600     case 1:
1601     {
1602       if (xdr_int(&xdrs,&x)==0 || xdr_int(&xdrs,&y)==0 || xdr_int(&xdrs,&z)==0)
1603       {
1604         olderror=errno;
1605         xdr_destroy(&xdrs);
1606         (void)fclose(fp);
1607         return strerror(olderror);
1608       }
1609       initcell(sheet,x,y,z);
1610       if (xdr_cell(&xdrs,SHEET(sheet,x,y,z))==0)
1611       {
1612         freecell(sheet,x,y,z);
1613         olderror=errno;
1614         xdr_destroy(&xdrs);
1615         (void)fclose(fp);
1616         return strerror(olderror);
1617       }
1618       break;
1619     }
1620     /*}}}*/
1621     /* default -- should not happen */ /*{{{*/
1622     default:
1623     {
1624       xdr_destroy(&xdrs);
1625       fclose(fp);
1626       sheet->changed=0;
1627       cachelabels(sheet);
1628       forceupdate(sheet);
1629       return _("Invalid record, loading aborted");
1630     }
1631     /*}}}*/
1632   }
1633   xdr_destroy(&xdrs);
1634   if (fclose(fp)==EOF) return strerror(errno);
1635   sheet->changed=0;
1636   cachelabels(sheet);
1637   forceupdate(sheet);
1638   redraw_sheet(sheet);
1639   return (const char*)0;
1640 }
1641 /*}}}*/
1642 /* loadcsv       -- load/merge CSVs */ /*{{{*/
loadcsv(Sheet * sheet,const char * name)1643 const char *loadcsv(Sheet *sheet, const char *name)
1644 {
1645   /* variables */ /*{{{*/
1646   FILE *fp;
1647   Token **t;
1648   const char *err;
1649   int line,x;
1650   char ln[4096];
1651   const char *str;
1652   double value;
1653   long lvalue;
1654   int separator = 0;
1655   /*}}}*/
1656 
1657   if ((fp=fopen(name,"r"))==(FILE*)0) return strerror(errno);
1658   err=(const char*)0;
1659   for (x=0,line=1; fgets(ln,sizeof(ln),fp); ++line)
1660   {
1661     const char *s;
1662     const char *cend;
1663 
1664     if (!separator) { /* FIXME: find a better way to autodetect */
1665         int ccnt = 0, scnt = 0;
1666         char *pos = ln;
1667         while ((pos = strchr(pos, ','))) pos++, ccnt++;
1668         pos = ln;
1669         while ((pos = strchr(pos, ';'))) pos++, scnt++;
1670         if (ccnt || scnt) separator = 1;
1671         csv_setopt(scnt > ccnt);
1672     }
1673 
1674     s=cend=ln;
1675     x=0;
1676     do
1677     {
1678       t=malloc(2*sizeof(Token*));
1679       t[0]=malloc(sizeof(Token));
1680       t[1]=(Token*)0;
1681       lvalue=csv_long(s,&cend);
1682       if (s!=cend) /* ok, it is a integer */ /*{{{*/
1683       {
1684         t[0]->type=INT;
1685         t[0]->u.integer=lvalue;
1686         putcont(sheet, sheet->curx+x, sheet->cury+line-1, sheet->curz, t, 0);
1687       }
1688       /*}}}*/
1689       else
1690       {
1691         value=csv_double(s,&cend);
1692         if (s!=cend) /* ok, it is a double */ /*{{{*/
1693         {
1694           t[0]->type=FLOAT;
1695           t[0]->u.flt=value;
1696           putcont(sheet, sheet->curx+x, sheet->cury+line-1, sheet->curz, t, 0);
1697         }
1698         /*}}}*/
1699         else
1700         {
1701           str=csv_string(s,&cend);
1702           if (s!=cend) /* ok, it is a string */ /*{{{*/
1703           {
1704             t[0]->type=STRING;
1705             t[0]->u.string=mystrmalloc(str);
1706             putcont(sheet, sheet->curx+x, sheet->cury+line-1, sheet->curz, t, 0);
1707           }
1708           /*}}}*/
1709           else
1710           {
1711             tvecfree(t);
1712             csv_separator(s,&cend);
1713             while (s==cend && *s && *s!='\n')
1714             {
1715               err=_("unknown values ignored");
1716               csv_separator(++s,&cend);
1717             }
1718             /* else it is nothing, which does not need to be stored :) */
1719           }
1720         }
1721       }
1722     } while (s!=cend ? s=cend,++x,1 : 0);
1723   }
1724   fclose(fp);
1725   return err;
1726 }
1727 /*}}}*/
1728 /* insertcube    -- insert a block */ /*{{{*/
insertcube(Sheet * sheet,int x1,int y1,int z1,int x2,int y2,int z2,Direction ins)1729 void insertcube(Sheet *sheet, int x1, int y1, int z1, int x2, int y2, int z2, Direction ins)
1730 {
1731   /* variables */ /*{{{*/
1732   int x,y,z;
1733   /*}}}*/
1734 
1735   switch (ins)
1736   {
1737     /* IN_X    */ /*{{{*/
1738     case IN_X:
1739     {
1740       int right;
1741 
1742       right=sheet->dimx+x2-x1;
1743       for (z=z1; z<=z2; ++z) for (y=y1; y<=y2; ++y) for (x=right; x>x2; --x)
1744       {
1745         resize(sheet,x,y,z);
1746         SHEET(sheet,x,y,z)=SHEET(sheet,x-(x2-x1+1),y,z);
1747         SHEET(sheet,x-(x2-x1+1),y,z)=(Cell*)0;
1748       }
1749       break;
1750     }
1751     /*}}}*/
1752     /* IN_Y    */ /*{{{*/
1753     case IN_Y:
1754     {
1755       int down;
1756 
1757       down=sheet->dimy+y2-y1;
1758       for (z=z1; z<=z2; ++z) for (x=x1; x<=x2; ++x) for (y=down; y>y2; --y)
1759       {
1760         resize(sheet,x,y,z);
1761         SHEET(sheet,x,y,z)=SHEET(sheet,x,y-(y2-y1+1),z);
1762         SHEET(sheet,x,y-(y2-y1+1),z)=(Cell*)0;
1763       }
1764       break;
1765     }
1766     /*}}}*/
1767     /* IN_Z */ /*{{{*/
1768     case IN_Z:
1769     {
1770       int bottom;
1771 
1772       bottom=sheet->dimz+z2-z1;
1773       for (y=y1; y<=y2; ++y) for (x=x1; x<=x2; ++x) for (z=bottom; z>z2; --z)
1774       {
1775         resize(sheet,x,y,z);
1776         SHEET(sheet,x,y,z)=SHEET(sheet,x,y,z-(z2-z1+1));
1777         SHEET(sheet,x,y,z-(z2-z1+1))=(Cell*)0;
1778       }
1779       break;
1780     }
1781     /*}}}*/
1782     /* default */ /*{{{*/
1783     default: assert(0);
1784     /*}}}*/
1785   }
1786   sheet->changed=1;
1787   cachelabels(sheet);
1788   forceupdate(sheet);
1789 }
1790 /*}}}*/
1791 /* deletecube    -- delete a block */ /*{{{*/
deletecube(Sheet * sheet,int x1,int y1,int z1,int x2,int y2,int z2,Direction del)1792 void deletecube(Sheet *sheet, int x1, int y1, int z1, int x2, int y2, int z2, Direction del)
1793 {
1794   /* variables */ /*{{{*/
1795   int x,y,z;
1796   /*}}}*/
1797 
1798   /* free cells in marked block */ /*{{{*/
1799   for (x=x1; x<=x2; ++x)
1800   for (y=y1; y<=y2; ++y)
1801   for (z=z1; z<=z2; ++z)
1802   freecell(sheet,x,y,z);
1803   /*}}}*/
1804   switch (del)
1805   {
1806     /* IN_X */ /*{{{*/
1807     case IN_X:
1808     {
1809       for (z=z1; z<=z2; ++z) for (y=y1; y<=y2; ++y) for (x=x1; x<=sheet->dimx-(x2-x1+1); ++x)
1810       {
1811         if (x+(x2-x1+1)<sheet->dimx && y<sheet->dimy && z<sheet->dimz)
1812         {
1813           SHEET(sheet,x,y,z)=SHEET(sheet,x+(x2-x1+1),y,z);
1814           SHEET(sheet,x+(x2-x1+1),y,z)=(Cell*)0;
1815         }
1816       }
1817       break;
1818     }
1819     /*}}}*/
1820     /* IN_Y */ /*{{{*/
1821     case IN_Y:
1822     {
1823       for (z=z1; z<=z2; ++z) for (x=x1; x<=x2; ++x) for (y=y1; y<=sheet->dimy-(y2-y1+1); ++y)
1824       {
1825         if (x<sheet->dimx && y+(y2-y1+1)<sheet->dimy && z<sheet->dimz)
1826         {
1827           SHEET(sheet,x,y,z)=SHEET(sheet,x,y+(y2-y1+1),z);
1828           SHEET(sheet,x,y+(y2-y1+1),z)=(Cell*)0;
1829         }
1830       }
1831       break;
1832     }
1833     /*}}}*/
1834     /* IN_Z */ /*{{{*/
1835     case IN_Z:
1836     {
1837       for (y=y1; y<=y2; ++y) for (x=x1; x<=x2; ++x) for (z=z1; z<=sheet->dimz-(z2-z1+1); ++z)
1838       {
1839         if (x<sheet->dimx && y<sheet->dimy && z+(z2-z1+1)<sheet->dimz)
1840         {
1841           SHEET(sheet,x,y,z)=SHEET(sheet,x,y,z+(z2-z1+1));
1842           SHEET(sheet,x,y,z+(z2-z1+1))=(Cell*)0;
1843         }
1844       }
1845       break;
1846     }
1847     /*}}}*/
1848     /* default */ /*{{{*/
1849     default: assert(0);
1850     /*}}}*/
1851   }
1852   sheet->changed=1;
1853   cachelabels(sheet);
1854   forceupdate(sheet);
1855 }
1856 /*}}}*/
1857 /* moveblock     -- move a block */ /*{{{*/
moveblock(Sheet * sheet,int x1,int y1,int z1,int x2,int y2,int z2,int x3,int y3,int z3,int copy)1858 void moveblock(Sheet *sheet, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3, int copy)
1859 {
1860   /* variables */ /*{{{*/
1861   int dirx, diry, dirz;
1862   int widx, widy, widz;
1863   int x, y, z;
1864   int xf, xt, yf, yt, zf, zt;
1865   /*}}}*/
1866 
1867   if (x1==x3 && y1==y3 && z1==z3) return;
1868   widx=(x2-x1);
1869   widy=(y2-y1);
1870   widz=(z2-z1);
1871   if (x3>x1) { dirx=-1; xf=widx; xt=-1; } else { dirx=1; xf=0; xt=widx+1; }
1872   if (y3>y1) { diry=-1; yf=widy; yt=-1; } else { diry=1; yf=0; yt=widy+1; }
1873   if (z3>z1) { dirz=-1; zf=widz; zt=-1; } else { dirz=1; zf=0; zt=widz+1; }
1874   for (x=xf; x!=xt; x+=dirx)
1875   for (y=yf; y!=yt; y+=diry)
1876   for (z=zf; z!=zt; z+=dirz)
1877   {
1878     if (copy)
1879     {
1880       copycell(sheet,x1+x,y1+y,z1+z,sheet,x3+x,y3+y,z3+z);
1881     }
1882     else
1883     {
1884       if (x1+x<sheet->dimx && y1+y<sheet->dimy && z1+z<sheet->dimz)
1885       {
1886         resize(sheet,x3+x,y3+y,z3+z);
1887         SHEET(sheet,x3+x,y3+y,z3+z)=SHEET(sheet,x1+x,y1+y,z1+z);
1888         SHEET(sheet,x1+x,y1+y,z1+z)=(Cell*)0;
1889       }
1890       else
1891       {
1892         freecell(sheet,x3+x,y3+y,z3+z);
1893       }
1894     }
1895   }
1896   sheet->changed=1;
1897   cachelabels(sheet);
1898   forceupdate(sheet);
1899 }
1900 /*}}}*/
1901 /* sortblock     -- sort a block */ /*{{{*/
1902 /* Notes */ /*{{{*/
1903 /*
1904 The idea is to sort a block of cells in one direction by swapping the
1905 planes which are canonical to the sort key vectors.  An example is to
1906 sort a two dimensional block line-wise with one column as sort key.
1907 You can have multiple sort keys which all have the same direction and
1908 you can sort a cube plane-wise.
1909 */
1910 /*}}}*/
sortblock(Sheet * sheet,int x1,int y1,int z1,int x2,int y2,int z2,Direction dir,Sortkey * sk,size_t sklen)1911 const char *sortblock(Sheet *sheet, int x1, int y1, int z1, int x2, int y2, int z2, Direction dir, Sortkey *sk, size_t sklen)
1912 {
1913   /* variables */ /*{{{*/
1914   int x,y,z;
1915   int incx=0,incy=0,incz=0;
1916   int distx,disty,distz;
1917   int i,r=-3,norel,work;
1918   /*}}}*/
1919 
1920   /* asserts */ /*{{{*/
1921   assert(sklen>0);
1922   assert(x1>=0);
1923   assert(x2>=0);
1924   assert(y1>=0);
1925   assert(y2>=0);
1926   assert(z1>=0);
1927   assert(z2>=0);
1928   /*}}}*/
1929   norel=0;
1930   posorder(&x1,&x2);
1931   posorder(&y1,&y2);
1932   posorder(&z1,&z2);
1933   distx=(x2-x1+1);
1934   disty=(y2-y1+1);
1935   distz=(z2-z1+1);
1936   switch (dir)
1937   {
1938     case IN_X: incx=1; --x2; incy=0; incz=0; distx=1; break;
1939     case IN_Y: incx=0; incy=1; --y2; incz=0; disty=1; break;
1940     case IN_Z: incx=0; incy=0; incz=1; --z2; distz=1; break;
1941     default: assert(0);
1942   }
1943   assert(incx || incy || incz);
1944   do
1945   {
1946     work=0;
1947     for (x=x1,y=y1,z=z1; x<=x2&&y<=y2&&z<=z2; x+=incx,y+=incy,z+=incz)
1948     {
1949       for (i=0; i<sklen; ++i)
1950       {
1951         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);
1952         if (r==2) norel=1;
1953         else if (r==-1 || r==1) break;
1954         else assert(r==0);
1955       }
1956       if (r==1)
1957       {
1958         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);
1959         work=1;
1960       }
1961     }
1962     x2-=incx;
1963     y2-=incy;
1964     z2-=incz;
1965   } while (work);
1966   cachelabels(sheet);
1967   forceupdate(sheet);
1968   sheet->changed=1;
1969   if (norel) return _("uncomparable elements");
1970   else return (const char*)0;
1971 }
1972 /*}}}*/
1973 /* mirrorblock   -- mirror a block */ /*{{{*/
mirrorblock(Sheet * sheet,int x1,int y1,int z1,int x2,int y2,int z2,Direction dir)1974 void mirrorblock(Sheet *sheet, int x1, int y1, int z1, int x2, int y2, int z2, Direction dir)
1975 {
1976   switch (dir)
1977   {
1978     case IN_X: /* left-right */ /*{{{*/
1979     {
1980       int x,middle=(x2-x1+1)/2;
1981       for (x=0; x<middle; ++x)
1982       {
1983         swapblock(sheet,x1+x,y1,z1,sheet,x2-x,y1,z1, 1,y2-y1+1,z2-z1+1);
1984       }
1985       break;
1986     }
1987     /*}}}*/
1988     case IN_Y: /* upside-down */ /*{{{*/
1989     {
1990       int y,middle=(y2-y1+1)/2;
1991       for (y=0; y<middle; ++y)
1992       {
1993         swapblock(sheet,x1,y1+y,z1,sheet,x1,y2-y,z1, x2-x1+1,1,z2-z1+1);
1994       }
1995       break;
1996     }
1997     /*}}}*/
1998     case IN_Z: /* front-back */ /*{{{*/
1999     {
2000       int z,middle=(z2-z1+1)/2;
2001       for (z=0; z<middle; ++z)
2002       {
2003         swapblock(sheet,x1,y1,z1+z,sheet,x1,y1,z2-z, x2-x1+1,y2-y1+1,1);
2004       }
2005       break;
2006     }
2007     /*}}}*/
2008     default: assert(0);
2009   }
2010   sheet->changed=1;
2011   cachelabels(sheet);
2012   forceupdate(sheet);
2013 }
2014 /*}}}*/
2015