src/highlighter.c

changeset 66
1b12cf799fee
parent 57
eba880c1705c
child 67
5da2cb5aea6b
equal deleted inserted replaced
60:9f25df78925e 66:1b12cf799fee
31 31
32 #include <stdlib.h> 32 #include <stdlib.h>
33 #include <stdio.h> 33 #include <stdio.h>
34 #include <string.h> 34 #include <string.h>
35 #include <ctype.h> 35 #include <ctype.h>
36 #include "ucx/string.h" 36
37 #include "ucx/utils.h" 37 #include <cx/string.h>
38 38
39 static void put_htmlescaped(UcxBuffer *dest, char c) { 39 static void put_htmlescaped(CxBuffer *dest, char c) {
40 if (c == '>') { 40 if (c == '>') {
41 ucx_buffer_puts(dest, "&gt;"); 41 cxBufferPutString(dest, "&gt;");
42 } else if (c == '<') { 42 } else if (c == '<') {
43 ucx_buffer_puts(dest, "&lt;"); 43 cxBufferPutString(dest, "&lt;");
44 } else if (c) { 44 } else if (c) {
45 ucx_buffer_putc(dest, c); 45 cxBufferPut(dest, c);
46 } 46 }
47 } 47 }
48 48
49 static void put_htmlescapedstr(UcxBuffer *dest, sstr_t s) { 49 static void put_htmlescapedstr(CxBuffer *dest, cxstring s) {
50 for (int i = 0 ; i < s.length ; i++) { 50 for (int i = 0 ; i < s.length ; i++) {
51 put_htmlescaped(dest, s.ptr[i]); 51 put_htmlescaped(dest, s.ptr[i]);
52 } 52 }
53 } 53 }
54 54
55 static int check_keyword(sstr_t word, const char** keywords) { 55 static int check_keyword(cxstring word, const char** keywords) {
56 for (int i = 0 ; keywords[i] ; i++) { 56 for (int i = 0 ; keywords[i] ; i++) {
57 if (sstrcmp(word, sstr((char*)keywords[i])) == 0) { 57 if (cx_strcmp(word, cx_str(keywords[i])) == 0) {
58 return 1; 58 return 1;
59 } 59 }
60 } 60 }
61 return 0; 61 return 0;
62 } 62 }
63 63
64 static int check_capsonly(sstr_t word) { 64 static int check_capsonly(cxstring word) {
65 for (size_t i = 0 ; i < word.length ; i++) { 65 for (size_t i = 0 ; i < word.length ; i++) {
66 if (!isupper(word.ptr[i]) && !isdigit(word.ptr[i]) 66 if (!isupper(word.ptr[i]) && !isdigit(word.ptr[i])
67 && word.ptr[i] != '_') { 67 && word.ptr[i] != '_') {
68 return 0; 68 return 0;
69 } 69 }
71 return 1; 71 return 1;
72 } 72 }
73 73
74 /* Plaintext Highlighter */ 74 /* Plaintext Highlighter */
75 75
76 void c2html_plain_highlighter(char *src, UcxBuffer *dest, 76 void c2html_plain_highlighter(char const *src, CxBuffer *dest,
77 c2html_highlighter_data *hd) { 77 c2html_highlighter_data *hd) {
78 while (*src && *src != '\n') { 78 while (*src && *src != '\n') {
79 if (*src != '\r') { 79 if (*src != '\r') {
80 put_htmlescaped(dest, *src); 80 put_htmlescaped(dest, *src);
81 } 81 }
82 src++; 82 src++;
83 } 83 }
84 ucx_buffer_putc(dest, '\n'); 84 cxBufferPut(dest, '\n');
85 } 85 }
86 86
87 /* C Highlighter */ 87 /* C Highlighter */
88 88
89 static const char* ckeywords[] = { 89 static const char* ckeywords[] = {
92 "long", "register", "return", "short", "signed", "sizeof", "static", 92 "long", "register", "return", "short", "signed", "sizeof", "static",
93 "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", 93 "struct", "switch", "typedef", "union", "unsigned", "void", "volatile",
94 "while", NULL 94 "while", NULL
95 }; 95 };
96 96
97 void c2html_c_highlighter(char *src, UcxBuffer *dest, 97 void c2html_c_highlighter(char const *src, CxBuffer *dest,
98 c2html_highlighter_data *hd) { 98 c2html_highlighter_data *hd) {
99 /* reset buffers without clearing them */ 99 /* reset buffers without clearing them */
100 hd->primary_buffer->size = hd->primary_buffer->pos = 0; 100 hd->primary_buffer.size = hd->primary_buffer.pos = 0;
101 hd->secondary_buffer->size = hd->secondary_buffer->pos = 0; 101 hd->secondary_buffer.size = hd->secondary_buffer.pos = 0;
102 102
103 /* alias the buffers for better handling */ 103 /* alias the buffers for better handling */
104 UcxBuffer *wbuf = hd->primary_buffer; 104 CxBuffer *wbuf = &hd->primary_buffer;
105 UcxBuffer *ifilebuf = hd->secondary_buffer; 105 CxBuffer *ifilebuf = &hd->secondary_buffer;
106 106
107 /* local information */ 107 /* local information */
108 size_t sp = (size_t)-1; 108 size_t sp = (size_t)-1;
109 int isstring = 0, iscomment = 0, isinclude = 0, parseinclude = 0; 109 int isstring = 0, iscomment = 0, isinclude = 0, parseinclude = 0;
110 char quote = '\0'; 110 char quote = '\0';
111 int isescaping = 0; 111 int isescaping = 0;
112 112
113 /* continue a multi line comment highlighting */ 113 /* continue a multi line comment highlighting */
114 if (hd->multiline_comment) { 114 if (hd->multiline_comment) {
115 iscomment = 1; 115 iscomment = 1;
116 ucx_buffer_puts(dest, "<span class=\"c2html-comment\">"); 116 cxBufferPutString(dest, "<span class=\"c2html-comment\">");
117 } 117 }
118 118
119 char c; 119 char c;
120 do { 120 do {
121 c = src[++sp]; 121 c = src[++sp];
124 /* comments */ 124 /* comments */
125 if (!isstring && c == '/') { 125 if (!isstring && c == '/') {
126 if (hd->multiline_comment && sp > 0 && src[sp-1] == '*') { 126 if (hd->multiline_comment && sp > 0 && src[sp-1] == '*') {
127 iscomment = 0; 127 iscomment = 0;
128 hd->multiline_comment = 0; 128 hd->multiline_comment = 0;
129 ucx_buffer_puts(dest, "/</span>"); 129 cxBufferPutString(dest, "/</span>");
130 continue; 130 continue;
131 } else if (!iscomment && (src[sp+1] == '/' || src[sp+1] == '*')) { 131 } else if (!iscomment && (src[sp+1] == '/' || src[sp+1] == '*')) {
132 iscomment = 1; 132 iscomment = 1;
133 hd->multiline_comment = (src[sp+1] == '*'); 133 hd->multiline_comment = (src[sp+1] == '*');
134 ucx_buffer_puts(dest, "<span class=\"c2html-comment\">"); 134 cxBufferPutString(dest, "<span class=\"c2html-comment\">");
135 } 135 }
136 } 136 }
137 137
138 if (iscomment) { 138 if (iscomment) {
139 if (c == '\n') { 139 if (c == '\n') {
140 ucx_buffer_puts(dest, "</span>\n"); 140 cxBufferPutString(dest, "</span>\n");
141 } else { 141 } else {
142 put_htmlescaped(dest, c); 142 put_htmlescaped(dest, c);
143 } 143 }
144 } else if (isinclude) { 144 } else if (isinclude) {
145 if (c == '<') { 145 if (c == '<') {
146 ucx_buffer_puts(dest, 146 cxBufferPutString(dest,
147 "<span class=\"c2html-stdinclude\">&lt;"); 147 "<span class=\"c2html-stdinclude\">&lt;");
148 } else if (c == '\"') { 148 } else if (c == '\"') {
149 if (parseinclude) { 149 if (parseinclude) {
150 ucx_buffer_puts(dest, "\">"); 150 cxBufferPutString(dest, "\">");
151 ucx_buffer_write(ifilebuf->space, 1, ifilebuf->size, dest); 151 cxBufferWrite(ifilebuf->space, 1, ifilebuf->size, dest);
152 ucx_buffer_puts(dest, "\"</a>"); 152 cxBufferPutString(dest, "\"</a>");
153 parseinclude = 0; 153 parseinclude = 0;
154 } else { 154 } else {
155 ucx_buffer_puts(dest, 155 cxBufferPutString(dest,
156 "<a class=\"c2html-userinclude\" href=\""); 156 "<a class=\"c2html-userinclude\" href=\"");
157 ucx_buffer_putc(ifilebuf, '\"'); 157 cxBufferPut(ifilebuf, '\"');
158 parseinclude = 1; 158 parseinclude = 1;
159 } 159 }
160 } else if (c == '>') { 160 } else if (c == '>') {
161 ucx_buffer_puts(dest, "&gt;</span>"); 161 cxBufferPutString(dest, "&gt;</span>");
162 } else { 162 } else {
163 if (parseinclude) { 163 if (parseinclude) {
164 ucx_buffer_putc(ifilebuf, c); 164 cxBufferPut(ifilebuf, c);
165 } 165 }
166 put_htmlescaped(dest, c); 166 put_htmlescaped(dest, c);
167 } 167 }
168 } else { 168 } else {
169 /* strings */ 169 /* strings */
170 if (!isescaping && (c == '\'' || c == '\"')) { 170 if (!isescaping && (c == '\'' || c == '\"')) {
171 if (isstring) { 171 if (isstring) {
172 put_htmlescaped(dest, c); 172 put_htmlescaped(dest, c);
173 if (c == quote) { 173 if (c == quote) {
174 isstring = 0; 174 isstring = 0;
175 ucx_buffer_puts(dest, "</span>"); 175 cxBufferPutString(dest, "</span>");
176 } else { 176 } else {
177 put_htmlescaped(dest, c); 177 put_htmlescaped(dest, c);
178 } 178 }
179 } else { 179 } else {
180 isstring = 1; 180 isstring = 1;
181 quote = c; 181 quote = c;
182 ucx_buffer_puts(dest, "<span class=\"c2html-string\">"); 182 cxBufferPutString(dest, "<span class=\"c2html-string\">");
183 put_htmlescaped(dest, c); 183 put_htmlescaped(dest, c);
184 } 184 }
185 } else { 185 } else {
186 if (isstring) { 186 if (isstring) {
187 put_htmlescaped(dest, c); 187 put_htmlescaped(dest, c);
188 } else if (isalnum(c) || c == '_' || c == '#') { 188 } else if (isalnum(c) || c == '_' || c == '#') {
189 /* buffer the current word */ 189 /* buffer the current word */
190 ucx_buffer_putc(wbuf, c); 190 cxBufferPut(wbuf, c);
191 } else { 191 } else {
192 /* write buffered word, if any */ 192 /* write buffered word, if any */
193 if (wbuf->size > 0) { 193 if (wbuf->size > 0) {
194 sstr_t word = sstrn(wbuf->space, wbuf->size); 194 cxstring word = cx_strn(wbuf->space, wbuf->size);
195 int closespan = 1; 195 int closespan = 1;
196 sstr_t typesuffix = ST("_t"); 196 cxstring typesuffix = CX_STR("_t");
197 if (check_keyword(word, ckeywords)) { 197 if (check_keyword(word, ckeywords)) {
198 ucx_buffer_puts(dest, 198 cxBufferPutString(dest,
199 "<span class=\"c2html-keyword\">"); 199 "<span class=\"c2html-keyword\">");
200 } else if (sstrsuffix(word, typesuffix)) { 200 } else if (cx_strsuffix(word, typesuffix)) {
201 ucx_buffer_puts(dest, 201 cxBufferPutString(dest,
202 "<span class=\"c2html-type\">"); 202 "<span class=\"c2html-type\">");
203 } else if (word.ptr[0] == '#') { 203 } else if (word.ptr[0] == '#') {
204 isinclude = !sstrcmp(word, S("#include")); 204 isinclude = !cx_strcmp(word, CX_STR("#include"));
205 ucx_buffer_puts(dest, 205 cxBufferPutString(dest,
206 "<span class=\"c2html-directive\">"); 206 "<span class=\"c2html-directive\">");
207 } else if (check_capsonly(word)) { 207 } else if (check_capsonly(word)) {
208 ucx_buffer_puts(dest, 208 cxBufferPutString(dest,
209 "<span class=\"c2html-macroconst\">"); 209 "<span class=\"c2html-macroconst\">");
210 } else { 210 } else {
211 closespan = 0; 211 closespan = 0;
212 } 212 }
213 put_htmlescapedstr(dest, word); 213 put_htmlescapedstr(dest, word);
214 if (closespan) { 214 if (closespan) {
215 ucx_buffer_puts(dest, "</span>"); 215 cxBufferPutString(dest, "</span>");
216 } 216 }
217 } 217 }
218 wbuf->pos = wbuf->size = 0; /* reset word buffer */ 218 wbuf->pos = wbuf->size = 0; /* reset word buffer */
219 219
220 /* write current character */ 220 /* write current character */
237 "transient", "catch", "extends", "int", "short", "try", "char", "final", 237 "transient", "catch", "extends", "int", "short", "try", "char", "final",
238 "interface", "static", "void", "class", "finally", "long", "strictfp", 238 "interface", "static", "void", "class", "finally", "long", "strictfp",
239 "volatile", "const", "float", "native", "super", "while", NULL 239 "volatile", "const", "float", "native", "super", "while", NULL
240 }; 240 };
241 241
242 void c2html_java_highlighter(char *src, UcxBuffer *dest, 242 void c2html_java_highlighter(char const *src, CxBuffer *dest,
243 c2html_highlighter_data *hd) { 243 c2html_highlighter_data *hd) {
244 /* reset buffers without clearing them */ 244 /* reset buffers without clearing them */
245 hd->primary_buffer->size = hd->primary_buffer->pos = 0; 245 hd->primary_buffer.size = hd->primary_buffer.pos = 0;
246 hd->secondary_buffer->size = hd->secondary_buffer->pos = 0; 246 hd->secondary_buffer.size = hd->secondary_buffer.pos = 0;
247 247
248 /* alias the buffers for better handling */ 248 /* alias the buffers for better handling */
249 UcxBuffer *wbuf = hd->primary_buffer; 249 CxBuffer *wbuf = &hd->primary_buffer;
250 250
251 /* local information */ 251 /* local information */
252 size_t sp = (size_t)-1; 252 size_t sp = (size_t)-1;
253 int isstring = 0, iscomment = 0, isimport = 0; 253 int isstring = 0, iscomment = 0, isimport = 0;
254 char quote = '\0'; 254 char quote = '\0';
255 int isescaping = 0; 255 int isescaping = 0;
256 256
257 if (hd->multiline_comment) { 257 if (hd->multiline_comment) {
258 iscomment = 1; 258 iscomment = 1;
259 ucx_buffer_puts(dest, "<span class=\"c2html-comment\">"); 259 cxBufferPutString(dest, "<span class=\"c2html-comment\">");
260 } 260 }
261 261
262 char c; 262 char c;
263 do { 263 do {
264 c = src[++sp]; 264 c = src[++sp];
267 /* comments */ 267 /* comments */
268 if (!isstring && c == '/') { 268 if (!isstring && c == '/') {
269 if (hd->multiline_comment && sp > 0 && src[sp-1] == '*') { 269 if (hd->multiline_comment && sp > 0 && src[sp-1] == '*') {
270 iscomment = 0; 270 iscomment = 0;
271 hd->multiline_comment = 0; 271 hd->multiline_comment = 0;
272 ucx_buffer_puts(dest, "/</span>"); 272 cxBufferPutString(dest, "/</span>");
273 continue; 273 continue;
274 } else if (!iscomment && (src[sp+1] == '/' || src[sp+1] == '*')) { 274 } else if (!iscomment && (src[sp+1] == '/' || src[sp+1] == '*')) {
275 iscomment = 1; 275 iscomment = 1;
276 hd->multiline_comment = (src[sp+1] == '*'); 276 hd->multiline_comment = (src[sp+1] == '*');
277 ucx_buffer_puts(dest, "<span class=\"c2html-comment\">"); 277 cxBufferPutString(dest, "<span class=\"c2html-comment\">");
278 } 278 }
279 } 279 }
280 280
281 if (iscomment) { 281 if (iscomment) {
282 if (c == '\n') { 282 if (c == '\n') {
283 ucx_buffer_puts(dest, "</span>\n"); 283 cxBufferPutString(dest, "</span>\n");
284 } else { 284 } else {
285 put_htmlescaped(dest, c); 285 put_htmlescaped(dest, c);
286 } 286 }
287 } else if (isimport) { 287 } else if (isimport) {
288 /* TODO: local imports */ 288 /* TODO: local imports */
291 if (!isescaping && (c == '\'' || c == '\"')) { 291 if (!isescaping && (c == '\'' || c == '\"')) {
292 if (isstring) { 292 if (isstring) {
293 put_htmlescaped(dest, c); 293 put_htmlescaped(dest, c);
294 if (c == quote) { 294 if (c == quote) {
295 isstring = 0; 295 isstring = 0;
296 ucx_buffer_puts(dest, "</span>"); 296 cxBufferPutString(dest, "</span>");
297 } else { 297 } else {
298 put_htmlescaped(dest, c); 298 put_htmlescaped(dest, c);
299 } 299 }
300 } else { 300 } else {
301 isstring = 1; 301 isstring = 1;
302 quote = c; 302 quote = c;
303 ucx_buffer_puts(dest, 303 cxBufferPutString(dest,
304 "<span class=\"c2html-string\">"); 304 "<span class=\"c2html-string\">");
305 put_htmlescaped(dest, c); 305 put_htmlescaped(dest, c);
306 } 306 }
307 } else { 307 } else {
308 if (isstring) { 308 if (isstring) {
309 put_htmlescaped(dest, c); 309 put_htmlescaped(dest, c);
310 } else if (isalnum(c) || c == '_' || c == '@') { 310 } else if (isalnum(c) || c == '_' || c == '@') {
311 /* buffer the current word */ 311 /* buffer the current word */
312 ucx_buffer_putc(wbuf, c); 312 cxBufferPut(wbuf, c);
313 } else { 313 } else {
314 /* write buffered word, if any */ 314 /* write buffered word, if any */
315 if (wbuf->size > 0) { 315 if (wbuf->size > 0) {
316 sstr_t word = sstrn(wbuf->space, wbuf->size); 316 cxstring word = cx_strn(wbuf->space, wbuf->size);
317 int closespan = 1; 317 int closespan = 1;
318 if (check_keyword(word, jkeywords)) { 318 if (check_keyword(word, jkeywords)) {
319 ucx_buffer_puts(dest, 319 cxBufferPutString(dest,
320 "<span class=\"c2html-keyword\">"); 320 "<span class=\"c2html-keyword\">");
321 } else if (isupper(word.ptr[0])) { 321 } else if (isupper(word.ptr[0])) {
322 ucx_buffer_puts(dest, 322 cxBufferPutString(dest,
323 "<span class=\"c2html-type\">"); 323 "<span class=\"c2html-type\">");
324 } else if (word.ptr[0] == '@') { 324 } else if (word.ptr[0] == '@') {
325 ucx_buffer_puts(dest, 325 cxBufferPutString(dest,
326 "<span class=\"c2html-directive\">"); 326 "<span class=\"c2html-directive\">");
327 } else if (check_capsonly(word)) { 327 } else if (check_capsonly(word)) {
328 ucx_buffer_puts(dest, 328 cxBufferPutString(dest,
329 "<span class=\"c2html-macroconst\">"); 329 "<span class=\"c2html-macroconst\">");
330 } else { 330 } else {
331 closespan = 0; 331 closespan = 0;
332 } 332 }
333 put_htmlescapedstr(dest, word); 333 put_htmlescapedstr(dest, word);
334 334
335 if (closespan) { 335 if (closespan) {
336 ucx_buffer_puts(dest, "</span>"); 336 cxBufferPutString(dest, "</span>");
337 } 337 }
338 } 338 }
339 wbuf->pos = wbuf->size = 0; /* reset buffer */ 339 wbuf->pos = wbuf->size = 0; /* reset buffer */
340 340
341 /* write current character */ 341 /* write current character */

mercurial