workbench/classes/zune: Compile fixed for AROS m68k
[AROS.git] / workbench / c / Version.c
blob7394ff7df16e7242937e67436605bb5f184f4e01
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Version CLI command
6 Lang: english
7 */
9 /******************************************************************************
11 NAME
13 Version [<library|device|file>] [<version #>] [<revision #>] [FILE] [FULL] [RES]
15 SYNOPSIS
17 NAME/M,MD5SUM/S,VERSION/N,REVISION/N,FILE/S,FULL/S,RES/S
19 LOCATION
23 FUNCTION
25 Prints or checks the version and revision information of a file, library or device.
27 INPUTS
29 NAME -- name of file, library or device to check. If not given it
30 prints version and revision of Kickstart.
31 MD5SUM -- #FIXME what is that?
32 VERSION -- checks for version and returns error code 5 (warn) if the
33 version of the file is lower.
34 REVISION -- checks for revision and returns error code 5 (warn) if the
35 revision of the file is lower.
36 FILE -- reads from file and ignores currently loaded libraries and devices
37 FULL -- prints additional information
38 RES -- gets version of resident commands
40 RESULT
42 NOTES
44 EXAMPLE
46 BUGS
48 SEE ALSO
50 INTERNALS
52 HISTORY
54 ******************************************************************************/
56 #include <aros/arosbase.h>
57 #include <aros/config.h>
58 #include <aros/inquire.h>
59 #include <proto/aros.h>
61 #define ENABLE_RT 1
62 #include <aros/rt.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <stdio.h>
67 #include <ctype.h>
68 #include <proto/exec.h>
69 #include <exec/execbase.h>
70 #include <exec/libraries.h>
71 #include <exec/memory.h>
72 #include <exec/types.h>
73 #include <exec/resident.h>
74 #include <proto/dos.h>
75 #include <proto/utility.h>
76 #include <dos/datetime.h>
77 #include <dos/dos.h>
78 #include <dos/dosextens.h>
80 /*===[md5.h]==============================================================*/
82 /* Data structure for MD5 (Message-Digest) computation */
83 typedef struct {
84 ULONG buf[4]; /* scratch buffer */
85 ULONG i[2]; /* number of _bits_ handled mod 2^64 */
86 unsigned char in[64]; /* input buffer */
87 } MD5_CTX;
89 void MD5Init(MD5_CTX *mdContext);
90 void MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);
91 void MD5Final(unsigned char digest[16], MD5_CTX *mdContext);
93 /*==[md5.c]===============================================================*/
96 * Used in 'version' as is, just removed the #include "ambient.h"
98 * Harry Sintonen <sintonen@iki.fi>
102 * Ambient - the ultimate desktop
103 * ------------------------------
104 * (c) 2001-2003 by David Gerber <zapek@meanmachine.ch>
105 * All Rights Reserved
107 * $Id$
110 //#include "ambient.h"
111 //#include <exec/types.h>
114 ***********************************************************************
115 ** md5.c -- the source code for MD5 routines **
116 ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
117 ** Created: 2/17/90 RLR **
118 ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
119 ***********************************************************************
123 * Edited 7 May 93 by CP to change the interface to match that
124 * of the MD5 routines in RSAREF. Due to this alteration, this
125 * code is "derived from the RSA Data Security, Inc. MD5 Message-
126 * Digest Algorithm". (See below.)
130 ***********************************************************************
131 ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
132 ** **
133 ** License to copy and use this software is granted provided that **
134 ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
135 ** Digest Algorithm" in all material mentioning or referencing this **
136 ** software or this function. **
137 ** **
138 ** License is also granted to make and use derivative works **
139 ** provided that such works are identified as "derived from the RSA **
140 ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
141 ** material mentioning or referencing the derived work. **
142 ** **
143 ** RSA Data Security, Inc. makes no representations concerning **
144 ** either the merchantability of this software or the suitability **
145 ** of this software for any particular purpose. It is provided "as **
146 ** is" without express or implied warranty of any kind. **
147 ** **
148 ** These notices must be retained in any copies of any part of this **
149 ** documentation and/or software. **
150 ***********************************************************************
153 //#include "md5.h"
156 ***********************************************************************
157 ** Message-digest routines: **
158 ** To form the message digest for a message M **
159 ** (1) Initialize a context buffer mdContext using MD5Init **
160 ** (2) Call MD5Update on mdContext and M **
161 ** (3) Call MD5Final on mdContext **
162 ** The message digest is now in the bugffer passed to MD5Final **
163 ***********************************************************************
166 static unsigned char PADDING[64] = {
167 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
177 /* F, G, H and I are basic MD5 functions */
178 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
179 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
180 #define H(x, y, z) ((x) ^ (y) ^ (z))
181 #define I(x, y, z) ((y) ^ ((x) | (~z)))
183 /* ROTATE_LEFT rotates x left n bits */
184 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
186 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
187 /* Rotation is separate from addition to prevent recomputation */
188 #define FF(a, b, c, d, x, s, ac) \
189 {(a) += F ((b), (c), (d)) + (x) + (ULONG)(ac); \
190 (a) = ROTATE_LEFT ((a), (s)); \
191 (a) += (b); \
193 #define GG(a, b, c, d, x, s, ac) \
194 {(a) += G ((b), (c), (d)) + (x) + (ULONG)(ac); \
195 (a) = ROTATE_LEFT ((a), (s)); \
196 (a) += (b); \
198 #define HH(a, b, c, d, x, s, ac) \
199 {(a) += H ((b), (c), (d)) + (x) + (ULONG)(ac); \
200 (a) = ROTATE_LEFT ((a), (s)); \
201 (a) += (b); \
203 #define II(a, b, c, d, x, s, ac) \
204 {(a) += I ((b), (c), (d)) + (x) + (ULONG)(ac); \
205 (a) = ROTATE_LEFT ((a), (s)); \
206 (a) += (b); \
209 static void Transform(register ULONG *buf,register ULONG *in);
211 /* The routine MD5Init initializes the message-digest context
212 mdContext. All fields are set to zero.
214 void MD5Init ( MD5_CTX *mdContext)
216 mdContext->i[0] = mdContext->i[1] = (ULONG)0;
218 /* Load magic initialization constants.
220 mdContext->buf[0] = (ULONG)0x67452301L;
221 mdContext->buf[1] = (ULONG)0xefcdab89L;
222 mdContext->buf[2] = (ULONG)0x98badcfeL;
223 mdContext->buf[3] = (ULONG)0x10325476L;
226 /* The routine MD5Update updates the message-digest context to
227 account for the presence of each of the characters inBuf[0..inLen-1]
228 in the message whose digest is being computed.
230 void MD5Update (MD5_CTX *mdContext, unsigned char *inBuf,
231 unsigned int inLen)
233 register int i, ii;
234 int mdi;
235 ULONG in[16];
237 /* compute number of bytes mod 64 */
238 mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
240 /* update number of bits */
241 if ((mdContext->i[0] + ((ULONG)inLen << 3)) < mdContext->i[0])
242 mdContext->i[1]++;
243 mdContext->i[0] += ((ULONG)inLen << 3);
244 mdContext->i[1] += ((ULONG)inLen >> 29);
246 while (inLen--)
248 /* add new character to buffer, increment mdi */
249 mdContext->in[mdi++] = *inBuf++;
251 /* transform if necessary */
252 if (mdi == 0x40)
254 for (i = 0, ii = 0; i < 16; i++, ii += 4)
255 in[i] = (((ULONG)mdContext->in[ii+3]) << 24) |
256 (((ULONG)mdContext->in[ii+2]) << 16) |
257 (((ULONG)mdContext->in[ii+1]) << 8) |
258 ((ULONG)mdContext->in[ii]);
259 Transform (mdContext->buf, in);
260 mdi = 0;
265 /* The routine MD5Final terminates the message-digest computation and
266 ends with the desired message digest in mdContext->digest[0...15].
268 void MD5Final (unsigned char digest[16], MD5_CTX *mdContext)
270 ULONG in[16];
271 int mdi;
272 unsigned int i, ii;
273 unsigned int padLen;
275 /* save number of bits */
276 in[14] = mdContext->i[0];
277 in[15] = mdContext->i[1];
279 /* compute number of bytes mod 64 */
280 mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
282 /* pad out to 56 mod 64 */
283 padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
284 MD5Update (mdContext, PADDING, padLen);
286 /* append length in bits and transform */
287 for (i = 0, ii = 0; i < 14; i++, ii += 4)
288 in[i] = (((ULONG)mdContext->in[ii+3]) << 24) |
289 (((ULONG)mdContext->in[ii+2]) << 16) |
290 (((ULONG)mdContext->in[ii+1]) << 8) |
291 ((ULONG)mdContext->in[ii]);
292 Transform (mdContext->buf, in);
294 /* store buffer in digest */
295 for (i = 0, ii = 0; i < 4; i++, ii += 4)
297 digest[ii] = (unsigned char) (mdContext->buf[i] & 0xFF);
298 digest[ii+1] = (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
299 digest[ii+2] = (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
300 digest[ii+3] = (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
304 /* Basic MD5 step. Transforms buf based on in. Note that if the Mysterious
305 Constants are arranged backwards in little-endian order and decrypted with
306 the DES they produce OCCULT MESSAGES!
308 void Transform(register ULONG *buf,register ULONG *in)
310 register ULONG a = buf[0], b = buf[1], c = buf[2], d = buf[3];
312 /* Round 1 */
313 #define S11 7
314 #define S12 12
315 #define S13 17
316 #define S14 22
317 FF ( a, b, c, d, in[ 0], S11, 0xD76AA478L); /* 1 */
318 FF ( d, a, b, c, in[ 1], S12, 0xE8C7B756L); /* 2 */
319 FF ( c, d, a, b, in[ 2], S13, 0x242070DBL); /* 3 */
320 FF ( b, c, d, a, in[ 3], S14, 0xC1BDCEEEL); /* 4 */
321 FF ( a, b, c, d, in[ 4], S11, 0xF57C0FAFL); /* 5 */
322 FF ( d, a, b, c, in[ 5], S12, 0x4787C62AL); /* 6 */
323 FF ( c, d, a, b, in[ 6], S13, 0xA8304613L); /* 7 */
324 FF ( b, c, d, a, in[ 7], S14, 0xFD469501L); /* 8 */
325 FF ( a, b, c, d, in[ 8], S11, 0x698098D8L); /* 9 */
326 FF ( d, a, b, c, in[ 9], S12, 0x8B44F7AFL); /* 10 */
327 FF ( c, d, a, b, in[10], S13, 0xFFFF5BB1L); /* 11 */
328 FF ( b, c, d, a, in[11], S14, 0x895CD7BEL); /* 12 */
329 FF ( a, b, c, d, in[12], S11, 0x6B901122L); /* 13 */
330 FF ( d, a, b, c, in[13], S12, 0xFD987193L); /* 14 */
331 FF ( c, d, a, b, in[14], S13, 0xA679438EL); /* 15 */
332 FF ( b, c, d, a, in[15], S14, 0x49B40821L); /* 16 */
334 /* Round 2 */
335 #define S21 5
336 #define S22 9
337 #define S23 14
338 #define S24 20
339 GG ( a, b, c, d, in[ 1], S21, 0xF61E2562L); /* 17 */
340 GG ( d, a, b, c, in[ 6], S22, 0xC040B340L); /* 18 */
341 GG ( c, d, a, b, in[11], S23, 0x265E5A51L); /* 19 */
342 GG ( b, c, d, a, in[ 0], S24, 0xE9B6C7AAL); /* 20 */
343 GG ( a, b, c, d, in[ 5], S21, 0xD62F105DL); /* 21 */
344 GG ( d, a, b, c, in[10], S22, 0x02441453L); /* 22 */
345 GG ( c, d, a, b, in[15], S23, 0xD8A1E681L); /* 23 */
346 GG ( b, c, d, a, in[ 4], S24, 0xE7D3FBC8L); /* 24 */
347 GG ( a, b, c, d, in[ 9], S21, 0x21E1CDE6L); /* 25 */
348 GG ( d, a, b, c, in[14], S22, 0xC33707D6L); /* 26 */
349 GG ( c, d, a, b, in[ 3], S23, 0xF4D50D87L); /* 27 */
350 GG ( b, c, d, a, in[ 8], S24, 0x455A14EDL); /* 28 */
351 GG ( a, b, c, d, in[13], S21, 0xA9E3E905L); /* 29 */
352 GG ( d, a, b, c, in[ 2], S22, 0xFCEFA3F8L); /* 30 */
353 GG ( c, d, a, b, in[ 7], S23, 0x676F02D9L); /* 31 */
354 GG ( b, c, d, a, in[12], S24, 0x8D2A4C8AL); /* 32 */
356 /* Round 3 */
357 #define S31 4
358 #define S32 11
359 #define S33 16
360 #define S34 23
361 HH ( a, b, c, d, in[ 5], S31, 0xFFFA3942L); /* 33 */
362 HH ( d, a, b, c, in[ 8], S32, 0x8771F681L); /* 34 */
363 HH ( c, d, a, b, in[11], S33, 0x6D9D6122L); /* 35 */
364 HH ( b, c, d, a, in[14], S34, 0xFDE5380CL); /* 36 */
365 HH ( a, b, c, d, in[ 1], S31, 0xA4BEEA44L); /* 37 */
366 HH ( d, a, b, c, in[ 4], S32, 0x4BDECFA9L); /* 38 */
367 HH ( c, d, a, b, in[ 7], S33, 0xF6BB4B60L); /* 39 */
368 HH ( b, c, d, a, in[10], S34, 0xBEBFBC70L); /* 40 */
369 HH ( a, b, c, d, in[13], S31, 0x289B7EC6L); /* 41 */
370 HH ( d, a, b, c, in[ 0], S32, 0xEAA127FAL); /* 42 */
371 HH ( c, d, a, b, in[ 3], S33, 0xD4EF3085L); /* 43 */
372 HH ( b, c, d, a, in[ 6], S34, 0x04881D05L); /* 44 */
373 HH ( a, b, c, d, in[ 9], S31, 0xD9D4D039L); /* 45 */
374 HH ( d, a, b, c, in[12], S32, 0xE6DB99E5L); /* 46 */
375 HH ( c, d, a, b, in[15], S33, 0x1FA27CF8L); /* 47 */
376 HH ( b, c, d, a, in[ 2], S34, 0xC4AC5665L); /* 48 */
378 /* Round 4 */
379 #define S41 6
380 #define S42 10
381 #define S43 15
382 #define S44 21
383 II ( a, b, c, d, in[ 0], S41, 0xF4292244L); /* 49 */
384 II ( d, a, b, c, in[ 7], S42, 0x432AFF97L); /* 50 */
385 II ( c, d, a, b, in[14], S43, 0xAB9423A7L); /* 51 */
386 II ( b, c, d, a, in[ 5], S44, 0xFC93A039L); /* 52 */
387 II ( a, b, c, d, in[12], S41, 0x655B59C3L); /* 53 */
388 II ( d, a, b, c, in[ 3], S42, 0x8F0CCC92L); /* 54 */
389 II ( c, d, a, b, in[10], S43, 0xFFEFF47DL); /* 55 */
390 II ( b, c, d, a, in[ 1], S44, 0x85845DD1L); /* 56 */
391 II ( a, b, c, d, in[ 8], S41, 0x6FA87E4FL); /* 57 */
392 II ( d, a, b, c, in[15], S42, 0xFE2CE6E0L); /* 58 */
393 II ( c, d, a, b, in[ 6], S43, 0xA3014314L); /* 59 */
394 II ( b, c, d, a, in[13], S44, 0x4E0811A1L); /* 60 */
395 II ( a, b, c, d, in[ 4], S41, 0xF7537E82L); /* 61 */
396 II ( d, a, b, c, in[11], S42, 0xBD3AF235L); /* 62 */
397 II ( c, d, a, b, in[ 2], S43, 0x2AD7D2BBL); /* 63 */
398 II ( b, c, d, a, in[ 9], S44, 0xEB86D391L); /* 64 */
400 buf[0] += a;
401 buf[1] += b;
402 buf[2] += c;
403 buf[3] += d;
406 /*==[end md5.c]============================================================*/
409 const TEXT version[] = "$VER: Version 42.1 (12.11.2006)\n";
411 static const char ERROR_HEADER[] = "Version";
413 #define TEMPLATE "NAME/M,MD5SUM/S,VERSION/N,REVISION/N,FILE/S,FULL/S,RES/S"
414 struct
416 CONST_STRPTR *arg_name;
417 IPTR arg_md5sum;
418 LONG *arg_version;
419 LONG *arg_revision;
420 IPTR arg_file;
421 IPTR arg_full;
422 IPTR arg_res;
424 args;
426 LONG mversion, mrevision;
428 struct
430 STRPTR pv_name;
431 ULONG pv_flags;
432 LONG pv_version;
433 LONG pv_revision;
434 //LONG pv_days;
435 STRPTR pv_vername;
436 STRPTR pv_revname;
437 STRPTR pv_datestr;
438 STRPTR pv_extralf;
439 STRPTR pv_extrastr;
440 UBYTE pv_md5sum[16];
442 parsedver = { NULL, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, {0}};
444 #define PVF_MD5SUM (1 << 0)
445 #define PVF_NOVERSION (1 << 1)
447 static
448 int makeverstring(CONST_STRPTR name);
449 static
450 void printverstring(void);
451 static
452 void freeverstring(void);
453 static
454 int makesysver(void);
455 static
456 int cmpargsparsed(void);
459 /**************************** support functions ************************/
461 /* Duplicate string, by given length or -1 for full length
463 static
464 STRPTR dupstr(CONST_STRPTR buffer, LONG len)
466 STRPTR ret = NULL;
468 if (buffer)
470 if (len == -1)
471 len = strlen(buffer);
473 ret = AllocVec(len + 1, MEMF_ANY);
474 if (ret)
476 CopyMem((STRPTR) buffer, ret, len);
477 ret[len] = '\0';
481 return ret;
485 static
486 inline int myisspace(int c)
488 return (c == ' ' || c == '\t');
492 /* Return a pointer to a string, stripped by all leading whitespace characters
493 * (SPACE, TAB).
495 static
496 STRPTR skipwhites(CONST_STRPTR buffer)
498 for (;; buffer++)
500 if (buffer[0] == '\0' || !isspace(buffer[0]))
502 return (STRPTR) buffer;
508 /* Return a pointer to a string, stripped by all leading space characters
509 * (SPACE).
511 static
512 STRPTR skipspaces(CONST_STRPTR buffer)
514 for (;; buffer++)
516 if (buffer[0] == '\0' || buffer[0] != ' ')
518 return (STRPTR) buffer;
524 /* Strip all whitespace-characters from the end of a string. Note that the
525 * buffer passed in will be modified!
527 static
528 void stripwhites(STRPTR buffer)
530 int len = strlen(buffer);
532 while (len > 0)
534 if (!isspace(buffer[len-1]))
536 buffer[len] = '\0';
537 return;
539 len--;
541 buffer[len] = '\0';
545 /* Searches for a given string in a file and stores up to *lenptr characters
546 * into the buffer beginning with the first character after the given string.
548 static
549 int findinfile(BPTR file, CONST_STRPTR string, STRPTR buffer, int *lenptr, unsigned char digest[16])
551 int error = RETURN_OK;
552 int buflen = *lenptr, len = 0, pos, stringlen;
553 BOOL ready = FALSE;
554 MD5_CTX md5ctx;
555 STRPTR bufpos;
556 STRPTR tmp;
558 tmp = AllocMem(buflen, MEMF_PUBLIC);
559 if (!tmp)
561 return RETURN_FAIL;
564 stringlen = strlen(string);
565 *lenptr = -1;
567 if (args.arg_md5sum)
569 MD5Init(&md5ctx);
572 bufpos = tmp;
573 while ((len = Read(file, &tmp[len], buflen - len)) > 0)
575 pos = 0;
577 if (args.arg_md5sum)
579 MD5Update(&md5ctx, bufpos, len);
582 if (ready)
584 /* If we get here we're scanning the rest of the file for md5sum. - Piru */
585 len = 0;
587 else
589 while ((len - pos) >= stringlen)
591 /* Compare the current buffer position with the supplied string. */
592 if (strncmp(&tmp[pos], string, stringlen) == 0)
594 /* It is equal! Now move the rest of the buffer to the top of
595 * the buffer and fill it up.
597 int findstrlen = len - pos;
599 memcpy(buffer, &tmp[pos + stringlen], findstrlen);
601 len = Read(file, &buffer[findstrlen], buflen - findstrlen);
602 if (len >= 0)
604 if (args.arg_md5sum)
606 MD5Update(&md5ctx, &buffer[findstrlen], len);
609 *lenptr = findstrlen + len;
611 else
613 error = RETURN_FAIL;
615 ready = TRUE;
616 break;
618 pos++;
620 /* Move the rest of the buffer that could not be compared (because it
621 * is smaller than the string to compare) to the top of the buffer.
623 if (!ready)
625 memmove(tmp, &tmp[len - stringlen], stringlen);
627 else
629 /* If we're not md5summing, stop file scanning now. - Piru */
630 if (!args.arg_md5sum)
632 break;
635 len = stringlen;
638 bufpos = &tmp[len];
641 FreeMem(tmp, buflen);
643 if (len == -1)
645 error = RETURN_FAIL;
648 if (args.arg_md5sum)
650 memset(digest, 0, 16);
651 MD5Final(digest, &md5ctx);
654 return error;
658 /*************************** parsing functions *************************/
660 /* Convert a date in the form DD.MM.YY or DD.MM.YYYY into a numerical
661 * value. Return FALSE, if buffer doesn't contain a valid date.
663 static
664 BOOL makedatefromstring(CONST_STRPTR *bufptr)
666 CONST_STRPTR buffer = *bufptr;
667 struct DateTime dt;
668 CONST_STRPTR headerstart, end;
669 STRPTR newbuf;
670 LONG res;
671 int len, i;
672 UBYTE c;
674 //if (isspace(buffer[0]))
675 // buffer++;
677 headerstart = buffer;
679 buffer = strchr(buffer, '(');
680 if (!buffer)
682 return FALSE;
684 buffer++;
685 end = strchr(buffer, ')');
686 if (!end)
688 return FALSE;
690 len = (int)(end - buffer);
691 newbuf = dupstr(buffer, len);
692 if (!newbuf)
694 return FALSE;
696 for (i = 0; i < len; i++)
698 c = newbuf[i];
700 if (c == '.' || c == '/')
701 newbuf[i] = '-';
702 else if (!isalnum(c))
704 end = buffer + i;
705 newbuf[i] = '\0';
706 break;
710 //Printf("date: \"%s\"\n", (LONG) newbuf);
712 dt.dat_Format = FORMAT_CDN;
713 dt.dat_Flags = 0;
714 dt.dat_StrDay = NULL;
715 dt.dat_StrDate = newbuf;
716 dt.dat_StrTime = NULL;
717 res = StrToDate(&dt);
718 if (!res)
720 dt.dat_Format = FORMAT_DOS;
721 res = StrToDate(&dt);
722 if (!res)
724 //Printf("StrToDate failed!\n");
725 FreeVec(newbuf);
726 return FALSE;
729 FreeVec(newbuf);
731 //parsedver.pv_days = dt.dat_Stamp.ds_Days;
733 parsedver.pv_datestr = AllocVec(buffer - headerstart + LEN_DATSTRING + 2, MEMF_ANY);
734 if (!parsedver.pv_datestr)
736 return FALSE;
739 dt.dat_Stamp.ds_Minute = 0;
740 dt.dat_Stamp.ds_Tick = 0;
742 dt.dat_StrDate = parsedver.pv_datestr + (buffer - headerstart);
743 dt.dat_Format = FORMAT_DEF;
744 if (!DateToStr(&dt))
746 //Printf("DateToStr failed!\n");
747 return FALSE;
750 CopyMem((STRPTR) headerstart, parsedver.pv_datestr, buffer - headerstart);
751 res = strlen(parsedver.pv_datestr);
752 parsedver.pv_datestr[res++] = ')';
753 parsedver.pv_datestr[res] = '\0';
755 *bufptr = end + 1;
757 return TRUE;
761 /* Check whether the given string contains a version in the form
762 * <version>.<revision> . If not return FALSE, otherwise fill in parsedver and
763 * return TRUE.
765 static
766 BOOL makeversionfromstring(CONST_STRPTR *bufptr)
768 LONG pos, ver, rev;
769 CONST_STRPTR buffer = *bufptr;
770 CONST_STRPTR verstart, revstart;
772 //Printf("makeversionfromstring: buffer \"%s\"\n", (LONG) buffer);
774 /* Do version */
776 verstart = buffer;
777 pos = StrToLong((STRPTR) buffer, &ver);
778 if (pos == -1)
780 return FALSE;
782 parsedver.pv_version = ver;
783 parsedver.pv_revision = -1;
785 parsedver.pv_vername = dupstr(verstart, pos);
786 if (!parsedver.pv_vername)
788 return FALSE;
791 /* Do revision */
793 buffer += pos;
794 revstart = buffer;
795 buffer = skipspaces(buffer); /* NOTE: skipspaces, not skipwhites! */
796 if (*buffer != '.')
798 *bufptr = buffer;
799 return TRUE;
802 buffer++;
803 pos = StrToLong((STRPTR) buffer, &rev);
804 if (pos == -1)
806 *bufptr = buffer;
807 return TRUE;
810 parsedver.pv_revision = rev;
812 /* calc the revision string len */
813 pos = buffer + pos - revstart;
814 parsedver.pv_revname = dupstr(revstart, pos);
815 if (!parsedver.pv_revname)
817 return FALSE;
820 *bufptr = revstart + pos;
822 return TRUE;
826 static
827 void printverstring(void)
829 if (args.arg_md5sum)
831 if (parsedver.pv_flags & PVF_MD5SUM)
833 #ifdef __AROS__
834 /* Endianess safe version */
836 Printf("%02lX%02lX%02lX%02lX"
837 "%02lX%02lX%02lX%02lX"
838 "%02lX%02lX%02lX%02lX"
839 "%02lX%02lX%02lX%02lX ",
840 parsedver.pv_md5sum[0],
841 parsedver.pv_md5sum[1],
842 parsedver.pv_md5sum[2],
843 parsedver.pv_md5sum[3],
844 parsedver.pv_md5sum[4],
845 parsedver.pv_md5sum[5],
846 parsedver.pv_md5sum[6],
847 parsedver.pv_md5sum[7],
848 parsedver.pv_md5sum[8],
849 parsedver.pv_md5sum[9],
850 parsedver.pv_md5sum[10],
851 parsedver.pv_md5sum[11],
852 parsedver.pv_md5sum[12],
853 parsedver.pv_md5sum[13],
854 parsedver.pv_md5sum[14],
855 parsedver.pv_md5sum[15]);
857 #else
858 VPrintf("%08lX%08lX%08lX%08lX ", parsedver.pv_md5sum);
859 #endif
861 else
863 /* "01234567012345670123456701234567: " */
864 PutStr("<no md5sum available> ");
868 if (parsedver.pv_flags & PVF_NOVERSION)
870 Printf("%s\n", (IPTR) parsedver.pv_name);
872 else
874 if (args.arg_full)
876 /* If md5sum output was there, avoid linefeed to allow parsing the output - Piru */
877 if (args.arg_md5sum)
879 parsedver.pv_extralf = " ";
882 Printf("%s%s%s%s%s%s%s\n",
883 (IPTR) parsedver.pv_name, (IPTR) (*parsedver.pv_name ? " " : ""),
884 (IPTR) parsedver.pv_vername, (IPTR) parsedver.pv_revname,
885 (IPTR) parsedver.pv_datestr,
886 parsedver.pv_extralf ? (IPTR) parsedver.pv_extralf : (IPTR) "\n",
887 parsedver.pv_extrastr ? (IPTR) parsedver.pv_extrastr : (IPTR) "");
889 else
891 Printf("%s%s%s%s\n",
892 (IPTR) parsedver.pv_name, (IPTR) (*parsedver.pv_name ? " " : ""),
893 (IPTR) parsedver.pv_vername, (IPTR) parsedver.pv_revname);
899 static
900 int makedata(CONST_STRPTR buffer, CONST_STRPTR ptr, int pos)
902 //Printf("makedata: buffer \"%s\" prt \"%s\"\n", (LONG) buffer, (LONG) ptr);
904 if (makeversionfromstring(&ptr))
906 CONST_STRPTR endp;
907 BOOL doskip;
909 /* It is! */
910 /* Copy the program-name into a buffer. */
911 parsedver.pv_name = dupstr(buffer, pos);
912 if (!parsedver.pv_name)
914 PrintFault(ERROR_NO_FREE_STORE, (STRPTR) ERROR_HEADER);
915 return RETURN_FAIL;
918 /* Now find the date */
919 //Printf("makedatafromstring: ptr #1: \"%s\"\n", (LONG) ptr);
920 doskip = strchr(ptr, '(') ? TRUE : FALSE;
921 (void) makedatefromstring(&ptr);
923 //Printf("makedatafromstring: ptr #2: \"%s\"\n", (LONG) ptr);
924 if (doskip)
925 ptr = skipspaces(ptr); /* NOTE: not skipwhites! */
926 for (endp = ptr; *endp != '\0' && *endp != '\r' && *endp != '\n'; endp++)
928 pos = endp - ptr;
929 if (pos)
931 parsedver.pv_extrastr = dupstr(ptr, pos);
932 if (!parsedver.pv_extrastr)
934 PrintFault(ERROR_NO_FREE_STORE, (STRPTR) ERROR_HEADER);
935 return RETURN_FAIL;
938 if (doskip)
939 parsedver.pv_extralf = "\n";
942 return 1;
945 return 0;
949 /* Retrieves version information from string. The data is stored in the
950 * global struct parsedver.pv_
953 static
954 int makedatafromstring(CONST_STRPTR buffer)
956 int error = RETURN_OK;
957 int pos = 0;
958 LONG add, dummy;
960 while (buffer[pos] && buffer[pos] != '\r' && buffer[pos] != '\n')
962 /* NOTE: Not isspace()! - Piru */
963 if (myisspace(buffer[pos]) &&
964 (add = StrToLong((STRPTR) buffer + pos + 1, &dummy)) != -1)
966 CONST_STRPTR ptr;
968 /* Found something, which looks like a version. Now check, if it
969 * really is.
972 //Printf("makedatafromstring: buffer + %ld: \"%s\"\n", pos, (LONG) buffer + pos);
974 ptr = buffer + pos + 1;
976 if (makedata(buffer, ptr, pos))
978 break;
981 pos++;
984 if (!buffer[pos] || buffer[pos] == '\r' || buffer[pos] == '\n')
986 CONST_STRPTR endp;
988 /* use the whatever is after ver tag as name */
989 for (endp = buffer; *endp != '\0' && *endp != '\r' && *endp != '\n'; endp++)
991 pos = endp - buffer;
993 parsedver.pv_name = dupstr(buffer, pos);
994 if (!parsedver.pv_name)
996 PrintFault(ERROR_NO_FREE_STORE, (STRPTR) ERROR_HEADER);
997 return RETURN_FAIL;
1001 /* Strip any whitespaces from the tail of the program-name.
1003 if (parsedver.pv_name)
1005 stripwhites(parsedver.pv_name);
1008 return error;
1012 /* Case-insensitive FindResident()
1014 static
1015 struct Resident *findresident(CONST_STRPTR name)
1017 struct Resident **rp;
1018 struct Resident *resident;
1020 rp = (struct Resident **) SysBase->ResModules;
1022 while ((resident = *rp++))
1024 #ifdef __mc68000__
1025 if (((LONG)resident) < 0)
1026 rp = (struct Resident **)((ULONG)resident & 0x7fffffff);
1027 #else
1028 if (((IPTR)resident) & 0x01)
1029 rp = (struct Resident **)((IPTR)resident & ~1);
1030 #endif
1031 else {
1032 if (!Stricmp(resident->rt_Name, (STRPTR) name))
1033 break;
1037 return resident;
1041 /* Case-insensitive FindName()
1043 static
1044 struct Node *findname(struct List *list, CONST_STRPTR name)
1046 struct Node *node;
1048 ForeachNode(list, node)
1050 if (!Stricmp(node->ln_Name, (STRPTR) name))
1052 return node;
1056 return NULL;
1060 /* Retrieve information from resident modules. Returns 0 for success.
1062 static
1063 int createresidentver(struct Resident *MyResident)
1065 STRPTR buffer = NULL, tmpbuffer;
1066 int error, pos = 0, foundver = FALSE;
1068 if (MyResident->rt_IdString)
1070 buffer = skipwhites(MyResident->rt_IdString);
1071 //Printf("createresidentver: buffer \"%s\"\n", (LONG) buffer);
1073 /* Locate version part */
1074 while (buffer[pos])
1076 LONG dummy;
1078 /* NOTE: Not isspace()! - Piru */
1079 if (myisspace(buffer[pos]) &&
1080 StrToLong(buffer + pos + 1, &dummy) != -1)
1082 buffer += pos;
1083 foundver = TRUE;
1084 break;
1086 pos++;
1088 //Printf("createresidentver: buffer: \"%s\"\n", (LONG) buffer);
1092 /* If could not find any version info, use the resident rt_Name */
1093 if (!foundver)
1094 buffer = "";
1096 //Printf("createresidentver: buffer: \"%s\"\n", (LONG) buffer);
1098 tmpbuffer = AllocVec(strlen(MyResident->rt_Name) + strlen(buffer) + 1, MEMF_ANY);
1099 if (!tmpbuffer)
1101 PrintFault(ERROR_NO_FREE_STORE, (STRPTR) ERROR_HEADER);
1102 return RETURN_FAIL;
1105 strcpy(tmpbuffer, MyResident->rt_Name);
1106 strcat(tmpbuffer, buffer);
1107 //Printf("createresidentver: tmpbuffer: \"%s\"\n", (LONG) tmpbuffer);
1108 error = makedatafromstring(tmpbuffer);
1110 FreeVec(tmpbuffer);
1112 return error;
1116 /* Retrieve version information from library. Returns 0 for success.
1118 static
1119 int createlibraryver(struct Library *MyLibrary)
1121 STRPTR buffer, tmpbuffer;
1122 int error, foundver = FALSE, pos;
1124 if (MyLibrary->lib_IdString)
1126 //Printf("createlibraryver: lib_IdString \"%s\"\n", (LONG) MyLibrary->lib_IdString);
1127 buffer = skipwhites(MyLibrary->lib_IdString);
1129 //Printf("createlibraryver: buffer \"%s\"\n", (LONG) buffer);
1131 /* Find full 'ver.rev' version info
1133 pos = 0;
1134 while (buffer[pos])
1136 LONG dummy, add;
1138 /* NOTE: Not isspace()! - Piru */
1139 if (myisspace(buffer[pos]) &&
1140 (add = StrToLong(buffer + pos + 1, &dummy)) != -1 &&
1141 buffer[pos + 1 + add] == '.')
1143 buffer += pos;
1144 pos = 0;
1145 foundver = TRUE;
1146 break;
1148 pos++;
1151 /* If could not find 'ver.rev', find any numeric */
1152 if (!foundver)
1154 pos = 0;
1155 while (buffer[pos])
1157 LONG dummy;
1159 /* NOTE: Not isspace()! - Piru */
1160 if (myisspace(buffer[pos]) &&
1161 StrToLong(buffer + pos + 1, &dummy) != -1)
1163 buffer += pos;
1164 pos = 0;
1165 foundver = TRUE;
1166 break;
1168 pos++;
1173 /* If could not find any version info, use the resident rt_Name */
1174 if (!foundver)
1176 buffer = "";
1177 error = RETURN_WARN;
1180 tmpbuffer = AllocVec(strlen(MyLibrary->lib_Node.ln_Name) + strlen(buffer) + 1, MEMF_ANY);
1181 if (!tmpbuffer)
1183 PrintFault(ERROR_NO_FREE_STORE, (STRPTR) ERROR_HEADER);
1184 return RETURN_FAIL;
1187 strcpy(tmpbuffer, MyLibrary->lib_Node.ln_Name);
1188 strcat(tmpbuffer, buffer);
1189 //Printf("createlibraryver: tmpbuffer: \"%s\"\n", (LONG) tmpbuffer);
1190 pos = makedatafromstring(tmpbuffer);
1191 if (pos > error)
1193 error = pos;
1196 FreeVec(tmpbuffer);
1198 return error;
1202 /* Create default strings
1204 static
1205 int createdefvers(CONST_STRPTR name)
1207 FreeVec(parsedver.pv_revname);
1208 FreeVec(parsedver.pv_vername);
1209 FreeVec(parsedver.pv_name);
1211 parsedver.pv_name = dupstr(name, -1);
1212 parsedver.pv_vername = AllocVec(14, MEMF_ANY);
1213 parsedver.pv_revname = AllocVec(15, MEMF_ANY);
1215 if (parsedver.pv_name &&
1216 parsedver.pv_vername &&
1217 parsedver.pv_revname)
1219 sprintf(parsedver.pv_vername, "%ld", parsedver.pv_version);
1220 sprintf(parsedver.pv_revname, ".%ld", parsedver.pv_revision);
1222 return RETURN_OK;
1225 return RETURN_FAIL;
1229 /* Create version info from named resident
1231 static
1232 int makeresidentver(CONST_STRPTR name)
1234 struct Resident *MyResident;
1235 int error = -1;
1237 if ((MyResident = findresident(name)))
1239 error = createresidentver(MyResident);
1240 if (error != RETURN_OK)
1242 /* get values from residenttag */
1243 parsedver.pv_version = MyResident->rt_Version;
1244 parsedver.pv_revision = -1;
1245 error = createdefvers(MyResident->rt_Name);
1249 return error;
1253 /* Create version info from named list node
1255 static
1256 int makeexeclistver(struct List *list, CONST_STRPTR name)
1258 struct Library *MyLibrary;
1259 int error = -1;
1261 Forbid();
1263 MyLibrary = (struct Library *) findname(list, name);
1264 if (MyLibrary)
1266 /* get values from library */
1267 ULONG ver = MyLibrary->lib_Version;
1268 ULONG rev = MyLibrary->lib_Revision;
1270 error = createlibraryver(MyLibrary);
1271 if (error != RETURN_OK ||
1272 parsedver.pv_version != ver ||
1273 parsedver.pv_revision != rev)
1275 /* special case where createlibraryrev was successful, but
1276 * version or revision don't match.
1278 if (error == RETURN_OK)
1280 /* If there is extrastr, make sure there's linefeed, too.
1282 if (parsedver.pv_extrastr)
1284 parsedver.pv_extralf = "\n";
1288 /* get values from library */
1289 parsedver.pv_version = ver;
1290 parsedver.pv_revision = rev;
1292 error = createdefvers(MyLibrary->lib_Node.ln_Name);
1296 Permit();
1298 return error;
1302 /* Find resident from seglist, return NULL if none found
1304 static
1305 struct Resident *FindLibResident(BPTR Segment)
1307 while (Segment)
1309 IPTR *MySegment;
1310 UWORD *MyBuffer;
1311 UWORD *EndBuffer;
1313 MySegment = (IPTR*) BADDR(Segment);
1314 MyBuffer = (UWORD*) &MySegment[1];
1315 EndBuffer = (UWORD*) &MySegment[(MySegment[-1] - sizeof(ULONG) * 4) / sizeof(ULONG)];
1317 while (MyBuffer < EndBuffer)
1319 struct Resident *MyResident;
1321 MyResident = (struct Resident*) MyBuffer;
1322 if (MyResident->rt_MatchWord == RTC_MATCHWORD &&
1323 MyResident->rt_MatchTag == MyResident)
1325 return MyResident;
1328 MyBuffer++;
1331 Segment =(BPTR) MySegment[0];
1334 SetIoErr(ERROR_OBJECT_NOT_FOUND);
1335 return NULL;
1339 /* Find $VER: tag from seglist, return NULL if none found
1340 Returns dupstr()d string or NULL.
1342 static
1343 STRPTR FindSegmentVER(BPTR Segment)
1345 while (Segment)
1347 ULONG *MySegment;
1348 CONST_STRPTR MyBuffer;
1349 CONST_STRPTR EndBuffer;
1350 CONST_STRPTR SegmentEnd;
1352 MySegment = (ULONG*) BADDR(Segment);
1353 MyBuffer = (CONST_STRPTR) &MySegment[1];
1354 SegmentEnd = ((CONST_STRPTR) MySegment) + MySegment[-1] - sizeof(ULONG) * 2;
1355 EndBuffer = SegmentEnd - 5;
1357 while (MyBuffer < EndBuffer)
1359 if (MyBuffer[0] == '$' &&
1360 MyBuffer[1] == 'V' &&
1361 MyBuffer[2] == 'E' &&
1362 MyBuffer[3] == 'R' &&
1363 MyBuffer[4] == ':')
1365 CONST_STRPTR EndPtr;
1367 MyBuffer += 5;
1368 /* Required because some smartass could end his $VER: tag
1369 * without '\0' in the segment to save space. - Piru
1371 for (EndPtr = MyBuffer; EndPtr < SegmentEnd && *EndPtr; EndPtr++)
1373 if (EndPtr - MyBuffer)
1375 return dupstr(MyBuffer, EndPtr - MyBuffer);
1379 MyBuffer++;
1382 Segment =(BPTR) MySegment[0];
1385 SetIoErr(ERROR_OBJECT_NOT_FOUND);
1386 return NULL;
1390 /* Create version info from named device
1392 static
1393 int makedevicever(CONST_STRPTR name)
1395 struct DevProc *MyDevProc;
1396 int error = -1;
1398 MyDevProc = GetDeviceProc((STRPTR) name, NULL);
1399 if (MyDevProc)
1401 if (MyDevProc->dvp_DevNode->dol_Type == DLT_DEVICE)
1403 #ifdef __AROS__
1404 #warning "FIXME: AROS specific version info for devices"
1405 error = RETURN_FAIL;
1406 #else
1407 BPTR SegList;
1409 SegList = MyDevProc->dvp_DevNode->dol_misc.dol_handler.dol_SegList;
1410 if (SegList)
1412 struct Resident *MyResident;
1414 MyResident = FindLibResident(SegList);
1415 if (MyResident)
1417 error = createresidentver(MyResident);
1419 else
1420 error = RETURN_FAIL;
1422 #endif
1424 FreeDeviceProc(MyDevProc);
1427 if (error != RETURN_OK && error != -1)
1429 Printf("Could not find version information for '%s'\n", name);
1432 return error;
1436 /* Retrieve version information from file. Return 0 for success.
1438 #define BUFFERSIZE (16384 + 1)
1439 static
1440 int makefilever(CONST_STRPTR name)
1442 BPTR file;
1443 int error; // = RETURN_OK;
1445 file = Open((STRPTR) name, MODE_OLDFILE);
1446 if (file)
1448 UBYTE *buffer;
1450 buffer = AllocMem(BUFFERSIZE, MEMF_PUBLIC);
1451 if (buffer)
1453 int len = BUFFERSIZE - 1;
1455 error = findinfile(file, "$VER:", buffer, &len, parsedver.pv_md5sum);
1456 if (error == RETURN_OK)
1458 parsedver.pv_flags |= PVF_MD5SUM;
1460 if (len >= 0)
1462 STRPTR startbuffer;
1464 buffer[len] = '\0';
1465 startbuffer = skipwhites(buffer);
1467 //Printf("startbuffer \"%s\"\n", startbuffer);
1468 error = makedatafromstring(startbuffer);
1470 else
1472 /* Try LoadSeg
1474 error = RETURN_ERROR;
1476 Close(file);
1478 file = LoadSeg((STRPTR) name);
1479 if (file)
1481 struct Resident *MyResident;
1483 MyResident = FindLibResident(file);
1484 if (MyResident /*&&
1485 (MyResident->rt_Type == NT_LIBRARY ||
1486 MyResident->rt_Type == NT_DEVICE)*/)
1488 error = createresidentver(MyResident);
1491 UnLoadSeg(file);
1493 file = BNULL;
1495 if (error != RETURN_OK)
1497 /* If user didn't ask for md5sum or we could not calculate it.
1499 if (!args.arg_md5sum || (!(parsedver.pv_flags & PVF_MD5SUM)))
1501 Printf("Could not find version information for '%s'\n", (IPTR) name);
1506 else
1508 PrintFault(IoErr(), (STRPTR) ERROR_HEADER);
1511 FreeMem(buffer, BUFFERSIZE);
1513 else
1515 error = RETURN_FAIL;
1516 PrintFault(IoErr(), (STRPTR) ERROR_HEADER);
1519 if (file)
1520 Close(file);
1522 else
1524 LONG ioerr = IoErr();
1526 if (ioerr == ERROR_OBJECT_NOT_FOUND ||
1527 ioerr == ERROR_OBJECT_WRONG_TYPE)
1529 error = -1;
1531 else
1533 PrintFault(IoErr(), (STRPTR) ERROR_HEADER);
1534 error = RETURN_FAIL;
1538 return error;
1542 static
1543 int makerescmdver(CONST_STRPTR name)
1545 int error = -1;
1546 struct Segment *segment;
1548 Forbid();
1550 segment = FindSegment((STRPTR) name, NULL, 0);
1551 if (!segment)
1553 segment = FindSegment((STRPTR) name, NULL, 1);
1556 if (segment)
1558 if (segment->seg_UC == CMD_INTERNAL ||
1559 segment->seg_UC == CMD_DISABLED)
1561 Permit();
1562 error = makeresidentver("shell");
1563 Forbid();
1565 else
1567 STRPTR buffer = FindSegmentVER(segment->seg_Seg);
1568 if (buffer)
1570 STRPTR startbuffer;
1572 startbuffer = skipwhites(buffer);
1574 //Printf("startbuffer \"%s\"\n", (LONG) startbuffer);
1575 error = makedatafromstring(startbuffer);
1577 FreeVec(buffer);
1582 Permit();
1584 return error;
1587 static
1588 int setvervar(CONST_STRPTR name, LONG ver, LONG rev)
1590 UBYTE buf[32];
1592 sprintf(buf, "%ld.%ld", (LONG) ver, (LONG) rev);
1594 return SetVar((STRPTR) name, buf, -1, GVF_LOCAL_ONLY | LV_VAR) ? RETURN_OK : -1;
1598 static
1599 int makekickversion(void)
1601 parsedver.pv_version = SysBase->LibNode.lib_Version;
1602 parsedver.pv_revision = SysBase->SoftVer;
1604 setvervar("Kickstart",
1605 parsedver.pv_version,
1606 parsedver.pv_revision);
1608 Printf("Kickstart %ld.%ld",
1609 (LONG) parsedver.pv_version, (LONG) parsedver.pv_revision);
1611 return RETURN_OK;
1615 static
1616 int makewbversion(void)
1618 int error = -1;
1619 struct Library *VersionBase;
1621 VersionBase = OpenLibrary("version.library", 0);
1622 if (VersionBase)
1624 error = makeexeclistver(&SysBase->LibList, "version.library");
1626 if (error == RETURN_OK)
1628 STRPTR newname = dupstr("Workbench", -1);
1629 if (newname)
1631 FreeVec(parsedver.pv_name);
1632 parsedver.pv_name = newname;
1634 setvervar("Workbench", parsedver.pv_version, parsedver.pv_revision);
1637 CloseLibrary(VersionBase);
1640 return error;
1644 static
1645 int makesysver(void)
1647 int error;
1649 error = makekickversion();
1650 if (error == RETURN_OK)
1652 error = makewbversion();
1654 if (error == RETURN_OK)
1656 PutStr(", ");
1658 else
1660 /* prevent silly errormsg if no version.library */
1661 PutStr("\n");
1662 error = RETURN_WARN;
1666 return error;
1670 /* Determine, by which means to get the version-string.
1672 static
1673 int makeverstring(CONST_STRPTR name)
1675 int error; // = RETURN_OK;
1676 BOOL volume = name[strlen(name) - 1] == ':';
1677 CONST_STRPTR filepart = FilePart(name);
1679 error = -1;
1681 if (!volume && !args.arg_file)
1683 if (*filepart)
1685 error = makeresidentver(filepart);
1686 if (error != RETURN_OK)
1689 /* Try libraries
1691 error = makeexeclistver(&SysBase->LibList, filepart);
1692 if (error != RETURN_OK)
1694 STRPTR namebuf;
1695 ULONG namelen = strlen(filepart);
1697 /* 12 is "MOSSYS:LIBS/" */
1698 if ((namebuf = AllocVec(12 + namelen + 4 + 1, MEMF_PUBLIC)))
1700 strcpy(namebuf, "LIBS:");
1701 strcat(namebuf, filepart);
1702 error = makefilever(namebuf);
1704 /* Try devices
1706 if (error != RETURN_OK)
1708 error = makeexeclistver(&SysBase->DeviceList, filepart);
1709 if (error != RETURN_OK)
1711 strcpy(namebuf, "DEVS:");
1712 strcat(namebuf, filepart);
1713 error = makefilever(namebuf);
1716 FreeVec(namebuf);
1723 if (!args.arg_res && error == -1)
1725 if (volume)
1727 error = makedevicever(name);
1729 else
1731 if (*filepart)
1733 error = makefilever(name);
1738 if (!args.arg_file && error == -1)
1740 error = makerescmdver(name);
1743 if (error)
1745 /* If user asked for md5sum, and we could calculate it, don't print error
1746 * but the md5sum + file.
1748 if (args.arg_md5sum && (parsedver.pv_flags & PVF_MD5SUM))
1750 parsedver.pv_name = dupstr(name, -1);
1751 parsedver.pv_flags |= PVF_NOVERSION;
1752 error = RETURN_OK;
1756 if (error == -1)
1758 PrintFault(ERROR_OBJECT_NOT_FOUND, (STRPTR) ERROR_HEADER);
1759 error = RETURN_FAIL;
1762 return error;
1766 static
1767 void freeverstring(void)
1769 parsedver.pv_flags = 0;
1770 parsedver.pv_version = 0;
1771 parsedver.pv_revision = 0;
1773 FreeVec(parsedver.pv_extrastr);
1774 parsedver.pv_extrastr = NULL;
1775 parsedver.pv_extralf = NULL;
1776 FreeVec(parsedver.pv_datestr);
1777 parsedver.pv_datestr = NULL;
1778 FreeVec(parsedver.pv_revname);
1779 parsedver.pv_revname = NULL;
1780 FreeVec(parsedver.pv_vername);
1781 parsedver.pv_vername = NULL;
1782 FreeVec(parsedver.pv_name);
1783 parsedver.pv_name = NULL;
1786 /* Compare the version given as argument with the version from the object.
1787 * Return RETURN_WARN, if args-v>object-v, otherwise return RETURN_OK.
1789 static
1790 int cmpargsparsed(void)
1792 if (args.arg_version)
1794 if (*(args.arg_version) > parsedver.pv_version)
1796 return RETURN_WARN;
1798 else if (*(args.arg_version) == parsedver.pv_version && args.arg_revision)
1800 if (*(args.arg_revision) > parsedver.pv_revision)
1802 return RETURN_WARN;
1806 else if (args.arg_revision)
1808 if (*(args.arg_revision) > parsedver.pv_revision)
1810 return RETURN_WARN;
1813 return RETURN_OK;
1816 /******************************* main program ****************************/
1818 int __nocommandline;
1820 int main (void)
1822 LONG error = RETURN_FAIL;
1824 struct RDArgs *rda;
1826 rda = ReadArgs(TEMPLATE, (IPTR *) &args, NULL);
1827 if (rda)
1829 if (!args.arg_name || !*args.arg_name)
1831 /* No args, make system version */
1832 error = makesysver();
1833 if (error == RETURN_OK)
1835 printverstring();
1836 if (parsedver.pv_flags & PVF_NOVERSION)
1838 error = RETURN_FAIL;
1840 if (error == RETURN_OK)
1842 error = cmpargsparsed();
1845 freeverstring();
1847 else
1849 CONST_STRPTR *name;
1850 BOOL multifile;
1851 #if 1
1852 /* Workaround for:
1853 * version file ver
1854 * version file ver rev
1856 if (!args.arg_version && !args.arg_revision)
1858 LONG narg = 1;
1859 while (args.arg_name[narg]) { narg++; }
1860 if (narg == 2 || narg == 3)
1862 if (StrToLong(args.arg_name[1], &mversion) > 0)
1864 args.arg_version = &mversion;
1865 args.arg_name[1] = args.arg_name[2];
1866 if (narg == 3)
1868 args.arg_name[2] = NULL;
1870 if (narg == 3)
1872 if (StrToLong(args.arg_name[1], &mrevision) > 0)
1874 args.arg_revision = &mrevision;
1875 args.arg_name[1] = NULL;
1881 #endif
1882 multifile = args.arg_name[1] != NULL;
1884 for (name = args.arg_name; *name; name++)
1886 error = makeverstring(*name);
1887 if (error == RETURN_OK)
1889 printverstring();
1891 if (!multifile)
1893 /* Single args, do compare stuff also */
1894 if (parsedver.pv_flags & PVF_NOVERSION)
1896 error = RETURN_FAIL;
1898 if (error == RETURN_OK)
1900 error = cmpargsparsed();
1904 freeverstring();
1909 FreeArgs(rda);
1911 else
1913 PrintFault(IoErr(), (STRPTR) ERROR_HEADER);
1914 error = RETURN_FAIL;
1917 RT_Exit();
1919 return(error);