]>
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 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
25 #include <sys/queue.h>
33 #define log_error(fmt, ...) \
34 do { if (DEBUG_E) fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
35 __LINE__, __func__, ##__VA_ARGS__); } while (0)
37 #define log_verbose(fmt, ...) \
38 do { if (DEBUG_V) fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \
39 __LINE__, __func__, __VA_ARGS__); } while (0)
41 struct _csv_field_t_
{
42 TAILQ_ENTRY(_csv_field_t_
) next_field
;
47 struct _csv_record_t_
{
48 TAILQ_HEAD(, _csv_field_t_
) fields
;
49 TAILQ_ENTRY(_csv_record_t_
) next_record
;
55 TAILQ_HEAD(, _csv_record_t_
) records
;
67 return (csv
->csv_len
);
76 csv
= malloc(sizeof(csv_t
));
78 log_error("CSV Malloc failed\n");
82 memset(csv
, 0, sizeof(csv_t
));
86 TAILQ_INIT(&(csv
->records
));
91 csv_clean (csv_t
*csv
)
96 rec
= TAILQ_FIRST(&(csv
->records
));
98 rec_n
= TAILQ_NEXT(rec
, next_record
);
99 csv_remove_record(csv
, rec
);
105 csv_free (csv_t
*csv
)
113 csv_init_record (csv_record_t
*record
)
115 TAILQ_INIT(&(record
->fields
));
120 csv_record_iter (csv_t
*csv
)
122 return(TAILQ_FIRST(&(csv
->records
)));
126 csv_record_iter_next (csv_record_t
*rec
)
128 if(!rec
) return NULL
;
129 return(TAILQ_NEXT(rec
, next_record
));
133 csv_field_iter (csv_record_t
*rec
,
136 if(!rec
) return NULL
;
137 *fld
= TAILQ_FIRST(&(rec
->fields
));
138 return ((*fld
)->field
);
142 csv_field_iter_next (csv_field_t
**fld
)
144 *fld
= TAILQ_NEXT(*fld
, next_field
);
145 if ((*fld
) == NULL
) {
148 return ((*fld
)->field
);
152 csv_field_len(csv_field_t
*fld
)
155 return fld
->field_len
;
161 csv_decode_record(csv_record_t
*rec
)
163 char *curr
= rec
->record
;
167 field
= strpbrk(curr
, ",");
168 while (field
!= NULL
) {
169 fld
= malloc(sizeof(csv_field_t
));
171 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
173 fld
->field_len
= field
-curr
;
176 field
= strpbrk(curr
, ",");
178 field
= strstr(curr
, "\n");
182 fld
= malloc(sizeof(csv_field_t
));
185 fld
->field_len
= field
-curr
;
186 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
191 csv_add_field_to_record(csv_t
*csv
,
196 char *str
= rec
->record
;
197 int rlen
= rec
->rec_len
;
198 int blen
= csv
->buflen
;
200 fld
= malloc(sizeof(csv_field_t
));
202 log_error("field malloc failed\n");
203 /* more cleanup needed */
206 TAILQ_INSERT_TAIL(&(rec
->fields
), fld
, next_field
);
207 fld
->field
= str
+rlen
;
208 fld
->field_len
= snprintf((str
+rlen
), (blen
- rlen
), "%s", col
);
209 rlen
+= fld
->field_len
;
215 csv_encode (csv_t
*csv
,
221 char *buf
= csv
->buf
;
222 int len
= csv
->buflen
;
223 int pointer
= csv
->pointer
;
232 /* allocate sufficient buffer */
233 str
= (char *)malloc(csv
->buflen
);
235 log_error("field str malloc failed\n");
240 va_start(list
, count
);
241 rec
= malloc(sizeof(csv_record_t
));
243 log_error("record malloc failed\n");
249 csv_init_record(rec
);
251 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
255 * Iterate through the fields passed as a variable list and add them
257 for (tempc
= 0; tempc
< count
; tempc
++) {
258 col
= va_arg(list
, char *);
259 fld
= csv_add_field_to_record(csv
, rec
, col
);
261 log_error("fld malloc failed\n");
262 csv_remove_record(csv
, rec
);
266 if (tempc
< (count
- 1)) {
267 rec
->rec_len
+= snprintf((str
+rec
->rec_len
), (len
- rec
->rec_len
), ",");
270 rec
->rec_len
+= snprintf((str
+rec
->rec_len
), (len
- rec
->rec_len
), "\n");
272 csv
->csv_len
+= rec
->rec_len
;
273 csv
->pointer
+= rec
->rec_len
;
278 csv_num_records (csv_t
*csv
)
281 return csv
->num_recs
;
287 csv_encode_record (csv_t
*csv
,
296 csv_field_t
*fld
= NULL
;
299 va_start(list
, count
);
300 str
= csv_field_iter(rec
, &fld
);
301 for (tempc
= 0; tempc
< count
; tempc
++) {
302 col
= va_arg(list
, char *);
303 for (i
= 0; i
< fld
->field_len
; i
++) {
306 str
= csv_field_iter_next(&fld
);
313 csv_append_record (csv_t
*csv
,
320 int len
= csv
->buflen
, tlen
;
326 /* not only works with discrete bufs */
331 /* create a new rec */
332 rec
= calloc(1, sizeof(csv_record_t
));
334 log_error("record malloc failed\n");
337 csv_init_record(rec
);
338 rec
->record
= calloc(1, csv
->buflen
);
340 log_error("field str malloc failed\n");
344 csv_insert_record(csv
, rec
);
349 va_start(list
, count
);
351 if (rec
->rec_len
&& (str
[rec
->rec_len
-1] == '\n'))
352 str
[rec
->rec_len
-1] = ',';
355 * Iterate through the fields passed as a variable list and add them
358 for (tempc
= 0; tempc
< count
; tempc
++) {
359 col
= va_arg(list
, char *);
360 fld
= csv_add_field_to_record(csv
, rec
, col
);
362 log_error("fld malloc failed\n");
365 if (tempc
< (count
- 1)) {
366 rec
->rec_len
+= snprintf((str
+rec
->rec_len
),
367 (len
- rec
->rec_len
), ",");
370 rec
->rec_len
+= snprintf((str
+rec
->rec_len
),
371 (len
- rec
->rec_len
), "\n");
373 csv
->csv_len
+= (rec
->rec_len
- tlen
);
374 csv
->pointer
+= (rec
->rec_len
- tlen
);
379 csv_serialize(csv_t
*csv
, char *msgbuf
, int msglen
)
384 if (!csv
|| !msgbuf
) return -1;
386 rec
= csv_record_iter(csv
);
387 while (rec
!= NULL
) {
388 if ((offset
+ rec
->rec_len
) >= msglen
)
390 offset
+= sprintf(&msgbuf
[offset
], "%s", rec
->record
);
391 rec
= csv_record_iter_next(rec
);
398 csv_clone_record (csv_t
*csv
, csv_record_t
*in_rec
, csv_record_t
**out_rec
)
403 /* first check if rec belongs to this csv */
404 if(!csv_is_record_valid(csv
, in_rec
)){
405 log_error("rec not in this csv\n");
409 /* only works with csv with discrete bufs */
411 log_error("un-supported for this csv type - single buf detected\n");
415 /* create a new rec */
416 rec
= calloc(1, sizeof(csv_record_t
));
418 log_error("record malloc failed\n");
421 csv_init_record(rec
);
422 curr
= calloc(1, csv
->buflen
);
424 log_error("field str malloc failed\n");
429 rec
->rec_len
= in_rec
->rec_len
;
430 strcpy(rec
->record
, in_rec
->record
);
432 /* decode record into fields */
433 csv_decode_record(rec
);
439 csv_remove_record (csv_t
*csv
, csv_record_t
*rec
)
441 csv_field_t
*fld
, *p_fld
;
443 /* first check if rec belongs to this csv */
444 if(!csv_is_record_valid(csv
, rec
)){
445 log_error("rec not in this csv\n");
450 csv_field_iter(rec
, &fld
);
453 csv_field_iter_next(&fld
);
454 TAILQ_REMOVE(&(rec
->fields
), p_fld
, next_field
);
458 TAILQ_REMOVE(&(csv
->records
), rec
, next_record
);
461 csv
->csv_len
-= rec
->rec_len
;
462 csv
->pointer
-= rec
->rec_len
;
469 csv_insert_record (csv_t
*csv
, csv_record_t
*rec
)
471 /* first check if rec already in csv */
472 if(csv_is_record_valid(csv
, rec
)){
473 log_error("rec already in this csv\n");
477 /* we can only insert records if no buf was supplied during csv init */
479 log_error("un-supported for this csv type - single buf detected\n");
483 /* do we go beyond the max buf set for this csv ?*/
484 if ((csv
->csv_len
+ rec
->rec_len
) > csv
->buflen
) {
485 log_error("cannot insert - exceeded buf size\n");
489 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
491 csv
->csv_len
+= rec
->rec_len
;
492 csv
->pointer
+= rec
->rec_len
;
496 csv_concat_record (csv_t
*csv
,
504 /* first check if rec1 and rec2 belong to this csv */
505 if(!csv_is_record_valid(csv
, rec1
) ||
506 !csv_is_record_valid(csv
, rec2
)) {
507 log_error("rec1 and/or rec2 invalid\n");
511 /* we can only concat records if no buf was supplied during csv init */
513 log_error("un-supported for this csv type - single buf detected\n");
517 /* create a new rec */
518 rec
= calloc(1, sizeof(csv_record_t
));
520 log_error("record malloc failed\n");
523 csv_init_record(rec
);
525 curr
= (char *)calloc(1, csv
->buflen
);
527 log_error("field str malloc failed\n");
532 /* concat the record string */
533 ret
= strstr(rec1
->record
, "\n");
535 log_error("rec1 str not properly formatted\n");
539 snprintf(curr
, (int)(ret
- rec1
->record
+ 1), "%s", rec1
->record
);
542 ret
= strstr(rec2
->record
, "\n");
544 log_error("rec2 str not properly formatted\n");
548 snprintf((curr
+strlen(curr
)), (int)(ret
- rec2
->record
+ 1), "%s",
551 rec
->rec_len
= strlen(curr
);
555 (csv
->csv_len
- rec1
->rec_len
- rec2
->rec_len
+ rec
->rec_len
));
557 /* decode record into fields */
558 csv_decode_record(rec
);
560 /* now remove rec1 and rec2 and insert rec into this csv */
561 csv_remove_record(csv
, rec1
);
562 csv_remove_record(csv
, rec2
);
563 csv_insert_record(csv
, rec
);
575 csv_decode (csv_t
*csv
, char *inbuf
)
581 buf
= (inbuf
)? inbuf
:csv
->buf
;
582 pos
= strpbrk(buf
, "\n");
583 while (pos
!= NULL
) {
584 rec
= calloc(1, sizeof(csv_record_t
));
587 csv_init_record(rec
);
588 TAILQ_INSERT_TAIL(&(csv
->records
), rec
, next_record
);
593 rec
->record
= calloc(1, csv
->buflen
);
595 log_error("field str malloc failed\n");
598 strncpy(rec
->record
, buf
, pos
-buf
+1);
600 rec
->rec_len
= pos
-buf
+1;
601 /* decode record into fields */
602 csv_decode_record(rec
);
604 pos
= strpbrk(buf
, "\n");
609 csv_is_record_valid(csv_t
*csv
, csv_record_t
*in_rec
)
614 rec
= csv_record_iter(csv
);
620 rec
= csv_record_iter_next(rec
);
627 csv_dump (csv_t
*csv
)
633 rec
= csv_record_iter(csv
);
634 while (rec
!= NULL
) {
635 str
= csv_field_iter(rec
, &fld
);
636 while (str
!= NULL
) {
637 fprintf(stderr
, "%s\n", str
);
638 str
= csv_field_iter_next(&fld
);
640 rec
= csv_record_iter_next(rec
);
647 get_memory_usage (pid_t pid
)
650 char buf
[4096], status_child
[BUFSIZ
];
653 sprintf(status_child
, "/proc/%d/status", pid
);
654 if ((fd
= open(status_child
, O_RDONLY
)) < 0)
663 vm
= strstr(buf
, "VmData:");
665 sscanf(vm
, "%*s %d", &data
);
667 vm
= strstr(buf
, "VmStk:");
669 sscanf(vm
, "%*s %d", &stack
);
684 char hdr1
[32], hdr2
[32];
686 log_verbose("Mem: %ld\n", get_memory_usage(getpid()));
687 csv_init(&csv
, buf
, 256);
688 sprintf(hdr1
, "%4u", 0);
689 sprintf(hdr2
, "%4u", 1);
690 log_verbose("(%d/%d/%d/%d)\n", strlen(hdr1
),
691 strlen(hdr2
), atoi(hdr1
), atoi(hdr2
));
692 rec
= csv_encode(&csv
, 2, hdr1
, hdr2
);
693 csv_encode(&csv
, 4, "name", "age", "sex", "hei");
694 csv_encode(&csv
, 3, NULL
, "0", NULL
);
695 csv_encode(&csv
, 2, "p", "35");
696 for (i
=0; i
< 50; i
++) {
697 csv_encode(&csv
, 2, "p", "10");
699 csv_encode(&csv
, 2, "pdfadfadfadsadsaddfdfdsfdsd",
700 "35444554545454545");
701 log_verbose("%s\n", buf
);
702 sprintf(hdr1
, "%4u", csv
.csv_len
);
703 sprintf(hdr2
, "%4u", 1);
704 log_verbose("(%d/%d/%d/%d)\n", strlen(hdr1
),
705 strlen(hdr2
), atoi(hdr1
), atoi(hdr2
));
706 rec
= csv_encode_record(&csv
, rec
, 2, hdr1
, hdr2
);
707 log_verbose("(%d/%d)\n%s\n", rec
->rec_len
, csv
.csv_len
, buf
);
709 log_verbose("Mem: %ld\n", get_memory_usage(getpid()));
711 log_verbose("Mem: %ld\n", get_memory_usage(getpid()));
712 csv_init(&csv
, buf
, 256);
713 csv_decode(&csv
, NULL
);
714 log_verbose("AFTER DECODE\n");
717 log_verbose("Mem: %ld\n", get_memory_usage(getpid()));