add config support
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
/driver
|
||||
/out
|
||||
@@ -0,0 +1,21 @@
|
||||
CFLAGS := -O0 -g -fsanitize=address,undefined -std=c17 -Wmissing-declarations -Wall -Wextra -MMD
|
||||
|
||||
all: driver
|
||||
|
||||
driver: scanvalue.c
|
||||
$(CC) $(CFLAGS) -o $@ scanvalue.c -lm
|
||||
|
||||
test: all
|
||||
bash run.sh
|
||||
|
||||
-include driver.d
|
||||
|
||||
clean:
|
||||
rm -f *.o *.d driver
|
||||
|
||||
distclean: clean
|
||||
|
||||
format:
|
||||
clang-format -i *.[ch]
|
||||
|
||||
.PHONY: all clean distclean format test
|
||||
@@ -0,0 +1,16 @@
|
||||
= """
|
||||
Roses are red
|
||||
Violets are blue"""
|
||||
|
||||
# On a Unix system, the above multi-line string will most likely be the same as:
|
||||
= "Roses are red\nViolets are blue"
|
||||
|
||||
# On a Windows system, it will most likely be equivalent to:
|
||||
= "Roses are red\r\nViolets are blue"
|
||||
|
||||
= """Here are two quotation marks: "". Simple enough."""
|
||||
= """Here are three quotation marks: ""\"."""
|
||||
= """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
|
||||
|
||||
# "This," she said, "is just a pointless statement."
|
||||
= """"This," she said, "is just a pointless statement.""""# What you see is what you get.
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
# integers
|
||||
= [ 1, 2, 3 ]
|
||||
|
||||
# colors
|
||||
= [ "red", "yellow", "green" ]
|
||||
|
||||
# nested
|
||||
= [ [ 1, 2 ], [3, 4, 5] ]
|
||||
= [ [ 1, 2 ], ["a", "b", "c"] ]
|
||||
= [ "all", 'strings', """are the same""", '''type''' ]
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Mixed-type arrays are allowed
|
||||
= [ 0.1, 0.2, 0.5, 1.0, 2, 5 ]
|
||||
= [
|
||||
"Foo Bar <foo@example.com>",
|
||||
{ }
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
# multiline
|
||||
= [
|
||||
1, 2, 3
|
||||
]
|
||||
|
||||
# extra comma at end
|
||||
= [
|
||||
1,
|
||||
2, # this is ok
|
||||
]
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
= { }
|
||||
@@ -0,0 +1,17 @@
|
||||
# all results are the same
|
||||
|
||||
= "abc"
|
||||
|
||||
= """
|
||||
a\
|
||||
|
||||
|
||||
b\
|
||||
c"""
|
||||
|
||||
= """\
|
||||
a\
|
||||
b\
|
||||
c\
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# line-ending backslash with whitespace "geeee\ "
|
||||
# result should be "heeee\ngeeee"
|
||||
|
||||
= """
|
||||
heeee
|
||||
geeee\
|
||||
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,2 @@
|
||||
= "\t tab tab tab \t"
|
||||
= "\e There is no escape! \e"
|
||||
@@ -0,0 +1 @@
|
||||
= inf
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
= 2023-01-01T12:34:56.123456789Z
|
||||
= 2023-01-01T12:34:56.123456789
|
||||
= 07:32:00.123456789
|
||||
@@ -0,0 +1,11 @@
|
||||
= 'C:\Users\nodejs\templates'
|
||||
= '\\ServerX\admin$\system32\'
|
||||
= 'Tom "Dubs" Preston-Werner'
|
||||
= '<\i\c*\s*>'
|
||||
= '''I [dw]on't need \d{2} apples'''
|
||||
= '''
|
||||
The first newline is
|
||||
trimmed in raw strings.
|
||||
All other whitespace
|
||||
is preserved.
|
||||
'''
|
||||
@@ -0,0 +1,7 @@
|
||||
= '''Here are fifteen quotation marks: """""""""""""""'''
|
||||
|
||||
# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
|
||||
= "Here are fifteen apostrophes: '''''''''''''''"
|
||||
|
||||
# 'That,' she said, 'is still pointless.'
|
||||
= ''''That,' she said, 'is still pointless.''''
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
= "pi"
|
||||
= +99
|
||||
= 42
|
||||
= 0
|
||||
= -17
|
||||
= 1_000
|
||||
= 5_349_221
|
||||
= 53_49_221 # Indian number system grouping
|
||||
= 1_2_3_4_5 # VALID but discouraged
|
||||
@@ -0,0 +1,11 @@
|
||||
# hexadecimal with prefix `0x`
|
||||
= 0xDEADBEEF
|
||||
= 0xdeadbeef
|
||||
= 0xdead_beef
|
||||
|
||||
# octal with prefix `0o`
|
||||
= 0o01234567
|
||||
= 0o755 # useful for Unix file permissions
|
||||
|
||||
# binary with prefix `0b`
|
||||
= 0b11010110
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
# fractional
|
||||
= +1.0
|
||||
= 3.1415
|
||||
= -0.01
|
||||
|
||||
# exponent
|
||||
= 5e+22
|
||||
= 1e06
|
||||
= -2E-2
|
||||
|
||||
# both
|
||||
= 6.626e-34
|
||||
|
||||
= 224_617.445_991_228
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
# infinity
|
||||
= inf # positive infinity
|
||||
= +inf # positive infinity
|
||||
= -inf # negative infinity
|
||||
|
||||
# not a number
|
||||
= nan # actual sNaN/qNaN encoding is implementation-specific
|
||||
= +nan # same as `nan`
|
||||
= -nan # valid, actual encoding is implementation-specific
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
= true
|
||||
= false
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
= 1979-05-27T07:32:00Z
|
||||
= 1979-05-27T00:32:00-07:00
|
||||
= 1979-05-27T00:32:00.999999-07:00
|
||||
= 1979-05-27 07:32:00Z
|
||||
= 1979-05-27T07:32:00
|
||||
= 1979-05-27T00:32:00.999999
|
||||
= 1979-05-27
|
||||
= 07:32:00
|
||||
= 00:32:00.999999
|
||||
|
||||
# lower
|
||||
= 1987-07-05t17:45:00z
|
||||
@@ -0,0 +1,2 @@
|
||||
# trailing .
|
||||
= 1997-09-09T09:09:09.
|
||||
@@ -0,0 +1,2 @@
|
||||
# timezone offset overflow minute
|
||||
= 1985-06-18 17:04:07+12:60
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
mkdir -p out
|
||||
|
||||
echo
|
||||
echo =========================
|
||||
echo == scanvalue test
|
||||
echo =========================
|
||||
|
||||
for fname in {1..100} e{1..100}; do
|
||||
IN="in/$fname"
|
||||
if [ -f $IN ]; then
|
||||
echo test $fname
|
||||
OUT="out/$fname.out"
|
||||
GOOD="good/$fname.out"
|
||||
./driver $IN &> $OUT
|
||||
diff $GOOD $OUT || { echo '--- FAILED ---'; exit 1; }
|
||||
fi
|
||||
done
|
||||
|
||||
echo DONE
|
||||
@@ -0,0 +1,161 @@
|
||||
#include "../../src/tomlc17.c"
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char **g_argv = 0;
|
||||
int g_argc = 0;
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr, "Usage: %s fname\n", g_argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void printspecial(const char *p, int n) {
|
||||
for (int i = 0; i < n; i++, p++) {
|
||||
int ch = (*p == '\n') ? '_' : *p;
|
||||
putchar(ch);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *fmt_double(double f, char *buf, int buflen) {
|
||||
snprintf(buf, buflen, "%.16g", f);
|
||||
if (!strchr(buf, 'e') && !strchr(buf, '.') && !strchr(buf, 'n')) {
|
||||
// add a .0 if the number is an int, and not inf or nan.
|
||||
snprintf(buf, buflen, "%.16g%s", f, ".0");
|
||||
}
|
||||
if (isnan(f) && signbit(f)) {
|
||||
snprintf(buf, buflen, "%s", "-nan");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void printtok(char *content, const token_t tok) {
|
||||
// clang-format off
|
||||
#define CASESTR(x) case TOK_ ## x: s = #x; break
|
||||
// clang-format on
|
||||
char *s = 0;
|
||||
switch (tok.toktyp) {
|
||||
CASESTR(DOT);
|
||||
CASESTR(EQUAL);
|
||||
CASESTR(COMMA);
|
||||
CASESTR(LBRACK);
|
||||
CASESTR(RBRACK);
|
||||
CASESTR(LBRACE);
|
||||
CASESTR(RBRACE);
|
||||
CASESTR(STRING);
|
||||
CASESTR(MLSTRING);
|
||||
CASESTR(LITSTRING);
|
||||
CASESTR(MLLITSTRING);
|
||||
CASESTR(TIME);
|
||||
CASESTR(DATE);
|
||||
CASESTR(DATETIME);
|
||||
CASESTR(DATETIMETZ);
|
||||
CASESTR(INTEGER);
|
||||
CASESTR(FLOAT);
|
||||
CASESTR(BOOL);
|
||||
CASESTR(LIT);
|
||||
CASESTR(ENDL);
|
||||
CASESTR(FIN);
|
||||
default:
|
||||
s = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
printf("%s %ld %d ", s, tok.str.ptr - content, tok.str.len);
|
||||
printspecial(tok.str.ptr, tok.str.len);
|
||||
|
||||
char buf[50];
|
||||
switch (tok.toktyp) {
|
||||
case TOK_INTEGER:
|
||||
printf(" %" PRId64, tok.u.int64);
|
||||
break;
|
||||
case TOK_FLOAT:
|
||||
printf(" %s", fmt_double(tok.u.fp64, buf, sizeof(buf)));
|
||||
break;
|
||||
case TOK_BOOL:
|
||||
printf(" %s", tok.u.b1 ? "true" : "false");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static char *readfile(const char *fname, int *ret_len) {
|
||||
FILE *fp = fopen(fname, "r");
|
||||
if (!fp) {
|
||||
perror("fopen");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Seek to the end of the file to determine its size
|
||||
if (fseek(fp, 0, SEEK_END) != 0) {
|
||||
perror("fseek");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
long file_size = ftell(fp);
|
||||
if (file_size == -1) {
|
||||
perror("ftell");
|
||||
exit(1);
|
||||
}
|
||||
rewind(fp); // Go back to the beginning of the file
|
||||
|
||||
// Allocate memory for the file content, plus one for the null terminator
|
||||
char *content = malloc(file_size + 1);
|
||||
if (!content) {
|
||||
perror("out of memory");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Read the file into the buffer
|
||||
size_t read_size = fread(content, 1, file_size, fp);
|
||||
if (read_size != (size_t)file_size) {
|
||||
perror("fread");
|
||||
exit(1);
|
||||
}
|
||||
content[file_size] = '\0'; // Null-terminate the string
|
||||
fclose(fp);
|
||||
|
||||
*ret_len = file_size;
|
||||
return content;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
g_argc = argc;
|
||||
g_argv = argv;
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
}
|
||||
int len;
|
||||
char *content = readfile(argv[1], &len);
|
||||
char errbuf[200];
|
||||
|
||||
scanner_t scanner;
|
||||
scanner_t *sp = &scanner;
|
||||
scan_init(sp, content, len, errbuf, sizeof(errbuf));
|
||||
|
||||
for (;;) {
|
||||
(void)scan_key; // silent compiler
|
||||
token_t tok;
|
||||
if (scan_value(sp, &tok)) {
|
||||
printf("%s\n", errbuf);
|
||||
goto bail;
|
||||
}
|
||||
if (tok.toktyp == TOK_FIN) {
|
||||
break;
|
||||
}
|
||||
printtok(content, tok);
|
||||
}
|
||||
|
||||
if (sp->errmsg) {
|
||||
printf("ERROR: %s (line %d)\n", sp->errmsg, sp->lineno);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
free(content);
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
free(content);
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user