예제 #1
0
파일: tokenizer.c 프로젝트: jwerle/libjson
json_value_t *
json_tokenize (json_tokenizer_t *self, const char *src) {
  char ch = 0;
  char quote = 0;
  char uchar = 0;
  int pos = 0;
  const char *tmpsrc = src;
  json_tokenizer_state_t *state = &self->state;
  json_tokenizer_state_t *next_state = &self->next_state;
  json_value_t *current = self->current;
  json_token_t *token = json_token_new();

  self->src = src;
  self->buf = buffer_new_with_copy((char *) src);
  self->src_length = strlen(src);

  *state = JSON_TOKENIZER_STATE_START;

  self->tokens[self->depth] = token;

  while ((ch = head(self))) {
    parse: switch (*state) {
      case JSON_TOKENIZER_STATE_ERROR:
        goto error;
        break;

      case JSON_TOKENIZER_STATE_CONTINUE:
        goto parse;
        break;

      case JSON_TOKENIZER_STATE_SUCCESS:
        goto complete;
        break;

      /**
       * Handles whitespace and goes to
       * complete when buffer is fully read
       */

      case JSON_TOKENIZER_STATE_WHITESPACE:
        while (isspace(ch)) {
          if (!next(self) || !(ch = head(self))) {
            goto complete;
          }
        }

        /**
         * @TODO - handle comments
         */

        state = next_state;
        break;

      /**
       * Peeks at char to determine value
       * type
       */

      case JSON_TOKENIZER_STATE_START:

        printf("%c, ",ch);
        switch (ch) {

          /**
           * Sets state to null, position to 0,
           * and goes back to parse the switch
           */

          case JSON_TOKEN_NULL_CHAR:
            *state = JSON_TOKENIZER_STATE_NULL;
            pos = 0;
            buffer_clear(self->buf);
            goto parse;
            break;

          /**
           * Sets state to parse a string
           * in the case of double or single
           * quotes
           */

          case JSON_TOKEN_SINGLE_QUOTE:
          case JSON_TOKEN_DOUBLE_QUOTE:
            *state = JSON_TOKENIZER_STATE_STRING;
            quote = ch;
            buffer_clear(self->buf);
            break;

          /**
           * Sets state to boolean and position
           * to 0
           */

          case JSON_TOKEN_TRUE_CHAR:
          case JSON_TOKEN_FALSE_CHAR:
            *state = JSON_TOKENIZER_STATE_BOOLEAN;
            pos = 0;
            buffer_clear(self->buf);
            goto parse;
            break;

          /**
           * Sets state to number
           */

          case '0': case '1': case '2': case '3': case '4':
          case '5': case '6': case '7': case '8': case '9':
          case '-':
            *state = JSON_TOKENIZER_STATE_NUMBER;
            buffer_clear(self->buf);
            goto parse;
            break;

          /**
           * Prepares an empty object, sets
           * state to filter whitespace and
           * next state to start parsing the
           * object
           */

          case JSON_TOKEN_OBJECT_LEFT_BRACE:
            *state = JSON_TOKENIZER_STATE_WHITESPACE;
            *next_state = JSON_TOKENIZER_STATE_OBJECT_START;
            current = (json_value_t *) json_object_new();
            break;

          /**
           * Prepares an empty array, sets
           * state to filter whitespace and
           * next state to start parsing the
           * array
           */

          case JSON_TOKEN_ARRAY_LEFT_BRACE:
            *state = JSON_TOKENIZER_STATE_WHITESPACE;
            *next_state = JSON_TOKENIZER_STATE_ARRAY;
            current = (json_value_t *) json_array_new();
            break;

          /**
           * Set the error flag and errno for an unexpected
           * token
           */

          default:
            self->errno = JSON_EUNEXPECTED_TOKEN;

#ifdef JSON_DEBUG
            json_perror(JSON_EUNEXPECTED_TOKEN, ch);
#endif
            goto error;
        }
        break;

      /**
       * Completes parse if depth is 0
       */
      case JSON_TOKENIZER_STATE_END:
        if (0 == self->depth) goto complete;
        self->depth--;
        break;

      /**
       *
       */

      case JSON_TOKENIZER_STATE_NULL:
        buffer_append(self->buf, &ch);

        if (strncmp(JSON_NULL, self->buf->data, strlen(JSON_NULL))) {
          if (pos == strlen(JSON_NULL)) {
            *state = JSON_TOKENIZER_STATE_WHITESPACE;
            *next_state = JSON_TOKENIZER_STATE_END;
            current = (json_value_t *) json_null_new();
            goto parse;
          }
        } else {
          self->errno = JSON_ENULL_PARSE_ERROR;

#ifdef JSON_DEBUG
          json_perror(JSON_ENULL_PARSE_ERROR, ch);
#endif
          goto error;
        }

        pos++;
        break;

      /**
       * @TODO - Handle comments
       */


      /**
       *
       */

      case JSON_TOKENIZER_STATE_STRING:

        tmpsrc = self->buf->data;
        while (1) {
          if (quote == ch) {
            printf("c %c\n", ch);
            *state = JSON_TOKENIZER_STATE_WHITESPACE;
            *next_state = JSON_TOKENIZER_STATE_END;
            current = (json_value_t *) json_string_new(self->buf->data);
            break;
          } else if ('\\' == ch) {
            *state = JSON_TOKENIZER_STATE_STRING_ESCAPE;
            *next_state = JSON_TOKENIZER_STATE_STRING;
            break;
          } else if (!next(self) || !(ch = head(self))) {
            // @TODO
            goto complete;
          }
        }

        break;

      /**
        *
        */

       case JSON_TOKENIZER_STATE_STRING_ESCAPE:
        switch (ch) {
          // handle escaped characters
          case '"': case '\\': case '/':
            buffer_append(self->buf, &ch);
            state = next_state;
            break;

          case 'b':
            buffer_append(self->buf, "\b");
            state = next_state;
            break;
          case 'r':
            buffer_append(self->buf, "\r");
            state = next_state;
            break;
          case 'n':
            buffer_append(self->buf, "\n");
            state = next_state;
            break;
          case 't':
            buffer_append(self->buf, "\t");
            state = next_state;
            break;
          case 'u':
            pos = 0;
            uchar = 0;
            *state = JSON_TOKENIZER_STATE_STRING_UNICODE;
            break;

          default:
          self->errno = JSON_ESTRING_PARSE_ERROR;

#ifdef JSON_DEBUG
          json_perror(JSON_ESTRING_PARSE_ERROR, ch);
#endif

        }
        break;

       case JSON_TOKENIZER_STATE_STRING_UNICODE:

        /**
         * @TODO - handle unicode
         */

        break;

       case JSON_TOKENIZER_STATE_BOOLEAN:
        buffer_append(self->buf, &ch);
        if (0 == strcmp(JSON_TRUE, self->buf->data)) {
          if (pos == strlen(JSON_TRUE)) {
            *state = JSON_TOKENIZER_STATE_WHITESPACE;
            *next_state = JSON_TOKENIZER_STATE_END;
            current = (json_value_t *) json_boolean_new(1);
            goto parse;
          } else if (0 == strcmp(JSON_TRUE, self->buf->data)) {
            if (0 == strcmp(JSON_FALSE, self->buf->data)) {
              *state = JSON_TOKENIZER_STATE_WHITESPACE;
              *next_state = JSON_TOKENIZER_STATE_END;
              current = (json_value_t *) json_boolean_new(0);
              goto parse;
            }
          } else {
            self->errno = JSON_EBOOLEAN_PARSE_ERROR;

#ifdef JSON_DEBUG
            json_perror(JSON_EBOOLEAN_PARSE_ERROR, ch);
#endif
          }
        }
        break;

       case JSON_TOKENIZER_STATE_NUMBER:
        break;

       case JSON_TOKENIZER_STATE_ARRAY:
        break;

       case JSON_TOKENIZER_STATE_ARRAY_PUSH:
        break;

       case JSON_TOKENIZER_STATE_ARRAY_SEP:
        break;

       case JSON_TOKENIZER_STATE_OBJECT_START:
        break;

       case JSON_TOKENIZER_STATE_OBJECT:
        break;

       case JSON_TOKENIZER_STATE_OBJECT_END:
        break;

       case JSON_TOKENIZER_STATE_OBJECT_VALUE_SET:
        break;

       case JSON_TOKENIZER_STATE_OBJECT_VALUE:
        break;

       case JSON_TOKENIZER_STATE_OBJECT_SEP:
        break;
    }

    if (!(ch = next(self))) {
      break;
    }
  }

complete:
  return current;

error:
  return NULL;
}
예제 #2
0
파일: main.c 프로젝트: qute/json
int
main (int argc, char **argv) {
  json_value_t *value = NULL;
  json_value_t *root = NULL;
  char *filename = NULL;
  char *key = NULL;
  char *src = NULL;
  int i = 0;

#define usage() printf("usage: %s <file> [key]\n", argv[0]);

  if (argc < 2) {
    usage();
    return 1;
  }

  // parse opts
  for (i = 1; i < argc; ++i) {
    if (EQ(argv[i], "--each")) {
      each = 1;
    } else if (EQ(argv[i], "--stream")) {
      stream = 1;
    } else if (EQ(argv[i], "--help")) {
      usage();
      return 0;
    }
  }

  if (ferror(stdin)) {
    return 1;
  } else if (0 == isatty(0)) {
    filename = "<stdin>";
    tty = 1;
    if (argc > 1 && '-' != argv[1][0]) {
      key = argv[1];
    }
  } else {
    filename = argv[1];
    if (0 != fs_exists(filename)) {
      printf("E: not found - `%s'\n", filename);
      return 1;
    }

    src = fs_read(filename);
    if (NULL == src) {
      return 1;
    }

    if (argc > 2 && '-' !=  argv[2][0]) {
      key = argv[2];
    }
  }

  do {
    if (tty) {
      src = read_stdin();
    }

    if (NULL == src || 0 == strlen(src)) {
      break;
    }

    // proxy source if just streaming stdin
    // without a key lookup
    if (NULL == key && stream) {
      printf("%s", src);
      continue;
    }

    root = json_parse(filename, src);

    if (NULL == root) {
      return 1;
    } else if (root->errno) {
      json_perror(root);
      return 1;
    }

    if (NULL != key) {
      value = json_get(root, key);
      if (NULL == value) {
        return 1;
      }

      free(root);
      root = value;
    } else {
      value = root;
    }

    if (1 == each && JSON_ARRAY == value->type) {
      value = value->values[0];
      while (value) {
        printf("%s\n", json_stringify(value));
        value = value->next;
      }
    } else {
      printf("%s\n", json_stringify(value));
    }

    json_destroy(root);
    free(src);
    value = NULL;
    root = NULL;
    src = NULL;

  } while (tty);

  return 0;
}