|
|
| version 1.1, 2010/06/02 17:17:56 | version 1.1.2.4, 2010/06/04 11:05:18 |
|---|---|
| Line 0 | Line 1 |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <termios.h> | |
| #include <poll.h> | |
| #include <aitio.h> | |
| #include <sys/types.h> | |
| #include <sys/param.h> | |
| #include <sys/stat.h> | |
| #include <sys/queue.h> | |
| #include "keys.h" | |
| int freeLineCLI(linebuffer_t * __restrict buffer); | |
| static inline void | |
| clrscrEOL(linebuffer_t * __restrict buf) | |
| { | |
| register int i; | |
| if (buf) { | |
| write(buf->line_out, K_CR, 1); | |
| for (i = 0; i < buf->line_len; i++) | |
| write(buf->line_out, K_SPACE, 1); | |
| } | |
| } | |
| static inline void | |
| printfEOL(linebuffer_t * __restrict buf, int len, int prompt) | |
| { | |
| if (buf) { | |
| write(buf->line_out, K_CR, 1); | |
| if (prompt && buf->line_prompt) | |
| write(buf->line_out, buf->line_prompt, buf->line_bol); | |
| write(buf->line_out, buf->line_buf, len == -1 ? buf->line_eol - buf->line_bol: len); | |
| } | |
| } | |
| static inline void | |
| printfCR(linebuffer_t * __restrict buf, int prompt) | |
| { | |
| if (buf) { | |
| write(buf->line_out, K_CR, 1); | |
| if (prompt) | |
| if (prompt && buf->line_prompt) | |
| write(buf->line_out, buf->line_prompt, buf->line_bol); | |
| } | |
| } | |
| static inline void | |
| printfCLI(linebuffer_t * __restrict buf, const unsigned char *text, int textlen, int prompt) | |
| { | |
| if (buf && text && textlen) { | |
| if (prompt && buf->line_prompt) | |
| write(buf->line_out, buf->line_prompt, buf->line_bol); | |
| write(buf->line_out, text, textlen); | |
| } | |
| } | |
| static int | |
| catCh2Buf(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| int pos; | |
| unsigned char b[BUFSIZ]; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| pos = buf->line_eol - buf->line_bol; | |
| if (buf->line_mode == LINEMODE_INS) | |
| memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos, | |
| buf->line_len - buf->line_eol); | |
| if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1) | |
| buf->line_len += buf->line_keys[idx].key_len; | |
| buf->line_eol += buf->line_keys[idx].key_len; | |
| memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len); | |
| buf->line_buf[buf->line_len - 1] = 0; | |
| write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len); | |
| if (buf->line_mode == LINEMODE_INS) { | |
| printfCLI(buf, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len, | |
| buf->line_len - buf->line_eol, 0); | |
| printfEOL(buf, -1, 1); | |
| } | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufEOL(int idx, void * __restrict buffer) | |
| { | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| printfCR(buffer, 1); | |
| return RETCODE_EOL; | |
| } | |
| static int | |
| bufEOF(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len); | |
| return RETCODE_EOF; | |
| } | |
| static int | |
| bufTab(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| /* show */ | |
| write(buf->line_out, "shmink", 6); | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufUP(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| int pos; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| if (!buf->line_h) | |
| buf->line_h = TAILQ_FIRST(&buf->line_history); | |
| else | |
| buf->line_h = TAILQ_NEXT(buf->line_h, hist_next); | |
| if (!buf->line_h) | |
| return RETCODE_OK; | |
| clrscrEOL(buf); | |
| freeLineCLI(buf); | |
| pos = buf->line_eol - buf->line_bol; | |
| buf->line_len += buf->line_h->hist_len; | |
| buf->line_eol += buf->line_h->hist_len; | |
| memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len); | |
| buf->line_buf[buf->line_len - 1] = 0; | |
| printfEOL(buf, -1, 1); | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufDOWN(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| int pos; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| if (!buf->line_h) | |
| buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead); | |
| else | |
| buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next); | |
| if (!buf->line_h) | |
| return RETCODE_OK; | |
| clrscrEOL(buf); | |
| freeLineCLI(buf); | |
| pos = buf->line_eol - buf->line_bol; | |
| buf->line_len += buf->line_h->hist_len; | |
| buf->line_eol += buf->line_h->hist_len; | |
| memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len); | |
| buf->line_buf[buf->line_len - 1] = 0; | |
| printfEOL(buf, -1, 1); | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufClr(int idx, void * __restrict buffer) | |
| { | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| clrscrEOL(buffer); | |
| freeLineCLI(buffer); | |
| printfCR(buffer, 1); | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufBS(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| if (buf->line_bol < buf->line_eol) { | |
| clrscrEOL(buf); | |
| buf->line_eol--; | |
| buf->line_len--; | |
| memmove(buf->line_buf + buf->line_eol - buf->line_bol, | |
| buf->line_buf + buf->line_eol - buf->line_bol + 1, | |
| buf->line_len - buf->line_eol); | |
| buf->line_buf[buf->line_len - 1] = 0; | |
| printfEOL(buf, buf->line_len - 1, 1); | |
| printfEOL(buf, -1, 1); | |
| } | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufBTAB(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| if (buf->line_bol < buf->line_eol) { | |
| clrscrEOL(buf); | |
| buf->line_len = buf->line_eol - buf->line_bol + 1; | |
| buf->line_buf[buf->line_len - 1] = 0; | |
| printfEOL(buf, -1, 1); | |
| } | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufMode(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS; | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufBegin(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| buf->line_eol = buf->line_bol; | |
| printfCR(buf, 1); | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufEnd(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| buf->line_eol = buf->line_len - 1; | |
| printfEOL(buf, -1, 1); | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufLEFT(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| if (buf->line_bol < buf->line_eol) | |
| printfEOL(buf, --buf->line_eol - buf->line_bol, 1); | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufRIGHT(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| if (buf->line_eol < buf->line_len - 1) | |
| printfEOL(buf, ++buf->line_eol - buf->line_bol, 1); | |
| return RETCODE_OK; | |
| } | |
| static int | |
| bufDel(int idx, void * __restrict buffer) | |
| { | |
| linebuffer_t *buf = buffer; | |
| if (!buffer || idx < 0 || idx > MAX_BINDKEY) | |
| return RETCODE_ERR; | |
| clrscrEOL(buf); | |
| buf->line_len--; | |
| memmove(buf->line_buf + buf->line_eol - buf->line_bol, | |
| buf->line_buf + buf->line_eol - buf->line_bol + 1, | |
| buf->line_len - buf->line_eol); | |
| buf->line_buf[buf->line_len - 1] = 0; | |
| printfEOL(buf, buf->line_len - 1, 1); | |
| printfEOL(buf, -1, 1); | |
| return RETCODE_OK; | |
| } | |
| // --------------------------------------------------------------- | |
| int | |
| bindKeyCLI(bindkey_t * __restrict key, linebuffer_t * __restrict buffer) | |
| { | |
| register int i; | |
| if (!key || !buffer) | |
| return RETCODE_ERR; | |
| for (i = 0; i < MAX_BINDKEY; i++) | |
| if (key->key_len == buffer->line_keys[i].key_len && | |
| !memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) { | |
| buffer->line_keys[i].key_func = key->key_func; | |
| return i; | |
| } | |
| return RETCODE_OK; | |
| } | |
| linebuffer_t * | |
| initCLI(int fin, int fout, const char *prompt) | |
| { | |
| linebuffer_t *buffer; | |
| bindkey_t *keys; | |
| register int i; | |
| struct termios t; | |
| memset(&t, 0, sizeof t); | |
| /* init buffer */ | |
| buffer = malloc(sizeof (linebuffer_t)); | |
| if (!buffer) | |
| return NULL; | |
| else { | |
| memset(buffer, 0, sizeof(linebuffer_t)); | |
| buffer->line_in = fin; | |
| buffer->line_out = fout; | |
| TAILQ_INIT(&buffer->line_history); | |
| if (prompt) { | |
| buffer->line_prompt = strdup(prompt); | |
| if (!buffer->line_prompt) { | |
| free(buffer); | |
| return NULL; | |
| } else { | |
| buffer->line_bol = strlen(buffer->line_prompt); | |
| buffer->line_eol = buffer->line_bol; | |
| } | |
| } | |
| } | |
| buffer->line_buf = malloc(BUFSIZ); | |
| if (!buffer->line_buf) { | |
| if (buffer->line_prompt) | |
| free(buffer->line_prompt); | |
| free(buffer); | |
| return NULL; | |
| } else { | |
| memset(buffer->line_buf, 0, BUFSIZ); | |
| buffer->line_len = 1 + buffer->line_eol; | |
| } | |
| keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t)); | |
| if (!keys) { | |
| if (buffer->line_prompt) | |
| free(buffer->line_prompt); | |
| free(buffer->line_buf); | |
| free(buffer); | |
| return NULL; | |
| } else | |
| memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1)); | |
| /* fill key bindings */ | |
| // ascii chars & ctrl+chars | |
| for (i = 0; i < 256; i++) { | |
| *keys[i].key_ch = (unsigned char) i; | |
| keys[i].key_len = 1; | |
| if (!i || i == *K_CTRL_D) | |
| keys[i].key_func = bufEOF; | |
| if (i == *K_CTRL_M || i == *K_CTRL_J) | |
| keys[i].key_func = bufEOL; | |
| if (i == *K_CTRL_H || i == *K_BACKSPACE) | |
| keys[i].key_func = bufBS; | |
| if (i == *K_CTRL_C) | |
| keys[i].key_func = bufClr; | |
| if (i == *K_CTRL_A) | |
| keys[i].key_func = bufBegin; | |
| if (i == *K_CTRL_E) | |
| keys[i].key_func = bufEnd; | |
| if (i >= *K_SPACE && i < *K_BACKSPACE) | |
| keys[i].key_func = catCh2Buf; | |
| if (i > *K_BACKSPACE && i < 0xff) | |
| keys[i].key_func = catCh2Buf; | |
| } | |
| // alt+chars | |
| for (i = 256; i < 512; i++) { | |
| keys[i].key_ch[0] = 0x1b; | |
| keys[i].key_ch[1] = (unsigned char) i - 256; | |
| keys[i].key_len = 2; | |
| } | |
| // 3 bytes | |
| keys[i].key_len = sizeof K_F1 - 1; | |
| memcpy(keys[i].key_ch, K_F1, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F2 - 1; | |
| memcpy(keys[i].key_ch, K_F2, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F3 - 1; | |
| memcpy(keys[i].key_ch, K_F3, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F4 - 1; | |
| memcpy(keys[i].key_ch, K_F4, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F1 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F2 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F3 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F4 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F5 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F6 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F7 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F8 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F9 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F10 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F11 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_SH_F12 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F1 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F1, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F2 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F2, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F3 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F3, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F4 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F4, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F5 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F5, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F6 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F6, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F7 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F7, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F8 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F8, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F9 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F9, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F10 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F10, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F11 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F11, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_CTRL_F12 - 1; | |
| memcpy(keys[i].key_ch, K_CTRL_F12, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_HOME - 1; | |
| keys[i].key_func = bufBegin; | |
| memcpy(keys[i].key_ch, K_HOME, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_END - 1; | |
| keys[i].key_func = bufEnd; | |
| memcpy(keys[i].key_ch, K_END, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_UP - 1; | |
| keys[i].key_func = bufUP; | |
| memcpy(keys[i].key_ch, K_UP, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_DOWN - 1; | |
| keys[i].key_func = bufDOWN; | |
| memcpy(keys[i].key_ch, K_DOWN, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_RIGHT - 1; | |
| keys[i].key_func = bufRIGHT; | |
| memcpy(keys[i].key_ch, K_RIGHT, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_LEFT - 1; | |
| keys[i].key_func = bufLEFT; | |
| memcpy(keys[i].key_ch, K_LEFT, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_BTAB - 1; | |
| keys[i].key_func = bufBTAB; | |
| memcpy(keys[i].key_ch, K_BTAB, keys[i++].key_len); | |
| // 4 bytes | |
| keys[i].key_len = sizeof K_INS - 1; | |
| keys[i].key_func = bufMode; | |
| memcpy(keys[i].key_ch, K_INS, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_DEL - 1; | |
| keys[i].key_func = bufDel; | |
| memcpy(keys[i].key_ch, K_DEL, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_PGUP - 1; | |
| memcpy(keys[i].key_ch, K_PGUP, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_PGDN - 1; | |
| memcpy(keys[i].key_ch, K_PGDN, keys[i++].key_len); | |
| // 5 bytes | |
| keys[i].key_len = sizeof K_F5 - 1; | |
| memcpy(keys[i].key_ch, K_F5, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F6 - 1; | |
| memcpy(keys[i].key_ch, K_F6, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F7 - 1; | |
| memcpy(keys[i].key_ch, K_F7, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F8 - 1; | |
| memcpy(keys[i].key_ch, K_F8, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F9 - 1; | |
| memcpy(keys[i].key_ch, K_F9, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F10 - 1; | |
| memcpy(keys[i].key_ch, K_F10, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F11 - 1; | |
| memcpy(keys[i].key_ch, K_F11, keys[i++].key_len); | |
| keys[i].key_len = sizeof K_F12 - 1; | |
| memcpy(keys[i].key_ch, K_F12, keys[i++].key_len); | |
| tcgetattr(buffer->line_in, &t); | |
| t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT); | |
| t.c_iflag |= IGNBRK; | |
| t.c_cc[VMIN] = 1; | |
| t.c_cc[VTIME] = 0; | |
| tcsetattr(buffer->line_in, TCSANOW, &t); | |
| buffer->line_keys = keys; | |
| return buffer; | |
| } | |
| void | |
| endCLI(linebuffer_t * __restrict buffer) | |
| { | |
| struct tagHistory *h; | |
| if (buffer) { | |
| while ((h = TAILQ_FIRST(&buffer->line_history))) { | |
| TAILQ_REMOVE(&buffer->line_history, h, hist_next); | |
| free(h); | |
| } | |
| if (buffer->line_prompt) | |
| free(buffer->line_prompt); | |
| if (buffer->line_keys) | |
| free(buffer->line_keys); | |
| if (buffer->line_buf) | |
| free(buffer->line_buf); | |
| free(buffer); | |
| buffer = NULL; | |
| } | |
| } | |
| void | |
| setPromptCLI(linebuffer_t * __restrict buffer, const char *prompt) | |
| { | |
| if (buffer) { | |
| if (buffer->line_prompt) { | |
| free(buffer->line_prompt); | |
| buffer->line_prompt = NULL; | |
| buffer->line_bol = 0; | |
| } | |
| if (prompt) { | |
| buffer->line_prompt = strdup(prompt); | |
| if (buffer->line_prompt) { | |
| buffer->line_bol = strlen(buffer->line_prompt); | |
| buffer->line_eol = buffer->line_bol; | |
| buffer->line_len = 1 + buffer->line_eol; | |
| } | |
| } | |
| } | |
| } | |
| int | |
| freeLineCLI(linebuffer_t * __restrict buffer) | |
| { | |
| int code = RETCODE_ERR; | |
| if (buffer) { | |
| if (buffer->line_buf) | |
| free(buffer->line_buf); | |
| buffer->line_buf = malloc(BUFSIZ); | |
| if (buffer->line_buf) { | |
| memset(buffer->line_buf, 0, BUFSIZ); | |
| buffer->line_eol = buffer->line_bol; | |
| buffer->line_len = 1 + buffer->line_eol; | |
| code = RETCODE_OK; | |
| } | |
| } | |
| return code; | |
| } | |
| int | |
| readLineCLI(linebuffer_t * __restrict buffer) | |
| { | |
| int code, readLen; | |
| register int i; | |
| char buf[BUFSIZ]; | |
| struct pollfd fds; | |
| if (!buffer) | |
| return RETCODE_ERR; | |
| memset(&fds, 0, sizeof fds); | |
| fds.fd = buffer->line_in; | |
| fds.events = POLLIN; | |
| printfCR(buffer, 1); | |
| while (42) { | |
| if (poll(&fds, 1, -1) < 1) | |
| return RETCODE_ERR; | |
| memset(buf, 0, sizeof buf); | |
| readLen = read(buffer->line_in, buf, BUFSIZ); | |
| if (readLen == -1) | |
| return RETCODE_ERR; | |
| if (!readLen) | |
| return RETCODE_EOF; | |
| recheck: | |
| // for (i = 0; i < readLen; i++) | |
| // printf("i=%d readLen=%d buf=%x\n", i, readLen, (u_char) buf[i]); | |
| for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--) | |
| if (readLen >= buffer->line_keys[i].key_len && | |
| !memcmp(buffer->line_keys[i].key_ch, buf, buffer->line_keys[i].key_len)) { | |
| readLen -= buffer->line_keys[i].key_len; | |
| if (readLen) | |
| memmove(buf, buf + buffer->line_keys[i].key_len, readLen); | |
| else | |
| memset(buf, 0, buffer->line_keys[i].key_len); | |
| if (buffer->line_keys[i].key_func) | |
| if ((code = buffer->line_keys[i].key_func(i, buffer))) | |
| readLen = 0; | |
| if (readLen) | |
| goto recheck; | |
| else | |
| break; | |
| } | |
| if (code) | |
| break; | |
| } | |
| return code; | |
| } | |
| int | |
| addHistoryCLI(linebuffer_t * __restrict buffer, const char * __restrict str) | |
| { | |
| struct tagHistory *h; | |
| if (!buffer) | |
| return RETCODE_ERR; | |
| if (!(h = malloc(sizeof(struct tagHistory)))) { | |
| return RETCODE_ERR; | |
| } else | |
| memset(h, 0, sizeof(struct tagHistory)); | |
| if (str) { | |
| if (!*str) { | |
| free(h); | |
| return RETCODE_OK; | |
| } | |
| h->hist_len = strlcpy(h->hist_line, str, BUFSIZ); | |
| } else { | |
| if (!*buffer->line_buf || buffer->line_len < 2) { | |
| free(h); | |
| return RETCODE_OK; | |
| } | |
| memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len)); | |
| io_TrimStr((unsigned char*) h->hist_line); | |
| h->hist_len = strlen(h->hist_line); | |
| } | |
| TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next); | |
| return h->hist_len; | |
| } | |
| int | |
| saveHistoryCLI(linebuffer_t * __restrict buffer, const char *histfile, int lines) | |
| { | |
| FILE *f; | |
| mode_t mode; | |
| char szFName[MAXPATHLEN]; | |
| struct tagHistory *h; | |
| if (!buffer) | |
| return RETCODE_ERR; | |
| if (!histfile) | |
| strlcpy(szFName, HISTORY_FILE, MAXPATHLEN); | |
| else | |
| strlcpy(szFName, histfile, MAXPATHLEN); | |
| mode = umask(0177); | |
| f = fopen(szFName, "w"); | |
| if (!f) | |
| return RETCODE_ERR; | |
| TAILQ_FOREACH(h, &buffer->line_history, hist_next) { | |
| fprintf(f, "%s\n", h->hist_line); | |
| if (lines) | |
| lines--; | |
| else | |
| break; | |
| } | |
| fclose(f); | |
| umask(mode); | |
| return RETCODE_OK; | |
| } | |
| int | |
| loadHistoryCLI(linebuffer_t * __restrict buffer, const char *histfile) | |
| { | |
| FILE *f; | |
| char szFName[MAXPATHLEN], buf[BUFSIZ]; | |
| struct tagHistory *h; | |
| if (!buffer) | |
| return RETCODE_ERR; | |
| if (!histfile) | |
| strlcpy(szFName, HISTORY_FILE, MAXPATHLEN); | |
| else | |
| strlcpy(szFName, histfile, MAXPATHLEN); | |
| f = fopen(szFName, "r"); | |
| if (!f) | |
| return RETCODE_ERR; | |
| while (fgets(buf, BUFSIZ, f)) { | |
| if (!*buf || *buf == '#') | |
| continue; | |
| else | |
| io_TrimStr((unsigned char*) buf); | |
| if (!(h = malloc(sizeof(struct tagHistory)))) { | |
| fclose(f); | |
| return RETCODE_ERR; | |
| } else | |
| memset(h, 0, sizeof(struct tagHistory)); | |
| h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ); | |
| TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next); | |
| } | |
| fclose(f); | |
| return RETCODE_OK; | |
| } | |
| inline void | |
| resetHistoryCLI(linebuffer_t * __restrict buffer) | |
| { | |
| buffer->line_h = NULL; | |
| } | |
| // ------------------------------------------------------------ | |
| int | |
| main() | |
| { | |
| int ret; | |
| bindkey_t key = { sizeof K_TAB - 1, K_TAB, bufTab }; | |
| linebuffer_t *buffer = initCLI(STDIN_FILENO, STDOUT_FILENO, CLI_PROMPT); | |
| bindKeyCLI(&key, buffer); | |
| loadHistoryCLI(buffer, NULL); | |
| while (42) { | |
| ret = readLineCLI(buffer); | |
| addHistoryCLI(buffer, NULL); | |
| printf("LINE=%s (%d)/%d/%d CODE=%d\n", buffer->line_buf, buffer->line_len, buffer->line_eol, buffer->line_bol, ret); | |
| freeLineCLI(buffer); | |
| resetHistoryCLI(buffer); | |
| if (ret == RETCODE_EOF) | |
| break; | |
| } | |
| saveHistoryCLI(buffer, NULL, HISTORY_LINES); | |
| endCLI(buffer); | |
| return 0; | |
| } |