/* Next available MSG number is  33 */

/***************************************************************************
   Module Name:  appmngr.c

   Copyright (C) 1992, 1993, 1994 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:  App loads and unloads a series of ADS apps, and displays
                 The currently loaded ADS applications.

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

   Function Entry Points:
        void
        main(argc, argv)
        int    argc;              [Number of argument passed in cmd line]
        char   *argv[];           [Array of pointers to arguments]

   Exported ADS Functions
        TESTXLOAD                 [Test ADS_ XLOAD/XUNLOAD/LOADED functions]

   Modification History:
        Feb 26 1992 - bcm - original creation

   Notes and restrictions on use:


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

/**************************************************************************/
/*  MODULE NAME  */
/**************************************************************************/
#define    APPMNGR

/****************************************************************************/
/*  DEFINES  */
/****************************************************************************/
#define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))

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

typedef struct resbuf rbtype;

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

#include <stdio.h>
#include "adslib.h"
#include "ol_errno.h"
/****************************************************************************/
/*  LOCAL FUNCTION FORWARD DECLARATIONS  */
/****************************************************************************/
int     testappmngr();

/**************************************************************************/
/*  GLOBAL VARIABLES  */
/**************************************************************************/
/* Table of ADS functions */
ftblent exfun[] = {
            {/*MSG0*/"C:TESTAPPMNGR", testappmngr},
        };

/* Table of ADS applications */
char    *AppTable[] = {
            /*MSG0*/"ads_perr",
            /*MSG0*/"appmngr",
            /*MSG0*/"arbmat",
            /*MSG0*/"asctext",
            /*MSG0*/"colext",
            /*MSG0*/"dlgtest",
            /*MSG0*/"dragger",
            /*MSG0*/"fact",
            /*MSG0*/"gpalsym",
            /*MSG0*/"gravity",
            /*MSG0*/"magnets",
            /*MSG0*/"project",
            /*MSG0*/"ptext",
            /*MSG0*/"sld2ps",
            /*MSG0*/"sqr",
            /*MSG0*/"tower",
        };

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

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

/****************************************************************************/
/*  LOCAL FUNCTION DECLARATIONS  */
/****************************************************************************/

int funcload   _((void));
int funcunload _((void));
int dofun      _((void));
int geterrno   _((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))
            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 main(internal) */
/*+
    This is the main entry point for the ADS application.  All ADS
    requests will be dispatched from this function.  This is your
    standard ADS dispatch loop.
-*/
/******************************************************************************/
void
/*FCN*/main(argc,argv)
int argc;
char *argv[];
{
    short scode = RSRSLT;          /* Normal result code (default) */
    int   stat;
    char  errmsg[80];

    ads_init(argc, argv);          /* Initiate communication with AutoLISP */

    for ( ;; ) {                   /* Request/Result loop */

        if ((stat = ads_link(scode)) < 0) {
            sprintf(errmsg,
                    /*MSG1*/"APPMNGR: bad status from ads_link() = %d\n",
                    stat);
#ifdef Macintosh
            macalert(errmsg);
#else
            puts(errmsg);
            fflush(stdout);
#endif /* Macintosh */
            exit(1);
        }

        scode = RSRSLT;           /* Reset result code */

        switch (stat) {

        case RQXLOAD:             /* Load & define functions */
            scode = funcload() ? -RSRSLT : -RSERR;
            break;

        case RQXUNLD:             /* Unload functions */
            scode = funcunload() ? -RSRSLT : -RSERR;
            ads_printf(/*MSG2*/"Unloading.\n");
            break;

        case RQSUBR:             /* Handle request for external function */
            dofun();
            break;

        default:
            break;
        }
    }
}

/******************************************************************************/
/*.doc testappmngr(internal) */
/*+
    This function is called from dofun function as a result of RQSUBR
    request being sent to the main dispatch loop.

    The function will walk thru the AppTable and perform an ADS_XLOAD
    on each application.  The message Loading apname... will be printed
    before each application is attempted to be loaded.  If the load
    fails, then the message will be followed by the messaged FAILED..

    The next phase of the test will make a call to the function
    ADS_LOADED to obtain the list of currently loaded applications.  It
    will then walk thu the list and perform an ADS_XUNLOAD on each
    application.  The message Unloading appname... will be printed
    before each application is attempted to be unloaded.  Note, that
    some applications may generate messages of their own, so the output
    may not be exactly as described.  If an application fails to be
    unloaded, then the message FAILED will follow the unloading
    message.

    This function always returns RTNORM.
-*/
/******************************************************************************/
int
/*FCN*/testappmngr()
{
    rbtype      *args;
    rbtype      *tapl;
    rbtype      *applist;
    int         x;
    int         i;
    int         pcount;

    args = ads_getargs();
    ads_printf(/*MSG3*/"\nPerforming ads_xload, ads_xunload, and ads_loaded test\n");
    pcount = 5;
    if (args != NULL) {
        if (args->restype == RTSHORT)
            pcount = args->resval.rint;
    }

    for (i = 1; i <= pcount; i++) {
        ads_printf(/*MSG4*/"\n\n\nPass %d.\n\n\n", i);
        for (x = 0; x < ELEMENTS(AppTable); x++) {
            ads_printf(/*MSG5*/"Loading %s...\n", AppTable[x]);
            if (ads_xload(AppTable[x]) != RTNORM)
                switch(geterrno()) {
                case OL_ENULLPTR:
                    ads_printf(/*MSG6*/"Filename argument was a NULL pointer.\n");
                    break;
                case OL_EOPEN:
                    ads_printf(/*MSG7*/"Specified file could not be opened.\n");
                    break;
                case OL_ELOADED:
                    ads_printf(/*MSG8*/"Specified file is already loaded.\n");
                    break;
                case OL_ENOMEM:
                    ads_printf(/*MSG9*/"No room for app control block.\n");
                    break;
                case OL_EMAXAPP:
                    ads_printf(/*MSG10*/"Max number of ADS apps loaded.\n");
                    break;
                case OL_EEXEC:
                    ads_printf(/*MSG11*/"App could not be executed.\n");
                    break;
                case OL_EVERSION:
                    ads_printf(/*MSG12*/"App contains wrong ADS version #.\n");
                    break;
                }
        }

        for (tapl = applist = ads_loaded(); tapl != NULL; tapl = tapl->rbnext) {
            if (tapl->restype == RTSTR && tapl->resval.rstring != NULL) {
                ads_printf(/*MSG13*/"Unloading %s...\n", tapl->resval.rstring);
                if (ads_xunload(tapl->resval.rstring) != RTNORM)
                    switch(geterrno()) {
                    case OL_ENULLPTR:
                        ads_printf(/*MSG14*/"Filename argument was a NULL pointer.\n");
                        break;
                    case OL_EDENIED:
                        ads_printf(/*MSG15*/"An app cannot unload itself this way,\n");
                        ads_printf(/*MSG16*/"and nested apps cannot be unloaded.\n");
                        break;
                    case OL_EREFUSE:
                        ads_printf(/*MSG17*/"App refused to unload.\n");
                        break;
                    case OL_ENOTLOADED:
                        ads_printf(/*MSG18*/"App is not loaded, so it\n");
                        ads_printf(/*MSG19*/"cannot be unloaded.\n");
                        break;
                    }
            }
        }

        if (applist != NULL)
            ads_relrb(applist);
    }
    return RTNORM;
}
