From: caw@miroc.Chi.IL.US (Christopher A. Wichura)
Newsgroups: comp.sys.amiga.programmer
Subject: Re: Version numbers
Date: 13 Apr 92 14:28:19 GMT
X-NewsSoftware: Amiga GRn V1.28 2/25/92 (Beta) by Mike Schwartz

In article <1992Apr5.040159.24086@samba.oit.unc.edu> Frederick.Theilig@bbs.oit.unc.edu (Frederick Theilig) writes:
>
>     Once while browsing through the Amiga Style Guide, I noticed their
> comment on using version numbers.  Somehow, one is to burn in the
> text "$VER: <progname> x.xx" into their program.  All well and good.
> Any ideas as to the best method for doing this?  At the moment, I do
> char ver = "$VER: bla bla", which works.  Is there a better way?  I'm
> using DICE.

I made a little program to do this for me.  I've included the source to it
after my .signature.  Basically, what it does is make a linker object which
it maintains.

Assume your program is called FooBar.  Then, when you start the project,
you'd go

	UpCVersion FooBar version.o c

That creates a linker object called version.o, which you would then link with
your other modules to imbed this string in your program.  The major version
number will be 0, as will the revision number.  I chose to go with major = 0
as one can use it for initial development and then when ready for a real
release you bump the major version up to 1.

	UpCVersion FooBar version.o

will bump the revision number up by one.

	UpCVersion FooBar version.o v

will bump the major revision number up by one and reset the revision number
to zero.

UpCVersion will also put the proper time stamp into the version string for
you, so you always want to run it before making a release.  I actually have
my make files set up so that it is run as part of the link phase.  i.e.,
(this is for SAS's lmk):

GIFMachine: $(OBJS)
	UpCVersion GIFMachine version.o
	BLink <WITH < (GIFMachine.lnk)
FROM $(OBJS) version.o
TO GIFMachine
LIB $(LIBS)
$(LFLAGS)
<

There are a couple other things that UpCVersion provides for you.  It
contains three XREFs which you can access from your code.  These are:

	UBYTE __far VersionID[];
	ULONG __far Version;
	ULONG __far Revision;

	Assembler programmers should note that these have the standard
	C variable prefix so from assembler it's really _VersionID, etc.

The two ULONGs are pretty obvious as to what they are.  VersionID is a string
of the form

	ver.rev (d.m.y)          (no newline at the end, but null terminated)

I like to spit the program name out with ANSI CSI code around it, so I do
things along the lines of

	printf("%sProgName%s v%s", LeadCSI, TrailCSI, VersionID);

The __far is SAS specific, and I don't know what DICE uses as its equivalent
(or if it even has one).  It's needed because I store the information in a
CODE hunk instead of a DATA hunk.  This has to do mainly with making resident
programs, as it means the version string and all don't have to be cloned over
for each instance of the program run.

People are free to use this program as they see fit.  I'm not accountable for
any loss of productivity or money or data or whatnot that may occur while it
is in use, however.

-=> CAW

Oh, yeah, to compile UpCVersion with SAS use:

lc -d2 -v -cs -rr -O UpCVersion.c
blink lib:cres.o UpCVersion.o to UpCVersion lib lib:lcr.lib lib:amiga.lib nd sc sd

--

Christopher A. Wichura                Multitasking.  Just DO it.
caw@miroc.chi.il.us  (my amiga)                          ...the Amiga way...
u12401@uicvm.uic.edu (school account)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

typedef unsigned long	ULONG;
typedef unsigned char	UBYTE;

char toupper(char);

ULONG	XDEFBuf[17] = {
	0x000003ef, 0x01000002, 0x5f566572, 0x73696f6e,
	0x00000000, 0x01000003, 0x5f566572, 0x73696f6e,
	0x49440000, 0x0000000F, 0x01000003, 0x5f526576,
	0x6973696f, 0x6e000000, 0x00000004, 0x00000000,
	0x000003f2
};

void main(int argc, char *argv[])
{
	ULONG	Version[1];
	ULONG	Revision[1];
	UBYTE	CharBuf[200];
	ULONG	WriteBuf[10];
	FILE *	fh;
	int	MakeNew;

	if ((argc == 4) && (toupper(argv[3][0]) == 'C')) {
		MakeNew = 1;
		Version[0] = 0;
		Revision[0] = 0;
	} else
		MakeNew = 0;

	if (!MakeNew) {
		if (!(fh = fopen(argv[2], "r"))) {
			printf("Error: couldn't open %s for read.\n", argv[2]);
			exit(10);
		}

		fseek(fh, 16, 0);
		fread((char *)&Version, sizeof(ULONG), 1, fh);
		fread((char *)&Revision, sizeof(ULONG), 1, fh);
		fclose(fh);

		Revision[0]++;
	}

	if ((argc == 4) && (toupper(argv[3][0]) == 'V')) {
		Version[0]++;
		Revision[0] = 0;
	}

	{
		long t;
		struct tm *Time;

		time(&t);
		Time = localtime(&t);

		memset((char *)CharBuf, 0, sizeof(CharBuf));
		sprintf((char *)CharBuf, "$VER: %s %d.%d (%d.%d.%d)",
			argv[1],
			Version[0], Revision[0],
			Time->tm_mday,
			Time->tm_mon + 1,
			Time->tm_year);
	}

	if (!(fh = fopen(argv[2], "w"))) {
		printf("Error: couldn't open %s for write.\n", argv[2]);
		exit(10);
	}

	WriteBuf[0] = 0x3e7;
	WriteBuf[1] = 0;
	WriteBuf[2] = 0x3e9;
	WriteBuf[3] = (((strlen(CharBuf) + 1) + 3) / 4) + 2;
	WriteBuf[4] = Version[0];
	WriteBuf[5] = Revision[0];
	fwrite((char *)WriteBuf, sizeof(ULONG), 6, fh);
	fwrite((char *)CharBuf, WriteBuf[3] - 2, sizeof(ULONG), fh);
	XDEFBuf[9] += strlen(argv[1]);
	fwrite((char *)XDEFBuf, sizeof(ULONG), (sizeof(XDEFBuf) / sizeof(ULONG)), fh);
	fclose(fh);
}