Annotation of libaitcli/src/aitcli.c, revision 1.2.2.7
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.7 ! misho 6: * $Id: aitcli.c,v 1.2.2.6 2010/06/07 11:32:50 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:
387: // ---------------------------------------------------------------
388:
389: /*
1.2.2.4 misho 390: * cli_Printf() Send message to CLI session
391: * @buffer = CLI buffer
392: * @fmt = printf format string
393: * @... = arguments defined in fmt
394: * return: none
395: */
396: inline void
397: cli_Printf(linebuffer_t * __restrict buffer, char *fmt, ...)
398: {
399: va_list lst;
400: FILE *f;
401:
402: if (fmt) {
403: f = fdopen(buffer->line_out, "a");
404: if (!f) {
405: LOGERR;
406: return;
407: }
408:
409: va_start(lst, fmt);
410: vfprintf(f, fmt, lst);
411: va_end(lst);
412: } else
413: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
414: }
415:
416: /*
1.2.2.3 misho 417: * cli_BindKey() Bind function to key
418: * @key = key structure
419: * @buffer = CLI buffer
420: * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
421: */
422: int
423: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict buffer)
424: {
425: register int i;
426:
427: if (!key || !buffer) {
428: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
429: return RETCODE_ERR;
430: }
431:
432: for (i = 0; i < MAX_BINDKEY; i++)
433: if (key->key_len == buffer->line_keys[i].key_len &&
434: !memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) {
435: buffer->line_keys[i].key_func = key->key_func;
436: return i;
437: }
438:
439: return RETCODE_OK;
440: }
441:
442:
443: /*
1.2.2.6 misho 444: * cli_addCommand() Add command to CLI session
445: * @buffer = CLI buffer
446: * @csCmd = Command name
447: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
448: * @funcCmd = Callback function when user call command
449: * @csInfo = Inline information for command
450: * @csHelp = Help line when call help
451: * return: RETCODE_ERR error, RETCODE_OK ok
452: */
453: int
454: cli_addCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
455: const char *csInfo, const char *csHelp)
456: {
457: struct tagCommand *cmd;
458:
459: if (!buffer || !csCmd || !funcCmd) {
460: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
461: return RETCODE_ERR;
462: }
463:
464: cmd = malloc(sizeof(struct tagCommand));
465: if (!cmd) {
466: LOGERR;
467: return RETCODE_ERR;
468: } else
469: memset(cmd, 0, sizeof(struct tagCommand));
470:
471: cmd->cmd_level = cliLevel;
472: cmd->cmd_func = funcCmd;
473: cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
474: if (csInfo)
475: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
476: if (csHelp)
477: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
478: SLIST_INSERT_HEAD(&buffer->line_cmds, cmd, cmd_next);
479: return RETCODE_OK;
480: }
481:
482: /*
483: * cli_delCommand() Delete command from CLI session
484: * @buffer = CLI buffer
485: * @csCmd = Command name
486: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
487: * return: RETCODE_ERR error, RETCODE_OK ok
488: */
489: int
490: cli_delCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel)
491: {
492: struct tagCommand *cmd;
493: int ret = RETCODE_OK;
494:
495: if (!buffer || !csCmd) {
496: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
497: return RETCODE_ERR;
498: }
499:
500: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
501: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
502: ret = 1;
503: SLIST_REMOVE(&buffer->line_cmds, cmd, tagCommand, cmd_next);
504: free(cmd);
505: break;
506: }
507:
508: return ret;
509: }
510:
511: /*
512: * cli_updCommand() Update command in CLI session
513: * @buffer = CLI buffer
514: * @csCmd = Command name
515: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
516: * @funcCmd = Callback function when user call command
517: * @csInfo = Inline information for command
518: * @csHelp = Help line when call help
519: * return: RETCODE_ERR error, RETCODE_OK ok
520: */
521: int
522: cli_updCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
523: const char *csInfo, const char *csHelp)
524: {
525: struct tagCommand *cmd;
526: int ret = RETCODE_OK;
527:
528: if (!buffer || !csCmd) {
529: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
530: return RETCODE_ERR;
531: }
532:
533: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
534: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
535: ret = 1;
536:
537: if (funcCmd)
538: cmd->cmd_func = funcCmd;
539: if (csInfo)
540: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
541: if (csHelp)
542: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
543:
544: break;
545: }
546:
547: return ret;
548: }
549:
550:
551: /*
1.2.2.3 misho 552: * cli_addHistory() Add line to history
553: * @buffer = CLI buffer
1.2.2.4 misho 554: * @str = Add custom text or if NULL use readed line from CLI buffer
1.2.2.3 misho 555: * return: RETCODE_ERR error, RETCODE_OK ok
556: */
557: int
558: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
559: {
560: struct tagHistory *h;
561:
562: if (!buffer) {
563: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
564: return RETCODE_ERR;
565: }
566:
567: if (!(h = malloc(sizeof(struct tagHistory)))) {
568: LOGERR;
569: return RETCODE_ERR;
570: } else
571: memset(h, 0, sizeof(struct tagHistory));
572:
573: if (str) {
574: if (!*str) {
575: free(h);
576: return RETCODE_OK;
577: }
578:
579: h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
580: } else {
581: if (!*buffer->line_buf || buffer->line_len < 2) {
582: free(h);
583: return RETCODE_OK;
584: }
585:
586: memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len));
587: io_TrimStr((u_char*) h->hist_line);
588: h->hist_len = strlen(h->hist_line);
589: }
590:
591: TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
592: return h->hist_len;
593: }
594:
595: /*
596: * cli_saveHistory() Save history to file
597: * @buffer = CLI buffer
598: * @histfile = History filename, if NULL will be use default name
599: * @lines = Maximum history lines to save
600: * return: RETCODE_ERR error, RETCODE_OK ok
601: */
602: int
603: cli_saveHistory(linebuffer_t * __restrict buffer, const char *histfile, int lines)
604: {
605: FILE *f;
606: mode_t mode;
607: char szFName[MAXPATHLEN];
608: struct tagHistory *h;
609:
610: if (!buffer) {
611: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
612: return RETCODE_ERR;
613: }
614: if (!histfile)
615: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
616: else
617: strlcpy(szFName, histfile, MAXPATHLEN);
618:
619: mode = umask(0177);
620: f = fopen(szFName, "w");
621: if (!f) {
622: LOGERR;
623: return RETCODE_ERR;
624: }
625:
626: TAILQ_FOREACH(h, &buffer->line_history, hist_next) {
627: fprintf(f, "%s\n", h->hist_line);
628:
629: if (lines)
630: lines--;
631: else
632: break;
633: }
634:
635: fclose(f);
636: umask(mode);
637:
638: return RETCODE_OK;
639: }
640:
641: /*
642: * cli_loadHistory() Load history from file
643: * @buffer = CLI buffer
644: * @histfile = History filename, if NULL will be use default name
645: * return: RETCODE_ERR error, RETCODE_OK ok
646: */
647: int
648: cli_loadHistory(linebuffer_t * __restrict buffer, const char *histfile)
649: {
650: FILE *f;
651: char szFName[MAXPATHLEN], buf[BUFSIZ];
652: struct tagHistory *h;
653:
654: if (!buffer) {
655: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
656: return RETCODE_ERR;
657: }
658: if (!histfile)
659: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
660: else
661: strlcpy(szFName, histfile, MAXPATHLEN);
662:
663: f = fopen(szFName, "r");
1.2.2.4 misho 664: if (!f)
665: return RETCODE_OK;
1.2.2.3 misho 666:
667: while (fgets(buf, BUFSIZ, f)) {
668: if (!*buf || *buf == '#')
669: continue;
670: else
671: io_TrimStr((u_char*) buf);
672:
673: if (!(h = malloc(sizeof(struct tagHistory)))) {
674: LOGERR;
675: fclose(f);
676: return RETCODE_ERR;
677: } else
678: memset(h, 0, sizeof(struct tagHistory));
679:
680: h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
681: TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next);
682: }
683:
684: fclose(f);
685:
686: return RETCODE_OK;
687: }
688:
689: /*
690: * cli_resetHistory() Reset history search in CLI session
691: * @buffer = CLI buffer
692: * return: none
693: */
694: inline void
695: cli_resetHistory(linebuffer_t * __restrict buffer)
696: {
697: buffer->line_h = NULL;
698: }
699:
700:
701: /*
702: * cli_freeLine() Clear entire line
703: * @buffer = CLI buffer
704: * return: RETCODE_ERR error, RETCODE_OK ok
705: */
706: inline int
707: cli_freeLine(linebuffer_t * __restrict buffer)
708: {
709: int code = RETCODE_ERR;
710:
711: if (buffer) {
712: if (buffer->line_buf)
713: free(buffer->line_buf);
714:
715: buffer->line_buf = malloc(BUFSIZ);
716: if (buffer->line_buf) {
717: memset(buffer->line_buf, 0, BUFSIZ);
718: buffer->line_eol = buffer->line_bol;
719: buffer->line_len = 1 + buffer->line_eol;
720:
721: code = RETCODE_OK;
722: } else
723: LOGERR;
724: } else
725: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
726:
727: return code;
728: }
729:
730: /*
731: * cli_setPrompt() Set new prompt for CLI session
732: * @buffer = CLI buffer
733: * @prompt = new text for prompt or if NULL disable prompt
734: * return: none
735: */
736: inline void
737: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
738: {
739: if (buffer) {
740: if (buffer->line_prompt) {
741: free(buffer->line_prompt);
742: buffer->line_prompt = NULL;
743: buffer->line_bol = 0;
744: }
745:
746: if (prompt) {
747: buffer->line_prompt = strdup(prompt);
748: if (buffer->line_prompt) {
749: buffer->line_bol = strlen(buffer->line_prompt);
750: buffer->line_eol = buffer->line_bol;
751: buffer->line_len = 1 + buffer->line_eol;
752: } else
753: LOGERR;
754: }
755: } else
756: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
757: }
758:
759:
760: /*
761: * cliEnd() Clear data, Free resources and close CLI session
762: * @buffer = CLI buffer
763: * return: RETCODE_ERR error, RETCODE_OK ok
764: */
765: void
766: cliEnd(linebuffer_t * __restrict buffer)
767: {
768: struct tagHistory *h;
1.2.2.4 misho 769: struct tagCommand *c;
1.2.2.3 misho 770:
771: if (buffer) {
1.2.2.4 misho 772: while ((c = SLIST_FIRST(&buffer->line_cmds))) {
773: SLIST_REMOVE_HEAD(&buffer->line_cmds, cmd_next);
774: free(c);
775: }
1.2.2.3 misho 776: while ((h = TAILQ_FIRST(&buffer->line_history))) {
777: TAILQ_REMOVE(&buffer->line_history, h, hist_next);
778: free(h);
779: }
780:
781: if (buffer->line_prompt)
782: free(buffer->line_prompt);
783:
784: if (buffer->line_keys)
785: free(buffer->line_keys);
786: if (buffer->line_buf)
787: free(buffer->line_buf);
788:
789: free(buffer);
790: buffer = NULL;
791: } else
792: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
793: }
794:
795: /*
796: * cliInit() Start CLI session, allocate memory for resources and bind keys
797: * @fin = Input device handle
798: * @fout = Output device handle
799: * @prompt = text for prompt, if NULL disable prompt
800: * return: NULL if error or !=NULL CLI buffer
801: */
802: linebuffer_t *
803: cliInit(int fin, int fout, const char *prompt)
804: {
805: linebuffer_t *buffer;
806: bindkey_t *keys;
807: register int i;
808: struct termios t;
809:
810: memset(&t, 0, sizeof t);
811: /* init buffer */
812: buffer = malloc(sizeof (linebuffer_t));
813: if (!buffer) {
814: LOGERR;
815: return NULL;
816: } else {
817: memset(buffer, 0, sizeof(linebuffer_t));
818:
819: buffer->line_in = fin;
820: buffer->line_out = fout;
821:
822: TAILQ_INIT(&buffer->line_history);
1.2.2.4 misho 823: SLIST_INIT(&buffer->line_cmds);
1.2.2.3 misho 824:
825: if (prompt) {
826: buffer->line_prompt = strdup(prompt);
827: if (!buffer->line_prompt) {
828: LOGERR;
829: free(buffer);
830: return NULL;
831: } else
832: buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
833: }
834: }
835: buffer->line_buf = malloc(BUFSIZ);
836: if (!buffer->line_buf) {
837: LOGERR;
838: if (buffer->line_prompt)
839: free(buffer->line_prompt);
840: free(buffer);
841: return NULL;
842: } else {
843: memset(buffer->line_buf, 0, BUFSIZ);
844: buffer->line_len = 1 + buffer->line_eol;
845: }
846: keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
847: if (!keys) {
848: LOGERR;
849: if (buffer->line_prompt)
850: free(buffer->line_prompt);
851: free(buffer->line_buf);
852: free(buffer);
853: return NULL;
854: } else
855: memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
856:
1.2.2.7 ! misho 857: /* add helper functions */
! 858: cli_addCommand(buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
! 859:
1.2.2.3 misho 860: /* fill key bindings */
861: // ascii chars & ctrl+chars
862: for (i = 0; i < 256; i++) {
863: *keys[i].key_ch = (u_char) i;
864: keys[i].key_len = 1;
865:
866: if (!i || i == *K_CTRL_D)
867: keys[i].key_func = bufEOF;
868: if (i == *K_CTRL_M || i == *K_CTRL_J)
869: keys[i].key_func = bufEOL;
870: if (i == *K_CTRL_H || i == *K_BACKSPACE)
871: keys[i].key_func = bufBS;
872: if (i == *K_CTRL_C)
873: keys[i].key_func = bufCLR;
874: if (i == *K_CTRL_A)
875: keys[i].key_func = bufBEGIN;
876: if (i == *K_CTRL_E)
877: keys[i].key_func = bufEND;
878: if (i >= *K_SPACE && i < *K_BACKSPACE)
879: keys[i].key_func = bufCHAR;
880: if (i > *K_BACKSPACE && i < 0xff)
881: keys[i].key_func = bufCHAR;
882: }
883: // alt+chars
884: for (i = 256; i < 512; i++) {
885: keys[i].key_ch[0] = 0x1b;
886: keys[i].key_ch[1] = (u_char) i - 256;
887: keys[i].key_len = 2;
888: }
889:
890: // 3 bytes
891: keys[i].key_len = sizeof K_F1 - 1;
892: memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
893: i++;
894: keys[i].key_len = sizeof K_F2 - 1;
895: memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
896: i++;
897: keys[i].key_len = sizeof K_F3 - 1;
898: memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
899: i++;
900: keys[i].key_len = sizeof K_F4 - 1;
901: memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
902: i++;
903: keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
904: memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
905: i++;
906: keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
907: memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
908: i++;
909: keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
910: memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
911: i++;
912: keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
913: memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
914: i++;
915: keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
916: memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
917: i++;
918: keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
919: memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
920: i++;
921: keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
922: memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
923: i++;
924: keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
925: memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
926: i++;
927: keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
928: memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
929: i++;
930: keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
931: memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
932: i++;
933: keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
934: memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
935: i++;
936: keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
937: memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
938: i++;
939: keys[i].key_len = sizeof K_CTRL_F1 - 1;
940: memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
941: i++;
942: keys[i].key_len = sizeof K_CTRL_F2 - 1;
943: memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
944: i++;
945: keys[i].key_len = sizeof K_CTRL_F3 - 1;
946: memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
947: i++;
948: keys[i].key_len = sizeof K_CTRL_F4 - 1;
949: memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
950: i++;
951: keys[i].key_len = sizeof K_CTRL_F5 - 1;
952: memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
953: i++;
954: keys[i].key_len = sizeof K_CTRL_F6 - 1;
955: memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
956: i++;
957: keys[i].key_len = sizeof K_CTRL_F7 - 1;
958: memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
959: i++;
960: keys[i].key_len = sizeof K_CTRL_F8 - 1;
961: memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
962: i++;
963: keys[i].key_len = sizeof K_CTRL_F9 - 1;
964: memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
965: i++;
966: keys[i].key_len = sizeof K_CTRL_F10 - 1;
967: memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
968: i++;
969: keys[i].key_len = sizeof K_CTRL_F11 - 1;
970: memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
971: i++;
972: keys[i].key_len = sizeof K_CTRL_F12 - 1;
973: memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
974: i++;
975: keys[i].key_len = sizeof K_HOME - 1;
976: keys[i].key_func = bufBEGIN;
977: memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
978: i++;
979: keys[i].key_len = sizeof K_END - 1;
980: keys[i].key_func = bufEND;
981: memcpy(keys[i].key_ch, K_END, keys[i].key_len);
982: i++;
983: keys[i].key_len = sizeof K_UP - 1;
984: keys[i].key_func = bufUP;
985: memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
986: i++;
987: keys[i].key_len = sizeof K_DOWN - 1;
988: keys[i].key_func = bufDOWN;
989: memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
990: i++;
991: keys[i].key_len = sizeof K_RIGHT - 1;
992: keys[i].key_func = bufRIGHT;
993: memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
994: i++;
995: keys[i].key_len = sizeof K_LEFT - 1;
996: keys[i].key_func = bufLEFT;
997: memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
998: i++;
999: keys[i].key_len = sizeof K_BTAB - 1;
1000: keys[i].key_func = bufBTAB;
1001: memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1002: i++;
1003: // 4 bytes
1004: keys[i].key_len = sizeof K_INS - 1;
1005: keys[i].key_func = bufMODE;
1006: memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1007: i++;
1008: keys[i].key_len = sizeof K_DEL - 1;
1009: keys[i].key_func = bufDEL;
1010: memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1011: i++;
1012: keys[i].key_len = sizeof K_PGUP - 1;
1013: memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1014: i++;
1015: keys[i].key_len = sizeof K_PGDN - 1;
1016: memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1017: i++;
1018: // 5 bytes
1019: keys[i].key_len = sizeof K_F5 - 1;
1020: memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1021: i++;
1022: keys[i].key_len = sizeof K_F6 - 1;
1023: memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1024: i++;
1025: keys[i].key_len = sizeof K_F7 - 1;
1026: memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1027: i++;
1028: keys[i].key_len = sizeof K_F8 - 1;
1029: memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1030: i++;
1031: keys[i].key_len = sizeof K_F9 - 1;
1032: memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1033: i++;
1034: keys[i].key_len = sizeof K_F10 - 1;
1035: memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1036: i++;
1037: keys[i].key_len = sizeof K_F11 - 1;
1038: memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1039: i++;
1040: keys[i].key_len = sizeof K_F12 - 1;
1041: memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1042: i++;
1043:
1044: tcgetattr(buffer->line_in, &t);
1045: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1046: t.c_iflag |= IGNBRK;
1047: t.c_cc[VMIN] = 1;
1048: t.c_cc[VTIME] = 0;
1049: tcsetattr(buffer->line_in, TCSANOW, &t);
1050:
1051: buffer->line_keys = keys;
1052: return buffer;
1053: }
1054:
1.2 misho 1055: /*
1.2.2.4 misho 1056: * cliReadLine() Read line from opened CLI session
1057: * @buffer = CLI buffer
1058: * return: NULL if error or !=NULL readed line, must be free after use!
1.2 misho 1059: */
1.2.2.4 misho 1060: char *
1061: cliReadLine(linebuffer_t * __restrict buffer)
1.2 misho 1062: {
1.2.2.4 misho 1063: int code, readLen;
1064: register int i;
1065: struct pollfd fds;
1066: char buf[BUFSIZ], *str = NULL;
1.2 misho 1067:
1.2.2.4 misho 1068: if (!buffer) {
1069: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1070: return NULL;
1.2 misho 1071: }
1072:
1.2.2.4 misho 1073: memset(&fds, 0, sizeof fds);
1074: fds.fd = buffer->line_in;
1075: fds.events = POLLIN;
1076:
1077: printfCR(buffer, 1);
1078: while (42) {
1079: if (poll(&fds, 1, -1) < 1) {
1080: LOGERR;
1081: return str;
1082: }
1.2 misho 1083:
1.2.2.4 misho 1084: memset(buf, 0, sizeof buf);
1085: readLen = read(buffer->line_in, buf, BUFSIZ);
1086: if (readLen == -1) {
1087: LOGERR;
1088: return str;
1089: }
1090: if (!readLen) {
1091: if (buffer->line_buf)
1092: str = strdup(buffer->line_buf);
1093: else
1094: cli_SetErr(EPIPE, "Error:: unknown state ...");
1095: return str;
1096: }
1.2 misho 1097:
1.2.2.4 misho 1098: recheck:
1099: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
1100: if (readLen >= buffer->line_keys[i].key_len &&
1101: !memcmp(buffer->line_keys[i].key_ch, buf,
1102: buffer->line_keys[i].key_len)) {
1103: readLen -= buffer->line_keys[i].key_len;
1104: if (readLen)
1105: memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
1106: else
1107: memset(buf, 0, buffer->line_keys[i].key_len);
1108:
1109: if (buffer->line_keys[i].key_func)
1110: if ((code = buffer->line_keys[i].key_func(i, buffer)))
1111: readLen = 0;
1112:
1113: if (readLen)
1114: goto recheck;
1115: else
1116: break;
1117: }
1.2 misho 1118:
1.2.2.4 misho 1119: if (code)
1120: break;
1121: }
1122:
1.2.2.5 misho 1123: if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
1.2.2.4 misho 1124: str = strdup(buffer->line_buf);
1125: return str;
1.2 misho 1126: }
1.2.2.4 misho 1127:
1128:
1.2 misho 1129: /*
1.2.2.4 misho 1130: * cliNetLoop() CLI network main loop binded to socket
1131: * @buffer = CLI buffer
1132: * @csHistFile = History file name
1.2 misho 1133: * @sock = client socket
1134: * @term = stdin termios
1135: * @win = window size of tty
1.2.2.4 misho 1136: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1137: */
1.2.2.1 misho 1138: int
1.2.2.4 misho 1139: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock,
1140: struct termios *term, struct winsize *win)
1.2 misho 1141: {
1.2.2.4 misho 1142: u_char buf[BUFSIZ];
1143: int pty, r, s, alen, attrlen, flg, ret = 0;
1.2 misho 1144: fd_set fds;
1145: struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
1146: struct telnetAttrs *a, Attr[10];
1147:
1148: switch (forkpty(&pty, NULL, term, win)) {
1149: case -1:
1150: LOGERR;
1151: return -1;
1152: case 0:
1153: close(sock);
1154:
1.2.2.4 misho 1155: // buffer = cliInit(STDIN_FILENO, STDOUT_FILENO, csPrompt);
1156: // if (!buffer)
1157: // return RETCODE_ERR;
1158:
1159: ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
1160:
1161: // cliEnd(buffer);
1162:
1.2 misho 1163: /* spawn Shell mode */
1164: /*
1165: execl("/bin/tcsh", "tcsh", NULL);
1166: */
1.2.2.4 misho 1167:
1.2 misho 1168: _exit(ret);
1169: default:
1170: /* spawn Shell mode */
1171: telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
1172: telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
1173: telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
1174: telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
1175: telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
1176: if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
1177: cli_Errno = telnet_GetErrno();
1178: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1179: return -1;
1180: } else
1181: flg = 0;
1182:
1183: while (42) {
1184: FD_ZERO(&fds);
1185: FD_SET(sock, &fds);
1186: FD_SET(pty, &fds);
1187: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
1188: if (!ret)
1189: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
1190:
1191: break;
1192: }
1193:
1194: r = FD_ISSET(sock, &fds) ? sock : pty;
1195: s = FD_ISSET(sock, &fds) ? pty : sock;
1196:
1197: if ((ret = telnetRecv(r, &a, &alen, buf, BUFSIZ)) < 0) {
1198: if (a)
1199: free(a);
1200:
1201: if (-2 == ret)
1202: continue;
1203: // EOF
1204: if (-3 == ret)
1205: shutdown(r, SHUT_RD);
1206: else {
1207: cli_Errno = telnet_GetErrno();
1208: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1209: }
1210: break;
1211: }
1212: attrlen = 0;
1213: if (1 == flg && alen) {
1214: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
1215: telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1216: }
1217: if (2 == flg && alen) {
1218: telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
1219: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1220: LFLOW_OFF, NULL, 0);
1221: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1222: LFLOW_RESTART_XON, NULL, 0);
1223: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1224: }
1225: if (a)
1226: free(a);
1227:
1228: if ((ret = telnetSend(s, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
1229: cli_Errno = telnet_GetErrno();
1230: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1231: break;
1232: } else
1233: flg++;
1234: }
1235:
1236: close(pty);
1237: }
1238:
1239: return ret;
1240: }
1241:
1242: /*
1.2.2.4 misho 1243: * cliLoop() CLI main loop
1244: * @buffer = CLI buffer
1245: * @csHistFile = History file name
1246: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 1247: */
1.2.2.4 misho 1248: int
1249: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
1.1 misho 1250: {
1251: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
1252: register int i;
1.2.2.4 misho 1253: int ret = RETCODE_OK;
1254: struct tagCommand *cmd;
1.1 misho 1255:
1.2.2.4 misho 1256: /*
1.1 misho 1257: inline int inline_help()
1258: {
1259: cli_Cmd_Help(cmdList ? cmdList : cli_stdCmds, -1, out, NULL);
1260: rl_on_new_line();
1261: return 0;
1262: }
1263:
1264: char **cli_stdCompletion(const char *text, int start, int end)
1265: {
1266: register int i;
1267: char **matches = NULL;
1268:
1269: char *cmdCompGet(const char *text, int state)
1270: {
1271: int len = strlen(text);
1272:
1273: for (i = state; cmdList[i].cmd_name; i++) {
1274: if (strncmp(cmdList[i].cmd_name, "---", 3) &&
1275: !strncmp(cmdList[i].cmd_name, text, len))
1276: return strdup(cmdList[i].cmd_name);
1277: }
1278:
1279: return NULL;
1280: }
1281:
1282: if (!start)
1283: matches = rl_completion_matches(text, cmdCompGet);
1284: else
1285: for (i = 0; cmdList[i].cmd_name; i++) {
1286: if (!cmdList[i].cmd_comp)
1287: continue;
1288: if (!strncmp(rl_line_buffer, cmdList[i].cmd_name, strlen(cmdList[i].cmd_name)))
1289: matches = rl_completion_matches(text, cmdList[i].cmd_comp);
1290: }
1291:
1292: return matches;
1293: }
1.2.2.4 misho 1294:
1295:
1296: */
1297:
1.1 misho 1298: /* --- main body of CLI --- */
1.2.2.4 misho 1299:
1300: if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
1301: return RETCODE_ERR;
1.1 misho 1302:
1303: do {
1.2.2.4 misho 1304: line = cliReadLine(buffer);
1.2.2.5 misho 1305: if (!line) {
1306: printfNL(buffer, 0);
1.1 misho 1307: break;
1.2.2.5 misho 1308: } else
1.2.2.4 misho 1309: cli_addHistory(buffer, NULL);
1.1 misho 1310: // clear whitespaces
1311: for (s = line; isspace(*s); s++);
1312: if (*s) {
1313: for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
1314: *++t = 0;
1315: }
1316:
1317: if (*s) {
1318: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1319: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
1320: *app ? app++ : app);
1321:
1322: // exec_cmd ...
1.2.2.4 misho 1323: i = 0;
1324: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
1325: if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1 misho 1326: break;
1.2.2.4 misho 1327: else
1328: i++;
1329: }
1.2.2.5 misho 1330:
1.1 misho 1331: if (!cmd) {
1.2.2.5 misho 1332: cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
1.1 misho 1333: ret = -1;
1334: } else
1.2.2.4 misho 1335: ret = cmd->cmd_func(buffer, i, items);
1.1 misho 1336: }
1337:
1.2.2.4 misho 1338: cli_freeLine(buffer);
1339: cli_resetHistory(buffer);
1.1 misho 1340: free(line);
1341: } while (ret < 1);
1342:
1.2.2.4 misho 1343: cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
1.1 misho 1344: return ret;
1345: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>