]>
git.proxmox.com Git - mirror_frr.git/blob - lib/csv.c
2 * Copyright (C) 2013 Cumulus Networks, Inc.
4 * This file is part of Quagga.
6 * Quagga is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * Quagga is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Quagga; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26 #include <sys/queue.h>
34 #define log_error(fmt, ...) \
37 fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
38 __LINE__, __func__, ##__VA_ARGS__); \
41 #define log_verbose(fmt, ...) \
44 fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
45 __LINE__, __func__, __VA_ARGS__); \
48 struct _csv_field_t_
{
49 TAILQ_ENTRY(_csv_field_t_
) next_field
;
54 struct _csv_record_t_
{
55 TAILQ_HEAD(, _csv_field_t_
) fields
;
56 TAILQ_ENTRY(_csv_record_t_
) next_record
;
62 TAILQ_HEAD(, _csv_record_t_
) records
;
71 int csvlen(csv_t
*csv
)
73 return (csv
->csv_len
);
76 csv_t
*csv_init(csv_t
*csv
, char *buf
, int buflen
)
79 csv
= malloc(sizeof(csv_t
));
81 log_error("CSV Malloc failed\n");
85 memset(csv
, 0, sizeof(csv_t
));
89 TAILQ_INIT(&(csv
->records
));
93 void csv_clean(csv_t
*csv
)
98 rec
= TAILQ_FIRST(&(csv
->records
));
100 rec_n
= TAILQ_NEXT(rec
, next_record
);
101 csv_remove_record(csv
, rec
);
106 void csv_free(csv_t
*csv
)
113 static void csv_init_record(csv_record_t
*record
)
115 TAILQ_INIT(&(record
->fields
));
119 csv_record_t
*csv_record_iter(csv_t
*csv
)
121 return (TAILQ_FIRST(&(csv
->records
)));
124 csv_record_t
*csv_record_iter_next(csv_record_t
*rec
)
128 return (TAILQ_NEXT(rec
, next_record
));
131 char *csv_field_iter(csv_record_t
*rec
, csv_field_t
**fld
)
135 *fld
= TAILQ_FIRST(&(rec
->fields
));
136 return ((*fld
)->field
);
139 char *csv_field_iter_next(csv_field_t
**fld
)
141 *fld
= TAILQ_NEXT(*fld
, next_field
);
142 if ((*fld
) == NULL
) {
145 return ((*fld
)->field
);
148 int csv_field_len(csv_field_t
*fld
)
151 return fld
->field_len
;
156 static void csv_decode_record(csv_record_t
*rec
)
158 char *curr
= rec
->record
;
162 field
= strpbrk(curr
, ",");
163 while (field
!= NULL
) {
164 fld
= malloc(sizeof(csv_field_t
));
166 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
168 fld
->field_len
= field
- curr
;
171 field
= strpbrk(curr
, ",");
173 field
= strstr(curr
, "\n");
177 fld
= malloc(sizeof(csv_field_t
));
180 fld
->field_len
= field
- curr
;
181 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
185 static csv_field_t
*csv_add_field_to_record(csv_t
*csv
, csv_record_t
*rec
,
189 char *str
= rec
->record
;
190 int rlen
= rec
->rec_len
;
191 int blen
= csv
->buflen
;
193 fld
= malloc(sizeof(csv_field_t
));
195 log_error("field malloc failed\n");
196 /* more cleanup needed */
199 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
200 fld
->field
= str
+ rlen
;
201 fld
->field_len
= snprintf((str
+ rlen
), (blen
- rlen
), "%s", col
);
202 rlen
+= fld
->field_len
;
207 csv_record_t
*csv_encode(csv_t
*csv
, int count
, ...)
211 char *buf
= csv
->buf
;
212 int len
= csv
->buflen
;
213 int pointer
= csv
->pointer
;
222 /* allocate sufficient buffer */
223 str
= (char *)malloc(csv
->buflen
);
225 log_error("field str malloc failed\n");
230 va_start(list
, count
);
231 rec
= malloc(sizeof(csv_record_t
));
233 log_error("record malloc failed\n");
239 csv_init_record(rec
);
241 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
245 * Iterate through the fields passed as a variable list and add them
247 for (tempc
= 0; tempc
< count
; tempc
++) {
248 col
= va_arg(list
, char *);
249 fld
= csv_add_field_to_record(csv
, rec
, col
);
251 log_error("fld malloc failed\n");
252 csv_remove_record(csv
, rec
);
256 if (tempc
< (count
- 1)) {
257 rec
->rec_len
+= snprintf((str
+ rec
->rec_len
),
258 (len
- rec
->rec_len
), ",");
262 snprintf((str
+ rec
->rec_len
), (len
- rec
->rec_len
), "\n");
264 csv
->csv_len
+= rec
->rec_len
;
265 csv
->pointer
+= rec
->rec_len
;
269 int csv_num_records(csv_t
*csv
)
272 return csv
->num_recs
;
277 csv_record_t
*csv_encode_record(csv_t
*csv
, csv_record_t
*rec
, int count
, ...)
283 csv_field_t
*fld
= NULL
;
286 va_start(list
, count
);
287 str
= csv_field_iter(rec
, &fld
);
288 for (tempc
= 0; tempc
< count
; tempc
++) {
289 col
= va_arg(list
, char *);
290 for (i
= 0; i
< fld
->field_len
; i
++) {
293 str
= csv_field_iter_next(&fld
);
299 csv_record_t
*csv_append_record(csv_t
*csv
, csv_record_t
*rec
, int count
, ...)
303 int len
= csv
->buflen
, tlen
;
309 /* not only works with discrete bufs */
314 /* create a new rec */
315 rec
= calloc(1, sizeof(csv_record_t
));
317 log_error("record malloc failed\n");
320 csv_init_record(rec
);
321 rec
->record
= calloc(1, csv
->buflen
);
323 log_error("field str malloc failed\n");
327 csv_insert_record(csv
, rec
);
332 va_start(list
, count
);
334 if (rec
->rec_len
&& (str
[rec
->rec_len
- 1] == '\n'))
335 str
[rec
->rec_len
- 1] = ',';
338 * Iterate through the fields passed as a variable list and add them
341 for (tempc
= 0; tempc
< count
; tempc
++) {
342 col
= va_arg(list
, char *);
343 fld
= csv_add_field_to_record(csv
, rec
, col
);
345 log_error("fld malloc failed\n");
348 if (tempc
< (count
- 1)) {
349 rec
->rec_len
+= snprintf((str
+ rec
->rec_len
),
350 (len
- rec
->rec_len
), ",");
354 snprintf((str
+ rec
->rec_len
), (len
- rec
->rec_len
), "\n");
356 csv
->csv_len
+= (rec
->rec_len
- tlen
);
357 csv
->pointer
+= (rec
->rec_len
- tlen
);
361 int csv_serialize(csv_t
*csv
, char *msgbuf
, int msglen
)
369 rec
= csv_record_iter(csv
);
370 while (rec
!= NULL
) {
371 if ((offset
+ rec
->rec_len
) >= msglen
)
373 offset
+= sprintf(&msgbuf
[offset
], "%s", rec
->record
);
374 rec
= csv_record_iter_next(rec
);
380 void csv_clone_record(csv_t
*csv
, csv_record_t
*in_rec
, csv_record_t
**out_rec
)
385 /* first check if rec belongs to this csv */
386 if (!csv_is_record_valid(csv
, in_rec
)) {
387 log_error("rec not in this csv\n");
391 /* only works with csv with discrete bufs */
394 "un-supported for this csv type - single buf detected\n");
398 /* create a new rec */
399 rec
= calloc(1, sizeof(csv_record_t
));
401 log_error("record malloc failed\n");
404 csv_init_record(rec
);
405 curr
= calloc(1, csv
->buflen
);
407 log_error("field str malloc failed\n");
412 rec
->rec_len
= in_rec
->rec_len
;
413 strcpy(rec
->record
, in_rec
->record
);
415 /* decode record into fields */
416 csv_decode_record(rec
);
421 void csv_remove_record(csv_t
*csv
, csv_record_t
*rec
)
423 csv_field_t
*fld
, *p_fld
;
425 /* first check if rec belongs to this csv */
426 if (!csv_is_record_valid(csv
, rec
)) {
427 log_error("rec not in this csv\n");
432 csv_field_iter(rec
, &fld
);
435 csv_field_iter_next(&fld
);
436 TAILQ_REMOVE(&(rec
->fields
), p_fld
, next_field
);
440 TAILQ_REMOVE(&(csv
->records
), rec
, next_record
);
443 csv
->csv_len
-= rec
->rec_len
;
444 csv
->pointer
-= rec
->rec_len
;
450 void csv_insert_record(csv_t
*csv
, csv_record_t
*rec
)
452 /* first check if rec already in csv */
453 if (csv_is_record_valid(csv
, rec
)) {
454 log_error("rec already in this csv\n");
458 /* we can only insert records if no buf was supplied during csv init */
461 "un-supported for this csv type - single buf detected\n");
465 /* do we go beyond the max buf set for this csv ?*/
466 if ((csv
->csv_len
+ rec
->rec_len
) > csv
->buflen
) {
467 log_error("cannot insert - exceeded buf size\n");
471 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
473 csv
->csv_len
+= rec
->rec_len
;
474 csv
->pointer
+= rec
->rec_len
;
477 csv_record_t
*csv_concat_record(csv_t
*csv
, csv_record_t
*rec1
,
484 /* first check if rec1 and rec2 belong to this csv */
485 if (!csv_is_record_valid(csv
, rec1
)
486 || !csv_is_record_valid(csv
, rec2
)) {
487 log_error("rec1 and/or rec2 invalid\n");
491 /* we can only concat records if no buf was supplied during csv init */
494 "un-supported for this csv type - single buf detected\n");
498 /* create a new rec */
499 rec
= calloc(1, sizeof(csv_record_t
));
501 log_error("record malloc failed\n");
504 csv_init_record(rec
);
506 curr
= (char *)calloc(1, csv
->buflen
);
508 log_error("field str malloc failed\n");
513 /* concat the record string */
514 ret
= strstr(rec1
->record
, "\n");
516 log_error("rec1 str not properly formatted\n");
520 snprintf(curr
, (int)(ret
- rec1
->record
+ 1), "%s", rec1
->record
);
523 ret
= strstr(rec2
->record
, "\n");
525 log_error("rec2 str not properly formatted\n");
529 snprintf((curr
+ strlen(curr
)), (int)(ret
- rec2
->record
+ 1), "%s",
532 rec
->rec_len
= strlen(curr
);
536 > (csv
->csv_len
- rec1
->rec_len
- rec2
->rec_len
+ rec
->rec_len
));
538 /* decode record into fields */
539 csv_decode_record(rec
);
541 /* now remove rec1 and rec2 and insert rec into this csv */
542 csv_remove_record(csv
, rec1
);
543 csv_remove_record(csv
, rec2
);
544 csv_insert_record(csv
, rec
);
555 void csv_decode(csv_t
*csv
, char *inbuf
)
561 buf
= (inbuf
) ? inbuf
: csv
->buf
;
562 pos
= strpbrk(buf
, "\n");
563 while (pos
!= NULL
) {
564 rec
= calloc(1, sizeof(csv_record_t
));
567 csv_init_record(rec
);
568 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
573 rec
->record
= calloc(1, csv
->buflen
);
575 log_error("field str malloc failed\n");
578 strncpy(rec
->record
, buf
, pos
- buf
+ 1);
580 rec
->rec_len
= pos
- buf
+ 1;
581 /* decode record into fields */
582 csv_decode_record(rec
);
584 pos
= strpbrk(buf
, "\n");
588 int csv_is_record_valid(csv_t
*csv
, csv_record_t
*in_rec
)
593 rec
= csv_record_iter(csv
);
599 rec
= csv_record_iter_next(rec
);
605 void csv_dump(csv_t
*csv
)
611 rec
= csv_record_iter(csv
);
612 while (rec
!= NULL
) {
613 str
= csv_field_iter(rec
, &fld
);
614 while (str
!= NULL
) {
615 fprintf(stderr
, "%s\n", str
);
616 str
= csv_field_iter_next(&fld
);
618 rec
= csv_record_iter_next(rec
);
624 static int get_memory_usage(pid_t pid
)
627 char buf
[4096], status_child
[BUFSIZ
];
630 sprintf(status_child
, "/proc/%d/status", pid
);
631 if ((fd
= open(status_child
, O_RDONLY
)) < 0)
640 vm
= strstr(buf
, "VmData:");
642 sscanf(vm
, "%*s %d", &data
);
644 vm
= strstr(buf
, "VmStk:");
646 sscanf(vm
, "%*s %d", &stack
);
661 char hdr1
[32], hdr2
[32];
663 log_verbose("Mem: %ld\n", get_memory_usage(getpid()));
664 csv_init(&csv
, buf
, 256);
665 sprintf(hdr1
, "%4u", 0);
666 sprintf(hdr2
, "%4u", 1);
667 log_verbose("(%d/%d/%d/%d)\n", strlen(hdr1
), strlen(hdr2
), atoi(hdr1
),
669 rec
= csv_encode(&csv
, 2, hdr1
, hdr2
);
670 csv_encode(&csv
, 4, "name", "age", "sex", "hei");
671 csv_encode(&csv
, 3, NULL
, "0", NULL
);
672 csv_encode(&csv
, 2, "p", "35");
673 for (i
= 0; i
< 50; i
++) {
674 csv_encode(&csv
, 2, "p", "10");
676 csv_encode(&csv
, 2, "pdfadfadfadsadsaddfdfdsfdsd", "35444554545454545");
677 log_verbose("%s\n", buf
);
678 sprintf(hdr1
, "%4u", csv
.csv_len
);
679 sprintf(hdr2
, "%4u", 1);
680 log_verbose("(%d/%d/%d/%d)\n", strlen(hdr1
), strlen(hdr2
), atoi(hdr1
),
682 rec
= csv_encode_record(&csv
, rec
, 2, hdr1
, hdr2
);
683 log_verbose("(%d/%d)\n%s\n", rec
->rec_len
, csv
.csv_len
, buf
);
685 log_verbose("Mem: %ld\n", get_memory_usage(getpid()));
687 log_verbose("Mem: %ld\n", get_memory_usage(getpid()));
688 csv_init(&csv
, buf
, 256);
689 csv_decode(&csv
, NULL
);
690 log_verbose("AFTER DECODE\n");
693 log_verbose("Mem: %ld\n", get_memory_usage(getpid()));