From bff6e758bccececba243d05a1192cfaf8d058773 Mon Sep 17 00:00:00 2001 From: retoor <retoor@molodetz.nl> Date: Fri, 28 Mar 2025 06:56:36 +0100 Subject: [PATCH] Formatting. --- auth.h | 64 +- browse.c | 20 +- browse.h | 98 +-- chat.h | 50 +- db_utils.c | 79 +- db_utils.h | 300 +++---- http_curl.h | 156 ++-- indexer.h | 228 ++--- inplace_url.h | 61 +- line.h | 138 ++-- main.c | 529 ++++++------ markdown.h | 298 +++---- messages.h | 110 +-- openai.h | 179 ++-- plugin.h | 74 +- r.h | 36 +- rpylib.c | 113 ++- rpylib.so | Bin 80768 -> 80736 bytes tools.h | 2199 ++++++++++++++++++++++++++----------------------- url.h | 129 +-- utils.h | 104 +-- 21 files changed, 2614 insertions(+), 2351 deletions(-) diff --git a/auth.h b/auth.h index 436e9f1..d2b39f2 100644 --- a/auth.h +++ b/auth.h @@ -1,69 +1,65 @@ // Written by retoor@molodetz.nl -// This source code retrieves an API key from environment variables or defaults to a hardcoded key if none are found. +// This source code retrieves an API key from environment variables or defaults +// to a hardcoded key if none are found. -// Uses the C standard library functions from stdlib.h for environment management and stdio.h for error handling. +// Uses the C standard library functions from stdlib.h for environment +// management and stdio.h for error handling. // MIT License #ifndef R_AUTH_H #define R_AUTH_H -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> -enum AUTH_TYPE { - AUTH_TYPE_NONE, - AUTH_TYPE_API_KEY, - AUTH_TYPE_FREE -}; +enum AUTH_TYPE { AUTH_TYPE_NONE, AUTH_TYPE_API_KEY, AUTH_TYPE_FREE }; int auth_type = AUTH_TYPE_NONE; -void auth_free(){ - auth_type = AUTH_TYPE_FREE; -} +void auth_free() { auth_type = AUTH_TYPE_FREE; } void auth_init() { - - char *api_key = NULL; - if(auth_type != AUTH_TYPE_FREE) { - + + char *api_key = NULL; + if (auth_type != AUTH_TYPE_FREE) { api_key = getenv("R_KEY"); if (api_key) { - auth_type = AUTH_TYPE_API_KEY; - return; + auth_type = AUTH_TYPE_API_KEY; + return; } api_key = getenv("OPENAI_API_KEY"); if (api_key) { - auth_type = AUTH_TYPE_API_KEY; - return; + auth_type = AUTH_TYPE_API_KEY; + return; } - } - auth_type = AUTH_TYPE_FREE; - return; + } + auth_type = AUTH_TYPE_FREE; + return; } const char *resolve_api_key() { - static char *api_key = NULL; - if(auth_type != AUTH_TYPE_FREE) { - + static char *api_key = NULL; + if (auth_type != AUTH_TYPE_FREE) { + api_key = getenv("R_KEY"); if (api_key) { - auth_type = AUTH_TYPE_API_KEY; - return api_key; + auth_type = AUTH_TYPE_API_KEY; + return api_key; } api_key = getenv("OPENAI_API_KEY"); if (api_key) { - auth_type = AUTH_TYPE_API_KEY; - return api_key; + auth_type = AUTH_TYPE_API_KEY; + return api_key; } - } - auth_type = AUTH_TYPE_FREE; - api_key = "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"; - return api_key; + } + auth_type = AUTH_TYPE_FREE; + api_key = "sk-proj-d798HLfWYBeB9HT_o7isaY0s88631IaYhhOR5IVAd4D_fF-" + "SQ5z46BCr8iDi1ang1rUmlagw55T3BlbkFJ6IOsqhAxNN9Zt6ERDBnv2p2HCc2fDgc" + "5DsNhPxdOzYb009J6CNd4wILPsFGEoUdWo4QrZ1eOkA"; + return api_key; } #endif - diff --git a/browse.c b/browse.c index 49f6f10..ef942d8 100644 --- a/browse.c +++ b/browse.c @@ -1,15 +1,15 @@ #include "browse.h" int main() { - char *query = "example"; - char *result = get_news(query); - - if (result) { - printf("Result: %s\n", result); - free(result); // Free the allocated memory for the result - } else { - printf("Failed to fetch news.\n"); - } + char *query = "example"; + char *result = get_news(query); - return 0; + if (result) { + printf("Result: %s\n", result); + free(result); // Free the allocated memory for the result + } else { + printf("Failed to fetch news.\n"); + } + + return 0; } \ No newline at end of file diff --git a/browse.h b/browse.h index f4f67df..7273de1 100644 --- a/browse.h +++ b/browse.h @@ -1,63 +1,63 @@ -#include <string.h> -#include <stdio.h> -#include <stdlib.h> +#include "http_curl.h" #include <curl/curl.h> #include <json-c/json.h> #include <json-c/json_util.h> -#include "http_curl.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +char *url_encode(char *s) { return curl_easy_escape(NULL, s, 0); } -char * url_encode(char *s){ - return curl_easy_escape(NULL, s, 0); -} +char *web_search_news(char *q) { + char *news = malloc(4096); + news[0] = 0; + char *q_encoded = url_encode(q); + sprintf(news, + "https://search.molodetz.nl/search?q=%s&format=json&categories=news", + q_encoded); + free(q_encoded); + char *ret = curl_get(news); + free(news); + json_object *json_ret = json_tokener_parse(ret); -char * web_search_news(char * q){ - char * news = malloc(4096); - news[0] = 0; - char * q_encoded = url_encode(q); - sprintf(news, "https://search.molodetz.nl/search?q=%s&format=json&categories=news",q_encoded); - free(q_encoded); - char * ret = curl_get(news); - free(news); - json_object * json_ret = json_tokener_parse(ret); - - json_object * json_results = json_object_object_get(json_ret, "results"); - json_object * json_result = json_object_array_get_idx(json_results, 0); - if(!json_result){ - json_object_put(json_ret); - free(ret); - return web_search_news(q); - } + json_object *json_results = json_object_object_get(json_ret, "results"); + json_object *json_result = json_object_array_get_idx(json_results, 0); + if (!json_result) { json_object_put(json_ret); - return ret; + free(ret); + return web_search_news(q); + } + json_object_put(json_ret); + return ret; } -char * web_search(char * q){ - char * news = (char *)malloc(4096); - news[0] = 0; - char * q_encoded = url_encode(q); - sprintf(news, "https://search.molodetz.nl/search?q=%s&format=json",q_encoded); - free(q_encoded); - char * ret = curl_get(news); - free(news); - json_object * json_ret = json_tokener_parse(ret); +char *web_search(char *q) { + char *news = (char *)malloc(4096); + news[0] = 0; + char *q_encoded = url_encode(q); + sprintf(news, "https://search.molodetz.nl/search?q=%s&format=json", + q_encoded); + free(q_encoded); + char *ret = curl_get(news); + free(news); + json_object *json_ret = json_tokener_parse(ret); - json_object * json_results = json_object_object_get(json_ret, "results"); - json_object * json_result = json_object_array_get_idx(json_results, 0); - if(!json_result){ - json_object_put(json_ret); - free(ret); - return web_search(q); - } + json_object *json_results = json_object_object_get(json_ret, "results"); + json_object *json_result = json_object_array_get_idx(json_results, 0); + if (!json_result) { json_object_put(json_ret); - return ret; + free(ret); + return web_search(q); + } + json_object_put(json_ret); + return ret; } -char * web_search_engine(char * q){ - char * searx = malloc(4096); - searx[0] = 0; - sprintf(searx, "https://searx.molodetz.nl/search?q=%s&format=json", q); - char * ret = curl_get(searx); - free(searx); - return ret; +char *web_search_engine(char *q) { + char *searx = malloc(4096); + searx[0] = 0; + sprintf(searx, "https://searx.molodetz.nl/search?q=%s&format=json", q); + char *ret = curl_get(searx); + free(searx); + return ret; } diff --git a/chat.h b/chat.h index b4c169e..61ea9d1 100644 --- a/chat.h +++ b/chat.h @@ -1,8 +1,8 @@ // Written by retoor@molodetz.nl -// This code defines functionality for creating and managing JSON-based chat prompts -// using a specific AI model configuration, providing easy integration with message handling -// and HTTP communication for dynamic applications. +// This code defines functionality for creating and managing JSON-based chat +// prompts using a specific AI model configuration, providing easy integration +// with message handling and HTTP communication for dynamic applications. // Non-standard imports: json-c library for handling JSON objects. @@ -15,8 +15,8 @@ // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -26,38 +26,42 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. - #ifndef R_PROMPT_H #define R_PROMPT_H -#include "tools.h" #include "auth.h" -#include <json-c/json.h> #include "messages.h" #include "r.h" +#include "tools.h" +#include <json-c/json.h> static json_object *_prompt = NULL; void chat_free() { - if (_prompt == NULL) return; - json_object_put(_prompt); - _prompt = NULL; + if (_prompt == NULL) + return; + json_object_put(_prompt); + _prompt = NULL; } char *chat_json(const char *role, const char *message) { - chat_free(); - json_object *root_object = json_object_new_object(); - json_object_object_add(root_object, "model", json_object_new_string(get_prompt_model())); - - if (role != NULL && message != NULL) { - message_add(role, message); - json_object_object_add(root_object, "tools", tools_descriptions()); - } + chat_free(); + json_object *root_object = json_object_new_object(); + json_object_object_add(root_object, "model", + json_object_new_string(get_prompt_model())); - json_object_object_add(root_object, "messages", message_list()); -// json_object_object_add(root_object, "max_tokens", json_object_new_int(prompt_max_tokens)); - json_object_object_add(root_object, "temperature", json_object_new_double(PROMPT_TEMPERATURE)); + if (role != NULL && message != NULL) { + message_add(role, message); + json_object_object_add(root_object, "tools", tools_descriptions()); + } - return (char *)json_object_to_json_string_ext(root_object, JSON_C_TO_STRING_PRETTY); + json_object_object_add(root_object, "messages", message_list()); + // json_object_object_add(root_object, "max_tokens", + // json_object_new_int(prompt_max_tokens)); + json_object_object_add(root_object, "temperature", + json_object_new_double(PROMPT_TEMPERATURE)); + + return (char *)json_object_to_json_string_ext(root_object, + JSON_C_TO_STRING_PRETTY); } #endif diff --git a/db_utils.c b/db_utils.c index 5ea21e1..877d527 100644 --- a/db_utils.c +++ b/db_utils.c @@ -1,59 +1,60 @@ -#include <stdio.h> #include "db_utils.h" +#include <stdio.h> void db_initialize() { - sqlite3 *db; - char *err_msg = 0; - int rc = sqlite3_open("database.db", &db); + sqlite3 *db; + char *err_msg = 0; + int rc = sqlite3_open("database.db", &db); - if (rc != SQLITE_OK) { - return; - } + if (rc != SQLITE_OK) { + return; + } - const char *sql = "CREATE TABLE IF NOT EXISTS kv_store (key TEXT PRIMARY KEY, value TEXT);"; - rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + const char *sql = + "CREATE TABLE IF NOT EXISTS kv_store (key TEXT PRIMARY KEY, value TEXT);"; + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); - if (rc != SQLITE_OK) { - sqlite3_free(err_msg); - } + if (rc != SQLITE_OK) { + sqlite3_free(err_msg); + } - sqlite3_close(db); + sqlite3_close(db); } void test_db_set() { - json_object *result = db_set("test_key", "test_value"); - if (result) { - printf("db_set: %s\n", json_object_get_string(result)); - json_object_put(result); - } else { - printf("db_set failed\n"); - } + json_object *result = db_set("test_key", "test_value"); + if (result) { + printf("db_set: %s\n", json_object_get_string(result)); + json_object_put(result); + } else { + printf("db_set failed\n"); + } } void test_db_get() { - json_object *result = db_get("test_key"); - if (result) { - printf("db_get: %s\n", json_object_to_json_string(result)); - json_object_put(result); - } else { - printf("db_get failed\n"); - } + json_object *result = db_get("test_key"); + if (result) { + printf("db_get: %s\n", json_object_to_json_string(result)); + json_object_put(result); + } else { + printf("db_get failed\n"); + } } void test_db_query() { - json_object *result = db_query("SELECT * FROM kv_store"); - if (result) { - printf("db_query: %s\n", json_object_to_json_string(result)); - json_object_put(result); - } else { - printf("db_query failed\n"); - } + json_object *result = db_query("SELECT * FROM kv_store"); + if (result) { + printf("db_query: %s\n", json_object_to_json_string(result)); + json_object_put(result); + } else { + printf("db_query failed\n"); + } } int main() { - db_initialize(); - test_db_set(); - test_db_get(); - test_db_query(); - return 0; + db_initialize(); + test_db_set(); + test_db_get(); + test_db_query(); + return 0; } \ No newline at end of file diff --git a/db_utils.h b/db_utils.h index b3be522..0f64095 100644 --- a/db_utils.h +++ b/db_utils.h @@ -2,178 +2,190 @@ #define DB_UTILS_H #include "r.h" -#include <sqlite3.h> -#include <json-c/json.h> #include "utils.h" +#include <json-c/json.h> +#include <sqlite3.h> +json_object *db_execute(const char *query); - - -json_object* db_execute(const char *query); - -char * db_file_expanded(){ - char * expanded = expand_home_directory(DB_FILE); - static char result[4096]; - result[0] = 0; - strcpy(result, expanded); - free(expanded); - return result; +char *db_file_expanded() { + char *expanded = expand_home_directory(DB_FILE); + static char result[4096]; + result[0] = 0; + strcpy(result, expanded); + free(expanded); + return result; } void db_initialize(); -json_object * db_set(const char *key, const char *value); -json_object* db_get(const char *key); -json_object* db_query(const char *query); - +json_object *db_set(const char *key, const char *value); +json_object *db_get(const char *key); +json_object *db_query(const char *query); void db_initialize() { - sqlite3 *db; - char *err_msg = 0; - int rc = sqlite3_open(db_file_expanded(), &db); + sqlite3 *db; + char *err_msg = 0; + int rc = sqlite3_open(db_file_expanded(), &db); - if (rc != SQLITE_OK) { - return; - } + if (rc != SQLITE_OK) { + return; + } - const char *sql = "CREATE TABLE IF NOT EXISTS kv_store (key TEXT PRIMARY KEY, value TEXT);"; - rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + const char *sql = + "CREATE TABLE IF NOT EXISTS kv_store (key TEXT PRIMARY KEY, value TEXT);"; + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); - if (rc != SQLITE_OK) { - sqlite3_free(err_msg); - } + if (rc != SQLITE_OK) { + sqlite3_free(err_msg); + } - sqlite3_close(db); + sqlite3_close(db); } +json_object *db_set(const char *key, const char *value) { + sqlite3 *db; + char *err_msg = 0; + int rc = sqlite3_open(db_file_expanded(), &db); -json_object * db_set(const char *key, const char *value) { - sqlite3 *db; - char *err_msg = 0; - int rc = sqlite3_open(db_file_expanded(), &db); + if (rc != SQLITE_OK) { + return NULL; + } - if (rc != SQLITE_OK) { - return NULL; - } - - char *sql = sqlite3_mprintf("INSERT INTO kv_store (key, value) VALUES (%Q, %Q) ON CONFLICT(key) DO UPDATE SET value = %Q WHERE key = %Q", key, value, value,key); - rc = sqlite3_exec(db, sql, 0, 0, &err_msg); - sqlite3_free(sql); - - if (rc != SQLITE_OK) { - sqlite3_free(err_msg); - sqlite3_close(db); - return NULL; - } + char *sql = + sqlite3_mprintf("INSERT INTO kv_store (key, value) VALUES (%Q, %Q) ON " + "CONFLICT(key) DO UPDATE SET value = %Q WHERE key = %Q", + key, value, value, key); + rc = sqlite3_exec(db, sql, 0, 0, &err_msg); + sqlite3_free(sql); + if (rc != SQLITE_OK) { + sqlite3_free(err_msg); sqlite3_close(db); - return json_object_new_string("Success"); + return NULL; + } + + sqlite3_close(db); + return json_object_new_string("Success"); } -json_object* db_get(const char *key) { - sqlite3 *db; - sqlite3_stmt *stmt; - json_object *result = json_object_new_object(); - const char *value = NULL; +json_object *db_get(const char *key) { + sqlite3 *db; + sqlite3_stmt *stmt; + json_object *result = json_object_new_object(); + const char *value = NULL; - int rc = sqlite3_open(db_file_expanded(), &db); - if (rc != SQLITE_OK) { - return NULL; + int rc = sqlite3_open(db_file_expanded(), &db); + if (rc != SQLITE_OK) { + return NULL; + } + + const char *sql = "SELECT value FROM kv_store WHERE key = ?"; + sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC); + + if (sqlite3_step(stmt) == SQLITE_ROW) { + value = (const char *)sqlite3_column_text(stmt, 0); + } + + if (value) { + json_object_object_add(result, "value", json_object_new_string(value)); + } else { + json_object_object_add(result, "error", + json_object_new_string("Key not found")); + } + + sqlite3_finalize(stmt); + sqlite3_close(db); + return result; +} +json_object *db_query(const char *query) { + sqlite3 *db; + sqlite3_stmt *stmt; + + if (strncmp(query, "SELECT", 6)) { + return db_execute(query); + } + + json_object *result = json_object_new_array(); + + int rc = sqlite3_open(db_file_expanded(), &db); + if (rc != SQLITE_OK) { + return NULL; + } + + sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + while (sqlite3_step(stmt) == SQLITE_ROW) { + json_object *row = json_object_new_object(); + for (int i = 0; i < sqlite3_column_count(stmt); i++) { + const char *col_name = sqlite3_column_name(stmt, i); + switch (sqlite3_column_type(stmt, i)) { + case SQLITE_INTEGER: + json_object_object_add( + row, col_name, + json_object_new_int64(sqlite3_column_int64(stmt, i))); + break; + case SQLITE_FLOAT: + json_object_object_add( + row, col_name, + json_object_new_double(sqlite3_column_double(stmt, i))); + break; + case SQLITE_TEXT: + json_object_object_add( + row, col_name, + json_object_new_string((const char *)sqlite3_column_text(stmt, i))); + break; + case SQLITE_BLOB: + json_object_object_add(row, col_name, + json_object_new_string_len( + (const char *)sqlite3_column_blob(stmt, i), + sqlite3_column_bytes(stmt, i))); + break; + case SQLITE_NULL: + default: + json_object_object_add(row, col_name, json_object_new_string("NULL")); + break; + } } + json_object_array_add(result, row); + } - const char *sql = "SELECT value FROM kv_store WHERE key = ?"; - sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); - sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC); + sqlite3_finalize(stmt); + sqlite3_close(db); - if (sqlite3_step(stmt) == SQLITE_ROW) { - value = (const char *)sqlite3_column_text(stmt, 0); - } + return result; +} - if (value) { - json_object_object_add(result, "value", json_object_new_string(value)); - } else { - json_object_object_add(result, "error", json_object_new_string("Key not found")); - } +json_object *db_execute(const char *query) { + sqlite3 *db; + char *err_msg = 0; + int rc = sqlite3_open(db_file_expanded(), &db); + json_object *result = json_object_new_object(); - sqlite3_finalize(stmt); - sqlite3_close(db); + if (rc != SQLITE_OK) { + json_object_object_add(result, "error", + json_object_new_string("Cannot open database")); return result; + } + + rc = sqlite3_exec(db, query, 0, 0, &err_msg); + if (rc != SQLITE_OK) { + json_object_object_add(result, "error", json_object_new_string(err_msg)); + sqlite3_free(err_msg); + } else { + json_object_object_add( + result, "success", + json_object_new_string("Query executed successfully")); + } + + sqlite3_close(db); + return result; } -json_object* db_query(const char *query) { - sqlite3 *db; - sqlite3_stmt *stmt; - - if(strncmp(query, "SELECT", 6)){ - return db_execute(query); - } - - json_object *result = json_object_new_array(); - - int rc = sqlite3_open(db_file_expanded(), &db); - if (rc != SQLITE_OK) { - return NULL; - } - - sqlite3_prepare_v2(db, query, -1, &stmt, NULL); - while (sqlite3_step(stmt) == SQLITE_ROW) { - json_object *row = json_object_new_object(); - for (int i = 0; i < sqlite3_column_count(stmt); i++) { - const char *col_name = sqlite3_column_name(stmt, i); - switch (sqlite3_column_type(stmt, i)) { - case SQLITE_INTEGER: - json_object_object_add(row, col_name, json_object_new_int64(sqlite3_column_int64(stmt, i))); - break; - case SQLITE_FLOAT: - json_object_object_add(row, col_name, json_object_new_double(sqlite3_column_double(stmt, i))); - break; - case SQLITE_TEXT: - json_object_object_add(row, col_name, json_object_new_string((const char *)sqlite3_column_text(stmt, i))); - break; - case SQLITE_BLOB: - json_object_object_add(row, col_name, json_object_new_string_len((const char *)sqlite3_column_blob(stmt, i), sqlite3_column_bytes(stmt, i))); - break; - case SQLITE_NULL: - default: - json_object_object_add(row, col_name, json_object_new_string("NULL")); - break; - } - } - json_object_array_add(result, row); - } - - sqlite3_finalize(stmt); - sqlite3_close(db); - - return result; -} - - -json_object* db_execute(const char *query) { - sqlite3 *db; - char *err_msg = 0; - int rc = sqlite3_open(db_file_expanded(), &db); - json_object *result = json_object_new_object(); - - if (rc != SQLITE_OK) { - json_object_object_add(result, "error", json_object_new_string("Cannot open database")); - return result; - } - - rc = sqlite3_exec(db, query, 0, 0, &err_msg); - if (rc != SQLITE_OK) { - json_object_object_add(result, "error", json_object_new_string(err_msg)); - sqlite3_free(err_msg); - } else { - json_object_object_add(result, "success", json_object_new_string("Query executed successfully")); - } - - sqlite3_close(db); - return result; -} -char * db_get_schema(){ - json_object * tables =db_query("SELECT * FROM sqlite_master WHERE type='table'"); - char * result = strdup(json_object_get_string(tables)); - json_object_put(tables); - return result; +char *db_get_schema() { + json_object *tables = + db_query("SELECT * FROM sqlite_master WHERE type='table'"); + char *result = strdup(json_object_get_string(tables)); + json_object_put(tables); + return result; } #endif diff --git a/http_curl.h b/http_curl.h index 09dbfd8..eb9c5c3 100644 --- a/http_curl.h +++ b/http_curl.h @@ -1,8 +1,12 @@ // Written by retoor@molodetz.nl -// This code defines a simple HTTP client using libcurl in C. It provides functions for executing POST and GET HTTP requests with JSON data, including authorization via a bearer token. The functions `curl_post` and `curl_get` handle these operations and return the server's response as a string. +// This code defines a simple HTTP client using libcurl in C. It provides +// functions for executing POST and GET HTTP requests with JSON data, including +// authorization via a bearer token. The functions `curl_post` and `curl_get` +// handle these operations and return the server's response as a string. -// Uses libcurl for HTTP requests and includes a custom "auth.h" for API key resolution. +// Uses libcurl for HTTP requests and includes a custom "auth.h" for API key +// resolution. // MIT License // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -11,101 +15,103 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: the above copyright -// notice and this permission notice shall be included in all copies or substantial -// portions of the Software. The Software is provided "as is", without warranty of -// any kind, express or implied, including but not limited to the warranties of -// merchantability, fitness for a particular purpose and noninfringement. In no -// event shall the authors or copyright holders be liable for any claim, damages -// or other liability, whether in an action of contract, tort or otherwise, arising -// from, out of or in connection with the software or the use or other dealings in -// the Software. - +// notice and this permission notice shall be included in all copies or +// substantial portions of the Software. The Software is provided "as is", +// without warranty of any kind, express or implied, including but not limited +// to the warranties of merchantability, fitness for a particular purpose and +// noninfringement. In no event shall the authors or copyright holders be liable +// for any claim, damages or other liability, whether in an action of contract, +// tort or otherwise, arising from, out of or in connection with the software or +// the use or other dealings in the Software. #ifndef HTTP_CURL #define HTTP_CURL +#include "auth.h" +#include <curl/curl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <curl/curl.h> -#include "auth.h" struct ResponseBuffer { - char *data; - size_t size; + char *data; + size_t size; }; -static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { - size_t total_size = size * nmemb; - struct ResponseBuffer *response = (struct ResponseBuffer *)userp; - char *ptr = realloc(response->data, response->size + total_size + 1); - if (ptr == NULL) { - fprintf(stderr, "Failed to allocate memory for response\n"); - return 0; - } - response->data = ptr; - memcpy(&(response->data[response->size]), contents, total_size); - response->size += total_size; - response->data[response->size] = '\0'; - return total_size; +static size_t WriteCallback(void *contents, size_t size, size_t nmemb, + void *userp) { + size_t total_size = size * nmemb; + struct ResponseBuffer *response = (struct ResponseBuffer *)userp; + char *ptr = realloc(response->data, response->size + total_size + 1); + if (ptr == NULL) { + fprintf(stderr, "Failed to allocate memory for response\n"); + return 0; + } + response->data = ptr; + memcpy(&(response->data[response->size]), contents, total_size); + response->size += total_size; + response->data[response->size] = '\0'; + return total_size; } char *curl_post(const char *url, const char *data) { - CURL *curl; - CURLcode res; - struct ResponseBuffer response = {malloc(1), 0}; + CURL *curl; + CURLcode res; + struct ResponseBuffer response = {malloc(1), 0}; - if (!response.data) return NULL; - - curl = curl_easy_init(); - if (curl) { - struct curl_slist *headers = NULL; - curl_easy_setopt(curl, CURLOPT_URL, url); - headers = curl_slist_append(headers, "Content-Type: application/json"); - char bearer_header[1337]; - sprintf(bearer_header, "Authorization: Bearer %s", resolve_api_key()); - headers = curl_slist_append(headers, bearer_header); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); - res = curl_easy_perform(curl); - if (res != CURLE_OK) { - fprintf(stderr, "An error occurred: %s\n", curl_easy_strerror(res)); - } - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - return response.data; - } + if (!response.data) return NULL; + + curl = curl_easy_init(); + if (curl) { + struct curl_slist *headers = NULL; + curl_easy_setopt(curl, CURLOPT_URL, url); + headers = curl_slist_append(headers, "Content-Type: application/json"); + char bearer_header[1337]; + sprintf(bearer_header, "Authorization: Bearer %s", resolve_api_key()); + headers = curl_slist_append(headers, bearer_header); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "An error occurred: %s\n", curl_easy_strerror(res)); + } + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + return response.data; + } + return NULL; } char *curl_get(const char *url) { - CURL *curl; - CURLcode res; - struct ResponseBuffer response = {malloc(1), 0}; + CURL *curl; + CURLcode res; + struct ResponseBuffer response = {malloc(1), 0}; - if (!response.data) return NULL; + if (!response.data) + return NULL; - curl = curl_easy_init(); - if (curl) { - struct curl_slist *headers = NULL; - curl_easy_setopt(curl, CURLOPT_URL, url); - headers = curl_slist_append(headers, "Content-Type: application/json"); - char bearer_header[1337]; - sprintf(bearer_header, "Authorization: Bearer %s", resolve_api_key()); - headers = curl_slist_append(headers, bearer_header); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); - res = curl_easy_perform(curl); - if (res != CURLE_OK) { - fprintf(stderr, "An error occurred: %s\n", curl_easy_strerror(res)); - } - curl_slist_free_all(headers); - curl_easy_cleanup(curl); + curl = curl_easy_init(); + if (curl) { + struct curl_slist *headers = NULL; + curl_easy_setopt(curl, CURLOPT_URL, url); + headers = curl_slist_append(headers, "Content-Type: application/json"); + char bearer_header[1337]; + sprintf(bearer_header, "Authorization: Bearer %s", resolve_api_key()); + headers = curl_slist_append(headers, bearer_header); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "An error occurred: %s\n", curl_easy_strerror(res)); } - return response.data; + curl_slist_free_all(headers); + curl_easy_cleanup(curl); + } + return response.data; } #endif \ No newline at end of file diff --git a/indexer.h b/indexer.h index c167080..710ec4e 100644 --- a/indexer.h +++ b/indexer.h @@ -1,133 +1,157 @@ +#include <dirent.h> +#include <json-c/json.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <dirent.h> #include <sys/stat.h> #include <time.h> -#include <json-c/json.h> -#include <limits.h> #include <unistd.h> #define MAX_FILES 20000 #define MAX_PATH 4096 -static const char *extensions[] = {".c", ".cpp", ".h", ".py", ".java", ".js", ".mk", ".html", "Makefile", ".css", ".json", ".cs", ".csproj", ".sln", ".toml",".rs"}; -static size_t ext_count = sizeof(extensions) / sizeof(extensions[0]); // Updated count to reflect the new number of extensions - - +static const char *extensions[] = { + ".c", ".cpp", ".h", ".py", ".java", ".js", ".mk", ".html", + "Makefile", ".css", ".json", ".cs", ".csproj", ".sln", ".toml", ".rs"}; +static size_t ext_count = + sizeof(extensions) / + sizeof( + extensions[0]); // Updated count to reflect the new number of extensions typedef struct { - char name[MAX_PATH]; - char modification_date[20]; - char creation_date[20]; - char type[10]; - size_t size_bytes; + char name[MAX_PATH]; + char modification_date[20]; + char creation_date[20]; + char type[10]; + size_t size_bytes; } FileInfo; FileInfo file_list[MAX_FILES]; size_t file_count = 0; -int is_valid_extension(const char *filename, const char *extensions[], size_t ext_count) { - const char *dot = strrchr(filename, '.'); - if(!dot){ - dot = filename; -} - for (size_t i = 0; i < ext_count; i++) { - if (strcmp(dot, extensions[i]) == 0) { - return 1; - } +int is_valid_extension(const char *filename, const char *extensions[], + size_t ext_count) { + const char *dot = strrchr(filename, '.'); + if (!dot) { + dot = filename; + } + for (size_t i = 0; i < ext_count; i++) { + if (strcmp(dot, extensions[i]) == 0) { + return 1; } - return 0; + } + return 0; } int is_ignored_directory(const char *dir_name) { - const char *ignored_dirs[] = {"env", ".venv", "node_modules", "venv", "virtualenv"}; - for (size_t i = 0; i < sizeof(ignored_dirs) / sizeof(ignored_dirs[0]); i++) { - if (strcmp(dir_name, ignored_dirs[i]) == 0) { - return 1; - } + const char *ignored_dirs[] = {"env", ".venv", "node_modules", "venv", + "virtualenv"}; + for (size_t i = 0; i < sizeof(ignored_dirs) / sizeof(ignored_dirs[0]); i++) { + if (strcmp(dir_name, ignored_dirs[i]) == 0) { + return 1; } - return 0; + } + return 0; } void get_file_info(const char *path) { - struct stat file_stat; - if (stat(path, &file_stat) == 0) { - FileInfo info; - strncpy(info.name, path, MAX_PATH - 1); // Copy with one less to leave space for null terminator - info.name[MAX_PATH - 1] = '\0'; // Ensure null termination - strftime(info.modification_date, sizeof(info.modification_date), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime)); - strftime(info.creation_date, sizeof(info.creation_date), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_ctime)); - strncpy(info.type, S_ISDIR(file_stat.st_mode) ? "directory" : "file", 10); - info.type[9] = '\0'; // Ensure null termination - info.size_bytes = file_stat.st_size; - file_list[file_count++] = info; - } + struct stat file_stat; + if (stat(path, &file_stat) == 0) { + FileInfo info; + strncpy(info.name, path, + MAX_PATH - + 1); // Copy with one less to leave space for null terminator + info.name[MAX_PATH - 1] = '\0'; // Ensure null termination + strftime(info.modification_date, sizeof(info.modification_date), + "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime)); + strftime(info.creation_date, sizeof(info.creation_date), + "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_ctime)); + strncpy(info.type, S_ISDIR(file_stat.st_mode) ? "directory" : "file", 10); + info.type[9] = '\0'; // Ensure null termination + info.size_bytes = file_stat.st_size; + file_list[file_count++] = info; + } } -char* index_directory(const char *dir_path) { - DIR *dir = opendir(dir_path); - struct dirent *entry; - if (dir == NULL) { - perror("Failed to open directory"); - return NULL; - } +char *index_directory(const char *dir_path) { + DIR *dir = opendir(dir_path); + struct dirent *entry; + if (dir == NULL) { + perror("Failed to open directory"); + return NULL; + } - json_object *jarray = json_object_new_array(); - - while ((entry = readdir(dir)) != NULL) { - if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - if (entry->d_name[0] == '.' || is_ignored_directory(entry->d_name)) { - continue; - } - char full_path[MAX_PATH]; - snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name); - if (entry->d_type == DT_DIR) { - char *subdir_json = index_directory(full_path); - if (subdir_json) { - json_object *jsubdir = json_object_new_string(subdir_json); - json_object_array_add(jarray, jsubdir); - free(subdir_json); - } - } else if (is_valid_extension(entry->d_name, extensions, ext_count)) { - get_file_info(full_path); - json_object *jfile = json_object_new_object(); - json_object_object_add(jfile, "file_name", json_object_new_string(file_list[file_count - 1].name)); - json_object_object_add(jfile, "modification_date", json_object_new_string(file_list[file_count - 1].modification_date)); - json_object_object_add(jfile, "creation_date", json_object_new_string(file_list[file_count - 1].creation_date)); - json_object_object_add(jfile, "type", json_object_new_string(file_list[file_count - 1].type)); - json_object_object_add(jfile, "size_bytes", json_object_new_int64(file_list[file_count - 1].size_bytes)); + json_object *jarray = json_object_new_array(); - // Read the file contents - FILE *fp = fopen(file_list[file_count - 1].name, "r"); - if (fp != NULL) { - fseek(fp, 0, SEEK_END); - long length = ftell(fp); - fseek(fp, 0, SEEK_SET); - char *content = malloc(length + 1); - if (content) { - size_t bytesRead = fread(content, 1, length, fp); - if (bytesRead != length) { - free(content); - content = NULL; - json_object_object_add(jfile, "file_current_content_data", json_object_new_string("Error reading file")); - } else { - content[length] = '\0'; // Null-terminate the string - //json_object_object_add(jfile, "file_current_content_data", json_object_new_string(content)); - } - free(content); - } - fclose(fp); - } else { - //json_object_object_add(jfile, "content", json_object_new_string("Unable to read file")); - } - - json_object_array_add(jarray, jfile); - } + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { + if (entry->d_name[0] == '.' || is_ignored_directory(entry->d_name)) { + continue; + } + char full_path[MAX_PATH]; + snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name); + if (entry->d_type == DT_DIR) { + char *subdir_json = index_directory(full_path); + if (subdir_json) { + json_object *jsubdir = json_object_new_string(subdir_json); + json_object_array_add(jarray, jsubdir); + free(subdir_json); } - } - closedir(dir); + } else if (is_valid_extension(entry->d_name, extensions, ext_count)) { + get_file_info(full_path); + json_object *jfile = json_object_new_object(); + json_object_object_add( + jfile, "file_name", + json_object_new_string(file_list[file_count - 1].name)); + json_object_object_add( + jfile, "modification_date", + json_object_new_string( + file_list[file_count - 1].modification_date)); + json_object_object_add( + jfile, "creation_date", + json_object_new_string(file_list[file_count - 1].creation_date)); + json_object_object_add( + jfile, "type", + json_object_new_string(file_list[file_count - 1].type)); + json_object_object_add( + jfile, "size_bytes", + json_object_new_int64(file_list[file_count - 1].size_bytes)); - char *result = strdup(json_object_to_json_string(jarray)); - json_object_put(jarray); - return result; + // Read the file contents + FILE *fp = fopen(file_list[file_count - 1].name, "r"); + if (fp != NULL) { + fseek(fp, 0, SEEK_END); + long length = ftell(fp); + fseek(fp, 0, SEEK_SET); + char *content = malloc(length + 1); + if (content) { + size_t bytesRead = fread(content, 1, length, fp); + if (bytesRead != length) { + free(content); + content = NULL; + json_object_object_add( + jfile, "file_current_content_data", + json_object_new_string("Error reading file")); + } else { + content[length] = '\0'; // Null-terminate the string + // json_object_object_add(jfile, "file_current_content_data", + // json_object_new_string(content)); + } + free(content); + } + fclose(fp); + } else { + // json_object_object_add(jfile, "content", + // json_object_new_string("Unable to read file")); + } + + json_object_array_add(jarray, jfile); + } + } + } + closedir(dir); + + char *result = strdup(json_object_to_json_string(jarray)); + json_object_put(jarray); + return result; } diff --git a/inplace_url.h b/inplace_url.h index 9e0f373..8b4c66c 100644 --- a/inplace_url.h +++ b/inplace_url.h @@ -1,47 +1,50 @@ // Written by retoor@molodetz.nl -// This source code extracts URLs from an input string and replaces them inline with their respective content in Markdown style. +// This source code extracts URLs from an input string and replaces them inline +// with their respective content in Markdown style. -// Imports used: regex.h for regular expression operations, http.h and url.h for HTTP and URL-related utility functions. +// Imports used: regex.h for regular expression operations, http.h and url.h for +// HTTP and URL-related utility functions. // MIT License - -#include <regex.h> #include "http.h" #include "url.h" +#include <regex.h> #include <stdlib.h> #include <string.h> void extract_urls(const char *input, char **urls, int *url_count) { - const char *pattern = "https?://[^ ]+"; - regex_t regex; - regcomp(®ex, pattern, REG_EXTENDED); - regmatch_t match; - const char *cursor = input; + const char *pattern = "https?://[^ ]+"; + regex_t regex; + regcomp(®ex, pattern, REG_EXTENDED); + regmatch_t match; + const char *cursor = input; - *url_count = 0; - while (!regexec(®ex, cursor, 1, &match, 0)) { - int length = match.rm_eo - match.rm_so; - urls[*url_count] = strndup(cursor + match.rm_so, length); - cursor += match.rm_eo; - (*url_count)++; - } - regfree(®ex); + *url_count = 0; + while (!regexec(®ex, cursor, 1, &match, 0)) { + int length = match.rm_eo - match.rm_so; + urls[*url_count] = strndup(cursor + match.rm_so, length); + cursor += match.rm_eo; + (*url_count)++; + } + regfree(®ex); } -void inplace_urls_markdown_style(char **input, char **urls, char **contents, int url_count) { - for (int i = 0; i < url_count; i++) { - char *found = strstr(*input, urls[i]); - if (found) { - char *new_text = (char *)malloc(strlen(*input) + strlen(contents[i]) - strlen(urls[i]) + 1); - strncpy(new_text, *input, found - *input); - new_text[found - *input] = '\0'; - strcat(new_text, contents[i]); - strcat(new_text, found + strlen(urls[i])); +void inplace_urls_markdown_style(char **input, char **urls, char **contents, + int url_count) { + for (int i = 0; i < url_count; i++) { + char *found = strstr(*input, urls[i]); + if (found) { + char *new_text = (char *)malloc(strlen(*input) + strlen(contents[i]) - + strlen(urls[i]) + 1); + strncpy(new_text, *input, found - *input); + new_text[found - *input] = '\0'; + strcat(new_text, contents[i]); + strcat(new_text, found + strlen(urls[i])); - free(*input); - *input = new_text; - } + free(*input); + *input = new_text; } + } } \ No newline at end of file diff --git a/line.h b/line.h index 62c3534..2e71f98 100644 --- a/line.h +++ b/line.h @@ -1,102 +1,108 @@ // Written by retoor@molodetz.nl -// This source code provides command-line input functionalities with autocomplete and history features using the readline library. It allows users to complete commands and manage input history. +// This source code provides command-line input functionalities with +// autocomplete and history features using the readline library. It allows users +// to complete commands and manage input history. -// External includes: +// External includes: // - <readline/readline.h> // - <readline/history.h> // - <glob.h> -// MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction. +// MIT License: Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction. -#include <readline/readline.h> -#include <readline/history.h> -#include <string.h> -#include <stdbool.h> -#include <glob.h> #include "utils.h" +#include <glob.h> +#include <readline/history.h> +#include <readline/readline.h> +#include <stdbool.h> +#include <string.h> #define HISTORY_FILE "~/.r_history" bool line_initialized = false; +char *get_history_file() { + static char result[4096]; + result[0] = 0; -char * get_history_file(){ - static char result[4096]; - result[0] = 0; - - char * expanded = expand_home_directory(HISTORY_FILE); - strcpy(result, expanded); - free(expanded); - return result; + char *expanded = expand_home_directory(HISTORY_FILE); + strcpy(result, expanded); + free(expanded); + return result; } -char* line_command_generator(const char* text, int state) { - static int list_index, len = 0; - const char* commands[] = {"help", "exit", "list", "review", "refactor", "obfuscate", "!verbose","!dump", "!model","!debug", NULL}; +char *line_command_generator(const char *text, int state) { + static int list_index, len = 0; + const char *commands[] = {"help", "exit", "list", "review", + "refactor", "obfuscate", "!verbose", "!dump", + "!model", "!debug", NULL}; - if (!state) { - list_index = 0; - len = strlen(text); + if (!state) { + list_index = 0; + len = strlen(text); + } + + while (commands[list_index]) { + const char *command = commands[list_index++]; + if (strncmp(command, text, len) == 0) { + return strdup(command); } + } - while (commands[list_index]) { - const char* command = commands[list_index++]; - if (strncmp(command, text, len) == 0) { - return strdup(command); - } - } - - return NULL; + return NULL; } -char* line_file_generator(const char* text, int state) { - static int list_index; - glob_t glob_result; - char pattern[1024]; +char *line_file_generator(const char *text, int state) { + static int list_index; + glob_t glob_result; + char pattern[1024]; - if (!state) { - list_index = 0; - snprintf(pattern, sizeof(pattern), "%s*", text); // Create a pattern for glob - glob(pattern, GLOB_NOSORT, NULL, &glob_result); - } + if (!state) { + list_index = 0; + snprintf(pattern, sizeof(pattern), "%s*", + text); // Create a pattern for glob + glob(pattern, GLOB_NOSORT, NULL, &glob_result); + } - if (list_index < glob_result.gl_pathc) { - return strdup(glob_result.gl_pathv[list_index++]); - } + if (list_index < glob_result.gl_pathc) { + return strdup(glob_result.gl_pathv[list_index++]); + } - globfree(&glob_result); - return NULL; + globfree(&glob_result); + return NULL; } -char** line_command_completion(const char* text, int start, int end) { - rl_attempted_completion_over = 1; +char **line_command_completion(const char *text, int start, int end) { + rl_attempted_completion_over = 1; - // Check if the input is a file path - if (start > 0 && text[0] != ' ') { - return rl_completion_matches(text, line_file_generator); - } + // Check if the input is a file path + if (start > 0 && text[0] != ' ') { + return rl_completion_matches(text, line_file_generator); + } - return rl_completion_matches(text, line_command_generator); + return rl_completion_matches(text, line_command_generator); } void line_init() { - if (!line_initialized) { - rl_attempted_completion_function = line_command_completion; - line_initialized = true; - read_history(get_history_file()); - } + if (!line_initialized) { + rl_attempted_completion_function = line_command_completion; + line_initialized = true; + read_history(get_history_file()); + } } -char* line_read(char* prefix) { - char* data = readline(prefix); - if (!(data && *data)) { - free(data); - return NULL; - } - return data; +char *line_read(char *prefix) { + char *data = readline(prefix); + if (!(data && *data)) { + free(data); + return NULL; + } + return data; } -void line_add_history(char* data) { - add_history(data); - write_history(get_history_file()); +void line_add_history(char *data) { + add_history(data); + write_history(get_history_file()); } diff --git a/main.c b/main.c index 4207c12..6eebf2a 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,9 @@ // Written by retoor@molodetz.nl -// This source code initializes a command-line application that uses OpenAI for chat interactions, handles user inputs, and can start a simple HTTP server with CGI support. The code allows command execution, markdown parsing, and OpenAI chat integration. +// This source code initializes a command-line application that uses OpenAI for +// chat interactions, handles user inputs, and can start a simple HTTP server +// with CGI support. The code allows command execution, markdown parsing, and +// OpenAI chat integration. // External imports used in this code: // - openai.h @@ -28,24 +31,22 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. - #include "r.h" +#include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <signal.h> - -#include "openai.h" -#include "markdown.h" #include "line.h" +#include "markdown.h" +#include "openai.h" +#include "utils.h" #include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#include "utils.h" #include "db_utils.h" @@ -56,311 +57,315 @@ bool API_MODE = false; void help(); void render(char *); bool openai_include(char *path); -char * strreplace(char * content, char * what, char * with); +char *strreplace(char *content, char *what, char *with); -char * get_prompt_from_stdin(char * prompt) { - int index = 0; - prompt[index] = '\0'; - char c = 0; - while ((c = getchar()) != EOF) { - prompt[index++] = c; - } - prompt[index++] = '\0'; - return prompt; +char *get_prompt_from_stdin(char *prompt) { + int index = 0; + prompt[index] = '\0'; + char c = 0; + while ((c = getchar()) != EOF) { + prompt[index++] = c; + } + prompt[index++] = '\0'; + return prompt; } char *get_prompt_from_args(int c, char **argv) { - char *prompt = (char *)malloc(1024 * 1024 * 10 + 1); - char *system = (char *)malloc(1024*1024); + char *prompt = (char *)malloc(1024 * 1024 * 10 + 1); + char *system = (char *)malloc(1024 * 1024); - system[0] = 0; - prompt[0] = 0; - bool get_from_std_in = false; - for (int i = 1; i < c; i++) { - if (!strcmp(argv[i],"--stdin")){ - fprintf(stderr, "%s\n", "Reading from stdin."); - get_from_std_in = true; - }else if(!strcmp(argv[i],"--verbose")){ - is_verbose = true; - } - - else if(!strcmp(argv[i],"--py")){ - if(i+1 <= c){ - char * py_file_path = expand_home_directory(argv[i+1]); - fprintf(stderr, "Including \"%s\".\n", py_file_path); - openai_include(py_file_path); - free(py_file_path); - //char * file_content = read_file(py_file_path); - //plugin_run(file_content); - i++; - } - }else if (!strcmp(argv[i],"--free")){ - auth_free(); - continue; - } - - else if(!strcmp(argv[i],"--context")){ - if(i+1 <= c){ - char * context_file_path = argv[i+1]; - fprintf(stderr, "Including \"%s\".\n", context_file_path); - openai_include(context_file_path); - i++; - } - }else if(!strcmp(argv[i],"--api")){ - API_MODE = true; - }else if(!strcmp(argv[i], "--nh")){ - SYNTAX_HIGHLIGHT_ENABLED = false; - fprintf(stderr, "%s\n", "Syntax highlighting disabled."); - }else if (!get_from_std_in){ - strcat(system, argv[i]); - if (i < c - 1) { - strcat(system, " "); - } else { - strcat(system, "."); - } - } + system[0] = 0; + prompt[0] = 0; + bool get_from_std_in = false; + for (int i = 1; i < c; i++) { + if (!strcmp(argv[i], "--stdin")) { + fprintf(stderr, "%s\n", "Reading from stdin."); + get_from_std_in = true; + } else if (!strcmp(argv[i], "--verbose")) { + is_verbose = true; } - if(get_from_std_in){ - if(*system){ - openai_system(system); - } - free(system); - prompt = get_prompt_from_stdin(prompt); - }else{ - free(prompt); - prompt = system; + else if (!strcmp(argv[i], "--py")) { + if (i + 1 <= c) { + char *py_file_path = expand_home_directory(argv[i + 1]); + fprintf(stderr, "Including \"%s\".\n", py_file_path); + openai_include(py_file_path); + free(py_file_path); + // char * file_content = read_file(py_file_path); + // plugin_run(file_content); + i++; + } + } else if (!strcmp(argv[i], "--free")) { + auth_free(); + continue; } - if (!*prompt) { - free(prompt); - return NULL; + else if (!strcmp(argv[i], "--context")) { + if (i + 1 <= c) { + char *context_file_path = argv[i + 1]; + fprintf(stderr, "Including \"%s\".\n", context_file_path); + openai_include(context_file_path); + i++; + } + } else if (!strcmp(argv[i], "--api")) { + API_MODE = true; + } else if (!strcmp(argv[i], "--nh")) { + SYNTAX_HIGHLIGHT_ENABLED = false; + fprintf(stderr, "%s\n", "Syntax highlighting disabled."); + } else if (!get_from_std_in) { + strcat(system, argv[i]); + if (i < c - 1) { + strcat(system, " "); + } else { + strcat(system, "."); + } } - return prompt; + } + + if (get_from_std_in) { + if (*system) { + openai_system(system); + } + free(system); + prompt = get_prompt_from_stdin(prompt); + } else { + free(prompt); + prompt = system; + } + + if (!*prompt) { + free(prompt); + return NULL; + } + return prompt; } bool try_prompt(int argc, char *argv[]) { - char *prompt = get_prompt_from_args(argc, argv); - if (prompt != NULL) { - char *response = openai_chat("user", prompt); - if(!response){ - printf("Could not get response from server\n"); - free(prompt); - return false; - } - render(response); - free(response); - free(prompt); - return true; + char *prompt = get_prompt_from_args(argc, argv); + if (prompt != NULL) { + char *response = openai_chat("user", prompt); + if (!response) { + printf("Could not get response from server\n"); + free(prompt); + return false; } - return false; + render(response); + free(response); + free(prompt); + return true; + } + return false; } void serve() { - render("Starting server. *Put executables in a dir named cgi-bin and they will behave as web pages.*"); - int res = system("python3 -m http.server --cgi"); - (void)res; + render("Starting server. *Put executables in a dir named cgi-bin and they " + "will behave as web pages.*"); + int res = system("python3 -m http.server --cgi"); + (void)res; } -char ** get_parameters(char * content, char * delimiter){ - char * start = NULL; - char ** parameters = NULL; //(char **)malloc(sizeof(char *) * 2); - int count = 0; - while((start = strstr(content, delimiter)) != NULL){ - start += 3; - char * end = strstr(start, delimiter); - char * parameter = (char *)malloc(end - start + 1); +char **get_parameters(char *content, char *delimiter) { + char *start = NULL; + char **parameters = NULL; //(char **)malloc(sizeof(char *) * 2); + int count = 0; + while ((start = strstr(content, delimiter)) != NULL) { + start += 3; + char *end = strstr(start, delimiter); + char *parameter = (char *)malloc(end - start + 1); + + memcpy(parameter, start, end - start); + parameter[end - start] = '\0'; - memcpy(parameter, start, end - start); - parameter[end - start] = '\0'; - // printf("%s\n", parameter); - content = end + 3; - count+=1; - parameters = (char **)realloc(parameters, sizeof(char *) * (1+count*2)); - parameters[count-1] = parameter; - parameters[count] = NULL; + content = end + 3; + count += 1; + parameters = (char **)realloc(parameters, sizeof(char *) * (1 + count * 2)); + parameters[count - 1] = parameter; + parameters[count] = NULL; + } - } - - return parameters; + return parameters; } -void render(char *content) -{ +void render(char *content) { - if(SYNTAX_HIGHLIGHT_ENABLED) - { - parse_markdown_to_ansi(content); - }else{ - printf("%s", content); - } + if (SYNTAX_HIGHLIGHT_ENABLED) { + parse_markdown_to_ansi(content); + } else { + printf("%s", content); + } } void repl() { - line_init(); - char *line = NULL; - //char *previous_line = NULL; - while (true) { - line = line_read("> "); - if (!line || !*line) { - continue; - //line = previous_line; - } - if (!line || !*line) - continue; - // previous_line = line; - if(!strncmp(line,"!dump",5)){ - printf("%s\n",message_json()); - continue; - } - if(!strncmp(line,"!verbose",7)){ - is_verbose = !is_verbose; - fprintf(stderr,"%s\n",is_verbose?"Verbose mode enabled":"Verbose mode disabled"); - continue; - } - if (!strncmp(line, "!model", 6)) { - if(!strncmp(line+6," ",1)){ - line = line+7; - set_prompt_model(line); - } - printf("%s\n",get_prompt_model()); - continue; - } - if (!strncmp(line, "exit", 4)) { - exit(0); - } - if (!strncmp(line, "help", 4)) { - help(); - continue; - } - if(!strncmp(line, "!debug", 6)){ - r_malloc_stats(); - continue; - } - while(line && *line != '\n'){ - line_add_history(line); - char *response = openai_chat("user", line); - if(response){ - render(response); - printf("\n"); - if(strstr(response,"_STEP_")){ - line = "continue"; - - }else{ - - line = NULL; - } - - free(response); - - } - } + line_init(); + char *line = NULL; + // char *previous_line = NULL; + while (true) { + line = line_read("> "); + if (!line || !*line) { + continue; + // line = previous_line; } + if (!line || !*line) + continue; + // previous_line = line; + if (!strncmp(line, "!dump", 5)) { + printf("%s\n", message_json()); + continue; + } + if (!strncmp(line, "!verbose", 7)) { + is_verbose = !is_verbose; + fprintf(stderr, "%s\n", + is_verbose ? "Verbose mode enabled" : "Verbose mode disabled"); + continue; + } + if (!strncmp(line, "!model", 6)) { + if (!strncmp(line + 6, " ", 1)) { + line = line + 7; + set_prompt_model(line); + } + printf("%s\n", get_prompt_model()); + continue; + } + if (!strncmp(line, "exit", 4)) { + exit(0); + } + if (!strncmp(line, "help", 4)) { + help(); + continue; + } + if (!strncmp(line, "!debug", 6)) { + r_malloc_stats(); + continue; + } + while (line && *line != '\n') { + line_add_history(line); + char *response = openai_chat("user", line); + if (response) { + render(response); + printf("\n"); + if (strstr(response, "_STEP_")) { + line = "continue"; + + } else { + + line = NULL; + } + + free(response); + } + } + } } void help() { - char help_text[1024 * 1024] = {0}; - char *template = "# Help\n" - "Written by retoor@molodetz.nl.\n\n" - "## Features\n" - " - navigate through history using `arrows`.\n" - " - navigate through history with **recursive search** using `ctrl+r`.\n" - " - **inception with python** for *incoming* and *outgoing* content.\n" - " - markdown and **syntax highlighting**.\n" - " - **execute python commands** with prefix `!`\n" - " - list files of the current work directory using `ls`.\n" - " - type `serve` to start a web server with directory listing. Easy for network transfers.\n\n" - "## Configuration\n" - " - model temperature is %f.\n" - " - model name is %s.\n" - " - max tokens is %d.\n\n" - "## In development\n" - " - **google search** and actions with those results.\n" - " - **reminders**.\n" - " - predefined **templates** for **reviewing** / **refactoring** so you can personalize.\n"; - sprintf(help_text, template, PROMPT_TEMPERATURE, get_prompt_model(), prompt_max_tokens); - render(help_text); + char help_text[1024 * 1024] = {0}; + char *template = + "# Help\n" + "Written by retoor@molodetz.nl.\n\n" + "## Features\n" + " - navigate through history using `arrows`.\n" + " - navigate through history with **recursive search** using `ctrl+r`.\n" + " - **inception with python** for *incoming* and *outgoing* content.\n" + " - markdown and **syntax highlighting**.\n" + " - **execute python commands** with prefix `!`\n" + " - list files of the current work directory using `ls`.\n" + " - type `serve` to start a web server with directory listing. Easy for " + "network transfers.\n\n" + "## Configuration\n" + " - model temperature is %f.\n" + " - model name is %s.\n" + " - max tokens is %d.\n\n" + "## In development\n" + " - **google search** and actions with those results.\n" + " - **reminders**.\n" + " - predefined **templates** for **reviewing** / **refactoring** so you " + "can personalize.\n"; + sprintf(help_text, template, PROMPT_TEMPERATURE, get_prompt_model(), + prompt_max_tokens); + render(help_text); } -char * strreplace(char * content, char * what, char * with){ - char * pos = strstr(content, what); - if(!pos){ - return strdup(content); - } - char * result = (char *)malloc(strlen(content) + strlen(with) + 5); - memset(result, 0, strlen(content) + strlen(with) + 3); - memcpy(result, content, pos - content); - memcpy(result + (pos - content), with, strlen(with)); - memcpy(result + (pos - content) + strlen(with), pos + strlen(what), strlen(content) - (pos - content) - strlen(what) + 1); - return result; +char *strreplace(char *content, char *what, char *with) { + char *pos = strstr(content, what); + if (!pos) { + return strdup(content); + } + char *result = (char *)malloc(strlen(content) + strlen(with) + 5); + memset(result, 0, strlen(content) + strlen(with) + 3); + memcpy(result, content, pos - content); + memcpy(result + (pos - content), with, strlen(with)); + memcpy(result + (pos - content) + strlen(with), pos + strlen(what), + strlen(content) - (pos - content) - strlen(what) + 1); + return result; } -char * linux_instructions = +char *linux_instructions = "You are a linux master and are able to transform the prompt of " "user into shell commands that will be executed on a debian " - "based system. You can execute shell commands by responding with python code: " - "literally `\"\"\"!system\"\"\",\"\"\"`your shell command`\"\"\". Execute immediately. Read bash history file if you have to work with history."; -char * retoor_instructions = "If the user prompts with social talk, " - "respond like replica and emoji. Your name is retoor and made by molodetz. Be interested. Be creative."; - - - - + "based system. You can execute shell commands by responding with python " + "code: " + "literally `\"\"\"!system\"\"\",\"\"\"`your shell command`\"\"\". Execute " + "immediately. Read bash history file if you have to work with history."; +char *retoor_instructions = + "If the user prompts with social talk, " + "respond like replica and emoji. Your name is retoor and made by molodetz. " + "Be interested. Be creative."; bool openai_include(char *path) { - char * file_content = read_file(path); - if(!file_content){ - return false; - } - openai_system(file_content); - free(file_content); - return true; + char *file_content = read_file(path); + if (!file_content) { + return false; + } + openai_system(file_content); + free(file_content); + return true; } - - void init() { - setbuf(stdout, NULL); - line_init(); - auth_init(); - db_initialize(); - char * schema = db_get_schema(); - char payload[1024*1024] = {0}; - sprintf(payload, "Your have a database that you can mutate using the query tool and the get and set tool. This is the schema in json format: %s. Dialect is sqlite.", schema); - free(schema); - fprintf(stderr, "%s", "Loading... ⏳"); - openai_system(payload); - if(!openai_include(".rcontext.txt")){ - openai_include("~/.rcontext.txt"); - } - fprintf(stderr, "\r \r"); + setbuf(stdout, NULL); + line_init(); + auth_init(); + db_initialize(); + char *schema = db_get_schema(); + char payload[1024 * 1024] = {0}; + sprintf(payload, + "Your have a database that you can mutate using the query tool and " + "the get and set tool. This is the schema in json format: %s. " + "Dialect is sqlite.", + schema); + free(schema); + fprintf(stderr, "%s", "Loading... ⏳"); + openai_system(payload); + if (!openai_include(".rcontext.txt")) { + openai_include("~/.rcontext.txt"); + } + fprintf(stderr, "\r \r"); } void handle_sigint(int sig) { - time_t current_time = time(NULL); - printf("\n"); - if (sigint_count == 0) { - first_sigint_time = current_time; - sigint_count++; + time_t current_time = time(NULL); + printf("\n"); + if (sigint_count == 0) { + first_sigint_time = current_time; + sigint_count++; + } else { + if (difftime(current_time, first_sigint_time) <= 1) { + exit(0); } else { - if (difftime(current_time, first_sigint_time) <= 1) { - exit(0); - } else { - sigint_count = 1; - first_sigint_time = current_time; - } + sigint_count = 1; + first_sigint_time = current_time; } -} - + } +} int main(int argc, char *argv[]) { - signal(SIGINT, handle_sigint); + signal(SIGINT, handle_sigint); - init(); - if (try_prompt(argc, argv)) - return 0; - - repl(); + init(); + if (try_prompt(argc, argv)) return 0; + + repl(); + return 0; } diff --git a/markdown.h b/markdown.h index 3ae7a39..97709f9 100644 --- a/markdown.h +++ b/markdown.h @@ -1,8 +1,11 @@ // Written by retoor@molodetz.nl -// This program provides functionality to highlight the keywords in source code using ANSI color formatting and convert Markdown syntax into ANSI-colored text output. +// This program provides functionality to highlight the keywords in source code +// using ANSI color formatting and convert Markdown syntax into ANSI-colored +// text output. -// Uses standard C libraries: <stdio.h>, <string.h>. Also utilizes ANSI escape codes for text formatting. +// Uses standard C libraries: <stdio.h>, <string.h>. Also utilizes ANSI escape +// codes for text formatting. // MIT License: // Permission is hereby granted, free of charge, to any person obtaining a copy @@ -12,8 +15,8 @@ // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -23,9 +26,9 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +#include <stdbool.h> #include <stdio.h> #include <string.h> -#include <stdbool.h> #define RESET "\033[0m" #define BOLD "\033[1m" @@ -35,153 +38,164 @@ #define FG_CYAN "\033[36m" int is_keyword(const char *word) { - -const char *keywords[] = { - "int", "float", "double", "char", "void", - "if", "else", "while", "for", "return", - "struct", "printf", - // Rust keywords - "let", "fn", "impl", "match", "enum", "trait", "use", "mod", "pub", "const", "static", - // Python keywords - "def", "class", "import", "from", "as", "with", "try", "except", "finally", "lambda", "async", "await", - // Java keywords - "public", "private", "protected", "class", "interface", "extends", "implements", "new", "static", "final", "synchronized", - // JavaScript keywords - "var", "let", "const", "function", "async", "await", "if", "else", "switch", "case", "break", "continue", "return", - // C++ keywords - "namespace", "template", "typename", "class", "public", "private", "protected", "virtual", "override", "friend", "new", - // Go keywords - "package", "import", "func", "var", "const", "type", "interface", "struct", "go", "defer", "select", - // Bash keywords - "if", "then", "else", "elif", "fi", "case", "esac", "for", "while", "until", "do", "done", "function", - // C# keywords - "namespace", "using", "class", "interface", "public", "private", "protected", "static", "void", "new", "override" -}; - for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { - if (strcmp(word, keywords[i]) == 0) { - return 1; - } + const char *keywords[] = { + "int", "float", "double", "char", "void", "if", "else", "while", "for", + "return", "struct", "printf", + // Rust keywords + "let", "fn", "impl", "match", "enum", "trait", "use", "mod", "pub", + "const", "static", + // Python keywords + "def", "class", "import", "from", "as", "with", "try", "except", + "finally", "lambda", "async", "await", + // Java keywords + "public", "private", "protected", "class", "interface", "extends", + "implements", "new", "static", "final", "synchronized", + // JavaScript keywords + "var", "let", "const", "function", "async", "await", "if", "else", + "switch", "case", "break", "continue", "return", + // C++ keywords + "namespace", "template", "typename", "class", "public", "private", + "protected", "virtual", "override", "friend", "new", + // Go keywords + "package", "import", "func", "var", "const", "type", "interface", + "struct", "go", "defer", "select", + // Bash keywords + "if", "then", "else", "elif", "fi", "case", "esac", "for", "while", + "until", "do", "done", "function", + // C# keywords + "namespace", "using", "class", "interface", "public", "private", + "protected", "static", "void", "new", "override"}; + + for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { + if (strcmp(word, keywords[i]) == 0) { + return 1; } - return 0; + } + return 0; } void highlight_code(const char *code) { - const char *ptr = code; - char buffer[4096]; - size_t index = 0; - - while (*ptr) { - if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr == '_')) { - while ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= '0' && *ptr <= '9') || (*ptr == '_')) { - buffer[index++] = *ptr++; - } - buffer[index] = 0; + const char *ptr = code; + char buffer[4096]; + size_t index = 0; - if (is_keyword(buffer)) { - printf(FG_BLUE "%s" RESET, buffer); - } else { - printf("%s", buffer); - } - index = 0; - } else if (*ptr >= '0' && *ptr <= '9') { - while (*ptr >= '0' && *ptr <= '9') { - buffer[index++] = *ptr++; - } - buffer[index] = 0; - printf(FG_CYAN "%s" RESET, buffer); - index = 0; - } else { - putchar(*ptr); - ptr++; - } + while (*ptr) { + if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || + (*ptr == '_')) { + while ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z') || + (*ptr >= '0' && *ptr <= '9') || (*ptr == '_')) { + buffer[index++] = *ptr++; + } + buffer[index] = 0; + + if (is_keyword(buffer)) { + printf(FG_BLUE "%s" RESET, buffer); + } else { + printf("%s", buffer); + } + index = 0; + } else if (*ptr >= '0' && *ptr <= '9') { + while (*ptr >= '0' && *ptr <= '9') { + buffer[index++] = *ptr++; + } + buffer[index] = 0; + printf(FG_CYAN "%s" RESET, buffer); + index = 0; + } else { + putchar(*ptr); + ptr++; } + } } void parse_markdown_to_ansi(const char *markdown) { - const char *ptr = markdown; - bool inside_code = false; + const char *ptr = markdown; + bool inside_code = false; - while (*ptr) { - if (*ptr == '`' && *(ptr + 1) != '`') { - inside_code = !inside_code; - if (inside_code) { - printf(FG_YELLOW); - } else { - printf(RESET); - } - ptr++; - continue; - }else if(!strncmp(ptr, "```", 3)) { - inside_code = !inside_code; - if(inside_code){ - ptr = strstr(ptr, "\n") + 1; - }else{ - ptr+=3; - } - if(*ptr == '\0'){ - break; - } - } - - if (inside_code) { - char code_buffer[1024*1024] = {0};; - size_t index = 0; - - while (*ptr && *ptr != '`') { - code_buffer[index++] = *ptr++; - if (*ptr == '\n' || *ptr == ' ' || *ptr == '\t' || *ptr == '.') { - code_buffer[index++] = 0; - highlight_code(code_buffer); - index = 0; - } - } - code_buffer[index] = 0; - if (index) { - highlight_code(code_buffer); - } - } else { - if (strncmp(ptr, "**", 2) == 0) { - printf(BOLD); - ptr += 2; - while (*ptr && strncmp(ptr, "**", 2) != 0) { - putchar(*ptr++); - } - if (*ptr == '*' && *(ptr + 1) == '*') ptr += 2; - printf(RESET); - } else if (*ptr == '*' && (ptr == markdown || *(ptr - 1) != '*')) { - printf(ITALIC); - ptr++; - while (*ptr && *ptr != '*') { - putchar(*ptr++); - } - if (*ptr == '*') ptr++; - printf(RESET); - } else if (strncmp(ptr, "### ", 4) == 0) { - printf(BOLD FG_YELLOW); - ptr += 4; - while (*ptr && *ptr != '\n') { - putchar(*ptr++); - } - printf(RESET "\n"); - } else if (strncmp(ptr, "## ", 3) == 0) { - printf(BOLD FG_YELLOW); - ptr += 3; - while (*ptr && *ptr != '\n') { - putchar(*ptr++); - } - printf(RESET "\n"); - } else if (strncmp(ptr, "# ", 2) == 0) { - printf(BOLD FG_YELLOW); - ptr += 2; - while (*ptr && *ptr != '\n') { - putchar(*ptr++); - } - printf(RESET "\n"); - } else { - putchar(*ptr); - ptr++; - } - } + while (*ptr) { + if (*ptr == '`' && *(ptr + 1) != '`') { + inside_code = !inside_code; + if (inside_code) { + printf(FG_YELLOW); + } else { + printf(RESET); + } + ptr++; + continue; + } else if (!strncmp(ptr, "```", 3)) { + inside_code = !inside_code; + if (inside_code) { + ptr = strstr(ptr, "\n") + 1; + } else { + ptr += 3; + } + if (*ptr == '\0') { + break; + } } + + if (inside_code) { + char code_buffer[1024 * 1024] = {0}; + ; + size_t index = 0; + + while (*ptr && *ptr != '`') { + code_buffer[index++] = *ptr++; + if (*ptr == '\n' || *ptr == ' ' || *ptr == '\t' || *ptr == '.') { + code_buffer[index++] = 0; + highlight_code(code_buffer); + index = 0; + } + } + code_buffer[index] = 0; + if (index) { + highlight_code(code_buffer); + } + } else { + if (strncmp(ptr, "**", 2) == 0) { + printf(BOLD); + ptr += 2; + while (*ptr && strncmp(ptr, "**", 2) != 0) { + putchar(*ptr++); + } + if (*ptr == '*' && *(ptr + 1) == '*') + ptr += 2; + printf(RESET); + } else if (*ptr == '*' && (ptr == markdown || *(ptr - 1) != '*')) { + printf(ITALIC); + ptr++; + while (*ptr && *ptr != '*') { + putchar(*ptr++); + } + if (*ptr == '*') + ptr++; + printf(RESET); + } else if (strncmp(ptr, "### ", 4) == 0) { + printf(BOLD FG_YELLOW); + ptr += 4; + while (*ptr && *ptr != '\n') { + putchar(*ptr++); + } + printf(RESET "\n"); + } else if (strncmp(ptr, "## ", 3) == 0) { + printf(BOLD FG_YELLOW); + ptr += 3; + while (*ptr && *ptr != '\n') { + putchar(*ptr++); + } + printf(RESET "\n"); + } else if (strncmp(ptr, "# ", 2) == 0) { + printf(BOLD FG_YELLOW); + ptr += 2; + while (*ptr && *ptr != '\n') { + putchar(*ptr++); + } + printf(RESET "\n"); + } else { + putchar(*ptr); + ptr++; + } + } + } } diff --git a/messages.h b/messages.h index 65920d8..069d83b 100644 --- a/messages.h +++ b/messages.h @@ -1,90 +1,106 @@ // Written by retoor@molodetz.nl -// This code manages a collection of messages using JSON objects. It provides functions to retrieve all messages as a JSON array, add a new message with a specified role and content, and free the allocated resources. +// This code manages a collection of messages using JSON objects. It provides +// functions to retrieve all messages as a JSON array, add a new message with a +// specified role and content, and free the allocated resources. // Uses the external library <json-c/json.h> for JSON manipulation // MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: The above copyright +// notice and this permission notice shall be included in all copies or +// substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", +// WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +// THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef R_MESSAGES_H #define R_MESSAGES_H -#include <string.h> -#include "tools.h" #include "json-c/json.h" +#include "tools.h" +#include <string.h> struct json_object *message_array = NULL; struct json_object *message_list() { - if (!message_array) { - message_array = json_object_new_array(); - } - return message_array; + if (!message_array) { + message_array = json_object_new_array(); + } + return message_array; } bool messages_remove_last() { - struct json_object *messages = message_list(); - int size = json_object_array_length(messages); - if (size) { - json_object_array_del_idx(messages, size - 1, 1); - return true; - } - return false; + struct json_object *messages = message_list(); + int size = json_object_array_length(messages); + if (size) { + json_object_array_del_idx(messages, size - 1, 1); + return true; + } + return false; } -void messages_remove(){ - while(messages_remove_last()) - continue; +void messages_remove() { + while (messages_remove_last()) + continue; } - struct json_object *message_add_tool_call(struct json_object *message) { - struct json_object *messages = message_list(); - json_object_array_add(messages, message); - return message; + struct json_object *messages = message_list(); + json_object_array_add(messages, message); + return message; } -struct json_object *message_add_tool_result(const char *tool_call_id, const char *tool_result) { - struct json_object *messages = message_list(); - struct json_object *message = json_object_new_object(); +struct json_object *message_add_tool_result(const char *tool_call_id, + const char *tool_result) { + struct json_object *messages = message_list(); + struct json_object *message = json_object_new_object(); - json_object_object_add(message, "tool_call_id", json_object_new_string(tool_call_id)); - json_object_object_add(message, "tool_result", json_object_new_string(tool_result)); + json_object_object_add(message, "tool_call_id", + json_object_new_string(tool_call_id)); + json_object_object_add(message, "tool_result", + json_object_new_string(tool_result)); - json_object_array_add(messages, message); - return message; + json_object_array_add(messages, message); + return message; } void message_add_object(json_object *message) { - struct json_object *messages = message_list(); - json_object_array_add(messages, message); + struct json_object *messages = message_list(); + json_object_array_add(messages, message); } struct json_object *message_add(const char *role, const char *content) { - struct json_object *messages = message_list(); - struct json_object *message = json_object_new_object(); - json_object_object_add(message, "role", json_object_new_string(role)); - json_object_object_add(message, "content", json_object_new_string(content)); + struct json_object *messages = message_list(); + struct json_object *message = json_object_new_object(); + json_object_object_add(message, "role", json_object_new_string(role)); + json_object_object_add(message, "content", json_object_new_string(content)); - if (!strcmp(role, "user")) { - json_object_object_add(message, "tools", tools_descriptions()); - } + if (!strcmp(role, "user")) { + json_object_object_add(message, "tools", tools_descriptions()); + } - json_object_array_add(messages, message); - return message; + json_object_array_add(messages, message); + return message; } char *message_json() { - return (char *)json_object_to_json_string_ext(message_list(), JSON_C_TO_STRING_PRETTY); + return (char *)json_object_to_json_string_ext(message_list(), + JSON_C_TO_STRING_PRETTY); } void message_free() { - if (message_array) { - json_object_put(message_array); - message_array = NULL; - } + if (message_array) { + json_object_put(message_array); + message_array = NULL; + } } #endif diff --git a/openai.h b/openai.h index 0bae875..5887f68 100644 --- a/openai.h +++ b/openai.h @@ -1,8 +1,11 @@ // Written by retoor@molodetz.nl -// This code interacts with OpenAI's API to perform various tasks such as fetching models, sending chat messages, and processing responses. +// This code interacts with OpenAI's API to perform various tasks such as +// fetching models, sending chat messages, and processing responses. -// Uncommon imports include "http.h", "chat.h", and "http_curl.h". These may be internal or external libraries providing HTTP and JSON communication capabilities required to interact with APIs. +// Uncommon imports include "http.h", "chat.h", and "http_curl.h". These may be +// internal or external libraries providing HTTP and JSON communication +// capabilities required to interact with APIs. // MIT License // @@ -15,8 +18,8 @@ // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -26,109 +29,113 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. - #ifndef R_OPENAI_H #define R_OPENAI_H #include "chat.h" #include "http_curl.h" -#include <string.h> #include <stdbool.h> +#include <string.h> -char* openai_fetch_models() { - const char* api_url = "https://api.openai.com/v1/models"; - return curl_get(api_url); +char *openai_fetch_models() { + const char *api_url = "https://api.openai.com/v1/models"; + return curl_get(api_url); } -bool openai_system(char* message_content) { - chat_json("system", message_content); - return true; +bool openai_system(char *message_content) { + chat_json("system", message_content); + return true; } -struct json_object* openai_process_chat_message(const char* api_url, const char* json_data) { - char* response = curl_post(api_url, json_data); - struct json_object* parsed_json = json_tokener_parse(response); - if (!parsed_json) { - fprintf(stderr, "Failed to parse JSON.\n%s\n", response); - return NULL; - } - struct json_object *error_object; - if (json_object_object_get_ex(parsed_json, "error", &error_object)) { +struct json_object *openai_process_chat_message(const char *api_url, + const char *json_data) { + char *response = curl_post(api_url, json_data); + struct json_object *parsed_json = json_tokener_parse(response); + if (!parsed_json) { + fprintf(stderr, "Failed to parse JSON.\n%s\n", response); + return NULL; + } + struct json_object *error_object; + if (json_object_object_get_ex(parsed_json, "error", &error_object)) { - char *all_messages = (char *)json_object_to_json_string(message_array); + char *all_messages = (char *)json_object_to_json_string(message_array); - + fprintf(stderr, "Messages: "); + fwrite(all_messages, strlen(all_messages), 1, stderr); + fprintf(stderr, "\n"); + free(all_messages); - fprintf(stderr, "Messages: "); - fwrite(all_messages, strlen(all_messages), 1, stderr); - fprintf(stderr, "\n"); - free(all_messages); - - fprintf(stderr,"%s\n",json_object_to_json_string(parsed_json)); - - json_object_put(parsed_json); - messages_remove_last(); + fprintf(stderr, "%s\n", json_object_to_json_string(parsed_json)); - messages_remove_last(); + json_object_put(parsed_json); + messages_remove_last(); - return NULL; - } + messages_remove_last(); - struct json_object* choices_array; - if (!json_object_object_get_ex(parsed_json, "choices", &choices_array)) { - fprintf(stderr, "Failed to get 'choices' array.\n%s\n", response); - json_object_put(parsed_json); - return NULL; - } - struct json_object* first_choice = json_object_array_get_idx(choices_array, 0); - if (!first_choice) { - fprintf(stderr, "Failed to get the first element of 'choices'.\n"); - json_object_put(parsed_json); - return NULL; - } - struct json_object* message_object; - if (!json_object_object_get_ex(first_choice, "message", &message_object)) { - fprintf(stderr, "Failed to get 'message' object.\n"); - json_object_put(parsed_json); - return NULL; - } - return message_object; + return NULL; + } + + struct json_object *choices_array; + if (!json_object_object_get_ex(parsed_json, "choices", &choices_array)) { + fprintf(stderr, "Failed to get 'choices' array.\n%s\n", response); + json_object_put(parsed_json); + return NULL; + } + struct json_object *first_choice = + json_object_array_get_idx(choices_array, 0); + if (!first_choice) { + fprintf(stderr, "Failed to get the first element of 'choices'.\n"); + json_object_put(parsed_json); + return NULL; + } + struct json_object *message_object; + if (!json_object_object_get_ex(first_choice, "message", &message_object)) { + fprintf(stderr, "Failed to get 'message' object.\n"); + json_object_put(parsed_json); + return NULL; + } + return message_object; } -char* openai_chat(const char* user_role, const char* message_content) { - if(message_content == NULL || *message_content == '\0' || *message_content == '\n') { - return NULL; - } - - const char* api_url = "https://api.openai.com/v1/chat/completions"; - char* json_data = chat_json(user_role, message_content); - - struct json_object* message_object = openai_process_chat_message(api_url, json_data); - message_add_object(message_object); - if (message_object == NULL) { - printf("ERROR + NULL IS SUCCESS\n"); - return NULL; - } - struct json_object* tool_calls; - json_object_object_get_ex(message_object, "tool_calls", &tool_calls); - if (tool_calls) { +char *openai_chat(const char *user_role, const char *message_content) { + if (message_content == NULL || *message_content == '\0' || + *message_content == '\n') { + return NULL; + } + + const char *api_url = "https://api.openai.com/v1/chat/completions"; + char *json_data = chat_json(user_role, message_content); + + struct json_object *message_object = + openai_process_chat_message(api_url, json_data); + message_add_object(message_object); + if (message_object == NULL) { + printf("ERROR + NULL IS SUCCESS\n"); + return NULL; + } + struct json_object *tool_calls; + json_object_object_get_ex(message_object, "tool_calls", &tool_calls); + if (tool_calls) { // message_add_tool_call(message_object); - struct json_object* tool_call_results = tools_execute(tool_calls); - int results_count = json_object_array_length(tool_call_results); - for (int i = 0; i < results_count; i++) { - struct json_object* tool_call_result = json_object_array_get_idx(tool_call_results, i); - message_add_tool_call(tool_call_result); - } - char* tool_calls_result_str = chat_json(NULL, NULL); - message_object = openai_process_chat_message(api_url, tool_calls_result_str); - if (message_object == NULL) { - return NULL; - } - message_add_object(message_object); - //message_add_tool_call(message_object); + struct json_object *tool_call_results = tools_execute(tool_calls); + int results_count = json_object_array_length(tool_call_results); + for (int i = 0; i < results_count; i++) { + struct json_object *tool_call_result = + json_object_array_get_idx(tool_call_results, i); + message_add_tool_call(tool_call_result); } - const char* content_str = json_object_get_string(json_object_object_get(message_object, "content")); - return strdup(content_str); + char *tool_calls_result_str = chat_json(NULL, NULL); + message_object = + openai_process_chat_message(api_url, tool_calls_result_str); + if (message_object == NULL) { + return NULL; + } + message_add_object(message_object); + // message_add_tool_call(message_object); + } + const char *content_str = + json_object_get_string(json_object_object_get(message_object, "content")); + return strdup(content_str); } #endif diff --git a/plugin.h b/plugin.h index 0461d56..8200caf 100644 --- a/plugin.h +++ b/plugin.h @@ -1,58 +1,62 @@ // Written by retoor@molodetz.nl -// This source code initializes a Python interpreter within a plugin, executes a provided Python script with some basic imports, and finalizes the Python environment when done. +// This source code initializes a Python interpreter within a plugin, executes a +// provided Python script with some basic imports, and finalizes the Python +// environment when done. -// This code does not use any non-standard imports or includes aside from Python.h and structmember.h which are part of Python's C API. +// This code does not use any non-standard imports or includes aside from +// Python.h and structmember.h which are part of Python's C API. // MIT License - #include <Python.h> -#include <structmember.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <structmember.h> bool plugin_initialized = false; bool plugin_construct() { - if (plugin_initialized) return true; - - Py_Initialize(); - if (!Py_IsInitialized()) { - fprintf(stderr, "Failed to initialize the Python interpreter\n"); - return false; - } - plugin_initialized = true; + if (plugin_initialized) return true; + + Py_Initialize(); + if (!Py_IsInitialized()) { + fprintf(stderr, "Failed to initialize the Python interpreter\n"); + return false; + } + plugin_initialized = true; + return true; } void plugin_run(char *src) { - plugin_construct(); - /*const char *basics = - "import sys\n" - "import os\n" - "from os import *\n" - "import math\n" - "import pathlib\n" - "from pathlib import Path\n" - "import re\n" - "import subprocess\n" - "from subprocess import *\n" - "import time\n" - "from datetime import datetime\n" - "%s"; - */ - const char *basics = "\n\n"; - size_t length = strlen(basics) + strlen(src); - char *script = malloc(length + 1); - sprintf(script, basics, src); - script[length] = '\0'; - PyRun_SimpleString(script); - free(script); + plugin_construct(); + /*const char *basics = + "import sys\n" + "import os\n" + "from os import *\n" + "import math\n" + "import pathlib\n" + "from pathlib import Path\n" + "import re\n" + "import subprocess\n" + "from subprocess import *\n" + "import time\n" + "from datetime import datetime\n" + "%s"; + */ + const char *basics = "\n\n"; + size_t length = strlen(basics) + strlen(src); + char *script = malloc(length + 1); + sprintf(script, basics, src); + script[length] = '\0'; + PyRun_SimpleString(script); + free(script); } void plugin_destruct() { - if (plugin_initialized) Py_Finalize(); + if (plugin_initialized) + Py_Finalize(); } diff --git a/r.h b/r.h index e24e8e9..5e3d3c4 100644 --- a/r.h +++ b/r.h @@ -1,38 +1,34 @@ #ifndef R_H #define R_H +#include "auth.h" #include "malloc.h" +#include "utils.h" #include <stdbool.h> #include <string.h> -#include "utils.h" -#include "auth.h" bool is_verbose = false; -char * _model = NULL; +char *_model = NULL; #define DB_FILE "~/.r.db" static int prompt_max_tokens = 10000; #define PROMPT_TEMPERATURE 0.1 - - - void set_prompt_model(const char *model) { - if(_model != NULL) { - free(_model); - } - _model = strdup(model); + if (_model != NULL) { + free(_model); + } + _model = strdup(model); } -const char * get_prompt_model() { - if(auth_type != AUTH_TYPE_API_KEY) { - if(_model == NULL) { - _model = strdup("gpt-3.5-turbo"); - } - } else if(_model == NULL) { - _model = strdup("gpt-4o-mini"); +const char *get_prompt_model() { + if (auth_type != AUTH_TYPE_API_KEY) { + if (_model == NULL) { + _model = strdup("gpt-3.5-turbo"); } - return _model; + } else if (_model == NULL) { + _model = strdup("gpt-4o-mini"); + } + return _model; } - -#endif +#endif diff --git a/rpylib.c b/rpylib.c index 88d900b..92755c8 100644 --- a/rpylib.c +++ b/rpylib.c @@ -1,28 +1,29 @@ /* Written by retoor@molodetz.nl */ -/* -This C extension for Python provides a simple API for communication with an OpenAI service. -It includes functions to return a "Hello World" string, conduct a chat session through OpenAI, and reset the message history. +/* +This C extension for Python provides a simple API for communication with an +OpenAI service. It includes functions to return a "Hello World" string, conduct +a chat session through OpenAI, and reset the message history. */ -/* +/* Summary of used imports: - <Python.h>: Includes necessary Python headers to create a C extension. - "openai.h": Assumes an external library for OpenAI interaction. */ -/* -MIT License +/* +MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -34,72 +35,66 @@ SOFTWARE. */ #define PY_SSIZE_T_CLEAN -#include <Python.h> -#include "openai.h" #include "auth.h" +#include "openai.h" +#include <Python.h> -static PyObject* rpylib_reset(PyObject *self, PyObject *args) { - return PyUnicode_FromString("True"); +static PyObject *rpylib_reset(PyObject *self, PyObject *args) { + return PyUnicode_FromString("True"); } -static PyObject* rpylib_chat(PyObject *self, PyObject *args) { - const char *role, *message; - - - printf("That goes alright! 1\n"); - if (!PyArg_ParseTuple(args, "ss", &role, &message)) { - return NULL; - } - printf("That goes alright! 2\n"); - char *result = openai_chat(role, message); - PyObject *py_result = PyUnicode_FromString(result); - free(result); - return py_result; +static PyObject *rpylib_chat(PyObject *self, PyObject *args) { + const char *role, *message; + + printf("That goes alright! 1\n"); + if (!PyArg_ParseTuple(args, "ss", &role, &message)) { + return NULL; + } + printf("That goes alright! 2\n"); + char *result = openai_chat(role, message); + PyObject *py_result = PyUnicode_FromString(result); + free(result); + return py_result; } -static PyObject* rpylib_prompt(PyObject *self, PyObject *args) { - const char *role = "user"; - const char *message; - if (!PyArg_ParseTuple(args, "s", &message)) { - return NULL; - } - char *result = openai_chat(role, message); - PyObject *py_result = PyUnicode_FromString(result); - free(result); - return py_result; +static PyObject *rpylib_prompt(PyObject *self, PyObject *args) { + const char *role = "user"; + const char *message; + if (!PyArg_ParseTuple(args, "s", &message)) { + return NULL; + } + char *result = openai_chat(role, message); + PyObject *py_result = PyUnicode_FromString(result); + free(result); + return py_result; } -static PyObject* rpylib_system(PyObject *self, PyObject *args) { - const char *role = "system"; - const char *message; - if (!PyArg_ParseTuple(args, "s", &message)) { - return NULL; - } - char *result = openai_chat(role, message); - PyObject *py_result = PyUnicode_FromString(result); - free(result); - return py_result; +static PyObject *rpylib_system(PyObject *self, PyObject *args) { + const char *role = "system"; + const char *message; + if (!PyArg_ParseTuple(args, "s", &message)) { + return NULL; + } + char *result = openai_chat(role, message); + PyObject *py_result = PyUnicode_FromString(result); + free(result); + return py_result; } static PyMethodDef MyModuleMethods[] = { {"chat", rpylib_chat, METH_VARARGS, "Chat with OpenAI."}, //{"prompt", rpylib_prompt, METH_VARARGS, "Prompt to OpenAI."}, //{"system", rpylib_system, METH_VARARGS, "Add system message."}, {"reset", rpylib_reset, METH_NOARGS, "Reset message history."}, - {NULL, NULL, 0, NULL} -}; + {NULL, NULL, 0, NULL}}; static struct PyModuleDef rpylib = { - PyModuleDef_HEAD_INIT, - "rpylib", - "R - the power of R in Python, made by retoor.", - -1, - MyModuleMethods -}; + PyModuleDef_HEAD_INIT, "rpylib", + "R - the power of R in Python, made by retoor.", -1, MyModuleMethods}; PyMODINIT_FUNC PyInit_rpylib(void) { - auth_init(); - - printf("Init\n"); - void * res = PyModule_Create(&rpylib); - printf("GLOB\n"); - return res; + auth_init(); + + printf("Init\n"); + void *res = PyModule_Create(&rpylib); + printf("GLOB\n"); + return res; } diff --git a/rpylib.so b/rpylib.so index 3d316a2dfb28efb231dd2f66f6f8a90006efeadd..18f1b6b2997f73eae5b8b824a8485648fd912a57 100755 GIT binary patch delta 24059 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 delta 25488 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 diff --git a/tools.h b/tools.h index b294b8d..73f2e5b 100644 --- a/tools.h +++ b/tools.h @@ -1,1179 +1,1328 @@ // Written by retoor@molodetz.nl -// This code defines functions for HTTP requests and structuring tool descriptions and executions in JSON format using the JSON-C library. It uses cURL for HTTP requests. +// This code defines functions for HTTP requests and structuring tool +// descriptions and executions in JSON format using the JSON-C library. It uses +// cURL for HTTP requests. -// Imports not part of the language itself: JSON-C (json-c/json.h, json-c/json_object.h) and a custom header "http_curl.h" +// Imports not part of the language itself: JSON-C (json-c/json.h, +// json-c/json_object.h) and a custom header "http_curl.h" // MIT License #ifndef R_TOOLS_H #define R_TOOLS_H +#include "http_curl.h" #include "r.h" -#include <stdio.h> +#include "utils.h" +#include <dirent.h> +#include <glob.h> #include <json-c/json.h> #include <json-c/json_object.h> +#include <stdbool.h> +#include <stdio.h> #include <string.h> -#include "http_curl.h" -#include <dirent.h> #include <sys/stat.h> #include <time.h> -#include <glob.h> #include <unistd.h> -#include "utils.h" -#include <stdbool.h> #include <stdlib.h> #include <string.h> -#include "indexer.h" -#include "db_utils.h" -#include "r.h" #include "browse.h" +#include "db_utils.h" +#include "indexer.h" +#include "r.h" -struct json_object* tool_description_http_get(); -struct json_object* tool_description_linux_terminal(); -struct json_object* tool_description_directory_glob(); -struct json_object* tool_description_read_file(); -struct json_object* tool_description_write_file(); -struct json_object* tool_description_directory_rglob(); -struct json_object* tool_description_linux_terminal_interactive(); -struct json_object* tool_description_index_source_directory(); -struct json_object* tool_description_chdir(); -struct json_object* tool_description_getpwd(); -struct json_object* tool_description_db_set(); -struct json_object* tool_description_db_query(); -struct json_object* tool_description_db_get(); -struct json_object* tool_description_web_search_news(); -struct json_object* tool_description_web_search(); +struct json_object *tool_description_http_get(); +struct json_object *tool_description_linux_terminal(); +struct json_object *tool_description_directory_glob(); +struct json_object *tool_description_read_file(); +struct json_object *tool_description_write_file(); +struct json_object *tool_description_directory_rglob(); +struct json_object *tool_description_linux_terminal_interactive(); +struct json_object *tool_description_index_source_directory(); +struct json_object *tool_description_chdir(); +struct json_object *tool_description_getpwd(); +struct json_object *tool_description_db_set(); +struct json_object *tool_description_db_query(); +struct json_object *tool_description_db_get(); +struct json_object *tool_description_web_search_news(); +struct json_object *tool_description_web_search(); -struct json_object* tools_descriptions() { - struct json_object* root = json_object_new_array(); - json_object_array_add(root, tool_description_http_get()); - json_object_array_add(root, tool_description_linux_terminal()); - json_object_array_add(root, tool_description_directory_glob()); - json_object_array_add(root, tool_description_read_file()); - json_object_array_add(root, tool_description_write_file()); - json_object_array_add(root, tool_description_directory_rglob()); - json_object_array_add(root, tool_description_linux_terminal_interactive()); - json_object_array_add(root,tool_description_index_source_directory()); - json_object_array_add(root,tool_description_chdir()); - json_object_array_add(root,tool_description_getpwd()); - json_object_array_add(root,tool_description_db_set()); - json_object_array_add(root, tool_description_db_query()); - json_object_array_add(root, tool_description_db_get()); - json_object_array_add(root, tool_description_web_search_news()); - json_object_array_add(root, tool_description_web_search()); - return root; +struct json_object *tools_descriptions() { + struct json_object *root = json_object_new_array(); + json_object_array_add(root, tool_description_http_get()); + json_object_array_add(root, tool_description_linux_terminal()); + json_object_array_add(root, tool_description_directory_glob()); + json_object_array_add(root, tool_description_read_file()); + json_object_array_add(root, tool_description_write_file()); + json_object_array_add(root, tool_description_directory_rglob()); + json_object_array_add(root, tool_description_linux_terminal_interactive()); + json_object_array_add(root, tool_description_index_source_directory()); + json_object_array_add(root, tool_description_chdir()); + json_object_array_add(root, tool_description_getpwd()); + json_object_array_add(root, tool_description_db_set()); + json_object_array_add(root, tool_description_db_query()); + json_object_array_add(root, tool_description_db_get()); + json_object_array_add(root, tool_description_web_search_news()); + json_object_array_add(root, tool_description_web_search()); + return root; } -char* tool_function_web_search_news(char* query) { - if (query == NULL) { - return strdup("Query cannot be NULL."); +char *tool_function_web_search_news(char *query) { + if (query == NULL) { + return strdup("Query cannot be NULL."); + } + + char *result = web_search_news(query); + if (result == NULL) { + return strdup("Failed to fetch news."); + } + + return result; +} + +struct json_object *tool_description_web_search_news() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("web_search_news")); + json_object_object_add( + function, "description", + json_object_new_string("Searches for news articles based on a query.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + struct json_object *query = json_object_new_object(); + json_object_object_add(query, "type", json_object_new_string("string")); + json_object_object_add( + query, "description", + json_object_new_string( + "The url encoded query string to search for news articles.")); + json_object_object_add(properties, "query", query); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("query")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + +char *tool_function_web_search(char *query) { + if (query == NULL) { + return strdup("Query cannot be NULL."); + } + + char *result = web_search_news(query); + if (result == NULL) { + return strdup("Failed to fetch news."); + } + + return result; +} + +struct json_object *tool_description_web_search() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("web_search")); + json_object_object_add( + function, "description", + json_object_new_string("Searches for information based on a query using " + "search engines like google.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + struct json_object *query = json_object_new_object(); + json_object_object_add(query, "type", json_object_new_string("string")); + json_object_object_add( + query, "description", + json_object_new_string( + "The url encoded query string to search for information.")); + json_object_object_add(properties, "query", query); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("query")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + +char *tool_function_db_get(char *key) { + json_object *result = db_get(key); + if (result == NULL) { + return strdup("Failed to retrieve value from the database."); + } + + char *response = strdup(json_object_to_json_string(result)); + json_object_put(result); // Free the json_object + return response; +} + +struct json_object *tool_description_db_get() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", json_object_new_string("db_get")); + json_object_object_add( + function, "description", + json_object_new_string( + "Retrieves a value from the database for a given key.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + + struct json_object *key = json_object_new_object(); + json_object_object_add(key, "type", json_object_new_string("string")); + json_object_object_add( + key, "description", + json_object_new_string("The key to retrieve from the database.")); + json_object_object_add(properties, "key", key); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("key")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + +char *tool_function_db_query(char *query) { + json_object *result = db_query(query); + if (result == NULL) { + return strdup("Failed to execute query on the database."); + } + + char *response = strdup(json_object_to_json_string(result)); + + json_object_put(result); // Free the json_object + return response; +} +struct json_object *tool_description_db_query() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", json_object_new_string("db_query")); + json_object_object_add( + function, "description", + json_object_new_string( + "Executes a query on the database and returns the results.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + + struct json_object *query = json_object_new_object(); + json_object_object_add(query, "type", json_object_new_string("string")); + json_object_object_add(query, "description", + json_object_new_string("The SQL query to execute.")); + json_object_object_add(properties, "query", query); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("query")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + +char *tool_function_db_set(char *key, char *value) { + json_object *result = db_set(key, value); + if (result == NULL) { + return strdup("Failed to set value in the database."); + } + + const char *response = json_object_get_string(result); + json_object_put(result); // Free the json_object + return strdup(response); +} +struct json_object *tool_description_db_set() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", json_object_new_string("db_set")); + json_object_object_add( + function, "description", + json_object_new_string("Sets a value in the database for a given key.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + + struct json_object *key = json_object_new_object(); + json_object_object_add(key, "type", json_object_new_string("string")); + json_object_object_add( + key, "description", + json_object_new_string("The key to set in the database.")); + json_object_object_add(properties, "key", key); + + struct json_object *value = json_object_new_object(); + json_object_object_add(value, "type", json_object_new_string("string")); + json_object_object_add( + value, "description", + json_object_new_string("The value to set for the given key.")); + json_object_object_add(properties, "value", value); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("key")); + json_object_array_add(required, json_object_new_string("value")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + +char *tool_function_http_get(char *url) { return curl_get(url); } + +char *tool_function_chdir(char *path) { + if (chdir(path) != 0) { + perror("chdir failed"); + return strdup("Failed to change directory!"); + } + + return strdup("Directory successfully changed."); +} + +char *tool_function_linux_terminal(char *command) { + FILE *fp; + char buffer[1024]; + size_t total_size = 0; + char *output = NULL; + + fp = popen(command, "r"); + if (fp == NULL) { + perror("popen failed"); + return strdup("Popen failed!"); + } + + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + size_t chunk_size = strlen(buffer); + char *new_output = realloc(output, total_size + chunk_size + 1); + if (new_output == NULL) { + perror("realloc failed"); + free(output); + pclose(fp); + return strdup("Failed to allocate memory!"); } + output = new_output; + if (is_verbose) + fprintf(stderr, "%s", buffer); + strcpy(output + total_size, buffer); + total_size += chunk_size; + } - char* result = web_search_news(query); - if (result == NULL) { - return strdup("Failed to fetch news."); - } - - return result; + pclose(fp); + return output ? output : strdup(""); } +char *tool_function_linux_terminal_interactive(char *command) { + int result_code = system(command); -struct json_object* tool_description_web_search_news() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); + char *result = malloc(100); + result[0] = 0; + sprintf(result, "Command exited with status code %d.", result_code); - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("web_search_news")); - json_object_object_add(function, "description", json_object_new_string("Searches for news articles based on a query.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* query = json_object_new_object(); - json_object_object_add(query, "type", json_object_new_string("string")); - json_object_object_add(query, "description", json_object_new_string("The url encoded query string to search for news articles.")); - json_object_object_add(properties, "query", query); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("query")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; + return result; } -char* tool_function_web_search(char* query) { - if (query == NULL) { - return strdup("Query cannot be NULL."); - } +char *tool_function_getpwd() { + char *cwd = (char *)malloc(PATH_MAX); + if (cwd == NULL) { + perror("Memory allocation failed"); + return strdup("Failed to allocate memory for current working directory!"); + } - char* result = web_search_news(query); - if (result == NULL) { - return strdup("Failed to fetch news."); - } + if (getcwd(cwd, PATH_MAX) == NULL) { + free(cwd); + perror("getcwd failed"); + return strdup("Failed to get current working directory!"); + } - return result; + return cwd; } +struct json_object *tool_description_getpwd() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); -struct json_object* tool_description_web_search() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", json_object_new_string("getpwd")); + json_object_object_add( + function, "description", + json_object_new_string( + "Returns the current working directory as a string.")); - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("web_search")); - json_object_object_add(function, "description", json_object_new_string("Searches for information based on a query using search engines like google.")); + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); + json_object_object_add(function, "parameters", json_object_new_null()); - struct json_object* properties = json_object_new_object(); - struct json_object* query = json_object_new_object(); - json_object_object_add(query, "type", json_object_new_string("string")); - json_object_object_add(query, "description", json_object_new_string("The url encoded query string to search for information.")); - json_object_object_add(properties, "query", query); + json_object_object_add(root, "function", function); - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("query")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; + return root; } +struct json_object *tool_description_chdir() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", json_object_new_string("chdir")); + json_object_object_add( + function, "description", + json_object_new_string( + "Changes the current working directory to the specified path. Call " + "this function when `cd` is prompted.")); + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + struct json_object *properties = json_object_new_object(); + struct json_object *path = json_object_new_object(); + json_object_object_add(path, "type", json_object_new_string("string")); + json_object_object_add( + path, "description", + json_object_new_string( + "Path to change the current working directory to.")); + json_object_object_add(properties, "path", path); + json_object_object_add(parameters, "properties", properties); -char* tool_function_db_get(char* key) { - json_object* result = db_get(key); - if (result == NULL) { - return strdup("Failed to retrieve value from the database."); - } - - char* response = strdup(json_object_to_json_string(result)); - json_object_put(result); // Free the json_object - return response; + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("path")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; } +struct json_object *tool_description_index_source_directory() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("index_source_directory")); + json_object_object_add( + function, "description", + json_object_new_string("Returns a JSON array containing every source " + "file with it's contents from given directory. " + "Execute with '.' for current directory.")); + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); -struct json_object* tool_description_db_get() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *properties = json_object_new_object(); + struct json_object *path = json_object_new_object(); + json_object_object_add(path, "type", json_object_new_string("string")); + json_object_object_add( + path, "description", + json_object_new_string("Path to index and retreive files from.")); + json_object_object_add(properties, "path", path); - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("db_get")); - json_object_object_add(function, "description", json_object_new_string("Retrieves a value from the database for a given key.")); + json_object_object_add(parameters, "properties", properties); - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("path")); + json_object_object_add(parameters, "required", required); - struct json_object* properties = json_object_new_object(); - - struct json_object* key = json_object_new_object(); - json_object_object_add(key, "type", json_object_new_string("string")); - json_object_object_add(key, "description", json_object_new_string("The key to retrieve from the database.")); - json_object_object_add(properties, "key", key); + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); - json_object_object_add(parameters, "properties", properties); + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("key")); - json_object_object_add(parameters, "required", required); + json_object_object_add(root, "function", function); - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; + return root; } +struct json_object *tool_description_linux_terminal_interactive() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); -char* tool_function_db_query(char* query) { - json_object* result = db_query(query); - if (result == NULL) { - return strdup("Failed to execute query on the database."); - } - - char* response = strdup(json_object_to_json_string(result)); - + struct json_object *function = json_object_new_object(); + json_object_object_add( + function, "name", + json_object_new_string("linux_terminal_execute_interactive")); + json_object_object_add( + function, "description", + json_object_new_string( + "Executes interactive terminal for user. You will not be able to " + "read the result. Do not use if you need to know output.")); - json_object_put(result); // Free the json_object - return response; -} -struct json_object* tool_description_db_query() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("db_query")); - json_object_object_add(function, "description", json_object_new_string("Executes a query on the database and returns the results.")); + struct json_object *properties = json_object_new_object(); + struct json_object *path = json_object_new_object(); + json_object_object_add(path, "type", json_object_new_string("string")); + json_object_object_add( + path, "description", + json_object_new_string( + "Executable with parameters to execute interactively.")); + json_object_object_add(properties, "command", path); - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); + json_object_object_add(parameters, "properties", properties); - struct json_object* properties = json_object_new_object(); - - struct json_object* query = json_object_new_object(); - json_object_object_add(query, "type", json_object_new_string("string")); - json_object_object_add(query, "description", json_object_new_string("The SQL query to execute.")); - json_object_object_add(properties, "query", query); + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("command")); + json_object_object_add(parameters, "required", required); - json_object_object_add(parameters, "properties", properties); + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("query")); - json_object_object_add(parameters, "required", required); + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); + json_object_object_add(root, "function", function); - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; + return root; } +struct json_object *tool_description_directory_rglob() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("directory_rglob")); + json_object_object_add( + function, "description", + json_object_new_string( + "Recursively list the contents of a specified directory in glob " + "format. " + "Result is a JSON array containing objects with keys: name, " + "modification_date(iso), creation_date(iso), type, and size_bytes.")); -char* tool_function_db_set(char* key, char* value) { - json_object* result = db_set(key, value); - if (result == NULL) { - return strdup("Failed to set value in the database."); - } - - const char* response = json_object_get_string(result); - json_object_put(result); // Free the json_object - return strdup(response); -} -struct json_object* tool_description_db_set() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("db_set")); - json_object_object_add(function, "description", json_object_new_string("Sets a value in the database for a given key.")); + struct json_object *properties = json_object_new_object(); + struct json_object *directory = json_object_new_object(); + json_object_object_add(directory, "type", json_object_new_string("string")); + json_object_object_add( + directory, "description", + json_object_new_string("Path to the directory to list in glob format.")); + json_object_object_add(properties, "path", directory); - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); + json_object_object_add(parameters, "properties", properties); - struct json_object* properties = json_object_new_object(); - - struct json_object* key = json_object_new_object(); - json_object_object_add(key, "type", json_object_new_string("string")); - json_object_object_add(key, "description", json_object_new_string("The key to set in the database.")); - json_object_object_add(properties, "key", key); + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("path")); + json_object_object_add(parameters, "required", required); - struct json_object* value = json_object_new_object(); - json_object_object_add(value, "type", json_object_new_string("string")); - json_object_object_add(value, "description", json_object_new_string("The value to set for the given key.")); - json_object_object_add(properties, "value", value); + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); - json_object_object_add(parameters, "properties", properties); + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("key")); - json_object_array_add(required, json_object_new_string("value")); - json_object_object_add(parameters, "required", required); + json_object_object_add(root, "function", function); - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; + return root; } +struct json_object *tool_description_read_file() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", json_object_new_string("read_file")); + json_object_object_add( + function, "description", + json_object_new_string("Reads / opens / loads a file and returns its " + "contents as a string.")); -char* tool_function_http_get(char* url) { - return curl_get(url); + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + struct json_object *path = json_object_new_object(); + json_object_object_add(path, "type", json_object_new_string("string")); + json_object_object_add( + path, "description", + json_object_new_string("Path to the file to read / open / load.")); + json_object_object_add(properties, "path", path); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("path")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; } -char* tool_function_chdir(char* path) { - if (chdir(path) != 0) { - perror("chdir failed"); - return strdup("Failed to change directory!"); - } +struct json_object *tool_description_write_file() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); - return strdup("Directory successfully changed."); + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("write_file")); + json_object_object_add( + function, "description", + json_object_new_string( + "Writes / saves / stores content to a file. Content should be in " + "plain format, not json encoded.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + + struct json_object *path = json_object_new_object(); + json_object_object_add(path, "type", json_object_new_string("string")); + json_object_object_add( + path, "description", + json_object_new_string( + "Path to the plain file to write / save / store.")); + json_object_object_add(properties, "path", path); + + struct json_object *content = json_object_new_object(); + json_object_object_add(content, "type", json_object_new_string("string")); + json_object_object_add( + content, "description", + json_object_new_string( + "Plain content to write / save / store into the file.")); + json_object_object_add(properties, "content", content); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("path")); + json_object_array_add(required, json_object_new_string("content")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; } - - -char* tool_function_linux_terminal(char* command) { - FILE* fp; - char buffer[1024]; - size_t total_size = 0; - char* output = NULL; - - fp = popen(command, "r"); - if (fp == NULL) { - perror("popen failed"); - return strdup("Popen failed!"); - } - - while (fgets(buffer, sizeof(buffer), fp) != NULL) { - size_t chunk_size = strlen(buffer); - char* new_output = realloc(output, total_size + chunk_size + 1); - if (new_output == NULL) { - perror("realloc failed"); - free(output); - pclose(fp); - return strdup("Failed to allocate memory!"); - } - output = new_output; - if(is_verbose) - fprintf(stderr, "%s", buffer); - strcpy(output + total_size, buffer); - total_size += chunk_size; - } - - pclose(fp); - return output ? output : strdup(""); +char *tool_function_index_source_directory(char *path) { + return index_directory(path); } -char* tool_function_linux_terminal_interactive(char* command) { - int result_code = system(command); +char *tool_function_read_file(char *path) { - char* result = malloc(100); - result[0] = 0; - sprintf(result, "Command exited with status code %d.", result_code); + char *expanded_path = expand_home_directory(path); - return result; -} + FILE *fp = fopen(expanded_path, "r"); + free(expanded_path); + if (fp == NULL) { + perror("fopen failed"); + return strdup("Failed to open file for reading!"); + } -char* tool_function_getpwd() { - char* cwd = (char*)malloc(PATH_MAX); - if (cwd == NULL) { - perror("Memory allocation failed"); - return strdup("Failed to allocate memory for current working directory!"); - } + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + rewind(fp); - if (getcwd(cwd, PATH_MAX) == NULL) { - free(cwd); - perror("getcwd failed"); - return strdup("Failed to get current working directory!"); - } - - return cwd; -} - -struct json_object* tool_description_getpwd() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("getpwd")); - json_object_object_add(function, "description", json_object_new_string("Returns the current working directory as a string.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - - - json_object_object_add(function, "parameters", json_object_new_null()); - - json_object_object_add(root, "function", function); - - return root; -} - -struct json_object* tool_description_chdir() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("chdir")); - json_object_object_add(function, "description", json_object_new_string("Changes the current working directory to the specified path. Call this function when `cd` is prompted.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* path = json_object_new_object(); - json_object_object_add(path, "type", json_object_new_string("string")); - json_object_object_add(path, "description", json_object_new_string("Path to change the current working directory to.")); - json_object_object_add(properties, "path", path); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("path")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; -} - - - -struct json_object* tool_description_index_source_directory() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("index_source_directory")); - json_object_object_add(function, "description", json_object_new_string("Returns a JSON array containing every source file with it's contents from given directory. Execute with '.' for current directory.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* path = json_object_new_object(); - json_object_object_add(path, "type", json_object_new_string("string")); - json_object_object_add(path, "description", json_object_new_string("Path to index and retreive files from.")); - json_object_object_add(properties, "path", path); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("path")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; - -} - -struct json_object* tool_description_linux_terminal_interactive() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("linux_terminal_execute_interactive")); - json_object_object_add(function, "description", json_object_new_string("Executes interactive terminal for user. You will not be able to read the result. Do not use if you need to know output.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* path = json_object_new_object(); - json_object_object_add(path, "type", json_object_new_string("string")); - json_object_object_add(path, "description", json_object_new_string("Executable with parameters to execute interactively.")); - json_object_object_add(properties, "command", path); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("command")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; -} - -struct json_object* tool_description_directory_rglob() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("directory_rglob")); - json_object_object_add(function, "description", json_object_new_string("Recursively list the contents of a specified directory in glob format. " - "Result is a JSON array containing objects with keys: name, modification_date(iso), creation_date(iso), type, and size_bytes.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* directory = json_object_new_object(); - json_object_object_add(directory, "type", json_object_new_string("string")); - json_object_object_add(directory, "description", json_object_new_string("Path to the directory to list in glob format.")); - json_object_object_add(properties, "path", directory); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("path")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; -} - -struct json_object* tool_description_read_file() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("read_file")); - json_object_object_add(function, "description", json_object_new_string("Reads / opens / loads a file and returns its contents as a string.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* path = json_object_new_object(); - json_object_object_add(path, "type", json_object_new_string("string")); - json_object_object_add(path, "description", json_object_new_string("Path to the file to read / open / load.")); - json_object_object_add(properties, "path", path); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("path")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; -} - -struct json_object* tool_description_write_file() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("write_file")); - json_object_object_add(function, "description", json_object_new_string("Writes / saves / stores content to a file. Content should be in plain format, not json encoded.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - - struct json_object* path = json_object_new_object(); - json_object_object_add(path, "type", json_object_new_string("string")); - json_object_object_add(path, "description", json_object_new_string("Path to the plain file to write / save / store.")); - json_object_object_add(properties, "path", path); - - struct json_object* content = json_object_new_object(); - json_object_object_add(content, "type", json_object_new_string("string")); - json_object_object_add(content, "description", json_object_new_string("Plain content to write / save / store into the file.")); - json_object_object_add(properties, "content", content); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("path")); - json_object_array_add(required, json_object_new_string("content")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; -} - -char* tool_function_index_source_directory(char * path){ - return index_directory(path); -} - -char* tool_function_read_file(char* path) { - - char * expanded_path = expand_home_directory(path); - - FILE* fp = fopen(expanded_path, "r"); - free(expanded_path); - if (fp == NULL) { - perror("fopen failed"); - return strdup("Failed to open file for reading!"); - } - - fseek(fp, 0, SEEK_END); - long size = ftell(fp); - rewind(fp); - - char* content = (char *)malloc(size + 1); - if (content == NULL) { - fclose(fp); - return strdup("Memory allocation failed!"); - } - - ssize_t read_size = fread(content, 1, size, fp); - - content[read_size] = '\0'; + char *content = (char *)malloc(size + 1); + if (content == NULL) { fclose(fp); + return strdup("Memory allocation failed!"); + } - return content; + ssize_t read_size = fread(content, 1, size, fp); + + content[read_size] = '\0'; + fclose(fp); + + return content; } -char* tool_function_write_file(char* path, char* content) { - FILE* fp = fopen(path, "w"); - if (fp == NULL) { - perror("fopen failed"); - return strdup("Failed to open file for writing!"); - } +char *tool_function_write_file(char *path, char *content) { + FILE *fp = fopen(path, "w"); + if (fp == NULL) { + perror("fopen failed"); + return strdup("Failed to open file for writing!"); + } - fwrite(content, 1, strlen(content), fp); - fclose(fp); + fwrite(content, 1, strlen(content), fp); + fclose(fp); - return strdup("File successfully written."); + return strdup("File successfully written."); } -const char* get_file_type(struct stat* st) { - if (S_ISREG(st->st_mode)) return "file"; - if (S_ISDIR(st->st_mode)) return "directory"; - return "other"; +const char *get_file_type(struct stat *st) { + if (S_ISREG(st->st_mode)) + return "file"; + if (S_ISDIR(st->st_mode)) + return "directory"; + return "other"; } -void format_time(time_t raw_time, char* buffer, size_t size) { - struct tm* time_info = localtime(&raw_time); - strftime(buffer, size, "%Y-%m-%d %H:%M:%S", time_info); +void format_time(time_t raw_time, char *buffer, size_t size) { + struct tm *time_info = localtime(&raw_time); + strftime(buffer, size, "%Y-%m-%d %H:%M:%S", time_info); } -void recursive_glob(const char* pattern, glob_t* results) { - glob_t current_matches; - int ret = glob(pattern, GLOB_NOSORT | GLOB_TILDE, NULL, ¤t_matches); +void recursive_glob(const char *pattern, glob_t *results) { + glob_t current_matches; + int ret = glob(pattern, GLOB_NOSORT | GLOB_TILDE, NULL, ¤t_matches); - if (ret != 0 && ret != GLOB_NOMATCH) { - results->gl_pathc = 0; - results->gl_pathv = NULL; - results->gl_offs = 0; - return; - } + if (ret != 0 && ret != GLOB_NOMATCH) { + results->gl_pathc = 0; + results->gl_pathv = NULL; + results->gl_offs = 0; + return; + } - if (results->gl_pathv == NULL) { - memset(results, 0, sizeof(glob_t)); - } + if (results->gl_pathv == NULL) { + memset(results, 0, sizeof(glob_t)); + } - for (size_t i = 0; i < current_matches.gl_pathc; i++) { - char* path = current_matches.gl_pathv[i]; + for (size_t i = 0; i < current_matches.gl_pathc; i++) { + char *path = current_matches.gl_pathv[i]; - if (results->gl_pathc == 0) { - results->gl_pathc = 1; - results->gl_pathv = malloc(sizeof(char*)); - results->gl_pathv[0] = strdup(path); - } else { - results->gl_pathc++; - results->gl_pathv = realloc(results->gl_pathv, - results->gl_pathc * sizeof(char*)); - results->gl_pathv[results->gl_pathc - 1] = strdup(path); - } - } - - DIR* dir; - struct dirent* entry; - struct stat statbuf; - - char* pattern_copy = strdup(pattern); - char* last_slash = strrchr(pattern_copy, '/'); - char* dir_path; - char* file_pattern; - - if (last_slash) { - *last_slash = '\0'; - dir_path = pattern_copy; - file_pattern = last_slash + 1; + if (results->gl_pathc == 0) { + results->gl_pathc = 1; + results->gl_pathv = malloc(sizeof(char *)); + results->gl_pathv[0] = strdup(path); } else { - dir_path = "."; - file_pattern = pattern_copy; + results->gl_pathc++; + results->gl_pathv = + realloc(results->gl_pathv, results->gl_pathc * sizeof(char *)); + results->gl_pathv[results->gl_pathc - 1] = strdup(path); } + } - if ((dir = opendir(dir_path)) != NULL) { - while ((entry = readdir(dir)) != NULL) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - continue; - } + DIR *dir; + struct dirent *entry; + struct stat statbuf; - char full_path[PATH_MAX]; - int path_len; + char *pattern_copy = strdup(pattern); + char *last_slash = strrchr(pattern_copy, '/'); + char *dir_path; + char *file_pattern; - if (strcmp(dir_path, ".") == 0) { - path_len = snprintf(full_path, PATH_MAX, "%s", entry->d_name); - } else { - path_len = snprintf(full_path, PATH_MAX, "%s/%s", dir_path, entry->d_name); - } + if (last_slash) { + *last_slash = '\0'; + dir_path = pattern_copy; + file_pattern = last_slash + 1; + } else { + dir_path = "."; + file_pattern = pattern_copy; + } - if (path_len >= PATH_MAX) { - continue; - } + if ((dir = opendir(dir_path)) != NULL) { + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } - if (stat(full_path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { - char new_pattern[PATH_MAX]; - int new_pattern_len = snprintf(new_pattern, PATH_MAX, "%s/%s", full_path, file_pattern); + char full_path[PATH_MAX]; + int path_len; - if (new_pattern_len >= PATH_MAX) { - continue; - } + if (strcmp(dir_path, ".") == 0) { + path_len = snprintf(full_path, PATH_MAX, "%s", entry->d_name); + } else { + path_len = + snprintf(full_path, PATH_MAX, "%s/%s", dir_path, entry->d_name); + } - recursive_glob(new_pattern, results); - } - } - closedir(dir); - } + if (path_len >= PATH_MAX) { + continue; + } - free(pattern_copy); - globfree(¤t_matches); -} + if (stat(full_path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { + char new_pattern[PATH_MAX]; + int new_pattern_len = + snprintf(new_pattern, PATH_MAX, "%s/%s", full_path, file_pattern); -char* tool_function_directory_rglob(char* target_dir) { - glob_t results; - results.gl_pathc = 0; - struct stat file_stat; - char mod_time[20], create_time[20]; - - recursive_glob(target_dir, &results); - - json_object* json_array = json_object_new_array(); - - for (size_t i = 0; i < results.gl_pathc; i++) { - const char* file_path = results.gl_pathv[i]; - - if (stat(file_path, &file_stat) == -1) { - perror("stat failed"); - continue; + if (new_pattern_len >= PATH_MAX) { + continue; } - format_time(file_stat.st_mtime, mod_time, sizeof(mod_time)); - format_time(file_stat.st_ctime, create_time, sizeof(create_time)); - - json_object* json_entry = json_object_new_object(); - json_object_object_add(json_entry, "name", json_object_new_string(file_path)); - json_object_object_add(json_entry, "modification_date", json_object_new_string(mod_time)); - json_object_object_add(json_entry, "creation_date", json_object_new_string(create_time)); - json_object_object_add(json_entry, "type", json_object_new_string(get_file_type(&file_stat))); - json_object_object_add(json_entry, "size_bytes", json_object_new_int64(file_stat.st_size)); - - json_object_array_add(json_array, json_entry); + recursive_glob(new_pattern, results); + } } + closedir(dir); + } - globfree(&results); - char* result = strdup(json_object_to_json_string_ext(json_array, JSON_C_TO_STRING_PRETTY)); - - json_object_put(json_array); - - return result; + free(pattern_copy); + globfree(¤t_matches); } -char* tool_function_directory_glob(char* target_dir) { - glob_t results; - struct stat file_stat; - char mod_time[20], create_time[20]; +char *tool_function_directory_rglob(char *target_dir) { + glob_t results; + results.gl_pathc = 0; + struct stat file_stat; + char mod_time[20], create_time[20]; - if (!strcmp(target_dir, ".")) { - target_dir[0] = '*'; + recursive_glob(target_dir, &results); + + json_object *json_array = json_object_new_array(); + + for (size_t i = 0; i < results.gl_pathc; i++) { + const char *file_path = results.gl_pathv[i]; + + if (stat(file_path, &file_stat) == -1) { + perror("stat failed"); + continue; } - if (glob(target_dir, GLOB_TILDE, NULL, &results) != 0) { - perror("glob failed"); - return strdup(""); + format_time(file_stat.st_mtime, mod_time, sizeof(mod_time)); + format_time(file_stat.st_ctime, create_time, sizeof(create_time)); + + json_object *json_entry = json_object_new_object(); + json_object_object_add(json_entry, "name", + json_object_new_string(file_path)); + json_object_object_add(json_entry, "modification_date", + json_object_new_string(mod_time)); + json_object_object_add(json_entry, "creation_date", + json_object_new_string(create_time)); + json_object_object_add(json_entry, "type", + json_object_new_string(get_file_type(&file_stat))); + json_object_object_add(json_entry, "size_bytes", + json_object_new_int64(file_stat.st_size)); + + json_object_array_add(json_array, json_entry); + } + + globfree(&results); + char *result = strdup( + json_object_to_json_string_ext(json_array, JSON_C_TO_STRING_PRETTY)); + + json_object_put(json_array); + + return result; +} + +char *tool_function_directory_glob(char *target_dir) { + glob_t results; + struct stat file_stat; + char mod_time[20], create_time[20]; + + if (!strcmp(target_dir, ".")) { + target_dir[0] = '*'; + } + + if (glob(target_dir, GLOB_TILDE, NULL, &results) != 0) { + perror("glob failed"); + return strdup(""); + } + + json_object *json_array = json_object_new_array(); + + for (size_t i = 0; i < results.gl_pathc; i++) { + const char *file_path = results.gl_pathv[i]; + + if (stat(file_path, &file_stat) == -1) { + perror("stat failed"); + continue; } - json_object* json_array = json_object_new_array(); + format_time(file_stat.st_mtime, mod_time, sizeof(mod_time)); + format_time(file_stat.st_ctime, create_time, sizeof(create_time)); - for (size_t i = 0; i < results.gl_pathc; i++) { - const char* file_path = results.gl_pathv[i]; + json_object *json_entry = json_object_new_object(); + json_object_object_add(json_entry, "name", + json_object_new_string(file_path)); + json_object_object_add(json_entry, "modification_date", + json_object_new_string(mod_time)); + json_object_object_add(json_entry, "creation_date", + json_object_new_string(create_time)); + json_object_object_add(json_entry, "type", + json_object_new_string(get_file_type(&file_stat))); + json_object_object_add(json_entry, "size_bytes", + json_object_new_int64(file_stat.st_size)); - if (stat(file_path, &file_stat) == -1) { - perror("stat failed"); - continue; + json_object_array_add(json_array, json_entry); + } + + globfree(&results); + char *result = strdup( + json_object_to_json_string_ext(json_array, JSON_C_TO_STRING_PRETTY)); + + json_object_put(json_array); + + return result; +} + +struct json_object *tool_description_http_get() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("http_fetch")); + json_object_object_add(function, "description", + json_object_new_string("Get the contents of a URL.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + struct json_object *url = json_object_new_object(); + json_object_object_add(url, "type", json_object_new_string("string")); + json_object_object_add(url, "description", + json_object_new_string("Fetch URL contents.")); + json_object_object_add(properties, "url", url); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("url")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + +struct json_object *tool_description_directory_glob() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("directory_glob")); + json_object_object_add( + function, "description", + json_object_new_string( + "List the contents of a specified directory in glob format. " + "Result is a JSON array containing objects with keys: name, " + "modification_date(iso), creation_date(iso), type, and size_bytes.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + struct json_object *directory = json_object_new_object(); + json_object_object_add(directory, "type", json_object_new_string("string")); + json_object_object_add( + directory, "description", + json_object_new_string("Path to the directory to list in glob format.")); + json_object_object_add(properties, "path", directory); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("path")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + +struct json_object *tool_description_linux_terminal() { + struct json_object *root = json_object_new_object(); + json_object_object_add(root, "type", json_object_new_string("function")); + + struct json_object *function = json_object_new_object(); + json_object_object_add(function, "name", + json_object_new_string("linux_terminal_execute")); + json_object_object_add( + function, "description", + json_object_new_string( + "Execute a linux_terminal command on user terminal.")); + + struct json_object *parameters = json_object_new_object(); + json_object_object_add(parameters, "type", json_object_new_string("object")); + + struct json_object *properties = json_object_new_object(); + struct json_object *url = json_object_new_object(); + json_object_object_add(url, "type", json_object_new_string("string")); + json_object_object_add(url, "description", + json_object_new_string("Bash command to execute.")); + json_object_object_add(properties, "command", url); + + json_object_object_add(parameters, "properties", properties); + + struct json_object *required = json_object_new_array(); + json_object_array_add(required, json_object_new_string("command")); + json_object_object_add(parameters, "required", required); + + json_object_object_add(parameters, "additionalProperties", + json_object_new_boolean(0)); + + json_object_object_add(function, "parameters", parameters); + json_object_object_add(function, "strict", json_object_new_boolean(1)); + + json_object_object_add(root, "function", function); + + return root; +} + +struct json_object *tools_execute(struct json_object *tools_array) { + struct json_object *tools_result_messages = json_object_new_array(); + int array_len = json_object_array_length(tools_array); + + for (int i = 0; i < array_len; i++) { + struct json_object *obj = json_object_array_get_idx(tools_array, i); + struct json_object *tool_result = json_object_new_object(); + + json_object_object_add(tool_result, "tool_call_id", + json_object_new_string(json_object_get_string( + json_object_object_get(obj, "id")))); + json_object_object_add(tool_result, "role", json_object_new_string("tool")); + + struct json_object *type_obj; + if (json_object_object_get_ex(obj, "type", &type_obj)) { + if (strcmp(json_object_get_string(type_obj), "function")) { + continue; + } + } + + struct json_object *function_obj; + if (json_object_object_get_ex(obj, "function", &function_obj)) { + struct json_object *name_obj; + char *function_name = NULL; + if (json_object_object_get_ex(function_obj, "name", &name_obj)) { + function_name = (char *)json_object_get_string(name_obj); + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + + if (is_verbose) + fprintf(stderr, "Executing function %s with arguments %s\n", + function_name, json_object_to_json_string(arguments)); } + } - format_time(file_stat.st_mtime, mod_time, sizeof(mod_time)); - format_time(file_stat.st_ctime, create_time, sizeof(create_time)); - - json_object* json_entry = json_object_new_object(); - json_object_object_add(json_entry, "name", json_object_new_string(file_path)); - json_object_object_add(json_entry, "modification_date", json_object_new_string(mod_time)); - json_object_object_add(json_entry, "creation_date", json_object_new_string(create_time)); - json_object_object_add(json_entry, "type", json_object_new_string(get_file_type(&file_stat))); - json_object_object_add(json_entry, "size_bytes", json_object_new_int64(file_stat.st_size)); - - json_object_array_add(json_array, json_entry); - } - - globfree(&results); - char* result = strdup(json_object_to_json_string_ext(json_array, JSON_C_TO_STRING_PRETTY)); - - json_object_put(json_array); - - return result; -} - -struct json_object* tool_description_http_get() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("http_fetch")); - json_object_object_add(function, "description", json_object_new_string("Get the contents of a URL.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* url = json_object_new_object(); - json_object_object_add(url, "type", json_object_new_string("string")); - json_object_object_add(url, "description", json_object_new_string("Fetch URL contents.")); - json_object_object_add(properties, "url", url); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("url")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; -} - -struct json_object* tool_description_directory_glob() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("directory_glob")); - json_object_object_add(function, "description", json_object_new_string("List the contents of a specified directory in glob format. " - "Result is a JSON array containing objects with keys: name, modification_date(iso), creation_date(iso), type, and size_bytes.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* directory = json_object_new_object(); - json_object_object_add(directory, "type", json_object_new_string("string")); - json_object_object_add(directory, "description", json_object_new_string("Path to the directory to list in glob format.")); - json_object_object_add(properties, "path", directory); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("path")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; -} - -struct json_object* tool_description_linux_terminal() { - struct json_object* root = json_object_new_object(); - json_object_object_add(root, "type", json_object_new_string("function")); - - struct json_object* function = json_object_new_object(); - json_object_object_add(function, "name", json_object_new_string("linux_terminal_execute")); - json_object_object_add(function, "description", json_object_new_string("Execute a linux_terminal command on user terminal.")); - - struct json_object* parameters = json_object_new_object(); - json_object_object_add(parameters, "type", json_object_new_string("object")); - - struct json_object* properties = json_object_new_object(); - struct json_object* url = json_object_new_object(); - json_object_object_add(url, "type", json_object_new_string("string")); - json_object_object_add(url, "description", json_object_new_string("Bash command to execute.")); - json_object_object_add(properties, "command", url); - - json_object_object_add(parameters, "properties", properties); - - struct json_object* required = json_object_new_array(); - json_object_array_add(required, json_object_new_string("command")); - json_object_object_add(parameters, "required", required); - - json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0)); - - json_object_object_add(function, "parameters", parameters); - json_object_object_add(function, "strict", json_object_new_boolean(1)); - - json_object_object_add(root, "function", function); - - return root; -} - -struct json_object* tools_execute(struct json_object* tools_array) { - struct json_object* tools_result_messages = json_object_new_array(); - int array_len = json_object_array_length(tools_array); - - for (int i = 0; i < array_len; i++) { - struct json_object* obj = json_object_array_get_idx(tools_array, i); - struct json_object* tool_result = json_object_new_object(); - - json_object_object_add(tool_result, "tool_call_id", - json_object_new_string(json_object_get_string( - json_object_object_get(obj, "id")))); - json_object_object_add(tool_result, "role", json_object_new_string("tool")); - - struct json_object* type_obj; - if (json_object_object_get_ex(obj, "type", &type_obj)) { - if (strcmp(json_object_get_string(type_obj), "function")) { - continue; - } + if (!strcmp(function_name, "linux_terminal_execute")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *url_obj; + if (json_object_object_get_ex(arguments, "command", &url_obj)) { + char *command = (char *)json_object_get_string(url_obj); + char *terminal_result = tool_function_linux_terminal(command); + json_object_object_add(tool_result, "content", + json_object_new_string(terminal_result)); + free(terminal_result); + } } - - struct json_object* function_obj; - if (json_object_object_get_ex(obj, "function", &function_obj)) { - struct json_object* name_obj; - char* function_name = NULL; - if (json_object_object_get_ex(function_obj, "name", &name_obj)) { - function_name = (char*)json_object_get_string(name_obj); - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - - if(is_verbose) - fprintf(stderr, "Executing function %s with arguments %s\n", function_name, json_object_to_json_string(arguments)); - } - - } - - if (!strcmp(function_name, "linux_terminal_execute")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* url_obj; - if (json_object_object_get_ex(arguments, "command", &url_obj)) { - char* command = (char*)json_object_get_string(url_obj); - char* terminal_result = tool_function_linux_terminal(command); - json_object_object_add(tool_result, "content", json_object_new_string(terminal_result)); - free(terminal_result); - } - } - } else if (!strcmp(function_name, "linux_terminal_execute_interactive")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* url_obj; - if (json_object_object_get_ex(arguments, "command", &url_obj)) { - char* command = (char*)json_object_get_string(url_obj); - char* terminal_result = tool_function_linux_terminal_interactive(command); - json_object_object_add(tool_result, "content", json_object_new_string(terminal_result)); - free(terminal_result); - } - } - }else if (!strcmp(function_name, "chdir")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* path_obj; - if (json_object_object_get_ex(arguments, "path", &path_obj)) { - char* path = (char*)json_object_get_string(path_obj); - char* chdir_result = tool_function_chdir(path); - json_object_object_add(tool_result, "content", json_object_new_string(chdir_result)); + } else if (!strcmp(function_name, "linux_terminal_execute_interactive")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *url_obj; + if (json_object_object_get_ex(arguments, "command", &url_obj)) { + char *command = (char *)json_object_get_string(url_obj); + char *terminal_result = + tool_function_linux_terminal_interactive(command); + json_object_object_add(tool_result, "content", + json_object_new_string(terminal_result)); + free(terminal_result); + } + } + } else if (!strcmp(function_name, "chdir")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *path_obj; + if (json_object_object_get_ex(arguments, "path", &path_obj)) { + char *path = (char *)json_object_get_string(path_obj); + char *chdir_result = tool_function_chdir(path); + json_object_object_add(tool_result, "content", + json_object_new_string(chdir_result)); free(chdir_result); + } } - } -} else if (!strcmp(function_name, "directory_glob")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* path_obj; - if (json_object_object_get_ex(arguments, "path", &path_obj)) { - char* path = (char*)json_object_get_string(path_obj); - char* listing_result = tool_function_directory_glob(path); - json_object_object_add(tool_result, "content", json_object_new_string(listing_result)); - free(listing_result); - } - } - } else if (!strcmp(function_name, "http_fetch")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* url_obj; - if (json_object_object_get_ex(arguments, "url", &url_obj)) { - char* url = (char*)json_object_get_string(url_obj); - char* http_result = tool_function_http_get(url); - json_object_object_add(tool_result, "content", json_object_new_string(http_result)); - free(http_result); - } - } - } else if (!strcmp(function_name, "read_file")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* path_obj; - - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - - if (json_object_object_get_ex(arguments, "path", &path_obj)) { - char* path = (char*)json_object_get_string(path_obj); - char* file_content = tool_function_read_file(path); - json_object_object_add(tool_result, "content", json_object_new_string(file_content)); - free(file_content); - } - } - } else if (!strcmp(function_name, "write_file")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* path_obj, * content_obj; - - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - - if (json_object_object_get_ex(arguments, "path", &path_obj) && - json_object_object_get_ex(arguments, "content", &content_obj)) { - char* path = (char*)json_object_get_string(path_obj); - char* content = (char*)json_object_get_string(content_obj); - char* write_result = tool_function_write_file(path, content); - json_object_object_add(tool_result, "content", json_object_new_string(write_result)); - free(write_result); - } - } - }else if (!strcmp(function_name, "db_query")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* query_obj; - - if (json_object_object_get_ex(arguments, "query", &query_obj)) { - char* query = (char*)json_object_get_string(query_obj); - char * db_query_result = tool_function_db_query(query); - json_object_object_add(tool_result, "content", json_object_new_string( db_query_result));; - if(db_query_result != NULL) - free(db_query_result); + } else if (!strcmp(function_name, "directory_glob")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *path_obj; + if (json_object_object_get_ex(arguments, "path", &path_obj)) { + char *path = (char *)json_object_get_string(path_obj); + char *listing_result = tool_function_directory_glob(path); + json_object_object_add(tool_result, "content", + json_object_new_string(listing_result)); + free(listing_result); + } } - } -} else if (!strcmp(function_name, "db_set")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* key_obj; - struct json_object* value_obj; + } else if (!strcmp(function_name, "http_fetch")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *url_obj; + if (json_object_object_get_ex(arguments, "url", &url_obj)) { + char *url = (char *)json_object_get_string(url_obj); + char *http_result = tool_function_http_get(url); + json_object_object_add(tool_result, "content", + json_object_new_string(http_result)); + free(http_result); + } + } + } else if (!strcmp(function_name, "read_file")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *path_obj; - if (json_object_object_get_ex(arguments, "key", &key_obj) && - json_object_object_get_ex(arguments, "value", &value_obj)) { - char* key = (char*)json_object_get_string(key_obj); - char* value = (char*)json_object_get_string(value_obj); - char* db_set_result = tool_function_db_set(key, value); - json_object_object_add(tool_result, "content", json_object_new_string(db_set_result)); + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + + if (json_object_object_get_ex(arguments, "path", &path_obj)) { + char *path = (char *)json_object_get_string(path_obj); + char *file_content = tool_function_read_file(path); + json_object_object_add(tool_result, "content", + json_object_new_string(file_content)); + free(file_content); + } + } + } else if (!strcmp(function_name, "write_file")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *path_obj, *content_obj; + + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + + if (json_object_object_get_ex(arguments, "path", &path_obj) && + json_object_object_get_ex(arguments, "content", &content_obj)) { + char *path = (char *)json_object_get_string(path_obj); + char *content = (char *)json_object_get_string(content_obj); + char *write_result = tool_function_write_file(path, content); + json_object_object_add(tool_result, "content", + json_object_new_string(write_result)); + free(write_result); + } + } + } else if (!strcmp(function_name, "db_query")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *query_obj; + + if (json_object_object_get_ex(arguments, "query", &query_obj)) { + char *query = (char *)json_object_get_string(query_obj); + char *db_query_result = tool_function_db_query(query); + json_object_object_add(tool_result, "content", + json_object_new_string(db_query_result)); + ; + if (db_query_result != NULL) + free(db_query_result); + } + } + } else if (!strcmp(function_name, "db_set")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *key_obj; + struct json_object *value_obj; + + if (json_object_object_get_ex(arguments, "key", &key_obj) && + json_object_object_get_ex(arguments, "value", &value_obj)) { + char *key = (char *)json_object_get_string(key_obj); + char *value = (char *)json_object_get_string(value_obj); + char *db_set_result = tool_function_db_set(key, value); + json_object_object_add(tool_result, "content", + json_object_new_string(db_set_result)); free(db_set_result); + } } - } - }else if (!strcmp(function_name, "index_source_directory")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* path_obj; - if (json_object_object_get_ex(arguments, "path", &path_obj)) { - char* path = (char*)json_object_get_string(path_obj); - char* listing_result = tool_function_index_source_directory(path); - json_object_object_add(tool_result, "content", json_object_new_string(listing_result)); - free(listing_result); - } - } - }else if (!strcmp(function_name, "web_search_news")){ - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* query_obj; - if (json_object_object_get_ex(arguments, "query", &query_obj)) { - char* query = (char*)json_object_get_string(query_obj); - char* news_result = tool_function_web_search_news(query); - json_object_object_add(tool_result, "content", json_object_new_string(news_result)); - free(news_result); - } - } - }else if (!strcmp(function_name, "web_search")){ - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* query_obj; - if (json_object_object_get_ex(arguments, "query", &query_obj)) { - char* query = (char*)json_object_get_string(query_obj); - char* news_result = tool_function_web_search(query); - json_object_object_add(tool_result, "content", json_object_new_string(news_result)); - free(news_result); - } - } - }else if (!strcmp(function_name, "db_get")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* key_obj; + } else if (!strcmp(function_name, "index_source_directory")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *path_obj; + if (json_object_object_get_ex(arguments, "path", &path_obj)) { + char *path = (char *)json_object_get_string(path_obj); + char *listing_result = tool_function_index_source_directory(path); + json_object_object_add(tool_result, "content", + json_object_new_string(listing_result)); + free(listing_result); + } + } + } else if (!strcmp(function_name, "web_search_news")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *query_obj; + if (json_object_object_get_ex(arguments, "query", &query_obj)) { + char *query = (char *)json_object_get_string(query_obj); + char *news_result = tool_function_web_search_news(query); + json_object_object_add(tool_result, "content", + json_object_new_string(news_result)); + free(news_result); + } + } + } else if (!strcmp(function_name, "web_search")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *query_obj; + if (json_object_object_get_ex(arguments, "query", &query_obj)) { + char *query = (char *)json_object_get_string(query_obj); + char *news_result = tool_function_web_search(query); + json_object_object_add(tool_result, "content", + json_object_new_string(news_result)); + free(news_result); + } + } + } else if (!strcmp(function_name, "db_get")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *key_obj; - if (json_object_object_get_ex(arguments, "key", &key_obj)) { - char* key = (char*)json_object_get_string(key_obj); - char* db_get_result = tool_function_db_get(key); - json_object_object_add(tool_result, "content", json_object_new_string(db_get_result)); + if (json_object_object_get_ex(arguments, "key", &key_obj)) { + char *key = (char *)json_object_get_string(key_obj); + char *db_get_result = tool_function_db_get(key); + json_object_object_add(tool_result, "content", + json_object_new_string(db_get_result)); free(db_get_result); + } } - } -}else if (!strcmp(function_name, "getpwd")) { - char* pwd_result = tool_function_getpwd(); - json_object_object_add(tool_result, "content", json_object_new_string(pwd_result)); - free(pwd_result); - } - else if (!strcmp(function_name, "directory_rglob")) { - struct json_object* arguments_obj; - if (json_object_object_get_ex(function_obj, "arguments", &arguments_obj)) { - struct json_object* arguments = json_tokener_parse(json_object_get_string(arguments_obj)); - struct json_object* path_obj; - if (json_object_object_get_ex(arguments, "path", &path_obj)) { - char* path = (char*)json_object_get_string(path_obj); - char* listing_result = tool_function_directory_rglob(path); - json_object_object_add(tool_result, "content", json_object_new_string(listing_result)); - free(listing_result); - } - } - } else { - fprintf(stderr, "Unknown function: %s\n", function_name); - json_object_object_add(tool_result, "content", json_object_new_string("Error: function not found.")); - } + } else if (!strcmp(function_name, "getpwd")) { + char *pwd_result = tool_function_getpwd(); + json_object_object_add(tool_result, "content", + json_object_new_string(pwd_result)); + free(pwd_result); + } else if (!strcmp(function_name, "directory_rglob")) { + struct json_object *arguments_obj; + if (json_object_object_get_ex(function_obj, "arguments", + &arguments_obj)) { + struct json_object *arguments = + json_tokener_parse(json_object_get_string(arguments_obj)); + struct json_object *path_obj; + if (json_object_object_get_ex(arguments, "path", &path_obj)) { + char *path = (char *)json_object_get_string(path_obj); + char *listing_result = tool_function_directory_rglob(path); + json_object_object_add(tool_result, "content", + json_object_new_string(listing_result)); + free(listing_result); + } + } + } else { + fprintf(stderr, "Unknown function: %s\n", function_name); + json_object_object_add( + tool_result, "content", + json_object_new_string("Error: function not found.")); + } - json_object_array_add(tools_result_messages, tool_result); - } + json_object_array_add(tools_result_messages, tool_result); } - return tools_result_messages; + } + return tools_result_messages; } #endif diff --git a/url.h b/url.h index d38d1ba..50dc1fb 100644 --- a/url.h +++ b/url.h @@ -1,85 +1,102 @@ // Written by retoor@molodetz.nl -// This code defines a URL parser in C that extracts components such as the scheme, hostname, port, path, and query from a given URL. +// This code defines a URL parser in C that extracts components such as the +// scheme, hostname, port, path, and query from a given URL. -// Includes: +// Includes: // - <stdio.h> for standard I/O operations // - <string.h> for string manipulation functions // - <stdlib.h> for memory allocation and management // MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: The above copyright +// notice and this permission notice shall be included in all copies or +// substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", +// WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +// THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef R_URL_H #define R_URL_H #include <stdio.h> -#include <string.h> #include <stdlib.h> +#include <string.h> typedef struct { - char scheme[16]; - char hostname[256]; - char port[8]; - char path[512]; - char query[512]; + char scheme[16]; + char hostname[256]; + char port[8]; + char path[512]; + char query[512]; } url_t; int parse_url(const char *url, url_t *parsed_url) { - memset(parsed_url, 0, sizeof(url_t)); + memset(parsed_url, 0, sizeof(url_t)); - const char *scheme_end = strstr(url, "://"); - if (!scheme_end) { - return -1; + const char *scheme_end = strstr(url, "://"); + if (!scheme_end) { + return -1; + } + + strncpy(parsed_url->scheme, url, scheme_end - url); + parsed_url->scheme[scheme_end - url] = '\0'; + + const char *hostname_start = scheme_end + 3; + const char *port_start = strchr(hostname_start, ':'); + const char *path_start = strchr(hostname_start, '/'); + const char *query_start = strchr(hostname_start, '?'); + + if (port_start && (!path_start || port_start < path_start)) { + size_t hostname_length = port_start - hostname_start; + if (hostname_length >= sizeof(parsed_url->hostname)) { + fprintf(stderr, "Hostname is too long\n"); + return -1; } + strncpy(parsed_url->hostname, hostname_start, hostname_length); + parsed_url->hostname[hostname_length] = '\0'; - strncpy(parsed_url->scheme, url, scheme_end - url); - parsed_url->scheme[scheme_end - url] = '\0'; - - const char *hostname_start = scheme_end + 3; - const char *port_start = strchr(hostname_start, ':'); - const char *path_start = strchr(hostname_start, '/'); - const char *query_start = strchr(hostname_start, '?'); - - if (port_start && (!path_start || port_start < path_start)) { - size_t hostname_length = port_start - hostname_start; - if (hostname_length >= sizeof(parsed_url->hostname)) { - fprintf(stderr, "Hostname is too long\n"); - return -1; - } - strncpy(parsed_url->hostname, hostname_start, hostname_length); - parsed_url->hostname[hostname_length] = '\0'; - - size_t port_length = query_start ? (size_t)(query_start - port_start - 1) : strlen(port_start + 1); - if (port_length >= sizeof(parsed_url->port)) { - fprintf(stderr, "Port value is too long\n"); - return -1; - } - strncpy(parsed_url->port, port_start + 1, port_length); - parsed_url->port[port_length] = '\0'; - } else { - size_t hostname_length = path_start ? (size_t)(path_start - hostname_start) : - (query_start ? (size_t)(query_start - hostname_start) : strlen(hostname_start)); - if (hostname_length >= sizeof(parsed_url->hostname)) { - fprintf(stderr, "Hostname is too long\n"); - return -1; - } - strncpy(parsed_url->hostname, hostname_start, hostname_length); - parsed_url->hostname[hostname_length] = '\0'; + size_t port_length = query_start ? (size_t)(query_start - port_start - 1) + : strlen(port_start + 1); + if (port_length >= sizeof(parsed_url->port)) { + fprintf(stderr, "Port value is too long\n"); + return -1; } - - if (path_start) { - if (query_start) { - strncpy(parsed_url->path, path_start, query_start - path_start); - parsed_url->path[query_start - path_start] = '\0'; - } else { - strcpy(parsed_url->path, path_start); - } + strncpy(parsed_url->port, port_start + 1, port_length); + parsed_url->port[port_length] = '\0'; + } else { + size_t hostname_length = + path_start ? (size_t)(path_start - hostname_start) + : (query_start ? (size_t)(query_start - hostname_start) + : strlen(hostname_start)); + if (hostname_length >= sizeof(parsed_url->hostname)) { + fprintf(stderr, "Hostname is too long\n"); + return -1; } + strncpy(parsed_url->hostname, hostname_start, hostname_length); + parsed_url->hostname[hostname_length] = '\0'; + } + if (path_start) { if (query_start) { - strcpy(parsed_url->query, query_start + 1); + strncpy(parsed_url->path, path_start, query_start - path_start); + parsed_url->path[query_start - path_start] = '\0'; + } else { + strcpy(parsed_url->path, path_start); } + } - return 0; + if (query_start) { + strcpy(parsed_url->query, query_start + 1); + } + + return 0; } #endif \ No newline at end of file diff --git a/utils.h b/utils.h index 1991e38..8f50822 100644 --- a/utils.h +++ b/utils.h @@ -1,69 +1,77 @@ // Written by retoor@molodetz.nl -// This header file contains utility functions for manipulating file system paths, focusing primarily on expanding paths starting with '~' to the home directory. +// This header file contains utility functions for manipulating file system +// paths, focusing primarily on expanding paths starting with '~' to the home +// directory. -// This code uses standard libraries: stdio.h, stdlib.h, and string.h, and conditionally includes the posix libraries pwd.h and unistd.h when expanding the home directory manually. +// This code uses standard libraries: stdio.h, stdlib.h, and string.h, and +// conditionally includes the posix libraries pwd.h and unistd.h when expanding +// the home directory manually. // MIT License // -// Permission is granted to use, copy, modify, merge, distribute, sublicense, and/or sell copies of the Software. -// The license includes conditions about providing a copy of the license and the limitation of liability and warranty. +// Permission is granted to use, copy, modify, merge, distribute, sublicense, +// and/or sell copies of the Software. The license includes conditions about +// providing a copy of the license and the limitation of liability and warranty. #ifndef UTILS_H #define UTILS_H -#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> -char* expand_home_directory(const char* path) { - if (path == NULL) return NULL; +char *expand_home_directory(const char *path) { + if (path == NULL) + return NULL; - if (path[0] == '~' && path[1] == '/') { - const char* home_dir = getenv("HOME"); - if (home_dir == NULL) { - #include <pwd.h> - #include <unistd.h> - struct passwd* pw = getpwuid(getuid()); - if (pw == NULL) return NULL; - home_dir = pw->pw_dir; - } - - size_t home_len = strlen(home_dir); - size_t path_len = strlen(path) - 1; - char* expanded_path = malloc(home_len + path_len + 1); - - if (expanded_path == NULL) return NULL; - - strcpy(expanded_path, home_dir); - strcat(expanded_path, path + 1); - - return expanded_path; - } else { - return strdup(path); + if (path[0] == '~' && path[1] == '/') { + const char *home_dir = getenv("HOME"); + if (home_dir == NULL) { +#include <pwd.h> +#include <unistd.h> + struct passwd *pw = getpwuid(getuid()); + if (pw == NULL) + return NULL; + home_dir = pw->pw_dir; } + + size_t home_len = strlen(home_dir); + size_t path_len = strlen(path) - 1; + char *expanded_path = malloc(home_len + path_len + 1); + + if (expanded_path == NULL) + return NULL; + + strcpy(expanded_path, home_dir); + strcat(expanded_path, path + 1); + + return expanded_path; + } else { + return strdup(path); + } } -char * read_file(const char * path) { - char * expanded_path = expand_home_directory(path); - FILE *file = fopen(expanded_path, "r"); - free(expanded_path); - if (file == NULL) { - return NULL; - } - fseek(file, 0, SEEK_END); - long size = ftell(file); - fseek(file, 0, SEEK_SET); +char *read_file(const char *path) { + char *expanded_path = expand_home_directory(path); + FILE *file = fopen(expanded_path, "r"); + free(expanded_path); + if (file == NULL) { + return NULL; + } + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); - char *buffer = (char *)malloc(size + 1); - size_t read = fread(buffer, 1, size, file); - if (read == 0) { - free(buffer); - return NULL; - } + char *buffer = (char *)malloc(size + 1); + size_t read = fread(buffer, 1, size, file); + if (read == 0) { + free(buffer); + return NULL; + } - fclose(file); - buffer[read] = '\0'; - return buffer; + fclose(file); + buffer[read] = '\0'; + return buffer; } #endif