/*
**
** FUNCS.C     A module to be included with EVAL.C that handles
**             the manipulation of functions.
**
** Originally written 5/89 in ANSI C
**
** To add/change the functions in Eval:
** --------------------------------------------------------------
** 1. If the name of your function is longer than MAXFLEN, or the
**    argument list string is longer than MAXALEN, then increase the
**    size of these defines (MAXFLEN in eval.h, MAXALEN in funcs.c).
** 1. Update the value of NUMFUNCS in eval.h (total number of functions).
** 2. Add a #define for any new functions to the list of #defines
**    below.  You do not need to keep the list in alphabetic order.
** 3. Add the function ID (#define tag), name, argument list, and a
**    brief descripton to the flist[] array below.  Please keep the list
**    in alphabetic order by function name.
** 4. Add the actual function code to the func_eval function below.
**    Follow the examples of other functions.
** 5. If necessary, add the C-code for new math functions to emath.c,
**    and add prototypes for new C math functions to eval.h
**    NOTICE:  Read the disclaimer about adding code to emath.c in
**             the comments of emath.c.
** 6. Recompile ALL modules.
**
**
** Eval is a floating point expression evaluator.
** This file last updated in version 1.12
** For the version number, see eval.h
** Copyright (C) 1993  Will Menninger
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
** Free Software Foundation; either version 2 of the License, or any
** later version.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License along
** with this program; if not, write to the Free Software Foundation, Inc.,
** 675 Mass Ave, Cambridge, MA 02139, USA.
**
** The author until 9/93 can be contacted at:
** e-mail:     willus@ilm.pfc.mit.edu
** U.S. mail:  Will Menninger, 45 River St., #2, Boston, MA 02108-1124
**
*/

#include   "eval.h"

#define    ABSVAL      1
#define    ACOS        2
#define    ACOSH       3
#define    ASIN        4
#define    ASINH       5
#define    ATAN        6
#define    ATAN2       7
#define    ATANH       8
#define    BESSI       9
#define    BESSJ       10
#define    BESSK       11
#define    CEIL        12
#define    COS         13
#define    COSH        14
#define    DBESSI      15
#define    DBESSJ      16
#define    DBESSK      17
#define    DJROOT      18
#define    EXP         19
#define    FACT        20
#define    FLOOR       21
#define    JROOT       22
#define    LN          23
#define    LOG         24
#define    SIGN        25
#define    SIN         26
#define    SINH        27
#define    SQRT        28
#define    TAN         29
#define    TANH        30

FUNC    flist[NUMFUNCS] =
{
{ABSVAL,"abs",    "x",  "absolute value"                              },
{ACOS,  "acos",   "x",  "arccosine, return value in radians"          },
{ACOSH, "acosh",  "x",  "inverse hyperbolic cosine"                   },
{ASIN,  "asin",   "x",  "arcsine, return value in radians"            },
{ASINH, "asinh",  "x",  "inverse hyperbolic sine"                     },
{ATAN,  "atan",   "x",  "arctangent, return value in radians"         },
{ATAN2, "atan2",  "y,x","arctangent of y/x, return value in radians"  },
{ATANH, "atanh",  "x",  "inverse hyperbolic tangent"                  },
{BESSI, "bessi",  "m,x","bessel function Im(x)"                       },
{BESSJ, "bessj",  "m,x","bessel function Jm(x)"                       },
{BESSK, "bessk",  "m,x","bessel function Km(x)"                       },
{CEIL,  "ceil",   "x",  "round up"                                    },
{COS,   "cos",    "x",  "cosine, x in radians"                        },
{COSH,  "cosh",   "x",  "hyperbolic cosine"                           },
{DBESSI,"dbessi", "m,x","derivative of bessel function:  Im'(x)"      },
{DBESSJ,"dbessj", "m,x","derivative of bessel function:  Jm'(x)"      },
{DBESSK,"dbessk", "m,x","derivative of bessel function:  Km'(x)"      },
{DJROOT,"djroot", "m,n","nth non-zero root of Jm'(x)"                 },
{EXP,   "exp",    "x",  "e (2.718..) raised to the power of x"        },
{FACT,  "fact",   "n",  "factorial (n!)"                              },
{FLOOR, "floor",  "x",  "round down"                                  },
{JROOT, "jroot",  "m,n","nth non-zero root of Jm(x)"                  },
{LN,    "ln",     "x",  "natural logarithm (base e)"                  },
{LOG,   "log",    "x",  "logarithm to the base 10"                    },
{SIGN,  "sgn",    "x",  "-1 if x<0, 0 if x=0, +1 if x>0"              },
{SIN,   "sin",    "x",  "sine, x in radians"                          },
{SINH,  "sinh",   "x",  "hyperbolic sine"                             },
{SQRT,  "sqrt",   "x",  "squareroot"                                  },
{TAN,   "tan",    "x",  "tangent, x in radians"                       },
{TANH,  "tanh",   "x",  "hyperbolic tangent"                          }
};


static BOOLEAN func_error(int,int);
static int     maxfunclen(FUNCPTR);

/*
** print_funclist(FILE *s,char *input,int d)
**
** Prints a list of the functions
**
*/
int print_funclist(FILE *s,char *input,int d)

    {
    char    line[MAXALEN+MAXFLEN+MAXDLEN+10];
    int     i,j,k,l,n,m1,nc,cw,nr,li,c;

    m1=maxfunclen(flist)+2;
    cw=m1+2;
    if (d)
        nc=1;
    else
        {
        nc=(SCRWIDTH+3)/cw;
        if (nc<=0)
            nc=1;
        }
    nr=(NUMFUNCS+nc-1)/nc;
    for (i=0;i<nr;i++)
        {
        li=0;
        for (j=0;j<nc;j++)
            {
            k=i+j*nr;
            if (k>=NUMFUNCS)
                break;
            for (l=0;(c=flist[k].name[l])!=EOS;l++)
                line[li++]=c;
            line[li++]='(';
            for (l++,n=l;(c=flist[k].argspec[l-n])!=EOS;l++)
                line[li++]=c;
            line[li++]=')';
            for (l++;l<m1;l++)
                line[li++]=' ';
            if (d)
                {
                for (l=0;l<4;l++)
                    line[li++]=' ';
                line[li]=EOS;
                strcat(line,flist[k].desc);
                li=strlen(line);
                }
            else
                if (j<nc-1)
                    for (;l<cw;l++)
                        line[li++]=' ';
            }
        line[li]=EOS;
        printf("%s\n",line);
        if (s==stdin && i!=nr-1 && ((i+3)%NLINES)==0)
            {
            printf("\nPress <ENTER> for more...\n");
            printf("%s",PROMPT);
            input[0]=EOS;
            fgets(input,MAXINPUT,s);
            fixup(input);
            if (input[0]!=EOS)
                return(1);
            printf("\n");
            }
        }
    printf("\n");
    return(0);
    }


/*
** maxfunclen(FUNCPTR flist)
**
** returns the length of the longest function name plus arguments
** (used for printing)
**
*/

static int maxfunclen(FUNCPTR flist)

   {
   int     i,len,max;

   for (max=strlen(flist[0].name)+strlen(flist[0].argspec),i=1;i<NUMFUNCS;i++)
       if ((len=strlen(flist[i].name)+strlen(flist[i].argspec))>max)
           max=len;
   return(max);
   }


int func_code(char *s)

    {
    int    i,step,c,count;

    i=step=NUMFUNCS>>1;
    count=0;
    while (1)
        {
        if (step>1)
            step>>=1;
        else
            {
            count++;
            if (count>5)
                break;
            }
        if (!(c=strcmp(s,flist[i].name)))
            return(i+1);
        if (c>0)
                {
                if (i==NUMFUNCS-1)
                    break;
                i=i+step;
                continue;
                }
        if (i==0)
            break;
        i=i-step;
        }
    return(0);
    }



int func_nargs(int code)

    {
    return((int)((strlen(flist[code-1].argspec)+1)/2));
    }


char *func_name(int code)

    {
    return(flist[code-1].name);
    }


BOOLEAN func_eval(int code,double *args,double *ret_val)

    {
    switch (flist[code-1].id)
        {
        case ABSVAL:
            (*ret_val)=fabs(args[0]);
            return(1);
        case ACOS:
            if (args[0]<-1 || args[0]>1)
                return(func_error(code,0));
            (*ret_val)=acos(args[0]);
            return(1);
        case ACOSH:
            if (args[0]<1)
                return(func_error(code,0));
            (*ret_val)=acosh(args[0]);
            return(1);
        case ASIN:
            if (args[0]<-1 || args[0]>1)
                return(func_error(code,0));
            (*ret_val)=asin(args[0]);
            return(1);
        case ASINH:
            (*ret_val)=asinh(args[0]);
            return(1);
        case ATAN:
            (*ret_val)=atan(args[0]);
            return(1);
        case ATAN2:
            (*ret_val)=atan2(args[0],args[1]);
            return(1);
        case ATANH:
            if (args[0]<=-1 || args[0]>=1)
                return(func_error(code,0));
            (*ret_val)=atanh(args[0]);
            return(1);
        case BESSI:
            if (args[0]!=((int)args[0]))
                return(func_error(code,1));
            (*ret_val)=bessi((int)args[0],args[1]);
            return(1);
        case BESSJ:
            if (args[0]!=((int)args[0]))
                return(func_error(code,1));
            (*ret_val)=bessj((int)args[0],args[1]);
            return(1);
        case BESSK:
            if (args[0]!=((int)args[0]))
                return(func_error(code,1));
            (*ret_val)=bessk((int)args[0],args[1]);
            return(1);
        case CEIL:
            (*ret_val)=ceil(args[0]);
            return(1);
        case COS:
            (*ret_val)=cos(args[0]);
            return(1);
        case COSH:
            (*ret_val)=cosh(args[0]);
            return(1);
        case DBESSI:
            if (args[0]!=((int)args[0]))
                return(func_error(code,1));
            (*ret_val)=dbessi((int)args[0],args[1]);
            return(1);
        case DBESSJ:
            if (args[0]!=((int)args[0]))
                return(func_error(code,1));
            (*ret_val)=dbessj((int)args[0],args[1]);
            return(1);
        case DBESSK:
            if (args[0]!=((int)args[0]))
                return(func_error(code,1));
            (*ret_val)=dbessk((int)args[0],args[1]);
            return(1);
        case DJROOT:
            if (args[0]!=((int)args[0]))
                return(func_error(code,1));
            if (args[1]!=((int)args[1]) || args[1]<1)
                return(func_error(code,2));
            (*ret_val)=djroot((int)args[0],(int)args[1]);
            return(1);
        case EXP:
            (*ret_val)=exp(args[0]);
            return(1);
        case FACT:
            if (args[0]<0)
                return(func_error(code,5));
            if (args[0]!=((int)args[0]))
                return(func_error(code,3));
            (*ret_val)=factorial((int)args[0]);
            return(1);
        case FLOOR:
            (*ret_val)=floor(args[0]);
            return(1);
        case JROOT:
            if (args[0]!=((int)args[0]))
                return(func_error(code,1));
            if (args[1]!=((int)args[1]) || args[1]<1)
                return(func_error(code,2));
            (*ret_val)=jroot((int)args[0],(int)args[1]);
            return(1);
        case LN:
            if (args[0]<=0)
                return(func_error(code,4));
            (*ret_val)=log(args[0]);
            return(1);
        case LOG:
            if (args[0]<=0)
                return(func_error(code,4));
            (*ret_val)=log10(args[0]);
            return(1);
        case SIGN:
            (*ret_val)=SGN(args[0]);
            return(1);
        case SIN:
            (*ret_val)=sin(args[0]);
            return(1);
        case SINH:
            (*ret_val)=sinh(args[0]);
            return(1);
        case SQRT:
            if (args[0]<0)
                return(func_error(code,5));
            (*ret_val)=sqrt(args[0]);
            return(1);
        case TAN:
            (*ret_val)=tan(args[0]);
            return(1);
        case TANH:
            (*ret_val)=tanh(args[0]);
            return(1);
        }
    printf("Unknown function code.\n");
    return(0);
    }


static BOOLEAN func_error(int code,int error)

    {
    static char *error_code[] = {
                "argument out of range",
                "first argument must be an integer",
                "second argument must be a positive integer",
                "argument must be an integer",
                "argument must be positive",
                "argument must be non-negative",
                };
    printf("%s:  %s.\n",flist[code-1].name,error_code[error]);
    return(0);
    }


syntax highlighted by Code2HTML, v. 0.9.1