GnuCash 2.4.99
fin-interactive.c
00001 /***************************************************************************
00002                           fin-interactive.c  -  description
00003                              -------------------
00004     begin                : Thursday June 15 2000
00005     email                : tboldt@attglobal.net
00006     Author               : Terry D. Boldt
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 /*
00019  *  Functions to interact with user and call financial equations
00020  *  6-22-2000
00021  *
00022  */
00023 
00024 #include <stdio.h>
00025 #include <string.h>
00026 #include <time.h>
00027 #include <mcheck.h>
00028 
00029 #include "finvar.h"
00030 #include "finproto.h"
00031 #include "fin_spl_protos.h"
00032 #include "numeric_ops.h"
00033 
00034 static void  prt_status(
00035     fi_ptr       fi,
00036     FILE        *ofile);
00037 
00038 static void set_fin_vars(
00039     void);
00040 
00041 static void unset_fin_vars(
00042     void);
00043 
00044 #define PREDEFINED_FIN_VARS 9
00045 
00046 /* define local financial variables
00047  */
00048 static unsigned npp;
00049 static double   ir;
00050 static double   pv;
00051 static double   pmt;
00052 static double   fv;
00053 static unsigned CF;
00054 static unsigned PF;
00055 static unsigned disc;
00056 static unsigned bep;
00057 
00058 /* define local variable for roundoff precesion
00059  * default here to value for US currency
00060  */
00061 static unsigned prec = 2;
00062 
00063 /* declare array of structures for local financial variables
00064  */
00065 static var_store      predefined_fin_vars[PREDEFINED_FIN_VARS];
00066 
00067 /* declare array of finacial varibale names used by user to access financial variables
00068  */
00069 static char *fin_var_names[] =
00070 {
00071     "n",
00072     "i",
00073     "pv",
00074     "pmt",
00075     "fv",
00076     "CF",
00077     "PF",
00078     "disc",
00079     "bep",
00080 };
00081 
00082 /* declare array of financial variables
00083  */
00084 static void *fin_vars[] =
00085 {
00086     (void *)&npp,
00087     (void *)&ir,
00088     (void *)&pv,
00089     (void *)&pmt,
00090     (void *)&fv,
00091     (void *)&CF,
00092     (void *)&PF,
00093     (void *)&disc,
00094     (void *)&bep,
00095 };
00096 
00097 /* declare array of financial variable basic numeric types
00098  */
00099 static char fin_type[] =
00100 {
00101     INT_TYPE,
00102     DBL_TYPE,
00103     DBL_TYPE,
00104     DBL_TYPE,
00105     DBL_TYPE,
00106     INT_TYPE,
00107     INT_TYPE,
00108     INT_TYPE,
00109     INT_TYPE,
00110 };
00111 
00112 static char sl_commands[] = "acdqsv";
00113 
00114 /* function to set local financial variables into array for use by expression parser
00115  * as pre-defined variables
00116  */
00117 static void set_fin_vars(
00118     void)
00119 {
00120     unsigned    cntr;
00121     numeric_ptr value;
00122 
00123     for ( cntr = 0 ; cntr < PREDEFINED_FIN_VARS ; cntr++ )
00124     {
00125         predefined_fin_vars[cntr].variable_name = fin_var_names[cntr];
00126         predefined_fin_vars[cntr].assign_flag = EOS;
00127         predefined_fin_vars[cntr].value = value = (numeric_ptr)calloc(1, sizeof(numeric));
00128         predefined_fin_vars[cntr].next_var = &predefined_fin_vars[cntr + 1];
00129         switch ( value->type = fin_type[cntr] )
00130         {
00131         case INT_TYPE:
00132             value->value.int_value = *(unsigned *)(fin_vars[cntr]);
00133             break;
00134         case DBL_TYPE:
00135             value->value.dbl_value = *(double *)(fin_vars[cntr]);
00136             break;
00137         } /* endswitch */
00138     } /* endfor */
00139     predefined_fin_vars[PREDEFINED_FIN_VARS - 1].next_var = NULL;
00140 } /* set_fin_vars */
00141 
00142 /* free storage used by local financial variables
00143  */
00144 static void unset_fin_vars(
00145     void)
00146 {
00147     unsigned    cntr;
00148     numeric_ptr value;
00149 
00150     for ( cntr = 0 ; cntr < PREDEFINED_FIN_VARS ; cntr++ )
00151     {
00152         free(predefined_fin_vars[cntr].value);
00153     } /* endfor */
00154 } /* unset_fin_vars */
00155 
00156 /* check variable set by expression parser against local financial variables
00157  * and update local values as necessary. Also convert variables to proper type
00158  * to reflect the native type of the local variable
00159  */
00160 void            chk_vars(
00161     var_store_ptr   predefined_vars,
00162     void          **var_array,
00163     char           *var_type,
00164     unsigned        var_cnt)
00165 {
00166     unsigned    cntr;
00167     numeric_ptr value;
00168 
00169     for ( cntr = 0 ; cntr < var_cnt ; cntr++ )
00170     {
00171         if ( predefined_vars[cntr].assign_flag == ASSIGNED_TO )
00172         {
00173             predefined_vars[cntr].assign_flag = EOS;
00174             value = (numeric_ptr)(predefined_vars[cntr].value);
00175             switch ( var_type[cntr] )
00176             {
00177             case INT_TYPE:
00178                 switch ( value->type )
00179                 {
00180                 case INT_TYPE:
00181                     *(int *)(var_array[cntr]) = value->value.int_value;
00182                     break;
00183                 case DBL_TYPE:
00184                     value->value.int_value      =
00185                         *(int *)(var_array[cntr]) = (unsigned)(value->value.dbl_value);
00186                     value->type = INT_TYPE;
00187                     break;
00188                 } /* endswitch */
00189                 break;
00190             case DBL_TYPE:
00191                 switch ( value->type )
00192                 {
00193                 case INT_TYPE:
00194                     value->value.dbl_value         =
00195                         *(double *)(var_array[cntr]) = (double)(value->value.int_value);
00196                     value->type = DBL_TYPE;
00197                     break;
00198                 case DBL_TYPE:
00199                     *(double *)(var_array[cntr]) = value->value.dbl_value;
00200                     break;
00201                 } /* endswitch */
00202                 break;
00203             } /* endswitch */
00204         } /* endif */
00205     } /* endfor */
00206 } /* chk_fin_vars */
00207 
00208 /* error encountered by expression parser - output error message
00209  * and offending string
00210  */
00211 void           parse_error(unsigned error_code,
00212                            char *buf_start,
00213                            char *buf_err)
00214 {
00215     char *err_str;
00216     unsigned       bc = (unsigned)(buf_err - buf_start);
00217 
00218     switch ( error_code )
00219     {
00220     case UNBALANCED_PARENS:
00221         err_str = "Unbalanced Parenthesis\n";
00222         break;
00223     case STACK_OVERFLOW:
00224         err_str = "Stack Overflow\n";
00225         break;
00226     case STACK_UNDERFLOW:
00227         err_str = "Stack Underflow\n";
00228         break;
00229     case UNDEFINED_CHARACTER:
00230         err_str = "Unrecognized Character\n";
00231         break;
00232     case NOT_A_VARIABLE:
00233         err_str = "Need a Variable on Left side of assignment operator, '='\n";
00234         break;
00235     case NOT_A_FUNC:
00236         err_str = "Need a valid Function name.\n";
00237         break;
00238 
00239     } /* endswitch */
00240     printf(err_str);
00241     printf("%s\n", buf_start);
00242     if ( bc ) for ( bc - 1 ; bc ; bc-- ) printf(" ");
00243     printf("^");
00244     /*  printf("%s\n",buf_err + 1);     */
00245     printf("\n");
00246 } /* parse_error */
00247 
00248 int             main(int argc, char **argv, char **env)
00249 {
00250     char   buffer[200], *errp;
00251     size_t          sbuf;
00252     size_t          retcnt;
00253     var_store       value;
00254     var_store_ptr   value_list;
00255     numeric_ptr     nval;
00256     unsigned        compute,
00257            jj,
00258            yrE,
00259            monthE,
00260            dayE,
00261            yrI,
00262            monthI,
00263            dayI;
00264     struct tm      *times_E,
00265             *times_I;
00266     void           *parse_env;
00267     amort_sched     amortsched;
00268     financial_info  fininfo;
00269 
00270     /* check dynamic storage allocation
00271      */
00272     /*          mtrace();       */
00273     set_default(&fininfo);
00274     set_fin_vars();
00275     parse_env = init_parser(predefined_fin_vars,
00276                             '.',
00277                             ',',
00278                             trans_numeric,
00279                             numeric_ops,
00280                             negate_numeric,
00281                             free_numeric);
00282 
00283     npp  = fininfo.npp;
00284     ir   = fininfo.ir;
00285     pv   = fininfo.pv;
00286     pmt  = fininfo.pmt;
00287     fv   = fininfo.fv;
00288     CF   = fininfo.CF;
00289     PF   = fininfo.PF;
00290     disc = fininfo.disc;
00291     bep  = fininfo.bep;
00292 
00293     fininfo.prec = prec;
00294 
00295     printf("Single Letter Commands:\na -- amortization schedule\nc -- compute financial variable\nd -- delete variable\ns -- output financial variable status\nq -- quit\nv -- list defined variables\n");
00296     for (;;)
00297 {
00298         printf("<>");
00299         retcnt = strlen(fgets(buffer, 190, stdin));
00300         if ( (retcnt == 2) && (strchr(sl_commands, buffer[0]) != NULL) )
00301         {
00302             if ( buffer[0] == 'q' ) break;
00303             amortsched.prec = fininfo.prec;
00304             switch ( buffer[0] )
00305             {
00306             case 'a':
00307                 if ( amortsched.Eff_Date_jdn && amortsched.Init_Date_jdn )
00308                 {
00309                     printf("Current Effective  year: %u\nCurrent Effective month: %u\nCurrent Effective   day: %u\nCurrent Initial    year: %u\nCurrent Initial   month: %u\nCurrent Initial     day %u\n",
00310                            amortsched.year_E,
00311                            amortsched.month_E,
00312                            amortsched.day_E,
00313                            amortsched.year_I,
00314                            amortsched.month_I,
00315                            amortsched.day_I);
00316                     printf("Change dates ? (y/n) ");
00317                     fgets(buffer, 190, stdin);
00318                 }
00319                 else
00320                 {
00321                     buffer[0] = 'y';
00322                 } /* endif */
00323                 if ( buffer[0] == 'y' )
00324                 {
00325                     printf("Enter Effective Date - year: ");
00326                     fgets(buffer, 190, stdin);
00327                     if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
00328                     {
00329                         nval = (numeric_ptr)(value.value);
00330                         switch ( nval->type )
00331                         {
00332                         case INT_TYPE:
00333                             amortsched.year_E = nval->value.int_value;
00334                             break;
00335                         case DBL_TYPE:
00336                             amortsched.year_E = (unsigned)(nval->value.dbl_value);
00337                             break;
00338                         } /* endswitch */
00339                         if ( !value.variable_name ) free_numeric(value.value);
00340                     }
00341                     else
00342                     {
00343                         parse_error(get_parse_error(parse_env), buffer, errp);
00344                     } /* endif */
00345                     printf("Enter Effective Date - month: ");
00346                     fgets(buffer, 190, stdin);
00347                     if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
00348                     {
00349                         nval = (numeric_ptr)(value.value);
00350                         switch ( nval->type )
00351                         {
00352                         case INT_TYPE:
00353                             amortsched.month_E = nval->value.int_value;
00354                             break;
00355                         case DBL_TYPE:
00356                             amortsched.month_E = (unsigned)(nval->value.dbl_value);
00357                             break;
00358                         } /* endswitch */
00359                         if ( !value.variable_name ) free_numeric(value.value);
00360                     }
00361                     else
00362                     {
00363                         parse_error(get_parse_error(parse_env), buffer, errp);
00364                     } /* endif */
00365                     printf("Enter Effective Date - day: ");
00366                     fgets(buffer, 190, stdin);
00367                     if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
00368                     {
00369                         nval = (numeric_ptr)(value.value);
00370                         switch ( nval->type )
00371                         {
00372                         case INT_TYPE:
00373                             amortsched.day_E = nval->value.int_value;
00374                             break;
00375                         case DBL_TYPE:
00376                             amortsched.day_E = (unsigned)(nval->value.dbl_value);
00377                             break;
00378                         } /* endswitch */
00379                         if ( !value.variable_name ) free_numeric(value.value);
00380                     }
00381                     else
00382                     {
00383                         parse_error(get_parse_error(parse_env), buffer, errp);
00384                     } /* endif */
00385                     printf("Enter Initial Payment Date - year: ");
00386                     fgets(buffer, 190, stdin);
00387                     if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
00388                     {
00389                         nval = (numeric_ptr)(value.value);
00390                         switch ( nval->type )
00391                         {
00392                         case INT_TYPE:
00393                             amortsched.year_I = nval->value.int_value;
00394                             break;
00395                         case DBL_TYPE:
00396                             amortsched.year_I = (unsigned)(nval->value.dbl_value);
00397                             break;
00398                         } /* endswitch */
00399                         if ( !value.variable_name ) free_numeric(value.value);
00400                     }
00401                     else
00402                     {
00403                         parse_error(get_parse_error(parse_env), buffer, errp);
00404                     } /* endif */
00405                     printf("Enter Initial Payment Date - month: ");
00406                     fgets(buffer, 190, stdin);
00407                     if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
00408                     {
00409                         nval = (numeric_ptr)(value.value);
00410                         switch ( nval->type )
00411                         {
00412                         case INT_TYPE:
00413                             amortsched.month_I = nval->value.int_value;
00414                             break;
00415                         case DBL_TYPE:
00416                             amortsched.month_I = (unsigned)(nval->value.dbl_value);
00417                             break;
00418                         } /* endswitch */
00419                         if ( !value.variable_name ) free_numeric(value.value);
00420                     }
00421                     else
00422                     {
00423                         parse_error(get_parse_error(parse_env), buffer, errp);
00424                     } /* endif */
00425                     printf("Enter Initial Payment Date - day: ");
00426                     fgets(buffer, 190, stdin);
00427                     if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
00428                     {
00429                         nval = (numeric_ptr)(value.value);
00430                         switch ( nval->type )
00431                         {
00432                         case INT_TYPE:
00433                             amortsched.day_I = nval->value.int_value;
00434                             break;
00435                         case DBL_TYPE:
00436                             amortsched.day_I = (unsigned)(nval->value.dbl_value);
00437                             break;
00438                         } /* endswitch */
00439                         if ( !value.variable_name ) free_numeric(value.value);
00440                     }
00441                     else
00442                     {
00443                         parse_error(get_parse_error(parse_env), buffer, errp);
00444                     } /* endif */
00445                 } /* endif */
00446 
00447                 amortsched.n     = npp;
00448                 amortsched.nint  = ir;
00449                 amortsched.pv    = pv;
00450                 amortsched.pmt   = pmt;
00451                 amortsched.fv    = fv;
00452                 amortsched.CF    = CF;
00453                 amortsched.PF    = PF;
00454                 amortsched.disc  = disc;
00455                 amortsched.bep   = bep;
00456 
00457                 Amortization_init(&amortsched);
00458                 amort_opt(&amortsched, parse_env);
00459 
00460                 (void)Amortization_Schedule(&amortsched);
00461                 prt_amortization_schedule(&amortsched, stdout);
00462                 Amortization_free(&amortsched);
00463                 break;
00464             case 'c':
00465 
00466                 printf("Compute:\nn   - 1\ni   - 2\npv  - 3\npmt - 4\nfv  - 5\n1, 2, 3, 4 or 5: ");
00467                 retcnt = strlen(fgets(buffer, 190, stdin));
00468                 compute = buffer[0] - '0';
00469 
00470                 switch ( compute-- )
00471                 {
00472                 case 0: /* all values specified nothing to compute */
00473                     break;
00474                 case 1: /* compute number of periods, npp */
00475                     printf("Computing numbor of periods\n");
00476                     npp = fi_calc_num_payments(&fininfo);
00477                     printf("Number of Periods: %u\n", npp);
00478                     nval = (numeric_ptr)(predefined_fin_vars[compute].value);
00479                     nval->value.int_value = npp;
00480                     break;
00481                 case 2: /* compute interest, ir */
00482                     printf("Computing interest rate\n");
00483                     ir = fi_calc_interest(&fininfo);
00484                     printf("Nominal Interest Rate: %.*f\n", prec, ir);
00485                     nval = (numeric_ptr)(predefined_fin_vars[compute].value);
00486                     nval->value.dbl_value = ir;
00487                     break;
00488                 case 3: /* compute present value, pv */
00489                     printf("Computing Present Value\n");
00490                     pv = fi_calc_present_value(&fininfo);
00491                     printf("Present Value: %.*f\n", prec, pv);
00492                     nval = (numeric_ptr)(predefined_fin_vars[compute].value);
00493                     nval->value.dbl_value = pv;
00494                     break;
00495                 case 4: /* compute periodic payment, pmt */
00496                     printf("Computing periodic payment\n");
00497                     pmt = fi_calc_payment(&fininfo);
00498                     printf("Periodic Payment: %.*f\n", prec, pmt);
00499                     nval = (numeric_ptr)(predefined_fin_vars[compute].value);
00500                     nval->value.dbl_value = pmt;
00501                     break;
00502                 case 5: /* compute future value, fv */
00503                     printf("Computing Future Value\n");
00504                     fv = fi_calc_future_value(&fininfo);
00505                     printf("Future Value: %.*f\n", prec, fv);
00506                     nval = (numeric_ptr)(predefined_fin_vars[compute].value);
00507                     nval->value.dbl_value = fv;
00508                     break;
00509                 default:    /* whoops */
00510                     break;
00511                 } /* endswitch */
00512                 break;
00513             case 'd':
00514                 printf("Enter name of variable to delete: ");
00515                 retcnt = strlen(fgets(buffer, 190, stdin));
00516                 buffer[retcnt - 1] = EOS;
00517                 if ( !delete_var(buffer, parse_env) )
00518                 {
00519                     printf("Unable to delete specified variable\n");
00520                 } /* endif */
00521                 break;
00522             case 's':
00523                 prt_status(&fininfo,
00524                            stdout);
00525                 break;
00526             case 'v':
00527                 for ( value_list = parser_get_vars(parse_env) ; value_list ; value_list = value_list->next_var )
00528                 {
00529                     printf("%s: ", value_list->variable_name);
00530                     nval = (numeric_ptr)(value_list->value);
00531                     switch ( nval->type )
00532                     {
00533                     case INT_TYPE:
00534                         printf("%i\n", nval->value.int_value);
00535                         break;
00536                     case DBL_TYPE:
00537                         printf("%.*f\n", prec, nval->value.dbl_value);
00538                         break;
00539                     } /* endswitch */
00540                 } /* endfor */
00541                 break;
00542             } /* endswitch */
00543         }
00544         else if ( retcnt > 1 )
00545         {
00546             buffer[retcnt - 1] = EOS;
00547 
00548             if ( (errp = parse_string(&value, buffer, parse_env)) == NULL )
00549             {
00550                 if ( value.variable_name ) printf("Variable: %s\n", value.variable_name);
00551                 nval = (numeric_ptr)(value.value);
00552                 switch ( nval->type )
00553                 {
00554                 case INT_TYPE:
00555                     printf("Evaluated Value: %i\n", nval->value.int_value);
00556                     break;
00557                 case DBL_TYPE:
00558                     printf("Evaluated Value: %.*f\n", prec, nval->value.dbl_value);
00559                     break;
00560                 } /* endswitch */
00561                 if ( !value.variable_name ) free_numeric(value.value);
00562                 chk_vars(predefined_fin_vars, fin_vars, fin_type, PREDEFINED_FIN_VARS);
00563                 fininfo.npp = npp;
00564                 fininfo.ir = ir;
00565                 fininfo.pv = pv;
00566                 fininfo.pmt = pmt;
00567                 fininfo.fv = fv;
00568                 fininfo.CF = CF;
00569                 fininfo.PF = PF;
00570                 fininfo.disc = disc;
00571                 fininfo.bep = bep;
00572             }
00573             else
00574             {
00575                 parse_error(get_parse_error(parse_env), buffer, errp);
00576             } /* endif */
00577         } /* endif */
00578     } /* endfor */
00579     exit_parser(parse_env);
00580     unset_fin_vars();
00581 } /* main */
00582 
00583 static void  prt_status(
00584     fi_ptr       fi,
00585     FILE        *ofile)
00586 {
00587     fprintf(ofile, "<================================>\nCurrent Financial Calculator Status:\n");
00588     fprintf(ofile, "Compounding Frequency: (CF) %u\n", fi->CF);
00589     fprintf(ofile, "Payment     Frequency: (PF) %u\n", fi->PF);
00590     fprintf(ofile, "Compounding: %s\n", fi->disc ? "Discrete (disc = TRUE)" : "Continuous (disc = FALSE)");
00591     fprintf(ofile, "Payments: %s\n", fi->bep ? "Beginning of Period (bep = TRUE)" : "End of Period (bep = FALSE)");
00592     if ( fi->npp > 12 ) fprintf(ofile, "Number of Payment Periods (n): %u\t\t(Years: %u)\n", fi->npp, fi->npp / fi->PF);
00593     else fprintf(ofile, "Number of Payment Periods (n): %u\n", fi->npp);
00594     if ((fi->CF == 1) && (fi->PF == 1) ) fprintf(ofile, "Nominal Interest per Payment Period (i): %f\t(Annualized: %.*f\n", fi->ir, fi->prec, fi->ir * 12);
00595     else fprintf(ofile, "Nominal Annual Interest Rate (i): %.*f\n", fi->prec, fi->ir);
00596     /*    fprintf(ofile, "  Effective Interest Rate Per Payment Period: %f\n",eff_int(nint/100.0,CF,PF));   */
00597     fprintf(ofile, "Present Value (pv): %.*f\n", fi->prec, fi->pv);
00598     fprintf(ofile, "Periodic Payment (pmt): %.*f\n", fi->prec, fi->pmt);
00599     fprintf(ofile, "Future Value (fv): %.*f\n<================================>\n", fi->prec, fi->fv);
00600 }   /* prt_status */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines