/[ascend]/trunk/models/johnpye/datareader/texttable.c
ViewVC logotype

Contents of /trunk/models/johnpye/datareader/texttable.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 809 - (show annotations) (download) (as text)
Mon Aug 7 14:48:55 2006 UTC (13 years, 11 months ago) by johnpye
File MIME type: text/x-csrc
File size: 21906 byte(s)
A little more tinkering on the Data Reader. I have added routines
to read data from the TMY2 format, but they're a long way from being
fully implemented yet. The added files sun.c and sun.h should
provide some useful routines for sun position and time of day, for
use with the TMY2 reader functions.
1 /* TextTable: A small C library to read data tables in text files */
2
3 /*
4 * Copyright (c) 2003,2004, Jean-Sebastien Roy (js@jeannot.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26 static char const rcsid[] =
27 "@(#) $Jeannot: texttable.c,v 1.15 2004/10/26 17:47:29 js Exp $";
28
29 #include <stddef.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <float.h>
36 #include <stdarg.h>
37
38 #include "texttable.h"
39
40 /* Extern constant */
41
42 size_t texttable_sizeof[TEXTTABLE_TYPE_MAX-1] = {
43 sizeof(char),
44 sizeof(short),
45 sizeof(int),
46 sizeof(long),
47 #ifdef HAS_LONGLONG
48 sizeof(long long),
49 #endif
50 sizeof(float),
51 sizeof(double),
52 sizeof(char *)
53 };
54
55 /* Static constants */
56
57 static char *texttable_errorstrings[TEXTTABLE_ERR_MAX] = {
58 "texttable: no error",
59 "texttable: memory allocation error",
60 "texttable: invalid argument",
61 "texttable: unknown type",
62 "texttable: too few columns",
63 "texttable: too many columns",
64 "texttable: invalid data",
65 "texttable: file error"
66 };
67
68 /* Static prototypes */
69
70 /*
71 * Read a line from stream 'file'.
72 * Return NULL if an error occurs.
73 * If non NULL, the returned pointer point to a '\0' terminated string.
74 * The end of line character '\n' is ommited.
75 */
76 static char *texttable_fgetln(FILE *file);
77
78 /*
79 * Read a line from stream 'file'.
80 * Return NULL if an error occurs.
81 * If non NULL, the returned pointer point to a '\0' terminated string.
82 * The end of line character '\n' is ommited.
83 * Temporary storage of size '*bufsize' provided by 'buf' is used if
84 * buff != NULL, buf may be reallocated. In this case, the returned pointer
85 * point to the reallocated buffer. *bufsize contains the new size of the
86 * buffer.
87 */
88 static char *texttable_fgets(FILE *file, char *buf, size_t *bufsize);
89
90 /*
91 * Separate strings using 'delimiter' as the delimiter.
92 * Locate and replace in the *stringp the first occurence of the delimiter
93 * character. The location of the next character after the delimiter
94 * character (or NULL, if the end of the string was reached) is stored in
95 * *stringp. The original value of *stringp is returned.
96 *
97 * Loosely based upon the 'strsep' BSD libc function.
98 */
99 static char *texttable_strsep(char **stringp, char delimiter);
100
101 /* Implementation */
102
103 char *texttable_fgetln(FILE *file)
104 {
105 return texttable_fgets(file, NULL, NULL);
106 }
107
108 /* TEXTTABLE_FGETS_BUFFER must be greater or equal to 2 */
109 #define TEXTTABLE_FGETS_BUFFER 256
110 char *texttable_fgets(FILE *file, char *buf, size_t *bufsize)
111 {
112 char *nbuf, *cur;
113 size_t remsize, tbufsize = 0;
114
115 if (bufsize == NULL)
116 bufsize = &tbufsize;
117
118 if (buf == NULL)
119 {
120 if (*bufsize < 2)
121 *bufsize = TEXTTABLE_FGETS_BUFFER;
122 buf = malloc((*bufsize)*sizeof(*buf));
123 }
124
125 remsize = *bufsize;
126 cur = buf;
127 while (1)
128 {
129 char *res;
130
131 res = fgets(cur, (int) remsize, file);
132 if (res == NULL)
133 {
134 free(buf);
135 return NULL;
136 }
137 if ((res = strchr(cur,'\n')) != NULL)
138 {
139 *res = '\0';
140 return buf;
141 }
142 if (feof(file))
143 return buf;
144
145 nbuf = realloc(buf, (*bufsize)*2*sizeof(*buf));
146 if (nbuf == NULL)
147 {
148 free(buf);
149 return NULL;
150 }
151 buf = nbuf;
152 cur = buf + *bufsize - 1;
153 remsize = *bufsize + 1;
154 *bufsize += *bufsize;
155 }
156 }
157
158 char *texttable_strsep(char **stringp, char delimiter)
159 {
160 char *s, *tok = *stringp;
161 char c;
162
163 if (tok == NULL)
164 return NULL;
165
166 for (s = tok;(c = *s);s++)
167 {
168 if (delimiter == c)
169 {
170 *s = 0;
171 *stringp = s+1;
172 return tok;
173 }
174 }
175 *stringp = NULL;
176 return tok;
177 }
178
179 int texttable_new(texttable *tt, size_t columns)
180 {
181 size_t column;
182
183 tt->type = NULL;
184 tt->name = NULL;
185 tt->data.dvoid = NULL;
186 tt->rows = 0;
187 tt->columns = columns;
188
189 if (tt->columns == 0)
190 return TEXTTABLE_NOERR;
191
192 tt->type = malloc(sizeof(*tt->type)*tt->columns);
193 if (tt->type == NULL)
194 {
195 texttable_free(tt);
196 return TEXTTABLE_ENOMEM;
197 }
198 for (column=0;column<tt->columns;column++)
199 tt->type[column] = TEXTTABLE_UNKNOWN;
200
201 tt->name = malloc(sizeof(*tt->name)*tt->columns);
202 if (tt->name == NULL)
203 {
204 texttable_free(tt);
205 return TEXTTABLE_ENOMEM;
206 }
207 for (column=0;column<tt->columns;column++)
208 tt->name[column] = NULL;
209
210 tt->data.dvoid = malloc(sizeof(*tt->data.dvoid)*tt->columns);
211 if (tt->data.dvoid == NULL)
212 {
213 texttable_free(tt);
214 return TEXTTABLE_ENOMEM;
215 }
216 for (column=0;column<tt->columns;column++)
217 tt->data.dvoid[column] = NULL;
218
219 return TEXTTABLE_NOERR;
220 }
221
222 void texttable_free(texttable *tt)
223 {
224 size_t column;
225
226 if (tt->name != NULL)
227 {
228 for (column=0;column<tt->columns;column++)
229 if (tt->name[column] != NULL)
230 free(tt->name[column]);
231 free(tt->name);
232 tt->name = NULL;
233 }
234
235 if (tt->data.dvoid != NULL)
236 {
237 for (column=0;column<tt->columns;column++)
238 if (tt->data.dvoid[column] != NULL)
239 {
240 /* free strings */
241 if (tt->type[column] == TEXTTABLE_STRING)
242 {
243 size_t row;
244 for (row = 0; row < tt->rows; row++)
245 free(((char **)tt->data.dvoid[column])[row]);
246 }
247 free(tt->data.dvoid[column]);
248 }
249 free(tt->data.dvoid);
250 tt->data.dvoid = NULL;
251 }
252
253 if (tt->type != NULL)
254 {
255 free(tt->type);
256 tt->type = NULL;
257 }
258 }
259
260 int texttable_readheader(texttable *tt, FILE *file, char delimiter,
261 int hasnames)
262 {
263 char *c;
264 size_t columns;
265 int err;
266 char *header;
267 long offset;
268
269 offset = ftell(file);
270 if (offset == -1)
271 return TEXTTABLE_EFERROR;
272
273 header = texttable_fgetln(file);
274 if (header == NULL)
275 {
276 if (feof(file) || ferror(file))
277 return TEXTTABLE_EFERROR;
278 return TEXTTABLE_ENOMEM;
279 }
280
281 /* Counting the columns */
282 c = header;
283 columns = 1;
284 while (*c)
285 if (*(c++) == delimiter)
286 columns ++;
287
288 if (!hasnames)
289 {
290 err = fseek(file, offset, SEEK_SET);
291 if (err)
292 return TEXTTABLE_EFERROR;
293 }
294
295 err = texttable_new(tt, columns);
296 if (err)
297 {
298 free(header);
299 return err;
300 }
301
302 /* Reading the names */
303 if (hasnames)
304 {
305 char *input = header, *tok;
306 for (columns = 0;(tok = texttable_strsep(&input, delimiter)) != NULL;
307 columns++)
308 {
309 tt->name[columns] = strdup(tok);
310 if (tt->name[columns] == NULL)
311 {
312 texttable_free(tt);
313 free(header);
314 return TEXTTABLE_ENOMEM;
315 }
316 }
317 }
318
319 free(header);
320
321 return TEXTTABLE_NOERR;
322 }
323
324 int texttable_guesstype(texttable *tt, FILE *file, char delimiter, size_t rows)
325 {
326 size_t column;
327 int err;
328 char *buf;
329 long offset;
330
331 offset = ftell(file);
332 if (offset == -1)
333 return TEXTTABLE_EFERROR;
334
335 while ((rows--) && (buf = texttable_fgetln(file)) != NULL)
336 {
337 char *input = buf, *tok;
338 for (column = 0;
339 (tok = texttable_strsep(&input, delimiter)) != NULL;column++)
340 {
341 if (column == tt->columns)
342 return TEXTTABLE_ETOOMANYC; /* To many columns */
343
344 if (tok[0] == '\0' && tt->type[column] != TEXTTABLE_CHAR
345 && tt->type[column] != TEXTTABLE_STRING)
346 {
347 if(tt->type[column] == TEXTTABLE_UNKNOWN)
348 tt->type[column] = TEXTTABLE_CHAR;
349 else
350 tt->type[column] = TEXTTABLE_STRING;
351 }
352
353 if (tt->type[column] == TEXTTABLE_UNKNOWN)
354 tt->type[column] = TEXTTABLE_INT; /* Default type */
355
356 switch (tt->type[column])
357 {
358 case TEXTTABLE_CHAR:
359 if (tok[0] != '\0' && tok[1] != '\0') /* strlen > 1 */
360 tt->type[column] = TEXTTABLE_STRING;
361 break;
362 case TEXTTABLE_SHORT:
363 case TEXTTABLE_INT:
364 case TEXTTABLE_LONG:
365 #ifdef HAS_LONGLONG
366 case TEXTTABLE_LONGLONG:
367 #endif
368 {
369 char *endptr;
370 #ifdef HAS_LONGLONG
371 long long value;
372 #else
373 long value;
374 #endif
375
376 errno = 0; /* Clear error */
377 #ifdef HAS_LONGLONG
378 value = strtoll(tok, &endptr, 10);
379 #else
380 value = strtol(tok, &endptr, 10);
381 #endif
382 if (endptr == tok)
383 {
384 /* No digits */
385 tt->type[column] = TEXTTABLE_STRING;
386 break;
387 }
388 /* Skip whitespace */
389 if(*endptr)
390 for (;isspace(*endptr);endptr++);
391 if (*endptr)
392 {
393 /* Invalid character */
394 tt->type[column] = TEXTTABLE_DOUBLE;
395 /* will go to 'case TEXTTABLE_DOUBLE' */
396 }
397 else
398 {
399 if (errno == ERANGE)
400 {
401 tt->type[column] = TEXTTABLE_STRING;
402 break;
403 }
404 switch (tt->type[column])
405 {
406 case TEXTTABLE_SHORT:
407 if (value <= SHRT_MAX && value >= SHRT_MIN)
408 break;
409 tt->type[column] = TEXTTABLE_INT;
410 case TEXTTABLE_INT:
411 if (value <= INT_MAX && value >= INT_MIN)
412 break;
413 tt->type[column] = TEXTTABLE_LONG;
414 case TEXTTABLE_LONG:
415 #ifdef HAS_LONGLONG
416 if (value <= LONG_MAX && value >= LONG_MIN)
417 break;
418 tt->type[column] = TEXTTABLE_LONGLONG;
419 case TEXTTABLE_LONGLONG:
420 #endif
421 break;
422 default:;
423 /* NOTREACHED */
424 }
425 break;
426 }
427 }
428 case TEXTTABLE_FLOAT:
429 case TEXTTABLE_DOUBLE:
430 {
431 char *endptr;
432 double value;
433
434 errno = 0; /* Clear error */
435 value = strtod(tok, &endptr);
436 if (endptr == tok)
437 {
438 /* No digits */
439 tt->type[column] = TEXTTABLE_STRING;
440 break;
441 }
442 /* Skip whitespace */
443 for (;isspace(*endptr);endptr++);
444 if (*endptr || errno == ERANGE)
445 {
446 /* Invalid character */
447 tt->type[column] = TEXTTABLE_STRING;
448 break;
449 }
450 if (tt->type[column] == TEXTTABLE_FLOAT)
451 {
452 if (value <= FLT_MAX && value > -FLT_MAX)
453 break;
454 tt->type[column] = TEXTTABLE_DOUBLE;
455 }
456 break;
457 }
458 case TEXTTABLE_STRING:
459 break;
460 default:
461 free(buf);
462 return TEXTTABLE_EUNKTYPE;
463 }
464 }
465
466 free(buf);
467 }
468
469 if (ferror(file))
470 return TEXTTABLE_EFERROR;
471
472 if (!feof(file) && (rows != -1))
473 return TEXTTABLE_ENOMEM;
474
475 err = fseek(file, offset, SEEK_SET);
476 if (err)
477 return TEXTTABLE_EFERROR;
478
479 return TEXTTABLE_NOERR;
480 }
481
482 int texttable_allocate(texttable *tt, size_t rows)
483 {
484 int status;
485 status = texttable_reallocate(tt, rows);
486 if (status) return status;
487 tt->rows = rows;
488 return TEXTTABLE_NOERR;
489 }
490
491 int texttable_reallocate(texttable *tt, size_t maxrows)
492 {
493 size_t column;
494
495 for (column=0;column<tt->columns;column++)
496 if (tt->type[column]<0 || tt->type[column]>=TEXTTABLE_UNKNOWN)
497 return TEXTTABLE_EUNKTYPE;
498
499 if (maxrows<tt->rows)
500 tt->rows = maxrows;
501
502 for (column=0;column<tt->columns;column++)
503 {
504 void *ndata;
505 ndata = realloc(tt->data.dvoid[column],
506 maxrows*texttable_sizeof[tt->type[column]]);
507 if (ndata != NULL)
508 tt->data.dvoid[column] = ndata;
509 else if (maxrows>tt->rows)
510 return TEXTTABLE_ENOMEM;
511 }
512
513 return TEXTTABLE_NOERR;
514 }
515
516 int texttable_readdata(texttable *tt, FILE *file, char delimiter)
517 {
518 char *buf = NULL;
519 size_t maxrows, column, bufsize = 0;
520 int err;
521
522 maxrows = tt->rows;
523
524 while ((buf = texttable_fgets(file, buf, &bufsize)) != NULL)
525 {
526 char *input = buf, *tok;
527
528 /* Allocate enough space */
529 if (tt->rows == maxrows)
530 {
531 maxrows += maxrows;
532 if (!maxrows)
533 maxrows = 256;
534 texttable_reallocate(tt, maxrows);
535 }
536
537 for (column = 0;
538 (tok = texttable_strsep(&input, delimiter)) != NULL;column++)
539 {
540 if (column == tt->columns)
541 {
542 free(buf);
543 return TEXTTABLE_ETOOMANYC; /* To many columns */
544 }
545
546 switch (tt->type[column])
547 {
548 case TEXTTABLE_CHAR:
549 tt->data.dchar[column][tt->rows] = tok[0];
550 break;
551 case TEXTTABLE_SHORT:
552 case TEXTTABLE_INT:
553 case TEXTTABLE_LONG:
554 #ifdef HAS_LONGLONG
555 case TEXTTABLE_LONGLONG:
556 #endif
557 {
558 char *endptr;
559 #ifdef HAS_LONGLONG
560 long long value;
561 #else
562 long value;
563 #endif
564
565 errno = 0; /* Clear error */
566 #ifdef HAS_LONGLONG
567 value = strtoll(tok, &endptr, 10);
568 #else
569 value = strtol(tok, &endptr, 10);
570 #endif
571 if (endptr == tok)
572 {
573 /* No digits */
574 free(buf);
575 return TEXTTABLE_EINDATA;
576 }
577 /* Skip whitespace */
578 for (;isspace(*endptr);endptr++);
579 if (*endptr)
580 {
581 /* Invalid character */
582 free(buf);
583 return TEXTTABLE_EINDATA;
584 }
585 if (errno == ERANGE)
586 {
587 free(buf);
588 return TEXTTABLE_EINDATA;
589 }
590 switch (tt->type[column])
591 {
592 case TEXTTABLE_SHORT:
593 if (value <= SHRT_MAX && value >= SHRT_MIN)
594 {
595 tt->data.dshort[column][tt->rows] = (short)value;
596 break;
597 }
598 free(buf);
599 return TEXTTABLE_EINDATA;
600 case TEXTTABLE_INT:
601 if (value <= INT_MAX && value >= INT_MIN)
602 {
603 tt->data.dint[column][tt->rows] = (int)value;
604 break;
605 }
606 free(buf);
607 return TEXTTABLE_EINDATA;
608 case TEXTTABLE_LONG:
609 #ifdef HAS_LONGLONG
610 if (value <= LONG_MAX && value >= LONG_MIN)
611 {
612 tt->data.dlong[column][tt->rows] = (long)value;
613 break;
614 }
615 free(buf);
616 return TEXTTABLE_EINDATA;
617 case TEXTTABLE_LONGLONG:
618 tt->data.dlonglong[column][tt->rows] = (long long)value;
619 #else
620 tt->data.dlong[column][tt->rows] = (long)value;
621 #endif
622 break;
623 default:;
624 /* NOTREACHED */
625 }
626 break;
627 }
628 case TEXTTABLE_FLOAT:
629 case TEXTTABLE_DOUBLE:
630 {
631 char *endptr;
632 double value;
633
634 errno = 0; /* Clear error */
635 value = strtod(tok, &endptr);
636 if (endptr == tok)
637 {
638 /* No digits */
639 free(buf);
640 return TEXTTABLE_EINDATA;
641 }
642 /* Skip whitespace */
643 if (*endptr)
644 for (;isspace(*endptr);endptr++);
645 if (*endptr || errno == ERANGE)
646 {
647 /* Invalid character */
648 free(buf);
649 return TEXTTABLE_EINDATA;
650 }
651 if (tt->type[column] == TEXTTABLE_FLOAT)
652 {
653 if (value <= FLT_MAX && value > -FLT_MAX)
654 {
655 tt->data.dfloat[column][tt->rows] = (float)value;
656 break;
657 }
658 else
659 {
660 free(buf);
661 return TEXTTABLE_EINDATA;
662 }
663 }
664 tt->data.ddouble[column][tt->rows] = (double)value;
665 break;
666 }
667 case TEXTTABLE_STRING:
668 {
669 char *newstr = strdup(tok);
670 if (newstr == NULL)
671 {
672 free(buf);
673 return TEXTTABLE_ENOMEM;
674 }
675 tt->data.dstring[column][tt->rows] = newstr;
676 break;
677 }
678 default:
679 free(buf);
680 return TEXTTABLE_EUNKTYPE;
681 }
682 }
683
684 if (column != tt->columns)
685 {
686 free(buf);
687 return TEXTTABLE_ETOOFEWC; /* Too few columns */
688 }
689
690 tt->rows ++;
691 }
692
693 /* Unallocate surplus */
694 if (maxrows > tt->rows)
695 {
696 err = texttable_reallocate(tt, tt->rows);
697 if (err)
698 return err; /* NOTREACHED */
699 }
700
701 if (ferror(file))
702 return TEXTTABLE_EFERROR;
703
704 if (!feof(file))
705 return TEXTTABLE_ENOMEM;
706
707 /* We should test for a file error */
708
709 return TEXTTABLE_NOERR;
710 }
711
712 int texttable_write(texttable *tt, FILE *file, char delimiter, int hasnames)
713 {
714 size_t row, column;
715 int err;
716
717 if (hasnames)
718 {
719 for (column=0;column<tt->columns;column++)
720 {
721 err = fputs(tt->name[column], file);
722 if (err == EOF)
723 return TEXTTABLE_EFERROR;
724 if (column<(tt->columns-1))
725 {
726 err = putc(delimiter, file);
727 if (err == EOF)
728 return TEXTTABLE_EFERROR;
729 }
730 }
731 err = putc('\n', file);
732 if (err == EOF)
733 return TEXTTABLE_EFERROR;
734 }
735
736 for (row = 0;row<tt->rows;row++)
737 {
738 for (column = 0;column<tt->columns;column++)
739 {
740 switch (tt->type[column])
741 {
742 case TEXTTABLE_CHAR:
743 if (tt->data.dchar[column][row])
744 {
745 err = fputc(tt->data.dchar[column][row], file);
746 if (err == EOF)
747 return TEXTTABLE_EFERROR;
748 }
749 break;
750 case TEXTTABLE_SHORT:
751 err = fprintf(file, "%d", (int)(tt->data.dshort[column][row]));
752 if (err < 0)
753 return TEXTTABLE_EFERROR;
754 break;
755 case TEXTTABLE_INT:
756 err = fprintf(file, "%d", tt->data.dint[column][row]);
757 if (err < 0)
758 return TEXTTABLE_EFERROR;
759 break;
760 case TEXTTABLE_LONG:
761 err = fprintf(file, "%ld", tt->data.dlong[column][row]);
762 if (err < 0)
763 return TEXTTABLE_EFERROR;
764 break;
765 #ifdef HAS_LONGLONG
766 case TEXTTABLE_LONGLONG:
767 err = fprintf(file, "%lld", tt->data.dlonglong[column][row]);
768 if (err < 0)
769 return TEXTTABLE_EFERROR;
770 break;
771 #endif
772 case TEXTTABLE_FLOAT:
773 err = fprintf(file, "%g", (double)(tt->data.dfloat[column][row]));
774 if (err < 0)
775 return TEXTTABLE_EFERROR;
776 break;
777 case TEXTTABLE_DOUBLE:
778 err = fprintf(file, "%g", tt->data.ddouble[column][row]);
779 if (err < 0)
780 return TEXTTABLE_EFERROR;
781 break;
782 case TEXTTABLE_STRING:
783 err = fputs(tt->data.dstring[column][row], file);
784 if (err == EOF)
785 return TEXTTABLE_EFERROR;
786 break;
787 default:
788 return TEXTTABLE_EUNKTYPE;
789 }
790 if (column<(tt->columns-1))
791 {
792 err = putc(delimiter, file);
793 if (err == EOF)
794 return TEXTTABLE_EFERROR;
795 }
796 }
797 err = putc('\n', file);
798 if (err == EOF)
799 return TEXTTABLE_EFERROR;
800 }
801
802 return TEXTTABLE_NOERR;
803 }
804
805 char *texttable_strerror(int err)
806 {
807 if (err<0 || err>=TEXTTABLE_ERR_MAX)
808 return "texttable: error unknown";
809 return texttable_errorstrings[err];
810 }
811
812 void texttable_perror(int status, char *file, int line)
813 {
814 #ifndef NDEBUG
815 fprintf(stderr, "%s source=%s line=%d\n", texttable_strerror(status),
816 file, line);
817 #else
818 fprintf(stderr, "%s\n", texttable_strerror(status));
819 #endif
820 exit(EXIT_FAILURE);
821 }
822
823 /* High level API */
824
825 int texttable_readtable(FILE *file, char delimiter, int hasnames,
826 size_t columns, texttable_type *type, char ***name, size_t *rows, ...)
827 {
828 int status;
829 texttable tt;
830 va_list ap;
831 size_t c;
832
833 status = texttable_readheader(&tt, file, delimiter, hasnames);
834 if (status) goto cleanUp;
835
836 if (tt.columns<columns)
837 {
838 status = TEXTTABLE_ETOOFEWC;
839 goto cleanUp;
840 }
841
842 if (tt.columns>columns)
843 {
844 status = TEXTTABLE_ETOOMANYC;
845 goto cleanUp;
846 }
847
848 for (c=0;c<columns;c++)
849 tt.type[c] = type[c];
850
851 status = texttable_readdata(&tt, file, delimiter);
852 if (status) goto cleanUp;
853
854 if(columns > 0)
855 {
856 va_start(ap, rows);
857 for (c=0;c<columns;c++)
858 {
859 void **ptr = va_arg(ap, void **);
860 if (ptr != NULL)
861 {
862 *ptr = tt.data.dvoid[c];
863 tt.data.dvoid[c] = NULL;
864 }
865 }
866 va_end(ap);
867 }
868
869 *rows = tt.rows;
870
871 if (name != NULL)
872 {
873 *name = tt.name;
874 tt.name = NULL;
875 }
876
877 cleanUp:
878 texttable_free(&tt);
879 return status;
880 }
881
882 int texttable_writetable(FILE *file, char delimiter, size_t columns,
883 texttable_type *type, char **name, size_t rows, ...)
884 {
885 int status;
886 texttable tt;
887 va_list ap;
888 size_t c;
889
890 status = texttable_new(&tt, columns);
891 if (status) goto cleanUp;
892
893 if (name != NULL)
894 {
895 for (c=0;c<columns;c++)
896 tt.name[c] = name[c];
897 }
898
899 if(columns > 0)
900 {
901 va_start(ap, rows);
902 for (c=0;c<columns;c++)
903 {
904 void *ptr = va_arg(ap, void *);
905 tt.type[c] = type[c];
906 tt.data.dvoid[c] = ptr;
907 }
908 va_end(ap);
909 }
910
911 tt.rows = rows;
912
913 status = texttable_write(&tt, file, delimiter, name != NULL);
914
915 if (name != NULL)
916 {
917 for (c=0;c<columns;c++)
918 {
919 tt.name[c] = NULL;
920 tt.data.dvoid[c] = NULL;
921 }
922 }
923
924 cleanUp:
925 texttable_free(&tt);
926 return status;
927 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22