#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 free_arrays(void); static void indent_str(char **str, const int ind); static void init_arrays(void); static void nav_index(FILE *f); static void outputs(FILE *out); 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 read_and_process(FILE *in); static void *safe_malloc(const size_t size); static void *safe_realloc(void *ptr, const size_t size); static void srohtml(FILE *in, FILE *out); 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, "
\n"); indent_str(&ind, ++indentation); array_strcat(&body, ind); array_strcat(&body, "\n"); img_presence = 1; array_strcat(&body, ind); array_strcat(&body, "
"); strcpy(tag_closure, "
"); 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, "\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, ""); 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, "\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"); setlocale(LC_ALL, ""); if (publication_date != NULL) { array_strcat(&body, "\t\t\t

Pubblicazione:

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

Revisione:

\n"); 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 free_arrays(void) { free(head.data); free(body.data); free(figure_sizes.data); free(index.data); free(sitography.data); } 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 init_arrays(void) { 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); } 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; in = NULL; out = NULL; 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; } 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; } if (argc == 3) out = fopen(argv[2], "w"); else out = stdout; if (out == NULL) { fprintf(stderr, BIN ": Can't open %s.\n", argv[2]); return 1; } srohtml(in, out); return 0; } void nav_index(FILE *f) { int i, n; int ind; closure *tag; array nav_cls; index_title *next_title, *title; ind = 2; array_init(&nav_cls, sizeof(closure), 4); tag = NULL; findent(ind++, f); fputs("\n", f); free(nav_cls.data); } void outputs(FILE *out) { char *bodystr; char c; bodystr = body.data; c = bodystr[index_position]; fputs(head.data, out); bodystr[index_position] = '\0'; fputs(bodystr, out); if (index_position) nav_index(out); bodystr[index_position] = c; fputs(bodystr + index_position, out); } void page_head(void) { size_t i; img *sizes; array_strcat(&head, "\n"); array_strcat(&head, "\n"); array_strcat(&head, "\t\n"); array_strcat(&head, "\t\t\n"); array_strcat(&head, "\t\t\n"); if (author != NULL) { array_strcat(&head, "\t\t\n"); free(author); } if (description != NULL) { array_strcat(&head, "\t\t\n"); free(description); } array_strcat(&head, "\t\t\n"); array_strcat(&head, "\t\t\n"); if (title != NULL) { array_strcat(&head, "\t\t"); array_strcat_html(&head, title, tag_content); array_strcat(&head, "\n"); free(title); } array_strcat(&head, "\t\n"); } void print_help(void) { print_usage(); fputs("\n", stdout); fputs("Without INPUT, the roff source code will be read from standard input.\n", stdout); fputs("Without OUTPUT, the resulting HTML will be sent to standard output.\n", stdout); fputs("To use a different output from stdout, you must specify the input first,\n", stdout); fputs("or use shell redirection.\n", stdout); fputs("\n", stdout); fputs("\"" BIN " -h\" or \"--help\" prints this help text.\n", stdout); fputs("\"" BIN " -v\" or \"--version\" prints version and license information.\n", stdout); fputs("\n", stdout); fputs(BIN " exits with 0 only when it converts the input into HTML,\n", stdout); fputs("otherwise it exits with 1.\n", stdout); exit(1); } void print_usage(void) { fputs("Usage: " BIN " [INPUT [OUTPUT]]\n", stdout); } void print_version(void) { fputs(BIN " " VERSION "\n", stdout); fputs("Copyright (C) 2024 Matteo Bini\n", stdout); fputs("License: GPLv3+ .\n", stdout); fputs("This is free software: you are free to change and redistribute it.\n", stdout); fputs("There is NO WARRANTY, to the extent permitted by law.\n", stdout); fputs("\n", stdout); fputs("Written by Matteo Bini.\n", stdout); exit(1); } void read_and_process(FILE *in) { size_t len; char *line; 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); } void pop_closure(array *a) { closure *tag; if (a->length <= 0) return; tag = array_at(a, a->length - 1); if (tag == NULL) { fprintf(stderr, BIN ": Can't find tag closure at position %i, in array type.\n", a->length - 1); exit(1); } free(tag->name); array_pop(a); } 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; } void srohtml(FILE *in, FILE *out) { init_arrays(); array_strcat(&body, "\t\n"); read_and_process(in); fclose(in); if (strcmp(tag_closure, "")) cmd_close(); page_head(); footnotes(); footer(); array_strcat(&body, "\t\n\n"); outputs(out); fclose(out); free_arrays(); } 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 * array_strcat(array *dst, const char *src) { char *c; size_t i, len; len = strlen(src); for (i = 0; i < len; i++) { c = array_push(dst); *c = src[i]; } c = array_push(dst); *c = '\0'; dst->length--; return dst->data; } char * array_strcat_html(array *dst, const char *src, const html_val_type t) { char *c; size_t i, len; len = strlen(src); for (i = 0; i < len; i++) { if (t == tag_attribute && src[i] == '"') array_strcat(dst, """); else if (src[i] == '&') array_strcat(dst, "&"); else if (src[i] == '<') array_strcat(dst, "<"); else if (src[i] == '>') array_strcat(dst, ">"); else { c = array_push(dst); *c = src[i]; } } c = array_push(dst); *c = '\0'; dst->length--; return dst->data; }