#include
#include
#include
#include
#include
/* macros */
#define BODY_START_SIZE 26624 /* 26 x 1024 byte = 26 KiB */
#define CLS_MAX 16
#define DATE_LEN 10
#define FAVICON "data:image/gif;base64,R0lGODlhEAAQAKEAAAAAcP///wAAcAAAcCH5BAEKAAIALAAAAAAQABAAQAIwlBWZxxwAQWjtTQRvlZhTnGSfYT3eZ3WaE4mjGa1UasoH7c6tzYanfqmhJMKXglcAADs="
#define FIGCAPTION_TAG_LEN 12
#define FIGURE_SIZES_START 4
#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 {
void *data;
size_t length;
size_t size;
size_t unit_size;
} array;
typedef struct {
int indentation;
char *name;
} closure;
typedef enum {
tag_content = 0,
tag_attribute = 1
} html_val_type;
typedef struct {
char *id;
char *print_width;
char *width;
} img;
typedef struct {
char *desc;
char *id;
char heading;
} index_title;
typedef struct {
char *desc;
char *href;
} note;
/* function declarations */
static void add_closure(closure *tag, const char *name, 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 *array_at(array *a, const size_t i);
static void array_init(array *a, const size_t size, size_t num);
static void *array_pop(array *a);
static void *array_push(array *a);
static char *array_strcat(array *dst, const char *src);
static char *array_strcat_html(array *dst, const char *src, const html_val_type t);
static void cmd(char *line);
static void cmd_a(const char *line);
static void cmd_au_de_ti(char **dst, const char *line);
static void cmd_br(void);
static void cmd_close(void);
static void cmd_default_figure_sizes(const char *line);
static void cmd_em(const char *line);
static void cmd_figure(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_index(const char *line);
static void cmd_lang(const char *line);
static void cmd_line_tag(const char *tag);
static void cmd_note(const char *line);
static void cmd_publication_date(const char *line);
static void cmd_q(const char *line);
static void cmd_strong(const char *line);
static void cmd_tag_end(const char *tag);
static void cmd_tag_start(const char *tag, const char *id, const char *class);
static void cmd_time(const char *line);
static void cmd_url(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, const int ind);
static void nav_index(FILE *f);
static void page_head(void);
static void pop_closure(array *a);
static void print_help(void);
static void print_usage(void);
static void print_version(void);
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);
/* variables */
char *author = NULL;
array body;
char *description = NULL;
int figcaption_presence = 0;
array figure_sizes;
array head;
size_t heading_position = 0;
int img_presence = 0;
int indentation = 2;
array index;
char *index_heading = NULL;
char *index_heading_id = NULL;
size_t index_position = 0;
char *language = NULL;
int li_presence = 0;
int licence_container = 0;
int nav_presence = 0;
char *publication_date = NULL;
array sitography;
int space = 0;
char tag_closure[CLS_MAX];
char *title = NULL;
/* function implementations */
void
add_closure(closure *tag, const char *name, const int ind)
{
tag->indentation = ind;
tag->name = safe_malloc(sizeof(char) * (strlen(name) + 1));
strcpy(tag->name, name);
}
void
add_h_to_index(const char heading, const char *id)
{
index_title *new;
new = array_push(&index);
new->desc = NULL;
new->heading = heading;
new->id = safe_malloc(sizeof(char) * (strlen(id) + 1));
strcpy(new->id, id);
heading_position = strlen(body.data);
}
int
add_note(const char *href, const char *desc)
{
note *new;
new = array_push(&sitography);
new->href = safe_malloc(sizeof(char) * (strlen(href) + 1));
strcpy(new->href, href);
new->desc = safe_malloc(sizeof(char) * (strlen(desc) + 1));
strcpy(new->desc, desc);
return sitography.length;
}
void *
array_at(array *a, const size_t i)
{
if (i >= a->length)
return NULL;
return (char *) a->data + i * a->unit_size;
}
void *
array_pop(array *a)
{
if (a->length == 0)
return NULL;
a->length--;
return (char *) a->data + a->length * a->unit_size;
}
void *
array_push(array *a)
{
if (a->length == a->size) {
a->size *= 2;
a->data = safe_realloc(a->data, a->unit_size * a->size);
}
return (char *) a->data + a->length++ * a->unit_size;
}
void
cmd(char *line)
{
char *end;
size_t cmdlen;
if (!(end = strchr(line, ' ')))
end = line + strlen(line);
cmdlen = end - ++line;
if (!strncmp(line, "A", cmdlen))
cmd_a(line);
else if (!strncmp(line, "AUTHOR", cmdlen))
cmd_au_de_ti(&author, line);
else if (!strncmp(line, "BR", cmdlen))
cmd_br();
else if (!strncmp(line, "DEFAULT_FIGURE_SIZES", cmdlen))
cmd_default_figure_sizes(line);
else if (!strncmp(line, "DESCRIPTION", cmdlen))
cmd_au_de_ti(&description, line);
else if (!strncmp(line, "TIME", cmdlen))
cmd_time(line);
else if (!strncmp(line, "EM", cmdlen))
cmd_em(line);
else if (!strncmp(line, "FIGURE", cmdlen))
cmd_figure(line);
else if (!strncmp(line, "H1", cmdlen))
cmd_h(line);
else if (!strncmp(line, "H2", cmdlen))
cmd_h(line);
else if (!strncmp(line, "H3", cmdlen))
cmd_h(line);
else if (!strncmp(line, "H4", cmdlen))
cmd_h(line);
else if (!strncmp(line, "H5", cmdlen))
cmd_h(line);
else if (!strncmp(line, "H6", cmdlen))
cmd_h(line);
else if (!strncmp(line, "HR", cmdlen))
cmd_hr();
else if (!strncmp(line, "I", cmdlen))
cmd_i(line);
else if (!strncmp(line, "INDEX", cmdlen))
cmd_index(line);
else if (!strncmp(line, "LANG", cmdlen))
cmd_lang(line);
else if (!strncmp(line, "LI", cmdlen)) {
cmd_line_tag("li");
li_presence = 1;
} else if (!strncmp(line, "LICENSE_END", cmdlen))
cmd_tag_end("div");
else if (!strncmp(line, "LICENSE_START", cmdlen)) {
cmd_tag_start("div", "", "contenitore-licenza");
cmd_hr();
} else if (!strncmp(line, "NAV_END", cmdlen))
cmd_tag_end("nav");
else if (!strncmp(line, "NAV_START", cmdlen)) {
cmd_tag_start("nav", "", "");
nav_presence = 1;
} else if (!strncmp(line, "NOTE", cmdlen))
cmd_note(line);
else if (!strncmp(line, "P", cmdlen))
cmd_line_tag("p");
else if (!strncmp(line, "PUBLICATION_DATE", cmdlen))
cmd_publication_date(line);
else if (!strncmp(line, "Q", cmdlen))
cmd_q(line);
else if (!strncmp(line, "STRONG", cmdlen))
cmd_strong(line);
else if (!strncmp(line, "TITLE", cmdlen))
cmd_au_de_ti(&title, line);
else if (!strncmp(line, "UL_END", cmdlen))
cmd_tag_end("ul");
else if (!strncmp(line, "UL_START", cmdlen))
cmd_tag_start("ul", "", "");
else if (!strncmp(line, "URL", cmdlen))
cmd_url(line);
}
void
cmd_a(const char *line)
{
char *href, *in, *title;
href = NULL;
in = NULL;
title = NULL;
/* move past "A" */
line += 1;
/* move past arguments, once found them */
line += stread_param(line, &href);
line += stread_param(line, &in);
line += stread_param(line, &title);
if (space)
array_strcat(&body, " ");
array_strcat(&body, "");
array_strcat_html(&body, in, tag_attribute);
array_strcat(&body, "");
free(href);
free(in);
free(title);
}
void
cmd_au_de_ti(char **dst, const char *line)
{
/* move past command */
line = strchr(line, ' ');
if (line == NULL)
return;
/* move past ' ', if present */
if (line[0] == ' ')
line++;
if (*dst != NULL)
free(*dst);
*dst = safe_malloc(sizeof(char) * (strlen(line) + 1));
strcpy(*dst, line);
}
void
cmd_br(void)
{
array_strcat(&body, "
");
space = 0;
}
void
cmd_close(void)
{
char *bodystr;
char *ind, *line;
index_title *title;
bodystr = body.data;
ind = NULL;
line = NULL;
title = NULL;
if (!strcmp(tag_closure, "")) {
if (body.length >= FIGCAPTION_TAG_LEN + indentation)
line = bodystr + body.length - FIGCAPTION_TAG_LEN;
if (line != NULL && !strcmp(line, "")) {
*(line - indentation) = '\0';
body.length = strlen(bodystr);
} else {
figcaption_presence = 1;
array_strcat(&body, "\n");
}
indent_str(&ind, --indentation);
array_strcat(&body, ind);
free(ind);
}
if ((!strcmp(tag_closure, "") ||
!strcmp(tag_closure, "") ||
!strcmp(tag_closure, "") ||
!strcmp(tag_closure, "")) &&
index_position && heading_position) {
title = array_at(&index, index.length - 1);
if (title == NULL) {
fprintf(stderr, BIN ": Can't find title at position %i, in index array.\n", index.length - 1);
exit(1);
}
title->desc = safe_malloc(sizeof(char) * (strlen(bodystr + heading_position) + 1));
strcpy(title->desc, bodystr + heading_position);
heading_position = 0;
}
array_strcat(&body, tag_closure);
array_strcat(&body, "\n");
strcpy(tag_closure, "");
space = 0;
}
void
cmd_default_figure_sizes(const char *line)
{
char *print_width, *width;
img *sizes;
print_width = NULL;
width = NULL;
/* move past "DEFAULT_FIGURE_SIZES" */
line += 20;
/* move past arguments, once found them */
line += stread_param(line, &width);
line += stread_param(line, &print_width);
if (strcmp(width, "")) {
sizes = array_at(&figure_sizes, 0);
if (sizes == NULL)
sizes = array_push(&figure_sizes);
sizes->id = NULL;
sizes->print_width = NULL;
sizes->width = width;
if (strcmp(print_width, ""))
sizes->print_width = print_width;
}
if (!strcmp(print_width, ""))
free(print_width);
if (!strcmp(width, ""))
free(width);
}
void
cmd_em(const char *line)
{
/* move past "EM" */
line += 2;
/* move past ' ', if present */
if (line[0] == ' ')
line++;
if (space)
array_strcat(&body, " ");
array_strcat(&body, "");
array_strcat(&body, line);
array_strcat(&body, "");
}
void
cmd_figure(const char *line)
{
char *id, *ind, *print_width, *src, *width;
img *sizes;
id = NULL;
ind = NULL;
print_width = NULL;
src = NULL;
width = NULL;
/* move past "FIGURE" */
line += 6;
/* move past arguments, once found them */
line += stread_param(line, &src);
line += stread_param(line, &id);
line += stread_param(line, &width);
line += stread_param(line, &print_width);
indent_str(&ind, indentation);
array_strcat(&body, ind);
array_strcat(&body, "");
if (strcmp(id, "") && strcmp(width, "")) {
sizes = array_push(&figure_sizes);
sizes->id = id;
sizes->print_width = NULL;
sizes->width = width;
if (strcmp(print_width, ""))
sizes->print_width = print_width;
}
if (!strcmp(width, ""))
free(id);
free(ind);
if (!strcmp(print_width, ""))
free(print_width);
free(src);
if (!strcmp(width, ""))
free(width);
}
void
cmd_h(const char *line)
{
const char *id;
char h[2], *ind;
h[0] = line[1];
h[1] = '\0';
id = NULL;
ind = NULL;
indent_str(&ind, indentation);
array_strcat(&body, ind);
array_strcat(&body, " 4 && line[2] == ' ' && line[3] != '\0') {
id = line + 3;
array_strcat(&body, " id=\"");
array_strcat_html(&body, id, tag_attribute);
array_strcat(&body, "\"");
}
array_strcat(&body, ">");
strcpy(tag_closure, "';
tag_closure[5] = '\0';
if (id != NULL && index_position != 0)
add_h_to_index(line[1], id);
free(ind);
}
void
cmd_hr(void)
{
char *ind;
ind = NULL;
indent_str(&ind, indentation);
array_strcat(&body, ind);
array_strcat(&body, "
\n");
free(ind);
}
void
cmd_i(const char *line)
{
/* move past "I" */
line += 1;
/* move past ' ', if present */
if (line[0] == ' ')
line++;
if (space)
array_strcat(&body, " ");
array_strcat(&body, "");
array_strcat(&body, line);
array_strcat(&body, "");
space = 1;
}
void
cmd_index(const char *line)
{
/* move past "INDEX" */
line += 5;
/* move past arguments, once found them */
line += stread_param(line, &index_heading);
line += stread_param(line, &index_heading_id);
if (!strcmp(index_heading, "")) {
free(index_heading);
index_heading = NULL;
}
if (!strcmp(index_heading_id, "")) {
free(index_heading_id);
index_heading_id = NULL;
}
index_position = body.length;
}
void
cmd_lang(const char *line)
{
/* move past "LANG" */
line += 4;
/* move past ' ', if present */
if (line[0] == ' ')
line++;
if (strlen(line) != LANG_LEN)
return;
if (language == NULL) {
language = safe_malloc(sizeof(char) * (LANG_LEN + 1));
language[LANG_LEN] = '\0';
}
strncpy(language, line, LANG_LEN);
}
void
cmd_line_tag(const char *tag)
{
char *ind;
ind = NULL;
indent_str(&ind, indentation);
array_strcat(&body, ind);
array_strcat(&body, "<");
array_strcat(&body, tag);
array_strcat(&body, ">");
strcpy(tag_closure, "");
strcat(tag_closure, tag);
strcat(tag_closure, ">");
free(ind);
}
void
cmd_nav_end(const char *line)
{
char *ind;
ind = NULL;
indentation--;
indent_str(&ind, indentation);
array_strcat(&body, ind);
array_strcat(&body, "\n");
free(ind);
}
void
cmd_note(const char *line)
{
char *desc, *href, *title;
char index[NOTES_MAX_DIGITS + 1];
desc = NULL;
href = NULL;
title = NULL;
/* move past "NOTE" */
line += 4;
/* move past arguments, once found them */
line += stread_param(line, &href);
line += stread_param(line, &desc);
line += stread_param(line, &title);
if (space)
array_strcat(&body, " ");
sprintf(index, "%u", add_note(href, desc));
array_strcat(&body, "[");
array_strcat(&body, index);
array_strcat(&body, "]");
free(desc);
free(href);
free(title);
}
void
cmd_publication_date(const char *line)
{
/* move past "PUBLICATION_DATE" */
line += 16;
/* move past ' ', if present */
if (line[0] == ' ')
line++;
if (strlen(line) != DATE_LEN)
return;
if (publication_date == NULL) {
publication_date = safe_malloc(sizeof(char) * (DATE_LEN + 1));
publication_date[DATE_LEN] = '\0';
}
strncpy(publication_date, line, DATE_LEN);
}
void
cmd_q(const char *line)
{
char *cite;
cite = NULL;
/* move past "Q" */
line += 1;
/* move past argument, if found it */
line += stread_param(line, &cite);
if (space)
array_strcat(&body, " ");
array_strcat(&body, "");
space = 0;
strcpy(tag_closure, "
");
free(cite);
}
void
cmd_strong(const char *line)
{
char *bodystr;
bodystr = body.data;
/* move past "STRONG" */
line += 6;
/* move past space, if present */
if (line[0] == ' ')
line++;
if (space && body.length > 0 && bodystr[body.length - 1] != '\'')
array_strcat(&body, " ");
array_strcat(&body, "");
array_strcat(&body, line);
array_strcat(&body, "");
}
void
cmd_tag_end(const char *tag)
{
char *ind;
ind = NULL;
indentation--;
indent_str(&ind, indentation);
array_strcat(&body, ind);
array_strcat(&body, "");
array_strcat(&body, tag);
array_strcat(&body, ">\n");
free(ind);
}
void
cmd_tag_start(const char *tag, const char *id, const char *class)
{
char *ind;
ind = NULL;
licence_container = 1;
indent_str(&ind, indentation);
array_strcat(&body, ind);
array_strcat(&body, "<");
array_strcat(&body, tag);
if (strcmp(id, "")) {
array_strcat(&body, " id=\"");
array_strcat_html(&body, id, tag_attribute);
array_strcat(&body, "\"");
}
if (strcmp(class, "")) {
array_strcat(&body, " class=\"");
array_strcat_html(&body, class, tag_attribute);
array_strcat(&body, "\"");
}
array_strcat(&body, ">\n");
indentation++;
free(ind);
}
void
cmd_time(const char *line)
{
char *datetime, *in;
datetime = NULL;
in = NULL;
/* move past "TIME" */
line += 4;
/* move past arguments, once found them */
line += stread_param(line, &datetime);
line += stread_param(line, &in);
if (space)
array_strcat(&body, " ");
array_strcat(&body, "");
free(datetime);
free(in);
}
void
cmd_url(const char *line)
{
/* move past "URL" */
line += 3;
/* move past ' ', if present */
if (line[0] == ' ')
line++;
if (space)
array_strcat(&body, " ");
array_strcat(&body, "<");
array_strcat_html(&body, line, tag_content);
array_strcat(&body, ">");
}
void
findent(const int ind, FILE *f)
{
char *str;
str = NULL;
indent_str(&str, ind);
fputs(str, f);
free(str);
}
void
footer(void)
{
size_t max;
struct tm *now;
char str[16];
time_t s;
int tm_mday, tm_mon, tm_year;
struct tm tm_pd = { 0 };
max = 16;
array_strcat(&body, "\t\t\n");
}
void
footnotes(void)
{
note *cur;
int i;
size_t dig_num, x;
char id[NOTES_MAX_DIGITS + 1];
char pad[6 * (NOTES_MAX_DIGITS - 1) + 1];
if (sitography.length == 0)
return;
array_strcat(&body, "\t\t
\n");
array_strcat(&body, "\t\t\n");
array_strcat(&body, "\t\t\t
Sitografia
\n");
cur = sitography.data;
sprintf(id, "%u", sitography.length);
dig_num = strlen(id);
for (i = 0; i < sitography.length; i++) {
sprintf(id, "%u", i + 1);
array_strcat(&body, "\t\t\t
");
strcpy(pad, "");
for (x = strlen(id); x < dig_num; x++)
strcat(pad, " ");
array_strcat(&body, pad);
array_strcat(&body, "");
array_strcat(&body, id);
array_strcat(&body, " ");
if (strcmp(cur->desc, "")) {
array_strcat_html(&body, cur->desc, tag_content);
array_strcat(&body, " ");
}
array_strcat(&body, "<href);
array_strcat(&body, "\">");
array_strcat_html(&body, cur->href, tag_content);
array_strcat(&body, ">
\n");
free(cur->desc);
free(cur->href);
cur++;
}
array_strcat(&body, "\t\t
\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(""", f);
else if (str[i] == '&')
res = fputs("&", f);
else if (str[i] == '<')
res = fputs("<", f);
else if (str[i] == '>')
res = fputs(">", f);
else
res = fputc(str[i], f);
}
return 1;
}
size_t
fread_line(FILE *file, char **str, size_t *len)
{
int c;
size_t i;
if (*str == NULL) {
*len = LINE_START + 1;
*str = safe_malloc(sizeof(char) * *len);
}
i = 0;
while ((c = fgetc(file)) && c != '\n' && c != EOF && i < LINE_MAX) {
if (i >= *len - 1) {
*len *= 2;
*str = safe_realloc(*str, sizeof(char) * *len);
}
(*str)[i] = c;
i++;
}
(*str)[i] = '\0';
*len = i;
return c == EOF ? EOF : i;
}
void
indent_str(char **str, const int ind)
{
int i;
if (*str == NULL || strlen(*str) <= ind) {
free(*str);
*str = safe_malloc(sizeof(char) * (ind + 1));
}
for (i = 0; i < ind; i++)
(*str)[i] = '\t';
(*str)[ind] = '\0';
}
void
array_init(array *a, const size_t size, size_t num)
{
num = num == 0 ? 1 : num;
a->data = safe_malloc(size * num);
a->length = 0;
a->size = num;
a->unit_size = size;
}
int
main (int argc, char *argv[])
{
FILE *in, *out;
size_t len;
char *line;
if (argc == 2) {
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
print_help();
if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
print_version();
}
if (argc > 3) {
print_usage();
return 1;
}
setlocale(LC_ALL, "");
if (argc >= 2)
in = fopen(argv[1], "r");
else
in = stdin;
if (in == NULL) {
fprintf(stderr, BIN ": Can't open %s.\n", argv[1]);
return 1;
}
array_init(&head, sizeof(char), BODY_START_SIZE / 4);
array_init(&body, sizeof(char), BODY_START_SIZE);
array_init(&figure_sizes, sizeof(img), FIGURE_SIZES_START);
array_init(&index, sizeof(index_title), INDEX_START);
array_init(&sitography, sizeof(note), NOTES_START);
array_strcat(&body, "\t\n");
len = 0;
line = NULL;
while (fread_line(in, &line, &len) != EOF) {
if (!len)
cmd_close();
else if (len >= 2 && line[0] == '.')
cmd(line);
else if (len >= 2 && line[0] == '\\' && line[1] == '"')
continue;
else {
if (space &&
line[0] != '!' &&
line[0] != '\'' &&
line[0] != ',' &&
line[0] != '.' &&
line[0] != '.' &&
line[0] != ';' &&
line[0] != '?')
array_strcat(&body, " ");
array_strcat_html(&body, line, tag_content);
space = 1;
}
free(line);
len = 0;
line = NULL;
}
free(line);
if (in != stdin)
fclose(in);
if (strcmp(tag_closure, ""))
cmd_close();
page_head();
footnotes();
footer();
array_strcat(&body, "\t\n