1 /*
2 * Copyright (C) 1991, 1992, 1993 by Chris Thewalt (thewalt@ce.berkeley.edu)
3 *
4 * Permission to use, copy, modify, and distribute this software
5 * for any purpose and without fee is hereby granted, provided
6 * that the above copyright notices appear in all copies and that both the
7 * copyright notice and this permission notice appear in supporting
8 * documentation. This software is provided "as is" without express or
9 * implied warranty.
10 *
11 * Thanks to the following people who have provided enhancements and fixes:
12 * Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List,
13 * DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten,
14 * Edin Hodzic, Eric J Bivona, Kai Uwe Rommel, Danny Quah, Ulrich Betzler
15 */
16
17 #include "cligen_config.h"
18
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/select.h>
23 #include <netinet/in.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <signal.h>
28
29 #include "cligen_buf.h"
30 #include "cligen_cv.h"
31 #include "cligen_cvec.h"
32 #include "cligen_parsetree.h"
33 #include "cligen_pt_head.h"
34 #include "cligen_object.h"
35 #include "cligen_io.h"
36 #include "cligen_handle.h"
37 #include "cligen_history_internal.h"
38
39 #include "cligen_getline.h" /* exported interface */
40
41 /********************* exported variables ********************************/
42
43 int (*gl_in_hook)() = NULL;
44 int (*gl_out_hook)() = NULL;
45 int (*gl_tab_hook)() = NULL;
46 int (*gl_qmark_hook)() = NULL;
47 int (*gl_susp_hook)() = NULL;
48 int (*gl_interrupt_hook)() = NULL;
49
50 /******************** internal interface *********************************/
51
52 /* begin forward declared internal functions */
53 static void gl_init1(void); /* prepare to edit a line */
54 static void gl_cleanup(void); /* to undo gl_init1 */
55 void gl_char_init(void); /* get ready for no echo input */
56 void gl_char_cleanup(void); /* undo gl_char_init */
57 static size_t (*gl_strlen)() = (size_t(*)())strlen;
58 /* returns printable prompt width */
59
60 static void gl_addchar(cligen_handle h, int c); /* install specified char */
61 static void gl_del(cligen_handle h, int loc); /* del, either left (-1) or cur (0) */
62 static inline void gl_fixup(cligen_handle h, char*,int,int);/* fixup state variables and screen */
63 static int gl_getc(cligen_handle h); /* read one char from terminal */
64 static void gl_kill(cligen_handle h, int pos); /* delete to EOL */
65 static void gl_kill_begin(cligen_handle h, int pos); /* delete to BEGIN of line */
66 static void gl_kill_word(cligen_handle h, int pos); /* delete word */
67 static void gl_newline(cligen_handle); /* handle \n or \r */
68 static int gl_puts(char *buf); /* write a line to terminal */
69
70 static void gl_transpose(cligen_handle h); /* transpose two chars */
71 static void gl_yank(cligen_handle h); /* yank killed text */
72 static void gl_word(cligen_handle h, int dir); /* move a word */
73
74 static void search_addchar(cligen_handle h, int c); /* increment search string */
75 static void search_term(cligen_handle); /* reset with current contents */
76 static void search_back(cligen_handle h, int new); /* look back for current string */
77 static void search_forw(cligen_handle h, int new); /* look forw for current string */
78 /* end forward declared internal functions */
79
80 /* begin global variables */
81 static int gl_init_done = -1; /* terminal mode flag */
82 static int gl_termw = 80; /* actual terminal width */
83 static int gl_utf8 = 0; /* UTF-8 experimental mode */
84 static int gl_scrolling_mode = 1; /* Scrolling on / off */
85 static int gl_scrollw = 27; /* width of EOL scrolling region */
86 static int gl_width = 0; /* net size available for input */
87 static int gl_extent = 0; /* how far to redraw, 0 means all */
88 static int gl_overwrite = 0; /* overwrite mode */
89 static int gl_pos, gl_cnt = 0; /* position and size of input */
90
91 static char gl_intrc = 0; /* keyboard SIGINT char (^C) */
92 static char gl_quitc = 0; /* keyboard SIGQUIT char (^]) */
93 static char gl_suspc = 0; /* keyboard SIGTSTP char (^Z) */
94 static char gl_dsuspc = 0; /* delayed SIGTSTP char */
95 static int gl_search_mode = 0; /* search mode flag */
96
97 static int exitchars[8] = {0,}; /* 8 different exit chars should be enough */
98 static int gl_iseof = 0;
99
100 static int fixup_gl_shift; /* index of first on screen character */
101 static int fixup_off_right; /* true if more text right of screen */
102 static int fixup_off_left; /* true if more text left of screen */
103 static char fixup_last_prompt[80] = "";
104
105 #define SEARCH_LEN 100
106 static char search_prompt[SEARCH_LEN+2]; /* prompt includes search string */
107 static char search_string[SEARCH_LEN];
108 static int search_pos = 0; /* current location in search_string */
109 static int search_forw_flg = 0; /* search direction flag */
110 static int search_last = 0; /* last match found */
111
112 /* end global variables */
113
114
115 /************************ nonportable part *********************************/
116
117 #ifdef unix
118 #ifndef __unix__
119 #define __unix__
120 #endif /* not __unix__ */
121 #endif /* unix */
122
123 #ifdef _IBMR2
124 #ifndef __unix__
125 #define __unix__
126 #endif
127 #endif
128
129 #ifdef __GO32__
130 #include <pc.h>
131 #undef MSDOS
132 #undef __unix__
133 #endif
134
135 #ifdef MSDOS
136 #include <bios.h>
137 #endif
138
139 #ifdef __unix__
140 #include <unistd.h>
141
142 #define POSIX
143 #ifdef POSIX /* use POSIX interface */
144 #include <termios.h>
145 struct termios new_termios, old_termios;
146 #else /* not POSIX */
147 #include <sys/ioctl.h>
148 #ifdef M_XENIX /* does not really use bsd terminal interface */
149 #undef TIOCSETN
150 #endif /* M_XENIX */
151 #ifdef TIOCSETN /* use BSD interface */
152 #include <sgtty.h>
153 struct sgttyb new_tty, old_tty;
154 struct tchars tch;
155 struct ltchars ltch;
156 #else /* use SYSV interface */
157 #include <termio.h>
158 struct termio new_termio, old_termio;
159 #endif /* TIOCSETN */
160 #endif /* POSIX */
161 #endif /* __unix__ */
162
163 #ifdef vms
164 #include <descrip.h>
165 #include <ttdef.h>
166 #include <iodef.h>
167 #include unixio
168
169 static int setbuff[2]; /* buffer to set terminal attributes */
170 static short chan = -1; /* channel to terminal */
171 struct dsc$descriptor_s descrip; /* VMS descriptor */
172 #endif
173
174 void
gl_char_init(void)175 gl_char_init(void) /* turn off input echo */
176 {
177 #ifdef __unix__
178 #ifdef POSIX
179 tcgetattr(0, &old_termios);
180 gl_intrc = old_termios.c_cc[VINTR];
181 gl_quitc = old_termios.c_cc[VQUIT];
182 #ifdef VSUSP
183 gl_suspc = old_termios.c_cc[VSUSP];
184 #endif
185 #ifdef VDSUSP
186 gl_dsuspc = old_termios.c_cc[VDSUSP];
187 #endif
188 new_termios = old_termios;
189 new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
190 new_termios.c_iflag |= (IGNBRK|IGNPAR);
191 new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
192 new_termios.c_cc[VMIN] = 1;
193 new_termios.c_cc[VTIME] = 0;
194 tcsetattr(0, TCSADRAIN, &new_termios);
195 #else /* not POSIX */
196 #ifdef TIOCSETN /* BSD */
197 ioctl(0, TIOCGETC, &tch);
198 ioctl(0, TIOCGLTC, <ch);
199 gl_intrc = tch.t_intrc;
200 gl_quitc = tch.t_quitc;
201 gl_suspc = ltch.t_suspc;
202 gl_dsuspc = ltch.t_dsuspc;
203 ioctl(0, TIOCGETP, &old_tty);
204 new_tty = old_tty;
205 new_tty.sg_flags |= RAW;
206 new_tty.sg_flags &= ~ECHO;
207 ioctl(0, TIOCSETN, &new_tty);
208 #else /* SYSV */
209 ioctl(0, TCGETA, &old_termio);
210 gl_intrc = old_termio.c_cc[VINTR];
211 gl_quitc = old_termio.c_cc[VQUIT];
212 new_termio = old_termio;
213 new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
214 new_termio.c_iflag |= (IGNBRK|IGNPAR);
215 new_termio.c_lflag &= ~(ICANON|ISIG|ECHO);
216 new_termio.c_cc[VMIN] = 1;
217 new_termio.c_cc[VTIME] = 0;
218 ioctl(0, TCSETA, &new_termio);
219 #endif /* TIOCSETN */
220 #endif /* POSIX */
221 #endif /* __unix__ */
222
223 #ifdef vms
224 descrip.dsc$w_length = strlen("tt:");
225 descrip.dsc$b_dtype = DSC$K_DTYPE_T;
226 descrip.dsc$b_class = DSC$K_CLASS_S;
227 descrip.dsc$a_pointer = "tt:";
228 (void)sys$assign(&descrip,&chan,0,0);
229 (void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0);
230 setbuff[1] |= TT$M_NOECHO;
231 (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
232 #endif /* vms */
233 }
234
235 void
gl_char_cleanup(void)236 gl_char_cleanup(void) /* undo effects of gl_char_init */
237 {
238 #ifdef __unix__
239 #ifdef POSIX
240 tcsetattr(0, TCSADRAIN, &old_termios);
241 #else /* not POSIX */
242 #ifdef TIOCSETN /* BSD */
243 ioctl(0, TIOCSETN, &old_tty);
244 #else /* SYSV */
245 ioctl(0, TCSETA, &old_termio);
246 #endif /* TIOCSETN */
247 #endif /* POSIX */
248 #endif /* __unix__ */
249
250 #ifdef vms
251 setbuff[1] &= ~TT$M_NOECHO;
252 (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
253 sys$dassgn(chan);
254 chan = -1;
255 #endif
256 }
257
258 #if MSDOS || __EMX__ || __GO32__
pc_keymap(int c)259 int pc_keymap(int c)
260 {
261 switch (c) {
262 case 72: c = 16; /* up -> ^P */
263 break;
264 case 80: c = 14; /* down -> ^N */
265 break;
266 case 75: c = 2; /* left -> ^B */
267 break;
268 case 77: c = 6; /* right -> ^F */
269 break;
270 default: c = 0; /* make it garbage */
271 }
272 return c;
273 }
274 #endif /* MSDOS || __EMX__ || __GO32__ */
275
276
277 #if CLIGEN_REGFD
278 struct regfd {
279 int fd;
280 int (*cb)(int, void*);
281 void *arg;
282 };
283 static int nextfds = 0;
284 static struct regfd *extfds = NULL;
285
286 /* XXX: If arg is malloced, the treatment of arg creates leaks */
287 int
gl_regfd(int fd,cligen_fd_cb_t * cb,void * arg)288 gl_regfd(int fd,
289 cligen_fd_cb_t *cb,
290 void *arg)
291 {
292 int i;
293 struct regfd *tmp;
294
295 for (i = 0; i < nextfds; i++) {
296 if (extfds[i].fd == fd) { /* Already registered. Update arg and cb */
297 extfds[i].cb = cb;
298 extfds[i].arg = arg;
299 return 0;
300 }
301 }
302
303 if ((tmp = realloc(extfds, (nextfds+1) * sizeof(*extfds))) == NULL)
304 return -1;
305 tmp[nextfds].fd = fd;
306 tmp[nextfds].cb = cb;
307 tmp[nextfds].arg = arg;
308 extfds = tmp;
309 nextfds++;
310
311 return 0;
312 }
313
314 int
gl_unregfd(int fd)315 gl_unregfd(int fd)
316 {
317 int i;
318
319 for (i = 0; i < nextfds; i++) {
320 if (extfds[i].fd == fd) {
321 if (i+1 < nextfds)
322 memcpy(&extfds[i], &extfds[i+1], nextfds-i);
323 extfds = realloc(extfds, (nextfds-1) * sizeof(*extfds));
324 nextfds--;
325 return 0;
326 }
327 }
328
329 return -1;
330 }
331
332 int
gl_select()333 gl_select()
334 {
335 int i;
336 fd_set fdset;
337
338 while (1){
339 FD_ZERO(&fdset);
340 FD_SET(0, &fdset);
341 for(i = 0; i < nextfds; i++)
342 FD_SET(extfds[i].fd, &fdset);
343 if (select(FD_SETSIZE, &fdset, NULL, NULL, NULL) < 0)
344 return -1;
345 for(i = 0; i < nextfds; i++)
346 if (FD_ISSET(extfds[i].fd, &fdset))
347 if (extfds[i].cb(extfds[i].fd, extfds[i].arg) < 0)
348 return -1;
349 if (FD_ISSET(0, &fdset))
350 break;
351 }
352 return 0;
353 }
354 #endif
355
356
357 int
gl_eof()358 gl_eof()
359 {
360 return gl_iseof;
361 }
362
363 void
gl_exitchar_add(char c)364 gl_exitchar_add(char c)
365 {
366 int i;
367
368 for (i=0;sizeof(exitchars);i++)
369 if (!exitchars[i]){
370 exitchars[i] = c;
371 break;
372 }
373 }
374
375 /* check if c is an exit char */
376 static int
gl_exitchar(char c)377 gl_exitchar(char c)
378 {
379 int i;
380
381 for (i=0;sizeof(exitchars);i++){
382 if (!exitchars[i])
383 break;
384 if (exitchars[i] == c)
385 return 1;
386 }
387 return 0; /* ^C */
388 }
389
390 /*! Initiate an exit, not actually made, but gl_exiting() will return 1.
391 * @param[in] h CLIgen handle
392 */
393 static char *
gl_exit(cligen_handle h)394 gl_exit(cligen_handle h)
395 {
396 char *gl_buf = cligen_buf(h);
397
398 gl_iseof++;
399 gl_buf[0] = 0;
400 gl_cleanup();
401 gl_putc('\n');
402 return gl_buf;
403 }
404
405 /*! Get a character without echoing it to screen
406 * @param[in] h CLIgen handle
407 */
408 static int
gl_getc(cligen_handle h)409 gl_getc(cligen_handle h)
410 {
411 int c;
412 #ifdef __unix__
413 unsigned char ch;
414 #endif
415
416 #if CLIGEN_REGFD
417 gl_select(); /* block until something arrives on stdin */
418 #endif
419 #ifdef __unix__
420 while ((c = read(0, &ch, 1)) == -1) {
421 if (errno == EINTR){
422 if (gl_interrupt_hook(h) <0)
423 return -1;
424 continue;
425 }
426 break;
427 }
428 if (c == 0){
429 gl_iseof++;
430 cligen_buf(h)[0] = 0; /* clean exit from gl? */
431 gl_cleanup();
432 gl_putc('\n');
433 return -1;
434 }
435 c = (ch <= 0)? -1 : ch;
436 #endif /* __unix__ */
437 #ifdef MSDOS
438 c = _bios_keybrd(_NKEYBRD_READ);
439 #endif /* MSDOS */
440 #ifdef __GO32__
441 c = getkey() ;
442 if (c > 255) c = pc_keymap(c & 0377);
443 #endif /* __GO32__ */
444 #ifdef __TURBOC__
445 while(!bioskey(1))
446 ;
447 c = bioskey(0);
448 #endif
449 #if MSDOS || __TURBOC__
450 if ((c & 0377) == 224) {
451 c = pc_keymap((c >> 8) & 0377);
452 } else {
453 c &= 0377;
454 }
455 #endif /* MSDOS || __TURBOC__ */
456 #ifdef __EMX__
457 c = _read_kbd(0, 1, 0);
458 if (c == 224 || c == 0) {
459 c = pc_keymap(_read_kbd(0, 1, 0));
460 } else {
461 c &= 0377;
462 }
463 #endif
464 #ifdef vms
465 if(chan < 0) {
466 c='\0';
467 }
468 (void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0);
469 c &= 0177; /* get a char */
470 #endif
471 return c;
472 }
473
474 int
gl_putc(int c)475 gl_putc(int c)
476 {
477 char ch = c;
478
479 if (write(1, &ch, 1) < 0)
480 return -1;
481 if (ch == '\n') {
482 ch = '\r'; /* RAW mode needs '\r', does not hurt */
483 if (write(1, &ch, 1) < 0)
484 return -1;
485 }
486 return 0;
487 }
488
489 /******************** fairly portable part *********************************/
490
491 static int
gl_puts(char * buf)492 gl_puts(char *buf)
493 {
494 int len;
495
496 if (buf) {
497 len = strlen(buf);
498 if (write(1, buf, len) < 0)
499 return -1;
500 }
501 return 0;
502 }
503
504 /*! set up variables and terminal
505 * @see gl_init cal this once first
506 */
507 static void
gl_init1()508 gl_init1()
509 {
510 gl_iseof = 0;
511 gl_char_init();
512 gl_init_done = 1;
513 }
514
515 /*! undo effects of gl_init1, as necessary */
516 static void
gl_cleanup()517 gl_cleanup()
518 {
519 if (gl_init_done > 0)
520 gl_char_cleanup();
521 gl_init_done = 0;
522 }
523
524 int
gl_getscrolling(void)525 gl_getscrolling(void)
526 {
527 return gl_scrolling_mode;
528 }
529
530 void
gl_setscrolling(int mode)531 gl_setscrolling(int mode)
532 {
533 gl_scrolling_mode = mode;
534 }
535
536 int
gl_getwidth(void)537 gl_getwidth(void)
538 {
539 return gl_termw;
540 }
541
542 /*! Set UTF-8 experimental mode
543 * @param[in] enabled Set to 1 to enable UTF-8 experimental mode
544 */
545 int
gl_utf8_set(int mode)546 gl_utf8_set(int mode)
547 {
548 gl_utf8 = mode;
549 return 0;
550 }
551
552 /*! get UTF-8 experimental mode
553 * @retval 0 UTF-8 is disabled
554 * @retval 1 UTF-8 is enabled
555 */
556 int
gl_utf8_get(void)557 gl_utf8_get(void)
558 {
559 return gl_utf8;
560 }
561
562 int
gl_setwidth(int w)563 gl_setwidth(int w)
564 {
565 if (w < TERM_MIN_SCREEN_WIDTH)
566 return -1;
567 gl_termw = w;
568 gl_scrollw = w / 3;
569 return 0;
570 }
571
572 /*! Main getline function handling a command line
573 *
574 * @param[in] h CLIgen handle
575 * @param[out] buf Pointer to char* buffer containing CLIgen command
576 * @retval 0 OK: string or EOF
577 * @retval -1 Error
578 * Typically called by cliread.
579 */
580 int
gl_getline(cligen_handle h,char ** buf)581 gl_getline(cligen_handle h,
582 char **buf)
583 {
584 int c, loc, tmp;
585 char *gl_prompt;
586 int escape = 0;
587 #ifdef __unix__
588 int sig;
589 #endif
590
591 gl_init1();
592 gl_prompt = (cligen_prompt(h))? cligen_prompt(h) : "";
593 cligen_buf(h)[0] = 0;
594 if (gl_in_hook)
595 gl_in_hook(h, cligen_buf(h));
596 gl_fixup(h, gl_prompt, -2, cligen_buf_size(h));
597 while ((c = gl_getc(h)) >= 0) {
598 gl_extent = 0; /* reset to full extent */
599 if (isprint(c) || (escape&&c=='\n')) {
600 if (escape == 0 && c == '\\')
601 escape++;
602 else{
603 if (escape ==0 && c == '?' && gl_qmark_hook) {
604 escape = 0;
605 if ((loc = gl_qmark_hook(h, cligen_buf(h))) < 0)
606 goto err;
607 gl_fixup(h, gl_prompt, -2, gl_pos);
608 }
609 else{
610 escape = 0;
611 if (gl_search_mode)
612 search_addchar(h, c);
613 else
614 gl_addchar(h, c);
615 }
616 }
617 } else {
618 escape = 0;
619 if (gl_search_mode) { /* after ^S or ^R */
620 if (c == '\033' || c == '\016' || c == '\020') { /* ESC, ^N, ^P */
621 search_term(h);
622 c = 0; /* ignore the character */
623 } else if (c == '\010' || c == '\177') { /* del */
624 search_addchar(h, -1); /* unwind search string */
625 c = 0;
626 } else if (c != '\022' && c != '\023') { /* ^R ^S */
627 search_term(h); /* terminate and handle char */
628 }
629 }
630 /* special exit characters */
631 if (gl_exitchar(c))
632 goto exit;
633 switch (c) {
634 case '\n': case '\r': /* newline */
635 gl_newline(h);
636 goto done;
637 /*NOTREACHED*/
638 break;
639 case '\001': gl_fixup(h, gl_prompt, -1, 0); /* ^A */
640 break;
641 case '\002': gl_fixup(h, gl_prompt, -1, gl_pos-1); /* ^B */
642 break;
643 case '\004': /* ^D */
644 if (gl_cnt == 0)
645 goto exit;
646 else
647 gl_del(h, 0);
648 break;
649 case '\005': gl_fixup(h, gl_prompt, -1, gl_cnt); /* ^E */
650 break;
651 case '\006': gl_fixup(h, gl_prompt, -1, gl_pos+1); /* ^F */
652 break;
653 case '\010': case '\177': gl_del(h, -1); /* ^H and DEL */
654 break;
655 case '\t': /* TAB */
656 if (gl_tab_hook) {
657 tmp = gl_pos;
658 if ((loc = gl_tab_hook(h, &tmp)) < 0)
659 goto err;
660 gl_fixup(h, gl_prompt, -2, tmp);
661 #if 0
662 if (loc != -1 || tmp != gl_pos)
663 gl_fixup(h, gl_prompt, loc, tmp);
664 #endif
665 }
666 break;
667 case '\013': gl_kill(h, gl_pos); /* ^K */
668 break;
669 case '\014':
670 gl_clear_screen(h); /* ^L */
671 break;
672 case '\016': /* ^N */
673 hist_copy_next(h);
674 if (gl_in_hook)
675 gl_in_hook(h, cligen_buf(h));
676 gl_fixup(h, gl_prompt, 0, cligen_buf_size(h));
677 break;
678 case '\017': gl_overwrite = !gl_overwrite; /* ^O */
679 break;
680 case '\020': /* ^P */
681 hist_copy_prev(h);
682 if (gl_in_hook)
683 gl_in_hook(h, cligen_buf(h));
684 gl_fixup(h, gl_prompt, 0, cligen_buf_size(h));
685 break;
686 case '\022': search_back(h, 1); /* ^R */
687 break;
688 case '\023': search_forw(h, 1); /* ^S */
689 break;
690 case '\024': gl_transpose(h); /* ^T */
691 break;
692 case '\025': gl_kill_begin(h, gl_pos); /* ^U */
693 break;
694 case '\027': gl_kill_word(h, gl_pos); /* ^W */
695 break;
696 case '\031': gl_yank(h); /* ^Y */
697 break;
698 case '\032': /* ^Z */
699 if(gl_susp_hook) {
700 tmp = gl_pos;
701 loc = gl_susp_hook(cligen_userhandle(h)?cligen_userhandle(h):h,
702 cligen_buf(h), gl_strlen(gl_prompt), &tmp);
703 if (loc != -1 || tmp != gl_pos)
704 gl_fixup(h, gl_prompt, loc, tmp);
705 if (strchr (cligen_buf(h), '\n'))
706 goto done;
707 }
708 break;
709 case '\033': /* ansi arrow keys (ESC) */
710 c = gl_getc(h);
711 /* ESC-[ is normal and ESC-O is application cursor keys */
712 if (c == '[' || c == 'O') {
713 switch(c = gl_getc(h)) {
714 case 'A': /* up */
715 hist_copy_prev(h);
716 if (gl_in_hook)
717 gl_in_hook(h, cligen_buf(h));
718 gl_fixup(h, gl_prompt, 0, cligen_buf_size(h));
719 break;
720 case 'B': /* down */
721 hist_copy_next(h);
722 if (gl_in_hook)
723 gl_in_hook(h, cligen_buf(h));
724 gl_fixup(h, gl_prompt, 0, cligen_buf_size(h));
725 break;
726 case 'C': gl_fixup(h, gl_prompt, -1, gl_pos+1); /* right */
727 break;
728 case 'D': gl_fixup(h, gl_prompt, -1, gl_pos-1); /* left */
729 break;
730 default: gl_putc('\007'); /* who knows */
731 break;
732 }
733 } else if (c == 'f' || c == 'F') {
734 gl_word(h, 1);
735 } else if (c == 'b' || c == 'B') {
736 gl_word(h, -1);
737 } else
738 gl_putc('\007');
739 break;
740 default: /* check for a terminal signal */
741 #ifdef __unix__
742 if ((c & 0xe0) == 0xc0){ /* UTF-2 */
743 int c2;
744 c2 = gl_getc(h);
745 if (gl_utf8){
746 gl_addchar(h, c);
747 gl_addchar(h, c2);
748 }
749 }
750 else if ((c & 0xf0) == 0xe0){ /* UTF-2 */
751 int c2, c3;
752 c2 = gl_getc(h);
753 c3 = gl_getc(h);
754 if (gl_utf8){
755 gl_addchar(h, c);
756 gl_addchar(h, c2);
757 gl_addchar(h, c3);
758 }
759 }
760 else if ((c & 0xf8) == 0xf0){ /* UTF-3 */
761 int c2, c3, c4;
762 c2 = gl_getc(h);
763 c3 = gl_getc(h);
764 c4 = gl_getc(h);
765 if (gl_utf8){
766 gl_addchar(h, c);
767 gl_addchar(h, c2);
768 gl_addchar(h, c3);
769 gl_addchar(h, c4);
770 }
771 }
772 if (c > 0) { /* ignore 0 (reset above) */
773 sig = 0;
774 #ifdef SIGINT
775 if (c == gl_intrc)
776 sig = SIGINT;
777 #endif
778 #ifdef SIGQUIT
779 if (c == gl_quitc)
780 sig = SIGQUIT;
781 #endif
782 #ifdef SIGTSTP
783 if (c == gl_suspc || c == gl_dsuspc)
784 sig = SIGTSTP;
785 #endif
786 if (sig != 0) {
787 gl_cleanup();
788 kill(0, sig);
789 gl_init1();
790 gl_redraw(h);
791 gl_kill(h, 0);
792 c = 0;
793 }
794 }
795 #endif /* __unix__ */
796 if (c > 0)
797 gl_putc('\007');
798 break;
799 }
800 }
801 } /* while */
802 cligen_buf(h)[0] = 0;
803 done:
804 gl_cleanup();
805 *buf = cligen_buf(h);
806 return 0;
807 exit: /* ie exit from cli, not necessarily error */
808 gl_exit(h);
809 *buf = cligen_buf(h);
810 return 0;
811 err: /* fatal error */
812 gl_cleanup();
813 return -1;
814 }
815
816 /*! Add the character c to the input buffer at current location
817 * @param[in] h CLIgen handle
818 * @param[in] c Character
819 */
820 static void
gl_addchar(cligen_handle h,int c)821 gl_addchar(cligen_handle h,
822 int c)
823 {
824 int i;
825
826 cligen_buf_increase(h, gl_cnt+1); /* assume increase enough for gl_pos-gl_cnt */
827 if (gl_overwrite == 0 || gl_pos == gl_cnt) {
828 for (i=gl_cnt; i >= gl_pos; i--)
829 cligen_buf(h)[i+1] = cligen_buf(h)[i];
830 cligen_buf(h)[gl_pos] = c;
831 gl_fixup(h, cligen_prompt(h), gl_pos, gl_pos+1);
832 } else {
833 cligen_buf(h)[gl_pos] = c;
834 gl_extent = 1;
835 gl_fixup(h, cligen_prompt(h), gl_pos, gl_pos+1);
836 }
837 }
838
839 /*! Add the kill buffer to the input buffer at current location
840 * @param[in] h CLIgen handle
841 */
842 static void
gl_yank(cligen_handle h)843 gl_yank(cligen_handle h)
844 {
845 int i, len;
846
847 len = strlen(cligen_killbuf(h));
848 if (len > 0) {
849 if (gl_overwrite == 0) {
850 cligen_buf_increase(h, gl_cnt + len + 1);
851 for (i=gl_cnt; i >= gl_pos; i--)
852 cligen_buf(h)[i+len] = cligen_buf(h)[i];
853 for (i=0; i < len; i++)
854 cligen_buf(h)[gl_pos+i] = cligen_killbuf(h)[i];
855 gl_fixup(h, cligen_prompt(h), gl_pos, gl_pos+len);
856 } else {
857 if (gl_pos + len > gl_cnt) {
858 cligen_buf_increase(h, gl_pos + len + 1);
859 cligen_buf(h)[gl_pos + len] = 0;
860 }
861 for (i=0; i < len; i++)
862 cligen_buf(h)[gl_pos+i] = cligen_killbuf(h)[i];
863 gl_extent = len;
864 gl_fixup(h, cligen_prompt(h), gl_pos, gl_pos+len);
865 }
866 } else
867 gl_putc('\007');
868 }
869
870 /*! Switch character under cursor and to left of cursor
871 * @param[in] h CLIgen handle
872 */
873 static void
gl_transpose(cligen_handle h)874 gl_transpose(cligen_handle h)
875 {
876 int c;
877
878 if (gl_pos > 0 && gl_cnt > gl_pos) {
879 c = cligen_buf(h)[gl_pos-1];
880 cligen_buf(h)[gl_pos-1] = cligen_buf(h)[gl_pos];
881 cligen_buf(h)[gl_pos] = c;
882 gl_extent = 2;
883 gl_fixup(h, cligen_prompt(h), gl_pos-1, gl_pos);
884 } else
885 gl_putc('\007');
886 }
887
888 /*! Cleans up entire line before returning to caller.
889 *
890 * @param[in] h CLIgen handle
891 * A \n is appended. If line longer than screen, redraw starting at beginning
892 */
893 static void
gl_newline(cligen_handle h)894 gl_newline(cligen_handle h)
895 {
896 int len = gl_cnt;
897 int loc;
898
899 if (gl_scrolling_mode)
900 loc = gl_width - 5; /* shifts line back to start position */
901 else
902 loc = gl_cnt;
903
904 cligen_buf_increase(h, gl_cnt+1); /* \n\0 added */
905 if (gl_out_hook) {
906 len = strlen(cligen_buf(h));
907 }
908 if (loc > len)
909 loc = len;
910 gl_fixup(h, cligen_prompt(h), -1, loc); /* must do this before appending \n */
911 cligen_buf(h)[len] = '\n';
912 cligen_buf(h)[len+1] = '\0';
913 gl_putc('\n');
914 }
915
916 /*! Delete a character.
917 * @param[in] h CLIgen handle
918 * @param[in] loc -1 : delete character to left of cursor
919 * 0 : delete character under cursor
920 */
921 static void
gl_del(cligen_handle h,int loc)922 gl_del(cligen_handle h,
923 int loc)
924 {
925 int i;
926
927 if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
928 for (i=gl_pos+loc; i < gl_cnt; i++)
929 cligen_buf(h)[i] = cligen_buf(h)[i+1];
930 gl_fixup(h, cligen_prompt(h), gl_pos+loc, gl_pos+loc);
931 } else
932 gl_putc('\007');
933 }
934
935 /*! Delete position to end of line
936 * @param[in] h CLIgen handle
937 * @param[in] pos Delete from pos to the end of line
938 */
939 static void
gl_kill(cligen_handle h,int pos)940 gl_kill(cligen_handle h,
941 int pos)
942 {
943 if (pos < gl_cnt) {
944 cligen_killbuf_increase(h, cligen_buf_size(h));
945 strncpy(cligen_killbuf(h), cligen_buf(h) + pos, cligen_buf_size(h));
946 cligen_buf(h)[pos] = '\0';
947 gl_fixup(h, cligen_prompt(h), pos, pos);
948 } else
949 gl_putc('\007');
950 }
951
952 /* Delete from pos to start of line
953 * @param[in] h CLIgen handle
954 * @param[in] pos Delete from pos to start of line
955 */
956 static void
gl_kill_begin(cligen_handle h,int pos)957 gl_kill_begin(cligen_handle h,
958 int pos)
959 {
960 int i;
961 int len;
962
963 if (pos != 0) {
964 len = strlen(cligen_buf(h));
965 cligen_killbuf_increase(h, pos);
966 strncpy(cligen_killbuf(h), cligen_buf(h), pos);
967 cligen_killbuf(h)[pos] = '\0';
968 memmove(cligen_buf(h), cligen_buf(h) + pos, len-pos+1); /* memmove may overlap */
969 gl_fixup(h, cligen_prompt(h), 0, 0);
970 for (i=gl_pos; i < gl_cnt; i++)
971 gl_putc(cligen_buf(h)[i]);
972 gl_fixup(h, cligen_prompt(h), -2, 0);
973 } else
974 gl_putc('\007');
975 }
976
977 /*! Delete one previous word from pos
978 * @param[in] h CLIgen handle
979 * @param[in] pos Delete one previous word from pos
980 */
981 static void
gl_kill_word(cligen_handle h,int pos)982 gl_kill_word(cligen_handle h,
983 int pos)
984 {
985 int i, wpos;
986
987 if (pos == 0)
988 gl_putc('\007');
989 else {
990 wpos = pos;
991 if (pos > 0)
992 pos--;
993 while (isspace((int)cligen_buf(h)[pos]) && pos > 0)
994 pos--;
995 while (!isspace((int)cligen_buf(h)[pos]) && pos > 0)
996 pos--;
997 if (pos < gl_cnt && isspace((int)cligen_buf(h)[pos])) /* move onto word */
998 pos++;
999 cligen_killbuf_increase(h, wpos-pos);
1000 strncpy(cligen_killbuf(h), cligen_buf(h)+pos, wpos-pos);
1001 cligen_killbuf(h)[wpos-pos] = '\0';
1002 memmove(cligen_buf(h)+pos, cligen_buf(h) + wpos, wpos-pos+1);
1003 gl_fixup(h, cligen_prompt(h), wpos, pos);
1004 for (i=gl_pos; i < gl_cnt; i++)
1005 gl_putc(cligen_buf(h)[i]);
1006 gl_fixup(h, cligen_prompt(h), -2, pos);
1007
1008 }
1009 }
1010
1011
1012 /*! Move forward or backword one word
1013 * @param[in] h CLIgen handle
1014 * @param[in] direction >0 forward; else backward
1015 */
1016 static void
gl_word(cligen_handle h,int direction)1017 gl_word(cligen_handle h,
1018 int direction)
1019
1020 {
1021 int pos = gl_pos;
1022
1023 if (direction > 0) { /* forward */
1024 while (!isspace((int)cligen_buf(h)[pos]) && (pos < gl_cnt))
1025 pos++;
1026 while (isspace((int)cligen_buf(h)[pos]) && pos < gl_cnt)
1027 pos++;
1028 } else { /* backword */
1029 if (pos > 0)
1030 pos--;
1031 while (isspace((int)cligen_buf(h)[pos]) && pos > 0)
1032 pos--;
1033 while (!isspace((int)cligen_buf(h)[pos]) && pos > 0)
1034 pos--;
1035 if (pos < gl_cnt && isspace((int)cligen_buf(h)[pos])) /* move onto word */
1036 pos++;
1037 }
1038 gl_fixup(h, cligen_prompt(h), -1, pos);
1039 }
1040
1041 static int
move_cursor_up(int nr)1042 move_cursor_up(int nr)
1043 {
1044 gl_putc(033);
1045 gl_putc('[');
1046 gl_putc('1');
1047 gl_putc('A');
1048 return 0;
1049 }
1050
1051 static int
move_cursor_right(int nr)1052 move_cursor_right(int nr)
1053 {
1054 char str[16];
1055 int i;
1056 gl_putc(033);
1057 gl_putc('[');
1058 snprintf(str, 15, "%d", nr);
1059 for (i=0; i<strlen(str); i++)
1060 gl_putc(str[i]);
1061 gl_putc('C');
1062 return 0;
1063 }
1064
1065 static int
wrap_line()1066 wrap_line()
1067 {
1068 gl_putc('\n'); /* wrap line */
1069 return 0;
1070 }
1071
1072 static int
unwrap_line()1073 unwrap_line()
1074 {
1075 move_cursor_up(1);
1076 move_cursor_right(gl_termw-1);
1077 return 0;
1078 }
1079
1080 int
wrap(int p,int plen)1081 wrap(int p,
1082 int plen)
1083 {
1084 return (p+plen+1)%gl_termw==0;
1085 }
1086
gl_clear_screen(cligen_handle h)1087 void gl_clear_screen(cligen_handle h)
1088 {
1089 if (gl_init_done <= 0) {
1090 return;
1091 }
1092
1093 gl_putc('\033'); /* clear */
1094 gl_putc('[');
1095 gl_putc('2');
1096 gl_putc('J');
1097
1098 gl_putc('\033'); /* home */
1099 gl_putc('[');
1100 gl_putc('H');
1101
1102 gl_fixup(h, cligen_prompt(h), -2, gl_pos);
1103 }
1104
1105 /*! Emit a newline, reset and redraw prompt and current input line
1106 * @param[in] h CLIgen handle
1107 */
1108 void
gl_redraw(cligen_handle h)1109 gl_redraw(cligen_handle h)
1110 {
1111 if (gl_init_done > 0) {
1112 gl_putc('\n');
1113 gl_fixup(h, cligen_prompt(h), -2, gl_pos);
1114 }
1115 }
1116
1117 /*! Redrawing or moving within line
1118 *
1119 * This function is used both for redrawing when input changes or for
1120 * moving within the input line. The parameters are:
1121 *
1122 * @param[in] h CLIgen handle
1123 * @param[in] prompt Compared to last_prompt[] for changes;
1124 * @param[in] change Index of the start of changes in the input buffer,
1125 * with -1 indicating no changes, -2 indicating we're on
1126 * a new line, redraw everything.
1127 * @param[in] cursor The desired location of the cursor after the call.
1128 * A value of cligen_buf_size(h) can be used to indicate
1129 * the cursor should move just past the end of the input line.
1130 */
1131 static void
gl_fixup_noscroll(cligen_handle h,char * prompt,int change,int cursor)1132 gl_fixup_noscroll(cligen_handle h,
1133 char *prompt,
1134 int change,
1135 int cursor)
1136 {
1137 int left = 0, right = -1; /* bounds for redraw */
1138 int pad; /* how much to erase at end of line */
1139 int backup; /* how far to backup before fixing */
1140 int i;
1141 int p; /* pos */
1142 int new_right = -1; /* alternate right bound, using gl_extent */
1143 int l1, l2;
1144 int plen=strlen(prompt);
1145
1146 if (change == -2) { /* reset */
1147 gl_pos = gl_cnt = fixup_gl_shift = fixup_off_right = fixup_off_left = 0;
1148 gl_putc('\r');
1149 gl_puts(prompt);
1150 strncpy(fixup_last_prompt, prompt, sizeof(fixup_last_prompt));
1151 change = 0;
1152 gl_width = gl_termw - gl_strlen(prompt);
1153 } else if (strcmp(prompt, fixup_last_prompt) != 0) {
1154 l1 = gl_strlen(fixup_last_prompt);
1155 l2 = gl_strlen(prompt);
1156 gl_cnt = gl_cnt + l1 - l2;
1157 strncpy(fixup_last_prompt, prompt, sizeof(fixup_last_prompt));
1158 gl_putc('\r');
1159 gl_puts(prompt);
1160 gl_pos = fixup_gl_shift;
1161 gl_width = gl_termw - l2;
1162 change = 0;
1163 }
1164 pad = (fixup_off_right)? gl_width - 1 : gl_cnt - fixup_gl_shift; /* old length */
1165 backup = gl_pos - fixup_gl_shift;
1166 if (change >= 0) {
1167 gl_cnt = strlen(cligen_buf(h));
1168 if (change > gl_cnt)
1169 change = gl_cnt;
1170 }
1171 if (cursor > gl_cnt) {
1172 if (cursor != cligen_buf_size(h)) /* cligen_buf_size(h) means end of line */
1173 gl_putc('\007');
1174 cursor = gl_cnt;
1175 }
1176 if (cursor < 0) {
1177 gl_putc('\007');
1178 cursor = 0;
1179 }
1180 if (change >= 0) { /* text changed */
1181 if (change < fixup_gl_shift + fixup_off_left) {
1182 left = fixup_gl_shift;
1183 } else {
1184 left = change;
1185 backup = gl_pos - change;
1186 }
1187 right = gl_cnt;
1188 new_right = (gl_extent && (right > left + gl_extent))?
1189 left + gl_extent : right;
1190 }
1191 pad -= gl_cnt - fixup_gl_shift;
1192 pad = (pad < 0)? 0 : pad;
1193 if (left <= right) { /* clean up screen */
1194 for (p=left+backup-1; p >= left; p--){
1195 if (wrap(p, plen))
1196 unwrap_line();
1197 else
1198 gl_putc('\b');
1199 }
1200 if (left == fixup_gl_shift && fixup_off_left) {
1201 gl_putc('$');
1202 left++;
1203 }
1204 for (p=left; p < new_right; p++){
1205 gl_putc(cligen_buf(h)[p]);
1206 if (wrap(p, plen))
1207 wrap_line();
1208 }
1209 gl_pos = new_right;
1210 for (p=new_right; p < new_right+pad; p++){ /* erase remains of prev line */
1211 gl_putc(' ');
1212 if (wrap(p, plen))
1213 wrap_line();
1214 }
1215 gl_pos += pad;
1216 }
1217 /* move to final cursor location */
1218 if (gl_pos - cursor > 0) {
1219 for (p=gl_pos; p > cursor; p--){
1220 if (wrap(p-1, plen))
1221 unwrap_line();
1222 else
1223 gl_putc('\b');
1224 }
1225 }
1226 else {
1227 for (i=gl_pos; i < cursor; i++)
1228 gl_putc(cligen_buf(h)[i]);
1229 }
1230 gl_pos = cursor;
1231 }
1232
1233
1234 /*! Redrawing or moving within line
1235 *
1236 * This function is used both for redrawing when input changes or for
1237 * moving within the input line. The parameters are:
1238 * prompt: compared to last_prompt[] for changes;
1239 * change : the index of the start of changes in the input buffer,
1240 * with -1 indicating no changes, -2 indicating we're on
1241 * a new line, redraw everything.
1242 * cursor : the desired location of the cursor after the call.
1243 * A value of cligen_buf_size(h) can be used to indicate the cursor should
1244 * move just past the end of the input line.
1245 */
1246 static void
gl_fixup_scroll(cligen_handle h,char * prompt,int change,int cursor)1247 gl_fixup_scroll(cligen_handle h,
1248 char *prompt,
1249 int change,
1250 int cursor)
1251 {
1252 int left = 0, right = -1; /* bounds for redraw */
1253 int pad; /* how much to erase at end of line */
1254 int backup; /* how far to backup before fixing */
1255 int new_shift; /* value of shift based on cursor */
1256 int extra; /* adjusts when shift (scroll) happens */
1257 int i;
1258 int new_right = -1; /* alternate right bound, using gl_extent */
1259 int l1, l2;
1260
1261 if (change == -2) { /* reset */
1262 gl_pos = gl_cnt = fixup_gl_shift = fixup_off_right = fixup_off_left = 0;
1263 gl_putc('\r');
1264 gl_puts(prompt);
1265 strncpy(fixup_last_prompt, prompt, sizeof(fixup_last_prompt));
1266 change = 0;
1267 gl_width = gl_termw - gl_strlen(prompt);
1268 } else if (strcmp(prompt, fixup_last_prompt) != 0) {
1269 l1 = gl_strlen(fixup_last_prompt);
1270 l2 = gl_strlen(prompt);
1271 gl_cnt = gl_cnt + l1 - l2;
1272 strncpy(fixup_last_prompt, prompt, sizeof(fixup_last_prompt));
1273 gl_putc('\r');
1274 gl_puts(prompt);
1275 gl_pos = fixup_gl_shift;
1276 gl_width = gl_termw - l2;
1277 change = 0;
1278 }
1279 pad = (fixup_off_right)? gl_width - 1 : gl_cnt - fixup_gl_shift; /* old length */
1280 backup = gl_pos - fixup_gl_shift;
1281 if (change >= 0) {
1282 gl_cnt = strlen(cligen_buf(h));
1283 if (change > gl_cnt)
1284 change = gl_cnt;
1285 }
1286 if (cursor > gl_cnt) {
1287 if (cursor != cligen_buf_size(h)) /* cligen_buf_size(h) means end of line */
1288 gl_putc('\007');
1289 cursor = gl_cnt;
1290 }
1291 if (cursor < 0) {
1292 gl_putc('\007');
1293 cursor = 0;
1294 }
1295 if (fixup_off_right || (fixup_off_left && cursor < fixup_gl_shift + gl_width - gl_scrollw / 2)){
1296 extra = 2; /* shift the scrolling boundary */
1297 }
1298 else
1299 extra = 0;
1300
1301 new_shift = cursor + extra + gl_scrollw - gl_width;
1302 if (new_shift > 0) {
1303 new_shift /= gl_scrollw;
1304 new_shift *= gl_scrollw;
1305 } else
1306 new_shift = 0;
1307 if (new_shift != fixup_gl_shift) { /* scroll occurs */
1308 fixup_gl_shift = new_shift;
1309 fixup_off_left = (fixup_gl_shift)? 1 : 0;
1310 fixup_off_right = (gl_cnt > fixup_gl_shift + gl_width - 1)? 1 : 0;
1311 left = fixup_gl_shift;
1312 new_right = right = (fixup_off_right)? fixup_gl_shift + gl_width - 2 : gl_cnt;
1313 } else if (change >= 0) { /* no scroll, but text changed */
1314 if (change < fixup_gl_shift + fixup_off_left) {
1315 left = fixup_gl_shift;
1316 } else {
1317 left = change;
1318 backup = gl_pos - change;
1319 }
1320 fixup_off_right = (gl_cnt > fixup_gl_shift + gl_width - 1)? 1 : 0;
1321 right = (fixup_off_right)? fixup_gl_shift + gl_width - 2 : gl_cnt;
1322 new_right = (gl_extent && (right > left + gl_extent))?
1323 left + gl_extent : right;
1324 }
1325 pad -= (fixup_off_right)? gl_width - 1 : gl_cnt - fixup_gl_shift;
1326 pad = (pad < 0)? 0 : pad;
1327 if (left <= right) { /* clean up screen */
1328 for (i=0; i < backup; i++)
1329 gl_putc('\b');
1330 if (left == fixup_gl_shift && fixup_off_left) {
1331 gl_putc('$');
1332 left++;
1333 }
1334 for (i=left; i < new_right; i++)
1335 gl_putc(cligen_buf(h)[i]);
1336 gl_pos = new_right;
1337 if (fixup_off_right && new_right == right) {
1338 gl_putc('$');
1339 gl_pos++;
1340 } else {
1341 for (i=0; i < pad; i++) /* erase remains of prev line */
1342 gl_putc(' ');
1343 gl_pos += pad;
1344 }
1345 }
1346 i = gl_pos - cursor; /* move to final cursor location */
1347 if (i > 0) {
1348 while (i--)
1349 gl_putc('\b');
1350 } else {
1351 for (i=gl_pos; i < cursor; i++)
1352 gl_putc(cligen_buf(h)[i]);
1353 }
1354 gl_pos = cursor;
1355 }
1356
1357 static inline void
gl_fixup(cligen_handle h,char * prompt,int change,int cursor)1358 gl_fixup(cligen_handle h,
1359 char *prompt,
1360 int change,
1361 int cursor)
1362 {
1363 if (gl_scrolling_mode)
1364 return gl_fixup_scroll(h, prompt, change, cursor);
1365 else
1366 return gl_fixup_noscroll(h, prompt, change, cursor);
1367 }
1368
1369 /******************* strlen stuff **************************************/
1370
1371 void
gl_strwidth(size_t (* func)())1372 gl_strwidth(size_t (*func)())
1373 {
1374 if (func != 0) {
1375 gl_strlen = func;
1376 }
1377 }
1378
1379
1380 /******************* Search stuff **************************************/
1381
1382
1383 static void
search_update(cligen_handle h,int c)1384 search_update(cligen_handle h,
1385 int c)
1386 {
1387 if (c == 0) {
1388 search_pos = 0;
1389 search_string[0] = 0;
1390 search_prompt[0] = '?';
1391 search_prompt[1] = ' ';
1392 search_prompt[2] = 0;
1393 } else if (c > 0){
1394 if (search_pos+1 < SEARCH_LEN) {
1395 search_string[search_pos] = c;
1396 search_string[search_pos+1] = 0;
1397 search_prompt[search_pos] = c;
1398 search_prompt[search_pos+1] = '?';
1399 search_prompt[search_pos+2] = ' ';
1400 search_prompt[search_pos+3] = 0;
1401 search_pos++;
1402 }
1403 } else {
1404 if (search_pos > 0) {
1405 search_pos--;
1406 search_string[search_pos] = 0;
1407 search_prompt[search_pos] = '?';
1408 search_prompt[search_pos+1] = ' ';
1409 search_prompt[search_pos+2] = 0;
1410 } else {
1411 gl_putc('\007');
1412 hist_pos_set(h, hist_last_get(h));
1413 }
1414 }
1415 }
1416
1417 /*! Search addchar
1418 * @param[in] h CLIgen handle
1419 */
1420 static void
search_addchar(cligen_handle h,int c)1421 search_addchar(cligen_handle h,
1422 int c)
1423 {
1424 char *loc;
1425
1426 search_update(h, c);
1427 if (c < 0) {
1428 if (search_pos > 0) {
1429 hist_pos_set(h, search_last);
1430 } else {
1431 cligen_buf(h)[0] = 0;
1432 hist_pos_set(h, hist_last_get(h));
1433 }
1434 hist_copy_pos(h);
1435 }
1436 if ((loc = strstr(cligen_buf(h), search_string)) != 0) {
1437 gl_fixup(h, search_prompt, 0, loc - cligen_buf(h));
1438 } else if (search_pos > 0) {
1439 if (search_forw_flg) {
1440 search_forw(h, 0);
1441 } else {
1442 search_back(h, 0);
1443 }
1444 } else {
1445 gl_fixup(h, search_prompt, 0, 0);
1446 }
1447 }
1448
1449 /*! Search terminate
1450 * @param[in] h CLIgen handle
1451 */
1452 static void
search_term(cligen_handle h)1453 search_term(cligen_handle h)
1454 {
1455 gl_search_mode = 0;
1456 if (cligen_buf(h)[0] == 0) /* not found, reset hist list */
1457 hist_pos_set(h, hist_last_get(h));
1458 if (gl_in_hook)
1459 gl_in_hook(h, cligen_buf(h));
1460 gl_fixup(h, cligen_prompt(h), 0, gl_pos);
1461 }
1462
1463 /*! Search backwards
1464 * @param[in] h CLIgen handle
1465 */
1466 static void
search_back(cligen_handle h,int new_search)1467 search_back(cligen_handle h,
1468 int new_search)
1469 {
1470 int found = 0;
1471 char *p, *loc;
1472 int last;
1473
1474 search_forw_flg = 0;
1475 if (gl_search_mode == 0) {
1476 last = hist_last_get(h);
1477 hist_pos_set(h, last);
1478 search_last = last;
1479 search_update(h, 0);
1480 gl_search_mode = 1;
1481 cligen_buf(h)[0] = 0;
1482 gl_fixup(h, search_prompt, 0, 0);
1483 } else if (search_pos > 0) {
1484 while (!found) {
1485 p = hist_prev(h);
1486 if (*p == 0) { /* not found, done looking */
1487 cligen_buf(h)[0] = 0;
1488 gl_fixup(h, search_prompt, 0, 0);
1489 found = 1;
1490 } else if ((loc = strstr(p, search_string)) != 0) {
1491 strncpy(cligen_buf(h), p, cligen_buf_size(h));
1492 gl_fixup(h, search_prompt, 0, loc - p);
1493 if (new_search)
1494 search_last = hist_pos(h);
1495 found = 1;
1496 }
1497 }
1498 } else {
1499 gl_putc('\007');
1500 }
1501 }
1502
1503 /*! Search forward
1504 * @param[in] h CLIgen handle
1505 */
1506 static void
search_forw(cligen_handle h,int new_search)1507 search_forw(cligen_handle h,
1508 int new_search)
1509 {
1510 int found = 0;
1511 char *p, *loc;
1512 int last;
1513
1514 search_forw_flg = 1;
1515 if (gl_search_mode == 0) {
1516 last = hist_last_get(h);
1517 hist_pos_set(h, last);
1518 search_last = last;
1519
1520 search_update(h, 0);
1521 gl_search_mode = 1;
1522 cligen_buf(h)[0] = 0;
1523 gl_fixup(h, search_prompt, 0, 0);
1524 } else if (search_pos > 0) {
1525 while (!found) {
1526 p = hist_next(h);
1527 if (*p == 0) { /* not found, done looking */
1528 cligen_buf(h)[0] = 0;
1529 gl_fixup(h, search_prompt, 0, 0);
1530 found = 1;
1531 } else if ((loc = strstr(p, search_string)) != 0) {
1532 strncpy(cligen_buf(h), p, cligen_buf_size(h));
1533 gl_fixup(h, search_prompt, 0, loc - p);
1534 if (new_search)
1535 search_last = hist_pos(h);
1536 found = 1;
1537 }
1538 }
1539 } else {
1540 gl_putc('\007');
1541 }
1542 }
1543
1544