Prerequestite libraries: OSlib

moduleversion.h

/*
 * Copyright (C) Stewart Brodie, 1996
 *
 * Use freely, no liability accepted for any losses, etc.
 *
 * This file: moduleversion.h
 *
 * This code performs the first half of a *RMEnsure procedure - rather
 * than executing an arbitrary *-command, the version number is (optionally)
 * returned and a flag indicating whether the module was found, older than
 * same as, or newer than the version specified.
 *
 */
#ifndef _moduleversion_h_included
#define _moduleversion_h_included
#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
        moduleversion_NOT_FOUND,
        moduleversion_TOO_OLD,
        moduleversion_MATCH,
        moduleversion_NEWER
} module_version_flags;

typedef struct {
        int	major;
        int	minor;
} module_version_number;

/* Determine the presence/absence and optionally the version number of
 * a RISC OS module.
 *
 * Parameters:
 * name:    module name, cannot be NULL
 * wanted:  pointer to a structure containing minimum acceptable version
 *          (may be NULL if looking for any version - treated as 0.00)
 * present: pointer to a structure in which to store the version number
 *          of the module if it was found (and if it is non-NULL).
 *          Structure is not updated if function returns NOT_FOUND
 *
 * Returns:
 *          one of the values of module_version_flags defined above.
 *          The `present' structure is not touched if this value is
 *          moduleversion_TOO_OLD, but is with any other result
 */
extern module_version_flags moduleversion_check(const char */*name*/,
	module_version_number */*wanted*/, module_version_number */*present*/);

#ifdef __cplusplus
}
#endif
#endif


moduleversion.c

/*
 * Copyright (C) Stewart Brodie, 1996
 *
 * Use freely, no liability accepted for any losses, etc.
 *
 * This file: moduleversion.c
 *
 */
#include "moduleversion.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "OS:osmodule.h"

module_version_flags moduleversion_check(const char *name,
	module_version_number *wanted, module_version_number *present)
{
	byte *code;
	const int *module_header;
	const char *help_string;
	int count;
	module_version_number want = { 0,0 };
	module_version_number found = { -1, -1 };
	module_version_flags flags = moduleversion_NOT_FOUND;
	os_error *err = xosmodule_lookup(name, NULL, NULL, &code, NULL, NULL);

	if (err) {
	        return flags;
	}

	if (wanted) want = *wanted;
	
	module_header = (const int *)code;
	if (!module_header[5]) {
	        return flags;
	}
	help_string = (char *)(code + module_header[5]);
	count = 0;
	while (*help_string) {
	        if (*help_string == '\t') {
	                ++help_string;
	                count = (count + 8) & ~7;
	                continue;
	        }
	        if (count >= 16 && isdigit(*help_string)) {
	                /* think we've found it */
	                if (help_string[1] == '.' ||
	                   (isdigit(help_string[1]) && help_string[2] == '.')) {
	                           /* We're pretty sure now */
	                           count = sscanf(help_string, "%u.%u",
	                           	&found.major, &found.minor);
	                           if (count != 2) {
	                                   return flags;
	                           }
	                           if (present) *present = found;
	                           if (found.major > want.major) {
	                                   return moduleversion_NEWER;
	                           }
	                           if (found.major < want.major) {
	                                   return moduleversion_TOO_OLD;
	                           }
	                           if (found.minor > want.minor) {
	                                   return moduleversion_NEWER;
	                           }
	                           if (found.minor < want.minor) {
	                                   return moduleversion_TOO_OLD;
	                           }
	                           return moduleversion_MATCH;
	                }
	                /* Doesn't look like a version number .. carry on */
	        }
	        ++help_string;
	        ++count;
	}
	
	/* We reached the end of the string - we are now confused */
	return moduleversion_NOT_FOUND;
}

#ifdef TEST
int main(int argc, char **argv)
{
        module_version_flags flags;
        module_version_number wanted, present;
        ++argv;
        --argc;
        for (;argc >= 2;argc-=2,argv+=2) {
                if (sscanf(argv[1], "%u.%u", &wanted.major, &wanted.minor) != 2) continue;
                flags = moduleversion_check(argv[0], &wanted, &present);
		(void) printf("%s: ", argv[0]);
                switch (flags) {
                        case moduleversion_NOT_FOUND:
	                        (void) printf("not found\n");
	                        break;
                        case moduleversion_MATCH:
                        	(void) printf("%u.%02u found - exact version match\n",
                        		present.major, present.minor);
                        	break;
                        case moduleversion_TOO_OLD:
                        	(void) printf("%u.%02u found - too old\n",
                        		present.major, present.minor);
				break;
                        case moduleversion_NEWER:
                        	(void) printf("%u.%02u found - newer than minimum\n",
                        		present.major, present.minor);
                        	break;
                }
        }
        return 0;
}
#endif