1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <unistd.h>
4: #include <string.h>
5: #include <termios.h>
6: #include <poll.h>
7: #include <aitio.h>
8: #include <sys/param.h>
9: #include <sys/stat.h>
10: #include <sys/queue.h>
11: #include "keys.h"
12:
13:
14: int freeLineCLI(linebuffer_t * __restrict buffer);
15:
16:
17: static int
18: catCh2Buf(int idx, void * __restrict buffer)
19: {
20: linebuffer_t *buf = buffer;
21: char *ptr;
22:
23: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
24: return RETCODE_ERR;
25:
26: ptr = realloc(buf->line_buf, buf->line_len + buf->line_keys[idx].key_len);
27: if (!ptr)
28: return RETCODE_ERR;
29: else
30: buf->line_len += buf->line_keys[idx].key_len;
31:
32: memcpy(ptr + buf->line_eol, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
33: ptr[buf->line_len - 1] = 0;
34:
35: /* show */
36: write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
37:
38: buf->line_eol += buf->line_keys[idx].key_len;
39: buf->line_buf = ptr;
40: return RETCODE_OK;
41: }
42:
43: static int
44: bufEOL(int idx, void * __restrict buffer)
45: {
46: linebuffer_t *buf = buffer;
47:
48: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
49: return RETCODE_ERR;
50:
51: /* show */
52: write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
53:
54: return RETCODE_EOL;
55: }
56:
57: static int
58: bufEOF(int idx, void * __restrict buffer)
59: {
60: linebuffer_t *buf = buffer;
61:
62: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
63: return RETCODE_ERR;
64:
65: /* show */
66: write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
67:
68: return RETCODE_EOF;
69: }
70:
71: static int
72: bufTab(int idx, void * __restrict buffer)
73: {
74: linebuffer_t *buf = buffer;
75:
76: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
77: return RETCODE_ERR;
78:
79: /* show */
80: write(buf->line_out, "shmink", 6);
81:
82: return RETCODE_OK;
83: }
84:
85: static int
86: bufUP(int idx, void * __restrict buffer)
87: {
88: linebuffer_t *buf = buffer;
89: char *ptr;
90: register int i;
91:
92: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
93: return RETCODE_ERR;
94:
95: if (!buf->line_h)
96: buf->line_h = TAILQ_FIRST(&buf->line_history);
97: else
98: buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
99: if (!buf->line_h)
100: return RETCODE_OK;
101:
102: /* clear line */
103: write(buf->line_out, K_CR, 1);
104: for (i = 0; i < buf->line_len; i++)
105: write(buf->line_out, K_SPACE, 1);
106:
107: freeLineCLI(buffer);
108: ptr = realloc(buf->line_buf, buf->line_len + buf->line_h->hist_len);
109: if (!ptr)
110: return RETCODE_ERR;
111: else
112: buf->line_len += buf->line_h->hist_len;
113:
114: memcpy(ptr + buf->line_eol, buf->line_h->hist_line, buf->line_h->hist_len);
115: ptr[buf->line_len - 1] = 0;
116:
117: buf->line_eol += buf->line_h->hist_len;
118: buf->line_buf = ptr;
119:
120: /* show */
121: write(buf->line_out, K_CR, 1);
122: write(buf->line_out, buf->line_buf, buf->line_len);
123:
124: return RETCODE_OK;
125: }
126:
127: static int
128: bufDOWN(int idx, void * __restrict buffer)
129: {
130: linebuffer_t *buf = buffer;
131: char *ptr;
132: register int i;
133:
134: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
135: return RETCODE_ERR;
136:
137: if (!buf->line_h)
138: buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
139: else
140: buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
141: if (!buf->line_h)
142: return RETCODE_OK;
143:
144: /* clear line */
145: write(buf->line_out, K_CR, 1);
146: for (i = 0; i < buf->line_len; i++)
147: write(buf->line_out, K_SPACE, 1);
148:
149: freeLineCLI(buffer);
150: ptr = realloc(buf->line_buf, buf->line_len + buf->line_h->hist_len);
151: if (!ptr)
152: return RETCODE_ERR;
153: else
154: buf->line_len += buf->line_h->hist_len;
155:
156: memcpy(ptr + buf->line_eol, buf->line_h->hist_line, buf->line_h->hist_len);
157: ptr[buf->line_len - 1] = 0;
158:
159: buf->line_eol += buf->line_h->hist_len;
160: buf->line_buf = ptr;
161:
162: /* show */
163: write(buf->line_out, K_CR, 1);
164: write(buf->line_out, buf->line_buf, buf->line_len);
165:
166: return RETCODE_OK;
167: }
168:
169: static int
170: bufClr(int idx, void * __restrict buffer)
171: {
172: linebuffer_t *buf = buffer;
173: register int i;
174:
175: if (!buffer || idx < 0 || idx > MAX_BINDKEY)
176: return RETCODE_ERR;
177:
178: /* clear line */
179: write(buf->line_out, K_CR, 1);
180: for (i = 0; i < buf->line_len; i++)
181: write(buf->line_out, K_SPACE, 1);
182:
183: freeLineCLI(buffer);
184:
185: write(buf->line_out, K_CR, 1);
186: return RETCODE_OK;
187: }
188:
189: // ---------------------------------------------------------------
190:
191: int
192: bindKeyCLI(bindkey_t * __restrict key, linebuffer_t * __restrict buffer)
193: {
194: register int i;
195:
196: if (!key || !buffer)
197: return RETCODE_ERR;
198:
199: for (i = 0; i < MAX_BINDKEY; i++)
200: if (key->key_len == buffer->line_keys[i].key_len &&
201: !memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) {
202: buffer->line_keys[i].key_func = key->key_func;
203: return i;
204: }
205: return RETCODE_OK;
206: }
207:
208: linebuffer_t *
209: initCLI(int fin, int fout)
210: {
211: linebuffer_t *buffer;
212: bindkey_t *keys;
213: register int i;
214: struct termios t;
215:
216: memset(&t, 0, sizeof t);
217: /* init buffer */
218: buffer = malloc(sizeof (linebuffer_t));
219: if (!buffer)
220: return NULL;
221: else {
222: memset(buffer, 0, sizeof(linebuffer_t));
223:
224: buffer->line_in = fin;
225: buffer->line_out = fout;
226:
227: TAILQ_INIT(&buffer->line_history);
228: }
229: buffer->line_buf = malloc(1);
230: if (!buffer->line_buf) {
231: free(buffer);
232: return NULL;
233: } else {
234: *buffer->line_buf = 0;
235: buffer->line_len = 1;
236: }
237: keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
238: if (!keys) {
239: free(buffer->line_buf);
240: free(buffer);
241: return NULL;
242: } else
243: memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
244:
245: /* fill key bindings */
246: // ascii chars & ctrl+chars
247: for (i = 0; i < 256; i++) {
248: *keys[i].key_ch = (unsigned char) i;
249: keys[i].key_len = 1;
250:
251: if (!i || i == *K_CTRL_D)
252: keys[i].key_func = bufEOF;
253: if (i == *K_CTRL_M || i == *K_CTRL_J)
254: keys[i].key_func = bufEOL;
255: if (i == *K_CTRL_C)
256: keys[i].key_func = bufClr;
257: if (i >= *K_SPACE && i < *K_BACKSPACE)
258: keys[i].key_func = catCh2Buf;
259: if (i > *K_BACKSPACE && i < 0xff)
260: keys[i].key_func = catCh2Buf;
261: }
262: // alt+chars
263: for (i = 256; i < 512; i++) {
264: keys[i].key_ch[0] = 0x1b;
265: keys[i].key_ch[1] = (unsigned char) i - 256;
266: keys[i].key_len = 2;
267: }
268:
269: // 3 bytes
270: keys[i].key_len = sizeof K_F1 - 1;
271: memcpy(keys[i].key_ch, K_F1, keys[i++].key_len);
272: keys[i].key_len = sizeof K_F2 - 1;
273: memcpy(keys[i].key_ch, K_F2, keys[i++].key_len);
274: keys[i].key_len = sizeof K_F3 - 1;
275: memcpy(keys[i].key_ch, K_F3, keys[i++].key_len);
276: keys[i].key_len = sizeof K_F4 - 1;
277: memcpy(keys[i].key_ch, K_F4, keys[i++].key_len);
278: keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
279: memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i++].key_len);
280: keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
281: memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i++].key_len);
282: keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
283: memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i++].key_len);
284: keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
285: memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i++].key_len);
286: keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
287: memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i++].key_len);
288: keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
289: memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i++].key_len);
290: keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
291: memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i++].key_len);
292: keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
293: memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i++].key_len);
294: keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
295: memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i++].key_len);
296: keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
297: memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i++].key_len);
298: keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
299: memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i++].key_len);
300: keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
301: memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i++].key_len);
302: keys[i].key_len = sizeof K_CTRL_F1 - 1;
303: memcpy(keys[i].key_ch, K_CTRL_F1, keys[i++].key_len);
304: keys[i].key_len = sizeof K_CTRL_F2 - 1;
305: memcpy(keys[i].key_ch, K_CTRL_F2, keys[i++].key_len);
306: keys[i].key_len = sizeof K_CTRL_F3 - 1;
307: memcpy(keys[i].key_ch, K_CTRL_F3, keys[i++].key_len);
308: keys[i].key_len = sizeof K_CTRL_F4 - 1;
309: memcpy(keys[i].key_ch, K_CTRL_F4, keys[i++].key_len);
310: keys[i].key_len = sizeof K_CTRL_F5 - 1;
311: memcpy(keys[i].key_ch, K_CTRL_F5, keys[i++].key_len);
312: keys[i].key_len = sizeof K_CTRL_F6 - 1;
313: memcpy(keys[i].key_ch, K_CTRL_F6, keys[i++].key_len);
314: keys[i].key_len = sizeof K_CTRL_F7 - 1;
315: memcpy(keys[i].key_ch, K_CTRL_F7, keys[i++].key_len);
316: keys[i].key_len = sizeof K_CTRL_F8 - 1;
317: memcpy(keys[i].key_ch, K_CTRL_F8, keys[i++].key_len);
318: keys[i].key_len = sizeof K_CTRL_F9 - 1;
319: memcpy(keys[i].key_ch, K_CTRL_F9, keys[i++].key_len);
320: keys[i].key_len = sizeof K_CTRL_F10 - 1;
321: memcpy(keys[i].key_ch, K_CTRL_F10, keys[i++].key_len);
322: keys[i].key_len = sizeof K_CTRL_F11 - 1;
323: memcpy(keys[i].key_ch, K_CTRL_F11, keys[i++].key_len);
324: keys[i].key_len = sizeof K_CTRL_F12 - 1;
325: memcpy(keys[i].key_ch, K_CTRL_F12, keys[i++].key_len);
326: keys[i].key_len = sizeof K_HOME - 1;
327: memcpy(keys[i].key_ch, K_HOME, keys[i++].key_len);
328: keys[i].key_len = sizeof K_END - 1;
329: memcpy(keys[i].key_ch, K_END, keys[i++].key_len);
330: keys[i].key_len = sizeof K_UP - 1;
331: keys[i].key_func = bufUP;
332: memcpy(keys[i].key_ch, K_UP, keys[i++].key_len);
333: keys[i].key_len = sizeof K_DOWN - 1;
334: keys[i].key_func = bufDOWN;
335: memcpy(keys[i].key_ch, K_DOWN, keys[i++].key_len);
336: keys[i].key_len = sizeof K_RIGHT - 1;
337: memcpy(keys[i].key_ch, K_RIGHT, keys[i++].key_len);
338: keys[i].key_len = sizeof K_LEFT - 1;
339: memcpy(keys[i].key_ch, K_LEFT, keys[i++].key_len);
340: keys[i].key_len = sizeof K_BTAB - 1;
341: memcpy(keys[i].key_ch, K_BTAB, keys[i++].key_len);
342: // 4 bytes
343: keys[i].key_len = sizeof K_INS - 1;
344: memcpy(keys[i].key_ch, K_INS, keys[i++].key_len);
345: keys[i].key_len = sizeof K_DEL - 1;
346: memcpy(keys[i].key_ch, K_DEL, keys[i++].key_len);
347: keys[i].key_len = sizeof K_PGUP - 1;
348: memcpy(keys[i].key_ch, K_PGUP, keys[i++].key_len);
349: keys[i].key_len = sizeof K_PGDN - 1;
350: memcpy(keys[i].key_ch, K_PGDN, keys[i++].key_len);
351: // 5 bytes
352: keys[i].key_len = sizeof K_F5 - 1;
353: memcpy(keys[i].key_ch, K_F5, keys[i++].key_len);
354: keys[i].key_len = sizeof K_F6 - 1;
355: memcpy(keys[i].key_ch, K_F6, keys[i++].key_len);
356: keys[i].key_len = sizeof K_F7 - 1;
357: memcpy(keys[i].key_ch, K_F7, keys[i++].key_len);
358: keys[i].key_len = sizeof K_F8 - 1;
359: memcpy(keys[i].key_ch, K_F8, keys[i++].key_len);
360: keys[i].key_len = sizeof K_F9 - 1;
361: memcpy(keys[i].key_ch, K_F9, keys[i++].key_len);
362: keys[i].key_len = sizeof K_F10 - 1;
363: memcpy(keys[i].key_ch, K_F10, keys[i++].key_len);
364: keys[i].key_len = sizeof K_F11 - 1;
365: memcpy(keys[i].key_ch, K_F11, keys[i++].key_len);
366: keys[i].key_len = sizeof K_F12 - 1;
367: memcpy(keys[i].key_ch, K_F12, keys[i++].key_len);
368:
369: tcgetattr(buffer->line_in, &t);
370: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
371: t.c_iflag |= IGNBRK;
372: t.c_cc[VMIN] = 1;
373: t.c_cc[VTIME] = 0;
374: tcsetattr(buffer->line_in, TCSANOW, &t);
375:
376: buffer->line_keys = keys;
377: return buffer;
378: }
379:
380: void
381: endCLI(linebuffer_t * __restrict buffer)
382: {
383: struct tagHistory *h;
384:
385: if (buffer) {
386: while ((h = TAILQ_FIRST(&buffer->line_history))) {
387: TAILQ_REMOVE(&buffer->line_history, h, hist_next);
388: free(h);
389: }
390:
391: if (buffer->line_keys)
392: free(buffer->line_keys);
393: if (buffer->line_buf)
394: free(buffer->line_buf);
395:
396: free(buffer);
397: buffer = NULL;
398: }
399: }
400:
401: int
402: freeLineCLI(linebuffer_t * __restrict buffer)
403: {
404: int code = RETCODE_ERR;
405:
406: if (buffer) {
407: if (buffer->line_buf)
408: free(buffer->line_buf);
409:
410: buffer->line_buf = malloc(1);
411: if (buffer->line_buf) {
412: *buffer->line_buf = 0;
413: buffer->line_eol = 0;
414: buffer->line_len = 1;
415:
416: code = RETCODE_OK;
417: }
418: }
419:
420: return code;
421: }
422:
423: int
424: readLineCLI(linebuffer_t * __restrict buffer)
425: {
426: int code, readLen;
427: register int i;
428: char buf[BUFSIZ];
429: struct pollfd fds;
430:
431: if (!buffer)
432: return RETCODE_ERR;
433:
434: memset(&fds, 0, sizeof fds);
435: fds.fd = buffer->line_in;
436: fds.events = POLLIN;
437:
438: while (42) {
439: if (poll(&fds, 1, -1) < 1)
440: return RETCODE_ERR;
441:
442: memset(buf, 0, sizeof buf);
443: readLen = read(buffer->line_in, buf, BUFSIZ);
444: if (readLen == -1)
445: return RETCODE_ERR;
446: if (!readLen)
447: return RETCODE_EOF;
448:
449: recheck:
450: // for (i = 0; i < readLen; i++)
451: // printf("i=%d readLen=%d buf=%x\n", i, readLen, (u_char) buf[i]);
452: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
453: if (readLen >= buffer->line_keys[i].key_len &&
454: !memcmp(buffer->line_keys[i].key_ch, buf, buffer->line_keys[i].key_len)) {
455: readLen -= buffer->line_keys[i].key_len;
456: if (readLen)
457: memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
458: else
459: memset(buf, 0, buffer->line_keys[i].key_len);
460:
461: if (buffer->line_keys[i].key_func)
462: if ((code = buffer->line_keys[i].key_func(i, buffer)))
463: readLen = 0;
464:
465: if (readLen)
466: goto recheck;
467: else
468: break;
469: }
470:
471: if (code)
472: break;
473: }
474:
475: return code;
476: }
477:
478: int
479: addHistoryCLI(linebuffer_t * __restrict buffer, const char * __restrict str)
480: {
481: struct tagHistory *h;
482:
483: if (!buffer)
484: return RETCODE_ERR;
485:
486: if (!(h = malloc(sizeof(struct tagHistory)))) {
487: return RETCODE_ERR;
488: } else
489: memset(h, 0, sizeof(struct tagHistory));
490:
491: if (str) {
492: if (!*str) {
493: free(h);
494: return RETCODE_OK;
495: }
496:
497: h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
498: } else {
499: if (!*buffer->line_buf || buffer->line_len < 2) {
500: free(h);
501: return RETCODE_OK;
502: }
503:
504: memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len));
505: io_TrimStr((unsigned char*) h->hist_line);
506: h->hist_len = strlen(h->hist_line);
507: }
508:
509: TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
510: return h->hist_len;
511: }
512:
513: int
514: saveHistoryCLI(linebuffer_t * __restrict buffer, const char *histfile)
515: {
516: FILE *f;
517: mode_t mode;
518: char szFName[MAXPATHLEN];
519: struct tagHistory *h;
520:
521: if (!buffer)
522: return RETCODE_ERR;
523: if (!histfile)
524: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
525: else
526: strlcpy(szFName, histfile, MAXPATHLEN);
527:
528: mode = umask(0177);
529: f = fopen(szFName, "w");
530: if (!f)
531: return RETCODE_ERR;
532: TAILQ_FOREACH(h, &buffer->line_history, hist_next)
533: fprintf(f, "%s\n", h->hist_line);
534: fclose(f);
535: umask(mode);
536:
537: return RETCODE_OK;
538: }
539:
540: int
541: loadHistoryCLI(linebuffer_t * __restrict buffer, const char *histfile)
542: {
543: FILE *f;
544: char szFName[MAXPATHLEN], buf[BUFSIZ];
545: struct tagHistory *h;
546:
547: if (!buffer)
548: return RETCODE_ERR;
549: if (!histfile)
550: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
551: else
552: strlcpy(szFName, histfile, MAXPATHLEN);
553:
554: f = fopen(szFName, "r");
555: if (!f)
556: return RETCODE_ERR;
557: while (fgets(buf, BUFSIZ, f)) {
558: if (!*buf || *buf == '#')
559: continue;
560: else
561: io_TrimStr((unsigned char*) buf);
562:
563: if (!(h = malloc(sizeof(struct tagHistory)))) {
564: fclose(f);
565: return RETCODE_ERR;
566: } else
567: memset(h, 0, sizeof(struct tagHistory));
568:
569: h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
570: TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next);
571: }
572: fclose(f);
573:
574: return RETCODE_OK;
575: }
576:
577: inline void
578: resetHistoryCLI(linebuffer_t * __restrict buffer)
579: {
580: buffer->line_h = NULL;
581: }
582:
583:
584: int
585: main()
586: {
587: int ret;
588: bindkey_t key = { sizeof K_TAB - 1, K_TAB, bufTab };
589: linebuffer_t *buffer = initCLI(STDIN_FILENO, STDOUT_FILENO);
590:
591: bindKeyCLI(&key, buffer);
592:
593: loadHistoryCLI(buffer, NULL);
594:
595: while (42) {
596: ret = readLineCLI(buffer);
597: addHistoryCLI(buffer, NULL);
598:
599: printf("LINE=%s (%d)/%d CODE=%d\n", buffer->line_buf, buffer->line_len, buffer->line_eol, ret);
600:
601: freeLineCLI(buffer);
602: resetHistoryCLI(buffer);
603:
604: if (ret == RETCODE_EOF)
605: break;
606: }
607:
608: saveHistoryCLI(buffer, NULL);
609:
610: endCLI(buffer);
611: return 0;
612: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>