Annotation of libaitcli/src/aitcli.c, revision 1.2.2.8
1.1 misho 1: /*************************************************************************
2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.2.2.8 ! misho 6: * $Id: aitcli.c,v 1.2.2.7 2010/06/07 11:54:00 misho Exp $
1.1 misho 7: *
8: *************************************************************************/
9: #include "global.h"
1.2.2.7 misho 10: #include "cli.h"
1.1 misho 11:
12:
13: #pragma GCC visibility push(hidden)
14:
1.2.2.2 misho 15: /*
16: commands_t cli_stdCmds[] = {
1.1 misho 17: { "test", cli_Cmd_Unsupported, "Test - Don`t use default command structure!", "test <cr>", cli_Comp_Filename },
18: { "-------", NULL, "---------------------", NULL, NULL },
19: { "help", cli_Cmd_Help, "Help screen", "help [command] <cr>", NULL },
20: { "exit", cli_Cmd_Exit, "Exit from console", "exit <cr>", NULL },
21: { NULL, NULL, NULL, NULL }
22: };
1.2.2.2 misho 23: */
1.1 misho 24:
25: // ------------------------------------------------
26:
27: int cli_Errno;
28: char cli_Error[STRSIZ];
29:
30: #pragma GCC visibility pop
31:
32: // cli_GetErrno() Get error code of last operation
1.2.2.2 misho 33: inline int
34: cli_GetErrno()
1.1 misho 35: {
36: return cli_Errno;
37: }
38:
39: // io_GetError() Get error text of last operation
1.2.2.2 misho 40: inline const char *
41: cli_GetError()
1.1 misho 42: {
43: return cli_Error;
44: }
45:
46: // cli_SetErr() Set error to variables for internal use!!!
1.2.2.2 misho 47: inline void
48: cli_SetErr(int eno, char *estr, ...)
1.1 misho 49: {
50: va_list lst;
51:
52: cli_Errno = eno;
53: memset(cli_Error, 0, STRSIZ);
54: va_start(lst, estr);
55: vsnprintf(cli_Error, STRSIZ, estr, lst);
56: va_end(lst);
57: }
58:
59: // ------------------------------------------------------------
60:
1.2.2.2 misho 61: static inline void
62: clrscrEOL(linebuffer_t * __restrict buf)
1.1 misho 63: {
1.2.2.2 misho 64: register int i;
1.1 misho 65:
1.2.2.2 misho 66: if (buf) {
67: write(buf->line_out, K_CR, 1);
1.1 misho 68:
1.2.2.2 misho 69: for (i = 0; i < buf->line_len; i++)
70: write(buf->line_out, K_SPACE, 1);
71: }
1.1 misho 72: }
73:
1.2.2.2 misho 74: static inline void
75: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2 misho 76: {
1.2.2.2 misho 77: if (buf) {
78: write(buf->line_out, K_CR, 1);
1.2 misho 79:
1.2.2.2 misho 80: if (prompt && buf->line_prompt)
81: write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2 misho 82:
1.2.2.2 misho 83: write(buf->line_out, buf->line_buf, len == -1 ? buf->line_eol - buf->line_bol: len);
84: }
1.2 misho 85: }
86:
1.2.2.2 misho 87: static inline void
88: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2 misho 89: {
1.2.2.2 misho 90: if (buf) {
91: write(buf->line_out, K_CR, 1);
92:
93: if (prompt)
94: if (prompt && buf->line_prompt)
95: write(buf->line_out, buf->line_prompt, buf->line_bol);
96: }
1.2 misho 97: }
98:
1.2.2.2 misho 99: static inline void
1.2.2.4 misho 100: printfNL(linebuffer_t * __restrict buf, int prompt)
101: {
102: if (buf) {
103: write(buf->line_out, K_ENTER, 1);
104:
105: if (prompt)
106: if (prompt && buf->line_prompt)
107: write(buf->line_out, buf->line_prompt, buf->line_bol);
108: }
109: }
110:
111: static inline void
1.2.2.2 misho 112: printfCLI(linebuffer_t * __restrict buf, const unsigned char *text, int textlen, int prompt)
1.2 misho 113: {
1.2.2.2 misho 114: if (buf && text && textlen) {
115: if (prompt && buf->line_prompt)
116: write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2 misho 117:
1.2.2.2 misho 118: write(buf->line_out, text, textlen);
119: }
1.2 misho 120: }
121:
1.2.2.2 misho 122: // ------------------------------------------------------------
123:
1.2.2.3 misho 124: static int
125: bufCHAR(int idx, void * __restrict buffer)
126: {
127: linebuffer_t *buf = buffer;
128: int pos;
129:
130: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
131: return RETCODE_ERR;
132:
133: pos = buf->line_eol - buf->line_bol;
134:
135: if (buf->line_mode == LINEMODE_INS)
136: memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos,
137: buf->line_len - buf->line_eol);
138: if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
139: buf->line_len += buf->line_keys[idx].key_len;
140: buf->line_eol += buf->line_keys[idx].key_len;
141:
142: memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
143: buf->line_buf[buf->line_len - 1] = 0;
144:
145: write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
146:
147: if (buf->line_mode == LINEMODE_INS) {
148: printfCLI(buf, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len,
149: buf->line_len - buf->line_eol, 0);
150: printfEOL(buf, -1, 1);
151: }
152: return RETCODE_OK;
153: }
154:
155: static int
156: bufEOL(int idx, void * __restrict buffer)
157: {
158: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
159: return RETCODE_ERR;
160:
161: printfCR(buffer, 1);
162: return RETCODE_EOL;
163: }
164:
165: static int
166: bufEOF(int idx, void * __restrict buffer)
167: {
168: linebuffer_t *buf = buffer;
169:
170: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
171: return RETCODE_ERR;
172:
173: write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
174: return RETCODE_EOF;
175: }
176:
177: static int
178: bufUP(int idx, void * __restrict buffer)
179: {
180: linebuffer_t *buf = buffer;
181: int pos;
182:
183: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
184: return RETCODE_ERR;
185:
186: if (!buf->line_h)
187: buf->line_h = TAILQ_FIRST(&buf->line_history);
188: else
189: buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
190: if (!buf->line_h)
191: return RETCODE_OK;
192:
193: clrscrEOL(buf);
194: cli_freeLine(buf);
195:
196: pos = buf->line_eol - buf->line_bol;
197:
198: buf->line_len += buf->line_h->hist_len;
199: buf->line_eol += buf->line_h->hist_len;
200:
201: memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
202: buf->line_buf[buf->line_len - 1] = 0;
203:
204: printfEOL(buf, -1, 1);
205: return RETCODE_OK;
206: }
207:
208: static int
209: bufDOWN(int idx, void * __restrict buffer)
210: {
211: linebuffer_t *buf = buffer;
212: int pos;
213:
214: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
215: return RETCODE_ERR;
216:
217: if (!buf->line_h)
218: buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
219: else
220: buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
221: if (!buf->line_h)
222: return RETCODE_OK;
223:
224: clrscrEOL(buf);
225: cli_freeLine(buf);
226:
227: pos = buf->line_eol - buf->line_bol;
228:
229: buf->line_len += buf->line_h->hist_len;
230: buf->line_eol += buf->line_h->hist_len;
231:
232: memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
233: buf->line_buf[buf->line_len - 1] = 0;
234:
235: printfEOL(buf, -1, 1);
236: return RETCODE_OK;
237: }
238:
239: static int
240: bufCLR(int idx, void * __restrict buffer)
241: {
242: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
243: return RETCODE_ERR;
244:
245: clrscrEOL(buffer);
246: cli_freeLine(buffer);
247:
248: printfCR(buffer, 1);
249: return RETCODE_OK;
250: }
251:
252: static int
253: bufBS(int idx, void * __restrict buffer)
254: {
255: linebuffer_t *buf = buffer;
256:
257: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
258: return RETCODE_ERR;
259:
260: if (buf->line_bol < buf->line_eol) {
261: clrscrEOL(buf);
262:
263: buf->line_eol--;
264: buf->line_len--;
265: memmove(buf->line_buf + buf->line_eol - buf->line_bol,
266: buf->line_buf + buf->line_eol - buf->line_bol + 1,
267: buf->line_len - buf->line_eol);
268: buf->line_buf[buf->line_len - 1] = 0;
269:
270: printfEOL(buf, buf->line_len - 1, 1);
271: printfEOL(buf, -1, 1);
272: }
273:
274: return RETCODE_OK;
275: }
276:
277: static int
278: bufBTAB(int idx, void * __restrict buffer)
279: {
280: linebuffer_t *buf = buffer;
281:
282: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
283: return RETCODE_ERR;
284:
285: if (buf->line_bol < buf->line_eol) {
286: clrscrEOL(buf);
287:
288: buf->line_len = buf->line_eol - buf->line_bol + 1;
289: buf->line_buf[buf->line_len - 1] = 0;
290:
291: printfEOL(buf, -1, 1);
292: }
293:
294: return RETCODE_OK;
295: }
296:
297: static int
298: bufMODE(int idx, void * __restrict buffer)
299: {
300: linebuffer_t *buf = buffer;
301:
302: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
303: return RETCODE_ERR;
304:
305: buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
306: return RETCODE_OK;
307: }
308:
309: static int
310: bufBEGIN(int idx, void * __restrict buffer)
311: {
312: linebuffer_t *buf = buffer;
313:
314: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
315: return RETCODE_ERR;
316:
317: buf->line_eol = buf->line_bol;
318:
319: printfCR(buf, 1);
320: return RETCODE_OK;
321: }
322:
323: static int
324: bufEND(int idx, void * __restrict buffer)
325: {
326: linebuffer_t *buf = buffer;
327:
328: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
329: return RETCODE_ERR;
330:
331: buf->line_eol = buf->line_len - 1;
332:
333: printfEOL(buf, -1, 1);
334: return RETCODE_OK;
335: }
336:
337: static int
338: bufLEFT(int idx, void * __restrict buffer)
339: {
340: linebuffer_t *buf = buffer;
341:
342: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
343: return RETCODE_ERR;
344:
345: if (buf->line_bol < buf->line_eol)
346: printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
347:
348: return RETCODE_OK;
349: }
350:
351: static int
352: bufRIGHT(int idx, void * __restrict buffer)
353: {
354: linebuffer_t *buf = buffer;
355:
356: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
357: return RETCODE_ERR;
358:
359: if (buf->line_eol < buf->line_len - 1)
360: printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
361:
362: return RETCODE_OK;
363: }
364:
365: static int
366: bufDEL(int idx, void * __restrict buffer)
367: {
368: linebuffer_t *buf = buffer;
369:
370: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
371: return RETCODE_ERR;
372:
373: clrscrEOL(buf);
374:
375: buf->line_len--;
376: memmove(buf->line_buf + buf->line_eol - buf->line_bol,
377: buf->line_buf + buf->line_eol - buf->line_bol + 1,
378: buf->line_len - buf->line_eol);
379: buf->line_buf[buf->line_len - 1] = 0;
380:
381: printfEOL(buf, buf->line_len - 1, 1);
382: printfEOL(buf, -1, 1);
383:
384: return RETCODE_OK;
385: }
386:
1.2.2.8 ! misho 387: static int
! 388: bufComp(int idx, void * __restrict buffer)
! 389: {
! 390: linebuffer_t *buf = buffer;
! 391:
! 392: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
! 393: return RETCODE_ERR;
! 394:
! 395: return RETCODE_OK;
! 396: }
! 397:
! 398: static int
! 399: bufHelp(int idx, void * __restrict buffer)
! 400: {
! 401: linebuffer_t *buf = buffer;
! 402:
! 403: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
! 404: return RETCODE_ERR;
! 405:
! 406: cli_Cmd_Help(buf, -1, NULL);
! 407: printfCR(buf, 1);
! 408: return RETCODE_OK;
! 409: }
! 410:
1.2.2.3 misho 411: // ---------------------------------------------------------------
412:
413: /*
1.2.2.4 misho 414: * cli_Printf() Send message to CLI session
415: * @buffer = CLI buffer
416: * @fmt = printf format string
417: * @... = arguments defined in fmt
418: * return: none
419: */
420: inline void
421: cli_Printf(linebuffer_t * __restrict buffer, char *fmt, ...)
422: {
423: va_list lst;
424: FILE *f;
425:
426: if (fmt) {
427: f = fdopen(buffer->line_out, "a");
428: if (!f) {
429: LOGERR;
430: return;
431: }
432:
433: va_start(lst, fmt);
434: vfprintf(f, fmt, lst);
435: va_end(lst);
436: } else
437: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
438: }
439:
440: /*
1.2.2.3 misho 441: * cli_BindKey() Bind function to key
442: * @key = key structure
443: * @buffer = CLI buffer
444: * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
445: */
446: int
447: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict buffer)
448: {
449: register int i;
450:
451: if (!key || !buffer) {
452: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
453: return RETCODE_ERR;
454: }
455:
456: for (i = 0; i < MAX_BINDKEY; i++)
457: if (key->key_len == buffer->line_keys[i].key_len &&
458: !memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) {
459: buffer->line_keys[i].key_func = key->key_func;
460: return i;
461: }
462:
463: return RETCODE_OK;
464: }
465:
466:
467: /*
1.2.2.6 misho 468: * cli_addCommand() Add command to CLI session
469: * @buffer = CLI buffer
470: * @csCmd = Command name
471: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
472: * @funcCmd = Callback function when user call command
473: * @csInfo = Inline information for command
474: * @csHelp = Help line when call help
475: * return: RETCODE_ERR error, RETCODE_OK ok
476: */
477: int
478: cli_addCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
479: const char *csInfo, const char *csHelp)
480: {
481: struct tagCommand *cmd;
482:
483: if (!buffer || !csCmd || !funcCmd) {
484: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
485: return RETCODE_ERR;
486: }
487:
488: cmd = malloc(sizeof(struct tagCommand));
489: if (!cmd) {
490: LOGERR;
491: return RETCODE_ERR;
492: } else
493: memset(cmd, 0, sizeof(struct tagCommand));
494:
495: cmd->cmd_level = cliLevel;
496: cmd->cmd_func = funcCmd;
497: cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
498: if (csInfo)
499: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
500: if (csHelp)
501: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
502: SLIST_INSERT_HEAD(&buffer->line_cmds, cmd, cmd_next);
503: return RETCODE_OK;
504: }
505:
506: /*
507: * cli_delCommand() Delete command from CLI session
508: * @buffer = CLI buffer
509: * @csCmd = Command name
510: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
511: * return: RETCODE_ERR error, RETCODE_OK ok
512: */
513: int
514: cli_delCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel)
515: {
516: struct tagCommand *cmd;
517: int ret = RETCODE_OK;
518:
519: if (!buffer || !csCmd) {
520: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
521: return RETCODE_ERR;
522: }
523:
524: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
525: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
526: ret = 1;
527: SLIST_REMOVE(&buffer->line_cmds, cmd, tagCommand, cmd_next);
528: free(cmd);
529: break;
530: }
531:
532: return ret;
533: }
534:
535: /*
536: * cli_updCommand() Update command in CLI session
537: * @buffer = CLI buffer
538: * @csCmd = Command name
539: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
540: * @funcCmd = Callback function when user call command
541: * @csInfo = Inline information for command
542: * @csHelp = Help line when call help
543: * return: RETCODE_ERR error, RETCODE_OK ok
544: */
545: int
546: cli_updCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
547: const char *csInfo, const char *csHelp)
548: {
549: struct tagCommand *cmd;
550: int ret = RETCODE_OK;
551:
552: if (!buffer || !csCmd) {
553: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
554: return RETCODE_ERR;
555: }
556:
557: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
558: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
559: ret = 1;
560:
561: if (funcCmd)
562: cmd->cmd_func = funcCmd;
563: if (csInfo)
564: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
565: if (csHelp)
566: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
567:
568: break;
569: }
570:
571: return ret;
572: }
573:
574:
575: /*
1.2.2.3 misho 576: * cli_addHistory() Add line to history
577: * @buffer = CLI buffer
1.2.2.4 misho 578: * @str = Add custom text or if NULL use readed line from CLI buffer
1.2.2.3 misho 579: * return: RETCODE_ERR error, RETCODE_OK ok
580: */
581: int
582: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
583: {
584: struct tagHistory *h;
585:
586: if (!buffer) {
587: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
588: return RETCODE_ERR;
589: }
590:
591: if (!(h = malloc(sizeof(struct tagHistory)))) {
592: LOGERR;
593: return RETCODE_ERR;
594: } else
595: memset(h, 0, sizeof(struct tagHistory));
596:
597: if (str) {
598: if (!*str) {
599: free(h);
600: return RETCODE_OK;
601: }
602:
603: h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
604: } else {
605: if (!*buffer->line_buf || buffer->line_len < 2) {
606: free(h);
607: return RETCODE_OK;
608: }
609:
610: memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len));
611: io_TrimStr((u_char*) h->hist_line);
612: h->hist_len = strlen(h->hist_line);
613: }
614:
615: TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
616: return h->hist_len;
617: }
618:
619: /*
620: * cli_saveHistory() Save history to file
621: * @buffer = CLI buffer
622: * @histfile = History filename, if NULL will be use default name
623: * @lines = Maximum history lines to save
624: * return: RETCODE_ERR error, RETCODE_OK ok
625: */
626: int
627: cli_saveHistory(linebuffer_t * __restrict buffer, const char *histfile, int lines)
628: {
629: FILE *f;
630: mode_t mode;
631: char szFName[MAXPATHLEN];
632: struct tagHistory *h;
633:
634: if (!buffer) {
635: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
636: return RETCODE_ERR;
637: }
638: if (!histfile)
639: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
640: else
641: strlcpy(szFName, histfile, MAXPATHLEN);
642:
643: mode = umask(0177);
644: f = fopen(szFName, "w");
645: if (!f) {
646: LOGERR;
647: return RETCODE_ERR;
648: }
649:
650: TAILQ_FOREACH(h, &buffer->line_history, hist_next) {
651: fprintf(f, "%s\n", h->hist_line);
652:
653: if (lines)
654: lines--;
655: else
656: break;
657: }
658:
659: fclose(f);
660: umask(mode);
661:
662: return RETCODE_OK;
663: }
664:
665: /*
666: * cli_loadHistory() Load history from file
667: * @buffer = CLI buffer
668: * @histfile = History filename, if NULL will be use default name
669: * return: RETCODE_ERR error, RETCODE_OK ok
670: */
671: int
672: cli_loadHistory(linebuffer_t * __restrict buffer, const char *histfile)
673: {
674: FILE *f;
675: char szFName[MAXPATHLEN], buf[BUFSIZ];
676: struct tagHistory *h;
677:
678: if (!buffer) {
679: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
680: return RETCODE_ERR;
681: }
682: if (!histfile)
683: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
684: else
685: strlcpy(szFName, histfile, MAXPATHLEN);
686:
687: f = fopen(szFName, "r");
1.2.2.4 misho 688: if (!f)
689: return RETCODE_OK;
1.2.2.3 misho 690:
691: while (fgets(buf, BUFSIZ, f)) {
692: if (!*buf || *buf == '#')
693: continue;
694: else
695: io_TrimStr((u_char*) buf);
696:
697: if (!(h = malloc(sizeof(struct tagHistory)))) {
698: LOGERR;
699: fclose(f);
700: return RETCODE_ERR;
701: } else
702: memset(h, 0, sizeof(struct tagHistory));
703:
704: h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
705: TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next);
706: }
707:
708: fclose(f);
709:
710: return RETCODE_OK;
711: }
712:
713: /*
714: * cli_resetHistory() Reset history search in CLI session
715: * @buffer = CLI buffer
716: * return: none
717: */
718: inline void
719: cli_resetHistory(linebuffer_t * __restrict buffer)
720: {
721: buffer->line_h = NULL;
722: }
723:
724:
725: /*
726: * cli_freeLine() Clear entire line
727: * @buffer = CLI buffer
728: * return: RETCODE_ERR error, RETCODE_OK ok
729: */
730: inline int
731: cli_freeLine(linebuffer_t * __restrict buffer)
732: {
733: int code = RETCODE_ERR;
734:
735: if (buffer) {
736: if (buffer->line_buf)
737: free(buffer->line_buf);
738:
739: buffer->line_buf = malloc(BUFSIZ);
740: if (buffer->line_buf) {
741: memset(buffer->line_buf, 0, BUFSIZ);
742: buffer->line_eol = buffer->line_bol;
743: buffer->line_len = 1 + buffer->line_eol;
744:
745: code = RETCODE_OK;
746: } else
747: LOGERR;
748: } else
749: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
750:
751: return code;
752: }
753:
754: /*
755: * cli_setPrompt() Set new prompt for CLI session
756: * @buffer = CLI buffer
757: * @prompt = new text for prompt or if NULL disable prompt
758: * return: none
759: */
760: inline void
761: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
762: {
763: if (buffer) {
764: if (buffer->line_prompt) {
765: free(buffer->line_prompt);
766: buffer->line_prompt = NULL;
767: buffer->line_bol = 0;
768: }
769:
770: if (prompt) {
771: buffer->line_prompt = strdup(prompt);
772: if (buffer->line_prompt) {
773: buffer->line_bol = strlen(buffer->line_prompt);
774: buffer->line_eol = buffer->line_bol;
775: buffer->line_len = 1 + buffer->line_eol;
776: } else
777: LOGERR;
778: }
779: } else
780: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
781: }
782:
783:
784: /*
785: * cliEnd() Clear data, Free resources and close CLI session
786: * @buffer = CLI buffer
787: * return: RETCODE_ERR error, RETCODE_OK ok
788: */
789: void
790: cliEnd(linebuffer_t * __restrict buffer)
791: {
792: struct tagHistory *h;
1.2.2.4 misho 793: struct tagCommand *c;
1.2.2.3 misho 794:
795: if (buffer) {
1.2.2.4 misho 796: while ((c = SLIST_FIRST(&buffer->line_cmds))) {
797: SLIST_REMOVE_HEAD(&buffer->line_cmds, cmd_next);
798: free(c);
799: }
1.2.2.3 misho 800: while ((h = TAILQ_FIRST(&buffer->line_history))) {
801: TAILQ_REMOVE(&buffer->line_history, h, hist_next);
802: free(h);
803: }
804:
805: if (buffer->line_prompt)
806: free(buffer->line_prompt);
807:
808: if (buffer->line_keys)
809: free(buffer->line_keys);
810: if (buffer->line_buf)
811: free(buffer->line_buf);
812:
813: free(buffer);
814: buffer = NULL;
815: } else
816: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
817: }
818:
819: /*
820: * cliInit() Start CLI session, allocate memory for resources and bind keys
821: * @fin = Input device handle
822: * @fout = Output device handle
823: * @prompt = text for prompt, if NULL disable prompt
824: * return: NULL if error or !=NULL CLI buffer
825: */
826: linebuffer_t *
827: cliInit(int fin, int fout, const char *prompt)
828: {
829: linebuffer_t *buffer;
830: bindkey_t *keys;
831: register int i;
832: struct termios t;
833:
834: memset(&t, 0, sizeof t);
835: /* init buffer */
836: buffer = malloc(sizeof (linebuffer_t));
837: if (!buffer) {
838: LOGERR;
839: return NULL;
840: } else {
841: memset(buffer, 0, sizeof(linebuffer_t));
842:
843: buffer->line_in = fin;
844: buffer->line_out = fout;
845:
846: TAILQ_INIT(&buffer->line_history);
1.2.2.4 misho 847: SLIST_INIT(&buffer->line_cmds);
1.2.2.3 misho 848:
849: if (prompt) {
850: buffer->line_prompt = strdup(prompt);
851: if (!buffer->line_prompt) {
852: LOGERR;
853: free(buffer);
854: return NULL;
855: } else
856: buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
857: }
858: }
859: buffer->line_buf = malloc(BUFSIZ);
860: if (!buffer->line_buf) {
861: LOGERR;
862: if (buffer->line_prompt)
863: free(buffer->line_prompt);
864: free(buffer);
865: return NULL;
866: } else {
867: memset(buffer->line_buf, 0, BUFSIZ);
868: buffer->line_len = 1 + buffer->line_eol;
869: }
870: keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
871: if (!keys) {
872: LOGERR;
873: if (buffer->line_prompt)
874: free(buffer->line_prompt);
875: free(buffer->line_buf);
876: free(buffer);
877: return NULL;
878: } else
879: memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
880:
1.2.2.7 misho 881: /* add helper functions */
882: cli_addCommand(buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
1.2.2.8 ! misho 883: cli_addCommand(buffer, "help", 0, cli_Cmd_Help, "help [command] <cr>", "Help screen");
1.2.2.7 misho 884:
1.2.2.3 misho 885: /* fill key bindings */
886: // ascii chars & ctrl+chars
887: for (i = 0; i < 256; i++) {
888: *keys[i].key_ch = (u_char) i;
889: keys[i].key_len = 1;
890:
891: if (!i || i == *K_CTRL_D)
892: keys[i].key_func = bufEOF;
893: if (i == *K_CTRL_M || i == *K_CTRL_J)
894: keys[i].key_func = bufEOL;
895: if (i == *K_CTRL_H || i == *K_BACKSPACE)
896: keys[i].key_func = bufBS;
897: if (i == *K_CTRL_C)
898: keys[i].key_func = bufCLR;
899: if (i == *K_CTRL_A)
900: keys[i].key_func = bufBEGIN;
901: if (i == *K_CTRL_E)
902: keys[i].key_func = bufEND;
1.2.2.8 ! misho 903: if (i == *K_TAB)
! 904: keys[i].key_func = bufComp;
1.2.2.3 misho 905: if (i >= *K_SPACE && i < *K_BACKSPACE)
906: keys[i].key_func = bufCHAR;
907: if (i > *K_BACKSPACE && i < 0xff)
908: keys[i].key_func = bufCHAR;
1.2.2.8 ! misho 909: if (i == '?')
! 910: keys[i].key_func = bufHelp;
1.2.2.3 misho 911: }
912: // alt+chars
913: for (i = 256; i < 512; i++) {
914: keys[i].key_ch[0] = 0x1b;
915: keys[i].key_ch[1] = (u_char) i - 256;
916: keys[i].key_len = 2;
917: }
918:
919: // 3 bytes
920: keys[i].key_len = sizeof K_F1 - 1;
921: memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
922: i++;
923: keys[i].key_len = sizeof K_F2 - 1;
924: memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
925: i++;
926: keys[i].key_len = sizeof K_F3 - 1;
927: memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
928: i++;
929: keys[i].key_len = sizeof K_F4 - 1;
930: memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
931: i++;
932: keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
933: memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
934: i++;
935: keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
936: memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
937: i++;
938: keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
939: memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
940: i++;
941: keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
942: memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
943: i++;
944: keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
945: memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
946: i++;
947: keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
948: memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
949: i++;
950: keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
951: memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
952: i++;
953: keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
954: memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
955: i++;
956: keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
957: memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
958: i++;
959: keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
960: memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
961: i++;
962: keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
963: memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
964: i++;
965: keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
966: memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
967: i++;
968: keys[i].key_len = sizeof K_CTRL_F1 - 1;
969: memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
970: i++;
971: keys[i].key_len = sizeof K_CTRL_F2 - 1;
972: memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
973: i++;
974: keys[i].key_len = sizeof K_CTRL_F3 - 1;
975: memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
976: i++;
977: keys[i].key_len = sizeof K_CTRL_F4 - 1;
978: memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
979: i++;
980: keys[i].key_len = sizeof K_CTRL_F5 - 1;
981: memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
982: i++;
983: keys[i].key_len = sizeof K_CTRL_F6 - 1;
984: memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
985: i++;
986: keys[i].key_len = sizeof K_CTRL_F7 - 1;
987: memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
988: i++;
989: keys[i].key_len = sizeof K_CTRL_F8 - 1;
990: memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
991: i++;
992: keys[i].key_len = sizeof K_CTRL_F9 - 1;
993: memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
994: i++;
995: keys[i].key_len = sizeof K_CTRL_F10 - 1;
996: memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
997: i++;
998: keys[i].key_len = sizeof K_CTRL_F11 - 1;
999: memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
1000: i++;
1001: keys[i].key_len = sizeof K_CTRL_F12 - 1;
1002: memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
1003: i++;
1004: keys[i].key_len = sizeof K_HOME - 1;
1005: keys[i].key_func = bufBEGIN;
1006: memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
1007: i++;
1008: keys[i].key_len = sizeof K_END - 1;
1009: keys[i].key_func = bufEND;
1010: memcpy(keys[i].key_ch, K_END, keys[i].key_len);
1011: i++;
1012: keys[i].key_len = sizeof K_UP - 1;
1013: keys[i].key_func = bufUP;
1014: memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
1015: i++;
1016: keys[i].key_len = sizeof K_DOWN - 1;
1017: keys[i].key_func = bufDOWN;
1018: memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
1019: i++;
1020: keys[i].key_len = sizeof K_RIGHT - 1;
1021: keys[i].key_func = bufRIGHT;
1022: memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
1023: i++;
1024: keys[i].key_len = sizeof K_LEFT - 1;
1025: keys[i].key_func = bufLEFT;
1026: memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
1027: i++;
1028: keys[i].key_len = sizeof K_BTAB - 1;
1029: keys[i].key_func = bufBTAB;
1030: memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1031: i++;
1032: // 4 bytes
1033: keys[i].key_len = sizeof K_INS - 1;
1034: keys[i].key_func = bufMODE;
1035: memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1036: i++;
1037: keys[i].key_len = sizeof K_DEL - 1;
1038: keys[i].key_func = bufDEL;
1039: memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1040: i++;
1041: keys[i].key_len = sizeof K_PGUP - 1;
1042: memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1043: i++;
1044: keys[i].key_len = sizeof K_PGDN - 1;
1045: memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1046: i++;
1047: // 5 bytes
1048: keys[i].key_len = sizeof K_F5 - 1;
1049: memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1050: i++;
1051: keys[i].key_len = sizeof K_F6 - 1;
1052: memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1053: i++;
1054: keys[i].key_len = sizeof K_F7 - 1;
1055: memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1056: i++;
1057: keys[i].key_len = sizeof K_F8 - 1;
1058: memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1059: i++;
1060: keys[i].key_len = sizeof K_F9 - 1;
1061: memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1062: i++;
1063: keys[i].key_len = sizeof K_F10 - 1;
1064: memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1065: i++;
1066: keys[i].key_len = sizeof K_F11 - 1;
1067: memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1068: i++;
1069: keys[i].key_len = sizeof K_F12 - 1;
1070: memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1071: i++;
1072:
1073: tcgetattr(buffer->line_in, &t);
1074: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1075: t.c_iflag |= IGNBRK;
1076: t.c_cc[VMIN] = 1;
1077: t.c_cc[VTIME] = 0;
1078: tcsetattr(buffer->line_in, TCSANOW, &t);
1079:
1080: buffer->line_keys = keys;
1081: return buffer;
1082: }
1083:
1.2 misho 1084: /*
1.2.2.4 misho 1085: * cliReadLine() Read line from opened CLI session
1086: * @buffer = CLI buffer
1087: * return: NULL if error or !=NULL readed line, must be free after use!
1.2 misho 1088: */
1.2.2.4 misho 1089: char *
1090: cliReadLine(linebuffer_t * __restrict buffer)
1.2 misho 1091: {
1.2.2.4 misho 1092: int code, readLen;
1093: register int i;
1094: struct pollfd fds;
1095: char buf[BUFSIZ], *str = NULL;
1.2 misho 1096:
1.2.2.4 misho 1097: if (!buffer) {
1098: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1099: return NULL;
1.2 misho 1100: }
1101:
1.2.2.4 misho 1102: memset(&fds, 0, sizeof fds);
1103: fds.fd = buffer->line_in;
1104: fds.events = POLLIN;
1105:
1106: printfCR(buffer, 1);
1107: while (42) {
1108: if (poll(&fds, 1, -1) < 1) {
1109: LOGERR;
1110: return str;
1111: }
1.2 misho 1112:
1.2.2.4 misho 1113: memset(buf, 0, sizeof buf);
1114: readLen = read(buffer->line_in, buf, BUFSIZ);
1115: if (readLen == -1) {
1116: LOGERR;
1117: return str;
1118: }
1119: if (!readLen) {
1120: if (buffer->line_buf)
1121: str = strdup(buffer->line_buf);
1122: else
1123: cli_SetErr(EPIPE, "Error:: unknown state ...");
1124: return str;
1125: }
1.2 misho 1126:
1.2.2.4 misho 1127: recheck:
1128: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
1129: if (readLen >= buffer->line_keys[i].key_len &&
1130: !memcmp(buffer->line_keys[i].key_ch, buf,
1131: buffer->line_keys[i].key_len)) {
1132: readLen -= buffer->line_keys[i].key_len;
1133: if (readLen)
1134: memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
1135: else
1136: memset(buf, 0, buffer->line_keys[i].key_len);
1137:
1138: if (buffer->line_keys[i].key_func)
1139: if ((code = buffer->line_keys[i].key_func(i, buffer)))
1140: readLen = 0;
1141:
1142: if (readLen)
1143: goto recheck;
1144: else
1145: break;
1146: }
1.2 misho 1147:
1.2.2.4 misho 1148: if (code)
1149: break;
1150: }
1151:
1.2.2.5 misho 1152: if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
1.2.2.4 misho 1153: str = strdup(buffer->line_buf);
1154: return str;
1.2 misho 1155: }
1.2.2.4 misho 1156:
1157:
1.2 misho 1158: /*
1.2.2.4 misho 1159: * cliNetLoop() CLI network main loop binded to socket
1160: * @buffer = CLI buffer
1161: * @csHistFile = History file name
1.2 misho 1162: * @sock = client socket
1163: * @term = stdin termios
1164: * @win = window size of tty
1.2.2.4 misho 1165: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1166: */
1.2.2.1 misho 1167: int
1.2.2.4 misho 1168: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock,
1169: struct termios *term, struct winsize *win)
1.2 misho 1170: {
1.2.2.4 misho 1171: u_char buf[BUFSIZ];
1172: int pty, r, s, alen, attrlen, flg, ret = 0;
1.2 misho 1173: fd_set fds;
1174: struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
1175: struct telnetAttrs *a, Attr[10];
1176:
1177: switch (forkpty(&pty, NULL, term, win)) {
1178: case -1:
1179: LOGERR;
1180: return -1;
1181: case 0:
1182: close(sock);
1183:
1.2.2.8 ! misho 1184: if (buffer) {
! 1185: ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
! 1186: cliEnd(buffer);
! 1187: } else
! 1188: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1.2.2.4 misho 1189:
1.2 misho 1190: /* spawn Shell mode */
1191: /*
1192: execl("/bin/tcsh", "tcsh", NULL);
1193: */
1.2.2.4 misho 1194:
1.2 misho 1195: _exit(ret);
1196: default:
1197: /* spawn Shell mode */
1198: telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
1199: telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
1200: telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
1201: telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
1202: telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
1203: if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
1204: cli_Errno = telnet_GetErrno();
1205: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1206: return -1;
1207: } else
1208: flg = 0;
1209:
1210: while (42) {
1211: FD_ZERO(&fds);
1212: FD_SET(sock, &fds);
1213: FD_SET(pty, &fds);
1214: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
1215: if (!ret)
1216: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
1217:
1218: break;
1219: }
1220:
1221: r = FD_ISSET(sock, &fds) ? sock : pty;
1222: s = FD_ISSET(sock, &fds) ? pty : sock;
1223:
1224: if ((ret = telnetRecv(r, &a, &alen, buf, BUFSIZ)) < 0) {
1225: if (a)
1226: free(a);
1227:
1228: if (-2 == ret)
1229: continue;
1230: // EOF
1231: if (-3 == ret)
1232: shutdown(r, SHUT_RD);
1233: else {
1234: cli_Errno = telnet_GetErrno();
1235: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1236: }
1237: break;
1238: }
1239: attrlen = 0;
1240: if (1 == flg && alen) {
1241: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
1242: telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1243: }
1244: if (2 == flg && alen) {
1245: telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
1246: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1247: LFLOW_OFF, NULL, 0);
1248: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1249: LFLOW_RESTART_XON, NULL, 0);
1250: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1251: }
1252: if (a)
1253: free(a);
1254:
1255: if ((ret = telnetSend(s, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
1256: cli_Errno = telnet_GetErrno();
1257: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1258: break;
1259: } else
1260: flg++;
1261: }
1262:
1263: close(pty);
1264: }
1265:
1266: return ret;
1267: }
1268:
1269: /*
1.2.2.4 misho 1270: * cliLoop() CLI main loop
1271: * @buffer = CLI buffer
1272: * @csHistFile = History file name
1273: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 1274: */
1.2.2.4 misho 1275: int
1276: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
1.1 misho 1277: {
1278: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
1279: register int i;
1.2.2.4 misho 1280: int ret = RETCODE_OK;
1281: struct tagCommand *cmd;
1.1 misho 1282:
1.2.2.4 misho 1283: /*
1.1 misho 1284:
1285: char **cli_stdCompletion(const char *text, int start, int end)
1286: {
1287: register int i;
1288: char **matches = NULL;
1289:
1290: char *cmdCompGet(const char *text, int state)
1291: {
1292: int len = strlen(text);
1293:
1294: for (i = state; cmdList[i].cmd_name; i++) {
1295: if (strncmp(cmdList[i].cmd_name, "---", 3) &&
1296: !strncmp(cmdList[i].cmd_name, text, len))
1297: return strdup(cmdList[i].cmd_name);
1298: }
1299:
1300: return NULL;
1301: }
1302:
1303: if (!start)
1304: matches = rl_completion_matches(text, cmdCompGet);
1305: else
1306: for (i = 0; cmdList[i].cmd_name; i++) {
1307: if (!cmdList[i].cmd_comp)
1308: continue;
1309: if (!strncmp(rl_line_buffer, cmdList[i].cmd_name, strlen(cmdList[i].cmd_name)))
1310: matches = rl_completion_matches(text, cmdList[i].cmd_comp);
1311: }
1312:
1313: return matches;
1314: }
1.2.2.4 misho 1315:
1316:
1317: */
1318:
1.1 misho 1319: /* --- main body of CLI --- */
1.2.2.4 misho 1320:
1321: if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
1322: return RETCODE_ERR;
1.1 misho 1323:
1324: do {
1.2.2.4 misho 1325: line = cliReadLine(buffer);
1.2.2.5 misho 1326: if (!line) {
1327: printfNL(buffer, 0);
1.1 misho 1328: break;
1.2.2.5 misho 1329: } else
1.2.2.4 misho 1330: cli_addHistory(buffer, NULL);
1.1 misho 1331: // clear whitespaces
1332: for (s = line; isspace(*s); s++);
1333: if (*s) {
1334: for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
1335: *++t = 0;
1336: }
1337:
1338: if (*s) {
1339: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1340: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
1341: *app ? app++ : app);
1342:
1343: // exec_cmd ...
1.2.2.4 misho 1344: i = 0;
1345: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
1346: if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1 misho 1347: break;
1.2.2.4 misho 1348: else
1349: i++;
1350: }
1.2.2.5 misho 1351:
1.1 misho 1352: if (!cmd) {
1.2.2.5 misho 1353: cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
1.1 misho 1354: ret = -1;
1355: } else
1.2.2.4 misho 1356: ret = cmd->cmd_func(buffer, i, items);
1.1 misho 1357: }
1358:
1.2.2.4 misho 1359: cli_freeLine(buffer);
1360: cli_resetHistory(buffer);
1.1 misho 1361: free(line);
1362: } while (ret < 1);
1363:
1.2.2.4 misho 1364: cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
1.1 misho 1365: return ret;
1366: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>