* Huge dewarnification.. some segfaults fixed
2 * Copyright (C) 2007, 2008, 2009
3 * pancake <youterm.com>
5 * dietline is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * dietline is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with dietline; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 /* dietline is a lighweight and portable library similar to GNU readline */
28 static void cons_set_raw(int b);
29 static int cons_get_real_columns();
39 #include <sys/ioctl.h>
46 const char *dl_prompt = "> ";
47 const char *dl_clipboard = NULL;
48 static char *dl_nullstr = "";
49 static char dl_buffer[DL_BUFSIZE];
50 static int dl_buffer_len = 0;
51 static int dl_buffer_idx = 0;
53 /* autocompletion callback */
54 char **(*dl_callback)(const char *text, int start, int end) = NULL;
57 char **dl_history = NULL;
58 int dl_histsize = DL_HISTSIZE;
60 int dl_autosave = 0; // TODO
61 int dl_disable = 0; // TODO use fgets..no autocompletion
63 // TODO : FULL READLINE COMPATIBILITY
64 // rl_attempted_completion_function = rad_autocompletion;
65 // char **rad_autocompletion(const char *text, int start, int end)
66 // return matches = rl_completion_matches (text, rad_offset_matches);
75 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
77 GetConsoleMode(h, &mode);
78 SetConsoleMode(h, 0); // RAW
79 ret = ReadConsole(h, buf,1, &out, NULL);
82 if (read(0,buf,1) == 1)
86 SetConsoleMode(h, mode);
88 int ret = read(0,buf,1);
98 static char *labels = NULL;
99 static unsigned int size = 0;
100 static unsigned int lsize = 0;
102 static int label_get(const char *name)
105 for(i=0;i<size;i++) {
106 if (!strcmp(name, labels+i+4)) {
107 memcpy(&n, labels+i, 4);
110 i+=strlen(labels+i+4)+4;
115 static void label_add (const char *str) {
116 unsigned int size = dl_histidx;
117 unsigned int len = strlen(str)-1;
119 //eprintf("New label(%s)\n",str);
120 memset(labels+lsize+4, '\0', BLOCK-((lsize+len+4)%BLOCK));
121 memcpy(labels+lsize, &size, 4);
122 memcpy(labels+lsize+4, str, len);
128 unsigned int i, p, n = 0;
129 for(i=0;i<lsize;i++,n++) {
130 memcpy(&p, labels+i, 4);
131 printf(" %03d %03d %s\n", i, p, labels+i+4);
132 i+=strlen(labels+i+4)+4;
136 static void label_reset()
143 static int is_label(const char *str)
150 if (str[strlen(str)-1]==':') {
162 int dl_hist_label(const char *label, void (*cb)(const char*))
166 /* labelling stuff */
168 if (!is_label(label+1))
171 switch(is_label(label)) {
178 i = label_get(label);
184 if (dl_history != NULL)
185 for(i=0; i<dl_histsize; i++) {
186 if (dl_history[i] == NULL)
188 fprintf(stderr, "%s\n", dl_history[i]);
191 else fprintf(stderr, "%s\n", dl_history[i]);
197 int dl_hist_add(const char *line)
199 #if HAVE_LIB_READLINE
202 if (dl_histidx>=dl_histsize)
203 dl_histidx = 0; // workaround
204 if (*line) { // && dl_histidx < dl_histsize) {
205 dl_history[dl_histidx++] = strdup(line);
215 strncpy(dl_buffer, dl_history[--dl_histidx], DL_BUFSIZE-1);
217 dl_buffer_len = strlen(dl_buffer);
226 if (dl_histidx<dl_histsize) {
227 if (dl_history[dl_histidx] == NULL) {
229 dl_buffer_idx = dl_buffer_len = 0;
232 strncpy(dl_buffer, dl_history[dl_histidx++], DL_BUFSIZE-1);
234 dl_buffer_len = strlen(dl_buffer);
244 if (dl_history != NULL)
245 for(i=0;i<dl_histsize; i++) {
246 if (dl_history[i] == NULL)
248 printf("%.3d %s\n", i, dl_history[i]);
257 if (dl_history != NULL)
258 for(i=0;i<dl_histsize; i++) {
260 dl_history[i] = NULL;
262 return dl_histidx=0, dl_histsize;
273 /* load history from file. if file == NULL load from ~/.<prg>.history or so */
274 int dl_hist_load(const char *file)
276 #if HAVE_LIB_READLINE
283 snprintf(buf, 1023, "%s/%s", get_home_directory(), file);
284 fd = fopen(buf, "r");
288 fgets(buf, 1023, fd);
290 buf[strlen(buf)-1]='\0';
292 fgets(buf, 1023, fd);
300 int dl_hist_save(const char *file)
302 #if HAVE_LIB_READLINE
303 rad_readline_finish();
309 snprintf(buf, 1023, "%s/%s", get_home_directory(), file);
310 fd = fopen(buf, "w");
313 for(i=0;i<dl_histidx;i++) {
314 fputs(dl_history[i], fd);
323 int dl_hist_chop(const char *file, int limit)
329 /* initialize history stuff */
332 #if HAVE_LIB_READLINE
336 labels = malloc(BLOCK);
337 dl_history = (char **)malloc(dl_histsize*sizeof(char *));
338 if (dl_history==NULL)
340 memset(dl_history, '\0', dl_histsize*sizeof(char *));
342 dl_histsize = DL_HISTSIZE;
352 unsigned char buf[10];
355 buf[0]=dl_readchar();
362 buf[0] = dl_readchar();
363 printf("unicode-%02x-%02x\n", buf[0],buf[1]);
365 case 8: // wtf is 127?
366 case 127: printf("backspace\n"); break;
367 case 32: printf("space\n"); break;
370 printf("esc-%02x-%02x-%02x-%02x\n",
371 buf[0],buf[1],buf[2],buf[3]);
373 case 12: printf("^L\n"); break;
374 case 13: printf("intro\n"); break;
375 case 18: printf("^R\n"); break;
376 case 9: printf("tab\n"); break;
377 case 3: printf("control-c\n"); break;
378 case 0: printf("control-space\n"); break;
380 printf("(code:%d)\n", buf[0]);
389 /* main readline function */
390 char *dl_readline(int argc, const char **argv)
395 int columns = cons_get_real_columns()-2;
397 dl_buffer_idx = dl_buffer_len = 0;
401 dl_echo = config.verbose;
406 fgets(dl_buffer, DL_BUFSIZE-1, stdin);
407 dl_buffer[strlen(dl_buffer)] = '\0';
408 return (*dl_buffer)? dl_buffer : NULL;
411 memset(&buf,0,sizeof buf);
415 printf("%s", dl_prompt);
428 for(i=1;i<argc;i++) {
429 if (dl_buffer_len==0||!strncmp(argv[i], dl_buffer, dl_buffer_len)) {
430 len+=strlen(argv[i])+1;
431 if (len+dl_buffer_len+4 >= columns) break;
432 printf("%s ", argv[i]);
440 dl_buffer[dl_buffer_len]='\0';
441 buf[0] = dl_readchar();
443 // printf("\x1b[K\r");
444 columns = cons_get_real_columns()-2;
448 printf("\r%*c\r", columns, ' ');
453 case 0: // control-space
460 dl_buffer_idx = dl_buffer_len;
465 dl_buffer[dl_buffer_idx = dl_buffer_len = 0] = '\0';
470 if (!dl_buffer[0]) { /* eof */
475 case 10: // ^J -- ignore
477 case 11: // ^K -- ignore
479 case 19: // ^S -- backspace
480 dl_buffer_idx = dl_buffer_idx?dl_buffer_idx-1:0;
482 case 12: // ^L -- right
483 dl_buffer_idx = dl_buffer_idx<dl_buffer_len?dl_buffer_idx+1:dl_buffer_len;
485 printf("\x1b[2J\x1b[0;0H");
489 dl_clipboard = strdup(dl_buffer);
495 if (dl_buffer_idx>0) {
496 for(i=dl_buffer_idx-1;i&&dl_buffer[i]==' ';i--);
497 for(;i&&dl_buffer[i]!=' ';i--);
498 for(;i>0&&dl_buffer[i]==' ';i--);
500 if (dl_buffer[i+1]==' ')
503 strcpy(dl_buffer+i, dl_buffer+dl_buffer_idx);
504 dl_buffer_len = strlen(dl_buffer);
508 case 25: // ^Y - paste
509 if (dl_clipboard != NULL) {
510 dl_buffer_len += strlen(dl_clipboard);
511 // TODO: support endless strings
512 if (dl_buffer_len < DL_BUFSIZE) {
513 dl_buffer_idx = dl_buffer_len;
514 strcat(dl_buffer, dl_clipboard);
515 } else dl_buffer_len -= strlen(dl_clipboard);
524 case 27: //esc-5b-41-00-00
525 buf[0] = dl_readchar();
526 buf[1] = dl_readchar();
530 if (dl_buffer_idx<dl_buffer_len)
531 strcpy(dl_buffer, dl_buffer+1);
541 dl_buffer_idx = dl_buffer_idx<dl_buffer_len?dl_buffer_idx+1:dl_buffer_len;
544 dl_buffer_idx = dl_buffer_idx?dl_buffer_idx-1:0;
552 if (dl_buffer_idx < dl_buffer_len) {
553 if (dl_buffer_idx>0) {
555 memcpy(dl_buffer+dl_buffer_idx, dl_buffer+dl_buffer_idx+1,strlen(dl_buffer+dl_buffer_idx));
558 dl_buffer_idx = --dl_buffer_len;
559 if (dl_buffer_len<0) dl_buffer_len=0;
560 dl_buffer[dl_buffer_len]='\0';
567 // XXX does not autocompletes correctly
568 // XXX needs to check if valid results have the same prefix (from 1 to N)
569 if (dl_callback != NULL) {
570 //const char *from = strrchr(dl_buffer, ' ');
571 //char **res = dl_callback(dl_buffer, (from==NULL)?dl_buffer_idx:from-dl_buffer, dl_buffer_len);
572 /* TODO: manage res */
575 for(i=1,opt=0;i<argc;i++)
576 if (!strncmp(argv[i], dl_buffer, dl_buffer_idx))
579 if (dl_buffer_len>0&&opt==1)
580 for(i=1;i<argc;i++) {
581 if (!strncmp(dl_buffer, argv[i], dl_buffer_len)) {
582 strcpy(dl_buffer, argv[i]);
583 dl_buffer_idx = dl_buffer_len = strlen(dl_buffer);
584 // TODO: if only 1 keyword hits:
585 // if (argv[i][dl_buffer_len]=='\0') {
586 // strcat(dl_buffer, " ");
594 if (dl_buffer_idx==0 || opt>1) {
596 printf("%s%s\n",dl_prompt,dl_buffer);
597 for(i=1;i<argc;i++) {
598 if (dl_buffer_len==0||!strncmp(argv[i], dl_buffer, dl_buffer_len)) {
599 len+=strlen(argv[i]);
600 // if (len+dl_buffer_len+4 >= columns) break;
602 printf("%s ", argv[i]);
612 // TODO: SUPPORT FOR ^R (search command in history)
618 for(i=1;i<argc;i++) {
619 if (dl_buffer_len==0 || !strncmp(argv[i], dl_buffer, dl_buffer_len)) {
620 printf("%*c", columns, ' ');
622 printf("\n\n(%s)\n\n", dl_buffer);
629 /* XXX use ^A & ^E */
630 if (dl_buffer_idx<dl_buffer_len) {
631 for(i = ++dl_buffer_len;i>dl_buffer_idx;i--)
632 dl_buffer[i] = dl_buffer[i-1];
633 dl_buffer[dl_buffer_idx] = buf[0];
635 dl_buffer[dl_buffer_len]=buf[0];
637 if (dl_buffer_len>1000)
639 dl_buffer[dl_buffer_len]='\0';
645 printf("\r%s%s", dl_prompt, dl_buffer);
646 printf("\r%s", dl_prompt);
648 for(i=0;i<dl_buffer_idx;i++)
649 printf("%c", dl_buffer[i]);
657 printf("\r%s%s\n", dl_prompt, dl_buffer);
661 if (dl_buffer[0]=='!' && dl_buffer[1]=='\0') {
673 static struct termios tio_old, tio_new;
677 #include <sys/ioctl.h>
678 #include <sys/wait.h>
679 #include <sys/socket.h>
682 static void cons_set_raw(int b)
686 tcgetattr(0, &tio_old);
687 memcpy ((char *)&tio_new, (char *)&tio_old, sizeof(struct termios));
688 tio_new.c_iflag &= ~(BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
689 tio_new.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
690 tio_new.c_cflag &= ~(CSIZE|PARENB);
691 tio_new.c_cflag |= CS8;
692 tio_new.c_cc[VMIN]=1; // Solaris stuff hehe
693 tcsetattr(0, TCSANOW, &tio_new);
698 tcsetattr(0, TCSANOW, &tio_old);
703 static int cons_get_real_columns()
710 if (ioctl(1, TIOCGWINSZ, &win)) {
719 int main(int argc, const char **argv)
730 ret = dl_readline(argc, argv);
732 printf(" [line] '%s'\n", ret);