25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 * POSSIBILITY OF SUCH DAMAGE. |
26 * POSSIBILITY OF SUCH DAMAGE. |
27 * |
27 * |
28 */ |
28 */ |
29 |
29 |
30 #include <unistd.h> |
|
31 |
|
32 #include "c2html.h" |
30 #include "c2html.h" |
33 #include "highlighter.h" |
|
34 |
31 |
35 #include "ucx/list.h" |
32 #include "ucx/list.h" |
|
33 #include "ucx/utils.h" |
36 |
34 |
37 static int appendfile(const char *filename, FILE *fout, |
35 #define try_write(wfnc, str, n, buf, written, maxlen) \ |
38 char *copybuf, size_t copybuflen, const char *errmsg) { |
36 { \ |
39 FILE *headerfile = fopen(filename, "r"); |
37 size_t m = maxlen-written; \ |
40 if (!headerfile) { |
38 written += wfnc(str, 1, n > m ? m : n, buf); \ |
41 perror(errmsg); |
|
42 if (fout != stdout) { |
|
43 fclose(fout); |
|
44 } |
|
45 return 1; |
|
46 } |
39 } |
47 ucx_stream_copy(headerfile, fout, |
|
48 (read_func) fread, (write_func) fwrite, |
|
49 copybuf, copybuflen, (size_t)-1); |
|
50 fclose(headerfile); |
|
51 return 0; |
|
52 } |
|
53 |
40 |
54 static void printhelp() { |
41 static size_t formatlines(c2html_highlighter_func highlighter, UcxList *in, |
55 printf("Formats source code using HTML.\n\nUsage:\n" |
42 void *outbuf, write_func wfnc, size_t maxlen, int showlineno) { |
56 " c2html [Options] FILE\n\n" |
43 /* total written bytes */ |
57 " Options:\n" |
44 size_t written = 0; |
58 " -h Prints this help message\n" |
|
59 " -j Highlight Java instead of C source code\n" |
|
60 " -o <output> Output file (stdout, if not specified)\n" |
|
61 " -H <header> Prepend header file\n" |
|
62 " -F <footer> Append footer file\n" |
|
63 " -p Disable highlighting (plain text)\n" |
|
64 " -l Disable line numbers\n" |
|
65 " -V, -v Prints version and exits\n" |
|
66 "\n"); |
|
67 } |
|
68 |
|
69 static void formatlines(highlighter_func highlighter, |
|
70 UcxList *in, write_func out, void *stream, int showlineno) { |
|
71 |
45 |
72 /* compute width of line numbering */ |
46 /* compute width of line numbering */ |
73 int lnw = 0; |
47 int lnw = 0; |
74 if (showlineno) { |
48 if (showlineno) { |
75 size_t lines = ucx_list_size(in); |
49 size_t lines = ucx_list_size(in); |
76 for (size_t p = 1; p < lines ; p*=10) lnw++; |
50 for (size_t p = 1; p < lines ; p*=10) lnw++; |
77 } |
51 } |
78 |
52 |
79 /* start monospace formatting */ |
53 /* start monospace formatting */ |
80 out("<pre>\n", 1, 6, stream); |
54 try_write(wfnc, "<pre>\n", 6, outbuf, written, maxlen); |
81 |
55 |
82 /* process lines */ |
56 /* process lines */ |
83 size_t lineno = 0; |
57 size_t lineno = 0; |
84 HighlighterData *hd = new_highlighter_data(); |
58 c2html_highlighter_data* hd = malloc(sizeof(c2html_highlighter_data)); |
|
59 hd->multiline_comment = 0; |
|
60 hd->primary_buffer = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); |
|
61 hd->secondary_buffer = ucx_buffer_new(NULL, 32, UCX_BUFFER_AUTOEXTEND); |
85 UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); |
62 UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); |
86 if(!line || !hd) { |
|
87 perror("Error allocating buffer for output"); |
|
88 return; |
|
89 } |
|
90 |
63 |
91 UCX_FOREACH(sourceline, in) { |
64 UCX_FOREACH(sourceline, in) { |
92 /* increase line number and clean line buffer */ |
65 /* increase line number and clean line buffer */ |
93 lineno++; |
66 lineno++; |
94 ucx_buffer_clear(line); |
67 ucx_buffer_clear(line); |
102 |
75 |
103 /* process code line */ |
76 /* process code line */ |
104 highlighter(sourceline->data, line, hd); |
77 highlighter(sourceline->data, line, hd); |
105 |
78 |
106 /* write code line */ |
79 /* write code line */ |
107 out(line->space, 1, line->size, stream); |
80 try_write(wfnc, line->space, line->size, outbuf, written, maxlen); |
|
81 |
|
82 if (written == maxlen) break; |
108 } |
83 } |
109 |
84 |
110 /* end monospace formatting */ |
85 /* end monospace formatting */ |
111 out("</pre>\n", 1, 7, stream); |
86 try_write(wfnc, "</pre>\n", 7, outbuf, written, maxlen); |
112 |
87 |
113 /* cleanup and return */ |
88 /* cleanup and return */ |
114 free_highlighter_data(hd); |
89 ucx_buffer_free(hd->primary_buffer); |
|
90 ucx_buffer_free(hd->secondary_buffer); |
|
91 free(hd); |
115 ucx_buffer_free(line); |
92 ucx_buffer_free(line); |
|
93 |
|
94 return written; |
116 } |
95 } |
117 |
96 |
118 #define FILEBUF_SIZE 4096 |
97 size_t c2html_formatn(void* inputbuffer, read_func rfnc, |
|
98 char* ibuf, size_t ibuflen, void* outputbuffer, write_func wfnc, |
|
99 size_t maxlen, c2html_highlighter_func hltr, int showln) { |
|
100 |
|
101 UcxBuffer *content = ucx_buffer_new(NULL, ibuflen*2, UCX_BUFFER_AUTOEXTEND); |
|
102 ucx_stream_copy(inputbuffer, content, rfnc, (write_func) ucx_buffer_write, |
|
103 ibuf, ibuflen, (size_t)-1); |
119 |
104 |
120 enum source_type { |
105 UcxList *lines = ucx_list_append(NULL, content->space); |
121 SOURCE_C, |
106 for (size_t i = 1 ; i < content->size ; i++) { |
122 SOURCE_JAVA, |
107 if (content->space[i] == '\r') { |
123 SOURCE_PLAIN |
108 content->space[i] = '\n'; i++; |
124 }; |
109 } |
125 |
110 if (content->space[i] == '\n' && i+1 < content->size) { |
126 int main(int argc, char** argv) { |
111 ucx_list_append(lines, content->space+i+1); |
127 |
|
128 /* Default settings */ |
|
129 Settings settings; |
|
130 memset(&settings, 0, sizeof(settings)); |
|
131 settings.showlinenumbers = 1; |
|
132 enum source_type sourcetype = SOURCE_C; |
|
133 |
|
134 /* Parse command line */ |
|
135 char optc; |
|
136 while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) { |
|
137 switch (optc) { |
|
138 case 'o': |
|
139 if (!(optarg[0] == '-' && optarg[1] == 0)) { |
|
140 settings.outfilename = optarg; |
|
141 } |
|
142 break; |
|
143 case 'F': |
|
144 settings.footerfile = optarg; |
|
145 break; |
|
146 case 'H': |
|
147 settings.headerfile = optarg; |
|
148 break; |
|
149 case 'j': |
|
150 sourcetype = SOURCE_JAVA; |
|
151 break; |
|
152 case 'p': |
|
153 sourcetype = SOURCE_PLAIN; |
|
154 break; |
|
155 case 'l': |
|
156 settings.showlinenumbers = 0; |
|
157 break; |
|
158 case 'h': |
|
159 printhelp(); |
|
160 return EXIT_SUCCESS; |
|
161 case 'v': |
|
162 case 'V': |
|
163 #ifdef VERSION_DEVELOP |
|
164 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR); |
|
165 #else |
|
166 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR); |
|
167 #endif |
|
168 return EXIT_SUCCESS; |
|
169 default: |
|
170 return EXIT_FAILURE; |
|
171 } |
112 } |
172 } |
113 } |
173 |
114 |
174 if (optind != argc-1) { |
115 size_t n = formatlines(hltr, lines, outputbuffer, wfnc, maxlen, showln); |
175 printhelp(); |
116 |
176 return EXIT_FAILURE; |
117 ucx_buffer_free(content); |
177 } else { |
118 return n; |
178 /* Choose highlighter */ |
|
179 highlighter_func hltr = NULL; |
|
180 switch (sourcetype) { |
|
181 case SOURCE_C: |
|
182 hltr = c_highlighter; |
|
183 break; |
|
184 case SOURCE_JAVA: |
|
185 hltr = java_highlighter; |
|
186 break; |
|
187 case SOURCE_PLAIN: |
|
188 hltr = plain_highlighter; |
|
189 break; |
|
190 default: /* should be unreachable */ |
|
191 fprintf(stderr, "error in enum source_type\n"); |
|
192 return EXIT_FAILURE; |
|
193 } |
|
194 |
|
195 /* Open output file */ |
|
196 settings.infilename = argv[optind]; |
|
197 FILE *fout; |
|
198 if (settings.outfilename) { |
|
199 fout = fopen(settings.outfilename, "w"); |
|
200 if (!fout) { |
|
201 perror("Error opening output file"); |
|
202 return EXIT_FAILURE; |
|
203 } |
|
204 } else { |
|
205 fout = stdout; |
|
206 } |
|
207 |
|
208 /* Allocate file buffer */ |
|
209 char *filebuf = malloc(FILEBUF_SIZE); |
|
210 if (!filebuf) { |
|
211 perror("Error allocating file buffer"); |
|
212 return EXIT_FAILURE; |
|
213 } |
|
214 |
|
215 /* Prepend header file */ |
|
216 if (appendfile(settings.headerfile, fout, filebuf, FILEBUF_SIZE, |
|
217 "Error opening header file")) { |
|
218 return EXIT_FAILURE; |
|
219 } |
|
220 |
|
221 /* Process input file */ |
|
222 FILE *inputfile = fopen(settings.infilename, "r"); |
|
223 if (inputfile) { |
|
224 UcxBuffer *content = ucx_buffer_new(NULL, |
|
225 FILEBUF_SIZE*2, UCX_BUFFER_AUTOEXTEND); |
|
226 { |
|
227 ucx_stream_copy(inputfile, content, (read_func) fread, |
|
228 (write_func) ucx_buffer_write, |
|
229 filebuf, FILEBUF_SIZE, (size_t)-1); |
|
230 } |
|
231 fclose(inputfile); |
|
232 |
|
233 UcxList *inputlines = ucx_list_append(NULL, content->space); |
|
234 for (size_t i = 1 ; i < content->size ; i++) { |
|
235 if (content->space[i] == '\r') { |
|
236 content->space[i] = '\n'; i++; |
|
237 } |
|
238 if (content->space[i] == '\n' && i+1 < content->size) { |
|
239 ucx_list_append(inputlines, content->space+i+1); |
|
240 } |
|
241 } |
|
242 |
|
243 formatlines(hltr, inputlines, |
|
244 (write_func) fwrite, fout, settings.showlinenumbers); |
|
245 |
|
246 ucx_buffer_free(content); |
|
247 } else { |
|
248 perror("Error opening input file"); |
|
249 if (fout != stdout) { |
|
250 fclose(fout); |
|
251 } |
|
252 return EXIT_FAILURE; |
|
253 } |
|
254 |
|
255 /* Append footer file */ |
|
256 if (appendfile(settings.footerfile, fout, filebuf, FILEBUF_SIZE, |
|
257 "Error opening footer file")) { |
|
258 return EXIT_FAILURE; |
|
259 } |
|
260 |
|
261 free(filebuf); |
|
262 |
|
263 return EXIT_SUCCESS; |
|
264 } |
|
265 } |
119 } |
266 |
120 |
|
121 size_t c2html_format(void* inputbuffer, read_func rfnc, |
|
122 char* ibuf, size_t ibuflen, void* outputbuffer, write_func wfnc, |
|
123 c2html_highlighter_func hltr, int showln) { |
|
124 return c2html_formatn(inputbuffer, rfnc, ibuf, ibuflen, |
|
125 outputbuffer, wfnc, (size_t)-1, hltr, showln); |
|
126 } |
|
127 |
|
128 size_t c2html_format_file(FILE* inputfile, char *ibuf, size_t ibuflen, |
|
129 void* outputbuffer, write_func wfnc, |
|
130 c2html_highlighter_func hltr, int showln) { |
|
131 return c2html_format(inputfile, (read_func) fread, ibuf, ibuflen, |
|
132 outputbuffer, wfnc, hltr, showln); |
|
133 } |
|
134 |
|
135 void c2html_fformat_file(FILE *inputfile, char *ibuf, size_t ibuflen, |
|
136 FILE* outputfile, c2html_highlighter_func hltr, int showln) { |
|
137 c2html_format(inputfile, (read_func) fread, ibuf, ibuflen, |
|
138 outputfile, (write_func) fwrite, hltr, showln); |
|
139 } |