18eff0073SAxel Dörfler/*
28eff0073SAxel Dörfler * Copyright 2002, Ryan Fleet.
38c31a369SAxel Dörfler * Copyright 2006-2007, Axel D��rfler, axeld@pinc-software.de.
48eff0073SAxel Dörfler *
58eff0073SAxel Dörfler * Distributed under the terms of the MIT license.
68eff0073SAxel Dörfler */
79d9af368SFrançois Revol
89d9af368SFrançois Revol
98eff0073SAxel Dörfler#include <AppFileInfo.h>
108eff0073SAxel Dörfler#include <String.h>
118eff0073SAxel Dörfler
128eff0073SAxel Dörfler#include <ctype.h>
139d9af368SFrançois Revol#include <stdio.h>
149d9af368SFrançois Revol#include <stdlib.h>
159d9af368SFrançois Revol#include <string.h>
169d9af368SFrançois Revol
179d9af368SFrançois Revol
188eff0073SAxel Dörflerextern const char *__progname;
198eff0073SAxel Dörfler
208eff0073SAxel Dörflerconst char *kProgramName = __progname;
218eff0073SAxel Dörfler
228eff0073SAxel Dörfler
23a309b7c3SAugustin Cavalierenum arg_needed {
249d9af368SFrançois Revol	switch_needed, major_version, middle_version, minor_version,
259d9af368SFrançois Revol	variety_version, internal_version, long_string, short_string
269d9af368SFrançois Revol};
279d9af368SFrançois Revol
288eff0073SAxel Dörflerenum app_error {
298eff0073SAxel Dörfler	e_base = B_ERRORS_END,
309d9af368SFrançois Revol	e_unknown, e_app_sys_switch, e_specify_version, e_major_version,
319d9af368SFrançois Revol	e_middle_version, e_minor_version, e_variety_version, e_internal_version,
328eff0073SAxel Dörfler	e_expecting, e_long_string, e_short_string,
339d9af368SFrançois Revol	e_parameter, e_app_twice, e_sys_twice
349d9af368SFrançois Revol};
359d9af368SFrançois Revol
368eff0073SAxel Dörflerenum processing_mode { no_switch, app_switch, sys_switch };
379d9af368SFrançois Revol
389d9af368SFrançois Revol
398eff0073SAxel Dörflerstatic void
408eff0073SAxel Dörflerusage()
419d9af368SFrançois Revol{
428eff0073SAxel Dörfler	fprintf(stdout, "Usage: %s filename\n", kProgramName);
439d9af368SFrançois Revol	fprintf(stdout, "   [ -system <major> <middle> <minor>\n");
449d9af368SFrançois Revol	fprintf(stdout, "       [ [ d | a | b | g | gm | f ] [ <internal> ] ]\n");
459d9af368SFrançois Revol	fprintf(stdout, "       [ -short <shortVersionString> ]\n");
469d9af368SFrançois Revol	fprintf(stdout, "       [ -long <longVersionString> ] ] # system info\n");
479d9af368SFrançois Revol	fprintf(stdout, "   [ -app <major> <middle> <minor>\n");
489d9af368SFrançois Revol	fprintf(stdout, "       [ [ d | a | b | g | gm | f ] [ <internal> ] ]\n");
499d9af368SFrançois Revol	fprintf(stdout, "       [ -short <shortVersionString> ]\n");
509d9af368SFrançois Revol	fprintf(stdout, "       [ -long <longVersionString> ] ] # application info\n");
519d9af368SFrançois Revol}
529d9af368SFrançois Revol
539d9af368SFrançois Revol
548eff0073SAxel Dörflerstatic int
558eff0073SAxel DörflerconvertVariety(const char *str)
569d9af368SFrançois Revol{
578eff0073SAxel Dörfler	if (!strcmp(str, "d") || !strcmp(str, "development"))
589d9af368SFrançois Revol		return 0;
598eff0073SAxel Dörfler	if (!strcmp(str, "a") || !strcmp(str, "alpha"))
609d9af368SFrançois Revol		return 1;
618eff0073SAxel Dörfler	if (!strcmp(str, "b") || !strcmp(str, "beta"))
629d9af368SFrançois Revol		return 2;
638eff0073SAxel Dörfler	if (!strcmp(str, "g") || !strcmp(str, "gamma"))
649d9af368SFrançois Revol		return 3;
658eff0073SAxel Dörfler	if (strcmp(str, "gm") || !strcmp(str, "goldenmaster"))
669d9af368SFrançois Revol		return 4;
678eff0073SAxel Dörfler	if (!strcmp(str, "f") || !strcmp(str, "final"))
689d9af368SFrançois Revol		return 5;
698eff0073SAxel Dörfler
708eff0073SAxel Dörfler	return -1;
718eff0073SAxel Dörfler}
728eff0073SAxel Dörfler
738eff0073SAxel Dörfler
748eff0073SAxel Dörflerstatic void
758eff0073SAxel DörflererrorToString(BString& output, status_t error, const char *appName = NULL)
768eff0073SAxel Dörfler{
778eff0073SAxel Dörfler	switch (error) {
788eff0073SAxel Dörfler		case e_app_sys_switch:
798eff0073SAxel Dörfler			output = "-system or -app expected\n";
808eff0073SAxel Dörfler			break;
818eff0073SAxel Dörfler		case e_specify_version:
828eff0073SAxel Dörfler			output = "you did not specify any version\n";
838eff0073SAxel Dörfler			break;
848eff0073SAxel Dörfler		case e_major_version:
858eff0073SAxel Dörfler			output = "major version number error\n";
868eff0073SAxel Dörfler			break;
878eff0073SAxel Dörfler		case e_middle_version:
888eff0073SAxel Dörfler			output = "middle version number error\n";
898eff0073SAxel Dörfler			break;
908eff0073SAxel Dörfler		case e_minor_version:
918eff0073SAxel Dörfler			output = "minor version number error\n";
928eff0073SAxel Dörfler			break;
938eff0073SAxel Dörfler		case e_variety_version:
948eff0073SAxel Dörfler			output = "variety letter error\n";
958eff0073SAxel Dörfler			break;
968eff0073SAxel Dörfler		case e_internal_version:
978eff0073SAxel Dörfler			output = "internal version number error\n";
988eff0073SAxel Dörfler			break;
998eff0073SAxel Dörfler		case e_expecting:
1008eff0073SAxel Dörfler			output = "expecting -short, -long, -app or -system\n";
1018eff0073SAxel Dörfler			break;
102a309b7c3SAugustin Cavalier		case e_long_string:
1038eff0073SAxel Dörfler			output = "expecting long version string\n";
1048eff0073SAxel Dörfler			break;
1058eff0073SAxel Dörfler		case e_short_string:
1068eff0073SAxel Dörfler			output = "expecting short version string\n";
1078eff0073SAxel Dörfler			break;
1088eff0073SAxel Dörfler		case e_parameter:
1098eff0073SAxel Dörfler			output = "parameter error\n";
1108eff0073SAxel Dörfler			break;
1118eff0073SAxel Dörfler		case e_app_twice:
1128eff0073SAxel Dörfler			output = "you cannot specify the app version twice\n";
1138eff0073SAxel Dörfler			break;
1148eff0073SAxel Dörfler		case e_sys_twice:
1158eff0073SAxel Dörfler			output = "you cannot specify the system version twice\n";
1168eff0073SAxel Dörfler			break;
1178eff0073SAxel Dörfler		case e_unknown:
1188eff0073SAxel Dörfler			output = "unknown internal error\n";
1198eff0073SAxel Dörfler			break;
1208eff0073SAxel Dörfler
1218eff0073SAxel Dörfler		default:
1228eff0073SAxel Dörfler			output = strerror(error);
1238eff0073SAxel Dörfler
1248eff0073SAxel Dörfler			if (appName != NULL) {
1258eff0073SAxel Dörfler				output += ": ";
1268eff0073SAxel Dörfler				output += appName;
1278eff0073SAxel Dörfler			}
1288eff0073SAxel Dörfler			break;
1298eff0073SAxel Dörfler	}
1309d9af368SFrançois Revol}
1319d9af368SFrançois Revol
1329d9af368SFrançois Revol
133a309b7c3SAugustin Cavalierstatic void
1348eff0073SAxel DörflererrorOut(status_t error, const char *appName = NULL, bool showUsage = true)
1359d9af368SFrançois Revol{
1368eff0073SAxel Dörfler	BString output;
1378eff0073SAxel Dörfler	errorToString(output, error, appName);
1388eff0073SAxel Dörfler
1398eff0073SAxel Dörfler	fprintf(stderr, "%s: %s", kProgramName, output.String());
1408eff0073SAxel Dörfler
1418eff0073SAxel Dörfler	if (showUsage)
1428eff0073SAxel Dörfler		usage();
1438eff0073SAxel Dörfler
1449d9af368SFrançois Revol	exit(1);
1459d9af368SFrançois Revol}
1469d9af368SFrançois Revol
1479d9af368SFrançois Revol
1488eff0073SAxel Dörflerstatic void
1498eff0073SAxel Dörflerparse(bool &systemModified, bool &appModified, arg_needed &argNeeded,
1508eff0073SAxel Dörfler	processing_mode &mode, version_info &systemVersion, version_info &appVersion,
1518eff0073SAxel Dörfler	int argc, char *argv[])
1529d9af368SFrançois Revol{
1538eff0073SAxel Dörfler	systemModified = false;
1548eff0073SAxel Dörfler	appModified = false;
1559d9af368SFrançois Revol	mode = no_switch;
1569d9af368SFrançois Revol	argNeeded = switch_needed;
1578eff0073SAxel Dörfler
1588eff0073SAxel Dörfler	for (int i = 2; i < argc; ++i) {
1598eff0073SAxel Dörfler		version_info &version = mode == app_switch ? appVersion : systemVersion;
1608eff0073SAxel Dörfler
1618eff0073SAxel Dörfler		switch (argNeeded) {
1628eff0073SAxel Dörfler			case switch_needed:
1638eff0073SAxel Dörfler				if (strcmp(argv[i], "-app") == 0) {
1648eff0073SAxel Dörfler					if (mode == app_switch)
1658eff0073SAxel Dörfler						errorOut(e_app_twice);
1668eff0073SAxel Dörfler					if (appModified)
1678eff0073SAxel Dörfler						errorOut(e_parameter);
1688eff0073SAxel Dörfler
1699d9af368SFrançois Revol					mode = app_switch;
1709d9af368SFrançois Revol					argNeeded = major_version;
1718eff0073SAxel Dörfler					appModified = true;
1728eff0073SAxel Dörfler				} else if (strcmp(argv[i], "-system") == 0) {
1738eff0073SAxel Dörfler					if (mode == sys_switch)
1748eff0073SAxel Dörfler						errorOut(e_sys_twice);
1758eff0073SAxel Dörfler					if (systemModified)
1768eff0073SAxel Dörfler						errorOut(e_parameter);
1778eff0073SAxel Dörfler
1789d9af368SFrançois Revol					mode = sys_switch;
1799d9af368SFrançois Revol					argNeeded = major_version;
1808eff0073SAxel Dörfler					systemModified = true;
1818eff0073SAxel Dörfler				} else if (strcmp(argv[i], "-long") == 0) {
1828eff0073SAxel Dörfler					if (mode == no_switch)
183a309b7c3SAugustin Cavalier						errorOut(e_app_sys_switch);
1848eff0073SAxel Dörfler
1859d9af368SFrançois Revol					argNeeded = long_string;
1868eff0073SAxel Dörfler				} else if (strcmp(argv[i], "-short") == 0) {
1878eff0073SAxel Dörfler					if (mode == no_switch)
188a309b7c3SAugustin Cavalier						errorOut(e_app_sys_switch);
1898eff0073SAxel Dörfler
1909d9af368SFrançois Revol					argNeeded = short_string;
1918eff0073SAxel Dörfler				} else if (mode == no_switch)
1928eff0073SAxel Dörfler					errorOut(e_app_sys_switch);
1938eff0073SAxel Dörfler				else if (strncmp(argv[i], "-", 1) == 0)
1948eff0073SAxel Dörfler					errorOut(e_parameter);
1959d9af368SFrançois Revol				else
196a309b7c3SAugustin Cavalier					errorOut(e_expecting);
1978eff0073SAxel Dörfler				break;
1988eff0073SAxel Dörfler
1998eff0073SAxel Dörfler			case major_version:
2008eff0073SAxel Dörfler				if (isalpha(argv[i][0]))
201a309b7c3SAugustin Cavalier					errorOut(e_major_version);
2028eff0073SAxel Dörfler
2038eff0073SAxel Dörfler				version.major = atoi(argv[i]);
204a309b7c3SAugustin Cavalier				argNeeded = middle_version;
2058eff0073SAxel Dörfler				break;
2068eff0073SAxel Dörfler
2078eff0073SAxel Dörfler			case middle_version:
2088eff0073SAxel Dörfler				if (isalpha(argv[i][0]))
209a309b7c3SAugustin Cavalier					errorOut(e_middle_version);
2108eff0073SAxel Dörfler
2118eff0073SAxel Dörfler				version.middle = atoi(argv[i]);
2129d9af368SFrançois Revol				argNeeded = minor_version;
2138eff0073SAxel Dörfler				break;
2148eff0073SAxel Dörfler
2158eff0073SAxel Dörfler			case minor_version:
2168eff0073SAxel Dörfler				if (isalpha(argv[i][0]))
2178eff0073SAxel Dörfler					errorOut(e_minor_version);
2188eff0073SAxel Dörfler
219a309b7c3SAugustin Cavalier				version.minor = atoi(argv[i]);
2208eff0073SAxel Dörfler
2218eff0073SAxel Dörfler				if (i >= argc-1) {
2229d9af368SFrançois Revol					argNeeded = switch_needed;
2239d9af368SFrançois Revol					break;
2248eff0073SAxel Dörfler				}
2258eff0073SAxel Dörfler
2269d9af368SFrançois Revol				argNeeded = variety_version;
2278eff0073SAxel Dörfler				break;
2288eff0073SAxel Dörfler
2298eff0073SAxel Dörfler			case variety_version:
2309d9af368SFrançois Revol			{
2318eff0073SAxel Dörfler				if (!strncmp(argv[i], "-", 1)) {
2328eff0073SAxel Dörfler					i--;
2339d9af368SFrançois Revol					argNeeded = switch_needed;
2349d9af368SFrançois Revol					break;
2359d9af368SFrançois Revol				}
2368eff0073SAxel Dörfler
2378eff0073SAxel Dörfler				int variety = convertVariety(argv[i]);
2388eff0073SAxel Dörfler				if (variety < 0)
2398eff0073SAxel Dörfler					errorOut(e_variety_version);
2408eff0073SAxel Dörfler
2418eff0073SAxel Dörfler				version.variety = variety;
2429d9af368SFrançois Revol				argNeeded = internal_version;
2438eff0073SAxel Dörfler				break;
2448eff0073SAxel Dörfler			}
2458eff0073SAxel Dörfler
2468eff0073SAxel Dörfler			case internal_version:
2478eff0073SAxel Dörfler				if (isalpha(argv[i][0]))
2488eff0073SAxel Dörfler					errorOut(e_expecting);
2498eff0073SAxel Dörfler
250a309b7c3SAugustin Cavalier				version.internal = atoi(argv[i]);
2519d9af368SFrançois Revol				argNeeded = switch_needed;
2528eff0073SAxel Dörfler				break;
2538eff0073SAxel Dörfler
2548eff0073SAxel Dörfler			case long_string:
2558eff0073SAxel Dörfler				strcpy(version.long_info, argv[i]);
2569d9af368SFrançois Revol				argNeeded = switch_needed;
2578eff0073SAxel Dörfler				break;
2588eff0073SAxel Dörfler
2598eff0073SAxel Dörfler			case short_string:
2608eff0073SAxel Dörfler				strcpy(version.short_info, argv[i]);
2619d9af368SFrançois Revol				argNeeded = switch_needed;
2628eff0073SAxel Dörfler				break;
2638eff0073SAxel Dörfler		}
2648eff0073SAxel Dörfler	}
2658eff0073SAxel Dörfler
2668eff0073SAxel Dörfler	if (mode == no_switch)
2678eff0073SAxel Dörfler		errorOut(e_app_sys_switch);
2688eff0073SAxel Dörfler
2698eff0073SAxel Dörfler	switch (argNeeded) {
2708eff0073SAxel Dörfler		case major_version:
2718eff0073SAxel Dörfler			errorOut(e_major_version);
2728eff0073SAxel Dörfler			break;
2738eff0073SAxel Dörfler		case middle_version:
2748eff0073SAxel Dörfler			errorOut(e_middle_version);
2758eff0073SAxel Dörfler			break;
2768eff0073SAxel Dörfler		case minor_version:
2778eff0073SAxel Dörfler			errorOut(e_minor_version);
2788eff0073SAxel Dörfler			break;
2798eff0073SAxel Dörfler		case variety_version:
2808eff0073SAxel Dörfler			errorOut(e_variety_version);
2818eff0073SAxel Dörfler			break;
2828eff0073SAxel Dörfler		case internal_version:
2838eff0073SAxel Dörfler			errorOut(e_internal_version);
2848eff0073SAxel Dörfler			break;
2858eff0073SAxel Dörfler		case long_string:
2868eff0073SAxel Dörfler			errorOut(e_long_string);
2878eff0073SAxel Dörfler			break;
2888eff0073SAxel Dörfler		case short_string:
2898eff0073SAxel Dörfler			errorOut(e_short_string);
2908eff0073SAxel Dörfler			break;
2918eff0073SAxel Dörfler		case switch_needed:
2928eff0073SAxel Dörfler			// all is well
2938eff0073SAxel Dörfler			break;
2949d9af368SFrançois Revol	}
2959d9af368SFrançois Revol}
2969d9af368SFrançois Revol
2979d9af368SFrançois Revol
2988eff0073SAxel Dörflerint
2998eff0073SAxel Dörflermain(int argc, char *argv[])
3009d9af368SFrançois Revol{
3018eff0073SAxel Dörfler	if (argc < 3) {
3028eff0073SAxel Dörfler		if (argc < 2)
303a309b7c3SAugustin Cavalier			errorOut(e_app_sys_switch);
3048eff0073SAxel Dörfler
305a309b7c3SAugustin Cavalier		errorOut(e_specify_version);
3069d9af368SFrançois Revol	}
3078eff0073SAxel Dörfler
3088eff0073SAxel Dörfler	// reset version infos
3098eff0073SAxel Dörfler
3108eff0073SAxel Dörfler	version_info systemVersion, appVersion;
3118eff0073SAxel Dörfler	memset(&systemVersion, 0, sizeof(version_info));
3128eff0073SAxel Dörfler	memset(&appVersion, 0, sizeof(version_info));
3138eff0073SAxel Dörfler
3148eff0073SAxel Dörfler	// process arguments
3158eff0073SAxel Dörfler
3168eff0073SAxel Dörfler	processing_mode mode;
3178eff0073SAxel Dörfler	arg_needed argNeeded;
3188eff0073SAxel Dörfler	bool systemModified, appModified;
3198eff0073SAxel Dörfler
3208eff0073SAxel Dörfler	parse(systemModified, appModified, argNeeded, mode, systemVersion,
3218eff0073SAxel Dörfler		appVersion, argc, argv);
3228eff0073SAxel Dörfler
3238eff0073SAxel Dörfler	// write back changes
3248eff0073SAxel Dörfler
3258eff0073SAxel Dörfler	BFile file;
3268eff0073SAxel Dörfler	status_t status = file.SetTo(argv[1], B_READ_WRITE);
3278eff0073SAxel Dörfler	if (status != B_OK)
3288eff0073SAxel Dörfler		errorOut(status, argv[1], false);
3298eff0073SAxel Dörfler
3308eff0073SAxel Dörfler	BAppFileInfo info;
3318eff0073SAxel Dörfler	status = info.SetTo(&file);
3328eff0073SAxel Dörfler	if (status != B_OK)
3338eff0073SAxel Dörfler		errorOut(status, argv[1], false);
3348eff0073SAxel Dörfler
3358c31a369SAxel Dörfler	if (systemModified ^ appModified) {
3368c31a369SAxel Dörfler		// clear out other app info if not present - this works around a
3378c31a369SAxel Dörfler		// bug in BeOS, see bug #681.
3388c31a369SAxel Dörfler		version_kind kind = systemModified ? B_APP_VERSION_KIND : B_SYSTEM_VERSION_KIND;
3398c31a369SAxel Dörfler		version_info clean;
3408c31a369SAxel Dörfler
3418c31a369SAxel Dörfler		if (info.GetVersionInfo(&clean, kind) != B_OK) {
3428c31a369SAxel Dörfler			memset(&clean, 0, sizeof(version_info));
3438c31a369SAxel Dörfler			info.SetVersionInfo(&clean, kind);
3448c31a369SAxel Dörfler		}
3458c31a369SAxel Dörfler	}
3468c31a369SAxel Dörfler
3478eff0073SAxel Dörfler	if (appModified) {
3488eff0073SAxel Dörfler		status = info.SetVersionInfo(&appVersion, B_APP_VERSION_KIND);
3498eff0073SAxel Dörfler		if (status < B_OK)
3508eff0073SAxel Dörfler			errorOut(status, NULL, false);
3519d9af368SFrançois Revol	}
3528eff0073SAxel Dörfler
3538eff0073SAxel Dörfler	if (systemModified) {
354a309b7c3SAugustin Cavalier		status = info.SetVersionInfo(&systemVersion, B_SYSTEM_VERSION_KIND);
3558eff0073SAxel Dörfler		if (status < B_OK)
3568eff0073SAxel Dörfler			errorOut(status, NULL, false);
357a309b7c3SAugustin Cavalier	}
3588eff0073SAxel Dörfler
3599d9af368SFrançois Revol	return 0;
3609d9af368SFrançois Revol}
3619d9af368SFrançois Revol
362