Reorganized the directory structure

This commit is contained in:
2022-09-25 09:23:29 +09:00
parent 1bac167e2d
commit 84d1c4c55f
864 changed files with 11 additions and 12 deletions

20
lib/xli/Makefile.am Normal file
View File

@ -0,0 +1,20 @@
AUTOMAKE_OPTIONS = nostdinc
AM_CPPFLAGS = \
-I$(top_builddir)/include \
-I$(top_srcdir)/include
lib_LTLIBRARIES = libqsexli.la
libqsexli_la_SOURCES = xli-prv.h xli.c err.c \
read.c read-ini.c read-json.c \
write.c write-ini.c write-json.c \
std.c json.c
libqsexli_la_LDFLAGS = -L../cmn -L../si -version-info 1:0:0 -no-undefined
libqsexli_la_LIBADD = -lqsesi -lqsecmn
libqsexli_la_DEPENDENCIES = ../../lib/si/libqsesi.la ../../lib/cmn/libqsecmn.la
if ENABLE_CXX
libqsexli_la_SOURCES += SkvEnv.cpp
endif

785
lib/xli/Makefile.in Normal file
View File

@ -0,0 +1,785 @@
# Makefile.in generated by automake 1.16.2 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
@ENABLE_CXX_TRUE@am__append_1 = SkvEnv.cpp
subdir = lib/xli
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_sign.m4 \
$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
$(top_srcdir)/m4/ax_cxx_namespace.m4 \
$(top_srcdir)/m4/ax_lib_mysql.m4 $(top_srcdir)/m4/ax_numval.m4 \
$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/lx_find_mpi.m4 \
$(top_srcdir)/m4/qse_try_cflags.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/include/qse/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(libdir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
am__libqsexli_la_SOURCES_DIST = xli-prv.h xli.c err.c read.c \
read-ini.c read-json.c write.c write-ini.c write-json.c std.c \
json.c SkvEnv.cpp
@ENABLE_CXX_TRUE@am__objects_1 = SkvEnv.lo
am_libqsexli_la_OBJECTS = xli.lo err.lo read.lo read-ini.lo \
read-json.lo write.lo write-ini.lo write-json.lo std.lo \
json.lo $(am__objects_1)
libqsexli_la_OBJECTS = $(am_libqsexli_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
libqsexli_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(libqsexli_la_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES =
depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/SkvEnv.Plo ./$(DEPDIR)/err.Plo \
./$(DEPDIR)/json.Plo ./$(DEPDIR)/read-ini.Plo \
./$(DEPDIR)/read-json.Plo ./$(DEPDIR)/read.Plo \
./$(DEPDIR)/std.Plo ./$(DEPDIR)/write-ini.Plo \
./$(DEPDIR)/write-json.Plo ./$(DEPDIR)/write.Plo \
./$(DEPDIR)/xli.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_@AM_V@)
am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
am__v_CXX_0 = @echo " CXX " $@;
am__v_CXX_1 =
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
am__v_CXXLD_0 = @echo " CXXLD " $@;
am__v_CXXLD_1 =
SOURCES = $(libqsexli_la_SOURCES)
DIST_SOURCES = $(am__libqsexli_la_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/ac/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_MODE = @BUILD_MODE@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DL_LIBS = @DL_LIBS@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GREP = @GREP@
HAVE_CXX = @HAVE_CXX@
HAVE_CXX11 = @HAVE_CXX11@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LIPO = @LIPO@
LN_S = @LN_S@
LTDL_LIBS = @LTDL_LIBS@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MPICC = @MPICC@
MPI_CFLAGS = @MPI_CFLAGS@
MPI_CLDFLAGS = @MPI_CLDFLAGS@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_LDFLAGS = @MYSQL_LDFLAGS@
MYSQL_LIBS = @MYSQL_LIBS@
MYSQL_VERSION = @MYSQL_VERSION@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
PACKAGE_VERSION_PATCH = @PACKAGE_VERSION_PATCH@
PATH_SEPARATOR = @PATH_SEPARATOR@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
QSE_PROJECT_AUTHOR = @QSE_PROJECT_AUTHOR@
QSE_PROJECT_URL = @QSE_PROJECT_URL@
QUADMATH_LIBS = @QUADMATH_LIBS@
RANLIB = @RANLIB@
RM = @RM@
RMDIR = @RMDIR@
SED = @SED@
SENDFILE_LIBS = @SENDFILE_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKET_LIBS = @SOCKET_LIBS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
TRUE = @TRUE@
UCI_LIBS = @UCI_LIBS@
UNICOWS_LIBS = @UNICOWS_LIBS@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
ax_pthread_config = @ax_pthread_config@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = nostdinc
AM_CPPFLAGS = \
-I$(top_builddir)/include \
-I$(top_srcdir)/include
lib_LTLIBRARIES = libqsexli.la
libqsexli_la_SOURCES = xli-prv.h xli.c err.c read.c read-ini.c \
read-json.c write.c write-ini.c write-json.c std.c json.c \
$(am__append_1)
libqsexli_la_LDFLAGS = -L../cmn -L../si -version-info 1:0:0 -no-undefined
libqsexli_la_LIBADD = -lqsesi -lqsecmn
libqsexli_la_DEPENDENCIES = ../../lib/si/libqsesi.la ../../lib/cmn/libqsecmn.la
all: all-am
.SUFFIXES:
.SUFFIXES: .c .cpp .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/xli/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign lib/xli/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
}
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
done
clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libqsexli.la: $(libqsexli_la_OBJECTS) $(libqsexli_la_DEPENDENCIES) $(EXTRA_libqsexli_la_DEPENDENCIES)
$(AM_V_CXXLD)$(libqsexli_la_LINK) -rpath $(libdir) $(libqsexli_la_OBJECTS) $(libqsexli_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SkvEnv.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/err.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read-ini.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read-json.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/std.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/write-ini.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/write-json.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/write.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xli.Plo@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@echo '# dummy' >$@-t && $(am__mv) $@-t $@
am--depfiles: $(am__depfiles_remade)
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cpp.lo:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES)
installdirs:
for dir in "$(DESTDIR)$(libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-am
-rm -f ./$(DEPDIR)/SkvEnv.Plo
-rm -f ./$(DEPDIR)/err.Plo
-rm -f ./$(DEPDIR)/json.Plo
-rm -f ./$(DEPDIR)/read-ini.Plo
-rm -f ./$(DEPDIR)/read-json.Plo
-rm -f ./$(DEPDIR)/read.Plo
-rm -f ./$(DEPDIR)/std.Plo
-rm -f ./$(DEPDIR)/write-ini.Plo
-rm -f ./$(DEPDIR)/write-json.Plo
-rm -f ./$(DEPDIR)/write.Plo
-rm -f ./$(DEPDIR)/xli.Plo
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-libLTLIBRARIES
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/SkvEnv.Plo
-rm -f ./$(DEPDIR)/err.Plo
-rm -f ./$(DEPDIR)/json.Plo
-rm -f ./$(DEPDIR)/read-ini.Plo
-rm -f ./$(DEPDIR)/read-json.Plo
-rm -f ./$(DEPDIR)/read.Plo
-rm -f ./$(DEPDIR)/std.Plo
-rm -f ./$(DEPDIR)/write-ini.Plo
-rm -f ./$(DEPDIR)/write-json.Plo
-rm -f ./$(DEPDIR)/write.Plo
-rm -f ./$(DEPDIR)/xli.Plo
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-libLTLIBRARIES
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-libLTLIBRARIES install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

326
lib/xli/SkvEnv.cpp Normal file
View File

@ -0,0 +1,326 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/xli/SkvEnv.hpp>
#include <qse/xli/stdxli.h>
#include <qse/cmn/str.h>
#include "../cmn/mem-prv.h"
#include "xli-prv.h"
#define SCTN_KEY_SPLITTER QSE_T('*')
QSE_BEGIN_NAMESPACE(QSE)
static qse_char_t splitter[2] = { SCTN_KEY_SPLITTER, QSE_T('\0') };
SkvEnv::SkvEnv (Mmgr* mmgr): Mmged(mmgr), xli(QSE_NULL)
{
}
SkvEnv::~SkvEnv ()
{
if (this->xli) qse_xli_close (this->xli);
}
int SkvEnv::addItem (const qse_char_t* name, const qse_char_t* dval, ProbeProc probe)
{
qse_char_t* sctn, * key;
qse_size_t sctn_len, key_len;
ItemList::Node* np;
if (this->split_name(name, &sctn, &sctn_len, &key, &key_len) == -1) return -1;
for (np = this->item_list.getHeadNode(); np; np = np->getNextNode())
{
Item& item = np->getValue();
if (qse_strxcmp(sctn, sctn_len, item.sctn) == 0 &&
qse_strxcmp(key, key_len, item.key) == 0) return -1;
}
try { np = this->item_list.append (Item()); }
catch (...) { return -1; }
Item& item = np->getValue();
qse_strxncpy (item.sctn, QSE_COUNTOF(item.sctn), sctn, sctn_len);
qse_strxncpy (item.key, QSE_COUNTOF(item.key), key, key_len);
qse_strxjoin (
item.name, QSE_COUNTOF(item.name),
item.sctn, splitter, item.key, QSE_NULL);
qse_strxcpy (item.dval, QSE_COUNTOF(item.dval), dval);
item.probe = probe;
// set its default value
if (this->setValue(name, item.dval) <= -1)
{
this->item_list.remove (np);
return -1;
}
return 0;
}
int SkvEnv::removeItem (const qse_char_t* name)
{
qse_char_t* sctn, * key;
qse_size_t sctn_len, key_len;
if (this->split_name (name, &sctn, &sctn_len, &key, &key_len) == -1) return -1;
for (ItemList::Node* np = this->item_list.getHeadNode(); np; np = np->getNextNode())
{
Item& item = np->value;
if (qse_strxcmp(sctn, sctn_len, item.sctn) == 0 &&
qse_strxcmp(key, key_len, item.key) == 0)
{
this->item_list.remove (np);
return 0;
}
}
return -1;
}
const qse_char_t* SkvEnv::getValue (const qse_char_t* name) const
{
if (!this->xli) return QSE_NULL;
qse_xli_pair_t* pair = qse_xli_findpair(this->xli, QSE_NULL, name);
if (!pair) return QSE_NULL;
QSE_ASSERT (pair->val != QSE_NULL);
QSE_ASSERT (pair->val->type == QSE_XLI_STR);
return (((qse_xli_str_t*)pair->val))->ptr;
}
int SkvEnv::setValue (const qse_char_t* name, const qse_char_t* value)
{
qse_char_t* sctn, * key;
qse_size_t sctn_len, key_len;
if (this->split_name(name, &sctn, &sctn_len, &key, &key_len) <= -1) return -1;
if (!this->xli)
{
this->xli = qse_xli_openstdwithmmgr(this->getMmgr(), 0, 0, QSE_NULL);
if (!this->xli) return -1;
qse_xli_setopt (this->xli, QSE_XLI_KEYSPLITTER, splitter);
}
// find if the name is a registered item name.
for (ItemList::Node* np = this->item_list.getHeadNode(); np; np = np->getNextNode())
{
Item& item = np->value;
if (qse_strxcmp(sctn, sctn_len, item.sctn) == 0 &&
qse_strxcmp(key, key_len, item.key) == 0)
{
// if it's the registered item name, change the value.
return this->set_value_with_item (item, value);
}
}
return -1;
}
int SkvEnv::split_name (const qse_char_t* name, qse_char_t** sctn, qse_size_t* sctn_len, qse_char_t** key, qse_size_t* key_len)
{
QSE_ASSERT (name != QSE_NULL);
QSE_ASSERT (sctn != QSE_NULL);
QSE_ASSERT (sctn_len != QSE_NULL);
QSE_ASSERT (key != QSE_NULL);
QSE_ASSERT (key_len != QSE_NULL);
qse_char_t* p;
qse_cstr_t s, k;
p = qse_strtok(name, splitter, &s);
if (!p || s.len == 0) return -1;
qse_strtok(p, QSE_NULL, &k);
if (k.len == 0) return -1;
*sctn = s.ptr;
*sctn_len = s.len;
*key = k.ptr;
*key_len = k.len;
return 0;
}
int SkvEnv::set_value_with_item (Item& item, const qse_char_t* value)
{
#if 0
if (this->probe_item_value(item, value) <= -1) return -1;
qse_cstr_t v = { (qse_char_t*)value, qse_strlen(value) };
qse_xli_pair_t* pair;
pair = qse_xli_setpairwithstr(this->xli, QSE_NULL, item.name, &v, QSE_NULL);
if (!pair)
{
if (qse_xli_geterrnum(this->xli) != QSE_XLI_ENOENT) return -1;
pair = qse_xli_findpair(this->xli, QSE_NULL, item.sctn);
if (!pair)
{
pair = qse_xli_insertpairwithemptylist(this->xli, QSE_NULL, QSE_NULL, item.sctn, QSE_NULL, QSE_NULL);
if (!pair) return -1;
}
QSE_ASSERT (pair->val != QSE_NULL);
QSE_ASSERT (pair->val->type == QSE_XLI_LIST);
if (!qse_xli_insertpairwithstr(this->xli, (qse_xli_list_t*)pair->val, QSE_NULL, item.key, QSE_NULL, QSE_NULL, &v, QSE_NULL)) return -1;
}
this->accept_item_value (item, value);
return 0;
#else
// this function adds/updates the pair with the given value
// before it verifies the value. as long as verification is
// ok, the value is guaranteed to be set.
qse_cstr_t v = { (qse_char_t*)value, qse_strlen(value) };
qse_xli_pair_t* sctn_pair = QSE_NULL, * kv_pair = QSE_NULL;
sctn_pair = qse_xli_findpair(this->xli, QSE_NULL, item.sctn);
if (sctn_pair)
{
// section exists.
QSE_ASSERT (sctn_pair->val && sctn_pair->val->type == QSE_XLI_LIST);
kv_pair = qse_xli_findpair(this->xli, (qse_xli_list_t*)sctn_pair->val, item.key);
if (kv_pair)
{
// key also exists
qse_xli_pair_t* existing_kv_pair = kv_pair;
kv_pair = QSE_NULL;
sctn_pair = QSE_NULL;
qse_xli_str_t* newstrv = qse_xli_makestrval(this->xli, &v, QSE_NULL);
if (!newstrv) goto rollback;
if (this->call_probe_item_value(item, value) <= -1)
{
qse_xli_freeval (this->xli, (qse_xli_val_t*)newstrv);
goto rollback;
}
qse_xli_freeval (this->xli, existing_kv_pair->val);
existing_kv_pair->val = (qse_xli_val_t*)newstrv;
}
else
{
kv_pair = qse_xli_insertpairwithstr(this->xli, (qse_xli_list_t*)sctn_pair->val, QSE_NULL, item.key, QSE_NULL, QSE_NULL, &v, QSE_NULL);
sctn_pair = QSE_NULL;
if (!kv_pair) goto rollback;
if (this->call_probe_item_value(item, value) <= -1) goto rollback;
}
}
else
{
sctn_pair = qse_xli_insertpairwithemptylist(this->xli, QSE_NULL, QSE_NULL, item.sctn, QSE_NULL, QSE_NULL);
if (!sctn_pair) return -1;
kv_pair = qse_xli_insertpairwithstr(this->xli, (qse_xli_list_t*)sctn_pair->val, QSE_NULL, item.key, QSE_NULL, QSE_NULL, &v, QSE_NULL);
if (!kv_pair) goto rollback;
if (this->call_probe_item_value(item, value) <= -1) goto rollback;
}
return 0;
rollback:
if (kv_pair) qse_xli_deletepair (this->xli, kv_pair);
if (sctn_pair) qse_xli_deletepair (this->xli, sctn_pair);
return -1;
#endif
}
int SkvEnv::load (const qse_char_t* path)
{
qse_xli_t* xli;
if (!this->xli)
{
// this means that no items have been registered with
// this->addItem(). so loading is meaningless.
return -1;
}
xli = qse_xli_openstdwithmmgr (this->getMmgr(), 0, 0, QSE_NULL);
if (!xli) return -1;
qse_xli_setopt (xli, QSE_XLI_KEYSPLITTER, splitter);
qse_xli_iostd_t in;
QSE_MEMSET (&in, 0, QSE_SIZEOF(in));
in.type = QSE_XLI_IOSTD_FILE;
in.u.file.path = path;
if (qse_xli_readinistd(xli, &in) <= -1)
{
qse_xli_close (xli);
return -1;
}
for (ItemList::Node* np = this->item_list.getHeadNode(); np; np = np->getNextNode())
{
Item& item = np->value;
qse_xli_pair_t* pair;
pair = qse_xli_findpair(xli, QSE_NULL, item.name);
if (pair)
{
qse_xli_str_t* strv = (qse_xli_str_t*)pair->val;
this->set_value_with_item (item, strv->ptr);
// ignore failure.
}
}
// TODO: check if there are any unknown names. flag it via callbacks???
qse_xli_close(xli);
return 0;
}
int SkvEnv::store (const qse_char_t* path)
{
if (!this->xli) return -1;
qse_xli_iostd_t out;
QSE_MEMSET (&out, 0, QSE_SIZEOF(out));
out.type = QSE_XLI_IOSTD_FILE;
out.u.file.path = path;
return qse_xli_writeinistd(this->xli, QSE_NULL, &out);
}
QSE_END_NAMESPACE(QSE)

151
lib/xli/err.c Normal file
View File

@ -0,0 +1,151 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xli-prv.h"
#include "../cmn/mem-prv.h"
const qse_char_t* qse_xli_dflerrstr (const qse_xli_t* xli, qse_xli_errnum_t errnum)
{
static const qse_char_t* errstr[] =
{
QSE_T("no error"),
QSE_T("other error"),
QSE_T("not implemented"),
QSE_T("subsystem error"),
QSE_T("internal error that should never have happened"),
QSE_T("insufficient memory"),
QSE_T("invalid parameter or data"),
QSE_T("'${0}' not found"),
QSE_T("'${0}' already exists"),
QSE_T("I/O error with file '${0}'"),
QSE_T("error returned by user I/O handler"),
QSE_T("syntax error"),
QSE_T("colon expected in place of '${0}'"),
QSE_T("semicolon expected in place of '${0}'"),
QSE_T("equal-sign expected in place of '${0}'"),
QSE_T("left-brace or equal-sign expected in place of '${0}'"),
QSE_T("left-brace or left-bracket expected in place of '${0}'"),
QSE_T("right-brace expected in place of '${0}'"),
QSE_T("right-bracket expected in place of '${0}'"),
QSE_T("comma expected in place of '${0}'"),
QSE_T("value expected in place of '${0}'"),
QSE_T("string not closed"),
QSE_T("string tag not closed"),
QSE_T("'@include' not followed by a string"),
QSE_T("invalid character '${0}'"),
QSE_T("invalid tag character '${0}'"),
QSE_T("'${0}' not recognized"),
QSE_T("@ not followed by a valid word"),
QSE_T("invalid identifier '${0}'"),
QSE_T("key expected in place of '${0}'"),
QSE_T("missing key after key tag"),
QSE_T("undefined key '${0}'"),
QSE_T("no alias for '${0}'"),
QSE_T("value expected in place of '${0}'"),
QSE_T("illegal value for '${0}'"),
QSE_T("no value for '${0}'"),
QSE_T("uncomplying number of string segments for '${0}'"),
QSE_T("section tag expected in place of '${0}'")
};
return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))?
errstr[errnum]: QSE_T("unknown error");
}
qse_xli_errstr_t qse_xli_geterrstr (const qse_xli_t* xli)
{
return xli->errstr;
}
void qse_xli_seterrstr (qse_xli_t* xli, qse_xli_errstr_t errstr)
{
xli->errstr = errstr;
}
qse_xli_errnum_t qse_xli_geterrnum (const qse_xli_t* xli)
{
return xli->errnum;
}
const qse_xli_loc_t* qse_xli_geterrloc (const qse_xli_t* xli)
{
return &xli->errloc;
}
const qse_char_t* qse_xli_geterrmsg (const qse_xli_t* xli)
{
return (xli->errmsg[0] == QSE_T('\0'))?
qse_xli_geterrstr(xli)(xli,xli->errnum): xli->errmsg;
}
void qse_xli_geterror (
const qse_xli_t* xli, qse_xli_errnum_t* errnum,
const qse_char_t** errmsg, qse_xli_loc_t* errloc)
{
if (errnum != QSE_NULL) *errnum = xli->errnum;
if (errmsg != QSE_NULL)
{
*errmsg = (xli->errmsg[0] == QSE_T('\0'))?
qse_xli_geterrstr(xli)(xli,xli->errnum):
xli->errmsg;
}
if (errloc != QSE_NULL) *errloc = xli->errloc;
}
void qse_xli_seterrnum (
qse_xli_t* xli, qse_xli_errnum_t errnum, const qse_cstr_t* errarg)
{
qse_xli_seterror (xli, errnum, errarg, QSE_NULL);
}
void qse_xli_seterrmsg (
qse_xli_t* xli, qse_xli_errnum_t errnum,
const qse_char_t* errmsg, const qse_xli_loc_t* errloc)
{
xli->errnum = errnum;
qse_strxcpy (xli->errmsg, QSE_COUNTOF(xli->errmsg), errmsg);
if (errloc != QSE_NULL) xli->errloc = *errloc;
else QSE_MEMSET (&xli->errloc, 0, QSE_SIZEOF(xli->errloc));
}
void qse_xli_seterror (
qse_xli_t* xli, qse_xli_errnum_t errnum,
const qse_cstr_t* errarg, const qse_xli_loc_t* errloc)
{
const qse_char_t* errfmt;
xli->errnum = errnum;
errfmt = qse_xli_geterrstr(xli)(xli,xli->errnum);
QSE_ASSERT (errfmt != QSE_NULL);
qse_strxfncpy (xli->errmsg, QSE_COUNTOF(xli->errmsg), errfmt, errarg);
if (errloc != QSE_NULL) xli->errloc = *errloc;
else QSE_MEMSET (&xli->errloc, 0, QSE_SIZEOF(xli->errloc));
}

995
lib/xli/json.c Normal file
View File

@ -0,0 +1,995 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/xli/json.h>
#include <qse/cmn/chr.h>
#include <qse/cmn/str.h>
#include <qse/cmn/mbwc.h>
#include "../cmn/mem-prv.h"
#define QSE_JSON_TOKEN_NAME_ALIGN 64
typedef struct qse_json_state_node_t qse_json_state_node_t;
struct qse_json_state_node_t
{
qse_json_state_t state;
union
{
struct
{
int got_value;
} ia; /* in array */
struct
{
/* 0: ready to get key (at the beginning or got comma),
* 1: got key, 2: got colon, 3: got value */
int state;
} id; /* in dictionary */
struct
{
int escaped;
int digit_count;
/* acc is always of unicode type to handle \u and \U.
* in the bch mode, it will get converted to a utf8 stream. */
qse_wchar_t acc;
} sv;
struct
{
int escaped;
int digit_count;
/* for a character, no way to support the unicode character
* in the bch mode */
qse_char_t acc;
} cv;
struct
{
int dotted;
} nv;
} u;
qse_json_state_node_t* next;
};
struct qse_json_t
{
QSE_JSON_HDR;
qse_json_errnum_t errnum;
struct
{
qse_char_t backup[256];
qse_char_t buf[256];
/*qse_size_t len;*/
} errmsg;
qse_json_prim_t prim;
struct
{
int trait;
} cfg;
qse_json_state_node_t state_top;
qse_json_state_node_t* state_stack;
qse_cstr_t tok;
qse_size_t tok_capa;
};
/* ========================================================================= */
static void clear_token (qse_json_t* json)
{
json->tok.len = 0;
if (json->tok_capa > 0) json->tok.ptr[json->tok.len] = QSE_T('\0');
}
static int add_char_to_token (qse_json_t* json, qse_char_t ch)
{
if (json->tok.len >= json->tok_capa)
{
qse_char_t* tmp;
qse_size_t newcapa;
newcapa = QSE_ALIGNTO_POW2(json->tok.len + 2, QSE_JSON_TOKEN_NAME_ALIGN); /* +2 here because of -1 when setting newcapa */
tmp = (qse_char_t*)qse_json_reallocmem(json, json->tok.ptr, newcapa * QSE_SIZEOF(*tmp));
if (!tmp) return -1;
json->tok_capa = newcapa - 1; /* -1 to secure space for terminating null */
json->tok.ptr = tmp;
}
json->tok.ptr[json->tok.len++] = ch;
json->tok.ptr[json->tok.len] = QSE_T('\0');
return 0;
}
static int add_chars_to_token (qse_json_t* json, const qse_char_t* ptr, qse_size_t len)
{
qse_size_t i;
if (json->tok_capa - json->tok.len > len)
{
qse_char_t* tmp;
qse_size_t newcapa;
newcapa = QSE_ALIGNTO_POW2(json->tok.len + len + 1, QSE_JSON_TOKEN_NAME_ALIGN);
tmp = (qse_char_t*)qse_json_reallocmem(json, json->tok.ptr, newcapa * QSE_SIZEOF(*tmp));
if (!tmp) return -1;
json->tok_capa = newcapa - 1;
json->tok.ptr = tmp;
}
for (i = 0; i < len; i++)
json->tok.ptr[json->tok.len++] = ptr[i];
json->tok.ptr[json->tok.len] = QSE_T('\0');
return 0;
}
static QSE_INLINE qse_char_t unescape (qse_char_t c)
{
switch (c)
{
case QSE_T('a'): return QSE_T('\a');
case QSE_T('b'): return QSE_T('\b');
case QSE_T('f'): return QSE_T('\f');
case QSE_T('n'): return QSE_T('\n');
case QSE_T('r'): return QSE_T('\r');
case QSE_T('t'): return QSE_T('\t');
case QSE_T('v'): return QSE_T('\v');
default: return c;
}
}
/* ========================================================================= */
static int push_state (qse_json_t* json, qse_json_state_t state)
{
qse_json_state_node_t* ss;
ss = (qse_json_state_node_t*)qse_json_callocmem(json, QSE_SIZEOF(*ss));
if (!ss) return -1;
ss->state = state;
ss->next = json->state_stack;
json->state_stack = ss;
return 0;
}
static void pop_state (qse_json_t* json)
{
qse_json_state_node_t* ss;
ss = json->state_stack;
QSE_ASSERT (ss != QSE_NULL && ss != &json->state_top);
json->state_stack = ss->next;
if (json->state_stack->state == QSE_JSON_STATE_IN_ARRAY)
{
json->state_stack->u.ia.got_value = 1;
}
else if (json->state_stack->state == QSE_JSON_STATE_IN_DIC)
{
json->state_stack->u.id.state++;
}
/* TODO: don't free this. move it to the free list? */
qse_json_freemem (json, ss);
}
static void pop_all_states (qse_json_t* json)
{
while (json->state_stack != &json->state_top) pop_state (json);
}
/* ========================================================================= */
static int invoke_data_inst (qse_json_t* json, qse_json_inst_t inst)
{
if (json->state_stack->state == QSE_JSON_STATE_IN_DIC && json->state_stack->u.id.state == 1)
{
if (inst != QSE_JSON_INST_STRING)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("dictionary key not a string - %.*js"), (int)json->tok.len, json->tok.ptr);
return -1;
}
inst = QSE_JSON_INST_KEY;
}
if (json->prim.instcb(json, inst, &json->tok) <= -1) return -1;
return 0;
}
static int handle_string_value_char (qse_json_t* json, qse_cint_t c)
{
int ret = 1;
if (json->state_stack->u.sv.escaped == 3)
{
if (c >= '0' && c <= '7')
{
json->state_stack->u.sv.acc = json->state_stack->u.sv.acc * 8 + c - '0';
json->state_stack->u.sv.digit_count++;
if (json->state_stack->u.sv.digit_count >= json->state_stack->u.sv.escaped) goto add_sv_acc;
}
else
{
ret = 0;
goto add_sv_acc;
}
}
else if (json->state_stack->u.sv.escaped >= 2)
{
if (c >= '0' && c <= '9')
{
json->state_stack->u.sv.acc = json->state_stack->u.sv.acc * 16 + c - '0';
json->state_stack->u.sv.digit_count++;
if (json->state_stack->u.sv.digit_count >= json->state_stack->u.sv.escaped) goto add_sv_acc;
}
else if (c >= 'a' && c <= 'f')
{
json->state_stack->u.sv.acc = json->state_stack->u.sv.acc * 16 + c - 'a' + 10;
json->state_stack->u.sv.digit_count++;
if (json->state_stack->u.sv.digit_count >= json->state_stack->u.sv.escaped) goto add_sv_acc;
}
else if (c >= 'A' && c <= 'F')
{
json->state_stack->u.sv.acc = json->state_stack->u.sv.acc * 16 + c - 'A' + 10;
json->state_stack->u.sv.digit_count++;
if (json->state_stack->u.sv.digit_count >= json->state_stack->u.sv.escaped) goto add_sv_acc;
}
else
{
ret = 0;
add_sv_acc:
#if defined(QSE_CHAR_IS_WCHAR)
if (add_char_to_token(json, json->state_stack->u.sv.acc) <= -1) return -1;
#else
/* convert the character to utf8 */
{
qse_mchar_t bcsbuf[QSE_MBLEN_MAX];
qse_size_t n;
n = json->_cmgr->wctomb(json->state_stack->u.sv.acc, bcsbuf, QSE_COUNTOF(bcsbuf));
if (n == 0 || n > QSE_COUNTOF(bcsbuf))
{
/* illegal character or buffer to small */
qse_json_seterrfmt (json, QSE_JSON_EECERR, QSE_T("unable to convert %jc"), json->state_stack->u.sv.acc);
return -1;
}
if (add_chars_to_token(json, bcsbuf, n) <= -1) return -1;
}
#endif
json->state_stack->u.sv.escaped = 0;
}
}
else if (json->state_stack->u.sv.escaped == 1)
{
if (c >= '0' && c <= '8')
{
json->state_stack->u.sv.escaped = 3;
json->state_stack->u.sv.digit_count = 0;
json->state_stack->u.sv.acc = c - '0';
}
else if (c == 'x')
{
json->state_stack->u.sv.escaped = 2;
json->state_stack->u.sv.digit_count = 0;
json->state_stack->u.sv.acc = 0;
}
else if (c == 'u')
{
json->state_stack->u.sv.escaped = 4;
json->state_stack->u.sv.digit_count = 0;
json->state_stack->u.sv.acc = 0;
}
else if (c == 'U')
{
json->state_stack->u.sv.escaped = 8;
json->state_stack->u.sv.digit_count = 0;
json->state_stack->u.sv.acc = 0;
}
else
{
json->state_stack->u.sv.escaped = 0;
if (add_char_to_token(json, unescape(c)) <= -1) return -1;
}
}
else if (c == '\\')
{
json->state_stack->u.sv.escaped = 1;
}
else if (c == '\"')
{
pop_state (json);
if (invoke_data_inst(json, QSE_JSON_INST_STRING) <= -1) return -1;
}
else
{
if (add_char_to_token(json, c) <= -1) return -1;
}
return ret;
}
static int handle_character_value_char (qse_json_t* json, qse_cint_t c)
{
/* The real JSON dones't support character literal. this is HCL's own extension. */
int ret = 1;
if (json->state_stack->u.cv.escaped == 3)
{
if (c >= '0' && c <= '7')
{
json->state_stack->u.cv.acc = json->state_stack->u.cv.acc * 8 + c - '0';
json->state_stack->u.cv.digit_count++;
if (json->state_stack->u.cv.digit_count >= json->state_stack->u.cv.escaped) goto add_cv_acc;
}
else
{
ret = 0;
goto add_cv_acc;
}
}
if (json->state_stack->u.cv.escaped >= 2)
{
if (c >= '0' && c <= '9')
{
json->state_stack->u.cv.acc = json->state_stack->u.cv.acc * 16 + c - '0';
json->state_stack->u.cv.digit_count++;
if (json->state_stack->u.cv.digit_count >= json->state_stack->u.cv.escaped) goto add_cv_acc;
}
else if (c >= 'a' && c <= 'f')
{
json->state_stack->u.cv.acc = json->state_stack->u.cv.acc * 16 + c - 'a' + 10;
json->state_stack->u.cv.digit_count++;
if (json->state_stack->u.cv.digit_count >= json->state_stack->u.cv.escaped) goto add_cv_acc;
}
else if (c >= 'A' && c <= 'F')
{
json->state_stack->u.cv.acc = json->state_stack->u.cv.acc * 16 + c - 'A' + 10;
json->state_stack->u.cv.digit_count++;
if (json->state_stack->u.cv.digit_count >= json->state_stack->u.cv.escaped) goto add_cv_acc;
}
else
{
ret = 0;
add_cv_acc:
if (add_char_to_token(json, json->state_stack->u.cv.acc) <= -1) return -1;
json->state_stack->u.cv.escaped = 0;
}
}
else if (json->state_stack->u.cv.escaped == 1)
{
if (c >= '0' && c <= '8')
{
json->state_stack->u.cv.escaped = 3;
json->state_stack->u.cv.digit_count = 0;
json->state_stack->u.cv.acc = c - '0';
}
else if (c == 'x')
{
json->state_stack->u.cv.escaped = 2;
json->state_stack->u.cv.digit_count = 0;
json->state_stack->u.cv.acc = 0;
}
else if (c == 'u')
{
json->state_stack->u.cv.escaped = 4;
json->state_stack->u.cv.digit_count = 0;
json->state_stack->u.cv.acc = 0;
}
else if (c == 'U')
{
json->state_stack->u.cv.escaped = 8;
json->state_stack->u.cv.digit_count = 0;
json->state_stack->u.cv.acc = 0;
}
else
{
json->state_stack->u.cv.escaped = 0;
if (add_char_to_token(json, unescape(c)) <= -1) return -1;
}
}
else if (c == '\\')
{
json->state_stack->u.cv.escaped = 1;
}
else if (c == '\'')
{
pop_state (json);
if (json->tok.len < 1)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("no character in a character literal"));
return -1;
}
if (invoke_data_inst(json, QSE_JSON_INST_CHARACTER) <= -1) return -1;
}
else
{
if (add_char_to_token(json, c) <= -1) return -1;
}
if (json->tok.len > 1)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("too many characters in a character literal - %.*js"), (int)json->tok.len, json->tok.ptr);
return -1;
}
return ret;
}
static int handle_numeric_value_char (qse_json_t* json, qse_cint_t c)
{
if (QSE_ISMDIGIT(c) || (json->tok.len == 0 && (c == '+' || c == '-')))
{
if (add_char_to_token(json, c) <= -1) return -1;
return 1;
}
else if (!json->state_stack->u.nv.dotted && c == '.' &&
json->tok.len > 0 && QSE_ISMDIGIT(json->tok.ptr[json->tok.len - 1]))
{
if (add_char_to_token(json, c) <= -1) return -1;
json->state_stack->u.nv.dotted = 1;
return 1;
}
pop_state (json);
QSE_ASSERT (json->tok.len > 0);
if (!QSE_ISMDIGIT(json->tok.ptr[json->tok.len - 1]))
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("invalid numeric value - %.*js"), (int)json->tok.len, json->tok.ptr);
return -1;
}
if (invoke_data_inst(json, QSE_JSON_INST_NUMBER) <= -1) return -1;
return 0; /* start over */
}
static int handle_word_value_char (qse_json_t* json, qse_cint_t c)
{
qse_json_inst_t inst;
if (QSE_ISMALPHA(c))
{
if (add_char_to_token(json, c) <= -1) return -1;
return 1;
}
pop_state (json);
if (qse_strxcmp(json->tok.ptr, json->tok.len, QSE_T("null")) == 0) inst = QSE_JSON_INST_NIL;
else if (qse_strxcmp(json->tok.ptr, json->tok.len, QSE_T("true")) == 0) inst = QSE_JSON_INST_TRUE;
else if (qse_strxcmp(json->tok.ptr, json->tok.len, QSE_T("false")) == 0) inst = QSE_JSON_INST_FALSE;
else
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("invalid word value - %.*js"), (int)json->tok.len, json->tok.ptr);
return -1;
}
if (invoke_data_inst(json, inst) <= -1) return -1;
return 0; /* start over */
}
/* ========================================================================= */
static int handle_start_char (qse_json_t* json, qse_cint_t c)
{
if (c == '[')
{
if (push_state(json, QSE_JSON_STATE_IN_ARRAY) <= -1) return -1;
json->state_stack->u.ia.got_value = 0;
if (json->prim.instcb(json, QSE_JSON_INST_START_ARRAY, QSE_NULL) <= -1) return -1;
return 1;
}
else if (c == '{')
{
if (push_state(json, QSE_JSON_STATE_IN_DIC) <= -1) return -1;
json->state_stack->u.id.state = 0;
if (json->prim.instcb(json, QSE_JSON_INST_START_DIC, QSE_NULL) <= -1) return -1;
return 1;
}
else if (QSE_ISMSPACE(c))
{
/* do nothing */
return 1;
}
else
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("not starting with [ or { - %jc"), (qse_char_t)c);
return -1;
}
}
static int handle_char_in_array (qse_json_t* json, qse_cint_t c)
{
if (c == ']')
{
if (json->prim.instcb(json, QSE_JSON_INST_END_ARRAY, QSE_NULL) <= -1) return -1;
pop_state (json);
return 1;
}
else if (c == ',')
{
if (!json->state_stack->u.ia.got_value)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("redundant comma in array - %jc"), (qse_char_t)c);
return -1;
}
json->state_stack->u.ia.got_value = 0;
return 1;
}
else if (QSE_ISMSPACE(c))
{
/* do nothing */
return 1;
}
else
{
if (json->state_stack->u.ia.got_value)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("comma required in array - %jc"), (qse_char_t)c);
return -1;
}
if (c == '\"')
{
if (push_state(json, QSE_JSON_STATE_IN_STRING_VALUE) <= -1) return -1;
clear_token (json);
return 1;
}
else if (c == '\'')
{
if (push_state(json, QSE_JSON_STATE_IN_CHARACTER_VALUE) <= -1) return -1;
clear_token (json);
return 1;
}
/* TOOD: else if (c == '#') HCL radixed number
*/
else if (QSE_ISMDIGIT(c) || c == '+' || c == '-')
{
if (push_state(json, QSE_JSON_STATE_IN_NUMERIC_VALUE) <= -1) return -1;
clear_token (json);
json->state_stack->u.nv.dotted = 0;
return 0; /* start over */
}
else if (QSE_ISMALPHA(c))
{
if (push_state(json, QSE_JSON_STATE_IN_WORD_VALUE) <= -1) return -1;
clear_token (json);
return 0; /* start over */
}
else if (c == '[')
{
if (push_state(json, QSE_JSON_STATE_IN_ARRAY) <= -1) return -1;
json->state_stack->u.ia.got_value = 0;
if (json->prim.instcb(json, QSE_JSON_INST_START_ARRAY, QSE_NULL) <= -1) return -1;
return 1;
}
else if (c == '{')
{
if (push_state(json, QSE_JSON_STATE_IN_DIC) <= -1) return -1;
json->state_stack->u.id.state = 0;
if (json->prim.instcb(json, QSE_JSON_INST_START_DIC, QSE_NULL) <= -1) return -1;
return 1;
}
else
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("wrong character inside array - %jc[%d]"), (qse_char_t)c, (int)c);
return -1;
}
}
}
static int handle_char_in_dic (qse_json_t* json, qse_cint_t c)
{
if (c == '}')
{
if (json->prim.instcb(json, QSE_JSON_INST_END_DIC, QSE_NULL) <= -1) return -1;
pop_state (json);
return 1;
}
else if (c == ':')
{
if (json->state_stack->u.id.state != 1)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("redundant colon in dictionary - %jc"), (qse_char_t)c);
return -1;
}
json->state_stack->u.id.state++;
return 1;
}
else if (c == ',')
{
if (json->state_stack->u.id.state != 3)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("redundant comma in dicitonary - %jc"), (qse_char_t)c);
return -1;
}
json->state_stack->u.id.state = 0;
return 1;
}
else if (QSE_ISMSPACE(c))
{
/* do nothing */
return 1;
}
else
{
if (json->state_stack->u.id.state == 1)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("colon required in dicitonary - %jc"), (qse_char_t)c);
return -1;
}
else if (json->state_stack->u.id.state == 3)
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("comma required in dicitonary - %jc"), (qse_char_t)c);
return -1;
}
if (c == '\"')
{
if (push_state(json, QSE_JSON_STATE_IN_STRING_VALUE) <= -1) return -1;
clear_token (json);
return 1;
}
else if (c == '\'')
{
if (push_state(json, QSE_JSON_STATE_IN_CHARACTER_VALUE) <= -1) return -1;
clear_token (json);
return 1;
}
/* TOOD: else if (c == '#') HCL radixed number
*/
else if (QSE_ISMDIGIT(c) || c == '+' || c == '-')
{
if (push_state(json, QSE_JSON_STATE_IN_NUMERIC_VALUE) <= -1) return -1;
clear_token (json);
json->state_stack->u.nv.dotted = 0;
return 0; /* start over */
}
else if (QSE_ISMALPHA(c))
{
if (push_state(json, QSE_JSON_STATE_IN_WORD_VALUE) <= -1) return -1;
clear_token (json);
return 0; /* start over */
}
else if (c == '[')
{
if (push_state(json, QSE_JSON_STATE_IN_ARRAY) <= -1) return -1;
json->state_stack->u.ia.got_value = 0;
if (json->prim.instcb(json, QSE_JSON_INST_START_ARRAY, QSE_NULL) <= -1) return -1;
return 1;
}
else if (c == '{')
{
if (push_state(json, QSE_JSON_STATE_IN_DIC) <= -1) return -1;
json->state_stack->u.id.state = 0;
if (json->prim.instcb(json, QSE_JSON_INST_START_DIC, QSE_NULL) <= -1) return -1;
return 1;
}
else
{
qse_json_seterrfmt (json, QSE_JSON_EINVAL, QSE_T("wrong character inside dictionary - %jc[%d]"), (qse_char_t)c, (int)c);
return -1;
}
}
}
/* ========================================================================= */
static int handle_char (qse_json_t* json, qse_cint_t c)
{
int x;
start_over:
if (c == QSE_CHAR_EOF)
{
if (json->state_stack->state == QSE_JSON_STATE_START)
{
/* no input data */
return 0;
}
else
{
qse_json_seterrnum (json, QSE_JSON_EFINIS);
return -1;
}
}
switch (json->state_stack->state)
{
case QSE_JSON_STATE_START:
x = handle_start_char(json, c);
break;
case QSE_JSON_STATE_IN_ARRAY:
x = handle_char_in_array(json, c);
break;
case QSE_JSON_STATE_IN_DIC:
x = handle_char_in_dic(json, c);
break;
case QSE_JSON_STATE_IN_WORD_VALUE:
x = handle_word_value_char(json, c);
break;
case QSE_JSON_STATE_IN_STRING_VALUE:
x = handle_string_value_char(json, c);
break;
case QSE_JSON_STATE_IN_CHARACTER_VALUE:
x = handle_character_value_char(json, c);
break;
case QSE_JSON_STATE_IN_NUMERIC_VALUE:
x = handle_numeric_value_char(json, c);
break;
default:
qse_json_seterrfmt (json, QSE_JSON_EINTERN, QSE_T("internal error - must not be called for state %d"), (int)json->state_stack->state);
return -1;
}
if (x <= -1) return -1;
if (x == 0) goto start_over;
return 0;
}
/* ========================================================================= */
static int feed_json_data (qse_json_t* json, const qse_mchar_t* data, qse_size_t len, qse_size_t* xlen)
{
const qse_mchar_t* ptr;
const qse_mchar_t* end;
ptr = data;
end = ptr + len;
while (ptr < end)
{
qse_cint_t c;
#if defined(QSE_CHAR_IS_WCHAR)
qse_char_t uc;
qse_size_t bcslen;
qse_size_t n;
bcslen = end - ptr;
n = json->_cmgr->mbtowc(ptr, bcslen, &uc);
if (n == 0)
{
/* invalid sequence */
uc = *ptr;
n = 1;
}
else if (n > bcslen)
{
/* incomplete sequence */
*xlen = ptr - data; /* didn't manage to process in full */
return 0; /* feed more for incomplete sequence */
}
ptr += n;
c = uc;
#else
c = *ptr++;
#endif
/* handle a single character */
if (handle_char(json, c) <= -1) goto oops;
}
*xlen = ptr - data;
return 1;
oops:
/* TODO: compute the number of processed bytes so far and return it via a parameter??? */
/*printf ("feed oops....\n");*/
return -1;
}
/* ========================================================================= */
qse_json_t* qse_json_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_json_prim_t* prim, qse_json_errnum_t* errnum)
{
qse_json_t* json;
json = (qse_json_t*)QSE_MMGR_ALLOC(mmgr, QSE_SIZEOF(*json) + xtnsize);
if (!json)
{
if (errnum) *errnum = QSE_JSON_ENOMEM;
return QSE_NULL;
}
QSE_MEMSET (json, 0, QSE_SIZEOF(*json) + xtnsize);
json->_instsize = QSE_SIZEOF(*json);
json->_mmgr = mmgr;
json->_cmgr = qse_getdflcmgr();
json->prim = *prim;
json->state_top.state = QSE_JSON_STATE_START;
json->state_top.next = QSE_NULL;
json->state_stack = &json->state_top;
return json;
}
void qse_json_close (qse_json_t* json)
{
pop_all_states (json);
if (json->tok.ptr) qse_json_freemem (json, json->tok.ptr);
QSE_MMGR_FREE (json->_mmgr, json);
}
int qse_json_setoption (qse_json_t* json, qse_json_option_t id, const void* value)
{
switch (id)
{
case QSE_JSON_TRAIT:
json->cfg.trait = *(const int*)value;
return 0;
}
qse_json_seterrnum (json, QSE_JSON_EINVAL);
return -1;
}
int qse_json_getoption (qse_json_t* json, qse_json_option_t id, void* value)
{
switch (id)
{
case QSE_JSON_TRAIT:
*(int*)value = json->cfg.trait;
return 0;
};
qse_json_seterrnum (json, QSE_JSON_EINVAL);
return -1;
}
qse_json_errnum_t qse_json_geterrnum (qse_json_t* json)
{
return json->errnum;
}
const qse_char_t* qse_json_geterrmsg (qse_json_t* json)
{
const qse_char_t* __errstr[] =
{
QSE_T("no error"),
QSE_T("other error"),
QSE_T("not implemented"),
QSE_T("subsystem error"),
QSE_T("internal error"),
QSE_T("insufficient memory"),
QSE_T("invalid parameter or data"),
QSE_T("unexpected end of data")
};
return (json->errmsg.buf[0] == QSE_T('\0'))? __errstr[json->errnum]: json->errmsg.buf;
}
const qse_char_t* qse_json_backuperrmsg (qse_json_t* json)
{
qse_strxcpy (json->errmsg.backup, QSE_COUNTOF(json->errmsg.backup), qse_json_geterrmsg(json));
return json->errmsg.backup;
}
void qse_json_seterrnum (qse_json_t* json, qse_json_errnum_t errnum)
{
/*if (json->shuterr) return; */
json->errnum = errnum;
json->errmsg.buf[0] = QSE_T('\0');
}
void qse_json_seterrfmt (qse_json_t* json, qse_json_errnum_t errnum, const qse_char_t* errfmt, ...)
{
va_list ap;
json->errnum = errnum;
va_start (ap, errfmt);
qse_strxvfmt(json->errmsg.buf, QSE_COUNTOF(json->errmsg.buf), errfmt, ap);
va_end (ap);
}
/* ========================================================================= */
void* qse_json_allocmem (qse_json_t* json, qse_size_t size)
{
void* ptr;
ptr = QSE_MMGR_ALLOC(qse_json_getmmgr(json), size);
if (!ptr) qse_json_seterrnum (json, QSE_JSON_ENOMEM);
return ptr;
}
void* qse_json_callocmem (qse_json_t* json, qse_size_t size)
{
void* ptr;
ptr = QSE_MMGR_ALLOC(qse_json_getmmgr(json), size);
if (!ptr) qse_json_seterrnum (json, QSE_JSON_ENOMEM);
else QSE_MEMSET (ptr, 0, size);
return ptr;
}
void* qse_json_reallocmem (qse_json_t* json, void* ptr, qse_size_t size)
{
ptr = QSE_MMGR_REALLOC(qse_json_getmmgr(json), ptr, size);
if (!ptr) qse_json_seterrnum (json, QSE_JSON_ENOMEM);
return ptr;
}
void qse_json_freemem (qse_json_t* json, void* ptr)
{
QSE_MMGR_FREE (qse_json_getmmgr(json), ptr);
}
/* ========================================================================= */
qse_json_state_t qse_json_getstate (qse_json_t* json)
{
return json->state_stack->state;
}
void qse_json_reset (qse_json_t* json)
{
/* TODO: reset XXXXXXXXXXXXXXXXXXXXXXXXXXXxxxxx */
pop_all_states (json);
QSE_ASSERT (json->state_stack == &json->state_top);
json->state_stack->state = QSE_JSON_STATE_START;
}
int qse_json_feed (qse_json_t* json, const void* ptr, qse_size_t len, qse_size_t* xlen)
{
int x;
qse_size_t total, ylen;
const qse_mchar_t* buf;
buf = (const qse_mchar_t*)ptr;
total = 0;
while (total < len)
{
x = feed_json_data(json, &buf[total], len - total, &ylen);
if (x <= -1) return -1;
total += ylen;
if (x == 0) break; /* incomplete sequence encountered */
}
*xlen = total;
return 0;
}

515
lib/xli/read-ini.c Normal file
View File

@ -0,0 +1,515 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xli-prv.h"
#include <qse/cmn/chr.h>
/*
* It reads key-value pairs under sections as shown below:
*
* [SECTION1]
* key1 = value1
* key2 = value2
* [SECTION2]
* key1 = value1
*
* The above can get translated to the native XLI format shown below:
*
* SECTION1 {
* key1 = "value1";
* key2 = "value2";
* }
* SECTION2 {
* key1 = "value1";
* }
*
* The ini-format reader doesn't support file inclusion via @include.
*/
enum
{
TOK_STATUS_SAME_LINE = (1 << 0),
TOK_STATUS_UPTO_EOL = (1 << 1)
};
#define GET_CHAR(xli) \
do { if (qse_xli_getchar(xli) <= -1) return -1; } while(0)
#define GET_CHAR_TO(xli,c) \
do { \
if (qse_xli_getchar(xli) <= -1) return -1; \
c = (xli)->rio.last.c; \
} while(0)
#define ADD_TOKEN_CHAR(xli,tok,c) \
do { \
if (qse_str_ccat((tok)->name,(c)) == (qse_size_t)-1) \
{ \
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); \
return -1; \
} \
} while (0)
#define ADD_TOKEN_STR(xli,tok,s,l) \
do { \
if (qse_str_ncat((tok)->name,(s),(l)) == (qse_size_t)-1) \
{ \
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); \
return -1; \
} \
} while (0)
#define SET_TOKEN_TYPE(xli,tok,code) \
do { (tok)->type = (code); } while (0)
#define MATCH(xli,tok_type) ((xli)->tok.type == (tok_type))
#define MATCH(xli,tok_type) ((xli)->tok.type == (tok_type))
static int skip_spaces (qse_xli_t* xli)
{
qse_cint_t c = xli->rio.last.c;
if (xli->tok_status & TOK_STATUS_SAME_LINE)
{
while (QSE_ISSPACE(c) && c != QSE_T('\n')) GET_CHAR_TO (xli, c);
}
else
{
while (QSE_ISSPACE(c)) GET_CHAR_TO (xli, c);
}
return 0;
}
static int skip_comment (qse_xli_t* xli, qse_xli_tok_t* tok)
{
qse_cint_t c = xli->rio.last.c;
if (c == QSE_T(';'))
{
/* skip up to \n */
qse_str_clear (tok->name);
do
{
GET_CHAR_TO (xli, c);
if (c == QSE_T('\n') || c == QSE_CHAR_EOF) break;
if (xli->opt.trait & QSE_XLI_KEEPTEXT) ADD_TOKEN_CHAR (xli, tok, c);
}
while (1);
if ((xli->opt.trait & QSE_XLI_KEEPTEXT) &&
qse_xli_inserttext (xli, xli->parlink->list, QSE_NULL, QSE_STR_PTR(tok->name)) == QSE_NULL) return -1;
GET_CHAR (xli); /* eat the new line letter */
return 1; /* comment by ; */
}
return 0;
}
static int get_token_into (qse_xli_t* xli, qse_xli_tok_t* tok)
{
qse_cint_t c;
int n;
/*retry:*/
do
{
if (skip_spaces (xli) <= -1) return -1;
if (!(xli->tok_status & TOK_STATUS_UPTO_EOL))
{
if ((n = skip_comment (xli, tok)) <= -1) return -1;
}
else n = 0;
}
while (n >= 1);
qse_str_clear (tok->name);
tok->loc.file = xli->rio.last.file;
tok->loc.line = xli->rio.last.line;
tok->loc.colm = xli->rio.last.colm;
c = xli->rio.last.c;
if (c == QSE_CHAR_EOF)
{
ADD_TOKEN_STR (xli, tok, QSE_T("<EOF>"), 5);
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_EOF);
}
else if (xli->tok_status & TOK_STATUS_UPTO_EOL)
{
qse_size_t xlen = 0;
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_SQSTR);
do
{
if (c == QSE_CHAR_EOF || c == QSE_T(';')) break;
if (c == QSE_T('\n'))
{
GET_CHAR (xli);
break;
}
ADD_TOKEN_CHAR (xli, tok, c);
if (!QSE_ISSPACE(c)) xlen = QSE_STR_LEN(tok->name);
GET_CHAR_TO (xli, c);
}
while (1);
/* trim away trailing spaces */
qse_str_setlen (tok->name, xlen);
}
else if (c == QSE_T('['))
{
/* in the ini-styled format, a tag is used as a section name.
* but the kinds of allowed charaters are more limited than
* a normal tag in the xli format. */
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_TAG);
while (1)
{
GET_CHAR_TO (xli, c);
if (c == QSE_CHAR_EOF || c == QSE_T('\n'))
{
/* the string tag is not closed */
qse_xli_seterror (xli, QSE_XLI_ETAGNC, QSE_NULL, &xli->tok.loc);
return -1;
}
if (c == QSE_T(']'))
{
/* terminating quote */
GET_CHAR (xli);
break;
}
if (!QSE_ISALNUM(c) && c != QSE_T('-') && c != QSE_T('_') && c != QSE_T(':'))
{
qse_char_t cc = (qse_char_t)c;
qse_cstr_t ea;
ea.ptr = &cc;
ea.len = 1;
qse_xli_seterror (xli, QSE_XLI_ETAGCHR, &ea, &tok->loc);
return -1;
}
ADD_TOKEN_CHAR (xli, tok, c);
}
}
else if (c == QSE_T('_') || QSE_ISALPHA(c) ||
((xli->opt.trait & QSE_XLI_LEADDIGIT) && QSE_ISDIGIT(c)))
{
int lead_digit = QSE_ISDIGIT(c);
int all_digits = 1;
/* a normal identifier can be composed of wider varieties of
* characters than a keyword/directive */
while (1)
{
ADD_TOKEN_CHAR (xli, tok, c);
GET_CHAR_TO (xli, c);
if (c == QSE_T('_') || c == QSE_T('-') ||
c == QSE_T(':') || c == QSE_T('*') ||
c == QSE_T('/') || QSE_ISALPHA(c))
{
all_digits = 0;
}
else if (QSE_ISDIGIT(c))
{
/* nothing to do */
}
else break;
}
if (lead_digit && all_digits)
{
/* if an identifier begins with a digit, it must contain a non-digits character */
qse_xli_seterror (xli, QSE_XLI_EIDENT, QSE_STR_XSTR(tok->name), &tok->loc);
return -1;
}
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_IDENT);
}
else if (c == QSE_T('='))
{
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_EQ);
ADD_TOKEN_CHAR (xli, tok, c);
GET_CHAR (xli);
}
else
{
if ((xli->tok_status & TOK_STATUS_SAME_LINE) && c == QSE_T('\n'))
{
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_NL);
ADD_TOKEN_STR (xli, tok, QSE_T("<NL>"), 4);
GET_CHAR (xli);
}
/* not handled yet */
else if (c == QSE_T('\0'))
{
qse_cstr_t ea;
ea.ptr = QSE_T("<NUL>");
ea.len = 5;
qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc);
return -1;
}
else
{
qse_char_t cc = (qse_char_t)c;
qse_cstr_t ea;
ea.ptr = &cc;
ea.len = 1;
qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc);
return -1;
}
}
return 0;
}
static int get_token (qse_xli_t* xli)
{
return get_token_into (xli, &xli->tok);
}
static int read_list (qse_xli_t* xli)
{
qse_xli_pair_t* pair;
qse_cstr_t key;
qse_xli_list_t* curlist;
key.ptr = QSE_NULL;
key.len = 0;
while (1)
{
if (MATCH(xli, QSE_XLI_TOK_EOF)) break;
if (MATCH(xli, QSE_XLI_TOK_TAG))
{
/* insert a pair with an empty list */
pair = qse_xli_insertpairwithemptylist (xli, &xli->root->list, QSE_NULL, QSE_STR_PTR(xli->tok.name), QSE_NULL, QSE_NULL);
if (pair == QSE_NULL) goto oops;
curlist = (qse_xli_list_t*)pair->val;
xli->parlink->list = curlist;
while (1)
{
if (get_token (xli) <= -1) goto oops;
if (MATCH(xli, QSE_XLI_TOK_EOF)) break;
if (MATCH(xli, QSE_XLI_TOK_TAG))
{
/* switch to a new tag */
pair = qse_xli_insertpairwithemptylist (xli, &xli->root->list, QSE_NULL, QSE_STR_PTR(xli->tok.name), QSE_NULL, QSE_NULL);
if (pair == QSE_NULL) goto oops;
curlist = (qse_xli_list_t*)pair->val;
xli->parlink->list = curlist;
continue;
}
if (!MATCH(xli, QSE_XLI_TOK_IDENT))
{
qse_xli_seterror (xli, QSE_XLI_EKEY, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
if (xli->opt.trait & QSE_XLI_KEYNODUP)
{
qse_xli_atom_t* atom;
/* find any key conflicts in the current scope */
/* TODO: optimization. no sequential search */
atom = curlist->tail;
while (atom)
{
if (atom->type == QSE_XLI_PAIR &&
xli->opt.strcmp(((qse_xli_pair_t*)atom)->key, QSE_STR_PTR(xli->tok.name)) == 0)
{
qse_xli_seterror (xli, QSE_XLI_EEXIST, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
atom = atom->prev;
}
}
QSE_ASSERT (key.ptr == QSE_NULL);
key.len = QSE_STR_LEN(xli->tok.name);
key.ptr = qse_strdup(QSE_STR_PTR(xli->tok.name), qse_xli_getmmgr(xli));
if (key.ptr == QSE_NULL)
{
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
goto oops;
}
xli->tok_status |= TOK_STATUS_SAME_LINE;
if (get_token (xli) <= -1) goto oops;
if (!MATCH(xli, QSE_XLI_TOK_EQ))
{
qse_xli_seterror (xli, QSE_XLI_EEQ, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
/* read the value */
xli->tok_status |= TOK_STATUS_UPTO_EOL;
if (get_token (xli) <= -1) goto oops;
xli->tok_status &= ~(TOK_STATUS_SAME_LINE | TOK_STATUS_UPTO_EOL);
if (MATCH(xli, QSE_XLI_TOK_EOF))
{
/* empty value */
qse_cstr_t empty;
empty.ptr = QSE_T("");
empty.len = 0;
pair = qse_xli_insertpairwithstr (xli, curlist, QSE_NULL, key.ptr, QSE_NULL, QSE_NULL, &empty, QSE_NULL);
qse_xli_freemem (xli, key.ptr);
key.ptr = QSE_NULL;
if (pair == QSE_NULL) goto oops;
break;
}
if (MATCH(xli, QSE_XLI_TOK_SQSTR))
{
/* add a new pair with the initial string segment */
pair = qse_xli_insertpairwithstr (xli, curlist, QSE_NULL, key.ptr, QSE_NULL, QSE_NULL, QSE_STR_XSTR(xli->tok.name), QSE_NULL);
qse_xli_freemem (xli, key.ptr);
key.ptr = QSE_NULL;
if (pair == QSE_NULL) goto oops;
}
else
{
qse_xli_seterror (xli, QSE_XLI_EVAL, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
}
}
else
{
qse_xli_seterror (xli, QSE_XLI_ESECTAG, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
}
return 0;
oops:
if (key.ptr) qse_xli_freemem (xli, key.ptr);
return -1;
}
static int read_root_list (qse_xli_t* xli)
{
qse_xli_list_link_t* link;
link = qse_xli_makelistlink (xli, &xli->root->list);
if (!link) return -1;
if (qse_xli_getchar (xli) <= -1 || get_token (xli) <= -1 || read_list (xli) <= -1)
{
qse_xli_freelistlink (xli, link);
return -1;
}
QSE_ASSERT (link == xli->parlink);
qse_xli_freelistlink (xli, link);
return 0;
}
int qse_xli_readini (qse_xli_t* xli, qse_xli_io_impl_t io)
{
if (!io)
{
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
QSE_MEMSET (&xli->rio, 0, QSE_SIZEOF(xli->rio));
xli->rio.impl = io;
xli->rio.top.line = 1;
xli->rio.top.colm = 1;
xli->rio.inp = &xli->rio.top;
xli->tok_status = 0;
qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL);
qse_xli_clearrionames (xli);
QSE_ASSERT (QSE_STR_LEN(xli->dotted_curkey) == 0);
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;
if (!MATCH(xli, QSE_XLI_TOK_EOF))
{
qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc);
goto oops;
}
QSE_ASSERT (xli->rio.inp == &xli->rio.top);
qse_xli_closeactiverstream (xli);
qse_str_clear (xli->tok.name);
return 0;
oops:
/* an error occurred and control has reached here
* probably, some included files might not have been
* closed. close them */
while (xli->rio.inp != &xli->rio.top)
{
qse_xli_io_arg_t* prev;
/* nothing much to do about a close error */
qse_xli_closeactiverstream (xli);
prev = xli->rio.inp->prev;
QSE_ASSERT (xli->rio.inp->name != QSE_NULL);
qse_xli_freemem (xli, xli->rio.inp);
xli->rio.inp = prev;
}
qse_xli_closeactiverstream (xli);
qse_str_clear (xli->tok.name);
return -1;
}

1094
lib/xli/read-json.c Normal file

File diff suppressed because it is too large Load Diff

1287
lib/xli/read.c Normal file

File diff suppressed because it is too large Load Diff

745
lib/xli/std.c Normal file
View File

@ -0,0 +1,745 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xli-prv.h"
#include <qse/xli/stdxli.h>
#include <qse/cmn/path.h>
#include "../cmn/mem-prv.h"
typedef struct xtn_t
{
struct
{
struct
{
qse_xli_iostd_t* x;
union
{
/*
nothing to maintain for file here
*/
struct
{
const qse_char_t* ptr;
const qse_char_t* end;
} str;
} u;
} in;
struct
{
qse_xli_iostd_t* x;
union
{
struct
{
qse_sio_t* sio;
} file;
struct
{
qse_str_t* buf;
} str;
} u;
} out;
} s;
qse_xli_ecb_t ecb;
} xtn_t;
#if defined(QSE_HAVE_INLINE)
static QSE_INLINE xtn_t* GET_XTN(qse_xli_t* xli) { return (xtn_t*)((qse_uint8_t*)qse_xli_getxtn(xli) - QSE_SIZEOF(xtn_t)); }
#else
#define GET_XTN(xli) ((xtn_t*)((qse_uint8_t*)qse_xli_getxtn(xli) - QSE_SIZEOF(xtn_t)))
#endif
qse_xli_t* qse_xli_openstd (qse_size_t xtnsize, qse_size_t rootxtnsize, qse_xli_errnum_t* errnum)
{
return qse_xli_openstdwithmmgr (QSE_MMGR_GETDFL(), xtnsize, rootxtnsize, errnum);
}
static void fini_xtn (qse_xli_t* xli)
{
/* nothing to do */
}
static void clear_xtn (qse_xli_t* xli)
{
/* nothing to do */
}
qse_xli_t* qse_xli_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_size_t rootxtnsize, qse_xli_errnum_t* errnum)
{
qse_xli_t* xli;
xtn_t* xtn;
/* create an object */
xli = qse_xli_open(mmgr, QSE_SIZEOF(xtn_t) + xtnsize, rootxtnsize, errnum);
if (xli == QSE_NULL) goto oops;
xli->_instsize += QSE_SIZEOF(xtn_t);
/* initialize extension */
xtn = GET_XTN(xli);
/* the extension area has been cleared in qse_httpd_open().
* QSE_MEMSET (xtn, 0, QSE_SIZEOF(*xtn));*/
xtn->ecb.close = fini_xtn;
xtn->ecb.clear = clear_xtn;
qse_xli_pushecb (xli, &xtn->ecb);
return xli;
oops:
if (xli) qse_xli_close (xli);
return QSE_NULL;
}
static qse_sio_t* open_sio (qse_xli_t* xli, const qse_char_t* file, int flags)
{
qse_sio_t* sio;
sio = qse_sio_open(qse_xli_getmmgr(xli), 0, file, flags);
if (sio == QSE_NULL)
{
qse_cstr_t errarg;
errarg.ptr = (qse_char_t*)file;
errarg.len = qse_strlen(file);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &errarg);
}
return sio;
}
static qse_cstr_t sio_std_names[] =
{
{ QSE_T("stdin"), 5 },
{ QSE_T("stdout"), 6 },
{ QSE_T("stderr"), 6 }
};
static qse_sio_t* open_sio_std (qse_xli_t* xli, qse_sio_std_t std, int flags)
{
qse_sio_t* sio;
sio = qse_sio_openstd (qse_xli_getmmgr(xli), 0, std, flags);
if (sio == QSE_NULL) qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &sio_std_names[std]);
return sio;
}
static qse_ssize_t sf_in_open (qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xtn)
{
if (arg->prev == QSE_NULL)
{
qse_xli_iostd_t* psin = xtn->s.in.x;
QSE_ASSERT (arg == &xli->rio.top);
switch (psin->type)
{
/* normal source files */
case QSE_XLI_IOSTD_FILE:
if (psin->u.file.path == QSE_NULL ||
(psin->u.file.path[0] == QSE_T('-') &&
psin->u.file.path[1] == QSE_T('\0')))
{
/* no path name or - -> stdin */
arg->handle = open_sio_std (xli, QSE_SIO_STDIN, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR | QSE_SIO_LINEBREAK);
}
else
{
arg->handle = open_sio (xli, psin->u.file.path, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR | QSE_SIO_KEEPPATH);
}
if (arg->handle == QSE_NULL) return -1;
if (psin->u.file.cmgr) qse_sio_setcmgr (arg->handle, psin->u.file.cmgr);
/* update the object name to something more specific */
arg->name = psin->u.file.path;
if (arg->name == QSE_NULL) arg->name = sio_std_names[QSE_SIO_STDIN].ptr;
return 0;
case QSE_XLI_IOSTD_STR:
xtn->s.in.u.str.ptr = psin->u.str.ptr;
xtn->s.in.u.str.end = psin->u.str.ptr + psin->u.str.len;
return 0;
default:
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
return -1;
}
}
else
{
/* handle the included file - @include */
const qse_char_t* path;
qse_char_t fbuf[64];
qse_char_t* dbuf = QSE_NULL;
QSE_ASSERT (arg->name != QSE_NULL);
path = arg->name;
if (arg->prev->handle)
{
const qse_char_t* outer;
outer = qse_sio_getpath (arg->prev->handle);
if (outer)
{
const qse_char_t* base;
/* i'm being included from another file */
base = qse_basename(outer);
if (base != outer && arg->name[0] != QSE_T('/'))
{
qse_size_t tmplen, totlen, dirlen;
dirlen = base - outer;
totlen = qse_strlen(arg->name) + dirlen;
if (totlen >= QSE_COUNTOF(fbuf))
{
dbuf = qse_xli_allocmem (
xli, QSE_SIZEOF(qse_char_t) * (totlen + 1)
);
if (dbuf == QSE_NULL) return -1;
path = dbuf;
}
else path = fbuf;
tmplen = qse_strncpy ((qse_char_t*)path, outer, dirlen);
qse_strcpy ((qse_char_t*)path + tmplen, arg->name);
}
}
}
arg->handle = qse_sio_open (
qse_xli_getmmgr(xli), 0, path, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR | QSE_SIO_KEEPPATH
);
if (dbuf) qse_xli_freemem (xli, dbuf);
if (arg->handle == QSE_NULL)
{
qse_cstr_t ea;
ea.ptr = (qse_char_t*)arg->name;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
return -1;
}
return 0;
}
}
static qse_ssize_t sf_in_close (
qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xtn)
{
if (arg->prev == QSE_NULL)
{
switch (xtn->s.in.x->type)
{
case QSE_XLI_IOSTD_FILE:
QSE_ASSERT (arg->handle != QSE_NULL);
qse_sio_close (arg->handle);
break;
case QSE_XLI_IOSTD_STR:
/* nothing to close */
break;
default:
/* nothing to close */
break;
}
}
else
{
/* handle the included source file - @include */
QSE_ASSERT (arg->handle != QSE_NULL);
qse_sio_close (arg->handle);
}
return 0;
}
static qse_ssize_t sf_in_read (
qse_xli_t* xli, qse_xli_io_arg_t* arg,
qse_char_t* data, qse_size_t size, xtn_t* xtn)
{
if (arg->prev == QSE_NULL)
{
qse_ssize_t n;
switch (xtn->s.in.x->type)
{
case QSE_XLI_IOSTD_FILE:
QSE_ASSERT (arg->handle != QSE_NULL);
n = qse_sio_getstrn (arg->handle, data, size);
if (n <= -1)
{
qse_cstr_t ea;
ea.ptr = (qse_char_t*)xtn->s.in.x->u.file.path;
if (ea.ptr == QSE_NULL) ea.ptr = sio_std_names[QSE_SIO_STDIN].ptr;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
}
break;
case QSE_XLI_IOSTD_STR:
n = 0;
while (n < size && xtn->s.in.u.str.ptr < xtn->s.in.u.str.end)
{
data[n++] = *xtn->s.in.u.str.ptr++;
}
break;
default:
/* this should never happen */
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
n = -1;
break;
}
return n;
}
else
{
/* handle the included source file - @include */
qse_ssize_t n;
QSE_ASSERT (arg->name != QSE_NULL);
QSE_ASSERT (arg->handle != QSE_NULL);
n = qse_sio_getstrn (arg->handle, data, size);
if (n <= -1)
{
qse_cstr_t ea;
ea.ptr = (qse_char_t*)arg->name;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
}
return n;
}
}
static qse_ssize_t sf_in (
qse_xli_t* xli, qse_xli_io_cmd_t cmd,
qse_xli_io_arg_t* arg, qse_char_t* data, qse_size_t size)
{
xtn_t* xtn = GET_XTN(xli);
QSE_ASSERT (arg != QSE_NULL);
switch (cmd)
{
case QSE_XLI_IO_OPEN:
return sf_in_open (xli, arg, xtn);
case QSE_XLI_IO_CLOSE:
return sf_in_close (xli, arg, xtn);
case QSE_XLI_IO_READ:
return sf_in_read (xli, arg, data, size, xtn);
default:
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
return -1;
}
}
static qse_ssize_t sf_out_open (qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xtn)
{
if (arg->prev == QSE_NULL)
{
qse_xli_iostd_t* psout = xtn->s.out.x;
QSE_ASSERT (arg == &xli->wio.top);
switch (psout->type)
{
/* normal source files */
case QSE_XLI_IOSTD_FILE:
if (psout->u.file.path == QSE_NULL ||
(psout->u.file.path[0] == QSE_T('-') &&
psout->u.file.path[1] == QSE_T('\0')))
{
/* no path name or - -> stdout */
arg->handle = open_sio_std (xli, QSE_SIO_STDOUT, QSE_SIO_WRITE | QSE_SIO_CREATE | QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR | QSE_SIO_LINEBREAK);
}
else
{
arg->handle = open_sio (xli, psout->u.file.path, QSE_SIO_WRITE | QSE_SIO_CREATE | QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR | QSE_SIO_KEEPPATH);
}
if (arg->handle == QSE_NULL) return -1;
if (psout->u.file.cmgr) qse_sio_setcmgr (arg->handle, psout->u.file.cmgr);
/* update the object name to something more specific */
arg->name = psout->u.file.path;
if (arg->name == QSE_NULL) arg->name = sio_std_names[QSE_SIO_STDOUT].ptr;
return 0;
case QSE_XLI_IOSTD_STR:
xtn->s.out.u.str.buf = qse_str_open(qse_xli_getmmgr(xli), 0, 512);
if (xtn->s.out.u.str.buf == QSE_NULL)
{
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
return -1;
}
return 0;
default:
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
return -1;
}
}
else
{
/* handle the included file - @include */
const qse_char_t* path;
qse_char_t fbuf[64];
qse_char_t* dbuf = QSE_NULL;
QSE_ASSERT (arg->name != QSE_NULL);
path = arg->name;
if (arg->prev->handle)
{
const qse_char_t* outer;
outer = qse_sio_getpath (arg->prev->handle);
if (outer)
{
const qse_char_t* base;
/* i'm being included from another file */
base = qse_basename(outer);
if (base != outer && arg->name[0] != QSE_T('/'))
{
qse_size_t tmplen, totlen, dirlen;
dirlen = base - outer;
totlen = qse_strlen(arg->name) + dirlen;
if (totlen >= QSE_COUNTOF(fbuf))
{
dbuf = qse_xli_allocmem (
xli, QSE_SIZEOF(qse_char_t) * (totlen + 1)
);
if (dbuf == QSE_NULL) return -1;
path = dbuf;
}
else path = fbuf;
tmplen = qse_strncpy ((qse_char_t*)path, outer, dirlen);
qse_strcpy ((qse_char_t*)path + tmplen, arg->name);
}
}
}
arg->handle = qse_sio_open (
qse_xli_getmmgr(xli), 0, path, QSE_SIO_WRITE | QSE_SIO_CREATE | QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR | QSE_SIO_KEEPPATH
);
if (dbuf) qse_xli_freemem (xli, dbuf);
if (arg->handle == QSE_NULL)
{
qse_cstr_t ea;
/*ea.ptr = (qse_char_t*)arg->name;
ea.len = qse_strlen(ea.ptr);*/
ea.ptr = (qse_char_t*)path;
ea.len = qse_strlen(path);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
return -1;
}
return 0;
}
}
static qse_ssize_t sf_out_close (
qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xtn)
{
if (arg->prev == QSE_NULL)
{
switch (xtn->s.out.x->type)
{
case QSE_XLI_IOSTD_FILE:
QSE_ASSERT (arg->handle != QSE_NULL);
qse_sio_close (arg->handle);
break;
case QSE_XLI_IOSTD_STR:
/* nothing to close */
break;
default:
/* nothing to close */
break;
}
}
else
{
/* handle the included source file - @include */
QSE_ASSERT (arg->handle != QSE_NULL);
qse_sio_close (arg->handle);
}
return 0;
}
static qse_ssize_t sf_out_write (
qse_xli_t* xli, qse_xli_io_arg_t* arg,
qse_char_t* data, qse_size_t size, xtn_t* xtn)
{
if (arg->prev == QSE_NULL)
{
qse_ssize_t n;
switch (xtn->s.out.x->type)
{
case QSE_XLI_IOSTD_FILE:
QSE_ASSERT (arg->handle != QSE_NULL);
n = qse_sio_putstrn (arg->handle, data, size);
if (n <= -1)
{
qse_cstr_t ea;
ea.ptr = (qse_char_t*)xtn->s.out.x->u.file.path;
if (ea.ptr == QSE_NULL) ea.ptr = sio_std_names[QSE_SIO_STDOUT].ptr;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
}
break;
case QSE_XLI_IOSTD_STR:
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
if (qse_str_ncat (xtn->s.out.u.str.buf, data, size) == (qse_size_t)-1)
{
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
return -1;
}
n = size;
break;
default:
/* this should never happen */
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
n = -1;
break;
}
return n;
}
else
{
/* handle the included source file - @include */
qse_ssize_t n;
QSE_ASSERT (arg->name != QSE_NULL);
QSE_ASSERT (arg->handle != QSE_NULL);
n = qse_sio_putstrn (arg->handle, data, size);
if (n <= -1)
{
qse_cstr_t ea;
ea.ptr = (qse_char_t*)arg->name;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
}
return n;
}
}
static qse_ssize_t sf_out (
qse_xli_t* xli, qse_xli_io_cmd_t cmd,
qse_xli_io_arg_t* arg, qse_char_t* data, qse_size_t size)
{
xtn_t* xtn = GET_XTN(xli);
QSE_ASSERT (arg != QSE_NULL);
switch (cmd)
{
case QSE_XLI_IO_OPEN:
return sf_out_open (xli, arg, xtn);
case QSE_XLI_IO_CLOSE:
return sf_out_close (xli, arg, xtn);
case QSE_XLI_IO_WRITE:
return sf_out_write (xli, arg, data, size, xtn);
default:
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
return -1;
}
}
int qse_xli_readstd (qse_xli_t* xli, qse_xli_iostd_t* in)
{
xtn_t* xtn = GET_XTN(xli);
if (in == QSE_NULL || (in->type != QSE_XLI_IOSTD_FILE &&
in->type != QSE_XLI_IOSTD_STR))
{
/* the input is a must. at least 1 file or 1 string
* must be specified */
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
xtn->s.in.x = in;
return qse_xli_read(xli, sf_in);
}
int qse_xli_readinistd (qse_xli_t* xli, qse_xli_iostd_t* in)
{
xtn_t* xtn = GET_XTN(xli);
if (in == QSE_NULL || (in->type != QSE_XLI_IOSTD_FILE &&
in->type != QSE_XLI_IOSTD_STR))
{
/* the input is a must. at least 1 file or 1 string
* must be specified */
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
xtn->s.in.x = in;
return qse_xli_readini(xli, sf_in);
}
int qse_xli_readjsonstd (qse_xli_t* xli, qse_xli_iostd_t* in)
{
xtn_t* xtn = GET_XTN(xli);
if (in == QSE_NULL || (in->type != QSE_XLI_IOSTD_FILE &&
in->type != QSE_XLI_IOSTD_STR))
{
/* the input is a must. at least 1 file or 1 string
* must be specified */
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
xtn->s.in.x = in;
return qse_xli_readjson(xli, sf_in);
}
int qse_xli_writestd (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_iostd_t* out)
{
int n;
xtn_t* xtn = GET_XTN(xli);
if (out == QSE_NULL || (out->type != QSE_XLI_IOSTD_FILE &&
out->type != QSE_XLI_IOSTD_STR))
{
/* the input is a must. at least 1 file or 1 string
* must be specified */
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
xtn->s.out.x = out;
n = qse_xli_write (xli, root_list, sf_out);
if (out->type == QSE_XLI_IOSTD_STR)
{
if (n >= 0)
{
QSE_ASSERT (xtn->s.out.u.str.buf != QSE_NULL);
qse_str_yield (xtn->s.out.u.str.buf, &out->u.str, 0);
}
if (xtn->s.out.u.str.buf) qse_str_close (xtn->s.out.u.str.buf);
}
return n;
}
int qse_xli_writeinistd (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_iostd_t* out)
{
int n;
xtn_t* xtn = GET_XTN(xli);
if (out == QSE_NULL || (out->type != QSE_XLI_IOSTD_FILE &&
out->type != QSE_XLI_IOSTD_STR))
{
/* the input is a must. at least 1 file or 1 string
* must be specified */
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
xtn->s.out.x = out;
n = qse_xli_writeini (xli, root_list, sf_out);
if (out->type == QSE_XLI_IOSTD_STR)
{
if (n >= 0)
{
QSE_ASSERT (xtn->s.out.u.str.buf != QSE_NULL);
qse_str_yield (xtn->s.out.u.str.buf, &out->u.str, 0);
}
if (xtn->s.out.u.str.buf) qse_str_close (xtn->s.out.u.str.buf);
}
return n;
}
int qse_xli_writejsonstd (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_iostd_t* out)
{
int n;
xtn_t* xtn = GET_XTN(xli);
if (out == QSE_NULL || (out->type != QSE_XLI_IOSTD_FILE &&
out->type != QSE_XLI_IOSTD_STR))
{
/* the input is a must. at least 1 file or 1 string
* must be specified */
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
xtn->s.out.x = out;
n = qse_xli_writejson (xli, root_list, sf_out);
if (out->type == QSE_XLI_IOSTD_STR)
{
if (n >= 0)
{
QSE_ASSERT (xtn->s.out.u.str.buf != QSE_NULL);
qse_str_yield (xtn->s.out.u.str.buf, &out->u.str, 0);
}
if (xtn->s.out.u.str.buf) qse_str_close (xtn->s.out.u.str.buf);
}
return n;
}

199
lib/xli/write-ini.c Normal file
View File

@ -0,0 +1,199 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xli-prv.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 (xli->opt.cbs.pair_writable && !xli->opt.cbs.pair_writable(xli, pair)) continue;
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_TRUE:
if (write_to_current_stream (xli, QSE_T("true\n"), 5) <= -1) return -1;
break;
case QSE_XLI_FALSE:
if (write_to_current_stream (xli, QSE_T("false\n"), 6) <= -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("="), 1) <= -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 (depth < 1)
{
if (write_list(xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1 ||
write_to_current_stream (xli, QSE_T("\n"), 1) <= -1) return -1;
}
else
{
/* the ini format doesn't support deep nesting */
if (write_to_current_stream (xli, QSE_T("={}\n"), 4) <= -1) return -1;
}
break;
}
break;
}
case QSE_XLI_TEXT:
{
const qse_char_t* str = ((qse_xli_text_t*)curatom)->ptr;
/* don't honor VERBATIM and DEINDENT flags */
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_list_t* root_list, qse_xli_io_impl_t io)
{
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, (root_list? root_list: &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;
}

351
lib/xli/write-json.c Normal file
View File

@ -0,0 +1,351 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xli-prv.h"
#include <qse/cmn/chr.h>
typedef struct arg_data_t arg_data_t;
struct arg_data_t
{
int org_depth;
};
static int write_to_current_stream(qse_xli_t* xli, const qse_char_t* ptr, qse_size_t len, int escape)
{
qse_xli_io_arg_t* arg;
qse_size_t i;
arg = xli->wio.inp;
for (i = 0; i < len; i++)
{
if (escape)
{
if (ptr[i] == QSE_T('\\') || ptr[i] == QSE_T('\"') ||
ptr[i] == QSE_T('\b') || ptr[i] == QSE_T('\f') ||
ptr[i] == QSE_T('\n') || ptr[i] == QSE_T('\r') || ptr[i] == QSE_T('\t'))
{
qse_char_t ac;
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('\\');
switch (ptr[i])
{
case QSE_T('\b'): ac = 'b'; break;
case QSE_T('\f'): ac = 'f'; break;
case QSE_T('\n'): ac = 'n'; break;
case QSE_T('\r'): ac = 'r'; break;
case QSE_T('\t'): ac = 't'; break;
default: ac = ptr[i]; break;
}
arg->b.buf[arg->b.len++] = ac;
}
else if (ptr[i] >= 0x00 && ptr[i] <= 0x1F)
{
qse_char_t tmp[5];
if (arg->b.len + 6 > QSE_COUNTOF(arg->b.buf) && qse_xli_flushwstream(xli, arg) <= -1) return -1;
arg->b.buf[arg->b.len++] = QSE_T('\\');
arg->b.buf[arg->b.len++] = QSE_T('u');
/* use 'tmp' to avoid null termination beyond the buffer end */
qse_strxfmt(tmp, QSE_COUNTOF(tmp), QSE_T("%04X"), ptr[i]);
arg->b.len += qse_strcpy(&arg->b.buf[arg->b.len], tmp);
}
else
{
goto unescaped;
}
}
else
{
unescaped:
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];
}
/*
if (escape && (ptr[i] == QSE_T('\\') || ptr[i] == QSE_T('\"')))
{
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) && qse_xli_flushwstream(xli, arg) <= -1) return -1;
}
arg->b.buf[arg->b.len++] = ptr[i];
*/
}
return 0;
}
static int write_indentation (qse_xli_t* xli, int depth)
{
static const qse_char_t tabs[16] =
{
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t')
};
if (depth <= QSE_COUNTOF(tabs))
{
if (write_to_current_stream(xli, tabs, depth, 0) <= -1) return -1;
}
else
{
int i;
if (write_to_current_stream(xli, tabs, QSE_COUNTOF(tabs), 0) <= -1) return -1;
for (i = QSE_COUNTOF(tabs); i < depth; i++)
{
if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1;
}
}
return 0;
}
static int need_comma (qse_xli_t* xli, qse_xli_atom_t* start)
{
qse_xli_atom_t* cur;
for (cur = start; cur; cur = cur->next)
{
if (cur->type == QSE_XLI_PAIR)
{
if (xli->opt.cbs.pair_writable && !xli->opt.cbs.pair_writable(xli, (qse_xli_pair_t*)cur)) continue;
return 1;
}
if (cur->type == QSE_XLI_EOF) return 0; /* if EOF encountered in the included file, i don't want a comma at the end of the file */
}
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 (xli->opt.cbs.pair_writable && !xli->opt.cbs.pair_writable(xli, pair)) continue;
if (write_indentation(xli, depth) <= -1) return -1;
if (!(list->flags & QSE_XLI_LIST_ARRAYED))
{
if (pair->tag)
{
/* ignore tag in the json format */
}
if (write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -1 ||
write_to_current_stream(xli, pair->key, qse_strlen(pair->key), 1) <= -1 ||
write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -1) return -1;
if (pair->alias)
{
/* ignore alias in the json format */
}
if (write_to_current_stream(xli, QSE_T(": "), 2, 0) <= -1) return -1;
}
switch (pair->val->type)
{
case QSE_XLI_NIL:
if (write_to_current_stream(xli, QSE_T("nil"), 3, 0) <= -1) return -1;
break;
case QSE_XLI_TRUE:
if (write_to_current_stream(xli, QSE_T("true"), 4, 0) <= -1) return -1;
break;
case QSE_XLI_FALSE:
if (write_to_current_stream(xli, QSE_T("false"), 5, 0) <= -1) return -1;
break;
case QSE_XLI_STR:
{
qse_xli_str_t* str = (qse_xli_str_t*)pair->val;
/* ignore the string tag(str->tag) in the json format.
* concatenate multi-segmented string into 1 seperated by a comma */
int quote_needed;
/* if the string value is a non-numeric string or
* it is multi-segmented, quoting is needed */
quote_needed = !(str->flags & QSE_XLI_STR_NSTR) || str->next;
if (quote_needed && write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -1) return -1;
while (1)
{
if (write_to_current_stream(xli, str->ptr, str->len, quote_needed) <= -1) return -1;
if (!str->next) break;
if (write_to_current_stream(xli, QSE_T(","), 1, 0) <= -1) return -1;
str = str->next;
}
if (quote_needed && write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -1) return -1;
break;
}
case QSE_XLI_LIST:
{
static qse_char_t* obrac[] =
{
QSE_T("{\n"),
QSE_T("[\n")
};
static qse_char_t* cbrac[] =
{
QSE_T("}"),
QSE_T("]")
};
qse_xli_list_t* lv = (qse_xli_list_t*)pair->val;
if (write_to_current_stream(xli, obrac[lv->flags & QSE_XLI_LIST_ARRAYED], 2, 0) <= -1 ||
write_list (xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1 ||
write_indentation (xli, depth) <= -1 ||
write_to_current_stream(xli, cbrac[lv->flags & QSE_XLI_LIST_ARRAYED], 1, 0) <= -1) return -1;
break;
}
}
if (need_comma(xli, curatom->next) && write_to_current_stream(xli, QSE_T(","), 1, 0) <= -1) return -1;
if (write_to_current_stream(xli, QSE_T("\n"), 1, 0) <= -1) return -1;
break;
}
case QSE_XLI_TEXT:
{
qse_xli_text_t* ta;
const qse_char_t* str;
ta = (qse_xli_text_t*)curatom;
str = ta->ptr;
if (write_indentation(xli, depth - !!(ta->flags & QSE_XLI_TEXT_DEINDENT)) <= -1) return -1;
if ((!(ta->flags & QSE_XLI_TEXT_VERBATIM) && write_to_current_stream(xli, QSE_T("#"), 1, 0) <= -1) ||
write_to_current_stream(xli, str, qse_strlen(str), 0) <= -1 ||
write_to_current_stream(xli, QSE_T("\n"), 1, 0) <= -1) return -1;
break;
}
case QSE_XLI_FILE:
{
const qse_char_t* path = ((qse_xli_file_t*)curatom)->path;
if (write_indentation(xli, depth) <= -1) return -1;
if (write_to_current_stream(xli, QSE_T("@include \""), 10, 0) <= -1 ||
write_to_current_stream(xli, path, qse_strlen(path), 1) <= -1 ||
write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -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 (qse_xli_closeactivewstream(xli, &depth) <= -1) return -1;
if (need_comma(xli, curatom->next) && write_to_current_stream(xli, QSE_T(","), 1, 0) <= -1) return -1;
if (write_to_current_stream(xli, QSE_T("\n"), 1, 0) <= -1) return -1;
break;
}
}
return 0;
}
static int have_opening_marker (qse_xli_t* xli, qse_xli_list_t* list)
{
qse_xli_atom_t* curatom;
for (curatom = list->head; curatom; curatom = curatom->next)
{
qse_xli_text_t* ta;
if (curatom->type != QSE_XLI_TEXT) break;
ta = (qse_xli_text_t*)curatom;
if (ta->flags & (QSE_XLI_TEXT_ARRAYED_LIST_OPENER | QSE_XLI_TEXT_LIST_OPENER)) return 1;
}
return 0;
}
int qse_xli_writejson (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_io_impl_t io)
{
int n, marker;
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;
if (!root_list) root_list = &xli->root->list;
marker = have_opening_marker(xli, root_list);
if (!marker)
{
/* if the data has been loaded from a different format like xli or ini,
* there are no opening and closing markers. so emit them manually */
if (write_to_current_stream(xli, ((root_list->flags & QSE_XLI_LIST_ARRAYED)? QSE_T("[\n"): QSE_T("{\n")), 2, 0) <= -1) return -1;
}
/* begin writing the root list */
n = write_list (xli, root_list, 1);
if (!marker)
{
if (write_to_current_stream(xli, ((root_list->flags & QSE_XLI_LIST_ARRAYED)? QSE_T("]\n"): QSE_T("}\n")), 2, 0) <= -1) return -1;
}
/* 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;
}

424
lib/xli/write.c Normal file
View File

@ -0,0 +1,424 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xli-prv.h"
#include <qse/cmn/chr.h>
typedef struct arg_data_t arg_data_t;
struct arg_data_t
{
int org_depth;
};
int qse_xli_flushwstream (qse_xli_t* xli, qse_xli_io_arg_t* arg)
{
qse_ssize_t n;
while (arg->b.pos < arg->b.len)
{
n = xli->wio.impl (xli, QSE_XLI_IO_WRITE, xli->wio.inp, &arg->b.buf[arg->b.pos], arg->b.len - arg->b.pos);
if (n <= -1)
{
if (xli->errnum == QSE_XLI_ENOERR)
qse_xli_seterrnum (xli, QSE_XLI_EIOUSR, QSE_NULL);
return -1;
}
arg->b.pos += n;
}
arg->b.pos = 0;
arg->b.len = 0;
return 0;
}
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;
if (path == QSE_NULL)
{
/* top-level */
arg = &xli->wio.top;
}
else
{
qse_link_t* link;
qse_size_t plen;
arg_data_t* arg_data;
plen = qse_strlen (path);
link = (qse_link_t*) qse_xli_callocmem (xli,
QSE_SIZEOF(*link) + QSE_SIZEOF(qse_char_t) * (plen + 1));
if (link == QSE_NULL) return -1;
qse_strcpy ((qse_char_t*)(link + 1), path);
link->link = xli->wio_names;
xli->wio_names = link;
arg = (qse_xli_io_arg_t*) qse_xli_callocmem (xli, QSE_SIZEOF(*arg) + QSE_SIZEOF(*arg_data));
if (arg == QSE_NULL) return -1;
arg_data = (arg_data_t*)(arg + 1);
arg_data->org_depth = old_depth;
arg->name = (const qse_char_t*)(link + 1);
arg->prev = xli->wio.inp;
}
n = xli->wio.impl (xli, QSE_XLI_IO_OPEN, arg, QSE_NULL, 0);
if (n <= -1)
{
if (xli->errnum == QSE_XLI_ENOERR)
qse_xli_seterrnum (xli, QSE_XLI_EIOUSR, QSE_NULL);
if (arg != &xli->wio.top)
{
qse_xli_freemem (xli, arg);
/* don't clean up 'link' since it's linked to xli->wio_names */
}
return -1;
}
xli->wio.inp = arg;
return 0;
}
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;
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)
{
if (xli->errnum == QSE_XLI_ENOERR)
qse_xli_seterrnum (xli, QSE_XLI_EIOUSR, QSE_NULL);
return -1;
}
xli->wio.inp = arg->prev;
if (arg == &xli->wio.top)
{
if (org_depth) *org_depth = 0;
}
else
{
if (org_depth) *org_depth = ((arg_data_t*)(arg + 1))->org_depth;
qse_xli_freemem (xli, arg);
}
return 0;
}
static int write_to_current_stream (qse_xli_t* xli, const qse_char_t* ptr, qse_size_t len, int escape)
{
qse_xli_io_arg_t* arg;
qse_size_t i;
arg = xli->wio.inp;
for (i = 0; i < len; i++)
{
if (escape && (ptr[i] == QSE_T('\\') || ptr[i] == QSE_T('\"')))
{
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) && qse_xli_flushwstream (xli, arg) <= -1) return -1;
}
arg->b.buf[arg->b.len++] = ptr[i];
}
return 0;
}
static int write_indentation (qse_xli_t* xli, int depth)
{
static const qse_char_t tabs[16] =
{
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t')
};
if (depth <= QSE_COUNTOF(tabs))
{
if (write_to_current_stream (xli, tabs, depth, 0) <= -1) return -1;
}
else
{
int i;
if (write_to_current_stream (xli, tabs, QSE_COUNTOF(tabs), 0) <= -1) return -1;
for (i = QSE_COUNTOF(tabs); i < depth; i++)
{
if (write_to_current_stream (xli, QSE_T("\t"), 1, 0) <= -1) return -1;
}
}
return 0;
}
static int key_needs_quoting (qse_xli_t* xli, const qse_char_t* str, int nstr)
{
/* this determines if a key or an alias requires quoting for output.
* NSTR is not taken into account because it's only allowed as a value */
/* refer to the tokenization rule in get_token_into() in read.c */
qse_char_t c;
c = *str++;
if (c == QSE_T('\0')) return 1; /* an empty string requires a quoting */
if (c == QSE_T('_') || QSE_ISALPHA(c) || (!nstr && (xli->opt.trait & QSE_XLI_LEADDIGIT) && QSE_ISDIGIT(c)))
{
int lead_digit = QSE_ISDIGIT(c);
int all_digits = 1;
/* a normal identifier can be composed of wider varieties of
* characters than a keyword/directive */
while (1)
{
c = *str++;
if (c == QSE_T('\0')) break;
if (c == QSE_T('_') || c == QSE_T('-') || c == QSE_T(':') ||
c == QSE_T('*') || c == QSE_T('/') || QSE_ISALPHA(c))
{
all_digits = 0;
}
else if (QSE_ISDIGIT(c))
{
/* nothing to do */
}
else
{
/* a disallowed character for an identifier */
return 1; /* quote it */
}
}
if (lead_digit && all_digits)
{
/* if an identifier begins with a digit, it must contain a non-digit character */
/* in fact, it is not a valid identifer. so quote it */
return 1;
}
else
{
/* this must be a normal identifer */
return 0; /* no quoting needed */
}
}
else if (nstr && QSE_ISDIGIT(c))
{
do
{
c = *str++;
if (c == QSE_T('\0')) return 0; /* it's a numeric string */
}
while (QSE_ISDIGIT(c));
}
/* quote all the rest */
return 1;
}
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)
{
int quote_key = 0;
switch (curatom->type)
{
case QSE_XLI_PAIR:
{
qse_xli_pair_t* pair = (qse_xli_pair_t*)curatom;
if (xli->opt.cbs.pair_writable && !xli->opt.cbs.pair_writable(xli, pair)) continue;
if (write_indentation (xli, depth) <= -1) return -1;
if (pair->tag)
{
if (write_to_current_stream (xli, QSE_T("["), 1, 0) <= -1 ||
write_to_current_stream (xli, pair->tag, qse_strlen(pair->tag), 0) <= -1 ||
write_to_current_stream (xli, QSE_T("]"), 1, 0) <= -1) return -1;
}
if (key_needs_quoting(xli, pair->key, 0)) quote_key = 1;
if ((quote_key && write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) ||
write_to_current_stream (xli, pair->key, qse_strlen(pair->key), 0) <= -1 ||
(quote_key && write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1)) return -1;
if (pair->alias)
{
if (write_to_current_stream (xli, QSE_T(" \""), 2, 0) <= -1 ||
write_to_current_stream (xli, pair->alias, qse_strlen(pair->alias), 1) <= -1 ||
write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) return -1;
}
switch (pair->val->type)
{
case QSE_XLI_NIL:
if (write_to_current_stream (xli, QSE_T(";\n"), 2, 0) <= -1) return -1;
break;
case QSE_XLI_TRUE:
if (write_to_current_stream (xli, QSE_T(" = true;\n"), 9, 0) <= -1) return -1;
break;
case QSE_XLI_FALSE:
if (write_to_current_stream (xli, QSE_T(" = false;\n"), 10, 0) <= -1) return -1;
break;
case QSE_XLI_STR:
{
qse_xli_str_t* str = (qse_xli_str_t*)pair->val;
if (write_to_current_stream (xli, QSE_T(" = "), 3, 0) <= -1) return -1;
while (1)
{
if (str->tag)
{
if (write_to_current_stream (xli, QSE_T("["), 1, 0) <= -1 ||
write_to_current_stream (xli, str->tag, qse_strlen(str->tag), 0) <= -1 ||
write_to_current_stream (xli, QSE_T("]"), 1, 0) <= -1) return -1;
}
if ((!(str->flags & QSE_XLI_STR_NSTR) &&
write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) ||
write_to_current_stream (xli, str->ptr, str->len, 1) <= -1 ||
(!(str->flags & QSE_XLI_STR_NSTR) &&
write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1)) return -1;
if (!str->next) break;
if (write_to_current_stream (xli, QSE_T(", "), 2, 0) <= -1) return -1;
str = str->next;
}
if (write_to_current_stream (xli, QSE_T(";\n"), 2, 0) <= -1) return -1;
break;
}
case QSE_XLI_LIST:
{
if (write_to_current_stream (xli, QSE_T(" {\n"), 3, 0) <= -1 ||
write_list (xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1 ||
write_indentation (xli, depth) <= -1 ||
write_to_current_stream (xli, QSE_T("}\n"), 2, 0) <= -1) return -1;
break;
}
}
break;
}
case QSE_XLI_TEXT:
{
const qse_char_t* str = ((qse_xli_text_t*)curatom)->ptr;
/* don't honor VERBATIM and DEINDENT flags */
if (write_indentation(xli, depth) <= -1 ||
write_to_current_stream(xli, QSE_T("#"), 1, 0) <= -1 ||
write_to_current_stream(xli, str, qse_strlen(str), 0) <= -1 ||
write_to_current_stream(xli, QSE_T("\n"), 1, 0) <= -1) return -1;
break;
}
case QSE_XLI_FILE:
{
const qse_char_t* path = ((qse_xli_file_t*)curatom)->path;
if (write_indentation(xli, depth) <= -1 ||
write_to_current_stream(xli, QSE_T("@include \""), 10, 0) <= -1 ||
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 (qse_xli_openwstream(xli, ((qse_xli_file_t*)curatom)->path, depth) <= -1) return -1;
depth = 0;
break;
}
case QSE_XLI_EOF:
if (qse_xli_closeactivewstream (xli, &depth) <= -1) return -1;
break;
}
}
return 0;
}
void qse_xli_clearwionames (qse_xli_t* xli)
{
qse_link_t* cur;
while (xli->wio_names)
{
cur = xli->wio_names;
xli->wio_names = cur->link;
qse_xli_freemem (xli, cur);
}
}
int qse_xli_write (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_io_impl_t io)
{
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, (root_list? root_list: &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;
}

177
lib/xli/xli-prv.h Normal file
View File

@ -0,0 +1,177 @@
/*
* $Id$
*
Copyright (c) 2006-2019 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _QSE_LIB_XLI_XLI_H_
#define _QSE_LIB_XLI_XLI_H_
#include <qse/xli/xli.h>
#include <qse/cmn/str.h>
#include <qse/cmn/rbt.h>
#include "../cmn/mem-prv.h"
enum qse_xli_tok_type_t
{
QSE_XLI_TOK_EOF,
QSE_XLI_TOK_XINCLUDE,
QSE_XLI_TOK_TRUE,
QSE_XLI_TOK_FALSE,
QSE_XLI_TOK_NIL,
QSE_XLI_TOK_COLON,
QSE_XLI_TOK_SEMICOLON,
QSE_XLI_TOK_LBRACE,
QSE_XLI_TOK_RBRACE,
QSE_XLI_TOK_LBRACK,
QSE_XLI_TOK_RBRACK,
QSE_XLI_TOK_LPAREN,
QSE_XLI_TOK_RPAREN,
QSE_XLI_TOK_EQ,
QSE_XLI_TOK_COMMA,
QSE_XLI_TOK_DQSTR,
QSE_XLI_TOK_SQSTR,
QSE_XLI_TOK_NSTR,
QSE_XLI_TOK_IDENT,
QSE_XLI_TOK_TEXT,
QSE_XLI_TOK_TAG,
QSE_XLI_TOK_NL
};
typedef enum qse_xli_tok_type_t qse_xli_tok_type_t;
typedef struct qse_xli_tok_t qse_xli_tok_t;
struct qse_xli_tok_t
{
qse_xli_tok_type_t type;
qse_str_t* name;
qse_xli_loc_t loc;
};
typedef struct qse_xli_list_link_t qse_xli_list_link_t;
struct qse_xli_list_link_t
{
qse_xli_list_link_t* next;
qse_xli_list_t* list;
};
typedef struct qse_xli_root_list_t qse_xli_root_list_t;
struct qse_xli_root_list_t
{
qse_xli_list_t list;
qse_xli_nil_t xnil;
qse_xli_true_t xtrue;
qse_xli_false_t xfalse;
qse_mmgr_t* mmgr;
};
struct qse_xli_t
{
QSE_XLI_HDR;
qse_xli_errstr_t errstr; /**< error string getter */
qse_xli_errnum_t errnum; /**< stores an error number */
qse_char_t errmsg[128]; /**< error message holder */
qse_xli_loc_t errloc; /**< location of the last error */
struct
{
int trait;
qse_size_t pair_xtnsize;
qse_size_t root_xtnsize;
qse_char_t key_splitter; /**< character to use to split a key in the fqpn format */
qse_xli_cbs_t cbs;
int (*strcmp) (const qse_char_t* s1, const qse_char_t* s2);
int (*strxcmp) (const qse_char_t* s1, qse_size_t len1, const qse_char_t* s2);
} opt;
qse_xli_ecb_t* ecb;
qse_xli_root_list_t* root;
qse_xli_list_link_t* parlink; /* internal use only - link that points to the list being read currently */
qse_str_t* dotted_curkey;
qse_rbt_t* schema;
qse_xli_tok_t tok;
int tok_status;
struct
{
qse_xli_io_impl_t impl; /* input handler */
qse_xli_io_lxc_t last;
qse_xli_io_arg_t top; /* for top level */
qse_xli_io_arg_t* inp; /* current */
} rio;
qse_link_t* rio_names;
struct
{
qse_xli_io_impl_t impl; /* output handler */
qse_xli_io_arg_t top; /* for top level */
qse_xli_io_arg_t* inp; /* current */
} wio;
qse_link_t* wio_names;
};
#if defined(__cplusplus)
extern "C" {
#endif
int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr, qse_size_t rootxtnsize);
void qse_xli_fini (qse_xli_t* xli);
const qse_char_t* qse_xli_dflerrstr (
const qse_xli_t* xli, qse_xli_errnum_t errnum);
void qse_xli_clearrionames (qse_xli_t* xli);
void qse_xli_clearwionames (qse_xli_t* xli);
int qse_xli_getchar (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);
qse_xli_str_t* qse_xli_makestrval (qse_xli_t* xli, const qse_cstr_t* value, const qse_char_t* strtag);
qse_xli_list_t* qse_xli_makelistval (qse_xli_t* xli);
void qse_xli_freeval (qse_xli_t* xli, qse_xli_val_t* val);
#if defined(__cplusplus)
}
#endif
#endif

1264
lib/xli/xli.c Normal file

File diff suppressed because it is too large Load Diff