|
GnuCash 2.4.99
|
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 */
1.7.4