Sun, 11 Jun 2023 15:16:48 +0200
fix illegal memory access when input file does not end with line break
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 */
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
35 #include "c2html.h"
36 #include <cx/utils.h>
38 typedef struct {
39 char* outfilename;
40 char* headerfile;
41 char* footerfile;
42 char* infilename;
43 int showlinenumbers;
44 } Settings;
46 static int appendfile(const char *filename, FILE *fout, const char *errmsg) {
47 FILE *fin = fopen(filename, "r");
48 if (!fin) {
49 perror(errmsg);
50 if (fout != stdout) {
51 fclose(fout);
52 }
53 return 1;
54 }
55 cx_stream_copy(fin, fout, (cx_read_func) fread, (cx_write_func) fwrite);
56 fclose(fin);
57 return 0;
58 }
60 static void printhelp() {
61 printf("Formats source code using HTML.\n\nUsage:\n"
62 " c2html [Options] FILE\n\n"
63 " Options:\n"
64 " -h Prints this help message\n"
65 " -j Highlight Java instead of C source code\n"
66 " -o <output> Output file (stdout, if not specified)\n"
67 " -H <header> Prepend header file\n"
68 " -F <footer> Append footer file\n"
69 " -p Disable highlighting (plain text)\n"
70 " -l Disable line numbers\n"
71 " -V, -v Prints version and exits\n"
72 "\n");
73 }
75 int main(int argc, char** argv) {
77 /* Default settings */
78 Settings settings;
79 memset(&settings, 0, sizeof(settings));
80 settings.showlinenumbers = 1;
81 c2html_highlighter_func hltr = c2html_c_highlighter;
83 /* Parse command line */
84 int optc;
85 while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
86 switch (optc) {
87 case 'o':
88 if (!(optarg[0] == '-' && optarg[1] == 0)) {
89 settings.outfilename = optarg;
90 }
91 break;
92 case 'F':
93 settings.footerfile = optarg;
94 break;
95 case 'H':
96 settings.headerfile = optarg;
97 break;
98 case 'j':
99 hltr = c2html_java_highlighter;
100 break;
101 case 'p':
102 hltr = c2html_plain_highlighter;
103 break;
104 case 'l':
105 settings.showlinenumbers = 0;
106 break;
107 case 'h':
108 printhelp();
109 return EXIT_SUCCESS;
110 case 'v':
111 case 'V':
112 #ifdef VERSION_DEVELOP
113 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR);
114 #else
115 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
116 #endif
117 return EXIT_SUCCESS;
118 default:
119 return EXIT_FAILURE;
120 }
121 }
123 if (optind != argc-1) {
124 printhelp();
125 return EXIT_FAILURE;
126 } else {
127 /* Open output file */
128 settings.infilename = argv[optind];
129 FILE *fout;
130 if (settings.outfilename) {
131 fout = fopen(settings.outfilename, "w");
132 if (!fout) {
133 perror("Error opening output file");
134 return EXIT_FAILURE;
135 }
136 } else {
137 fout = stdout;
138 }
140 /* Prepend header file */
141 if (appendfile(settings.headerfile, fout,
142 "Error opening header file")) {
143 return EXIT_FAILURE;
144 }
146 /* Process input file */
147 FILE *inputfile = fopen(settings.infilename, "r");
148 if (inputfile) {
149 CxBuffer fbuf;
150 cxBufferInit(&fbuf, NULL, 4096, NULL, CX_BUFFER_AUTO_EXTEND);
151 cx_stream_copy(inputfile, &fbuf, (cx_read_func) fread,
152 (cx_write_func) cxBufferWrite);
153 cxBufferPut(&fbuf, 0);
154 fclose(inputfile);
155 c2html_textformat(
156 fbuf.space, fout, (cx_write_func ) fwrite, hltr,
157 settings.showlinenumbers
158 );
159 cxBufferDestroy(&fbuf);
160 } else {
161 perror("Error opening input file");
162 if (fout != stdout) {
163 fclose(fout);
164 }
165 return EXIT_FAILURE;
166 }
168 /* Append footer file */
169 if (appendfile(settings.footerfile, fout,
170 "Error opening footer file")) {
171 return EXIT_FAILURE;
172 }
174 return EXIT_SUCCESS;
175 }
176 }