Making structure and testing possibilities

This commit is contained in:
synt-xerror
2026-02-20 21:31:39 -03:00
parent 2de98772dd
commit e5709bb340
2 changed files with 192 additions and 95 deletions

BIN
neogities Executable file

Binary file not shown.

View File

@@ -7,8 +7,18 @@
#include <jansson.h> #include <jansson.h>
#include <string.h> #include <string.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <termios.h>
#include <readline/readline.h>
#include <readline/history.h>
// ------------------------- // -------------------------
// HTTP responde buffer // HTTP response buffer
// ------------------------- // -------------------------
struct response { struct response {
char *data; char *data;
@@ -103,36 +113,12 @@ static int perform_request(
return 0; return 0;
} }
// -------------------------
// JSON parsers
// -------------------------
void neocities_free_info(
neocities_info_t *info
)
{
if (!info) return;
free(info->sitename);
free(info->created_at);
free(info->last_updated);
free(info->domain);
for (size_t i=0; i<info->tag_count; i++) free(info->tags[i]);
free(info->tags);
}
void neocities_free_filelist(
neocities_filelist_t *list
)
{
if (!list) return;
for (size_t i=0; i<list->count; i++) free(list->paths[i]);
free(list->paths);
}
// ------------------------- // -------------------------
// info — GET /api/info // info — GET /api/info
// ------------------------- // -------------------------
int neocities_info( int neocities_info(
const char *sitename, neocities_info_t *out const char *sitename,
char** out
) )
{ {
char url[512]; char url[512];
@@ -145,48 +131,8 @@ int neocities_info(
int ret = perform_request(url, NULL, NULL, &resp, NULL); int ret = perform_request(url, NULL, NULL, &resp, NULL);
if (ret) return ret; if (ret) return ret;
json_error_t error; *out = resp.data;
json_t *root = json_loads(resp.data, 0, &error);
free(resp.data);
if (!root) return 3;
const char *result = json_string_value(json_object_get(root,"result"));
if (!result || strcmp(result,"success")!=0) { json_decref(root); return 4; }
json_t *info = json_object_get(root,"info");
if (!json_is_object(info)) {
json_decref(root);
return 4;
}
json_t *j_sitename = json_object_get(info,"sitename");
json_t *j_created = json_object_get(info,"created_at");
json_t *j_updated = json_object_get(info,"last_updated");
json_t *j_domain = json_object_get(info,"domain");
json_t *j_hits = json_object_get(info,"hits");
out->sitename = json_is_string(j_sitename) ? strdup(json_string_value(j_sitename)) : NULL;
out->created_at = json_is_string(j_created) ? strdup(json_string_value(j_created)) : NULL;
out->last_updated = json_is_string(j_updated) ? strdup(json_string_value(j_updated)) : NULL;
out->domain = json_is_string(j_domain) ? strdup(json_string_value(j_domain)) : NULL;
out->hits = json_is_integer(j_hits) ? json_integer_value(j_hits) : 0;
json_t *tags = json_object_get(info,"tags");
if (!json_is_array(tags)) {
out->tags = NULL;
out->tag_count = 0;
} else {
size_t tc = json_array_size(tags);
out->tags = malloc(sizeof(char*) * tc);
out->tag_count = tc;
for (size_t i=0; i<tc; i++) {
json_t *tag = json_array_get(tags,i);
out->tags[i] = json_is_string(tag) ? strdup(json_string_value(tag)) : NULL;
}
}
json_decref(root);
return 0; return 0;
} }
@@ -195,7 +141,8 @@ int neocities_info(
// ------------------------- // -------------------------
int neocities_list( int neocities_list(
const char *api_key, const char *api_key,
const char *path, neocities_filelist_t *out const char *path,
char **out
) )
{ {
char url[512]; char url[512];
@@ -206,22 +153,7 @@ int neocities_list(
int ret = perform_request(url, api_key, NULL, &resp, NULL); int ret = perform_request(url, api_key, NULL, &resp, NULL);
if (ret) return ret; if (ret) return ret;
json_error_t error; *out = resp.data;
json_t *root = json_loads(resp.data, 0, &error);
free(resp.data);
if (!root) return 3;
json_t *arr = json_object_get(root, "files");
if (!arr) { json_decref(root); return 4; }
size_t count = json_array_size(arr);
out->paths = malloc(sizeof(char*) * count);
out->count = count;
for (size_t i=0; i<count; i++) {
json_t *f = json_array_get(arr, i);
out->paths[i] = strdup(json_string_value(json_object_get(f,"path")));
}
json_decref(root);
return 0; return 0;
} }
@@ -317,19 +249,168 @@ int neocities_upload(
return 0; return 0;
} }
char* home()
{
struct passwd *u;
u = getpwuid(getuid());
if (!u) {
perror("invalid return of getpwuid() function.\n");
return NULL;
}
return u->pw_dir;
}
// DIR_NAME deve ser o nome do diretório, não o caminho (ex: task)
// Se HOME = NULL, a função assume que a pasta que quer está fora da pasta /home/usuário
// Importante: essa função retorna um char*. Para abrir o diretório retornado, você deve usar
// a função opendir() com o valor retornado de get_dir()
char* get_dir(const char* HOME, const char* DIR_NAME) {
if (DIR_NAME[0] == '~') {
perror("get_dir doesn't expand '~'");
return NULL;
}
if (DIR_NAME[0] == '/') {
perror("DIR_NAME can't begin with '/'");
return NULL;
}
const char *prefix = HOME ? HOME : "";
int size = strlen(prefix) + 1 + strlen(DIR_NAME) + 1;
char *DIR_FINAL = malloc(size);
if (!DIR_FINAL) {
perror("malloc failed");
return NULL;
}
sprintf(DIR_FINAL, "%s/%s", prefix, DIR_NAME);
DIR *dir = opendir(DIR_FINAL);
if (!dir) {
if (mkdir(DIR_FINAL, 0755) != 0) {
fprintf(stderr, "'%s' cannot be created\n", DIR_FINAL);
free(DIR_FINAL);
return NULL;
}
} else {
closedir(dir);
}
return DIR_FINAL;
}
char* get_file(const char* ROOT, const char* FILE_NAME) {
char* FINAL_FILE;
FINAL_FILE = malloc(strlen(ROOT) + strlen(FILE_NAME) + 1);
sprintf(FINAL_FILE, "%s/%s", ROOT, FILE_NAME);
return FINAL_FILE;
}
struct termios orig_termios;
void disable_raw_mode() { tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios); }
void enable_raw_mode() {
tcgetattr(STDIN_FILENO, &orig_termios);
atexit(disable_raw_mode);
struct termios raw = orig_termios;
raw.c_lflag &= ~(ECHO | ICANON);
raw.c_cc[VMIN] = 0; raw.c_cc[VTIME] = 1;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}
int read_key() {
char c; int n = read(STDIN_FILENO, &c, 1);
if (n == 1) {
if (c == '\033') {
char seq[2];
if (read(STDIN_FILENO, &seq[0], 1) != 1) return '\033';
if (read(STDIN_FILENO, &seq[1], 1) != 1) return '\033';
if (seq[0] == '[') {
switch(seq[1]) {
case 'A': return 1000; // cima
case 'B': return 1001; // baixo
}
}
return 0;
}
return c;
}
return 0;
}
int menu(char *titles[], int n_titles, char *options[], int n_options, char *footer, int circular) {
int selected = 0;
enable_raw_mode();
int total_lines = n_titles + n_options + (footer ? 1 : 0);
while (1) {
// só imprime normalmente, abaixo do que já está
for (int i = 0; i < n_titles; i++) printf("%s\n", titles[i]);
for (int i = 0; i < n_options; i++) {
if (i == selected) printf("> %s\n", options[i]);
else printf(" %s\n", options[i]);
}
if (footer) printf("%s\n", footer);
int key = read_key();
if (key == 1000) { selected--; if (circular && selected < 0) selected = n_options - 1; if (!circular && selected < 0) selected = 0; }
else if (key == 1001) { selected++; if (circular && selected >= n_options) selected = 0; if (!circular && selected >= n_options) selected = n_options - 1; }
else if (key == '\n') break;
else if (key == 27) { selected = -1; break; }
// depois de desenhar, sobe o cursor e apaga menu antigo
for (int i = 0; i < total_lines; i++) {
printf("\033[1A\033[2K"); // sobe 1 linha e limpa
}
}
// move cursor pro topo do menu antigo
printf("\033[%dA", total_lines);
// limpa cada linha
for (int i = 0; i < total_lines; i++) {
printf("\033[2K"); // limpa a linha
if (i != total_lines-1) printf("\033[1B"); // desce linha
}
// volta cursor pro topo do menu
printf("\033[%dA", total_lines-1);
disable_raw_mode();
return selected;
}
const char* DATA_DIR = ".local/share/neogities";
const char* CONFIG_DIR = ".config/neogities";
const char* CONFIG_FILE = "neogities.conf";
const char* ACCESS_FILE = "credentials";
int main() { int main() {
static const char* version = "v0.1.0"; static const char* version = "v0.1.0";
const char* DEF_DATA_DIR = get_dir(home(), DATA_DIR);
const char* DEF_CONFIG_DIR = get_dir(home(), DATA_DIR);
const char* DEF_CONFIG_FILE = get_file(DEF_CONFIG_DIR, CONFIG_FILE);
const char* DEF_ACCESS_FILE = get_file(DEF_DATA_DIR, ACCESS_FILE);
srand(time(NULL) ^ getpid()); srand(time(NULL) ^ getpid());
int n = rand() % 2; int a = rand() % 2;
int y = rand() % 2; int b = rand() % 2;
static const char* eyes[] = { "-_o", "o_o" }; static const char* eyes[] = { "-_o", "o_o" };
static const char* mouths[] = { "-", "~" }; static const char* mouths[] = { "-", "~" };
const char* eye = eyes[n]; const char* eye = eyes[a];
const char* mouth = mouths[y]; const char* mouth = mouths[b];
static const char *logo = static const char *logo =
"|\\---/|---------------o\n" "|\\---/|---------------o\n"
@@ -337,8 +418,24 @@ int main() {
" \\_%s_/ %s / o\n" " \\_%s_/ %s / o\n"
" o\n"; " o\n";
printf("Hello! You're not logged in.\n\n");
printf(logo, eye, mouth, version); printf(logo, eye, mouth, version);
return 0; /* char *titles[] = {"Meu Menu"};
} char *options[] = {"Opção 1", "Opção 2", "Opção 3"};
char *footer = "Use setas ↑↓ e Enter para selecionar. ESC para sair.";
int choice = menu(titles, 1, options, 3, footer, 1);
printf("Selecionou: %d\n", choice); */
/* char *input = readline("Nome: "); // mostra prompt e permite editar
if (input != NULL) {
printf("Você digitou: %s\n", input);
}
free(input); */
free((char*)DEF_DATA_DIR);
free((char*)DEF_CONFIG_DIR);
free((char*)DEF_CONFIG_FILE);
free((char*)DEF_ACCESS_FILE);
}