Tue, 23 Aug 2016 17:24:58 +0200
highlighter now use the UcxBuffer API for writing to the destination buffer
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 static void plain_highlighter(char *src, UcxBuffer *dest, int* x) {
51 while (*src && *src != '\n') {
52 put_htmlescaped(dest, *src);
53 src++;
54 }
55 ucx_buffer_putc(dest, '\n');
56 }
58 int formatlines(highlighter_func highlighter,
59 UcxList *in, write_func out, void *stream, int showlineno) {
61 /* compute width of line numbering */
62 int lnw;
63 if (showlineno) {
64 size_t lines = ucx_list_size(in);
65 lnw = 1;
66 int p = 1;
67 while ((p*=10) < lines) lnw++;
68 }
70 /* allocate line buffer */
71 UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
72 if(!line) {
73 return 1;
74 }
76 /* start monospace formatting */
77 out("<pre>\n", 1, 6, stream);
79 /* process lines */
80 size_t lineno = 0;
81 int multiline_comment = 0;
83 UCX_FOREACH(sourceline, in) {
84 /* increase line number and clean line buffer */
85 lineno++;
86 ucx_buffer_clear(line);
88 /* write line number */
89 if (showlineno) {
90 ucx_bprintf(line, "<span class=\"c2html-lineno\">"
91 "<a name=\"l%d\" href=\"#l%d\">%*d </a></span> ",
92 lineno, lineno, lnw, lineno);
93 }
95 /* process code line */
96 highlighter(sourceline->data, line, &multiline_comment);
98 /* write code line and reset buffer */
99 out(line->space, 1, line->size, stream);
100 }
102 /* end monospace formatting */
103 out("</pre>\n", 1, 7, stream);
105 /* cleanup and return */
106 ucx_buffer_free(line);
107 return 0;
108 }
110 #define FILEBUF_SIZE 4096
112 enum source_type {
113 SOURCE_C,
114 SOURCE_JAVA,
115 SOURCE_PLAIN
116 };
118 int main(int argc, char** argv) {
120 /* Default settings */
121 Settings settings;
122 memset(&settings, 0, sizeof(settings));
123 settings.showlinenumbers = 1;
124 enum source_type sourcetype = SOURCE_C;
126 /* Parse command line */
127 char optc;
128 while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
129 switch (optc) {
130 case 'o':
131 if (!(optarg[0] == '-' && optarg[1] == 0)) {
132 settings.outfilename = optarg;
133 }
134 break;
135 case 'F':
136 settings.footerfile = optarg;
137 break;
138 case 'H':
139 settings.headerfile = optarg;
140 break;
141 case 'j':
142 sourcetype = SOURCE_JAVA;
143 break;
144 case 'p':
145 sourcetype = SOURCE_PLAIN;
146 break;
147 case 'l':
148 settings.showlinenumbers = 0;
149 break;
150 case 'h':
151 printhelp();
152 return EXIT_SUCCESS;
153 case 'v':
154 case 'V':
155 #ifdef VERSION_DEVELOP
156 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR);
157 #else
158 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
159 #endif
160 return EXIT_SUCCESS;
161 default:
162 return EXIT_FAILURE;
163 }
164 }
166 if (optind != argc-1) {
167 printhelp();
168 return EXIT_FAILURE;
169 } else {
170 /* Choose highlighter */
171 highlighter_func hltr = NULL;
172 switch (sourcetype) {
173 case SOURCE_C:
174 hltr = c_highlighter;
175 break;
176 case SOURCE_JAVA:
177 hltr = java_highlighter;
178 break;
179 case SOURCE_PLAIN:
180 hltr = plain_highlighter;
181 break;
182 default: /* should be unreachable */
183 fprintf(stderr, "error in enum source_type\n");
184 return EXIT_FAILURE;
185 }
187 /* Open output file */
188 settings.infilename = argv[optind];
189 FILE *fout;
190 if (settings.outfilename) {
191 fout = fopen(settings.outfilename, "w");
192 if (!fout) {
193 perror("Error opening output file");
194 return EXIT_FAILURE;
195 }
196 } else {
197 fout = stdout;
198 }
200 /* Allocate file buffer */
201 char *filebuf = malloc(FILEBUF_SIZE);
202 if (!filebuf) {
203 perror("Error allocating file buffer");
204 return EXIT_FAILURE;
205 }
207 /* Prepend header file */
208 {
209 FILE *headerfile = fopen(settings.headerfile, "r");
210 if (!headerfile) {
211 perror("Error opening header file");
212 if (fout != stdout) {
213 fclose(fout);
214 }
215 return EXIT_FAILURE;
216 }
217 ucx_stream_copy(headerfile, fout,
218 (read_func) fread, (write_func) fwrite,
219 filebuf, FILEBUF_SIZE, (size_t)-1);
220 fclose(headerfile);
221 }
223 /* Process input file */
224 FILE *inputfile = fopen(settings.infilename, "r");
225 if (inputfile) {
226 UcxBuffer *content = ucx_buffer_new(NULL,
227 FILEBUF_SIZE*2, UCX_BUFFER_AUTOEXTEND);
228 {
229 ucx_stream_copy(inputfile, content, (read_func) fread,
230 (write_func) ucx_buffer_write,
231 filebuf, FILEBUF_SIZE, (size_t)-1);
232 }
233 fclose(inputfile);
235 UcxList *inputlines = ucx_list_append(NULL, content->space);
236 for (size_t i = 1 ; i < content->size ; i++) {
237 if (content->space[i] == '\r') {
238 content->space[i] = '\n'; i++;
239 }
240 if (content->space[i] == '\n' && i+1 < content->size) {
241 ucx_list_append(inputlines, content->space+i+1);
242 }
243 }
245 formatlines(hltr, inputlines,
246 (write_func) fwrite, fout, settings.showlinenumbers);
248 ucx_buffer_free(content);
249 } else {
250 perror("Error opening input file");
251 if (fout != stdout) {
252 fclose(fout);
253 }
254 return EXIT_FAILURE;
255 }
257 /* Append footer file */
258 {
259 FILE *footerfile = fopen(settings.footerfile, "r");
260 if (!footerfile) {
261 perror("Error opening footer file");
262 if (fout != stdout) {
263 fclose(fout);
264 }
265 return EXIT_FAILURE;
266 }
267 ucx_stream_copy(footerfile, fout,
268 (read_func) fread, (write_func) fwrite,
269 filebuf, FILEBUF_SIZE, (size_t)-1);
270 fclose(footerfile);
271 }
274 free(filebuf);
276 return EXIT_SUCCESS;
277 }
278 }