Upload files to "/"

This commit is contained in:
8nl 2024-11-10 09:38:38 +00:00
parent c6dc11871f
commit ae4e18faad
3 changed files with 465 additions and 0 deletions

8
Makefile Normal file
View File

@ -0,0 +1,8 @@
CC?=cc
CFLAGS?=-pedantic -Wall -Wextra
all:
$(CC) $(CFLAGS) img.c -o 8img
clean:
rm 8img

7
config.h Normal file
View File

@ -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"

450
img.c Normal file
View File

@ -0,0 +1,450 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <sys/stat.h>
#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, "<html>\n<head>\n<link rel='stylesheet' href='%s'>\n<title>%s</title>\n</head>\n<body>", CSS, TITLE);
/* Tags */
fputs("\n<p class='alltags'>\n<a href='index.html'>all </a>", fp);
for (size_t i = 0; i < ut.size; i++)
fprintf(fp, "<a href='%s.html'>%s </a>", ut.tags[i], ut.tags[i]);
fputs("</p><br>\n<div class='bar'></div>\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, "<article><a href='%s'><img class='img' src='%s' alt='%s'></a></article><br><br>\n", p->filename, p->filename, p->filename);
for (size_t i = 0; i < p->size; i++)
fprintf(fp, "<a href='%s.html'> %s</a>", p->tags[i], p->tags[i]);
fputs("\n<div class='bar'></div><br>\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, "<a href='%s.html'>(0) </a> ", file);
else
fprintf(fp, "<a href='%s.html'>[0] </a> ", file);
}
else {
char new_path[PATH_MAX + 1];
snprintf(new_path, sizeof(new_path), "%s-%zu.html", file, i);
if (i == page)
fprintf(fp, "<a href='%s'>(%zu) </a>", new_path, i);
else
fprintf(fp, "<a href='%s'>[%zu] </a>", new_path, i);
}
}
fprintf(fp, "</body></html>\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();
}