summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorꦌꦫꦶꦏ꧀ꦦꦿꦧꦮꦑꦩꦭ꧀ <erik@darapsa.co.id>2021-06-14 15:24:23 +0800
committerꦌꦫꦶꦏ꧀ꦦꦿꦧꦮꦑꦩꦭ꧀ <erik@darapsa.co.id>2021-06-14 15:24:23 +0800
commit51258871e3ad354ceebc4912548178705b5700d6 (patch)
tree6bbdb8ff3f452ee92f1b9b3a6d40c57326d97eb3
parent53410fd11fbd3206c8a7c4b56be90f2401849c09 (diff)
Strap results handler
-rw-r--r--Makefile.am22
-rw-r--r--client.c154
-rw-r--r--configure.ac1
-rw-r--r--icclient.h8
-rw-r--r--main.c82
-rw-r--r--request.c3
-rw-r--r--request.h16
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)
diff --git a/client.c b/client.c
index 4d8530a..fd7dda2 100644
--- a/client.c
+++ b/client.c
@@ -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
diff --git a/icclient.h b/icclient.h
index d537263..38fdb6e 100644
--- a/icclient.h
+++ b/icclient.h
@@ -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.
diff --git a/main.c b/main.c
index 45ec093..b3e4f4f 100644
--- a/main.c
+++ b/main.c
@@ -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();
}
diff --git a/request.c b/request.c
index 835bf3a..0a5f7fd 100644
--- a/request.c
+++ b/request.c
@@ -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();
diff --git a/request.h b/request.h
index dd19400..536db0f 100644
--- a/request.h
+++ b/request.h
@@ -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();
}