xref: /haiku/src/bin/rc/rc.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
1e221c09eSPhilippe Houdoin /*
2e221c09eSPhilippe Houdoin  * Copyright (c) 2003 Matthijs Hollemans
3e221c09eSPhilippe Houdoin  *
4e221c09eSPhilippe Houdoin  * Permission is hereby granted, free of charge, to any person obtaining a
5e221c09eSPhilippe Houdoin  * copy of this software and associated documentation files (the "Software"),
6e221c09eSPhilippe Houdoin  * to deal in the Software without restriction, including without limitation
7e221c09eSPhilippe Houdoin  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e221c09eSPhilippe Houdoin  * and/or sell copies of the Software, and to permit persons to whom the
9e221c09eSPhilippe Houdoin  * Software is furnished to do so, subject to the following conditions:
10e221c09eSPhilippe Houdoin  *
11e221c09eSPhilippe Houdoin  * The above copyright notice and this permission notice shall be included in
12e221c09eSPhilippe Houdoin  * all copies or substantial portions of the Software.
13e221c09eSPhilippe Houdoin  *
14e221c09eSPhilippe Houdoin  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15e221c09eSPhilippe Houdoin  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16e221c09eSPhilippe Houdoin  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17e221c09eSPhilippe Houdoin  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18e221c09eSPhilippe Houdoin  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19e221c09eSPhilippe Houdoin  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20e221c09eSPhilippe Houdoin  * DEALINGS IN THE SOFTWARE.
21e221c09eSPhilippe Houdoin  */
22e221c09eSPhilippe Houdoin 
23e221c09eSPhilippe Houdoin 
24e221c09eSPhilippe Houdoin #include <stdarg.h>
25e221c09eSPhilippe Houdoin #include <stdio.h>
26e221c09eSPhilippe Houdoin #include <stdlib.h>
27e221c09eSPhilippe Houdoin #include <string.h>
28e221c09eSPhilippe Houdoin 
29e221c09eSPhilippe Houdoin #include "rdef.h"
30e221c09eSPhilippe Houdoin 
31e221c09eSPhilippe Houdoin 
32e221c09eSPhilippe Houdoin extern const char *__progname;
33e221c09eSPhilippe Houdoin 
34e221c09eSPhilippe Houdoin static const char *kTitle = "Haiku Resource Compiler 1.1";
35e221c09eSPhilippe Houdoin static const char *kProgramName = __progname;
36e221c09eSPhilippe Houdoin 
37e221c09eSPhilippe Houdoin 
38e221c09eSPhilippe Houdoin static bool sQuiet = false;
39e221c09eSPhilippe Houdoin static bool sDecompile = false;
40e221c09eSPhilippe Houdoin static uint32 sFlags = 0;
41e221c09eSPhilippe Houdoin 
42e221c09eSPhilippe Houdoin static char sOutputFile[B_PATH_NAME_LENGTH] = { 0 };
43e221c09eSPhilippe Houdoin static char *sFirstInputFile = NULL;
44e221c09eSPhilippe Houdoin 
45e221c09eSPhilippe Houdoin 
46e221c09eSPhilippe Houdoin void
warn(const char * format,...)47e221c09eSPhilippe Houdoin warn(const char *format, ...)
48e221c09eSPhilippe Houdoin {
49e221c09eSPhilippe Houdoin 	va_list ap;
50e221c09eSPhilippe Houdoin 
51e221c09eSPhilippe Houdoin 	if (!sQuiet) {
52e221c09eSPhilippe Houdoin 		fprintf(stderr, "%s: Warning! ", kProgramName);
53e221c09eSPhilippe Houdoin 		va_start(ap, format);
54e221c09eSPhilippe Houdoin 		vfprintf(stderr, format, ap);
55e221c09eSPhilippe Houdoin 		va_end(ap);
56e221c09eSPhilippe Houdoin 		fprintf(stderr, "\n");
57e221c09eSPhilippe Houdoin 	}
58e221c09eSPhilippe Houdoin }
59e221c09eSPhilippe Houdoin 
60e221c09eSPhilippe Houdoin 
61e221c09eSPhilippe Houdoin void
error(const char * format,...)62e221c09eSPhilippe Houdoin error(const char *format, ...)
63e221c09eSPhilippe Houdoin {
64e221c09eSPhilippe Houdoin 	va_list ap;
65e221c09eSPhilippe Houdoin 
66e221c09eSPhilippe Houdoin 	if (!sQuiet) {
67e221c09eSPhilippe Houdoin 		fprintf(stderr, "%s: Error! ", kProgramName);
68e221c09eSPhilippe Houdoin 		va_start(ap, format);
69e221c09eSPhilippe Houdoin 		vfprintf(stderr, format, ap);
70e221c09eSPhilippe Houdoin 		va_end(ap);
71e221c09eSPhilippe Houdoin 		fprintf(stderr, "\n");
72e221c09eSPhilippe Houdoin 	}
73e221c09eSPhilippe Houdoin 
74e221c09eSPhilippe Houdoin 	exit(EXIT_FAILURE);
75e221c09eSPhilippe Houdoin }
76e221c09eSPhilippe Houdoin 
77e221c09eSPhilippe Houdoin 
78e221c09eSPhilippe Houdoin static void
usage()79e221c09eSPhilippe Houdoin usage()
80e221c09eSPhilippe Houdoin {
81e221c09eSPhilippe Houdoin 	printf("%s\n\n"
82e221c09eSPhilippe Houdoin 		"To compile an rdef script into a resource file:\n"
83e221c09eSPhilippe Houdoin 		"    %s [options] [-o <file>] <file>...\n\n"
84e221c09eSPhilippe Houdoin 		"To convert a resource file back into an rdef script:\n"
85e221c09eSPhilippe Houdoin 		"    %s [options] [-o <file>] -d <file>...\n\n"
86e221c09eSPhilippe Houdoin 		"Options:\n"
87e221c09eSPhilippe Houdoin 		"    -d --decompile       create an rdef script from a resource file\n"
88e221c09eSPhilippe Houdoin 		"       --auto-names      construct resource names from ID symbols\n"
89e221c09eSPhilippe Houdoin 		"    -h --help            show this message\n"
90e221c09eSPhilippe Houdoin 		"    -I --include <dir>   add <dir> to the list of include paths\n"
91e221c09eSPhilippe Houdoin 		"    -m --merge           do not erase existing contents of output file\n"
92e221c09eSPhilippe Houdoin 		"    -o --output          specify output file name, default is out.xxx\n"
93e221c09eSPhilippe Houdoin 		"    -q --quiet           do not display any error messages\n"
94e221c09eSPhilippe Houdoin 		"    -V --version         show software version and license\n",
95e221c09eSPhilippe Houdoin 		kTitle, kProgramName, kProgramName);
96e221c09eSPhilippe Houdoin 
97e221c09eSPhilippe Houdoin 	exit(EXIT_SUCCESS);
98e221c09eSPhilippe Houdoin }
99e221c09eSPhilippe Houdoin 
100e221c09eSPhilippe Houdoin 
101e221c09eSPhilippe Houdoin static void
version()102e221c09eSPhilippe Houdoin version()
103e221c09eSPhilippe Houdoin {
104e221c09eSPhilippe Houdoin 	printf("%s\n\n"
105e221c09eSPhilippe Houdoin 		"Copyright (c) 2003 Matthijs Hollemans\n\n"
106e221c09eSPhilippe Houdoin 
107e221c09eSPhilippe Houdoin 		"Permission is hereby granted, free of charge, to any person obtaining a\n"
108e221c09eSPhilippe Houdoin 		"copy of this software and associated documentation files (the \"Software\"),\n"
109e221c09eSPhilippe Houdoin 		"to deal in the Software without restriction, including without limitation\n"
110e221c09eSPhilippe Houdoin 		"the rights to use, copy, modify, merge, publish, distribute, sublicense,\n"
111e221c09eSPhilippe Houdoin 		"and/or sell copies of the Software, and to permit persons to whom the\n"
112e221c09eSPhilippe Houdoin 		"Software is furnished to do so, subject to the following conditions:\n\n"
113e221c09eSPhilippe Houdoin 
114e221c09eSPhilippe Houdoin 		"The above copyright notice and this permission notice shall be included in\n"
115e221c09eSPhilippe Houdoin 		"all copies or substantial portions of the Software.\n\n"
116e221c09eSPhilippe Houdoin 
117e221c09eSPhilippe Houdoin 		"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n"
118e221c09eSPhilippe Houdoin 		"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n"
119e221c09eSPhilippe Houdoin 		"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n"
120e221c09eSPhilippe Houdoin 		"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"
121e221c09eSPhilippe Houdoin 		"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n"
122e221c09eSPhilippe Houdoin 		"FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n"
123e221c09eSPhilippe Houdoin 		"DEALINGS IN THE SOFTWARE.\n",
124e221c09eSPhilippe Houdoin 		kTitle);
125e221c09eSPhilippe Houdoin 
126e221c09eSPhilippe Houdoin 	exit(EXIT_SUCCESS);
127e221c09eSPhilippe Houdoin }
128e221c09eSPhilippe Houdoin 
129e221c09eSPhilippe Houdoin 
130e221c09eSPhilippe Houdoin static bool
has_extension(char * name,const char * ext)131e221c09eSPhilippe Houdoin has_extension(char *name, const char *ext)
132e221c09eSPhilippe Houdoin {
133e221c09eSPhilippe Houdoin 	size_t nameLength = strlen(name);
134e221c09eSPhilippe Houdoin 	size_t extLength = strlen(ext);
135e221c09eSPhilippe Houdoin 
136e221c09eSPhilippe Houdoin 	if (nameLength > extLength)
137e221c09eSPhilippe Houdoin 		return strcmp(name + nameLength - extLength, ext) == 0;
138e221c09eSPhilippe Houdoin 
139e221c09eSPhilippe Houdoin 	return false;
140e221c09eSPhilippe Houdoin }
141e221c09eSPhilippe Houdoin 
142e221c09eSPhilippe Houdoin 
143e221c09eSPhilippe Houdoin static void
cut_extension(char * name,const char * ext)144e221c09eSPhilippe Houdoin cut_extension(char *name, const char *ext)
145e221c09eSPhilippe Houdoin {
146e221c09eSPhilippe Houdoin 	if (!has_extension(name, ext))
147e221c09eSPhilippe Houdoin 		return;
148e221c09eSPhilippe Houdoin 
149e221c09eSPhilippe Houdoin 	name[strlen(name) - strlen(ext)] = '\0';
150e221c09eSPhilippe Houdoin }
151e221c09eSPhilippe Houdoin 
152e221c09eSPhilippe Houdoin 
153e221c09eSPhilippe Houdoin static void
add_extension(char * name,const char * ext)154e221c09eSPhilippe Houdoin add_extension(char *name, const char *ext)
155e221c09eSPhilippe Houdoin {
156e221c09eSPhilippe Houdoin 	strlcat(name, ext, B_PATH_NAME_LENGTH);
157e221c09eSPhilippe Houdoin }
158e221c09eSPhilippe Houdoin 
159e221c09eSPhilippe Houdoin 
160e221c09eSPhilippe Houdoin static void
parse_options(int argc,char * argv[])161e221c09eSPhilippe Houdoin parse_options(int argc, char *argv[])
162e221c09eSPhilippe Houdoin {
163e221c09eSPhilippe Houdoin 	int32 args_left = argc - 1;
164e221c09eSPhilippe Houdoin 
165e221c09eSPhilippe Houdoin 	// ToDo: use getopt_long()
166e221c09eSPhilippe Houdoin 
167e221c09eSPhilippe Houdoin 	for (int32 i = 1; i < argc; ++i) {
168e221c09eSPhilippe Houdoin 		if (strcmp(argv[i], "-o") == 0
169e221c09eSPhilippe Houdoin 				|| strcmp(argv[i], "--output") == 0) {
170e221c09eSPhilippe Houdoin 			if (i + 1 >= argc)
171e221c09eSPhilippe Houdoin 				error("%s should be followed by a file name", argv[i]);
172e221c09eSPhilippe Houdoin 
173e221c09eSPhilippe Houdoin 			strcpy(sOutputFile, argv[i + 1]);
174e221c09eSPhilippe Houdoin 
175e221c09eSPhilippe Houdoin 			argv[i] = NULL;
176e221c09eSPhilippe Houdoin 			argv[i + 1] = NULL;
177e221c09eSPhilippe Houdoin 			++i; args_left -= 2;
178e221c09eSPhilippe Houdoin 		} else if (strcmp(argv[i], "-I") == 0
179e221c09eSPhilippe Houdoin 				|| strcmp(argv[i], "--include") == 0) {
180e221c09eSPhilippe Houdoin 			if (i + 1 >= argc)
181e221c09eSPhilippe Houdoin 				error("%s should be followed by a directory name", argv[i]);
182e221c09eSPhilippe Houdoin 
183e221c09eSPhilippe Houdoin 			rdef_add_include_dir(argv[i + 1], true);
184e221c09eSPhilippe Houdoin 
185e221c09eSPhilippe Houdoin 			argv[i] = NULL;
186e221c09eSPhilippe Houdoin 			argv[i + 1] = NULL;
187e221c09eSPhilippe Houdoin 			++i; args_left -= 2;
188e221c09eSPhilippe Houdoin 		} else if (strcmp(argv[i], "-d") == 0
189e221c09eSPhilippe Houdoin 				|| strcmp(argv[i], "--decompile") == 0) {
190e221c09eSPhilippe Houdoin 			sDecompile = true;
191e221c09eSPhilippe Houdoin 			argv[i] = NULL;
192e221c09eSPhilippe Houdoin 			--args_left;
193e221c09eSPhilippe Houdoin 		} else if (strcmp(argv[i], "-m") == 0
194e221c09eSPhilippe Houdoin 				|| strcmp(argv[i], "--merge") == 0) {
195e221c09eSPhilippe Houdoin 			sFlags |= RDEF_MERGE_RESOURCES;
196e221c09eSPhilippe Houdoin 			argv[i] = NULL;
197e221c09eSPhilippe Houdoin 			--args_left;
198e221c09eSPhilippe Houdoin 		} else if (strcmp(argv[i], "--auto-names") == 0) {
199e221c09eSPhilippe Houdoin 			sFlags |= RDEF_AUTO_NAMES;
200e221c09eSPhilippe Houdoin 			argv[i] = NULL;
201e221c09eSPhilippe Houdoin 			--args_left;
202e221c09eSPhilippe Houdoin 		} else if (strcmp(argv[i], "-q") == 0
203e221c09eSPhilippe Houdoin 				|| strcmp(argv[i], "--quiet") == 0) {
204e221c09eSPhilippe Houdoin 			sQuiet = true;
205e221c09eSPhilippe Houdoin 			argv[i] = NULL;
206e221c09eSPhilippe Houdoin 			--args_left;
207e221c09eSPhilippe Houdoin 		} else if (strcmp(argv[i], "-h") == 0
208e221c09eSPhilippe Houdoin 				|| strcmp(argv[i], "--help") == 0) {
209e221c09eSPhilippe Houdoin 			usage();
210e221c09eSPhilippe Houdoin 		} else if (strcmp(argv[i], "-V") == 0
211e221c09eSPhilippe Houdoin 				|| strcmp(argv[i], "--version") == 0) {
212e221c09eSPhilippe Houdoin 			version();
213e221c09eSPhilippe Houdoin 		} else if (!strcmp(argv[i], "-")) {
214e221c09eSPhilippe Houdoin 			// stdin input file
215e221c09eSPhilippe Houdoin 			break;
216e221c09eSPhilippe Houdoin 		} else if (argv[i][0] == '-') {
217e221c09eSPhilippe Houdoin 			error("unknown option %s", argv[i]);
218e221c09eSPhilippe Houdoin 			argv[i] = NULL;
219e221c09eSPhilippe Houdoin 			--args_left;
220e221c09eSPhilippe Houdoin 		}
221e221c09eSPhilippe Houdoin 	}
222e221c09eSPhilippe Houdoin 
22335f15210SStephan Aßmus 	if (args_left < 1) {
224e221c09eSPhilippe Houdoin 		error("no input files");
22535f15210SStephan Aßmus 		usage();
22635f15210SStephan Aßmus 	}
227e221c09eSPhilippe Houdoin 
228e221c09eSPhilippe Houdoin 	for (int i = 1; i < argc; ++i) {
229e221c09eSPhilippe Houdoin 		if (argv[i] == NULL)
230e221c09eSPhilippe Houdoin 			continue;
231e221c09eSPhilippe Houdoin 
232e221c09eSPhilippe Houdoin 		if (sFirstInputFile == NULL)
233e221c09eSPhilippe Houdoin 			sFirstInputFile = argv[i];
234e221c09eSPhilippe Houdoin 
235e221c09eSPhilippe Houdoin 		rdef_add_input_file(argv[i]);
236e221c09eSPhilippe Houdoin 	}
237e221c09eSPhilippe Houdoin 
238e221c09eSPhilippe Houdoin 	if (sOutputFile[0] == '\0') {
239e221c09eSPhilippe Houdoin 		// no output file name was given, use the name of the
240e221c09eSPhilippe Houdoin 		// first source file as base
241e221c09eSPhilippe Houdoin 		strlcpy(sOutputFile, sFirstInputFile, sizeof(sOutputFile));
242e221c09eSPhilippe Houdoin 
243e221c09eSPhilippe Houdoin 		cut_extension(sOutputFile, sDecompile ? ".rsrc" : ".rdef");
244e221c09eSPhilippe Houdoin 		add_extension(sOutputFile, sDecompile ? ".rdef" : ".rsrc");
245e221c09eSPhilippe Houdoin 	}
246e221c09eSPhilippe Houdoin }
247e221c09eSPhilippe Houdoin 
248e221c09eSPhilippe Houdoin 
249e221c09eSPhilippe Houdoin static void
compile()250e221c09eSPhilippe Houdoin compile()
251e221c09eSPhilippe Houdoin {
252e221c09eSPhilippe Houdoin 	if (!has_extension(sOutputFile, ".rsrc"))
253e221c09eSPhilippe Houdoin 		add_extension(sOutputFile, ".rsrc");
254e221c09eSPhilippe Houdoin 
255e221c09eSPhilippe Houdoin 	rdef_compile(sOutputFile);
256e221c09eSPhilippe Houdoin }
257e221c09eSPhilippe Houdoin 
258e221c09eSPhilippe Houdoin 
259e221c09eSPhilippe Houdoin static void
decompile()260e221c09eSPhilippe Houdoin decompile()
261e221c09eSPhilippe Houdoin {
262e221c09eSPhilippe Houdoin 	if (!has_extension(sOutputFile, ".rdef"))
263e221c09eSPhilippe Houdoin 		add_extension(sOutputFile, ".rdef");
264e221c09eSPhilippe Houdoin 
265e221c09eSPhilippe Houdoin 	rdef_decompile(sOutputFile);
266e221c09eSPhilippe Houdoin }
267e221c09eSPhilippe Houdoin 
268e221c09eSPhilippe Houdoin 
269e221c09eSPhilippe Houdoin static void
report_error()270e221c09eSPhilippe Houdoin report_error()
271e221c09eSPhilippe Houdoin {
272e221c09eSPhilippe Houdoin 	switch (rdef_err) {
273e221c09eSPhilippe Houdoin 		case RDEF_COMPILE_ERR:
274*f4742397SMurai Takashi 			error("%s:%" B_PRId32 " %s", rdef_err_file, rdef_err_line, rdef_err_msg);
275e221c09eSPhilippe Houdoin 			break;
276e221c09eSPhilippe Houdoin 
277e221c09eSPhilippe Houdoin 		case RDEF_FILE_NOT_FOUND:
278e221c09eSPhilippe Houdoin 			error("%s not found", rdef_err_file);
279e221c09eSPhilippe Houdoin 			break;
280e221c09eSPhilippe Houdoin 
281e221c09eSPhilippe Houdoin 		case RDEF_NO_RESOURCES:
282e221c09eSPhilippe Houdoin 			error("%s is not a resource file", rdef_err_file);
283e221c09eSPhilippe Houdoin 			break;
284e221c09eSPhilippe Houdoin 
285e221c09eSPhilippe Houdoin 		case RDEF_WRITE_ERR:
286e221c09eSPhilippe Houdoin 			error("error writing to %s (%s)", rdef_err_file, rdef_err_msg);
287e221c09eSPhilippe Houdoin 			break;
288e221c09eSPhilippe Houdoin 
289e221c09eSPhilippe Houdoin 		case B_NO_MEMORY:
290e221c09eSPhilippe Houdoin 			error("out of memory");
291e221c09eSPhilippe Houdoin 			break;
292e221c09eSPhilippe Houdoin 
293e221c09eSPhilippe Houdoin 		case B_ERROR:
294e221c09eSPhilippe Houdoin 		default:
295*f4742397SMurai Takashi 			error("unknown error: %" B_PRIx32 " (%s)", rdef_err, strerror(rdef_err));
296e221c09eSPhilippe Houdoin 			break;
297e221c09eSPhilippe Houdoin 	}
298e221c09eSPhilippe Houdoin }
299e221c09eSPhilippe Houdoin 
300e221c09eSPhilippe Houdoin 
301e221c09eSPhilippe Houdoin int
main(int argc,char * argv[])302e221c09eSPhilippe Houdoin main(int argc, char *argv[])
303e221c09eSPhilippe Houdoin {
304e221c09eSPhilippe Houdoin 	parse_options(argc, argv);
305e221c09eSPhilippe Houdoin 
306e221c09eSPhilippe Houdoin 	rdef_set_flags(sFlags);
307e221c09eSPhilippe Houdoin 
308e221c09eSPhilippe Houdoin 	if (sDecompile)
309e221c09eSPhilippe Houdoin 		decompile();
310e221c09eSPhilippe Houdoin 	else
311e221c09eSPhilippe Houdoin 		compile();
312e221c09eSPhilippe Houdoin 
313e221c09eSPhilippe Houdoin 	rdef_free_input_files();
314e221c09eSPhilippe Houdoin 	rdef_free_include_dirs();
315e221c09eSPhilippe Houdoin 
316e221c09eSPhilippe Houdoin 	if (rdef_err != B_OK)
317e221c09eSPhilippe Houdoin 		report_error();
318e221c09eSPhilippe Houdoin 
319e221c09eSPhilippe Houdoin 	return EXIT_SUCCESS;
320e221c09eSPhilippe Houdoin }
321e221c09eSPhilippe Houdoin 
322