/* Next available MSG number is   6 */

/*    

   SQR.C

   Copyright (C) 1990, 1991, 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 SQUARE ROOT application - by Mark Barrow - 3/14/90
 * Comments and revisions - Randy Clark, 4/23/90
 **********************************************************************
 */

#include  <stdio.h>
#include  <math.h>
#include  "adslib.h"

#define ExtFuncCount    1             /* Must increase this count if new
                                         external functions are added */

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

char *exfun[] = {/*MSG0*/"sqr"};      /* No "C:" -- to be called as an AutoLISP
                                         function, not as an AutoCAD command */

/* More functions could be added to this table.  For example:
   char *exfun[] = {"C:sqr", "C:shaft", "PIN"}; */

/*-----------------------------------------------------------------------*/
/* MAIN - the main routine */

void 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*/"SQRT: 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 */
            scode = dofun() ? RSRSLT : RSERR;
            break;

        default:
            break;
        }
    }
}
/*-----------------------------------------------------------------------*/
/* FUNCLOAD  --  Define this application's external functions  */

int funcload()
{
    int i;
    for (i = 0; i < ExtFuncCount; i++) {
        if (!ads_defun(exfun[i], i))
            return RTERROR;
    }
    return RTNORM;
}
/*-----------------------------------------------------------------------*/
/* FUNCUNLOAD  --  Unload external functions */

int funcunload()
{
    int i;

    /* Undefine each function we defined */

    for (i = 0; i < ExtFuncCount; i++) {
        ads_undef(exfun[i],i);
    }
    return RTNORM;
}
/*-----------------------------------------------------------------------*/
/* DOFUN -- Execute external function (called upon an RQSUBR request) */

int dofun()
{
    struct resbuf *rb;
    int val;
    ads_real x;
    extern ads_real rsqr _((ads_real));

    if ((val = ads_getfuncode()) < 0)
        return 0;

    if ((rb = ads_getargs()) == NULL)
        return 0;

    switch (val) {                    /* The 'sqr' function was defined
                                         to have a funcode of 0 */

    case 0:
        if (rb->restype == RTSHORT) {   /* Save in local variable */
            x = (ads_real) rb->resval.rint;
        } else if (rb->restype == RTREAL) {
            x = rb->resval.rreal;     /* Can accept either real
                                         or integer */
        } else {
            ads_fail(/*MSG3*/"Argument should be a real or integer value.");
            return 0;
        }
        if (x < 0) {                  /* Check argument range */
            ads_fail(/*MSG4*/"Argument should be positive.");
            return 0;
        }

        ads_retreal(rsqr(x));         /* Call the function itself, and
                                         return the value to AutoLISP */

        return 1;

    default:
        ads_fail(/*MSG5*/"Received nonexistent function code.");
        return 0;
    }
}
/*-----------------------------------------------------------------------*/
/* This is the implementation of the actual external function */

ads_real rsqr(x)              /* Figure square root (Newton-Raphson method) */
  ads_real x;
{
    ads_real y, c, cl;
    int n;

    if (x == 0.0) {
        return 0.0;
    }

#ifdef __STDC__
    y = frexp(x, &n);        /* split x to get exponent */
    y = ldexp(1.0, n / 2);   /* good guess at sqrt */
    n = 10;                  /* it will converge faster than this */
#else
    y = (0.154116 + 1.893872 * x) / (1.0 + 1.047988 * x);
    /* It takes a lot of iterations to get sqrt(1E22) from
       an initial guess of 1.9 */
    n = 50;
#endif
    c = 0.0;
    do {
        cl = c;
        c = (y - x / y) * 0.5;
        y -=  c;
    } while (c != cl && --n);
    return y;
}
