#include #include #include #include #include /* macros */ #define BODY_START_SIZE 26624 /* 26 x 1024 byte = 26 KiB */ #define CLS_MAX 8 #define DATE_LEN 10 #define FAVICON "data:image/gif;base64,R0lGODlhEAAQAKEAAAAAcP///wAAcAAAcCH5BAEKAAIALAAAAAAQABAAQAIwlBWZxxwAQWjtTQRvlZhTnGSfYT3eZ3WaE4mjGa1UasoH7c6tzYanfqmhJMKXglcAADs=" #define LANG_LEN 2 #define LINE_MAX 1000 #define NOTES_START 8 #define NOTES_MAX_DIGITS 3 typedef struct { char *desc; char *href; } note; typedef struct { size_t index; size_t size; note *notes; } 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 cmd(char *line); static void cmd_close(void); static void cmd_a(const char *line); static void cmd_au_de_ti(char **str, const char *line); static void cmd_dt(const char *line); static void cmd_h(const char *line); static void cmd_hr(void); static void cmd_la(const char *line); static void cmd_le(void); static void cmd_ls(void); static void cmd_no(const char *line); static void cmd_p(void); static void cmd_pd(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 footer(void); static void footnotes(void); static int fread_line(FILE *file, char **str, size_t *len); static void indent_str(char **str); static void page_head(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); 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 void string_enlarge(string *old, const size_t size); static int string_putc(string *dst, const char c); /* variables */ char *author = NULL; char closure[CLS_MAX]; char *description = NULL; int indentation = 2; char language[LANG_LEN + 1] = ""; int licence_container = 0; int space = 0; string head; string body; char pub_date[DATE_LEN + 1] = ""; references sitography; char *title = NULL; /* function implementations */ size_t add_note(const char *href, const char *desc) { note *new; if (sitography.index == sitography.size) { sitography.size *= 2; sitography.notes = safe_realloc(sitography.notes, sizeof(note) * sitography.size); } new = sitography.notes + sitography.index; 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); sitography.index++; return sitography.index; } 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, "AU", cmdlen)) cmd_au_de_ti(&author, line); else if (!strncmp(line, "DE", cmdlen)) cmd_au_de_ti(&description, line); else if (!strncmp(line, "DT", cmdlen)) cmd_dt(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, "LA", cmdlen)) cmd_la(line); else if (!strncmp(line, "LE", cmdlen)) cmd_le(); else if (!strncmp(line, "LS", cmdlen)) cmd_ls(); else if (!strncmp(line, "NO", cmdlen)) cmd_no(line); else if (!strncmp(line, "P", cmdlen)) cmd_p(); else if (!strncmp(line, "PD", cmdlen)) cmd_pd(line); else if (!strncmp(line, "ST", cmdlen)) cmd_st(line); else if (!strncmp(line, "TI", cmdlen)) cmd_au_de_ti(&title, line); else if (!strncmp(line, "TM", cmdlen)) cmd_tm(line); else if (!strncmp(line, "UR", cmdlen)) cmd_ur(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) string_cat(&body, " "); string_cat(&body, ""); string_cat_html(&body, in, 1); string_cat(&body, ""); free(href); free(in); free(title); } void cmd_au_de_ti(char **str, const char *line) { /* move past command */ line += 2; /* move past ' ', if present */ if (line[0] == ' ') line++; if (*str != NULL) free(*str); *str = safe_malloc(sizeof(char) * (strlen(line) + 1)); strcpy(*str, line); } void cmd_close(void) { string_cat(&body, closure); string_cat(&body, "\n"); strcpy(closure, ""); space = 0; } void cmd_dt(const char *line) { char *datetime, *in; datetime = NULL; in = NULL; /* move past "DT" */ line += 2; /* move past arguments, once found them */ line += stread_param(line, &datetime); line += stread_param(line, &in); if (space) string_cat(&body, " "); string_cat(&body, ""); free(datetime); free(in); } void cmd_h(const char *line) { string_cat(&body, "\t\t"); strcpy(closure, ""); } void cmd_la(const char *line) { /* move past "LA" */ line += 2; /* move past ' ', if present */ if (line[0] == ' ') line++; if (strlen(line) != LANG_LEN) return; strncpy(language, line, LANG_LEN); } void cmd_le(void) { char *ind; ind = NULL; indentation--; indent_str(&ind); string_cat(&body, ind); string_cat(&body, "\n"); free(ind); } void cmd_ls(void) { char *ind; ind = NULL; licence_container = 1; indent_str(&ind); string_cat(&body, ind); string_cat(&body, "
\n"); indentation++; free(ind); ind = NULL; indent_str(&ind); string_cat(&body, ind); string_cat(&body, "
\n"); free(ind); } void cmd_no(const char *line) { char *desc, *href, *title; char index[NOTES_MAX_DIGITS + 1]; desc = NULL; href = NULL; title = NULL; /* move past "NO" */ line += 2; /* move past arguments, once found them */ line += stread_param(line, &href); line += stread_param(line, &desc); line += stread_param(line, &title); if (space) string_cat(&body, " "); sprintf(index, "%u", add_note(href, desc)); string_cat(&body, "["); string_cat(&body, index); string_cat(&body, "]"); free(desc); free(href); free(title); } void cmd_p(void) { char *ind; ind = NULL; indent_str(&ind); string_cat(&body, ind); string_cat(&body, "

"); strcpy(closure, "

"); free(ind); } void cmd_pd(const char *line) { size_t len; /* move past "PD" */ line += 2; len = strlen(line); /* move past ' ' after PD */ if (len && line[0] == ' ') { line++; len--; if (len == DATE_LEN) strncpy(pub_date, line, DATE_LEN); } } void cmd_st(const char *line) { /* move past "ST" */ line += 2; /* move past space, if present */ if (line[0] == ' ') line++; if (space) string_cat(&body, " "); string_cat(&body, ""); string_cat(&body, line); string_cat(&body, ""); } void cmd_tm(const char *line) { char *date, *hours, *in; /* move past "TM" */ line += 2; /* move past arguments, once found them */ line += stread_param(line, &date); line += stread_param(line, &hours); line += stread_param(line, &in); if (space) string_cat(&body, " "); string_cat(&body, ""); free(date); free(hours); free(in); } void cmd_ur(const char *line) { /* move past "UR" */ line += 2; /* move past ' ', if present */ if (line[0] == ' ') line++; if (space) string_cat(&body, " "); string_cat(&body, "<"); string_cat_html(&body, line, 0); string_cat(&body, ">"); } 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; string_cat(&body, "\t\t
\n"); if (strcmp(pub_date, "")) { string_cat(&body, "\t\t\t

Pubblicazione:

\n"); } s = time(NULL); now = localtime(&s); string_cat(&body, "\t\t\t

Revisione:

\n"); string_cat(&body, "\t\t
\n"); } void footnotes(void) { note *cur; size_t i, dig_num, x; char id[NOTES_MAX_DIGITS + 1]; char pad[6 * (NOTES_MAX_DIGITS - 1) + 1]; if (sitography.index == 0) return; string_cat(&body, "\t\t
\n"); string_cat(&body, "\t\t
\n"); string_cat(&body, "\t\t\t

Sitografia

\n"); sprintf(id, "%u", sitography.index); dig_num = strlen(id); for (i = 0; i < sitography.index; i++) { cur = sitography.notes + i; sprintf(id, "%u", i + 1); string_cat(&body, "\t\t\t

"); strcpy(pad, ""); for (x = strlen(id); x < dig_num; x++) strcat(pad, " "); string_cat(&body, pad); string_cat(&body, ""); string_cat(&body, id); string_cat(&body, " "); if (strcmp(cur->desc, "")) { string_cat_html(&body, cur->desc, 0); string_cat(&body, " "); } string_cat(&body, "<href); string_cat(&body, "\">"); string_cat_html(&body, cur->href, 0); string_cat(&body, ">

\n"); free(cur->desc); free(cur->href); } free(sitography.notes); string_cat(&body, "\t\t
\n"); } int fread_line(FILE *file, char **str, size_t *len) { int c; char *end; size_t i; i = 0; while ((c = fgetc(file)) && c != '\n' && c != EOF && i < LINE_MAX) i++; *str = safe_malloc(i + 1); fseek(file, -i - 1, SEEK_CUR); fread(*str, 1, i, file); (*str)[i] = '\0'; *len = i; fseek(file, 1, SEEK_CUR); return c == EOF ? EOF : c; } void indent_str(char **str) { int i; *str = safe_malloc(sizeof(char) * (indentation + 1)); for (i = 0; i < indentation; i++) (*str)[i] = '\t'; (*str)[indentation] = '\0'; } int main (int argc, char *argv[]) { FILE *in, *out; size_t len; char *line; setlocale(LC_ALL, ""); in = fopen(argv[1], "r"); if (in == NULL) { fprintf(stderr, BIN ": Can't open %s.\n", argv[1]); return 1; } head.size = BODY_START_SIZE / 4; head.str = safe_malloc(head.size); strcpy(head.str, ""); head.len = 0; body.size = BODY_START_SIZE; body.str = safe_malloc(body.size); strcpy(body.str, ""); body.len = 0; string_cat(&body, "\t\n"); sitography.index = 0; sitography.size = NOTES_START; sitography.notes = malloc(sizeof(note) * sitography.size); 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] != '?') string_cat(&body, " "); string_cat_html(&body, line, 0); space = 1; } free(line); } free(line); fclose(in); if (strcmp(closure, "")) cmd_close(); page_head(); footnotes(); footer(); string_cat(&body, "\t\n\n"); if (argc < 3) out = stdout; else out = fopen(argv[2], "w"); if (out == NULL) { fprintf(stderr, BIN ": Can't open %s.\n", argv[2]); return 1; } fputs(head.str, out); fputs(body.str, out); fclose(out); return 0; } void page_head(void) { string_cat(&head, "\n"); string_cat(&head, "\n"); string_cat(&head, "\t\n"); string_cat(&head, "\t\t\n"); string_cat(&head, "\t\t\n"); string_cat(&head, "\t\t\n"); string_cat(&head, "\t\t\n"); string_cat(&head, "\t\t\n"); string_cat(&head, "\t\t\n"); string_cat(&head, "\t\t"); string_cat_html(&head, title, 0); string_cat(&head, "\n"); string_cat(&head, "\t\n"); free(author); free(description); free(title); } void * safe_malloc(const size_t size) { void *ptr; ptr = malloc(size); if (ptr == NULL) { fprintf(stderr, BIN ": Can't allocate %lu bytes.\n", size); exit(1); } return ptr; } void * safe_realloc(void *ptr, const size_t size) { void *new; new = realloc(ptr, size); if (new == NULL) { fprintf(stderr, BIN ": Can't allocate %lu bytes.\n", size); exit(1); } return new; } size_t stread_param(const char *src, char **str) { char c; char *end; size_t i, len; int p; c = ' '; p = 0; if (src[0] == ' ') { src++; p++; } if (src[0] == '"' || src[0] == '\'') { c = src[0]; src++; p += 2; } end = strchr(src, c); if (end) len = end - src; else len = strlen(src); *str = safe_malloc(len + 1); for (i = 0; i <= len; i++) (*str)[i] = '\0'; strncpy(*str, src, len); return len + p; } char * string_cat(string *dst, const char *src) { size_t len; len = strlen(src); if (len >= (dst->size - dst->len)) 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) { size_t i, len; len = strlen(src); for (i = 0; i < len; i++) { if (is_attr_val && src[i] == '"') string_cat(dst, """); else if (src[i] == '&') string_cat(dst, "&"); else if (src[i] == '<') string_cat(dst, "<"); else if (src[i] == '>') string_cat(dst, ">"); else string_putc(dst, src[i]); } return dst->str; } void string_enlarge(string *old, const size_t size) { old->str = safe_realloc(old->str, sizeof(char) * size); old->size = size; } int string_putc(string *dst, const char c) { if ((dst->size - dst->len) <= 1) string_enlarge(dst, (dst->size + 1) * 2 + 1); dst->str[dst->len] = c; dst->str[dst->len + 1] = '\0'; dst->len++; return (int) c; }