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