git.m455.casa

mth

clone url: git://git.m455.casa/mth


main.c

1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 enum states { RESET, P, PRE, CODE };
7
8 static void print_sanitized_character(char c) {
9 switch(c) {
10 case '&':
11 printf("&amp;");
12 break;
13 case '<':
14 printf("&lt;");
15 break;
16 case '>':
17 printf("&gt;");
18 break;
19 case '"':
20 printf("&quot;");
21 break;
22 case '\'':
23 printf("&#39;");
24 break;
25 default:
26 printf("%c", c);
27 }
28 }
29
30 static void print_converted_characters(char *line, int state) {
31 int i;
32
33 i = 0;
34 while(i < (int)strlen(line)) {
35 switch(state) {
36 case RESET:
37 if (line[i] == '`') {
38 printf("<code>");
39 state = CODE;
40 }
41 else {
42 print_sanitized_character(line[i]);
43 }
44 break;
45 case CODE:
46 if (line[i] == '`') {
47 printf("</code>");
48 state = RESET;
49 }
50 else {
51 print_sanitized_character(line[i]);
52 }
53 break;
54 default:
55 print_sanitized_character(line[i]);
56 }
57 i++;
58 }
59 }
60
61 static void print_converted_lines(FILE *fp) {
62 int state;
63 /* a size big enough for wrapping english or chinese text at 80 characters
64 * wide */
65 char line_buf[128];
66 char *found_str;
67
68 state = RESET;
69 while(fgets(line_buf, (int)sizeof(line_buf), fp) != NULL) {
70 switch(state) {
71 case RESET:
72 if ((found_str = strstr(line_buf, "title: ")) != NULL) {
73 char *h1_text = found_str + (strlen("title: "));
74 h1_text[strlen(h1_text) - 1] = '\0';
75 printf("\n<h1>");
76 print_converted_characters(h1_text, RESET);
77 printf("</h1>");
78 }
79 else if ((found_str = strstr(line_buf, "# ")) != NULL) {
80 char *h2_text = found_str + (strlen("# "));
81 h2_text[strlen(h2_text) - 1] = '\0';
82 printf("\n<h2>");
83 print_converted_characters(h2_text, RESET);
84 printf("</h2>");
85 }
86 else if (strstr(line_buf, "```") != NULL) {
87 (void) puts("\n<pre>");
88 state = PRE;
89 }
90 /* the check for the return value of 0 actually checks if
91 * something is not a space */
92 else if (isspace(line_buf[0]) == 0) {
93 (void) puts("\n<p>");
94 print_converted_characters(line_buf, P);
95 state = P;
96 }
97 break;
98
99 case PRE:
100 if (strstr(line_buf, "```") != NULL) {
101 (void) puts("</pre>");
102 state = RESET;
103 }
104 else {
105 print_converted_characters(line_buf, PRE);
106 }
107 break;
108
109 case P:
110 /* the check for the return value of 0 actually checks if
111 * something is not a space */
112 if (isspace(line_buf[0]) == 0) {
113 print_converted_characters(line_buf, P);
114 }
115 else {
116 (void) puts("</p>");
117 state = RESET;
118 }
119 }
120 }
121 /* handle paragraphs that end on the last line of the file */
122 if (feof(fp) != 0) {
123 if (state == P) {
124 (void) puts("</p>");
125 }
126 }
127 }
128
129 int main(int argc, char *argv[]) {
130 if (argc < 2) {
131 (void) puts("no input file");
132 }
133 else {
134 FILE *fp;
135 int r_fclose;
136
137 fp = fopen(argv[1], "r");
138 if (fp == NULL) {
139 perror("fopen()");
140 return 1;
141 }
142
143 (void) puts(
144 "<!DOCTYPE html>\n"
145 "<html lang=\"en\">\n"
146 "<head>\n"
147 "<meta charset=\"utf-8\">\n"
148 "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">\n"
149 "<link rel=\"icon\" type=\"image/x-icon\" href=\"/assets/favicon.ico\">\n"
150 "<link rel=\"alternate\" type=\"application/rss+xml\" href=\"https://m455.casa/feed.rss\">\n"
151 "<title>m455's interspace on the webternet</title>\n"
152 "<style>body{margin:0 auto;line-height:1.6;max-width:600px;font-family:system-ui,sans-serif;}code,pre{background-color:#eee;}</style>\n"
153 "</head>\n"
154 "<body>\n"
155 "<main>"
156 );
157
158 print_converted_lines(fp);
159
160 (void) puts(
161 "</main>\n"
162 "</body>\n"
163 "</html>"
164 );
165
166 r_fclose = fclose(fp);
167 if (r_fclose == EOF) {
168 perror("fclose()");
169 return 1;
170 }
171 }
172 return 0;
173 }