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
usage()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
convertVariety(const char * str)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
errorToString(BString & output,status_t error,const char * appName=NULL)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
errorOut(status_t error,const char * appName=NULL,bool showUsage=true)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
parse(bool & systemModified,bool & appModified,arg_needed & argNeeded,processing_mode & mode,version_info & systemVersion,version_info & appVersion,int argc,char * argv[])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
main(int argc,char * argv[])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