aboutsummaryrefslogtreecommitdiff
path: root/src/Infobox
diff options
context:
space:
mode:
Diffstat (limited to 'src/Infobox')
-rw-r--r--src/Infobox/Calculator.c41
-rw-r--r--src/Infobox/Dictionary.c197
-rw-r--r--src/Infobox/Dictionary.h2
-rw-r--r--src/Infobox/UnitConversion.c643
-rw-r--r--src/Infobox/Wikipedia.c155
5 files changed, 592 insertions, 446 deletions
diff --git a/src/Infobox/Calculator.c b/src/Infobox/Calculator.c
index 22563f7..16bc4fa 100644
--- a/src/Infobox/Calculator.c
+++ b/src/Infobox/Calculator.c
@@ -1,9 +1,9 @@
#include "Calculator.h"
+#include <ctype.h>
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <math.h>
-#include <ctype.h>
static char logic_log[4096];
@@ -15,7 +15,8 @@ typedef struct {
static double parse_expression(Parser *p);
static void skip_ws(Parser *p) {
- while (p->buffer[p->pos] == ' ') p->pos++;
+ while (p->buffer[p->pos] == ' ')
+ p->pos++;
}
static double parse_factor(Parser *p) {
@@ -27,7 +28,8 @@ static double parse_factor(Parser *p) {
if (p->buffer[p->pos] == '(') {
p->pos++;
double res = parse_expression(p);
- if (p->buffer[p->pos] == ')') p->pos++;
+ if (p->buffer[p->pos] == ')')
+ p->pos++;
return res;
}
char *endptr;
@@ -50,7 +52,7 @@ static double parse_term(Parser *p) {
char step[256];
snprintf(step, sizeof(step), "<div>%g %c %g = <b>%g</b></div>", old, op,
- right, left);
+ right, left);
strncat(logic_log, step, sizeof(logic_log) - strlen(logic_log) - 1);
} else
break;
@@ -72,7 +74,7 @@ static double parse_expression(Parser *p) {
char step[256];
snprintf(step, sizeof(step), "<div>%g %c %g = <b>%g</b></div>", old, op,
- right, left);
+ right, left);
strncat(logic_log, step, sizeof(logic_log) - strlen(logic_log) - 1);
} else
break;
@@ -82,33 +84,34 @@ static double parse_expression(Parser *p) {
double evaluate(const char *expr) {
logic_log[0] = '\0';
- if (!expr || strlen(expr) == 0) return 0.0;
+ if (!expr || strlen(expr) == 0)
+ return 0.0;
Parser p = {expr, 0};
return parse_expression(&p);
}
InfoBox fetch_calc_data(char *math_input) {
InfoBox info = {NULL, NULL, NULL, NULL};
- if (!math_input) return info;
+ if (!math_input)
+ return info;
double result = evaluate(math_input);
char html_output[5120];
snprintf(html_output, sizeof(html_output),
- "<div class='calc-container' style='line-height: 1.6;'>"
- "%s"
- "<div style='margin-top: 8px; border-top: 1px solid #eee; "
- "padding-top: 8px; font-size: 1.2em;'>"
- "<b>%g</b>"
- "</div>"
- "</div>",
- strlen(logic_log) > 0 ? logic_log : "<div>Constant value</div>",
- result);
+ "<div class='calc-container' style='line-height: 1.6;'>"
+ "%s"
+ "<div style='margin-top: 8px; border-top: 1px solid #eee; "
+ "padding-top: 8px; font-size: 1.2em;'>"
+ "<b>%g</b>"
+ "</div>"
+ "</div>",
+ strlen(logic_log) > 0 ? logic_log : "<div>Constant value</div>",
+ result);
info.title = strdup("Calculation");
info.extract = strdup(html_output);
- info.thumbnail_url =
- strdup("/static/calculation.svg");
+ info.thumbnail_url = strdup("/static/calculation.svg");
info.url = strdup("#");
return info;
diff --git a/src/Infobox/Dictionary.c b/src/Infobox/Dictionary.c
index 1900c21..053b0f2 100644
--- a/src/Infobox/Dictionary.c
+++ b/src/Infobox/Dictionary.c
@@ -1,6 +1,7 @@
#include "Dictionary.h"
#include "../Proxy/Proxy.h"
#include "../Scraping/Scraping.h"
+#include <ctype.h>
#include <curl/curl.h>
#include <libxml/HTMLparser.h>
#include <libxml/xpath.h>
@@ -8,42 +9,60 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include <ctype.h>
-static const char *PREFIXES[] = {
- "what is the definition of ", "what's the definition of ",
- "what is the meaning of ", "what's the meaning of ",
- "what does the word ", "definition of ", "meaning of ", "def of ",
- "define ", "definition ", "define:", "def ", "def:",
- "what does ", "what is ", "what's ", "whats ",
- "meaning ", "dictionary ", "dict ", NULL
-};
+static const char *PREFIXES[] = {"what is the definition of ",
+ "what's the definition of ",
+ "what is the meaning of ",
+ "what's the meaning of ",
+ "what does the word ",
+ "definition of ",
+ "meaning of ",
+ "def of ",
+ "define ",
+ "definition ",
+ "define:",
+ "def ",
+ "def:",
+ "what does ",
+ "what is ",
+ "what's ",
+ "whats ",
+ "meaning ",
+ "dictionary ",
+ "dict ",
+ NULL};
static const char *SUFFIXES[] = {
- " definition", " def", " meaning", " mean", " means",
- " dictionary", " dict", " define", " defined",
- " definition?", " def?", " meaning?", " mean?", " means?",
- " in english", " in english?", NULL
-};
+ " definition", " def", " meaning", " mean", " means",
+ " dictionary", " dict", " define", " defined", " definition?",
+ " def?", " meaning?", " mean?", " means?", " in english",
+ " in english?", NULL};
static const char *SKIP_WORDS[] = {"of ", "the ", "a ", "an ", NULL};
static const char *strcasestr_impl(const char *haystack, const char *needle) {
- if (!haystack || !needle || !*needle) return haystack;
+ if (!haystack || !needle || !*needle)
+ return haystack;
size_t len = strlen(needle);
for (const char *h = haystack; *h; h++) {
- if (strncasecmp(h, needle, len) == 0) return h;
+ if (strncasecmp(h, needle, len) == 0)
+ return h;
}
return NULL;
}
-struct MemStruct { char *memory; size_t size; };
+struct MemStruct {
+ char *memory;
+ size_t size;
+};
-static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
+static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
+ void *userp) {
size_t realsize = size * nmemb;
struct MemStruct *mem = (struct MemStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
- if (!ptr) return 0;
+ if (!ptr)
+ return 0;
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
@@ -53,40 +72,57 @@ static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *use
static char *xpath_text(xmlDocPtr doc, const char *xpath) {
xmlXPathContextPtr ctx = xmlXPathNewContext(doc);
- if (!ctx) return NULL;
+ if (!ctx)
+ return NULL;
xmlXPathObjectPtr obj = xmlXPathEvalExpression((const xmlChar *)xpath, ctx);
xmlXPathFreeContext(ctx);
if (!obj || !obj->nodesetval || obj->nodesetval->nodeNr == 0) {
- if (obj) xmlXPathFreeObject(obj);
+ if (obj)
+ xmlXPathFreeObject(obj);
return NULL;
}
xmlChar *content = xmlNodeGetContent(obj->nodesetval->nodeTab[0]);
char *result = content ? strdup((char *)content) : NULL;
- if (content) xmlFree(content);
+ if (content)
+ xmlFree(content);
xmlXPathFreeObject(obj);
return result;
}
-static char *build_html(const char *word, const char *pron, const char *pos,
- const char *def, const char *ex) {
+static char *build_html(const char *word, const char *pron, const char *pos,
+ const char *def, const char *ex) {
char html[4096];
- int n = snprintf(html, sizeof(html), "<div class='dict-container' style='line-height: 1.6;'>");
- if (word) n += snprintf(html + n, sizeof(html) - n,
- "<div style='font-size: 1.3em; font-weight: bold; margin-bottom: 4px;'>%s</div>", word);
- if (pron) n += snprintf(html + n, sizeof(html) - n,
- "<div style='color: #666; margin-bottom: 8px;'>/%s/</div>", pron);
- if (pos) n += snprintf(html + n, sizeof(html) - n,
- "<div style='font-style: italic; color: #888; margin-bottom: 8px;'>%s</div>", pos);
- if (def) n += snprintf(html + n, sizeof(html) - n,
- "<div style='margin-bottom: 8px;'>%s</div>", def);
- if (ex) n += snprintf(html + n, sizeof(html) - n,
- "<div style='color: #555; font-style: italic; margin-top: 8px;'>\"%s\"</div>", ex);
+ int n = snprintf(html, sizeof(html),
+ "<div class='dict-container' style='line-height: 1.6;'>");
+ if (word)
+ n += snprintf(html + n, sizeof(html) - n,
+ "<div style='font-size: 1.3em; font-weight: bold; "
+ "margin-bottom: 4px;'>%s</div>",
+ word);
+ if (pron)
+ n += snprintf(html + n, sizeof(html) - n,
+ "<div style='color: #666; margin-bottom: 8px;'>/%s/</div>",
+ pron);
+ if (pos)
+ n += snprintf(html + n, sizeof(html) - n,
+ "<div style='font-style: italic; color: #888; margin-bottom: "
+ "8px;'>%s</div>",
+ pos);
+ if (def)
+ n += snprintf(html + n, sizeof(html) - n,
+ "<div style='margin-bottom: 8px;'>%s</div>", def);
+ if (ex)
+ n += snprintf(html + n, sizeof(html) - n,
+ "<div style='color: #555; font-style: italic; margin-top: "
+ "8px;'>\"%s\"</div>",
+ ex);
snprintf(html + n, sizeof(html) - n, "</div>");
return strdup(html);
}
static char *extract_word(const char *query) {
- if (!query) return NULL;
+ if (!query)
+ return NULL;
const char *start = query;
@@ -98,9 +134,11 @@ static char *extract_word(const char *query) {
}
}
- while (*start == ' ') start++;
+ while (*start == ' ')
+ start++;
char *word = strdup(start);
- if (!word) return NULL;
+ if (!word)
+ return NULL;
int changed = 1;
while (changed) {
@@ -130,29 +168,37 @@ static char *extract_word(const char *query) {
}
size_t len = strlen(word);
- while (len > 0 && (word[len-1] == ' ' || word[len-1] == '?' ||
- word[len-1] == '!' || word[len-1] == '.')) {
+ while (len > 0 && (word[len - 1] == ' ' || word[len - 1] == '?' ||
+ word[len - 1] == '!' || word[len - 1] == '.')) {
word[--len] = '\0';
}
- if (len == 0) { free(word); return NULL; }
+ if (len == 0) {
+ free(word);
+ return NULL;
+ }
- for (size_t i = 0; i < len; i++) word[i] = tolower((unsigned char)word[i]);
+ for (size_t i = 0; i < len; i++)
+ word[i] = tolower((unsigned char)word[i]);
char *space = strchr(word, ' ');
- if (space) *space = '\0';
+ if (space)
+ *space = '\0';
return word;
}
int is_dictionary_query(const char *query) {
- if (!query) return 0;
+ if (!query)
+ return 0;
for (int i = 0; PREFIXES[i]; i++) {
size_t len = strlen(PREFIXES[i]);
if (strncasecmp(query, PREFIXES[i], len) == 0) {
const char *after = query + len;
- while (*after == ' ') after++;
- if (*after != '\0') return 1;
+ while (*after == ' ')
+ after++;
+ if (*after != '\0')
+ return 1;
}
}
@@ -160,23 +206,29 @@ int is_dictionary_query(const char *query) {
const char *pos = strcasestr_impl(query, SUFFIXES[i]);
if (pos) {
const char *after = pos + strlen(SUFFIXES[i]);
- while (*after == ' ' || *after == '?' || *after == '!' || *after == '.') after++;
- if (*after == '\0' && pos > query && (pos - query) < 100) return 1;
+ while (*after == ' ' || *after == '?' || *after == '!' || *after == '.')
+ after++;
+ if (*after == '\0' && pos > query && (pos - query) < 100)
+ return 1;
}
}
- if (strncasecmp(query, "what is ", 8) == 0 ||
- strncasecmp(query, "what's ", 7) == 0 ||
- strncasecmp(query, "whats ", 6) == 0) {
- const char *word = query + (strncasecmp(query, "what is ", 8) == 0 ? 8 :
- strncasecmp(query, "what's ", 7) == 0 ? 7 : 6);
- const char *articles[] = {"the ", "your ", "my ", "his ", "her ", "their ",
- "our ", "this ", "that ", "these ", "those ", "a ", "an ", NULL};
+ if (strncasecmp(query, "what is ", 8) == 0 ||
+ strncasecmp(query, "what's ", 7) == 0 ||
+ strncasecmp(query, "whats ", 6) == 0) {
+ const char *word = query + (strncasecmp(query, "what is ", 8) == 0 ? 8
+ : strncasecmp(query, "what's ", 7) == 0 ? 7
+ : 6);
+ const char *articles[] = {"the ", "your ", "my ", "his ", "her ",
+ "their ", "our ", "this ", "that ", "these ",
+ "those ", "a ", "an ", NULL};
for (int i = 0; articles[i]; i++) {
- if (strncasecmp(word, articles[i], strlen(articles[i])) == 0) return 0;
+ if (strncasecmp(word, articles[i], strlen(articles[i])) == 0)
+ return 0;
}
const char *space = strchr(word, ' ');
- if (!space || *(space + 1) == '\0' || *(space + 1) == '?') return 1;
+ if (!space || *(space + 1) == '\0' || *(space + 1) == '?')
+ return 1;
}
return 0;
@@ -184,10 +236,14 @@ int is_dictionary_query(const char *query) {
char *construct_dictionary_url(const char *query) {
char *word = extract_word(query);
- if (!word) return NULL;
+ if (!word)
+ return NULL;
CURL *curl = curl_easy_init();
- if (!curl) { free(word); return NULL; }
+ if (!curl) {
+ free(word);
+ return NULL;
+ }
char *escaped = curl_easy_escape(curl, word, 0);
const char *base = "https://dictionary.cambridge.org/dictionary/english/";
@@ -207,10 +263,14 @@ InfoBox fetch_dictionary_data(const char *query) {
InfoBox info = {NULL, NULL, NULL, NULL};
char *url = construct_dictionary_url(query);
- if (!url) return info;
+ if (!url)
+ return info;
CURL *curl = curl_easy_init();
- if (!curl) { free(url); return info; }
+ if (!curl) {
+ free(url);
+ return info;
+ }
struct MemStruct chunk = {malloc(1), 0};
curl_easy_setopt(curl, CURLOPT_URL, url);
@@ -222,10 +282,13 @@ InfoBox fetch_dictionary_data(const char *query) {
if (curl_easy_perform(curl) == CURLE_OK && chunk.size > 0) {
htmlDocPtr doc = htmlReadMemory(chunk.memory, chunk.size, url, NULL,
- HTML_PARSE_RECOVER | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING);
+ HTML_PARSE_RECOVER | HTML_PARSE_NOERROR |
+ HTML_PARSE_NOWARNING);
if (doc) {
char *word = xpath_text(doc, "//span[@class='hw dhw']");
- char *pron = xpath_text(doc, "//span[@class='us dpron-i']//span[@class='ipa dipa lpr-2 lpl-1']");
+ char *pron = xpath_text(
+ doc,
+ "//span[@class='us dpron-i']//span[@class='ipa dipa lpr-2 lpl-1']");
char *pos = xpath_text(doc, "//span[@class='pos dpos']");
char *def = xpath_text(doc, "(//div[@class='def ddef_d db'])[1]");
char *ex = xpath_text(doc, "(//span[@class='eg deg'])[1]");
@@ -237,7 +300,11 @@ InfoBox fetch_dictionary_data(const char *query) {
info.url = strdup(url);
}
- free(word); free(pron); free(pos); free(def); free(ex);
+ free(word);
+ free(pron);
+ free(pos);
+ free(def);
+ free(ex);
xmlFreeDoc(doc);
}
}
@@ -246,4 +313,4 @@ InfoBox fetch_dictionary_data(const char *query) {
free(chunk.memory);
free(url);
return info;
-} \ No newline at end of file
+}
diff --git a/src/Infobox/Dictionary.h b/src/Infobox/Dictionary.h
index 2f212c3..862edba 100644
--- a/src/Infobox/Dictionary.h
+++ b/src/Infobox/Dictionary.h
@@ -7,4 +7,4 @@ InfoBox fetch_dictionary_data(const char *word);
char *construct_dictionary_url(const char *word);
int is_dictionary_query(const char *query);
-#endif \ No newline at end of file
+#endif
diff --git a/src/Infobox/UnitConversion.c b/src/Infobox/UnitConversion.c
index 933dd71..4269f3c 100644
--- a/src/Infobox/UnitConversion.c
+++ b/src/Infobox/UnitConversion.c
@@ -23,49 +23,73 @@ typedef struct {
} UnitDef;
static const UnitDef UNITS[] = {
- {"metre", {"m", "metres", "meter", "meters"}, UNIT_LENGTH, 1.0},
- {"kilometre", {"km", "kilometres", "kilometer", "kilometers"}, UNIT_LENGTH, 1000.0},
- {"centimetre", {"cm", "centimetres", "centimeter", "centimeters"}, UNIT_LENGTH, 0.01},
- {"millimetre", {"mm", "millimetres", "millimeter", "millimeters"}, UNIT_LENGTH, 0.001},
- {"mile", {"mi", "miles"}, UNIT_LENGTH, 1609.344},
- {"yard", {"yd", "yards"}, UNIT_LENGTH, 0.9144},
- {"foot", {"ft", "feet", "'"}, UNIT_LENGTH, 0.3048},
- {"inch", {"in", "inches", "\""}, UNIT_LENGTH, 0.0254},
-
- {"kilogram", {"kg", "kilograms", "kilo", "kilos"}, UNIT_WEIGHT, 1.0},
- {"gram", {"g", "grams"}, UNIT_WEIGHT, 0.001},
- {"milligram", {"mg", "milligrams"}, UNIT_WEIGHT, 0.000001},
- {"pound", {"lb", "lbs", "pounds"}, UNIT_WEIGHT, 0.453592},
- {"ounce", {"oz", "ounces"}, UNIT_WEIGHT, 0.0283495},
- {"tonne", {"tonnes", "tons", "ton"}, UNIT_WEIGHT, 1000.0},
- {"stone", {"st", "stones"}, UNIT_WEIGHT, 6.35029},
-
- {"celsius", {"c", "°c", "degrees celsius", "degrees c"}, UNIT_TEMP, 1.0},
- {"fahrenheit", {"f", "°f", "degrees fahrenheit", "degrees f"}, UNIT_TEMP, 1.0},
- {"kelvin", {"k", "degrees kelvin", "degrees k"}, UNIT_TEMP, 1.0},
-
- {"litre", {"l", "litres", "liter", "liters"}, UNIT_VOLUME, 1.0},
- {"millilitre", {"ml", "millilitres", "milliliter", "milliliters"}, UNIT_VOLUME, 0.001},
- {"gallon", {"gal", "gallons"}, UNIT_VOLUME, 3.78541},
- {"quart", {"qt", "quarts"}, UNIT_VOLUME, 0.946353},
- {"pint", {"pt", "pints"}, UNIT_VOLUME, 0.473176},
- {"cup", {"cups"}, UNIT_VOLUME, 0.236588},
- {"fluid ounce", {"fl oz", "fluid ounces"}, UNIT_VOLUME, 0.0295735},
-
- {"square metre", {"sqm", "sq m", "m2", "square metres"}, UNIT_AREA, 1.0},
- {"square foot", {"sqft", "sq ft", "ft2", "square feet"}, UNIT_AREA, 0.092903},
- {"square kilometre", {"sqkm", "sq km", "km2", "square kilometres"}, UNIT_AREA, 1000000.0},
- {"square mile", {"sqmi", "sq mi", "mi2", "square miles"}, UNIT_AREA, 2589988.0},
- {"acre", {"acres"}, UNIT_AREA, 4046.86},
- {"hectare", {"ha", "hectares"}, UNIT_AREA, 10000.0},
-
- {"second", {"sec", "seconds", "s"}, UNIT_TIME, 1.0},
- {"minute", {"min", "minutes"}, UNIT_TIME, 60.0},
- {"hour", {"hr", "hours", "h"}, UNIT_TIME, 3600.0},
- {"day", {"days", "d"}, UNIT_TIME, 86400.0},
- {"week", {"weeks", "wk"}, UNIT_TIME, 604800.0},
- {"month", {"months", "mo"}, UNIT_TIME, 2629746.0},
- {"year", {"years", "yr"}, UNIT_TIME, 31556952.0},
+ {"metre", {"m", "metres", "meter", "meters"}, UNIT_LENGTH, 1.0},
+ {"kilometre",
+ {"km", "kilometres", "kilometer", "kilometers"},
+ UNIT_LENGTH,
+ 1000.0},
+ {"centimetre",
+ {"cm", "centimetres", "centimeter", "centimeters"},
+ UNIT_LENGTH,
+ 0.01},
+ {"millimetre",
+ {"mm", "millimetres", "millimeter", "millimeters"},
+ UNIT_LENGTH,
+ 0.001},
+ {"mile", {"mi", "miles"}, UNIT_LENGTH, 1609.344},
+ {"yard", {"yd", "yards"}, UNIT_LENGTH, 0.9144},
+ {"foot", {"ft", "feet", "'"}, UNIT_LENGTH, 0.3048},
+ {"inch", {"in", "inches", "\""}, UNIT_LENGTH, 0.0254},
+
+ {"kilogram", {"kg", "kilograms", "kilo", "kilos"}, UNIT_WEIGHT, 1.0},
+ {"gram", {"g", "grams"}, UNIT_WEIGHT, 0.001},
+ {"milligram", {"mg", "milligrams"}, UNIT_WEIGHT, 0.000001},
+ {"pound", {"lb", "lbs", "pounds"}, UNIT_WEIGHT, 0.453592},
+ {"ounce", {"oz", "ounces"}, UNIT_WEIGHT, 0.0283495},
+ {"tonne", {"tonnes", "tons", "ton"}, UNIT_WEIGHT, 1000.0},
+ {"stone", {"st", "stones"}, UNIT_WEIGHT, 6.35029},
+
+ {"celsius", {"c", "°c", "degrees celsius", "degrees c"}, UNIT_TEMP, 1.0},
+ {"fahrenheit",
+ {"f", "°f", "degrees fahrenheit", "degrees f"},
+ UNIT_TEMP,
+ 1.0},
+ {"kelvin", {"k", "degrees kelvin", "degrees k"}, UNIT_TEMP, 1.0},
+
+ {"litre", {"l", "litres", "liter", "liters"}, UNIT_VOLUME, 1.0},
+ {"millilitre",
+ {"ml", "millilitres", "milliliter", "milliliters"},
+ UNIT_VOLUME,
+ 0.001},
+ {"gallon", {"gal", "gallons"}, UNIT_VOLUME, 3.78541},
+ {"quart", {"qt", "quarts"}, UNIT_VOLUME, 0.946353},
+ {"pint", {"pt", "pints"}, UNIT_VOLUME, 0.473176},
+ {"cup", {"cups"}, UNIT_VOLUME, 0.236588},
+ {"fluid ounce", {"fl oz", "fluid ounces"}, UNIT_VOLUME, 0.0295735},
+
+ {"square metre", {"sqm", "sq m", "m2", "square metres"}, UNIT_AREA, 1.0},
+ {"square foot",
+ {"sqft", "sq ft", "ft2", "square feet"},
+ UNIT_AREA,
+ 0.092903},
+ {"square kilometre",
+ {"sqkm", "sq km", "km2", "square kilometres"},
+ UNIT_AREA,
+ 1000000.0},
+ {"square mile",
+ {"sqmi", "sq mi", "mi2", "square miles"},
+ UNIT_AREA,
+ 2589988.0},
+ {"acre", {"acres"}, UNIT_AREA, 4046.86},
+ {"hectare", {"ha", "hectares"}, UNIT_AREA, 10000.0},
+
+ {"second", {"sec", "seconds", "s"}, UNIT_TIME, 1.0},
+ {"minute", {"min", "minutes"}, UNIT_TIME, 60.0},
+ {"hour", {"hr", "hours", "h"}, UNIT_TIME, 3600.0},
+ {"day", {"days", "d"}, UNIT_TIME, 86400.0},
+ {"week", {"weeks", "wk"}, UNIT_TIME, 604800.0},
+ {"month", {"months", "mo"}, UNIT_TIME, 2629746.0},
+ {"year", {"years", "yr"}, UNIT_TIME, 31556952.0},
};
static const int UNIT_COUNT = sizeof(UNITS) / sizeof(UNITS[0]);
@@ -75,136 +99,142 @@ static int is_whitespace(char c) {
}
static const UnitDef *find_unit(const char *str) {
- if (!str || !*str) return NULL;
+ if (!str || !*str)
+ return NULL;
size_t len = strlen(str);
char normalized[64] = {0};
size_t j = 0;
for (size_t i = 0; i < len && j < 63; i++) {
- if ((unsigned char)str[i] == 0xC2 && (unsigned char)str[i+1] == 0xB0) {
- i++;
- continue;
- }
- if (str[i] == '^' && i + 1 < len && str[i + 1] == '2') {
- normalized[j++] = '2';
- i++;
- continue;
- }
- normalized[j++] = tolower((unsigned char)str[i]);
+ if ((unsigned char)str[i] == 0xC2 && (unsigned char)str[i + 1] == 0xB0) {
+ i++;
+ continue;
+ }
+ if (str[i] == '^' && i + 1 < len && str[i + 1] == '2') {
+ normalized[j++] = '2';
+ i++;
+ continue;
+ }
+ normalized[j++] = tolower((unsigned char)str[i]);
}
normalized[j] = '\0';
for (int i = 0; i < UNIT_COUNT; i++) {
- if (strcmp(normalized, UNITS[i].name) == 0) return &UNITS[i];
- for (int k = 0; k < 4 && UNITS[i].alias[k]; k++) {
- if (strcmp(normalized, UNITS[i].alias[k]) == 0) return &UNITS[i];
- }
+ if (strcmp(normalized, UNITS[i].name) == 0)
+ return &UNITS[i];
+ for (int k = 0; k < 4 && UNITS[i].alias[k]; k++) {
+ if (strcmp(normalized, UNITS[i].alias[k]) == 0)
+ return &UNITS[i];
+ }
}
return NULL;
}
int is_unit_conv_query(const char *query) {
- if (!query) return 0;
+ if (!query)
+ return 0;
- const char *patterns[] = {
- " to ", " in ", " into ",
- " = ", " equals ", " equal ",
- " convert ", " conversion ",
- " -> ", " → ",
- NULL
- };
+ const char *patterns[] = {" to ", " in ", " into ", " = ",
+ " equals ", " equal ", " convert ", " conversion ",
+ " -> ", " → ", NULL};
int has_pattern = 0;
for (int i = 0; patterns[i]; i++) {
- if (strstr(query, patterns[i])) {
- has_pattern = 1;
- break;
- }
+ if (strstr(query, patterns[i])) {
+ has_pattern = 1;
+ break;
+ }
}
if (!has_pattern) {
- const char *last_space = strrchr(query, ' ');
- if (last_space) {
- const UnitDef *u = find_unit(last_space + 1);
- if (u) {
- const char *before = query;
- while (*before && is_whitespace(*before)) before++;
- const char *num_end = before;
- while (*num_end &&
- (isdigit(*num_end) || *num_end == '.' || *num_end == '-' ||
- *num_end == '+' || *num_end == '/' || *num_end == '\'' || *num_end == '"')) {
- num_end++;
- }
- if (num_end > before) has_pattern = 1;
+ const char *last_space = strrchr(query, ' ');
+ if (last_space) {
+ const UnitDef *u = find_unit(last_space + 1);
+ if (u) {
+ const char *before = query;
+ while (*before && is_whitespace(*before))
+ before++;
+ const char *num_end = before;
+ while (*num_end &&
+ (isdigit(*num_end) || *num_end == '.' || *num_end == '-' ||
+ *num_end == '+' || *num_end == '/' || *num_end == '\'' ||
+ *num_end == '"')) {
+ num_end++;
+ }
+ if (num_end > before)
+ has_pattern = 1;
+ }
}
}
- }
return has_pattern;
}
static double parse_value(const char **ptr) {
const char *p = *ptr;
- while (*p && is_whitespace(*p)) p++;
+ while (*p && is_whitespace(*p))
+ p++;
double value = 0.0;
int has_num = 0;
- if (*p == '-' || *p == '+') p++;
- while (*p >= '0' && *p <= '9') {
- value = value * 10 + (*p - '0');
- has_num = 1;
- p++;
- }
- if (*p == '.') {
- p++;
- double frac = 0.1;
+ if (*p == '-' || *p == '+')
+ p++;
while (*p >= '0' && *p <= '9') {
- value += (*p - '0') * frac;
- frac *= 0.1;
+ value = value * 10 + (*p - '0');
has_num = 1;
p++;
}
+ if (*p == '.') {
+ p++;
+ double frac = 0.1;
+ while (*p >= '0' && *p <= '9') {
+ value += (*p - '0') * frac;
+ frac *= 0.1;
+ has_num = 1;
+ p++;
+ }
}
if (*p == '/' && has_num) {
- p++;
- double denom = 0.0;
- int has_denom = 0;
- while (*p >= '0' && *p <= '9') {
- denom = denom * 10 + (*p - '0');
- has_denom = 1;
p++;
- }
- if (has_denom && denom > 0) {
- value = value / denom;
- }
+ double denom = 0.0;
+ int has_denom = 0;
+ while (*p >= '0' && *p <= '9') {
+ denom = denom * 10 + (*p - '0');
+ has_denom = 1;
+ p++;
+ }
+ if (has_denom && denom > 0) {
+ value = value / denom;
+ }
}
while (*p == '\'' || *p == '"') {
- double extra = 0.0;
- p++;
- while (*p >= '0' && *p <= '9') {
- extra = extra * 10 + (*p - '0');
+ double extra = 0.0;
p++;
- }
- if (*p == '.') {
- p++;
- double frac = 0.1;
while (*p >= '0' && *p <= '9') {
- extra += (*p - '0') * frac;
- frac *= 0.1;
- p++;
+ extra = extra * 10 + (*p - '0');
+ p++;
}
- }
- if (*p == '\'' || *p == '"') p++;
- value += extra * (p[-1] == '\'' ? 0.3048 : 0.0254);
+ if (*p == '.') {
+ p++;
+ double frac = 0.1;
+ while (*p >= '0' && *p <= '9') {
+ extra += (*p - '0') * frac;
+ frac *= 0.1;
+ p++;
+ }
+ }
+ if (*p == '\'' || *p == '"')
+ p++;
+ value += extra * (p[-1] == '\'' ? 0.3048 : 0.0254);
}
if (!has_num) {
- *ptr = p;
- return 0.0;
+ *ptr = p;
+ return 0.0;
}
*ptr = p;
@@ -212,10 +242,13 @@ static double parse_value(const char **ptr) {
}
static int is_separator(char c) {
- return is_whitespace(c) || c == ',' || c == '.' || c == '(' || c == ')' || c == '\0';
+ return is_whitespace(c) || c == ',' || c == '.' || c == '(' || c == ')' ||
+ c == '\0';
}
-static int parse_conversion_query(const char *query, double *value, const UnitDef **from_unit, const UnitDef **to_unit) {
+static int parse_conversion_query(const char *query, double *value,
+ const UnitDef **from_unit,
+ const UnitDef **to_unit) {
*value = 0;
*from_unit = NULL;
*to_unit = NULL;
@@ -223,127 +256,151 @@ static int parse_conversion_query(const char *query, double *value, const UnitDe
const char *value_end = query;
*value = parse_value(&value_end);
- if (value_end == query) return 0;
+ if (value_end == query)
+ return 0;
const char *p = value_end;
- while (*p && is_whitespace(*p)) p++;
+ while (*p && is_whitespace(*p))
+ p++;
size_t remaining = strlen(p);
- if (remaining < 2) return 0;
+ if (remaining < 2)
+ return 0;
- const char *to_keywords[] = {" to ", " in ", " into ", " -> ", " → ", " = ", NULL};
+ const char *to_keywords[] = {" to ", " in ", " into ", " -> ",
+ " → ", " = ", NULL};
const char *to_pos = NULL;
size_t keyword_len = 0;
for (int i = 0; to_keywords[i]; i++) {
- const char *found = strstr(p, to_keywords[i]);
- if (found) {
- to_pos = found + strlen(to_keywords[i]);
- keyword_len = strlen(to_keywords[i]);
- break;
- }
+ const char *found = strstr(p, to_keywords[i]);
+ if (found) {
+ to_pos = found + strlen(to_keywords[i]);
+ keyword_len = strlen(to_keywords[i]);
+ break;
+ }
}
if (!to_pos) {
- const char *last_space = strrchr(p, ' ');
- if (last_space && last_space > p) {
- char from_part[64] = {0};
- size_t len = last_space - p;
- if (len < 63) {
- strncpy(from_part, p, len);
- *from_unit = find_unit(from_part);
- if (*from_unit) {
- *to_unit = find_unit(last_space + 1);
- return *to_unit ? 1 : 0;
- }
+ const char *last_space = strrchr(p, ' ');
+ if (last_space && last_space > p) {
+ char from_part[64] = {0};
+ size_t len = last_space - p;
+ if (len < 63) {
+ strncpy(from_part, p, len);
+ *from_unit = find_unit(from_part);
+ if (*from_unit) {
+ *to_unit = find_unit(last_space + 1);
+ return *to_unit ? 1 : 0;
+ }
+ }
}
- }
- return 0;
+ return 0;
}
char from_part[64] = {0};
size_t from_len = to_pos - p - keyword_len;
- if (from_len > 63) from_len = 63;
+ if (from_len > 63)
+ from_len = 63;
strncpy(from_part, p, from_len);
char *end_from = from_part + from_len;
- while (end_from > from_part && is_whitespace(end_from[-1])) end_from--;
+ while (end_from > from_part && is_whitespace(end_from[-1]))
+ end_from--;
*end_from = '\0';
*from_unit = find_unit(from_part);
if (!*from_unit) {
- char *end = from_part + strlen(from_part);
- while (end > from_part) {
- while (end > from_part && is_whitespace(end[-1])) end--;
- if (end <= from_part) break;
- char *start = end;
- while (start > from_part && !is_whitespace(start[-1])) start--;
- size_t word_len = end - start;
- memmove(from_part + word_len + 1, from_part, start - from_part);
- from_part[word_len] = ' ';
- from_part[word_len + 1] = '\0';
- *from_unit = find_unit(from_part);
- if (*from_unit) break;
- end = start;
- }
+ char *end = from_part + strlen(from_part);
+ while (end > from_part) {
+ while (end > from_part && is_whitespace(end[-1]))
+ end--;
+ if (end <= from_part)
+ break;
+ char *start = end;
+ while (start > from_part && !is_whitespace(start[-1]))
+ start--;
+ size_t word_len = end - start;
+ memmove(from_part + word_len + 1, from_part, start - from_part);
+ from_part[word_len] = ' ';
+ from_part[word_len + 1] = '\0';
+ *from_unit = find_unit(from_part);
+ if (*from_unit)
+ break;
+ end = start;
+ }
}
- if (!*from_unit) return 0;
+ if (!*from_unit)
+ return 0;
- while (*to_pos && is_whitespace(*to_pos)) to_pos++;
+ while (*to_pos && is_whitespace(*to_pos))
+ to_pos++;
- if (!*to_pos) return 0;
+ if (!*to_pos)
+ return 0;
char to_part[64] = {0};
size_t to_len = 0;
const char *tp = to_pos;
while (*tp && !is_separator(*tp) && to_len < 63) {
- to_part[to_len++] = *tp++;
+ to_part[to_len++] = *tp++;
}
to_part[to_len] = '\0';
*to_unit = find_unit(to_part);
if (!*to_unit) {
- const char *try_ptr = to_pos;
- while (*try_ptr && is_whitespace(*try_ptr)) try_ptr++;
- char try_buf[64] = {0};
- size_t try_len = 0;
- while (*try_ptr && try_len < 63) {
- try_buf[try_len++] = *try_ptr++;
- }
- while (try_len > 0) {
- *to_unit = find_unit(try_buf);
- if (*to_unit) {
- strcpy(to_part, try_buf);
- break;
+ const char *try_ptr = to_pos;
+ while (*try_ptr && is_whitespace(*try_ptr))
+ try_ptr++;
+ char try_buf[64] = {0};
+ size_t try_len = 0;
+ while (*try_ptr && try_len < 63) {
+ try_buf[try_len++] = *try_ptr++;
+ }
+ while (try_len > 0) {
+ *to_unit = find_unit(try_buf);
+ if (*to_unit) {
+ strcpy(to_part, try_buf);
+ break;
+ }
+ char *last_space = strrchr(try_buf, ' ');
+ if (!last_space)
+ break;
+ *last_space = '\0';
+ try_len = strlen(try_buf);
}
- char *last_space = strrchr(try_buf, ' ');
- if (!last_space) break;
- *last_space = '\0';
- try_len = strlen(try_buf);
- }
}
return *to_unit ? 1 : 0;
}
-static double convert_temp(double value, const UnitDef *from, const UnitDef *to) {
+static double convert_temp(double value, const UnitDef *from,
+ const UnitDef *to) {
double celsius = 0;
- if (strcmp(from->name, "celsius") == 0) celsius = value;
- else if (strcmp(from->name, "fahrenheit") == 0) celsius = (value - 32) * 5.0 / 9.0;
- else if (strcmp(from->name, "kelvin") == 0) celsius = value - 273.15;
-
- if (strcmp(to->name, "celsius") == 0) return celsius;
- else if (strcmp(to->name, "fahrenheit") == 0) return celsius * 9.0 / 5.0 + 32;
- else if (strcmp(to->name, "kelvin") == 0) return celsius + 273.15;
+ if (strcmp(from->name, "celsius") == 0)
+ celsius = value;
+ else if (strcmp(from->name, "fahrenheit") == 0)
+ celsius = (value - 32) * 5.0 / 9.0;
+ else if (strcmp(from->name, "kelvin") == 0)
+ celsius = value - 273.15;
+
+ if (strcmp(to->name, "celsius") == 0)
+ return celsius;
+ else if (strcmp(to->name, "fahrenheit") == 0)
+ return celsius * 9.0 / 5.0 + 32;
+ else if (strcmp(to->name, "kelvin") == 0)
+ return celsius + 273.15;
return 0;
}
-static double convert_value(double value, const UnitDef *from, const UnitDef *to) {
- if (from->type != to->type) return 0;
+static double convert_value(double value, const UnitDef *from,
+ const UnitDef *to) {
+ if (from->type != to->type)
+ return 0;
if (from->type == UNIT_TEMP) {
- return convert_temp(value, from, to);
+ return convert_temp(value, from, to);
}
double base_value = value * from->to_base;
@@ -351,112 +408,124 @@ static double convert_value(double value, const UnitDef *from, const UnitDef *to
}
static void format_number(double val, char *buf, size_t bufsize) {
- if (bufsize == 0) return;
+ if (bufsize == 0)
+ return;
if (val == 0) {
- snprintf(buf, bufsize, "0");
- return;
+ snprintf(buf, bufsize, "0");
+ return;
}
if (fabs(val) < 0.01 && fabs(val) > 0) {
- snprintf(buf, bufsize, "%.2g", val);
+ snprintf(buf, bufsize, "%.2g", val);
} else if (fabs(val) < 1) {
- snprintf(buf, bufsize, "%.2f", val);
- char *p = buf + strlen(buf) - 1;
- while (p > buf && *p == '0') *p-- = '\0';
- if (*p == '.') *p = '\0';
+ snprintf(buf, bufsize, "%.2f", val);
+ char *p = buf + strlen(buf) - 1;
+ while (p > buf && *p == '0')
+ *p-- = '\0';
+ if (*p == '.')
+ *p = '\0';
} else if (fmod(val + 0.0001, 1.0) < 0.0002) {
- snprintf(buf, bufsize, "%.0f", val);
+ snprintf(buf, bufsize, "%.0f", val);
} else {
- snprintf(buf, bufsize, "%.2f", val);
- char *p = buf + strlen(buf) - 1;
- while (p > buf && *p == '0') *p-- = '\0';
- if (*p == '.') *p = '\0';
+ snprintf(buf, bufsize, "%.2f", val);
+ char *p = buf + strlen(buf) - 1;
+ while (p > buf && *p == '0')
+ *p-- = '\0';
+ if (*p == '.')
+ *p = '\0';
}
}
-static const char *pluralize(const char *unit, double value, char *buf, size_t bufsize) {
+static const char *pluralize(const char *unit, double value, char *buf,
+ size_t bufsize) {
int is_one = (fabs(value - 1.0) < 0.0001 || fabs(value + 1.0) < 0.0001);
size_t len = strlen(unit);
- if (len == 0 || bufsize == 0) return unit;
+ if (len == 0 || bufsize == 0)
+ return unit;
strncpy(buf, unit, bufsize - 1);
buf[bufsize - 1] = '\0';
if (strcmp(unit, "foot") == 0 || strcmp(unit, "square foot") == 0) {
- if (is_one) strcpy(buf, unit);
- else strcpy(buf, strcmp(unit, "square foot") == 0 ? "square feet" : "feet");
- return buf;
+ if (is_one)
+ strcpy(buf, unit);
+ else
+ strcpy(buf, strcmp(unit, "square foot") == 0 ? "square feet" : "feet");
+ return buf;
}
if (strcmp(unit, "inch") == 0 || strcmp(unit, "square inch") == 0) {
- if (is_one) strcpy(buf, unit);
- else strcpy(buf, strcmp(unit, "square inch") == 0 ? "square inches" : "inches");
- return buf;
+ if (is_one)
+ strcpy(buf, unit);
+ else
+ strcpy(buf,
+ strcmp(unit, "square inch") == 0 ? "square inches" : "inches");
+ return buf;
}
if (strcmp(unit, "stone") == 0) {
- if (is_one) strcpy(buf, "stone");
- else strcpy(buf, "stones");
- return buf;
- }
- if (strcmp(unit, "celsius") == 0 ||
- strcmp(unit, "fahrenheit") == 0 ||
- strcmp(unit, "kelvin") == 0) {
- strcpy(buf, unit);
- return buf;
- }
-
- if (unit[len-1] == 's' ||
- unit[len-1] == 'x' ||
- unit[len-1] == 'z' ||
- (len >= 2 && unit[len-2] == 'c' && unit[len-1] == 'h') ||
- (len >= 2 && unit[len-2] == 's' && unit[len-1] == 'h')) {
- if (!is_one) {
- buf[len] = 'e';
- buf[len+1] = '\0';
- }
- } else if (unit[len-1] == 'y' && len >= 2 &&
- !(unit[len-2] == 'a' || unit[len-2] == 'e' ||
- unit[len-2] == 'i' || unit[len-2] == 'o' ||
- unit[len-2] == 'u')) {
- if (is_one) {
- buf[len-1] = '\0';
- } else {
- buf[len] = 's';
- buf[len+1] = '\0';
- }
- } else if (len >= 2 && unit[len-2] == 'f' && unit[len-1] == 'e') {
- if (is_one) {
- buf[len-2] = '\0';
- } else {
- buf[len-1] = 's';
- buf[len] = '\0';
- }
- } else if (unit[len-1] == 'f' && len >= 1) {
- if (is_one) {
- buf[len-1] = '\0';
- } else {
- buf[len-1] = 'v';
- buf[len] = 'e';
- buf[len+1] = 's';
- buf[len+2] = '\0';
- }
- } else if (unit[len-1] == 'e' && len >= 2 && unit[len-2] == 'f') {
- if (is_one) {
- buf[len-2] = '\0';
- } else {
- buf[len-1] = 's';
- buf[len] = '\0';
- }
+ if (is_one)
+ strcpy(buf, "stone");
+ else
+ strcpy(buf, "stones");
+ return buf;
+ }
+ if (strcmp(unit, "celsius") == 0 || strcmp(unit, "fahrenheit") == 0 ||
+ strcmp(unit, "kelvin") == 0) {
+ strcpy(buf, unit);
+ return buf;
+ }
+
+ if (unit[len - 1] == 's' || unit[len - 1] == 'x' || unit[len - 1] == 'z' ||
+ (len >= 2 && unit[len - 2] == 'c' && unit[len - 1] == 'h') ||
+ (len >= 2 && unit[len - 2] == 's' && unit[len - 1] == 'h')) {
+ if (!is_one) {
+ buf[len] = 'e';
+ buf[len + 1] = '\0';
+ }
+ } else if (unit[len - 1] == 'y' && len >= 2 &&
+ !(unit[len - 2] == 'a' || unit[len - 2] == 'e' ||
+ unit[len - 2] == 'i' || unit[len - 2] == 'o' ||
+ unit[len - 2] == 'u')) {
+ if (is_one) {
+ buf[len - 1] = '\0';
+ } else {
+ buf[len] = 's';
+ buf[len + 1] = '\0';
+ }
+ } else if (len >= 2 && unit[len - 2] == 'f' && unit[len - 1] == 'e') {
+ if (is_one) {
+ buf[len - 2] = '\0';
+ } else {
+ buf[len - 1] = 's';
+ buf[len] = '\0';
+ }
+ } else if (unit[len - 1] == 'f' && len >= 1) {
+ if (is_one) {
+ buf[len - 1] = '\0';
+ } else {
+ buf[len - 1] = 'v';
+ buf[len] = 'e';
+ buf[len + 1] = 's';
+ buf[len + 2] = '\0';
+ }
+ } else if (unit[len - 1] == 'e' && len >= 2 && unit[len - 2] == 'f') {
+ if (is_one) {
+ buf[len - 2] = '\0';
+ } else {
+ buf[len - 1] = 's';
+ buf[len] = '\0';
+ }
} else {
- if (!is_one) {
- buf[len] = 's';
- buf[len+1] = '\0';
- }
+ if (!is_one) {
+ buf[len] = 's';
+ buf[len + 1] = '\0';
+ }
}
return buf;
}
-static char *build_html(double value, const UnitDef *from, double result, const UnitDef *to) {
+static char *build_html(double value, const UnitDef *from, double result,
+ const UnitDef *to) {
static char html[4096];
char val_buf[64], res_buf[64], from_name_buf[64], to_name_buf[64];
format_number(value, val_buf, sizeof(val_buf));
@@ -466,30 +535,34 @@ static char *build_html(double value, const UnitDef *from, double result, const
pluralize(to->name, result, to_name_buf, sizeof(to_name_buf));
int n = snprintf(html, sizeof(html),
- "<div class='unit-conv-container' style='line-height: 1.6;'>"
- "<div style='font-size: 1.3em; margin-bottom: 8px;'>"
- "<b>%s %s</b> = <b>%s %s</b>"
- "</div>",
- val_buf, from_name_buf,
- res_buf, to_name_buf);
+ "<div class='unit-conv-container' style='line-height: 1.6;'>"
+ "<div style='font-size: 1.3em; margin-bottom: 8px;'>"
+ "<b>%s %s</b> = <b>%s %s</b>"
+ "</div>",
+ val_buf, from_name_buf, res_buf, to_name_buf);
snprintf(html + n, sizeof(html) - n, "</div>");
return html;
}
InfoBox fetch_unit_conv_data(const char *query) {
InfoBox info = {NULL, NULL, NULL, NULL};
- if (!query) return info;
+ if (!query)
+ return info;
double value = 0;
const UnitDef *from = NULL;
const UnitDef *to = NULL;
- if (!parse_conversion_query(query, &value, &from, &to)) return info;
- if (!from || !to) return info;
- if (from->type != to->type) return info;
+ if (!parse_conversion_query(query, &value, &from, &to))
+ return info;
+ if (!from || !to)
+ return info;
+ if (from->type != to->type)
+ return info;
double result = convert_value(value, from, to);
- if (result == 0 && value != 0 && from->type != UNIT_TEMP) return info;
+ if (result == 0 && value != 0 && from->type != UNIT_TEMP)
+ return info;
info.title = strdup("Unit Conversion");
info.extract = strdup(build_html(value, from, result, to));
diff --git a/src/Infobox/Wikipedia.c b/src/Infobox/Wikipedia.c
index 09c13c6..ffcc75b 100644
--- a/src/Infobox/Wikipedia.c
+++ b/src/Infobox/Wikipedia.c
@@ -14,41 +14,43 @@ struct WikiMemoryStruct {
};
static void shorten_summary(char **extract_ptr, int max_chars) {
- if (!extract_ptr || !*extract_ptr) return;
+ if (!extract_ptr || !*extract_ptr)
+ return;
char *text = *extract_ptr;
int len = strlen(text);
- if (len <= max_chars) return;
+ if (len <= max_chars)
+ return;
int end_pos = max_chars;
for (int i = max_chars; i > (max_chars / 2); i--) {
- if (text[i] == '.' || text[i] == '!' || text[i] == '?') {
- end_pos = i + 1;
- break;
- }
+ if (text[i] == '.' || text[i] == '!' || text[i] == '?') {
+ end_pos = i + 1;
+ break;
+ }
}
char *new_text = (char *)malloc(end_pos + 4);
if (new_text) {
- strncpy(new_text, text, end_pos);
- new_text[end_pos] = '\0';
- strcat(new_text, "...");
- free(*extract_ptr);
- *extract_ptr = new_text;
+ strncpy(new_text, text, end_pos);
+ new_text[end_pos] = '\0';
+ strcat(new_text, "...");
+ free(*extract_ptr);
+ *extract_ptr = new_text;
}
}
static size_t WikiWriteMemoryCallback(void *contents, size_t size, size_t nmemb,
- void *userp) {
+ void *userp) {
size_t realsize = size * nmemb;
struct WikiMemoryStruct *mem = (struct WikiMemoryStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if (ptr == NULL) {
- fprintf(stderr, "Not enough memory (realloc returned NULL)\n");
- return 0;
+ fprintf(stderr, "Not enough memory (realloc returned NULL)\n");
+ return 0;
}
mem->memory = ptr;
@@ -63,48 +65,49 @@ static void extract_wiki_info(xmlNode *node, InfoBox *info) {
xmlNode *cur_node = NULL;
for (cur_node = node; cur_node; cur_node = cur_node->next) {
- if (cur_node->type == XML_ELEMENT_NODE) {
- if (strcmp((const char *)cur_node->name, "page") == 0) {
- xmlChar *title = xmlGetProp(cur_node, (const xmlChar *)"title");
- if (title) {
- info->title = strdup((const char *)title);
-
- const char *base_article_url = "https://en.wikipedia.org/wiki/";
- char *formatted_title = strdup((const char *)title);
- for (int i = 0; formatted_title[i]; i++) {
- if (formatted_title[i] == ' ') formatted_title[i] = '_';
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ if (strcmp((const char *)cur_node->name, "page") == 0) {
+ xmlChar *title = xmlGetProp(cur_node, (const xmlChar *)"title");
+ if (title) {
+ info->title = strdup((const char *)title);
+
+ const char *base_article_url = "https://en.wikipedia.org/wiki/";
+ char *formatted_title = strdup((const char *)title);
+ for (int i = 0; formatted_title[i]; i++) {
+ if (formatted_title[i] == ' ')
+ formatted_title[i] = '_';
+ }
+
+ info->url =
+ malloc(strlen(base_article_url) + strlen(formatted_title) + 1);
+ if (info->url) {
+ strcpy(info->url, base_article_url);
+ strcat(info->url, formatted_title);
+ }
+ free(formatted_title);
+ xmlFree(title);
+ }
}
- info->url =
- malloc(strlen(base_article_url) + strlen(formatted_title) + 1);
- if (info->url) {
- strcpy(info->url, base_article_url);
- strcat(info->url, formatted_title);
+ if (strcmp((const char *)cur_node->name, "thumbnail") == 0) {
+ xmlChar *source = xmlGetProp(cur_node, (const xmlChar *)"source");
+ if (source) {
+ info->thumbnail_url = strdup((const char *)source);
+ xmlFree(source);
+ }
}
- free(formatted_title);
- xmlFree(title);
- }
- }
-
- if (strcmp((const char *)cur_node->name, "thumbnail") == 0) {
- xmlChar *source = xmlGetProp(cur_node, (const xmlChar *)"source");
- if (source) {
- info->thumbnail_url = strdup((const char *)source);
- xmlFree(source);
- }
- }
- if (strcmp((const char *)cur_node->name, "extract") == 0) {
- xmlChar *content = xmlNodeGetContent(cur_node);
- if (content) {
- info->extract = strdup((const char *)content);
+ if (strcmp((const char *)cur_node->name, "extract") == 0) {
+ xmlChar *content = xmlNodeGetContent(cur_node);
+ if (content) {
+ info->extract = strdup((const char *)content);
- shorten_summary(&(info->extract), 300);
- xmlFree(content);
- }
+ shorten_summary(&(info->extract), 300);
+ xmlFree(content);
+ }
+ }
}
- }
- extract_wiki_info(cur_node->children, info);
+ extract_wiki_info(cur_node->children, info);
}
}
@@ -120,27 +123,27 @@ InfoBox fetch_wiki_data(char *api_url) {
curl_handle = curl_easy_init();
if (curl_handle) {
- curl_easy_setopt(curl_handle, CURLOPT_URL, api_url);
- curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,
- WikiWriteMemoryCallback);
- curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
- curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
- apply_proxy_settings(curl_handle);
-
- res = curl_easy_perform(curl_handle);
-
- if (res == CURLE_OK) {
- xmlDocPtr doc =
- xmlReadMemory(chunk.memory, chunk.size, "noname.xml", NULL, 0);
- if (doc != NULL) {
- xmlNode *root_element = xmlDocGetRootElement(doc);
- extract_wiki_info(root_element, &info);
- xmlFreeDoc(doc);
+ curl_easy_setopt(curl_handle, CURLOPT_URL, api_url);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION,
+ WikiWriteMemoryCallback);
+ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
+ curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+ apply_proxy_settings(curl_handle);
+
+ res = curl_easy_perform(curl_handle);
+
+ if (res == CURLE_OK) {
+ xmlDocPtr doc =
+ xmlReadMemory(chunk.memory, chunk.size, "noname.xml", NULL, 0);
+ if (doc != NULL) {
+ xmlNode *root_element = xmlDocGetRootElement(doc);
+ extract_wiki_info(root_element, &info);
+ xmlFreeDoc(doc);
+ }
}
- }
- curl_easy_cleanup(curl_handle);
- free(chunk.memory);
+ curl_easy_cleanup(curl_handle);
+ free(chunk.memory);
}
return info;
@@ -148,18 +151,18 @@ InfoBox fetch_wiki_data(char *api_url) {
char *construct_wiki_url(const char *search_term) {
CURL *curl = curl_easy_init();
- if (!curl) return NULL;
+ if (!curl)
+ return NULL;
char *escaped_term = curl_easy_escape(curl, search_term, 0);
- const char *base =
- "https://en.wikipedia.org/w/"
- "api.php?action=query&prop=extracts|pageimages&exintro&"
- "explaintext&pithumbsize=400&format=xml&origin=*&titles=";
+ const char *base = "https://en.wikipedia.org/w/"
+ "api.php?action=query&prop=extracts|pageimages&exintro&"
+ "explaintext&pithumbsize=400&format=xml&origin=*&titles=";
char *full_url = malloc(strlen(base) + strlen(escaped_term) + 1);
if (full_url) {
- strcpy(full_url, base);
- strcat(full_url, escaped_term);
+ strcpy(full_url, base);
+ strcat(full_url, escaped_term);
}
curl_free(escaped_term);