14 Commits
dev ... 1.0.0

Author SHA1 Message Date
synt-xerror
b9b474af40 New: GET /api/key 2026-02-23 08:31:26 -03:00
synt-xerror
0543a9e9ce idk what am i doing 2026-02-20 21:30:22 -03:00
synt-xerror
1ee3da6722 Removing this (oops) 2026-02-19 02:28:40 -03:00
synt-xerror
f3667d615e fix link 2026-02-19 02:25:36 -03:00
synt-xerror
55788ace47 Example files 2026-02-19 02:21:09 -03:00
synt-xerror
94f34439dc update readme 2026-02-19 02:20:52 -03:00
synt-xerror
795cd984cd removing src folder 2026-02-19 02:20:23 -03:00
synt-xerror
cde638aa71 Temporary files 2026-02-19 02:19:49 -03:00
synt-xerror
832bb88ecd Removing jansson, the library won't parse json anymore 2026-02-19 02:18:43 -03:00
synt-xerror
7cdac92582 Fix: removing old and useless files 2026-02-16 22:05:53 -03:00
synt-xerror
878ee963b5 Fix: segfault error at info function 2026-02-16 21:37:20 -03:00
synt-xerror
c955ee08d4 New readme 2026-02-16 20:34:40 -03:00
synt-xerror
08cc4f9d75 Security improvements 2026-02-16 19:08:31 -03:00
synt-xerror
9ba4be8a92 Library is done for test and improvements 2026-02-16 17:01:21 -03:00
14 changed files with 402 additions and 450 deletions

4
.gitignore vendored Normal file → Executable file
View File

@@ -1 +1,3 @@
auto-commit.txt example
libneocities.a
neocities.o

View File

@@ -15,4 +15,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 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 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 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. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

44
Makefile Executable file → Normal file
View File

@@ -1,38 +1,10 @@
# ------------------------------ make:
# Neocities CLI Makefile (Portable) gcc -c neocities.c -o neocities.o
# ------------------------------ ar rcs libneocities.a neocities.o
# Default compiler
CC ?= gcc
# Compiler flags
CFLAGS ?= -Wall -O2 -Iinclude
# Libraries
LIBS ?= -lcurl -ljansson
# Source and target
SRC = \
src/main.c \
src/info.c
BIN = neocities
# Detect Windows (MSYS2 / MinGW)
ifeq ($(OS),Windows_NT)
RM = del /Q
BIN_EXT = .exe
else
RM = rm -f
BIN_EXT =
endif
# Build executable
all: $(BIN)$(BIN_EXT)
$(BIN)$(BIN_EXT): $(SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
# Clean build files
clean: clean:
$(RM) $(BIN)$(BIN_EXT) rm libneocities.a neocities.o
example:
rm -f example
gcc example.c -L. -lneocities -lcurl -o example

159
README.md
View File

@@ -1,121 +1,94 @@
# Neocities C CLI # Neocities API C library
A simple command-line tool written in C that interacts with the [Neocities API](https://neocities.org/api). Minimal, secure C wrapper for the Neocities API.
Currently, only the `--info` command is implemented — it fetches and displays basic information about your Neocities site.
--- ---
## Features ## Features
- Fetch site information using Neocities API
- Authenticates via environment variables * Site info retrieval
- JSON parsing with [jansson](https://digip.org/jansson/) * File listing
- Works on Linux, Windows (MSYS2/MinGW), and Android (via Termux) * Upload files
- Compilable with a Makefile for easy builds * Delete files
* Get API key
* TLS verification enabled by default
--- ---
## Requirements ## Requirements
Youll need: * libcurl
- A C compiler (`gcc` or `clang`)
- [libcurl](https://curl.se/libcurl/)
- [jansson](https://digip.org/jansson/)
- `make`
### Linux (Debian/Ubuntu-based) Linux (example):
```bash
sudo apt update
sudo apt install build-essential libcurl4-openssl-dev libjansson-dev make
```
### Windows (MSYS2 / MinGW)
```bash
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-curl mingw-w64-x86_64-jansson make
```
### Android (Termux)
```bash
pkg install clang curl-dev jansson make
```
## Building
Run in cloned repository:
```bash
make
```
This will generate the executable neocities (or neocities.exe on Windows).
To clean build files:
```bash
make clean
```
### Environment Variables
Before running, export your Neocities credentials:
#### Linux / macOS / Termux
```bash
export NEOCITIES_USER="your_username"
export NEOCITIES_PASS="your_password"
```
#### Windows (PowerShell)
```batch
setx NEOCITIES_USER "your_username"
setx NEOCITIES_PASS "your_password"
```
## Usage
```bash
./neocities --info
```
Example output:
``` ```
Neocities C CLI sudo apt install libcurl4-openssl-dev
Sitename: example
Hits: 42
Created at: 2024-01-10
Last updated: 2025-11-01
Domain: domain.com
Tags: art, blog, personal.
``` ```
## Optional: Install Globally ---
You can move the compiled executable to a directory in your PATH to run it from anywhere: ## API Overview
#### Linux / Termux ### Info (public)
```bash ```c
sudo mv neocities /usr/local/bin/ int neocities_info(const char *sitename, char **out);
``` ```
#### Windows (PowerShell) Fetch metadata about a site.
Move neocities.exe to a folder in your PATH, e.g., C:\Windows\System32\.
After that, you can run: ---
```batch ### List files
neocities --info
```c
int neocities_list(const char *api_key, const char *path, char** out);
``` ```
from any folder without specifying the path. List files at a path.
## Notes ---
Only the --info command is implemented for now. ### Upload
If you get curl_easy_perform errors, check your network and SSL setup. ```c
int neocities_upload(const char *api_key, const char **local_files, const char **remote_names, size_t count, char **response);
```
Uploads multiple files.
* `local_files[i]` → local path
* `remote_names[i]` → remote filename
---
### Delete
```c
int neocities_delete(const char *api_key, const char **filenames, size_t count, char **response);
```
Deletes files from the site.
---
### API Key
```c
int neocities_apikey(const char *user, const char *pass, char **out);
```
Get your API key.
---
## Example Usage
See example.c
---
## License
[MIT](LICENSE)
On Termux, use clang for the best compatibility.

35
example.c Normal file
View File

@@ -0,0 +1,35 @@
#include <stdio.h>
#include "neocities.h"
#include <stdlib.h>
int main() {
static const char* username = "YOUR_USERNAME";
static const char* api_key = "YOUR_API_KEY";
char* out = NULL;
// GET /api/key
if (neocities_apikey(username, "YOUR_PASSWORD", &out) == 0) printf("%s", out);
free(out);
// GET /api/info
if (neocities_info(username, &out) == 0) printf("%s", out);
free(out);
// GET /api/list
if (neocities_list(api_key, "/", &out) == 0) printf("%s", out);
free(out);
static const char* files[] = { "test.txt" };
static const int qnt_files = sizeof(files) / sizeof(files[0]);
// GET /api/upload
if (neocities_upload(api_key, files, files, qnt_files, &out) == 0) printf("%s", out);
free(out);
// GET /api/delete
if (neocities_delete(api_key, files, qnt_files, &out) == 0) printf("%s", out);
free(out);
return 0;
}

BIN
neocities

Binary file not shown.

273
neocities.c Normal file
View File

@@ -0,0 +1,273 @@
#include "neocities.h"
#include <curl/curl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// -------------------------
// HTTP response buffer
// -------------------------
struct response {
char *data;
size_t len;
};
static size_t write_cb(
void *ptr,
size_t size,
size_t nmemb,
void *userdata
)
{
struct response *r = (struct response*)userdata;
size_t chunk = size * nmemb;
char *tmp = realloc(r->data, r->len + chunk + 1);
if (!tmp) return 0;
r->data = tmp;
memcpy(r->data + r->len, ptr, chunk);
r->len += chunk;
r->data[r->len] = '\0';
return chunk;
}
// -------------------------
// HTTP helpers
// -------------------------
static int perform_request(
const char *url,
const char *api_key,
const char *post_fields,
struct response *resp,
curl_mime *mime
)
{
CURL *curl = curl_easy_init();
if (!curl) return 1;
resp->data = malloc(1);
resp->len = 0;
resp->data[0] = '\0';
struct curl_slist *headers = NULL;
if (api_key && strlen(api_key) > 0) {
char auth_header[512];
snprintf(auth_header, sizeof(auth_header),
"Authorization: Bearer %s", api_key);
headers = curl_slist_append(headers, auth_header);
}
curl_easy_setopt(curl, CURLOPT_URL, url);
if (headers)
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
/* SSL hardening */
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0L); // política
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp);
if (post_fields) {
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields);
}
if (mime)
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
CURLcode res = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if (res != CURLE_OK || http_code >= 400) {
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
free(resp->data);
return 2;
}
return 0;
}
// -------------------------
// info — GET /api/info
// -------------------------
int neocities_info(
const char *sitename,
char** out
)
{
char url[512];
if (sitename)
snprintf(url, sizeof(url), "https://neocities.org/api/info?sitename=%s", sitename);
else
snprintf(url, sizeof(url), "https://neocities.org/api/info");
struct response resp;
int ret = perform_request(url, NULL, NULL, &resp, NULL);
if (ret) return ret;
*out = resp.data;
return 0;
}
// -------------------------
// list — GET /api/list
// -------------------------
int neocities_list(
const char *api_key,
const char *path,
char **out
)
{
char url[512];
if (path) snprintf(url, sizeof(url), "https://neocities.org/api/list?path=%s", path);
else snprintf(url, sizeof(url), "https://neocities.org/api/list");
struct response resp;
int ret = perform_request(url, api_key, NULL, &resp, NULL);
if (ret) return ret;
*out = resp.data;
return 0;
}
// -------------------------
// delete — POST /api/delete
// -------------------------
int neocities_delete(
const char *api_key,
const char **filenames,
size_t count,
char **response
)
{
char body[1024] = "";
for (size_t i=0; i<count; i++) {
char tmp[256];
snprintf(tmp, sizeof(tmp), "filenames[]=%s&", filenames[i]);
strncat(body, tmp, sizeof(body)-strlen(body)-1);
}
struct response resp;
int ret = perform_request(
"https://neocities.org/api/delete",
api_key,
body,
&resp,
NULL
);
if (ret) return ret;
*response = resp.data;
return 0;
}
// -------------------------
// upload — POST /api/upload
// (multipart/form-data)
// -------------------------
int neocities_upload(
const char *api_key,
const char **local_files,
const char **remote_names,
size_t count,
char **response
)
{
if (!api_key || strlen(api_key) == 0)
return 3;
CURL *curl = curl_easy_init();
if (!curl) return 1;
struct response resp;
resp.data = malloc(1);
resp.len = 0;
resp.data[0] = '\0';
curl_easy_setopt(curl, CURLOPT_URL, "https://neocities.org/api/upload");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0L);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
struct curl_slist *headers = NULL;
char auth_header[512];
snprintf(auth_header, sizeof(auth_header),
"Authorization: Bearer %s", api_key);
headers = curl_slist_append(headers, auth_header);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_mime *form = curl_mime_init(curl);
for (size_t i=0; i<count; i++) {
curl_mimepart *part = curl_mime_addpart(form);
curl_mime_name(part, remote_names[i]);
curl_mime_filedata(part, local_files[i]);
}
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
CURLcode res = curl_easy_perform(curl);
curl_mime_free(form);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
if (res != CURLE_OK) { free(resp.data); return 2; }
*response = resp.data;
return 0;
}
// -------------------------
// key — GET /api/key
// -------------------------
int neocities_apikey(const char *user, const char *pass, char **out) {
struct response resp = {0};
char userpass[256];
snprintf(userpass, sizeof(userpass), "%s:%s", user, pass);
CURL *curl = curl_easy_init();
if (!curl) return 1;
resp.data = malloc(1);
resp.len = 0;
resp.data[0] = '\0';
curl_easy_setopt(curl, CURLOPT_URL, "https://neocities.org/api/key");
curl_easy_setopt(curl, CURLOPT_USERPWD, userpass); // aqui é equivalente ao -u do curl
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
CURLcode res = curl_easy_perform(curl);
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
curl_easy_cleanup(curl);
if (res != CURLE_OK || http_code >= 400) {
free(resp.data);
return 2;
}
*out = resp.data; // resposta da API
return 0;
}

15
neocities.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef NEOCITIES_H
#define NEOCITIES_H
#include <stddef.h>
// -------------------------
// API functions
// -------------------------
int neocities_info(const char *sitename, char **out);
int neocities_list(const char *api_key, const char *path, char **out);
int neocities_delete(const char *api_key, const char **filenames, size_t count, char **response);
int neocities_upload(const char *api_key, const char **local_files, const char **remote_names, size_t count, char **response);
int neocities_apikey(const char *user, const char *pass, char **out);
#endif // NEOCITIES_H

View File

@@ -1,156 +0,0 @@
#include "main.h" // Header local do projeto (declarações próprias: struct response, write_callback, etc.)
#include <stdio.h> // printf, fprintf
#include <stdlib.h> // getenv, malloc, free
#include <curl/curl.h> // libcurl: HTTP/HTTPS client
#include <jansson.h> // Jansson: parsing e manipulação de JSON
#include <string.h>
// Função responsável por buscar informações do site do usuário no Neocities
int fetch_neocities_info() {
// Lê variáveis de ambiente com credenciais
// NEOCITIES_USER e NEOCITIES_PASS são usadas para autenticação HTTP Basic
const char *user = getenv("NEOCITIES_USER");
const char *pass = getenv("NEOCITIES_PASS");
// const char *enc = getenv("NEOCITIES_PASS_ENC"); // Não usado aqui (possível uso futuro)
// Verificação básica: se usuário ou senha não existirem, aborta
if (!user || !pass) {
fprintf(stderr, "You're not logged!\n");
return 1;
}
// Buffer para "user:password", formato exigido por CURLOPT_USERPWD
char auth[256];
snprintf(auth, sizeof(auth), "%s:%s", user, pass);
// Inicializa um handle do libcurl
CURL *curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "Erro ao inicializar cURL\n");
return 1;
}
// Monta a URL da API do Neocities para obter informações do site
char infourl[256];
snprintf(
infourl,
sizeof(infourl),
"https://neocities.org/api/info?sitename=%s",
user
);
// Define a URL da requisição
curl_easy_setopt(curl, CURLOPT_URL, infourl);
// Define autenticação HTTP Basic (user:pass)
curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
// Estrutura usada para armazenar a resposta HTTP em memória
// resp.data será expandido pelo write_callback
struct response resp = { .data = malloc(1), .len = 0 };
resp.data[0] = '\0'; // Garante string vazia inicial
// Função chamada pelo libcurl sempre que dados são recebidos
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
// Ponteiro passado para o write_callback (estado da resposta)
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
// Executa a requisição HTTP de forma síncrona
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "Erro na requisição: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
free(resp.data);
return 1;
}
// Libera o handle do curl (a resposta já está em resp.data)
curl_easy_cleanup(curl);
// Estrutura para capturar erros de parsing JSON
json_error_t error;
// Converte a string JSON recebida em um objeto JSON manipulável
json_t *obj = json_loads(resp.data, 0, &error);
free(resp.data); // Não é mais necessária após o parsing
// Caso o JSON seja inválido
if (!obj) {
fprintf(stderr, "Erro ao parsear JSON: %s\n", error.text);
return 1;
}
// Obtém o campo "result" do JSON raiz
json_t *result_obj = json_object_get(obj, "result");
const char *result_str = json_string_value(result_obj);
// Caso a API tenha retornado erro
if (strcmp(result_str, "error") == 0) {
// Tipo de erro retornado pela API
const char *err_type =
json_string_value(json_object_get(obj, "error_type"));
// Mensagem de erro legível
const char *err_msg =
json_string_value(json_object_get(obj, "message"));
// Tratamento específico para erro de autenticação
if (strcmp(err_type, "invalid_auth") == 0) {
printf("Usuário ou senha incorretos!\n");
} else {
printf("Erro! %s\n", err_msg);
}
// Diminui o contador de referência do objeto JSON
json_decref(obj);
return 1;
}
// Caso a requisição tenha sido bem-sucedida
if (strcmp(result_str, "success") == 0) {
// Objeto "info" contém os dados do site
json_t *info_obj = json_object_get(obj, "info");
// Impressão direta dos campos retornados
printf("\nSitename: %s\n",
json_string_value(json_object_get(info_obj, "sitename")));
printf("Hits: %d\n",
(int)json_integer_value(json_object_get(info_obj, "hits")));
printf("Created at: %s\n",
json_string_value(json_object_get(info_obj, "created_at")));
printf("Last updated: %s\n",
json_string_value(json_object_get(info_obj, "last_updated")));
printf("Domain: %s\n",
json_string_value(json_object_get(info_obj, "domain")));
// Array de tags associadas ao site
json_t *tags = json_object_get(info_obj, "tags");
printf("Tags: ");
size_t index;
json_t *tag;
// Itera sobre o array JSON "tags"
json_array_foreach(tags, index, tag) {
printf(
"#%s%s",
json_string_value(tag),
(index < json_array_size(tags) - 1) ? ", " : "."
);
}
printf("\n\n");
}
// Libera o objeto JSON principal
json_decref(obj);
return 0;
}

View File

@@ -1,12 +0,0 @@
#ifndef INFO
#define INFO
// ^ Guardas de inclusão (include guards)
// Evitam que este header seja processado mais de uma vez
// durante a compilação, o que causaria redefinições.
// Declaração da função que busca informações do Neocities.
// O `void` indica explicitamente que a função não recebe parâmetros.
int fetch_neocities_info(void);
#endif
// ^ Fim do include guard

View File

@@ -1,27 +0,0 @@
#!/bin/bash
set -e
CONFIG_DIR="$HOME/.config/neocities"
CONFIG_FILE="$CONFIG_DIR/credentials"
mkdir -p "$CONFIG_DIR"
chmod 700 "$CONFIG_DIR"
read -p "Username: " USER
read -s -p "Password: " PASS
echo
read -p "Would you like to see the credentials on your screen to confirm? [Y/n]: " CHOICE
case $CHOICE in
y|Y) echo -e "Username: $USER\nPassword: $PASS" ;;
*) echo "" ;;
esac
cat > "$CONFIG_FILE" <<EOF
user = $USER
pass = $PASS
EOF
chmod 600 "$CONFIG_FILE"
echo "Credentials saved in $CONFIG_FILE"

View File

@@ -1,93 +0,0 @@
#include <stdio.h> // printf, fprintf
#include <stdlib.h> // malloc, realloc, free
#include <string.h> // strcmp, memcpy
#include <curl/curl.h> // libcurl (necessário para callbacks e tipos)
#include "main.h" // Declarações globais do projeto (upload_func, etc.)
#include "info.h" // Declaração de fetch_neocities_info()
// Estrutura usada para acumular a resposta HTTP em memória.
// É preenchida incrementalmente pelo write_callback.
struct response {
char *data; // Buffer dinâmico com os dados recebidos
size_t len; // Quantidade atual de bytes válidos em data
};
// Callback chamado pelo libcurl sempre que um novo bloco de dados chega.
// Não garante tamanho fixo nem chamada única.
size_t write_callback(void *data, size_t size, size_t nmemb, void *userdata) {
// userdata aponta para a struct response passada via CURLOPT_WRITEDATA
struct response *resp = (struct response *)userdata;
// Tamanho real do bloco recebido
size_t chunk_size = size * nmemb;
// Realoca o buffer para caber os novos dados + '\0'
char *tmp = realloc(resp->data, resp->len + chunk_size + 1);
if (!tmp) {
// Se realloc falhar, aborta a escrita
// Retornar 0 sinaliza erro ao libcurl
fprintf(stderr, "Erro de memória\n");
return 0;
}
// Atualiza o ponteiro com o novo buffer
resp->data = tmp;
// Copia o bloco recebido para o final do buffer atual
memcpy(resp->data + resp->len, data, chunk_size);
// Atualiza o tamanho total acumulado
resp->len += chunk_size;
// Garante que o buffer seja uma string C válida
resp->data[resp->len] = '\0';
// Retornar o número de bytes processados indica sucesso
return chunk_size;
}
// Tipo de ponteiro para função que representa um comando CLI.
// Todas as funções de comando retornam int e não recebem argumentos.
typedef int (*cmd_func_t)(void);
// Estrutura que associa:
// - nome do comando (string digitada no terminal)
// - função que implementa esse comando
typedef struct {
const char *name;
cmd_func_t func;
} command_entry;
int main(int argc, char *argv[]) {
// Tabela de comandos suportados pelo programa.
// Facilita adicionar novos comandos sem alterar a lógica principal.
command_entry commands[] = {
{"--info", fetch_neocities_info},
// {"--upload", upload_func}
};
// Verifica se ao menos um argumento foi passado
if (argc < 2) {
printf("No command provided.\n");
return 0;
}
// Percorre a tabela de comandos procurando correspondência
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
// Compara o argumento passado com o nome do comando
if (strcmp(argv[1], commands[i].name) == 0) {
// Executa a função associada ao comando
// e retorna imediatamente o código dela
return commands[i].func();
}
}
// Se nenhum comando conhecido foi encontrado
printf("Unknown command.\n");
return 0;
}

View File

@@ -1,31 +0,0 @@
#ifndef MAIN_H
#define MAIN_H
// Include guard:
// Impede múltiplas inclusões deste header no mesmo processo de compilação.
#include <stddef.h> // size_t
// Necessário para o tipo size_t, usado em tamanhos e contadores de memória.
// Declarações externas de variáveis globais.
// O `extern` indica que a definição real existe em outro arquivo .c.
extern const char *user;
extern const char *pass;
// Estrutura usada para armazenar dados recebidos dinamicamente,
// geralmente como resposta de uma requisição HTTP.
struct response {
char *data; // Buffer dinâmico contendo os dados acumulados
size_t len; // Quantidade de bytes válidos em data
};
// Protótipo da função de callback usada pelo libcurl.
// Essa função será chamada repetidamente conforme dados chegam.
size_t write_callback(
void *ptr, // Ponteiro para os dados recebidos
size_t size, // Tamanho de cada elemento
size_t nmemb, // Número de elementos
void *userdata // Ponteiro de contexto definido pelo usuário
);
#endif
// Fim do include guard

1
test.txt Normal file
View File

@@ -0,0 +1 @@
hellooo