| 
									
										
										
										
											2018-03-15 15:27:34 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * $Id$ | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |     Copyright (c) 2016-2018 Chung, Hyung-Hwan. All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |     modification, are permitted provided that the following conditions | 
					
						
							|  |  |  |     are met: | 
					
						
							|  |  |  |     1. Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  |        notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  |     2. Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  |        notice, this list of conditions and the following disclaimer in the | 
					
						
							|  |  |  |        documentation and/or other materials provided with the distribution. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR | 
					
						
							|  |  |  |     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 
					
						
							|  |  |  |     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 
					
						
							|  |  |  |     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 
					
						
							|  |  |  |     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 
					
						
							|  |  |  |     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
					
						
							|  |  |  |     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
					
						
							|  |  |  |     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  |     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 
					
						
							|  |  |  |     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "hcl-c.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | #include "hcl-prv.h"
 | 
					
						
							| 
									
										
										
										
											2018-11-03 15:57:14 +00:00
										 |  |  | #include "cb-impl.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | #define HCL_CLIENT_TOKEN_NAME_ALIGN 64
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | struct dummy_hcl_xtn_t | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	hcl_client_t* client; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | typedef struct dummy_hcl_xtn_t dummy_hcl_xtn_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum hcl_client_reply_attr_type_t | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 	HCL_CLIENT_REPLY_ATTR_TYPE_UNKNOWN, | 
					
						
							|  |  |  | 	HCL_CLIENT_REPLY_ATTR_TYPE_DATA | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | typedef enum hcl_client_reply_attr_type_t hcl_client_reply_attr_type_t; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | struct hcl_client_t | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	hcl_mmgr_t* mmgr; | 
					
						
							|  |  |  | 	hcl_cmgr_t* cmgr; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 	hcl_client_prim_t prim; | 
					
						
							|  |  |  | 	hcl_t* dummy_hcl; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	hcl_errnum_t errnum; | 
					
						
							|  |  |  | 	struct | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		hcl_ooch_t buf[HCL_ERRMSG_CAPA]; | 
					
						
							|  |  |  | 		hcl_oow_t len; | 
					
						
							|  |  |  | 	} errmsg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | 		hcl_bitmask_t trait; | 
					
						
							|  |  |  | 		hcl_bitmask_t logmask; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	} cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hcl_client_state_t state; | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 	struct | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 		struct | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			hcl_ooch_t* ptr; | 
					
						
							|  |  |  | 			hcl_oow_t len; | 
					
						
							|  |  |  | 			hcl_oow_t capa; | 
					
						
							|  |  |  | 		} tok; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 		hcl_client_reply_type_t type; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 		hcl_client_reply_attr_type_t last_attr_type; | 
					
						
							|  |  |  | 		struct | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 			hcl_ooch_t* ptr; | 
					
						
							|  |  |  | 			hcl_oow_t   len; | 
					
						
							|  |  |  | 			hcl_oow_t   capa; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 		} last_attr_key; /* the last attr key shown */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 		union | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			struct | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				hcl_oow_t nsplen; /* length remembered when the white space was shown */ | 
					
						
							|  |  |  | 			} reply_value_unquoted; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 			struct | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				int escaped; | 
					
						
							|  |  |  | 			} reply_value_quoted; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			struct | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				hcl_oow_t nsplen; /* length remembered when the white space was shown */ | 
					
						
							|  |  |  | 			} attr_value_unquoted; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			struct | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				int escaped; | 
					
						
							|  |  |  | 			} attr_value_quoted; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			struct | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				hcl_oow_t max; | 
					
						
							|  |  |  | 				hcl_oow_t tally; | 
					
						
							|  |  |  | 			} length_bounded_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			struct | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				int in_data_part; | 
					
						
							|  |  |  | 				int negated; | 
					
						
							|  |  |  | 				hcl_oow_t max; /* chunk length */ | 
					
						
							|  |  |  | 				hcl_oow_t tally;  | 
					
						
							|  |  |  | 				hcl_oow_t total; | 
					
						
							|  |  |  | 				hcl_oow_t clcount;  | 
					
						
							|  |  |  | 			} chunked_data; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 		} u; | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 	} rep; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | /* ========================================================================= */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | static void log_write_for_dummy (hcl_t* hcl, hcl_bitmask_t mask, const hcl_ooch_t* msg, hcl_oow_t len) | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	dummy_hcl_xtn_t* xtn = (dummy_hcl_xtn_t*)hcl_getxtn(hcl); | 
					
						
							|  |  |  | 	hcl_client_t* client; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	client = xtn->client; | 
					
						
							|  |  |  | 	client->prim.log_write (client, mask, msg, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ========================================================================= */ | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | static HCL_INLINE int is_spacechar (hcl_bch_t c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* TODO: handle other space unicode characters */ | 
					
						
							|  |  |  | 	switch (c) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-04-24 05:24:58 +00:00
										 |  |  | 		/* [NOTE]: '\n' is special and used as delimiter. so it's not treated
 | 
					
						
							|  |  |  | 		 *         as a space character */ | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 		case ' ': | 
					
						
							|  |  |  | 		case '\f': /* formfeed */ | 
					
						
							|  |  |  | 		case '\r': /* carriage return */ | 
					
						
							|  |  |  | 		case '\t': /* horizon tab */ | 
					
						
							|  |  |  | 		case '\v': /* vertical tab */ | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static HCL_INLINE int is_alphachar (hcl_ooci_t c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | /* TODO: support full unicode */ | 
					
						
							|  |  |  | 	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | static HCL_INLINE int is_digitchar (hcl_ooci_t c) | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | /* TODO: support full unicode */ | 
					
						
							|  |  |  | 	return (c >= '0' && c <= '9'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | static void clear_reply_token (hcl_client_t* client) | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	client->rep.tok.len = 0; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | static int add_to_reply_token (hcl_client_t* client, hcl_ooch_t ch) | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	if (client->rep.tok.len >= client->rep.tok.capa) | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 		hcl_ooch_t* tmp; | 
					
						
							|  |  |  | 		hcl_oow_t newcapa; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 		newcapa = HCL_ALIGN_POW2(client->rep.tok.len + 1, HCL_CLIENT_TOKEN_NAME_ALIGN); | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 		tmp = hcl_client_reallocmem(client, client->rep.tok.ptr, newcapa * HCL_SIZEOF(*tmp)); | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 		if (!tmp) return -1; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		client->rep.tok.capa = newcapa; | 
					
						
							|  |  |  | 		client->rep.tok.ptr = tmp; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	client->rep.tok.ptr[client->rep.tok.len++] = ch; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | static HCL_INLINE int is_token (hcl_client_t* client, const hcl_bch_t* str) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-04-07 15:54:16 +00:00
										 |  |  | 	return hcl_comp_oochars_bcstr(client->rep.tok.ptr, client->rep.tok.len, str) == 0; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | }  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static HCL_INLINE int is_token_integer (hcl_client_t* client, hcl_oow_t* value) | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	hcl_oow_t i; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 	hcl_oow_t v = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (client->rep.tok.len <= 0) return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 	for (i = 0; i < client->rep.tok.len; i++) | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		if (!is_digitchar(client->rep.tok.ptr[i])) return 0; | 
					
						
							|  |  |  | 		v = v * 10 + (client->rep.tok.ptr[i] - '0'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*value = v; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | }  | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-29 03:08:43 +00:00
										 |  |  | static HCL_INLINE hcl_ooch_t unescape (hcl_ooch_t c) | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-04-09 02:42:05 +00:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2018-03-29 03:08:43 +00:00
										 |  |  | 	/* as of this writing, the server side only escapes \ and ".
 | 
					
						
							|  |  |  | 	 * i don't know if n, r, f, t, v should be supported here */ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 	switch (c) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-04-22 18:18:45 +00:00
										 |  |  | 		case 'a': return '\a'; | 
					
						
							|  |  |  | 		case 'b': return '\b'; | 
					
						
							|  |  |  | 		case 'f': return '\f'; | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 		case 'n': return '\n'; | 
					
						
							|  |  |  | 		case 'r': return '\r'; | 
					
						
							|  |  |  | 		case 't': return '\t'; | 
					
						
							|  |  |  | 		case 'v': return '\v'; | 
					
						
							|  |  |  | 		default: return c; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-04-09 02:42:05 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 	return c; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | static int handle_char (hcl_client_t* client, hcl_ooci_t c, hcl_oow_t nbytes) | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	switch (client->state) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		case HCL_CLIENT_STATE_START: | 
					
						
							|  |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "unexpected end before reply name"); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '.') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				client->state = HCL_CLIENT_STATE_IN_REPLY_NAME; | 
					
						
							|  |  |  | 				clear_reply_token (client); | 
					
						
							|  |  |  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (is_spacechar(c))  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* skip whitespaces at the beginning of the start line before the reply name */ | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EINVAL, "reply line not starting with a period - %jc", (hcl_ooch_t)c); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case HCL_CLIENT_STATE_IN_REPLY_NAME: | 
					
						
							|  |  |  | 			if (is_alphachar(c) || (client->rep.tok.len > 2 && c == '-')) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				if (is_token(client, ".OK")) | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				{ | 
					
						
							|  |  |  | 					client->rep.type = HCL_CLIENT_REPLY_TYPE_OK; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				else if (is_token(client, ".ERROR")) | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				{ | 
					
						
							|  |  |  | 					client->rep.type = HCL_CLIENT_REPLY_TYPE_ERROR; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 					hcl_client_seterrbfmt (client, HCL_EINVAL, "unknown reply name %.*js", client->rep.tok.len, client->rep.tok.ptr); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 					goto oops; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				client->state = HCL_CLIENT_STATE_IN_REPLY_VALUE_START; | 
					
						
							|  |  |  | 				clear_reply_token (client); | 
					
						
							|  |  |  | 				/* [IMPORTANT] fall thru */ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_START: | 
					
						
							|  |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of reply line without newline"); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (is_spacechar(c)) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* do nothing. skip it */ | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '\n') | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				/* no value is specified. even no whitespaces.
 | 
					
						
							|  |  |  | 				 * switch to a long-format response */ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				if (client->prim.start_reply(client, client->rep.type, HCL_NULL, 0) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				client->state = HCL_CLIENT_STATE_IN_ATTR_KEY; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '\"') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				client->state = HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED; | 
					
						
							|  |  |  | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				client->rep.u.reply_value_quoted.escaped = 0; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* the first value character has been encountered */ | 
					
						
							|  |  |  | 				client->state = HCL_CLIENT_STATE_IN_REPLY_VALUE_UNQUOTED; | 
					
						
							|  |  |  | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | 
					
						
							|  |  |  | 				client->rep.u.reply_value_unquoted.nsplen = 0; | 
					
						
							|  |  |  | 				/* [IMPORTANT] fall thru */ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_UNQUOTED: | 
					
						
							|  |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of reply line without newline"); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '\n') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				client->rep.tok.len = client->rep.u.reply_value_unquoted.nsplen; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				goto reply_value_end; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | 
					
						
							|  |  |  | 				if (!is_spacechar(c)) client->rep.u.reply_value_unquoted.nsplen = client->rep.tok.len; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED: | 
					
						
							|  |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of reply line without closing quote"); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (client->rep.u.reply_value_quoted.escaped) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-03-29 03:08:43 +00:00
										 |  |  | 					c = unescape(c); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				else if (c == '\\') | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					client->rep.u.reply_value_quoted.escaped = 1; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else if (c == '\"') | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					client->state = HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED_TRAILER; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				client->rep.u.reply_value_quoted.escaped = 0; | 
					
						
							|  |  |  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 		case HCL_CLIENT_STATE_IN_REPLY_VALUE_QUOTED_TRAILER: | 
					
						
							|  |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of reply line without newline"); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '\n') | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			reply_value_end: | 
					
						
							|  |  |  | 				/* short-form format. the data pointer is passed to the start_reply 
 | 
					
						
							|  |  |  | 				 * callback. no end_reply callback is invoked. the data is assumed | 
					
						
							|  |  |  | 				 * to be in UTF-8 encoding. this is different from the data in the | 
					
						
							|  |  |  | 				 * long-format reply which is treated as octet stream */ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				if (client->prim.start_reply(client, client->rep.type, client->rep.tok.ptr, client->rep.tok.len) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				/* no end_reply() callback for the short-form reply */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				client->state = HCL_CLIENT_STATE_START; | 
					
						
							|  |  |  | 				clear_reply_token (client); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (is_spacechar(c)) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* skip white spaces after the closing quote */ | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EINVAL, "garbage after quoted reply value"); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 		case HCL_CLIENT_STATE_IN_ATTR_KEY: | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of attribute line"); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (client->rep.tok.len == 0) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				if (is_spacechar(c)) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					/* skip whitespaces at the beginning of the start line before the reply name */ | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else if (c != '.') | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 					hcl_client_seterrbfmt (client, HCL_EINVAL, "attribute name not starting with a period - [%jc]", (hcl_ooch_t)c); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 					goto oops; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else	if (is_alphachar(c) || (client->rep.tok.len > 2 && c == '-')) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				if (client->rep.tok.len <= 1) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					hcl_client_seterrbfmt (client, HCL_EINVAL, "attribute name too short"); | 
					
						
							|  |  |  | 					goto oops; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				if (is_token(client, ".DATA")) | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 					client->rep.last_attr_type = HCL_CLIENT_REPLY_ATTR_TYPE_DATA; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				/* PUT more known attribute handling here */ | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				else | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 					client->rep.last_attr_type = HCL_CLIENT_REPLY_ATTR_TYPE_UNKNOWN; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				/* remember the attribute name */ | 
					
						
							|  |  |  | 				if (client->rep.tok.len > client->rep.last_attr_key.capa) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					hcl_ooch_t* tmp; | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 					tmp = hcl_client_reallocmem(client, client->rep.last_attr_key.ptr, client->rep.tok.capa * HCL_SIZEOF(*tmp)); | 
					
						
							|  |  |  | 					if (!tmp) goto oops; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					client->rep.last_attr_key.ptr = tmp; | 
					
						
							|  |  |  | 					client->rep.last_attr_key.capa = client->rep.tok.capa; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-07 15:54:16 +00:00
										 |  |  | 				hcl_copy_oochars (client->rep.last_attr_key.ptr, client->rep.tok.ptr, client->rep.tok.len); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				client->rep.last_attr_key.len = client->rep.tok.len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				client->state = HCL_CLIENT_STATE_IN_ATTR_VALUE_START; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				clear_reply_token (client); | 
					
						
							|  |  |  | 				/* [IMPORTANT] fall thru */ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 		case HCL_CLIENT_STATE_IN_ATTR_VALUE_START: | 
					
						
							|  |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end without attribute value"); | 
					
						
							|  |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (is_spacechar(c)) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* do nothing. skip it */ | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '\n') | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EINVAL, "no attribute value for %.*js\n", client->rep.last_attr_key.len, client->rep.last_attr_key.ptr); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '\"') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				client->state = HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED; | 
					
						
							|  |  |  | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | 
					
						
							|  |  |  | 				client->rep.u.attr_value_quoted.escaped = 0; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* the first value character has been encountered */ | 
					
						
							|  |  |  | 				client->state = HCL_CLIENT_STATE_IN_ATTR_VALUE_UNQUOTED; | 
					
						
							|  |  |  | 				HCL_ASSERT (client->dummy_hcl, client->rep.tok.len == 0); | 
					
						
							|  |  |  | 				client->rep.u.attr_value_unquoted.nsplen = 0; | 
					
						
							|  |  |  | 				/* [IMPORTANT] fall thru */ | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 		case HCL_CLIENT_STATE_IN_ATTR_VALUE_UNQUOTED: | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of attribute line without newline"); | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '\n') | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				client->rep.tok.len = client->rep.u.attr_value_unquoted.nsplen; | 
					
						
							|  |  |  | 				goto attr_value_end; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | 
					
						
							|  |  |  | 				if (!is_spacechar(c)) client->rep.u.attr_value_unquoted.nsplen = client->rep.tok.len; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		case HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED: | 
					
						
							|  |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of attribute value without closing quote"); | 
					
						
							|  |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 			else  | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				if (client->rep.u.attr_value_quoted.escaped) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-03-29 03:08:43 +00:00
										 |  |  | 					c = unescape(c); | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 					/* TODO: more escaping handling like \0NNN \xXXXX \uXXXX \UXXXX */ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				else if (c == '\\') | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					client->rep.u.attr_value_quoted.escaped = 1; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else if (c == '\"') | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					client->state = HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED_TRAILER; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				client->rep.u.attr_value_quoted.escaped = 0; | 
					
						
							|  |  |  | 				if (add_to_reply_token(client, c) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 		case HCL_CLIENT_STATE_IN_ATTR_VALUE_QUOTED_TRAILER: | 
					
						
							|  |  |  | 			if (c == HCL_OOCI_EOF) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				hcl_client_seterrbfmt (client, HCL_EFINIS, "sudden end of attribute line without newline"); | 
					
						
							|  |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (c == '\n') | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			attr_value_end: | 
					
						
							|  |  |  | 				if (client->prim.feed_attr) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					hcl_oocs_t key, val; | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 					key.ptr = client->rep.last_attr_key.ptr; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 					key.len = client->rep.last_attr_key.len; | 
					
						
							|  |  |  | 					val.ptr = client->rep.tok.ptr; | 
					
						
							|  |  |  | 					val.len = client->rep.tok.len; | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 					if (client->prim.feed_attr (client, &key, &val) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (client->rep.last_attr_type == HCL_CLIENT_REPLY_ATTR_TYPE_DATA) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					hcl_oow_t length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					/* this must be the last attr. the trailing part are all data */ | 
					
						
							|  |  |  | 					if (is_token(client, "chunked")) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						client->state = HCL_CLIENT_STATE_IN_CHUNKED_DATA; | 
					
						
							|  |  |  | 						HCL_MEMSET (&client->rep.u.chunked_data, 0, HCL_SIZEOF(client->rep.u.chunked_data)); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					else if (is_token_integer(client, &length)) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						if (length > 0) | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							client->state = HCL_CLIENT_STATE_IN_LENGTH_BOUNDED_DATA; | 
					
						
							|  |  |  | 							/* [NOTE] the max length for the length-bounded transfer scheme is limited
 | 
					
						
							|  |  |  | 							 *        by the system word size as of this implementation */ | 
					
						
							|  |  |  | 							client->rep.u.length_bounded_data.max = length;  | 
					
						
							|  |  |  | 							client->rep.u.length_bounded_data.tally = 0; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						else | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							/* .DATA 0 has been received. this should be end of the reply */ | 
					
						
							|  |  |  | 							client->state = HCL_CLIENT_STATE_START; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					else | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						hcl_client_seterrbfmt (client, HCL_EINVAL, "invalid attribute value for .DATA - %.*js", client->rep.tok.len, client->rep.tok.ptr); | 
					
						
							|  |  |  | 						goto oops; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					/* continue processing the next attr */ | 
					
						
							|  |  |  | 					client->state = HCL_CLIENT_STATE_IN_ATTR_KEY; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				clear_reply_token (client); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else if (is_spacechar(c)) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* skip white spaces after the closing quote */ | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				hcl_client_seterrbfmt (client, HCL_EINVAL, "garbage after quoted attribute value for %.*js", client->rep.last_attr_key.len, client->rep.last_attr_key.ptr); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				goto oops; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 			hcl_client_seterrbfmt (client, HCL_EINTERN, "internal error - must not be called for state %d", (int)client->state); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | oops:  | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | static int feed_reply_data (hcl_client_t* client, const hcl_bch_t* data, hcl_oow_t len, hcl_oow_t* xlen) | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	const hcl_bch_t* ptr; | 
					
						
							|  |  |  | 	const hcl_bch_t* end; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 	ptr = data; | 
					
						
							|  |  |  | 	end = ptr + len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 	while (ptr < end) | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 		if (client->state == HCL_CLIENT_STATE_IN_LENGTH_BOUNDED_DATA) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			/* the data is treated as raw octets by this client */ | 
					
						
							|  |  |  | 			hcl_oow_t capa, avail, taken; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			capa = client->rep.u.length_bounded_data.max - client->rep.u.length_bounded_data.tally; | 
					
						
							|  |  |  | 			avail = end - ptr; | 
					
						
							|  |  |  | 			taken = (avail < capa)? avail: capa; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (client->prim.feed_data) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				if (client->prim.feed_data(client, ptr, taken) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ptr += taken; | 
					
						
							| 
									
										
										
										
											2018-03-22 07:15:19 +00:00
										 |  |  | 			client->rep.u.length_bounded_data.tally += taken; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			if (taken == capa) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* read all data. no more */ | 
					
						
							| 
									
										
										
										
											2018-03-22 07:15:19 +00:00
										 |  |  | 				HCL_ASSERT (client->dummy_hcl, client->rep.u.length_bounded_data.max == client->rep.u.length_bounded_data.tally); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				client->state = HCL_CLIENT_STATE_START; | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 				if (client->prim.end_reply(client, HCL_CLIENT_END_REPLY_STATE_OK) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else if (client->state == HCL_CLIENT_STATE_IN_CHUNKED_DATA) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			/* the data is treated as raw octets by this client */ | 
					
						
							|  |  |  | 			if (client->rep.u.chunked_data.in_data_part) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				hcl_oow_t capa, avail, taken; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				capa = client->rep.u.chunked_data.max - client->rep.u.chunked_data.tally; | 
					
						
							|  |  |  | 				avail = end - ptr; | 
					
						
							|  |  |  | 				taken = (avail < capa)? avail: capa; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (client->prim.feed_data) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 					if (client->prim.feed_data(client, ptr, taken) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				ptr += taken; | 
					
						
							|  |  |  | 				client->rep.u.chunked_data.tally += taken; | 
					
						
							|  |  |  | 				client->rep.u.chunked_data.total += taken; | 
					
						
							|  |  |  | 				if (taken == capa) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					/* finished one chunk */ | 
					
						
							|  |  |  | 					client->rep.u.chunked_data.negated = 0; | 
					
						
							|  |  |  | 					client->rep.u.chunked_data.max = 0; | 
					
						
							|  |  |  | 					client->rep.u.chunked_data.tally = 0; | 
					
						
							|  |  |  | 					client->rep.u.chunked_data.clcount = 0; | 
					
						
							|  |  |  | 					client->rep.u.chunked_data.in_data_part = 0; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				while (ptr < end) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 					hcl_bchu_t bc = (hcl_bchu_t)*ptr++; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 					if (bc == '-' && client->rep.u.chunked_data.clcount == 0 && !client->rep.u.chunked_data.negated) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						client->rep.u.chunked_data.negated = 1; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					else if (bc == ':')  | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						if (client->rep.u.chunked_data.clcount == 0) | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							hcl_client_seterrbfmt (client, HCL_EINVAL, "clone without valid chunk length"); | 
					
						
							|  |  |  | 							goto oops; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if (client->rep.u.chunked_data.negated) | 
					
						
							|  |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 							if (client->prim.end_reply(client, HCL_CLIENT_END_REPLY_STATE_REVOKED) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 							client->state = HCL_CLIENT_STATE_START; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						if (client->rep.u.chunked_data.max == 0) | 
					
						
							|  |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 							if (client->prim.end_reply(client, HCL_CLIENT_END_REPLY_STATE_OK) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 							client->state = HCL_CLIENT_STATE_START; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						else | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							client->rep.u.chunked_data.in_data_part = 1; | 
					
						
							|  |  |  | 							client->rep.u.chunked_data.tally = 0; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					else if (is_digitchar(bc))  | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						client->rep.u.chunked_data.max = client->rep.u.chunked_data.max * 10 + (bc - '0'); | 
					
						
							|  |  |  | 						client->rep.u.chunked_data.clcount++; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					else | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 						hcl_client_seterrbfmt (client, HCL_EINVAL, "invalid chunk length character - [%jc]", (hcl_ooch_t)bc); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 						goto oops; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 			hcl_ooci_t c; | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			hcl_oow_t bcslen; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 		#if defined(HCL_OOCH_IS_UCH)
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			hcl_oow_t ucslen; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 			hcl_ooch_t uc; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 			int n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			bcslen = end - ptr; | 
					
						
							|  |  |  | 			ucslen = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-07 15:54:16 +00:00
										 |  |  | 			n = hcl_conv_bchars_to_uchars_with_cmgr(ptr, &bcslen, &uc, &ucslen, client->cmgr, 0); | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 			if (n <= -1) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (n == -3) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					/* incomplete sequence */ | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 					*xlen = ptr - data; | 
					
						
							|  |  |  | 					return 0; /* feed more for incomplete sequence */ | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-04-22 18:18:45 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				uc = *ptr; | 
					
						
							|  |  |  | 				bcslen = 1; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			ptr += bcslen; | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 			c = uc; | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 		#else
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			bcslen = 1; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 			c = *ptr++; | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 		#endif
 | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 			if (handle_char(client, c, bcslen) <= -1) goto oops; | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	*xlen = ptr - data; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | oops: | 
					
						
							| 
									
										
										
										
											2018-04-21 02:13:53 +00:00
										 |  |  | 	/* TODO: compute the number of processed bytes so far and return it via a parameter??? */ | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | /*printf ("feed oops....\n");*/ | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 	return -1; | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 14:54:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | /* ========================================================================= */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_prim_t* prim, hcl_errnum_t* errnum) | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	hcl_client_t* client; | 
					
						
							|  |  |  | 	hcl_t* hcl; | 
					
						
							|  |  |  | 	hcl_vmprim_t vmprim; | 
					
						
							|  |  |  | 	dummy_hcl_xtn_t* xtn; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	client = (hcl_client_t*)HCL_MMGR_ALLOC(mmgr, HCL_SIZEOF(*client) + xtnsize); | 
					
						
							|  |  |  | 	if (!client)  | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (errnum) *errnum = HCL_ESYSMEM; | 
					
						
							|  |  |  | 		return HCL_NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HCL_MEMSET (&vmprim, 0, HCL_SIZEOF(vmprim)); | 
					
						
							|  |  |  | 	vmprim.log_write = log_write_for_dummy; | 
					
						
							| 
									
										
										
										
											2018-11-03 15:57:14 +00:00
										 |  |  | 	vmprim.syserrstrb = hcl_vmprim_syserrstrb; | 
					
						
							|  |  |  | 	vmprim.assertfail = hcl_vmprim_assertfail; | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	hcl = hcl_open(mmgr, HCL_SIZEOF(*xtn), 2048, &vmprim, errnum); | 
					
						
							|  |  |  | 	if (!hcl)  | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		HCL_MMGR_FREE (mmgr, client); | 
					
						
							|  |  |  | 		return HCL_NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	xtn = (dummy_hcl_xtn_t*)hcl_getxtn(hcl); | 
					
						
							|  |  |  | 	xtn->client = client; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HCL_MEMSET (client, 0, HCL_SIZEOF(*client) + xtnsize); | 
					
						
							|  |  |  | 	client->mmgr = mmgr; | 
					
						
							|  |  |  | 	client->cmgr = hcl_get_utf8_cmgr(); | 
					
						
							|  |  |  | 	client->prim = *prim; | 
					
						
							|  |  |  | 	client->dummy_hcl = hcl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | 	client->cfg.logmask = ~(hcl_bitmask_t)0; | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* the dummy hcl is used for this client to perform primitive operations
 | 
					
						
							|  |  |  | 	 * such as getting system time or logging. so the heap size doesn't  | 
					
						
							|  |  |  | 	 * need to be changed from the tiny value set above. */ | 
					
						
							|  |  |  | 	hcl_setoption (client->dummy_hcl, HCL_LOG_MASK, &client->cfg.logmask); | 
					
						
							|  |  |  | 	hcl_setcmgr (client->dummy_hcl, client->cmgr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return client; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void hcl_client_close (hcl_client_t* client) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-04-21 02:13:53 +00:00
										 |  |  | 	if (client->rep.tok.ptr) hcl_client_freemem (client, client->rep.tok.ptr); | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 	if (client->rep.last_attr_key.ptr) hcl_client_freemem (client, client->rep.last_attr_key.ptr); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 	hcl_close (client->dummy_hcl); | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 	HCL_MMGR_FREE (client->mmgr, client); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | int hcl_client_setoption (hcl_client_t* client, hcl_client_option_t id, const void* value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (id) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		case HCL_CLIENT_TRAIT: | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | 			client->cfg.trait = *(const hcl_bitmask_t*)value; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case HCL_CLIENT_LOG_MASK: | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | 			client->cfg.logmask = *(const hcl_bitmask_t*)value; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 			if (client->dummy_hcl)  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				/* setting this affects the dummy hcl immediately.
 | 
					
						
							|  |  |  | 				 * existing hcl instances inside worker threads won't get  | 
					
						
							|  |  |  | 				 * affected. new hcl instances to be created later  | 
					
						
							|  |  |  | 				 * is supposed to use the new value */ | 
					
						
							|  |  |  | 				hcl_setoption (client->dummy_hcl, HCL_LOG_MASK, value); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hcl_client_seterrnum (client, HCL_EINVAL); | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int hcl_client_getoption (hcl_client_t* client, hcl_client_option_t id, void* value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (id) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		case HCL_CLIENT_TRAIT: | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | 			*(hcl_bitmask_t*)value = client->cfg.trait; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case HCL_CLIENT_LOG_MASK: | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | 			*(hcl_bitmask_t*)value = client->cfg.logmask; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hcl_client_seterrnum (client, HCL_EINVAL); | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void* hcl_client_getxtn (hcl_client_t* client) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (void*)(client + 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | hcl_mmgr_t* hcl_client_getmmgr (hcl_client_t* client) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return client->mmgr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | hcl_cmgr_t* hcl_client_getcmgr (hcl_client_t* client) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return client->cmgr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void hcl_client_setcmgr (hcl_client_t* client, hcl_cmgr_t* cmgr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	client->cmgr = cmgr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | hcl_errnum_t hcl_client_geterrnum (hcl_client_t* client) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return client->errnum; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const hcl_ooch_t* hcl_client_geterrstr (hcl_client_t* client) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return hcl_errnum_to_errstr(client->errnum); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const hcl_ooch_t* hcl_client_geterrmsg (hcl_client_t* client) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (client->errmsg.len <= 0) return hcl_errnum_to_errstr(client->errnum); | 
					
						
							|  |  |  | 	return client->errmsg.buf; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void hcl_client_seterrnum (hcl_client_t* client, hcl_errnum_t errnum) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/*if (client->shuterr) return; */ | 
					
						
							|  |  |  | 	client->errnum = errnum; | 
					
						
							|  |  |  | 	client->errmsg.len = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | void hcl_client_seterrbfmt (hcl_client_t* client, hcl_errnum_t errnum, const hcl_bch_t* fmt, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	va_list ap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	va_start (ap, fmt); | 
					
						
							|  |  |  | 	hcl_seterrbfmtv (client->dummy_hcl, errnum, fmt, ap); | 
					
						
							|  |  |  | 	va_end (ap); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HCL_ASSERT (client->dummy_hcl, HCL_COUNTOF(client->errmsg.buf) == HCL_COUNTOF(client->dummy_hcl->errmsg.buf)); | 
					
						
							|  |  |  | 	client->errnum = errnum; | 
					
						
							| 
									
										
										
										
											2018-04-07 15:54:16 +00:00
										 |  |  | 	hcl_copy_oochars (client->errmsg.buf, client->dummy_hcl->errmsg.buf, HCL_COUNTOF(client->errmsg.buf)); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 	client->errmsg.len = client->dummy_hcl->errmsg.len; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void hcl_client_seterrufmt (hcl_client_t* client, hcl_errnum_t errnum, const hcl_uch_t* fmt, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	va_list ap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	va_start (ap, fmt); | 
					
						
							|  |  |  | 	hcl_seterrufmtv (client->dummy_hcl, errnum, fmt, ap); | 
					
						
							|  |  |  | 	va_end (ap); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HCL_ASSERT (client->dummy_hcl, HCL_COUNTOF(client->errmsg.buf) == HCL_COUNTOF(client->dummy_hcl->errmsg.buf)); | 
					
						
							|  |  |  | 	client->errnum = errnum; | 
					
						
							| 
									
										
										
										
											2018-04-07 15:54:16 +00:00
										 |  |  | 	hcl_copy_oochars (client->errmsg.buf, client->dummy_hcl->errmsg.buf, HCL_COUNTOF(client->errmsg.buf)); | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | 	client->errmsg.len = client->dummy_hcl->errmsg.len; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ========================================================================= */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | void hcl_client_logbfmt (hcl_client_t* client, hcl_bitmask_t mask, const hcl_bch_t* fmt, ...) | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	va_list ap; | 
					
						
							|  |  |  | 	va_start (ap, fmt); | 
					
						
							|  |  |  | 	hcl_logbfmtv (client->dummy_hcl, mask, fmt, ap); | 
					
						
							|  |  |  | 	va_end (ap); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-26 04:39:20 +00:00
										 |  |  | void hcl_client_logufmt (hcl_client_t* client, hcl_bitmask_t mask, const hcl_uch_t* fmt, ...) | 
					
						
							| 
									
										
										
										
											2018-03-21 10:38:10 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	va_list ap; | 
					
						
							|  |  |  | 	va_start (ap, fmt); | 
					
						
							|  |  |  | 	hcl_logufmtv (client->dummy_hcl, mask, fmt, ap); | 
					
						
							|  |  |  | 	va_end (ap); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ========================================================================= */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | void* hcl_client_allocmem (hcl_client_t* client, hcl_oow_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void* ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ptr = HCL_MMGR_ALLOC(client->mmgr, size); | 
					
						
							|  |  |  | 	if (!ptr) hcl_client_seterrnum (client, HCL_ESYSMEM); | 
					
						
							|  |  |  | 	return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void* hcl_client_callocmem (hcl_client_t* client, hcl_oow_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void* ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ptr = HCL_MMGR_ALLOC(client->mmgr, size); | 
					
						
							|  |  |  | 	if (!ptr) hcl_client_seterrnum (client, HCL_ESYSMEM); | 
					
						
							|  |  |  | 	else HCL_MEMSET (ptr, 0, size); | 
					
						
							|  |  |  | 	return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void* hcl_client_reallocmem (hcl_client_t* client, void* ptr, hcl_oow_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ptr = HCL_MMGR_REALLOC(client->mmgr, ptr, size); | 
					
						
							|  |  |  | 	if (!ptr) hcl_client_seterrnum (client, HCL_ESYSMEM); | 
					
						
							|  |  |  | 	return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void hcl_client_freemem (hcl_client_t* client, void* ptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	HCL_MMGR_FREE (client->mmgr, ptr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ========================================================================= */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | hcl_client_state_t hcl_client_getstate (hcl_client_t* client) | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 	return client->state; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | void hcl_client_reset (hcl_client_t* client) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* TODO: reset XXXXXXXXXXXXXXXXXXXXXXXXXXXxxxxx */ | 
					
						
							|  |  |  | 	client->state = HCL_CLIENT_STATE_START; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-03-17 16:07:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | int hcl_client_feed (hcl_client_t* client, const void* ptr, hcl_oow_t len, hcl_oow_t* xlen) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	int x; | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 	hcl_oow_t total, ylen; | 
					
						
							|  |  |  | 	const hcl_bch_t* buf; | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 	buf = (const hcl_bch_t*)ptr; | 
					
						
							|  |  |  | 	total = 0; | 
					
						
							|  |  |  | 	while (total < len) | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 		x = feed_reply_data(client, &buf[total], len - total, &ylen); | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 		if (x <= -1) return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 		total += ylen; | 
					
						
							|  |  |  | 		if (x == 0) break; /* incomplete sequence encountered */ | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-18 15:29:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 15:17:46 +00:00
										 |  |  | 	*xlen = total; | 
					
						
							| 
									
										
										
										
											2018-03-20 10:36:00 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } |