Tue, 23 Aug 2016 15:28:56 +0200
changes signature of parser functions to use a UcxBuffer - the functions itself don't use the API yet
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2016 Mike Becker. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29 #include "c2html.h"
31 #include "ucx/buffer.h"
32 #include "ucx/list.h"
33 #include "ucx/utils.h"
35 void printhelp() {
36 printf("Formats source code using HTML.\n\nUsage:\n"
37 " c2html [Options] FILE\n\n"
38 " Options:\n"
39 " -h Prints this help message\n"
40 " -j Highlight Java instead of C source code\n"
41 " -o <output> Output file (stdout, if not specified)\n"
42 " -H <header> Prepend header file\n"
43 " -F <footer> Append footer file\n"
44 " -p Disable highlighting (plain text)\n"
45 " -l Disable line numbers\n"
46 " -V, -v Prints version and exits\n"
47 "\n");
48 }
50 /* TODO: remove this workaround after refactoring highlighter structure */
51 static void plainparseline(char *src, UcxBuffer *dest, highlighter_t* hltr) {
52 size_t dp = 0;
53 char *buf = dest->space + dest->pos;
54 while (*src && *src != '\n') {
55 dp = writeescapedchar(buf, dp, *src);
56 src++;
57 }
58 buf[dp++] = '\n';
59 buf[dp] = '\0';
60 dest->pos += dp;
61 dest->size += dp;
62 }
64 int formatfile(
65 highlighter_t *highlighter,
66 UcxList *in, write_func out, void *stream,
67 int showlineno) {
69 /* compute width of line numbering */
70 int lnw;
71 if (showlineno) {
72 size_t lines = ucx_list_size(in);
73 lnw = 1;
74 int p = 1;
75 while ((p*=10) < lines) lnw++;
76 }
78 /* allocate line buffer */
79 UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
80 if(!line) {
81 return 1;
82 }
84 /* start monospace formatting */
85 out("<pre>\n", 1, 6, stream);
87 /* process lines */
88 size_t lineno = 0;
89 UCX_FOREACH(sourceline, in) {
90 /* increase line number and clean line buffer */
91 lineno++;
92 ucx_buffer_clear(line);
94 /* write line number */
95 if (showlineno) {
96 ucx_bprintf(line, "<span class=\"c2html-lineno\">"
97 "<a name=\"l%d\" href=\"#l%d\">%*d </a></span> ",
98 lineno, lineno, lnw, lineno);
99 }
101 /* process code line */
102 highlighter->parser(sourceline->data, line, highlighter);
104 /* write code line */
105 out(line->space, 1, line->size, stream);
106 }
108 /* end monospace formatting */
109 out("</pre>\n", 1, 7, stream);
111 /* cleanup and return */
112 ucx_buffer_free(line);
113 return 0;
114 }
116 #define FILEBUF_SIZE 4096
118 enum source_type {
119 SOURCE_C,
120 SOURCE_JAVA,
121 SOURCE_PLAIN
122 };
124 int main(int argc, char** argv) {
126 /* Default settings */
127 Settings settings;
128 memset(&settings, 0, sizeof(settings));
129 settings.showlinenumbers = 1;
130 enum source_type sourcetype = SOURCE_C;
132 /* Parse command line */
133 char optc;
134 while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
135 switch (optc) {
136 case 'o':
137 if (!(optarg[0] == '-' && optarg[1] == 0)) {
138 settings.outfilename = optarg;
139 }
140 break;
141 case 'F':
142 settings.footerfile = optarg;
143 break;
144 case 'H':
145 settings.headerfile = optarg;
146 break;
147 case 'j':
148 sourcetype = SOURCE_JAVA;
149 break;
150 case 'p':
151 sourcetype = SOURCE_PLAIN;
152 break;
153 case 'l':
154 settings.showlinenumbers = 0;
155 break;
156 case 'h':
157 printhelp();
158 return EXIT_SUCCESS;
159 case 'v':
160 case 'V':
161 #ifdef VERSION_DEVELOP
162 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR);
163 #else
164 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
165 #endif
166 return EXIT_SUCCESS;
167 default:
168 return EXIT_FAILURE;
169 }
170 }
172 if (optind != argc-1) {
173 printhelp();
174 return EXIT_FAILURE;
175 } else {
176 /* Configure highlighter */
177 highlighter_t *highlighter = calloc(1, sizeof(highlighter_t));
178 switch (sourcetype) {
179 case SOURCE_C:
180 highlighter->isdirective = check_cdirective;
181 highlighter->istype = check_ctype;
182 highlighter->keywords = ckeywords;
183 highlighter->parser = cparseline;
184 break;
185 case SOURCE_JAVA:
186 highlighter->isdirective = check_jdirective;
187 highlighter->istype = check_jtype;
188 highlighter->keywords = jkeywords;
189 highlighter->parser = jparseline;
190 break;
191 case SOURCE_PLAIN:
192 highlighter->parser = plainparseline;
193 break;
194 default: /* should be unreachable */
195 fprintf(stderr, "error in enum source_type\n");
196 return EXIT_FAILURE;
197 }
199 /* Open output file */
200 settings.infilename = argv[optind];
201 FILE *fout;
202 if (settings.outfilename) {
203 fout = fopen(settings.outfilename, "w");
204 if (!fout) {
205 perror("Error opening output file");
206 return EXIT_FAILURE;
207 }
208 } else {
209 fout = stdout;
210 }
212 /* Allocate file buffer */
213 char *filebuf = malloc(FILEBUF_SIZE);
214 if (!filebuf) {
215 perror("Error allocating file buffer");
216 return EXIT_FAILURE;
217 }
219 /* Prepend header file */
220 {
221 FILE *headerfile = fopen(settings.headerfile, "r");
222 if (!headerfile) {
223 perror("Error opening header file");
224 if (fout != stdout) {
225 fclose(fout);
226 }
227 return EXIT_FAILURE;
228 }
229 ucx_stream_copy(headerfile, fout,
230 (read_func) fread, (write_func) fwrite,
231 filebuf, FILEBUF_SIZE, (size_t)-1);
232 fclose(headerfile);
233 }
235 /* Process input file */
236 FILE *inputfile = fopen(settings.infilename, "r");
237 if (inputfile) {
238 UcxBuffer *content = ucx_buffer_new(NULL,
239 FILEBUF_SIZE*2, UCX_BUFFER_AUTOEXTEND);
240 {
241 ucx_stream_copy(inputfile, content, (read_func) fread,
242 (write_func) ucx_buffer_write,
243 filebuf, FILEBUF_SIZE, (size_t)-1);
244 }
245 fclose(inputfile);
247 UcxList *inputlines = ucx_list_append(NULL, content->space);
248 for (size_t i = 1 ; i < content->size ; i++) {
249 if (content->space[i] == '\r') {
250 content->space[i] = '\n'; i++;
251 }
252 if (content->space[i] == '\n' && i+1 < content->size) {
253 ucx_list_append(inputlines, content->space+i+1);
254 }
255 }
257 formatfile(
258 highlighter,
259 inputlines,
260 (write_func) fwrite,
261 fout,
262 settings.showlinenumbers);
264 free(highlighter);
265 ucx_buffer_free(content);
266 } else {
267 perror("Error opening input file");
268 if (fout != stdout) {
269 fclose(fout);
270 }
271 return EXIT_FAILURE;
272 }
274 /* Append footer file */
275 {
276 FILE *footerfile = fopen(settings.footerfile, "r");
277 if (!footerfile) {
278 perror("Error opening footer file");
279 if (fout != stdout) {
280 fclose(fout);
281 }
282 return EXIT_FAILURE;
283 }
284 ucx_stream_copy(footerfile, fout,
285 (read_func) fread, (write_func) fwrite,
286 filebuf, FILEBUF_SIZE, (size_t)-1);
287 fclose(footerfile);
288 }
291 free(filebuf);
293 return EXIT_SUCCESS;
294 }
295 }