<- Back to shtanton's homepage
aboutsummaryrefslogtreecommitdiff
path: root/cudl.c
diff options
context:
space:
mode:
Diffstat (limited to 'cudl.c')
-rw-r--r--cudl.c69
1 files changed, 67 insertions, 2 deletions
diff --git a/cudl.c b/cudl.c
index b596e92..b5022a7 100644
--- a/cudl.c
+++ b/cudl.c
@@ -5,6 +5,7 @@
#include "cudl.h"
#define STRIP_WHITESPACE(text) while (isspace(*(text))) (text)++
+
#define IS_KEY_CHAR(c) (\
'a' <= (c) && (c) <= 'z' ||\
'A' <= (c) && (c) <= 'Z' ||\
@@ -12,6 +13,10 @@
(c) == '_' || (c) == '-'\
)
+#define IS_DIGIT(c) (\
+ '0' <= (c) && (c) <= '9'\
+)
+
int cudl_err = CUDL_OK;
static char *fread_all(FILE *file) {
@@ -43,18 +48,26 @@ void cudl_debug(struct cudl_value value) {
else
printf("%%false");
break;
+ case CUDL_TAG_NUMBER:
+ printf("%lf", value.data.number);
+ break;
case CUDL_TAG_STRING:
printf("\"%s\"", value.data.string);
break;;
case CUDL_TAG_ARRAY:
printf("[");
- for (i = 0; i < value.data.array.length; i++)
+ for (i = 0; i < value.data.array.length; i++) {
+ if (i != 0)
+ printf(" ");
cudl_debug(value.data.array.values[i]);
+ }
printf("]");
break;
case CUDL_TAG_MAP:
printf("{");
for (i = 0; i < value.data.map.length; i++) {
+ if (i != 0)
+ printf(" ");
printf("\"%s\": ", value.data.map.fields[i].key);
cudl_debug(value.data.map.fields[i].value);
}
@@ -106,11 +119,61 @@ static size_t parse_bool_or_null(char *input, struct cudl_value *value) {
return 0;
}
+static size_t parse_number(char *input, struct cudl_value *value) {
+ double number;
+ size_t i, exponentStart;
+ int exponent, otherExponent;
+ int exponentUsed;
+ exponentUsed = 0;
+ number = 0;
+ i = input[0] == '-';
+ for (;; i++) {
+ if (IS_DIGIT(input[i])) {
+ number = number * 10 + (input[i] - '0');
+ exponent++;
+ continue;
+ } else if (input[i] == '.') {
+ exponent = 0;
+ exponentUsed = 1;
+ continue;
+ }
+ break;
+ }
+ if (input[0] == '-')
+ number = 0 - number;
+ if (!exponentUsed)
+ exponent = 0;
+ otherExponent = 0;
+ if (input[i] == 'e' && (IS_DIGIT(input[i+1]) || (input[i+1] == '-' && IS_DIGIT(input[i+2])))) {
+ i++;
+ exponentStart = i;
+ i += input[i] == '-';
+ for (;; i++) {
+ if (IS_DIGIT(input[i]))
+ otherExponent = otherExponent * 10 + (input[i] - '0');
+ else
+ break;
+ }
+ if (input[exponentStart] == '-')
+ otherExponent = 0 - otherExponent;
+ }
+ exponent = exponent - otherExponent;
+ for (; exponent > 0; exponent--) {
+ number /= 10;
+ }
+ for (; exponent < 0; exponent++) {
+ number *= 10;
+ }
+ value->tag = CUDL_TAG_NUMBER;
+ value->data.number = number;
+ return i;
+}
+
/* Convert UCS character to utf-8 bytes.
* Return number of bytes generated.
* Sets cudl_error on error.
* Shamelessly lifted from https://github.com/cktan/tomc99 */
-size_t cudl_ucs_to_utf8(int64_t ucs, char utf8[6]) {
+static size_t cudl_ucs_to_utf8(int64_t ucs, char utf8[6]) {
if (
0xd800 <= ucs && ucs <= 0xdfff ||
0xfffe <= ucs && ucs <= 0xffff ||
@@ -482,6 +545,8 @@ static size_t _parse_value(char *input, struct cudl_value *value) {
value->tag = CUDL_TAG_STRING;
return parse_quoted_string(++input, &value->data.string) + 1;
}
+ if (IS_DIGIT(*input) || *input == '-')
+ return parse_number(input, value);
cudl_err = CUDL_ERR_UNRECOGNISED_VALUE;
return 0;
}