Add VCS links
[debian-dgen.git] / sdl / prompt.c
blobc86b941e34810fb9509f961522aef6ab2753b418
1 #include <assert.h>
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include "prompt.h"
8 enum state_type {
9 TYPE_SPACE, /* between words */
10 TYPE_WORD, /* on a word */
11 TYPE_SQUOTE, /* on a word, between simple quotes */
12 TYPE_DQUOTE, /* on a word, between double quotes */
13 TYPE_BSLASH, /* after a backslash */
14 TYPE_BSLHEX1, /* \x, on the 1st hex digit */
15 TYPE_BSLHEX2, /* \x, on the 2nd hex digit */
16 TYPE_BSLOCT2, /* \[0-7], on the 2nd octal digit */
17 TYPE_BSLOCT3, /* \[0-7], on the 3rd octal digit */
18 TYPE_DQBSLASH, /* between ", after a backslash */
19 TYPE_DQBSLHEX1, /* between ", \x, on the 1st hex digit */
20 TYPE_DQBSLHEX2, /* between ", \x, on the 2nd hex digit */
21 TYPE_DQBSLOCT2, /* between ", \[0-7], on the 2nd octal digit */
22 TYPE_DQBSLOCT3, /* between ", \[0-7], on the 3rd octal digit */
23 TYPE_MAX /* number of elements in this enum */
26 enum state_match {
27 MATCH_SPACE, /* a space */
28 MATCH_SQUOTE, /* a simple quote */
29 MATCH_DQUOTE, /* a double quote */
30 MATCH_BSLASH, /* a backslash */
31 MATCH_HEX, /* a hex digit */
32 MATCH_OCT, /* an octal digit */
33 MATCH_x, /* an 'x' */
34 MATCH_ANY, /* anything else */
35 MATCH_MAX /* number of elements in this enum */
38 enum state_action {
39 ACTION_NONE, /* ignore input */
40 ACTION_CHAR, /* store character */
41 ACTION_DIGIT /* store hex or octal digit */
44 struct state {
45 enum state_type type; /* current state type */
46 struct {
47 enum state_action action; /* before going into next state */
48 enum state_type type; /* next state */
49 } next[MATCH_MAX];
52 static const struct state prompt_parse_state[TYPE_MAX] = {
54 TYPE_SPACE, /* between words */
56 { ACTION_NONE, TYPE_SPACE }, /* MATCH_SPACE */
57 { ACTION_NONE, TYPE_SQUOTE }, /* MATCH_SQUOTE */
58 { ACTION_NONE, TYPE_DQUOTE }, /* MATCH_DQUOTE */
59 { ACTION_NONE, TYPE_BSLASH }, /* MATCH_BSLASH */
60 { ACTION_CHAR, TYPE_WORD }, /* MATCH_HEX */
61 { ACTION_CHAR, TYPE_WORD }, /* MATCH_OCT */
62 { ACTION_CHAR, TYPE_WORD }, /* MATCH_x */
63 { ACTION_CHAR, TYPE_WORD } /* MATCH_ANY */
67 TYPE_WORD, /* on a word */
69 { ACTION_NONE, TYPE_SPACE }, /* MATCH_SPACE */
70 { ACTION_NONE, TYPE_SQUOTE }, /* MATCH_SQUOTE */
71 { ACTION_NONE, TYPE_DQUOTE }, /* MATCH_DQUOTE */
72 { ACTION_NONE, TYPE_BSLASH }, /* MATCH_BSLASH */
73 { ACTION_CHAR, TYPE_WORD }, /* MATCH_HEX */
74 { ACTION_CHAR, TYPE_WORD }, /* MATCH_OCT */
75 { ACTION_CHAR, TYPE_WORD }, /* MATCH_x */
76 { ACTION_CHAR, TYPE_WORD } /* MATCH_ANY */
80 TYPE_SQUOTE, /* on a word, between simple quotes */
82 { ACTION_CHAR, TYPE_SQUOTE }, /* MATCH_SPACE */
83 { ACTION_NONE, TYPE_WORD }, /* MATCH_SQUOTE */
84 { ACTION_CHAR, TYPE_SQUOTE }, /* MATCH_DQUOTE */
85 { ACTION_CHAR, TYPE_SQUOTE }, /* MATCH_BSLASH */
86 { ACTION_CHAR, TYPE_SQUOTE }, /* MATCH_HEX */
87 { ACTION_CHAR, TYPE_SQUOTE }, /* MATCH_OCT */
88 { ACTION_CHAR, TYPE_SQUOTE }, /* MATCH_x */
89 { ACTION_CHAR, TYPE_SQUOTE } /* MATCH_ANY */
93 TYPE_DQUOTE, /* on a word, between double quotes */
95 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SPACE */
96 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SQUOTE */
97 { ACTION_NONE, TYPE_WORD }, /* MATCH_DQUOTE */
98 { ACTION_NONE, TYPE_DQBSLASH }, /* MATCH_BSLASH */
99 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_HEX */
100 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_OCT */
101 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_x */
102 { ACTION_CHAR, TYPE_DQUOTE } /* MATCH_ANY */
106 TYPE_BSLASH, /* after a backslash */
108 { ACTION_CHAR, TYPE_WORD }, /* MATCH_SPACE */
109 { ACTION_CHAR, TYPE_WORD }, /* MATCH_SQUOTE */
110 { ACTION_CHAR, TYPE_WORD }, /* MATCH_DQUOTE */
111 { ACTION_CHAR, TYPE_WORD }, /* MATCH_BSLASH */
112 { ACTION_CHAR, TYPE_WORD }, /* MATCH_HEX */
113 { ACTION_DIGIT, TYPE_BSLOCT2 }, /* MATCH_OCT */
114 { ACTION_NONE, TYPE_BSLHEX1 }, /* MATCH_x */
115 { ACTION_CHAR, TYPE_WORD } /* MATCH_ANY */
119 TYPE_BSLHEX1, /* \x, on the first hex digit */
121 { ACTION_NONE, TYPE_SPACE }, /* MATCH_SPACE */
122 { ACTION_NONE, TYPE_SQUOTE }, /* MATCH_SQUOTE */
123 { ACTION_NONE, TYPE_DQUOTE }, /* MATCH_DQUOTE */
124 { ACTION_NONE, TYPE_BSLASH }, /* MATCH_BSLASH */
125 { ACTION_DIGIT, TYPE_BSLHEX2 }, /* MATCH_HEX */
126 { ACTION_DIGIT, TYPE_BSLHEX2 }, /* MATCH_OCT */
127 { ACTION_CHAR, TYPE_WORD }, /* MATCH_x */
128 { ACTION_CHAR, TYPE_WORD } /* MATCH_ANY */
132 TYPE_BSLHEX2, /* \x, on the second hex digit */
134 { ACTION_NONE, TYPE_SPACE }, /* MATCH_SPACE */
135 { ACTION_NONE, TYPE_SQUOTE }, /* MATCH_SQUOTE */
136 { ACTION_NONE, TYPE_DQUOTE }, /* MATCH_DQUOTE */
137 { ACTION_NONE, TYPE_BSLASH }, /* MATCH_BSLASH */
138 { ACTION_DIGIT, TYPE_WORD }, /* MATCH_HEX */
139 { ACTION_DIGIT, TYPE_WORD }, /* MATCH_OCT */
140 { ACTION_CHAR, TYPE_WORD }, /* MATCH_x */
141 { ACTION_CHAR, TYPE_WORD } /* MATCH_ANY */
145 TYPE_BSLOCT2, /* \, on the second octal digit */
147 { ACTION_NONE, TYPE_SPACE }, /* MATCH_SPACE */
148 { ACTION_NONE, TYPE_SQUOTE }, /* MATCH_SQUOTE */
149 { ACTION_NONE, TYPE_DQUOTE }, /* MATCH_DQUOTE */
150 { ACTION_NONE, TYPE_BSLASH }, /* MATCH_BSLASH */
151 { ACTION_CHAR, TYPE_WORD }, /* MATCH_HEX */
152 { ACTION_DIGIT, TYPE_BSLOCT3 }, /* MATCH_OCT */
153 { ACTION_CHAR, TYPE_WORD }, /* MATCH_x */
154 { ACTION_CHAR, TYPE_WORD } /* MATCH_ANY */
158 TYPE_BSLOCT3, /* \, on the third octal digit */
160 { ACTION_NONE, TYPE_SPACE }, /* MATCH_SPACE */
161 { ACTION_NONE, TYPE_SQUOTE }, /* MATCH_SQUOTE */
162 { ACTION_NONE, TYPE_DQUOTE }, /* MATCH_DQUOTE */
163 { ACTION_NONE, TYPE_BSLASH }, /* MATCH_BSLASH */
164 { ACTION_CHAR, TYPE_WORD }, /* MATCH_HEX */
165 { ACTION_DIGIT, TYPE_WORD }, /* MATCH_OCT */
166 { ACTION_CHAR, TYPE_WORD }, /* MATCH_x */
167 { ACTION_CHAR, TYPE_WORD } /* MATCH_ANY */
171 TYPE_DQBSLASH, /* between ", after a backslash */
173 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SPACE */
174 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SQUOTE */
175 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_DQUOTE */
176 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_BSLASH */
177 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_HEX */
178 { ACTION_DIGIT, TYPE_DQBSLOCT2 }, /* MATCH_OCT */
179 { ACTION_NONE, TYPE_DQBSLHEX1 }, /* MATCH_x */
180 { ACTION_CHAR, TYPE_DQUOTE } /* MATCH_ANY */
184 TYPE_DQBSLHEX1, /* between ", \x, on the 1st hex digit */
186 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SPACE */
187 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SQUOTE */
188 { ACTION_NONE, TYPE_WORD }, /* MATCH_DQUOTE */
189 { ACTION_NONE, TYPE_DQBSLASH }, /* MATCH_BSLASH */
190 { ACTION_DIGIT, TYPE_DQBSLHEX2 }, /* MATCH_HEX */
191 { ACTION_DIGIT, TYPE_DQBSLHEX2 }, /* MATCH_OCT */
192 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_x */
193 { ACTION_CHAR, TYPE_DQUOTE } /* MATCH_ANY */
197 TYPE_DQBSLHEX2, /* between ", \x, on the 2nd hex digit */
199 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SPACE */
200 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SQUOTE */
201 { ACTION_NONE, TYPE_WORD }, /* MATCH_DQUOTE */
202 { ACTION_NONE, TYPE_DQBSLASH }, /* MATCH_BSLASH */
203 { ACTION_DIGIT, TYPE_DQUOTE }, /* MATCH_HEX */
204 { ACTION_DIGIT, TYPE_DQUOTE }, /* MATCH_OCT */
205 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_x */
206 { ACTION_CHAR, TYPE_DQUOTE } /* MATCH_ANY */
210 TYPE_DQBSLOCT2, /* between ", \[0-7], on the 2nd octal digit */
212 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SPACE */
213 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SQUOTE */
214 { ACTION_NONE, TYPE_WORD }, /* MATCH_DQUOTE */
215 { ACTION_NONE, TYPE_DQBSLASH }, /* MATCH_BSLASH */
216 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_HEX */
217 { ACTION_DIGIT, TYPE_BSLOCT3 }, /* MATCH_OCT */
218 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_x */
219 { ACTION_CHAR, TYPE_DQUOTE } /* MATCH_ANY */
223 TYPE_DQBSLOCT3, /* between ", \[0-7], on the 3rd octal digit */
225 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SPACE */
226 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_SQUOTE */
227 { ACTION_NONE, TYPE_WORD }, /* MATCH_DQUOTE */
228 { ACTION_NONE, TYPE_DQBSLASH }, /* MATCH_BSLASH */
229 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_HEX */
230 { ACTION_DIGIT, TYPE_DQUOTE }, /* MATCH_OCT */
231 { ACTION_CHAR, TYPE_DQUOTE }, /* MATCH_x */
232 { ACTION_CHAR, TYPE_DQUOTE } /* MATCH_ANY */
237 void prompt_parse_clean(struct prompt_parse *pp)
239 if (pp->argv != NULL) {
240 unsigned int i;
242 for (i = 0; (pp->argv[i] != NULL); ++i)
243 free(pp->argv[i]);
244 free(pp->argv);
246 free(pp->args);
247 free(pp->argo);
248 memset(pp, 0, sizeof(*pp));
251 struct prompt_parse *prompt_parse(struct prompt *p, struct prompt_parse *pp)
253 struct prompt_history *ph = &p->history[p->current];
254 enum state_type type;
255 struct {
256 unsigned int length;
257 uint8_t tmp;
258 unsigned int word: 1;
259 unsigned int num: 1;
260 unsigned int last: 1;
261 } parsing;
262 uint8_t *s;
263 unsigned int i;
264 unsigned int j;
265 unsigned int k;
266 unsigned int argc;
267 unsigned int index;
268 unsigned int cursor;
269 enum state_action act;
270 uint8_t **argv = NULL;
271 unsigned int *args = NULL;
272 struct prompt_parse_argo *argo = NULL;
273 uint8_t *temp = NULL;
274 size_t size_max = 0;
275 uint8_t c = '\0';
276 enum state_type cur = TYPE_SPACE;
277 enum state_match ma = MATCH_SPACE;
279 assert(ph->length <= sizeof(ph->line));
280 assert(p->cursor <= ph->length);
281 argv_ok:
282 argc = 0;
283 index = 0;
284 cursor = ~0u;
285 memset(&parsing, 0, sizeof(parsing));
286 type = TYPE_SPACE;
287 for (s = ph->line, i = 0, j = 0, k = 0; (i != ph->length); ++i) {
288 cur = type;
289 c = s[i];
290 if ((cur == TYPE_BSLASH) || (cur == TYPE_DQBSLASH)) {
291 switch (c) {
292 case 'a':
293 c = '\a';
294 break;
295 case 'b':
296 c = '\b';
297 break;
298 case 'f':
299 c = '\f';
300 break;
301 case 'n':
302 c = '\n';
303 break;
304 case 'r':
305 c = '\r';
306 break;
307 case 't':
308 c = '\t';
309 break;
310 case 'v':
311 c = '\v';
312 break;
315 if (c == '\'')
316 ma = MATCH_SQUOTE;
317 else if (c == '"')
318 ma = MATCH_DQUOTE;
319 else if (c == '\\')
320 ma = MATCH_BSLASH;
321 else if (c == 'x')
322 ma = MATCH_x;
323 else if (isspace(c))
324 ma = MATCH_SPACE;
325 else if ((c >= '0') && (c <= '7') &&
326 ((cur == TYPE_BSLASH) ||
327 (cur == TYPE_BSLOCT2) ||
328 (cur == TYPE_BSLOCT3) ||
329 (cur == TYPE_DQBSLASH) ||
330 (cur == TYPE_DQBSLOCT2) ||
331 (cur == TYPE_DQBSLOCT3))) {
332 ma = MATCH_OCT;
333 parsing.tmp *= 8;
334 parsing.tmp += (c - '0');
336 else if ((isxdigit(c)) &&
337 ((cur == TYPE_BSLHEX1) ||
338 (cur == TYPE_BSLHEX2) ||
339 (cur == TYPE_DQBSLHEX1) ||
340 (cur == TYPE_DQBSLHEX2))) {
341 uint8_t x = c;
343 ma = MATCH_HEX;
344 parsing.tmp *= 16;
345 x &= 0xcf;
346 x -= (((c >> 6) & 0x01) * 7);
347 x &= 0x0f;
348 parsing.tmp += x;
350 else
351 ma = MATCH_ANY;
352 if (type == TYPE_SPACE) {
353 last:
354 if (i == p->cursor) {
355 index = argc;
356 if (type == TYPE_SPACE)
357 cursor = ~0u;
358 else
359 cursor = parsing.length;
361 if (parsing.num) {
362 if (temp != NULL)
363 temp[parsing.length] = parsing.tmp;
364 ++(parsing.length);
365 parsing.num = 0;
366 parsing.tmp = 0;
368 if (parsing.word) {
369 if (parsing.length > size_max)
370 size_max = parsing.length;
371 if (temp != NULL) {
372 argv[argc] = malloc
373 (sizeof(*argv[argc]) *
374 (parsing.length + 1));
375 if (argv[argc] == NULL)
376 goto fail;
377 memcpy(argv[argc], temp,
378 parsing.length);
379 argv[argc][parsing.length] = '\0';
380 args[argc] = parsing.length;
381 argo[argc].pos = k;
382 if (type == TYPE_SPACE)
383 argo[argc].len = ((i - 1) - k);
384 else
385 argo[argc].len = (i - k);
387 ++argc;
388 parsing.length = 0;
389 parsing.word = 0;
390 parsing.num = 0;
391 parsing.tmp = 0;
393 if ((i == p->cursor) && (type == TYPE_SPACE))
394 index = argc;
395 if (parsing.last) {
396 if (temp != NULL) {
397 argo[argc].pos = p->cursor;
398 argo[argc].len = 0;
400 goto end;
403 act = prompt_parse_state[cur].next[ma].action;
404 type = prompt_parse_state[cur].next[ma].type;
405 if (i == p->cursor) {
406 index = argc;
407 if ((cur == TYPE_SPACE) && (type == TYPE_SPACE))
408 cursor = ~0u;
409 else
410 cursor = parsing.length;
412 switch (act) {
413 case ACTION_NONE:
414 if (parsing.num) {
415 if (temp != NULL)
416 temp[parsing.length] = parsing.tmp;
417 ++(parsing.length);
418 ++j;
419 parsing.num = 0;
420 parsing.tmp = 0;
422 break;
423 case ACTION_CHAR:
424 if (parsing.num) {
425 if (temp != NULL)
426 temp[parsing.length] = parsing.tmp;
427 ++(parsing.length);
428 ++j;
429 parsing.num = 0;
430 parsing.tmp = 0;
432 if (temp != NULL)
433 temp[parsing.length] = c;
434 ++(parsing.length);
435 ++j;
436 break;
437 case ACTION_DIGIT:
438 parsing.num = 1;
439 break;
441 if ((cur == TYPE_SPACE) && (type != TYPE_SPACE)) {
442 k = i;
443 parsing.word = 1;
446 parsing.last = 1;
447 goto last;
448 end:
449 if (argv == NULL) {
450 if (((argv = malloc(sizeof(*argv) * (argc + 1))) == NULL) ||
451 ((args = malloc(sizeof(*args) * (argc + 1))) == NULL) ||
452 ((argo = malloc(sizeof(*argo) * (argc + 1))) == NULL) ||
453 ((size_max != 0) &&
454 ((temp = malloc(sizeof(*temp) * size_max)) == NULL))) {
455 argc = 0;
456 goto fail;
458 argv[argc] = NULL;
459 args[argc] = 0;
460 argo[argc].pos = 0;
461 argo[argc].len = 0;
462 goto argv_ok;
464 free(temp);
465 pp->index = index;
466 pp->cursor = cursor;
467 pp->argc = argc;
468 pp->argv = argv;
469 pp->args = args;
470 pp->argo = argo;
471 return pp;
472 fail:
473 free(temp);
474 if (argv != NULL) {
475 for (i = 0; (i < argc); ++i)
476 free(argv[i]);
477 free(argv);
479 free(args);
480 free(argo);
481 return NULL;
484 void prompt_init(struct prompt *p)
486 memset(p, 0, sizeof(*p));
487 p->entries = 1;
490 void prompt_push(struct prompt *p)
492 struct prompt_history *ph = &p->history[p->current];
494 assert(ph->length <= sizeof(ph->line));
495 assert(p->cursor <= ph->length);
496 assert(p->entries <= (sizeof(p->history) / sizeof(p->history[0])));
497 assert(p->current < p->entries);
498 /* don't keep empty strings */
499 if (ph->length == 0)
500 return;
501 if (p->entries != (sizeof(p->history) / sizeof(p->history[0])))
502 ++(p->entries);
503 if (p->current != 0)
504 p->history[0] = p->history[p->current];
505 memmove(&p->history[1], &p->history[0],
506 (sizeof(p->history[0]) * (p->entries - 1)));
507 memset(&p->history[0], 0, sizeof(p->history[0]));
508 p->cursor = 0;
509 p->current = 0;
512 void prompt_older(struct prompt *p)
514 assert(p->entries <= (sizeof(p->history) / sizeof(p->history[0])));
515 assert(p->current < p->entries);
516 if (p->current == (p->entries - 1))
517 return;
518 ++(p->current);
519 p->cursor = p->history[p->current].length;
520 assert(p->cursor <= sizeof(p->history[p->current].line));
523 void prompt_newer(struct prompt *p)
525 assert(p->entries <= (sizeof(p->history) / sizeof(p->history[0])));
526 assert(p->current < p->entries);
527 if (p->current == 0)
528 return;
529 --(p->current);
530 p->cursor = p->history[p->current].length;
531 assert(p->cursor <= sizeof(p->history[p->current].line));
534 void prompt_put(struct prompt *p, uint8_t c)
536 struct prompt_history *ph = &p->history[p->current];
538 assert(ph->length <= sizeof(ph->line));
539 assert(p->cursor <= ph->length);
540 if (p->cursor == ph->length) {
541 /* append character */
542 if (ph->length == sizeof(ph->line))
543 return;
544 ph->line[(ph->length++)] = c;
545 ++(p->cursor);
546 return;
548 /* insert character */
549 if (ph->length == sizeof(ph->line))
550 --(ph->length);
551 memmove(&ph->line[(p->cursor + 1)], &ph->line[p->cursor],
552 (ph->length - p->cursor));
553 ++(ph->length);
554 ph->line[(p->cursor++)] = c;
557 void prompt_delete(struct prompt *p)
559 struct prompt_history *ph = &p->history[p->current];
561 assert(ph->length <= sizeof(ph->line));
562 assert(p->cursor <= ph->length);
563 if (p->cursor == ph->length)
564 return;
565 /* delete character at cursor */
566 memmove(&ph->line[p->cursor], &ph->line[(p->cursor + 1)],
567 (ph->length - p->cursor));
568 --(ph->length);
571 void prompt_replace(struct prompt *p, unsigned int pos,
572 unsigned int len, const uint8_t *with,
573 unsigned int with_len)
575 struct prompt_history *ph = &p->history[p->current];
576 uint8_t *dest;
577 unsigned int dest_len;
578 unsigned int dest_maxlen;
580 assert(ph->length <= sizeof(ph->line));
581 assert(p->cursor <= ph->length);
582 if (pos > ph->length)
583 return;
584 dest = &ph->line[pos];
585 dest_len = (ph->length - pos);
586 dest_maxlen = (sizeof(ph->line) - pos);
587 if (len > dest_len)
588 len = dest_len;
589 if (with_len > dest_maxlen)
590 with_len = dest_maxlen;
591 if (with_len > len) {
592 unsigned int inc = (with_len - len);
594 if ((dest_len + inc) > dest_maxlen)
595 dest_len = (dest_maxlen - inc);
596 ph->length += inc;
597 memmove(&dest[with_len], &dest[len], dest_len);
599 else if (with_len < len) {
600 unsigned int dec = (len - with_len);
602 ph->length -= dec;
603 memmove(&dest[with_len], &dest[len], dest_len);
605 memcpy(dest, with, with_len);
606 if (p->cursor > ph->length)
607 p->cursor = ph->length;
608 assert(ph->length <= sizeof(ph->line));
609 assert(p->cursor <= ph->length);
612 void prompt_left(struct prompt *p)
614 /* move left */
615 if (p->cursor != 0)
616 --(p->cursor);
619 void prompt_right(struct prompt *p)
621 struct prompt_history *ph = &p->history[p->current];
623 assert(ph->length <= sizeof(ph->line));
624 assert(p->cursor <= ph->length);
625 /* move right */
626 if (p->cursor != ph->length)
627 ++(p->cursor);
630 void prompt_begin(struct prompt *p)
632 p->cursor = 0;
635 void prompt_end(struct prompt *p)
637 struct prompt_history *ph = &p->history[p->current];
639 assert(ph->length <= sizeof(ph->line));
640 assert(p->cursor <= ph->length);
641 p->cursor = ph->length;
644 void prompt_clear(struct prompt *p)
646 struct prompt_history *ph = &p->history[p->current];
648 assert(ph->length <= sizeof(ph->line));
649 assert(p->cursor <= ph->length);
650 ph->length = 0;
651 p->cursor = 0;
654 void prompt_backspace(struct prompt *p)
656 /* delete previous character */
657 if (p->cursor != 0) {
658 prompt_left(p);
659 prompt_delete(p);