diff options
| author | ꦌꦫꦶꦏ꧀ꦦꦿꦧꦮꦑꦩꦭ꧀ <erik@darapsa.co.id> | 2021-06-14 15:24:23 +0800 | 
|---|---|---|
| committer | ꦌꦫꦶꦏ꧀ꦦꦿꦧꦮꦑꦩꦭ꧀ <erik@darapsa.co.id> | 2021-06-14 15:24:23 +0800 | 
| commit | 51258871e3ad354ceebc4912548178705b5700d6 (patch) | |
| tree | 6bbdb8ff3f452ee92f1b9b3a6d40c57326d97eb3 | |
| parent | 53410fd11fbd3206c8a7c4b56be90f2401849c09 (diff) | |
Strap results handler
| -rw-r--r-- | Makefile.am | 22 | ||||
| -rw-r--r-- | client.c | 154 | ||||
| -rw-r--r-- | configure.ac | 1 | ||||
| -rw-r--r-- | icclient.h | 8 | ||||
| -rw-r--r-- | main.c | 82 | ||||
| -rw-r--r-- | request.c | 3 | ||||
| -rw-r--r-- | request.h | 16 | 
7 files changed, 192 insertions, 94 deletions
diff --git a/Makefile.am b/Makefile.am index 2929e04..f783d0d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,18 +8,28 @@ libicclient_la_SOURCES = \  			 login.c \  			 member.c \  			 admin.c -libicclient_la_CPPFLAGS = -I${prefix}/include -if WASM -libicclient_la_LDFLAGS = -static -else -libicclient_la_LDFLAGS = -lcurl -endif +libicclient_la_CPPFLAGS = -I${prefix}/include $(TIDY_CFLAGS) +libicclient_la_LDFLAGS =  $(TIDY_LIBS)  if IOS  libicclient_la_LDFLAGS += -static  endif +if WASM +libicclient_la_LDFLAGS += -static +else +libicclient_la_LDFLAGS += -lcurl +endif  include_HEADERS = icclient.h  pkginclude_HEADERS = \  		  icclient/typedefs.h \  		  icclient/ord.h \  		  icclient/member.h \  		  icclient/admin.h +bin_PROGRAMS = icclient +icclient_SOURCES = \ +		   main.c \ +		   client.c \ +		   request.c \ +		   login.c \ +		   member.c +icclient_CPPFLAGS = $(TIDY_CFLAGS) +icclient_LDFLAGS = -lcurl $(TIDY_LIBS) @@ -1,10 +1,156 @@  #include <string.h> +#include <stdbool.h> +#include <locale.h> +#include <langinfo.h> +#include <tidy.h> +#include <tidybuffio.h>  #include "request.h"  #include "icclient.h" -void icclient_init(const char *url, const char *certificate) +char *sampleurl; +static char *image_dir; +static locale_t loc = 0; + +void icclient_init(const char *url, const char *dir, const char *certificate) +{ +	size_t length = strlen(url); +	size_t append = url[length - 1] != '/'; +	sampleurl = malloc(length + append + 1); +	strcpy(sampleurl, url); +	if (append) +		strcat(sampleurl, "/"); +	image_dir = malloc(strlen(dir) + 1); +	strcpy(image_dir, dir); +	init(certificate); +} + +static void dumpNode(TidyDoc doc, TidyNode tnod, struct icclient_catalog **catalog, char **category, +		bool is_sku, bool is_category, bool is_price) +{ +	struct icclient_product *product; +	for (TidyNode child = tidyGetChild(tnod); child; child = tidyGetNext(child)) { +		ctmbstr name = tidyNodeGetName(child); +		if (name) { +			if (!strcmp(name, "html")) { +				char locale[11]; +				for (TidyAttr attr = tidyAttrFirst(child); attr; attr = tidyAttrNext(attr)) { +					if (!strcmp(tidyAttrValue(attr), "en")) +						strcpy(locale, "en_US.utf8"); +					else if (!strcmp(tidyAttrValue(attr), "id")) +						strcpy(locale, "id_ID.utf8"); +					if (!loc) +						loc = newlocale(LC_MONETARY_MASK | LC_NUMERIC_MASK, locale, 0); +				} +			} else if (!strcmp(name, "h3")) { +				is_sku = false; +				is_category = true; +				is_price = false; +			} else if (!strcmp(name, "img")) { +				static const char *subdir = "/items/"; +				char prefix[strlen(image_dir) + strlen(subdir) + 1]; +				sprintf(prefix, "%s%s", image_dir, subdir); +				size_t prefix_len = strlen(prefix); +				for (TidyAttr attr = tidyAttrFirst(child); attr; attr = tidyAttrNext(attr)) { +					if (!strcmp(tidyAttrName(attr), "src")) { +						if (strncmp(tidyAttrValue(attr), prefix, prefix_len)) +							break; +						product = malloc(sizeof(struct icclient_product)); +						memset(product, '\0', sizeof(struct icclient_product)); +						size_t len = strlen(tidyAttrValue(attr)) - prefix_len; +						product->image = malloc(len + 1); +						strncpy(product->image, tidyAttrValue(attr) + prefix_len, len + 1); +					} +					if (strcmp(tidyAttrName(attr), "title")) +						continue; +					product->description = malloc(strlen(tidyAttrValue(attr)) + 1); +					strcpy(product->description, tidyAttrValue(attr)); +					if (*category) { +						product->category = malloc(strlen(*category) + 1); +						strcpy(product->category, *category); +					} +					(*catalog)->length++; +					*catalog = realloc(*catalog, sizeof(struct icclient_catalog) +							+ sizeof(struct icclient_product *[(*catalog)->length])); +					(*catalog)->products[(*catalog)->length - 1] = product; +				} +			} else if (!strcmp(name, "h4")) { +					is_sku = true; +					is_category = false; +					is_price = false; +			} else if (is_sku && !strcmp(name, "a")) { +				is_sku = false; +				for (TidyAttr attr = tidyAttrFirst(child); attr; attr = tidyAttrNext(attr)) { +					char *sku = strrchr(tidyAttrValue(attr), '/'); +					char *session_id = strchr(sku++, '?'); +					if (session_id) +						*session_id = '\0'; +					product = (*catalog)->products[(*catalog)->length - 1]; +					product->sku = malloc(strlen(sku) + 1); +					strcpy(product->sku, sku); +				} +			} else if (!strcmp(name, "p") && !((*catalog)->products[(*catalog)->length - 1])->price) { +				is_sku = false; +				is_category = false; +				is_price = true; +			} else { +				is_sku = false; +				is_category = false; +				is_price = false; +			} +		} else if (is_category || is_price) { +			TidyBuffer buf; +			tidyBufInit(&buf); +			tidyNodeGetText(doc, child, &buf); +			char *text = (char *)buf.bp; +			product = (*catalog)->products[(*catalog)->length - 1]; +			if (is_category) { +				is_category = false; +				text[strlen(text) - 1] = '\0'; +				if (*category) +					free(*category); +				*category = malloc(strlen(text) + 1); +				strcpy(*category, text); +			} else { +				is_price = false; +#ifndef __ANDROID__ +				char *symbol = nl_langinfo_l(CRNCYSTR, loc); +				size_t symbol_len = strlen(symbol) - 1; +				if (symbol[0] == '-') +					text += symbol_len; +				char *separator = nl_langinfo_l(THOUSEP, loc); +				if (strstr(text, separator)) { +					size_t price_len = strlen(text) - symbol_len - 1; +					char price[price_len]; +					memset(price, '\0', price_len); +					strcat(price, strtok(text, separator)); +					strcat(price, strtok(NULL, separator)); +					product->price = atof(price); +				} else +					product->price = atof(text); +#endif +			} +			tidyBufFree(&buf); +		} +		dumpNode(doc, child, catalog, category, is_sku, is_category, is_price); +	} +} + +void handle_results(icclient_fetch_t *fetch)  { -	init(url, certificate); +	TidyDoc tdoc = tidyCreate(); +	tidyOptSetBool(tdoc, TidyXhtmlOut, yes); +	tidyParseString(tdoc, fetch->data); +	tidyCleanAndRepair(tdoc); +	tidyOptSetBool(tdoc, TidyForceOutput, yes); +	TidyBuffer output = {0}; +	tidyBufInit(&output); +	tidySaveBuffer(tdoc, &output); +	struct icclient_catalog *catalog = malloc(sizeof(struct icclient_catalog)); +	catalog->length = 0; +	dumpNode(tdoc, tidyGetRoot(tdoc), &catalog, &(char *){NULL}, false, false, false); +	tidyBufFree(&output); +	tidyRelease(tdoc); +	((void (*)(struct icclient_catalog *))fetch->userData)(catalog);  }  void icclient_results(const char *prod_group, void (*callback)(struct icclient_catalog *), void (*handler)(icclient_fetch_t *)) @@ -14,7 +160,7 @@ void icclient_results(const char *prod_group, void (*callback)(struct icclient_c  	char *space = NULL;  	while ((space = strchr(nonspaced, ' ')))  		*space = '-'; -	request(handler, (void *)callback, 0, "%s", nonspaced); +	request(handler ? handler : handle_results, (void *)callback, 0, "%s", nonspaced);  }  void icclient_flypage(const char *sku, void (*handler)(icclient_fetch_t *), struct icclient_product **productptr) @@ -57,6 +203,8 @@ void icclient_free_catalog(struct icclient_catalog *catalog)  void icclient_cleanup()  { +	if (loc) +		freelocale(loc);  #ifndef __EMSCRIPTEN__  	cleanup();  #endif diff --git a/configure.ac b/configure.ac index ba95804..e20dbb9 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,7 @@ AM_INIT_AUTOMAKE([-Wall -Werror foreign])  AC_PROG_CC  AM_PROG_AR  LT_INIT +PKG_CHECK_MODULES([TIDY], [tidy])  AC_CONFIG_HEADERS([config.h])  AC_CONFIG_FILES([Makefile])  AC_CHECK_HEADER_STDBOOL @@ -1,7 +1,7 @@  #ifndef ICCLIENT_H  #define ICCLIENT_H -#include <icclient/typedefs.h> +#include "icclient/typedefs.h"  #define	icclient_allproducts(callback, handler) icclient_results("All-Products", callback, handler) @@ -13,6 +13,7 @@ struct icclient_product {  	char *image;  	double price;  	char *prod_group; +	char *category;  	double weight;  	char *author;  	struct icclient_product_crosssell { @@ -32,11 +33,12 @@ extern "C" {  /*!   * \brief A function that needs to be run first. - * \param url Server root URL. + * \param sampleurl The value of the SAMPLEURL setting in products/variable.txt. + * \param image_dir The value of the IMAGE_DIR setting in products/variable.txt.   * \param certificate Path to the CA certificate file.   * \return True if the initialisation works, false otherwise.   */ -void icclient_init(const char *url, const char *certificate); +void icclient_init(const char *sampleurl, const char *image_dir, const char *certificate);  /*!   * \brief For fetching data about products that belong a specific group. @@ -2,7 +2,6 @@  #include <stdlib.h>  #include <string.h>  #include <stdbool.h> -#include <json.h>  #include "icclient.h"  #include "icclient/member.h" @@ -10,86 +9,31 @@ static void print_catalog(struct icclient_catalog *catalog)  {  	for (size_t i = 0; i < catalog->length; i++) {  		struct icclient_product *product = catalog->products[i]; -		printf("SKU: %s\n" -				"Description: %s\n" -				"Thumb: %s\n" -				"Image: %s\n" -				"Price: %f\n" -				"Product Group: %s\n", +		printf("sku: %s | " +				"desc: %s | " +				"img: %s | " +				"prc: %f | " +				"cat: %s\n",  				product->sku,  				product->description, -				product->thumb,  				product->image,  				product->price, -				product->prod_group +				product->category  		      );  	}  	icclient_free_catalog(catalog);  } - -static void handle_results(icclient_fetch_t *fetch) -{ -	json_tokener *tokener = json_tokener_new(); -	json_object *products = json_tokener_parse_ex(tokener, fetch->data, fetch->numBytes); -	json_tokener_free(tokener); -	size_t length = json_object_array_length(products); -	struct icclient_catalog *catalog = malloc(sizeof(struct icclient_catalog) + sizeof(struct icclient_product *[length])); -	catalog->length = length; -	for (size_t i = 0; i < length; i++) { -		catalog->products[i] = malloc(sizeof(struct icclient_product)); -		struct icclient_product *product = catalog->products[i]; -		memset(product, '\0', sizeof(struct icclient_product)); -		json_object *object = json_object_array_get_idx(products, i); -		struct json_object_iterator iterator = json_object_iter_begin(object); -		struct json_object_iterator iterator_end = json_object_iter_end(object); -		while (!json_object_iter_equal(&iterator, &iterator_end)) { -			const char *key = json_object_iter_peek_name(&iterator); -			json_object *val = json_object_iter_peek_value(&iterator); -			if (!strcmp(key, "price")) -				product->price = json_object_get_double(val); -			else { -				int len = json_object_get_string_len(val); -				if (len) { -					char *value = malloc(len + 1); -					strcpy(value, json_object_get_string(val)); -					if (!strcmp(key, "sku")) -						product->sku = value; -					else if (!strcmp(key, "thumb")) -						product->thumb = value; -					else if (!strcmp(key, "image")) -						product->image = value; -					else if (!strcmp(key, "description")) -						product->description = value; -					else if (!strcmp(key, "prod_group")) -						product->prod_group = value; -				} -			} -			json_object_iter_next(&iterator); -		} -	} -	((void (*)(struct icclient_catalog *))fetch->userData)(catalog); -} - +/*  static void print_user(icclient_fetch_t *fetch)  {  	printf("%s\n", fetch->data);  } - +*/  int main(int argc, char *argv[])  { -	char *url_line = NULL; -	printf("\nURL: "); -	ssize_t url_nread = getline(&url_line, &(size_t){0}, stdin); -	char *url =  malloc(--url_nread + 1); -	strncpy(url, url_line, url_nread); -	free(url_line); - -	printf("\n"); -	icclient_init(url, NULL); -	free(url); - -	icclient_allproducts(print_catalog, handle_results); - +	icclient_init("https://demo.interchangecommerce.org/i/demo", "/demo/images", NULL); +	icclient_allproducts(print_catalog, NULL); +/*  	char *name_line = NULL;  	printf("\nName: ");  	ssize_t name_nread = getline(&name_line, &(size_t){0}, stdin); @@ -108,7 +52,7 @@ int main(int argc, char *argv[])  	struct icclient_member *member = icclient_member_login(name, pass, NULL, NULL, NULL, print_user);  	free(name);  	free(pass); -	//icclient_member_logout(member); - +	icclient_member_logout(member); +*/  	icclient_cleanup();  } @@ -4,7 +4,6 @@  emscripten_fetch_attr_t attr;  #else  CURL *curl; -char *server_url;  size_t append(char *data, size_t size, size_t nmemb, icclient_fetch_t *fetch)  {  	size_t realsize = size * nmemb; @@ -16,6 +15,6 @@ size_t append(char *data, size_t size, size_t nmemb, icclient_fetch_t *fetch)  }  #endif -extern inline void init(const char *, const char *); +extern inline void init(const char *);  extern inline void request(void (*)(icclient_fetch_t *), void *, struct body *, char *, ...);  extern inline void cleanup(); @@ -25,11 +25,11 @@ struct body {  extern emscripten_fetch_attr_t attr;  #else  extern CURL *curl; -extern char *server_url; +extern char *sampleurl;  size_t append(char *, size_t, size_t, icclient_fetch_t *);  #endif -inline void init(const char *url, const char *certificate) +inline void init(const char *certificate)  {  #ifdef __EMSCRIPTEN__  	emscripten_fetch_attr_init(&attr); @@ -44,12 +44,6 @@ inline void init(const char *url, const char *certificate)  #ifdef DEBUG  	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);  #endif -	size_t length = strlen(url); -	size_t append = url[length - 1] != '/'; -	server_url = malloc(length + append + 1); -	strcpy(server_url, url); -	if (append) -		strcat(server_url, "/");  #endif  } @@ -60,7 +54,7 @@ inline void request(void (*handler)(icclient_fetch_t *), void *callback, struct  	unsigned int ival;  	size_t length =  #ifndef __EMSCRIPTEN__ -		strlen(server_url) + +		strlen(sampleurl) +  #endif  		strlen(fmt); @@ -90,7 +84,7 @@ inline void request(void (*handler)(icclient_fetch_t *), void *callback, struct  #ifdef __EMSCRIPTEN__  	memset(url, '\0', length + 1);  #else -	strcpy(url, server_url); +	strcpy(url, sampleurl);  #endif  	va_start(ap, fmt); @@ -158,7 +152,7 @@ inline void request(void (*handler)(icclient_fetch_t *), void *callback, struct  #ifndef __EMSCRIPTEN__  inline void cleanup()  { -	free(server_url); +	free(sampleurl);  	curl_easy_cleanup(curl);  	curl_global_cleanup();  }  |