Dynamic page index

This commit is contained in:
Matteo Bini 2024-07-30 16:44:43 +02:00
parent 86de41d87c
commit f79292d9f3
1 changed files with 369 additions and 75 deletions

444
srohtml.c
View File

@ -9,31 +9,61 @@
#define CLS_MAX 16
#define DATE_LEN 10
#define FAVICON "data:image/gif;base64,R0lGODlhEAAQAKEAAAAAcP///wAAcAAAcCH5BAEKAAIALAAAAAAQABAAQAIwlBWZxxwAQWjtTQRvlZhTnGSfYT3eZ3WaE4mjGa1UasoH7c6tzYanfqmhJMKXglcAADs="
#define INDEX_START 16
#define LANG_LEN 2
#define LINE_MAX 1000
#define LINE_START 80
#define NOTES_START 8
#define NOTES_MAX_DIGITS 3
typedef struct {
int indentation;
char *name;
} closure;
typedef struct {
int index;
int size;
closure *tags;
} closures;
typedef enum {
tag_content = 0,
tag_attribute = 1
} html_val_type;
typedef struct {
size_t size;
char *str;
} string;
typedef struct {
char *desc;
char *id;
char heading;
} index_title;
typedef struct {
int index;
int size;
index_title *titles;
} index;
typedef struct {
char *desc;
char *href;
} note;
typedef struct {
size_t index;
size_t size;
int index;
note *notes;
int size;
} references;
typedef struct {
size_t len;
size_t size;
char *str;
} string;
/* function declarations */
static size_t add_note(const char *href, const char *desc);
static void add_closure(closures *dst, const char *tag, const int ind);
static void add_h_to_index(const char heading, const char *id);
static int add_note(const char *href, const char *desc);
static void cmd(char *line);
static void cmd_close(void);
static void cmd_a(const char *line);
@ -45,6 +75,7 @@ static void cmd_fi(const char *line);
static void cmd_h(const char *line);
static void cmd_hr(void);
static void cmd_i(const char *line);
static void cmd_in();
static void cmd_la(const char *line);
static void cmd_le(void);
static void cmd_ls(void);
@ -55,11 +86,16 @@ static void cmd_q(const char *line);
static void cmd_st(const char *line);
static void cmd_tm(const char *line);
static void cmd_ur(const char *line);
static void findent(const int ind, FILE *f);
static void footer(void);
static void footnotes(void);
static int fputs_html(const char *str, FILE *f, const html_val_type t);
static size_t fread_line(FILE *file, char **str, size_t *len);
static void indent_str(char **str);
static void free_closures(closures *dst);
static void indent_str(char **str, const int ind);
static void nav_index(FILE *f);
static void page_head(void);
static void pop_closure(closures *dst);
static void print_help(void);
static void print_usage(void);
static void print_version(void);
@ -67,27 +103,68 @@ static void *safe_malloc(const size_t size);
static void *safe_realloc(void *ptr, const size_t size);
static size_t stread_param(const char *src, char **str);
static char *string_cat(string *dst, const char *src);
static char *string_cat_html(string *dst, const char *src, const int is_attr_val);
static char *string_cat_html(string *dst, const char *src, const html_val_type t);
static void string_enlarge(string *old, const size_t size);
static int string_putc(string *dst, const char c);
/* variables */
int imgs_presence = 0;
char *author = NULL;
char closure[CLS_MAX];
string body;
char *description = NULL;
string head;
size_t heading_position = 0;
int imgs_presence = 0;
int indentation = 2;
size_t index_position = 0;
char *language = NULL;
int licence_container = 0;
int space = 0;
string head;
string body;
index page_index;
char *pub_date = NULL;
references sitography;
int space = 0;
char tag_closure[CLS_MAX];
char *title = NULL;
/* function implementations */
size_t
void
add_closure(closures *dst, const char *name, const int ind)
{
closure *tag;
if (dst->index == dst->size) {
dst->size *= 2;
dst->tags = safe_realloc(dst->tags, sizeof(closure) * dst->size);
}
tag = dst->tags + dst->index;
tag->indentation = ind;
tag->name = safe_malloc(sizeof(char) * (strlen(name) + 1));
strcpy(tag->name, name);
dst->index++;
}
void
add_h_to_index(const char heading, const char *id)
{
index_title *new;
if (page_index.index == page_index.size) {
page_index.size *= 2;
page_index.titles = safe_realloc(page_index.titles, sizeof(index_title) * page_index.size);
}
new = page_index.titles + page_index.index;
new->desc = NULL;
new->heading = heading;
new->id = safe_malloc(sizeof(char) * (strlen(id) + 1));
strcpy(new->id, id);
heading_position = strlen(body.str);
}
int
add_note(const char *href, const char *desc)
{
note *new;
@ -147,6 +224,8 @@ cmd(char *line)
cmd_hr();
else if (!strncmp(line, "I", cmdlen))
cmd_i(line);
else if (!strncmp(line, "IN", cmdlen))
cmd_in();
else if (!strncmp(line, "LA", cmdlen))
cmd_la(line);
else if (!strncmp(line, "LE", cmdlen))
@ -199,11 +278,11 @@ cmd_a(const char *line)
string_cat(&body, "\"");
if (strcmp(title, "")) {
string_cat(&body, " title=\"");
string_cat_html(&body, title, 1);
string_cat_html(&body, title, tag_attribute);
string_cat(&body, "\"");
}
string_cat(&body, ">");
string_cat_html(&body, in, 1);
string_cat_html(&body, in, tag_attribute);
string_cat(&body, "</a>");
free(href);
@ -237,9 +316,28 @@ cmd_br(void)
void
cmd_close(void)
{
string_cat(&body, closure);
index_title *title;
title = NULL;
if ((!strcmp(tag_closure, "</h3>") ||
!strcmp(tag_closure, "</h4>") ||
!strcmp(tag_closure, "</h5>") ||
!strcmp(tag_closure, "</h6>")) &&
index_position && heading_position) {
title = page_index.titles + page_index.index;
title->desc = safe_malloc(sizeof(char) * (strlen(body.str + heading_position) + 1));
strcpy(title->desc, body.str + heading_position);
page_index.index++;
heading_position = 0;
}
string_cat(&body, tag_closure);
string_cat(&body, "\n");
strcpy(closure, "");
strcpy(tag_closure, "");
space = 0;
}
@ -260,12 +358,12 @@ cmd_dt(const char *line)
if (space)
string_cat(&body, " ");
string_cat(&body, "<time datetime=\"");
string_cat_html(&body, datetime, 1);
string_cat_html(&body, datetime, tag_attribute);
string_cat(&body, "\">");
if (!strcmp(in, ""))
string_cat_html(&body, datetime, 0);
string_cat_html(&body, datetime, tag_content);
else
string_cat_html(&body, in, 0);
string_cat_html(&body, in, tag_content);
string_cat(&body, "</time>");
free(datetime);
@ -301,7 +399,7 @@ cmd_fi(const char *line)
/* move past argument, once found it */
line += stread_param(line, &src);
indent_str(&ind);
indent_str(&ind, indentation);
string_cat(&body, ind);
string_cat(&body, "<figure><img src=\"");
@ -315,18 +413,28 @@ cmd_fi(const char *line)
void
cmd_h(const char *line)
{
const char *id;
id = NULL;
string_cat(&body, "\t\t<h");
string_putc(&body, line[1]);
if (line[2] == ' ' && line[3] != '\0') {
if (strlen(line) > 4 && line[2] == ' ' && line[3] != '\0') {
id = line + 3;
string_cat(&body, " id=\"");
string_cat_html(&body, line + 3, 1);
string_cat_html(&body, id, tag_attribute);
string_cat(&body, "\"");
}
string_cat(&body, ">");
strcpy(closure, "</h");
closure[3] = line[1];
closure[4] = '>';
closure[5] = '\0';
strcpy(tag_closure, "</h");
tag_closure[3] = line[1];
tag_closure[4] = '>';
tag_closure[5] = '\0';
if (id != NULL && index_position != 0)
add_h_to_index(line[1], id);
}
void
@ -349,6 +457,14 @@ cmd_i(const char *line)
string_cat(&body, "<i>");
string_cat(&body, line);
string_cat(&body, "</i>");
space = 1;
}
void
cmd_in(void)
{
index_position = strlen(body.str);
}
void
@ -379,7 +495,7 @@ cmd_le(void)
ind = NULL;
indentation--;
indent_str(&ind);
indent_str(&ind, indentation);
string_cat(&body, ind);
string_cat(&body, "</div>\n");
@ -394,14 +510,14 @@ cmd_ls(void)
ind = NULL;
licence_container = 1;
indent_str(&ind);
indent_str(&ind, indentation);
string_cat(&body, ind);
string_cat(&body, "<div class=\"contenitore-licenza\">\n");
indentation++;
free(ind);
ind = NULL;
indent_str(&ind);
indent_str(&ind, indentation);
string_cat(&body, ind);
string_cat(&body, "<hr>\n");
@ -435,7 +551,7 @@ cmd_no(const char *line)
string_cat(&body, "\"");
if (strcmp(title, "")) {
string_cat(&body, " title=\"");
string_cat_html(&body, title, 1);
string_cat_html(&body, title, tag_attribute);
string_cat(&body, "\"");
}
string_cat(&body, ">[");
@ -454,11 +570,11 @@ cmd_p(void)
ind = NULL;
indent_str(&ind);
indent_str(&ind, indentation);
string_cat(&body, ind);
string_cat(&body, "<p>");
strcpy(closure, "</p>");
strcpy(tag_closure, "</p>");
free(ind);
}
@ -500,12 +616,12 @@ cmd_q(const char *line)
string_cat(&body, "<q");
if (strcmp(cite, "")) {
string_cat(&body, " cite=\"");
string_cat_html(&body, cite, 1);
string_cat_html(&body, cite, tag_attribute);
string_cat(&body, "\"");
}
string_cat(&body, ">");
space = 0;
strcpy(closure, "</q></p>");
strcpy(tag_closure, "</q></p>");
free(cite);
@ -514,13 +630,17 @@ cmd_q(const char *line)
void
cmd_st(const char *line)
{
size_t len;
len = strlen(body.str);
/* move past "ST" */
line += 2;
/* move past space, if present */
if (line[0] == ' ')
line++;
if (space && body.str[body.len - 1] != '\'')
if (space && len > 0 && body.str[len - 1] != '\'')
string_cat(&body, " ");
string_cat(&body, "<strong>");
string_cat(&body, line);
@ -548,7 +668,7 @@ cmd_tm(const char *line)
string_cat(&body, hours);
}
string_cat(&body, "\">");
string_cat_html(&body, in, 0);
string_cat_html(&body, in, tag_content);
string_cat(&body, "</time>");
free(date);
@ -568,12 +688,24 @@ cmd_ur(const char *line)
if (space)
string_cat(&body, " ");
string_cat(&body, "&lt;<a class=\"url\" href=\"");
string_cat_html(&body, line, 1);
string_cat_html(&body, line, tag_attribute);
string_cat(&body, "\">");
string_cat_html(&body, line, 0);
string_cat_html(&body, line, tag_content);
string_cat(&body, "</a>&gt;");
}
void
findent(const int ind, FILE *f)
{
char *str;
str = NULL;
indent_str(&str, ind);
fputs(str, f);
free(str);
}
void
footer(void)
{
@ -620,10 +752,10 @@ footer(void)
string_cat(&body, "\">");
strftime(str, max, "%x", now);
string_cat_html(&body, str, 0);
string_cat_html(&body, str, tag_content);
strftime(str, max, " %R", now);
string_cat_html(&body, str, 0);
string_cat_html(&body, str, tag_content);
string_cat(&body, "</time></p>\n");
string_cat(&body, "\t\t</footer>\n");
@ -633,7 +765,8 @@ void
footnotes(void)
{
note *cur;
size_t i, dig_num, x;
int i;
size_t dig_num, x;
char id[NOTES_MAX_DIGITS + 1];
char pad[6 * (NOTES_MAX_DIGITS - 1) + 1];
@ -663,13 +796,13 @@ footnotes(void)
string_cat(&body, id);
string_cat(&body, "</a></span> ");
if (strcmp(cur->desc, "")) {
string_cat_html(&body, cur->desc, 0);
string_cat_html(&body, cur->desc, tag_content);
string_cat(&body, " ");
}
string_cat(&body, "&lt;<a class=\"url\" href=\"");
string_cat(&body, cur->href);
string_cat(&body, "\">");
string_cat_html(&body, cur->href, 0);
string_cat_html(&body, cur->href, tag_content);
string_cat(&body, "</a>&gt;</p>\n");
free(cur->desc);
free(cur->href);
@ -679,6 +812,33 @@ footnotes(void)
string_cat(&body, "\t\t</div>\n");
}
int
fputs_html(const char *str, FILE *f, const html_val_type t)
{
size_t i, len;
int res;
len = strlen(str);
res = 0;
for (i = 0; i < len; i++) {
if (res == EOF)
return EOF;
if (t == tag_attribute && str[i] == '"')
res = fputs("&quot;", f);
else if (str[i] == '&')
res = fputs("&amp;", f);
else if (str[i] == '<')
res = fputs("&lt;", f);
else if (str[i] == '>')
res = fputs("&gt;", f);
else
res = fputc(str[i], f);
}
return 1;
}
size_t
fread_line(FILE *file, char **str, size_t *len)
{
@ -707,14 +867,23 @@ fread_line(FILE *file, char **str, size_t *len)
}
void
indent_str(char **str)
free_closures(closures *dst)
{
int i;
*str = safe_malloc(sizeof(char) * (indentation + 1));
for (i = 0; i < indentation; i++)
for (i = 0; i < dst->index; i++)
free(dst->tags[i].name);
}
void
indent_str(char **str, const int ind)
{
int i;
*str = safe_malloc(sizeof(char) * (ind + 1));
for (i = 0; i < ind; i++)
(*str)[i] = '\t';
(*str)[indentation] = '\0';
(*str)[ind] = '\0';
}
int
@ -748,21 +917,23 @@ main (int argc, char *argv[])
}
head.size = BODY_START_SIZE / 4;
head.str = safe_malloc(head.size);
head.str = safe_malloc(sizeof(char) * head.size);
strcpy(head.str, "");
head.len = 0;
body.size = BODY_START_SIZE;
body.str = safe_malloc(body.size);
body.str = safe_malloc(sizeof(char) * body.size);
strcpy(body.str, "");
body.len = 0;
string_cat(&body, "\t<body>\n");
page_index.index = 0;
page_index.size = INDEX_START;
page_index.titles = safe_malloc(sizeof(index_title) * page_index.size);
sitography.index = 0;
sitography.size = NOTES_START;
sitography.notes = malloc(sizeof(note) * sitography.size);
string_cat(&body, "\t<body>\n");
len = 0;
line = NULL;
while (fread_line(in, &line, &len) != EOF) {
@ -782,7 +953,7 @@ main (int argc, char *argv[])
line[0] != ';' &&
line[0] != '?')
string_cat(&body, " ");
string_cat_html(&body, line, 0);
string_cat_html(&body, line, tag_content);
space = 1;
}
free(line);
@ -793,7 +964,7 @@ main (int argc, char *argv[])
if (in != stdin)
fclose(in);
if (strcmp(closure, ""))
if (strcmp(tag_closure, ""))
cmd_close();
page_head();
@ -812,12 +983,104 @@ main (int argc, char *argv[])
}
fputs(head.str, out);
fputs(body.str, out);
{
char c;
c = body.str[index_position];
body.str[index_position] = '\0';
fputs(body.str, out);
if (index_position)
nav_index(out);
body.str[index_position] = c;
fputs(body.str + index_position, out);
}
fclose(out);
return 0;
}
void
nav_index(FILE *f)
{
int i, n;
int ind;
closure *tag;
closures nav_cls;
index_title *next_title, *title;
ind = 2;
nav_cls.index = 0;
nav_cls.size = 4;
nav_cls.tags = safe_malloc(sizeof(closure) * nav_cls.size);
tag = NULL;
findent(ind++, f);
fputs("<nav>\n", f);
findent(ind, f);
fputs("<hr>\n", f);
findent(ind, f);
fputs("<h3 id=\"indice\">Indice</h3>\n", f);
for (i = 0; i < page_index.index; i++) {
title = page_index.titles + i;
next_title = i == page_index.index - 1 ? NULL : title + 1;
if (i == 0) {
findent(ind, f);
fputs("<ul>\n", f);
add_closure(&nav_cls, "ul", ind);
ind++;
}
findent(ind, f);
fputs("<li><a href=\"#", f);
fputs_html(title->id, f, tag_attribute);
fprintf(f, "\">%s</a>", title->desc);
add_closure(&nav_cls, "li", ind);
if (i == page_index.index - 1) {
fputs("</li>\n", f);
ind--;
pop_closure(&nav_cls);
for (n = nav_cls.index - 1; n >= 0; n--) {
tag = nav_cls.tags + n;
findent(tag->indentation, f);
fprintf(f, "</%s>\n", tag->name);
}
findent(tag->indentation, f);
fputs("<hr>\n", f);
ind--;
} else if (next_title->heading < title->heading) {
fputs("</li>\n", f);
pop_closure(&nav_cls);
findent(--ind, f);
fputs("</ul>\n", f);
pop_closure(&nav_cls);
findent(--ind, f);
fputs("</li>\n", f);
pop_closure(&nav_cls);
} else if (next_title->heading > title->heading) {
fputs("\n", f);
findent(++ind, f);
fputs("<ul>\n", f);
add_closure(&nav_cls, "ul", ind);
ind++;
} else if ((title + 1)->heading == title->heading) {
fputs("</li>\n", f);
pop_closure(&nav_cls);
}
free(title->desc);
free(title->id);
}
findent(--tag->indentation, f);
fputs("</nav>\n", f);
free_closures(&nav_cls);
free(nav_cls.tags);
free(page_index.titles);
}
void
page_head(void)
{
@ -826,7 +1089,7 @@ page_head(void)
string_cat(&head, "<html");
if (language != NULL) {
string_cat(&head, " lang=\"");
string_cat_html(&head, language, 1);
string_cat_html(&head, language, tag_attribute);
string_cat(&head, "\"");
free(language);
@ -841,7 +1104,7 @@ page_head(void)
if (author != NULL) {
string_cat(&head, "\t\t<meta name=\"author\" content=\"");
string_cat_html(&head, author, 1);
string_cat_html(&head, author, tag_attribute);
string_cat(&head, "\">\n");
free(author);
@ -849,7 +1112,7 @@ page_head(void)
if (description != NULL) {
string_cat(&head, "\t\t<meta name=\"description\" content=\"");
string_cat_html(&head, description, 1);
string_cat_html(&head, description, tag_attribute);
string_cat(&head, "\">\n");
free(description);
@ -864,7 +1127,13 @@ page_head(void)
" width: 90%;\n" \
" }\n" \
"\n" \
" p {\n" \
" p"
);
if (index_position)
string_cat(&head, ",\n\t\t\tli {");
else
string_cat(&head, " {");
string_cat(&head, "\n" \
" line-height: 1.5;\n" \
" }\n" \
"\n" \
@ -935,8 +1204,18 @@ page_head(void)
" @media print {\n" \
" body {\n" \
" max-width: 90%;\n" \
" }\n" \
"\n" \
" }\n"
);
if (index_position) {
string_cat(&head, "\n" \
" nav {\n" \
" display: none;\n" \
" }\n"
);
}
string_cat(&head, "\n" \
" a.nav {\n" \
" color: inherit;\n" \
" text-decoration: none;\n" \
@ -948,7 +1227,7 @@ page_head(void)
if (title != NULL) {
string_cat(&head, "\t\t<title>");
string_cat_html(&head, title, 0);
string_cat_html(&head, title, tag_content);
string_cat(&head, "</title>\n");
free(title);
@ -994,6 +1273,19 @@ print_version(void)
exit(1);
}
void
pop_closure(closures *dst)
{
closure *tag;
if (dst->index <= 0)
return;
tag = dst->tags + (dst->index - 1);
free(tag->name);
dst->index--;
}
void *
safe_malloc(const size_t size)
{
@ -1062,24 +1354,23 @@ string_cat(string *dst, const char *src)
len = strlen(src);
if (len >= (dst->size - dst->len))
if (len >= (dst->size - strlen(dst->str)))
string_enlarge(dst, (dst->size + len) * 2 + 1);
strcat(dst->str, src);
dst->len = dst->len + len;
return dst->str;
}
char *
string_cat_html(string *dst, const char *src, const int is_attr_val)
string_cat_html(string *dst, const char *src, const html_val_type t)
{
size_t i, len;
len = strlen(src);
for (i = 0; i < len; i++) {
if (is_attr_val && src[i] == '"')
if (t == tag_attribute && src[i] == '"')
string_cat(dst, "&quot;");
else if (src[i] == '&')
string_cat(dst, "&amp;");
@ -1104,12 +1395,15 @@ string_enlarge(string *old, const size_t size)
int
string_putc(string *dst, const char c)
{
if ((dst->size - dst->len) <= 1)
size_t len;
len = strlen(dst->str);
if ((dst->size - len) <= 1)
string_enlarge(dst, (dst->size + 1) * 2 + 1);
dst->str[dst->len] = c;
dst->str[dst->len + 1] = '\0';
dst->len++;
dst->str[len] = c;
dst->str[len + 1] = '\0';
return (int) c;
}