1 /*
2 ***** BEGIN LICENSE BLOCK *****
3
4 Copyright (C) 2001-2020 Olof Hagsand
5
6 This file is part of CLIgen.
7
8 Licensed under the Apache License, Version 2.0 (the "License");
9 you may not use this file except in compliance with the License.
10 You may obtain a copy of the License at
11
12 http://www.apache.org/licenses/LICENSE-2.0
13
14 Unless required by applicable law or agreed to in writing, software
15 distributed under the License is distributed on an "AS IS" BASIS,
16 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 See the License for the specific language governing permissions and
18 limitations under the License.
19
20 Alternatively, the contents of this file may be used under the terms of
21 the GNU General Public License Version 2 or later (the "GPL"),
22 in which case the provisions of the GPL are applicable instead
23 of those above. If you wish to allow use of your version of this file only
24 under the terms of the GPL, and not to allow others to
25 use your version of this file under the terms of Apache License version 2, indicate
26 your decision by deleting the provisions above and replace them with the
27 notice and other provisions required by the GPL. If you do not delete
28 the provisions above, a recipient may use your version of this file under
29 the terms of any one of the Apache License version 2 or the GPL.
30
31 ***** END LICENSE BLOCK *****
32
33
34 CLIgen variables - cgv
35 cgv:s are created when parsing an input string as instances of cg_obj variable
36 when matching.
37 Note that a cg_obj is a syntax object and contains a part that specifies cgv:s called cov
38 */
39 #include "cligen_config.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdint.h>
44 #include <limits.h>
45 #include <inttypes.h>
46 #include <unistd.h>
47 #include <ctype.h>
48 #include <sys/types.h>
49 #include <time.h>
50 #include <sys/time.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <assert.h>
55 #include <string.h>
56 #include <errno.h>
57
58 #include "cligen_buf.h"
59 #include "cligen_cv.h"
60 #include "cligen_cvec.h"
61 #include "cligen_parsetree.h"
62 #include "cligen_object.h"
63 #include "cligen_io.h"
64 #include "cligen_match.h"
65 #include "cligen_regex.h"
66 #include "cligen_getline.h"
67
68 #include "cligen_cv_internal.h"
69 /*
70 * URL protocol strings
71 */
72 static char *cg_urlprotostr[] = {
73 NULL,
74 "file",
75 "flash",
76 "tftp",
77 "ftp",
78 "telnet",
79 "http",
80 "ssh",
81 NULL
82 };
83
84 /*! Get name of cligen variable cv
85 * @param[in] cv CLIgen variable
86 * @retval name Name of cv
87 */
88 char *
cv_name_get(cg_var * cv)89 cv_name_get(cg_var *cv)
90 {
91 if (cv == NULL)
92 return 0;
93 return cv->var_name;
94 }
95
96 /*! Set new CLIgen varable name.
97 * Free previous string if existing.
98 * @param[in] cv CLIgen variable
99 * @param[in] s0 New name
100 * @retval s0 Return the new name
101 * @retval NULL Error
102 */
103 char *
cv_name_set(cg_var * cv,char * s0)104 cv_name_set(cg_var *cv,
105 char *s0)
106 {
107 char *s1 = NULL;
108
109 if (cv == NULL)
110 return 0;
111
112 /* Duplicate s0. Must be done before a free, in case s0 is part of the original */
113 if (s0){
114 if ((s1 = strdup(s0)) == NULL)
115 return NULL; /* error in errno */
116 }
117 if (cv->var_name != NULL)
118 free(cv->var_name);
119 cv->var_name = s1;
120 return s1;
121 }
122
123 /*! Get cv type
124 * @param[in] cv CLIgen variable
125 * @retval type Type of cv
126 */
127 enum cv_type
cv_type_get(cg_var * cv)128 cv_type_get(cg_var *cv)
129 {
130 if (cv == NULL)
131 return 0;
132 return cv->var_type;
133 }
134
135 /*! Set new CLIgen type.
136 * @param[in] cv CLIgen variable
137 * @param[in] t New type
138 * @retval t New type
139 */
140 enum cv_type
cv_type_set(cg_var * cv,enum cv_type x)141 cv_type_set(cg_var *cv,
142 enum cv_type x)
143 {
144 if (cv == NULL)
145 return 0;
146 return (cv->var_type = x);
147 }
148
149 /*! Get cv const flag
150 * @param[in] cv CLIgen variable
151 * @retval type Type of cv
152 */
153 char
cv_const_get(cg_var * cv)154 cv_const_get(cg_var *cv)
155 {
156 if (cv == NULL)
157 return 0;
158 return cv->var_const;
159 }
160
161 /*! Set CLIgen const flag.
162 * @param[in] cv CLIgen variable
163 * @param[in] t New type
164 * @retval t New type
165 */
166 char
cv_const_set(cg_var * cv,int c)167 cv_const_set(cg_var *cv,
168 int c)
169 {
170 if (cv == NULL)
171 return 0;
172 return (cv->var_const = c);
173 }
174
175 /*! Get application-specific cv flag
176 * @param[in] cv CLIgen variable
177 * @see cv_flag_set
178 */
179 char
cv_flag(cg_var * cv,char mask)180 cv_flag(cg_var *cv,
181 char mask)
182 {
183 if (cv == NULL)
184 return 0;
185 return cv->var_flag & mask;
186 }
187
188 /*! Clear application-specific cv flag
189 * @param[in] cv CLIgen variable
190 */
191 char
cv_flag_clr(cg_var * cv,char mask)192 cv_flag_clr(cg_var *cv,
193 char mask)
194 {
195 if (cv == NULL)
196 return 0;
197 return cv->var_flag ^= mask;
198 }
199
200 /*! Set application-specific cv flag
201 * @param[in] cv CLIgen variable
202 * @see cv_flag
203 */
204 char
cv_flag_set(cg_var * cv,char mask)205 cv_flag_set(cg_var *cv,
206 char mask)
207 {
208 if (cv == NULL)
209 return 0;
210 return cv->var_flag |= mask;
211 }
212
213 /*! Get value of cv without specific type set
214 * @param[in] cv CLIgen variable
215 */
216 void *
cv_value_get(cg_var * cv)217 cv_value_get(cg_var *cv)
218 {
219 if (cv == NULL)
220 return 0;
221 return &cv->u;
222 }
223
224 /*! Get boolean value of cv
225 * @param[in] cv CLIgen variable
226 */
227 char
cv_bool_get(cg_var * cv)228 cv_bool_get(cg_var *cv)
229 {
230 if (cv == NULL)
231 return 0;
232 return ((cv)->u.varu_bool);
233 }
234
235 /*! Set boolean value of cv
236 * @param[in] cv CLIgen variable
237 */
238 char
cv_bool_set(cg_var * cv,char x)239 cv_bool_set(cg_var *cv,
240 char x)
241 {
242 if (cv == NULL)
243 return 0;
244 return (cv->u.varu_bool = x);
245 }
246
247 /*! Get 8-bit integer value of cv
248 * @param[in] cv CLIgen variable
249 */
250 int8_t
cv_int8_get(cg_var * cv)251 cv_int8_get(cg_var *cv)
252 {
253 if (cv == NULL)
254 return 0;
255 return ((cv)->u.varu_int8);
256 }
257
258 /*! Set 8-bit integer value of cv
259 * @param[in] cv CLIgen variable
260 */
261 int8_t
cv_int8_set(cg_var * cv,int8_t x)262 cv_int8_set(cg_var *cv,
263 int8_t x)
264 {
265 if (cv == NULL)
266 return 0;
267 return (cv->u.varu_int8 = x);
268 }
269
270 /*! Get 16-bit integer value of cv
271 * @param[in] cv CLIgen variable
272 */
273 int16_t
cv_int16_get(cg_var * cv)274 cv_int16_get(cg_var *cv)
275 {
276 if (cv == NULL)
277 return 0;
278 return ((cv)->u.varu_int16);
279 }
280
281 /*! Set 16-bit integer value of cv
282 * @param[in] cv CLIgen variable
283 */
284 int16_t
cv_int16_set(cg_var * cv,int16_t x)285 cv_int16_set(cg_var *cv,
286 int16_t x)
287 {
288 if (cv == NULL)
289 return 0;
290 return (cv->u.varu_int16 = x);
291 }
292
293 /*! Get 32-bit integer value of cv
294 * @param[in] cv CLIgen variable
295 */
296 int32_t
cv_int32_get(cg_var * cv)297 cv_int32_get(cg_var *cv)
298 {
299 if (cv == NULL)
300 return 0;
301 return ((cv)->u.varu_int32);
302 }
303
304 /*! Set 32-bit integer value of cv
305 * @param[in] cv CLIgen variable
306 */
307 int32_t
cv_int32_set(cg_var * cv,int32_t x)308 cv_int32_set(cg_var *cv,
309 int32_t x)
310 {
311 if (cv == NULL)
312 return 0;
313 return (cv->u.varu_int32 = x);
314 }
315
316 /*! Get 64-bit integer value of cv
317 * @param[in] cv CLIgen variable
318 */
319 int64_t
cv_int64_get(cg_var * cv)320 cv_int64_get(cg_var *cv)
321 {
322 if (cv == NULL)
323 return 0;
324 return ((cv)->u.varu_int64);
325 }
326
327 /*! Set 64-bit integer value of cv
328 * @param[in] cv CLIgen variable
329 */
330 int64_t
cv_int64_set(cg_var * cv,int64_t x)331 cv_int64_set(cg_var *cv,
332 int64_t x)
333 {
334 if (cv == NULL)
335 return 0;
336 return (cv->u.varu_int64 = x);
337 }
338
339 /*! Get 8-bit unsigned integer value of cv
340 * @param[in] cv CLIgen variable
341 */
342 uint8_t
cv_uint8_get(cg_var * cv)343 cv_uint8_get(cg_var *cv)
344 {
345 if (cv == NULL)
346 return 0;
347 return ((cv)->u.varu_uint8);
348 }
349
350 /*! Set 8-bit unsigned integer value of cv
351 * @param[in] cv CLIgen variable
352 */
353 uint8_t
cv_uint8_set(cg_var * cv,uint8_t x)354 cv_uint8_set(cg_var *cv,
355 uint8_t x)
356 {
357 if (cv == NULL)
358 return 0;
359 return (cv->u.varu_uint8 = x);
360 }
361
362 /*! Get 16-bit unsigned integer value of cv
363 * @param[in] cv CLIgen variable
364 */
365 uint16_t
cv_uint16_get(cg_var * cv)366 cv_uint16_get(cg_var *cv)
367 {
368 if (cv == NULL)
369 return 0;
370 return ((cv)->u.varu_uint16);
371 }
372
373 /*! Set 16-bit unsigned integer value of cv
374 * @param[in] cv CLIgen variable
375 */
376 uint16_t
cv_uint16_set(cg_var * cv,uint16_t x)377 cv_uint16_set(cg_var *cv,
378 uint16_t x)
379 {
380 return (cv->u.varu_uint16 = x);
381 }
382
383 /*! Get 32-bit unsigned integer value of cv
384 * @param[in] cv CLIgen variable
385 */
386 uint32_t
cv_uint32_get(cg_var * cv)387 cv_uint32_get(cg_var *cv)
388 {
389 if (cv == NULL)
390 return 0;
391 return ((cv)->u.varu_uint32);
392 }
393
394 /*! Set 32-bit unsigned integer value of cv
395 * @param[in] cv CLIgen variable
396 */
397 uint32_t
cv_uint32_set(cg_var * cv,uint32_t x)398 cv_uint32_set(cg_var *cv,
399 uint32_t x)
400 {
401 if (cv == NULL)
402 return 0;
403 return (cv->u.varu_uint32 = x);
404 }
405
406 /*! Get 64-bit unsigned integer value of cv
407 * @param[in] cv CLIgen variable
408 */
409 uint64_t
cv_uint64_get(cg_var * cv)410 cv_uint64_get(cg_var *cv)
411 {
412 if (cv == NULL)
413 return 0;
414 return ((cv)->u.varu_uint64);
415 }
416
417 /*! Set 64-bit unsigned integer value of cv
418 * @param[in] cv CLIgen variable
419 */
420 uint64_t
cv_uint64_set(cg_var * cv,uint64_t x)421 cv_uint64_set(cg_var *cv,
422 uint64_t x)
423 {
424 if (cv == NULL)
425 return 0;
426 return (cv->u.varu_uint64 = x);
427 }
428
429 /*! Get n-value of decimal-64 of cv (eg exponent)
430 * @param[in] cv CLIgen variable
431 */
432 uint8_t
cv_dec64_n_get(cg_var * cv)433 cv_dec64_n_get(cg_var *cv)
434 {
435 if (cv == NULL)
436 return 0;
437 return ((cv)->var_dec64_n);
438 }
439
440 /*! Set n-value of decimal-64 of cv (eg exponent)
441 * @param[in] cv CLIgen variable
442 * XXX range check? 1..18
443 */
444 uint8_t
cv_dec64_n_set(cg_var * cv,uint8_t x)445 cv_dec64_n_set(cg_var *cv,
446 uint8_t x)
447 {
448 if (cv == NULL)
449 return 0;
450 return (cv->var_dec64_n = x);
451 }
452
453 /*! Get i-value of decimal-64 of cv (eg base)
454 * @param[in] cv CLIgen variable
455 */
456 int64_t
cv_dec64_i_get(cg_var * cv)457 cv_dec64_i_get(cg_var *cv)
458 {
459 if (cv == NULL)
460 return 0;
461 return ((cv)->var_dec64_i);
462 }
463
464 /*! Set i-value of decimal-64 of cv (eg base)
465 * @param[in] cv CLIgen variable
466 */
467 int64_t
cv_dec64_i_set(cg_var * cv,int64_t x)468 cv_dec64_i_set(cg_var *cv,
469 int64_t x)
470 {
471 if (cv == NULL)
472 return 0;
473 return (cv->var_dec64_i = x);
474 }
475
476 /*! Get pointer to cv string.
477 *
478 * @param[in] cv CLIgen variable
479 * String can be modified in-line but must call _set function to reallocate.
480 */
481 char *
cv_string_get(cg_var * cv)482 cv_string_get(cg_var *cv)
483 {
484 if (cv == NULL)
485 return 0;
486 return ((cv)->u.varu_string);
487 }
488
489 /*! Allocate new string from original NULL-terminated string. Malloc new string and free previous
490 * @param[in] cv CLIgen variable
491 * @param[in] s0 String to copy from
492 * @retval NULL Error
493 * @retval str the new (malloced) string
494 */
495 char *
cv_string_set(cg_var * cv,char * s0)496 cv_string_set(cg_var *cv,
497 char *s0)
498 {
499 char *s1 = NULL;
500
501 if (cv == NULL){
502 errno = EINVAL;
503 return NULL;
504 }
505 if (s0 == NULL){
506 errno = EINVAL;
507 return NULL;
508 }
509
510 /* Duplicate s0. Must be done before a free, in case s0 is part of the original */
511 if ((s1 = strdup(s0)) == NULL)
512 return NULL; /* error in errno */
513 if (cv->u.varu_string != NULL)
514 free(cv->u.varu_string);
515 cv->u.varu_string = s1;
516 return s1;
517 }
518
519 /*! Allocate new string from original by copying using strncpy
520 * @param[in] cv CLIgen variable
521 * @param[in] s0 String to copy
522 * @param[in] n Number of characters to copy (excluding NULL).
523 * @retval NULL Error
524 * @retval str the new (malloced) string
525 */
526 char *
cv_strncpy(cg_var * cv,char * s0,size_t n)527 cv_strncpy(cg_var *cv,
528 char *s0,
529 size_t n)
530 {
531 char *s1 = NULL;
532
533 if (cv == NULL){
534 errno = EINVAL;
535 return NULL;
536 }
537 if (s0 == NULL){
538 errno = EINVAL;
539 return NULL;
540 }
541 /* Allocate s1. and then copy */
542 if ((s1 = malloc(n+1)) == NULL)
543 return NULL; /* error in errno */
544 strncpy(s1, s0, n);
545 s1[n] = '\0';
546 if (cv->u.varu_string != NULL)
547 free(cv->u.varu_string);
548 cv->u.varu_string = s1;
549 return s1;
550 }
551
552 /*! Get ipv4addr, pointer returned, can be used to set value.
553 * @param[in] cv CLIgen variable
554 */
555 struct in_addr *
cv_ipv4addr_get(cg_var * cv)556 cv_ipv4addr_get(cg_var *cv)
557 {
558 if (cv == NULL)
559 return 0;
560 return &cv->u.varu_ipv4addr.varipv4_ipv4addr;
561 }
562
563 /*! Set ipv4addr, pointer returned
564 * @param[in] cv CLIgen variable
565 * @param[in] addr storage space for address
566 */
567 struct in_addr *
cv_ipv4addr_set(cg_var * cv,struct in_addr * addr)568 cv_ipv4addr_set(cg_var *cv, struct in_addr *addr)
569 {
570 if (cv && addr)
571 cv->var_ipv4addr = *addr;
572 return addr;
573 }
574
575 /*! Get ipv4addr length of cv
576 * @param[in] cv CLIgen variable
577 */
578 uint8_t
cv_ipv4masklen_get(cg_var * cv)579 cv_ipv4masklen_get(cg_var *cv)
580 {
581 if (cv == NULL)
582 return 0;
583 return cv->u.varu_ipv4addr.varipv4_masklen;
584 }
585
586 /*! Set ipv4addr length of cv
587 * @param[in] cv CLIgen variable
588 * @param[in] masklen storage spave for masklen
589 */
590 uint8_t
cv_ipv4masklen_set(cg_var * cv,uint8_t masklen)591 cv_ipv4masklen_set(cg_var *cv, uint8_t masklen)
592 {
593 if (cv == NULL)
594 return 0;
595 cv->u.varu_ipv4addr.varipv4_masklen = masklen;
596 return masklen;
597 }
598
599 /*! Get ipv6addr, pointer returned, can be used to set value.
600 * @param[in] cv CLIgen variable
601 */
602 struct in6_addr *
cv_ipv6addr_get(cg_var * cv)603 cv_ipv6addr_get(cg_var *cv)
604 {
605 if (cv == NULL)
606 return 0;
607 return &cv->u.varu_ipv6addr.varipv6_ipv6addr;
608 }
609
610 /*! Get ipv6addr length of cv
611 * @param[in] cv CLIgen variable
612 */
613 uint8_t
cv_ipv6masklen_get(cg_var * cv)614 cv_ipv6masklen_get(cg_var *cv)
615 {
616 if (cv == NULL)
617 return 0;
618 return cv->u.varu_ipv6addr.varipv6_masklen;
619 }
620
621 /*! Returns a pointer to 6-byte mac-address array.
622 *
623 * @param[in] cv CLIgen variable
624 * This can be used to set the address too
625 */
626 char *
cv_mac_get(cg_var * cv)627 cv_mac_get(cg_var *cv)
628 {
629 if (cv == NULL)
630 return 0;
631 return cv->u.varu_macaddr;
632 }
633
634 /*! Returns a pointer to uuid byte array.
635 *
636 * @param[in] cv CLIgen variable
637 * This can be used to set the uuid too.
638 */
639 unsigned char *
cv_uuid_get(cg_var * cv)640 cv_uuid_get(cg_var *cv)
641 {
642 if (cv == NULL)
643 return 0;
644 return cv->u.varu_uuid;
645 }
646
647 /*! Set uuid value
648 * @param[in] cv CLIgen variable
649 */
650 unsigned char *
cv_uuid_set(cg_var * cv,unsigned char * u)651 cv_uuid_set(cg_var *cv,
652 unsigned char *u)
653 {
654 if (cv == NULL)
655 return 0;
656 memcpy((char*)&cv->u.varu_uuid, u, 16);
657 return cv->u.varu_uuid;
658 }
659
660 /*! Returns a struct timeval by value.
661 * @param[in] cv CLIgen variable
662 */
663 struct timeval
cv_time_get(cg_var * cv)664 cv_time_get(cg_var *cv)
665 {
666 if (cv == NULL) {
667 struct timeval t = { 0 };
668 return t;
669 }
670 return cv->u.varu_time;
671 }
672
673 /*! Set timeval struct
674 * @param[in] cv CLIgen variable
675 * Returns a struct timeval by value.
676 */
677 struct timeval
cv_time_set(cg_var * cv,struct timeval t)678 cv_time_set(cg_var *cv,
679 struct timeval t)
680 {
681 if (cv == NULL) {
682 struct timeval t = { 0 };
683 return t;
684 }
685 cv->u.varu_time = t;
686 return t;
687 }
688
689 /*! Returns a void pointer
690 * @param[in] cv CLIgen variable
691 */
692 void *
cv_void_get(cg_var * cv)693 cv_void_get(cg_var *cv)
694 {
695 if (cv == NULL)
696 return NULL;
697 return cv->var_void;
698 }
699
700 /*! Set void pointer
701 * @param[in] cv CLIgen variable
702 */
703 int
cv_void_set(cg_var * cv,void * p)704 cv_void_set(cg_var *cv,
705 void *p)
706 {
707 if (cv)
708 cv->var_void = p;
709 return 0;
710 }
711
712 /*! Get pointer to URL proto string.
713 *
714 * @param[in] cv CLIgen variable
715 * String can be modified in-line but must call _set function to reallocate.
716 */
717 char *
cv_urlproto_get(cg_var * cv)718 cv_urlproto_get(cg_var *cv)
719 {
720 if (cv == NULL)
721 return 0;
722 return (cv)->u.varu_url.varurl_proto;
723 }
724
725 /*! Set URL protocol
726 * malloc new string from original. Free previous string if existing.
727 * @param[in] cv CLIgen variable
728 */
729 char *
cv_urlproto_set(cg_var * cv,char * s0)730 cv_urlproto_set(cg_var *cv,
731 char *s0)
732 {
733 char *s1 = NULL;
734
735 if (!cv) {
736 return 0;
737 }
738
739 /* Duplicate s0. Must be done before a free, in case s0 is part of the original */
740 if (s0){
741 if ((s1 = strdup(s0)) == NULL)
742 return NULL; /* error in errno */
743 }
744 if (cv->u.varu_url.varurl_proto != NULL)
745 free(cv->u.varu_url.varurl_proto);
746 cv->u.varu_url.varurl_proto = s1;
747 return s1;
748 }
749
750 /*! Get pointer to URL address string.
751 *
752 * @param[in] cv CLIgen variable
753 * String can be modified in-line but must call _set function to reallocate.
754 */
755 char *
cv_urladdr_get(cg_var * cv)756 cv_urladdr_get(cg_var *cv)
757 {
758 if (!cv) {
759 return 0;
760 }
761
762 return (cv)->u.varu_url.varurl_addr;
763 }
764
765 /*! Set URL address
766 * @param[in] cv CLIgen variable
767 * malloc new string from original. Free previous string if existing.
768 */
769 char *
cv_urladdr_set(cg_var * cv,char * s0)770 cv_urladdr_set(cg_var *cv,
771 char *s0)
772 {
773 char *s1 = NULL;
774
775 if (!cv) {
776 return 0;
777 }
778
779 /* Duplicate s0. Must be done before a free, in case s0 is part of the original */
780 if (s0){
781 if ((s1 = strdup(s0)) == NULL)
782 return NULL; /* error in errno */
783 }
784 if (cv->u.varu_url.varurl_addr != NULL)
785 free(cv->u.varu_url.varurl_addr);
786 cv->u.varu_url.varurl_addr = s1;
787 return s1;
788 }
789
790 /*! Get pointer to URL path string.
791 *
792 * @param[in] cv CLIgen variable
793 * String can be modified in-line but must call _set function to reallocate.
794 */
795 char *
cv_urlpath_get(cg_var * cv)796 cv_urlpath_get(cg_var *cv)
797 {
798 if (!cv) {
799 return 0;
800 }
801
802 return (cv)->u.varu_url.varurl_path;
803 }
804
805 /*! Set URL path
806 * @param[in] cv CLIgen variable
807 * malloc new string from original. Free previous string if existing.
808 */
809 char *
cv_urlpath_set(cg_var * cv,char * s0)810 cv_urlpath_set(cg_var *cv,
811 char *s0)
812 {
813 char *s1 = NULL;
814
815 if (!cv) {
816 return 0;
817 }
818
819 /* Duplicate s0. Must be done before a free, in case s0 is part of the original */
820 if (s0){
821 if ((s1 = strdup(s0)) == NULL)
822 return NULL; /* error in errno */
823 }
824 if (cv->u.varu_url.varurl_path != NULL)
825 free(cv->u.varu_url.varurl_path);
826 cv->u.varu_url.varurl_path = s1;
827 return s1;
828 }
829
830 /*! Get pointer to URL user string.
831 *
832 * @param[in] cv CLIgen variable
833 * String can be modified in-line but must call _set function to reallocate.
834 */
835 char *
cv_urluser_get(cg_var * cv)836 cv_urluser_get(cg_var *cv)
837 {
838 if (!cv) {
839 return 0;
840 }
841
842 return (cv)->u.varu_url.varurl_user;
843 }
844
845 /*! Set URL user
846 * @param[in] cv CLIgen variable
847 * malloc new string from original. Free previous string if existing.
848 */
849 char *
cv_urluser_set(cg_var * cv,char * s0)850 cv_urluser_set(cg_var *cv,
851 char *s0)
852 {
853 char *s1 = NULL;
854
855 if (!cv) {
856 return 0;
857 }
858
859 /* Duplicate s0. Must be done before a free, in case s0 is part of the original */
860 if (s0){
861 if ((s1 = strdup(s0)) == NULL)
862 return NULL; /* error in errno */
863 }
864 if (cv->u.varu_url.varurl_user != NULL)
865 free(cv->u.varu_url.varurl_user);
866 cv->u.varu_url.varurl_user = s1;
867 return s1;
868 }
869
870 /*! Get pointer to URL passwd string.
871 *
872 * @param[in] cv CLIgen variable
873 * String can be modified in-line but must call _set function to reallocate.
874 */
875 char *
cv_urlpasswd_get(cg_var * cv)876 cv_urlpasswd_get(cg_var *cv)
877 {
878 if (!cv) {
879 return 0;
880 }
881
882 return (cv)->u.varu_url.varurl_passwd;
883 }
884
885 /*! Set URL password
886 * @param[in] cv CLIgen variable
887 * malloc new string from original. Free previous string if existing.
888 */
889 char *
cv_urlpasswd_set(cg_var * cv,char * s0)890 cv_urlpasswd_set(cg_var *cv,
891 char *s0)
892 {
893 char *s1 = NULL;
894
895 if (!cv) {
896 return 0;
897 }
898
899 /* Duplicate s0. Must be done before a free, in case s0 is part of the original */
900 if (s0){
901 if ((s1 = strdup(s0)) == NULL)
902 return NULL; /* error in errno */
903 }
904 if (cv->u.varu_url.varurl_passwd != NULL)
905 free(cv->u.varu_url.varurl_passwd);
906 cv->u.varu_url.varurl_passwd = s1;
907 return s1;
908 }
909
910 /*! Parse an int64 number with explicit base and check for errors
911 * @param[in] str String containing number to parse
912 * @parame[in] base If base is 0 or 16, the string may include a "0x" prefix,
913 * the number will be read in base 16; otherwise, a zero base
914 * is taken as 10 (decimal) unless the next character is '0',
915 * in which case it is taken as 8 (octal).
916 * @param[in] imin Min range (set INT64_MIN for default)
917 * @param[in] imax Max range (set INT64_MAX for default)
918 * @param[out] val Value on success
919 * @param[out] reason Error string on failure
920 * @retval -1 : Error (fatal), with errno set to indicate error
921 * @retval 0 : Validation not OK, malloced reason is returned
922 * @retval 1 : Validation OK, value returned in val parameter
923 */
924 static int
parse_int64_base(char * str,int base,int64_t imin,int64_t imax,int64_t * val,char ** reason)925 parse_int64_base(char *str,
926 int base,
927 int64_t imin,
928 int64_t imax,
929 int64_t *val,
930 char **reason)
931 {
932 int64_t i;
933 char *ep;
934 int retval = -1;
935
936 errno = 0;
937 i = strtoll(str, &ep, base);
938 if (str[0] == '\0' || *ep != '\0'){
939 if (reason != NULL)
940 if ((*reason = cligen_reason("'%s' is not a number", str)) == NULL){
941 retval = -1;
942 goto done;
943 }
944 retval = 0;
945 goto done;
946 }
947 if (errno != 0){
948 if ((i == INT64_MIN || i == INT64_MAX) && errno == ERANGE){
949 errno = 0;
950 if (reason != NULL)
951 if ((*reason = cligen_reason("Number %s out of range: %" PRId64 " - %" PRId64, str, imin, imax)) == NULL){
952 retval = -1; /* malloc */
953 goto done;
954 }
955 retval = 0;
956 goto done;
957 }
958 else{
959 if ((*reason = cligen_reason("%s: %s", str, strerror(errno))) == NULL){
960 errno = 0;
961 retval = -1;
962 goto done;
963 }
964 }
965 errno = 0;
966 } /* if errno */
967 else if (i < imin || i > imax){
968 if (reason != NULL)
969 if ((*reason = cligen_reason("Number %s out of range: %" PRId64 " - %" PRId64, str, imin, imax)) == NULL){
970 retval = -1;
971 goto done;
972 }
973 retval = 0;
974 goto done;
975 }
976 *val = i;
977 retval = 1; /* OK */
978 done:
979 return retval;
980 }
981
982 /*! Parse an int8 number and check for errors
983 * @param[in] str String containing number to parse
984 * @param[out] val Value on success
985 * @param[out] reason Error string on failure
986 * @retval -1 : Error (fatal), with errno set to indicate error
987 * @retval 0 : Validation not OK, malloced reason is returned
988 * @retval 1 : Validation OK, value returned in val parameter
989 */
990 int
parse_int8(char * str,int8_t * val,char ** reason)991 parse_int8(char *str,
992 int8_t *val,
993 char **reason)
994 {
995 int64_t i;
996 int retval;
997
998 if ((retval = parse_int64_base(str, 0, -128, 127, &i, reason)) != 1)
999 goto done;
1000 *val = (int8_t)i;
1001 done:
1002 return retval;
1003 }
1004
1005 /*! Parse an int16 number and check for errors
1006 * @param[in] str String containing number to parse
1007 * @param[out] val Value on success
1008 * @param[out] reason Error string on failure
1009 * @retval -1 : Error (fatal), with errno set to indicate error
1010 * @retval 0 : Validation not OK, malloced reason is returned
1011 * @retval 1 : Validation OK, value returned in val parameter
1012 */
1013 int
parse_int16(char * str,int16_t * val,char ** reason)1014 parse_int16(char *str,
1015 int16_t *val,
1016 char **reason)
1017 {
1018 int64_t i;
1019 int retval;
1020
1021 if ((retval = parse_int64_base(str, 0, -32768, 32767, &i, reason)) != 1)
1022 goto done;
1023 *val = (int16_t)i;
1024 done:
1025 return retval;
1026 }
1027
1028 /*! Parse an int32 number and check for errors
1029 * @param[in] str String containing number to parse
1030 * @param[out] val Value on success
1031 * @param[out] reason Error string on failure
1032 * @retval -1 : Error (fatal), with errno set to indicate error
1033 * @retval 0 : Validation not OK, malloced reason is returned
1034 * @retval 1 : Validation OK, value returned in val parameter
1035 */
1036 int
parse_int32(char * str,int32_t * val,char ** reason)1037 parse_int32(char *str,
1038 int32_t *val,
1039 char **reason)
1040 {
1041 int64_t i;
1042 int retval;
1043
1044 if ((retval = parse_int64_base(str, 0, INT_MIN, INT_MAX, &i, reason)) != 1)
1045 goto done;
1046 *val = (int32_t)i;
1047 done:
1048 return retval;
1049 }
1050
1051 /*! Parse an int64 number and check for errors
1052 * @param[in] str String containing number to parse
1053 * @param[out] val Value on success
1054 * @param[out] reason Error string on failure
1055 * @retval -1 : Error (fatal), with errno set to indicate error
1056 * @retval 0 : Validation not OK, malloced reason is returned
1057 * @retval 1 : Validation OK, value returned in val parameter
1058 */
1059 int
parse_int64(char * str,int64_t * val,char ** reason)1060 parse_int64(char *str,
1061 int64_t *val,
1062 char **reason)
1063 {
1064 return parse_int64_base(str, 0, INT64_MIN, INT64_MAX, val, reason);
1065 }
1066
1067 /*! Parse an uint64 number and check for errors
1068 * @param[in] str String containing number to parse
1069 * @parame[in] base If base is 0 or 16, the string may include a "0x" prefix,
1070 * the number will be read in base 16; otherwise, a zero base
1071 * is taken as 10 (decimal) unless the next character is '0',
1072 * in which case it is taken as 8 (octal).
1073 * @param[in] umin Min range (set UINT64_MIN for default)
1074 * @param[in] umax Max range (set UINT64_MAX for default)
1075 * @param[out] val Value on success
1076 * @param[out] reason Error string on failure (if given)
1077 * @retval -1 : Error (fatal), with errno set to indicate error
1078 * @retval 0 : Validation not OK, malloced reason is returned
1079 * @retval 1 : Validation OK, value returned in val parameter
1080 * @note: we have to detect a minus sign ourselves,....
1081 */
1082 static int
parse_uint64_base(char * str,int base,uint64_t umin,uint64_t umax,uint64_t * val,char ** reason)1083 parse_uint64_base(char *str,
1084 int base,
1085 uint64_t umin,
1086 uint64_t umax,
1087 uint64_t *val,
1088 char **reason)
1089 {
1090 uint64_t i;
1091 char *ep;
1092 int retval = -1;
1093
1094 errno = 0;
1095 i = strtoull(str, &ep, base);
1096 if (str[0] == '\0' || *ep != '\0'){
1097 if (reason != NULL)
1098 if ((*reason = cligen_reason("'%s' is not a number", str)) == NULL){
1099 retval = -1; /* malloc */
1100 goto done;
1101 }
1102 retval = 0;
1103 goto done;
1104 }
1105 if (errno != 0){
1106 if (i == UINT64_MAX && errno == ERANGE){
1107 if (reason != NULL)
1108 if ((*reason = cligen_reason("Number %s out of range: 0 - %" PRIu64, str, umax)) == NULL){
1109 retval = -1; /* malloc */
1110 goto done;
1111 }
1112 retval = 0;
1113 goto done;
1114 }
1115 else{
1116 if ((*reason = cligen_reason("%s: %s", str, strerror(errno))) == NULL){
1117 retval = -1; /* malloc */
1118 goto done;
1119 }
1120 retval = 0;
1121 goto done;
1122 }
1123 }
1124 else if (i > umax){
1125 if (reason != NULL)
1126 if ((*reason = cligen_reason("Number %s out of range: %" PRIu64 " - %" PRIu64, str, umin, umax)) == NULL){
1127 retval = -1;
1128 goto done;
1129 }
1130 retval = 0;
1131 goto done;
1132 }
1133 /* strtoull does _not_ detect negative numbers,... */
1134 if (strchr(str, '-') != NULL){
1135 if (reason != NULL)
1136 if ((*reason = cligen_reason("Number %s out of range: 0 - %" PRIu64, str, umax)) == NULL){
1137 retval = -1; /* malloc */
1138 goto done;
1139 }
1140 retval = 0;
1141 goto done;
1142 }
1143 *val = i;
1144 retval = 1; /* OK */
1145 done:
1146 return retval;
1147 }
1148
1149 /*! Parse an uint8 number and check for errors
1150 * @param[in] str String containing number to parse
1151 * @param[out] val Value on success
1152 * @param[out] reason Error string on failure
1153 * @retval -1 : Error (fatal), with errno set to indicate error
1154 * @retval 0 : Validation not OK, malloced reason is returned
1155 * @retval 1 : Validation OK, value returned in val parameter
1156 */
1157 int
parse_uint8(char * str,uint8_t * val,char ** reason)1158 parse_uint8(char *str,
1159 uint8_t *val,
1160 char **reason)
1161 {
1162 uint64_t i;
1163 int retval;
1164
1165 if ((retval = parse_uint64_base(str, 0, 0, 255, &i, reason)) != 1)
1166 goto done;
1167 *val = (uint8_t)i;
1168 done:
1169 return retval;
1170 }
1171
1172 /*! Parse an uint16 number and check for errors
1173 * @param[in] str String containing number to parse
1174 * @param[out] val Value on success
1175 * @param[out] reason Error string on failure
1176 * @retval -1 : Error (fatal), with errno set to indicate error
1177 * @retval 0 : Validation not OK, malloced reason is returned
1178 * @retval 1 : Validation OK, value returned in val parameter
1179 */
1180 int
parse_uint16(char * str,uint16_t * val,char ** reason)1181 parse_uint16(char *str,
1182 uint16_t *val,
1183 char **reason)
1184 {
1185 uint64_t i;
1186 int retval;
1187
1188 if ((retval = parse_uint64_base(str, 0, 0, 65535, &i, reason)) != 1)
1189 goto done;
1190 *val = (uint16_t)i;
1191 done:
1192 return retval;
1193 }
1194
1195 /*! Parse an uint32 number and check for errors
1196 * @param[in] str String containing number to parse
1197 * @param[out] val Value on success
1198 * @param[out] reason Error string on failure
1199 * @retval -1 : Error (fatal), with errno set to indicate error
1200 * @retval 0 : Validation not OK, malloced reason is returned
1201 * @retval 1 : Validation OK, value returned in val parameter
1202 */
1203 int
parse_uint32(char * str,uint32_t * val,char ** reason)1204 parse_uint32(char *str,
1205 uint32_t *val,
1206 char **reason)
1207 {
1208 uint64_t i;
1209 int retval;
1210
1211 if ((retval = parse_uint64_base(str, 0, 0, UINT_MAX, &i, reason)) != 1)
1212 goto done;
1213 *val = (uint32_t)i;
1214 done:
1215 return retval;
1216 }
1217
1218 /*! Parse an uint64 number and check for errors
1219 * @param[in] str String containing number to parse
1220 * @param[out] val Value on success
1221 * @param[out] reason Error string on failure (if given)
1222 * @retval -1 : Error (fatal), with errno set to indicate error
1223 * @retval 0 : Validation not OK, malloced reason is returned
1224 * @retval 1 : Validation OK, value returned in val parameter
1225 * @note: we have to detect a minus sign ourselves,....
1226 */
1227 int
parse_uint64(char * str,uint64_t * val,char ** reason)1228 parse_uint64(char *str,
1229 uint64_t *val,
1230 char **reason)
1231 {
1232 return parse_uint64_base(str, 0, 0, UINT64_MAX, val, reason);
1233 }
1234
1235 /*! Parse a decimal64 value
1236 * @param[in] str String to parse
1237 * @param[in] n number of decimals
1238 * @param[out] dec64_i 64-bit number
1239 * @param[out] reason if given, malloced err string (retval=0), needs freeing
1240 * @retval -1 fatal error
1241 * @retval 0 parse error, reason in reason
1242 * @retval 1 OK
1243 */
1244 int
parse_dec64(char * str,uint8_t n,int64_t * dec64_i,char ** reason)1245 parse_dec64(char *str,
1246 uint8_t n,
1247 int64_t *dec64_i,
1248 char **reason)
1249 {
1250 int retval = 1;
1251 char *s0 = NULL; /* the whole string, eg aaa.bbb*/
1252 char *s1; /* the first part (eg aaa) */
1253 char *s2; /* the second part (eg bbb) */
1254 char *ss = NULL; /* Help string */
1255 int len1;
1256 int len2 = 0;
1257 int i;
1258
1259 /*
1260 +----------------+-----------------------+----------------------+
1261 | fraction-digit | min | max |
1262 +----------------+-----------------------+----------------------+
1263 | 1 | -922337203685477580.8 | 922337203685477580.7 |
1264 | 18 | -9.223372036854775808 | 9.223372036854775807 |
1265 +----------------+-----------------------+----------------------+
1266 */
1267
1268 if (n<=0 || n>18){
1269 if (reason != NULL)
1270 if ((*reason = cligen_reason("%s: fraction-digit=%d given but should be in interval [1:18]", __FUNCTION__, n)) == NULL){
1271 goto done;
1272 }
1273 retval = 0;
1274 goto done;
1275 }
1276 if ((s0 = strdup(str)) == NULL){
1277 retval = -1; /* malloc */
1278 goto done;
1279 }
1280 s2 = s0;
1281 s1 = strsep(&s2, ".");
1282 len1 = strlen(s1);
1283 if ((ss = malloc(strlen(str)+n+2)) == NULL){
1284 retval = -1; /* malloc */
1285 goto done;
1286 }
1287 memcpy(ss, s1, len1);
1288
1289 /*
1290 * | s1 |.| s2 |
1291 * | s1 | s2 |000|
1292 * <---n-->
1293 */
1294 if (s2){
1295 len2 = strlen(s2);
1296 if (len2 > n){
1297 if (reason != NULL)
1298 if ((*reason = cligen_reason("%s has %d fraction-digits but may only have %d", str, len2, n)) == NULL){
1299 retval = -1; /* malloc */
1300 goto done;
1301 }
1302 retval = 0;
1303 goto done;
1304 }
1305 memcpy(ss+len1, s2, len2);
1306 }
1307 /* Fill out with trailing zeroes if any
1308 | s1 | s2 |
1309 */
1310 for (i=len1+len2; i<len1+n; i++)
1311 ss[i] = '0';
1312 ss[len1+n] = '\0'; /* trailing zero */
1313 /* XXX: remove any beginning zeros */
1314 if ((retval = parse_int64_base(ss, 10, INT64_MIN, INT64_MAX, dec64_i, reason)) != 1)
1315 goto done;
1316 done:
1317 if (s0)
1318 free(s0);
1319 if (ss)
1320 free(ss);
1321 return retval;
1322 }
1323
1324 /*! Parse boolean values, eg true or false, on or off
1325 * @param[in] str String to parse
1326 * @param[in] val integer 0 or 1
1327 * @param[out] reason if given, malloced err string (retval=0), needs freeing
1328 * @retval -1 fatal error
1329 * @retval 0 parse error, reason in reason
1330 * @retval 1 OK
1331 */
1332 static int
parse_bool(char * str,uint8_t * val,char ** reason)1333 parse_bool(char *str,
1334 uint8_t *val,
1335 char **reason)
1336 {
1337 int i;
1338 int retval = 1;
1339
1340 if (strcmp(str, "true") == 0)
1341 i = 1;
1342 else if (strcmp(str, "false") == 0)
1343 i = 0;
1344 #ifdef BOOL_TRUTH_ON_OFF
1345 else if (strcmp(str, "on") == 0)
1346 i = 1;
1347 else if (strcmp(str, "off") == 0)
1348 i = 0;
1349 #endif
1350 #ifdef BOOL_TRUTH_ENABLE_DISABLE
1351 else if (strcmp(str, "enable") == 0)
1352 i = 1;
1353 else if (strcmp(str, "disable") == 0)
1354 i = 0;
1355 #endif
1356 else{
1357 if (reason)
1358 if ((*reason = cligen_reason("'%s' is not a boolean value", str)) == NULL){
1359 retval = -1;
1360 goto done;
1361 }
1362 retval = 0;
1363 goto done;
1364 }
1365 *val = i;
1366 done:
1367 return retval;
1368 }
1369
1370 /*! Parse an IPv4 address struct
1371 * @param[in] str String to parse
1372 * @param[in] val IPv4 binary address
1373 * @param[out] reason if given, malloced err string (retval=0), needs freeing
1374 * @retval -1 fatal error
1375 * @retval 0 parse error, reason in reason
1376 * @retval 1 OK
1377 */
1378 int
parse_ipv4addr(char * str,struct in_addr * val,char ** reason)1379 parse_ipv4addr(char *str,
1380 struct in_addr *val,
1381 char **reason)
1382 {
1383 int retval = -1;
1384
1385 if ((retval = inet_pton(AF_INET, str, val)) < 0)
1386 goto done;
1387 if (retval == 0 && reason)
1388 if ((*reason = cligen_reason("Invalid IPv4 address")) == NULL)
1389 retval = -1;
1390 done:
1391 return retval;
1392 }
1393
1394 /*! Parse an IPv6 address struct
1395 * @param[in] str String to parse
1396 * @param[in] val IPv6 binary address
1397 * @param[out] reason if given, malloced err string (retval=0), needs freeing
1398 * @retval -1 fatal error
1399 * @retval 0 parse error, reason in reason
1400 * @retval 1 OK
1401 */
1402 int
parse_ipv6addr(char * str,struct in6_addr * val,char ** reason)1403 parse_ipv6addr(char *str,
1404 struct in6_addr *val,
1405 char **reason)
1406 {
1407 int retval = -1;
1408
1409 if ((retval = inet_pton(AF_INET6, str, val)) < 0)
1410 goto done;
1411 if (retval == 0 && reason)
1412 if ((*reason = cligen_reason("Invalid IPv6 address")) == NULL)
1413 retval = -1;
1414 done:
1415 return retval;
1416 }
1417
1418
1419 /*! Own version of ether_aton():
1420 * parse string in colon hex notation and return a vector of chars.
1421 * @param[out] reason if given, malloced err string (retval=0), needs freeing
1422 */
1423
1424 #define MACADDR_OCTETS 6
1425 #define MACADDR_STRLEN (MACADDR_OCTETS * 3) - 1 /* 6*sizeof("xx:")-1 */
1426
1427 static int
parse_macaddr(char * str,char addr[MACADDR_OCTETS],char ** reason)1428 parse_macaddr(char *str,
1429 char addr[MACADDR_OCTETS],
1430 char **reason)
1431 {
1432 char *s1;
1433 int n_colons;
1434 unsigned int octets[MACADDR_OCTETS];
1435 int i;
1436
1437 /*
1438 * MAC addresses are exactly MACADDR_STRLEN (17) bytes long.
1439 */
1440 if ((str == NULL) || strlen(str) != MACADDR_STRLEN) {
1441 if (reason && (*reason = cligen_reason("%s: Invalid MAC address (bad length)", str)) == NULL) {
1442 return -1;
1443 }
1444 return 0;
1445 }
1446
1447 /*
1448 * Allow only valid charcters 0-9, a-f, A-F and ':'.
1449 */
1450 n_colons = 0;
1451 for (s1 = str; s1 && *s1; ++s1) {
1452 if (isxdigit(*s1)) {
1453 continue;
1454 }
1455 if (*s1 == ':') {
1456 ++n_colons;
1457 continue;
1458 }
1459
1460 if (reason) {
1461 *reason = cligen_reason("%s: Invalid MAC address (illegal character '%c')", str, *s1);
1462 if (*reason == NULL) {
1463 return -1;
1464 }
1465 }
1466 return 0;
1467 }
1468
1469 /*
1470 * Ensure exactly 6 octets.
1471 */
1472 if (n_colons != MACADDR_OCTETS - 1) {
1473 if (reason) {
1474 *reason = cligen_reason("%s: Invalid MAC address (should have 6 octets, not %d)", str, n_colons + 1);
1475 if (*reason == NULL) {
1476 return -1;
1477 }
1478 }
1479 return 0;
1480 }
1481
1482 /*
1483 * Ensure octets are proper two-character widths.
1484 */
1485 if (str[2] != ':' || str[5] != ':' || str[8] != ':'
1486 || str[11] != ':' || str[14] != ':' || str[17] != 0) {
1487 if (reason) {
1488 *reason = cligen_reason("%s: Invalid MAC address (poorly formed octets)", str);
1489 if (*reason == NULL) {
1490 return -1;
1491 }
1492 }
1493 return 0;
1494 }
1495
1496 sscanf(str,
1497 "%x:%02x:%02x:%02x:%02x:%02x",
1498 octets + 0, octets + 1, octets + 2,
1499 octets + 3, octets + 4, octets + 5);
1500
1501 for (i = 0; i < MACADDR_OCTETS; ++i) {
1502 addr[i] = octets[i];
1503 }
1504
1505 return 1; /* OK */
1506 }
1507
1508 /*! Parse URL
1509 * @param[in] url Syntax: <proto>://[<user>[:<passwd>]@]<addr>[/<path>]. May
1510 * be changed destructively
1511 * @param[in] cv CLIgen variable
1512 * @param[out] reason if given, malloced err string (retval=0), needs freeing
1513 * URL syntax:
1514
1515 */
1516 static int
parse_url(char * url,cg_var * cv,char ** reason)1517 parse_url(char *url,
1518 cg_var *cv,
1519 char **reason)
1520 {
1521 char *str0;
1522 char *str;
1523 char *tmp;
1524 char *tmp2;
1525 int retval = -1;
1526
1527 if ((str0 = strdup(url)) == NULL)
1528 goto done;
1529 str = str0;
1530 if ((tmp = strchr(str, ':')) == NULL)
1531 goto warn;
1532 if (strncmp(tmp, "://", 3)) /* :// */
1533 goto warn;
1534 *tmp = '\0';
1535 cv->var_urlproto = strdup(str);
1536 str = tmp+3;
1537 if ((tmp = strchr(str, '@')) != NULL){
1538 /* user field */
1539 *tmp = '\0';
1540 if ((tmp2 = strchr(str, ':')) != NULL){
1541 /* user:passwd field */
1542 *tmp2 = '\0';
1543 cv->var_urlpasswd = strdup(tmp2+1);
1544 }
1545 else
1546 cv->var_urlpasswd = strdup("");
1547 cv->var_urluser = strdup(str);
1548 str = tmp+1;
1549 }
1550 else{
1551 cv->var_urluser = strdup("");
1552 cv->var_urlpasswd = strdup("");
1553 }
1554 if ((tmp = strchr(str, '/')) != NULL)
1555 *tmp = '\0';
1556 cv->var_urladdr = strdup(str);
1557 if (tmp){
1558 str = tmp+1;
1559 cv->var_urlpath = strdup(str);
1560 }
1561 else
1562 cv->var_urlpath = strdup("");
1563 retval = 1; /* OK */
1564 done:
1565 if (str0)
1566 free(str0);
1567 return retval;
1568 warn:
1569 if (reason && (*reason = cligen_reason("%s: Invalid URL", url)) == NULL)
1570 return -1;
1571 if (str0)
1572 free(str0);
1573 return 0;
1574 }
1575
1576 /*! Translate url protocol string to enum
1577 * @param[in] str
1578 */
1579 int
str2urlproto(char * str)1580 str2urlproto(char *str)
1581 {
1582 int proto;
1583
1584 for (proto = 1;; proto++){
1585 if (cg_urlprotostr[proto] == NULL)
1586 break;
1587 if (strcmp(str, cg_urlprotostr[proto]) == 0)
1588 return proto;
1589 }
1590 return 0;
1591 }
1592
1593 /*! Translate uuid binary data structure to uuid ascii string
1594 * @param[in] u UUID as binary data structure
1595 * @param[out] fmt Format string.
1596 * @param[in] len Length of fmt needs to be at 37.
1597 * @retval 0 OK
1598 * @retval -1 Error
1599 */
1600 int
uuid2str(uuid_t u,char * fmt,int len)1601 uuid2str(uuid_t u,
1602 char *fmt,
1603 int len)
1604 {
1605 snprintf(fmt, len,
1606 "%02x%02x%02x%02x-" "%02x%02x-" "%02x%02x-" "%02x%02x-"
1607 "%02x%02x%02x%02x%02x%02x",
1608 u[0]&0xff, u[1]&0xff, u[2]&0xff, u[3]&0xff,
1609 u[4]&0xff, u[5]&0xff, u[6]&0xff, u[7]&0xff,
1610 u[8]&0xff, u[9]&0xff, u[10]&0xff, u[11]&0xff,
1611 u[12]&0xff, u[13]&0xff, u[14]&0xff, u[15]&0xff);
1612 return 0;
1613 }
1614
1615 /*! Given a single hex character, return its number as int
1616 */
1617 static int
toint(char c)1618 toint(char c)
1619 {
1620 if (c >= '0' && c <= '9')
1621 return c - '0';
1622 if (c >= 'A' && c <= 'F')
1623 return 10 + c - 'A';
1624 if (c >= 'a' && c <= 'f')
1625 return 10 + c - 'a';
1626 return -1;
1627 }
1628
1629 /*! Translate uuid ascii string to uuid binary data structure.
1630 * uuid string on form f47ac10b-58cc-4372-a567-0e02b2c3d479 to uuid data structure.
1631 * @param[in] in in-string is 36 bytes + null termination (37 bytes in total).
1632 * @param[out] u uuid is a 16 byte unsigned character array.
1633 * @retval 0 OK
1634 * @retval -1 Error
1635 */
1636 int
str2uuid(char * in,uuid_t u)1637 str2uuid(char *in,
1638 uuid_t u)
1639 {
1640 int i = 0, j = 0, k;
1641 int a, b;
1642 int retval = -1;
1643
1644 if (strlen(in) != 36)
1645 return -1;
1646 for (k=0; k<4; k++){
1647 a = toint(in[j++]);
1648 b = toint(in[j++]);
1649 if (a < 0 || b < 0)
1650 goto done;
1651 u[i++] = (a << 4) | b;
1652 }
1653 if (in[j++] != '-')
1654 goto done;
1655 for (k=0; k<2; k++){
1656 a = toint(in[j++]); b = toint(in[j++]);
1657 if (a < 0 || b < 0)
1658 goto done;
1659 u[i++] = (a << 4) | b;
1660 }
1661 if (in[j++] != '-')
1662 goto done;
1663 for (k=0; k<2; k++){
1664 a = toint(in[j++]); b = toint(in[j++]);
1665 if (a < 0 || b < 0)
1666 goto done;
1667 u[i++] = (a << 4) | b;
1668 }
1669 if (in[j++] != '-')
1670 goto done;
1671 for (k=0; k<2; k++){
1672 a = toint(in[j++]); b = toint(in[j++]);
1673 if (a < 0 || b < 0)
1674 goto done;
1675 u[i++] = (a << 4) | b;
1676 }
1677 if (in[j++] != '-')
1678 goto done;
1679 for (k=0; k<6; k++){
1680 a = toint(in[j++]); b = toint(in[j++]);
1681 if (a < 0 || b < 0)
1682 goto done;
1683 u[i++] = (a << 4) | b;
1684 }
1685 if (in[j] != '\0')
1686 goto done;
1687 retval = 0;
1688 done:
1689 return retval;
1690 }
1691
1692 /*! Given a single digit character, return its number as int
1693 */
1694 static int
todig(char c)1695 todig(char c)
1696 {
1697 if (c >= '0' && c <= '9')
1698 return c - '0';
1699 return -1;
1700 }
1701
1702 /*! Given a string with digits, return a number
1703 * @param[in] n Number of digits to read from s.
1704 * @param[in] s String containing digits
1705 * @retval 0 OK
1706 * @retval -1 Error
1707 * eg if s is "23456" and nr is 3, then return 234.
1708 * @note works for positive numbers and up to 2^31
1709 */
1710 int
cligen_tonum(int n,char * s)1711 cligen_tonum(int n,
1712 char *s)
1713 {
1714 int i;
1715 int a;
1716 int sum = 0;
1717 int retval = -1;
1718
1719 for (i=0; i<n; i++){
1720 if ((a = todig(s[i])) < 0)
1721 goto done;
1722 sum *= 10;
1723 sum += a;
1724 }
1725 retval = sum;
1726 done:
1727 return retval;
1728 }
1729
1730 /*! Translate (ascii) ISO 8601 time string to (binary) timeval
1731 * Translate ISO 8601 date+time on the form 2008-09-21T18:57:21.003456Z to a timeval structure.
1732 * @param[in] in Input ISO 8601 string
1733 * @param[out] tv Timeval
1734 * @retval 0 OK
1735 * @retval -1 Error
1736 * T can be space.
1737 * in-string is upto 26 bytes + null termination (27 bytes in total).
1738 * out timestamp is a 4+4 integer struct timeval
1739 * returns 0 if OK parses. -1 if not correct.
1740 * usec can be 1-6 digits. That is, .3 means 300000 usec.
1741 * @note : string coming in is expected to be UTC and we parse that into a tm struct and
1742 * then call mktime(). Problem is mktime() assumes tm is localtime. Therefore we must
1743 * adjust the timeval with the timezone to get it right. (Should be a mktime() that is
1744 * UTC).
1745 * @note ISO 8601 accepts years 0000-9999, but struct timeval is more restricted. In this code between 1970-2104
1746 * @note Zone designator support have been added (2019-01) but are not stored.
1747 * @note You should be able to leave out less significant fields. That is, 2003 is
1748 * a time. But now you can only leave out usec.
1749 * @see time2str
1750 */
1751 int
str2time(char * in,struct timeval * tv)1752 str2time(char *in,
1753 struct timeval *tv)
1754 {
1755 int retval = -1;
1756 int i = 0;
1757 int j;
1758 int len;
1759 int year;
1760 int month;
1761 int day;
1762 int hour;
1763 int min;
1764 int sec;
1765 int usec = 0;
1766 struct tm *tm;
1767 time_t t;
1768 char frac[7];
1769
1770 if ((year = cligen_tonum(4, &in[i])) < 0)
1771 goto done;
1772 if (year < 1970 || year > 2104)
1773 goto done;
1774 i += 4;
1775 if (in[i++] != '-')
1776 goto done;
1777 if ((month = cligen_tonum(2, &in[i])) < 0)
1778 goto done;
1779 if (month < 1 || month > 12)
1780 goto done;
1781 i += 2;
1782 if (in[i++] != '-')
1783 goto done;
1784 if ((day = cligen_tonum(2, &in[i])) < 0)
1785 goto done;
1786 if (day < 1 || day > 31)
1787 goto done;
1788 i += 2;
1789 if (in[i] != 'T' && in[i] != ' ')
1790 goto done;
1791 i++;
1792 if ((hour = cligen_tonum(2, &in[i])) < 0)
1793 goto done;
1794 if (hour > 23)
1795 goto done;
1796 i += 2;
1797 if (in[i++] != ':')
1798 goto done;
1799 if ((min = cligen_tonum(2, &in[i])) < 0)
1800 goto done;
1801 if (min > 59)
1802 goto done;
1803 i += 2;
1804 if (in[i++] != ':')
1805 goto done;
1806 if ((sec = cligen_tonum(2, &in[i])) < 0)
1807 goto done;
1808 if (sec > 59)
1809 goto done;
1810 i += 2;
1811 switch (in[i]){
1812 case '\0':
1813 goto mkdate;
1814 break;
1815 case '.':
1816 i++;
1817 break;
1818 case 'Z':
1819 case '+':
1820 case '-':
1821 goto zone;
1822 default:
1823 goto done;
1824 break;
1825 }
1826 for (len=0; len<6; len++){
1827 if (isdigit(in[i+len]))
1828 frac[len] = in[i+len];
1829 else
1830 break;
1831 }
1832 if (len < 1)
1833 goto done;
1834 frac[len] = 0;
1835 if ((usec = cligen_tonum(len, frac)) < 0)
1836 goto done;
1837 for (j=0; j<6-len; j++)
1838 usec *= 10;
1839 if (usec > 999999)
1840 goto done;
1841 i += len;
1842 zone:
1843 switch (in[i]){
1844 case 'Z':
1845 i++;
1846 break;
1847 case '+':
1848 case '-': /* not parsed */
1849 goto mkdate;
1850 default:
1851 goto done;
1852 }
1853 if (in[i] != '\0')
1854 goto done;
1855 mkdate:
1856 if ((tm = calloc(1, sizeof(struct tm))) == NULL){
1857 fprintf(stderr, "calloc: %s\n", strerror(errno));
1858 goto done;
1859 }
1860 tm->tm_year = year - 1900;
1861 tm->tm_mon = month - 1;
1862 tm->tm_mday = day;
1863 tm->tm_hour = hour;
1864 tm->tm_min = min;
1865 tm->tm_sec = sec;
1866 if ((t = mktime(tm)) < 0)
1867 goto done;
1868 #if 0 /* If I enable this, I get 1h extra when loading from file in summer.
1869 When parsing a timestamp such as 2013-04-03T10:50:36 from file to cv
1870 (and db). So that when it is printed again it is 2013-04-03T11:50:36
1871 I dont know why I enabled it in the first place. That is why I make this
1872 note.
1873 */
1874 if (tm->tm_isdst) /* Daylight savings time */
1875 t += 3600; /* add hour */
1876 #endif
1877 /* Must adjust with timezone, since mktime() assumes tm i local but it is UTC! */
1878 #ifdef linux
1879 t = t - timezone;
1880 #else
1881 {
1882 struct timeval tv;
1883 struct timezone tz;
1884 gettimeofday(&tv, &tz);
1885 t = t - tz.tz_minuteswest*60;
1886 }
1887 #endif
1888 free(tm);
1889 tv->tv_sec = t;
1890 tv->tv_usec = usec;
1891 retval = 0;
1892 done:
1893 return retval;
1894 }
1895
1896 /*! Translate (binary) timeval to (ascii) ISO 8601 time string
1897 * from timeval to ISO 8601 date+time on the form 2008-09-21T18:57:21.003456Z
1898 * @param[in] tv Timeval
1899 * @param[out] fmt Format string.
1900 * @param[in] len Length of format string. Must be at least 28 bytes.
1901 * @retval 0 OK
1902 * @retval -1 Error
1903 * @code
1904 * char timestr[28];
1905 * struct timeval tv;
1906 * gettimeofday(&tv);
1907 * if (time2str(tv, timestr, sizeof(timestr)) < 0)
1908 * err;
1909 * printf("%s", timestr);
1910 * @endcode
1911 * @see str2time
1912 */
1913 int
time2str(struct timeval tv,char * fmt,int len)1914 time2str(struct timeval tv,
1915 char *fmt,
1916 int len)
1917 {
1918 int retval = -1;
1919 struct tm *tm;
1920
1921 tm = gmtime((time_t*)&tv.tv_sec);
1922 if (snprintf(fmt, len, "%04d-%02d-%02dT%02d:%02d:%02d.%06ldZ",
1923 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour,
1924 tm->tm_min, tm->tm_sec, tv.tv_usec) < 0)
1925 goto done;
1926 retval = 0;
1927 done:
1928 return retval;
1929 }
1930
1931 /*! Translate (parse) a string to a CV type.
1932 * @param[in] str Name of type
1933 * @retval type CLIgen variable type
1934 */
1935 enum cv_type
cv_str2type(char * str)1936 cv_str2type(char *str)
1937 {
1938 if (strcmp(str, "int8") == 0)
1939 return CGV_INT8;
1940 if (strcmp(str, "int16") == 0)
1941 return CGV_INT16;
1942 if (strcmp(str, "int32") == 0)
1943 return CGV_INT32;
1944 if (strcmp(str, "int64") == 0)
1945 return CGV_INT64;
1946 if (strcmp(str, "uint8") == 0)
1947 return CGV_UINT8;
1948 if (strcmp(str, "uint16") == 0)
1949 return CGV_UINT16;
1950 if (strcmp(str, "uint32") == 0)
1951 return CGV_UINT32;
1952 if (strcmp(str, "uint64") == 0)
1953 return CGV_UINT64;
1954 if (strcmp(str, "decimal64") == 0)
1955 return CGV_DEC64;
1956 if (strcmp(str, "bool") == 0)
1957 return CGV_BOOL;
1958 if (strcmp(str, "string") == 0)
1959 return CGV_STRING;
1960 if (strcmp(str, "rest") == 0)
1961 return CGV_REST;
1962 if (strcmp(str, "interface") == 0)
1963 return CGV_INTERFACE;
1964 if (strcmp(str,"ipaddr") == 0 || strcmp(str,"ipv4addr") == 0)
1965 return CGV_IPV4ADDR;
1966 if (strcmp(str,"ipv4prefix") == 0)
1967 return CGV_IPV4PFX;
1968 if (strcmp(str,"ipv6addr") == 0)
1969 return CGV_IPV6ADDR;
1970 if (strcmp(str,"ipv6prefix") == 0)
1971 return CGV_IPV6PFX;
1972 if (strcmp(str,"macaddr") == 0)
1973 return CGV_MACADDR;
1974 if (strcmp(str,"url") == 0)
1975 return CGV_URL;
1976 if (strcmp(str,"uuid") == 0)
1977 return CGV_UUID;
1978 if (strcmp(str,"time") == 0)
1979 return CGV_TIME;
1980 if (strcmp(str,"void") == 0)
1981 return CGV_VOID; /* N/A */
1982 if (strcmp(str,"empty") == 0)
1983 return CGV_EMPTY;
1984 return CGV_ERR;
1985 }
1986
1987 /*! Translate (print) a cv type to a static string.
1988 * @param[in] tpe CLIgen variable type
1989 * @retval NULL Error
1990 * @retval str Static string containing name of type as ASCII string
1991 */
1992 char *
cv_type2str(enum cv_type type)1993 cv_type2str(enum cv_type type)
1994 {
1995 char *str = NULL;
1996 switch (type){
1997 case CGV_ERR:
1998 str="err";
1999 break;
2000 case CGV_INT8:
2001 str="int8";
2002 break;
2003 case CGV_INT16:
2004 str="int16";
2005 break;
2006 case CGV_INT32:
2007 str="int32";
2008 break;
2009 case CGV_INT64:
2010 str="int64";
2011 break;
2012 case CGV_UINT8:
2013 str="uint8";
2014 break;
2015 case CGV_UINT16:
2016 str="uint16";
2017 break;
2018 case CGV_UINT32:
2019 str="uint32";
2020 break;
2021 case CGV_UINT64:
2022 str="uint64";
2023 break;
2024 case CGV_DEC64:
2025 str="decimal64";
2026 break;
2027 case CGV_BOOL:
2028 str="bool";
2029 break;
2030 case CGV_STRING:
2031 str="string";
2032 break;
2033 case CGV_REST:
2034 str="rest";
2035 break;
2036 case CGV_INTERFACE:
2037 str="interface";
2038 break;
2039 case CGV_IPV4ADDR:
2040 str="ipv4addr";
2041 break;
2042 case CGV_IPV4PFX:
2043 str="ipv4prefix";
2044 break;
2045 case CGV_IPV6ADDR:
2046 str="ipv6addr";
2047 break;
2048 case CGV_IPV6PFX:
2049 str="ipv6prefix";
2050 break;
2051 case CGV_MACADDR:
2052 str="macaddr";
2053 break;
2054 case CGV_URL:
2055 str="url";
2056 break;
2057 case CGV_UUID:
2058 str="uuid";
2059 break;
2060 case CGV_TIME:
2061 str="time";
2062 break;
2063 case CGV_VOID:
2064 str="void";
2065 break;
2066 case CGV_EMPTY:
2067 str="empty";
2068 break;
2069 default:
2070 fprintf(stderr, "%s: invalid type: %d\n", __FUNCTION__, type);
2071 break;
2072 }
2073 return str;
2074 }
2075
2076 /*! Return length of cligen variable value (as stored in binary)
2077 *
2078 * @param[in] cv CLIgen variable
2079 * @retval len Length of variable
2080 * Special with strings that are only pointed to by the variable.
2081 * In that case the lengths of the strings pointed to are added, trailing
2082 * null included.
2083 */
2084 int
cv_len(cg_var * cv)2085 cv_len(cg_var *cv)
2086 {
2087 int len = 0;
2088
2089 switch (cv->var_type){
2090 case CGV_INT8:
2091 len = sizeof(cv->var_int8);
2092 break;
2093 case CGV_INT16:
2094 len = sizeof(cv->var_int16);
2095 break;
2096 case CGV_INT32:
2097 len = sizeof(cv->var_int32);
2098 break;
2099 case CGV_INT64:
2100 len = sizeof(cv->var_int64);
2101 break;
2102 case CGV_UINT8:
2103 len = sizeof(cv->var_uint8);
2104 break;
2105 case CGV_UINT16:
2106 len = sizeof(cv->var_uint16);
2107 break;
2108 case CGV_UINT32:
2109 len = sizeof(cv->var_uint32);
2110 break;
2111 case CGV_UINT64:
2112 len = sizeof(cv->var_uint64);
2113 break;
2114 case CGV_DEC64:
2115 len = sizeof(cv->var_dec64_i) + sizeof(cv->var_dec64_n);
2116 break;
2117 case CGV_BOOL:
2118 len = sizeof(cv->var_bool);
2119 break;
2120 case CGV_REST:
2121 len = (cv->var_rest ? strlen(cv->var_rest) : 0) + 1;
2122 break;
2123 case CGV_STRING:
2124 len = (cv->var_string ? strlen(cv->var_string) : 0) + 1;
2125 break;
2126 case CGV_INTERFACE:
2127 len = (cv->var_interface ? strlen(cv->var_interface) : 0) + 1;
2128 break;
2129 case CGV_IPV4ADDR:
2130 len = sizeof(cv->var_ipv4addr);
2131 break;
2132 case CGV_IPV4PFX:
2133 len = sizeof(cv->u.varu_ipv4addr);
2134 break;
2135 case CGV_IPV6ADDR:
2136 len = sizeof(cv->var_ipv6addr);
2137 break;
2138 case CGV_IPV6PFX:
2139 len = sizeof(cv->u.varu_ipv6addr);
2140 break;
2141 case CGV_MACADDR:
2142 len = sizeof(cv->var_macaddr);
2143 break;
2144 case CGV_URL:
2145 len = (cv->var_urlproto ? strlen(cv->var_urlproto):0) + 1 +
2146 (cv->var_urladdr ? strlen(cv->var_urladdr):0) + 1 +
2147 (cv->var_urlpath ? strlen(cv->var_urlpath):0) + 1 +
2148 (cv->var_urluser ? strlen(cv->var_urluser):0) + 1 +
2149 (cv->var_urlpasswd ? strlen(cv->var_urlpasswd):0) + 1;
2150 break;
2151 case CGV_UUID:
2152 len = sizeof(cv->var_uuid);
2153 break;
2154 case CGV_TIME:
2155 len = sizeof(cv->var_time);
2156 break;
2157 case CGV_VOID:
2158 len = sizeof(void*); /* N/A */
2159 break;
2160 case CGV_EMPTY:
2161 len = 0;
2162 break;
2163 default:
2164 break;
2165 }
2166 return len;
2167 }
2168
2169 /*! Print a dec64 cv to a string
2170 *
2171 * @param[in] cv A cligen variable of type CGV_DEC64 to print
2172 * @param[out] s0 A string that will hold the dec64
2173 * @param[inout] len A string that holds available free space in s0
2174 * @retval 0 OK
2175 * @retval -1 Error with error msg on stderr.
2176 */
2177 static int
cv_dec64_print(cg_var * cv,char * s0,int * s0len)2178 cv_dec64_print(cg_var *cv,
2179 char *s0,
2180 int *s0len)
2181 {
2182 int i;
2183 uint8_t n = cv->var_dec64_n;;
2184 int len;
2185 int64_t di;
2186
2187 assert(0<n && n<19);
2188 /* Convert negative numbers to positive and prepend a '-' at the end */
2189 di = cv_dec64_i_get(cv);
2190 if (di<0)
2191 di = -di;
2192 len = snprintf(s0, *s0len, "%0*" PRId64, n+1, di);
2193 assert(len>=n);
2194 *s0len -= len;
2195 /* Shift fraction digits right, including null character.
2196 * eg: xyz --> x.yz (if n==2)
2197 */
2198 for (i=len; i>=len-n; i--)
2199 s0[i+1] = s0[i];
2200 (*s0len)--;
2201 s0[len-n] = '.';
2202 /* prepend a '-' if the number is negative*/
2203 if (cv_dec64_i_get(cv)<0){
2204 for (i=len+1; i>=0; i--)
2205 s0[i+1] = s0[i];
2206 s0[0] = '-';
2207 (*s0len)--;
2208 }
2209 return 0;
2210 }
2211
2212 /*! Print value of CLIgen variable to CLIgen buf using printf style formats.
2213 * @param[in] cv CLIgen variable
2214 * @param[out] cb Value printed
2215 * The params shuld be switched cb<->cv
2216 */
2217 int
cv2cbuf(cg_var * cv,cbuf * cb)2218 cv2cbuf(cg_var *cv,
2219 cbuf *cb)
2220 {
2221 char straddr[INET6_ADDRSTRLEN];
2222 char ss[64];
2223 int sslen = sizeof(ss);
2224 char uuidstr[37];
2225 char timestr[28];
2226
2227 switch (cv->var_type){
2228 case CGV_INT8:
2229 cprintf(cb, "%" PRId8, cv->var_int8);
2230 break;
2231 case CGV_INT16:
2232 cprintf(cb, "%" PRId16, cv->var_int16);
2233 break;
2234 case CGV_INT32:
2235 cprintf(cb, "%" PRId32, cv->var_int32);
2236 break;
2237 case CGV_INT64:
2238 cprintf(cb, "%" PRId64, cv->var_int64);
2239 break;
2240 case CGV_UINT8:
2241 cprintf(cb, "%" PRIu8, cv->var_uint8);
2242 break;
2243 case CGV_UINT16:
2244 cprintf(cb, "%" PRIu16, cv->var_uint16);
2245 break;
2246 case CGV_UINT32:
2247 cprintf(cb, "%" PRIu32, cv->var_uint32);
2248 break;
2249 case CGV_UINT64:
2250 cprintf(cb, "%" PRIu64, cv->var_uint64);
2251 break;
2252 case CGV_DEC64:
2253 cv_dec64_print(cv, ss, &sslen);
2254 cprintf(cb, "%s", ss);
2255 break;
2256 case CGV_BOOL:
2257 if (cv->var_bool)
2258 cprintf(cb, "true");
2259 else
2260 cprintf(cb, "false");
2261 break;
2262 case CGV_REST:
2263 cprintf(cb, "%s", cv->var_rest);
2264 break;
2265 case CGV_STRING:
2266 cprintf(cb, "%s", cv->var_string);
2267 break;
2268 case CGV_INTERFACE:
2269 cprintf(cb, "%s", cv->var_interface);
2270 break;
2271 case CGV_IPV4ADDR:
2272 cprintf(cb, "%s", inet_ntoa(cv->var_ipv4addr));
2273 break;
2274 case CGV_IPV4PFX:
2275 cprintf(cb, "%s/%u",
2276 inet_ntoa (cv->var_ipv4addr),
2277 cv->var_ipv4masklen);
2278 break;
2279 case CGV_IPV6ADDR:
2280 if (inet_ntop(AF_INET6, &cv->var_ipv6addr, straddr, sizeof(straddr)) < 0){
2281 fprintf(stderr, "inet_ntop: %s\n", strerror(errno));
2282 return -1;
2283 }
2284 cprintf(cb, "%s", straddr);
2285 break;
2286 case CGV_IPV6PFX:
2287 if (inet_ntop(AF_INET6, &cv->var_ipv6addr, straddr, sizeof(straddr)) < 0){
2288 fprintf(stderr, "inet_ntop: %s\n", strerror(errno));
2289 return -1;
2290 }
2291 cprintf(cb, "%s/%u", straddr, cv->var_ipv6masklen);
2292 break;
2293 case CGV_MACADDR:
2294 cprintf(cb, "%02x:%02x:%02x:%02x:%02x:%02x",
2295 (uint8_t)cv->var_macaddr[0],
2296 (uint8_t)cv->var_macaddr[1],
2297 (uint8_t)cv->var_macaddr[2],
2298 (uint8_t)cv->var_macaddr[3],
2299 (uint8_t)cv->var_macaddr[4],
2300 (uint8_t)cv->var_macaddr[5]);
2301 break;
2302 case CGV_URL: /* <proto>://[<user>[:<passwd>]@]<addr>[/<path>] */
2303 cprintf(cb, "%s://%s%s%s%s%s/%s",
2304 cv->var_urlproto,
2305 cv->var_urluser,
2306 strlen(cv->var_urlpasswd)?":":"",
2307 cv->var_urlpasswd,
2308 strlen(cv->var_urluser)||strlen(cv->var_urlpasswd)?"@":"",
2309 cv->var_urladdr,
2310 cv->var_urlpath
2311 );
2312 break;
2313 case CGV_UUID:
2314 uuid2str(cv->var_uuid, uuidstr, sizeof(uuidstr));
2315 cprintf(cb, "%s", uuidstr);
2316 break;
2317 case CGV_TIME:
2318 time2str(cv->var_time, timestr, sizeof(timestr));
2319 cprintf(cb, "%s", timestr);
2320 break;
2321 case CGV_VOID: /* N/A */
2322 case CGV_EMPTY:
2323 break;
2324 default:
2325 break;
2326 }
2327 return 0;
2328 }
2329
2330 /*! Print value of CLIgen variable using printf style formats.
2331 *
2332 * You can use str=NULL to get the expected length.
2333 * The number of (potentially if str=NULL) written bytes is returned.
2334 * The value is printed as it would have been input, ie the reverse of
2335 * parsing.
2336 * Typically used by external code when transforming cgv:s.
2337 * Note, for strings, the length returned is _excluding_ the null byte, but the length
2338 * in supplied in the argument list is _including_ the null byte.
2339 * @param[in] cv CLIgen variable
2340 * @param[out] str Value printed in this string
2341 * @param[in] size Length of 'str'
2342 * @retval len How many bytes printed
2343 * @see cv2cbuf which also prints a CV but to cbuf
2344 * @see cv_print which also prints a CV but to a file
2345 */
2346 int
cv2str(cg_var * cv,char * str,size_t size)2347 cv2str(cg_var *cv,
2348 char *str,
2349 size_t size)
2350 {
2351 int len = 0;
2352 char straddr[INET6_ADDRSTRLEN];
2353 char ss[64];
2354 int sslen = sizeof(ss);
2355 char uuidstr[37];
2356 char timestr[28];
2357
2358 if (cv == NULL)
2359 return 0;
2360 switch (cv->var_type){
2361 case CGV_INT8:
2362 len = snprintf(str, size, "%" PRId8, cv->var_int8);
2363 break;
2364 case CGV_INT16:
2365 len = snprintf(str, size, "%" PRId16, cv->var_int16);
2366 break;
2367 case CGV_INT32:
2368 len = snprintf(str, size, "%" PRId32, cv->var_int32);
2369 break;
2370 case CGV_INT64:
2371 len = snprintf(str, size, "%" PRId64, cv->var_int64);
2372 break;
2373 case CGV_UINT8:
2374 len = snprintf(str, size, "%" PRIu8, cv->var_uint8);
2375 break;
2376 case CGV_UINT16:
2377 len = snprintf(str, size, "%" PRIu16, cv->var_uint16);
2378 break;
2379 case CGV_UINT32:
2380 len = snprintf(str, size, "%" PRIu32, cv->var_uint32);
2381 break;
2382 case CGV_UINT64:
2383 len = snprintf(str, size, "%" PRIu64, cv->var_uint64);
2384 break;
2385 case CGV_DEC64:
2386 cv_dec64_print(cv, ss, &sslen);
2387 len = snprintf(str, size, "%s", ss);
2388 break;
2389 case CGV_BOOL:
2390 if (cv->var_bool)
2391 len = snprintf(str, size, "true");
2392 else
2393 len = snprintf(str, size, "false");
2394 break;
2395 case CGV_REST:
2396 len = snprintf(str, size, "%s", cv->var_rest);
2397 break;
2398 case CGV_STRING:
2399 len = snprintf(str, size, "%s", cv->var_string);
2400 break;
2401 case CGV_INTERFACE:
2402 len = snprintf(str, size, "%s", cv->var_interface);
2403 break;
2404 case CGV_IPV4ADDR:
2405 len = snprintf(str, size, "%s", inet_ntoa(cv->var_ipv4addr));
2406 break;
2407 case CGV_IPV4PFX:
2408 len = snprintf(str, size, "%s/%u",
2409 inet_ntoa (cv->var_ipv4addr),
2410 cv->var_ipv4masklen);
2411 break;
2412 case CGV_IPV6ADDR:
2413 if (inet_ntop(AF_INET6, &cv->var_ipv6addr, straddr, sizeof(straddr)) < 0){
2414 fprintf(stderr, "inet_ntop: %s\n", strerror(errno));
2415 return -1;
2416 }
2417 len = snprintf(str, size, "%s", straddr);
2418 break;
2419 case CGV_IPV6PFX:
2420 if (inet_ntop(AF_INET6, &cv->var_ipv6addr, straddr, sizeof(straddr)) < 0){
2421 fprintf(stderr, "inet_ntop: %s\n", strerror(errno));
2422 return -1;
2423 }
2424 len = snprintf(str, size, "%s/%u", straddr, cv->var_ipv6masklen);
2425 break;
2426 case CGV_MACADDR:
2427 len = snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x",
2428 (uint8_t)cv->var_macaddr[0],
2429 (uint8_t)cv->var_macaddr[1],
2430 (uint8_t)cv->var_macaddr[2],
2431 (uint8_t)cv->var_macaddr[3],
2432 (uint8_t)cv->var_macaddr[4],
2433 (uint8_t)cv->var_macaddr[5]);
2434
2435 break;
2436 case CGV_URL: /* <proto>://[<user>[:<passwd>]@]<addr>[/<path>] */
2437 len = snprintf(str, size, "%s://%s%s%s%s%s/%s",
2438 cv->var_urlproto,
2439 cv->var_urluser,
2440 strlen(cv->var_urlpasswd)?":":"",
2441 cv->var_urlpasswd,
2442 strlen(cv->var_urluser)||strlen(cv->var_urlpasswd)?"@":"",
2443 cv->var_urladdr,
2444 cv->var_urlpath
2445 );
2446 break;
2447 case CGV_UUID:
2448 uuid2str(cv->var_uuid, uuidstr, sizeof(uuidstr));
2449 len = snprintf(str, size, "%s", uuidstr);
2450 break;
2451 case CGV_TIME:
2452 time2str(cv->var_time, timestr, sizeof(timestr));
2453 len = snprintf(str, size, "%s", timestr);
2454 break;
2455 case CGV_VOID: /* N/A */
2456 case CGV_EMPTY:
2457 break;
2458 default:
2459 break;
2460 }
2461 return len;
2462 }
2463
2464 /*! Print value of CLIgen variable using printf style formats into a new string
2465 *
2466 * @param[in] cv CLIgen variable
2467 * @retval str Malloced string containing value. Should be freed after use.
2468 * @see cv2str
2469 */
2470 char *
cv2str_dup(cg_var * cv)2471 cv2str_dup(cg_var *cv)
2472 {
2473 int len;
2474 char *str;
2475
2476 if (cv == NULL)
2477 return NULL;
2478 if ((len = cv2str (cv, NULL, 0)) < 0)
2479 return NULL;
2480 if ((str = (char *)malloc(len+1)) == NULL)
2481 return NULL;
2482 memset(str, '\0', len+1);
2483 if ((cv2str(cv, str, len+1)) < 0){
2484 free(str);
2485 return NULL;
2486 }
2487 return str;
2488 }
2489
2490 /*! Pretty print cligen variable value to a file
2491 *
2492 * @see cv2str which also prints a CV but to a string
2493 */
2494 int
cv_print(FILE * f,cg_var * cv)2495 cv_print(FILE *f,
2496 cg_var *cv)
2497 {
2498 int len = 0;
2499 char straddr[INET6_ADDRSTRLEN];
2500 char ss[64];
2501 int sslen = sizeof(ss);
2502 char uuidstr[37];
2503 char timestr[28];
2504
2505 switch (cv->var_type){
2506 case CGV_INT8:
2507 fprintf(f, "%" PRId8, cv->var_int8);
2508 break;
2509 case CGV_INT16:
2510 fprintf(f, "%" PRId16, cv->var_int16);
2511 break;
2512 case CGV_INT32:
2513 fprintf(f, "%" PRId32, cv->var_int32);
2514 break;
2515 case CGV_INT64:
2516 fprintf(f, "%" PRId64, cv->var_int64);
2517 break;
2518 case CGV_UINT8:
2519 fprintf(f, "%" PRIu8, cv->var_uint8);
2520 break;
2521 case CGV_UINT16:
2522 fprintf(f, "%" PRIu16, cv->var_uint16);
2523 break;
2524 case CGV_UINT32:
2525 fprintf(f, "%" PRIu32, cv->var_uint32);
2526 break;
2527 case CGV_UINT64:
2528 fprintf(f, "%" PRIu64, cv->var_uint64);
2529 break;
2530 case CGV_DEC64:
2531 cv_dec64_print(cv, ss, &sslen);
2532 fprintf(f, "%s", ss);
2533 break;
2534 case CGV_BOOL:
2535 if (cv->var_bool)
2536 fprintf(f, "true");
2537 else
2538 fprintf(f, "false");
2539 break;
2540 case CGV_REST:
2541 fprintf(f, "%s", cv->var_rest);
2542 break;
2543 case CGV_STRING:
2544 fprintf(f, "\"%s\"", cv->var_string);
2545 break;
2546 case CGV_INTERFACE:
2547 fprintf(f, "\"%s\"", cv->var_interface);
2548 break;
2549 case CGV_IPV4ADDR:
2550 fprintf(f, "%s", inet_ntoa(cv->var_ipv4addr));
2551 break;
2552 case CGV_IPV4PFX:
2553 fprintf(f, "%s/%d", inet_ntoa(cv->var_ipv4addr), cv->var_ipv4masklen);
2554 break;
2555 case CGV_IPV6ADDR:
2556 if (inet_ntop(AF_INET6, &cv->var_ipv6addr, straddr, sizeof(straddr)) < 0){
2557 fprintf(stderr, "inet_ntop: %s\n", strerror(errno));
2558 return -1;
2559 }
2560 fprintf(f, "%s", straddr);
2561 break;
2562 case CGV_IPV6PFX:
2563 if (inet_ntop(AF_INET6, &cv->var_ipv6addr, straddr, sizeof(straddr)) < 0){
2564 fprintf(stderr, "inet_ntop: %s\n", strerror(errno));
2565 return -1;
2566 }
2567 fprintf(f, "%s/%d", straddr, cv->var_ipv4masklen);
2568 break;
2569 case CGV_MACADDR:
2570 fprintf(f, "%02x:%02x:%02x:%02x:%02x:%02x",
2571 cv->var_macaddr[0],
2572 cv->var_macaddr[1],
2573 cv->var_macaddr[2],
2574 cv->var_macaddr[3],
2575 cv->var_macaddr[4],
2576 cv->var_macaddr[5]);
2577
2578 break;
2579 case CGV_URL: /* <proto>://[<user>[:<passwd>]@]<addr>[/<path>] */
2580 fprintf(f, "%s://%s%s%s%s%s/%s",
2581 cv->var_urlproto,
2582 cv->var_urluser,
2583 strlen(cv->var_urlpasswd)?":":"",
2584 cv->var_urlpasswd,
2585 strlen(cv->var_urluser)||strlen(cv->var_urlpasswd)?"@":"",
2586 cv->var_urladdr,
2587 cv->var_urlpath
2588 );
2589 break;
2590 case CGV_UUID:
2591 uuid2str(cv->var_uuid, uuidstr, sizeof(uuidstr));
2592 fprintf(f, "%s", uuidstr);
2593 break;
2594 case CGV_TIME:
2595 time2str(cv->var_time, timestr, sizeof(timestr));
2596 fprintf(f, "%s", timestr);
2597 break;
2598 case CGV_VOID: /* N/A */
2599 case CGV_EMPTY: /* N/A */
2600 break;
2601 default:
2602 break;
2603 }
2604 return len;
2605 }
2606
2607 /*! Print max value of a CLIgen variable type as string
2608 * @param[in] type CLIgen variable type
2609 * @param[out] str Max value printed in this string
2610 * @param[in] size Length of 'str'
2611 * @retval len How many bytes printed
2612 * @see cvtype_max2str_dup
2613 * You can use str=NULL to get the expected length.
2614 * The number of (potentially if str=NULL) written bytes is returned.
2615 * @note DEC64 type does not work, need fraction-digits,... use cv_max_set
2616 * @see cv_max_set
2617 */
2618 int
cvtype_max2str(enum cv_type type,char * str,size_t size)2619 cvtype_max2str(enum cv_type type,
2620 char *str,
2621 size_t size)
2622 {
2623 int len = 0;
2624
2625 switch (type){
2626 case CGV_INT8:
2627 len = snprintf(str, size, "%" PRId8, INT8_MAX);
2628 break;
2629 case CGV_INT16:
2630 len = snprintf(str, size, "%" PRId16, INT16_MAX);
2631 break;
2632 case CGV_INT32:
2633 len = snprintf(str, size, "%" PRId32, INT32_MAX);
2634 break;
2635 case CGV_INT64:
2636 len = snprintf(str, size, "%" PRId64, INT64_MAX);
2637 break;
2638 case CGV_UINT8:
2639 len = snprintf(str, size, "%" PRIu8, UINT8_MAX);
2640 break;
2641 case CGV_UINT16:
2642 len = snprintf(str, size, "%" PRIu16, UINT16_MAX);
2643 break;
2644 case CGV_UINT32:
2645 len = snprintf(str, size, "%" PRIu32, UINT32_MAX);
2646 break;
2647 case CGV_UINT64:
2648 len = snprintf(str, size, "%" PRIu64, UINT64_MAX);
2649 break;
2650 case CGV_DEC64:
2651 len = snprintf(str, size, "%" PRId64 ".0", INT64_MAX);
2652 break;
2653 case CGV_BOOL:
2654 len = snprintf(str, size, "true");
2655 break;
2656 default:
2657 break;
2658 }
2659 return len;
2660 }
2661
2662 /*! Print max value of a CLIgen variable type as string
2663 *
2664 * The string should be freed after use.
2665 * @param[in] type CLIgen variable type
2666 * @retval str Malloced string containing value. Should be freed after use.
2667 * @see cvtype_max2str
2668 * @note DEC64 type does not work, need fraction-digits,... use cv_max_set
2669 * @see cv_max_set
2670 */
2671 char *
cvtype_max2str_dup(enum cv_type type)2672 cvtype_max2str_dup(enum cv_type type)
2673 {
2674 int len;
2675 char *str;
2676
2677 if ((len = cvtype_max2str(type, NULL, 0)) < 0)
2678 return NULL;
2679 if ((str = (char *)malloc(len+1)) == NULL)
2680 return NULL;
2681 memset(str, '\0', len+1);
2682 if ((cvtype_max2str(type, str, len+1)) < 0){
2683 free(str);
2684 return NULL;
2685 }
2686 return str;
2687 }
2688
2689 int
cv_max_set(cg_var * cv)2690 cv_max_set(cg_var *cv)
2691 {
2692 switch (cv->var_type){
2693 case CGV_INT8:
2694 cv->var_int8 = INT8_MAX;
2695 break;
2696 case CGV_INT16:
2697 cv->var_int16 = INT16_MAX;
2698 break;
2699 case CGV_INT32:
2700 cv->var_int32 = INT32_MAX;
2701 break;
2702 case CGV_INT64:
2703 cv->var_int64 = INT64_MAX;
2704 break;
2705 case CGV_UINT8:
2706 cv->var_uint8 = UINT8_MAX;
2707 break;
2708 case CGV_UINT16:
2709 cv->var_uint16 = UINT16_MAX;
2710 break;
2711 case CGV_UINT32:
2712 cv->var_uint32 = UINT32_MAX;
2713 break;
2714 case CGV_UINT64:
2715 cv->var_uint64 = UINT64_MAX;
2716 break;
2717 case CGV_DEC64: /* assume fraction-digits is set to something */
2718 cv->var_uint64 = INT64_MAX;
2719 break;
2720 case CGV_BOOL:
2721 cv->var_bool = 1;
2722 break;
2723 default:
2724 break;
2725 }
2726 return 0;
2727 }
2728
2729 int
cv_min_set(cg_var * cv)2730 cv_min_set(cg_var *cv)
2731 {
2732 switch (cv->var_type){
2733 case CGV_INT8:
2734 cv->var_int8 = INT8_MIN;
2735 break;
2736 case CGV_INT16:
2737 cv->var_int16 = INT16_MIN;
2738 break;
2739 case CGV_INT32:
2740 cv->var_int32 = INT32_MIN;
2741 break;
2742 case CGV_INT64:
2743 cv->var_int64 = INT64_MIN;
2744 break;
2745 case CGV_UINT8:
2746 cv->var_uint8 = 0;
2747 break;
2748 case CGV_UINT16:
2749 cv->var_uint16 = 0;
2750 break;
2751 case CGV_UINT32:
2752 cv->var_uint32 = 0;
2753 break;
2754 case CGV_UINT64:
2755 cv->var_uint64 = 0;
2756 break;
2757 case CGV_DEC64: /* assume fraction-digits is set to something */
2758 cv->var_uint64 = INT64_MIN;
2759 break;
2760 case CGV_BOOL:
2761 cv->var_bool = 0;
2762 break;
2763 default:
2764 break;
2765 }
2766 return 0;
2767 }
2768
2769 /*! Parse cv from string.
2770 *
2771 * This function expects an initialized cv as created by cv_new() or
2772 * prepared by cv_reset().
2773 * The following is required of a cv before calling this function:
2774 * - A type field. So that the parser knows how to parse the string
2775 * - For decimal64 the fraction_digits (n) must be known.
2776 *
2777 * See also cv_parse() which has simpler error handling.
2778 * and cv_validate() where the cv is validated against a cligen object specification.
2779 *
2780 * @param[in] str0 Input string. Example, number variable, str can be "7834" or "0x7634"
2781 * @param[in] cv cligen variable, as prepared by cv_reset()/cv_new()
2782 * @param[out] reason If given, and if return value is 0, contains a malloced string
2783 * describing the reason why the validation failed. If given must be NULL.
2784 *
2785 * @retval -1 Error (fatal), with errno set to indicate error
2786 * @retval 0 Validation not OK, malloced reason is returned
2787 * @retval 1 Validation OK
2788 *
2789 * @code
2790 * cg_var *cv = cv_new(CGV_STRING);
2791 * char *reason=NULL;
2792 * if (cv_parse1("mystring", cv, &reason) < 0)
2793 * cv_free(cv);
2794 * free(reason);
2795 * @endcode
2796 */
2797 int
cv_parse1(char * str0,cg_var * cv,char ** reason)2798 cv_parse1(char *str0,
2799 cg_var *cv,
2800 char **reason)
2801 {
2802 int retval = -1;
2803 char *str;
2804 char *mask;
2805 int masklen;
2806 int i, j;
2807
2808 if (reason && (*reason != NULL)){
2809 fprintf(stderr, "reason must be NULL on calling\n");
2810 return -1;
2811 }
2812 if (str0 == NULL){
2813 if ((str = strdup("")) == NULL)
2814 goto done;
2815 }
2816 else
2817 if ((str = strdup(str0)) == NULL)
2818 goto done;
2819 switch (cv->var_type) {
2820 case CGV_INT8:
2821 retval = parse_int8(str, &cv->var_int8, reason);
2822 break;
2823 case CGV_INT16:
2824 retval = parse_int16(str, &cv->var_int16, reason);
2825 break;
2826 case CGV_INT32:
2827 retval = parse_int32(str, &cv->var_int32, reason);
2828 break;
2829 case CGV_INT64:
2830 retval = parse_int64(str, &cv->var_int64, reason);
2831 break;
2832 case CGV_UINT8:
2833 retval = parse_uint8(str, &cv->var_uint8, reason);
2834 break;
2835 case CGV_UINT16:
2836 retval = parse_uint16(str, &cv->var_uint16, reason);
2837 break;
2838 case CGV_UINT32:
2839 retval = parse_uint32(str, &cv->var_uint32, reason);
2840 break;
2841 case CGV_UINT64:
2842 retval = parse_uint64(str, &cv->var_uint64, reason);
2843 break;
2844 case CGV_DEC64:
2845 retval = parse_dec64(str, cv_dec64_n_get(cv), &cv->var_dec64_i, reason);
2846 break;
2847 case CGV_BOOL:
2848 retval = parse_bool(str, &cv->var_bool, reason);
2849 break;
2850 case CGV_REST:
2851 j = 0; /* decode string, remove \<delimiters */
2852 for (i=0;i<strlen(str);i++)
2853 if (str[i] != '\\')
2854 str[j++] = str[i];
2855 for (;j<strlen(str);j++)
2856 str[j] = '\0';
2857 if (cv->var_rest)
2858 free(cv->var_rest);
2859 if ((cv->var_rest = strdup(str)) == NULL)
2860 goto done;
2861 retval = 1;
2862 break;
2863 case CGV_STRING:
2864 j = 0; /* decode string, remove \<delimiters */
2865 for (i=0;i<strlen(str);i++)
2866 if (str[i] != '\\')
2867 str[j++] = str[i];
2868 for (;j<strlen(str);j++)
2869 str[j] = '\0';
2870 if (cv->var_string){
2871 free(cv->var_string);
2872 cv->var_string = NULL;
2873 }
2874 if ((cv->var_string = strdup(str)) == NULL)
2875 goto done;
2876 retval = 1;
2877 break;
2878 case CGV_INTERFACE:
2879 if (cv->var_interface)
2880 free(cv->var_interface);
2881 if ((cv->var_interface = strdup(str)) == NULL)
2882 goto done;
2883 retval = 1;
2884 break;
2885 case CGV_IPV4ADDR:
2886 cv->var_ipv4masklen = 32;
2887 retval = parse_ipv4addr(str, &cv->var_ipv4addr, reason);
2888 break;
2889 case CGV_IPV6ADDR:
2890 cv->var_ipv6masklen = 128;
2891 retval = parse_ipv6addr(str, &cv->var_ipv6addr, reason);
2892 break;
2893 case CGV_IPV4PFX:
2894 if ((mask = strchr (str, '/')) == NULL){
2895 retval = 0;
2896 if (reason)
2897 if ((*reason = cligen_reason("Mask-length missing")) == NULL)
2898 retval = -1;
2899 goto done;
2900 }
2901 *mask++ = '\0';
2902 if ((retval = parse_int32(mask, &masklen, reason)) <= 0)
2903 break;
2904 if (masklen > 32 || masklen < 0) {
2905 retval = 0;
2906 if (reason)
2907 if ((*reason = cligen_reason("Mask-length %s out of range:0 - 32", mask)) == NULL)
2908 retval = -1;
2909 goto done;
2910 }
2911 cv->var_ipv4masklen = masklen;
2912 retval = parse_ipv4addr(str, &cv->var_ipv4addr, reason);
2913 break;
2914 case CGV_IPV6PFX:
2915 if ((mask = strchr (str, '/')) == NULL){
2916 retval = 0;
2917 if (reason)
2918 if ((*reason = cligen_reason("Mask-length missing")) == NULL)
2919 retval = -1;
2920 goto done;
2921 }
2922 *mask++ = '\0';
2923 if ((retval = parse_int32(mask, &masklen, reason)) <= 0)
2924 break;
2925 if (masklen > 128 || masklen < 0) {
2926 retval = 0;
2927 if (reason &&
2928 (*reason = cligen_reason("Mask-length %s out of range: 0 - 128", mask))==NULL)
2929 retval = -1;
2930 goto done;
2931 }
2932 cv->var_ipv6masklen = masklen;
2933 retval = parse_ipv6addr(str, &cv->var_ipv6addr, reason);
2934 break;
2935 case CGV_MACADDR:
2936 retval = parse_macaddr(str, cv->var_macaddr, reason);
2937 break;
2938 case CGV_URL:
2939 retval = parse_url(str, cv, reason);
2940 break;
2941 case CGV_UUID:
2942 if (str2uuid(str, cv->var_uuid) < 0){
2943 retval = 0;
2944 if (reason &&
2945 (*reason = cligen_reason("Invalid uuid: %s", str))==NULL)
2946 retval = -1;
2947 goto done;
2948 }
2949 retval = 1;
2950 break;
2951 case CGV_TIME:
2952 if (str2time(str, &cv->var_time) < 0){ /* XXX calloc gives true error */
2953 retval = 0;
2954 if (reason &&
2955 (*reason = cligen_reason("Invalid time: %s", str))==NULL)
2956 retval = -1;
2957 goto done;
2958 }
2959 retval = 1;
2960 break;
2961 case CGV_VOID: /* N/A */
2962 case CGV_EMPTY:
2963 case CGV_ERR:
2964 retval = 0;
2965 if (reason)
2966 *reason = cligen_reason("Invalid variable");
2967 break;
2968 } /* switch */
2969 done:
2970 if (str)
2971 free (str);
2972 if (reason && *reason)
2973 assert(retval == 0); /* validation error only on reason */
2974 return retval;
2975 }
2976
2977 /*! Parse cv from string.
2978 *
2979 * This function expects an initialized cv as created by cv_new() or
2980 * prepared by cv_reset().
2981 * @note The following is required of a cv before calling this function:
2982 * - A type field. So that the parser knows how to parse the string
2983 * - For decimal64 the fraction_digits (n) must be known (cv_dec64_n_set())
2984 *
2985 * @see cv_parse1() with better error handling.
2986 * @see cv_validate() where cv is validated against a cligen object specification.
2987 *
2988 * Arguments:
2989 * @param[in] str Input string. Example, number variable, str can be "7834" or "0x7634"
2990 * @param[in] cv cligen variable, as prepared by cv_reset()/cv_new()
2991 * @retval -1 Error (fatal), or parsing error, printf error in stderr.
2992 * @retval 0 Parse OK
2993 *
2994 * @code
2995 * cg_var *cv = cv_new(CGV_STRING);
2996 * if (cv_parse("mystring", cv) < 0)
2997 * cv_free(cv);
2998 * @endcode
2999 */
3000 int
cv_parse(char * str,cg_var * cv)3001 cv_parse(char *str,
3002 cg_var *cv)
3003 {
3004 int retval;
3005 char *reason = NULL;
3006
3007 if ((retval = cv_parse1(str, cv, &reason)) < 0){
3008 fprintf(stderr, "cv parse error: %s\n", strerror(errno));
3009 return -1;
3010 }
3011 if (retval == 0){
3012 fprintf(stderr, "cv parse error: %s\n", reason);
3013 return -1;
3014 }
3015 return 0;
3016 }
3017
3018 /*! Range interval check if a number is in an interval
3019 * @param[in] i The number to check if it is in an interval
3020 * @param[in] cvlow cv containing lower bound
3021 * @param[in] cvupp cv containing upper bound
3022 * @param[in] type Numeric type string, eg "int32"
3023 * @retval 0 i is outside [low,upper]
3024 * @retval 1 i is in [low,upper]
3025 * @note need to use macro trick ## to fix different types
3026 */
3027 #define range_check(i, cvlow, cvupp, type) \
3028 (((i) >= cv_##type##_get(cvlow)) && \
3029 ((i) <= cv_##type##_get(cvupp)))
3030
3031 /*! Error messsage for int violating ranges */
3032 static int
outofrange(cg_var * cv0,cg_varspec * cs,char ** reason)3033 outofrange(cg_var *cv0,
3034 cg_varspec *cs,
3035 char **reason)
3036 {
3037 int retval = -1;
3038 cbuf *cb = NULL;
3039 cg_var *cv1;
3040 cg_var *cv2;
3041 int i;
3042
3043 if ((cb = cbuf_new()) == NULL)
3044 goto done;
3045 cprintf(cb, "Number ");
3046 cv2cbuf(cv0, cb);
3047 cprintf(cb, " out of range: ");
3048 for (i=0; i<cs->cgs_rangelen; i++){
3049 cv1 = cvec_i(cs->cgs_rangecvv_low, i);
3050 cv2 = cvec_i(cs->cgs_rangecvv_upp, i);
3051 if (i)
3052 cprintf(cb, ", ");
3053 cv2cbuf(cv1, cb);
3054 cprintf(cb, " - ");
3055 cv2cbuf(cv2, cb);
3056 }
3057 if (reason && (*reason = strdup(cbuf_get(cb))) == NULL)
3058 goto done;
3059 if (cb)
3060 cbuf_free(cb);
3061 retval = 0;
3062 done:
3063 return retval;
3064 }
3065
3066 /*! Error messsage for string violating string limits */
3067 static int
outoflength(uint64_t u64,cg_varspec * cs,char ** reason)3068 outoflength(uint64_t u64,
3069 cg_varspec *cs,
3070 char **reason)
3071 {
3072 int retval = -1;
3073 cbuf *cb = NULL;
3074 cg_var *cv1;
3075 cg_var *cv2;
3076 int i;
3077
3078 if ((cb = cbuf_new()) == NULL)
3079 goto done;
3080 cprintf(cb, "String length %" PRIu64 " out of range: ", u64);
3081 for (i=0; i<cs->cgs_rangelen; i++){
3082 cv1 = cvec_i(cs->cgs_rangecvv_low, i);
3083 cv2 = cvec_i(cs->cgs_rangecvv_upp, i);
3084 if (i)
3085 cprintf(cb, ", ");
3086 cv2cbuf(cv1, cb);
3087 cprintf(cb, " - ");
3088 cv2cbuf(cv2, cb);
3089 }
3090 if (reason && (*reason = strdup(cbuf_get(cb))) == NULL)
3091 goto done;
3092 if (cb)
3093 cbuf_free(cb);
3094 retval = 0;
3095 done:
3096 return retval;
3097 }
3098
3099 /*! Validate cligen variable cv using the spec in cs.
3100 *
3101 * @param[in] cv A cligen variable to validate. This is a correctly parsed cv.
3102 * @param[in] cs A cligen variable specification object that defines the cv.
3103 * @param[out] reason If given, and if return value is 0, contains a malloced string
3104 * describing the reason why the validation failed.
3105 * @retval -1 Error (fatal), with errno set to indicate error
3106 * @retval 0 Validation not OK, malloced reason is returned. returned reason must be freed
3107 * @retval 1 Validation OK
3108 */
3109 int
cv_validate(cligen_handle h,cg_var * cv,cg_varspec * cs,char ** reason)3110 cv_validate(cligen_handle h,
3111 cg_var *cv,
3112 cg_varspec *cs,
3113 char **reason)
3114 {
3115 int retval = 1; /* OK */
3116 int32_t i = 0;
3117 uint32_t u = 0;
3118 int64_t i64;
3119 uint64_t u64;
3120 char *str;
3121 int ok;
3122 int j;
3123 cg_var *cv1;
3124 cg_var *cv2;
3125
3126 switch (cs->cgs_vtype){
3127 case CGV_INT8:
3128 if (!cs->cgs_rangelen)
3129 break;
3130 i = cv_int8_get(cv);
3131 ok = 0; /* At least one should pass */
3132 for (j=0; j<cs->cgs_rangelen; j++){
3133 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3134 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3135 if ((ok = range_check(i, cv1, cv2, int8)) != 0)
3136 break;
3137 }
3138 if (!ok){
3139 if (outofrange(cv, cs, reason) < 0)
3140 goto done;
3141 retval = 0; /* No match */
3142 }
3143 break;
3144 case CGV_INT16:
3145 if (!cs->cgs_rangelen)
3146 break;
3147 i = cv_int16_get(cv);
3148 ok = 0; /* At least one should pass */
3149 for (j=0; j<cs->cgs_rangelen; j++){
3150 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3151 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3152 if ((ok = range_check(i, cv1, cv2, int16)) != 0)
3153 break;
3154 }
3155 if (!ok){
3156 if (outofrange(cv, cs, reason) < 0)
3157 goto done;
3158 retval = 0; /* No match */
3159 }
3160 break;
3161 case CGV_INT32:
3162 if (!cs->cgs_rangelen)
3163 break;
3164 i = cv_int32_get(cv);
3165 ok = 0; /* At least one should pass */
3166 for (j=0; j<cs->cgs_rangelen; j++){
3167 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3168 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3169 if ((ok = range_check(i, cv1, cv2, int32)) != 0)
3170 break;
3171 }
3172 if (!ok){
3173 if (outofrange(cv, cs, reason) < 0)
3174 goto done;
3175 retval = 0; /* No match */
3176 }
3177 break;
3178 case CGV_INT64:
3179 if (!cs->cgs_rangelen)
3180 break;
3181 i64 = cv_int64_get(cv);
3182 ok = 0; /* At least one should pass */
3183 for (j=0; j<cs->cgs_rangelen; j++){
3184 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3185 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3186 if ((ok = range_check(i64, cv1, cv2, int64)) != 0)
3187 break;
3188 }
3189 if (!ok){
3190 if (outofrange(cv, cs, reason) < 0)
3191 goto done;
3192 retval = 0; /* No match */
3193 }
3194 break;
3195 case CGV_UINT8:
3196 if (!cs->cgs_rangelen)
3197 break;
3198 u = cv_uint8_get(cv);
3199 ok = 0; /* At least one should pass */
3200 for (j=0; j<cs->cgs_rangelen; j++){
3201 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3202 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3203 if ((ok = range_check(u, cv1, cv2, uint8)) != 0)
3204 break;
3205 }
3206 if (!ok){
3207 if (outofrange(cv, cs, reason) < 0)
3208 goto done;
3209 retval = 0; /* No match */
3210 }
3211 break;
3212 case CGV_UINT16:
3213 if (!cs->cgs_rangelen)
3214 break;
3215 u = cv_uint16_get(cv);
3216 ok = 0; /* At least one should pass */
3217 for (j=0; j<cs->cgs_rangelen; j++){
3218 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3219 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3220 if ((ok = range_check(u, cv1, cv2, uint16)) != 0)
3221 break;
3222 }
3223 if (!ok){
3224 if (outofrange(cv, cs, reason) < 0)
3225 goto done;
3226 retval = 0; /* No match */
3227 }
3228 break;
3229 case CGV_UINT32:
3230 if (!cs->cgs_rangelen)
3231 break;
3232 u = cv_uint32_get(cv);
3233 ok = 0; /* At least one should pass */
3234 for (j=0; j<cs->cgs_rangelen; j++){
3235 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3236 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3237 if ((ok = range_check(u, cv1, cv2, uint32)) != 0)
3238 break;
3239 }
3240 if (!ok){
3241 if (outofrange(cv, cs, reason) < 0)
3242 goto done;
3243 retval = 0; /* No match */
3244 }
3245 break;
3246 case CGV_UINT64:
3247 if (!cs->cgs_rangelen)
3248 break;
3249 u64 = cv_uint64_get(cv);
3250 ok = 0; /* At least one should pass */
3251 for (j=0; j<cs->cgs_rangelen; j++){
3252 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3253 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3254 if ((ok = range_check(u64, cv1, cv2, uint64)) != 0)
3255 break;
3256 }
3257 if (!ok){
3258 if (outofrange(cv, cs, reason) < 0)
3259 goto done;
3260 retval = 0; /* No match */
3261 }
3262 break;
3263 case CGV_DEC64:
3264 if (cv_dec64_n_get(cv) != cs->cgs_dec64_n){
3265 if (reason)
3266 *reason = cligen_reason("Decimal 64 fraction-bits mismatch %d(cv) != %d(spec)",
3267 cv->var_dec64_n, cs->cgs_dec64_n);
3268 retval = 0;
3269 }
3270 if (!cs->cgs_rangelen)
3271 break;
3272 i64 = cv_int64_get(cv);
3273 ok = 0; /* At least one should pass */
3274 for (j=0; j<cs->cgs_rangelen; j++){
3275 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3276 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3277 if ((ok = range_check(i64, cv1, cv2, int64)) != 0)
3278 break;
3279 }
3280 if (!ok){
3281 if (reason){
3282 if (outofrange(cv, cs, reason) < 0)
3283 goto done;
3284 }
3285 retval = 0; /* No match */
3286 }
3287 break;
3288 case CGV_REST:
3289 case CGV_STRING:
3290 str = cv_string_get(cv);
3291 if (cs->cgs_regex != NULL){
3292 char *regexp;
3293 cv1 = NULL;
3294 while ((cv1 = cvec_each(cs->cgs_regex, cv1)) != NULL){
3295 regexp = cv_string_get(cv1);
3296 if ((retval = match_regexp(h, str, regexp, cv_flag(cv1, V_INVERT))) < 0)
3297 break;
3298 if (retval == 0){
3299 if (reason)
3300 *reason = cligen_reason("regexp match fail: %s does not match %s",
3301 str, regexp);
3302 retval = 0;
3303 break; /* from the while */
3304 }
3305 }
3306 if (retval == 0)
3307 break; /* from the switch */
3308 }
3309
3310 if (!cs->cgs_rangelen) /* Skip range check */
3311 break;
3312 u64 = strlen(str); /* size_t */
3313 ok = 0; /* At least one should pass */
3314 for (j=0; j<cs->cgs_rangelen; j++){
3315 cv1 = cvec_i(cs->cgs_rangecvv_low, j);
3316 cv2 = cvec_i(cs->cgs_rangecvv_upp, j);
3317 if ((ok = range_check(u64, cv1, cv2, uint64)) != 0)
3318 break;
3319 }
3320 if (!ok){
3321 if (outoflength(u64, cs, reason) < 0)
3322 goto done;
3323 retval = 0; /* No match */
3324 }
3325 break;
3326 case CGV_ERR:
3327 case CGV_VOID:
3328 retval = 0;
3329 if (reason)
3330 *reason = cligen_reason("Invalid cv");
3331 retval = 0;
3332 break;
3333 case CGV_BOOL:
3334 case CGV_INTERFACE:
3335 case CGV_IPV4ADDR:
3336 case CGV_IPV6ADDR:
3337 case CGV_IPV4PFX:
3338 case CGV_IPV6PFX:
3339 case CGV_MACADDR:
3340 case CGV_URL:
3341 case CGV_UUID:
3342 case CGV_TIME:
3343 case CGV_EMPTY:
3344 break;
3345 }
3346 if (reason && *reason)
3347 assert(retval == 0);
3348 done:
3349 return retval;
3350 }
3351
3352 /*! Compare two CLIgen variables as strcmp(3)
3353 * @param[in] cv1 CLIgen variable #1
3354 * @param[in] cv2 CLIgen variable #2
3355 * @retval 0 equal
3356 * @retval <0 cv1 is less than cv2
3357 * @retval >0 cv1 is greater than cv2
3358 * XXX assume dec64_n are equal
3359 */
3360 int
cv_cmp(cg_var * cv1,cg_var * cv2)3361 cv_cmp(cg_var *cv1,
3362 cg_var *cv2)
3363 {
3364 int n;
3365
3366 /* Same type? */
3367 if(cv1->var_type != cv2->var_type)
3368 return cv1->var_type - cv2->var_type;
3369
3370 switch (cv1->var_type) {
3371 case CGV_ERR:
3372 return 0;
3373 case CGV_INT8:
3374 return (cv1->var_int8 - cv2->var_int8);
3375 case CGV_INT16:
3376 return (cv1->var_int16 - cv2->var_int16);
3377 case CGV_INT32:
3378 return (cv1->var_int32 - cv2->var_int32);
3379 case CGV_INT64:
3380 return (cv1->var_int64 - cv2->var_int64);
3381 case CGV_UINT8:
3382 return (cv1->var_uint8 - cv2->var_uint8);
3383 case CGV_UINT16:
3384 return (cv1->var_uint16 - cv2->var_uint16);
3385 case CGV_UINT32:
3386 return (cv1->var_uint32 - cv2->var_uint32);
3387 case CGV_UINT64:
3388 return (cv1->var_uint64 - cv2->var_uint64);
3389 case CGV_DEC64:
3390 /* XXX assume dec64_n are equal */
3391 return (cv_dec64_i_get(cv1) - cv_dec64_i_get(cv2));
3392 case CGV_BOOL:
3393 return (cv1->var_bool - cv2->var_bool);
3394 case CGV_REST:
3395 case CGV_STRING:
3396 case CGV_INTERFACE: /* All strings have the same address */
3397 return strcmp(cv1->var_string, cv2->var_string);
3398 case CGV_IPV4ADDR:
3399 return memcmp(&cv1->var_ipv4addr, &cv2->var_ipv4addr,
3400 sizeof(cv1->var_ipv4addr));
3401 case CGV_IPV4PFX:
3402 if ((n = memcmp(&cv1->var_ipv4addr, &cv2->var_ipv4addr,
3403 sizeof(cv1->var_ipv4addr))))
3404 return n;
3405 return cv1->var_ipv4masklen - cv2->var_ipv4masklen;
3406 case CGV_IPV6ADDR:
3407 return memcmp(&cv1->var_ipv6addr, &cv2->var_ipv6addr,
3408 sizeof(cv1->var_ipv6addr));
3409 case CGV_IPV6PFX:
3410 if ((n = memcmp(&cv1->var_ipv6addr, &cv2->var_ipv6addr,
3411 sizeof(cv1->var_ipv6addr))))
3412 return n;
3413 return cv1->var_ipv6masklen - cv2->var_ipv6masklen;
3414 case CGV_MACADDR:
3415 return memcmp(&cv1->var_macaddr, &cv2->var_macaddr,
3416 sizeof(cv1->var_macaddr));
3417
3418 case CGV_URL:
3419 if ((n = strcmp(cv1->var_urlproto, cv2->var_urlproto)))
3420 return n;
3421 if ((n = strcmp(cv1->var_urladdr, cv2->var_urladdr)))
3422 return n;
3423 if ((n = strcmp(cv1->var_urlpath, cv2->var_urlpath)))
3424 return n;
3425 if ((n = strcmp(cv1->var_urluser, cv2->var_urluser)))
3426 return n;
3427 return strcmp(cv1->var_urlpasswd, cv2->var_urlpasswd);
3428 case CGV_UUID:
3429 return memcmp(cv1->var_uuid, cv2->var_uuid, 16);
3430 case CGV_TIME:
3431 return memcmp(&cv1->var_time, &cv2->var_time, sizeof(struct timeval));
3432 case CGV_VOID: /* compare pointers */
3433 return (cv1->var_void == cv2->var_void);
3434 case CGV_EMPTY: /* Always equal */
3435 return 0;
3436 }
3437
3438 return -1;
3439 }
3440
3441 /*! Copy from one cv to a new cv.
3442 *
3443 * The new cv should have been be initialized, such as after cv_new() or
3444 * after cv_reset().
3445 * The new cv may involve duplicating strings, etc.
3446
3447 * @retval 0 0n success,
3448 * @retval -1 On error with errno set (strdup errors)
3449 */
3450 int
cv_cp(cg_var * new,cg_var * old)3451 cv_cp(cg_var *new,
3452 cg_var *old)
3453 {
3454 int retval = -1;
3455
3456 memcpy(new, old, sizeof(*old));
3457 if (old->var_name)
3458 if ((new->var_name = strdup(old->var_name)) == NULL)
3459 goto done;
3460 if (old->var_show)
3461 if ((new->var_show = strdup(old->var_show)) == NULL)
3462 goto done;
3463 switch (new->var_type) {
3464 case CGV_ERR:
3465 break;
3466 case CGV_INT8:
3467 case CGV_INT16:
3468 case CGV_INT32:
3469 case CGV_INT64:
3470 case CGV_UINT8:
3471 case CGV_UINT16:
3472 case CGV_UINT32:
3473 case CGV_UINT64:
3474 case CGV_DEC64:
3475 case CGV_BOOL:
3476 break;
3477 case CGV_REST:
3478 case CGV_STRING:
3479 case CGV_INTERFACE: /* All strings have the same address */
3480 if (old->var_string)
3481 if ((new->var_string = strdup(old->var_string)) == NULL)
3482 goto done;
3483 break;
3484 case CGV_IPV4ADDR:
3485 case CGV_IPV4PFX:
3486 case CGV_IPV6ADDR:
3487 case CGV_IPV6PFX:
3488 case CGV_MACADDR:
3489 break;
3490 case CGV_URL:
3491 if (old->var_urlproto)
3492 if ((new->var_urlproto = strdup(old->var_urlproto)) == NULL)
3493 goto done;
3494 if (old->var_urladdr)
3495 if ((new->var_urladdr = strdup(old->var_urladdr)) == NULL)
3496 goto done;
3497 if (old->var_urlpath)
3498 if ((new->var_urlpath = strdup(old->var_urlpath)) == NULL)
3499 goto done;
3500 if (old->var_urluser)
3501 if ((new->var_urluser = strdup(old->var_urluser)) == NULL)
3502 goto done;
3503 if (old->var_urlpasswd)
3504 if ((new->var_urlpasswd = strdup(old->var_urlpasswd)) == NULL)
3505 goto done;
3506 break;
3507 case CGV_UUID:
3508 break;
3509 case CGV_TIME:
3510 break;
3511 case CGV_VOID: /* cp pointer */
3512 new->var_void = old->var_void;
3513 break;
3514 case CGV_EMPTY:
3515 break;
3516 }
3517 retval = 0;
3518 done:
3519 return retval;
3520 }
3521
3522 /*! Create a new cgv and copy the contents from the original.
3523 *
3524 * This may involve duplicating strings, etc.
3525 * The new cv needs to be freed by cv_free().
3526 */
3527 cg_var *
cv_dup(cg_var * old)3528 cv_dup(cg_var *old)
3529 {
3530 cg_var *new;
3531
3532 if ((new = cv_new(old->var_type)) == NULL)
3533 return NULL;
3534 if (cv_cp(new, old) < 0){
3535 cv_free(new);
3536 return NULL;
3537 }
3538 return new;
3539 }
3540
3541 /*! Create new cligen variable.
3542 *
3543 * @retval NULL on error, error printed on stder
3544 * @retval cv on success the malloc:ed cligen variable. Needs to be freed w cv_free()
3545 * @note returned cv needs to be freed with cv_free()
3546 * @note if type is CGV_DEC64, cv_dec64_n_set needs also be called
3547 * @see cvec_add which adds a cv to an existing cvec
3548 * @see cv_free
3549 */
3550 cg_var *
cv_new(enum cv_type type)3551 cv_new(enum cv_type type)
3552 {
3553 cg_var *cv;
3554
3555 if ((cv = malloc(sizeof(cg_var))) == NULL)
3556 goto done;
3557 memset(cv, 0, sizeof(*cv));
3558 cv->var_type = type;
3559 done:
3560 return cv;
3561
3562 }
3563
3564 /*! Free pointers and resets a single CLIgen variable cv
3565 *
3566 * But does not free the cgv itself!
3567 * the type is maintained after reset.
3568 */
3569 int
cv_reset(cg_var * cv)3570 cv_reset(cg_var *cv)
3571 {
3572 enum cv_type type = cv->var_type;
3573
3574 if (cv->var_name)
3575 free(cv->var_name);
3576 if (cv->var_show)
3577 free(cv->var_show);
3578 switch (cv->var_type) {
3579 case CGV_REST:
3580 case CGV_STRING:
3581 case CGV_INTERFACE:
3582 if (cv->var_string)
3583 free(cv->var_string); /* All strings have the same address */
3584 break;
3585 case CGV_URL:
3586 if (cv->var_urlproto)
3587 free(cv->var_urlproto);
3588 if (cv->var_urladdr)
3589 free(cv->var_urladdr);
3590 if (cv->var_urlpath)
3591 free(cv->var_urlpath);
3592 if (cv->var_urluser)
3593 free(cv->var_urluser);
3594 if (cv->var_urlpasswd)
3595 free(cv->var_urlpasswd);
3596 break;
3597 case CGV_VOID: /* XXX: freeit ? */
3598 break;
3599 case CGV_EMPTY:
3600 break;
3601 default:
3602 break;
3603 }
3604 memset(cv, 0, sizeof(*cv));
3605 cv->var_type = type;
3606 return 0;
3607 }
3608
3609 /*! Free a single CLIgen variable (cv) AND frees the cv itself
3610 *
3611 * @param[in] cv CLIgen variable
3612 * @see cv_new
3613 */
3614 int
cv_free(cg_var * cv)3615 cv_free(cg_var *cv)
3616 {
3617 if (cv) {
3618 cv_reset(cv);
3619 free(cv);
3620 }
3621 return 0;
3622 }
3623
3624 /*! Return the alloced memory of a CLIgen variable
3625 */
3626 size_t
cv_size(cg_var * cv)3627 cv_size(cg_var *cv)
3628 {
3629 size_t sz = 0;
3630
3631 sz += sizeof(struct cg_var);
3632 if (cv->var_name)
3633 sz += strlen(cv->var_name)+1;
3634 if (cv->var_show)
3635 sz += strlen(cv->var_show)+1;
3636 if (cv_isstring(cv->var_type))
3637 sz += strlen(cv->var_string)+1;
3638 return sz;
3639 }
3640