Subversion Repositories tendra.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
                 Crown Copyright (c) 1997
    
    This TenDRA(r) Computer Program is subject to Copyright
    owned by the United Kingdom Secretary of State for Defence
    acting through the Defence Evaluation and Research Agency
    (DERA).  It is made available to Recipients with a
    royalty-free licence for its use, reproduction, transfer
    to other parties and amendment for any purpose not excluding
    product development provided that any such use et cetera
    shall be deemed to be acceptance of the following conditions:-
    
        (1) Its Recipients shall ensure that this Notice is
        reproduced upon any copies or amended versions of it;
    
        (2) Any amended version of it shall be clearly marked to
        show both the nature of and the organisation responsible
        for the relevant amendment or amendments;
    
        (3) Its onward transfer from a recipient to another
        party shall be deemed to be that party's acceptance of
        these conditions;
    
        (4) DERA gives no warranty or assurance as to its
        quality or suitability for any purpose and DERA accepts
        no liability whatsoever in relation to any use to which
        it may be put.
*/


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

#ifndef FS_UTSNAME
#define FS_UTSNAME      1
#endif

#if FS_UTSNAME
#include <sys/types.h>
#include <sys/utsname.h>
#endif

#include "ossg.h"


/*
    CONVERT A STRING TO LOWER CASE

    This routine converts the string s to lower case, returning the result.
*/

static char *to_lower_case
    PROTO_N ( ( s ) )
    PROTO_T ( char *s )
{
    int c ;
    char *t = s ;
    while ( c = ( int ) *t, c != 0 ) {
        if ( isascii ( c ) && isupper ( c ) ) {
            *t = ( char ) tolower ( c ) ;
        }
        t++ ;
    }
    return ( s ) ;
}


/*
    PRINT A MACRO DEFINITION

    This routine prints a macro definition consisting of the prefix p
    followed by s, suitably transformed by replacing each non-alphanumeric
    character by an underscore.
*/

static void define_macro
    PROTO_N ( ( p, s ) )
    PROTO_T ( CONST char *p X CONST char *s )
{
    int c ;
    IGNORE printf ( "#define %s", p ) ;
    while ( c = ( int ) *( s++ ), c != 0 ) {
        if ( !isascii ( c ) || !isalnum ( c ) ) c = '_' ;
        IGNORE fputc ( c, stdout ) ;
    }
    IGNORE printf ( " 1\n" ) ;
    return ;
}


/*
    FIND A MACHINE TYPE

    These routines map the machine type as returned by uname (mapped to
    lower case), m, to the standard machine type used in the build.
*/

static CONST char *find_aix_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( m [8] == '7' && m [9] == '6' ) return ( "power" ) ;
    if ( m [8] == '7' && m [9] == '7' ) return ( "power" ) ;
    if ( m [8] == '4' && m [9] == '6' ) return ( "ppc601" ) ;
    return ( "unknown" ) ;
}

static CONST char *find_hpux_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( strncmp ( m, "9000/", 5 ) == 0 ) {
        if ( m [5] == '7' || m [5] == '8' ) return ( "hppa" ) ;
        if ( m [5] == '3' || m [5] == '4' ) return ( "680x0" ) ;
    }
    return ( "unknown" ) ;
}

static CONST char *find_irix_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( strcmp ( m, "ip22" ) == 0 ) return ( "mips" ) ;
    return ( "unknown" ) ;
}

static CONST char *find_linux_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( m [0] == 'i' && strstr ( m, "86" ) ) return ( "80x86" ) ;
    return ( "unknown" ) ;
}

static CONST char *find_osf1_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( strcmp ( m, "alpha" ) == 0 ) return ( "alpha" ) ;
    return ( "unknown" ) ;
}

static CONST char *find_sco_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( m [0] == 'i' && strstr ( m, "86" ) ) return ( "80x86" ) ;
    return ( "unknown" ) ;
}

static CONST char *find_sunos_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( strcmp ( m, "i86pc" ) == 0 ) return ( "80x86" ) ;
    if ( strncmp ( m, "sun3", 4 ) == 0 ) return ( "680x0" ) ;
    if ( strncmp ( m, "sun4", 4 ) == 0 ) return ( "sparc" ) ;
    return ( "unknown" ) ;
}

static CONST char *find_ultrix_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( strcmp ( m, "risc" ) == 0 ) return ( "mips" ) ;
    if ( strcmp ( m, "vax" ) == 0 ) return ( "vax" ) ;
    return ( "unknown" ) ;
}

static CONST char *find_unix_sv_machine
    PROTO_N ( ( m ) )
    PROTO_T ( CONST char *m )
{
    if ( m [0] == 'i' && m [2] == '8' && m [3] == '6' ) return ( "80x86" ) ;
    return ( "unknown" ) ;
}


/*
    FIND SCO RELEASE NUMBER

    On SCO the release number is not returned by uname.  Instead there is
    a function __scoinfo which returns the necessary information.  This
    routine finds the release number.
*/

static CONST char *find_sco_release
    PROTO_N ( ( buff ) )
    PROTO_T ( char *buff )
{
#if defined ( _M_XENIX ) && defined ( _TWO_USER )
    struct scoutsname us ;
    extern int __scoinfo PROTO_S ( ( struct scoutsname *, int ) ) ;
    if ( __scoinfo ( &us, ( int ) sizeof ( us ) ) != -1 ) {
        char *v = strchr ( us.release, 'v' ) ;
        if ( v ) {
            /* The release is the part following the 'v' */
            IGNORE strcpy ( buff, v + 1 ) ;
            return ( buff ) ;
        }
    }
#endif
    UNUSED ( buff ) ;
    return ( "unknown" ) ;
}


/*
    FIND LINUX EXECUTABLE FORMAT

    This routine finds whether the given version of linux supports the ELF
    or the a.out executable format.  It does this by examining the magic
    number at the start of an executable file, nm.
*/

static CONST char *find_linux_format
    PROTO_N ( ( nm ) )
    PROTO_T ( CONST char *nm )
{
    FILE *f = fopen ( nm, "rb" ) ;
    if ( f != NULL ) {
        char m [4] ;
        if ( fread ( m, sizeof ( char ), sizeof ( m ), f ) == 4 ) {
            if ( m [0] == 0x7f ) {
                if ( m [1] == 'E' && m [2] == 'L' && m [3] == 'F' ) {
                    IGNORE fclose ( f ) ;
                    return ( "elf" ) ;
                }
            }
        }
        IGNORE fclose ( f ) ;
    }
    return ( "aout" ) ;
}


/*
    MAIN ROUTINE

    This program is a rationalised form of uname which tries to give the
    operating system type, the operating system version and the processor
    type in a consistent form.  It may need extending to cover new
    operating systems.
*/

int main
    PROTO_N ( ( argc, argv ) )
    PROTO_T ( int argc X char **argv )
{
    char buff [50] ;
    CONST char *sysname = "unknown" ;
    CONST char *nodename = "anonymous" ;
    CONST char *release = "unknown" ;
    CONST char *version = "unknown" ;
    CONST char *machine = "unknown" ;
    CONST char *execform = "default" ;

    /* Call uname to find system information */
#if FS_UTSNAME
    struct utsname un ;
    if ( uname ( &un ) != -1 ) {
        sysname = to_lower_case ( un.sysname ) ;
        nodename = to_lower_case ( un.nodename ) ;
        release = un.release ;
        version = un.version ;
        machine = to_lower_case ( un.machine ) ;
    }
#endif

#ifdef DEBUG
    /* Print debugging information */
    IGNORE fprintf ( stderr, "sysname = \"%s\"\n", sysname ) ;
    IGNORE fprintf ( stderr, "nodename = \"%s\"\n", nodename ) ;
    IGNORE fprintf ( stderr, "release = \"%s\"\n", release ) ;
    IGNORE fprintf ( stderr, "version = \"%s\"\n", version ) ;
    IGNORE fprintf ( stderr, "machine = \"%s\"\n", machine ) ;
#endif

    /* Examine system information */
    if ( strcmp ( sysname, "aix" ) == 0 ) {
        machine = find_aix_machine ( machine ) ;
        IGNORE sprintf ( buff, "%s.%s", version, release ) ;
        release = buff ;

    } else if ( strcmp ( sysname, "freebsd" ) == 0 ) {
        machine = find_linux_machine ( machine ) ;

    } else if ( strcmp ( sysname, "hp-ux" ) == 0 ) {
        sysname = "hpux" ;
        machine = find_hpux_machine ( machine ) ;

    } else if ( strcmp ( sysname, "irix" ) == 0 ) {
        machine = find_irix_machine ( machine ) ;

    } else if ( strcmp ( sysname, "linux" ) == 0 ) {
        machine = find_linux_machine ( machine ) ;
        execform = find_linux_format ( argv [0] ) ;
        if ( strcmp ( execform, "aout" ) == 0 ) {
            /* Mark a.out versions */
            IGNORE sprintf ( buff, "%sA", release ) ;
            release = buff ;
        }

    } else if ( strcmp ( sysname, "msdos" ) == 0 ) {
        machine = find_sco_machine ( machine ) ;

    } else if ( strcmp ( sysname, "osf1" ) == 0 ) {
        machine = find_osf1_machine ( machine ) ;

    } else if ( strcmp ( sysname, "sco" ) == 0 ) {
        /* This doesn't actually happen - see below */
        release = find_sco_release ( buff ) ;
        machine = find_sco_machine ( machine ) ;

    } else if ( strcmp ( sysname, "sunos" ) == 0 ) {
        if ( release [0] == '5' ) {
            /* SunOS 5.x is really Solaris 2.x */
            sysname = "solaris" ;
            IGNORE sprintf ( buff, "2%s", release + 1 ) ;
            release = buff ;
        }
        machine = find_sunos_machine ( machine ) ;

    } else if ( strcmp ( sysname, "ultrix" ) == 0 ) {
        machine = find_ultrix_machine ( machine ) ;

    } else if ( strcmp ( sysname, "unix_sv" ) == 0 ) {
        IGNORE sprintf ( buff, "svr%s", release ) ;
        sysname = buff ;
        release = version ;
        machine = find_unix_sv_machine ( machine ) ;

    } else if ( strcmp ( sysname, nodename ) == 0 ) {
        /* This is a bug on SCO */
        sysname = "sco" ;
        release = find_sco_release ( buff ) ;
        machine = find_sco_machine ( machine ) ;

    } else if ( strncmp ( sysname, "cygwin32", 8 ) == 0 ) {
        sysname = "cygwin32" ;
        machine = find_linux_machine ( machine ) ;

    } else {
        /* Unknown operating system */
        sysname = "unknown" ;
        machine = "unknown" ;
        release = "unknown" ;
    }

    /* Print host type */
    if ( argc > 2 ) {
        IGNORE fprintf ( stderr, "tcc_host: Too many arguments.\n" ) ;
        argc = 2 ;
    }
    if ( argc == 2 ) {
        char *arg = argv [1] ;
        if ( strcmp ( arg, "-a" ) == 0 ) {
            IGNORE printf ( "%s %s %s\n", sysname, release, machine ) ;
            return ( 0 ) ;
        }
        if ( strcmp ( arg, "-d" ) == 0 ) {
            IGNORE printf ( "%s/%s/%s\n", sysname, release, machine ) ;
            return ( 0 ) ;
        }
        if ( strcmp ( arg, "-e" ) == 0 ) {
            IGNORE printf ( "%s\n", execform ) ;
            return ( 0 ) ;
        }
        if ( strcmp ( arg, "-h" ) == 0 ) {
            IGNORE printf ( "%s\n", nodename ) ;
            return ( 0 ) ;
        }
        if ( strcmp ( arg, "-m" ) == 0 ) {
            IGNORE printf ( "%s\n", machine ) ;
            return ( 0 ) ;
        }
        if ( strcmp ( arg, "-r" ) == 0 ) {
            IGNORE printf ( "%s\n", release ) ;
            return ( 0 ) ;
        }
        if ( strcmp ( arg, "-s" ) == 0 ) {
            IGNORE printf ( "%s\n", sysname ) ;
            return ( 0 ) ;
        }
        if ( strcmp ( arg, "-D" ) == 0 ) {
            define_macro ( "FS_OS_", sysname ) ;
            define_macro ( "FS_OS_VERS_", release ) ;
            define_macro ( "FS_CPU_", machine ) ;
            define_macro ( "FS_EXEC_", execform ) ;
            return ( 0 ) ;
        }
        IGNORE fprintf ( stderr, "tcc_host: Unknown argument '%s'.\n", arg ) ;
    }
    IGNORE printf ( "%s %s %s\n", sysname, release, machine ) ;
    return ( 0 ) ;
}