Tue, 23 Aug 2016 13:49:38 +0200
adds UCX + changes how the input file is read (uses an consecutive memory area now)
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 int copyfile(char *filename, FILE *dest) {
51 if (!filename) {
52 return 0;
53 }
55 FILE *src = fopen(filename, "r");
56 if (src) {
57 char buf[4096];
58 int r;
59 while ((r = fread(buf, 1, 4096, src)) > 0) {
60 fwrite(buf, 1, r, dest);
61 }
62 fclose(src);
63 return 0;
64 } else {
65 return 1;
66 }
67 }
69 #define WRITECONST(stream, out, cstr) out(cstr, 1, sizeof(cstr)-1, stream)
70 int formatfile(
71 highlighter_t *highlighter,
72 UcxList *in,
73 write_func out,
74 void *stream,
75 int showlineno) {
76 size_t lines = ucx_list_size(in);
78 UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
79 if(!line) {
80 return 1;
81 }
82 WRITECONST(stream, out, "<pre>\n");
84 int lnw;
85 {
86 lnw = 1;
87 int p = 1;
88 while ((p*=10) < lines) lnw++;
89 }
91 size_t lineno = 0;
92 UCX_FOREACH(sourceline, in) {
93 lineno++;
94 /* TODO: backwards compatibility: replace line->space in all occasions
95 * and use UcxBuffer functions
96 */
97 if (highlighter) {
98 highlighter->parser(sourceline->data, line->space, highlighter);
99 } else {
100 char *c = sourceline->data;
101 size_t dp = 0;
102 while (*c) {
103 dp = writeescapedchar(line->space, dp, *c);
104 c++;
105 }
106 line->space[dp] = '\0';
107 }
109 // write line number
110 if (showlineno) {
111 WRITECONST(stream, out, "<span class=\"c2html-lineno\">");
112 char lnbuf[128];
113 int len;
114 // line number link
115 len = snprintf(lnbuf, 128, "<a name=\"l%d\" href=\"#l%d\">",
116 lineno, lineno);
117 out(lnbuf, 1, len, stream);
118 // justified line number
119 len = snprintf(lnbuf, 128, "%*d ", lnw, lineno);
120 out(lnbuf, 1, len, stream);
121 WRITECONST(stream, out, "</a></span> ");
122 }
124 // write formated (or plain) code line
125 out(line->space, 1, strlen(line->space), stream);
126 }
128 WRITECONST(stream, out, "</pre>\n");
129 ucx_buffer_free(line);
130 return 0;
131 }
133 void init_c_highlighter(highlighter_t *highlighter) {
134 memset(highlighter, 0, sizeof(highlighter_t));
135 highlighter->isdirective = check_cdirective;
136 highlighter->istype = check_ctype;
137 highlighter->keywords = ckeywords;
138 highlighter->parser = cparseline;
139 }
141 void init_java_highlighter(highlighter_t *highlighter) {
142 memset(highlighter, 0, sizeof(highlighter_t));
143 highlighter->isdirective = check_jdirective;
144 highlighter->istype = check_jtype;
145 highlighter->keywords = jkeywords;
146 highlighter->parser = jparseline;
147 }
149 enum source_type {
150 SOURCE_C,
151 SOURCE_JAVA,
152 SOURCE_PLAIN
153 };
155 int main(int argc, char** argv) {
156 int retcode = EXIT_SUCCESS;
158 Settings settings;
159 memset(&settings, 0, sizeof(settings));
160 settings.showlinenumbers = 1;
162 enum source_type sourcetype = SOURCE_C;
164 char optc;
165 while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
166 switch (optc) {
167 case 'o':
168 if (!(optarg[0] == '-' && optarg[1] == 0)) {
169 settings.outfilename = optarg;
170 }
171 break;
172 case 'F':
173 settings.footerfile = optarg;
174 break;
175 case 'H':
176 settings.headerfile = optarg;
177 break;
178 case 'j':
179 sourcetype = SOURCE_JAVA;
180 break;
181 case 'p':
182 sourcetype = SOURCE_PLAIN;
183 break;
184 case 'l':
185 settings.showlinenumbers = 0;
186 break;
187 case 'h':
188 printhelp();
189 return EXIT_SUCCESS;
190 case 'v':
191 case 'V':
192 #ifdef VERSION_DEVELOP
193 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR);
194 #else
195 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
196 #endif
197 return EXIT_SUCCESS;
198 default:
199 return EXIT_FAILURE;
200 }
201 }
203 if (optind != argc-1) {
204 printhelp();
205 return 1;
206 } else {
207 settings.infilename = argv[optind];
208 FILE *fout;
209 if (settings.outfilename) {
210 fout = fopen(settings.outfilename, "w");
211 if (!fout) {
212 perror("Error opening output file");
213 return EXIT_FAILURE;
214 }
215 } else {
216 fout = stdout;
217 }
219 if (copyfile(settings.headerfile, fout)) {
220 perror("Error opening header file");
221 retcode = EXIT_FAILURE;
222 goto prog_end;
223 }
225 highlighter_t highlighter;
226 highlighter_t *hptr = &highlighter;
227 switch (sourcetype) {
228 case SOURCE_C:
229 init_c_highlighter(&highlighter);
230 break;
231 case SOURCE_JAVA:
232 init_java_highlighter(&highlighter);
233 break;
234 case SOURCE_PLAIN:
235 hptr = NULL;
236 break;
237 default: /* should be unreachable */
238 fprintf(stderr, "error in enum source_type\n");
239 retcode = EXIT_FAILURE;
240 goto prog_end;
241 }
243 FILE *inputfile = fopen(settings.infilename, "r");
244 if (inputfile) {
245 UcxBuffer *filebuf = ucx_buffer_new(NULL,
246 2048, UCX_BUFFER_AUTOEXTEND);
247 {
248 const size_t tmpbufsize = 512;
249 char *tmpbuf = malloc(tmpbufsize);
250 ucx_stream_copy(inputfile, filebuf, (read_func) fread,
251 (write_func) ucx_buffer_write,
252 tmpbuf, tmpbufsize, (size_t)-1);
253 free(tmpbuf);
254 }
255 fclose(inputfile);
257 UcxList *inputlines = ucx_list_append(NULL, filebuf->space);
258 for (size_t i = 1 ; i < filebuf->size ; i++) {
259 if (filebuf->space[i] == '\r') {
260 filebuf->space[i] = '\n'; i++;
261 }
262 if (filebuf->space[i] == '\n' && i+1 < filebuf->size) {
263 ucx_list_append(inputlines, filebuf->space+i+1);
264 }
265 }
267 formatfile(
268 hptr,
269 inputlines,
270 (write_func) fwrite,
271 fout,
272 settings.showlinenumbers);
273 ucx_buffer_free(filebuf);
274 } else {
275 perror("Error opening input file");
276 retcode = EXIT_FAILURE;
277 }
279 if (copyfile(settings.footerfile, fout)) {
280 perror("Error opening footer file");
281 retcode = EXIT_FAILURE;
282 }
284 prog_end:
285 if (fout != stdout) {
286 fclose(fout);
287 }
289 return retcode;
290 }
291 }