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