]>
git.proxmox.com Git - mirror_frr.git/blob - lib/csv.c
582106ebd429356cf98b6ff224c0f4e89dc6501a
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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <sys/queue.h>
38 #define log_error(fmt, ...) \
41 fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
42 __LINE__, __func__, ##__VA_ARGS__); \
45 #define log_verbose(fmt, ...) \
48 fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
49 __LINE__, __func__, __VA_ARGS__); \
52 struct _csv_field_t_
{
53 TAILQ_ENTRY(_csv_field_t_
) next_field
;
58 struct _csv_record_t_
{
59 TAILQ_HEAD(, _csv_field_t_
) fields
;
60 TAILQ_ENTRY(_csv_record_t_
) next_record
;
66 TAILQ_HEAD(, _csv_record_t_
) records
;
75 int csvlen(csv_t
*csv
)
77 return (csv
->csv_len
);
80 csv_t
*csv_init(csv_t
*csv
, char *buf
, int buflen
)
83 csv
= malloc(sizeof(csv_t
));
85 log_error("CSV Malloc failed\n");
89 memset(csv
, 0, sizeof(csv_t
));
93 TAILQ_INIT(&(csv
->records
));
97 void csv_clean(csv_t
*csv
)
102 rec
= TAILQ_FIRST(&(csv
->records
));
103 while (rec
!= NULL
) {
104 rec_n
= TAILQ_NEXT(rec
, next_record
);
105 csv_remove_record(csv
, rec
);
110 void csv_free(csv_t
*csv
)
117 static void csv_init_record(csv_record_t
*record
)
119 TAILQ_INIT(&(record
->fields
));
123 csv_record_t
*csv_record_iter(csv_t
*csv
)
125 return (TAILQ_FIRST(&(csv
->records
)));
128 csv_record_t
*csv_record_iter_next(csv_record_t
*rec
)
132 return (TAILQ_NEXT(rec
, next_record
));
135 char *csv_field_iter(csv_record_t
*rec
, csv_field_t
**fld
)
139 *fld
= TAILQ_FIRST(&(rec
->fields
));
140 return ((*fld
)->field
);
143 char *csv_field_iter_next(csv_field_t
**fld
)
145 *fld
= TAILQ_NEXT(*fld
, next_field
);
146 if ((*fld
) == NULL
) {
149 return ((*fld
)->field
);
152 int csv_field_len(csv_field_t
*fld
)
155 return fld
->field_len
;
160 static void csv_decode_record(csv_record_t
*rec
)
162 char *curr
= rec
->record
;
166 field
= strpbrk(curr
, ",");
167 while (field
!= NULL
) {
168 fld
= malloc(sizeof(csv_field_t
));
170 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
172 fld
->field_len
= field
- curr
;
175 field
= strpbrk(curr
, ",");
177 field
= strstr(curr
, "\n");
181 fld
= malloc(sizeof(csv_field_t
));
184 fld
->field_len
= field
- curr
;
185 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
189 static csv_field_t
*csv_add_field_to_record(csv_t
*csv
, csv_record_t
*rec
,
193 char *str
= rec
->record
;
194 int rlen
= rec
->rec_len
;
195 int blen
= csv
->buflen
;
197 fld
= malloc(sizeof(csv_field_t
));
199 log_error("field malloc failed\n");
200 /* more cleanup needed */
203 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
204 fld
->field
= str
+ rlen
;
205 fld
->field_len
= snprintf((str
+ rlen
), (blen
- rlen
), "%s", col
);
206 rlen
+= fld
->field_len
;
211 csv_record_t
*csv_encode(csv_t
*csv
, int count
, ...)
215 char *buf
= csv
->buf
;
216 int len
= csv
->buflen
;
217 int pointer
= csv
->pointer
;
226 /* allocate sufficient buffer */
227 str
= (char *)malloc(csv
->buflen
);
229 log_error("field str malloc failed\n");
234 va_start(list
, count
);
235 rec
= malloc(sizeof(csv_record_t
));
237 log_error("record malloc failed\n");
243 csv_init_record(rec
);
245 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
249 * Iterate through the fields passed as a variable list and add them
251 for (tempc
= 0; tempc
< count
; tempc
++) {
252 col
= va_arg(list
, char *);
253 fld
= csv_add_field_to_record(csv
, rec
, col
);
255 log_error("fld malloc failed\n");
256 csv_remove_record(csv
, rec
);
260 if (tempc
< (count
- 1)) {
261 rec
->rec_len
+= snprintf((str
+ rec
->rec_len
),
262 (len
- rec
->rec_len
), ",");
266 snprintf((str
+ rec
->rec_len
), (len
- rec
->rec_len
), "\n");
268 csv
->csv_len
+= rec
->rec_len
;
269 csv
->pointer
+= rec
->rec_len
;
273 int csv_num_records(csv_t
*csv
)
276 return csv
->num_recs
;
281 csv_record_t
*csv_encode_record(csv_t
*csv
, csv_record_t
*rec
, int count
, ...)
287 csv_field_t
*fld
= NULL
;
290 va_start(list
, count
);
291 str
= csv_field_iter(rec
, &fld
);
297 for (tempc
= 0; tempc
< count
; tempc
++) {
298 col
= va_arg(list
, char *);
299 for (i
= 0; i
< fld
->field_len
; i
++) {
302 str
= csv_field_iter_next(&fld
);
308 csv_record_t
*csv_append_record(csv_t
*csv
, csv_record_t
*rec
, int count
, ...)
312 int len
= csv
->buflen
, tlen
;
318 /* not only works with discrete bufs */
323 /* create a new rec */
324 rec
= calloc(1, sizeof(csv_record_t
));
326 log_error("record malloc failed\n");
329 csv_init_record(rec
);
330 rec
->record
= calloc(1, csv
->buflen
);
332 log_error("field str malloc failed\n");
336 csv_insert_record(csv
, rec
);
341 va_start(list
, count
);
343 if (rec
->rec_len
&& (str
[rec
->rec_len
- 1] == '\n'))
344 str
[rec
->rec_len
- 1] = ',';
347 * Iterate through the fields passed as a variable list and add them
350 for (tempc
= 0; tempc
< count
; tempc
++) {
351 col
= va_arg(list
, char *);
352 fld
= csv_add_field_to_record(csv
, rec
, col
);
354 log_error("fld malloc failed\n");
357 if (tempc
< (count
- 1)) {
358 rec
->rec_len
+= snprintf((str
+ rec
->rec_len
),
359 (len
- rec
->rec_len
), ",");
363 snprintf((str
+ rec
->rec_len
), (len
- rec
->rec_len
), "\n");
365 csv
->csv_len
+= (rec
->rec_len
- tlen
);
366 csv
->pointer
+= (rec
->rec_len
- tlen
);
370 int csv_serialize(csv_t
*csv
, char *msgbuf
, int msglen
)
378 rec
= csv_record_iter(csv
);
379 while (rec
!= NULL
) {
380 if ((offset
+ rec
->rec_len
) >= msglen
)
382 offset
+= sprintf(&msgbuf
[offset
], "%s", rec
->record
);
383 rec
= csv_record_iter_next(rec
);
389 void csv_clone_record(csv_t
*csv
, csv_record_t
*in_rec
, csv_record_t
**out_rec
)
394 /* first check if rec belongs to this csv */
395 if (!csv_is_record_valid(csv
, in_rec
)) {
396 log_error("rec not in this csv\n");
400 /* only works with csv with discrete bufs */
403 "un-supported for this csv type - single buf detected\n");
407 /* create a new rec */
408 rec
= calloc(1, sizeof(csv_record_t
));
410 log_error("record malloc failed\n");
413 csv_init_record(rec
);
414 curr
= calloc(1, csv
->buflen
);
416 log_error("field str malloc failed\n");
421 rec
->rec_len
= in_rec
->rec_len
;
422 strcpy(rec
->record
, in_rec
->record
);
424 /* decode record into fields */
425 csv_decode_record(rec
);
430 void csv_remove_record(csv_t
*csv
, csv_record_t
*rec
)
432 csv_field_t
*fld
= NULL
, *p_fld
;
434 /* first check if rec belongs to this csv */
435 if (!csv_is_record_valid(csv
, rec
)) {
436 log_error("rec not in this csv\n");
441 csv_field_iter(rec
, &fld
);
444 csv_field_iter_next(&fld
);
445 TAILQ_REMOVE(&(rec
->fields
), p_fld
, next_field
);
449 TAILQ_REMOVE(&(csv
->records
), rec
, next_record
);
452 csv
->csv_len
-= rec
->rec_len
;
453 csv
->pointer
-= rec
->rec_len
;
459 void csv_insert_record(csv_t
*csv
, csv_record_t
*rec
)
461 /* first check if rec already in csv */
462 if (csv_is_record_valid(csv
, rec
)) {
463 log_error("rec already in this csv\n");
467 /* we can only insert records if no buf was supplied during csv init */
470 "un-supported for this csv type - single buf detected\n");
474 /* do we go beyond the max buf set for this csv ?*/
475 if ((csv
->csv_len
+ rec
->rec_len
) > csv
->buflen
) {
476 log_error("cannot insert - exceeded buf size\n");
480 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
482 csv
->csv_len
+= rec
->rec_len
;
483 csv
->pointer
+= rec
->rec_len
;
486 csv_record_t
*csv_concat_record(csv_t
*csv
, csv_record_t
*rec1
,
493 /* first check if rec1 and rec2 belong to this csv */
494 if (!csv_is_record_valid(csv
, rec1
)
495 || !csv_is_record_valid(csv
, rec2
)) {
496 log_error("rec1 and/or rec2 invalid\n");
500 /* we can only concat records if no buf was supplied during csv init */
503 "un-supported for this csv type - single buf detected\n");
507 /* create a new rec */
508 rec
= calloc(1, sizeof(csv_record_t
));
510 log_error("record malloc failed\n");
513 csv_init_record(rec
);
515 curr
= (char *)calloc(1, csv
->buflen
);
517 log_error("field str malloc failed\n");
522 /* concat the record string */
523 ret
= strstr(rec1
->record
, "\n");
525 log_error("rec1 str not properly formatted\n");
529 snprintf(curr
, (int)(ret
- rec1
->record
+ 1), "%s", rec1
->record
);
532 ret
= strstr(rec2
->record
, "\n");
534 log_error("rec2 str not properly formatted\n");
538 snprintf((curr
+ strlen(curr
)), (int)(ret
- rec2
->record
+ 1), "%s",
541 rec
->rec_len
= strlen(curr
);
545 > (csv
->csv_len
- rec1
->rec_len
- rec2
->rec_len
+ rec
->rec_len
));
547 /* decode record into fields */
548 csv_decode_record(rec
);
550 /* now remove rec1 and rec2 and insert rec into this csv */
551 csv_remove_record(csv
, rec1
);
552 csv_remove_record(csv
, rec2
);
553 csv_insert_record(csv
, rec
);
564 void csv_decode(csv_t
*csv
, char *inbuf
)
570 buf
= (inbuf
) ? inbuf
: csv
->buf
;
573 pos
= strpbrk(buf
, "\n");
574 while (pos
!= NULL
) {
575 rec
= calloc(1, sizeof(csv_record_t
));
578 csv_init_record(rec
);
579 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
584 rec
->record
= calloc(1, csv
->buflen
);
586 log_error("field str malloc failed\n");
589 strncpy(rec
->record
, buf
, pos
- buf
+ 1);
591 rec
->rec_len
= pos
- buf
+ 1;
592 /* decode record into fields */
593 csv_decode_record(rec
);
595 pos
= strpbrk(buf
, "\n");
599 int csv_is_record_valid(csv_t
*csv
, csv_record_t
*in_rec
)
604 rec
= csv_record_iter(csv
);
610 rec
= csv_record_iter_next(rec
);
616 void csv_dump(csv_t
*csv
)
622 rec
= csv_record_iter(csv
);
623 while (rec
!= NULL
) {
624 str
= csv_field_iter(rec
, &fld
);
625 while (str
!= NULL
) {
626 fprintf(stderr
, "%s\n", str
);
627 str
= csv_field_iter_next(&fld
);
629 rec
= csv_record_iter_next(rec
);
635 static int get_memory_usage(pid_t pid
)
638 char buf
[4096], status_child
[BUFSIZ
];
641 sprintf(status_child
, "/proc/%d/status", pid
);
642 if ((fd
= open(status_child
, O_RDONLY
)) < 0)
651 vm
= strstr(buf
, "VmData:");
653 sscanf(vm
, "%*s %d", &data
);
655 vm
= strstr(buf
, "VmStk:");
657 sscanf(vm
, "%*s %d", &stack
);
669 char hdr1
[32], hdr2
[32];
671 log_verbose("Mem: %d\n", get_memory_usage(getpid()));
672 csv_init(&csv
, buf
, 256);
673 sprintf(hdr1
, "%4d", 0);
674 sprintf(hdr2
, "%4d", 1);
675 log_verbose("(%zu/%zu/%d/%d)\n", strlen(hdr1
), strlen(hdr2
), atoi(hdr1
),
677 rec
= csv_encode(&csv
, 2, hdr1
, hdr2
);
678 csv_encode(&csv
, 4, "name", "age", "sex", "hei");
679 csv_encode(&csv
, 3, NULL
, "0", NULL
);
680 csv_encode(&csv
, 2, "p", "35");
681 for (i
= 0; i
< 50; i
++) {
682 csv_encode(&csv
, 2, "p", "10");
684 csv_encode(&csv
, 2, "pdfadfadfadsadsaddfdfdsfdsd", "35444554545454545");
685 log_verbose("%s\n", buf
);
686 sprintf(hdr1
, "%4d", csv
.csv_len
);
687 sprintf(hdr2
, "%4d", 1);
688 log_verbose("(%zu/%zu/%d/%d)\n", strlen(hdr1
), strlen(hdr2
), atoi(hdr1
),
690 rec
= csv_encode_record(&csv
, rec
, 2, hdr1
, hdr2
);
691 log_verbose("(%d/%d)\n%s\n", rec
->rec_len
, csv
.csv_len
, buf
);
693 log_verbose("Mem: %d\n", get_memory_usage(getpid()));
695 log_verbose("Mem: %d\n", get_memory_usage(getpid()));
696 csv_init(&csv
, buf
, 256);
697 csv_decode(&csv
, NULL
);
698 log_verbose("%s", "AFTER DECODE\n");
701 log_verbose("Mem: %d\n", get_memory_usage(getpid()));