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