1 /*
2 * Grace - GRaphing, Advanced Computation and Exploration of data
3 *
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
5 *
6 * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
7 * Copyright (c) 1996-2002 Grace Development Team
8 *
9 * Maintained by Evgeny Stambulchik
10 *
11 *
12 * All Rights Reserved
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29 /*
30 *
31 * spreadsheet data stuff
32 *
33 */
34
35 #include <config.h>
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "defines.h"
42 #include "globals.h"
43 #include "utils.h"
44 #include "graphs.h"
45 #include "graphutils.h"
46 #include "files.h"
47 #include "ssdata.h"
48 #include "parser.h"
49
50 #include "protos.h"
51
copy_data_column(double * src,int nrows)52 double *copy_data_column(double *src, int nrows)
53 {
54 double *dest;
55
56 dest = xmalloc(nrows*SIZEOF_DOUBLE);
57 if (dest != NULL) {
58 memcpy(dest, src, nrows*SIZEOF_DOUBLE);
59 }
60 return dest;
61 }
62
copy_string_column(char ** src,int nrows)63 char **copy_string_column(char **src, int nrows)
64 {
65 char **dest;
66 int i;
67
68 dest = xmalloc(nrows*sizeof(char *));
69 if (dest != NULL) {
70 for (i = 0; i < nrows; i++)
71 dest[i] =copy_string(NULL, src[i]);
72 }
73 return dest;
74 }
75
76 /* TODO: index_shift */
allocate_index_data(int nrows)77 double *allocate_index_data(int nrows)
78 {
79 int i;
80 double *retval;
81
82 retval = xmalloc(nrows*SIZEOF_DOUBLE);
83 if (retval != NULL) {
84 for (i = 0; i < nrows; i++) {
85 retval[i] = i;
86 }
87 }
88 return retval;
89 }
90
allocate_mesh(double start,double stop,int len)91 double *allocate_mesh(double start, double stop, int len)
92 {
93 int i;
94 double *retval;
95
96 retval = xmalloc(len*SIZEOF_DOUBLE);
97 if (retval != NULL) {
98 double s = (start + stop)/2, d = (stop - start)/2;
99 for (i = 0; i < len; i++) {
100 retval[i] = s + d*((double) (2*i + 1 - len)/(len - 1));
101 }
102 }
103 return retval;
104 }
105
106 static ss_data blockdata = {0, 0, NULL, NULL};
107
set_blockdata(ss_data * ssd)108 void set_blockdata(ss_data *ssd)
109 {
110 free_ss_data(&blockdata);
111 if (ssd) {
112 memcpy(&blockdata, ssd, sizeof(ss_data));
113 }
114 }
115
get_blockncols(void)116 int get_blockncols(void)
117 {
118 return blockdata.ncols;
119 }
120
get_blocknrows(void)121 int get_blocknrows(void)
122 {
123 return blockdata.nrows;
124 }
125
get_blockformats(void)126 int *get_blockformats(void)
127 {
128 return blockdata.formats;
129 }
130
realloc_ss_data(ss_data * ssd,int nrows)131 int realloc_ss_data(ss_data *ssd, int nrows)
132 {
133 int i, j;
134 char **sp;
135
136 for (i = 0; i < ssd->ncols; i++) {
137 if (ssd->formats[i] == FFORMAT_STRING) {
138 sp = (char **) ssd->data[i];
139 for (j = nrows; j < ssd->nrows; j++) {
140 XCFREE(sp[j]);
141 }
142 ssd->data[i] = xrealloc(ssd->data[i], nrows*sizeof(char *));
143 sp = (char **) ssd->data[i];
144 for (j = ssd->nrows; j < nrows; j++) {
145 sp[j] = NULL;
146 }
147 } else {
148 ssd->data[i] = xrealloc(ssd->data[i], nrows*SIZEOF_DOUBLE);
149 }
150 }
151 ssd->nrows = nrows;
152
153 return RETURN_SUCCESS;
154 }
155
free_ss_data(ss_data * ssd)156 void free_ss_data(ss_data *ssd)
157 {
158 if (ssd) {
159 int i, j;
160 char **sp;
161
162 for (i = 0; i < ssd->ncols; i++) {
163 if (ssd->formats && ssd->formats[i] == FFORMAT_STRING) {
164 sp = (char **) ssd->data[i];
165 for (j = 0; j < ssd->nrows; j++) {
166 XCFREE(sp[j]);
167 }
168 }
169 XCFREE(ssd->data[i]);
170 }
171 XCFREE(ssd->data);
172 XCFREE(ssd->formats);
173 ssd->nrows = 0;
174 ssd->ncols = 0;
175 }
176 }
177
init_ss_data(ss_data * ssd,int ncols,int * formats)178 int init_ss_data(ss_data *ssd, int ncols, int *formats)
179 {
180 int i;
181
182 ssd->data = xmalloc(ncols*SIZEOF_VOID_P);
183 for (i = 0; i < ncols; i++) {
184 ssd->data[i] = NULL;
185 }
186 ssd->formats = xmalloc(ncols*SIZEOF_INT);
187 memcpy(ssd->formats, formats, ncols*SIZEOF_INT);
188 ssd->ncols = ncols;
189 ssd->nrows = 0;
190
191 return RETURN_SUCCESS;
192 }
193
next_token(char * s,char ** token,int * quoted)194 static char *next_token(char *s, char **token, int *quoted)
195 {
196 *quoted = FALSE;
197 *token = NULL;
198
199 if (s == NULL) {
200 return NULL;
201 }
202
203 while (*s == ' ' || *s == '\t') {
204 s++;
205 }
206 if (*s == '"') {
207 s++;
208 *token = s;
209 while (*s != '\0' && (*s != '"' || (*s == '"' && *(s - 1) == '\\'))) {
210 s++;
211 }
212 if (*s == '"') {
213 /* successfully identified a quoted string */
214 *quoted = TRUE;
215 }
216 } else {
217 *token = s;
218 if (**token == '\n') {
219 /* EOL reached */
220 return NULL;
221 }
222 while (*s != '\n' && *s != '\0' && *s != ' ' && *s != '\t') {
223 s++;
224 }
225 }
226
227 if (*s != '\0') {
228 *s = '\0';
229 s++;
230 return s;
231 } else {
232 return NULL;
233 }
234 }
235
parse_ss_row(const char * s,int * nncols,int * nscols,int ** formats)236 int parse_ss_row(const char *s, int *nncols, int *nscols, int **formats)
237 {
238 int ncols;
239 int quoted;
240 char *buf, *s1, *token;
241 double value;
242 Dates_format df_pref, ddummy;
243 const char *sdummy;
244
245 *nscols = 0;
246 *nncols = 0;
247 *formats = NULL;
248 df_pref = get_date_hint();
249 buf = copy_string(NULL, s);
250 s1 = buf;
251 while ((s1 = next_token(s1, &token, "ed)) != NULL) {
252 if (token == NULL) {
253 *nscols = 0;
254 *nncols = 0;
255 XCFREE(*formats);
256 xfree(buf);
257 return RETURN_FAILURE;
258 }
259
260 ncols = *nncols + *nscols;
261 /* reallocate the formats array */
262 if (ncols % 10 == 0) {
263 *formats = xrealloc(*formats, (ncols + 10)*SIZEOF_INT);
264 }
265
266 if (quoted) {
267 (*formats)[ncols] = FFORMAT_STRING;
268 (*nscols)++;
269 } else if (parse_date(token, df_pref, FALSE, &value, &ddummy) ==
270 RETURN_SUCCESS) {
271 (*formats)[ncols] = FFORMAT_DATE;
272 (*nncols)++;
273 } else if (parse_float(token, &value, &sdummy) == RETURN_SUCCESS) {
274 (*formats)[ncols] = FFORMAT_NUMBER;
275 (*nncols)++;
276 } else {
277 /* last resort - treat the field as string, even if not quoted */
278 (*formats)[ncols] = FFORMAT_STRING;
279 (*nscols)++;
280 }
281 }
282 xfree(buf);
283
284 return RETURN_SUCCESS;
285 }
286
287
288 /* NOTE: the input string will be corrupted! */
insert_data_row(ss_data * ssd,int row,char * s)289 int insert_data_row(ss_data *ssd, int row, char *s)
290 {
291 int i, j;
292 int ncols = ssd->ncols;
293 char *token;
294 int quoted;
295 char **sp;
296 double *np;
297 Dates_format df_pref, ddummy;
298 const char *sdummy;
299 int res;
300
301 df_pref = get_date_hint();
302 for (i = 0; i < ncols; i++) {
303 s = next_token(s, &token, "ed);
304 if (s == NULL || token == NULL) {
305 /* invalid line: free the already allocated string fields */
306 for (j = 0; j < i; j++) {
307 if (ssd->formats[j] == FFORMAT_STRING) {
308 sp = (char **) ssd->data[j];
309 XCFREE(sp[row]);
310 }
311 }
312 return RETURN_FAILURE;
313 } else {
314 if (ssd->formats[i] == FFORMAT_STRING) {
315 sp = (char **) ssd->data[i];
316 sp[row] = copy_string(NULL, token);
317 if (sp[row] != NULL) {
318 res = RETURN_SUCCESS;
319 } else {
320 res = RETURN_FAILURE;
321 }
322 } else if (ssd->formats[i] == FFORMAT_DATE) {
323 np = (double *) ssd->data[i];
324 res = parse_date(token, df_pref, FALSE, &np[row], &ddummy);
325 } else {
326 np = (double *) ssd->data[i];
327 res = parse_float(token, &np[row], &sdummy);
328 }
329 if (res != RETURN_SUCCESS) {
330 for (j = 0; j < i; j++) {
331 if (ssd->formats[j] == FFORMAT_STRING) {
332 sp = (char **) ssd->data[j];
333 XCFREE(sp[row]);
334 }
335 }
336 return RETURN_FAILURE;
337 }
338 }
339 }
340
341 return RETURN_SUCCESS;
342 }
343
344
store_data(ss_data * ssd,int load_type,char * label)345 int store_data(ss_data *ssd, int load_type, char *label)
346 {
347 int ncols, nncols, nncols_req, nscols, nrows;
348 int i, j;
349 double *xdata;
350 int gno, setno;
351 int x_from_index;
352
353 if (ssd == NULL) {
354 return RETURN_FAILURE;
355 }
356 ncols = ssd->ncols;
357 nrows = ssd->nrows;
358 if (ncols <= 0 || nrows <= 0) {
359 return RETURN_FAILURE;
360 }
361
362 nncols = 0;
363 for (j = 0; j < ncols; j++) {
364 if (ssd->formats[j] != FFORMAT_STRING) {
365 nncols++;
366 }
367 }
368 nscols = ncols - nncols;
369
370 gno = get_parser_gno();
371 if (is_valid_gno(gno) != TRUE) {
372 return RETURN_FAILURE;
373 }
374
375 switch (load_type) {
376 case LOAD_SINGLE:
377 if (nscols > 1) {
378 errmsg("Can not use more than one column of strings per set");
379 free_ss_data(ssd);
380 return RETURN_FAILURE;
381 }
382
383 nncols_req = settype_cols(curtype);
384 x_from_index = FALSE;
385 if (nncols_req == nncols + 1) {
386 x_from_index = TRUE;
387 } else if (nncols_req != nncols) {
388 errmsg("Column count incorrect");
389 return RETURN_FAILURE;
390 }
391
392 setno = nextset(gno);
393 set_dataset_type(gno, setno, curtype);
394
395 nncols = 0;
396 if (x_from_index) {
397 xdata = allocate_index_data(nrows);
398 if (xdata == NULL) {
399 free_ss_data(ssd);
400 }
401 setcol(gno, setno, nncols, xdata, nrows);
402 nncols++;
403 }
404 for (j = 0; j < ncols; j++) {
405 if (ssd->formats[j] == FFORMAT_STRING) {
406 set_set_strings(gno, setno, nrows, (char **) ssd->data[j]);
407 } else {
408 setcol(gno, setno, nncols, (double *) ssd->data[j], nrows);
409 nncols++;
410 }
411 }
412 if (!strlen(getcomment(gno, setno))) {
413 setcomment(gno, setno, label);
414 }
415
416 XCFREE(ssd->data);
417 XCFREE(ssd->formats);
418 break;
419 case LOAD_NXY:
420 if (nscols != 0) {
421 errmsg("Can not yet use strings when reading in data as NXY");
422 free_ss_data(ssd);
423 return RETURN_FAILURE;
424 }
425
426 for (i = 0; i < ncols - 1; i++) {
427 setno = nextset(gno);
428 if (setno == -1) {
429 free_ss_data(ssd);
430 return RETURN_FAILURE;
431 }
432 if (i > 0) {
433 xdata = copy_data_column((double *) ssd->data[0], nrows);
434 if (xdata == NULL) {
435 free_ss_data(ssd);
436 }
437 } else {
438 xdata = (double *) ssd->data[0];
439 }
440 set_dataset_type(gno, setno, SET_XY);
441 setcol(gno, setno, DATA_X, xdata, nrows);
442 setcol(gno, setno, DATA_Y, (double *) ssd->data[i + 1], nrows);
443 setcomment(gno, setno, label);
444 }
445
446 XCFREE(ssd->data);
447 XCFREE(ssd->formats);
448 break;
449 case LOAD_BLOCK:
450 set_blockdata(ssd);
451 break;
452 default:
453 errmsg("Internal error");
454 free_ss_data(ssd);
455 return RETURN_FAILURE;
456 }
457
458 return RETURN_SUCCESS;
459 }
460
field_string_to_cols(const char * fs,int * nc,int ** cols,int * scol)461 int field_string_to_cols(const char *fs, int *nc, int **cols, int *scol)
462 {
463 int col;
464 char *s, *buf;
465
466 buf = copy_string(NULL, fs);
467 if (buf == NULL) {
468 return RETURN_FAILURE;
469 }
470
471 s = buf;
472 *nc = 0;
473 while ((s = strtok(s, ":")) != NULL) {
474 (*nc)++;
475 s = NULL;
476 }
477 *cols = xmalloc((*nc)*SIZEOF_INT);
478 if (*cols == NULL) {
479 xfree(buf);
480 return RETURN_FAILURE;
481 }
482
483 strcpy(buf, fs);
484 s = buf;
485 *nc = 0;
486 *scol = -1;
487 while ((s = strtok(s, ":")) != NULL) {
488 int strcol;
489 if (*s == '{') {
490 char *s1;
491 strcol = TRUE;
492 s++;
493 if ((s1 = strchr(s, '}')) != NULL) {
494 *s1 = '\0';
495 }
496 } else {
497 strcol = FALSE;
498 }
499 col = atoi(s);
500 col--;
501 if (strcol) {
502 *scol = col;
503 } else {
504 (*cols)[*nc] = col;
505 (*nc)++;
506 }
507 s = NULL;
508 }
509
510 xfree(buf);
511
512 return RETURN_SUCCESS;
513 }
514
cols_to_field_string(int nc,int * cols,int scol)515 char *cols_to_field_string(int nc, int *cols, int scol)
516 {
517 int i;
518 char *s, buf[32];
519
520 s = NULL;
521 for (i = 0; i < nc; i++) {
522 sprintf(buf, "%d", cols[i] + 1);
523 if (i != 0) {
524 s = concat_strings(s, ":");
525 }
526 s = concat_strings(s, buf);
527 }
528 if (scol >= 0) {
529 sprintf(buf, ":{%d}", scol + 1);
530 s = concat_strings(s, buf);
531 }
532
533 return s;
534 }
535
create_set_fromblock(int gno,int setno,int type,int nc,int * coli,int scol,int autoscale)536 int create_set_fromblock(int gno, int setno,
537 int type, int nc, int *coli, int scol, int autoscale)
538 {
539 int i, ncols, blockncols, blocklen, column;
540 double *cdata;
541 char buf[256], *s;
542
543 blockncols = get_blockncols();
544 if (blockncols <= 0) {
545 errmsg("No block data read");
546 return RETURN_FAILURE;
547 }
548
549 blocklen = get_blocknrows();
550
551 ncols = settype_cols(type);
552 if (nc > ncols) {
553 errmsg("Too many columns scanned in column string");
554 return RETURN_FAILURE;
555 }
556 if (nc < ncols) {
557 errmsg("Too few columns scanned in column string");
558 return RETURN_FAILURE;
559 }
560
561 for (i = 0; i < nc; i++) {
562 if (coli[i] < -1 || coli[i] >= blockncols) {
563 errmsg("Column index out of range");
564 return RETURN_FAILURE;
565 }
566 }
567
568 if (scol >= blockncols) {
569 errmsg("String column index out of range");
570 return RETURN_FAILURE;
571 }
572
573 if (setno == NEW_SET) {
574 setno = nextset(gno);
575 if (setno == -1) {
576 return RETURN_FAILURE;
577 }
578 }
579
580 /* clear data stored in the set, if any */
581 killsetdata(gno, setno);
582
583 if (activateset(gno, setno) != RETURN_SUCCESS) {
584 return RETURN_FAILURE;
585 }
586
587 set_dataset_type(gno, setno, type);
588
589 for (i = 0; i < nc; i++) {
590 column = coli[i];
591 if (column == -1) {
592 cdata = allocate_index_data(blocklen);
593 } else {
594 if (blockdata.formats[column] != FFORMAT_STRING) {
595 cdata = copy_data_column((double *) blockdata.data[column], blocklen);
596 } else {
597 errmsg("Tried to read doubles from strings!");
598 killsetdata(gno, setno);
599 return RETURN_FAILURE;
600 }
601 }
602 if (cdata == NULL) {
603 killsetdata(gno, setno);
604 return RETURN_FAILURE;
605 }
606 setcol(gno, setno, i, cdata, blocklen);
607 }
608
609 /* strings, if any */
610 if (scol >= 0) {
611 if (blockdata.formats[scol] != FFORMAT_STRING) {
612 errmsg("Tried to read strings from doubles!");
613 killsetdata(gno, setno);
614 return RETURN_FAILURE;
615 } else {
616 set_set_strings(gno, setno, blocklen,
617 copy_string_column((char **) blockdata.data[scol], blocklen));
618 }
619 }
620
621 s = cols_to_field_string(nc, coli, scol);
622 sprintf(buf, "Cols %s", s);
623 xfree(s);
624 setcomment(gno, setno, buf);
625
626 autoscale_graph(gno, autoscale);
627
628 return RETURN_SUCCESS;
629 }
630