1 /* 2 * Copyright 2002, Ryan Fleet. 3 * Copyright 2006-2007, Axel Dörfler, axeld@pinc-software.de. 4 * 5 * Distributed under the terms of the MIT license. 6 */ 7 8 9 #include <AppFileInfo.h> 10 #include <String.h> 11 12 #include <ctype.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 18 extern const char *__progname; 19 20 const char *kProgramName = __progname; 21 22 23 enum arg_needed { 24 switch_needed, major_version, middle_version, minor_version, 25 variety_version, internal_version, long_string, short_string 26 }; 27 28 enum app_error { 29 e_base = B_ERRORS_END, 30 e_unknown, e_app_sys_switch, e_specify_version, e_major_version, 31 e_middle_version, e_minor_version, e_variety_version, e_internal_version, 32 e_expecting, e_long_string, e_short_string, 33 e_parameter, e_app_twice, e_sys_twice 34 }; 35 36 enum processing_mode { no_switch, app_switch, sys_switch }; 37 38 39 static void 40 usage() 41 { 42 fprintf(stdout, "Usage: %s filename\n", kProgramName); 43 fprintf(stdout, " [ -system <major> <middle> <minor>\n"); 44 fprintf(stdout, " [ [ d | a | b | g | gm | f ] [ <internal> ] ]\n"); 45 fprintf(stdout, " [ -short <shortVersionString> ]\n"); 46 fprintf(stdout, " [ -long <longVersionString> ] ] # system info\n"); 47 fprintf(stdout, " [ -app <major> <middle> <minor>\n"); 48 fprintf(stdout, " [ [ d | a | b | g | gm | f ] [ <internal> ] ]\n"); 49 fprintf(stdout, " [ -short <shortVersionString> ]\n"); 50 fprintf(stdout, " [ -long <longVersionString> ] ] # application info\n"); 51 } 52 53 54 static int 55 convertVariety(const char *str) 56 { 57 if (!strcmp(str, "d") || !strcmp(str, "development")) 58 return 0; 59 if (!strcmp(str, "a") || !strcmp(str, "alpha")) 60 return 1; 61 if (!strcmp(str, "b") || !strcmp(str, "beta")) 62 return 2; 63 if (!strcmp(str, "g") || !strcmp(str, "gamma")) 64 return 3; 65 if (!strcmp(str, "gm") || !strcmp(str, "goldenmaster")) 66 return 4; 67 if (!strcmp(str, "f") || !strcmp(str, "final")) 68 return 5; 69 70 return -1; 71 } 72 73 74 static void 75 errorToString(BString& output, status_t error, const char *appName = NULL) 76 { 77 switch (error) { 78 case e_app_sys_switch: 79 output = "-system or -app expected\n"; 80 break; 81 case e_specify_version: 82 output = "you did not specify any version\n"; 83 break; 84 case e_major_version: 85 output = "major version number error\n"; 86 break; 87 case e_middle_version: 88 output = "middle version number error\n"; 89 break; 90 case e_minor_version: 91 output = "minor version number error\n"; 92 break; 93 case e_variety_version: 94 output = "variety letter error\n"; 95 break; 96 case e_internal_version: 97 output = "internal version number error\n"; 98 break; 99 case e_expecting: 100 output = "expecting -short, -long, -app or -system\n"; 101 break; 102 case e_long_string: 103 output = "expecting long version string\n"; 104 break; 105 case e_short_string: 106 output = "expecting short version string\n"; 107 break; 108 case e_parameter: 109 output = "parameter error\n"; 110 break; 111 case e_app_twice: 112 output = "you cannot specify the app version twice\n"; 113 break; 114 case e_sys_twice: 115 output = "you cannot specify the system version twice\n"; 116 break; 117 case e_unknown: 118 output = "unknown internal error\n"; 119 break; 120 121 default: 122 output = strerror(error); 123 124 if (appName != NULL) { 125 output += ": "; 126 output += appName; 127 } 128 break; 129 } 130 } 131 132 133 static void 134 errorOut(status_t error, const char *appName = NULL, bool showUsage = true) 135 { 136 BString output; 137 errorToString(output, error, appName); 138 139 fprintf(stderr, "%s: %s", kProgramName, output.String()); 140 141 if (showUsage) 142 usage(); 143 144 exit(1); 145 } 146 147 148 static void 149 parse(bool &systemModified, bool &appModified, arg_needed &argNeeded, 150 processing_mode &mode, version_info &systemVersion, version_info &appVersion, 151 int argc, char *argv[]) 152 { 153 systemModified = false; 154 appModified = false; 155 mode = no_switch; 156 argNeeded = switch_needed; 157 158 for (int i = 2; i < argc; ++i) { 159 version_info &version = mode == app_switch ? appVersion : systemVersion; 160 161 switch (argNeeded) { 162 case switch_needed: 163 if (strcmp(argv[i], "-app") == 0) { 164 if (mode == app_switch) 165 errorOut(e_app_twice); 166 if (appModified) 167 errorOut(e_parameter); 168 169 mode = app_switch; 170 argNeeded = major_version; 171 appModified = true; 172 } else if (strcmp(argv[i], "-system") == 0) { 173 if (mode == sys_switch) 174 errorOut(e_sys_twice); 175 if (systemModified) 176 errorOut(e_parameter); 177 178 mode = sys_switch; 179 argNeeded = major_version; 180 systemModified = true; 181 } else if (strcmp(argv[i], "-long") == 0) { 182 if (mode == no_switch) 183 errorOut(e_app_sys_switch); 184 185 argNeeded = long_string; 186 } else if (strcmp(argv[i], "-short") == 0) { 187 if (mode == no_switch) 188 errorOut(e_app_sys_switch); 189 190 argNeeded = short_string; 191 } else if (mode == no_switch) 192 errorOut(e_app_sys_switch); 193 else if (strncmp(argv[i], "-", 1) == 0) 194 errorOut(e_parameter); 195 else 196 errorOut(e_expecting); 197 break; 198 199 case major_version: 200 if (isalpha(argv[i][0])) 201 errorOut(e_major_version); 202 203 version.major = atoi(argv[i]); 204 argNeeded = middle_version; 205 break; 206 207 case middle_version: 208 if (isalpha(argv[i][0])) 209 errorOut(e_middle_version); 210 211 version.middle = atoi(argv[i]); 212 argNeeded = minor_version; 213 break; 214 215 case minor_version: 216 if (isalpha(argv[i][0])) 217 errorOut(e_minor_version); 218 219 version.minor = atoi(argv[i]); 220 221 if (i >= argc-1) { 222 argNeeded = switch_needed; 223 break; 224 } 225 226 argNeeded = variety_version; 227 break; 228 229 case variety_version: 230 { 231 if (!strncmp(argv[i], "-", 1)) { 232 i--; 233 argNeeded = switch_needed; 234 break; 235 } 236 237 int variety = convertVariety(argv[i]); 238 if (variety < 0) 239 errorOut(e_variety_version); 240 241 version.variety = variety; 242 argNeeded = internal_version; 243 break; 244 } 245 246 case internal_version: 247 if (isalpha(argv[i][0])) 248 errorOut(e_expecting); 249 250 version.internal = atoi(argv[i]); 251 argNeeded = switch_needed; 252 break; 253 254 case long_string: 255 strcpy(version.long_info, argv[i]); 256 argNeeded = switch_needed; 257 break; 258 259 case short_string: 260 strcpy(version.short_info, argv[i]); 261 argNeeded = switch_needed; 262 break; 263 } 264 } 265 266 if (mode == no_switch) 267 errorOut(e_app_sys_switch); 268 269 switch (argNeeded) { 270 case major_version: 271 errorOut(e_major_version); 272 break; 273 case middle_version: 274 errorOut(e_middle_version); 275 break; 276 case minor_version: 277 errorOut(e_minor_version); 278 break; 279 case variety_version: 280 errorOut(e_variety_version); 281 break; 282 case internal_version: 283 errorOut(e_internal_version); 284 break; 285 case long_string: 286 errorOut(e_long_string); 287 break; 288 case short_string: 289 errorOut(e_short_string); 290 break; 291 case switch_needed: 292 // all is well 293 break; 294 } 295 } 296 297 298 int 299 main(int argc, char *argv[]) 300 { 301 if (argc < 3) { 302 if (argc < 2) 303 errorOut(e_app_sys_switch); 304 305 errorOut(e_specify_version); 306 } 307 308 // reset version infos 309 310 version_info systemVersion, appVersion; 311 memset(&systemVersion, 0, sizeof(version_info)); 312 memset(&appVersion, 0, sizeof(version_info)); 313 314 // process arguments 315 316 processing_mode mode; 317 arg_needed argNeeded; 318 bool systemModified, appModified; 319 320 parse(systemModified, appModified, argNeeded, mode, systemVersion, 321 appVersion, argc, argv); 322 323 // write back changes 324 325 BFile file; 326 status_t status = file.SetTo(argv[1], B_READ_WRITE); 327 if (status != B_OK) 328 errorOut(status, argv[1], false); 329 330 BAppFileInfo info; 331 status = info.SetTo(&file); 332 if (status != B_OK) 333 errorOut(status, argv[1], false); 334 335 if (systemModified ^ appModified) { 336 // clear out other app info if not present - this works around a 337 // bug in BeOS, see bug #681. 338 version_kind kind = systemModified ? B_APP_VERSION_KIND : B_SYSTEM_VERSION_KIND; 339 version_info clean; 340 341 if (info.GetVersionInfo(&clean, kind) != B_OK) { 342 memset(&clean, 0, sizeof(version_info)); 343 info.SetVersionInfo(&clean, kind); 344 } 345 } 346 347 if (appModified) { 348 status = info.SetVersionInfo(&appVersion, B_APP_VERSION_KIND); 349 if (status < B_OK) 350 errorOut(status, NULL, false); 351 } 352 353 if (systemModified) { 354 status = info.SetVersionInfo(&systemVersion, B_SYSTEM_VERSION_KIND); 355 if (status < B_OK) 356 errorOut(status, NULL, false); 357 } 358 359 return 0; 360 } 361 362