Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #include <assert.h>
  2. #include <ctype.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include "prompt.h"
  7.  
  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 */
  24. };
  25.  
  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 */
  36. };
  37.  
  38. enum state_action {
  39.         ACTION_NONE, /* ignore input */
  40.         ACTION_CHAR, /* store character */
  41.         ACTION_DIGIT /* store hex or octal digit */
  42. };
  43.  
  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];
  50. };
  51.  
  52. static const struct state prompt_parse_state[TYPE_MAX] = {
  53.         {
  54.                 TYPE_SPACE, /* between words */
  55.                 {
  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 */
  64.                 }
  65.         },
  66.         {
  67.                 TYPE_WORD, /* on a word */
  68.                 {
  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 */
  77.                 }
  78.         },
  79.         {
  80.                 TYPE_SQUOTE, /* on a word, between simple quotes */
  81.                 {
  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 */
  90.                 }
  91.         },
  92.         {
  93.                 TYPE_DQUOTE, /* on a word, between double quotes */
  94.                 {
  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 */
  103.                 }
  104.         },
  105.         {
  106.                 TYPE_BSLASH, /* after a backslash */
  107.                 {
  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 */
  116.                 }
  117.         },
  118.         {
  119.                 TYPE_BSLHEX1, /* \x, on the first hex digit */
  120.                 {
  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 */
  129.                 }
  130.         },
  131.         {
  132.                 TYPE_BSLHEX2, /* \x, on the second hex digit */
  133.                 {
  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 */
  142.                 }
  143.         },
  144.         {
  145.                 TYPE_BSLOCT2, /* \, on the second octal digit */
  146.                 {
  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 */
  155.                 }
  156.         },
  157.         {
  158.                 TYPE_BSLOCT3, /* \, on the third octal digit */
  159.                 {
  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 */
  168.                 }
  169.         },
  170.         {
  171.                 TYPE_DQBSLASH, /* between ", after a backslash */
  172.                 {
  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 */
  181.                 }
  182.         },
  183.         {
  184.                 TYPE_DQBSLHEX1, /* between ", \x, on the 1st hex digit */
  185.                 {
  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 */
  194.                 }
  195.         },
  196.         {
  197.                 TYPE_DQBSLHEX2, /* between ", \x, on the 2nd hex digit */
  198.                 {
  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 */
  207.                 }
  208.         },
  209.         {
  210.                 TYPE_DQBSLOCT2, /* between ", \[0-7], on the 2nd octal digit */
  211.                 {
  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 */
  220.                 }
  221.         },
  222.         {
  223.                 TYPE_DQBSLOCT3, /* between ", \[0-7], on the 3rd octal digit */
  224.                 {
  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 */
  233.                 }
  234.         }
  235. };
  236.  
  237. void prompt_parse_clean(struct prompt_parse *pp)
  238. {
  239.         if (pp->argv != NULL) {
  240.                 unsigned int i;
  241.  
  242.                 for (i = 0; (pp->argv[i] != NULL); ++i)
  243.                         free(pp->argv[i]);
  244.                 free(pp->argv);
  245.         }
  246.         free(pp->args);
  247.         free(pp->argo);
  248.         memset(pp, 0, sizeof(*pp));
  249. }
  250.  
  251. struct prompt_parse *prompt_parse(struct prompt *p, struct prompt_parse *pp)
  252. {
  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;
  278.  
  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;
  313.                         }
  314.                 }
  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');
  335.                 }
  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;
  342.  
  343.                         ma = MATCH_HEX;
  344.                         parsing.tmp *= 16;
  345.                         x &= 0xcf;
  346.                         x -= (((c >> 6) & 0x01) * 7);
  347.                         x &= 0x0f;
  348.                         parsing.tmp += x;
  349.                 }
  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;
  360.                         }
  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;
  367.                         }
  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);
  386.                                 }
  387.                                 ++argc;
  388.                                 parsing.length = 0;
  389.                                 parsing.word = 0;
  390.                                 parsing.num = 0;
  391.                                 parsing.tmp = 0;
  392.                         }
  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;
  399.                                 }
  400.                                 goto end;
  401.                         }
  402.                 }
  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;
  411.                 }
  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;
  421.                         }
  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;
  431.                         }
  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;
  440.                 }
  441.                 if ((cur == TYPE_SPACE) && (type != TYPE_SPACE)) {
  442.                         k = i;
  443.                         parsing.word = 1;
  444.                 }
  445.         }
  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;
  457.                 }
  458.                 argv[argc] = NULL;
  459.                 args[argc] = 0;
  460.                 argo[argc].pos = 0;
  461.                 argo[argc].len = 0;
  462.                 goto argv_ok;
  463.         }
  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);
  478.         }
  479.         free(args);
  480.         free(argo);
  481.         return NULL;
  482. }
  483.  
  484. void prompt_init(struct prompt *p)
  485. {
  486.         memset(p, 0, sizeof(*p));
  487.         p->entries = 1;
  488. }
  489.  
  490. void prompt_push(struct prompt *p)
  491. {
  492.         struct prompt_history *ph = &p->history[p->current];
  493.  
  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;
  510. }
  511.  
  512. void prompt_older(struct prompt *p)
  513. {
  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));
  521. }
  522.  
  523. void prompt_newer(struct prompt *p)
  524. {
  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));
  532. }
  533.  
  534. void prompt_put(struct prompt *p, uint8_t c)
  535. {
  536.         struct prompt_history *ph = &p->history[p->current];
  537.  
  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;
  547.         }
  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;
  555. }
  556.  
  557. void prompt_delete(struct prompt *p)
  558. {
  559.         struct prompt_history *ph = &p->history[p->current];
  560.  
  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);
  569. }
  570.  
  571. void prompt_replace(struct prompt *p, unsigned int pos,
  572.                     unsigned int len, const uint8_t *with,
  573.                     unsigned int with_len)
  574. {
  575.         struct prompt_history *ph = &p->history[p->current];
  576.         uint8_t *dest;
  577.         unsigned int dest_len;
  578.         unsigned int dest_maxlen;
  579.  
  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);
  593.  
  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);
  598.         }
  599.         else if (with_len < len) {
  600.                 unsigned int dec = (len - with_len);
  601.  
  602.                 ph->length -= dec;
  603.                 memmove(&dest[with_len], &dest[len], dest_len);
  604.         }
  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);
  610. }
  611.  
  612. void prompt_left(struct prompt *p)
  613. {
  614.         /* move left */
  615.         if (p->cursor != 0)
  616.                 --(p->cursor);
  617. }
  618.  
  619. void prompt_right(struct prompt *p)
  620. {
  621.         struct prompt_history *ph = &p->history[p->current];
  622.  
  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);
  628. }
  629.  
  630. void prompt_begin(struct prompt *p)
  631. {
  632.         p->cursor = 0;
  633. }
  634.  
  635. void prompt_end(struct prompt *p)
  636. {
  637.         struct prompt_history *ph = &p->history[p->current];
  638.  
  639.         assert(ph->length <= sizeof(ph->line));
  640.         assert(p->cursor <= ph->length);
  641.         p->cursor = ph->length;
  642. }
  643.  
  644. void prompt_clear(struct prompt *p)
  645. {
  646.         struct prompt_history *ph = &p->history[p->current];
  647.  
  648.         assert(ph->length <= sizeof(ph->line));
  649.         assert(p->cursor <= ph->length);
  650.         ph->length = 0;
  651.         p->cursor = 0;
  652. }
  653.  
  654. void prompt_backspace(struct prompt *p)
  655. {
  656.         /* delete previous character */
  657.         if (p->cursor != 0) {
  658.                 prompt_left(p);
  659.                 prompt_delete(p);
  660.         }
  661. }
  662.