searpent/searpent.c

137 lines
3.3 KiB
C

/*
* Copyright (c) 2023 Emma Tebibyte
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <curl/curl.h>
#include <jansson.h>
#define SEARX_QUERY_JSON "search?format=json&q="
typedef struct curl_read_data_t {
size_t len;
char* data;
} curl_read_data_t;
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
curl_read_data_t *data = (curl_read_data_t *)userp;
size_t old_len;
if (data->len == 0) {
data->len = nmemb;
data->data = (char *) malloc(nmemb);
memcpy(data->data, buffer, nmemb);
} else {
old_len = data->len;
data->len += nmemb;
data->data = (char *) realloc(data->data, data->len);
memcpy(data->data + old_len, buffer, nmemb);
}
return nmemb;
}
curl_read_data_t search(char *argv[], char *term) {
char *url = "https://searx.mxchange.org/";
size_t buf_size = sizeof(SEARX_QUERY_JSON) + strlen(url) + strlen(term);
char *search_url = malloc(buf_size);
char *error;
CURL *handle;
CURLcode res;
snprintf(search_url, buf_size, "%s%s%s", url, SEARX_QUERY_JSON, term);
curl_read_data_t json;
json.len = 0;
json.data = NULL;
handle = curl_easy_init();
if (handle) {
error[CURL_ERROR_SIZE];
curl_easy_setopt(handle, CURLOPT_URL, search_url);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &json);
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, error);
res = curl_easy_perform(handle);
curl_easy_cleanup(handle);
if (error != NULL) {
fprintf(stderr, "%s: %s", argv[0], error);
exit(EX_DATAERR);
}
} else {
fprintf(stderr, "%s: failed to initialize curl.\n");
}
return json;
}
json_t *parse_json(char *argv[], char* json) {
json_t *results;
json_error_t error;
json_t *json_val = json_loads(json, JSON_DECODE_ANY, &error);
if (!json_val) {
fprintf(stderr, "%s: Error parsing JSON: %s.", argv[0], error.text);
exit(EX_DATAERR);
}
results = json_object_get(json_val, "results");
if (results == NULL) {
fprintf(stderr, "%s: No results.", argv[0]);
exit(EX_DATAERR);
}
return results;
}
int print_results(json_t *results) {
size_t index;
json_t *value;
json_array_foreach(results, index, value) {
printf("%s: %s\n", index, value);
}
return EX_OK;
}
int main(int argc, char *argv[]) {
curl_read_data_t json;
json_t *results;
if (argc < 1) {
fprintf(stderr, "Usage: %s terms...", argv[0]);
return EX_USAGE;
}
for (int i = 1; i < argc; i++) {
json = search(argv, argv[i]);
results = parse_json(argv, json.data);
}
if (print_results(results) > 0) {
printf("%s: Error printing results.\n", argv[0]);
exit(1);
} else { return EX_OK; }
}