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 */
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 */
34 MATCH_ANY
, /* anything else */
35 MATCH_MAX
/* number of elements in this enum */
39 ACTION_NONE
, /* ignore input */
40 ACTION_CHAR
, /* store character */
41 ACTION_DIGIT
/* store hex or octal digit */
45 enum state_type type
; /* current state type */
47 enum state_action action
; /* before going into next state */
48 enum state_type type
; /* next state */
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
) {
242 for (i
= 0; (pp
->argv
[i
] != NULL
); ++i
)
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
;
258 unsigned int word
: 1;
260 unsigned int last
: 1;
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
;
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
);
285 memset(&parsing
, 0, sizeof(parsing
));
287 for (s
= ph
->line
, i
= 0, j
= 0, k
= 0; (i
!= ph
->length
); ++i
) {
290 if ((cur
== TYPE_BSLASH
) || (cur
== TYPE_DQBSLASH
)) {
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
))) {
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
))) {
346 x
-= (((c
>> 6) & 0x01) * 7);
352 if (type
== TYPE_SPACE
) {
354 if (i
== p
->cursor
) {
356 if (type
== TYPE_SPACE
)
359 cursor
= parsing
.length
;
363 temp
[parsing
.length
] = parsing
.tmp
;
369 if (parsing
.length
> size_max
)
370 size_max
= parsing
.length
;
373 (sizeof(*argv
[argc
]) *
374 (parsing
.length
+ 1));
375 if (argv
[argc
] == NULL
)
377 memcpy(argv
[argc
], temp
,
379 argv
[argc
][parsing
.length
] = '\0';
380 args
[argc
] = parsing
.length
;
382 if (type
== TYPE_SPACE
)
383 argo
[argc
].len
= ((i
- 1) - k
);
385 argo
[argc
].len
= (i
- k
);
393 if ((i
== p
->cursor
) && (type
== TYPE_SPACE
))
397 argo
[argc
].pos
= p
->cursor
;
403 act
= prompt_parse_state
[cur
].next
[ma
].action
;
404 type
= prompt_parse_state
[cur
].next
[ma
].type
;
405 if (i
== p
->cursor
) {
407 if ((cur
== TYPE_SPACE
) && (type
== TYPE_SPACE
))
410 cursor
= parsing
.length
;
416 temp
[parsing
.length
] = parsing
.tmp
;
426 temp
[parsing
.length
] = parsing
.tmp
;
433 temp
[parsing
.length
] = c
;
441 if ((cur
== TYPE_SPACE
) && (type
!= TYPE_SPACE
)) {
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
) ||
454 ((temp
= malloc(sizeof(*temp
) * size_max
)) == NULL
))) {
475 for (i
= 0; (i
< argc
); ++i
)
484 void prompt_init(struct prompt
*p
)
486 memset(p
, 0, sizeof(*p
));
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 */
501 if (p
->entries
!= (sizeof(p
->history
) / sizeof(p
->history
[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]));
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))
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
);
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
))
544 ph
->line
[(ph
->length
++)] = c
;
548 /* insert character */
549 if (ph
->length
== sizeof(ph
->line
))
551 memmove(&ph
->line
[(p
->cursor
+ 1)], &ph
->line
[p
->cursor
],
552 (ph
->length
- p
->cursor
));
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
)
565 /* delete character at cursor */
566 memmove(&ph
->line
[p
->cursor
], &ph
->line
[(p
->cursor
+ 1)],
567 (ph
->length
- p
->cursor
));
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
];
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
)
584 dest
= &ph
->line
[pos
];
585 dest_len
= (ph
->length
- pos
);
586 dest_maxlen
= (sizeof(ph
->line
) - pos
);
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
);
597 memmove(&dest
[with_len
], &dest
[len
], dest_len
);
599 else if (with_len
< len
) {
600 unsigned int dec
= (len
- with_len
);
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
)
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
);
626 if (p
->cursor
!= ph
->length
)
630 void prompt_begin(struct prompt
*p
)
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
);
654 void prompt_backspace(struct prompt
*p
)
656 /* delete previous character */
657 if (p
->cursor
!= 0) {