Diff for /libaitcli/example/t.c between versions 1.1 and 1.2

version 1.1, 2010/06/02 17:17:56 version 1.2, 2011/03/16 17:24:03
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;
   }

Removed from v.1.1  
changed lines
  Added in v.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>