Tue, 23 Aug 2016 13:59:48 +0200
fixes plaintext output
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 && *c != '\n') {
103 dp = writeescapedchar(line->space, dp, *c);
104 c++;
105 }
106 line->space[dp++] = '\n';
107 line->space[dp] = '\0';
108 }
110 // write line number
111 if (showlineno) {
112 WRITECONST(stream, out, "<span class=\"c2html-lineno\">");
113 char lnbuf[128];
114 int len;
115 // line number link
116 len = snprintf(lnbuf, 128, "<a name=\"l%d\" href=\"#l%d\">",
117 lineno, lineno);
118 out(lnbuf, 1, len, stream);
119 // justified line number
120 len = snprintf(lnbuf, 128, "%*d ", lnw, lineno);
121 out(lnbuf, 1, len, stream);
122 WRITECONST(stream, out, "</a></span> ");
123 }
125 // write formated (or plain) code line
126 out(line->space, 1, strlen(line->space), stream);
127 }
129 WRITECONST(stream, out, "</pre>\n");
130 ucx_buffer_free(line);
131 return 0;
132 }
134 void init_c_highlighter(highlighter_t *highlighter) {
135 memset(highlighter, 0, sizeof(highlighter_t));
136 highlighter->isdirective = check_cdirective;
137 highlighter->istype = check_ctype;
138 highlighter->keywords = ckeywords;
139 highlighter->parser = cparseline;
140 }
142 void init_java_highlighter(highlighter_t *highlighter) {
143 memset(highlighter, 0, sizeof(highlighter_t));
144 highlighter->isdirective = check_jdirective;
145 highlighter->istype = check_jtype;
146 highlighter->keywords = jkeywords;
147 highlighter->parser = jparseline;
148 }
150 enum source_type {
151 SOURCE_C,
152 SOURCE_JAVA,
153 SOURCE_PLAIN
154 };
156 int main(int argc, char** argv) {
157 int retcode = EXIT_SUCCESS;
159 Settings settings;
160 memset(&settings, 0, sizeof(settings));
161 settings.showlinenumbers = 1;
163 enum source_type sourcetype = SOURCE_C;
165 char optc;
166 while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
167 switch (optc) {
168 case 'o':
169 if (!(optarg[0] == '-' && optarg[1] == 0)) {
170 settings.outfilename = optarg;
171 }
172 break;
173 case 'F':
174 settings.footerfile = optarg;
175 break;
176 case 'H':
177 settings.headerfile = optarg;
178 break;
179 case 'j':
180 sourcetype = SOURCE_JAVA;
181 break;
182 case 'p':
183 sourcetype = SOURCE_PLAIN;
184 break;
185 case 'l':
186 settings.showlinenumbers = 0;
187 break;
188 case 'h':
189 printhelp();
190 return EXIT_SUCCESS;
191 case 'v':
192 case 'V':
193 #ifdef VERSION_DEVELOP
194 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR);
195 #else
196 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
197 #endif
198 return EXIT_SUCCESS;
199 default:
200 return EXIT_FAILURE;
201 }
202 }
204 if (optind != argc-1) {
205 printhelp();
206 return 1;
207 } else {
208 settings.infilename = argv[optind];
209 FILE *fout;
210 if (settings.outfilename) {
211 fout = fopen(settings.outfilename, "w");
212 if (!fout) {
213 perror("Error opening output file");
214 return EXIT_FAILURE;
215 }
216 } else {
217 fout = stdout;
218 }
220 if (copyfile(settings.headerfile, fout)) {
221 perror("Error opening header file");
222 retcode = EXIT_FAILURE;
223 goto prog_end;
224 }
226 highlighter_t highlighter;
227 highlighter_t *hptr = &highlighter;
228 switch (sourcetype) {
229 case SOURCE_C:
230 init_c_highlighter(&highlighter);
231 break;
232 case SOURCE_JAVA:
233 init_java_highlighter(&highlighter);
234 break;
235 case SOURCE_PLAIN:
236 hptr = NULL;
237 break;
238 default: /* should be unreachable */
239 fprintf(stderr, "error in enum source_type\n");
240 retcode = EXIT_FAILURE;
241 goto prog_end;
242 }
244 FILE *inputfile = fopen(settings.infilename, "r");
245 if (inputfile) {
246 UcxBuffer *filebuf = ucx_buffer_new(NULL,
247 2048, UCX_BUFFER_AUTOEXTEND);
248 {
249 const size_t tmpbufsize = 512;
250 char *tmpbuf = malloc(tmpbufsize);
251 ucx_stream_copy(inputfile, filebuf, (read_func) fread,
252 (write_func) ucx_buffer_write,
253 tmpbuf, tmpbufsize, (size_t)-1);
254 free(tmpbuf);
255 }
256 fclose(inputfile);
258 UcxList *inputlines = ucx_list_append(NULL, filebuf->space);
259 for (size_t i = 1 ; i < filebuf->size ; i++) {
260 if (filebuf->space[i] == '\r') {
261 filebuf->space[i] = '\n'; i++;
262 }
263 if (filebuf->space[i] == '\n' && i+1 < filebuf->size) {
264 ucx_list_append(inputlines, filebuf->space+i+1);
265 }
266 }
268 formatfile(
269 hptr,
270 inputlines,
271 (write_func) fwrite,
272 fout,
273 settings.showlinenumbers);
274 ucx_buffer_free(filebuf);
275 } else {
276 perror("Error opening input file");
277 retcode = EXIT_FAILURE;
278 }
280 if (copyfile(settings.footerfile, fout)) {
281 perror("Error opening footer file");
282 retcode = EXIT_FAILURE;
283 }
285 prog_end:
286 if (fout != stdout) {
287 fclose(fout);
288 }
290 return retcode;
291 }
292 }