2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
5 Desc: Version CLI command
9 /******************************************************************************
13 Version [<library|device|file>] [<version #>] [<revision #>] [FILE] [FULL] [RES]
17 NAME/M,MD5SUM/S,VERSION/N,REVISION/N,FILE/S,FULL/S,RES/S
25 Prints or checks the version and revision information of a file, library or device.
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
54 ******************************************************************************/
56 #include <aros/arosbase.h>
57 #include <aros/config.h>
58 #include <aros/inquire.h>
59 #include <proto/aros.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>
78 #include <dos/dosextens.h>
80 /*===[md5.h]==============================================================*/
82 /* Data structure for MD5 (Message-Digest) computation */
84 ULONG buf
[4]; /* scratch buffer */
85 ULONG i
[2]; /* number of _bits_ handled mod 2^64 */
86 unsigned char in
[64]; /* input buffer */
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
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. **
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. **
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. **
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. **
148 ** These notices must be retained in any copies of any part of this **
149 ** documentation and/or software. **
150 ***********************************************************************
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)); \
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)); \
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)); \
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)); \
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
,
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])
243 mdContext
->i
[0] += ((ULONG
)inLen
<< 3);
244 mdContext
->i
[1] += ((ULONG
)inLen
>> 29);
248 /* add new character to buffer, increment mdi */
249 mdContext
->in
[mdi
++] = *inBuf
++;
251 /* transform if necessary */
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
);
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
)
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];
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 */
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 */
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 */
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 */
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"
416 CONST_STRPTR
*arg_name
;
426 LONG mversion
, mrevision
;
442 parsedver
= { NULL
, 0, 0, 0, NULL
, NULL
, NULL
, NULL
, NULL
, {0}};
444 #define PVF_MD5SUM (1 << 0)
445 #define PVF_NOVERSION (1 << 1)
448 int makeverstring(CONST_STRPTR name
);
450 void printverstring(void);
452 void freeverstring(void);
454 int makesysver(void);
456 int cmpargsparsed(void);
459 /**************************** support functions ************************/
461 /* Duplicate string, by given length or -1 for full length
464 STRPTR
dupstr(CONST_STRPTR buffer
, LONG len
)
471 len
= strlen(buffer
);
473 ret
= AllocVec(len
+ 1, MEMF_ANY
);
476 CopyMem((STRPTR
) buffer
, ret
, len
);
486 inline int myisspace(int c
)
488 return (c
== ' ' || c
== '\t');
492 /* Return a pointer to a string, stripped by all leading whitespace characters
496 STRPTR
skipwhites(CONST_STRPTR 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
512 STRPTR
skipspaces(CONST_STRPTR 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!
528 void stripwhites(STRPTR buffer
)
530 int len
= strlen(buffer
);
534 if (!isspace(buffer
[len
-1]))
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.
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
;
558 tmp
= AllocMem(buflen
, MEMF_PUBLIC
);
564 stringlen
= strlen(string
);
573 while ((len
= Read(file
, &tmp
[len
], buflen
- len
)) > 0)
579 MD5Update(&md5ctx
, bufpos
, len
);
584 /* If we get here we're scanning the rest of the file for md5sum. - Piru */
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
);
606 MD5Update(&md5ctx
, &buffer
[findstrlen
], len
);
609 *lenptr
= findstrlen
+ len
;
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.
625 memmove(tmp
, &tmp
[len
- stringlen
], stringlen
);
629 /* If we're not md5summing, stop file scanning now. - Piru */
630 if (!args
.arg_md5sum
)
641 FreeMem(tmp
, buflen
);
650 memset(digest
, 0, 16);
651 MD5Final(digest
, &md5ctx
);
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.
664 BOOL
makedatefromstring(CONST_STRPTR
*bufptr
)
666 CONST_STRPTR buffer
= *bufptr
;
668 CONST_STRPTR headerstart
, end
;
674 //if (isspace(buffer[0]))
677 headerstart
= buffer
;
679 buffer
= strchr(buffer
, '(');
685 end
= strchr(buffer
, ')');
690 len
= (int)(end
- buffer
);
691 newbuf
= dupstr(buffer
, len
);
696 for (i
= 0; i
< len
; i
++)
700 if (c
== '.' || c
== '/')
702 else if (!isalnum(c
))
710 //Printf("date: \"%s\"\n", (LONG) newbuf);
712 dt
.dat_Format
= FORMAT_CDN
;
714 dt
.dat_StrDay
= NULL
;
715 dt
.dat_StrDate
= newbuf
;
716 dt
.dat_StrTime
= NULL
;
717 res
= StrToDate(&dt
);
720 dt
.dat_Format
= FORMAT_DOS
;
721 res
= StrToDate(&dt
);
724 //Printf("StrToDate failed!\n");
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
)
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
;
746 //Printf("DateToStr failed!\n");
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';
761 /* Check whether the given string contains a version in the form
762 * <version>.<revision> . If not return FALSE, otherwise fill in parsedver and
766 BOOL
makeversionfromstring(CONST_STRPTR
*bufptr
)
769 CONST_STRPTR buffer
= *bufptr
;
770 CONST_STRPTR verstart
, revstart
;
772 //Printf("makeversionfromstring: buffer \"%s\"\n", (LONG) buffer);
777 pos
= StrToLong((STRPTR
) buffer
, &ver
);
782 parsedver
.pv_version
= ver
;
783 parsedver
.pv_revision
= -1;
785 parsedver
.pv_vername
= dupstr(verstart
, pos
);
786 if (!parsedver
.pv_vername
)
795 buffer
= skipspaces(buffer
); /* NOTE: skipspaces, not skipwhites! */
803 pos
= StrToLong((STRPTR
) buffer
, &rev
);
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
)
820 *bufptr
= revstart
+ pos
;
827 void printverstring(void)
831 if (parsedver
.pv_flags
& PVF_MD5SUM
)
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]);
858 VPrintf("%08lX%08lX%08lX%08lX ", parsedver
.pv_md5sum
);
863 /* "01234567012345670123456701234567: " */
864 PutStr("<no md5sum available> ");
868 if (parsedver
.pv_flags
& PVF_NOVERSION
)
870 Printf("%s\n", (IPTR
) parsedver
.pv_name
);
876 /* If md5sum output was there, avoid linefeed to allow parsing the output - Piru */
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
) "");
892 (IPTR
) parsedver
.pv_name
, (IPTR
) (*parsedver
.pv_name
? " " : ""),
893 (IPTR
) parsedver
.pv_vername
, (IPTR
) parsedver
.pv_revname
);
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
))
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
);
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);
925 ptr
= skipspaces(ptr
); /* NOTE: not skipwhites! */
926 for (endp
= ptr
; *endp
!= '\0' && *endp
!= '\r' && *endp
!= '\n'; endp
++)
931 parsedver
.pv_extrastr
= dupstr(ptr
, pos
);
932 if (!parsedver
.pv_extrastr
)
934 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
939 parsedver
.pv_extralf
= "\n";
949 /* Retrieves version information from string. The data is stored in the
950 * global struct parsedver.pv_
954 int makedatafromstring(CONST_STRPTR buffer
)
956 int error
= RETURN_OK
;
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)
968 /* Found something, which looks like a version. Now check, if it
972 //Printf("makedatafromstring: buffer + %ld: \"%s\"\n", pos, (LONG) buffer + pos);
974 ptr
= buffer
+ pos
+ 1;
976 if (makedata(buffer
, ptr
, pos
))
984 if (!buffer
[pos
] || buffer
[pos
] == '\r' || buffer
[pos
] == '\n')
988 /* use the whatever is after ver tag as name */
989 for (endp
= buffer
; *endp
!= '\0' && *endp
!= '\r' && *endp
!= '\n'; endp
++)
993 parsedver
.pv_name
= dupstr(buffer
, pos
);
994 if (!parsedver
.pv_name
)
996 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1001 /* Strip any whitespaces from the tail of the program-name.
1003 if (parsedver
.pv_name
)
1005 stripwhites(parsedver
.pv_name
);
1012 /* Case-insensitive FindResident()
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
++))
1025 if (((LONG
)resident
) < 0)
1026 rp
= (struct Resident
**)((ULONG
)resident
& 0x7fffffff);
1028 if (((IPTR
)resident
) & 0x01)
1029 rp
= (struct Resident
**)((IPTR
)resident
& ~1);
1032 if (!Stricmp(resident
->rt_Name
, (STRPTR
) name
))
1041 /* Case-insensitive FindName()
1044 struct Node
*findname(struct List
*list
, CONST_STRPTR name
)
1048 ForeachNode(list
, node
)
1050 if (!Stricmp(node
->ln_Name
, (STRPTR
) name
))
1060 /* Retrieve information from resident modules. Returns 0 for success.
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 */
1078 /* NOTE: Not isspace()! - Piru */
1079 if (myisspace(buffer
[pos
]) &&
1080 StrToLong(buffer
+ pos
+ 1, &dummy
) != -1)
1088 //Printf("createresidentver: buffer: \"%s\"\n", (LONG) buffer);
1092 /* If could not find any version info, use the resident rt_Name */
1096 //Printf("createresidentver: buffer: \"%s\"\n", (LONG) buffer);
1098 tmpbuffer
= AllocVec(strlen(MyResident
->rt_Name
) + strlen(buffer
) + 1, MEMF_ANY
);
1101 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1105 strcpy(tmpbuffer
, MyResident
->rt_Name
);
1106 strcat(tmpbuffer
, buffer
);
1107 //Printf("createresidentver: tmpbuffer: \"%s\"\n", (LONG) tmpbuffer);
1108 error
= makedatafromstring(tmpbuffer
);
1116 /* Retrieve version information from library. Returns 0 for success.
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
1138 /* NOTE: Not isspace()! - Piru */
1139 if (myisspace(buffer
[pos
]) &&
1140 (add
= StrToLong(buffer
+ pos
+ 1, &dummy
)) != -1 &&
1141 buffer
[pos
+ 1 + add
] == '.')
1151 /* If could not find 'ver.rev', find any numeric */
1159 /* NOTE: Not isspace()! - Piru */
1160 if (myisspace(buffer
[pos
]) &&
1161 StrToLong(buffer
+ pos
+ 1, &dummy
) != -1)
1173 /* If could not find any version info, use the resident rt_Name */
1177 error
= RETURN_WARN
;
1180 tmpbuffer
= AllocVec(strlen(MyLibrary
->lib_Node
.ln_Name
) + strlen(buffer
) + 1, MEMF_ANY
);
1183 PrintFault(ERROR_NO_FREE_STORE
, (STRPTR
) ERROR_HEADER
);
1187 strcpy(tmpbuffer
, MyLibrary
->lib_Node
.ln_Name
);
1188 strcat(tmpbuffer
, buffer
);
1189 //Printf("createlibraryver: tmpbuffer: \"%s\"\n", (LONG) tmpbuffer);
1190 pos
= makedatafromstring(tmpbuffer
);
1202 /* Create default strings
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
);
1229 /* Create version info from named resident
1232 int makeresidentver(CONST_STRPTR name
)
1234 struct Resident
*MyResident
;
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
);
1253 /* Create version info from named list node
1256 int makeexeclistver(struct List
*list
, CONST_STRPTR name
)
1258 struct Library
*MyLibrary
;
1263 MyLibrary
= (struct Library
*) findname(list
, name
);
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
);
1302 /* Find resident from seglist, return NULL if none found
1305 struct Resident
*FindLibResident(BPTR Segment
)
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
)
1331 Segment
=(BPTR
) MySegment
[0];
1334 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
1339 /* Find $VER: tag from seglist, return NULL if none found
1340 Returns dupstr()d string or NULL.
1343 STRPTR
FindSegmentVER(BPTR Segment
)
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' &&
1365 CONST_STRPTR EndPtr
;
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
);
1382 Segment
=(BPTR
) MySegment
[0];
1385 SetIoErr(ERROR_OBJECT_NOT_FOUND
);
1390 /* Create version info from named device
1393 int makedevicever(CONST_STRPTR name
)
1395 struct DevProc
*MyDevProc
;
1398 MyDevProc
= GetDeviceProc((STRPTR
) name
, NULL
);
1401 if (MyDevProc
->dvp_DevNode
->dol_Type
== DLT_DEVICE
)
1404 #warning "FIXME: AROS specific version info for devices"
1405 error
= RETURN_FAIL
;
1409 SegList
= MyDevProc
->dvp_DevNode
->dol_misc
.dol_handler
.dol_SegList
;
1412 struct Resident
*MyResident
;
1414 MyResident
= FindLibResident(SegList
);
1417 error
= createresidentver(MyResident
);
1420 error
= RETURN_FAIL
;
1424 FreeDeviceProc(MyDevProc
);
1427 if (error
!= RETURN_OK
&& error
!= -1)
1429 Printf("Could not find version information for '%s'\n", name
);
1436 /* Retrieve version information from file. Return 0 for success.
1438 #define BUFFERSIZE (16384 + 1)
1440 int makefilever(CONST_STRPTR name
)
1443 int error
; // = RETURN_OK;
1445 file
= Open((STRPTR
) name
, MODE_OLDFILE
);
1450 buffer
= AllocMem(BUFFERSIZE
, MEMF_PUBLIC
);
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
;
1465 startbuffer
= skipwhites(buffer
);
1467 //Printf("startbuffer \"%s\"\n", startbuffer);
1468 error
= makedatafromstring(startbuffer
);
1474 error
= RETURN_ERROR
;
1478 file
= LoadSeg((STRPTR
) name
);
1481 struct Resident
*MyResident
;
1483 MyResident
= FindLibResident(file
);
1485 (MyResident->rt_Type == NT_LIBRARY ||
1486 MyResident->rt_Type == NT_DEVICE)*/)
1488 error
= createresidentver(MyResident
);
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
);
1508 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1511 FreeMem(buffer
, BUFFERSIZE
);
1515 error
= RETURN_FAIL
;
1516 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1524 LONG ioerr
= IoErr();
1526 if (ioerr
== ERROR_OBJECT_NOT_FOUND
||
1527 ioerr
== ERROR_OBJECT_WRONG_TYPE
)
1533 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1534 error
= RETURN_FAIL
;
1543 int makerescmdver(CONST_STRPTR name
)
1546 struct Segment
*segment
;
1550 segment
= FindSegment((STRPTR
) name
, NULL
, 0);
1553 segment
= FindSegment((STRPTR
) name
, NULL
, 1);
1558 if (segment
->seg_UC
== CMD_INTERNAL
||
1559 segment
->seg_UC
== CMD_DISABLED
)
1562 error
= makeresidentver("shell");
1567 STRPTR buffer
= FindSegmentVER(segment
->seg_Seg
);
1572 startbuffer
= skipwhites(buffer
);
1574 //Printf("startbuffer \"%s\"\n", (LONG) startbuffer);
1575 error
= makedatafromstring(startbuffer
);
1588 int setvervar(CONST_STRPTR name
, LONG ver
, LONG rev
)
1592 sprintf(buf
, "%ld.%ld", (LONG
) ver
, (LONG
) rev
);
1594 return SetVar((STRPTR
) name
, buf
, -1, GVF_LOCAL_ONLY
| LV_VAR
) ? RETURN_OK
: -1;
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
);
1616 int makewbversion(void)
1619 struct Library
*VersionBase
;
1621 VersionBase
= OpenLibrary("version.library", 0);
1624 error
= makeexeclistver(&SysBase
->LibList
, "version.library");
1626 if (error
== RETURN_OK
)
1628 STRPTR newname
= dupstr("Workbench", -1);
1631 FreeVec(parsedver
.pv_name
);
1632 parsedver
.pv_name
= newname
;
1634 setvervar("Workbench", parsedver
.pv_version
, parsedver
.pv_revision
);
1637 CloseLibrary(VersionBase
);
1645 int makesysver(void)
1649 error
= makekickversion();
1650 if (error
== RETURN_OK
)
1652 error
= makewbversion();
1654 if (error
== RETURN_OK
)
1660 /* prevent silly errormsg if no version.library */
1662 error
= RETURN_WARN
;
1670 /* Determine, by which means to get the version-string.
1673 int makeverstring(CONST_STRPTR name
)
1675 int error
; // = RETURN_OK;
1676 BOOL volume
= name
[strlen(name
) - 1] == ':';
1677 CONST_STRPTR filepart
= FilePart(name
);
1681 if (!volume
&& !args
.arg_file
)
1685 error
= makeresidentver(filepart
);
1686 if (error
!= RETURN_OK
)
1691 error
= makeexeclistver(&SysBase
->LibList
, filepart
);
1692 if (error
!= RETURN_OK
)
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
);
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
);
1723 if (!args
.arg_res
&& error
== -1)
1727 error
= makedevicever(name
);
1733 error
= makefilever(name
);
1738 if (!args
.arg_file
&& error
== -1)
1740 error
= makerescmdver(name
);
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
;
1758 PrintFault(ERROR_OBJECT_NOT_FOUND
, (STRPTR
) ERROR_HEADER
);
1759 error
= RETURN_FAIL
;
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.
1790 int cmpargsparsed(void)
1792 if (args
.arg_version
)
1794 if (*(args
.arg_version
) > parsedver
.pv_version
)
1798 else if (*(args
.arg_version
) == parsedver
.pv_version
&& args
.arg_revision
)
1800 if (*(args
.arg_revision
) > parsedver
.pv_revision
)
1806 else if (args
.arg_revision
)
1808 if (*(args
.arg_revision
) > parsedver
.pv_revision
)
1816 /******************************* main program ****************************/
1818 int __nocommandline
;
1822 LONG error
= RETURN_FAIL
;
1826 rda
= ReadArgs(TEMPLATE
, (IPTR
*) &args
, NULL
);
1829 if (!args
.arg_name
|| !*args
.arg_name
)
1831 /* No args, make system version */
1832 error
= makesysver();
1833 if (error
== RETURN_OK
)
1836 if (parsedver
.pv_flags
& PVF_NOVERSION
)
1838 error
= RETURN_FAIL
;
1840 if (error
== RETURN_OK
)
1842 error
= cmpargsparsed();
1854 * version file ver rev
1856 if (!args
.arg_version
&& !args
.arg_revision
)
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];
1868 args
.arg_name
[2] = NULL
;
1872 if (StrToLong(args
.arg_name
[1], &mrevision
) > 0)
1874 args
.arg_revision
= &mrevision
;
1875 args
.arg_name
[1] = NULL
;
1882 multifile
= args
.arg_name
[1] != NULL
;
1884 for (name
= args
.arg_name
; *name
; name
++)
1886 error
= makeverstring(*name
);
1887 if (error
== RETURN_OK
)
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();
1913 PrintFault(IoErr(), (STRPTR
) ERROR_HEADER
);
1914 error
= RETURN_FAIL
;