Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/.cproject
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/.cproject	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/.cproject	(revision 364)
@@ -22,5 +22,5 @@
 			<storageModule moduleId="com.renesas.cdt.managedbuild.core.toolchainInfo">
 				<option id="toolchain.id" value="gcc-arm-embedded"/>
-				<option id="toolchain.version" value="5.4.1.20160919"/>
+				<option id="toolchain.version" value="6.3.1.20170620"/>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -59,5 +59,5 @@
 							<option id="com.renesas.cdt.managedbuild.gcc.rz.option.warnStack.2041552637" name="Warn if stack size exceeds the limit (-Wstack-usage) (H')" superClass="com.renesas.cdt.managedbuild.gcc.rz.option.warnStack" useByScannerDiscovery="false" value="100" valueType="string"/>
 							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform.1106389026" isAbstract="false" osList="all" superClass="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform"/>
-							<builder buildPath="${workspace_loc:/app1_usb_watt_meter}/Debug" id="com.renesas.cdt.managedbuild.gcc.rz.builder.1499740602" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="GCC for Renesas Builder" parallelBuildOn="false" superClass="com.renesas.cdt.managedbuild.gcc.rz.builder"/>
+							<builder buildPath="${workspace_loc:/app1_usb_watt_meter}/Debug" id="com.renesas.cdt.managedbuild.gcc.rz.builder.1499740602" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="GCC for Renesas Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.renesas.cdt.managedbuild.gcc.rz.builder"/>
 							<tool id="com.renesas.cdt.managedbuild.gcc.rz.tool.assembler.473685659" name="Cross ARM GNU Assembler" superClass="com.renesas.cdt.managedbuild.gcc.rz.tool.assembler">
 								<option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor.600330630" name="Use preprocessor" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor" useByScannerDiscovery="false" value="true" valueType="boolean"/>
@@ -127,5 +127,5 @@
 			<storageModule moduleId="com.renesas.cdt.managedbuild.core.toolchainInfo">
 				<option id="toolchain.id" value="gcc-arm-embedded"/>
-				<option id="toolchain.version" value="5.4.1.20160919"/>
+				<option id="toolchain.version" value="6.3.1.20170620"/>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -164,5 +164,5 @@
 							<option id="com.renesas.cdt.managedbuild.gcc.rz.option.warnStack.504056262" name="Warn if stack size exceeds the limit (-Wstack-usage) (H')" superClass="com.renesas.cdt.managedbuild.gcc.rz.option.warnStack" useByScannerDiscovery="false" value="100" valueType="string"/>
 							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform.211973441" isAbstract="false" osList="all" superClass="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform"/>
-							<builder buildPath="${workspace_loc:/app1_usb_watt_meter}/DebugEther" id="com.renesas.cdt.managedbuild.gcc.rz.builder.559752886" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="GCC for Renesas Builder" parallelBuildOn="false" superClass="com.renesas.cdt.managedbuild.gcc.rz.builder"/>
+							<builder buildPath="${workspace_loc:/app1_usb_watt_meter}/DebugEther" id="com.renesas.cdt.managedbuild.gcc.rz.builder.559752886" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="GCC for Renesas Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.renesas.cdt.managedbuild.gcc.rz.builder"/>
 							<tool id="com.renesas.cdt.managedbuild.gcc.rz.tool.assembler.541834310" name="Cross ARM GNU Assembler" superClass="com.renesas.cdt.managedbuild.gcc.rz.tool.assembler">
 								<option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor.1603061550" name="Use preprocessor" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor" useByScannerDiscovery="false" value="true" valueType="boolean"/>
@@ -232,5 +232,5 @@
 			<storageModule moduleId="com.renesas.cdt.managedbuild.core.toolchainInfo">
 				<option id="toolchain.id" value="gcc-arm-embedded"/>
-				<option id="toolchain.version" value="5.4.1.20160919"/>
+				<option id="toolchain.version" value="6.3.1.20170620"/>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -269,5 +269,5 @@
 							<option id="com.renesas.cdt.managedbuild.gcc.rz.option.warnStack.1222794445" name="Warn if stack size exceeds the limit (-Wstack-usage) (H')" superClass="com.renesas.cdt.managedbuild.gcc.rz.option.warnStack" useByScannerDiscovery="false" value="100" valueType="string"/>
 							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform.1527919964" isAbstract="false" osList="all" superClass="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform"/>
-							<builder buildPath="${workspace_loc:/app1_usb_watt_meter}/DebugEnbt" id="com.renesas.cdt.managedbuild.gcc.rz.builder.896433184" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="GCC for Renesas Builder" parallelBuildOn="false" superClass="com.renesas.cdt.managedbuild.gcc.rz.builder"/>
+							<builder buildPath="${workspace_loc:/app1_usb_watt_meter}/DebugEnbt" id="com.renesas.cdt.managedbuild.gcc.rz.builder.896433184" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="GCC for Renesas Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.renesas.cdt.managedbuild.gcc.rz.builder"/>
 							<tool id="com.renesas.cdt.managedbuild.gcc.rz.tool.assembler.893283254" name="Cross ARM GNU Assembler" superClass="com.renesas.cdt.managedbuild.gcc.rz.tool.assembler">
 								<option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor.1741240748" name="Use preprocessor" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor" useByScannerDiscovery="false" value="true" valueType="boolean"/>
@@ -341,3 +341,4 @@
 		</configuration>
 	</storageModule>
+	<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
 </cproject>
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/Debug/Makefile
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/Debug/Makefile	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/Debug/Makefile	(revision 364)
@@ -182,5 +182,5 @@
 	CDEFS := -DTOPPERS_OMIT_TECS $(CDEFS)
 endif
-CDEFS := $(CDEFS) -DDHCP4_CLI_CFG -DUSE_PING -DUSE_RESOLVER -DUSE_NETAPP_SUBR -DECHONET_USE_MALLOC -DHAVE_CONFIG_H -DWOLFSSL_USER_SETTINGS -DRamDisk=_binary_______ntshell_src_rom_fs_bin_start
+CDEFS := $(CDEFS) -DDHCP4_CLI_CFG -DUSE_PING -DUSE_RESOLVER -DUSE_NETAPP_SUBR -DNOUSE_MPF_NET_BUF -DECHONET_USE_MALLOC -DHAVE_CONFIG_H -DWOLFSSL_USER_SETTINGS -DRamDisk=_binary_______ntshell_src_rom_fs_bin_start
 INCLUDES := -I. -I$(SRCDIR)/include -I$(SRCDIR) \
 	-I$(SRCDIR)/../btstack/include \
@@ -196,5 +196,5 @@
 	-I$(SRCDIR)/../curl-7.57.0 \
 	$(INCLUDES)
-LDFLAGS := $(LDFLAGS) -Wl,-Map=$(OBJNAME).map,--cref -L.
+LDFLAGS := $(LDFLAGS) -L.
 LIBS := $(LIBS) $(CXXLIBS)
 CFLAGS = $(COPTS) $(CDEFS) $(INCLUDES)
@@ -207,5 +207,6 @@
 APPL_COBJS := $(APPL_COBJS) netcmd.o fdtable.o io_stub.o socket_stub.o ffarch.o diskio.o ff.o sdfs.o ccsbcs.o ntshell.o text_editor.o text_history.o usrcmd.o vtrecv.o vtsend.o ntlibc.o ntstdio.o ntopt.o syscall.o tlsf.o
 APPLDIRS := $(APPLDIRS) ../../ntshell/lcd
-APPL_COBJS := $(APPL_COBJS) draw_font.o misaki_font.o
+APPL_COBJS := $(APPL_COBJS) draw_font.o shnm12_font.o
+APPL_CFLAGS := $(APPL_CFLAGS) -DSHNM12_FONT
 
 #
@@ -220,8 +221,8 @@
 APPL_ASMOBJS :=
 ifdef USE_CXX
-	APPL_CXXOBJS := main.o ntshell_main.o echonet_main.o client.o
+	APPL_CXXOBJS := main.o ntshell_main.o echonet_main.o client.o jsonsl.o
 	APPL_COBJS := $(APPL_COBJS)
 else
-	APPL_COBJS := $(APPL_COBJS) main.o ntshell_main.o echonet_main.o client.o
+	APPL_COBJS := $(APPL_COBJS) main.o ntshell_main.o echonet_main.o client.o jsonsl.o
 endif
 APPL_COBJS := $(APPL_COBJS) log_output.o vasyslog.o t_perror.o strerror.o
@@ -232,34 +233,35 @@
 endif
 
-
-#
-#  ネットワークサービスの定義
-#
-NO_USE_TINET_LIBRARY = true
-
-#  ネットワークインタフェースの選択、何れか一つ選択する。
-NET_IF = ether
-
-#  イーサネット・ディバイスドライバの選択
-NET_DEV = if_btusb
-
-#  ネットワーク層の選択
-#SUPPORT_INET6 = true
-SUPPORT_INET4 = true
-
-#  API に組込む機能の選択
-#API_CFG_IP4MAPPED_ADDR = true
-
-#  トランスポート層の選択
-SUPPORT_TCP = true
-SUPPORT_UDP = true
-
-# IGMPを有効に設定
-SUPPORT_IGMP = true
-
-#
-#  ネットワークサービスの Makefile のインクルード
-#
-include $(SRCDIR)/$(TINETDIR)/Makefile.tinet
+ifdef TINETDIR
+	#
+	#  ネットワークサービスの定義
+	#
+	NO_USE_TINET_LIBRARY = true
+
+	#  ネットワークインタフェースの選択、何れか一つ選択する。
+	NET_IF = ether
+
+	#  イーサネット・ディバイスドライバの選択
+	NET_DEV = if_btusb
+
+	#  ネットワーク層の選択
+	#SUPPORT_INET6 = true
+	SUPPORT_INET4 = true
+
+	#  API に組込む機能の選択
+	#API_CFG_IP4MAPPED_ADDR = true
+
+	#  トランスポート層の選択
+	SUPPORT_TCP = true
+	SUPPORT_UDP = true
+
+	# IGMPを有効に設定
+	SUPPORT_IGMP = true
+
+	#
+	#  ネットワークサービスの Makefile のインクルード
+	#
+	include $(SRCDIR)/$(TINETDIR)/Makefile.tinet
+endif
 
 #
@@ -294,6 +296,11 @@
 #  コンフィギュレータに関する定義
 #
-CFG_TRB := -T $(TINET_ROOT)/tinet.trb:tcpip -T ../../ntshell/echonet/echonet.trb:echonet -T $(TARGETDIR)/target_kernel.trb:kernel
-CFG_TABS := --api-table $(TINET_ROOT)/tcpip_api.def:tcpip \
+ifndef TINETDIR
+  CFG_TRB := -T $(TARGETDIR)/target_kernel.trb
+  CFG_TABS := --api-table $(SRCDIR)/kernel/kernel_api.def \
+			--symval-table $(SRCDIR)/kernel/kernel_sym.def $(CFG_TABS)
+else
+  CFG_TRB := -T $(TINET_ROOT)/tinet.trb:tcpip -T ../../ntshell/echonet/echonet.trb:echonet -T $(TARGETDIR)/target_kernel.trb:kernel
+  CFG_TABS := --api-table $(TINET_ROOT)/tcpip_api.def:tcpip \
 			--api-table ../../ntshell/echonet/echonet_api.def:echonet \
 			--api-table $(SRCDIR)/kernel/kernel_api.def:kernel \
@@ -301,4 +308,5 @@
 			--symval-table ../../ntshell/echonet/echonet_sym.def \
 			--symval-table $(SRCDIR)/kernel/kernel_sym.def $(CFG_TABS)
+endif
 CFG_ASMOBJS := $(CFG_ASMOBJS)
 CFG_COBJS := kernel_cfg.o echonet_cfg.o $(CFG_COBJS)
@@ -446,4 +454,11 @@
 
 #
+#  並列makeのための依存関係の定義
+#
+$(APPL_OBJS) $(filter-out $(CFG_DMY), $(SYSSVC_OBJS)): | kernel_cfg.timestamp
+$(APPL_ASMOBJS) $(filter-out $(CFG_DMY), $(SYSSVC_ASMOBJS)) $(KERNEL_ASMOBJS) $(CFG_ASMOBJS): \
+														| offset.timestamp
+
+#
 #  特別な依存関係の定義
 #
@@ -454,5 +469,5 @@
 #
 $(OBJFILE): $(ALL_OBJS) $(LIBS_DEP)
-	$(LINK) $(CFLAGS) $(LDFLAGS) $(OBJ_LDFLAGS) -o $(OBJFILE) \
+	$(LINK) $(CFLAGS) $(LDFLAGS) $(OBJ_LDFLAGS) -o $(OBJFILE) -Wl,-Map=$(OBJNAME).map,--cref \
 			$(START_OBJS) $(APPL_OBJS) $(SYSSVC_OBJS) $(CFG_OBJS) \
 			-Wl,--start-group $(ALL_LIBS) -Wl,--end-group $(END_OBJS)
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/DebugEnbt/Makefile
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/DebugEnbt/Makefile	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/DebugEnbt/Makefile	(revision 364)
@@ -182,5 +182,5 @@
 	CDEFS := -DTOPPERS_OMIT_TECS $(CDEFS)
 endif
-CDEFS := $(CDEFS) -DIF_ETHER_MULTI_NIC -DDHCP4_CLI_CFG -DUSE_PING -DUSE_RESOLVER -DUSE_NETAPP_SUBR -DECHONET_USE_MALLOC -DHAVE_CONFIG_H -DWOLFSSL_USER_SETTINGS -DRamDisk=_binary_______ntshell_src_rom_fs_bin_start
+CDEFS := $(CDEFS) -DIF_ETHER_MULTI_NIC -DDHCP4_CLI_CFG -DUSE_PING -DUSE_RESOLVER -DUSE_NETAPP_SUBR -DNOUSE_MPF_NET_BUF -DECHONET_USE_MALLOC -DHAVE_CONFIG_H -DWOLFSSL_USER_SETTINGS -DRamDisk=_binary_______ntshell_src_rom_fs_bin_start
 INCLUDES := -I. -I$(SRCDIR)/include -I$(SRCDIR) \
 	-I$(SRCDIR)/../btstack/include \
@@ -196,5 +196,5 @@
 	-I$(SRCDIR)/../curl-7.57.0 \
 	$(INCLUDES)
-LDFLAGS := $(LDFLAGS) -Wl,-Map=$(OBJNAME).map,--cref -L.
+LDFLAGS := $(LDFLAGS) -L.
 LIBS := $(LIBS) $(CXXLIBS)
 CFLAGS = $(COPTS) $(CDEFS) $(INCLUDES)
@@ -207,5 +207,6 @@
 APPL_COBJS := $(APPL_COBJS) netcmd.o fdtable.o io_stub.o socket_stub.o ffarch.o diskio.o ff.o sdfs.o ccsbcs.o ntshell.o text_editor.o text_history.o usrcmd.o vtrecv.o vtsend.o ntlibc.o ntstdio.o ntopt.o syscall.o tlsf.o
 APPLDIRS := $(APPLDIRS) ../../ntshell/lcd
-APPL_COBJS := $(APPL_COBJS) draw_font.o misaki_font.o
+APPL_COBJS := $(APPL_COBJS) draw_font.o shnm12_font.o
+APPL_CFLAGS := $(APPL_CFLAGS) -DSHNM12_FONT
 
 #
@@ -220,8 +221,8 @@
 APPL_ASMOBJS :=
 ifdef USE_CXX
-	APPL_CXXOBJS := main.o ntshell_main.o echonet_main.o client.o
+	APPL_CXXOBJS := main.o ntshell_main.o echonet_main.o client.o jsonsl.o
 	APPL_COBJS := $(APPL_COBJS)
 else
-	APPL_COBJS := $(APPL_COBJS) main.o ntshell_main.o echonet_main.o client.o
+	APPL_COBJS := $(APPL_COBJS) main.o ntshell_main.o echonet_main.o client.o jsonsl.o
 endif
 APPL_COBJS := $(APPL_COBJS) log_output.o vasyslog.o t_perror.o strerror.o
@@ -232,34 +233,35 @@
 endif
 
-
-#
-#  ネットワークサービスの定義
-#
-NO_USE_TINET_LIBRARY = true
-
-#  ネットワークインタフェースの選択、何れか一つ選択する。
-NET_IF = ether
-
-#  イーサネット・ディバイスドライバの選択
-NET_DEV = if_enbt
-
-#  ネットワーク層の選択
-#SUPPORT_INET6 = true
-SUPPORT_INET4 = true
-
-#  API に組込む機能の選択
-#API_CFG_IP4MAPPED_ADDR = true
-
-#  トランスポート層の選択
-SUPPORT_TCP = true
-SUPPORT_UDP = true
-
-# IGMPを有効に設定
-SUPPORT_IGMP = true
-
-#
-#  ネットワークサービスの Makefile のインクルード
-#
-include $(SRCDIR)/$(TINETDIR)/Makefile.tinet
+ifdef TINETDIR
+	#
+	#  ネットワークサービスの定義
+	#
+	NO_USE_TINET_LIBRARY = true
+
+	#  ネットワークインタフェースの選択、何れか一つ選択する。
+	NET_IF = ether
+
+	#  イーサネット・ディバイスドライバの選択
+	NET_DEV = if_enbt
+
+	#  ネットワーク層の選択
+	#SUPPORT_INET6 = true
+	SUPPORT_INET4 = true
+
+	#  API に組込む機能の選択
+	#API_CFG_IP4MAPPED_ADDR = true
+
+	#  トランスポート層の選択
+	SUPPORT_TCP = true
+	SUPPORT_UDP = true
+
+	# IGMPを有効に設定
+	SUPPORT_IGMP = true
+
+	#
+	#  ネットワークサービスの Makefile のインクルード
+	#
+	include $(SRCDIR)/$(TINETDIR)/Makefile.tinet
+endif
 
 #
@@ -294,6 +296,11 @@
 #  コンフィギュレータに関する定義
 #
-CFG_TRB := -T $(TINET_ROOT)/tinet.trb:tcpip -T ../../ntshell/echonet/echonet.trb:echonet -T $(TARGETDIR)/target_kernel.trb:kernel
-CFG_TABS := --api-table $(TINET_ROOT)/tcpip_api.def:tcpip \
+ifndef TINETDIR
+  CFG_TRB := -T $(TARGETDIR)/target_kernel.trb
+  CFG_TABS := --api-table $(SRCDIR)/kernel/kernel_api.def \
+			--symval-table $(SRCDIR)/kernel/kernel_sym.def $(CFG_TABS)
+else
+  CFG_TRB := -T $(TINET_ROOT)/tinet.trb:tcpip -T ../../ntshell/echonet/echonet.trb:echonet -T $(TARGETDIR)/target_kernel.trb:kernel
+  CFG_TABS := --api-table $(TINET_ROOT)/tcpip_api.def:tcpip \
 			--api-table ../../ntshell/echonet/echonet_api.def:echonet \
 			--api-table $(SRCDIR)/kernel/kernel_api.def:kernel \
@@ -301,4 +308,5 @@
 			--symval-table ../../ntshell/echonet/echonet_sym.def \
 			--symval-table $(SRCDIR)/kernel/kernel_sym.def $(CFG_TABS)
+endif
 CFG_ASMOBJS := $(CFG_ASMOBJS)
 CFG_COBJS := kernel_cfg.o echonet_cfg.o $(CFG_COBJS)
@@ -446,4 +454,11 @@
 
 #
+#  並列makeのための依存関係の定義
+#
+$(APPL_OBJS) $(filter-out $(CFG_DMY), $(SYSSVC_OBJS)): | kernel_cfg.timestamp
+$(APPL_ASMOBJS) $(filter-out $(CFG_DMY), $(SYSSVC_ASMOBJS)) $(KERNEL_ASMOBJS) $(CFG_ASMOBJS): \
+														| offset.timestamp
+
+#
 #  特別な依存関係の定義
 #
@@ -454,5 +469,5 @@
 #
 $(OBJFILE): $(ALL_OBJS) $(LIBS_DEP)
-	$(LINK) $(CFLAGS) $(LDFLAGS) $(OBJ_LDFLAGS) -o $(OBJFILE) \
+	$(LINK) $(CFLAGS) $(LDFLAGS) $(OBJ_LDFLAGS) -o $(OBJFILE) -Wl,-Map=$(OBJNAME).map,--cref \
 			$(START_OBJS) $(APPL_OBJS) $(SYSSVC_OBJS) $(CFG_OBJS) \
 			-Wl,--start-group $(ALL_LIBS) -Wl,--end-group $(END_OBJS)
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/DebugEther/Makefile
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/DebugEther/Makefile	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/DebugEther/Makefile	(revision 364)
@@ -182,5 +182,5 @@
 	CDEFS := -DTOPPERS_OMIT_TECS $(CDEFS)
 endif
-CDEFS := $(CDEFS) -DDHCP4_CLI_CFG -DUSE_PING -DUSE_RESOLVER -DUSE_NETAPP_SUBR -DECHONET_USE_MALLOC -DHAVE_CONFIG_H -DWOLFSSL_USER_SETTINGS -DRamDisk=_binary_______ntshell_src_rom_fs_bin_start
+CDEFS := $(CDEFS) -DDHCP4_CLI_CFG -DUSE_PING -DUSE_RESOLVER -DUSE_NETAPP_SUBR -DNOUSE_MPF_NET_BUF -DECHONET_USE_MALLOC -DHAVE_CONFIG_H -DWOLFSSL_USER_SETTINGS -DRamDisk=_binary_______ntshell_src_rom_fs_bin_start
 INCLUDES := -I. -I$(SRCDIR)/include -I$(SRCDIR) \
 	-I$(SRCDIR)/../btstack/include \
@@ -196,5 +196,5 @@
 	-I$(SRCDIR)/../curl-7.57.0 \
 	$(INCLUDES)
-LDFLAGS := $(LDFLAGS) -Wl,-Map=$(OBJNAME).map,--cref -L.
+LDFLAGS := $(LDFLAGS) -L.
 LIBS := $(LIBS) $(CXXLIBS)
 CFLAGS = $(COPTS) $(CDEFS) $(INCLUDES)
@@ -207,5 +207,6 @@
 APPL_COBJS := $(APPL_COBJS) netcmd.o fdtable.o io_stub.o socket_stub.o ffarch.o diskio.o ff.o sdfs.o ccsbcs.o ntshell.o text_editor.o text_history.o usrcmd.o vtrecv.o vtsend.o ntlibc.o ntstdio.o ntopt.o syscall.o tlsf.o
 APPLDIRS := $(APPLDIRS) ../../ntshell/lcd
-APPL_COBJS := $(APPL_COBJS) draw_font.o misaki_font.o
+APPL_COBJS := $(APPL_COBJS) draw_font.o shnm12_font.o
+APPL_CFLAGS := $(APPL_CFLAGS) -DSHNM12_FONT
 
 #
@@ -220,8 +221,8 @@
 APPL_ASMOBJS :=
 ifdef USE_CXX
-	APPL_CXXOBJS := main.o ntshell_main.o echonet_main.o client.o
+	APPL_CXXOBJS := main.o ntshell_main.o echonet_main.o client.o jsonsl.o
 	APPL_COBJS := $(APPL_COBJS)
 else
-	APPL_COBJS := $(APPL_COBJS) main.o ntshell_main.o echonet_main.o client.o
+	APPL_COBJS := $(APPL_COBJS) main.o ntshell_main.o echonet_main.o client.o jsonsl.o
 endif
 APPL_COBJS := $(APPL_COBJS) log_output.o vasyslog.o t_perror.o strerror.o
@@ -232,34 +233,35 @@
 endif
 
-
-#
-#  ネットワークサービスの定義
-#
-NO_USE_TINET_LIBRARY = true
-
-#  ネットワークインタフェースの選択、何れか一つ選択する。
-NET_IF = ether
-
-#  イーサネット・ディバイスドライバの選択
+ifdef TINETDIR
+	#
+	#  ネットワークサービスの定義
+	#
+	NO_USE_TINET_LIBRARY = true
+
+	#  ネットワークインタフェースの選択、何れか一つ選択する。
+	NET_IF = ether
+
+	#  イーサネット・ディバイスドライバの選択
 	NET_DEV = if_mbed
 
-#  ネットワーク層の選択
-#SUPPORT_INET6 = true
-SUPPORT_INET4 = true
-
-#  API に組込む機能の選択
-#API_CFG_IP4MAPPED_ADDR = true
-
-#  トランスポート層の選択
-SUPPORT_TCP = true
-SUPPORT_UDP = true
-
-# IGMPを有効に設定
-SUPPORT_IGMP = true
-
-#
-#  ネットワークサービスの Makefile のインクルード
-#
-include $(SRCDIR)/$(TINETDIR)/Makefile.tinet
+	#  ネットワーク層の選択
+	#SUPPORT_INET6 = true
+	SUPPORT_INET4 = true
+
+	#  API に組込む機能の選択
+	#API_CFG_IP4MAPPED_ADDR = true
+
+	#  トランスポート層の選択
+	SUPPORT_TCP = true
+	SUPPORT_UDP = true
+
+	# IGMPを有効に設定
+	SUPPORT_IGMP = true
+
+	#
+	#  ネットワークサービスの Makefile のインクルード
+	#
+	include $(SRCDIR)/$(TINETDIR)/Makefile.tinet
+endif
 
 #
@@ -294,6 +296,11 @@
 #  コンフィギュレータに関する定義
 #
-CFG_TRB := -T $(TINET_ROOT)/tinet.trb:tcpip -T ../../ntshell/echonet/echonet.trb:echonet -T $(TARGETDIR)/target_kernel.trb:kernel
-CFG_TABS := --api-table $(TINET_ROOT)/tcpip_api.def:tcpip \
+ifndef TINETDIR
+  CFG_TRB := -T $(TARGETDIR)/target_kernel.trb
+  CFG_TABS := --api-table $(SRCDIR)/kernel/kernel_api.def \
+			--symval-table $(SRCDIR)/kernel/kernel_sym.def $(CFG_TABS)
+else
+  CFG_TRB := -T $(TINET_ROOT)/tinet.trb:tcpip -T ../../ntshell/echonet/echonet.trb:echonet -T $(TARGETDIR)/target_kernel.trb:kernel
+  CFG_TABS := --api-table $(TINET_ROOT)/tcpip_api.def:tcpip \
 			--api-table ../../ntshell/echonet/echonet_api.def:echonet \
 			--api-table $(SRCDIR)/kernel/kernel_api.def:kernel \
@@ -301,4 +308,5 @@
 			--symval-table ../../ntshell/echonet/echonet_sym.def \
 			--symval-table $(SRCDIR)/kernel/kernel_sym.def $(CFG_TABS)
+endif
 CFG_ASMOBJS := $(CFG_ASMOBJS)
 CFG_COBJS := kernel_cfg.o echonet_cfg.o $(CFG_COBJS)
@@ -446,4 +454,11 @@
 
 #
+#  並列makeのための依存関係の定義
+#
+$(APPL_OBJS) $(filter-out $(CFG_DMY), $(SYSSVC_OBJS)): | kernel_cfg.timestamp
+$(APPL_ASMOBJS) $(filter-out $(CFG_DMY), $(SYSSVC_ASMOBJS)) $(KERNEL_ASMOBJS) $(CFG_ASMOBJS): \
+														| offset.timestamp
+
+#
 #  特別な依存関係の定義
 #
@@ -454,5 +469,5 @@
 #
 $(OBJFILE): $(ALL_OBJS) $(LIBS_DEP)
-	$(LINK) $(CFLAGS) $(LDFLAGS) $(OBJ_LDFLAGS) -o $(OBJFILE) \
+	$(LINK) $(CFLAGS) $(LDFLAGS) $(OBJ_LDFLAGS) -o $(OBJFILE) -Wl,-Map=$(OBJNAME).map,--cref \
 			$(START_OBJS) $(APPL_OBJS) $(SYSSVC_OBJS) $(CFG_OBJS) \
 			-Wl,--start-group $(ALL_LIBS) -Wl,--end-group $(END_OBJS)
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/client.c
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/client.c	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/client.c	(revision 364)
@@ -1,7 +1,7 @@
 /*
  *  TOPPERS ECHONET Lite Communication Middleware
- * 
+ *
  *  Copyright (C) 2016 Cores Co., Ltd. Japan
- * 
+ *
  *  上記著作権者は，以下の(1)～(4)の条件を満たす場合に限り，本ソフトウェ
  *  ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
@@ -26,5 +26,5 @@
  *      由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
  *      免責すること．
- * 
+ *
  *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
  *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
@@ -32,5 +32,5 @@
  *  アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
  *  の責任を負わない．
- * 
+ *
  *  @(#) $Id$
  */
@@ -48,12 +48,38 @@
 #include "ff.h"
 #include "util/ntstdio.h"
+#include "client.h"
+#include "jsonsl.h"
 
 #define SKIP_PEER_VERIFICATION
 //#define SKIP_HOSTNAME_VERIFICATION
+
+const char SCOPE_DRIVE_FILE[] = "https://www.googleapis.com/auth/drive.file";
+const char GRANT_TYPE_DEVICE[] = "http://oauth.net/grant_type/device/1.0";
+
 char response[80];
-extern ntstdio_t ntstdio;
+char errbuf[CURL_ERROR_SIZE];
+
+google_drive_t google_drive;
+
+void curl_setopt_common(CURL *curl);
+int google_drive_error_callback(jsonsl_t jsn, jsonsl_error_t err,
+	struct jsonsl_state_st *state, char *errat);
+void google_drive_state_callback(jsonsl_t jsn, jsonsl_action_t action,
+	struct jsonsl_state_st *state, const char *buf);
 
 void client_init(void)
 {
+	google_drive_t *gd = &google_drive;
+	jsonsl_t jsn;
+
+	memset(gd, 0, sizeof(google_drive_t));
+	memcpy(gd->fname, "1:/log/20160101000000.log", sizeof(gd->fname));
+
+	jsn = gd->jsn = jsonsl_new(3);
+	jsn->data = gd;
+	jsn->error_callback = google_drive_error_callback;
+	jsn->action_callback = google_drive_state_callback;
+	jsonsl_enable_all_callbacks(jsn);
+
 	//uITRON4_minit(ITRON_POOL_SIZE);
 
@@ -61,7 +87,548 @@
 }
 
-size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
-{
-	int rest = size * nmemb;
+size_t write_callback(void *buffer, size_t size, size_t nmemb, void *arg)
+{
+	google_drive_t *gd = (google_drive_t *)arg;
+	jsonsl_t jsn = gd->jsn;
+	size_t len = size * nmemb, pos;
+	jsonsl_char_t data;
+
+	for (pos = 0; pos < len; pos++) {
+		data = *((jsonsl_char_t *)&((uint8_t *)buffer)[pos]);
+
+		if ((gd->jsn_buf_pos >= 0) && (gd->jsn_buf_pos < sizeof(gd->jsn_buf)))
+			gd->jsn_buf[gd->jsn_buf_pos++] = data;
+		jsonsl_feed(jsn, &data, 1);
+	}
+
+	return len;
+}
+
+void get_device_id_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+	switch (gd->state) {
+	case psRoot:
+		if (state->level != 2) {
+			break;
+		}
+		else if (strcmp(buf, "device_code") == 0) {
+			gd->state = psDeviceCode;
+		}
+		else if (strcmp(buf, "user_code") == 0) {
+			gd->state = psUserCode;
+		}
+		else if (strcmp(buf, "expires_in") == 0) {
+			gd->state = psExpiresIn;
+		}
+		else if (strcmp(buf, "interval") == 0) {
+			gd->state = psInterval;
+		}
+		else if (strcmp(buf, "verification_url") == 0) {
+			gd->state = psVerificationUrl;
+		}
+		else if (strcmp(buf, "error") == 0) {
+			gd->state = psError;
+		}
+		else if (strcmp(buf, "error_description") == 0) {
+			gd->state = psErrorDescription;
+		}
+		break;
+	case psDeviceCode:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.device_code, buf, sizeof(gd->credential.device_code));
+			gd->state = psRoot;
+		}
+		break;
+	case psUserCode:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.user_code, buf, sizeof(gd->credential.user_code));
+			gd->state = psRoot;
+		}
+		break;
+	case psExpiresIn:
+		if (state->type == JSONSL_T_SPECIAL) {
+			gd->credential.expires_in = atoi(buf);
+			gd->state = psRoot;
+		}
+		break;
+	case psInterval:
+		if (state->type == JSONSL_T_SPECIAL) {
+			gd->credential.interval = atoi(buf);
+			gd->state = psRoot;
+		}
+		break;
+	case psVerificationUrl:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.verification_url, buf, sizeof(gd->credential.verification_url));
+			gd->state = psRoot;
+		}
+		break;
+	case psError:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->error.error, buf, sizeof(gd->error.error));
+			gd->state = psRoot;
+		}
+		break;
+	case psErrorDescription:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
+			gd->state = psRoot;
+		}
+		break;
+	}
+}
+
+void get_device_id_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+}
+
+int get_device_id(google_drive_t *gd, const char *scope)
+{
+	client_info_t *client_info = &gd->client_info;
+	credential_t *credential = &gd->credential;
+	CURLcode ret;
+	CURL *curl;
+	struct curl_slist *slist1;
+	size_t len;
+	char *postdata;
+	jsonsl_t jsn = gd->jsn;
+
+	gd->jsn_buf_pos = -1;
+
+	jsonsl_reset(jsn);
+	gd->start = get_device_id_state_start;
+	gd->end = get_device_id_state_end;
+
+	slist1 = NULL;
+	slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
+
+	curl = curl_easy_init();
+
+	char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
+	char *esc_scope = curl_easy_escape(curl, scope, strlen(scope));
+
+	len = sizeof("client_id=") + strlen(client_id) + sizeof("scope=") + strlen(esc_scope);
+	postdata = malloc(len);
+	snprintf(postdata, len, "client_id=%s&scope=%s", client_id, esc_scope);
+
+	curl_free(client_id);
+	curl_free(esc_scope);
+
+	curl_easy_setopt(curl, CURLOPT_URL, "https://accounts.google.com/o/oauth2/device/code");
+	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
+	curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
+	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
+	curl_setopt_common(curl);
+
+	curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+
+	ret = curl_easy_perform(curl);
+
+	free(postdata);
+
+	curl_easy_cleanup(curl);
+	curl = NULL;
+	curl_slist_free_all(slist1);
+	slist1 = NULL;
+
+	return (int)ret;
+}
+
+void get_access_token_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+	switch (gd->state) {
+	case psRoot:
+		if (state->level != 2) {
+			break;
+		}
+		else if (strcmp(buf, "access_token") == 0) {
+			gd->state = psAccessToken;
+		}
+		else if (strcmp(buf, "expires_in") == 0) {
+			gd->state = psExpiresIn;
+		}
+		else if (strcmp(buf, "refresh_token") == 0) {
+			gd->state = psRefreshToken;
+		}
+		else if (strcmp(buf, "scope") == 0) {
+			gd->state = psScope;
+		}
+		else if (strcmp(buf, "token_type") == 0) {
+			gd->state = psTokenType;
+		}
+		else if (strcmp(buf, "error") == 0) {
+			gd->state = psError;
+		}
+		else if (strcmp(buf, "error_description") == 0) {
+			gd->state = psErrorDescription;
+		}
+		break;
+	case psAccessToken:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.access_token, buf, sizeof(gd->credential.access_token));
+			gd->state = psRoot;
+		}
+		break;
+	case psExpiresIn:
+		if (state->type == JSONSL_T_SPECIAL) {
+			gd->credential.expires_in = atoi(buf);
+			gd->state = psRoot;
+		}
+		break;
+	case psRefreshToken:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.refresh_token, buf, sizeof(gd->credential.refresh_token));
+			gd->state = psRoot;
+		}
+		break;
+	case psScope:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.scope, buf, sizeof(gd->credential.scope));
+			gd->state = psRoot;
+		}
+		break;
+	case psTokenType:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.token_type, buf, sizeof(gd->credential.token_type));
+			gd->state = psRoot;
+		}
+		break;
+	case psError:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->error.error, buf, sizeof(gd->error.error));
+			gd->state = psRoot;
+		}
+		break;
+	case psErrorDescription:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
+			gd->state = psRoot;
+		}
+		break;
+	}
+}
+
+void get_access_token_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+}
+
+int get_access_token(google_drive_t *gd)
+{
+	client_info_t *client_info = &gd->client_info;
+	credential_t *credential = &gd->credential;
+	CURLcode ret;
+	CURL *curl;
+	struct curl_slist *slist1;
+	size_t len;
+	char *postdata;
+	jsonsl_t jsn = gd->jsn;
+
+	gd->jsn_buf_pos = -1;
+
+	jsonsl_reset(jsn);
+	gd->start = get_access_token_state_start;
+	gd->end = get_access_token_state_end;
+
+	slist1 = NULL;
+	slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
+
+	curl = curl_easy_init();
+
+	char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
+	char *client_secret = curl_easy_escape(curl, client_info->client_secret, strnlen(client_info->client_secret, sizeof(client_info->client_secret)));
+	char *grant_type = curl_easy_escape(curl, GRANT_TYPE_DEVICE, strnlen(GRANT_TYPE_DEVICE, sizeof(GRANT_TYPE_DEVICE)));
+
+	len = sizeof("client_id=") + strlen(client_id) + sizeof("client_secret=") + strlen(client_secret)
+		+ sizeof("code=") + strlen(credential->device_code) + sizeof("grant_type=") + strlen(grant_type);
+	postdata = malloc(len);
+	snprintf(postdata, len, "client_id=%s&client_secret=%s&code=%s&grant_type=%s",
+		client_id, client_secret, credential->device_code, grant_type);
+
+	curl_free(client_id);
+	curl_free(client_secret);
+	curl_free(grant_type);
+
+	curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
+	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
+	curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
+	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
+	curl_setopt_common(curl);
+
+	curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+
+	ret = curl_easy_perform(curl);
+
+	free(postdata);
+
+	curl_easy_cleanup(curl);
+	curl = NULL;
+	curl_slist_free_all(slist1);
+	slist1 = NULL;
+
+	return (int)ret;
+}
+
+void update_access_token_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+	switch (gd->state) {
+	case psRoot:
+		if (state->level != 2) {
+			break;
+		}
+		else if (strcmp(buf, "access_token") == 0) {
+			gd->state = psAccessToken;
+		}
+		else if (strcmp(buf, "expires_in") == 0) {
+			gd->state = psExpiresIn;
+		}
+		else if (strcmp(buf, "scope") == 0) {
+			gd->state = psScope;
+		}
+		else if (strcmp(buf, "token_type") == 0) {
+			gd->state = psTokenType;
+		}
+		else if (strcmp(buf, "error") == 0) {
+			gd->state = psError;
+		}
+		else if (strcmp(buf, "error_description") == 0) {
+			gd->state = psErrorDescription;
+		}
+		break;
+	case psAccessToken:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.access_token, buf, sizeof(gd->credential.access_token));
+			gd->state = psRoot;
+		}
+		break;
+	case psExpiresIn:
+		if (state->type == JSONSL_T_SPECIAL) {
+			gd->credential.expires_in = atoi(buf);
+			gd->state = psRoot;
+		}
+		break;
+	case psScope:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.scope, buf, sizeof(gd->credential.scope));
+			gd->state = psRoot;
+		}
+		break;
+	case psTokenType:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->credential.token_type, buf, sizeof(gd->credential.token_type));
+			gd->state = psRoot;
+		}
+		break;
+	case psError:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->error.error, buf, sizeof(gd->error.error));
+			gd->state = psRoot;
+		}
+		break;
+	case psErrorDescription:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
+			gd->state = psRoot;
+		}
+		break;
+	}
+}
+
+void update_access_token_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+}
+
+int update_access_token(google_drive_t *gd)
+{
+	client_info_t *client_info = &gd->client_info;
+	credential_t *credential = &gd->credential;
+	CURLcode ret;
+	CURL *curl;
+	struct curl_slist *slist1;
+	size_t len;
+	char *postdata;
+	jsonsl_t jsn = gd->jsn;
+
+	gd->jsn_buf_pos = -1;
+
+	jsonsl_reset(jsn);
+	gd->start = update_access_token_state_start;
+	gd->end = update_access_token_state_end;
+
+	slist1 = NULL;
+	slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
+
+	curl = curl_easy_init();
+
+	char *client_id = curl_easy_escape(curl, client_info->client_id, strnlen(client_info->client_id, sizeof(client_info->client_id)));
+	char *client_secret = curl_easy_escape(curl, client_info->client_secret, strnlen(client_info->client_secret, sizeof(client_info->client_secret)));
+
+	len = sizeof("client_id=") + strlen(client_id) + sizeof("client_secret=") + strlen(client_secret)
+		+ sizeof("refresh_token=") + strlen(credential->refresh_token);
+	postdata = malloc(len);
+	snprintf(postdata, len, "client_id=%s&client_secret=%s&code=%s&grant_type=refresh_token",
+		client_id, client_secret, credential->refresh_token);
+
+	curl_free(client_id);
+	curl_free(client_secret);
+
+	curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
+	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
+	curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
+	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
+	curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
+	curl_setopt_common(curl);
+
+	curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+
+	ret = curl_easy_perform(curl);
+
+	free(postdata);
+
+	curl_easy_cleanup(curl);
+	curl = NULL;
+	curl_slist_free_all(slist1);
+	slist1 = NULL;
+
+	return (int)ret;
+}
+
+void revoke_device_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+}
+
+void revoke_device_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+}
+
+int revoke_device(google_drive_t *gd)
+{
+	client_info_t *client_info = &gd->client_info;
+	credential_t *credential = &gd->credential;
+	CURLcode ret;
+	CURL *curl;
+	size_t len;
+	struct curl_slist *slist1;
+	char *postdata;
+	jsonsl_t jsn = gd->jsn;
+
+	gd->jsn_buf_pos = -1;
+
+	jsonsl_reset(jsn);
+	gd->start = revoke_device_state_start;
+	gd->end = revoke_device_state_end;
+
+	slist1 = NULL;
+	slist1 = curl_slist_append(slist1, "Content-Type: application/x-www-form-urlencoded");
+
+	curl = curl_easy_init();
+
+	len = sizeof("token=") + strlen(credential->access_token);
+	postdata = malloc(len);
+	snprintf(postdata, len, "token=%s", credential->access_token);
+
+	curl_easy_setopt(curl, CURLOPT_URL, "https://accounts.google.com/o/oauth2/revoke");
+	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
+	curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)strnlen(postdata, len));
+	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
+	curl_setopt_common(curl);
+
+	curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+
+	ret = curl_easy_perform(curl);
+
+	free(postdata);
+
+	curl_easy_cleanup(curl);
+	curl = NULL;
+	curl_slist_free_all(slist1);
+	slist1 = NULL;
+
+	return (int)ret;
+}
+
+void upload_file_state_start(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+	switch (gd->state) {
+	case psRoot:
+		if (state->level != 2) {
+			break;
+		}
+		else if (strcmp(buf, "kind") == 0) {
+			gd->state = psKind;
+		}
+		else if (strcmp(buf, "id") == 0) {
+			gd->state = psId;
+		}
+		else if (strcmp(buf, "name") == 0) {
+			gd->state = psName;
+		}
+		else if (strcmp(buf, "mimeType") == 0) {
+			gd->state = psMimeType;
+		}
+		else if (strcmp(buf, "error") == 0) {
+			gd->state = psError;
+		}
+		else if (strcmp(buf, "error_description") == 0) {
+			gd->state = psErrorDescription;
+		}
+		break;
+	case psKind:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->file.kind, buf, sizeof(gd->file.kind));
+			gd->state = psRoot;
+		}
+		break;
+	case psId:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->file.id, buf, sizeof(gd->file.id));
+			gd->state = psRoot;
+		}
+		break;
+	case psName:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->file.name, buf, sizeof(gd->file.name));
+			gd->state = psRoot;
+		}
+		break;
+	case psMimeType:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->file.mimeType, buf, sizeof(gd->file.mimeType));
+			gd->state = psRoot;
+		}
+		break;
+	case psError:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->error.error, buf, sizeof(gd->error.error));
+			gd->state = psRoot;
+		}
+		break;
+	case psErrorDescription:
+		if (state->type == JSONSL_T_STRING) {
+			strlcpy(gd->error.error_description, buf, sizeof(gd->error.error_description));
+			gd->state = psRoot;
+		}
+		break;
+	}
+}
+
+void upload_file_state_end(google_drive_t *gd, struct jsonsl_state_st *state, const char *buf)
+{
+}
+
+size_t read_callback(char *buffer, size_t size, size_t nitems, void *arg)
+{
+	FIL *file = (FIL *)arg;
+	UINT ret = 0;
+	FRESULT res;
+
+	res = f_read(file, buffer, size * nitems, &ret);
+	if (res != FR_OK)
+		return 0;
+
+	int rest = ret;
 	int len;
 
@@ -76,7 +643,7 @@
 		response[len] = '\0';
 
-		ntstdio_printf(&ntstdio, response);
-
-		dly_tsk(100 * 1000);
+		printf(response);
+
+		dly_tsk(100);
 
 		rest -= len;
@@ -84,42 +651,159 @@
 	}
 
-	return size * nmemb;
-}
-
-size_t read_data(char *buffer, size_t size, size_t nitems, void *instream)
-{
-	FIL *file = (FIL *)instream;
-	UINT ret = 0;
-	FRESULT res;
-
-	res = f_read(file, buffer, size * nitems, &ret);
-	if (res != FR_OK)
-		return 0;
-
-	int rest = ret;
-	int len;
-
-	while (rest > 0) {
-		len = rest;
-		if (len > (sizeof(response) - 1)) {
-			len = sizeof(response) - 1;
-		}
-
-		memcpy(response, buffer, len);
-
-		response[len] = '\0';
-
-		ntstdio_printf(&ntstdio, response);
-
-		dly_tsk(100);
-
-		rest -= len;
-		buffer = (char *)buffer + len;
-	}
-
 	return ret;
 }
 
-char errbuf[CURL_ERROR_SIZE];
+int seek_callback(void *arg, curl_off_t offset, int origin)
+{
+	FIL *file = (FIL *)arg;
+	BYTE mode;
+	FRESULT ret;
+
+	switch (origin) {
+	case SEEK_SET:
+		mode = F_SEEK_SET;
+		break;
+	case SEEK_CUR:
+		mode = F_SEEK_CUR;
+		break;
+	case SEEK_END:
+		mode = F_SEEK_END;
+		break;
+	default:
+		return CURL_SEEKFUNC_FAIL;
+	}
+
+	ret = f_seek(file, offset, mode);
+	if (ret != F_OK)
+		return CURL_SEEKFUNC_FAIL;
+
+	return CURL_SEEKFUNC_OK;
+}
+
+int upload_file(google_drive_t *gd, const char *filename, const char *localfilepath)
+{
+	CURLcode ret;
+	CURL *curl;
+	curl_mime *mime;
+	curl_mimepart *part;
+	struct curl_slist *slist1;
+	size_t len;
+	char *postdata, *authorization;
+	static const char buf[] = "Expect:";
+	jsonsl_t jsn = gd->jsn;
+	FIL file;
+	FRESULT fret;
+
+	gd->jsn_buf_pos = -1;
+
+	jsonsl_reset(jsn);
+	gd->start = upload_file_state_start;
+	gd->end = upload_file_state_end;
+
+	fret = f_open(&file, localfilepath, FA_READ);
+	if (fret != FR_OK) {
+		printf("log file open error %d\n", fret);
+		return -1;
+	}
+
+	len = sizeof("{\"name\":\"\"}") + strlen(filename);
+	postdata = malloc(len);
+	snprintf(postdata, len, "{\"name\":\"%s\"}", filename);
+
+	curl = curl_easy_init();
+
+	mime = curl_mime_init(curl);
+	part = curl_mime_addpart(mime);
+	curl_mime_name(part, "metadata");
+	curl_mime_type(part, "application/json;charset=utf-8");
+	curl_mime_data(part, postdata, CURL_ZERO_TERMINATED);
+	free(postdata);
+
+	part = curl_mime_addpart(mime);
+	curl_mime_name(part, "file");
+	curl_mime_type(part, "application/json");
+	curl_mime_data_cb(part, file.fsize, read_callback, seek_callback, NULL, &file);
+
+	len = sizeof("Authorization: Bearer ") + strnlen(gd->credential.access_token, sizeof(gd->credential.access_token));
+	authorization = malloc(len);
+	snprintf(authorization, len, "Authorization: Bearer %s", gd->credential.access_token);
+	slist1 = NULL;
+	slist1 = curl_slist_append(slist1, authorization);
+	free(authorization);
+
+	slist1 = curl_slist_append(slist1, buf);
+
+	curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
+	curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+	curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
+	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
+	curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
+	curl_setopt_common(curl);
+
+	curl_easy_setopt(curl, CURLOPT_WRITEDATA, gd);
+	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+
+	ret = curl_easy_perform(curl);
+
+	curl_easy_cleanup(curl);
+	curl = NULL;
+	curl_mime_free(mime);
+	mime = NULL;
+	curl_slist_free_all(slist1);
+	slist1 = NULL;
+
+	f_close(&file);
+
+	return (int)ret;
+}
+
+int google_drive_error_callback(jsonsl_t jsn, jsonsl_error_t err,
+	struct jsonsl_state_st *state, char *errat)
+{
+	return 0;
+}
+
+void google_drive_state_callback(jsonsl_t jsn, jsonsl_action_t action,
+	struct jsonsl_state_st *state, const char *buf)
+{
+	google_drive_t *gd = (google_drive_t *)jsn->data;
+
+	switch (action) {
+	case JSONSL_ACTION_PUSH:
+		switch (state->type) {
+		case JSONSL_T_SPECIAL:
+			gd->jsn_buf[0] = *buf;
+			gd->jsn_buf_pos = 1;
+			break;
+		case JSONSL_T_STRING:
+		case JSONSL_T_HKEY:
+			gd->jsn_buf_pos = 0;
+			break;
+		default:
+			gd->jsn_buf_pos = -1;
+		}
+		break;
+	case JSONSL_ACTION_POP:
+		switch (state->type) {
+		case JSONSL_T_SPECIAL:
+		case JSONSL_T_STRING:
+		case JSONSL_T_HKEY:
+			gd->jsn_buf_pos--;
+			if (gd->jsn_buf_pos < sizeof(gd->jsn_buf)) {
+				gd->jsn_buf[gd->jsn_buf_pos] = '\0';
+			}
+			gd->start(gd, state, gd->jsn_buf);
+			break;
+		default:
+			gd->jsn_buf[0] = '\0';
+			break;
+		}
+		gd->jsn_buf_pos = -1;
+		break;
+	default:
+		gd->jsn_buf_pos = -1;
+		break;
+	}
+}
 
 static void get_logfname(char *fname)
@@ -185,5 +869,5 @@
 	ret = f_open(&file, fname, FA_CREATE_ALWAYS | FA_WRITE);
 	if (ret != FR_OK) {
-		ntstdio_printf(&ntstdio, "not open a upload file %d\n", ret);
+		printf("not open a upload file %d\n", ret);
 		return ret;
 	}
@@ -232,5 +916,4 @@
 	f_putc('}', &file);
 
-file_close:
 	f_close(&file);
 
@@ -238,43 +921,12 @@
 }
 
-void client_task(intptr_t exinf)
-{
-	CURL *curl;
+void curl_setopt_common(CURL *curl)
+{
 	CURLcode res;
-	int error = 0;
-	//const char *data = "{\"value\":\"data post\"}";
-	struct curl_slist *list = NULL;
-	FIL file;
-	FRESULT ret;
-	char fname[] = {"1:/log/20160101000000.log"};
-
-	get_logfname(fname);
-
-	ret = write_log(fname);
-	if (ret != FR_OK) {
-		ntstdio_printf(&ntstdio, "log file write error %d\n", ret);
-		return;
-	}
-
-	ret = f_open(&file, fname, FA_READ);
-	if (ret != FR_OK) {
-		ntstdio_printf(&ntstdio, "log file open error %d\n", ret);
-		return;
-	}
-
-	ntstdio_printf(&ntstdio, "cURL start\n");
-
-	curl = curl_easy_init();
-	if (curl == NULL) {
-		ntstdio_printf(&ntstdio, "curl_easy_init() failed\n");
-		goto file_close;
-	}
 
 	/* ask libcurl to show us the verbose output */
-	curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
-
-	res = curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com/");
+	res = curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
 	if (res != CURLE_OK)
-		ntstdio_printf(&ntstdio, "CURLOPT_URL failed: %s\n",
+		printf("CURLOPT_VERBOSE failed: %s\n",
 			curl_easy_strerror(res));
 
@@ -283,5 +935,8 @@
 
 	/* provide a buffer to store errors in */
-	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
+	res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
+	if (res != CURLE_OK)
+		printf("CURLOPT_ERRORBUFFER failed: %s\n",
+			curl_easy_strerror(res));
 
 #ifdef SKIP_PEER_VERIFICATION
@@ -298,20 +953,20 @@
 	res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
 	if (res != CURLE_OK)
-		ntstdio_printf(&ntstdio, "CURLOPT_SSL_VERIFYPEER failed: %s\n",
+		printf("CURLOPT_SSL_VERIFYPEER failed: %s\n",
 			curl_easy_strerror(res));
 #else
 	res = curl_easy_setopt(curl, CURLOPT_CAINFO, "0:/certs/ca-cert.pem");
 	if (res != CURLE_OK)
-		ntstdio_printf(&ntstdio, "CURLOPT_CAINFO failed: %s\n",
+		printf("CURLOPT_CAINFO failed: %s\n",
 			curl_easy_strerror(res));
 
 	res = curl_easy_setopt(curl, CURLOPT_SSLCERT, "0:/certs/client-cert.pem");
 	if (res != CURLE_OK)
-		ntstdio_printf(&ntstdio, "CURLOPT_SSLCERT failed: %s\n",
+		printf("CURLOPT_SSLCERT failed: %s\n",
 			curl_easy_strerror(res));
 
 	res = curl_easy_setopt(curl, CURLOPT_SSLKEY, "0:/certs/client-key.pem");
 	if (res != CURLE_OK)
-		ntstdio_printf(&ntstdio, "CURLOPT_SSLKEY failed: %s\n",
+		printf("CURLOPT_SSLKEY failed: %s\n",
 			curl_easy_strerror(res));
 #endif
@@ -326,5 +981,5 @@
 	res = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
 	if (res != CURLE_OK)
-		ntstdio_printf(&ntstdio, "CURLOPT_SSL_VERIFYHOST failed: %s\n",
+		printf("CURLOPT_SSL_VERIFYHOST failed: %s\n",
 			curl_easy_strerror(res));
 #endif
@@ -332,53 +987,138 @@
 	/*res = curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy.example.com:8080");
 	if (res != CURLE_OK)
-		ntstdio_printf(&ntstdio, "CURLOPT_PROXY failed: %s\n",
+		printf("CURLOPT_PROXY failed: %s\n",
 			curl_easy_strerror(res));*/
 
-	curl_easy_setopt(curl, CURLOPT_POST, 1);
-
-	/* size of the POST data */
-	//curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(data));
-	curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, file.fsize);
-
-	/* pass in a pointer to the data - libcurl will not copy */
-	//curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
-
-	list = curl_slist_append(list, "Content-Type: application/json");
-
-	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
-
-	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&error);
-
-	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
-
-	/* now specify which file to upload */
-	curl_easy_setopt(curl, CURLOPT_READDATA, &file);
-
-	/* we want to use our own read function */
-	curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data);
-
-	ntstdio_printf(&ntstdio, "cURL perform the request\n");
-	tslp_tsk(100 * 1000);
-
-	/* Perform the request, res will get the return code */
-	res = curl_easy_perform(curl);
-	/* Check for errors */
-	if (res != CURLE_OK) {
-		ntstdio_printf(&ntstdio, "curl_easy_perform() failed: %s\n",
+	res = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
+	if (res != CURLE_OK)
+		printf("CURLOPT_NOPROGRESS failed: %s\n",
 			curl_easy_strerror(res));
-		ntstdio_printf(&ntstdio, errbuf);
-	}
-
-	/* always cleanup */
-	curl_easy_cleanup(curl);
-
-	ntstdio_printf(&ntstdio, "cURL end\n");
-
-file_close:
-	f_close(&file);
-}
-
-void client_fin(void)
-{
+
+	res = curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
+	if (res != CURLE_OK)
+		printf("CURLOPT_MAXREDIRS failed: %s\n",
+			curl_easy_strerror(res));
+
+	res = curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
+	if (res != CURLE_OK)
+		printf("CURLOPT_TCP_KEEPALIVE failed: %s\n",
+			curl_easy_strerror(res));
+}
+
+void client_set_client_id(const char *client_id)
+{
+	google_drive_t *gd = &google_drive;
+
+	strlcpy(gd->client_info.client_id, client_id, sizeof(gd->client_info.client_id));
+}
+
+void client_set_client_secret(const char *client_secret)
+{
+	google_drive_t *gd = &google_drive;
+
+	strlcpy(gd->client_info.client_secret, client_secret, sizeof(gd->client_info.client_secret));
+}
+
+int client_get_device_id(int argc, char **argv)
+{
+	google_drive_t *gd = &google_drive;
+	int ret;
+
+	ret = get_device_id(gd, SCOPE_DRIVE_FILE);
+	if (ret == 0) {
+		printf("Device was registered. Enter the code at the following URL\n");
+		printf("url:  %s\n", gd->credential.verification_url);
+		printf("code: %s\n", gd->credential.user_code);
+	}
+	else {
+		printf("Device register failed! %d\n", ret);
+	}
+
+	return ret;
+}
+
+int client_get_access_token(int argc, char **argv)
+{
+	google_drive_t *gd = &google_drive;
+	int ret;
+
+	ret = get_access_token(gd);
+	if (ret == 0) {
+		printf("Access token was give\n");
+		printf("Refresh token: %s\n", gd->credential.refresh_token);
+		printf("Access token: %s\n", gd->credential.access_token);
+	}
+	else {
+		printf("Access token gain failed. %d\n", ret);
+	}
+
+	return ret;
+}
+
+int client_update_access_token(int argc, char **argv)
+{
+	google_drive_t *gd = &google_drive;
+	int ret;
+
+	ret = update_access_token(gd);
+	if (ret == 0) {
+		printf("Access token was update\n");
+		printf("Access token: %s\n", gd->credential.access_token);
+	}
+	else {
+		printf("Access token update failed. %d\n", ret);
+	}
+
+	return ret;
+}
+
+int client_revoke(int argc, char **argv)
+{
+	google_drive_t *gd = &google_drive;
+	int ret;
+
+	ret = revoke_device(gd);
+	if (ret == 0) {
+		printf("Device was revoked.\n");
+	}
+	else {
+		printf("Device revoke failed. %d\n", ret);
+	}
+
+	return ret;
+}
+
+int client_upload_file(int argc, char **argv)
+{
+	google_drive_t *gd = &google_drive;
+	int ret;
+	FRESULT fret;
+	char fname[] = { "1:/log/20160101000000.log" };
+
+	get_logfname(fname);
+
+	fret = write_log(fname);
+	if (fret != FR_OK) {
+		printf("log file write error %d\n", fret);
+		return (int)fret;
+	}
+
+	ret = upload_file(gd, &fname[7], fname);
+	if (ret == 0) {
+		printf("%s was uploaded.\n", &fname[7]);
+	}
+	else {
+		printf("%s upload failed. %d\n", &fname[7], ret);
+	}
+
+	return ret;
+}
+
+void client_final(void)
+{
+	google_drive_t *gd = &google_drive;
+	jsonsl_t jsn = gd->jsn;
+
 	curl_global_cleanup();
-}
+	jsonsl_destroy(jsn);
+}
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/client.h
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/client.h	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/client.h	(revision 364)
@@ -39,14 +39,83 @@
 #define _CLIENT_H_
 
-#include <kernel.h>
-#include "target_kernel_impl.h"
+typedef struct client_info_t {
+	char client_id[80];
+	char client_secret[32];
+} client_info_t;
 
-#define CLIENT_PRIORITY		4		/* クライアントタスクの優先度 */
+typedef struct credential_t {
+	char device_code[100];
+	char user_code[12];
+	int expires_in;
+	int interval;
+	char verification_url[32];
+	char access_token[132];
+	char refresh_token[64];
+	char scope[64];
+	char token_type[16];
+} credential_t;
 
-#define CLIENT_STACK_SIZE	6144	/* スタック領域のサイズ */
+typedef struct error_response_t {
+	char error[64];
+	char error_description[64];
+} error_response_t;
 
-extern void client_init(void);
-extern void client_task(intptr_t exinf);
-extern void client_fin(void);
+typedef struct drive_file_t {
+	char kind[32];
+	char id[36];
+	char name[256];
+	char mimeType[40];
+} drive_file_t;
+
+typedef enum google_drive_parse_state_t {
+	psRoot,
+	psDeviceCode,
+	psUserCode,
+	psExpiresIn,
+	psInterval,
+	psVerificationUrl,
+	psAccessToken,
+	psRefreshToken,
+	psScope,
+	psTokenType,
+	psKind,
+	psId,
+	psName,
+	psMimeType,
+	psError,
+	psErrorDescription,
+} google_drive_parse_state_t;
+
+struct jsonsl_st;
+typedef struct jsonsl_st *jsonsl_t;
+
+typedef void (*parser_callback_t)(struct google_drive_t *gd, struct jsonsl_state_st *state, const char *buf);
+
+typedef struct google_drive_t {
+	client_info_t client_info;
+	credential_t credential;
+	drive_file_t file;
+	error_response_t error;
+	jsonsl_t jsn;
+	google_drive_parse_state_t state;
+	char fname[sizeof("1:/log/20160101000000.log")];
+	char jsn_buf[256];
+	int jsn_buf_pos;
+	parser_callback_t start;
+	parser_callback_t end;
+} google_drive_t;
+
+extern google_drive_t google_drive;
+
+void client_init(void);
+void client_final(void);
+
+void client_set_client_id(const char *client_id);
+void client_set_client_secret(const char *client_secret);
+int client_get_device_id(int argc, char **argv);
+int client_get_access_token(int argc, char **argv);
+int client_update_access_token(int argc, char **argv);
+int client_revoke(int argc, char **argv);
+int client_upload_file(int argc, char **argv);
 
 #endif /* _CLIENT_H_ */
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/echonet_main.c
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/echonet_main.c	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/echonet_main.c	(revision 364)
@@ -1,7 +1,7 @@
 /*
  *  TOPPERS ECHONET Lite Communication Middleware
- * 
+ *
  *  Copyright (C) 2016-2018 Cores Co., Ltd. Japan
- * 
+ *
  *  上記著作権者は，以下の(1)～(4)の条件を満たす場合に限り，本ソフトウェ
  *  ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
@@ -26,5 +26,5 @@
  *      由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
  *      免責すること．
- * 
+ *
  *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
  *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
@@ -32,9 +32,9 @@
  *  アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
  *  の責任を負わない．
- * 
+ *
  *  @(#) $Id$
  */
 
-/* 
+/*
  *  サンプルプログラム(1)の本体
  */
@@ -164,10 +164,10 @@
 {
 	/* サイズが１以外は受け付けない */
-	if(size != 1)
+	if (size != 1)
 		return 0;
 
 	*anno = *((uint8_t*)item->exinf) != *((uint8_t*)src);
 
-	switch(*(uint8_t *)src){
+	switch (*(uint8_t *)src) {
 	/* ONの場合 */
 	case 0x30:
@@ -196,10 +196,10 @@
 {
 	/* サイズが１以外は受け付けない */
-	if(size != 1)
+	if (size != 1)
 		return 0;
 
 	*anno = *((uint8_t *)item->exinf) != *((uint8_t *)src);
 
-	switch(*(uint8_t *)src){
+	switch (*(uint8_t *)src) {
 	/* 異常発生ありの場合 */
 	case 0x41:
@@ -271,5 +271,5 @@
 int date_prop_set(const EPRPINIB *item, const void *src, int size, bool_t *anno)
 {
-	uint8_t *p_src;
+	const uint8_t *p_src;
 	time_t temp;
 	struct tm _tm;
@@ -283,5 +283,5 @@
 	/* 年月日設定 */
 	p_src = (uint8_t *)src;
-	_tm.tm_year = (*(p_src++) * 100) + *p_src++;
+	_tm.tm_year = (*p_src++ * 100) + *p_src++;
 	_tm.tm_mon = (*p_src++) - 1;
 	_tm.tm_mday = *p_src++;
@@ -325,5 +325,5 @@
 
 	/* サイズが4以外は受け付けない */
-	if(size != 4)
+	if (size != 4)
 		return 0;
 
@@ -345,5 +345,5 @@
 
 	len = 48 - meter->current_pos;
-	if(len > 0)
+	if (len > 0)
 		memcpy(dst, &meter->integral_electric_energy_measurement_log[meter->current_pos], sizeof(uint32_t) * len);
 	dst = &((uint8_t *)dst)[len];
@@ -404,10 +404,10 @@
 
 	ret2 = get_tim(&now);
-	if (ret2 != E_OK){
+	if (ret2 != E_OK) {
 		syslog(LOG_ERROR, "get_tim");
 		return;
 	}
 
-	for(;;){
+	for (;;) {
 		prev = now;
 
@@ -417,5 +417,5 @@
 		/* 応答電文待ち */
 		ret = ecn_trcv_esv(&esv, timer);
-		if ((ret != E_OK) && (ret != E_BRK) && (ret != E_TMOUT)){
+		if ((ret != E_OK) && (ret != E_BRK) && (ret != E_TMOUT)) {
 			syslog(LOG_ERROR, "ecn_trcv_esv");
 			break;
@@ -423,5 +423,5 @@
 
 		ret2 = get_tim(&now);
-		if (ret2 != E_OK){
+		if (ret2 != E_OK) {
 			syslog(LOG_ERROR, "get_tim");
 			break;
@@ -438,5 +438,5 @@
 			/* 領域解放 */
 			ret = ecn_rel_esv(esv);
-			if (ret != E_OK){
+			if (ret != E_OK) {
 				syslog(LOG_ERROR, "ecn_rel_esv");
 				break;
@@ -447,5 +447,5 @@
 			/* 応答電文待ちの割り込みデータ取得 */
 			ret = ecn_get_brk_dat(esv, brkdat, sizeof(brkdat), &len);
-			if (ret != E_OK){
+			if (ret != E_OK) {
 				syslog(LOG_ERROR, "ecn_get_brk_dat");
 				break;
@@ -457,5 +457,5 @@
 			/* 領域解放 */
 			ret = ecn_rel_esv(esv);
-			if (ret != E_OK){
+			if (ret != E_OK) {
 				syslog(LOG_ERROR, "ecn_rel_esv");
 				break;
@@ -468,6 +468,4 @@
 }
 
-bool_t started = false;
-
 void echonet_change_netif_link(uint8_t link_up, uint8_t up)
 {
@@ -477,14 +475,10 @@
 		return;
 
-	if (up && !started) {
-		started = true;
-
-		/* ECHONETミドルウェアを起動 */
-		ret = ecn_sta_svc();
-		if (ret != E_OK)
-			return;
-
-		/* ECHONETミドルウェアを起動するのを待つ */
-		dly_tsk(100);
+	if (up) {
+		/* インスタンスリスト通知の送信 */
+		ret = ecn_ntf_inl();
+		if (ret != E_OK) {
+			syslog(LOG_ERROR, "ecn_ntf_inl");
+		}
 	}
 
@@ -500,10 +494,11 @@
 }
 
-enum main_state_t{
+enum main_state_t {
+	main_state_start,
 	main_state_idle,
 };
 
 int main_timer = TMO_FEVR;
-enum main_state_t main_state = main_state_idle;
+enum main_state_t main_state = main_state_start;
 int main_lcd_state = 0;
 int main_lcd_timer = TMO_FEVR;
@@ -557,8 +552,8 @@
 	analogin_init(&joystick, P1_12);
 
-	/* 10ms後にボタン状態を確認 */
-	main_timer = 10 * 1000;
-
-	/* ボタン状態読み込み */
+	/* ECHONETミドルウェアを起動するのを待つ */
+	main_state = main_state_start;
+	main_timer = 1000 * 1000;
+
 	btn = main_read_button(&joystick);
 	main_btn1_state = btn == BUTTON_LEFT;
@@ -568,5 +563,5 @@
 	spi_init(&lcd.hspi, P10_14, P10_15, P10_12, NC);
 	spi_format(&lcd.hspi, 8, 0, 0);
-	spi_frequency(&lcd.hspi, 1000000);
+	spi_frequency(&lcd.hspi, 4000000);
 
 	gpio_init_out(&lcd.cs_pin, P10_13);
@@ -590,4 +585,5 @@
 	main_adv_timer = 1000 * 1000;
 
+	/* メインタスクを起動 */
 	ER ret = act_tsk(MAIN_TASK);
 	if (ret != E_OK) {
@@ -603,6 +599,6 @@
 	int result = main_timer;
 
-	if((result == TMO_FEVR)
-		|| ((main_lcd_timer != TMO_FEVR) && (main_lcd_timer < result))){
+	if ((result == TMO_FEVR)
+		|| ((main_lcd_timer != TMO_FEVR) && (main_lcd_timer < result))) {
 		result = main_lcd_timer;
 	}
@@ -621,14 +617,14 @@
 static void main_progress(int interval)
 {
-	if(main_timer != TMO_FEVR){
+	if (main_timer != TMO_FEVR) {
 		main_timer -= interval;
-		if(main_timer < 0){
+		if (main_timer < 0) {
 			main_timer = 0;
 		}
 	}
 
-	if(main_lcd_timer != TMO_FEVR){
+	if (main_lcd_timer != TMO_FEVR) {
 		main_lcd_timer -= interval;
-		if(main_lcd_timer < 0){
+		if (main_lcd_timer < 0) {
 			main_lcd_timer = 0;
 		}
@@ -655,11 +651,11 @@
 
 	ret = ecn_itr_ini(&enm, esv);
-	if(ret != E_OK){
+	if (ret != E_OK) {
 		syslog(LOG_ERROR, "ecn_itr_ini");
 		return;
 	}
 
-	for(;;) {
-		while((ret = ecn_itr_nxt(&enm, &epc, &pdc, p_edt)) == E_OK) {
+	for (;;) {
+		while ((ret = ecn_itr_nxt(&enm, &epc, &pdc, p_edt)) == E_OK) {
 			switch (epc) {
 			case 0x80:
@@ -669,9 +665,9 @@
 			}
 		}
-		if(ret != E_BOVR){
+		if (ret != E_BOVR) {
 			syslog(LOG_ERROR, "ecn_itr_nxt");
 			break;
 		}
-		if(enm.is_eof)
+		if (enm.is_eof)
 			break;
 	}
@@ -684,9 +680,9 @@
 {
 	char mac_text[30] = "mac: ";
-	char ipaddr_text[30] = "ipaddr: ";
-	T_IN4_ADDR *ip4_addr;
+	char ipaddr_text[30] = "ipadr: ";
+	const T_IN4_ADDR *ip4_addr;
 	int pos;
 
-	switch(main_state){
+	switch (main_state) {
 	case main_state_idle:
 		if (len == 0)
@@ -704,10 +700,10 @@
 			pos = str_macaddr(&mac_text[4], sizeof(mac_text) - 4, mac_addr, 0);
 			mac_text[pos + 4] = '\0';
-			lcd_drawString(&lcd, mac_text, X_LINE_TO_PIX(&lcd, 0) + 10, Y_ROW_TO_PIX(&lcd, 14) + 10, ST7735_BLACK, ST7735_WHITE);
+			lcd_drawString(&lcd, mac_text, X_LINE_TO_PIX(&lcd, 0), Y_ROW_TO_PIX(&lcd, 11), ST7735_BLACK, ST7735_WHITE);
 
 			ip4_addr = in4_get_ifaddr(0);
-			pos = str_ipv4addr(&ipaddr_text[7], sizeof(ipaddr_text) - 7, ip4_addr, 0);
-			ipaddr_text[pos + 7] = '\0';
-			lcd_drawString(&lcd, ipaddr_text, X_LINE_TO_PIX(&lcd, 0) + 10, Y_ROW_TO_PIX(&lcd, 15) + 10, ST7735_BLACK, ST7735_WHITE);
+			pos = str_ipv4addr(&ipaddr_text[6], sizeof(ipaddr_text) - 6, ip4_addr, 0);
+			ipaddr_text[pos + 6] = '\0';
+			lcd_drawString(&lcd, ipaddr_text, X_LINE_TO_PIX(&lcd, 0), Y_ROW_TO_PIX(&lcd, 12), ST7735_BLACK, ST7735_WHITE);
 		}
 		break;
@@ -724,9 +720,9 @@
 static void main_timeout()
 {
-	if(main_timer == 0){
+	if (main_timer == 0) {
 		main_ontimer();
 	}
 
-	if(main_lcd_timer == 0){
+	if (main_lcd_timer == 0) {
 		main_lcd_ontimer();
 	}
@@ -746,5 +742,5 @@
 	int port_no, btn;
 
-	switch(main_lcd_state) {
+	switch (main_lcd_state) {
 	case 0:
 	case 1:
@@ -757,10 +753,10 @@
 		text[16] = '0' + main_7seg[port_no][2];
 		text[17] = '0' + main_7seg[port_no][3];
-		lcd_drawString(&lcd, &text[14], X_LINE_HALF_TO_PIX(&lcd, 11) + 10, Y_ROW_TO_PIX(&lcd, main_lcd_state + 4) + 10, ST7735_BLACK, ST7735_WHITE);
+		lcd_drawString(&lcd, &text[14], X_LINE_HALF_TO_PIX(&lcd, 11), Y_ROW_TO_PIX(&lcd, main_lcd_state + 2), ST7735_BLACK, ST7735_WHITE);
 		main_lcd_state++;
 		break;
 	case 6:
 		btn = main_read_button(&joystick);
-		lcd_drawString(&lcd, btn_texts[btn], X_LINE_TO_PIX(&lcd, 0) + 10, Y_ROW_TO_PIX(&lcd, 10) + 10, ST7735_BLACK, ST7735_WHITE);
+		lcd_drawString(&lcd, btn_texts[btn], X_LINE_TO_PIX(&lcd, 0), Y_ROW_TO_PIX(&lcd, 9), ST7735_BLACK, ST7735_WHITE);
 		main_lcd_state++;
 		break;
@@ -769,8 +765,8 @@
 		break;
 	case 10:
-		lcd_drawString(&lcd, "USB電力計", X_LINE_TO_PIX(&lcd, 10) + 10, Y_ROW_TO_PIX(&lcd, 0) + 10, ST7735_BLACK, ST7735_WHITE);
+		lcd_drawString(&lcd, "USB電力計", X_LINE_TO_PIX(&lcd, 6), Y_ROW_TO_PIX(&lcd, 0), ST7735_BLACK, ST7735_WHITE);
 		for (port_no = 0; port_no < 6; port_no++) {
 			text[3] = '1' + port_no;
-			lcd_drawString(&lcd, text, X_LINE_TO_PIX(&lcd, 0) + 10, Y_ROW_TO_PIX(&lcd, port_no + 4) + 10, ST7735_BLACK, ST7735_WHITE);
+			lcd_drawString(&lcd, text, X_LINE_TO_PIX(&lcd, 0), Y_ROW_TO_PIX(&lcd, port_no + 2), ST7735_BLACK, ST7735_WHITE);
 		}
 		main_lcd_state = 0;
@@ -802,8 +798,20 @@
 static void main_ontimer()
 {
+	ER ret;
 	uint8_t btn;
 	uint16_t ad_value;
 
-	switch(main_state){
+	switch (main_state) {
+	case main_state_start:
+		/* ECHONETミドルウェアを起動 */
+		ret = ecn_sta_svc();
+		if (ret != E_OK) {
+			syslog(LOG_ERROR, "ecn_sta_svc");
+		}
+
+		/* 10ms後にボタン状態を確認 */
+		main_state = main_state_idle;
+		main_timer = 10 * 1000;
+		break;
 	case main_state_idle:
 		/* 10ms後にボタン状態を確認 */
@@ -845,7 +853,7 @@
 
 		/* ボタン１の処理 */
-		if((btn == BUTTON_LEFT) && !main_btn1_state){
+		if ((btn == BUTTON_LEFT) && !main_btn1_state) {
 			main_btn1_count++;
-			if(main_btn1_count > 10){
+			if (main_btn1_count > 10) {
 				main_btn1_count = 0;
 				main_btn1_state = true;
@@ -854,7 +862,7 @@
 			}
 		}
-		else if((btn != BUTTON_LEFT) && main_btn1_state){
+		else if ((btn != BUTTON_LEFT) && main_btn1_state) {
 			main_btn1_count++;
-			if(main_btn1_count > 10){
+			if (main_btn1_count > 10) {
 				main_btn1_count = 0;
 				main_btn1_state = false;
@@ -865,7 +873,7 @@
 
 		/* ボタン２の処理 */
-		if((btn == BUTTON_RIGHT) && !main_btn2_state){
+		if ((btn == BUTTON_RIGHT) && !main_btn2_state) {
 			main_btn2_count++;
-			if(main_btn2_count > 10){
+			if (main_btn2_count > 10) {
 				main_btn2_count = 0;
 				main_btn2_state = true;
@@ -874,7 +882,7 @@
 			}
 		}
-		else if((btn != BUTTON_RIGHT) && main_btn2_state){
+		else if ((btn != BUTTON_RIGHT) && main_btn2_state) {
 			main_btn2_count++;
-			if(main_btn2_count > 10){
+			if (main_btn2_count > 10) {
 				main_btn2_count = 0;
 				main_btn2_state = false;
@@ -897,21 +905,21 @@
 static uint8_t main_read_button(analogin_t *obj)
 {
-    float a = analogin_read(obj);
-
-    a *= 5.0;
-
-    //printf("Button read analog = %f\r\n",a);
-    if (a < 0.2)
-    	return BUTTON_DOWN;
-    if (a < 1.0)
-    	return BUTTON_RIGHT;
-    if (a < 1.7)
-    	return BUTTON_SELECT;
-    if (a < 2.6)
-    	return BUTTON_UP;
-    if (a < 4.6)
-    	return BUTTON_LEFT;
-    else
-    	return BUTTON_NONE;
+	float a = analogin_read(obj);
+
+	a *= 5.0;
+
+	//printf("Button read analog = %f\r\n",a);
+	if (a < 0.2)
+		return BUTTON_DOWN;
+	if (a < 1.0)
+		return BUTTON_RIGHT;
+	if (a < 1.7)
+		return BUTTON_SELECT;
+	if (a < 2.6)
+		return BUTTON_UP;
+	if (a < 4.6)
+		return BUTTON_LEFT;
+	else
+		return BUTTON_NONE;
 }
 
@@ -924,11 +932,11 @@
 {
 	/* 押されて戻った時に処理する */
-	if(push)
+	if (push)
 		return;
 
 	/* 表示ポート番号 */
-	if(!main_rev){
+	if (!main_rev) {
 		main_port_no--;
-		if(main_port_no < 1){
+		if (main_port_no < 1) {
 			main_port_no = 1;
 			main_rev = true;
@@ -936,7 +944,7 @@
 		}
 	}
-	else{
+	else {
 		main_port_no++;
-		if(main_port_no > main_ad_count){
+		if (main_port_no > main_ad_count) {
 			main_port_no = main_ad_count;
 			main_rev = false;
@@ -952,5 +960,5 @@
 {
 	/* 押されて戻った時に処理する */
-	if(push)
+	if (push)
 		return;
 
@@ -961,7 +969,7 @@
 
 	/* 表示ポート番号 */
-	if(!main_rev){
+	if (!main_rev) {
 		main_port_no++;
-		if(main_port_no > main_ad_count){
+		if (main_port_no > main_ad_count) {
 			main_port_no = main_ad_count;
 			main_rev = false;
@@ -969,7 +977,7 @@
 		}
 	}
-	else{
+	else {
 		main_port_no--;
-		if(main_port_no < 1){
+		if (main_port_no < 1) {
 			main_port_no = 1;
 			main_rev = true;
@@ -988,5 +996,5 @@
 
 	main_port_no++;
-	if(main_port_no > main_ad_count)
+	if (main_port_no > main_ad_count)
 		main_port_no = 1;
 
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/jsonsl.c
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/jsonsl.c	(revision 364)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/jsonsl.c	(revision 364)
@@ -0,0 +1,1687 @@
+/* Copyright (C) 2012-2015 Mark Nunberg.
+ *
+ * See included LICENSE file for license details.
+ */
+/* copy from LICENSE file
+Copyright (c) 2012-2015 M. Nunberg, mnunberg@haskalah.org
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "jsonsl.h"
+#include <limits.h>
+#include <ctype.h>
+
+#ifdef JSONSL_USE_METRICS
+#define XMETRICS \
+    X(STRINGY_INSIGNIFICANT) \
+    X(STRINGY_SLOWPATH) \
+    X(ALLOWED_WHITESPACE) \
+    X(QUOTE_FASTPATH) \
+    X(SPECIAL_FASTPATH) \
+    X(SPECIAL_WSPOP) \
+    X(SPECIAL_SLOWPATH) \
+    X(GENERIC) \
+    X(STRUCTURAL_TOKEN) \
+    X(SPECIAL_SWITCHFIRST) \
+    X(STRINGY_CATCH) \
+    X(NUMBER_FASTPATH) \
+    X(ESCAPES) \
+    X(TOTAL) \
+
+struct jsonsl_metrics_st {
+#define X(m) \
+    unsigned long metric_##m;
+    XMETRICS
+#undef X
+};
+
+static struct jsonsl_metrics_st GlobalMetrics = { 0 };
+static unsigned long GenericCounter[0x100] = { 0 };
+static unsigned long StringyCatchCounter[0x100] = { 0 };
+
+#define INCR_METRIC(m) \
+    GlobalMetrics.metric_##m++;
+
+#define INCR_GENERIC(c) \
+        INCR_METRIC(GENERIC); \
+        GenericCounter[c]++; \
+
+#define INCR_STRINGY_CATCH(c) \
+    INCR_METRIC(STRINGY_CATCH); \
+    StringyCatchCounter[c]++;
+
+JSONSL_API
+void jsonsl_dump_global_metrics(void)
+{
+    int ii;
+    printf("JSONSL Metrics:\n");
+#define X(m) \
+    printf("\t%-30s %20lu (%0.2f%%)\n", #m, GlobalMetrics.metric_##m, \
+           (float)((float)(GlobalMetrics.metric_##m/(float)GlobalMetrics.metric_TOTAL)) * 100);
+    XMETRICS
+#undef X
+    printf("Generic Characters:\n");
+    for (ii = 0; ii < 0xff; ii++) {
+        if (GenericCounter[ii]) {
+            printf("\t[ %c ] %lu\n", ii, GenericCounter[ii]);
+        }
+    }
+    printf("Weird string loop\n");
+    for (ii = 0; ii < 0xff; ii++) {
+        if (StringyCatchCounter[ii]) {
+            printf("\t[ %c ] %lu\n", ii, StringyCatchCounter[ii]);
+        }
+    }
+}
+
+#else
+#define INCR_METRIC(m)
+#define INCR_GENERIC(c)
+#define INCR_STRINGY_CATCH(c)
+JSONSL_API
+void jsonsl_dump_global_metrics(void) { }
+#endif /* JSONSL_USE_METRICS */
+
+#define CASE_DIGITS \
+case '1': \
+case '2': \
+case '3': \
+case '4': \
+case '5': \
+case '6': \
+case '7': \
+case '8': \
+case '9': \
+case '0':
+
+static unsigned extract_special(unsigned);
+static int is_special_end(unsigned);
+static int is_allowed_whitespace(unsigned);
+static int is_allowed_escape(unsigned);
+static int is_simple_char(unsigned);
+static char get_escape_equiv(unsigned);
+
+JSONSL_API
+jsonsl_t jsonsl_new(int nlevels)
+{
+    unsigned int ii;
+    struct jsonsl_st * jsn;
+    
+    if (nlevels < 2) {
+        return NULL;
+    }
+
+    jsn = (struct jsonsl_st *)
+            calloc(1, sizeof (*jsn) +
+                    ( (nlevels-1) * sizeof (struct jsonsl_state_st) )
+            );
+
+    jsn->levels_max = (unsigned int) nlevels;
+    jsn->max_callback_level = UINT_MAX;
+    jsonsl_reset(jsn);
+    for (ii = 0; ii < jsn->levels_max; ii++) {
+        jsn->stack[ii].level = ii;
+    }
+    return jsn;
+}
+
+JSONSL_API
+void jsonsl_reset(jsonsl_t jsn)
+{
+    jsn->tok_last = 0;
+    jsn->can_insert = 1;
+    jsn->pos = 0;
+    jsn->level = 0;
+    jsn->stopfl = 0;
+    jsn->in_escape = 0;
+    jsn->expecting = 0;
+}
+
+JSONSL_API
+void jsonsl_destroy(jsonsl_t jsn)
+{
+    if (jsn) {
+        free(jsn);
+    }
+}
+
+
+#define FASTPARSE_EXHAUSTED 1
+#define FASTPARSE_BREAK 0
+
+/*
+ * This function is meant to accelerate string parsing, reducing the main loop's
+ * check if we are indeed a string.
+ *
+ * @param jsn the parser
+ * @param[in,out] bytes_p A pointer to the current buffer (i.e. current position)
+ * @param[in,out] nbytes_p A pointer to the current size of the buffer
+ * @return true if all bytes have been exhausted (and thus the main loop can
+ * return), false if a special character was examined which requires greater
+ * examination.
+ */
+static int
+jsonsl__str_fastparse(jsonsl_t jsn,
+                      const jsonsl_uchar_t **bytes_p, size_t *nbytes_p)
+{
+    const jsonsl_uchar_t *bytes = *bytes_p;
+    const jsonsl_uchar_t *end;
+    for (end = bytes + *nbytes_p; bytes != end; bytes++) {
+        if (
+#ifdef JSONSL_USE_WCHAR
+                *bytes >= 0x100 ||
+#endif /* JSONSL_USE_WCHAR */
+                (is_simple_char(*bytes))) {
+            INCR_METRIC(TOTAL);
+            INCR_METRIC(STRINGY_INSIGNIFICANT);
+        } else {
+            /* Once we're done here, re-calculate the position variables */
+            jsn->pos += (bytes - *bytes_p);
+            *nbytes_p -= (bytes - *bytes_p);
+            *bytes_p = bytes;
+            return FASTPARSE_BREAK;
+        }
+    }
+
+    /* Once we're done here, re-calculate the position variables */
+    jsn->pos += (bytes - *bytes_p);
+    return FASTPARSE_EXHAUSTED;
+}
+
+/* Functions exactly like str_fastparse, except it also accepts a 'state'
+ * argument, since the number's value is updated in the state. */
+static int
+jsonsl__num_fastparse(jsonsl_t jsn,
+                      const jsonsl_uchar_t **bytes_p, size_t *nbytes_p,
+                      struct jsonsl_state_st *state)
+{
+    int exhausted = 1;
+    size_t nbytes = *nbytes_p;
+    const jsonsl_uchar_t *bytes = *bytes_p;
+
+    for (; nbytes; nbytes--, bytes++) {
+        jsonsl_uchar_t c = *bytes;
+        if (isdigit(c)) {
+            INCR_METRIC(TOTAL);
+            INCR_METRIC(NUMBER_FASTPATH);
+            state->nelem = (state->nelem * 10) + (c - 0x30);
+        } else {
+            exhausted = 0;
+            break;
+        }
+    }
+    jsn->pos += (*nbytes_p - nbytes);
+    if (exhausted) {
+        return FASTPARSE_EXHAUSTED;
+    }
+    *nbytes_p = nbytes;
+    *bytes_p = bytes;
+    return FASTPARSE_BREAK;
+}
+
+JSONSL_API
+void
+jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes)
+{
+
+#define INVOKE_ERROR(eb) \
+    if (jsn->error_callback(jsn, JSONSL_ERROR_##eb, state, (char*)c)) { \
+        goto GT_AGAIN; \
+    } \
+    return;
+
+#define STACK_PUSH \
+    if (jsn->level >= (levels_max-1)) { \
+        jsn->error_callback(jsn, JSONSL_ERROR_LEVELS_EXCEEDED, state, (char*)c); \
+        return; \
+    } \
+    state = jsn->stack + (++jsn->level); \
+    state->ignore_callback = jsn->stack[jsn->level-1].ignore_callback; \
+    state->pos_begin = jsn->pos;
+
+#define STACK_POP_NOPOS \
+    state->pos_cur = jsn->pos; \
+    state = jsn->stack + (--jsn->level);
+
+
+#define STACK_POP \
+    STACK_POP_NOPOS; \
+    state->pos_cur = jsn->pos;
+
+#define CALLBACK_AND_POP_NOPOS(T) \
+        state->pos_cur = jsn->pos; \
+        DO_CALLBACK(T, POP); \
+        state->nescapes = 0; \
+        state = jsn->stack + (--jsn->level);
+
+#define CALLBACK_AND_POP(T) \
+        CALLBACK_AND_POP_NOPOS(T); \
+        state->pos_cur = jsn->pos;
+
+#define SPECIAL_POP \
+    CALLBACK_AND_POP(SPECIAL); \
+    jsn->expecting = 0; \
+    jsn->tok_last = 0; \
+
+#define CUR_CHAR (*(jsonsl_uchar_t*)c)
+
+#define DO_CALLBACK(T, action) \
+    if (jsn->call_##T && \
+            jsn->max_callback_level > state->level && \
+            state->ignore_callback == 0) { \
+        \
+        if (jsn->action_callback_##action) { \
+            jsn->action_callback_##action(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \
+        } else if (jsn->action_callback) { \
+            jsn->action_callback(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \
+        } \
+        if (jsn->stopfl) { return; } \
+    }
+
+    /**
+     * Verifies that we are able to insert the (non-string) item into a hash.
+     */
+#define ENSURE_HVAL \
+    if (state->nelem % 2 == 0 && state->type == JSONSL_T_OBJECT) { \
+        INVOKE_ERROR(HKEY_EXPECTED); \
+    }
+
+#define VERIFY_SPECIAL(lit) \
+        if (CUR_CHAR != (lit)[jsn->pos - state->pos_begin]) { \
+            INVOKE_ERROR(SPECIAL_EXPECTED); \
+        }
+
+#define VERIFY_SPECIAL_CI(lit) \
+        if (tolower(CUR_CHAR) != (lit)[jsn->pos - state->pos_begin]) { \
+            INVOKE_ERROR(SPECIAL_EXPECTED); \
+        }
+
+#define STATE_SPECIAL_LENGTH \
+    (state)->nescapes
+
+#define IS_NORMAL_NUMBER \
+    ((state)->special_flags == JSONSL_SPECIALf_UNSIGNED || \
+        (state)->special_flags == JSONSL_SPECIALf_SIGNED)
+
+#define STATE_NUM_LAST jsn->tok_last
+
+#define CONTINUE_NEXT_CHAR() continue
+
+    const jsonsl_uchar_t *c = (jsonsl_uchar_t*)bytes;
+    size_t levels_max = jsn->levels_max;
+    struct jsonsl_state_st *state = jsn->stack + jsn->level;
+    jsn->base = bytes;
+
+    for (; nbytes; nbytes--, jsn->pos++, c++) {
+        unsigned state_type;
+        INCR_METRIC(TOTAL);
+
+        GT_AGAIN:
+        state_type = state->type;
+        /* Most common type is typically a string: */
+        if (state_type & JSONSL_Tf_STRINGY) {
+            /* Special escape handling for some stuff */
+            if (jsn->in_escape) {
+                jsn->in_escape = 0;
+                if (!is_allowed_escape(CUR_CHAR)) {
+                    INVOKE_ERROR(ESCAPE_INVALID);
+                } else if (CUR_CHAR == 'u') {
+                    DO_CALLBACK(UESCAPE, UESCAPE);
+                    if (jsn->return_UESCAPE) {
+                        return;
+                    }
+                }
+                CONTINUE_NEXT_CHAR();
+            }
+
+            if (jsonsl__str_fastparse(jsn, &c, &nbytes) ==
+                    FASTPARSE_EXHAUSTED) {
+                /* No need to readjust variables as we've exhausted the iterator */
+                return;
+            } else {
+                if (CUR_CHAR == '"') {
+                    goto GT_QUOTE;
+                } else if (CUR_CHAR == '\\') {
+                    goto GT_ESCAPE;
+                } else {
+                    INVOKE_ERROR(WEIRD_WHITESPACE);
+                }
+            }
+            INCR_METRIC(STRINGY_SLOWPATH);
+
+        } else if (state_type == JSONSL_T_SPECIAL) {
+            /* Fast track for signed/unsigned */
+            if (IS_NORMAL_NUMBER) {
+                if (jsonsl__num_fastparse(jsn, &c, &nbytes, state) ==
+                        FASTPARSE_EXHAUSTED) {
+                    return;
+                } else {
+                    goto GT_SPECIAL_NUMERIC;
+                }
+            } else if (state->special_flags == JSONSL_SPECIALf_DASH) {
+#ifdef JSONSL_PARSE_NAN
+                if (CUR_CHAR == 'I' || CUR_CHAR == 'i') {
+                    /* parsing -Infinity? */
+                    state->special_flags = JSONSL_SPECIALf_NEG_INF;
+                    CONTINUE_NEXT_CHAR();
+                }
+#endif
+
+                if (!isdigit(CUR_CHAR)) {
+                    INVOKE_ERROR(INVALID_NUMBER);
+                }
+
+                if (CUR_CHAR == '0') {
+                    state->special_flags = JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED;
+                } else if (isdigit(CUR_CHAR)) {
+                    state->special_flags = JSONSL_SPECIALf_SIGNED;
+                    state->nelem = CUR_CHAR - 0x30;
+                } else {
+                    INVOKE_ERROR(INVALID_NUMBER);
+                }
+                CONTINUE_NEXT_CHAR();
+
+            } else if (state->special_flags == JSONSL_SPECIALf_ZERO) {
+                if (isdigit(CUR_CHAR)) {
+                    /* Following a zero! */
+                    INVOKE_ERROR(INVALID_NUMBER);
+                }
+                /* Unset the 'zero' flag: */
+                if (state->special_flags & JSONSL_SPECIALf_SIGNED) {
+                    state->special_flags = JSONSL_SPECIALf_SIGNED;
+                } else {
+                    state->special_flags = JSONSL_SPECIALf_UNSIGNED;
+                }
+                goto GT_SPECIAL_NUMERIC;
+            }
+
+            if ((state->special_flags & JSONSL_SPECIALf_NUMERIC) &&
+                    !(state->special_flags & JSONSL_SPECIALf_INF)) {
+                GT_SPECIAL_NUMERIC:
+                switch (CUR_CHAR) {
+                CASE_DIGITS
+                    STATE_NUM_LAST = '1';
+                    CONTINUE_NEXT_CHAR();
+
+                case '.':
+                    if (state->special_flags & JSONSL_SPECIALf_FLOAT) {
+                        INVOKE_ERROR(INVALID_NUMBER);
+                    }
+                    state->special_flags |= JSONSL_SPECIALf_FLOAT;
+                    STATE_NUM_LAST = '.';
+                    CONTINUE_NEXT_CHAR();
+
+                case 'e':
+                case 'E':
+                    if (state->special_flags & JSONSL_SPECIALf_EXPONENT) {
+                        INVOKE_ERROR(INVALID_NUMBER);
+                    }
+                    state->special_flags |= JSONSL_SPECIALf_EXPONENT;
+                    STATE_NUM_LAST = 'e';
+                    CONTINUE_NEXT_CHAR();
+
+                case '-':
+                case '+':
+                    if (STATE_NUM_LAST != 'e') {
+                        INVOKE_ERROR(INVALID_NUMBER);
+                    }
+                    STATE_NUM_LAST = '-';
+                    CONTINUE_NEXT_CHAR();
+
+                default:
+                    if (is_special_end(CUR_CHAR)) {
+                        goto GT_SPECIAL_POP;
+                    }
+                    INVOKE_ERROR(INVALID_NUMBER);
+                    break;
+                }
+            }
+            /* else if (!NUMERIC) */
+            if (!is_special_end(CUR_CHAR)) {
+                STATE_SPECIAL_LENGTH++;
+
+                /* Verify TRUE, FALSE, NULL */
+                if (state->special_flags == JSONSL_SPECIALf_TRUE) {
+                    VERIFY_SPECIAL("true");
+                } else if (state->special_flags == JSONSL_SPECIALf_FALSE) {
+                    VERIFY_SPECIAL("false");
+                } else if (state->special_flags == JSONSL_SPECIALf_NULL) {
+                    VERIFY_SPECIAL("null");
+#ifdef JSONSL_PARSE_NAN
+                } else if (state->special_flags == JSONSL_SPECIALf_POS_INF) {
+                    VERIFY_SPECIAL_CI("infinity");
+                } else if (state->special_flags == JSONSL_SPECIALf_NEG_INF) {
+                    VERIFY_SPECIAL_CI("-infinity");
+                } else if (state->special_flags == JSONSL_SPECIALf_NAN) {
+                    VERIFY_SPECIAL_CI("nan");
+                } else if (state->special_flags & JSONSL_SPECIALf_NULL ||
+                           state->special_flags & JSONSL_SPECIALf_NAN) {
+                   /* previous char was "n", are we parsing null or nan? */
+                   if (CUR_CHAR != 'u') {
+                      state->special_flags &= ~JSONSL_SPECIALf_NULL;
+                   }
+
+                   if (tolower(CUR_CHAR) != 'a') {
+                      state->special_flags &= ~JSONSL_SPECIALf_NAN;
+                   }
+#endif
+                }
+                INCR_METRIC(SPECIAL_FASTPATH);
+                CONTINUE_NEXT_CHAR();
+            }
+
+            GT_SPECIAL_POP:
+            jsn->can_insert = 0;
+            if (IS_NORMAL_NUMBER) {
+                /* Nothing */
+            } else if (state->special_flags == JSONSL_SPECIALf_ZERO ||
+                    state->special_flags == (JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED)) {
+                /* 0 is unsigned! */
+                state->special_flags = JSONSL_SPECIALf_UNSIGNED;
+            } else if (state->special_flags == JSONSL_SPECIALf_DASH) {
+                /* Still in dash! */
+                INVOKE_ERROR(INVALID_NUMBER);
+            } else if (state->special_flags & JSONSL_SPECIALf_INF) {
+                if (STATE_SPECIAL_LENGTH != 8) {
+                    INVOKE_ERROR(SPECIAL_INCOMPLETE);
+                }
+                state->nelem = 1;
+            } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) {
+                /* Check that we're not at the end of a token */
+                if (STATE_NUM_LAST != '1') {
+                    INVOKE_ERROR(INVALID_NUMBER);
+                }
+            } else if (state->special_flags == JSONSL_SPECIALf_TRUE) {
+                if (STATE_SPECIAL_LENGTH != 4) {
+                    INVOKE_ERROR(SPECIAL_INCOMPLETE);
+                }
+                state->nelem = 1;
+            } else if (state->special_flags == JSONSL_SPECIALf_FALSE) {
+                if (STATE_SPECIAL_LENGTH != 5) {
+                    INVOKE_ERROR(SPECIAL_INCOMPLETE);
+                }
+            } else if (state->special_flags == JSONSL_SPECIALf_NULL) {
+                if (STATE_SPECIAL_LENGTH != 4) {
+                    INVOKE_ERROR(SPECIAL_INCOMPLETE);
+                }
+            }
+            SPECIAL_POP;
+            jsn->expecting = ',';
+            if (is_allowed_whitespace(CUR_CHAR)) {
+                CONTINUE_NEXT_CHAR();
+            }
+            /**
+             * This works because we have a non-whitespace token
+             * which is not a special token. If this is a structural
+             * character then it will be gracefully handled by the
+             * switch statement. Otherwise it will default to the 'special'
+             * state again,
+             */
+            goto GT_STRUCTURAL_TOKEN;
+        } else if (is_allowed_whitespace(CUR_CHAR)) {
+            INCR_METRIC(ALLOWED_WHITESPACE);
+            /* So we're not special. Harmless insignificant whitespace
+             * passthrough
+             */
+            CONTINUE_NEXT_CHAR();
+        } else if (extract_special(CUR_CHAR)) {
+            /* not a string, whitespace, or structural token. must be special */
+            goto GT_SPECIAL_BEGIN;
+        }
+
+        INCR_GENERIC(CUR_CHAR);
+
+        if (CUR_CHAR == '"') {
+            GT_QUOTE:
+            jsn->can_insert = 0;
+            switch (state_type) {
+
+            /* the end of a string or hash key */
+            case JSONSL_T_STRING:
+                CALLBACK_AND_POP(STRING);
+                CONTINUE_NEXT_CHAR();
+            case JSONSL_T_HKEY:
+                CALLBACK_AND_POP(HKEY);
+                CONTINUE_NEXT_CHAR();
+
+            case JSONSL_T_OBJECT:
+                state->nelem++;
+                if ( (state->nelem-1) % 2 ) {
+                    /* Odd, this must be a hash value */
+                    if (jsn->tok_last != ':') {
+                        INVOKE_ERROR(MISSING_TOKEN);
+                    }
+                    jsn->expecting = ','; /* Can't figure out what to expect next */
+                    jsn->tok_last = 0;
+
+                    STACK_PUSH;
+                    state->type = JSONSL_T_STRING;
+                    DO_CALLBACK(STRING, PUSH);
+
+                } else {
+                    /* hash key */
+                    if (jsn->expecting != '"') {
+                        INVOKE_ERROR(STRAY_TOKEN);
+                    }
+                    jsn->tok_last = 0;
+                    jsn->expecting = ':';
+
+                    STACK_PUSH;
+                    state->type = JSONSL_T_HKEY;
+                    DO_CALLBACK(HKEY, PUSH);
+                }
+                CONTINUE_NEXT_CHAR();
+
+            case JSONSL_T_LIST:
+                state->nelem++;
+                STACK_PUSH;
+                state->type = JSONSL_T_STRING;
+                jsn->expecting = ',';
+                jsn->tok_last = 0;
+                DO_CALLBACK(STRING, PUSH);
+                CONTINUE_NEXT_CHAR();
+
+            case JSONSL_T_SPECIAL:
+                INVOKE_ERROR(STRAY_TOKEN);
+                break;
+
+            default:
+                INVOKE_ERROR(STRING_OUTSIDE_CONTAINER);
+                break;
+            } /* switch(state->type) */
+        } else if (CUR_CHAR == '\\') {
+            GT_ESCAPE:
+            INCR_METRIC(ESCAPES);
+        /* Escape */
+            if ( (state->type & JSONSL_Tf_STRINGY) == 0 ) {
+                INVOKE_ERROR(ESCAPE_OUTSIDE_STRING);
+            }
+            state->nescapes++;
+            jsn->in_escape = 1;
+            CONTINUE_NEXT_CHAR();
+        } /* " or \ */
+
+        GT_STRUCTURAL_TOKEN:
+        switch (CUR_CHAR) {
+        case ':':
+            INCR_METRIC(STRUCTURAL_TOKEN);
+            if (jsn->expecting != CUR_CHAR) {
+                INVOKE_ERROR(STRAY_TOKEN);
+            }
+            jsn->tok_last = ':';
+            jsn->can_insert = 1;
+            jsn->expecting = '"';
+            CONTINUE_NEXT_CHAR();
+
+        case ',':
+            INCR_METRIC(STRUCTURAL_TOKEN);
+            /**
+             * The comma is one of the more generic tokens.
+             * In the context of an OBJECT, the can_insert flag
+             * should never be set, and no other action is
+             * necessary.
+             */
+            if (jsn->expecting != CUR_CHAR) {
+                /* make this branch execute only when we haven't manually
+                 * just placed the ',' in the expecting register.
+                 */
+                INVOKE_ERROR(STRAY_TOKEN);
+            }
+
+            if (state->type == JSONSL_T_OBJECT) {
+                /* end of hash value, expect a string as a hash key */
+                jsn->expecting = '"';
+            } else {
+                jsn->can_insert = 1;
+            }
+
+            jsn->tok_last = ',';
+            jsn->expecting = '"';
+            CONTINUE_NEXT_CHAR();
+
+            /* new list or object */
+            /* hashes are more common */
+        case '{':
+        case '[':
+            INCR_METRIC(STRUCTURAL_TOKEN);
+            if (!jsn->can_insert) {
+                INVOKE_ERROR(CANT_INSERT);
+            }
+
+            ENSURE_HVAL;
+            state->nelem++;
+
+            STACK_PUSH;
+            /* because the constants match the opening delimiters, we can do this: */
+            state->type = CUR_CHAR;
+            state->nelem = 0;
+            jsn->can_insert = 1;
+            if (CUR_CHAR == '{') {
+                /* If we're a hash, we expect a key first, which is quouted */
+                jsn->expecting = '"';
+            }
+            if (CUR_CHAR == JSONSL_T_OBJECT) {
+                DO_CALLBACK(OBJECT, PUSH);
+            } else {
+                DO_CALLBACK(LIST, PUSH);
+            }
+            jsn->tok_last = 0;
+            CONTINUE_NEXT_CHAR();
+
+            /* closing of list or object */
+        case '}':
+        case ']':
+            INCR_METRIC(STRUCTURAL_TOKEN);
+            if (jsn->tok_last == ',' && jsn->options.allow_trailing_comma == 0) {
+                INVOKE_ERROR(TRAILING_COMMA);
+            }
+
+            jsn->can_insert = 0;
+            jsn->level--;
+            jsn->expecting = ',';
+            jsn->tok_last = 0;
+            if (CUR_CHAR == ']') {
+                if (state->type != '[') {
+                    INVOKE_ERROR(BRACKET_MISMATCH);
+                }
+                DO_CALLBACK(LIST, POP);
+            } else {
+                if (state->type != '{') {
+                    INVOKE_ERROR(BRACKET_MISMATCH);
+                } else if (state->nelem && state->nelem % 2 != 0) {
+                    INVOKE_ERROR(VALUE_EXPECTED);
+                }
+                DO_CALLBACK(OBJECT, POP);
+            }
+            state = jsn->stack + jsn->level;
+            state->pos_cur = jsn->pos;
+            CONTINUE_NEXT_CHAR();
+
+        default:
+            GT_SPECIAL_BEGIN:
+            /**
+             * Not a string, not a structural token, and not benign whitespace.
+             * Technically we should iterate over the character always, but since
+             * we are not doing full numerical/value decoding anyway (but only hinting),
+             * we only check upon entry.
+             */
+            if (state->type != JSONSL_T_SPECIAL) {
+                int special_flags = extract_special(CUR_CHAR);
+                if (!special_flags) {
+                    /**
+                     * Try to do some heuristics here anyway to figure out what kind of
+                     * error this is. The 'special' case is a fallback scenario anyway.
+                     */
+                    if (CUR_CHAR == '\0') {
+                        INVOKE_ERROR(FOUND_NULL_BYTE);
+                    } else if (CUR_CHAR < 0x20) {
+                        INVOKE_ERROR(WEIRD_WHITESPACE);
+                    } else {
+                        INVOKE_ERROR(SPECIAL_EXPECTED);
+                    }
+                }
+                ENSURE_HVAL;
+                state->nelem++;
+                if (!jsn->can_insert) {
+                    INVOKE_ERROR(CANT_INSERT);
+                }
+                STACK_PUSH;
+                state->type = JSONSL_T_SPECIAL;
+                state->special_flags = special_flags;
+                STATE_SPECIAL_LENGTH = 1;
+
+                if (special_flags == JSONSL_SPECIALf_UNSIGNED) {
+                    state->nelem = CUR_CHAR - 0x30;
+                    STATE_NUM_LAST = '1';
+                } else {
+                    STATE_NUM_LAST = '-';
+                    state->nelem = 0;
+                }
+                DO_CALLBACK(SPECIAL, PUSH);
+            }
+            CONTINUE_NEXT_CHAR();
+        }
+    }
+}
+
+JSONSL_API
+const char* jsonsl_strerror(jsonsl_error_t err)
+{
+    if (err == JSONSL_ERROR_SUCCESS) {
+        return "SUCCESS";
+    }
+#define X(t) \
+    if (err == JSONSL_ERROR_##t) \
+        return #t;
+    JSONSL_XERR;
+#undef X
+    return "<UNKNOWN_ERROR>";
+}
+
+JSONSL_API
+const char *jsonsl_strtype(jsonsl_type_t type)
+{
+#define X(o,c) \
+    if (type == JSONSL_T_##o) \
+        return #o;
+    JSONSL_XTYPE
+#undef X
+    return "UNKNOWN TYPE";
+
+}
+
+/*
+ *
+ * JPR/JSONPointer functions
+ *
+ *
+ */
+#ifndef JSONSL_NO_JPR
+static
+jsonsl_jpr_type_t
+populate_component(char *in,
+                   struct jsonsl_jpr_component_st *component,
+                   char **next,
+                   jsonsl_error_t *errp)
+{
+    unsigned long pctval;
+    char *c = NULL, *outp = NULL, *end = NULL;
+    size_t input_len;
+    jsonsl_jpr_type_t ret = JSONSL_PATH_NONE;
+
+    if (*next == NULL || *(*next) == '\0') {
+        return JSONSL_PATH_NONE;
+    }
+
+    /* Replace the next / with a NULL */
+    *next = strstr(in, "/");
+    if (*next != NULL) {
+        *(*next) = '\0'; /* drop the forward slash */
+        input_len = *next - in;
+        end = *next;
+        *next += 1; /* next character after the '/' */
+    } else {
+        input_len = strlen(in);
+        end = in + input_len + 1;
+    }
+
+    component->pstr = in;
+
+    /* Check for special components of interest */
+    if (*in == JSONSL_PATH_WILDCARD_CHAR && input_len == 1) {
+        /* Lone wildcard */
+        ret = JSONSL_PATH_WILDCARD;
+        goto GT_RET;
+    } else if (isdigit(*in)) {
+        /* ASCII Numeric */
+        char *endptr;
+        component->idx = strtoul(in, &endptr, 10);
+        if (endptr && *endptr == '\0') {
+            ret = JSONSL_PATH_NUMERIC;
+            goto GT_RET;
+        }
+    }
+
+    /* Default, it's a string */
+    ret = JSONSL_PATH_STRING;
+    for (c = outp = in; c < end; c++, outp++) {
+        char origc;
+        if (*c != '%') {
+            goto GT_ASSIGN;
+        }
+        /*
+         * c = { [+0] = '%', [+1] = 'b', [+2] = 'e', [+3] = '\0' }
+         */
+
+        /* Need %XX */
+        if (c+2 >= end) {
+            *errp = JSONSL_ERROR_PERCENT_BADHEX;
+            return JSONSL_PATH_INVALID;
+        }
+        if (! (isxdigit(*(c+1)) && isxdigit(*(c+2))) ) {
+            *errp = JSONSL_ERROR_PERCENT_BADHEX;
+            return JSONSL_PATH_INVALID;
+        }
+
+        /* Temporarily null-terminate the characters */
+        origc = *(c+3);
+        *(c+3) = '\0';
+        pctval = strtoul(c+1, NULL, 16);
+        *(c+3) = origc;
+
+        *outp = (char) pctval;
+        c += 2;
+        continue;
+
+        GT_ASSIGN:
+        *outp = *c;
+    }
+    /* Null-terminate the string */
+    for (; outp < c; outp++) {
+        *outp = '\0';
+    }
+
+    GT_RET:
+    component->ptype = ret;
+    if (ret != JSONSL_PATH_WILDCARD) {
+        component->len = strlen(component->pstr);
+    }
+    return ret;
+}
+
+JSONSL_API
+jsonsl_jpr_t
+jsonsl_jpr_new(const char *path, jsonsl_error_t *errp)
+{
+    char *my_copy = NULL;
+    int count, curidx;
+    struct jsonsl_jpr_st *ret = NULL;
+    struct jsonsl_jpr_component_st *components = NULL;
+    size_t origlen;
+    jsonsl_error_t errstacked;
+
+#define JPR_BAIL(err) *errp = err; goto GT_ERROR;
+
+    if (errp == NULL) {
+        errp = &errstacked;
+    }
+
+    if (path == NULL || *path != '/') {
+        JPR_BAIL(JSONSL_ERROR_JPR_NOROOT);
+    }
+
+    count = 1;
+    path++;
+    {
+        const char *c = path;
+        for (; *c; c++) {
+            if (*c == '/') {
+                count++;
+                if (*(c+1) == '/') {
+                    JPR_BAIL(JSONSL_ERROR_JPR_DUPSLASH);
+                }
+            }
+        }
+    }
+    if(*path) {
+        count++;
+    }
+
+    components = (struct jsonsl_jpr_component_st *)
+            malloc(sizeof(*components) * count);
+    if (!components) {
+        JPR_BAIL(JSONSL_ERROR_ENOMEM);
+    }
+
+    my_copy = (char *)malloc(strlen(path) + 1);
+    if (!my_copy) {
+        JPR_BAIL(JSONSL_ERROR_ENOMEM);
+    }
+
+    strcpy(my_copy, path);
+
+    components[0].ptype = JSONSL_PATH_ROOT;
+
+    if (*my_copy) {
+        char *cur = my_copy;
+        int pathret = JSONSL_PATH_STRING;
+        curidx = 1;
+        while (curidx < count) {
+            pathret = populate_component(cur, components + curidx, &cur, errp);
+            if (pathret > 0) {
+                curidx++;
+            } else {
+                break;
+            }
+        }
+
+        if (pathret == JSONSL_PATH_INVALID) {
+            JPR_BAIL(JSONSL_ERROR_JPR_BADPATH);
+        }
+    } else {
+        curidx = 1;
+    }
+
+    path--; /*revert path to leading '/' */
+    origlen = strlen(path) + 1;
+    ret = (struct jsonsl_jpr_st *)malloc(sizeof(*ret));
+    if (!ret) {
+        JPR_BAIL(JSONSL_ERROR_ENOMEM);
+    }
+    ret->orig = (char *)malloc(origlen);
+    if (!ret->orig) {
+        JPR_BAIL(JSONSL_ERROR_ENOMEM);
+    }
+    ret->components = components;
+    ret->ncomponents = curidx;
+    ret->basestr = my_copy;
+    ret->norig = origlen-1;
+    strcpy(ret->orig, path);
+
+    return ret;
+
+    GT_ERROR:
+    free(my_copy);
+    free(components);
+    if (ret) {
+        free(ret->orig);
+    }
+    free(ret);
+    return NULL;
+#undef JPR_BAIL
+}
+
+void jsonsl_jpr_destroy(jsonsl_jpr_t jpr)
+{
+    free(jpr->components);
+    free(jpr->basestr);
+    free(jpr->orig);
+    free(jpr);
+}
+
+/**
+ * Call when there is a possibility of a match, either as a final match or
+ * as a path within a match
+ * @param jpr The JPR path
+ * @param component Component corresponding to the current element
+ * @param prlevel The level of the *parent*
+ * @param chtype The type of the child
+ * @return Match status
+ */
+static jsonsl_jpr_match_t
+jsonsl__match_continue(jsonsl_jpr_t jpr,
+                       const struct jsonsl_jpr_component_st *component,
+                       unsigned prlevel, unsigned chtype)
+{
+    const struct jsonsl_jpr_component_st *next_comp = component + 1;
+    if (prlevel == jpr->ncomponents - 1) {
+        /* This is the match. Check the expected type of the match against
+         * the child */
+        if (jpr->match_type == 0 || jpr->match_type == chtype) {
+            return JSONSL_MATCH_COMPLETE;
+        } else {
+            return JSONSL_MATCH_TYPE_MISMATCH;
+        }
+    }
+    if (chtype == JSONSL_T_LIST) {
+        if (next_comp->ptype == JSONSL_PATH_NUMERIC) {
+            return JSONSL_MATCH_POSSIBLE;
+        } else {
+            return JSONSL_MATCH_TYPE_MISMATCH;
+        }
+    } else if (chtype == JSONSL_T_OBJECT) {
+        if (next_comp->ptype == JSONSL_PATH_NUMERIC) {
+            return JSONSL_MATCH_TYPE_MISMATCH;
+        } else {
+            return JSONSL_MATCH_POSSIBLE;
+        }
+    } else {
+        return JSONSL_MATCH_TYPE_MISMATCH;
+    }
+}
+
+JSONSL_API
+jsonsl_jpr_match_t
+jsonsl_path_match(jsonsl_jpr_t jpr,
+                  const struct jsonsl_state_st *parent,
+                  const struct jsonsl_state_st *child,
+                  const char *key, size_t nkey)
+{
+    const struct jsonsl_jpr_component_st *comp;
+    if (!parent) {
+        /* No parent. Return immediately since it's always a match */
+        return jsonsl__match_continue(jpr, jpr->components, 0, child->type);
+    }
+
+    comp = jpr->components + parent->level;
+
+    /* note that we don't need to verify the type of the match, this is
+     * always done through the previous call to jsonsl__match_continue.
+     * If we are in a POSSIBLE tree then we can be certain the types (at
+     * least at this level) are correct */
+    if (parent->type == JSONSL_T_OBJECT) {
+        if (comp->len != nkey || strncmp(key, comp->pstr, nkey) != 0) {
+            return JSONSL_MATCH_NOMATCH;
+        }
+    } else {
+        if (comp->idx != parent->nelem - 1) {
+            return JSONSL_MATCH_NOMATCH;
+        }
+    }
+    return jsonsl__match_continue(jpr, comp, parent->level, child->type);
+}
+
+JSONSL_API
+jsonsl_jpr_match_t
+jsonsl_jpr_match(jsonsl_jpr_t jpr,
+                   unsigned int parent_type,
+                   unsigned int parent_level,
+                   const char *key,
+                   size_t nkey)
+{
+    /* find our current component. This is the child level */
+    int cmpret;
+    struct jsonsl_jpr_component_st *p_component;
+    p_component = jpr->components + parent_level;
+
+    if (parent_level >= jpr->ncomponents) {
+        return JSONSL_MATCH_NOMATCH;
+    }
+
+    /* Lone query for 'root' element. Always matches */
+    if (parent_level == 0) {
+        if (jpr->ncomponents == 1) {
+            return JSONSL_MATCH_COMPLETE;
+        } else {
+            return JSONSL_MATCH_POSSIBLE;
+        }
+    }
+
+    /* Wildcard, always matches */
+    if (p_component->ptype == JSONSL_PATH_WILDCARD) {
+        if (parent_level == jpr->ncomponents-1) {
+            return JSONSL_MATCH_COMPLETE;
+        } else {
+            return JSONSL_MATCH_POSSIBLE;
+        }
+    }
+
+    /* Check numeric array index. This gets its special block so we can avoid
+     * string comparisons */
+    if (p_component->ptype == JSONSL_PATH_NUMERIC) {
+        if (parent_type == JSONSL_T_LIST) {
+            if (p_component->idx != nkey) {
+                /* Wrong index */
+                return JSONSL_MATCH_NOMATCH;
+            } else {
+                if (parent_level == jpr->ncomponents-1) {
+                    /* This is the last element of the path */
+                    return JSONSL_MATCH_COMPLETE;
+                } else {
+                    /* Intermediate element */
+                    return JSONSL_MATCH_POSSIBLE;
+                }
+            }
+        } else if (p_component->is_arridx) {
+            /* Numeric and an array index (set explicitly by user). But not
+             * a list for a parent */
+            return JSONSL_MATCH_TYPE_MISMATCH;
+        }
+    } else if (parent_type == JSONSL_T_LIST) {
+        return JSONSL_MATCH_TYPE_MISMATCH;
+    }
+
+    /* Check lengths */
+    if (p_component->len != nkey) {
+        return JSONSL_MATCH_NOMATCH;
+    }
+
+    /* Check string comparison */
+    cmpret = strncmp(p_component->pstr, key, nkey);
+    if (cmpret == 0) {
+        if (parent_level == jpr->ncomponents-1) {
+            return JSONSL_MATCH_COMPLETE;
+        } else {
+            return JSONSL_MATCH_POSSIBLE;
+        }
+    }
+
+    return JSONSL_MATCH_NOMATCH;
+}
+
+JSONSL_API
+void jsonsl_jpr_match_state_init(jsonsl_t jsn,
+                                 jsonsl_jpr_t *jprs,
+                                 size_t njprs)
+{
+    size_t ii, *firstjmp;
+    if (njprs == 0) {
+        return;
+    }
+    jsn->jprs = (jsonsl_jpr_t *)malloc(sizeof(jsonsl_jpr_t) * njprs);
+    jsn->jpr_count = njprs;
+    jsn->jpr_root = (size_t*)calloc(1, sizeof(size_t) * njprs * jsn->levels_max);
+    memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs);
+    /* Set the initial jump table values */
+
+    firstjmp = jsn->jpr_root;
+    for (ii = 0; ii < njprs; ii++) {
+        firstjmp[ii] = ii+1;
+    }
+}
+
+JSONSL_API
+void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn)
+{
+    if (jsn->jpr_count == 0) {
+        return;
+    }
+
+    free(jsn->jpr_root);
+    free(jsn->jprs);
+    jsn->jprs = NULL;
+    jsn->jpr_root = NULL;
+    jsn->jpr_count = 0;
+}
+
+/**
+ * This function should be called exactly once on each element...
+ * This should also be called in recursive order, since we rely
+ * on the parent having been initalized for a match.
+ *
+ * Since the parent is checked for a match as well, we maintain a 'serial' counter.
+ * Whenever we traverse an element, we expect the serial to be the same as a global
+ * integer. If they do not match, we re-initialize the context, and set the serial.
+ *
+ * This ensures a type of consistency without having a proactive reset by the
+ * main lexer itself.
+ *
+ */
+JSONSL_API
+jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn,
+                                    struct jsonsl_state_st *state,
+                                    const char *key,
+                                    size_t nkey,
+                                    jsonsl_jpr_match_t *out)
+{
+    struct jsonsl_state_st *parent_state;
+    jsonsl_jpr_t ret = NULL;
+
+    /* Jump and JPR tables for our own state and the parent state */
+    size_t *jmptable, *pjmptable;
+    size_t jmp_cur, ii, ourjmpidx;
+
+    if (!jsn->jpr_root) {
+        *out = JSONSL_MATCH_NOMATCH;
+        return NULL;
+    }
+
+    pjmptable = jsn->jpr_root + (jsn->jpr_count * (state->level-1));
+    jmptable = pjmptable + jsn->jpr_count;
+
+    /* If the parent cannot match, then invalidate it */
+    if (*pjmptable == 0) {
+        *jmptable = 0;
+        *out = JSONSL_MATCH_NOMATCH;
+        return NULL;
+    }
+
+    parent_state = jsn->stack + state->level - 1;
+
+    if (parent_state->type == JSONSL_T_LIST) {
+        nkey = (size_t) parent_state->nelem;
+    }
+
+    *jmptable = 0;
+    ourjmpidx = 0;
+    memset(jmptable, 0, sizeof(int) * jsn->jpr_count);
+
+    for (ii = 0; ii <  jsn->jpr_count; ii++) {
+        jmp_cur = pjmptable[ii];
+        if (jmp_cur) {
+            jsonsl_jpr_t jpr = jsn->jprs[jmp_cur-1];
+            *out = jsonsl_jpr_match(jpr,
+                                    parent_state->type,
+                                    parent_state->level,
+                                    key, nkey);
+            if (*out == JSONSL_MATCH_COMPLETE) {
+                ret = jpr;
+                *jmptable = 0;
+                return ret;
+            } else if (*out == JSONSL_MATCH_POSSIBLE) {
+                jmptable[ourjmpidx] = ii+1;
+                ourjmpidx++;
+            }
+        } else {
+            break;
+        }
+    }
+    if (!*jmptable) {
+        *out = JSONSL_MATCH_NOMATCH;
+    }
+    return NULL;
+}
+
+JSONSL_API
+const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match)
+{
+#define X(T,v) \
+    if ( match == JSONSL_MATCH_##T ) \
+        return #T;
+    JSONSL_XMATCH
+#undef X
+    return "<UNKNOWN>";
+}
+
+#endif /* JSONSL_WITH_JPR */
+
+static char *
+jsonsl__writeutf8(uint32_t pt, char *out)
+{
+    #define ADD_OUTPUT(c) *out = (char)(c); out++;
+
+    if (pt < 0x80) {
+        ADD_OUTPUT(pt);
+    } else if (pt < 0x800) {
+        ADD_OUTPUT((pt >> 6) | 0xC0);
+        ADD_OUTPUT((pt & 0x3F) | 0x80);
+    } else if (pt < 0x10000) {
+        ADD_OUTPUT((pt >> 12) | 0xE0);
+        ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80);
+        ADD_OUTPUT((pt & 0x3F) | 0x80);
+    } else {
+        ADD_OUTPUT((pt >> 18) | 0xF0);
+        ADD_OUTPUT(((pt >> 12) & 0x3F) | 0x80);
+        ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80);
+        ADD_OUTPUT((pt & 0x3F) | 0x80);
+    }
+    return out;
+    #undef ADD_OUTPUT
+}
+
+/* Thanks snej (https://github.com/mnunberg/jsonsl/issues/9) */
+static int
+jsonsl__digit2int(char ch) {
+    int d = ch - '0';
+    if ((unsigned) d < 10) {
+        return d;
+    }
+    d = ch - 'a';
+    if ((unsigned) d < 6) {
+        return d + 10;
+    }
+    d = ch - 'A';
+    if ((unsigned) d < 6) {
+        return d + 10;
+    }
+    return -1;
+}
+
+/* Assume 's' is at least 4 bytes long */
+static int
+jsonsl__get_uescape_16(const char *s)
+{
+    int ret = 0;
+    int cur;
+
+    #define GET_DIGIT(off) \
+        cur = jsonsl__digit2int(s[off]); \
+        if (cur == -1) { return -1; } \
+        ret |= (cur << (12 - (off * 4)));
+
+    GET_DIGIT(0);
+    GET_DIGIT(1);
+    GET_DIGIT(2);
+    GET_DIGIT(3);
+    #undef GET_DIGIT
+    return ret;
+}
+
+/**
+ * Utility function to convert escape sequences
+ */
+JSONSL_API
+size_t jsonsl_util_unescape_ex(const char *in,
+                               char *out,
+                               size_t len,
+                               const int toEscape[128],
+                               unsigned *oflags,
+                               jsonsl_error_t *err,
+                               const char **errat)
+{
+    const unsigned char *c = (const unsigned char*)in;
+    char *begin_p = out;
+    unsigned oflags_s;
+    uint16_t last_codepoint = 0;
+
+    if (!oflags) {
+        oflags = &oflags_s;
+    }
+    *oflags = 0;
+
+    #define UNESCAPE_BAIL(e,offset) \
+        *err = JSONSL_ERROR_##e; \
+        if (errat) { \
+            *errat = (const char*)(c+ (ptrdiff_t)(offset)); \
+        } \
+        return 0;
+
+    for (; len; len--, c++, out++) {
+        int uescval;
+        if (*c != '\\') {
+            /* Not an escape, so we don't care about this */
+            goto GT_ASSIGN;
+        }
+
+        if (len < 2) {
+            UNESCAPE_BAIL(ESCAPE_INVALID, 0);
+        }
+        if (!is_allowed_escape(c[1])) {
+            UNESCAPE_BAIL(ESCAPE_INVALID, 1)
+        }
+        if ((toEscape && toEscape[(unsigned char)c[1] & 0x7f] == 0 &&
+                c[1] != '\\' && c[1] != '"')) {
+            /* if we don't want to unescape this string, write the escape sequence to the output */
+            *out++ = *c++;
+            --len;
+            goto GT_ASSIGN;
+        }
+
+        if (c[1] != 'u') {
+            /* simple skip-and-replace using pre-defined maps.
+             * TODO: should the maps actually reflect the desired
+             * replacement character in toEscape?
+             */
+            char esctmp = get_escape_equiv(c[1]);
+            if (esctmp) {
+                /* Check if there is a corresponding replacement */
+                *out = esctmp;
+            } else {
+                /* Just gobble up the 'reverse-solidus' */
+                *out = c[1];
+            }
+            len--;
+            c++;
+            /* do not assign, just continue */
+            continue;
+        }
+
+        /* next == 'u' */
+        if (len < 6) {
+            /* Need at least six characters.. */
+            UNESCAPE_BAIL(UESCAPE_TOOSHORT, 2);
+        }
+
+        uescval = jsonsl__get_uescape_16((const char *)c + 2);
+        if (uescval == -1) {
+            UNESCAPE_BAIL(PERCENT_BADHEX, -1);
+        }
+
+        if (last_codepoint) {
+            uint16_t w1 = last_codepoint, w2 = (uint16_t)uescval;
+            uint32_t cp;
+
+            if (uescval < 0xDC00 || uescval > 0xDFFF) {
+                UNESCAPE_BAIL(INVALID_CODEPOINT, -1);
+            }
+
+            cp = (w1 & 0x3FF) << 10;
+            cp |= (w2 & 0x3FF);
+            cp += 0x10000;
+
+            out = jsonsl__writeutf8(cp, out) - 1;
+            last_codepoint = 0;
+
+        } else if (uescval < 0xD800 || uescval > 0xDFFF) {
+            *oflags |= JSONSL_SPECIALf_NONASCII;
+            out = jsonsl__writeutf8(uescval, out) - 1;
+
+        } else if (uescval < 0xDC00) {
+            *oflags |= JSONSL_SPECIALf_NONASCII;
+            last_codepoint = (uint16_t)uescval;
+            out--;
+        } else {
+            UNESCAPE_BAIL(INVALID_CODEPOINT, 2);
+        }
+
+        /* Post uescape cleanup */
+        len -= 5; /* Gobble up 5 chars after 'u' */
+        c += 5;
+        continue;
+
+        /* Only reached by previous branches */
+        GT_ASSIGN:
+        *out = *c;
+    }
+
+    if (last_codepoint) {
+        *err = JSONSL_ERROR_INVALID_CODEPOINT;
+        return 0;
+    }
+
+    *err = JSONSL_ERROR_SUCCESS;
+    return out - begin_p;
+}
+
+/**
+ * Character Table definitions.
+ * These were all generated via srcutil/genchartables.pl
+ */
+
+/**
+ * This table contains the beginnings of non-string
+ * allowable (bareword) values.
+ */
+static unsigned short Special_Table[0x100] = {
+        /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
+        /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2c */
+        /* 0x2d */ JSONSL_SPECIALf_DASH /* <-> */, /* 0x2d */
+        /* 0x2e */ 0,0, /* 0x2f */
+        /* 0x30 */ JSONSL_SPECIALf_ZERO /* <0> */, /* 0x30 */
+        /* 0x31 */ JSONSL_SPECIALf_UNSIGNED /* <1> */, /* 0x31 */
+        /* 0x32 */ JSONSL_SPECIALf_UNSIGNED /* <2> */, /* 0x32 */
+        /* 0x33 */ JSONSL_SPECIALf_UNSIGNED /* <3> */, /* 0x33 */
+        /* 0x34 */ JSONSL_SPECIALf_UNSIGNED /* <4> */, /* 0x34 */
+        /* 0x35 */ JSONSL_SPECIALf_UNSIGNED /* <5> */, /* 0x35 */
+        /* 0x36 */ JSONSL_SPECIALf_UNSIGNED /* <6> */, /* 0x36 */
+        /* 0x37 */ JSONSL_SPECIALf_UNSIGNED /* <7> */, /* 0x37 */
+        /* 0x38 */ JSONSL_SPECIALf_UNSIGNED /* <8> */, /* 0x38 */
+        /* 0x39 */ JSONSL_SPECIALf_UNSIGNED /* <9> */, /* 0x39 */
+        /* 0x3a */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x48 */
+        /* 0x49 */ JSONSL__INF_PROXY /* <I> */, /* 0x49 */
+        /* 0x4a */ 0,0,0,0, /* 0x4d */
+        /* 0x4e */ JSONSL__NAN_PROXY /* <N> */, /* 0x4e */
+        /* 0x4f */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x65 */
+        /* 0x66 */ JSONSL_SPECIALf_FALSE /* <f> */, /* 0x66 */
+        /* 0x67 */ 0,0, /* 0x68 */
+        /* 0x69 */ JSONSL__INF_PROXY /* <i> */, /* 0x69 */
+        /* 0x6a */ 0,0,0,0, /* 0x6d */
+        /* 0x6e */ JSONSL_SPECIALf_NULL|JSONSL__NAN_PROXY /* <n> */, /* 0x6e */
+        /* 0x6f */ 0,0,0,0,0, /* 0x73 */
+        /* 0x74 */ JSONSL_SPECIALf_TRUE /* <t> */, /* 0x74 */
+        /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */
+        /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */
+        /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */
+        /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */
+        /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0, /* 0xfe */
+};
+
+/**
+ * Contains characters which signal the termination of any of the 'special' bareword
+ * values.
+ */
+static int Special_Endings[0x100] = {
+        /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */
+        /* 0x09 */ 1 /* <TAB> */, /* 0x09 */
+        /* 0x0a */ 1 /* <LF> */, /* 0x0a */
+        /* 0x0b */ 0,0, /* 0x0c */
+        /* 0x0d */ 1 /* <CR> */, /* 0x0d */
+        /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
+        /* 0x20 */ 1 /* <SP> */, /* 0x20 */
+        /* 0x21 */ 0, /* 0x21 */
+        /* 0x22 */ 1 /* " */, /* 0x22 */
+        /* 0x23 */ 0,0,0,0,0,0,0,0,0, /* 0x2b */
+        /* 0x2c */ 1 /* , */, /* 0x2c */
+        /* 0x2d */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x39 */
+        /* 0x3a */ 1 /* : */, /* 0x3a */
+        /* 0x3b */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5a */
+        /* 0x5b */ 1 /* [ */, /* 0x5b */
+        /* 0x5c */ 1 /* \ */, /* 0x5c */
+        /* 0x5d */ 1 /* ] */, /* 0x5d */
+        /* 0x5e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7a */
+        /* 0x7b */ 1 /* { */, /* 0x7b */
+        /* 0x7c */ 0, /* 0x7c */
+        /* 0x7d */ 1 /* } */, /* 0x7d */
+        /* 0x7e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9d */
+        /* 0x9e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbd */
+        /* 0xbe */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdd */
+        /* 0xde */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfd */
+        /* 0xfe */ 0 /* 0xfe */
+};
+
+/**
+ * This table contains entries for the allowed whitespace as per RFC 4627
+ */
+static int Allowed_Whitespace[0x100] = {
+        /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */
+        /* 0x09 */ 1 /* <TAB> */, /* 0x09 */
+        /* 0x0a */ 1 /* <LF> */, /* 0x0a */
+        /* 0x0b */ 0,0, /* 0x0c */
+        /* 0x0d */ 1 /* <CR> */, /* 0x0d */
+        /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
+        /* 0x20 */ 1 /* <SP> */, /* 0x20 */
+        /* 0x21 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 */
+        /* 0x41 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 */
+        /* 0x61 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 */
+        /* 0x81 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0 */
+        /* 0xa1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xc0 */
+        /* 0xc1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xe0 */
+        /* 0xe1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xfe */
+};
+
+static const int String_No_Passthrough[0x100] = {
+        /* 0x00 */ 1 /* <NUL> */, /* 0x00 */
+        /* 0x01 */ 1 /* <SOH> */, /* 0x01 */
+        /* 0x02 */ 1 /* <STX> */, /* 0x02 */
+        /* 0x03 */ 1 /* <ETX> */, /* 0x03 */
+        /* 0x04 */ 1 /* <EOT> */, /* 0x04 */
+        /* 0x05 */ 1 /* <ENQ> */, /* 0x05 */
+        /* 0x06 */ 1 /* <ACK> */, /* 0x06 */
+        /* 0x07 */ 1 /* <BEL> */, /* 0x07 */
+        /* 0x08 */ 1 /* <BS> */, /* 0x08 */
+        /* 0x09 */ 1 /* <HT> */, /* 0x09 */
+        /* 0x0a */ 1 /* <LF> */, /* 0x0a */
+        /* 0x0b */ 1 /* <VT> */, /* 0x0b */
+        /* 0x0c */ 1 /* <FF> */, /* 0x0c */
+        /* 0x0d */ 1 /* <CR> */, /* 0x0d */
+        /* 0x0e */ 1 /* <SO> */, /* 0x0e */
+        /* 0x0f */ 1 /* <SI> */, /* 0x0f */
+        /* 0x10 */ 1 /* <DLE> */, /* 0x10 */
+        /* 0x11 */ 1 /* <DC1> */, /* 0x11 */
+        /* 0x12 */ 1 /* <DC2> */, /* 0x12 */
+        /* 0x13 */ 1 /* <DC3> */, /* 0x13 */
+        /* 0x14 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x21 */
+        /* 0x22 */ 1 /* <"> */, /* 0x22 */
+        /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x42 */
+        /* 0x43 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */
+        /* 0x5c */ 1 /* <\> */, /* 0x5c */
+        /* 0x5d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7c */
+        /* 0x7d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9c */
+        /* 0x9d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbc */
+        /* 0xbd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdc */
+        /* 0xdd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfc */
+        /* 0xfd */ 0,0, /* 0xfe */
+};
+
+/**
+ * Allowable two-character 'common' escapes:
+ */
+static int Allowed_Escapes[0x100] = {
+        /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
+        /* 0x20 */ 0,0, /* 0x21 */
+        /* 0x22 */ 1 /* <"> */, /* 0x22 */
+        /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2e */
+        /* 0x2f */ 1 /* </> */, /* 0x2f */
+        /* 0x30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4f */
+        /* 0x50 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */
+        /* 0x5c */ 1 /* <\> */, /* 0x5c */
+        /* 0x5d */ 0,0,0,0,0, /* 0x61 */
+        /* 0x62 */ 1 /* <b> */, /* 0x62 */
+        /* 0x63 */ 0,0,0, /* 0x65 */
+        /* 0x66 */ 1 /* <f> */, /* 0x66 */
+        /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */
+        /* 0x6e */ 1 /* <n> */, /* 0x6e */
+        /* 0x6f */ 0,0,0, /* 0x71 */
+        /* 0x72 */ 1 /* <r> */, /* 0x72 */
+        /* 0x73 */ 0, /* 0x73 */
+        /* 0x74 */ 1 /* <t> */, /* 0x74 */
+        /* 0x75 */ 1 /* <u> */, /* 0x75 */
+        /* 0x76 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x95 */
+        /* 0x96 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb5 */
+        /* 0xb6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd5 */
+        /* 0xd6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf5 */
+        /* 0xf6 */ 0,0,0,0,0,0,0,0,0, /* 0xfe */
+};
+
+/**
+ * This table contains the _values_ for a given (single) escaped character.
+ */
+static unsigned char Escape_Equivs[0x100] = {
+        /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */
+        /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x3f */
+        /* 0x40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5f */
+        /* 0x60 */ 0,0, /* 0x61 */
+        /* 0x62 */ 8 /* <b> */, /* 0x62 */
+        /* 0x63 */ 0,0,0, /* 0x65 */
+        /* 0x66 */ 12 /* <f> */, /* 0x66 */
+        /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */
+        /* 0x6e */ 10 /* <n> */, /* 0x6e */
+        /* 0x6f */ 0,0,0, /* 0x71 */
+        /* 0x72 */ 13 /* <r> */, /* 0x72 */
+        /* 0x73 */ 0, /* 0x73 */
+        /* 0x74 */ 9 /* <t> */, /* 0x74 */
+        /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */
+        /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */
+        /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */
+        /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */
+        /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0 /* 0xfe */
+};
+
+/* Definitions of above-declared static functions */
+static char get_escape_equiv(unsigned c) {
+    return Escape_Equivs[c & 0xff];
+}
+static unsigned extract_special(unsigned c) {
+    return Special_Table[c & 0xff];
+}
+static int is_special_end(unsigned c) {
+    return Special_Endings[c & 0xff];
+}
+static int is_allowed_whitespace(unsigned c) {
+    return c == ' ' || Allowed_Whitespace[c & 0xff];
+}
+static int is_allowed_escape(unsigned c) {
+    return Allowed_Escapes[c & 0xff];
+}
+static int is_simple_char(unsigned c) {
+    return !String_No_Passthrough[c & 0xff];
+}
+
+/* Clean up all our macros! */
+#undef INCR_METRIC
+#undef INCR_GENERIC
+#undef INCR_STRINGY_CATCH
+#undef CASE_DIGITS
+#undef INVOKE_ERROR
+#undef STACK_PUSH
+#undef STACK_POP_NOPOS
+#undef STACK_POP
+#undef CALLBACK_AND_POP_NOPOS
+#undef CALLBACK_AND_POP
+#undef SPECIAL_POP
+#undef CUR_CHAR
+#undef DO_CALLBACK
+#undef ENSURE_HVAL
+#undef VERIFY_SPECIAL
+#undef STATE_SPECIAL_LENGTH
+#undef IS_NORMAL_NUMBER
+#undef STATE_NUM_LAST
+#undef FASTPARSE_EXHAUSTED
+#undef FASTPARSE_BREAK
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/jsonsl.h
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/jsonsl.h	(revision 364)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/jsonsl.h	(revision 364)
@@ -0,0 +1,1025 @@
+/**
+ * JSON Simple/Stacked/Stateful Lexer.
+ * - Does not buffer data
+ * - Maintains state
+ * - Callback oriented
+ * - Lightweight and fast. One source file and one header file
+ *
+ * Copyright (C) 2012-2015 Mark Nunberg
+ * See included LICENSE file for license details.
+ */
+/* copy from LICENSE file
+Copyright (c) 2012-2015 M. Nunberg, mnunberg@haskalah.org
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef JSONSL_H_
+#define JSONSL_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h>
+#include <wchar.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef JSONSL_USE_WCHAR
+typedef jsonsl_char_t wchar_t;
+typedef jsonsl_uchar_t unsigned wchar_t;
+#else
+typedef char jsonsl_char_t;
+typedef unsigned char jsonsl_uchar_t;
+#endif /* JSONSL_USE_WCHAR */
+
+#ifdef JSONSL_PARSE_NAN
+#define JSONSL__NAN_PROXY JSONSL_SPECIALf_NAN
+#define JSONSL__INF_PROXY JSONSL_SPECIALf_INF
+#else
+#define JSONSL__NAN_PROXY 0
+#define JSONSL__INF_PROXY 0
+#endif
+
+/* Stolen from http-parser.h, and possibly others */
+#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#if !defined(_MSC_VER) || _MSC_VER<1400
+typedef unsigned int size_t;
+typedef int ssize_t;
+#endif
+#else
+#include <stdint.h>
+#endif
+
+
+#if (!defined(JSONSL_STATE_GENERIC)) && (!defined(JSONSL_STATE_USER_FIELDS))
+#define JSONSL_STATE_GENERIC
+#endif /* !defined JSONSL_STATE_GENERIC */
+
+#ifdef JSONSL_STATE_GENERIC
+#define JSONSL_STATE_USER_FIELDS
+#endif /* JSONSL_STATE_GENERIC */
+
+/* Additional fields for component object */
+#ifndef JSONSL_JPR_COMPONENT_USER_FIELDS
+#define JSONSL_JPR_COMPONENT_USER_FIELDS
+#endif
+
+#ifndef JSONSL_API
+/**
+ * We require a /DJSONSL_DLL so that users already using this as a static
+ * or embedded library don't get confused
+ */
+#if defined(_WIN32) && defined(JSONSL_DLL)
+#define JSONSL_API __declspec(dllexport)
+#else
+#define JSONSL_API
+#endif /* _WIN32 */
+
+#endif /* !JSONSL_API */
+
+#ifndef JSONSL_INLINE
+#if defined(_MSC_VER)
+  #define JSONSL_INLINE __inline
+  #elif defined(__GNUC__)
+  #define JSONSL_INLINE __inline__
+  #else
+  #define JSONSL_INLINE inline
+  #endif /* _MSC_VER or __GNUC__ */
+#endif /* JSONSL_INLINE */
+
+#define JSONSL_MAX_LEVELS 512
+
+struct jsonsl_st;
+typedef struct jsonsl_st *jsonsl_t;
+
+typedef struct jsonsl_jpr_st* jsonsl_jpr_t;
+
+/**
+ * This flag is true when AND'd against a type whose value
+ * must be in "quoutes" i.e. T_HKEY and T_STRING
+ */
+#define JSONSL_Tf_STRINGY 0xffff00
+
+/**
+ * Constant representing the special JSON types.
+ * The values are special and aid in speed (the OBJECT and LIST
+ * values are the char literals of their openings).
+ *
+ * Their actual value is a character which attempts to resemble
+ * some mnemonic reference to the actual type.
+ *
+ * If new types are added, they must fit into the ASCII printable
+ * range (so they should be AND'd with 0x7f and yield something
+ * meaningful)
+ */
+#define JSONSL_XTYPE \
+    X(STRING,   '"'|JSONSL_Tf_STRINGY) \
+    X(HKEY,     '#'|JSONSL_Tf_STRINGY) \
+    X(OBJECT,   '{') \
+    X(LIST,     '[') \
+    X(SPECIAL,  '^') \
+    X(UESCAPE,  'u')
+typedef enum {
+#define X(o, c) \
+    JSONSL_T_##o = c,
+    JSONSL_XTYPE
+    JSONSL_T_UNKNOWN = '?',
+    /* Abstract 'root' object */
+    JSONSL_T_ROOT = 0
+#undef X
+} jsonsl_type_t;
+
+/**
+ * Subtypes for T_SPECIAL. We define them as flags
+ * because more than one type can be applied to a
+ * given object.
+ */
+
+#define JSONSL_XSPECIAL \
+    X(NONE, 0) \
+    X(SIGNED,       1<<0) \
+    X(UNSIGNED,     1<<1) \
+    X(TRUE,         1<<2) \
+    X(FALSE,        1<<3) \
+    X(NULL,         1<<4) \
+    X(FLOAT,        1<<5) \
+    X(EXPONENT,     1<<6) \
+    X(NONASCII,     1<<7) \
+    X(NAN,          1<<8) \
+    X(INF,          1<<9)
+typedef enum {
+#define X(o,b) \
+    JSONSL_SPECIALf_##o = b,
+    JSONSL_XSPECIAL
+#undef X
+    /* Handy flags for checking */
+
+    JSONSL_SPECIALf_UNKNOWN = 1 << 10,
+
+    /** @private Private */
+    JSONSL_SPECIALf_ZERO    = 1 << 11 | JSONSL_SPECIALf_UNSIGNED,
+    /** @private */
+    JSONSL_SPECIALf_DASH    = 1 << 12,
+    /** @private */
+    JSONSL_SPECIALf_POS_INF = (JSONSL_SPECIALf_INF),
+    JSONSL_SPECIALf_NEG_INF = (JSONSL_SPECIALf_INF|JSONSL_SPECIALf_SIGNED),
+
+    /** Type is numeric */
+    JSONSL_SPECIALf_NUMERIC = (JSONSL_SPECIALf_SIGNED| JSONSL_SPECIALf_UNSIGNED),
+
+    /** Type is a boolean */
+    JSONSL_SPECIALf_BOOLEAN = (JSONSL_SPECIALf_TRUE|JSONSL_SPECIALf_FALSE),
+
+    /** Type is an "extended", not integral type (but numeric) */
+   JSONSL_SPECIALf_NUMNOINT =
+       (JSONSL_SPECIALf_FLOAT|JSONSL_SPECIALf_EXPONENT|JSONSL_SPECIALf_NAN
+        |JSONSL_SPECIALf_INF)
+} jsonsl_special_t;
+
+
+/**
+ * These are the various types of stack (or other) events
+ * which will trigger a callback.
+ * Like the type constants, this are also mnemonic
+ */
+#define JSONSL_XACTION \
+    X(PUSH, '+') \
+    X(POP, '-') \
+    X(UESCAPE, 'U') \
+    X(ERROR, '!')
+typedef enum {
+#define X(a,c) \
+    JSONSL_ACTION_##a = c,
+    JSONSL_XACTION
+    JSONSL_ACTION_UNKNOWN = '?'
+#undef X
+} jsonsl_action_t;
+
+
+/**
+ * Various errors which may be thrown while parsing JSON
+ */
+#define JSONSL_XERR \
+/* Trailing garbage characters */ \
+    X(GARBAGE_TRAILING) \
+/* We were expecting a 'special' (numeric, true, false, null) */ \
+    X(SPECIAL_EXPECTED) \
+/* The 'special' value was incomplete */ \
+    X(SPECIAL_INCOMPLETE) \
+/* Found a stray token */ \
+    X(STRAY_TOKEN) \
+/* We were expecting a token before this one */ \
+    X(MISSING_TOKEN) \
+/* Cannot insert because the container is not ready */ \
+    X(CANT_INSERT) \
+/* Found a '\' outside a string */ \
+    X(ESCAPE_OUTSIDE_STRING) \
+/* Found a ':' outside of a hash */ \
+    X(KEY_OUTSIDE_OBJECT) \
+/* found a string outside of a container */ \
+    X(STRING_OUTSIDE_CONTAINER) \
+/* Found a null byte in middle of string */ \
+    X(FOUND_NULL_BYTE) \
+/* Current level exceeds limit specified in constructor */ \
+    X(LEVELS_EXCEEDED) \
+/* Got a } as a result of an opening [ or vice versa */ \
+    X(BRACKET_MISMATCH) \
+/* We expected a key, but got something else instead */ \
+    X(HKEY_EXPECTED) \
+/* We got an illegal control character (bad whitespace or something) */ \
+    X(WEIRD_WHITESPACE) \
+/* Found a \u-escape, but there were less than 4 following hex digits */ \
+    X(UESCAPE_TOOSHORT) \
+/* Invalid two-character escape */ \
+    X(ESCAPE_INVALID) \
+/* Trailing comma */ \
+    X(TRAILING_COMMA) \
+/* An invalid number was passed in a numeric field */ \
+    X(INVALID_NUMBER) \
+/* Value is missing for object */ \
+    X(VALUE_EXPECTED) \
+/* The following are for JPR Stuff */ \
+    \
+/* Found a literal '%' but it was only followed by a single valid hex digit */ \
+    X(PERCENT_BADHEX) \
+/* jsonpointer URI is malformed '/' */ \
+    X(JPR_BADPATH) \
+/* Duplicate slash */ \
+    X(JPR_DUPSLASH) \
+/* No leading root */ \
+    X(JPR_NOROOT) \
+/* Allocation failure */ \
+    X(ENOMEM) \
+/* Invalid unicode codepoint detected (in case of escapes) */ \
+    X(INVALID_CODEPOINT)
+
+typedef enum {
+    JSONSL_ERROR_SUCCESS = 0,
+#define X(e) \
+    JSONSL_ERROR_##e,
+    JSONSL_XERR
+#undef X
+    JSONSL_ERROR_GENERIC
+} jsonsl_error_t;
+
+
+/**
+ * A state is a single level of the stack.
+ * Non-private data (i.e. the 'data' field, see the STATE_GENERIC section)
+ * will remain in tact until the item is popped.
+ *
+ * As a result, it means a parent state object may be accessed from a child
+ * object, (the parents fields will all be valid). This allows a user to create
+ * an ad-hoc hierarchy on top of the JSON one.
+ *
+ */
+struct jsonsl_state_st {
+    /**
+     * The JSON object type
+     */
+    unsigned type;
+
+    /** If this element is special, then its extended type is here */
+    unsigned special_flags;
+
+    /**
+     * The position (in terms of number of bytes since the first call to
+     * jsonsl_feed()) at which the state was first pushed. This includes
+     * opening tokens, if applicable.
+     *
+     * @note For strings (i.e. type & JSONSL_Tf_STRINGY is nonzero) this will
+     * be the position of the first quote.
+     *
+     * @see jsonsl_st::pos which contains the _current_ position and can be
+     * used during a POP callback to get the length of the element.
+     */
+    size_t pos_begin;
+
+    /**FIXME: This is redundant as the same information can be derived from
+     * jsonsl_st::pos at pop-time */
+    size_t pos_cur;
+
+    /**
+     * Level of recursion into nesting. This is mainly a convenience
+     * variable, as this can technically be deduced from the lexer's
+     * level parameter (though the logic is not that simple)
+     */
+    unsigned int level;
+
+
+    /**
+     * how many elements in the object/list.
+     * For objects (hashes), an element is either
+     * a key or a value. Thus for one complete pair,
+     * nelem will be 2.
+     *
+     * For special types, this will hold the sum of the digits.
+     * This only holds true for values which are simple signed/unsigned
+     * numbers. Otherwise a special flag is set, and extra handling is not
+     * performed.
+     */
+    uint64_t nelem;
+
+
+
+    /*TODO: merge this and special_flags into a union */
+
+
+    /**
+     * Useful for an opening nest, this will prevent a callback from being
+     * invoked on this item or any of its children
+     */
+    int ignore_callback;
+
+    /**
+     * Counter which is incremented each time an escape ('\') is encountered.
+     * This is used internally for non-string types and should only be
+     * inspected by the user if the state actually represents a string
+     * type.
+     */
+    unsigned int nescapes;
+
+    /**
+     * Put anything you want here. if JSONSL_STATE_USER_FIELDS is here, then
+     * the macro expansion happens here.
+     *
+     * You can use these fields to store hierarchical or 'tagging' information
+     * for specific objects.
+     *
+     * See the documentation above for the lifetime of the state object (i.e.
+     * if the private data points to allocated memory, it should be freed
+     * when the object is popped, as the state object will be re-used)
+     */
+#ifndef JSONSL_STATE_GENERIC
+    JSONSL_STATE_USER_FIELDS
+#else
+
+    /**
+     * Otherwise, this is a simple void * pointer for anything you want
+     */
+    void *data;
+#endif /* JSONSL_STATE_USER_FIELDS */
+};
+
+/**Gets the number of elements in the list.
+ * @param st The state. Must be of type JSONSL_T_LIST
+ * @return number of elements in the list
+ */
+#define JSONSL_LIST_SIZE(st) ((st)->nelem)
+
+/**Gets the number of key-value pairs in an object
+ * @param st The state. Must be of type JSONSL_T_OBJECT
+ * @return the number of key-value pairs in the object
+ */
+#define JSONSL_OBJECT_SIZE(st) ((st)->nelem / 2)
+
+/**Gets the numeric value.
+ * @param st The state. Must be of type JSONSL_T_SPECIAL and
+ *           special_flags must have the JSONSL_SPECIALf_NUMERIC flag
+ *           set.
+ * @return the numeric value of the state.
+ */
+#define JSONSL_NUMERIC_VALUE(st) ((st)->nelem)
+
+/*
+ * So now we need some special structure for keeping the
+ * JPR info in sync. Preferrably all in a single block
+ * of memory (there's no need for separate allocations.
+ * So we will define a 'table' with the following layout
+ *
+ * Level    nPosbl  JPR1_last   JPR2_last   JPR3_last
+ *
+ * 0        1       NOMATCH     POSSIBLE    POSSIBLE
+ * 1        0       NOMATCH     NOMATCH     COMPLETE
+ * [ table ends here because no further path is possible]
+ *
+ * Where the JPR..n corresponds to the number of JPRs
+ * requested, and nPosble is a quick flag to determine
+ *
+ * the number of possibilities. In the future this might
+ * be made into a proper 'jump' table,
+ *
+ * Since we always mark JPRs from the higher levels descending
+ * into the lower ones, a prospective child match would first
+ * look at the parent table to check the possibilities, and then
+ * see which ones were possible..
+ *
+ * Thus, the size of this blob would be (and these are all ints here)
+ * nLevels * nJPR * 2.
+ *
+ * the 'Width' of the table would be nJPR*2, and the 'height' would be
+ * nlevels
+ */
+
+/**
+ * This is called when a stack change ocurs.
+ *
+ * @param jsn The lexer
+ * @param action The type of action, this can be PUSH or POP
+ * @param state A pointer to the stack currently affected by the action
+ * @param at A pointer to the position of the input buffer which triggered
+ * this action.
+ */
+typedef void (*jsonsl_stack_callback)(
+        jsonsl_t jsn,
+        jsonsl_action_t action,
+        struct jsonsl_state_st* state,
+        const jsonsl_char_t *at);
+
+
+/**
+ * This is called when an error is encountered.
+ * Sometimes it's possible to 'erase' characters (by replacing them
+ * with whitespace). If you think you have corrected the error, you
+ * can return a true value, in which case the parser will backtrack
+ * and try again.
+ *
+ * @param jsn The lexer
+ * @param error The error which was thrown
+ * @param state the current state
+ * @param a pointer to the position of the input buffer which triggered
+ * the error. Note that this is not const, this is because you have the
+ * possibility of modifying the character in an attempt to correct the
+ * error
+ *
+ * @return zero to bail, nonzero to try again (this only makes sense if
+ * the input buffer has been modified by this callback)
+ */
+typedef int (*jsonsl_error_callback)(
+        jsonsl_t jsn,
+        jsonsl_error_t error,
+        struct jsonsl_state_st* state,
+        jsonsl_char_t *at);
+
+struct jsonsl_st {
+    /** Public, read-only */
+
+    /** This is the current level of the stack */
+    unsigned int level;
+
+    /** Flag set to indicate we should stop processing */
+    unsigned int stopfl;
+
+    /**
+     * This is the current position, relative to the beginning
+     * of the stream.
+     */
+    size_t pos;
+
+    /** This is the 'bytes' variable passed to feed() */
+    const jsonsl_char_t *base;
+
+    /** Callback invoked for PUSH actions */
+    jsonsl_stack_callback action_callback_PUSH;
+
+    /** Callback invoked for POP actions */
+    jsonsl_stack_callback action_callback_POP;
+
+    /** Default callback for any action, if neither PUSH or POP callbacks are defined */
+    jsonsl_stack_callback action_callback;
+
+    /**
+     * Do not invoke callbacks for objects deeper than this level.
+     * NOTE: This field establishes the lower bound for ignored callbacks,
+     * and is thus misnamed. `min_ignore_level` would actually make more
+     * sense, but we don't want to break API.
+     */
+    unsigned int max_callback_level;
+
+    /** The error callback. Invoked when an error happens. Should not be NULL */
+    jsonsl_error_callback error_callback;
+
+    /* these are boolean flags you can modify. You will be called
+     * about notification for each of these types if the corresponding
+     * variable is true.
+     */
+
+    /**
+     * @name Callback Booleans.
+     * These determine whether a callback is to be invoked for certain types of objects
+     * @{*/
+
+    /** Boolean flag to enable or disable the invokcation for events on this type*/
+    int call_SPECIAL;
+    int call_OBJECT;
+    int call_LIST;
+    int call_STRING;
+    int call_HKEY;
+    /*@}*/
+
+    /**
+     * @name u-Escape handling
+     * Special handling for the \\u-f00d type sequences. These are meant
+     * to be translated back into the corresponding octet(s).
+     * A special callback (if set) is invoked with *at=='u'. An application
+     * may wish to temporarily suspend parsing and handle the 'u-' sequence
+     * internally (or not).
+     */
+
+     /*@{*/
+
+    /** Callback to be invoked for a u-escape */
+    jsonsl_stack_callback action_callback_UESCAPE;
+
+    /** Boolean flag, whether to invoke the callback */
+    int call_UESCAPE;
+
+    /** Boolean flag, whether we should return after encountering a u-escape:
+     * the callback is invoked and then we return if this is true
+     */
+    int return_UESCAPE;
+    /*@}*/
+
+    struct {
+        int allow_trailing_comma;
+    } options;
+
+    /** Put anything here */
+    void *data;
+
+    /*@{*/
+    /** Private */
+    int in_escape;
+    char expecting;
+    char tok_last;
+    int can_insert;
+    unsigned int levels_max;
+
+#ifndef JSONSL_NO_JPR
+    size_t jpr_count;
+    jsonsl_jpr_t *jprs;
+
+    /* Root pointer for JPR matching information */
+    size_t *jpr_root;
+#endif /* JSONSL_NO_JPR */
+    /*@}*/
+
+    /**
+     * This is the stack. Its upper bound is levels_max, or the
+     * nlevels argument passed to jsonsl_new. If you modify this structure,
+     * make sure that this member is last.
+     */
+    struct jsonsl_state_st stack[1];
+};
+
+
+/**
+ * Creates a new lexer object, with capacity for recursion up to nlevels
+ *
+ * @param nlevels maximum recursion depth
+ */
+JSONSL_API
+jsonsl_t jsonsl_new(int nlevels);
+
+/**
+ * Feeds data into the lexer.
+ *
+ * @param jsn the lexer object
+ * @param bytes new data to be fed
+ * @param nbytes size of new data
+ */
+JSONSL_API
+void jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes);
+
+/**
+ * Resets the internal parser state. This does not free the parser
+ * but does clean it internally, so that the next time feed() is called,
+ * it will be treated as a new stream
+ *
+ * @param jsn the lexer
+ */
+JSONSL_API
+void jsonsl_reset(jsonsl_t jsn);
+
+/**
+ * Frees the lexer, cleaning any allocated memory taken
+ *
+ * @param jsn the lexer
+ */
+JSONSL_API
+void jsonsl_destroy(jsonsl_t jsn);
+
+/**
+ * Gets the 'parent' element, given the current one
+ *
+ * @param jsn the lexer
+ * @param cur the current nest, which should be a struct jsonsl_nest_st
+ */
+static JSONSL_INLINE
+struct jsonsl_state_st *jsonsl_last_state(const jsonsl_t jsn,
+                                          const struct jsonsl_state_st *state)
+{
+    /* Don't complain about overriding array bounds */
+    if (state->level > 1) {
+        return jsn->stack + state->level - 1;
+    } else {
+        return NULL;
+    }
+}
+
+/**
+ * Gets the state of the last fully consumed child of this parent. This is
+ * only valid in the parent's POP callback.
+ *
+ * @param the lexer
+ * @return A pointer to the child.
+ */
+static JSONSL_INLINE
+struct jsonsl_state_st *jsonsl_last_child(const jsonsl_t jsn,
+                                          const struct jsonsl_state_st *parent)
+{
+    return jsn->stack + (parent->level + 1);
+}
+
+/**Call to instruct the parser to stop parsing and return. This is valid
+ * only from within a callback */
+static JSONSL_INLINE
+void jsonsl_stop(jsonsl_t jsn)
+{
+    jsn->stopfl = 1;
+}
+
+/**
+ * This enables receiving callbacks on all events. Doesn't do
+ * anything special but helps avoid some boilerplate.
+ * This does not touch the UESCAPE callbacks or flags.
+ */
+static JSONSL_INLINE
+void jsonsl_enable_all_callbacks(jsonsl_t jsn)
+{
+    jsn->call_HKEY = 1;
+    jsn->call_STRING = 1;
+    jsn->call_OBJECT = 1;
+    jsn->call_SPECIAL = 1;
+    jsn->call_LIST = 1;
+}
+
+/**
+ * A macro which returns true if the current state object can
+ * have children. This means a list type or an object type.
+ */
+#define JSONSL_STATE_IS_CONTAINER(state) \
+        (state->type == JSONSL_T_OBJECT || state->type == JSONSL_T_LIST)
+
+/**
+ * These two functions, dump a string representation
+ * of the error or type, respectively. They will never
+ * return NULL
+ */
+JSONSL_API
+const char* jsonsl_strerror(jsonsl_error_t err);
+JSONSL_API
+const char* jsonsl_strtype(jsonsl_type_t jt);
+
+/**
+ * Dumps global metrics to the screen. This is a noop unless
+ * jsonsl was compiled with JSONSL_USE_METRICS
+ */
+JSONSL_API
+void jsonsl_dump_global_metrics(void);
+
+/* This macro just here for editors to do code folding */
+#ifndef JSONSL_NO_JPR
+
+/**
+ * @name JSON Pointer API
+ *
+ * JSONPointer API. This isn't really related to the lexer (at least not yet)
+ * JSONPointer provides an extremely simple specification for providing
+ * locations within JSON objects. We will extend it a bit and allow for
+ * providing 'wildcard' characters by which to be able to 'query' the stream.
+ *
+ * See http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00
+ *
+ * Currently I'm implementing the 'single query' API which can only use a single
+ * query component. In the future I will integrate my yet-to-be-published
+ * Boyer-Moore-esque prefix searching implementation, in order to allow
+ * multiple paths to be merged into one for quick and efficient searching.
+ *
+ *
+ * JPR (as we'll refer to it within the source) can be used by splitting
+ * the components into mutliple sections, and incrementally 'track' each
+ * component. When JSONSL delivers a 'pop' callback for a string, or a 'push'
+ * callback for an object, we will check to see whether the index matching
+ * the component corresponding to the current level contains a match
+ * for our path.
+ *
+ * In order to do this properly, a structure must be maintained within the
+ * parent indicating whether its children are possible matches. This flag
+ * will be 'inherited' by call children which may conform to the match
+ * specification, and discarded by all which do not (thereby eliminating
+ * their children from inheriting it).
+ *
+ * A successful match is a complete one. One can provide multiple paths with
+ * multiple levels of matches e.g.
+ *  /foo/bar/baz/^/blah
+ *
+ *  @{
+ */
+
+/** The wildcard character */
+#ifndef JSONSL_PATH_WILDCARD_CHAR
+#define JSONSL_PATH_WILDCARD_CHAR '^'
+#endif /* WILDCARD_CHAR */
+
+#define JSONSL_XMATCH \
+    X(COMPLETE,1) \
+    X(POSSIBLE,0) \
+    X(NOMATCH,-1) \
+    X(TYPE_MISMATCH, -2)
+
+typedef enum {
+
+#define X(T,v) \
+    JSONSL_MATCH_##T = v,
+    JSONSL_XMATCH
+
+#undef X
+    JSONSL_MATCH_UNKNOWN
+} jsonsl_jpr_match_t;
+
+typedef enum {
+    JSONSL_PATH_STRING = 1,
+    JSONSL_PATH_WILDCARD,
+    JSONSL_PATH_NUMERIC,
+    JSONSL_PATH_ROOT,
+
+    /* Special */
+    JSONSL_PATH_INVALID = -1,
+    JSONSL_PATH_NONE = 0
+} jsonsl_jpr_type_t;
+
+struct jsonsl_jpr_component_st {
+    /** The string the component points to */
+    char *pstr;
+    /** if this is a numeric type, the number is 'cached' here */
+    unsigned long idx;
+    /** The length of the string */
+    size_t len;
+    /** The type of component (NUMERIC or STRING) */
+    jsonsl_jpr_type_t ptype;
+
+    /** Set this to true to enforce type checking between dict keys and array
+     * indices. jsonsl_jpr_match() will return TYPE_MISMATCH if it detects
+     * that an array index is actually a child of a dictionary. */
+    short is_arridx;
+
+    /* Extra fields (for more advanced searches. Default is empty) */
+    JSONSL_JPR_COMPONENT_USER_FIELDS
+};
+
+struct jsonsl_jpr_st {
+    /** Path components */
+    struct jsonsl_jpr_component_st *components;
+    size_t ncomponents;
+
+    /**Type of the match to be expected. If nonzero, will be compared against
+     * the actual type */
+    unsigned match_type;
+
+    /** Base of allocated string for components */
+    char *basestr;
+
+    /** The original match string. Useful for returning to the user */
+    char *orig;
+    size_t norig;
+};
+
+/**
+ * Create a new JPR object.
+ *
+ * @param path the JSONPointer path specification.
+ * @param errp a pointer to a jsonsl_error_t. If this function returns NULL,
+ * then more details will be in this variable.
+ *
+ * @return a new jsonsl_jpr_t object, or NULL on error.
+ */
+JSONSL_API
+jsonsl_jpr_t jsonsl_jpr_new(const char *path, jsonsl_error_t *errp);
+
+/**
+ * Destroy a JPR object
+ */
+JSONSL_API
+void jsonsl_jpr_destroy(jsonsl_jpr_t jpr);
+
+/**
+ * Match a JSON object against a type and specific level
+ *
+ * @param jpr the JPR object
+ * @param parent_type the type of the parent (should be T_LIST or T_OBJECT)
+ * @param parent_level the level of the parent
+ * @param key the 'key' of the child. If the parent is an array, this should be
+ * empty.
+ * @param nkey - the length of the key. If the parent is an array (T_LIST), then
+ * this should be the current index.
+ *
+ * NOTE: The key of the child means any kind of associative data related to the
+ * element. Thus: <<< { "foo" : [ >>,
+ * the opening array's key is "foo".
+ *
+ * @return a status constant. This indicates whether a match was excluded, possible,
+ * or successful.
+ */
+JSONSL_API
+jsonsl_jpr_match_t jsonsl_jpr_match(jsonsl_jpr_t jpr,
+                                    unsigned int parent_type,
+                                    unsigned int parent_level,
+                                    const char *key, size_t nkey);
+
+/**
+ * Alternate matching algorithm. This matching algorithm does not use
+ * JSONPointer but relies on a more structured searching mechanism. It
+ * assumes that there is a clear distinction between array indices and
+ * object keys. In this case, the jsonsl_path_component_st::ptype should
+ * be set to @ref JSONSL_PATH_NUMERIC for an array index (the
+ * jsonsl_path_comonent_st::is_arridx field will be removed in a future
+ * version).
+ *
+ * @param jpr The path
+ * @param parent The parent structure. Can be NULL if this is the root object
+ * @param child The child structure. Should not be NULL
+ * @param key Object key, if an object
+ * @param nkey Length of object key
+ * @return Status constant if successful
+ *
+ * @note
+ * For successful matching, both the key and the path itself should be normalized
+ * to contain 'proper' utf8 sequences rather than utf16 '\uXXXX' escapes. This
+ * should currently be done in the application. Another version of this function
+ * may use a temporary buffer in such circumstances (allocated by the application).
+ *
+ * Since this function also checks the state of the child, it should only
+ * be called on PUSH callbacks, and not POP callbacks
+ */
+JSONSL_API
+jsonsl_jpr_match_t
+jsonsl_path_match(jsonsl_jpr_t jpr,
+                  const struct jsonsl_state_st *parent,
+                  const struct jsonsl_state_st *child,
+                  const char *key, size_t nkey);
+
+
+/**
+ * Associate a set of JPR objects with a lexer instance.
+ * This should be called before the lexer has been fed any data (and
+ * behavior is undefined if you don't adhere to this).
+ *
+ * After using this function, you may subsequently call match_state() on
+ * given states (presumably from within the callbacks).
+ *
+ * Note that currently the first JPR is the quickest and comes
+ * pre-allocated with the state structure. Further JPR objects
+ * are chained.
+ *
+ * @param jsn The lexer
+ * @param jprs An array of jsonsl_jpr_t objects
+ * @param njprs How many elements in the jprs array.
+ */
+JSONSL_API
+void jsonsl_jpr_match_state_init(jsonsl_t jsn,
+                                 jsonsl_jpr_t *jprs,
+                                 size_t njprs);
+
+/**
+ * This follows the same semantics as the normal match,
+ * except we infer parent and type information from the relevant state objects.
+ * The match status (for all possible JPR objects) is set in the *out parameter.
+ *
+ * If a match has succeeded, then its JPR object will be returned. In all other
+ * instances, NULL is returned;
+ *
+ * @param jpr The jsonsl_jpr_t handle
+ * @param state The jsonsl_state_st which is a candidate
+ * @param key The hash key (if applicable, can be NULL if parent is list)
+ * @param nkey Length of hash key (if applicable, can be zero if parent is list)
+ * @param out A pointer to a jsonsl_jpr_match_t. This will be populated with
+ * the match result
+ *
+ * @return If a match was completed in full, then the JPR object containing
+ * the matching path will be returned. Otherwise, the return is NULL (note, this
+ * does not mean matching has failed, it can still be part of the match: check
+ * the out parameter).
+ */
+JSONSL_API
+jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn,
+                                    struct jsonsl_state_st *state,
+                                    const char *key,
+                                    size_t nkey,
+                                    jsonsl_jpr_match_t *out);
+
+
+/**
+ * Cleanup any memory allocated and any states set by
+ * match_state_init() and match_state()
+ * @param jsn The lexer
+ */
+JSONSL_API
+void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn);
+
+/**
+ * Return a string representation of the match result returned by match()
+ */
+JSONSL_API
+const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match);
+
+/* @}*/
+
+/**
+ * Utility function to convert escape sequences into their original form.
+ *
+ * The decoders I've sampled do not seem to specify a standard behavior of what
+ * to escape/unescape.
+ *
+ * RFC 4627 Mandates only that the quoute, backslash, and ASCII control
+ * characters (0x00-0x1f) be escaped. It is often common for applications
+ * to escape a '/' - however this may also be desired behavior. the JSON
+ * spec is not clear on this, and therefore jsonsl leaves it up to you.
+ *
+ * Additionally, sometimes you may wish to _normalize_ JSON. This is specifically
+ * true when dealing with 'u-escapes' which can be expressed perfectly fine
+ * as utf8. One use case for normalization is JPR string comparison, in which
+ * case two effectively equivalent strings may not match because one is using
+ * u-escapes and the other proper utf8. To normalize u-escapes only, pass in
+ * an empty `toEscape` table, enabling only the `u` index.
+ *
+ * @param in The input string.
+ * @param out An allocated output (should be the same size as in)
+ * @param len the size of the buffer
+ * @param toEscape - A sparse array of characters to unescape. Characters
+ * which are not present in this array, e.g. toEscape['c'] == 0 will be
+ * ignored and passed to the output in their original form.
+ * @param oflags If not null, and a \uXXXX escape expands to a non-ascii byte,
+ * then this variable will have the SPECIALf_NONASCII flag on.
+ *
+ * @param err A pointer to an error variable. If an error ocurrs, it will be
+ * set in this variable
+ * @param errat If not null and an error occurs, this will be set to point
+ * to the position within the string at which the offending character was
+ * encountered.
+ *
+ * @return The effective size of the output buffer.
+ *
+ * @note
+ * This function now encodes the UTF8 equivalents of utf16 escapes (i.e.
+ * 'u-escapes'). Previously this would encode the escapes as utf16 literals,
+ * which while still correct in some sense was confusing for many (especially
+ * considering that the inputs were variations of char).
+ *
+ * @note
+ * The output buffer will never be larger than the input buffer, since
+ * standard escape sequences (i.e. '\t') occupy two bytes in the source
+ * but only one byte (when unescaped) in the output. Likewise u-escapes
+ * (i.e. \uXXXX) will occupy six bytes in the source, but at the most
+ * two bytes when escaped.
+ */
+JSONSL_API
+size_t jsonsl_util_unescape_ex(const char *in,
+                               char *out,
+                               size_t len,
+                               const int toEscape[128],
+                               unsigned *oflags,
+                               jsonsl_error_t *err,
+                               const char **errat);
+
+/**
+ * Convenience macro to avoid passing too many parameters
+ */
+#define jsonsl_util_unescape(in, out, len, toEscape, err) \
+    jsonsl_util_unescape_ex(in, out, len, toEscape, NULL, err, NULL)
+
+#endif /* JSONSL_NO_JPR */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* JSONSL_H_ */
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/main.c
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/main.c	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/main.c	(revision 364)
@@ -45,4 +45,5 @@
 #include <sil.h>
 #include <setjmp.h>
+#include <stdlib.h>
 #include <string.h>
 #include "syssvc/serial.h"
@@ -80,5 +81,7 @@
 
 ID ws_api_mailboxid = MAIN_DATAQUEUE;
+#ifndef NOUSE_MPF_NET_BUF
 ID ws_mempoolid = MPF_NET_BUF_256;
+#endif
 
 #if defined(IF_ETHER_BTUSB) || defined(IF_ETHER_ENBT)
@@ -114,7 +117,42 @@
 static void main_timeout();
 
+extern int ntshell_exit;
+
 int uart_read(char *buf, int cnt, void *extobj)
 {
-	return serial_rea_dat(SIO_PORTID, (char *)buf, cnt);
+	struct main_t *obj = (struct main_t *)extobj;
+	int result;
+	ER ret;
+	int timer;
+
+	obj->prev = obj->now;
+
+	/* タイマー取得 */
+	timer = main_get_timer();
+
+	/* 待ち */
+	ret = serial_trea_dat(SIO_PORTID, buf, cnt, timer);
+	if ((ret < 0) && (ret != E_OK) && (ret != E_TMOUT)) {
+		syslog(LOG_NOTICE, "tslp_tsk ret: %s %d", itron_strerror(ret), timer);
+		ntshell_exit = 1;
+		return -1;
+	}
+	result = (int)ret;
+
+	ret = get_tim(&obj->now);
+	if (ret != E_OK) {
+		syslog(LOG_NOTICE, "get_tim ret: %s", itron_strerror(ret));
+		ntshell_exit = 1;
+		return -1;
+	}
+
+			/* 時間経過 */
+	int elapse = obj->now - obj->prev;
+	main_progress(elapse);
+
+	/* タイムアウト処理 */
+	main_timeout();
+
+	return result;
 }
 
@@ -122,19 +160,4 @@
 {
 	return serial_wri_dat(SIO_PORTID, buf, cnt);
-}
-
-unsigned char ntstdio_xi(struct ntstdio_t *handle)
-{
-	char buf[1];
-	if(serial_rea_dat(SIO_PORTID, buf, 1) != 1)
-		return -EIO;
-	return buf[0];
-}
-
-void ntstdio_xo(struct ntstdio_t *handle, unsigned char c)
-{
-	char buf[1];
-	buf[0] = c;
-	serial_wri_dat(SIO_PORTID, buf, 1);
 }
 
@@ -156,5 +179,5 @@
 	main_initialize();
 
-	ntshell_init(&ntshell, uart_read, uart_write, cmd_execute, NULL);
+	ntshell_init(&ntshell, uart_read, uart_write, cmd_execute, &main_obj);
 	ntshell_set_prompt(&ntshell, "NTShell>");
 	ntshell_execute(&ntshell);
@@ -176,7 +199,12 @@
 	ER ret;
 
+#ifdef TOPPERS_OMIT_TECS
+	serial_opn_por(SIO_PORTID);
+#endif
+	serial_ctl_por(SIO_PORTID, IOCTL_FCSND | IOCTL_FCRCV);
+
 	//wolfSSL_Debugging_ON();
 
-	ntshell_task_init();
+	ntshell_task_init(uart_read, uart_write, &main_obj);
 
 	main_obj.timer = TMO_FEVR;
@@ -313,8 +341,31 @@
 }
 
+int cmd_creid(int argc, char **argv)
+{
+	if (argc != 2) {
+		printf("creid {client_id}\n");
+		return 0;
+	}
+
+	client_set_client_id(argv[1]);
+
+	return 0;
+}
+
+int cmd_secret(int argc, char **argv)
+{
+	if (argc != 2) {
+		printf("secret {client_secret}\n");
+		return 0;
+	}
+
+	client_set_client_secret(argv[1]);
+
+	return 0;
+}
+
 int cmd_logupload(int argc, char **argv)
 {
-	client_task(0);
-	return 0;
+	return client_upload_file(argc, argv);
 }
 
@@ -335,4 +386,11 @@
 	{"dnsc", "DNS client", usrcmd_dnsc },
 	{"ntpc", "NTP client", usrcmd_ntpc },
+	{"creid", "Regster device", cmd_creid},
+	{"secret", "Regster device", cmd_secret},
+	{"gdi", "get_device_id", client_get_device_id},
+	{"gat", "get_access_token", client_get_access_token},
+	{"uat", "update_access_token", client_update_access_token},
+	{"rd", "revoke device", client_revoke},
+	{"uf", "upload_file", client_upload_file},
 	{"logupload", "Upload log to server", cmd_logupload},
 	{"info", "This is a description text string for info command.", usrcmd_info},
Index: asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/main.cfg
===================================================================
--- asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/main.cfg	(revision 359)
+++ asp3_tinet_ecnl_arm/trunk/app1_usb_watt_meter/src/main.cfg	(revision 364)
@@ -54,5 +54,4 @@
 INCLUDE("tinet/tinet_asp.cfg");
 INCLUDE("tinet_main.cfg");
-INCLUDE("netinet/ip_igmp.cfg");
 
 /* DHCP クライアント */
