/* Next available MSG number is     3 */

/*****************************************************************************
      CAL.C
      (C) Copyright 1988-1994 by Autodesk, Inc.

      This program is copyrighted by Autodesk, Inc. and is  licensed
      to you under the following conditions.  You may not distribute
      or  publish the source code of this program in any form.   You
      may  incorporate this code in object form in derivative  works
      provided  such  derivative  works  are  (i.) are  designed and 
      intended  to  work  solely  with  Autodesk, Inc. products, and 
      (ii.)  contain  Autodesk's  copyright  notice  "(C)  Copyright  
      1988-1993 by Autodesk, Inc."

      AUTODESK  PROVIDES THIS PROGRAM "AS IS" AND WITH  ALL  FAULTS.
      AUTODESK  SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF  MER-
      CHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK,  INC.
      DOES  NOT  WARRANT THAT THE OPERATION OF THE PROGRAM  WILL  BE
      UNINTERRUPTED OR ERROR FREE.

  Description: The main file of the "Geometry Calculator" ADS application.

  Notes:

  The Geometry Calculator application consists of the following files:

  cal.c      ... The main file establishing link with ADS
  callex.c   ... Lexical analyser
  calexpr.c  ... Syntax analyser
  calmngf.c  ... Management of calculator functions
  calstdf.c  ... Standard calculator functions
  calusrf.c  ... User-defined calculator functions
  calerr.c   ... Error handling
  util.c     ... Some utility functions

  callex.h   ... Hearer file for callex.c
  calexpr.h  ... Header file for calexpr.c
  calmngf.h  ... Header file for calmngf.c
  calerr.h   ... Header file for calerr.c
  util.h     ... Header file for util.c
  cal.h      ... Includes all the above include files plus some basic
                 C include files.

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


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

#define MODULE_ID CAL_C_

#include  "cal.h"

#include "xmf.h"
#include "ads_ix.h"

/* Application name */ 
extern char ads_appname[];

/****************************************************************************/
/*  IMPORTED FUNCTIONS                                                      */
/****************************************************************************/

void cal_register_standard_functions _((void));
void cal_register_user_functions _((void));


/****************************************************************************/
/*  STATIC VARIABLES AND FUNCTIONS                                          */
/****************************************************************************/

static int calculator_function _((void));
static int load_ADS_functions _((void));
static int execute_ADS_function _((void));

static struct {char *name; int msgind; int (*func) _((void));} ADS_funcs_table[] =
{
    /*MSG0*/"CAL",    3,  calculator_function,
    /*MSG0*/"C:CAL",  4,  calculator_function,
};


/****************************************************************************/
/*.doc load_ADS_functions(internal)*/
/*+
    Standard code for loading the ADS functions from 'ADS_funcs_table[]'.
-*/
/****************************************************************************/


static int
/*FCN*/load_ADS_functions()
{
    int i, ni = ELEMENTS(ADS_funcs_table);
    char *fnom;

    for (i = 0; i < ELEMENTS(ADS_funcs_table); i++)
    {
        if (ads_defun(ADS_funcs_table[i].name, i) != RTNORM) {
            return(RSERR);
        }
	if (ads_regfunc(ADS_funcs_table[i].func, i) != RTNORM) {
	    return(RSERR);
	}

	/* Now define and register the localized names for each function */
        fnom = XMSG("(various)", ADS_funcs_table[i].msgind);
	if (ads_defun(fnom, i + ni) != RTNORM) {
	    return(RSERR);
	}
	if (ads_regfunc(ADS_funcs_table[i].func, i + ni) != RTNORM) {
	    return(RSERR);
	}
    }
    return(RSRSLT);
} /*load_ADS_functions*/


/****************************************************************************/
/*.doc execute_ADS_function(internal)*/
/*+
    Standard code for executing an ADS function from 'ADS_funcs_table[]'.
-*/
/****************************************************************************/


static int
/*FCN*/execute_ADS_function()
{
    int           i;

    if (((i = ads_getfuncode()) < 0) ||
        (i >= ELEMENTS(ADS_funcs_table))) {
        return(RSERR);
    }

    ads_retnil();

    (*ADS_funcs_table[i].func)();

    return(RSRSLT);
} /*execute_ADS_function*/


/****************************************************************************/
/*.doc main(external)*/
/*+
    The main function.
-*/
/****************************************************************************/


void
/*FCN*/main(argc, argv)

  int  argc;
  char *argv[];
{
    int   request;
    short success         = RSRSLT;
    int   load_first_time = TRUE;
    char errmsg[80];

    ads_init(argc,argv);
    cal_err = FALSE;

    XMF_init(ads_appname, (void(*)())ads_abort);

    for (;;) {

        if ((request = ads_link(success)) < 0) {
            sprintf(errmsg,
                    XMSG("cal: bad status from ads_link() = %d\n", 1),
                    request);
#ifdef Macintosh
            macalert(errmsg);
#else
            puts(errmsg);
            fflush(stdout);
#endif /* Macintosh */
	    XMF_term();
            ads_exit(1);
        }
        success = RSRSLT;

        switch (request) {

        case RQXLOAD:
            if (load_first_time) {
                cal_register_standard_functions();
                cal_register_user_functions();
                if (cal_err)
		{
		    XMF_term();
                    ads_exit(1);
		}
                load_first_time = FALSE;
            }
            success = load_ADS_functions();
            break;

        case RQSUBR:
            success = execute_ADS_function();
            break;

        case RQXUNLD:
	    XMF_term();
	    break;
        case RQSAVE:
	    break;
        case RQQUIT:
        case RQEND:
	    XMF_term();
            break;

        default:
            break;
        } /*switch*/
    } /*forever*/

} /*main*/


/****************************************************************************/
/*.doc calculator_function(internal)*/
/*+
  Function evaluates arithmetic expression string which it receives 
  in 'buff'. If no result buffer is provided, the function prompts
  for a string.
-*/
/****************************************************************************/


static int
/*FCN*/calculator_function()

{
    struct resbuf *buff;
    int             success;
    vector_real_int value;
    char            line[MAX_LINE_LENGTH+1];

    buff = ads_getargs();

    do {
        cal_err = 0;                  /* Reset the global error flag */
        
        /* Get the input entier from the string resbuf, or, 
           if not present, prompt the user to enter a string */
        
        if (buff != NULL) {
            if ((buff->restype != RTSTR) || (buff->rbnext != NULL)) {
                error(27, NULL);
                return FALSE;
            } else {
                strcpy(line, buff->resval.rstring);
            }
        } else {
            do {
                ads_initget(1, NULL);
                success = ads_getstring(TRUE, XMSG(">> Expression: ", 2), line);
                
                if (success == RTCAN) {
                    return RSRSLT;
                } else if (success != RTNORM) {
                    error(27, NULL);
                    return RSERR;
                }
            } while (line[0] == EOS);
        }
        
        success = cal_evaluate_expression(line, &value);
        
        if (success) {
            switch (value.type) {
            case vector_type:
                ads_retpoint(value.v);
                break;
            case real_type:
                ads_retreal(value.r);
                break;
            case int_type:
                ads_retint((int)value.r);
                break;
            default:
                break;
            } /*switch*/
        } 
    } while (!success && (buff == NULL));

    return RSRSLT;  /* Returns always true */

} /*calculator_function*/
