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