Release notes for v0.8.
[shell-fm.git] / source / readline.c
blob17b529af86444a79f2d0860e895ec39dcbbd611a
1 /*
2 Copyright (C) 2006-2010 by Jonas Kramer
3 Published under the terms of the GNU General Public License (GPL).
4 */
6 #define _GNU_SOURCE
8 #include <stdio.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include <termios.h>
12 #include <assert.h>
14 #include "readline.h"
15 #include "interface.h"
17 static void delete(unsigned);
19 char * readline(struct prompt * setup) {
20 int eoln = 0, seq = 0, histsize = 0, index = -1, changed = !0;
21 static char line[1024];
22 unsigned length = 0;
24 assert(setup != NULL);
26 /* Print prompt if present. */
27 if(setup->prompt)
28 fputs(setup->prompt, stderr);
30 /* Initialize line (empty or with preset text if given). */
31 memset(line, 0, sizeof(line));
32 if(setup->line) {
33 strncpy(line, setup->line, sizeof(line) - 1);
34 length = strlen(line);
35 fputs(line, stderr);
38 /* Count items in history. */
39 for(histsize = 0; setup->history && setup->history[histsize]; ++histsize);
40 index = histsize;
42 while(!eoln) {
43 int key = fgetc(stdin);
45 switch(key) {
46 case 8: /* Backspace. */
47 case 127: /* Delete. */
48 /* We don't support moving the cursor from the end of the line
49 * so handle these the same. */
50 if(length > 0) {
51 delete(1);
52 line[--length] = 0;
53 changed = !0;
55 break;
57 case 9: /* Tab. */
58 /* Call the callback function for completion if present. */
59 if(setup->callback != NULL) {
60 if(setup->callback(line, sizeof(line), changed)) {
61 delete(length);
62 length = strlen(line);
63 memset(line + length, 0, sizeof(line) - length);
64 fprintf(stderr, "\r%s%s", setup->prompt, line);
66 changed = 0;
68 break;
70 case 4: /* EOF (^D) */
71 case 10: /* Line break. */
72 case 13: /* Carriage return (who knows...) */
73 eoln = !0;
74 break;
76 case 21: /* ^U */
77 delete(length);
78 length = 0;
79 break;
81 case 23: /* ^W */
82 if(length > 0) {
83 int alpha = isalpha(line[length - 1]);
84 while(length > 0 && isalpha(line[length - 1]) == alpha) {
85 line[--length] = 0;
86 delete(1);
88 changed = !0;
91 break;
93 case 27: /* Escape. */
94 ++seq;
95 changed = !0;
96 break;
98 default:
99 changed = !0;
100 if(seq > 0) {
101 if(seq < 2)
102 ++seq;
103 else {
104 seq = 0;
105 switch(key) {
106 case 65: /* Up. */
107 case 66: /* Down. */
108 if(histsize) {
109 if(key == 66 && index < histsize - 1)
110 ++index;
112 if(key == 65 && index > -1)
113 --index;
115 delete(length);
116 memset(line, 0, length);
117 length = 0;
119 if(index > -1 && index < histsize) {
120 strncpy(
121 line,
122 setup->history[index],
123 sizeof(line) - 1
126 length = strlen(line);
127 fputs(line, stderr);
131 break;
135 else {
136 if(length < sizeof(line)) {
137 line[length++] = key;
138 fputc(key, stderr);
144 fputc(10, stderr);
146 return line;
149 void canon(int enable) {
150 struct termios term;
151 tcgetattr(fileno(stdin), & term);
153 term.c_lflag = enable
154 ? term.c_lflag | ICANON | ECHO
155 : term.c_lflag & ~(ICANON | ECHO);
157 tcsetattr(fileno(stdin), TCSANOW, & term);
160 static void delete(unsigned n) {
161 while(n--)
162 fputs("\b \b", stderr);