diff --git a/qse/cmd/xli/xli.c b/qse/cmd/xli/xli.c index 4cfaf4f8..35b109b9 100644 --- a/qse/cmd/xli/xli.c +++ b/qse/cmd/xli/xli.c @@ -56,6 +56,10 @@ # include #endif +#define IO_FLAG_INI_INPUT (1 << 0) +#define IO_FLAG_INI_OUTPUT (1 << 1) + +static int g_io_flags = 0; static qse_char_t* g_input_file = QSE_NULL; static qse_char_t* g_output_file = QSE_NULL; static qse_char_t* g_lookup_key = QSE_NULL; @@ -151,6 +155,8 @@ static void print_usage (qse_sio_t* out, int argc, qse_char_t* argv[]) qse_fprintf (out, QSE_T(" --version show version\n")); qse_fprintf (out, QSE_T(" -i file specify an input file\n")); qse_fprintf (out, QSE_T(" -o file specify an output file\n")); + qse_fprintf (out, QSE_T(" -I file specify an ini input file\n")); + qse_fprintf (out, QSE_T(" -O file specify an ini output file\n")); qse_fprintf (out, QSE_T(" -u disallow duplicate keys\n")); qse_fprintf (out, QSE_T(" -a allow a key alias\n")); qse_fprintf (out, QSE_T(" -f keep file inclusion info\n")); @@ -188,9 +194,9 @@ static int handle_args (int argc, qse_char_t* argv[]) static qse_opt_t opt = { #if defined(QSE_BUILD_DEBUG) - QSE_T("hi:o:uaftsdnlKSvm:X:"), + QSE_T("hi:o:I:O:uaftsdnlKSvm:X:"), #else - QSE_T("hi:o:uaftsdnlKSvm:"), + QSE_T("hi:o:I:O:uaftsdnlKSvm:"), #endif lng }; @@ -226,10 +232,22 @@ static int handle_args (int argc, qse_char_t* argv[]) case QSE_T('i'): g_input_file = opt.arg; + g_io_flags &= ~IO_FLAG_INI_INPUT; + break; + + case QSE_T('I'): + g_input_file = opt.arg; + g_io_flags |= IO_FLAG_INI_INPUT; break; case QSE_T('o'): g_output_file = opt.arg; + g_io_flags &= ~IO_FLAG_INI_OUTPUT; + break; + + case QSE_T('O'): + g_output_file = opt.arg; + g_io_flags |= IO_FLAG_INI_OUTPUT; break; case QSE_T('u'): @@ -368,7 +386,7 @@ static int xli_main (int argc, qse_char_t* argv[]) qse_mmgr_t* mmgr = QSE_MMGR_GETDFL(); qse_xli_t* xli = QSE_NULL; qse_xli_iostd_t in, out; - int ret = -1; + int ret = -1, n; ret = handle_args (argc, argv); if (ret <= -1) return -1; @@ -413,7 +431,8 @@ static int xli_main (int argc, qse_char_t* argv[]) in.u.file.path = g_input_file; in.u.file.cmgr = g_infile_cmgr; - if (qse_xli_readinistd (xli, &in) <= -1) + n = (g_io_flags & IO_FLAG_INI_INPUT)? qse_xli_readinistd(xli, &in): qse_xli_readstd(xli, &in); + if (n <= -1) { const qse_xli_loc_t* errloc; @@ -506,7 +525,8 @@ static int xli_main (int argc, qse_char_t* argv[]) out.type = QSE_XLI_IOSTD_FILE; out.u.file.path = g_output_file? g_output_file: QSE_T("-"); out.u.file.cmgr = g_outfile_cmgr; - ret = qse_xli_writestd (xli, &out); + + ret = (g_io_flags & IO_FLAG_INI_OUTPUT)? qse_xli_writeinistd(xli, &out): qse_xli_writestd(xli, &out); oops: if (xli) qse_xli_close (xli); diff --git a/qse/lib/xli/read-ini.c b/qse/lib/xli/read-ini.c index b9ced29a..0662dc68 100644 --- a/qse/lib/xli/read-ini.c +++ b/qse/lib/xli/read-ini.c @@ -471,7 +471,7 @@ int qse_xli_readini (qse_xli_t* xli, qse_xli_io_impl_t io) QSE_ASSERT (QSE_STR_LEN(xli->dotted_curkey) == 0); - if (qse_xli_openstream (xli, xli->rio.inp) <= -1) return -1; + if (qse_xli_openrstream (xli, xli->rio.inp) <= -1) return -1; /* the input stream is open now */ if (read_root_list (xli) <= -1) goto oops; @@ -483,7 +483,7 @@ int qse_xli_readini (qse_xli_t* xli, qse_xli_io_impl_t io) } QSE_ASSERT (xli->rio.inp == &xli->rio.top); - qse_xli_closecurrentstream (xli); + qse_xli_closeactiverstream (xli); qse_str_clear (xli->tok.name); return 0; @@ -496,7 +496,7 @@ oops: qse_xli_io_arg_t* prev; /* nothing much to do about a close error */ - qse_xli_closecurrentstream (xli); + qse_xli_closeactiverstream (xli); prev = xli->rio.inp->prev; QSE_ASSERT (xli->rio.inp->name != QSE_NULL); @@ -504,7 +504,7 @@ oops: xli->rio.inp = prev; } - qse_xli_closecurrentstream (xli); + qse_xli_closeactiverstream (xli); qse_str_clear (xli->tok.name); return -1; } diff --git a/qse/lib/xli/read.c b/qse/lib/xli/read.c index 208168f7..876ab452 100644 --- a/qse/lib/xli/read.c +++ b/qse/lib/xli/read.c @@ -37,7 +37,7 @@ enum static qse_xli_scm_t scm_val_iffy = { QSE_XLI_SCM_VALSTR | QSE_XLI_SCM_KEYNODUP, 1, 1 }; -int qse_xli_openstream (qse_xli_t* xli, qse_xli_io_arg_t* arg) +int qse_xli_openrstream (qse_xli_t* xli, qse_xli_io_arg_t* arg) { qse_ssize_t n; @@ -52,7 +52,7 @@ int qse_xli_openstream (qse_xli_t* xli, qse_xli_io_arg_t* arg) return 0; } -int qse_xli_closecurrentstream (qse_xli_t* xli) +int qse_xli_closeactiverstream (qse_xli_t* xli) { qse_ssize_t n; @@ -67,8 +67,6 @@ int qse_xli_closecurrentstream (qse_xli_t* xli) return 0; } - - #define GET_CHAR(xli) \ do { if (qse_xli_getchar(xli) <= -1) return -1; } while(0) @@ -402,7 +400,7 @@ static int begin_include (qse_xli_t* xli) /* let the argument's prev point field to the current */ arg->prev = xli->rio.inp; - if (qse_xli_openstream(xli, arg) <= -1) goto oops; + if (qse_xli_openrstream(xli, arg) <= -1) goto oops; /* i update the current pointer after opening is successful */ xli->rio.inp = arg; @@ -1186,7 +1184,7 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io) QSE_ASSERT (QSE_STR_LEN(xli->dotted_curkey) == 0); - if (qse_xli_openstream (xli, xli->rio.inp) <= -1) return -1; + if (qse_xli_openrstream (xli, xli->rio.inp) <= -1) return -1; /* the input stream is open now */ if (read_root_list (xli) <= -1) goto oops; @@ -1200,7 +1198,7 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io) } QSE_ASSERT (xli->rio.inp == &xli->rio.top); - qse_xli_closecurrentstream (xli); + qse_xli_closeactiverstream (xli); qse_str_clear (xli->tok.name); return 0; @@ -1213,7 +1211,7 @@ oops: qse_xli_io_arg_t* prev; /* nothing much to do about a close error */ - qse_xli_closecurrentstream (xli); + qse_xli_closeactiverstream (xli); prev = xli->rio.inp->prev; QSE_ASSERT (xli->rio.inp->name != QSE_NULL); @@ -1221,7 +1219,7 @@ oops: xli->rio.inp = prev; } - qse_xli_closecurrentstream (xli); + qse_xli_closeactiverstream (xli); qse_str_clear (xli->tok.name); return -1; } diff --git a/qse/lib/xli/write-ini.c b/qse/lib/xli/write-ini.c index e9d163bb..9b494d34 100644 --- a/qse/lib/xli/write-ini.c +++ b/qse/lib/xli/write-ini.c @@ -26,7 +26,154 @@ #include "xli.h" +static int write_to_current_stream (qse_xli_t* xli, const qse_char_t* ptr, qse_size_t len) +{ + qse_xli_io_arg_t* arg; + qse_size_t i; + + arg = xli->wio.inp; + + for (i = 0; i < len; i++) + { + if (arg->b.len + 1 > QSE_COUNTOF(arg->b.buf) && qse_xli_flushwstream (xli, arg) <= -1) return -1; + arg->b.buf[arg->b.len++] = ptr[i]; + } + + return 0; +} + +static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) +{ + qse_xli_atom_t* curatom; + + for (curatom = list->head; curatom; curatom = curatom->next) + { + switch (curatom->type) + { + case QSE_XLI_PAIR: + { + qse_xli_pair_t* pair = (qse_xli_pair_t*)curatom; + + if (pair->tag) + { + /* the tag can't be written. so ignore it */ + /* do nothing */ + } + + if (depth <= 0) + { + if (write_to_current_stream (xli, QSE_T("["), 1) <= -1 || + write_to_current_stream (xli, pair->key, qse_strlen(pair->key)) <= -1 || + write_to_current_stream (xli, QSE_T("]\n"), 2) <= -1) return -1; + } + else + { + if (write_to_current_stream (xli, pair->key, qse_strlen(pair->key)) <= -1) return -1; + } + + if (pair->alias) + { + /* no alias is supported. so ignore it */ + /* do nothing */ + } + + switch (pair->val->type) + { + case QSE_XLI_NIL: + if (write_to_current_stream (xli, QSE_T("\n"), 1) <= -1) return -1; + break; + + case QSE_XLI_STR: + { + qse_xli_str_t* str = (qse_xli_str_t*)pair->val; + + if (depth > 0) + { + /* key = value is not supported at the top level */ + + if (write_to_current_stream (xli, QSE_T(" = "), 3) <= -1) return -1; + while (1) + { + if (str->tag) + { + /* no string tag is supported. ignore it */ + /* do nothing */ + } + + if (write_to_current_stream (xli, str->ptr, str->len) <= -1) return -1; + + #if 0 + if (!str->next) break; + + if (write_to_current_stream (xli, QSE_T(", "), 2) <= -1) return -1; + str = str->next; + #else + /* no multi-segment string is supported. ignore it */ + break; + #endif + } + } + + if (write_to_current_stream (xli, QSE_T("\n"), 1) <= -1) return -1; + break; + } + + case QSE_XLI_LIST: + if (write_list (xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1) return -1; + break; + } + break; + } + + case QSE_XLI_TEXT: + { + const qse_char_t* str = ((qse_xli_text_t*)curatom)->ptr; + + if (write_to_current_stream (xli, QSE_T(";"), 1) <= -1 || + write_to_current_stream (xli, str, qse_strlen(str)) <= -1 || + write_to_current_stream (xli, QSE_T("\n"), 1) <= -1) return -1; + break; + } + + case QSE_XLI_FILE: + /* no file inclusion is supported by the ini-format. ignore it */ + break; + + case QSE_XLI_EOF: + /* no file inclusion is supported by the ini-format. so no EOF. ignore it */ + break; + } + } + + return 0; +} + int qse_xli_writeini (qse_xli_t* xli, qse_xli_io_impl_t io) { -return -1; + int n; + + if (io == QSE_NULL) + { + qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); + return -1; + } + + QSE_MEMSET (&xli->wio, 0, QSE_SIZEOF(xli->wio)); + xli->wio.impl = io; + xli->wio.inp = &xli->wio.top; + + qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL); + qse_xli_clearwionames (xli); + + /* open the top level stream */ + if (qse_xli_openwstream (xli, QSE_NULL, 0) <= -1) return -1; + + /* begin writing the root list */ + n = write_list (xli, &xli->root->list, 0); + + /* close all open streams. there should be only the + * top-level stream here if there occurred no errors */ + while (xli->wio.inp) qse_xli_closeactivewstream (xli, QSE_NULL); + + return n; } diff --git a/qse/lib/xli/write.c b/qse/lib/xli/write.c index 6f9e8539..f7da194d 100644 --- a/qse/lib/xli/write.c +++ b/qse/lib/xli/write.c @@ -32,7 +32,7 @@ struct arg_data_t int org_depth; }; -static int flush (qse_xli_t* xli, qse_xli_io_arg_t* arg) +int qse_xli_flushwstream (qse_xli_t* xli, qse_xli_io_arg_t* arg) { qse_ssize_t n; @@ -54,7 +54,7 @@ static int flush (qse_xli_t* xli, qse_xli_io_arg_t* arg) return 0; } -static int open_new_stream (qse_xli_t* xli, const qse_char_t* path, int old_depth) +int qse_xli_openwstream (qse_xli_t* xli, const qse_char_t* path, int old_depth) { qse_ssize_t n; qse_xli_io_arg_t* arg; @@ -107,14 +107,14 @@ static int open_new_stream (qse_xli_t* xli, const qse_char_t* path, int old_dept return 0; } -static int close_current_stream (qse_xli_t* xli, int* org_depth) +int qse_xli_closeactivewstream (qse_xli_t* xli, int* org_depth) { qse_ssize_t n; qse_xli_io_arg_t* arg; arg = xli->wio.inp; - flush (xli, arg); /* TODO: do i have to care about the result? */ + qse_xli_flushwstream (xli, arg); /* TODO: do i have to care about the result? */ n = xli->wio.impl (xli, QSE_XLI_IO_CLOSE, arg, QSE_NULL, 0); if (n <= -1) @@ -149,12 +149,12 @@ static int write_to_current_stream (qse_xli_t* xli, const qse_char_t* ptr, qse_s { if (escape && (ptr[i] == QSE_T('\\') || ptr[i] == QSE_T('\"'))) { - if (arg->b.len + 2 > QSE_COUNTOF(arg->b.buf) && flush (xli, arg) <= -1) return -1; + if (arg->b.len + 2 > QSE_COUNTOF(arg->b.buf) && qse_xli_flushwstream (xli, arg) <= -1) return -1; arg->b.buf[arg->b.len++] = QSE_T('\\'); } else { - if (arg->b.len + 1 > QSE_COUNTOF(arg->b.buf) && flush (xli, arg) <= -1) return -1; + if (arg->b.len + 1 > QSE_COUNTOF(arg->b.buf) && qse_xli_flushwstream (xli, arg) <= -1) return -1; } arg->b.buf[arg->b.len++] = ptr[i]; } @@ -292,13 +292,13 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) write_to_current_stream (xli, path, qse_strlen(path), 1) <= -1 || write_to_current_stream (xli, QSE_T("\";\n"), 3, 0) <= -1) return -1; - if (open_new_stream (xli, ((qse_xli_file_t*)curatom)->path, depth) <= -1) return -1; + if (qse_xli_openwstream (xli, ((qse_xli_file_t*)curatom)->path, depth) <= -1) return -1; depth = 0; break; } case QSE_XLI_EOF: - if (close_current_stream (xli, &depth) <= -1) return -1; + if (qse_xli_closeactivewstream (xli, &depth) <= -1) return -1; break; } } @@ -335,14 +335,14 @@ int qse_xli_write (qse_xli_t* xli, qse_xli_io_impl_t io) qse_xli_clearwionames (xli); /* open the top level stream */ - if (open_new_stream (xli, QSE_NULL, 0) <= -1) return -1; + if (qse_xli_openwstream (xli, QSE_NULL, 0) <= -1) return -1; /* begin writing the root list */ n = write_list (xli, &xli->root->list, 0); /* close all open streams. there should be only the * top-level stream here if there occurred no errors */ - while (xli->wio.inp) close_current_stream (xli, QSE_NULL); + while (xli->wio.inp) qse_xli_closeactivewstream (xli, QSE_NULL); return n; } diff --git a/qse/lib/xli/xli.h b/qse/lib/xli/xli.h index 106e0f37..fd1f4923 100644 --- a/qse/lib/xli/xli.h +++ b/qse/lib/xli/xli.h @@ -140,8 +140,12 @@ void qse_xli_clearwionames (qse_xli_t* xli); int qse_xli_getchar (qse_xli_t* xli); -int qse_xli_openstream (qse_xli_t* xli, qse_xli_io_arg_t* arg); -int qse_xli_closecurrentstream (qse_xli_t* xli); +int qse_xli_openrstream (qse_xli_t* xli, qse_xli_io_arg_t* arg); +int qse_xli_closeactiverstream (qse_xli_t* xli); + +int qse_xli_openwstream (qse_xli_t* xli, const qse_char_t* path, int old_depth); +int qse_xli_closeactivewstream (qse_xli_t* xli, int* org_depth); +int qse_xli_flushwstream (qse_xli_t* xli, qse_xli_io_arg_t* arg); qse_xli_list_link_t* qse_xli_makelistlink (qse_xli_t* xli, qse_xli_list_t* parlist); void qse_xli_freelistlink (qse_xli_t* xli, qse_xli_list_link_t* link);