cis_config
AsciiTable.h
1 #include <string.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <regex.h>
6 // Only include if not already included
7 #if !defined (ASCIIFILE_INCLUDED)
8 #include "AsciiFile.h"
9 #endif
10 
12 enum mytypes { STRING, FLOAT, DOUBLE,
13  SHORTSHORT, SHORT, INT, LONG, LONGLONG,
14  USHORTSHORT, USHORT, UINT, ULONG, ULONGLONG };
15 
24 static inline
25 int compile_regex (regex_t * r, const char * regex_text)
26 {
27  int status = regcomp (r, regex_text, REG_EXTENDED|REG_NEWLINE);
28  if (status != 0) {
29  char error_message[LINE_SIZE_MAX];
30  regerror (status, r, error_message, LINE_SIZE_MAX);
31  printf ("Regex error compiling '%s': %s\n",
32  regex_text, error_message);
33  return 1;
34  }
35  return 0;
36 };
37 
47 static inline
48 int count_matches(const char *regex_text, const char *to_match) {
49  int ret;
50  int n_match = 0;
51  regex_t r;
52  // Compile
53  ret = compile_regex(&r, regex_text);
54  if (ret)
55  return -1;
56  // Loop until string done
57  const char * p = to_match;
58  const int n_sub_matches = 10;
59  regmatch_t m[n_sub_matches];
60  while (1) {
61  int nomatch = regexec(&r, p, n_sub_matches, m, 0);
62  if (nomatch)
63  break;
64  n_match++;
65  p += m[0].rm_eo;
66  }
67  return n_match;
68 };
69 
78 static inline
79 int count_formats(const char* fmt_str) {
80  const char * fmt_regex = "%([[:digit:]]+\\$)?[+-]?([ 0]|\'.{1})?-?[[:digit:]]*(\\.[[:digit:]]+)?[lhjztL]*[bcdeEufFgGosxX]";
81  int ret = count_matches(fmt_regex, fmt_str);
82  /* printf("%d, %s\n", ret, fmt_str); */
83  return ret;
84 };
85 
87 typedef struct asciiTable_t {
89  char format_str[LINE_SIZE_MAX];
90  char column[64];
91  int ncols;
92  int *format_typ;
93  int *format_siz;
94  int row_siz;
95  int status;
96 } asciiTable_t;
97 
103 static inline
104 int at_open(asciiTable_t *t) {
105  return af_open(&((*t).f));
106 };
107 
113 static inline
114 void at_close(asciiTable_t *t) {
115  af_close(&((*t).f));
116 };
117 
125 static inline
126 int at_vreadline(const asciiTable_t t, va_list ap) {
127  int ret = 0, com = 1;
128  size_t nread = LINE_SIZE_MAX;
129  char *line = (char*)malloc(nread);
130  while ((ret >= 0) && (com == 1)) {
131  ret = af_readline_full(t.f, &line, &nread);
132  if (ret < 0)
133  return ret;
134  com = af_is_comment(t.f, line);
135  }
136  int sret = vsscanf(line, t.format_str, ap);
137  if (sret != t.ncols) {
138  printf("at_vreadline: %d arguments filled, but %d were expected\n",
139  sret, t.ncols);
140  ret = -1;
141  }
142  free(line);
143  return ret;
144 };
145 
153 static inline
154 int at_vwriteline(const asciiTable_t t, va_list ap) {
155  int ret = vfprintf(t.f.fd, t.format_str, ap);
156  return ret;
157 };
158 
166 static inline
167 int at_readline(const asciiTable_t t, ...) {
168  va_list ap;
169  va_start(ap, t); // might need to use last element in structure
170  int ret = at_vreadline(t, ap);
171  va_end(ap);
172  return ret;
173 };
174 
182 static inline
183 int at_writeline(const asciiTable_t t, ...) {
184  va_list ap;
185  va_start(ap, t);
186  int ret = at_vwriteline(t, ap);
187  va_end(ap);
188  return ret;
189 };
190 
196 static inline
197 int at_writeformat(const asciiTable_t t) {
198  int ret;
199  if (af_is_open(t.f) == 1) {
200  ret = fwrite(t.f.comment, 1, strlen(t.f.comment), t.f.fd);
201  if (ret < 0)
202  return ret;
203  }
204  ret = af_writeline_full(t.f, t.format_str);
205  return ret;
206 };
207 
214 static inline
215 int at_discover_format_str(asciiTable_t *t) {
216  int ret = at_open(t);
217  if (ret < 0)
218  return ret;
219  size_t nread = LINE_SIZE_MAX;
220  char *line = (char*)malloc(nread);
221  ret = -1;
222  while (getline(&line, &nread, (*t).f.fd) >= 0) {
223  if (af_is_comment((*t).f, line) == 1) {
224  if (count_formats(line) > 0) {
225  strcpy((*t).format_str, line + strlen((*t).f.comment));
226  ret = 0;
227  break;
228  }
229  }
230  }
231  at_close(t);
232  free(line);
233  return ret;
234 };
235 
241 static inline
242 int at_set_ncols(asciiTable_t *t) {
243  // Assumes that format_str already done
244  int count;
245  count = count_formats((*t).format_str);
246  (*t).ncols = count;
247  return count;
248 };
249 
256 static inline
257 int at_set_format_typ(asciiTable_t *t) {
258  (*t).format_typ = (int*)malloc((*t).ncols*sizeof(int));
259  (*t).format_siz = (int*)malloc((*t).ncols*sizeof(int));
260  size_t beg = 0, end;
261  int icol = 0;
262  char ifmt[100];
263  (*t).row_siz = 0;
264  while (beg < strlen((*t).format_str)) {
265  if ((*t).format_str[beg] == '%') {
266  end = beg;
267  while (end < strlen((*t).format_str)) {
268  // Advance end to next column separator or new line
269  if ((strncmp((*t).format_str + end, (*t).column, strlen((*t).column)) == 0) ||
270  (strncmp((*t).format_str + end, (*t).f.newline, strlen((*t).f.newline)) == 0)) {
271  strncpy(ifmt, &((*t).format_str)[beg], end-beg);
272  ifmt[end-beg] = '\0';
273  if ((*t).format_str[end-1] == 's') {
274  // String (variable length)
275  (*t).format_typ[icol] = STRING;
276  char len_fmt[100];
277  strncpy(len_fmt, &((*t).format_str)[beg+1], end-beg-2);
278  sscanf(len_fmt, "%d", &((*t).format_siz[icol]));
279  } else if (((*t).format_str[end-1] == 'f') ||
280  ((*t).format_str[end-1] == 'e') ||
281  ((*t).format_str[end-1] == 'E') ||
282  ((*t).format_str[end-1] == 'g') ||
283  ((*t).format_str[end-1] == 'G')) {
284  (*t).format_typ[icol] = DOUBLE;
285  (*t).format_siz[icol] = sizeof(double);
286  // Hack to allow double to be specified
287  /* if ((*t).format_str[end-2] == 'l') { */
288  /* (*t).format_typ[icol] = DOUBLE; */
289  /* (*t).format_siz[icol] = sizeof(double); */
290  /* } else { */
291  /* (*t).format_typ[icol] = FLOAT; */
292  /* (*t).format_siz[icol] = sizeof(float); */
293  /* } */
294  } else if (((*t).format_str[end-1] == 'd') ||
295  ((*t).format_str[end-1] == 'i')) {
296  // Integers
297  if ((*t).format_str[end-2] == 'h') {
298  if ((*t).format_str[end-3] == 'h') {
299  (*t).format_typ[icol] = SHORTSHORT;
300  (*t).format_siz[icol] = sizeof(char);
301  } else {
302  (*t).format_typ[icol] = SHORT;
303  (*t).format_siz[icol] = sizeof(short);
304  }
305  } else if ((*t).format_str[end-2] == 'l') {
306  if ((*t).format_str[end-3] == 'l') {
307  (*t).format_typ[icol] = LONGLONG;
308  (*t).format_siz[icol] = sizeof(long long);
309  } else {
310  (*t).format_typ[icol] = LONG;
311  (*t).format_siz[icol] = sizeof(long);
312  }
313  } else {
314  (*t).format_typ[icol] = INT;
315  (*t).format_siz[icol] = sizeof(int);
316  }
317  } else if (((*t).format_str[end-1] == 'u') ||
318  ((*t).format_str[end-1] == 'o') ||
319  ((*t).format_str[end-1] == 'x') ||
320  ((*t).format_str[end-1] == 'X')) {
321  // Unsigned integers
322  if ((*t).format_str[end-2] == 'h') {
323  if ((*t).format_str[end-3] == 'h') {
324  (*t).format_typ[icol] = USHORTSHORT;
325  (*t).format_siz[icol] = sizeof(unsigned char);
326  } else {
327  (*t).format_typ[icol] = USHORT;
328  (*t).format_siz[icol] = sizeof(unsigned short);
329  }
330  } else if ((*t).format_str[end-2] == 'l') {
331  if ((*t).format_str[end-3] == 'l') {
332  (*t).format_typ[icol] = ULONGLONG;
333  (*t).format_siz[icol] = sizeof(unsigned long long);
334  } else {
335  (*t).format_typ[icol] = ULONG;
336  (*t).format_siz[icol] = sizeof(unsigned long);
337  }
338  } else {
339  (*t).format_typ[icol] = UINT;
340  (*t).format_siz[icol] = sizeof(unsigned int);
341  }
342  } else {
343  printf("Could not parse format string: %s\n", ifmt);
344  return -1;
345  }
346  /* printf("%d: %s, typ = %d, siz = %d\n", icol, ifmt, */
347  /* (*t).format_typ[icol], (*t).format_siz[icol]); */
348  (*t).row_siz += (*t).format_siz[icol];
349  icol++;
350  break;
351  }
352  end++;
353  }
354  }
355  beg++;
356  }
357  return 0;
358 };
359 
370 static inline
371 int at_vbytes_to_array(const asciiTable_t t, const char *data,
372  const int data_siz, va_list ap) {
373  // check size of array
374  /* int data_siz = strlen(data); */
375  if ((data_siz % t.row_siz) != 0) {
376  printf("Data size (%d) not an even number of rows (row size is %d)\n",
377  data_siz, t.row_siz);
378  return -1;
379  }
380  // Loop through
381  int nrows = data_siz / t.row_siz;
382  int cur_pos = 0, col_siz;
383  for (int i = 0; i < t.ncols; i++) {
384  char **temp;
385  col_siz = nrows*t.format_siz[i];
386  temp = va_arg(ap, char**);
387  *temp = (char*)malloc(col_siz);
388  // C order memory
389  /* for (int j = 0; j < nrows; j++) { */
390  /* memcpy(*temp + j*t.format_siz[i], data + j*t.row_siz + cur_pos, t.format_siz[i]); */
391  /* } */
392  /* cur_pos += t.format_siz[i]; */
393  // F order memory
394  memcpy(*temp, data+cur_pos, col_siz);
395  cur_pos += col_siz;
396  /* printf("col %d: cur_pos = %d, col_siz = %d, data = %s, raw_data = ", i, cur_pos, col_siz, *temp); */
397  /* fwrite(*temp, col_siz, 1, stdout); */
398  /* printf("\n"); */
399  }
400  return nrows;
401 };
402 
411 static inline
412 int at_varray_to_bytes(const asciiTable_t t, char **data, int nrows, va_list ap) {
413  // Allocate
414  *data = (char*)realloc(*data, nrows*t.row_siz);
415  // Loop through
416  int cur_pos = 0, col_siz;
417  char *temp;
418  for (int i = 0; i < t.ncols; i++) {
419  col_siz = nrows*t.format_siz[i];
420  temp = va_arg(ap, char*);
421  memcpy(*data+cur_pos, temp, col_siz);
422  cur_pos += col_siz;
423  }
424  return cur_pos;
425 };
426 
437 static inline
438 int at_bytes_to_array(const asciiTable_t t, char *data, int data_siz, ...) {
439  va_list ap;
440  va_start(ap, data_siz);
441  int ret = at_vbytes_to_array(t, data, data_siz, ap);
442  va_end(ap);
443  return ret;
444 };
445 
454 static inline
455 int at_array_to_bytes(const asciiTable_t t, char **data, int nrows, ...) {
456  va_list ap;
457  va_start(ap, nrows);
458  int ret = at_varray_to_bytes(t, data, nrows, ap);
459  va_end(ap);
460  return ret;
461 };
462 
467 static inline
468 void at_cleanup(asciiTable_t *t) {
469  if ((*t).format_typ)
470  free((*t).format_typ);
471  if ((*t).format_siz)
472  free((*t).format_siz);
473  (*t).format_typ = NULL;
474  (*t).format_siz = NULL;
475 };
476 
493 static inline
494 asciiTable_t asciiTable(const char *filepath, const char *io_mode,
495  const char *format_str, const char *comment,
496  const char *column, const char *newline) {
497  asciiTable_t t;
498  strcpy(t.format_str, "\0");
499  t.ncols = 0;
500  t.format_typ = NULL;
501  t.format_siz = NULL;
502  t.row_siz = 0;
503  t.status = 0;
504  t.f = asciiFile(filepath, io_mode, comment, newline);
505  // Set defaults for optional parameters
506  if (column == NULL)
507  strcpy(t.column, "\t");
508  else
509  strcpy(t.column, column);
510  // Guess format string from file
511  if (format_str == NULL) {
512  if (strcmp(io_mode, "r") == 0) {
513  t.status = at_discover_format_str(&t);
514  } else {
515  t.status = -1;
516  }
517  } else {
518  strcpy(t.format_str, format_str);
519  }
520  // Get number of columns & types
521  if (t.status >= 0)
522  t.status = at_set_ncols(&t);
523  if (t.status >= 0)
524  t.status = at_set_format_typ(&t);
525  /* printf("status = %d\n", t.status); */
526  /* printf("format_str = %s\n", t.format_str); */
527  /* printf("ncols = %d, row_siz = %d\n", t.ncols, t.row_siz); */
528  return t;
529 };
530 
int row_siz
Size of an entire row in bytes.
Definition: AsciiTable.h:94
int * format_typ
Array of ncols integers specifying column types.
Definition: AsciiTable.h:92
char comment[64]
Character(s) indicating a comment.
Definition: AsciiFile.h:16
char format_str[LINE_SIZE_MAX]
Format string for rows.
Definition: AsciiTable.h:89
asciiFile_t f
ASCII file structure.
Definition: AsciiTable.h:88
int * format_siz
Array of ncols sizes for elements in each column.
Definition: AsciiTable.h:93
char column[64]
Character(s) used to seperate columns.
Definition: AsciiTable.h:90
int ncols
Number of columns in the table.
Definition: AsciiTable.h:91
Structure containing information about an ASCII text file.
Definition: AsciiFile.h:13
FILE * fd
File identifier for ASCII file when open.
Definition: AsciiFile.h:18
Structure containing information about an ASCII table.
Definition: AsciiTable.h:87
int status
Negative if format_str has not been set yet.
Definition: AsciiTable.h:95