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