/* Next available MSG number is  89 */

/*
   ADS_PERR.CC

   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.
    
   .

   ADS_PERR.C   -  ADS routine to print the error message
                   associated with the value of "errno" upon failure
                   of a call to AutoCAD.  This routine is meant to be
                   invoked by other ADS programs, and contains a table
                   of the current error messages as found in ol_errno.h.
                   This routine is meant to parallel the Unix
                   perror() function.

                   ads_perror() is a Lisp-callable or invokable function that
                   takes an optional single argument and prints the message on
                   the AutoCAD command line.  The syntax is:

                   (ads_perror "string")

                   The string is optional; if provided, it is printed on a
                   separate line before the system error message.  To be of
                   most use, the argument string should include the name of the
                   program that incurred the error.  The error number is taken
                   from the system variable "errno", which is set when most
                   errors occur, but not cleared when non-erroneous calls are
                   made.
 */


#include <stdlib.h>
#include <iostream.h>
#include <string.h>
#include "rxdefs.h"
#include "adslib.h"
#include "ol_errno.h"


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


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


extern int ads_perror();

int funcload   (void);
int funcunload (void);
int dofun      (void);


/* The error message array */
static struct {
    int num;                          /* AutoCAD ERRNO code */
    char *msg;                        /* Explanatory message */
} errtbl[] = {
    {  0, /*MSG88*/"Normal status; no error noted." },
    {  1, /*MSG1*/"Invalid symbol table name." },
    {  2, /*MSG2*/"Invalid name (entity or selection set) value." },
    {  3, /*MSG3*/"Exceeded max number of selection sets." },
    {  4, /*MSG4*/"Invalid selection set." },
    {  5, /*MSG5*/"Improper use of Block Definition entity." },
    {  6, /*MSG6*/"Improper use of Xref entity." },
    {  7, /*MSG7*/"Entity selection failure by pick." },
    {  8, /*MSG8*/"End of entity file." },
    {  9, /*MSG9*/"End of Block Definition file." },
    { 10, /*MSG10*/"Failure of eidlast." },
    { 11, /*MSG11*/"Illegal entdel of Viewport." },
    { 12, /*MSG12*/"Operation not allowed during PLINE." },
    { 13, /*MSG13*/"Invalid handle." },
    { 14, /*MSG14*/"Handles not enabled." },
    { 15, /*MSG15*/"Invalid TRANS request." },
    { 16, /*MSG16*/"Invalid space trans request." },
    { 17, /*MSG17*/"Invalid use of deleted entity." },
    { 18, /*MSG18*/"Invalid table name." },
    { 19, /*MSG19*/"Invalid table function argument." },
    { 20, /*MSG20*/"Attempt to set read-only variable." },
    { 21, /*MSG21*/"Zero value invalid." },
    { 22, /*MSG22*/"Value out of range." },
    { 23, /*MSG23*/"Complex regen in progress." },
    { 24, /*MSG24*/"Attempt to change entity type." },
    { 25, /*MSG25*/"Bad layer name." },
    { 26, /*MSG26*/"Bad linetype name." },
    { 27, /*MSG27*/"Bad color name." },
    { 28, /*MSG28*/"Bad text style name." },
    { 29, /*MSG29*/"Bad shape name." },
    { 30, /*MSG30*/"Bad field for entity type." },
    { 31, /*MSG31*/"Attempted entmod of deleted entity." },
    { 32, /*MSG32*/"Attempted entmod of SEQEND." },
    { 33, /*MSG33*/"Attempt to change handle." },
    { 34, /*MSG34*/"Illegal modification of viewport visibility." },
    { 35, /*MSG35*/"Entity on locked layer." },
    { 36, /*MSG36*/"Bad entity type." },
    { 37, /*MSG37*/"Bad PLINE entity." },
    { 38, /*MSG38*/"Incomplete complex entity in block." },
    { 39, /*MSG39*/"Invalid block name field." },
    { 40, /*MSG40*/"Duplicate block flag fields." },
    { 41, /*MSG41*/"Duplicate block name fields." },
    { 42, /*MSG42*/"Bad normal vector." },
    { 43, /*MSG43*/"Missing block name." },
    { 44, /*MSG44*/"Missing block flags." },
    { 45, /*MSG45*/"Invalid anonymous block." },
    { 46, /*MSG46*/"Invalid Block Definition entity." },
    { 47, /*MSG47*/"Mandatory field missing." },
    { 48, /*MSG48*/"Unrecognized extended data type." },
    { 49, /*MSG49*/"Improper nesting of list in Xdata." },
    { 50, /*MSG50*/"Improper location of APPID field." },
    { 51, /*MSG51*/"Exceeded maximum Xdata size." },
    { 52, /*MSG52*/"Entity selection failure by null response." },
    { 53, /*MSG53*/"Duplicate application name in Xdata." },
    { 54, /*MSG56*/"Attempt to make or modify Viewport entity." },
    { 55, /*MSG57*/"Attempt to make an Xref or dependent symbol." },
    { 56, /*MSG58*/"Bad ssget filter: unterminated clause." },
    { 57, /*MSG59*/"Bad ssget filter: missing test operand." },
    { 58, /*MSG60*/"Bad ssget filter: invalid test operation string." },
    { 59, /*MSG61*/"Bad ssget filter: empty clause or improper nesting." },
    { 60, /*MSG62*/"Bad ssget filter: begin/end clause mismatch." },
    { 61, /*MSG63*/"Bad ssget filter: wrong number of XOR/NOT operands." },
    { 62, /*MSG64*/"Bad ssget filter: maximum nesting level exceeded." },
    { 63, /*MSG65*/"Bad ssget filter: invalid group code." },
    { 64, /*MSG66*/"Bad ssget filter: invalid string test." },
    { 65, /*MSG67*/"Bad ssget filter: invalid vector test." },
    { 66, /*MSG68*/"Bad ssget filter: invalid real test." },
    { 67, /*MSG69*/"Bad ssget filter: invalid integer test." },
    { 68, /*MSG70*/"Digitizer isn't a tablet" },
    { 69, /*MSG71*/"Tablet isn't calibrated." },
    { 70, /*MSG72*/"Invalid arguments to (TABLET) function." },
    { 71, /*MSG73*/"Not enough memory to allocate resbuf." },
    { 72, /*MSG74*/"NULL Pointer was provided as an argument." },
    { 73, /*MSG75*/"The specified file can't be opened." },
    { 74, /*MSG76*/"The specified application is already loaded." },
    { 75, /*MSG77*/"The maximum number of loaded ADS apps has been reached." },
    { 76, /*MSG78*/"The specified application could not be executed." },
    { 77, /*MSG79*/"The ADS app has an incompatible version number." },
    { 78, /*MSG80*/"The ADS app is active or nested and can't be unloaded." },
    { 79, /*MSG81*/"The ADS application refused to XUNLOAD." },
    { 80, /*MSG82*/"The specified ADS application is not loaded." },
    { 81, /*MSG83*/"Insuficient memory to load ADS application." },
    { 82, /*MSG84*/"Invalid transformation matrix." },
    { 83, /*MSG85*/"Invalid symbol name." },
    { 84, /*MSG86*/"Invalid symbol value." },
    { 85, /*MSG87*/"Operation not allowed while a dialogue box is active." },
};

/* Table of ADS functions */
ftblent exfun[] = {
		{"ADS_PERROR", ads_perror},
};


extern "C" {                         
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg,void * pkt);
}


/******************************************************************************/
/*.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;
		// When ads_regfunc works...
		//
		// ads_regfunc(ads_perror, 0) == RTNORM);
    }
    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);
}


AcRx::AppRetCode 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:
	    break;
        case AcRx::kInvkSubrMsg:
            dofun();
            break;
        case AcRx::kLoadADSMsg:
            funcload();
            break;
        case AcRx::kUnloadADSMsg:
            funcunload();
            ads_printf(/*MSG2*/"Unloading.\n");
            break;
	case AcRx::kUnloadAppMsg:
        default:
	    break;
    }
    return AcRx::kRetOK;
}

 
int
ads_perror()
{
    int i;
    struct resbuf *argl, errval;

    if (ads_getfuncode() != 0)        /* This is the ONLY function here */
        return RSRSLT;

    if (ads_getvar(/*MSG0*/"ERRNO", &errval) == RTERROR)
        return RSRSLT;

    argl = ads_getargs();
    if (argl && argl->restype == RTSTR && strlen(argl->resval.rstring))
        ads_printf("%s: ", argl->resval.rstring);

    for (i = 0; i < ELEMENTS(errtbl); i++)
        if (errtbl[i].num == errval.resval.rint && errtbl[i].msg != NULL)
            break;

    if (i < ELEMENTS(errtbl))
        ads_printf("%s\n", errtbl[i].msg);
    else
        ads_printf("Unknown error code %d.\n", errval.resval.rint);

    ads_retvoid();

    return RSRSLT;
}


