UniRec  3.3.1
unirec2csv.c
Go to the documentation of this file.
1 #include <stdint.h>
2 #include <inttypes.h>
3 #include <ctype.h>
4 #include <time.h>
5 #include <unirec/unirec2csv.h>
6 
7 urcsv_t *urcsv_init(ur_template_t *tmplt, char delimiter)
8 {
9  if (tmplt == NULL) {
10  return NULL;
11  }
12  urcsv_t *s = malloc(sizeof(urcsv_t));
13  if (s != NULL) {
14  s->tmplt = tmplt;
15  s->delimiter = delimiter;
16  /* default size of buffer */
17  s->buffer_size = 4096;
18  s->free_space = s->buffer_size;
19  s->buffer = calloc(s->buffer_size, sizeof(s->buffer[0]));
20  if (s->buffer == NULL) {
21  free(s);
22  return NULL;
23  }
24  }
25  return s;
26 }
27 
28 void urcsv_free(urcsv_t **urcsv)
29 {
30  if (urcsv != NULL && *urcsv != NULL) {
31  free((*urcsv)->buffer);
32  free(*urcsv);
33  (*urcsv) = NULL;
34  }
35 }
36 
37 char *urcsv_header(urcsv_t *urcsv)
38 {
39  if (urcsv == NULL) {
40  return NULL;
41  }
42  return ur_template_string_delimiter(urcsv->tmplt, urcsv->delimiter);
43 }
44 
45 int urcsv_value(char *dst, uint32_t size, void *ptr, int type, int field_len)
46 {
47  int written = 0;
48  char *p = dst;
49 
50  // Static field - check what type is it and use appropriate format
51  switch (type) {
52  case UR_TYPE_UINT8:
53  written = snprintf(p, size, "%" PRIu8, *(uint8_t*) ptr);
54  break;
55  case UR_TYPE_UINT16:
56  written = snprintf(p, size, "%" PRIu16, *(uint16_t*) ptr);
57  break;
58  case UR_TYPE_UINT32:
59  written = snprintf(p, size, "%" PRIu32, *(uint32_t*) ptr);
60  break;
61  case UR_TYPE_UINT64:
62  written = snprintf(p, size, "%" PRIu64, *(uint64_t*) ptr);
63  break;
64  case UR_TYPE_INT8:
65  written = snprintf(p, size, "%" PRIi8, *(int8_t*) ptr);
66  break;
67  case UR_TYPE_INT16:
68  written = snprintf(p, size, "%" PRIi16, *(int16_t*) ptr);
69  break;
70  case UR_TYPE_INT32:
71  written = snprintf(p, size, "%" PRIi32, *(int32_t*) ptr);
72  break;
73  case UR_TYPE_INT64:
74  written = snprintf(p, size, "%" PRIi64, *(int64_t*) ptr);
75  break;
76  case UR_TYPE_CHAR:
77  written = snprintf(p, size, "%c", *(char*) ptr);
78  break;
79  case UR_TYPE_FLOAT:
80  written = snprintf(p, size, "%f", *(float*) ptr);
81  break;
82  case UR_TYPE_DOUBLE:
83  written = snprintf(p, size, "%f", *(double*) ptr);
84  break;
85  case UR_TYPE_IP:
86  {
87  // IP address - convert to human-readable format and print
88  char str[46];
89  ip_to_str((ip_addr_t*) ptr, str);
90  written = snprintf(p, size, "%s", str);
91  }
92  break;
93  case UR_TYPE_MAC:
94  {
95  // MAC address - convert to human-readable format and print
96  char str[MAC_STR_LEN];
97  mac_to_str((mac_addr_t *) ptr, str);
98  written = snprintf(p, size, "%s", str);
99  }
100  break;
101  case UR_TYPE_TIME:
102  {
103  // Timestamp - convert to human-readable format and print
104  time_t sec = ur_time_get_sec(*(ur_time_t*) ptr);
105  int usec = ur_time_get_usec(*(ur_time_t*) ptr);
106  char str[40];
107  struct tm tm_tmp;
108  strftime(str, 39, "%FT%T", gmtime_r(&sec, &tm_tmp));
109  written = snprintf(p, size, "%s.%06i", str, usec);
110  }
111  break;
112  default:
113  {
114  // Unknown type - print the value in hex
115  strncpy(p, "0x", size);
116  written += 2;
117  p += 2;
118  for (int i = 0; i < field_len && written < size; i++) {
119  int w = snprintf(p, size - written, "%02x", ((unsigned char *) ptr)[i]);
120  written += w;
121  p += w;
122  }
123  }
124  break;
125  } // case (field type)
126 
127  return written;
128 }
129 
130 int urcsv_field(char *dst, uint32_t size, const void *rec, ur_field_type_t id, ur_template_t *tmplt)
131 {
132  int written = 0;
133  char *p = dst;
134 
135  // Get pointer to the field (valid for static fields only)
136  void *ptr = ur_get_ptr_by_id(tmplt, rec, id);
137  int type = ur_get_type(id);
138 
139  if (type == UR_TYPE_STRING) {
140  // Printable string - print it as it is
141  int fs = ur_get_var_len(tmplt, rec, id);
142  char *data = ur_get_ptr_by_id(tmplt, rec, id);
143  *(p++) = '"';
144  written++;
145 
146  while (fs-- && (written < size)) {
147  switch (*data) {
148  case '\n': // Replace newline with space
149  /* TODO / FIXME possible bug - info lost */
150  *(p++) = ' ';
151  written++;
152  break;
153  case '"' : // Double quotes in string
154  *(p++) = '"';
155  written++;
156  *(p++) = '"';
157  written++;
158  break;
159  default: // Check if character is printable
160  if (isprint(*data)) {
161  *(p++) = *data;
162  written++;
163  }
164  }
165  data++;
166  }
167  *(p++) = '"';
168  written++;
169  } else if (type == UR_TYPE_BYTES) {
170  // Generic string of bytes - print each byte as two hex digits
171  int fs = ur_get_var_len(tmplt, rec, id);
172  unsigned char *data = ur_get_ptr_by_id(tmplt, rec, id);
173  while (fs-- && (written < size)) {
174  int w = snprintf(p, size, "%02x", *data++);
175  written += w;
176  p += w;
177  }
178  } else if (ur_is_varlen(id)) {
179  int elem_type = ur_array_get_elem_type(id);
180  int elem_size = ur_array_get_elem_size(id);
181  int elem_cnt = ur_array_get_elem_cnt(tmplt, rec, id);
182  int array_len = ur_get_len(tmplt, rec, id);
183  int i;
184 
185  if (written + 2 < size) {
186  written += 2;
187  *(p++) = '[';
188  for (i = 0; i < elem_cnt; i++) {
189  int w = urcsv_value(p, size - written, ((char *) ptr) + i * elem_size, elem_type, array_len);
190  written += w;
191  p += w;
192  if (written + 1 >= size) {
193  /* not enough space */
194  return 0;
195  }
196  if (i + 1 != elem_cnt) {
197  *(p++) = '|';
198  written++;
199  }
200  }
201  *(p++) = ']';
202  }
203  } else {
204  return urcsv_value(p, size, ptr, type, ur_get_len(tmplt, rec, id));
205  }
206 
207  return written;
208 }
209 
210 char *urcsv_record(urcsv_t *urcsv, const void *rec)
211 {
212  int delim = 0;
213  int i = 0, written = 0;
214  ur_field_id_t id = 0;
215 
216  if (urcsv == NULL || rec == NULL) {
217  return NULL;
218  }
219 
220  urcsv->curpos = urcsv->buffer;
221  urcsv->free_space = urcsv->buffer_size;
222 
223  // Iterate over all output fields
224  while ((id = ur_iter_fields_record_order(urcsv->tmplt, i++)) != UR_ITER_END) {
225  if (delim != 0) {
226  *(urcsv->curpos++) = urcsv->delimiter;
227  urcsv->free_space -= 1;
228  }
229 
230  delim = 1;
231  if (ur_is_present(urcsv->tmplt, id)) {
232  // check buffer and field size
233  size_t field_size = ur_get_len(urcsv->tmplt, rec, id);
234  if (field_size > urcsv->free_space) {
235  size_t size = urcsv->buffer_size / 2;
236  if (urcsv->free_space + size < field_size)
237  size = field_size;
238  urcsv->free_space += size;
239  urcsv->buffer_size += size;
240  uint32_t offset = urcsv->curpos - urcsv->buffer;
241  void *temp = realloc(urcsv->buffer, urcsv->buffer_size);
242  if (temp != NULL) {
243  urcsv->buffer = temp;
244  urcsv->curpos = urcsv->buffer + offset;
245  } else {
246  return NULL;
247  }
248  }
249  written = urcsv_field(urcsv->curpos, urcsv->free_space, rec, id, urcsv->tmplt);
250 
251  urcsv->free_space -= written;
252  urcsv->curpos += written;
253  } else {
254  continue;
255  }
256  } // loop over fields
257 
258  *urcsv->curpos = 0;
259  return strdup(urcsv->buffer);
260 }
261 
uint32_t buffer_size
Definition: unirec2csv.h:66
uint32_t free_space
Definition: unirec2csv.h:71
char delimiter
Definition: unirec2csv.h:76
char * curpos
Definition: unirec2csv.h:61
ur_template_t * tmplt
Definition: unirec2csv.h:51
char * buffer
Definition: unirec2csv.h:56
char * urcsv_header(urcsv_t *urcsv)
Definition: unirec2csv.c:37
void urcsv_free(urcsv_t **urcsv)
Definition: unirec2csv.c:28
char * urcsv_record(urcsv_t *urcsv, const void *rec)
Definition: unirec2csv.c:210
int urcsv_field(char *dst, uint32_t size, const void *rec, ur_field_type_t id, ur_template_t *tmplt)
Definition: unirec2csv.c:130
urcsv_t * urcsv_init(ur_template_t *tmplt, char delimiter)
Definition: unirec2csv.c:7
INLINE_IMPL void ip_to_str(const ip_addr_t *addr, char *str)
Definition: ipaddr.h:325
#define ur_is_varlen(field_id)
Is given field variable-length? Return true (non-zero value) if given ID refers to a field with varia...
Definition: unirec.h:646
#define ur_array_get_elem_type(field_id)
Get type of an element stored in an UniRec array.
Definition: unirec.h:555
ur_iter_t ur_iter_fields_record_order(const ur_template_t *tmplt, int index)
Iterate over fields of a template This function can be used to iterate over all fields of a given tem...
Definition: unirec.c:1312
#define ur_get_var_len(tmplt, rec, field_id)
Get size of a variable sized field in the record. Get size of a variable-length field in the record....
Definition: unirec.h:474
char * ur_template_string_delimiter(const ur_template_t *tmplt, int delimiter)
Get UniRec specifier of the tmplt template with delimiter between fields.
Definition: unirec.c:257
#define ur_array_get_elem_cnt(tmplt, rec, field_id)
Get number of elements stored in an UniRec array.
Definition: unirec.h:546
#define ur_array_get_elem_size(field_id)
Get size of a single element of UniRec field.
Definition: unirec.h:535
#define ur_get_len(tmplt, rec, field)
Get length of UniRec field Get actual length of fixed or variable-length UniRec field.
Definition: unirec.h:506
#define ur_get_type(field_id)
Get type of UniRec field Get type of any UniRec defined field.
Definition: unirec.h:388
#define ur_get_ptr_by_id(tmplt, data, field_id)
Get pointer to UniRec field Get pointer to fixed or varible length UniRec field. In contrast to ur_ge...
Definition: unirec.h:442
#define ur_is_present(tmplt, field_id)
Is given field present in given template? Return true (non-zero value) if given template contains fie...
Definition: unirec.h:638
#define ur_time_get_sec(time)
Get number of seconds from ur_time_t.
Definition: ur_time.h:124
#define ur_time_get_usec(time)
Get number of microeconds from ur_time_t.
Definition: ur_time.h:139
uint64_t ur_time_t
Type of timestamps used in UniRec Timestamps in UniRec are stored as number of seconds from Unix epoc...
Definition: ur_time.h:61
mac_addr_t
Definition: macaddr.h:75
#define MAC_STR_LEN
Definition: macaddr.h:57
int urcsv_value(char *dst, uint32_t size, void *ptr, int type, int field_len)
Definition: unirec2csv.c:45
Definition of UniRec API to create CSV-like representation of UniRec data.
INLINE_IMPL void mac_to_str(const mac_addr_t *addr, char *str)
Definition: macaddr.h:129
ur_field_type_t
Definition: unirec.h:95
@ UR_TYPE_UINT64
unsigned int (64b)
Definition: unirec.h:105
@ UR_TYPE_INT16
int (8b)
Definition: unirec.h:102
@ UR_TYPE_IP
IP address (128b)
Definition: unirec.h:109
@ UR_TYPE_INT8
int (8b)
Definition: unirec.h:100
@ UR_TYPE_CHAR
char
Definition: unirec.h:98
@ UR_TYPE_DOUBLE
double (64b)
Definition: unirec.h:108
@ UR_TYPE_TIME
time (64b)
Definition: unirec.h:111
@ UR_TYPE_UINT8
unsigned int (8b)
Definition: unirec.h:99
@ UR_TYPE_INT64
int (64b)
Definition: unirec.h:106
@ UR_TYPE_STRING
var-len fields (string where only printable characters are expected; '\0' at the end should NOT be in...
Definition: unirec.h:96
@ UR_TYPE_INT32
int (32b)
Definition: unirec.h:104
@ UR_TYPE_UINT16
unsigned int (16b)
Definition: unirec.h:101
@ UR_TYPE_UINT32
unsigned int (32b)
Definition: unirec.h:103
@ UR_TYPE_MAC
MAC address (48b)
Definition: unirec.h:110
@ UR_TYPE_BYTES
var-len fields (generic string of bytes)
Definition: unirec.h:97
@ UR_TYPE_FLOAT
float (32b)
Definition: unirec.h:107
int16_t ur_field_id_t
Type of UniRec field identifiers.
Definition: unirec.h:136
#define UR_ITER_END
Last value in iterating through the fields.
Definition: unirec.h:76
UniRec template. It contains a table mapping a field to its position in an UniRec record.
Definition: unirec.h:191