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, ">"); |
41 cxBufferPutString(dest, ">"); |
42 } else if (c == '<') { |
42 } else if (c == '<') { |
43 ucx_buffer_puts(dest, "<"); |
43 cxBufferPutString(dest, "<"); |
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 } |
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\"><"); |
147 "<span class=\"c2html-stdinclude\"><"); |
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, "></span>"); |
161 cxBufferPutString(dest, "></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]; |
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 */ |