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