diff --git a/srohtml.c b/srohtml.c index b68839a..173a780 100644 --- a/srohtml.c +++ b/srohtml.c @@ -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, ""); 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, "") || + !strcmp(tag_closure, "") || + !strcmp(tag_closure, "") || + !strcmp(tag_closure, "")) && + 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, ""); 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, "
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, ""); string_cat(&body, line); string_cat(&body, ""); + + 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, "\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, "
\n"); indentation++; free(ind); ind = NULL; - indent_str(&ind); + indent_str(&ind, indentation); string_cat(&body, ind); string_cat(&body, "
\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, "

"); - strcpy(closure, "

"); + strcpy(tag_closure, "

"); free(ind); } @@ -500,12 +616,12 @@ cmd_q(const char *line) string_cat(&body, ""); space = 0; - strcpy(closure, "

"); + strcpy(tag_closure, "

"); 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, ""); 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, ""); free(date); @@ -568,12 +688,24 @@ cmd_ur(const char *line) if (space) string_cat(&body, " "); string_cat(&body, "<"); - string_cat_html(&body, line, 0); + string_cat_html(&body, line, tag_content); string_cat(&body, ">"); } +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, "

\n"); string_cat(&body, "\t\t\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, " "); 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, "<href); string_cat(&body, "\">"); - string_cat_html(&body, cur->href, 0); + string_cat_html(&body, cur->href, tag_content); string_cat(&body, ">

\n"); free(cur->desc); free(cur->href); @@ -679,6 +812,33 @@ footnotes(void) string_cat(&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) { @@ -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\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\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("\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, "\n"); free(author); @@ -849,7 +1112,7 @@ page_head(void) if (description != NULL) { string_cat(&head, "\t\t\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"); - string_cat_html(&head, title, 0); + string_cat_html(&head, title, tag_content); string_cat(&head, "\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, """); else if (src[i] == '&') string_cat(dst, "&"); @@ -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; }