cis_config
AsciiTable.h
1 #include <../tools.h>
2 #include "AsciiFile.h"
3 
5 #ifndef ASCIITABLE_H_
6 #define ASCIITABLE_H_
7 
8 #define FMT_LEN 100
9 
11 enum fmt_types { AT_STRING, AT_FLOAT, AT_DOUBLE, AT_COMPLEX,
12  AT_SHORTSHORT, AT_SHORT, AT_INT, AT_LONG, AT_LONGLONG,
13  AT_USHORTSHORT, AT_USHORT, AT_UINT, AT_ULONG, AT_ULONGLONG };
14 
21 static inline
22 int count_complex_formats(const char* fmt_str) {
23  const char * fmt_regex = "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?[lhjztL]*[eEfFgG]"
24  "%([[:digit:]]+\\$)?[+-]([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?[lhjztL]*[eEfFgG]j";
25  int ret = count_matches(fmt_regex, fmt_str);
26  /* printf("%d, %s\n", ret, fmt_str); */
27  return ret;
28 };
29 
38 static inline
39 int count_formats(const char* fmt_str) {
40  const char * fmt_regex = "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?[lhjztL]*(64)?[bcdeEufFgGosxX]";
41  int ret = count_matches(fmt_regex, fmt_str);
42  /* printf("%d, %s\n", ret, fmt_str); */
43  return ret;
44 };
45 
54 static inline
55 int simplify_formats(char *fmt_str, const size_t fmt_len) {
56  const char * fmt_regex1 = "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?([lhjztL]*)([eEfFgG])";
57  // "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?([lhjztL]*)([eEfFgG])";
58  // "%([[:digit:]]+\\$)?[+-]?([ 0]|'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?([lhjztL])*([eEfFgG])";
59  int ret = regex_replace_sub(fmt_str, fmt_len, fmt_regex1,
60  "%$4$5", 0);
61  if (ret > 0) {
62  const char * fmt_regex2 = "%[lhjztL]*([fF])";
63  ret = regex_replace_sub(fmt_str, fmt_len, fmt_regex2,
64  "%l$1", 0);
65  }
66 /*#ifdef _WIN32
67  if (ret > 0) {
68  const char * fmt_regex3 = "%l64([du])";
69  ret = regex_replace_sub(fmt_str, fmt_len, fmt_regex3, "%l$1", 0);
70  }
71 #endif*/
72  return ret;
73 };
74 
76 typedef struct asciiTable_t {
78  char format_str[LINE_SIZE_MAX];
79  char column[64];
80  int ncols;
81  int *format_typ;
82  int *format_siz;
83  int row_siz;
84  int status;
85 } asciiTable_t;
86 
92 static inline
93 int at_open(asciiTable_t *t) {
94  return af_open(&((*t).f));
95 };
96 
102 static inline
103 void at_close(asciiTable_t *t) {
104  af_close(&((*t).f));
105 };
106 
116 static inline
117 int at_readline_full_realloc(const asciiTable_t t, char **buf,
118  const size_t len_buf, const int allow_realloc) {
119  // Read lines until there's one that's not a comment
120  int ret = 0, com = 1;
121  size_t nread = LINE_SIZE_MAX;
122  char *line = (char*)malloc(nread);
123  if (line == NULL) {
124  cislog_error("at_readline_full_realloc: Failed to malloc line.");
125  return -1;
126  }
127  while ((ret >= 0) && (com == 1)) {
128  ret = af_readline_full(t.f, &line, &nread);
129  if (ret < 0) {
130  free(line);
131  return ret;
132  }
133  com = af_is_comment(t.f, line);
134  }
135  if (ret > (int)len_buf) {
136  if (allow_realloc) {
137  cislog_debug("at_readline_full_realloc: reallocating buffer from %d to %d bytes.",
138  (int)len_buf, ret + 1);
139  char *temp_buf = (char*)realloc(*buf, ret + 1);
140  if (temp_buf == NULL) {
141  cislog_error("at_readline_full_realloc: Failed to realloc buffer.");
142  free(*buf);
143  free(line);
144  return -1;
145  }
146  *buf = temp_buf;
147  } else {
148  cislog_error("at_readline_full_realloc: line (%d bytes) is larger than destination buffer (%d bytes)",
149  ret, (int)len_buf);
150  ret = -1;
151  free(line);
152  return ret;
153  }
154  }
155  strcpy(*buf, line);
156  free(line);
157  return ret;
158 };
159 
168 static inline
169 int at_readline_full(const asciiTable_t t, char *buf, const size_t len_buf) {
170  // Read but don't realloc buf
171  return at_readline_full_realloc(t, &buf, len_buf, 0);
172 };
173 
180 static inline
181 int at_writeline_full(const asciiTable_t t, const char* line) {
182  int ret;
183  ret = af_writeline_full(t.f, line);
184  return ret;
185 };
186 
195 static inline
196 int at_vbytes_to_row(const asciiTable_t t, const char* line, va_list ap) {
197  // Simplify format for vsscanf
198  char fmt[LINE_SIZE_MAX];
199  strcpy(fmt, t.format_str);
200  int sret = simplify_formats(fmt, LINE_SIZE_MAX);
201  if (sret < 0) {
202  cislog_debug("at_vbytes_to_row: simplify_formats returned %d", sret);
203  return -1;
204  }
205  // Interpret line
206  int ret = vsscanf(line, fmt, ap);
207  if (ret != t.ncols) {
208  cislog_error("at_vbytes_to_row: %d arguments filled, but %d were expected",
209  sret, t.ncols);
210  ret = -1;
211  }
212  return ret;
213 };
214 
225 static inline
226 int at_vrow_to_bytes(const asciiTable_t t, char *buf, const size_t buf_siz, va_list ap) {
227  int ret = vsnprintf(buf, buf_siz, t.format_str, ap);
228  return ret;
229 };
230 
238 static inline
239 int at_vreadline(const asciiTable_t t, va_list ap) {
240  int ret;
241  // Read lines until there's one that's not a comment
242  size_t nread = LINE_SIZE_MAX;
243  char *line = (char*)malloc(nread);
244  if (line == NULL) {
245  cislog_error("at_vreadline: Failed to malloc line.");
246  return -1;
247  }
248  ret = at_readline_full(t, line, nread);
249  if (ret < 0) {
250  free(line);
251  return ret;
252  }
253  // Parse line
254  int sret = at_vbytes_to_row(t, line, ap);
255  if (sret < 0)
256  ret = -1;
257  free(line);
258  return ret;
259 };
260 
268 static inline
269 int at_vwriteline(const asciiTable_t t, va_list ap) {
270  int ret = vfprintf(t.f.fd, t.format_str, ap);
271  return ret;
272 };
273 
281 static inline
282 int at_readline(const asciiTable_t t, ...) {
283  va_list ap;
284  va_start(ap, t); // might need to use last element in structure
285  int ret = at_vreadline(t, ap);
286  va_end(ap);
287  return ret;
288 };
289 
297 static inline
298 int at_writeline(const asciiTable_t t, ...) {
299  va_list ap;
300  va_start(ap, t);
301  int ret = at_vwriteline(t, ap);
302  va_end(ap);
303  return ret;
304 };
305 
311 static inline
312 int at_writeformat(const asciiTable_t t) {
313  int ret;
314  if (af_is_open(t.f) == 1) {
315  ret = (int)fwrite(t.f.comment, 1, strlen(t.f.comment), t.f.fd);
316  if (ret < 0)
317  return ret;
318  }
319  ret = af_writeline_full(t.f, t.format_str);
320  return ret;
321 };
322 
329 static inline
330 int at_discover_format_str(asciiTable_t *t) {
331  int ret = at_open(t);
332  if (ret < 0)
333  return ret;
334  size_t nread = LINE_SIZE_MAX;
335  char *line = (char*)malloc(nread);
336  if (line == NULL) {
337  cislog_error("at_discover_format_str: Failed to malloc line.");
338  return -1;
339  }
340  ret = -1;
341  while (getline(&line, &nread, (*t).f.fd) >= 0) {
342  if (af_is_comment((*t).f, line) == 1) {
343  if (count_formats(line) > 0) {
344  strcpy((*t).format_str, line + strlen((*t).f.comment));
345  ret = 0;
346  break;
347  }
348  }
349  }
350  at_close(t);
351  free(line);
352  return ret;
353 };
354 
360 static inline
361 int at_set_ncols(asciiTable_t *t) {
362  // Assumes that format_str already done
363  int count;
364  count = count_formats((*t).format_str);
365  (*t).ncols = count;
366  return count;
367 };
368 
369 
375 static inline
376 int at_set_format_siz(asciiTable_t *t) {
377  /* (*t).format_siz = (int*)malloc((*t).ncols*sizeof(int)); */
378  int i, typ, siz;
379  (*t).row_siz = 0;
380  for (i = 0; i < (*t).ncols; i++) {
381  typ = (*t).format_typ[i];
382  siz = (*t).format_siz[i];
383  if (typ == AT_STRING) siz = (*t).format_siz[i]; // TODO
384  else if (typ == AT_FLOAT) siz = sizeof(float);
385  else if (typ == AT_DOUBLE) siz = sizeof(double);
386  else if (typ == AT_COMPLEX) siz = 2*sizeof(double);
387  else if (typ == AT_SHORTSHORT) siz = sizeof(char);
388  else if (typ == AT_SHORT) siz = sizeof(short);
389  else if (typ == AT_LONGLONG) siz = sizeof(long long);
390  else if (typ == AT_LONG) siz = sizeof(long);
391  else if (typ == AT_INT) siz = sizeof(int);
392  else if (typ == AT_USHORTSHORT) siz = sizeof(unsigned char);
393  else if (typ == AT_USHORT) siz = sizeof(unsigned short);
394  else if (typ == AT_ULONGLONG) siz = sizeof(unsigned long long);
395  else if (typ == AT_ULONG) siz = sizeof(unsigned long);
396  else if (typ == AT_UINT) siz = sizeof(unsigned int);
397  else siz = -1;
398  if (siz < 0) {
399  cislog_error("at_set_format_siz: Could not set size for column %d with type %d", i, typ);
400  return -1;
401  }
402  (*t).format_siz[i] = siz;
403  (*t).row_siz += siz;
404  // printf("format_str = %s\n", t->format_str);
405  // printf("col %d/%d siz = %d\n", i, (*t).ncols, siz);
406  }
407  return 0;
408 }
409 
416 static inline
417 int at_set_format_typ(asciiTable_t *t) {
418  (*t).format_typ = (int*)malloc((*t).ncols*sizeof(int));
419  (*t).format_siz = (int*)malloc((*t).ncols*sizeof(int));
420  if (((*t).format_typ == NULL) || ((*t).format_siz == NULL)) {
421  cislog_error("at_set_format_typ: Failed to alloc format_typ/format_siz");
422  return -1;
423  }
424  size_t beg = 0, end;
425  int icol = 0;
426  char ifmt[FMT_LEN];
427  // Initialize
428  for (icol = 0; icol < (*t).ncols; icol++) {
429  (*t).format_typ[icol] = -1;
430  (*t).format_siz[icol] = -1;
431  }
432  // Loop over string
433  icol = 0;
434  int mres;
435  size_t sind, eind;
436  char re_fmt[FMT_LEN];
437  sprintf(re_fmt, "%%[^%s%s]+[%s%s]",
438  (*t).column, (*t).f.newline, (*t).column, (*t).f.newline);
439  while (beg < strlen((*t).format_str)) {
440  mres = find_match(re_fmt, (*t).format_str + beg, &sind, &eind);
441  if (mres < 0) {
442  cislog_error("at_set_format_typ: find_match returned %d", mres);
443  return -1;
444  } else if (mres == 0) {
445  beg++;
446  continue;
447  }
448  beg += sind;
449  end = beg + (eind - sind);
450  strncpy(ifmt, &((*t).format_str)[beg], end-beg);
451  ifmt[end-beg] = '\0';
452  if (find_match("%.*s", ifmt, &sind, &eind)) {
453  (*t).format_typ[icol] = AT_STRING;
454  mres = regex_replace_sub(ifmt, FMT_LEN,
455  "%(\\.)?([[:digit:]]*)s(.*)", "$2", 0);
456  (*t).format_siz[icol] = atoi(ifmt);
457 #ifdef _WIN32
458  } else if (find_match("(%.*[fFeEgG]){2}j", ifmt, &sind, &eind)) {
459 #else
460  } else if (find_match("(\%.*[fFeEgG]){2}j", ifmt, &sind, &eind)) {
461 #endif
462  /* (*t).format_typ[icol] = AT_COMPLEX; */
463  (*t).format_typ[icol] = AT_DOUBLE;
464  icol++;
465  (*t).format_typ[icol] = AT_DOUBLE;
466  } else if (find_match("%.*[fFeEgG]", ifmt, &sind, &eind)) {
467  (*t).format_typ[icol] = AT_DOUBLE;
468  /* } else if (find_match("%.*l[fFeEgG]", ifmt, &sind, &eind)) { */
469  /* (*t).format_typ[icol] = AT_DOUBLE; */
470  /* } else if (find_match("%.*[fFeEgG]", ifmt, &sind, &eind)) { */
471  /* (*t).format_typ[icol] = AT_FLOAT; */
472  } else if (find_match("%.*hh[id]", ifmt, &sind, &eind)) {
473  (*t).format_typ[icol] = AT_SHORTSHORT;
474  } else if (find_match("%.*h[id]", ifmt, &sind, &eind)) {
475  (*t).format_typ[icol] = AT_SHORT;
476  } else if (find_match("%.*ll[id]", ifmt, &sind, &eind)) {
477  (*t).format_typ[icol] = AT_LONGLONG;
478  } else if (find_match("%.*l64[id]", ifmt, &sind, &eind)) {
479  (*t).format_typ[icol] = AT_LONGLONG;
480  } else if (find_match("%.*l[id]", ifmt, &sind, &eind)) {
481  (*t).format_typ[icol] = AT_LONG;
482  } else if (find_match("%.*[id]", ifmt, &sind, &eind)) {
483  (*t).format_typ[icol] = AT_INT;
484  } else if (find_match("%.*hh[uoxX]", ifmt, &sind, &eind)) {
485  (*t).format_typ[icol] = AT_USHORTSHORT;
486  } else if (find_match("%.*h[uoxX]", ifmt, &sind, &eind)) {
487  (*t).format_typ[icol] = AT_USHORT;
488  } else if (find_match("%.*ll[uoxX]", ifmt, &sind, &eind)) {
489  (*t).format_typ[icol] = AT_ULONGLONG;
490  } else if (find_match("%.*l64[uoxX]", ifmt, &sind, &eind)) {
491  (*t).format_typ[icol] = AT_ULONGLONG;
492  } else if (find_match("%.*l[uoxX]", ifmt, &sind, &eind)) {
493  (*t).format_typ[icol] = AT_ULONG;
494  } else if (find_match("%.*[uoxX]", ifmt, &sind, &eind)) {
495  (*t).format_typ[icol] = AT_UINT;
496  } else {
497  cislog_error("at_set_format_typ: Could not parse format string: %s", ifmt);
498  return -1;
499  }
500  beg = end;
501  icol++;
502  }
503  return at_set_format_siz(t);
504 };
505 
516 static inline
517 int at_vbytes_to_array(const asciiTable_t t, const char *data,
518  const size_t data_siz, va_list ap) {
519  // check size of array
520  /* size_t data_siz = strlen(data); */
521  if ((data_siz % t.row_siz) != 0) {
522  cislog_error("at_vbytes_to_array: Data: %s", data);
523  cislog_error("at_vbytes_to_array: Data size (%d) not an even number of rows (row size is %d)",
524  (int)data_siz, t.row_siz);
525  return -1;
526  }
527  // Loop through
528  int nrows = (int)data_siz / t.row_siz;
529  int cur_pos = 0, col_siz;
530  int i;
531  for (i = 0; i < t.ncols; i++) {
532  char **temp;
533  char *t2;
534  temp = va_arg(ap, char**);
535  col_siz = nrows*t.format_siz[i];
536  t2 = (char*)realloc(*temp, col_siz);
537  if (t2 == NULL) {
538  cislog_error("at_vbytes_to_array: Failed to realloc temp var.");
539  free(*temp);
540  return -1;
541  }
542  *temp = t2;
543  // C order memory
544  /* for (int j = 0; j < nrows; j++) { */
545  /* memcpy(*temp + j*t.format_siz[i], data + j*t.row_siz + cur_pos, t.format_siz[i]); */
546  /* } */
547  /* cur_pos += t.format_siz[i]; */
548  // F order memory
549  memcpy(*temp, data+cur_pos, col_siz);
550  cur_pos += col_siz;
551  /* printf("col %d: cur_pos = %d, col_siz = %d, data = %s, raw_data = ", i, cur_pos, col_siz, *temp); */
552  /* fwrite(*temp, col_siz, 1, stdout); */
553  /* printf("\n"); */
554  }
555  return nrows;
556 };
557 
569 static inline
570 int at_varray_to_bytes(const asciiTable_t t, char *data, const size_t data_siz, va_list ap) {
571  int nrows = va_arg(ap, int);
572  int msg_siz = nrows*t.row_siz;
573  if (msg_siz > (int)data_siz) {
574  cislog_debug("at_varray_to_bytes: Message size (%d bytes) will exceed allocated buffer (%d bytes).",
575  msg_siz, (int)data_siz);
576  return msg_siz;
577  }
578  // Loop through
579  int cur_pos = 0, col_siz;
580  char *temp;
581  int i;
582  for (i = 0; i < t.ncols; i++) {
583  col_siz = nrows*t.format_siz[i];
584  temp = va_arg(ap, char*);
585  memcpy(data+cur_pos, temp, col_siz);
586  cur_pos += col_siz;
587  }
588  return cur_pos;
589 };
590 
601 static inline
602 int at_bytes_to_array(const asciiTable_t t, char *data, size_t data_siz, ...) {
603  va_list ap;
604  va_start(ap, data_siz);
605  int ret = at_vbytes_to_array(t, data, data_siz, ap);
606  va_end(ap);
607  return ret;
608 };
609 
621 static inline
622 int at_array_to_bytes(const asciiTable_t t, char *data, const size_t data_siz, ...) {
623  va_list ap;
624  va_start(ap, data_siz);
625  int ret = at_varray_to_bytes(t, data, data_siz, ap);
626  va_end(ap);
627  return ret;
628 };
629 
634 static inline
635 void at_cleanup(asciiTable_t *t) {
636  if ((*t).format_typ)
637  free((*t).format_typ);
638  if ((*t).format_siz)
639  free((*t).format_siz);
640  (*t).format_typ = NULL;
641  (*t).format_siz = NULL;
642 };
643 
652 int at_update(asciiTable_t *t, const char *filepath, const char *io_mode) {
653  int flag = 0;
654  flag = af_update(&(t->f), filepath, io_mode);
655  if (flag == 0) {
656  if ((strlen(t->format_str) == 0) && (strcmp(io_mode, "r") == 0)) {
657  flag = at_discover_format_str(t);
658  if (flag >= 0)
659  flag = at_set_ncols(t);
660  if (flag >= 0)
661  flag = at_set_format_typ(t);
662  }
663  }
664  t->status = flag;
665  return flag;
666 };
667 
684 static inline
685 asciiTable_t asciiTable(const char *filepath, const char *io_mode,
686  const char *format_str, const char *comment,
687  const char *column, const char *newline) {
688  asciiTable_t t;
689  strcpy(t.format_str, "\0");
690  t.ncols = 0;
691  t.format_typ = NULL;
692  t.format_siz = NULL;
693  t.row_siz = 0;
694  t.status = 0;
695  t.f = asciiFile(filepath, io_mode, comment, newline);
696  // Set defaults for optional parameters
697  if (column == NULL)
698  strcpy(t.column, "\t");
699  else
700  strcpy(t.column, column);
701  // Guess format string from file
702  if (format_str == NULL) {
703  if (strcmp(io_mode, "r") == 0) {
704  t.status = at_discover_format_str(&t);
705  } else {
706  t.status = -1;
707  }
708  } else {
709  strcpy(t.format_str, format_str);
710  }
711  // Get number of columns & types
712  if (t.status >= 0)
713  t.status = at_set_ncols(&t);
714  if (t.status >= 0)
715  t.status = at_set_format_typ(&t);
716  /* printf("status = %d\n", t.status); */
717  /* printf("format_str = %s\n", t.format_str); */
718  /* printf("ncols = %d, row_siz = %d\n", t.ncols, t.row_siz); */
719  return t;
720 };
721 
722 #endif /*ASCIITABLE_H_*/
int row_siz
Size of an entire row in bytes.
Definition: AsciiTable.h:83
int * format_typ
Array of ncols integers specifying column types.
Definition: AsciiTable.h:81
char comment[64]
Character(s) indicating a comment.
Definition: AsciiFile.h:14
char format_str[LINE_SIZE_MAX]
Format string for rows.
Definition: AsciiTable.h:78
asciiFile_t f
ASCII file structure.
Definition: AsciiTable.h:77
int * format_siz
Array of ncols sizes for elements in each column.
Definition: AsciiTable.h:82
char column[64]
Character(s) used to seperate columns.
Definition: AsciiTable.h:79
int ncols
Number of columns in the table.
Definition: AsciiTable.h:80
Structure containing information about an ASCII text file.
Definition: AsciiFile.h:11
FILE * fd
File identifier for ASCII file when open.
Definition: AsciiFile.h:16
Structure containing information about an ASCII table.
Definition: AsciiTable.h:76
int status
Negative if format_str has not been set yet.
Definition: AsciiTable.h:84