/* Next available MSG number is  33 */

/***************************************************************************
   Module Name:  gpalsym.cc

   Copyright (C) 1994,1996 by Autodesk, Inc.
 
   Permission to use, copy, modify, and distribute this software in 
   object code form for any purpose and without fee is hereby granted, 
   provided that the above copyright notice appears in all copies and 
   that both that copyright notice and the limited warranty and 
   restricted rights notice below appear in all supporting 
   documentation.
 
   AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  
   AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
   DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 
   UNINTERRUPTED OR ERROR FREE.
 
   Use, duplication, or disclosure by the U.S. Government is subject to 
   restrictions set forth in FAR 52.227-19 (Commercial Computer 
   Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 
   (Rights in Technical Data and Computer Software), as applicable.
    
   .

   Description:  RXADS sample program which exercises the ads_getsym and
                 ads_putsym functions.

   Author     :
                 Autodesk, Inc.
                 2320 Marinship Way
                 Sausalito, CA. 94965
                 (415)332-2344

    This Arx application is a conversion from the original sample ADS app
    appmngr.c.

    CREATED BY:  William Howison, January 1994

    What it tests :

    - Setting an AutoLISP variable to a value using ads_putsym.

    - Getting an AutoLISP variable using ads_getsym.

    Function Entry Points:
      AcRx::AppRetCode
        acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt);

    Exported ADS Functions
        TESTGPSYM                 [Test the ADS_XXXSYM functions]

    Modification History:
        Jan 27 1994 - bch - original creation

    Notes and restrictions on use:


***************************************************************************/

/**************************************************************************/
/*  MODULE NAME  */
/**************************************************************************/
#define    GPALSYM

/****************************************************************************/
/*  DEFINES  */
/****************************************************************************/
#define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
#define SPOINT(p, x, y, z) p[X] = (x); p[Y] = (y); p[Z] = (z)
#define CPOINT(dst, src) dst[X] = src[X]; dst[Y] = src[Y]; dst[Z] = src[Z]

/**************************************************************************/
/*  TYPEDEFS  */
/**************************************************************************/
/* ADS Function Table */
typedef struct {
    char    *name;
    int     (*fptr)();
} ftblent;

typedef struct resbuf rbtype;

/**************************************************************************/
/*  INCLUDES  */
/**************************************************************************/

#include <math.h>
#include <stdio.h>
#include "adslib.h"
#include "rxdefs.h"
#include "ol_errno.h"
#include "adesk.h"


extern "C" {
/****************************************************************************/
/*  LOCALLY DEFINED ENTRY POINT INVOKED BY Arx                              */
/****************************************************************************/
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt);
}
 
/****************************************************************************/
/*  LOCAL FUNCTION FORWARD DECLARATIONS  */
/****************************************************************************/
int     getsym();
int     putsym();

/**************************************************************************/
/*  GLOBAL VARIABLES  */
/**************************************************************************/
/* Table of ADS functions */
ftblent exfun[] = {
            {/*MSG0*/"GETSYM", getsym},
            {/*MSG0*/"PUTSYM", putsym},
        };

/**************************************************************************/
/*  EXTERNAL FUNCTION DECLARATIONS  */
/**************************************************************************/

/**************************************************************************/
/*  EXTERNAL VARIABLE DECLARATIONS  */
/**************************************************************************/

/****************************************************************************/
/*  LOCAL FUNCTION DECLARATIONS  */
/****************************************************************************/
int geterrno   _((void));
int funcload   _((void));
int funcunload _((void));
int dofun      _((void));

/******************************************************************************/
/*.doc geterrno(internal) */
/*+
    This function is called to obtain the value of the AutoCAD system
    variable ERRNO and return it as a result.
-*/
/******************************************************************************/
int
/*FCN*/geterrno()
{
    rbtype errval;

    ads_getvar(/*MSG0*/"ERRNO", &errval);

    return errval.resval.rint;
}

/******************************************************************************/
/*.doc funcload(internal) */
/*+
    This function is called to define all function names in the ADS
    function table.  Each named function will be callable from lisp or
    invokable from another ADS application.
-*/
/******************************************************************************/
int
/*FCN*/funcload()
{
    int i;
    for (i = 0; i < ELEMENTS(exfun); i++) {
        if (ads_defun(exfun[i].name, i) != RTNORM)
            return RTERROR;
    }

    return RTNORM;
}

/******************************************************************************/
/*.doc funclunoad(internal) */
/*+
    This function is called to undefine all function names in the ADS
    function table.  Each named function will be removed from the
    AutoLISP hash table.
-*/
/******************************************************************************/
int
/*FCN*/funcunload()
{
    int i;

    /* Undefine each function we defined */

    for (i = 0; i < ELEMENTS(exfun); i++) {
        ads_undef(exfun[i].name,i);
    }

    return RTNORM;
}
/******************************************************************************/
/*.doc dofun(internal) */
/*+
    This function is called to invoke the function which has the
    registerd function code that is obtained from  ads_getfuncode.  The
    function will return RTERROR if the function code is invalid, or
    RSERR if the invoked function fails to return RTNORM.  The value
    RSRSLT will be returned if the function code is valid and the
    invoked subroutine returns RTNORM.
-*/
/******************************************************************************/
int
/*FCN*/dofun()
{
    int    val;
    int    rc;

    ads_retvoid();

    if ((val = ads_getfuncode()) < 0 || val > ELEMENTS(exfun))
        return RTERROR;

    rc = (*exfun[val].fptr)();

    return ((rc == RTNORM) ? RSRSLT:RSERR);
}

/******************************************************************************/
/*.doc getsym(internal) */
/*+
    This function is called from dofun function as a result of RQSUBR
    request being sent to the main dispatch loop.  It requires one
    string argument which specifies the name of an AutoLISP symbol
    whos value should be returned.

    This function always returns RTNORM.  An error message will be
    displayed in the event of an error, and nil will be returned.
    Otherwise, the value of the AutoLISP symbol will be returned
    to the AutoLISP caller.
-*/
/******************************************************************************/
int
/*FCN*/getsym()
{
    rbtype      *args;
    int         rc;
    rbtype      *varval = NULL;

    args = ads_getargs();
    if (args == NULL || args->restype != RTSTR) {
        ads_printf(/*MSG3*/"Requires an AutoLISP symbol name in \"s.\n");
        return RTNORM;
    }

    rc = ads_getsym(args->resval.rstring, &varval);
    if (rc != RTNORM) {
        switch(geterrno()) {
        case OL_ESYMNAM:
            ads_printf(/*MSG4*/"Invalid AutoLISP symbol name.\n");
            break;
        case OL_ENULLPTR:
            ads_printf(/*MSG5*/"Passed NULL pointer to ads_getsym.\n");
            break;
        case OL_ENEWRB:
            ads_printf(/*MSG6*/"Can't allocate result buffer.\n");
            break;
        case OL_ESYMVAL:
            ads_printf(/*MSG7*/"Invalid symbol value.\n");
            break;
        }
    } else {
       if (varval != NULL) {
           if (varval->rbnext == NULL)
               ads_retval(varval);
           else
               ads_retlist(varval);
       }
    }
    if (varval != NULL)
        ads_relrb(varval);

    return RTNORM;
}

/******************************************************************************/
/*.doc putsym(internal) */
/*+
    This function is called from dofun function as a result of RQSUBR
    request being sent to the main dispatch loop.  It requires two
    arguments.  The first argument is a string containing the name of
    an AutoLISP symbol to set.  The second argument can be any data
    type or list containing any data type which can be represented
    in an ADS resbuf structure.

    This function always returns RTNORM to the C caller.  This function
    always return nil if the operation fails.  Otherwise, the value of
    the second argument is returned.

    A message will be displayed if an error occurs, and the value
    returned to the AutoLISP caller will be nil.
-*/
/******************************************************************************/
int
/*FCN*/putsym()
{
    rbtype      *args;
    int         rc;

    args = ads_getargs();
    ads_retnil();

    if (args == NULL || args->restype != RTSTR) {
        ads_printf(/*MSG8*/"Requires name of AutoLISP symbol in \"s, and\n");
        ads_printf(/*MSG9*/"value to be assigned to symbol.\n");
        return RTNORM;
    }
    
    rc = ads_putsym(args->resval.rstring, args->rbnext);
    if (rc != RTNORM) {
        switch(geterrno()) {
        case OL_ESYMNAM:
            ads_printf(/*MSG10*/"Invalid AutoLISP symbol name.\n");
            break;
        case OL_ESYMVAL:
            ads_printf(/*MSG11*/"Invalid symbol value.\n");
            break;
        }
    } else {
        if (args->rbnext != NULL) {
            if (args->rbnext->rbnext == NULL)
                ads_retval(args->rbnext);
            else
                ads_retlist(args->rbnext);
        }
    }
    return RTNORM;
}

/* =================== Arx Module Interface Functions ================ */
 
AcRx::AppRetCode
/*FCN*/acrxEntryPoint(AcRx::AppMsgCode msg, void * ptr)
{
 
    if (ptr != NULL) {
        // We have been handed some kind of object
        // but we aren't going to do anything with it.
    }
 
    switch(msg) {
        case AcRx::kInitAppMsg:
             acrxUnlockApplication(ptr);
            break;
        case AcRx::kInvkSubrMsg:
            dofun();
            break;
        case AcRx::kLoadDwgMsg:
            funcload();
            break;
        case AcRx::kUnloadDwgMsg:
            funcunload();
            ads_printf(/*MSG2*/"Unloading.\n");
            break;
        case AcRx::kUnloadAppMsg:
        default:
            break;
    }
    return AcRx::kRetOK;
}

