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