diff options
Diffstat (limited to 'src/Infobox')
| -rw-r--r-- | src/Infobox/Calculator.c | 115 | ||||
| -rw-r--r-- | src/Infobox/Calculator.h | 9 | ||||
| -rw-r--r-- | src/Infobox/Infobox.c | 13 | ||||
| -rw-r--r-- | src/Infobox/Infobox.h | 13 | ||||
| -rw-r--r-- | src/Infobox/Wikipedia.c | 165 | ||||
| -rw-r--r-- | src/Infobox/Wikipedia.h | 9 |
6 files changed, 324 insertions, 0 deletions
diff --git a/src/Infobox/Calculator.c b/src/Infobox/Calculator.c new file mode 100644 index 0000000..b80ce21 --- /dev/null +++ b/src/Infobox/Calculator.c @@ -0,0 +1,115 @@ +#include "Calculator.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <ctype.h> + +static char logic_log[4096]; + +typedef struct { + const char *buffer; + int pos; +} Parser; + +static double parse_expression(Parser *p); + +static void skip_ws(Parser *p) { + while (p->buffer[p->pos] == ' ') p->pos++; +} + +static double parse_factor(Parser *p) { + skip_ws(p); + if (p->buffer[p->pos] == '-') { + p->pos++; + return -parse_factor(p); + } + if (p->buffer[p->pos] == '(') { + p->pos++; + double res = parse_expression(p); + if (p->buffer[p->pos] == ')') p->pos++; + return res; + } + char *endptr; + double val = strtod(&p->buffer[p->pos], &endptr); + p->pos = (int)(endptr - p->buffer); + return val; +} + +static double parse_term(Parser *p) { + double left = parse_factor(p); + while (1) { + skip_ws(p); + char op = p->buffer[p->pos]; + if (op == '*' || op == '/') { + p->pos++; + double right = parse_factor(p); + double old = left; + left = (op == '*') ? left * right : left / right; + + char step[256]; + + snprintf(step, sizeof(step), "<div>%g %c %g = <b>%g</b></div>", old, op, + right, left); + strncat(logic_log, step, sizeof(logic_log) - strlen(logic_log) - 1); + } else + break; + } + return left; +} + +static double parse_expression(Parser *p) { + double left = parse_term(p); + while (1) { + skip_ws(p); + char op = p->buffer[p->pos]; + if (op == '+' || op == '-') { + p->pos++; + double right = parse_term(p); + double old = left; + left = (op == '+') ? left + right : left - right; + + char step[256]; + + snprintf(step, sizeof(step), "<div>%g %c %g = <b>%g</b></div>", old, op, + right, left); + strncat(logic_log, step, sizeof(logic_log) - strlen(logic_log) - 1); + } else + break; + } + return left; +} + +double evaluate(const char *expr) { + logic_log[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; + + 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); + + info.title = strdup("Calculation"); + info.extract = strdup(html_output); + info.thumbnail_url = + strdup("/static/calculation.svg"); + info.url = strdup("#"); + + return info; +} diff --git a/src/Infobox/Calculator.h b/src/Infobox/Calculator.h new file mode 100644 index 0000000..275aed6 --- /dev/null +++ b/src/Infobox/Calculator.h @@ -0,0 +1,9 @@ +#ifndef CALCULATOR_H +#define CALCULATOR_H + +#include "Infobox.h" + +double evaluate(const char *expr); +InfoBox fetch_calc_data(char *math_input); + +#endif diff --git a/src/Infobox/Infobox.c b/src/Infobox/Infobox.c new file mode 100644 index 0000000..5043c05 --- /dev/null +++ b/src/Infobox/Infobox.c @@ -0,0 +1,13 @@ +#include "Infobox.h" +#include <stdlib.h> + +void free_infobox(InfoBox *info) { + if (info->title) + free(info->title); + if (info->thumbnail_url) + free(info->thumbnail_url); + if (info->extract) + free(info->extract); + if (info->url) + free(info->url); +} diff --git a/src/Infobox/Infobox.h b/src/Infobox/Infobox.h new file mode 100644 index 0000000..a052b80 --- /dev/null +++ b/src/Infobox/Infobox.h @@ -0,0 +1,13 @@ +#ifndef INFOBOX_H +#define INFOBOX_H + +typedef struct { + char *title; + char *thumbnail_url; + char *extract; + char *url; +} InfoBox; + +void free_infobox(InfoBox *info); + +#endif diff --git a/src/Infobox/Wikipedia.c b/src/Infobox/Wikipedia.c new file mode 100644 index 0000000..ed4645f --- /dev/null +++ b/src/Infobox/Wikipedia.c @@ -0,0 +1,165 @@ +#include "Wikipedia.h" +#include <curl/curl.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct WikiMemoryStruct { + char *memory; + size_t size; +}; + +static void shorten_summary(char **extract_ptr, int max_chars) { + if (!extract_ptr || !*extract_ptr) return; + + char *text = *extract_ptr; + int len = strlen(text); + + 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; + } + } + + 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; + } +} + +static size_t WikiWriteMemoryCallback(void *contents, size_t size, size_t nmemb, + 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; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +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] = '_'; + } + + 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); + } + } + + 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); + + shorten_summary(&(info->extract), 300); + xmlFree(content); + } + } + } + extract_wiki_info(cur_node->children, info); + } +} + +InfoBox fetch_wiki_data(char *api_url) { + CURL *curl_handle; + CURLcode res; + struct WikiMemoryStruct chunk; + InfoBox info = {NULL, NULL, NULL, NULL}; + + chunk.memory = malloc(1); + chunk.size = 0; + + 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"); + + 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); + } + + return info; +} + +char *construct_wiki_url(const char *search_term) { + CURL *curl = curl_easy_init(); + 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="; + + char *full_url = malloc(strlen(base) + strlen(escaped_term) + 1); + if (full_url) { + strcpy(full_url, base); + strcat(full_url, escaped_term); + } + + curl_free(escaped_term); + curl_easy_cleanup(curl); + return full_url; +} diff --git a/src/Infobox/Wikipedia.h b/src/Infobox/Wikipedia.h new file mode 100644 index 0000000..8a8103e --- /dev/null +++ b/src/Infobox/Wikipedia.h @@ -0,0 +1,9 @@ +#ifndef WIKIPEDIA_H +#define WIKIPEDIA_H + +#include "Infobox.h" + +InfoBox fetch_wiki_data(char *api_url); +char *construct_wiki_url(const char *search_term); + +#endif |
