/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  OS/2 Accelerator table related semantic actions.
*
****************************************************************************/


#include <ctype.h>
#include <string.h>
#include "wresall.h"
#include "errors.h"
#include "global.h"
#include "rcmem.h"
#include "ytab.gh"
#include "semaccel.h"

#include "reserr.h"
int ResOS2WriteAccelEntry( AccelTableEntryOS2 * currentry, WResFileID handle )
/**********************************************************************/
{
    int     numwrote;

    numwrote = WRESWRITE( handle, currentry, sizeof(AccelTableEntryOS2) );
    if( numwrote != sizeof( AccelTableEntryOS2 ) ) {
        WRES_ERROR( WRS_WRITE_FAILED );
        return( TRUE );
    }
    return( FALSE );
}

#define CTRL_EVENT  0x8000

const FullAccelFlagsOS2 DefaultAccelFlagsOS2 = { 0, FALSE };

int SemOS2StrToAccelEvent( char * string )
/*************************************/
{
    if (*string == '^') {
        /* control character requested */
        string++;
        if (isalpha( *string )) {
            return( *string | CTRL_EVENT );
        } else {
            return( 0 );
        }
    } else if (isprint( *string )) {
        /* only accept printable characters in this position */
        return( *string );
    } else {
        return( 0 );
    }
}

static void CheckAccelFlags( uint_16 * flags, unsigned long idval )
/********************************************************************/
{
    /* CHAR is the default */
    if ( !( *flags & OS2_ACCEL_VIRTUALKEY ) && !( *flags & OS2_ACCEL_CHAR ) )
        *flags |= OS2_ACCEL_CHAR;
#if 0
    if ( !( *flags & OS2_ACCEL_VIRTUALKEY ) ) {
        if (*flags & OS2_ACCEL_SHIFT) {
            *flags &= ~OS2_ACCEL_SHIFT;
            RcWarning( ERR_ACCEL_KEYWORD_IGNORED, "SHIFT", idval );
        }
        if (*flags & OS2_ACCEL_CONTROL) {
            *flags &= ~OS2_ACCEL_CONTROL;
            RcWarning( ERR_ACCEL_KEYWORD_IGNORED, "CONTROL", idval );
        }
    }
#endif
}

FullAccelEntryOS2 SemOS2MakeAccItem( AccelEvent event, unsigned long idval,
                    FullAccelFlagsOS2 flags )
/*************************************************************************/
{
    FullAccelEntryOS2      entry;

//    if (event.strevent || flags.typegiven) {
        CheckAccelFlags( &flags.flags, idval );
        entry.entry.Ascii = event.event;
        entry.entry.Flags = flags.flags;
        entry.entry.Id = idval;
        if( event.event & CTRL_EVENT ) {
            entry.entry.Ascii  = event.event & ~CTRL_EVENT;
            entry.entry.Flags |= OS2_ACCEL_CTRL;
        }

//    } else {
//        RcError( ERR_ACCEL_NO_TYPE, idval );
//        ErrorHasOccured = TRUE;
//        entry.entry.Ascii = 0;
//        entry.entry.Flags = 0;
//        entry.entry.Id = 0;
//    }

    return( entry );
}

FullAccelTableOS2 *SemOS2NewAccelTable( FullAccelEntryOS2 firstentry )
/***************************************************************/
{
    FullAccelTableOS2   *newtable;
    FullAccelEntryOS2   *newentry;

    newtable = RcMemMalloc( sizeof( FullAccelTableOS2 ) );
    newentry = RcMemMalloc( sizeof( FullAccelEntryOS2 ) );

    if( newtable == NULL || newentry == NULL ) {
        RcError( ERR_OUT_OF_MEMORY );
        ErrorHasOccured = TRUE;
        return( NULL );
    }

    *newentry = firstentry;
    newtable->head = NULL;
    newtable->tail = NULL;
    newtable->codepage = 850;   // TODO: get real codepage

    ResAddLLItemAtEnd( (void **) &(newtable->head), (void **) &(newtable->tail), newentry );

    return( newtable );
}

extern FullAccelTableOS2 *SemOS2AddAccelEntry( FullAccelEntryOS2 currentry,
                                               FullAccelTableOS2 * currtable )
/******************************************************************/
{
    FullAccelEntryOS2     *newentry;

    newentry = RcMemMalloc( sizeof(FullAccelEntryOS2) );

    if( newentry == NULL ) {
        RcError( ERR_OUT_OF_MEMORY );
        ErrorHasOccured = TRUE;
        return( NULL );
    }

    *newentry = currentry;

    ResAddLLItemAtEnd( (void **) &(currtable->head), (void **) &(currtable->tail), newentry );

    return( currtable );
}

static void SemOS2FreeAccelTable( FullAccelTableOS2 * acctable )
/**************************************************************/
{
    FullAccelEntryOS2   *currentry;
    FullAccelEntryOS2   *oldentry;

    currentry = acctable->head;
    while( currentry != NULL ) {
        oldentry = currentry;
        currentry = currentry->next;
        RcMemFree( oldentry );
    }
    RcMemFree( acctable );
}

static int SemOS2CountAccelTableEntries( FullAccelTableOS2 * acctable )
/*********************************************************************/
{
    FullAccelEntryOS2   *currentry;
    int                 count = 0;

    currentry = acctable->head;
    while( currentry != NULL ) {
        count++;
        currentry = currentry->next;
    }
    return( count );
}

static int SemOS2WriteAccelTableEntries( FullAccelTableOS2 * acctable,
                                        WResFileID handle )
/*********************************************************************/
{
    FullAccelEntryOS2   *currentry;
    int                 error;
    uint_16             tmp;

    tmp = SemOS2CountAccelTableEntries( acctable );
    error = ResWriteUint16( &tmp, handle );
    if( !error ) {
        tmp = acctable->codepage;
        error = ResWriteUint16( &tmp, handle );
    }
    currentry = acctable->head;
    while( currentry != NULL && !error ) {
        ResOS2WriteAccelEntry( &currentry->entry, handle );
        currentry = currentry->next;
    }
    return( error );
}

extern void SemOS2WriteAccelTable( WResID * name, ResMemFlags flags,
                                   FullAccelTableOS2 * acctable )
/******************************************************************/
{
    ResLocation     loc;
    int             error;
    int             err_code;

    if( !ErrorHasOccured ) {
        loc.start = SemStartResource();
        error = SemOS2WriteAccelTableEntries( acctable, CurrResFile.handle );
        if(error) {
            err_code = LastWresErr();
            goto OutputWriteError;
        }
        loc.len = SemEndResource( loc.start );
        SemAddResourceFree( name, WResIDFromNum( OS2_RT_ACCELTABLE ), flags, loc );
    } else {
        RcMemFree( name );
    }

    SemOS2FreeAccelTable( acctable );
    return;

OutputWriteError:
    RcError( ERR_WRITTING_RES_FILE, CurrResFile.filename,
             strerror( err_code ) );
    ErrorHasOccured = TRUE;
    SemOS2FreeAccelTable( acctable );
    return;

}
