//
//  Copyright (C) 1997,1998,1999 Forest Edge Software, see License.txt for Rights
//
//  Program:    eVAX, a "Virtual VAX" for Mac OS Computers
//
//  Author:     Tom Cole
//
//  Module:     vms_logicals.c
//
//  Purpose:    Runtime support for VMS logical name services.
//
//  History:    12/10/99    Created.


#include "vax.pch"
#include "shim.h"
#include "services.h"
#include "ss_def.h"

struct LNM {
    LONGWORD            attr;
    LONGWORD            len;
    char                name[ 1 ];
};

struct LNMLST {
    struct LNMLST *     next;
    LONGWORD		len;
    char *              value;
    struct LNM          logical;
}

struct LNMTBL {
    struct LNMTBL *     next;
    struct LNMLST *     names;
    struct LNM          table;
};


struct LNMTBL tables = 0L;

long create_logical_name( char * table, char * name, char * value, LONGWORD attr );
long find_logical_name( char * table_name, char * name, struct LNMLST ** r );
long strcmp_upcase( char * first, char * second );


/*
 *  Internal routine that does a strcmp() but uppercases the data
 */

long strcmp_upcase( char * first, char * second )
{
    long n;
    char ch1, ch2;

    for( n = 0; n < 65535; n++ ) {
        ch1 = first[ n ];
        ch2 = second[ n ];

        if( ch1 == 0 && ch2 == 0 )
            return 0;
        if( ch1 == 0 )
            return -1;
        if( ch2 == 0 )
            return 1;

        if( ch1 >= 'a' && ch1 <= 'z' )
            ch1 -= 32;

        if( ch2 >= 'a' && ch2 <= 'z' )
            ch2 -= 32;

        if( ch1 == ch2 )
            continue;

        if( ch1 < ch2 )
            return -1;

        return 1;
    }

    return 0;
}

/*
 *  Internal routine to create a logical name.
 */

long create_logical_name( char * table_name, char * name, 
                             char * value, LONGWORD attr )
{
    long size, name_len;
    struct LNMTBL * tp;
    struct LNMLST * nm;

    /* Find the matching table */

    for( tp = tables; tp; tp = tp-> next ) {
        if( strcmp_upcase( tp-> table.name, table_name ) == 0 ) {
            break;
        }
    }
 
    /* If the table wasn't found, then create it */

    if( tp == 0L ) {
        name_len = strlen( table_name );
        size = sizeof( struct LNMTBL ) + name_len;
        tp = ( struct LNMTBL * ) getmem( size );

        if( tp == 0L )
            return VAX_NOMEM;

        tp-> next = tables;
        tables = tp;
        tp-> attr = 0L;
        tp-> table.len = name_len;
        strcpy( tp-> table.name, table_name );
        tp-> names = 0L;
    }

    /*  See if the name is already in the table */

    for( nm = tp-> name; nm; nm = nm-> next ) {
        if( strcmp_upcase( nm-> logical.name, logical_name ) == 0 )
            break;
    }

    /* If the name wasn't found then create it */

    if( nm == 0L ) {
        name_len = strlen( logical_name );
        size = sizeof( struct LNMLST ) + name_len;
        nm = ( struct LNMLST * ) getmem( size );

        if( nm == 0L )
            return VAX_NOMEM;

        nm-> next = tp-> names;
        tp-> names = nm;
        nm-> attr = 0L;
        nm-> logical.len = name_len;
        strcpy( nm-> logical.name, logical_name );
        nm-> value = 0L;
        nm-> len = 0;
    }

    /* If there was an old value, free it up */

    if( nm-> value ) {
        freemem( nm-> value );
        nm-> value = 0L;
        nm-> len = 0;
    }

    /* Allocate storage for new value and store it away */

    nm-> len = strlen( value );
    nm-> value = getmem( nm-> len + 1 );
    strcpy( nm-> value, value );
    nm-> attr = attr;

    return VAX_OK;
}


/*
 *  Internal routine to locate a logical name.
 */

long find_logical_name( char * table_name, char * name, struct LNMLST ** r )
{
    long size, name_len;
    struct LNMTBL * tp;
    struct LNMLST * nm;

    /* If the caller wants a LNMLST entry ptr back, clear it for now */

    if( r != 0L )
        *r = 0L;

    /* Find the matching table */

    for( tp = tables; tp; tp = tp-> next ) {
        if( strcmp_upcase( tp-> table.name, table_name ) == 0 ) {
            break;
        }
    }
 
    /* If the table wasn't found, then fail */

    if( tp == 0L )
        return SS_NOLOGNAM;

    /*  Find the name in the table */

    for( nm = tp-> name; nm; nm = nm-> next ) {
        if( strcmp_upcase( nm-> logical.name, logical_name ) == 0 )
            break;
    }

    /* If the name wasn't found then fail */

    if( nm == 0L )
        return SS_NOLOGNAM;

    /* Otherwise fill in the caller's pointer and we're done */

    if( r != 0L )
        *r = nm;

    return SS_NORMAL;
}


long init_logical_names()
{

    static done = 0;

    if( done )
        return VAX_OK;

    create_logical_name( "LNM$ROOT", "SYS$COMMAND", "TTA0:", 0L );
    create_logical_name( "LNM$ROOT", "SYS$INPUT", "TTA0:", 0L );
    create_logical_name( "LNM$ROOT", "SYS$OUTPUT", "TTA0:", 0L );
    create_logical_name( "LNM$ROOT", "TT", "TTA0:", 0L );
 
    return VAX_OK;
}



SSDEF( sys_trnlnm )
{

    LONGWORD attr;
    char * table_name, logical_name;

    struct LNMLST * lnm;

    LONGWORD list_addr;
    LONGWORD table_desc;

    /* See if there is an attribute flag set */

    if( argv[ 0 ] != 0L ) {
        rc = load_memory( argv[ 0 ], &attr, 4 );
    }
    else
        attr = 0;

    /* Get the table name */

    table_name = load_dstring( argv[ 1 ]);

    /* And the logical name itself */

    logical_name = load_dstring( argv[ 2 ]);

    /* Go ahead and fetch the data about it now */

    sts = find_logical_name( table_name, logical_name, &lnm );
    if( sts != SS_NORMAL )
        return sts;

    /* Traverse the list of stuff we need to do with this one */

    list_addr = argv[ 4 ];
    if( list_addr == 0L )
        return SS_NORMAL;

    rc = load_memory( list_addr, ( void * ) &bsize, 2 );
    rc = load_memory( list_addr+2, ( void * ) &code, 2 );
    sts = SS_NORMAL;

    while(( bsize != 0L ) && ( code != 0L )) {

        rc = load_memory( list_addr+4, ( void * ) &buff, 4 );
        rc = load_memory( list_addr+8, ( void * ) &ret_addr, 4 );
        list_addr = list_addr + 12;

        switch( code ) {
        default:  sts = SS_INVARG;
        }

        rc = load_memory( list_addr, ( void * ) &bsize, 2 );
        rc = load_memory( list_addr+2, ( void * ) &code, 2 );

    }

    return sts;
}

