#include "../../src/tomlc17.c" #include 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; }