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