cis_config: /root/cis_interface/cis_interface/cis_interface/dataio/AsciiTable.h Source File

cis_config

AsciiTable.h
1
2 #ifndef ASCIITABLE_H_
3 #define ASCIITABLE_H_
4
5 #include <../tools.h>
6 #include "AsciiFile.h"
7
8 #ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
9 extern "C" {
10 #endif
11
12 #define FMT_LEN 100
13
15 enum fmt_types { AT_STRING, AT_FLOAT, AT_DOUBLE, AT_COMPLEX,
16 AT_SHORTSHORT, AT_SHORT, AT_INT, AT_LONG, AT_LONGLONG,
17 AT_USHORTSHORT, AT_USHORT, AT_UINT, AT_ULONG, AT_ULONGLONG };
18
25 static inline
26 int count_complex_formats(const char* fmt_str) {
27 const char * fmt_regex = "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?[lhjztL]*[eEfFgG]"
28 "%([[:digit:]]+\\$)?[+-]([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?[lhjztL]*[eEfFgG]j";
29 int ret = count_matches(fmt_regex, fmt_str);
30 /* printf("%d, %s\n", ret, fmt_str); */
31 return ret;
32 };
33
42 static inline
43 int count_formats(const char* fmt_str) {
44 const char * fmt_regex = "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?[lhjztL]*(64)?[bcdeEufFgGosxX]";
45 int ret = count_matches(fmt_regex, fmt_str);
46 /* printf("%d, %s\n", ret, fmt_str); */
47 return ret;
48 };
49
58 static inline
59 int simplify_formats(char *fmt_str, const size_t fmt_len) {
60 const char * fmt_regex1 = "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?([lhjztL]*)([eEfFgG])";
61 // "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?([lhjztL]*)([eEfFgG])";
62 // "%([[:digit:]]+\\$)?[+-]?([ 0]|'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?([lhjztL])*([eEfFgG])";
63 int ret = regex_replace_sub(fmt_str, fmt_len, fmt_regex1,
64 "%$4$5", 0);
65 if (ret > 0) {
66 const char * fmt_regex2 = "%[lhjztL]*([fF])";
67 ret = regex_replace_sub(fmt_str, fmt_len, fmt_regex2,
68 "%l$1", 0);
69 }
70 /*#ifdef _WIN32
71 if (ret > 0) {
72 const char * fmt_regex3 = "%l64([du])";
73 ret = regex_replace_sub(fmt_str, fmt_len, fmt_regex3, "%l$1", 0);
74 }
75 #endif*/
76 return ret;
77 };
78
80 typedef struct asciiTable_t {
81 asciiFile_t f;
82 char format_str[LINE_SIZE_MAX];
83 char column[64];
84 int ncols;
85 int *format_typ;
86 int *format_siz;
87 int row_siz;
88 int status;
89 } asciiTable_t;
90
96 static inline
97 int at_open(asciiTable_t *t) {
98 return af_open(&((*t).f));
99 };
100
106 static inline
107 void at_close(asciiTable_t *t) {
108 af_close(&((*t).f));
109 };
110
120 static inline
121 int at_readline_full_realloc(const asciiTable_t t, char **buf,
122 const size_t len_buf, const int allow_realloc) {
123 // Read lines until there's one that's not a comment
124 int ret = 0, com = 1;
125 size_t nread = LINE_SIZE_MAX;
126 char *line = (char*)malloc(nread);
127 if (line == NULL) {
128 cislog_error("at_readline_full_realloc: Failed to malloc line.");
129 return -1;
130 }
131 while ((ret >= 0) && (com == 1)) {
132 ret = af_readline_full(t.f, &line, &nread);
133 if (ret < 0) {
134 free(line);
135 return ret;
136 }
137 com = af_is_comment(t.f, line);
138 }
139 if (ret > (int)len_buf) {
140 if (allow_realloc) {
141 cislog_debug("at_readline_full_realloc: reallocating buffer from %d to %d bytes.",
142 (int)len_buf, ret + 1);
143 char *temp_buf = (char*)realloc(*buf, ret + 1);
144 if (temp_buf == NULL) {
145 cislog_error("at_readline_full_realloc: Failed to realloc buffer.");
146 free(*buf);
147 free(line);
148 return -1;
149 }
150 *buf = temp_buf;
151 } else {
152 cislog_error("at_readline_full_realloc: line (%d bytes) is larger than destination buffer (%d bytes)",
153 ret, (int)len_buf);
154 ret = -1;
155 free(line);
156 return ret;
157 }
158 }
159 strcpy(*buf, line);
160 free(line);
161 return ret;
162 };
163
172 static inline
173 int at_readline_full(const asciiTable_t t, char *buf, const size_t len_buf) {
174 // Read but don't realloc buf
175 return at_readline_full_realloc(t, &buf, len_buf, 0);
176 };
177
184 static inline
185 int at_writeline_full(const asciiTable_t t, const char* line) {
186 int ret;
187 ret = af_writeline_full(t.f, line);
188 return ret;
189 };
190
199 static inline
200 int at_vbytes_to_row(const asciiTable_t t, const char* line, va_list ap) {
201 // Simplify format for vsscanf
202 char fmt[LINE_SIZE_MAX];
203 strcpy(fmt, t.format_str);
204 int sret = simplify_formats(fmt, LINE_SIZE_MAX);
205 if (sret < 0) {
206 cislog_debug("at_vbytes_to_row: simplify_formats returned %d", sret);
207 return -1;
208 }
209 // Interpret line
210 int ret = vsscanf(line, fmt, ap);
211 if (ret != t.ncols) {
212 cislog_error("at_vbytes_to_row: %d arguments filled, but %d were expected",
213 sret, t.ncols);
214 ret = -1;
215 }
216 return ret;
217 };
218
229 static inline
230 int at_vrow_to_bytes(const asciiTable_t t, char *buf, const size_t buf_siz, va_list ap) {
231 int ret = vsnprintf(buf, buf_siz, t.format_str, ap);
232 return ret;
233 };
234
242 static inline
243 int at_vreadline(const asciiTable_t t, va_list ap) {
244 int ret;
245 // Read lines until there's one that's not a comment
246 size_t nread = LINE_SIZE_MAX;
247 char *line = (char*)malloc(nread);
248 if (line == NULL) {
249 cislog_error("at_vreadline: Failed to malloc line.");
250 return -1;
251 }
252 ret = at_readline_full(t, line, nread);
253 if (ret < 0) {
254 free(line);
255 return ret;
256 }
257 // Parse line
258 int sret = at_vbytes_to_row(t, line, ap);
259 if (sret < 0)
260 ret = -1;
261 free(line);
262 return ret;
263 };
264
272 static inline
273 int at_vwriteline(const asciiTable_t t, va_list ap) {
274 int ret = vfprintf(t.f.fd, t.format_str, ap);
275 return ret;
276 };
277
285 static inline
286 int at_readline(const asciiTable_t t, ...) {
287 va_list ap;
288 va_start(ap, t); // might need to use last element in structure
289 int ret = at_vreadline(t, ap);
290 va_end(ap);
291 return ret;
292 };
293
301 static inline
302 int at_writeline(const asciiTable_t t, ...) {
303 va_list ap;
304 va_start(ap, t);
305 int ret = at_vwriteline(t, ap);
306 va_end(ap);
307 return ret;
308 };
309
315 static inline
316 int at_writeformat(const asciiTable_t t) {
317 int ret;
318 if (af_is_open(t.f) == 1) {
319 ret = (int)fwrite(t.f.comment, 1, strlen(t.f.comment), t.f.fd);
320 if (ret < 0)
321 return ret;
322 }
323 ret = af_writeline_full(t.f, t.format_str);
324 return ret;
325 };
326
333 static inline
334 int at_discover_format_str(asciiTable_t *t) {
335 int ret = at_open(t);
336 if (ret < 0)
337 return ret;
338 size_t nread = LINE_SIZE_MAX;
339 char *line = (char*)malloc(nread);
340 if (line == NULL) {
341 cislog_error("at_discover_format_str: Failed to malloc line.");
342 return -1;
343 }
344 ret = -1;
345 while (getline(&line, &nread, (*t).f.fd) >= 0) {
346 if (af_is_comment((*t).f, line) == 1) {
347 if (count_formats(line) > 0) {
348 strcpy((*t).format_str, line + strlen((*t).f.comment));
349 ret = 0;
350 break;
351 }
352 }
353 }
354 at_close(t);
355 free(line);
356 return ret;
357 };
358
364 static inline
365 int at_set_ncols(asciiTable_t *t) {
366 // Assumes that format_str already done
367 int count;
368 count = count_formats((*t).format_str);
369 (*t).ncols = count;
370 return count;
371 };
372
373
379 static inline
380 int at_set_format_siz(asciiTable_t *t) {
381 /* (*t).format_siz = (int*)malloc((*t).ncols*sizeof(int)); */
382 int i, typ, siz;
383 (*t).row_siz = 0;
384 for (i = 0; i < (*t).ncols; i++) {
385 typ = (*t).format_typ[i];
386 siz = (*t).format_siz[i];
387 if (typ == AT_STRING) siz = (*t).format_siz[i]; // TODO
388 else if (typ == AT_FLOAT) siz = sizeof(float);
389 else if (typ == AT_DOUBLE) siz = sizeof(double);
390 else if (typ == AT_COMPLEX) siz = 2*sizeof(double);
391 else if (typ == AT_SHORTSHORT) siz = sizeof(char);
392 else if (typ == AT_SHORT) siz = sizeof(short);
393 else if (typ == AT_LONGLONG) siz = sizeof(long long);
394 else if (typ == AT_LONG) siz = sizeof(long);
395 else if (typ == AT_INT) siz = sizeof(int);
396 else if (typ == AT_USHORTSHORT) siz = sizeof(unsigned char);
397 else if (typ == AT_USHORT) siz = sizeof(unsigned short);
398 else if (typ == AT_ULONGLONG) siz = sizeof(unsigned long long);
399 else if (typ == AT_ULONG) siz = sizeof(unsigned long);
400 else if (typ == AT_UINT) siz = sizeof(unsigned int);
401 else siz = -1;
402 if (siz < 0) {
403 cislog_error("at_set_format_siz: Could not set size for column %d with type %d", i, typ);
404 return -1;
405 }
406 (*t).format_siz[i] = siz;
407 (*t).row_siz += siz;
408 // printf("format_str = %s\n", t->format_str);
409 // printf("col %d/%d siz = %d\n", i, (*t).ncols, siz);
410 }
411 return 0;
412 }
413
420 static inline
421 int at_set_format_typ(asciiTable_t *t) {
422 (*t).format_typ = (int*)malloc((*t).ncols*sizeof(int));
423 (*t).format_siz = (int*)malloc((*t).ncols*sizeof(int));
424 if (((*t).format_typ == NULL) || ((*t).format_siz == NULL)) {
425 cislog_error("at_set_format_typ: Failed to alloc format_typ/format_siz");
426 return -1;
427 }
428 size_t beg = 0, end;
429 int icol = 0;
430 char ifmt[FMT_LEN];
431 // Initialize
432 for (icol = 0; icol < (*t).ncols; icol++) {
433 (*t).format_typ[icol] = -1;
434 (*t).format_siz[icol] = -1;
435 }
436 // Loop over string
437 icol = 0;
438 int mres;
439 size_t sind, eind;
440 char re_fmt[FMT_LEN];
441 sprintf(re_fmt, "%%[^%s%s]+[%s%s]",
442 (*t).column, (*t).f.newline, (*t).column, (*t).f.newline);
443 while (beg < strlen((*t).format_str)) {
444 mres = find_match(re_fmt, (*t).format_str + beg, &sind, &eind);
445 if (mres < 0) {
446 cislog_error("at_set_format_typ: find_match returned %d", mres);
447 return -1;
448 } else if (mres == 0) {
449 beg++;
450 continue;
451 }
452 beg += sind;
453 end = beg + (eind - sind);
454 strncpy(ifmt, &((*t).format_str)[beg], end-beg);
455 ifmt[end-beg] = '\0';
456 if (find_match("%.*s", ifmt, &sind, &eind)) {
457 (*t).format_typ[icol] = AT_STRING;
458 mres = regex_replace_sub(ifmt, FMT_LEN,
459 "%(\\.)?([[:digit:]]*)s(.*)", "$2", 0);
460 (*t).format_siz[icol] = atoi(ifmt);
461 #ifdef _WIN32
462 } else if (find_match("(%.*[fFeEgG]){2}j", ifmt, &sind, &eind)) {
463 #else
464 } else if (find_match("(\%.*[fFeEgG]){2}j", ifmt, &sind, &eind)) {
465 #endif
466 /* (*t).format_typ[icol] = AT_COMPLEX; */
467 (*t).format_typ[icol] = AT_DOUBLE;
468 icol++;
469 (*t).format_typ[icol] = AT_DOUBLE;
470 } else if (find_match("%.*[fFeEgG]", ifmt, &sind, &eind)) {
471 (*t).format_typ[icol] = AT_DOUBLE;
472 /* } else if (find_match("%.*l[fFeEgG]", ifmt, &sind, &eind)) { */
473 /* (*t).format_typ[icol] = AT_DOUBLE; */
474 /* } else if (find_match("%.*[fFeEgG]", ifmt, &sind, &eind)) { */
475 /* (*t).format_typ[icol] = AT_FLOAT; */
476 } else if (find_match("%.*hh[id]", ifmt, &sind, &eind)) {
477 (*t).format_typ[icol] = AT_SHORTSHORT;
478 } else if (find_match("%.*h[id]", ifmt, &sind, &eind)) {
479 (*t).format_typ[icol] = AT_SHORT;
480 } else if (find_match("%.*ll[id]", ifmt, &sind, &eind)) {
481 (*t).format_typ[icol] = AT_LONGLONG;
482 } else if (find_match("%.*l64[id]", ifmt, &sind, &eind)) {
483 (*t).format_typ[icol] = AT_LONGLONG;
484 } else if (find_match("%.*l[id]", ifmt, &sind, &eind)) {
485 (*t).format_typ[icol] = AT_LONG;
486 } else if (find_match("%.*[id]", ifmt, &sind, &eind)) {
487 (*t).format_typ[icol] = AT_INT;
488 } else if (find_match("%.*hh[uoxX]", ifmt, &sind, &eind)) {
489 (*t).format_typ[icol] = AT_USHORTSHORT;
490 } else if (find_match("%.*h[uoxX]", ifmt, &sind, &eind)) {
491 (*t).format_typ[icol] = AT_USHORT;
492 } else if (find_match("%.*ll[uoxX]", ifmt, &sind, &eind)) {
493 (*t).format_typ[icol] = AT_ULONGLONG;
494 } else if (find_match("%.*l64[uoxX]", ifmt, &sind, &eind)) {
495 (*t).format_typ[icol] = AT_ULONGLONG;
496 } else if (find_match("%.*l[uoxX]", ifmt, &sind, &eind)) {
497 (*t).format_typ[icol] = AT_ULONG;
498 } else if (find_match("%.*[uoxX]", ifmt, &sind, &eind)) {
499 (*t).format_typ[icol] = AT_UINT;
500 } else {
501 cislog_error("at_set_format_typ: Could not parse format string: %s", ifmt);
502 return -1;
503 }
504 beg = end;
505 icol++;
506 }
507 return at_set_format_siz(t);
508 };
509
520 static inline
521 int at_vbytes_to_array(const asciiTable_t t, const char *data,
522 const size_t data_siz, va_list ap) {
523 // check size of array
524 /* size_t data_siz = strlen(data); */
525 if ((data_siz % t.row_siz) != 0) {
526 cislog_error("at_vbytes_to_array: Data: %s", data);
527 cislog_error("at_vbytes_to_array: Data size (%d) not an even number of rows (row size is %d)",
528 (int)data_siz, t.row_siz);
529 return -1;
530 }
531 // Loop through
532 int nrows = (int)data_siz / t.row_siz;
533 int cur_pos = 0, col_siz;
534 int i;
535 for (i = 0; i < t.ncols; i++) {
536 char **temp;
537 char *t2;
538 temp = va_arg(ap, char**);
539 col_siz = nrows*t.format_siz[i];
540 t2 = (char*)realloc(*temp, col_siz);
541 if (t2 == NULL) {
542 cislog_error("at_vbytes_to_array: Failed to realloc temp var.");
543 free(*temp);
544 return -1;
545 }
546 *temp = t2;
547 // C order memory
548 /* for (int j = 0; j < nrows; j++) { */
549 /* memcpy(*temp + j*t.format_siz[i], data + j*t.row_siz + cur_pos, t.format_siz[i]); */
550 /* } */
551 /* cur_pos += t.format_siz[i]; */
552 // F order memory
553 memcpy(*temp, data+cur_pos, col_siz);
554 cur_pos += col_siz;
555 /* printf("col %d: cur_pos = %d, col_siz = %d, data = %s, raw_data = ", i, cur_pos, col_siz, *temp); */
556 /* fwrite(*temp, col_siz, 1, stdout); */
557 /* printf("\n"); */
558 }
559 return nrows;
560 };
561
573 static inline
574 int at_varray_to_bytes(const asciiTable_t t, char *data, const size_t data_siz, va_list ap) {
575 int nrows = va_arg(ap, int);
576 int msg_siz = nrows*t.row_siz;
577 if (msg_siz > (int)data_siz) {
578 cislog_debug("at_varray_to_bytes: Message size (%d bytes) will exceed allocated buffer (%d bytes).",
579 msg_siz, (int)data_siz);
580 return msg_siz;
581 }
582 // Loop through
583 int cur_pos = 0, col_siz;
584 char *temp;
585 int i;
586 for (i = 0; i < t.ncols; i++) {
587 col_siz = nrows*t.format_siz[i];
588 temp = va_arg(ap, char*);
589 memcpy(data+cur_pos, temp, col_siz);
590 cur_pos += col_siz;
591 }
592 return cur_pos;
593 };
594
605 static inline
606 int at_bytes_to_array(const asciiTable_t t, char *data, size_t data_siz, ...) {
607 va_list ap;
608 va_start(ap, data_siz);
609 int ret = at_vbytes_to_array(t, data, data_siz, ap);
610 va_end(ap);
611 return ret;
612 };
613
625 static inline
626 int at_array_to_bytes(const asciiTable_t t, char *data, const size_t data_siz, ...) {
627 va_list ap;
628 va_start(ap, data_siz);
629 int ret = at_varray_to_bytes(t, data, data_siz, ap);
630 va_end(ap);
631 return ret;
632 };
633
638 static inline
639 void at_cleanup(asciiTable_t *t) {
640 if ((*t).format_typ)
641 free((*t).format_typ);
642 if ((*t).format_siz)
643 free((*t).format_siz);
644 (*t).format_typ = NULL;
645 (*t).format_siz = NULL;
646 };
647
656 static inline
657 int at_update(asciiTable_t *t, const char *filepath, const char *io_mode) {
658 int flag = 0;
659 flag = af_update(&(t->f), filepath, io_mode);
660 if (flag == 0) {
661 if ((strlen(t->format_str) == 0) && (strcmp(io_mode, "r") == 0)) {
662 flag = at_discover_format_str(t);
663 if (flag >= 0)
664 flag = at_set_ncols(t);
665 if (flag >= 0)
666 flag = at_set_format_typ(t);
667 }
668 }
669 t->status = flag;
670 return flag;
671 };
672
689 static inline
690 asciiTable_t asciiTable(const char *filepath, const char *io_mode,
691 const char *format_str, const char *comment,
692 const char *column, const char *newline) {
693 asciiTable_t t;
694 strcpy(t.format_str, "\0");
695 t.ncols = 0;
696 t.format_typ = NULL;
697 t.format_siz = NULL;
698 t.row_siz = 0;
699 t.status = 0;
700 t.f = asciiFile(filepath, io_mode, comment, newline);
701 // Set defaults for optional parameters
702 if (column == NULL)
703 strcpy(t.column, "\t");
704 else
705 strcpy(t.column, column);
706 // Guess format string from file
707 if (format_str == NULL) {
708 if (strcmp(io_mode, "r") == 0) {
709 t.status = at_discover_format_str(&t);
710 } else {
711 t.status = -1;
712 }
713 } else {
714 strcpy(t.format_str, format_str);
715 }
716 // Get number of columns & types
717 if (t.status >= 0)
718 t.status = at_set_ncols(&t);
719 if (t.status >= 0)
720 t.status = at_set_format_typ(&t);
721 /* printf("status = %d\n", t.status); */
722 /* printf("format_str = %s\n", t.format_str); */
723 /* printf("ncols = %d, row_siz = %d\n", t.ncols, t.row_siz); */
724 return t;
725 };
726
727 #ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
728 }
729 #endif
730
731 #endif /*ASCIITABLE_H_*/
asciiTable_t::row_siz
int row_siz
Size of an entire row in bytes.
Definition: AsciiTable.h:87
asciiTable_t::format_typ
int * format_typ
Array of ncols integers specifying column types.
Definition: AsciiTable.h:85
asciiFile_t::comment
char comment[64]
Character(s) indicating a comment.
Definition: AsciiFile.h:18
asciiTable_t::format_str
char format_str[LINE_SIZE_MAX]
Format string for rows.
Definition: AsciiTable.h:82
asciiTable_t::f
asciiFile_t f
ASCII file structure.
Definition: AsciiTable.h:81
asciiTable_t::format_siz
int * format_siz
Array of ncols sizes for elements in each column.
Definition: AsciiTable.h:86
asciiTable_t::column
char column[64]
Character(s) used to seperate columns.
Definition: AsciiTable.h:83
asciiTable_t::ncols
int ncols
Number of columns in the table.
Definition: AsciiTable.h:84
asciiFile_t
Structure containing information about an ASCII text file.
Definition: AsciiFile.h:15
asciiFile_t::fd
FILE * fd
File identifier for ASCII file when open.
Definition: AsciiFile.h:20
asciiTable_t
Structure containing information about an ASCII table.
Definition: AsciiTable.h:80
asciiTable_t::status
int status
Negative if format_str has not been set yet.
Definition: AsciiTable.h:88