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