src/c2html.c

changeset 55
bf54085ce341
parent 53
5e47a26a16f0
child 57
eba880c1705c
equal deleted inserted replaced
54:b3f24e23bc25 55:bf54085ce341
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 }

mercurial