From ae4e18faad44e0514775cc8e9d8dc113e745aca8 Mon Sep 17 00:00:00 2001 From: 8nl <8nl@noreply.git.macaw.me> Date: Sun, 10 Nov 2024 09:38:38 +0000 Subject: [PATCH] Upload files to "/" --- Makefile | 8 + config.h | 7 + img.c | 450 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 465 insertions(+) create mode 100644 Makefile create mode 100644 config.h create mode 100644 img.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..872e518 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +CC?=cc +CFLAGS?=-pedantic -Wall -Wextra + +all: + $(CC) $(CFLAGS) img.c -o 8img + +clean: + rm 8img diff --git a/config.h b/config.h new file mode 100644 index 0000000..75a4dec --- /dev/null +++ b/config.h @@ -0,0 +1,7 @@ +#define TITLE "8img gallery" +#define POST_PER_PAGE 10 + +/* Absolute path to */ +#define ROOT "8img_dir" +#define DB ROOT"/db" +#define CSS ROOT"/styles.css" diff --git a/img.c b/img.c new file mode 100644 index 0000000..b09f609 --- /dev/null +++ b/img.c @@ -0,0 +1,450 @@ +#include +#include +#include +#include +#include +#include +#include +#include "config.h" + +struct DB_STR { + char *filename; + + char **tags; + size_t size; + + struct DB_STR *next; +}; + +struct UNIQ_TAGS { + char **tags; + size_t size; +}; + +char *gen_id(void) { + char *alf = "qwertyUIOPasdfghjklQWERTASDFGHJKLZXCVBNMzxcvbnm1234567890"; + + static char id[6]; + for (size_t i = 0; i < sizeof(id); i++) + id[i] = alf[rand() % sizeof(alf)]; + + id[sizeof(id) - 1] = '\0'; + return id; +} + +FILE *file_open(const char *file, const char *mode) { + FILE *fp = fopen(file, mode); + if (fp == NULL) { + fprintf(stderr, "8img: %s: %s\n", file, strerror(errno)); + return NULL; + } + + return fp; +} + +void copy(const char *src, const char *dst) { + FILE *ifp = file_open(src, "r"); + if (ifp == NULL) + exit(1); + + FILE *ofp = file_open(dst, "a"); + if (ofp == NULL) { + fclose(ifp); + exit(1); + } + + char buf[4096]; + size_t ret = 0; + while ((ret = fread(buf, sizeof(char), sizeof(buf), ifp))) + fwrite(buf, sizeof(char), ret, ofp); + + fclose(ifp); + fclose(ofp); +} + +void add(char **list, const int size) { + char *name = NULL; + char new_path[PATH_MAX + 1]; + + while (1) { + name = gen_id(); + snprintf(new_path, sizeof(new_path), "%s/%s", ROOT, name); + + struct stat sb; + if (stat(new_path, &sb) < 0) + break; + } + + /* Copy file */ + copy(list[0], new_path); + + /* Update db */ + FILE *fp = file_open(DB, "a"); + if (fp == NULL) + exit(1); + + /* Write filename ,tag1,tag2... to the db */ + fprintf(fp, "%s ", name); + for (int i = 1; i < size; i++) { + if (strchr(list[i], ',') == NULL || strchr(list[i], ' ') == NULL) + fprintf(fp, ",%s", list[i]); + + else + fprintf(stderr, "8img: tag '%s' contain ',' or ' '\n", list[i]); + } + + fputc('\n', fp); + fclose(fp); +} + +void free_db(struct DB_STR *db) { + if (db == NULL) + return; + + while (db != NULL) { + struct DB_STR *i = db->next; + if (i == NULL) + return; + + if (db->filename != NULL) + free(db->filename); + + if (db->tags != NULL) { + for (size_t i = 0; i < db->size; i++) + if (db->tags[i] != NULL) + free(db->tags[i]); + + free(db->tags); + } + + free(db); + db = i; + } +} + +int append_tag(struct DB_STR *db, const char *tok, const size_t allocated) { + if (allocated == 0) { + db->tags = malloc(sizeof(char *) * (db->size + 1)); + if (db->tags == NULL) + return 1; + + db->tags[0] = strdup(tok); + if (db->tags[0] == NULL) { + free(db->tags); + return 1; + } + } + + else { + db->tags[allocated] = strdup(tok); + if (db->tags[allocated] == NULL) + return 1; + } + + return 0; +} + +struct DB_STR *new_db_value(char *str) { + struct DB_STR *db = malloc(sizeof(struct DB_STR)); + if (db == NULL) + return NULL; + + + /* Filename */ + char *tok = strtok(str, " "); + char *ptr = strrchr(tok, '\n'); + if (ptr != NULL) + *ptr = '\0'; + + db->filename = strdup(tok); + if (db->filename == NULL) + goto NDV_CLOSE; + + + /* Tags */ + tok = strtok(NULL, " "); + if (tok == NULL) + db->tags = NULL; + + else { + ptr = strrchr(tok, '\n'); + if (ptr != NULL) + *ptr = '\0'; + + for (size_t i = 0; i < strlen(tok); i++) + if (tok[i] == ',') + db->size++; + + size_t allocated = 0; + char *tok2 = strtok(tok, ","); + while (tok2 != NULL) { + if (append_tag(db, tok2, allocated)) + goto NDV_CLOSE; + + allocated++; + tok2 = strtok(NULL, ","); + } + } + + + return db; + +NDV_CLOSE: + free_db(db); + return NULL; +} + +struct DB_STR *read_db(void) { + FILE *fp = file_open(DB, "r"); + if (fp == NULL) + exit(1); + + int ret = 1; + + char *line = NULL; + ssize_t bytes = 0; + size_t n = 0; + + struct DB_STR *db = NULL; + struct DB_STR *i = NULL; + + while ((bytes = getline(&line, &n, fp))) { + if (bytes == -1) + break; + + else if (bytes <= 1) + continue; + + db = new_db_value(line); + if (db == NULL) + goto RDB_CLOSE; + + db->next = i; + i = db; + } + + ret = 0; + +RDB_CLOSE: + fclose(fp); + if (line) + free(line); + + if (ret) { + free_db(db); + fprintf(stderr, "8img: db: %s\n", strerror(errno)); + } + + return db; +} + +struct DB_STR *build_html(FILE *fp, const char *file, const struct UNIQ_TAGS ut, struct DB_STR *db, const size_t page, const size_t pages) { + fprintf(fp, "\n\n\n%s\n\n", CSS, TITLE); + + /* Tags */ + fputs("\n

\nall ", fp); + for (size_t i = 0; i < ut.size; i++) + fprintf(fp, "%s ", ut.tags[i], ut.tags[i]); + fputs("


\n
\n", fp); + + /* Images */ + size_t images = 0; + struct DB_STR *p = db; + while (p != NULL) { + struct DB_STR *i = p->next; + if (strcmp(file, "index")) { + char flag = 1; + for (size_t i = 0; i < p->size; i++) + if (!strcmp(p->tags[i], file)) + flag = 0; + + if (flag) { + p = i; + continue; + } + } + + fprintf(fp, "
%s


\n", p->filename, p->filename, p->filename); + for (size_t i = 0; i < p->size; i++) + fprintf(fp, " %s", p->tags[i], p->tags[i]); + + fputs("\n

\n", fp); + + p = i; + images++; + if (images >= POST_PER_PAGE) + break; + } + + for (size_t i = 0; i < pages; i++) { + if (i == 0) { + if (i == page) + fprintf(fp, "(0) ", file); + + else + fprintf(fp, "[0] ", file); + } + + else { + char new_path[PATH_MAX + 1]; + snprintf(new_path, sizeof(new_path), "%s-%zu.html", file, i); + + if (i == page) + fprintf(fp, "(%zu) ", new_path, i); + + else + fprintf(fp, "[%zu] ", new_path, i); + } + + } + + fprintf(fp, "\n"); + return p; +} + +void build(const char *file, const struct UNIQ_TAGS ut, struct DB_STR *db) { + FILE *fp = NULL; + + size_t page = 0; + size_t pages = 0; + + /* Count pages */ + size_t count = 0; + struct DB_STR *p = db; + while (p != NULL) { + struct DB_STR *i = p->next; + + if (!strcmp(file, "index")) + count++; + + else { + for (size_t i = 0; i < p->size; i++) + if (!strcmp(file, p->tags[i])) + count++; + } + + if (count >= POST_PER_PAGE) { + count = 0; + pages++; + } + + p = i; + } + + p = db; + while (1) { + if (fp != NULL) + fclose(fp); + + char new_path[PATH_MAX + 1]; + if (page == 0) + snprintf(new_path, sizeof(new_path), "%s/%s.html", ROOT, file); + + else + snprintf(new_path, sizeof(new_path), "%s/%s-%zu.html", ROOT, file, page); + + FILE *fp = file_open(new_path, "w"); + if (fp == NULL) + return; + + p = build_html(fp, file, ut, p, page, pages); + if (p == NULL) { + fclose(fp); + break; + } + + page++; + } +} + +char **uniq(struct DB_STR *db, size_t *uniq_size) { + char **uniq_tag = malloc(sizeof(char *)); + if (uniq_tag == NULL) + return NULL; + + struct DB_STR *p = db; + while (p != NULL) { + struct DB_STR *i = p->next; + + for (size_t i = 0; i < p->size; i++) { + if (p->tags == NULL) + break; + + char flag = 0; + for (size_t j = 0; j < *uniq_size; j++) { + if (!strcmp(p->tags[i], uniq_tag[j])) + flag = 1; + } + + if (flag) + continue; + + char **bckp = realloc(uniq_tag, sizeof(char *) * (*uniq_size + 1)); + if (bckp == NULL) { + free(uniq_tag); + return NULL; + } + + uniq_tag = bckp; + uniq_tag[*uniq_size] = p->tags[i]; + (*uniq_size)++; + } + + p = i; + } + + return uniq_tag; +} + +void rebuild(void) { + struct DB_STR *db = read_db(); + if (db == NULL) + return; + + /* Uniq */ + size_t uniq_size = 0; + char **uniq_tag = uniq(db, &uniq_size); + if (uniq_tag != NULL) { + struct UNIQ_TAGS ut = {.tags = uniq_tag, .size = uniq_size}; + + for (size_t i = 0; i < uniq_size; i++) + build(uniq_tag[i], ut, db); + + build("index", ut, db); + } + + else + fprintf(stderr, "8img: malloc: %s\n", strerror(errno)); + + /* Close */ + if (uniq_tag != NULL) + free(uniq_tag); + + free_db(db); +} + +void help(void) { + puts("8img [add/rebuild]:\n\tadd [img] [tag1] [tag2] [...]\n\trebuild"); + exit(0); +} + +int main(int argc, char **argv) { + if (argc < 2) + help(); + + mkdir(ROOT, 0777); + srand(getpid()); + + argv++; + argc--; + + /* Parse args */ + if (!strcmp(argv[0], "add") && argc > 1) + add(argv + 1, argc - 1); + + else if (!strcmp(argv[0], "rebuild")) + rebuild(); + + else + help(); +}