예제 #1
0
cparser_result_t cparser_line_prev_line(cparser_t *parser) {
  int n;

  if (!VALID_PARSER(parser)) {
    return CPARSER_ERR_INVALID_PARAMS;
  }

  /*
   * Erase the current line
   */
  for (n = 0; n < cparser_line_last(parser); n++) {
    parser->cfg.prints(parser, "\b \b");
  }

  /*
   * Go to the previous line
   */
  parser->cur_line--;
  if (0 > parser->cur_line) {
    parser->cur_line = parser->max_line;
  }

  /*
   * Print out the new line
   */
  cparser_line_print(parser, 0, 0);

  return CPARSER_OK;
}
예제 #2
0
cparser_result_t
cparser_line_delete (cparser_t *parser)
{
    cparser_line_t *line;
    int n;

    if (!VALID_PARSER(parser)) {
        return CPARSER_ERR_INVALID_PARAMS;
    }
    line = &parser->lines[parser->cur_line];
    assert(line->current <= line->last);
    if (!line->last || !line->current) {
        /* Line is empty or we're at the beginning of the line */
        return CPARSER_ERR_NOT_EXIST;
    }

    /* Move all character after current position back by one */
    for (n = line->current; n < line->last; n++) {
        line->buf[n-1] = line->buf[n];
    }
    line->current--;
    line->last--;
    line->buf[line->last] = '\0';

    /* Update the display */
    parser->cfg.printc(parser, '\b');
    parser->cfg.prints(parser, LINE_CURRENT(line));
    parser->cfg.prints(parser, " \b");
    for (n = line->current; n < line->last; n++) {
        parser->cfg.printc(parser, '\b');
    }
    return CPARSER_OK;
}
예제 #3
0
char cparser_line_char(const cparser_t *parser, short pos) {
  const cparser_line_t *line;
  assert(VALID_PARSER(parser));
  line = &parser->lines[parser->cur_line];
  assert(pos < line->last);
  return line->buf[pos];
}
예제 #4
0
char
cparser_line_current_char (const cparser_t *parser)
{
    const cparser_line_t *line;
    assert(VALID_PARSER(parser));
    line = &parser->lines[parser->cur_line];
    return line->buf[line->current];
}
예제 #5
0
cparser_result_t cparser_walk(cparser_t *parser, cparser_walker_fn pre_fn,
                              cparser_walker_fn post_fn, void *cookie) {
  if (!VALID_PARSER(parser) || (!pre_fn && !post_fn)) {
    return CPARSER_ERR_INVALID_PARAMS;
  }

  return cparser_walk_internal(parser, parser->root[parser->root_level],
                               pre_fn, post_fn, cookie);
}
예제 #6
0
char cparser_line_prev_char(cparser_t *parser) {
  cparser_line_t *line;

  assert(VALID_PARSER(parser));
  line = &parser->lines[parser->cur_line];
  if (!line->current) {
    /*
     * Already at the beginning of the line
     */
    return 0;
  }

  parser->cfg.printc(parser, '\b');
  line->current--;

  return '\b';
}
예제 #7
0
/**
 * \brief    Generate context-sensitive help.
 *
 * \param    parser Pointer to the parser structure.
 */
static cparser_result_t cparser_help(cparser_t *parser) {
  cparser_node_t *node;
  cparser_token_t *token;
  int local_is_complete;

  assert(VALID_PARSER(parser));
  if (CPARSER_STATE_WHITESPACE == parser->state) {
    /*
     * Just print out every children
     */
    for (node = parser->cur_node->children; NULL != node;
         node = node->sibling) {
      cparser_help_print_node(parser, node, 1, 1);
    }
  } else if (CPARSER_STATE_ERROR == parser->state) {
    /*
     * We have some problem parsing. Just print out the last known
     * good parse point and list the valid options.
     */
    cparser_print_error(parser, "Last known good parse point.");
    for (node = parser->cur_node->children; NULL != node;
         node = node->sibling) {
      cparser_help_print_node(parser, node, 1, 1);
    }
  } else {
    /*
     * We have a partial match
     */
    node = parser->cur_node->children;
    token = CUR_TOKEN(parser);
    for (node = parser->cur_node->children; NULL != node;
         node = node->sibling) {
      if (!NODE_USABLE(parser, node)) {
        continue;
      }
      if (CPARSER_OK ==
          cparser_match_fn_tbl[node->type](token->buf, token->token_len,
                                           node, &local_is_complete)) {
        cparser_help_print_node(parser, node, 1, 1);
      }
    }
  }
  cparser_line_print(parser, 1, 1);
  return CPARSER_OK;
}
예제 #8
0
char cparser_line_next_char(cparser_t *parser) {
  char retval;
  cparser_line_t *line;

  assert(VALID_PARSER(parser));
  line = &parser->lines[parser->cur_line];
  if (line->last == line->current) {
    /*
     * Already at the end of the line
     */
    return 0;
  }

  retval = line->buf[line->current];
  parser->cfg.printc(parser, retval);
  line->current++;

  return retval;
}
예제 #9
0
cparser_result_t cparser_line_advance(cparser_t *parser) {
  int rc;

  if (!VALID_PARSER(parser)) {
    return CPARSER_ERR_INVALID_PARAMS;
  }

  parser->cur_line++;
  if (CPARSER_MAX_LINES <= parser->cur_line) {
    parser->cur_line = 0;
  }
  if (parser->max_line < parser->cur_line) {
    parser->max_line = parser->cur_line;
  }

  rc = cparser_line_reset(&parser->lines[parser->cur_line]);
  assert(0 == rc);

  return CPARSER_OK;
}
예제 #10
0
cparser_result_t cparser_run(cparser_t *parser) {
  int ch;
  cparser_char_t ch_type = 0;

  if (!VALID_PARSER(parser))
    return CPARSER_ERR_INVALID_PARAMS;

  parser->cfg.io_init(parser);
  cparser_print_prompt(parser);
  parser->done = 0;

  while (!parser->done) {
    parser->cfg.getch(parser, &ch, &ch_type);
    cparser_input(parser, ch, ch_type);
  } /* while not done */

  parser->cfg.io_cleanup(parser);

  return CPARSER_OK;
}
예제 #11
0
void
cparser_line_print (const cparser_t *parser, int print_prompt, int new_line)
{
    const cparser_line_t *line;
    int n;

    assert(VALID_PARSER(parser));
    if (new_line) {
        parser->cfg.printc(parser, '\n');
    }
    if (print_prompt) {
        cparser_print_prompt(parser);
    }
    line = &parser->lines[parser->cur_line];
    parser->cfg.prints(parser, line->buf);

    /* Move the cursor back the current position */
    for (n = line->current; n < line->last; n++) {
        parser->cfg.printc(parser, '\b');
    }
}
예제 #12
0
cparser_result_t cparser_line_insert(cparser_t *parser, char ch) {
  int n;
  cparser_line_t *line;

  if (!VALID_PARSER(parser) || !ch) {
    return CPARSER_ERR_INVALID_PARAMS;
  }
  line = &parser->lines[parser->cur_line];
  if (CPARSER_MAX_LINE_SIZE <= line->last) {
    return CPARSER_ERR_OUT_OF_RES;
  }

  /*
   * Move all characters from current to last back by 1
   */
  for (n = line->last; n > line->current; n--) {
    line->buf[n] = line->buf[n - 1];
  }
  line->buf[++line->last] = '\0';

  /*
   * Insert the new character and update the line display. We do not
   * have full curse support here. Instead, we simply assume all
   * characters are on the same line and use backspace to move the
   * cursor.
   */
  line->buf[line->current] = ch;
  parser->cfg.printc(parser, ch);
  line->current++; /* update current position */
  parser->cfg.prints(parser, LINE_CURRENT(line));

  /*
   * Move cursor back to the current position
   */
  for (n = line->current; n < line->last; n++) {
    parser->cfg.printc(parser, '\b');
  }

  return CPARSER_OK;
}
예제 #13
0
short cparser_line_last(const cparser_t *parser) {
  assert(VALID_PARSER(parser));
  return parser->lines[parser->cur_line].last;
}
예제 #14
0
cparser_result_t cparser_load_cmd(cparser_t *parser, char *filename) {
  FILE *fp;
  char buf[128];
  size_t rsize, n;
  int fd, indent = 0, last_indent = -1, new_line = 1, m, line_num = 0;

  if (!VALID_PARSER(parser) || !filename) {
    return CPARSER_ERR_INVALID_PARAMS;
  }

  fd = parser->cfg.fd;
  parser->cfg.fd = -1;

  fp = fopen(filename, "r");
  if (!fp) {
    return CPARSER_NOT_OK;
  }

  cparser_fsm_reset(parser);
  while (!feof(fp)) {
    rsize = fread(buf, 1, sizeof(buf), fp);
    for (n = 0; n < rsize; n++) {
      /*
       * Examine the input characters to maintain indent level
       */
      if ('\n' == buf[n]) {
        cparser_result_t rc;
        char buf[128];

        line_num++;
        indent = 0;
        new_line = 1;
        rc = cparser_execute_cmd(parser);
        if (CPARSER_OK == rc) {
          continue;
        }
        parser->cfg.fd = fd;
        switch (rc) {
          case CPARSER_ERR_PARSE_ERR:
            snprintf(buf, sizeof(buf), "Line %d: Parse error.\n",
                     line_num);
            parser->cfg.prints(parser, buf);
            break;
          case CPARSER_ERR_INCOMP_CMD:
            snprintf(buf, sizeof(buf), "Line %d: Incomplete command.\n",
                     line_num);
            parser->cfg.prints(parser, buf);
            break;
          default:
            assert(0);
        }
        return CPARSER_NOT_OK;
      } else if (' ' == buf[n]) {
        if (new_line) {
          indent++;
        }
      } else {
        if (new_line) {
          new_line = 0;
          if (indent < last_indent) {
            for (m = indent; m < last_indent; m++) {
              if (CPARSER_OK != cparser_submode_exit(parser)) {
                break;
              }
              cparser_fsm_reset(parser);
            }
          }
          last_indent = indent;
        }
      }
      (void)cparser_fsm_input(parser, buf[n]);
    }
  }
  fclose(fp);

  while (parser->root_level) {
    (void)cparser_submode_exit(parser);
    cparser_fsm_reset(parser);
  }
  parser->cfg.fd = fd;
  return CPARSER_OK;
}
예제 #15
0
cparser_result_t cparser_input(cparser_t *parser, char ch,
                               cparser_char_t ch_type) {
  int n, do_echo;
  cparser_result_t rc;

  if (!VALID_PARSER(parser)) {
    return CPARSER_ERR_INVALID_PARAMS;
  }

  if (cparser_is_user_input(parser, &do_echo)) {
    /*
     * Process user input
     */
    if (CPARSER_CHAR_REGULAR != ch_type) {
      return CPARSER_OK;
    }
    if ('\n' == ch) {
      /*
       * We have a complete input. Call the callback.
       */
      assert(parser->user_input_cb);
      parser->user_buf[parser->user_buf_count] = '\0';
      rc = parser->user_input_cb(parser, parser->user_buf,
                                 parser->user_buf_count);
      cparser_input_reset(parser);
      cparser_print_prompt(parser);
      return rc;
    }

    if ((parser->cfg.ch_erase == ch) || (parser->cfg.ch_del == ch)) {
      if (parser->user_buf_count > 0) {
        parser->user_buf_count--;
      }
      if (parser->user_do_echo) {
        parser->cfg.printc(parser, '\b');
      }
    } else if ((parser->user_buf_count + 1) < parser->user_buf_size) {
      parser->user_buf[parser->user_buf_count] = ch;
      parser->user_buf_count++;
      if (parser->user_do_echo) {
        parser->cfg.printc(parser, ch);
      }
    }
    return CPARSER_OK;
  }

  switch (ch_type) {
    case CPARSER_CHAR_REGULAR: {
      if ((parser->cfg.ch_complete == ch) || (parser->cfg.ch_help == ch)) {
        /*
         * Completion and help character do not go into the line
         * buffer. So, do nothing.
         */
        break;
      }
      if ((parser->cfg.ch_erase == ch) || (parser->cfg.ch_del == ch)) {
        rc = cparser_line_delete(parser);
        assert(CPARSER_ERR_INVALID_PARAMS != rc);
        if (CPARSER_ERR_NOT_EXIST == rc) {
          return CPARSER_OK;
        }
      } else if ('\n' == ch) {
        /*
         * Put the rest of the line into parser FSM
         */
        for (n = cparser_line_current(parser);
             n < cparser_line_last(parser); n++) {
          rc = cparser_fsm_input(parser, cparser_line_char(parser, n));
          assert(CPARSER_OK == rc);
        }
      } else {
        (void)cparser_line_insert(parser, ch);
      }
      break;
    }
    case CPARSER_CHAR_UP_ARROW: {
      rc = cparser_line_prev_line(parser);
      assert(CPARSER_OK == rc);

      /*
       * Reset the token stack and re-enter the command
       */
      cparser_fsm_reset(parser);
      for (n = 0; n < cparser_line_current(parser); n++) {
        rc = cparser_fsm_input(parser, cparser_line_char(parser, n));
        assert(CPARSER_OK == rc);
      }

      return CPARSER_OK;
    }
    case CPARSER_CHAR_DOWN_ARROW: {
      rc = cparser_line_next_line(parser);
      assert(CPARSER_OK == rc);

      /*
       * Reset the token stack and re-enter the command
       */
      cparser_fsm_reset(parser);
      for (n = 0; n < cparser_line_current(parser); n++) {
        rc = cparser_fsm_input(parser, cparser_line_char(parser, n));
        assert(CPARSER_OK == rc);
      }

      return CPARSER_OK;
    }
    case CPARSER_CHAR_LEFT_ARROW: {
      ch = cparser_line_prev_char(parser);
      if (!ch) {
        parser->cfg.printc(parser, '\a');
        return CPARSER_OK;
      }
      break;
    }
    case CPARSER_CHAR_RIGHT_ARROW: {
      ch = cparser_line_next_char(parser);
      if (!ch) {
        parser->cfg.printc(parser, '\a');
        return CPARSER_OK;
      }
      break;
    }
    case CPARSER_CHAR_FIRST: {
      do {
        ch = cparser_line_prev_char(parser);
        if (ch) {
          cparser_fsm_input(parser, ch);
        }
      } while (ch);
      return CPARSER_OK;
    }
    case CPARSER_CHAR_LAST: {
      do {
        ch = cparser_line_next_char(parser);
        if (ch) {
          cparser_fsm_input(parser, ch);
        }
      } while (ch);
      return CPARSER_OK;
    }
    default: {
      /*
       * An unknown character. Alert and continue
       */
      parser->cfg.printc(parser, '\a');
      return CPARSER_NOT_OK;
    }
  } /* switch (ch_type) */

  /*
   * Handle special characters
   */
  if (ch == parser->cfg.ch_complete) {
    while (cparser_complete_one_level(parser))
      ;
    return CPARSER_OK;
  } else if (ch == parser->cfg.ch_help) {
    /*
     * Ask for context sensitve help
     */
    cparser_help(parser);
    return CPARSER_OK;
  } else if ('\n' == ch) {
    rc = cparser_execute_cmd(parser);
    cparser_line_advance(parser);
    return rc;
  }

  return cparser_fsm_input(parser, (char)ch);
}
예제 #16
0
/**
 * \brief    If the command is not complete, attempt to complete the
 *command.
 *           If there is a complete comamnd, execute the glue (& action)
 *           function of a command.
 *
 * \param    parser Pointer to the parser structure.
 *
 * \return   CPARSER_OK if a valid command is executed; CPARSER_NOT_OK
 *           otherwise.
 */
static cparser_result_t cparser_execute_cmd(cparser_t *parser) {
  int do_echo;
  cparser_result_t rc = CPARSER_OK;
  assert(VALID_PARSER(parser));

  /*
   * Enter a command. There are three possibilites:
   * 1. If we are in WHITESPACE state, we check if there is
   *    only one child of keyword type. If yes, we recurse
   *    into it and repeat until either: a) there is more than
   *    one choice, b) We are at a END node. If there is more
   *    than one choice, we look for an END node. In either
   *    case, if an END node is found, we execute the action
   *    function.
   *
   * 2. If we are in TOKEN state, we check if we have an unique
   *    match. If yes, re recurse into it and repeat just
   *    like WHITESPACE state until we find an END node.
   *
   * 3. If we are in ERROR state, we print out an error.
   *
   * Afterward, we reset the parser state and move to the
   * next line buffer.
   */
  if ((CPARSER_STATE_TOKEN == parser->state) ||
      (CPARSER_STATE_WHITESPACE == parser->state)) {
    cparser_node_t *child;

    if (CPARSER_STATE_TOKEN == parser->state) {
      cparser_token_t *token;
      cparser_node_t *match;
      int is_complete;

      token = CUR_TOKEN(parser);
      if ((1 <= cparser_match(parser, token->buf, token->token_len,
                              parser->cur_node, &match, &is_complete)) &&
          (is_complete)) {
        cparser_complete_fn fn = cparser_complete_fn_tbl[match->type];
        if (fn) {
          fn(parser, match, token->buf, token->token_len);
        }
        rc = cparser_input(parser, ' ', CPARSER_CHAR_REGULAR);
        assert(CPARSER_OK == rc);
      } else {
        cparser_print_error(parser, "Incomplete command\n");
        rc = CPARSER_ERR_INCOMP_CMD;

        /*
         * Reset the internal buffer, state and cur_node
         */
        cparser_record_command(parser, rc);
        cparser_fsm_reset(parser);
        cparser_print_prompt(parser);
        return rc;
      }
    }

    /*
     * Look for a single keyword node child
     */
    child = parser->cur_node->children;
    assert(child);
    while ((CPARSER_NODE_KEYWORD == child->type) &&
           NODE_USABLE(parser, child) && (!child->sibling)) {
      cparser_token_t *token = CUR_TOKEN(parser);
      cparser_complete_keyword(parser, child, token->buf,
                               token->token_len);
      rc = cparser_input(parser, ' ', CPARSER_CHAR_REGULAR);
      assert(CPARSER_OK == rc);

      child = parser->cur_node->children;
      assert(child);
    }

    /*
     * Look for an end node
     */
    child = parser->cur_node->children;
    while ((NULL != child) &&
           !((CPARSER_NODE_END == child->type) &&
             NODE_USABLE(parser, child))) {
      child = child->sibling;
    }
    if (child) {
      assert(CPARSER_NODE_END == child->type);

      /*
       * Execute the glue function
       */
      parser->cur_node = child;
      parser->cfg.printc(parser, '\n');
      rc = ((cparser_glue_fn)child->param)(parser);
    } else {
      if (parser->token_tos) {
        cparser_print_error(parser, "Incomplete command\n");
        rc = CPARSER_ERR_INCOMP_CMD;
      }

      /*
       * Reset FSM states and advance to the next line
       */
      cparser_record_command(parser, rc);
      cparser_fsm_reset(parser);
      if (CPARSER_OK == rc) {
        /*
         * This is just a blank line
         */
        parser->cfg.printc(parser, '\n');
      }
      cparser_print_prompt(parser);
      return rc;
    }
  } else if (CPARSER_STATE_ERROR == parser->state) {
    cparser_print_error(parser, "Parse error\n");
    rc = CPARSER_ERR_PARSE_ERR;
  }

  /*
   * Reset FSM states and advance to the next line
   */
  cparser_record_command(parser, rc);
  cparser_fsm_reset(parser);
  if (!cparser_is_user_input(parser, &do_echo)) {
    cparser_print_prompt(parser);
  }
  return rc;
}