version 1.1, 2010/06/02 17:17:56
|
version 1.1.2.3, 2010/06/04 09:16:59
|
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_buf + buf->line_eol + 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_eol--; |
|
buf->line_len--; |
|
buf->line_buf[buf->line_eol - buf->line_bol] = 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_buf + buf->line_eol + 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*/ NULL); |
|
|
|
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; |
|
} |