1/*
2 * Copyright 2002-2007, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Ryan Fleet
7 *		Vasilis Kaoutsis
8 */
9
10
11#include <Application.h>
12#include <AppFileInfo.h>
13
14#include <stdio.h>
15#include <string.h>
16
17
18void
19usage()
20{
21	printf("usage: version [OPTION] FILENAME [FILENAME2, ...]\n"
22		"Returns the version of a file.\n\n"
23		"        -h, --help              this usage message\n"
24		"        -l, --long              print long version information of FILENAME\n"
25		"        -n, --numerical         print in numerical mode\n"
26		"                                (Major miDdle miNor Variety Internal)\n"
27		"        -s, --system            print system version instead of app version\n"
28		"        --version               print version information for this command\n");
29}
30
31
32status_t
33get_version(const char *filename, version_kind kind, bool longFlag, bool numericalFlag)
34{
35	BFile file(filename, O_RDONLY);
36	if (file.InitCheck() != B_OK) {
37		printf("Couldn't get file info!\n");
38		return B_FILE_ERROR;
39	}
40
41	BAppFileInfo info(&file);
42	if (info.InitCheck() != B_OK) {
43		printf("Couldn't get file info!\n");
44		return B_FILE_ERROR;
45	}
46
47	version_info version;
48	if (info.GetVersionInfo(&version, kind) != B_OK) {
49		printf("Version unknown!\n");
50		return B_ERROR;
51	}
52
53	if (longFlag) {
54		printf("%s\n", version.long_info);
55		return B_OK;
56	}
57
58	if (numericalFlag) {
59		printf("%" B_PRIu32 " ", version.major);
60		printf("%" B_PRIu32 " ", version.middle);
61		printf("%" B_PRIu32 " ", version.minor);
62
63		switch (version.variety) {
64			case B_DEVELOPMENT_VERSION:
65				printf("d ");
66				break;
67
68			case B_ALPHA_VERSION:
69				printf("a ");
70				break;
71
72			case B_BETA_VERSION:
73				printf("b ");
74				break;
75
76			case B_GAMMA_VERSION:
77				printf("g ");
78				break;
79
80			case B_GOLDEN_MASTER_VERSION:
81				printf("gm ");
82				break;
83
84			case B_FINAL_VERSION:
85				printf("f ");
86				break;
87		}
88
89		printf("%" B_PRIu32 "\n", version.internal);
90		return B_OK;
91	}
92
93	printf("%s\n", version.short_info);
94	return B_OK;
95}
96
97
98/*!
99	determines whether  \a string1 contains at least one or more of the characters
100	of \a string2 but none of which \a string2 doesn't contain.
101
102	examples:
103	true == ("hel" == "help"); true == ("help" == "help"); true == ("h" == "help");
104	false == ("held" == "help"); false == ("helped" == "help");
105*/
106bool
107str_less_equal(const char *str1, const char *str2)
108{
109	char *ptr1 = const_cast<char*>(str1);
110	char *ptr2 = const_cast<char*>(str2);
111
112	while (*ptr1 != '\0') {
113		if (*ptr1 != *ptr2)
114			return false;
115		++ptr1;
116		++ptr2;
117	}
118	return true;
119}
120
121
122int
123main(int argc, char *argv[])
124{
125	BApplication app("application/x.vnd.Haiku-version");
126	version_kind kind = B_APP_VERSION_KIND;
127	bool longFlag = false;
128	bool numericalFlag = false;
129	int i;
130
131	if (argc < 2) {
132		usage();
133		return 0;
134	}
135
136	for (i = 1; i < argc; ++i) {
137		if (argv[i][0] == '-') {
138			char *ptr = argv[i];
139			++ptr;
140
141			if (*ptr == '-') {
142				bool lessEqual = false;
143				++ptr;
144
145				if (*ptr == 'h') {
146					lessEqual = str_less_equal(ptr, "help");
147					if (lessEqual) {
148						usage();
149						return 0;
150					}
151				} else if (*ptr == 'l') {
152					lessEqual = str_less_equal(ptr, "long");
153					if (lessEqual)
154						longFlag = true;
155				} else if (*ptr == 'n') {
156					lessEqual = str_less_equal(ptr, "numerical");
157					if (lessEqual)
158						numericalFlag = true;
159				} else if (*ptr == 's') {
160					lessEqual = str_less_equal(ptr, "system");
161					if (lessEqual)
162						kind = B_SYSTEM_VERSION_KIND;
163				} else if (*ptr == 'v') {
164					lessEqual = str_less_equal(ptr, "version");
165					if (lessEqual) {
166						get_version(argv[0], B_APP_VERSION_KIND, false, false);
167						return 0;
168					}
169				}
170
171				if (!lessEqual)
172					printf("%s unrecognized option `%s'\n", argv[0], argv[i]);
173			} else {
174				while (*ptr != '\0') {
175					if (*ptr == 'h') {
176						usage();
177						return 0;
178					} else if (*ptr == 's')
179						kind = B_SYSTEM_VERSION_KIND;
180					else if (*ptr == 'l')
181						longFlag = true;
182					else if (*ptr == 'n')
183						numericalFlag = true;
184					else {
185						printf("%s: invalid option -- %c\n", argv[0], *ptr);
186						return 1;
187					}
188
189					if (argc < 3) {
190						printf("%s: missing FILENAME(S) \n", argv[0]);
191						return 1;
192					}
193
194					++ptr;
195				}
196			}
197		}
198	}
199
200	for (i = 1; i < argc; ++i) {
201		if (argv[i][0] != '-'
202			&& get_version(argv[i], kind, longFlag, numericalFlag) != B_OK)
203			return 1;
204	}
205
206	return 0;
207}
208