add config support
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
#include "../../src/tomlc17.c"
|
||||
#include <inttypes.h>
|
||||
|
||||
const char **g_argv = 0;
|
||||
int g_argc = 0;
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr, "Usage: %s [fname]\n", g_argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Print a string in json. Properly escape special chars.
|
||||
static void print_string(const char *s, int len) {
|
||||
printf("{\"type\": \"string\", \"value\": \"");
|
||||
for (int i = 0; i < len; i++) {
|
||||
int ch = s[i];
|
||||
if (isprint(ch) && ch != '\"' && ch != '\\') {
|
||||
putchar(ch);
|
||||
continue;
|
||||
}
|
||||
switch (ch) {
|
||||
case '\b':
|
||||
putchar('\\');
|
||||
putchar('b');
|
||||
break; // Escape backspace
|
||||
case '\t':
|
||||
putchar('\\');
|
||||
putchar('t');
|
||||
break; // Escape tab
|
||||
case '\n':
|
||||
putchar('\\');
|
||||
putchar('n');
|
||||
break; // Escape newline
|
||||
case '\f':
|
||||
putchar('\\');
|
||||
putchar('f');
|
||||
break; // Escape formfeed
|
||||
case '\r':
|
||||
putchar('\\');
|
||||
putchar('r');
|
||||
break; // Escape carriage return
|
||||
case '"':
|
||||
putchar('\\');
|
||||
putchar('"');
|
||||
break; // Escape double quotes
|
||||
case '\\':
|
||||
putchar('\\');
|
||||
putchar('\\');
|
||||
break; // Escape backslash
|
||||
default:
|
||||
if (0 <= ch && ch < ' ') {
|
||||
printf("\\u%04x", ch);
|
||||
} else {
|
||||
putchar(ch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\"}");
|
||||
}
|
||||
|
||||
// Print a key
|
||||
static void print_key(const char *s, int len) {
|
||||
putchar('"');
|
||||
for (int i = 0; i < len; i++) {
|
||||
int ch = s[i];
|
||||
if (isprint(ch) && ch != '\"' && ch != '\\') {
|
||||
putchar(ch);
|
||||
continue;
|
||||
}
|
||||
switch (ch) {
|
||||
case '"':
|
||||
putchar('\\');
|
||||
putchar('"');
|
||||
break; // Escape double quotes
|
||||
case '\\':
|
||||
putchar('\\');
|
||||
putchar('\\');
|
||||
break; // Escape backslash
|
||||
case '\b':
|
||||
putchar('\\');
|
||||
putchar('b');
|
||||
break; // Escape backspace
|
||||
case '\f':
|
||||
putchar('\\');
|
||||
putchar('f');
|
||||
break; // Escape formfeed
|
||||
case '\n':
|
||||
putchar('\\');
|
||||
putchar('n');
|
||||
break; // Escape newline
|
||||
case '\r':
|
||||
putchar('\\');
|
||||
putchar('r');
|
||||
break; // Escape carriage return
|
||||
case '\t':
|
||||
putchar('\\');
|
||||
putchar('t');
|
||||
break; // Escape tab
|
||||
default:
|
||||
if (0 <= ch && ch < ' ') {
|
||||
printf("\\u%04x", ch);
|
||||
} else {
|
||||
putchar(ch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
putchar('"');
|
||||
}
|
||||
|
||||
// Print a DATE datum
|
||||
static void print_date(toml_datum_t datum) {
|
||||
printf("{\"type\": \"date-local\", \"value\": \"%04d-%02d-%02d\"}",
|
||||
datum.u.ts.year, datum.u.ts.month, datum.u.ts.day);
|
||||
}
|
||||
|
||||
// Print a TIME datum
|
||||
static void print_time(toml_datum_t datum) {
|
||||
char fracstr[20];
|
||||
fracstr[0] = fracstr[1] = '\0';
|
||||
if (datum.u.ts.usec) {
|
||||
double f = datum.u.ts.usec / 1000000.0;
|
||||
snprintf(fracstr, sizeof(fracstr), "%.6f", f);
|
||||
fracstr[5] = '\0'; // millisec precision
|
||||
}
|
||||
printf("{\"type\": \"time-local\", \"value\": \"%02d:%02d:%02d%s\"}",
|
||||
datum.u.ts.hour, datum.u.ts.minute, datum.u.ts.second, fracstr + 1);
|
||||
}
|
||||
|
||||
// Print a DATETIME datum
|
||||
static void print_datetime(toml_datum_t datum) {
|
||||
char fracstr[20];
|
||||
fracstr[0] = fracstr[1] = '\0';
|
||||
if (datum.u.ts.usec) {
|
||||
double f = datum.u.ts.usec / 1000000.0;
|
||||
snprintf(fracstr, sizeof(fracstr), "%.6f", f);
|
||||
fracstr[5] = '\0'; // millisec precision
|
||||
}
|
||||
printf("{\"type\": \"datetime-local\", \"value\": \"%04d-%02d-%02d "
|
||||
"%02d:%02d:%02d%s\"}",
|
||||
datum.u.ts.year, datum.u.ts.month, datum.u.ts.day, datum.u.ts.hour,
|
||||
datum.u.ts.minute, datum.u.ts.second, fracstr + 1);
|
||||
}
|
||||
|
||||
// Print a DATETIMETZ datum
|
||||
static void print_datetimetz(toml_datum_t datum) {
|
||||
char fracstr[20];
|
||||
char tzstr[20];
|
||||
fracstr[0] = fracstr[1] = tzstr[0] = '\0';
|
||||
if (datum.u.ts.usec) {
|
||||
double f = datum.u.ts.usec / 1000000.0;
|
||||
snprintf(fracstr, sizeof(fracstr), "%.6f", f);
|
||||
fracstr[5] = '\0'; // millisec precision
|
||||
}
|
||||
int tz = datum.u.ts.tz;
|
||||
char sign = tz < 0 ? '-' : '+';
|
||||
tz = tz < 0 ? -tz : tz;
|
||||
snprintf(tzstr, sizeof(tzstr), "%c%02d:%02d", sign, tz / 60, tz % 60);
|
||||
|
||||
printf("{\"type\": \"datetime\", \"value\": \"%04d-%02d-%02d "
|
||||
"%02d:%02d:%02d%s%s\"}",
|
||||
datum.u.ts.year, datum.u.ts.month, datum.u.ts.day, datum.u.ts.hour,
|
||||
datum.u.ts.minute, datum.u.ts.second, fracstr + 1, tzstr);
|
||||
}
|
||||
|
||||
// Print indent spaces
|
||||
int indent_level = 0;
|
||||
static int indent() {
|
||||
for (int i = 0; i < indent_level * 2; i++) {
|
||||
putchar(' ');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Print datum tree recursively
|
||||
static void print_datum(toml_datum_t datum) {
|
||||
char buf[50];
|
||||
|
||||
switch (datum.type) {
|
||||
case TOML_STRING:
|
||||
print_string(datum.u.str.ptr, datum.u.str.len);
|
||||
break;
|
||||
case TOML_INT64:
|
||||
printf("{\"type\": \"integer\", \"value\": \"%" PRId64 "\"}",
|
||||
datum.u.int64);
|
||||
break;
|
||||
case TOML_FP64:
|
||||
printf("{\"type\": \"float\", \"value\": \"%s\"}",
|
||||
fmt_double(datum.u.fp64, buf, sizeof(buf)));
|
||||
break;
|
||||
case TOML_BOOLEAN:
|
||||
printf("{\"type\": \"bool\", \"value\": \"%s\"}",
|
||||
datum.u.boolean ? "true" : "false");
|
||||
break;
|
||||
case TOML_DATE:
|
||||
print_date(datum);
|
||||
break;
|
||||
case TOML_TIME:
|
||||
print_time(datum);
|
||||
break;
|
||||
case TOML_DATETIME:
|
||||
print_datetime(datum);
|
||||
break;
|
||||
case TOML_DATETIMETZ:
|
||||
print_datetimetz(datum);
|
||||
break;
|
||||
case TOML_ARRAY:
|
||||
printf("[");
|
||||
for (int i = 0; i < datum.u.arr.size; i++) {
|
||||
printf("%s", i ? ", " : "");
|
||||
print_datum(datum.u.arr.elem[i]);
|
||||
}
|
||||
printf("]");
|
||||
break;
|
||||
case TOML_TABLE:
|
||||
printf("{\n");
|
||||
indent_level++;
|
||||
for (int i = 0; i < datum.u.tab.size; i++) {
|
||||
printf("%s", i ? ",\n" : "");
|
||||
indent();
|
||||
print_key(datum.u.tab.key[i], datum.u.tab.len[i]);
|
||||
putchar(':');
|
||||
putchar(' ');
|
||||
print_datum(datum.u.tab.value[i]);
|
||||
}
|
||||
printf("\n");
|
||||
indent_level--;
|
||||
indent(), printf("}");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: unimplemented datum type %d\n", datum.type);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
g_argc = argc;
|
||||
g_argv = argv;
|
||||
if (argc > 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
toml_option_t opt = toml_default_option();
|
||||
opt.check_utf8 = 1;
|
||||
toml_set_option(opt);
|
||||
|
||||
toml_result_t result;
|
||||
if (argc == 2) {
|
||||
result = toml_parse_file_ex(argv[1]);
|
||||
} else {
|
||||
result = toml_parse_file(stdin);
|
||||
}
|
||||
|
||||
if (!result.ok) {
|
||||
printf("%s\n", result.errmsg);
|
||||
toml_free(result);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print_datum(result.toptab);
|
||||
printf("\n");
|
||||
|
||||
toml_free(result);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user