import cbaos v0.1
[cbaos.git] / cbashell / cbashell.c
blob843b2732ed43c36494b1c73a821a0d7dcd254b10
1 /* Author: Domen Puncer <domen@cba.si>. License: WTFPL, see file LICENSE */
2 #include <stdio.h>
3 #include <string.h>
4 #include <compiler.h>
6 #include "command.h"
8 #define HIST_SIZE 5
9 #define LINE_LEN 64
10 static char history[HIST_SIZE][LINE_LEN+1]; /* circ buf of nul terminated strings should be more effective */
11 static int hist_len = 0;
12 static int hist_pos = -1;
14 static char line[LINE_LEN+1];
15 static int pos;
16 static int len;
18 enum vt100_key {
19 K_CTRL_C = 3,
20 K_CTRL_H = 8,
21 K_BACKSPACE = 8,
22 K_CTRL_U = '\x15',
23 K_ENTER = '\r',
24 K_ESCAPE = '\x1b',
25 K_BACKSPACE2 = '\x7f',
27 /* below are our made up values */
28 /* vt100 start */
29 K_VT100_START = 0x100,
30 K_UP,
31 K_DOWN,
32 K_RIGHT,
33 K_LEFT,
34 K_END,
35 K_HOME,
36 K_INSERT,
37 K_DELETE,
38 K_PGUP,
39 K_PGDN,
41 /* internal marks */
42 K_PARTIAL = 0xfff0,
43 K_INVALID,
46 struct vt100_seq {
47 enum vt100_key key;
48 const char *seq;
51 static const struct vt100_seq vt100_seqs[] = {
52 { .key = K_UP, .seq = "[A" },
53 { .key = K_DOWN, .seq = "[B" },
54 { .key = K_RIGHT, .seq = "[C" },
55 { .key = K_LEFT, .seq = "[D" },
56 { .key = K_END, .seq = "[F" },
57 { .key = K_HOME, .seq = "[H" },
58 { .key = K_INSERT, .seq = "[2~" },
59 { .key = K_DELETE, .seq = "[3~" },
60 { .key = K_PGUP, .seq = "[5~" },
61 { .key = K_PGDN, .seq = "[6~" },
65 static int vt100_cmp(const char *seq, int len, const char *ntseq)
67 int i;
68 for (i=0; i<len; i++)
69 if (seq[i] != ntseq[i])
70 return -1;
72 /* full match */
73 if (ntseq[i] == '\0')
74 return 0;
76 /* matched, but the sequence wasn't complete */
77 return 1;
80 #if 0
81 static const char *vt100_seq(enum vt100_key key)
83 int i;
84 for (i=0; i<ALEN(vt100_seqs); i++) {
85 if (vt100_seqs[i].key == key)
86 return vt100_seqs[i].seq;
88 return NULL;
90 #endif
92 static enum vt100_key vt100_match(const char *seq, int len)
94 int i;
96 for (i=0; i<ALEN(vt100_seqs); i++) {
97 int m;
98 m = vt100_cmp(seq, len, vt100_seqs[i].seq);
99 if (m == 0)
100 return vt100_seqs[i].key;
101 else if (m == 1)
102 return K_PARTIAL;
104 return K_INVALID;
108 static void cbashell_command(const char *cmd)
110 int i;
112 for (i=0; command_list[i]; i++)
113 if (command_list[i](cmd) != 0)
114 break;
119 * readline like prompt handling
120 * TODO history should be improved with a circ buf for string storage or sth,
121 * to be more effective.
123 static int cbashell_char(int c)
125 if (hist_pos >= 0 && !(c == K_UP || c == K_DOWN)) {
126 strcpy(line, history[hist_pos]);
127 hist_pos = -1;
130 if (c >= ' ' && c < '\x7f') {
131 /* guard against buffer overflow */
132 if (len >= LINE_LEN)
133 return 0;
135 memmove(&line[pos+1], &line[pos], len-pos);
136 line[pos++] = c;
137 len++;
139 line[len] = '\0';
140 if (pos < len) {
141 /* string (overwrites), move back x left */
142 printf("%s\x1b[%iD", &line[pos-1], len-pos);
143 } else {
144 printf("%c", c);
146 } else
147 if (c == K_ENTER) {
148 if (len == 0) {
149 strcpy(line, history[0]);
150 goto repeat_last;
153 int i;
154 if (hist_len >= HIST_SIZE)
155 hist_len = HIST_SIZE-1;
157 for (i=hist_len-1; i>=0; i--)
158 strcpy(history[i+1], history[i]);
159 strcpy(history[0], line);
160 hist_len++;
162 repeat_last:
163 printf("\n");
164 cbashell_command(line);
166 printf("> ");
168 len = pos = 0;
169 line[len] = '\0';
170 } else
171 if (c == K_BACKSPACE || c == K_BACKSPACE2) {
172 if (pos > 0) {
173 memmove(&line[pos-1], &line[pos], len-pos);
174 pos--;
175 len--;
177 if (pos < len) {
178 line[len] = '\0';
179 /* move left, clear line right, string, move x left */
180 printf("\x1b[D\x1b[K%s\x1b[%iD", &line[pos], len-pos);
181 } else {
182 printf("\x1b[D\x1b[K");
185 } else
186 if (c == K_DELETE) {
187 if (pos < len) {
188 memmove(&line[pos], &line[pos+1], len-pos-1);
189 len--;
191 line[len] = '\0';
192 if (pos < len) {
193 /* clear line right, string, move x left */
194 printf("\x1b[K%s\x1b[%iD", &line[pos], len-pos);
195 } else
196 printf("\x1b[K");
198 } else
199 if (c == K_CTRL_C) {
200 return -1;
201 } else
202 if (c == K_LEFT) {
203 if (pos > 0) {
204 pos--;
205 printf("\x1b[D"); /* left */
207 } else
208 if (c == K_RIGHT) {
209 if (pos < len) {
210 pos++;
211 printf("\x1b[C"); /* right */
213 } else
214 if (c == K_HOME) {
215 if (pos > 0) {
216 printf("\x1b[%iD", pos); /* left x */
217 pos = 0;
219 } else
220 if (c == K_END) {
221 if (pos < len) {
222 printf("\x1b[%iC", len-pos); /* right x */
223 pos = len;
225 } else
226 if (c == K_UP) {
227 if (hist_pos < hist_len-1) {
228 hist_pos++;
229 if (pos > 0)
230 printf("\x1b[%iD", pos); /* left x */
231 printf("\x1b[K%s", history[hist_pos]); /* clear line right, print history */
232 len = pos = strlen(history[hist_pos]);
234 } else
235 if (c == K_DOWN) {
236 if (hist_pos >= 0) {
237 const char *newline = line;
238 hist_pos--;
239 if (hist_pos >= 0)
240 newline = history[hist_pos];
241 if (pos > 0)
242 printf("\x1b[%iD", pos); /* left x */
243 printf("\x1b[K%s", newline); /* clear line right, print history */
244 len = pos = strlen(newline);
246 } else
247 if (c == K_CTRL_U) {
248 if (pos > 0)
249 printf("\x1b[%iD", pos); /* left x */
250 printf("\x1b[K"); /* clear line right */
251 len = pos = 0;
252 line[len] = '\0';
253 } else
254 if (c >= K_VT100_START) {
255 /* debugging print */
256 printf("vt100:%i ", c);
258 else {
259 printf("%02x ", c);
261 return 0;
264 /* partial VT100 parsing, see
265 * http://ascii-table.com/ansi-escape-sequences-vt-100.php
267 int cbashell_charraw(int c)
269 static int inside_esc;
270 static char esc[8];
271 static int esc_pos;
273 /* VT100 stuff */
274 if (inside_esc) {
275 /* just a silly guard */
276 if (esc_pos == sizeof(esc))
277 esc_pos = 0;
279 esc[esc_pos++] = c;
280 c = vt100_match(esc, esc_pos);
281 if (c == K_INVALID) {
282 int i;
283 int r = 0;
284 r |= cbashell_char('^');
285 r |= cbashell_char('[');
286 for (i=0; i<esc_pos; i++)
287 r |= cbashell_char(esc[i]);
289 inside_esc = 0;
290 return r;
291 } else
292 if (c == K_PARTIAL)
293 return 0;
295 inside_esc = 0;
296 return cbashell_char(c);
299 if (c == K_ESCAPE) {
300 inside_esc = 1;
301 esc_pos = 0;
302 return 0;
305 return cbashell_char(c);
308 void cbashell_init()
310 printf("> ");
312 len = pos = 0;
313 line[len] = '\0';
315 hist_len = 0;
316 hist_pos = -1;