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 {
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_*/
int row_siz
Size of an entire row in bytes.
Definition: AsciiTable.h:87
int * format_typ
Array of ncols integers specifying column types.
Definition: AsciiTable.h:85
char comment[64]
Character(s) indicating a comment.
Definition: AsciiFile.h:18
char format_str[LINE_SIZE_MAX]
Format string for rows.
Definition: AsciiTable.h:82
asciiFile_t f
ASCII file structure.
Definition: AsciiTable.h:81
int * format_siz
Array of ncols sizes for elements in each column.
Definition: AsciiTable.h:86
char column[64]
Character(s) used to seperate columns.
Definition: AsciiTable.h:83
int ncols
Number of columns in the table.
Definition: AsciiTable.h:84
Structure containing information about an ASCII text file.
Definition: AsciiFile.h:15
FILE * fd
File identifier for ASCII file when open.
Definition: AsciiFile.h:20
Structure containing information about an ASCII table.
Definition: AsciiTable.h:80
int status
Negative if format_str has not been set yet.
Definition: AsciiTable.h:88