first commit

This commit is contained in:
Your Name 2025-01-24 20:30:34 +03:00
commit 3dcd9520d5
7 changed files with 543 additions and 0 deletions

11
LICENSE Normal file
View File

@ -0,0 +1,11 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

8
Makefile Normal file
View File

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

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# 8img

12
config.h Normal file
View File

@ -0,0 +1,12 @@
/* Absolute path to */
#define ROOT "."
#define DB ROOT"/db"
/* Html generator */
#define CSS "style.css"
#define LOGO "logo.jpg"
#define DESC "from outer space"
#define TITLE "8img gallery"
#define POST_PER_PAGE 5

474
img.c Normal file
View File

@ -0,0 +1,474 @@
#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(const char *filename) {
const char *alf = "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM";
char *ext = strrchr(filename, '.');
if (ext == NULL)
ext = "";
size_t size = 7 + strlen(ext);
char *id = malloc(size);
if (id == NULL)
return NULL;
for (size_t i = 0; i < size - strlen(ext); i++)
id[i] = alf[rand() % sizeof(alf)];
strcat(id, ext);
id[size] = '\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(list[0]);
if (name == NULL) {
fprintf(stderr, "8img: malloc: %s\n", strerror(errno));
exit(1);
}
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) {
free(name);
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);
free(name);
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>\n<a href='index.html'><img id='logo' src='%s'></a><h1 id='desc'>%s<br>%s/p%zu</h1>\n<center>", CSS, TITLE, LOGO, DESC, file, page);
/* Tags */
fputs("\n<a id='alltags' href='index.html'>all</a>", fp);
for (size_t i = 0; i < ut.size; i++)
fprintf(fp, "<a id='alltags' href='%s.html'> %s</a>", ut.tags[i], ut.tags[i]);
fputs("\n<br><br><br>\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, "<a href='%s'><img src='%s' alt='%s'></a><br>", p->filename, p->filename, p->filename);
for (size_t i = 0; i < p->size; i++)
fprintf(fp, "<a class='tags' href='%s.html'> %s</a>", p->tags[i], p->tags[i]);
fputs("\n<br><br><br>\n", fp);
p = i;
images++;
if (images >= POST_PER_PAGE)
break;
}
fputs("\n<div class='pager'>\n", fp);
for (size_t i = 0; i <= pages; i++) {
if (i == 0) {
if (i == page)
fprintf(fp, "<a id='curr' 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 id='curr' href='%s'>%zu</a>", new_path, i);
else
fprintf(fp, "<a href='%s'> %zu </a>", new_path, i);
}
}
fprintf(fp, "\n</div>\n</center>\n</body>\n</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 (count == POST_PER_PAGE) {
count = 0;
pages++;
}
if (!strcmp(file, "index"))
count++;
else {
for (size_t i = 0; i < p->size; i++)
if (!strcmp(file, p->tags[i]))
count++;
}
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\n\tversion");
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 if (!strcmp(argv[0], "version"))
puts("8img version: 1.0.1\nWritten under WTFPL License.");
else
help();
return 0;
}

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

36
style.css Normal file
View File

@ -0,0 +1,36 @@
body {
margin: auto;
padding: 2em;
}
a {
text-decoration: none;
color: #000000;
}
/* */
#logo {
display: block;
max-width: 10%;
}
#desc {
color: #000000;
}
.tags {
color: #000000;
}
/* */
.pager {}
.pager a {
text-decoration: underline;
}
.pager #curr {
color: #ffffff;
background-color: #000000;
}