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 #include "cligen_config.h"
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <stdarg.h>
39 #include <inttypes.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <assert.h>
46 #include <ctype.h>
47 #define __USE_GNU /* strverscmp */
48 #include <string.h>
49 #include <errno.h>
50 #include <termios.h>
51 #include <signal.h>
52 #include <sys/ioctl.h>
53 
54 #include "cligen_buf.h"
55 #include "cligen_cv.h"
56 #include "cligen_cvec.h"
57 #include "cligen_parsetree.h"
58 #include "cligen_pt_head.h"
59 #include "cligen_object.h"
60 #include "cligen_io.h"
61 #include "cligen_handle.h"
62 #include "cligen_read.h"
63 #include "cligen_parse.h"
64 #include "cligen_history.h"
65 #include "cligen_getline.h"
66 #include "cligen_handle_internal.h"
67 #include "cligen_history.h"
68 #include "cligen_history_internal.h"
69 
70 /*
71  * Constants
72  */
73 #define TREENAME_KEYWORD_DEFAULT "treename"
74 
75 /* forward */
76 static int terminal_rows_set1(int rows);
77 
78 /*
79  * Variables
80  */
81 /* Number of terminal rows as used by cligen_output pageing routine
82  * @see cligen_output
83  */
84 static int _terminalrows = 0;
85 
86 /* Truncate help string on right margin mode
87  * This only applies if you have really long help strings, such as when generating them from a
88  * spec.
89  * @see print_help_line
90  */
91 static int _helpstr_truncate = 0;
92 
93 /* Limit number of lines to show, 0 means unlimited
94  * This only applies if you have multi-line help strings, such as when generating them from a
95  * spec.
96  * @see print_help_line
97  */
98 static int _helpstr_lines = 0;
99 
100 /*! Get window size and set terminal row size
101  * @param[in] h       CLIgen handle
102  * The only real effect this has is to set the getline width parameter which effects scrolling
103  */
104 static int
cligen_gwinsz(cligen_handle h)105 cligen_gwinsz(cligen_handle h)
106 {
107     struct winsize ws;
108 
109     if (ioctl(0, TIOCGWINSZ, &ws) == -1){
110 	perror("ioctl(STDIN_FILENO,TIOCGWINSZ)");
111 	return -1;
112     }
113     terminal_rows_set1(ws.ws_row); /* note special treatment of 0 in sub function */
114     cligen_terminal_width_set(h, ws.ws_col);
115 
116     return 0;
117 }
118 
119 void
sigwinch_handler(int arg)120 sigwinch_handler(int arg)
121 {
122     cligen_gwinsz(0);
123 }
124 
125 /*! This is the first call the CLIgen API and returns a handle.
126  * Allocate CLIgen handle to be used in API calls
127  * Initialize prompt, tabs, query terminal setting for width etc.
128  * @retval h  CLIgen handle
129  */
130 cligen_handle
cligen_init(void)131 cligen_init(void)
132 {
133     struct cligen_handle *ch;
134     cligen_handle         h = NULL;
135     struct sigaction      sigh;
136 
137     if ((ch = malloc(sizeof(*ch))) == NULL){
138 	fprintf(stderr, "%s: malloc: %s\n", __FUNCTION__, strerror(errno));
139 	goto done;
140     }
141     memset(ch, 0, sizeof(*ch));
142     ch->ch_magic = CLIGEN_MAGIC;
143     ch->ch_tabmode = 0x0; /* see CLIGEN_TABMODE_* */
144     ch->ch_delimiter = ' ';
145     h = (cligen_handle)ch;
146     cligen_prompt_set(h, CLIGEN_PROMPT_DEFAULT);
147     /* Only if stdin and stdout refers to a terminal make win size check */
148     if (isatty(0) && isatty(1)){
149 	if (cligen_gwinsz(h) < 0)
150 	    return NULL;
151 	cligen_interrupt_hook(h, cligen_gwinsz);
152 	memset(&sigh, 0, sizeof(sigh));
153 	sigh.sa_handler = sigwinch_handler;
154 	if (sigaction(SIGWINCH, &sigh, NULL) < 0){
155 	    perror("sigaction");
156 	    return NULL;
157 	}
158     }
159     else
160 	terminal_rows_set1(0);
161     cliread_init(h);
162     cligen_buf_init(h);
163     /* getline cant function without some history */
164     (void)cligen_hist_init(h, CLIGEN_HISTSIZE_DEFAULT);
165   done:
166     return h;
167 }
168 
169 /*! This is the last call to the CLIgen API an application should make
170  * @param[in] h       CLIgen handle
171  */
172 int
cligen_exit(cligen_handle h)173 cligen_exit(cligen_handle h)
174 {
175     struct cligen_handle *ch = handle(h);
176     pt_head              *ph;
177 
178     hist_exit(h);
179     cligen_buf_cleanup(h);
180     if (ch->ch_prompt)
181 	free(ch->ch_prompt);
182     if (ch->ch_nomatch)
183 	free(ch->ch_nomatch);
184     if (ch->ch_treename_keyword)
185 	free(ch->ch_treename_keyword);
186     if (ch->ch_fn_str)
187 	free(ch->ch_fn_str);
188     while ((ph = ch->ch_pt_head) != NULL){
189 	ch->ch_pt_head = ph->ph_next;
190 	cligen_ph_free(ph);
191     }
192     free(ch);
193     return 0;
194 }
195 
196 /*! Check struct magic number for sanity checks
197  * @param[in] h       CLIgen handle
198  * return 0 if OK, -1 if fail.
199  */
200 int
cligen_check(cligen_handle h)201 cligen_check(cligen_handle h)
202 {
203     /* Dont use handle macro to avoid recursion */
204     struct cligen_handle *ch = (struct cligen_handle *)(h);
205 
206     return ch->ch_magic == CLIGEN_MAGIC ? 0 : -1;
207 }
208 
209 /*! return CLIgen exiting status
210  * @param[in] h       CLIgen handle
211  */
212 int
cligen_exiting(cligen_handle h)213 cligen_exiting(cligen_handle h)
214 {
215     struct cligen_handle *ch = handle(h);
216 
217     return ch->ch_exiting;
218 }
219 
220 /*! Set  CLIgen exiting status
221  * @param[in] h       CLIgen handle
222  */
223 int
cligen_exiting_set(cligen_handle h,int status)224 cligen_exiting_set(cligen_handle h,
225 		   int           status)
226 {
227     struct cligen_handle *ch = handle(h);
228 
229     ch->ch_exiting = status;
230     return 0;
231 }
232 
233 /*! Get comment character.
234  * @param[in] h       CLIgen handle
235  */
236 char
cligen_comment(cligen_handle h)237 cligen_comment(cligen_handle h)
238 {
239     struct cligen_handle *ch = handle(h);
240 
241     return ch->ch_comment;
242 }
243 
244 /*! Set comment character.
245  * @param[in] h       CLIgen handle
246  */
247 int
cligen_comment_set(cligen_handle h,char c)248 cligen_comment_set(cligen_handle h,
249 		   char          c)
250 {
251     struct cligen_handle *ch = handle(h);
252 
253     ch->ch_comment = c;
254     return 0;
255 }
256 
257 /*! Get current prompt string
258  * @param[in] h       CLIgen handle
259  */
260 char*
cligen_prompt(cligen_handle h)261 cligen_prompt(cligen_handle h)
262 {
263     struct cligen_handle *ch = handle(h);
264 
265     return ch->ch_prompt;
266 }
267 
268 /*! Set CLIgen prompt string. See manual for special prompt characters.
269  * @param[in] h       CLIgen handle
270  * @param[in] prompt  Prompt string
271  */
272 int
cligen_prompt_set(cligen_handle h,char * prompt)273 cligen_prompt_set(cligen_handle h,
274 		  char         *prompt)
275 {
276     struct cligen_handle *ch = handle(h);
277 
278     if (ch->ch_prompt){
279 	if (strcmp(prompt, ch->ch_prompt) == 0)
280 	    return 0;
281 	free(ch->ch_prompt);
282 	ch->ch_prompt = NULL;
283     }
284     if (prompt){
285 	if ((ch->ch_prompt = strdup(prompt)) == NULL)
286 	    return -1;
287     }
288     return 0;
289 }
290 
291 /*! Get CLIgen parse-tree head holding all parsetrees in the system
292  */
293 pt_head *
cligen_pt_head_get(cligen_handle h)294 cligen_pt_head_get(cligen_handle h)
295 {
296     struct cligen_handle *ch = handle(h);
297 
298     return ch->ch_pt_head;
299 }
300 
301 /*! Set CLIgen parse-tree head holding all parsetrees in the system
302  */
303 int
cligen_pt_head_set(cligen_handle h,pt_head * ph)304 cligen_pt_head_set(cligen_handle h,
305 		   pt_head      *ph)
306 {
307     struct cligen_handle *ch = handle(h);
308 
309     ch->ch_pt_head = ph;
310     return 0;
311 }
312 
313 /*! Get name of treename keyword used in parsing
314  * @param[in] h       CLIgen handle
315  * Example in CLIgen file where 'treename' is treename_keyword:
316  * treename = "foo";
317  * bar @bar;
318  * y;
319  */
320 char*
cligen_treename_keyword(cligen_handle h)321 cligen_treename_keyword(cligen_handle h)
322 {
323     struct cligen_handle *ch = handle(h);
324 
325     return ch->ch_treename_keyword?ch->ch_treename_keyword:TREENAME_KEYWORD_DEFAULT;
326 }
327 
328 /*! Set currently active parsetree by name.
329  * @param[in] h       CLIgen handle
330  */
331 int
cligen_treename_keyword_set(cligen_handle h,char * treename)332 cligen_treename_keyword_set(cligen_handle h,
333 			    char         *treename)
334 {
335     struct cligen_handle *ch = handle(h);
336 
337     if (ch->ch_treename_keyword){
338 	free(ch->ch_treename_keyword);
339 	ch->ch_treename_keyword = NULL;
340     }
341     if (treename)
342 	if ((ch->ch_treename_keyword = strdup(treename)) == NULL)
343 	    return -1;
344     return 0;
345 }
346 
347 /*! Return CLIgen object that matched in the current callback.
348  *  After an evaluation when calling a callback, a node has been matched in the
349  * current parse-tree. This matching node is returned (and set) here.
350  * @param[in] h       CLIgen handle
351  */
352 cg_obj *
cligen_co_match(cligen_handle h)353 cligen_co_match(cligen_handle h)
354 {
355     struct cligen_handle *ch = handle(h);
356 
357     return ch->ch_co_match;
358 }
359 
360 /*!
361  * @param[in] h       CLIgen handle
362  */
363 int
cligen_co_match_set(cligen_handle h,cg_obj * co)364 cligen_co_match_set(cligen_handle h,
365 		    cg_obj       *co)
366 {
367     struct cligen_handle *ch = handle(h);
368 
369     ch->ch_co_match = co;
370     return 0;
371 }
372 
373 /*! Get callback function name string
374  *
375  * @code
376  * static int
377  * my_cb(cligen_handle h, cvec *vars, cg_var *arg)
378  * {
379  *   printf("cb: %s\n", cligen_fn_str_get(h));
380  *   return 0;
381  * }
382  * @endcode
383  * @param[in] h       CLIgen handle
384  */
385 char *
cligen_fn_str_get(cligen_handle h)386 cligen_fn_str_get(cligen_handle h)
387 {
388     struct cligen_handle *ch = handle(h);
389 
390     return ch->ch_fn_str;
391 }
392 
393 /*! Set callback function name string
394  *
395  * @param[in] h       CLIgen handle
396  * @param[in] fn_str  Name of function that was called in this callback
397  */
398 int
cligen_fn_str_set(cligen_handle h,char * fn_str)399 cligen_fn_str_set(cligen_handle h,
400 		  char         *fn_str)
401 {
402     struct cligen_handle *ch = handle(h);
403 
404     if (ch->ch_fn_str){
405 	free(ch->ch_fn_str);
406 	ch->ch_fn_str = NULL;
407     }
408     if (fn_str){
409 	if ((ch->ch_fn_str = strdup(fn_str)) == NULL)
410 	    return -1;
411     }
412     return 0;
413 }
414 
415 /*! Get number of displayed terminal rows.
416  * @param[in] h       CLIgen handle
417  */
418 int
cligen_terminal_rows(cligen_handle h)419 cligen_terminal_rows(cligen_handle h)
420 {
421 //    struct cligen_handle *ch = handle(h);
422 
423     return _terminalrows; /* ch->ch_terminalrows; */
424 }
425 
426 /*! Set number of displayed terminal rows, internal function
427  * @param[in] h       CLIgen handle
428  * @param[in] rows    Number of lines in a terminal (y-direction)
429  */
430 static int
terminal_rows_set1(int rows)431 terminal_rows_set1(int rows)
432 {
433     _terminalrows = rows;
434     return 0;
435 }
436 
437 /*! Set number of displayed terminal rows.
438  * @param[in] h       CLIgen handle
439  * @param[in] rows    Number of lines in a terminal (y-direction)
440  */
441 int
cligen_terminal_rows_set(cligen_handle h,int rows)442 cligen_terminal_rows_set(cligen_handle h,
443 			int           rows)
444 {
445     int            retval = -1;
446     struct winsize ws;
447 
448     /* Sanity checks :
449      * (1) only set new value if it runs in a tty
450      * (2) cannot determine window size
451      */
452     if (!isatty(0) || !isatty(1))
453 	goto ok;
454     if (ioctl(0, TIOCGWINSZ, &ws) == -1){
455 	perror("ioctl(STDIN_FILENO,TIOCGWINSZ)");
456 	goto done;
457     }
458     if (ws.ws_row !=0 )
459 	goto ok;
460     terminal_rows_set1(rows);
461  ok:
462     retval = 0;
463  done:
464     return retval;
465 }
466 
467 /*! Get length of lines (number of 'columns' in a line)
468  *
469  * @param[in] h       CLIgen handle
470  */
471 int
cligen_terminal_width(cligen_handle h)472 cligen_terminal_width(cligen_handle h)
473 {
474 //    struct cligen_handle *ch = handle(h);
475 
476     return gl_getwidth();
477 }
478 
479 /*! Set width of a CLIgen line in characters, ie, the number of 'columns' in a line
480  *
481  * @param[in] h       CLIgen handle
482  * @param[in] length  Number of characters in a line - x-direction (see notes)
483  * @note if length = 0, then set it to 65535 to effectively disable all scrolling mechanisms
484  * @note if length < 21 set it to 21, which is getline's limit.
485  */
486 int
cligen_terminal_width_set(cligen_handle h,int length)487 cligen_terminal_width_set(cligen_handle h,
488 			   int           length)
489 {
490     //    struct cligen_handle *ch = handle(h);
491     int retval = -1;
492 
493     /* if length = 0, then set it to 65535 to effectively disable all scrolling mechanisms */
494     if (length == 0)
495 	length = 0xffff;
496     /* if length < 21 set it to 21, which is getline's limit. */
497     else if (length < TERM_MIN_SCREEN_WIDTH)
498 	length = TERM_MIN_SCREEN_WIDTH;
499     if (gl_setwidth(length) < 0)
500 	goto done; /* shouldnt happen */
501     retval = 0;
502  done:
503     return retval;
504 }
505 
506 /*! Get cligen/getline UTF-8 experimental mode
507  *
508  * @param[in] h       CLIgen handle
509  * @retval    0       UTF-8 mode disabled
510  * @retval    1       UTF-8 mode enabled
511  */
512 int
cligen_utf8_get(cligen_handle h)513 cligen_utf8_get(cligen_handle h)
514 {
515     return gl_utf8_get();
516 }
517 
518 /*! Set cligen/getline UTF-8 experimental mode
519  *
520  * @param[in] h       CLIgen handle
521  * @retval    0       UTF-8 mode disabled
522  * @retval    1       UTF-8 mode enabled
523  */
524 int
cligen_utf8_set(cligen_handle h,int mode)525 cligen_utf8_set(cligen_handle h,
526 		int           mode)
527 {
528     return gl_utf8_set(mode);
529 }
530 
531 /*! Get line scrolling mode
532  *
533  * @param[in] h       CLIgen handle
534  * @retval    0       Line scrolling off
535  * @retval    1       Line scrolling on
536  */
537 int
cligen_line_scrolling(cligen_handle h)538 cligen_line_scrolling(cligen_handle h)
539 {
540     return gl_getscrolling();
541 }
542 
543 /*! Set line scrolling mode
544  *
545  * @param[in] h      CLIgen handle
546  * @param[in] mode   0: turn line scrolling off, 1: turn on
547  * @retval    old    Previous setting
548  */
549 int
cligen_line_scrolling_set(cligen_handle h,int mode)550 cligen_line_scrolling_set(cligen_handle h,
551 			  int           mode)
552 {
553     int prev = gl_getscrolling();
554 
555     gl_setscrolling(mode);
556     return prev;
557 }
558 
559 /*! Return help string truncate mode (for ?)
560  *
561  * Whether to truncate help string on right margin or wrap long help lines.
562  * This only applies if you have really long help strings, such as when generating them from a
563  * spec.
564  * @param[in] h       CLIgen handle (dummy, need to be called where h is NULL)
565  * @retval    0       Do not truncate help string on right margin (wrap long help lines)
566  * @retval    1       Truncate help string on right margin (do not wrap long help lines)
567  * @see print_help_line
568  */
569 int
cligen_helpstring_truncate(cligen_handle h)570 cligen_helpstring_truncate(cligen_handle h)
571 {
572     return _helpstr_truncate;
573 }
574 
575 /*! Set help string truncate mode (for ?)
576  *
577  * Whether to truncate help string on right margin or wrap long help lines.
578  * This only applies if you have really long help strings, such as when generating them from a
579  * spec.
580  * @param[in]  h     CLIgen handle (dummy, need to be called where h is NULL)
581  * @param[in]  mode  0: Wrap long help strings, 1: Truncate help string
582  * @retval     0     OK
583  * @see print_help_line
584  */
585 int
cligen_helpstring_truncate_set(cligen_handle h,int mode)586 cligen_helpstring_truncate_set(cligen_handle h,
587 			       int           mode)
588 {
589     _helpstr_truncate = mode;
590     return 0;
591 }
592 
593 /*! Return number of help string lines to display (for ?)
594  *
595  * This only applies if you have multi-line help strings, such as when generating them from a
596  * spec.
597  * @param[in] h       CLIgen handle (dummy, need to be called where h is NULL)
598  * @retval    n       Number of help string lines to display per command, 0 is unlimted
599  * @see print_help_line
600  */
601 int
cligen_helpstring_lines(cligen_handle h)602 cligen_helpstring_lines(cligen_handle h)
603 {
604     return _helpstr_lines;
605 }
606 
607 /*! Set help string truncate mode (for ?)
608  *
609  * This only applies if you have multi-line help strings, such as when generating them from a
610  * spec.
611  * @param[in] h       CLIgen handle (dummy, need to be called where h is NULL)
612  * @retval    n       Number of help string lines to display per command, 0 means unlimited.
613  * @see print_help_line
614  */
615 int
cligen_helpstring_lines_set(cligen_handle h,int lines)616 cligen_helpstring_lines_set(cligen_handle h,
617 			       int        lines)
618 {
619     _helpstr_lines = lines;
620     return 0;
621 }
622 
623 /*! Get tab-mode.
624  *
625  * @param[in] h       CLIgen handle
626  * @retval    flags   Bitwise OR of CLIGEN_TABMODE_* flags
627  * @see cligen_tabmode_set for documentation on mode
628  */
629 int
cligen_tabmode(cligen_handle h)630 cligen_tabmode(cligen_handle h)
631 {
632     struct cligen_handle *ch = handle(h);
633 
634     return ch->ch_tabmode;
635 }
636 
637 /*! Set Cligen tab mode. Combination of CLIGEN_TABMODE_* flags
638  *
639  * @param[in] h       CLIgen handle
640  * @param[in] mode    Bitwise OR of CLIGEN_TABMODE_* flags
641  * CLIGEN_TABMODE_COLUMNS:
642  * 0 is 'short/ios' mode, 1 is long/junos mode.
643  * Two ways to show commands: show_help_column and show_help_line
644  * show_help_line
645  *  cli> interface name
646  * 100GigabyteEthernet6/0/0 TenGigabyteEthernet6/0/0 TenGigabyteEthernet6/0
647  * TenGigabyteEthernet6/0/0 TenGigabyteEthernet6/0/0 TenGigabyteEthernet6/0
648  *
649  * show_help_columns:
650  * cli> interface name TenGigabyteEthernet6/0/0.
651  * TenGigabyteEthernet6/0/0 This is one mighty interface
652  * TenGigabyteEthernet6/0/0 This is one mighty interface
653  *
654  * short/ios:  ?:   show_multi_long
655  *             TAB: show_multi  (many columns)
656  * long/junos: TAB and ?: show_multi_long
657  *
658  * CLIGEN_TABMODE_VARS:
659  * 0: command completion preference,
660  * 1: same preference for vars
661  * @example if clispec is:
662  * a {
663  *   b;
664  *  <c:int32>, cb("a.b");
665  * }
666  * Typing "a <TAB>"
667  * 0: completes to "a b"
668  * 1: does not complete, shows:
669  *   b
670  *   <c>
671  *
672  * CLIGEN_TABMODE_STEPS
673  * 0: complete 1 level. 1: complete all
674  * Example: syntax is 'a b;':
675  * 0: gives completion to 'a ' on first TAB and to 'a b ' on second.
676  * 1: gives completion to 'a b ' on first TAB.
677  */
678 int
cligen_tabmode_set(cligen_handle h,int mode)679 cligen_tabmode_set(cligen_handle h,
680 		   int           mode)
681 {
682     struct cligen_handle *ch = handle(h);
683 
684     ch->ch_tabmode = mode;
685     return 0;
686 }
687 
688 static int _lexicalorder = 0; /* XXX shouldnt be global */
689 
690 /*! Get lexical matching order
691  *
692  * @param[in] h       CLIgen handle
693  * @retval 0  strcmp
694  * @retval 1  strverscmp
695  */
696 int
cligen_lexicalorder(cligen_handle h)697 cligen_lexicalorder(cligen_handle h)
698 {
699 //    struct cligen_handle *ch = handle(h);
700 
701 //    return ch->ch_lexicalorder;
702     return _lexicalorder;
703 }
704 
705 /*! Set lexical matching order.
706  *
707  * @param[in] h  CLIgen handle
708  * @param[in] n  strcmp (0) or strverscmp (1).
709  */
710 int
cligen_lexicalorder_set(cligen_handle h,int n)711 cligen_lexicalorder_set(cligen_handle h,
712 			int           n)
713 {
714 //    struct cligen_handle *ch = handle(h);
715 
716 //    ch->ch_lexicalorder = n;
717     _lexicalorder = n;
718     return 0;
719 }
720 
721 static int _ignorecase = 0; /* XXX shouldnt be global */
722 
723 /*! Ignore uppercase/lowercase or not
724  * @param[in] h       CLIgen handle
725  */
726 int
cligen_ignorecase(cligen_handle h)727 cligen_ignorecase(cligen_handle h)
728 {
729 //    struct cligen_handle *ch = handle(h);
730 
731 //    return ch->ch_ignorecase;
732     return _ignorecase;
733 }
734 
735 /*! Ignore uppercase/lowercase or not
736  * @param[in] h       CLIgen handle
737  */
738 int
cligen_ignorecase_set(cligen_handle h,int n)739 cligen_ignorecase_set(cligen_handle h,
740 		      int           n)
741 {
742 //    struct cligen_handle *ch = handle(h);
743 
744 //    ch->ch_ignorecase = n;
745     _ignorecase = n;
746     return 0;
747 }
748 
749 /*! Debug syntax by printing dynamically on stderr. Get function.
750  * @param[in] h       CLIgen handle
751  */
cligen_logsyntax(cligen_handle h)752 int cligen_logsyntax(cligen_handle h)
753 {
754     struct cligen_handle *ch = handle(h);
755 
756     return ch->ch_logsyntax;
757 }
758 
759 /*! Debug syntax by printing dynamically on stderr. Set function.
760  * @param[in] h       CLIgen handle
761  */
cligen_logsyntax_set(cligen_handle h,int n)762 int cligen_logsyntax_set(cligen_handle h,
763 			 int           n)
764 {
765     struct cligen_handle *ch = handle(h);
766 
767     ch->ch_logsyntax = n;
768     return 0;
769 }
770 
771 /*! Get app-specific handle for callbacks instead of cligen handle.
772  *
773  * An application may choose to use another handle than cligen_handle in callbacks
774  * and completion functions.
775  * @param[in] h       CLIgen handle
776  */
777 void*
cligen_userhandle(cligen_handle h)778 cligen_userhandle(cligen_handle h)
779 {
780     struct cligen_handle *ch = handle(h);
781 
782     return ch->ch_userhandle;
783 }
784 
785 /*! Set app-specific handle for callbacks instead of cligen handle
786  * @param[in] h       CLIgen handle
787  */
788 int
cligen_userhandle_set(cligen_handle h,void * userhandle)789 cligen_userhandle_set(cligen_handle h,
790 		      void         *userhandle)
791 {
792     struct cligen_handle *ch = handle(h);
793 
794     ch->ch_userhandle = userhandle;
795     return 0;
796 }
797 
798 /*! Get regex engine / method
799  *
800  * @param[in] h   CLIgen handle
801  * @retval    0   Posix regex
802  * @retval    1   XSD Libxml2 regex
803  */
804 int
cligen_regex_xsd(cligen_handle h)805 cligen_regex_xsd(cligen_handle h)
806 {
807     struct cligen_handle *ch = handle(h);
808 
809     return ch->ch_regex_xsd;
810 }
811 
812 /*! Set regex engine to 0: posix, or 1: XSD / Libxml2
813  * @param[in] h       CLIgen handle
814  * @param[in] mode    0: posix (default), 1: libxml2 xsd regex
815  */
816 int
cligen_regex_xsd_set(cligen_handle h,int mode)817 cligen_regex_xsd_set(cligen_handle h,
818 		     int           mode)
819 {
820     struct cligen_handle *ch = handle(h);
821 
822     ch->ch_regex_xsd = mode;
823     return 0;
824 }
825 
826 
827 static int _getline_bufsize = GETLINE_BUFLEN_DEFAULT;
828 static int _getline_killbufsize = GETLINE_BUFLEN_DEFAULT;
829 
830 /*!
831  * @param[in] h       CLIgen handle
832  */
833 char*
cligen_buf(cligen_handle h)834 cligen_buf(cligen_handle h)
835 {
836     struct cligen_handle *ch = handle(h);
837 
838     return ch->ch_buf;
839 }
840 
841 /*!
842  * @param[in] h       CLIgen handle
843  */
844 char*
cligen_killbuf(cligen_handle h)845 cligen_killbuf(cligen_handle h)
846 {
847     struct cligen_handle *ch = handle(h);
848 
849     return ch->ch_killbuf;
850 }
851 
852 /*! Return length cligen line buffer
853  * @param[in] h       CLIgen handle
854  * @see cligen_buf_increase
855  */
856 int
cligen_buf_size(cligen_handle h)857 cligen_buf_size(cligen_handle h)
858 {
859     return _getline_bufsize;
860 }
861 
862 /*! Return length cligen kill buffer
863  * @param[in] h       CLIgen handle
864  */
865 int
cligen_killbuf_size(cligen_handle h)866 cligen_killbuf_size(cligen_handle h)
867 {
868     return _getline_killbufsize;
869 }
870 
871 /*!
872  * @param[in] h       CLIgen handle
873  */
874 int
cligen_buf_init(cligen_handle h)875 cligen_buf_init(cligen_handle h)
876 {
877     struct cligen_handle *ch = handle(h);
878 
879     if ((ch->ch_buf = malloc(_getline_bufsize)) == NULL){
880 	fprintf(stderr, "%s malloc: %s\n", __FUNCTION__, strerror(errno));
881 	return -1;
882     }
883     memset(ch->ch_buf, 0, _getline_bufsize);
884     if ((ch->ch_killbuf = malloc(_getline_killbufsize)) == NULL){
885 	fprintf(stderr, "%s malloc: %s\n", __FUNCTION__, strerror(errno));
886 	return -1;
887     }
888     memset(ch->ch_killbuf, 0, _getline_killbufsize);
889     return 0;
890 }
891 
892 /*! Increase cligen buffer length with *2 to satisfy new length
893  * @param[in] h       CLIgen handle
894  * @param[in] len1    New minimal length (add null for end of string)
895  * |-------------------|------|--------||------|
896  * ^                   ^      ^        ^^      ^
897  * ch_buf              len0   |     len1+1     |
898  *                            bufsize0         bufsize1 = 2^n*bufsize0
899  */
900 int
cligen_buf_increase(cligen_handle h,size_t len1)901 cligen_buf_increase(cligen_handle h,
902 		    size_t        len1)
903 {
904     struct cligen_handle *ch = handle(h);
905     size_t                len0 = _getline_bufsize; /* orig length */
906 
907     if (_getline_bufsize >= len1 + 1)
908       return 0;
909     while (_getline_bufsize < len1 + 1)
910       _getline_bufsize *= 2;
911     if ((ch->ch_buf = realloc(ch->ch_buf, _getline_bufsize)) == NULL){
912 	fprintf(stderr, "%s realloc: %s\n", __FUNCTION__, strerror(errno));
913 	return -1;
914     }
915     memset(ch->ch_buf+len0, 0, _getline_bufsize-len0);
916     return 0;
917 }
918 
919 /*! Increase cligen kill buffer length with *2 to satisfy new length
920  * @param[in] h       CLIgen handle
921  * @param[in] len1    New minimal length
922  */
923 int
cligen_killbuf_increase(cligen_handle h,size_t len1)924 cligen_killbuf_increase(cligen_handle h,
925 			size_t        len1)
926 {
927     struct cligen_handle *ch = handle(h);
928     int                   len0 = _getline_killbufsize;
929 
930     if (_getline_killbufsize >= len1 + 1)
931       return 0;
932     while (_getline_killbufsize < len1 + 1)
933       _getline_killbufsize *= 2;
934     if ((ch->ch_killbuf = realloc(ch->ch_killbuf, _getline_killbufsize)) == NULL){
935 	fprintf(stderr, "%s realloc: %s\n", __FUNCTION__, strerror(errno));
936 	return -1;
937     }
938     memset(ch->ch_killbuf+len0, 0, _getline_killbufsize-len0);
939     return 0;
940 }
941 
942 /*!
943  * @param[in] h       CLIgen handle
944  */
945 int
cligen_buf_cleanup(cligen_handle h)946 cligen_buf_cleanup(cligen_handle h)
947 {
948     struct cligen_handle *ch = handle(h);
949 
950     if (ch->ch_buf){
951 	free(ch->ch_buf);
952 	ch->ch_buf = NULL;
953     }
954     if (ch->ch_killbuf){
955 	free(ch->ch_killbuf);
956 	ch->ch_killbuf = NULL;
957     }
958     return 0;
959 }
960 
961 char
cligen_delimiter(cligen_handle h)962 cligen_delimiter(cligen_handle h)
963 {
964     struct cligen_handle *ch = handle(h);
965     return ch->ch_delimiter;
966 }
967 
968 int
cligen_delimiter_set(cligen_handle h,char delimiter)969 cligen_delimiter_set(cligen_handle h,
970 		     char          delimiter)
971 {
972     struct cligen_handle *ch = handle(h);
973 
974     ch->ch_delimiter = delimiter;
975     return 0;
976 }
977 
978 /*! Get preference mode, return all with same pref(ambiguos) or first (1)
979  * @param[in] h      CLIgen handle
980  * @retval    1      Preference mode is set (return first)
981  * @retval    0      Preference mode is not set (ambiguous)
982  */
983 int
cligen_preference_mode(cligen_handle h)984 cligen_preference_mode(cligen_handle h)
985 {
986     struct cligen_handle *ch = handle(h);
987 
988     return ch->ch_preference_mode;
989 }
990 
991 /*! Set preference mode, return all with same pref(ambiguous) or first (1)
992  * More specifically, if several cligen object variables match with same preference,
993  * select the first, do not match all.
994  * Example:
995  * key (<a:string length[4]> | <a:string length[40]>);
996  * @param[in] h      CLIgen handle
997  * @param[in] flag   Set to 1 to return first, 0 if ambiguous
998  * @retval    0      OK
999  */
1000 int
cligen_preference_mode_set(cligen_handle h,int flag)1001 cligen_preference_mode_set(cligen_handle h,
1002 			   int           flag)
1003 {
1004     struct cligen_handle *ch = handle(h);
1005 
1006     ch->ch_preference_mode = flag;
1007     return 0;
1008 }
1009