home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 November / PCWorld_2000-11_cd.bin / Komunik / sambar444 / _SETUP.1 / finance.c < prev    next >
C/C++ Source or Header  |  2000-06-05  |  16KB  |  688 lines

  1. /*
  2. ** FINANCE
  3. **
  4. **      HTTP Wrapper for the Financial Tools
  5. **
  6. **        Confidential Property of Tod Sambar
  7. **        (c) Copyright Tod Sambar 1996
  8. **        All rights reserved.
  9. **
  10. **
  11. ** Public Functions:
  12. **
  13. **        finance_init
  14. **
  15. **
  16. ** History:
  17. ** Chg#    Date    Description                                                Resp
  18. ** ----    -------    -------------------------------------------------------    ----
  19. **         6SEP96    Created                                                    sambar
  20. */
  21.  
  22. #include    <stdio.h>
  23. #include    <memory.h>
  24. #include    <string.h>
  25. #include    <stdlib.h>
  26. #include    <math.h>
  27. #include    <finance.h>
  28.  
  29. /*
  30. ** Finance RPC Commands
  31. */
  32. typedef struct finance__rpcs
  33. {
  34.     SA_CHAR        *name;
  35.     SA_RPCPARAM    *params;
  36.     SA_INT        numparams;
  37.     SA_INT        auth;
  38.     SA_VOID        *func;
  39.     SA_CHAR        *descr;
  40. } FINANCE__RPCS;
  41.  
  42. static SA_RPCPARAM        amorcalcp [] = 
  43. {
  44.     { "price",         1,     "The price of the property." },
  45.     { "months",        1,     "The number of month of sthe load." },
  46.     { "rate",         1,     "The rate of the loan." },
  47.     { "month",         1,     "The starting month of the loan." },
  48.     { "year",         1,     "The starting year of the loan." }
  49. };
  50. static SA_RPCPARAM        fvmdcalcp [] = 
  51. {
  52.     { "amount",     1,    "The regular amount of deposit." },
  53.     { "deposits",     1,    "The number of deposits per year." },
  54.     { "months",     1,    "The total number of months." },
  55.     { "rate",         1,    "The normal interest rate." }
  56. };
  57. static SA_RPCPARAM        fvpscalcp [] = 
  58. {
  59.     { "sum",         1,     "The present sum to be calculated." },
  60.     { "rate",         1,     "The annual interest rate." },
  61.     { "periods",     1,     "The number of periods per year." },
  62.     { "periods",     1,     "The number of periods to maturity." }
  63. };
  64. static SA_RPCPARAM        mortcalcp [] = 
  65. {
  66.     { "price",         1,    "The sale price of the home." },
  67.     { "down",         1,    "The down payment amount." },
  68.     { "years",         1,    "The number of years to pay off the mortgage." },
  69.     { "rate",         1,    "The interest rate." }
  70. };
  71. static SA_RPCPARAM        ratecalcp [] = 
  72. {
  73.     { "price",        1,    "The principal value of the loan." },
  74.     { "terms",        1,    "The number of terms per year." },
  75.     { "periods",    1,    "The number of periods of the loan." },
  76.     { "payment",    1,    "The amount of each payment." }
  77. };
  78.  
  79. static FINANCE__RPCS     finance_rpcs [] =
  80. {
  81.     { "amorcalc",    amorcalcp,    sizeof(amorcalcp) / sizeof(SA_RPCPARAM),
  82.       SA_AUTHORIZATION_ALL,    (SA_VOID *)finance_amorcalc,
  83.       "Amortization schedule calculation." },
  84.     { "fvmdcalc",    fvmdcalcp,    sizeof(fvmdcalcp) / sizeof(SA_RPCPARAM),
  85.       SA_AUTHORIZATION_ALL,    (SA_VOID *)finance_fvmdcalc,
  86.       "Future value of monthly deposit calculator." },
  87.     { "fvpscalc",    fvpscalcp,    sizeof(fvpscalcp) / sizeof(SA_RPCPARAM),
  88.       SA_AUTHORIZATION_ALL,    (SA_VOID *)finance_fvpscalc,
  89.       "Future value of present sum calculator." },
  90.     { "mortcalc",    mortcalcp,    sizeof(mortcalcp) / sizeof(SA_RPCPARAM),
  91.       SA_AUTHORIZATION_ALL,    (SA_VOID *)finance_mortcalc,
  92.       "Mortgage calculator." },
  93.     { "ratecalc",    ratecalcp,    sizeof(ratecalcp) / sizeof(SA_RPCPARAM),
  94.       SA_AUTHORIZATION_ALL,    (SA_VOID *)finance_ratecalc,
  95.       "Interest rate calculator." }
  96. };
  97.  
  98. /*
  99. **  FINANCE_INIT
  100. **
  101. **    Initialize the Financial Tools calculators.
  102. **
  103. **  Parameters:
  104. **    sactx        Sambar Server context
  105. **
  106. **  Returns:
  107. **    SA_SUCCEED | SA_FAIL
  108. */
  109. SA_RETCODE SA_PUBLIC
  110. finance_init(sactx)
  111. SA_CTX        *sactx;
  112. {
  113.     int            i;
  114.  
  115.     /* Register the Finance RPCs with the application                    */
  116.     for (i = 0; i < sizeof(finance_rpcs) / sizeof(FINANCE__RPCS); i++)
  117.     {
  118.         if (sa_cmd_init(sactx, finance_rpcs[i].name, 
  119.             finance_rpcs[i].params, finance_rpcs[i].numparams,
  120.             finance_rpcs[i].auth, finance_rpcs[i].descr, 
  121.             (SA_RPCFUNC)finance_rpcs[i].func) != SA_SUCCEED)
  122.         {
  123.             sa_log(sactx, "Unable to initialize Finance RPCs");
  124.             return (SA_FAIL);
  125.         }
  126.     } 
  127.  
  128.     sa_log(sactx, "Finance Library Initialized");
  129.  
  130.     return (SA_SUCCEED);
  131. }
  132.  
  133. /*
  134. **  FINANCE_FVPSCALC
  135. **
  136. **    Future value of present sum calculator.
  137. **
  138. **  Parameters:
  139. **    sactx        Sambar Server context
  140. **    saconn        Sambar Server connection
  141. **    saparams    RPC Parameters
  142. **    infop        Error parameters
  143. **
  144. **  Returns:
  145. **    SA_SUCCEED | SA_FAIL
  146. */
  147. SA_RETCODE SA_PUBLIC
  148. finance_fvpscalc(sactx, saconn, saparams, infop)
  149. SA_CTX        *sactx;
  150. SA_CONN        *saconn;
  151. SA_PARAMS    *saparams;
  152. SA_INT        *infop;
  153. {
  154.     SA_INT        i;
  155.     SA_INT        periods;
  156.     SA_INT        numperiods;
  157.     SA_INT        datalen;
  158.     double        pressum;
  159.     double        rate;
  160.     double        tmp1;
  161.     double        tmp2;
  162.     double        fvps;
  163.     SA_CHAR        *data;
  164.     SA_CHAR        buffer[256];
  165.  
  166.  
  167.     /* Get the present sum                                                */
  168.     if ((sa_param(sactx, saparams, "sum", &data, &datalen) != SA_SUCCEED) 
  169.         || (datalen == 0) || (datalen > 32))
  170.     {
  171.         *infop = SA_E_INVALIDDATA;
  172.         return (SA_FAIL);
  173.     }
  174.  
  175.     pressum = atof(data);
  176.  
  177.     /* Get the annual interest rate                                     */
  178.     if ((sa_param(sactx, saparams, "rate", &data, &datalen) != SA_SUCCEED)
  179.         || (datalen == 0) || (datalen > 32))
  180.     {
  181.         *infop = SA_E_INVALIDDATA;
  182.         return (SA_FAIL);
  183.     }
  184.  
  185.     rate = atof(data);
  186.  
  187.     /* Get the number of periods per year                                */
  188.     if ((sa_param(sactx, saparams, "periods", &data, &datalen) != SA_SUCCEED)
  189.         || (datalen == 0) || (datalen > 32))
  190.     {
  191.         *infop = SA_E_INVALIDDATA;
  192.         return (SA_FAIL);
  193.     }
  194.  
  195.     periods = atoi(data);
  196.  
  197.     /* Get the number of periods to maturity                            */
  198.     if ((sa_param(sactx, saparams, "numperiods", &data, &datalen) != SA_SUCCEED)
  199.         || (datalen == 0) || (datalen > 32))
  200.     {
  201.         *infop = SA_E_INVALIDDATA;
  202.         return (SA_FAIL);
  203.     }
  204.  
  205.     numperiods = atoi(data);
  206.  
  207.     if ((pressum <= 0) || (rate <= 0) || (periods <= 0) || (numperiods <= 0))
  208.     {
  209.         *infop = SA_E_INVALIDDATA;
  210.         return (SA_FAIL);
  211.     }
  212.  
  213.     tmp1 = 1.0 + ((rate / (float)periods) / 100);
  214.     tmp2 = tmp1;
  215.     if (numperiods != 1)
  216.     {
  217.         for (i = 1; i < numperiods - 1; i++)
  218.         {
  219.             tmp1 = tmp1 * tmp2;
  220.         }
  221.     }
  222.  
  223.     fvps = pressum * tmp1;
  224.  
  225.     if (sa_send_macro(saconn, "FINANCE_FVPSCALC") != SA_SUCCEED)
  226.         return (SA_FAIL);
  227.  
  228.     sprintf(buffer, "$%11.2f\n", fvps);
  229.     if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  230.         return (SA_FAIL);
  231.  
  232.     if (sa_send_macro(saconn, "FINANCE_FOOTER") != SA_SUCCEED)
  233.         return (SA_FAIL);
  234.  
  235.     return (SA_SUCCEED);
  236. }
  237.  
  238. /*
  239. **  FINANCE_AMORCALC
  240. **
  241. **    Amortization schedule calculator.
  242. **
  243. **  Parameters:
  244. **    sactx        Sambar Server context
  245. **    saconn        Sambar Server connection
  246. **    saparams    RPC Parameters
  247. **    infop        Error parameters
  248. **
  249. **  Returns:
  250. **    SA_SUCCEED | SA_FAIL
  251. */
  252. SA_RETCODE SA_PUBLIC
  253. finance_amorcalc(sactx, saconn, saparams, infop)
  254. SA_CTX        *sactx;
  255. SA_CONN        *saconn;
  256. SA_PARAMS    *saparams;
  257. SA_INT        *infop;
  258. {
  259.     SA_INT        i;
  260.     SA_INT        months;
  261.     SA_INT        start;
  262.     SA_INT        year;
  263.     SA_INT        datalen;
  264.     double        price;
  265.     double        rate;
  266.     double        payment;
  267.     double        tmp1;
  268.     double        tmp2;
  269.     double        at;
  270.     double        ay;
  271.     SA_CHAR        *data;
  272.     SA_CHAR        buffer[256];
  273.  
  274.     /* Get the principle amount                                         */
  275.     if ((sa_param(sactx, saparams, "price", &data, &datalen) != SA_SUCCEED)
  276.         || (datalen == 0) || (datalen > 32))
  277.     {
  278.         *infop = SA_E_INVALIDDATA;
  279.         return (SA_FAIL);
  280.     }
  281.  
  282.     price = atof(data);
  283.  
  284.     /* Get the number of months in the loan                             */
  285.     if ((sa_param(sactx, saparams, "months", &data, &datalen) != SA_SUCCEED)
  286.         || (datalen == 0) || (datalen > 32))
  287.     {
  288.         *infop = SA_E_INVALIDDATA;
  289.         return (SA_FAIL);
  290.     }
  291.  
  292.     months = atoi(data);
  293.  
  294.     /* Get the interest rate                                             */
  295.     if ((sa_param(sactx, saparams, "rate", &data, &datalen) != SA_SUCCEED)
  296.         || (datalen == 0) || (datalen > 32))
  297.     {
  298.         *infop = SA_E_INVALIDDATA;
  299.         return (SA_FAIL);
  300.     }
  301.  
  302.     rate = atof(data);
  303.  
  304.     /* Get the starting month                                             */
  305.     if ((sa_param(sactx, saparams, "month", &data, &datalen) != SA_SUCCEED)
  306.         || (datalen == 0) || (datalen > 32))
  307.     {
  308.         *infop = SA_E_INVALIDDATA;
  309.         return (SA_FAIL);
  310.     }
  311.  
  312.     start = atoi(data);
  313.  
  314.     /* Get the starting year                                             */
  315.     if ((sa_param(sactx, saparams, "year", &data, &datalen) != SA_SUCCEED)
  316.         || (datalen == 0) || (datalen > 32))
  317.     {
  318.         *infop = SA_E_INVALIDDATA;
  319.         return (SA_FAIL);
  320.     }
  321.  
  322.     year = atoi(data);
  323.  
  324.     if ((price <= 0) || (months <= 0) || (rate <= 0) || (start <= 0) ||
  325.         (year <= 0))
  326.     {
  327.         *infop = SA_E_INVALIDDATA;
  328.         return (SA_FAIL);
  329.     }
  330.  
  331.     if (sa_send_macro(saconn, "FINANCE_AMORCALC") != SA_SUCCEED)
  332.         return (SA_FAIL);
  333.  
  334.     start--;
  335.     year--;
  336.  
  337.     tmp1 = rate / 1200.0;
  338.     tmp2 = 1.0 - (1.0 / pow((float)(tmp1+1), (float)months));
  339.     payment = price * tmp1 / tmp2;
  340.  
  341.     at = ay = 0.0;
  342.     for (i = 0; i < months; i++)
  343.     {
  344.         if (start >= 12)
  345.         {
  346.             year++;
  347.             at += ay;
  348.             sprintf(buffer, 
  349.                 "<I>Total Interest for paid during %ld:</I> $%11.2f<BR>\n",
  350.                 year, ay);
  351.             if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  352.                 return (SA_FAIL);
  353.  
  354.             ay = 0.0;
  355.             start = 0;
  356.         }
  357.  
  358.         ay = ay + (price * tmp1);
  359.         price = price - (payment - (price * tmp1));
  360.  
  361.         if (price > 0.0)
  362.             start++;
  363.         else
  364.             break;
  365.     }
  366.  
  367.     if (start > 0)
  368.     {
  369.         at += ay;
  370.         sprintf(buffer, "<I>Total Interest paid during %ld:</I> $%11.2f<BR>\n",
  371.                 year, ay);
  372.         if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  373.             return (SA_FAIL);
  374.     }
  375.  
  376.     sprintf(buffer, 
  377.         "<BR><B><I>Total Interest paid during loan:</B></I> $%11.2f<BR>\n",
  378.         at);
  379.     if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  380.         return (SA_FAIL);
  381.  
  382.     if (sa_send_macro(saconn, "FINANCE_FOOTER") != SA_SUCCEED)
  383.         return (SA_FAIL);
  384.  
  385.     return (SA_SUCCEED);
  386. }
  387.  
  388. /*
  389. **  FINANCE_RATECALC
  390. **
  391. **    Interest rate calculator.
  392. **
  393. **  Parameters:
  394. **    sactx        Sambar Server context
  395. **    saconn        Sambar Server connection
  396. **    saparams    RPC Parameters
  397. **    infop        Error parameters
  398. **
  399. **  Returns:
  400. **    SA_SUCCEED | SA_FAIL
  401. */
  402. SA_RETCODE SA_PUBLIC
  403. finance_ratecalc(sactx, saconn, saparams, infop)
  404. SA_CTX        *sactx;
  405. SA_CONN        *saconn;
  406. SA_PARAMS    *saparams;
  407. SA_INT        *infop;
  408. {
  409.     SA_INT        i;
  410.     SA_INT        terms;
  411.     SA_INT        periods;
  412.     SA_INT        datalen;
  413.     double        price;
  414.     double        payment;
  415.     double        tmp1;
  416.     double        tmp2;
  417.     double        rate;
  418.     SA_CHAR        *data;
  419.     SA_CHAR        buffer[256];
  420.  
  421.     /* Get the principal value of the loan                                 */
  422.     if ((sa_param(sactx, saparams, "price", &data, &datalen) != SA_SUCCEED)
  423.         || (datalen == 0) || (datalen > 32))
  424.     {
  425.         *infop = SA_E_INVALIDDATA;
  426.         return (SA_FAIL);
  427.     }
  428.  
  429.     price = atof(data);
  430.  
  431.     /* Get the number of terms per year                                 */
  432.     if ((sa_param(sactx, saparams, "terms", &data, &datalen) != SA_SUCCEED)
  433.         || (datalen == 0) || (datalen > 32))
  434.     {
  435.         *infop = SA_E_INVALIDDATA;
  436.         return (SA_FAIL);
  437.     }
  438.  
  439.     terms = atoi(data);
  440.  
  441.     /* Get the number of periods of the load                             */
  442.     if ((sa_param(sactx, saparams, "periods", &data, &datalen) != SA_SUCCEED)
  443.         || (datalen == 0) || (datalen > 32))
  444.     {
  445.         *infop = SA_E_INVALIDDATA;
  446.         return (SA_FAIL);
  447.     }
  448.  
  449.     periods = atoi(data);
  450.  
  451.     /* Get the amount of each payment                                     */
  452.     if ((sa_param(sactx, saparams, "payment", &data, &datalen) != SA_SUCCEED)
  453.         || (datalen == 0) || (datalen > 32))
  454.     {
  455.         *infop = SA_E_INVALIDDATA;
  456.         return (SA_FAIL);
  457.     }
  458.  
  459.     payment = atof(data);
  460.  
  461.     if ((price <= 0) || (terms <= 0) || (periods <= 0) || (payment <= 0))
  462.     {
  463.         *infop = SA_E_INVALIDDATA;
  464.         return (SA_FAIL);
  465.     }
  466.  
  467.     tmp1 = 0.008;
  468.     i = 0;
  469.     while (i < 1000000)
  470.     {
  471.         tmp2 = payment / price * pow((float)(tmp1+1), (float)(periods-1)) /
  472.                 pow((float)(tmp1+1), (float)periods);
  473.         if (tmp1 - tmp2 < 0.000001 && tmp1 - tmp2 > -0.000001)
  474.             i = 1000000;
  475.         else
  476.             tmp1 = tmp2;
  477.  
  478.         i++;
  479.     }
  480.  
  481.     rate = tmp2 * terms * 100;
  482.  
  483.     if (sa_send_macro(saconn, "FINANCE_MORTCALC") != SA_SUCCEED)
  484.         return (SA_FAIL);
  485.  
  486.     sprintf(buffer, "%11.4f%%\n", rate);
  487.     if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  488.         return (SA_FAIL);
  489.  
  490.     if (sa_send_macro(saconn, "FINANCE_FOOTER") != SA_SUCCEED)
  491.         return (SA_FAIL);
  492.  
  493.     return (SA_SUCCEED);
  494. }
  495.  
  496. /*
  497. **  FINANCE_MORTCALC
  498. **
  499. **    Mortgage calculator.
  500. **
  501. **  Parameters:
  502. **    sactx        Sambar Server context
  503. **    saconn        Sambar Server connection
  504. **    saparams    RPC Parameters
  505. **    infop        Error parameters
  506. **
  507. **  Returns:
  508. **    SA_SUCCEED | SA_FAIL
  509. */
  510. SA_RETCODE SA_PUBLIC
  511. finance_mortcalc(sactx, saconn, saparams, infop)
  512. SA_CTX        *sactx;
  513. SA_CONN        *saconn;
  514. SA_PARAMS    *saparams;
  515. SA_INT        *infop;
  516. {
  517.     SA_INT        years;
  518.     SA_INT        datalen;
  519.     double        price;
  520.     double        down;
  521.     double        rate;
  522.     double        tmp1;
  523.     double        mort;
  524.     SA_CHAR        *data;
  525.     SA_CHAR        buffer[256];
  526.     
  527.     /* Get the sale price of the house                                     */
  528.     if ((sa_param(sactx, saparams, "price", &data, &datalen) != SA_SUCCEED)
  529.         || (datalen == 0) || (datalen > 32))
  530.     {
  531.         *infop = SA_E_INVALIDDATA;
  532.         return (SA_FAIL);
  533.     }
  534.  
  535.     price = atof(data);
  536.  
  537.     /* Get the down payment amount                                         */
  538.     if ((sa_param(sactx, saparams, "down", &data, &datalen) != SA_SUCCEED)
  539.         || (datalen == 0) || (datalen > 32))
  540.     {
  541.         *infop = SA_E_INVALIDDATA;
  542.         return (SA_FAIL);
  543.     }
  544.  
  545.     down = atof(data);
  546.  
  547.     /* Get the number of years to pay off the mortgage                     */
  548.     if ((sa_param(sactx, saparams, "years", &data, &datalen) != SA_SUCCEED)
  549.         || (datalen == 0) || (datalen > 32))
  550.     {
  551.         *infop = SA_E_INVALIDDATA;
  552.         return (SA_FAIL);
  553.     }
  554.  
  555.     years = atoi(data);
  556.  
  557.     /* Get the interest rate                                             */
  558.     if ((sa_param(sactx, saparams, "rate", &data, &datalen) != SA_SUCCEED)
  559.         || (datalen == 0) || (datalen > 32))
  560.     {
  561.         *infop = SA_E_INVALIDDATA;
  562.         return (SA_FAIL);
  563.     }
  564.  
  565.     rate = atof(data);
  566.  
  567.     if ((price <= 0) || (down <= 0) || (years <= 0) || (rate <= 0) ||
  568.         (down > price))
  569.     {
  570.         *infop = SA_E_INVALIDDATA;
  571.         return (SA_FAIL);
  572.     }
  573.  
  574.     tmp1 = rate / (12 * 100);
  575.     mort = (price - down) * (tmp1 / (1 - pow(1 + tmp1, - (years * 12))));
  576.  
  577.     if (sa_send_macro(saconn, "FINANCE_MORTCALC") != SA_SUCCEED)
  578.         return (SA_FAIL);
  579.  
  580.     sprintf(buffer, "$%11.2f\n", mort);
  581.     if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  582.         return (SA_FAIL);
  583.  
  584.     if (sa_send_macro(saconn, "FINANCE_FOOTER") != SA_SUCCEED)
  585.         return (SA_FAIL);
  586.  
  587.     return (SA_SUCCEED);
  588. }
  589.  
  590. /*
  591. **  FINANCE_FVMDCALC
  592. **
  593. **    Future value of monthly deposit calculator.
  594. **
  595. **  Parameters:
  596. **    sactx        Sambar Server context
  597. **    saconn        Sambar Server connection
  598. **    saparams    RPC Parameters
  599. **    infop        Error parameters
  600. **
  601. **  Returns:
  602. **    SA_SUCCEED | SA_FAIL
  603. */
  604. SA_RETCODE SA_PUBLIC
  605. finance_fvmdcalc(sactx, saconn, saparams, infop)
  606. SA_CTX        *sactx;
  607. SA_CONN        *saconn;
  608. SA_PARAMS    *saparams;
  609. SA_INT        *infop;
  610. {
  611.     SA_INT        deposits;
  612.     SA_INT        months;
  613.     SA_INT        years;
  614.     SA_INT        datalen;
  615.     double        amount;
  616.     double        rate;
  617.     double        tmp1;
  618.     double        tmp2;
  619.     double        fvmd;
  620.     SA_CHAR        *data;
  621.     SA_CHAR        buffer[256];
  622.  
  623.     /* Get the regular amount of deposit                                */
  624.     if ((sa_param(sactx, saparams, "amount", &data, &datalen) != SA_SUCCEED)
  625.         || (datalen == 0) || (datalen > 32))
  626.     {
  627.         *infop = SA_E_INVALIDDATA;
  628.         return (SA_FAIL);
  629.     }
  630.  
  631.     amount = atof(data);
  632.  
  633.     /* Get the number of deposits per year                                 */
  634.     if ((sa_param(sactx, saparams, "deposits", &data, &datalen) != SA_SUCCEED)
  635.         || (datalen == 0) || (datalen > 32))
  636.     {
  637.         *infop = SA_E_INVALIDDATA;
  638.         return (SA_FAIL);
  639.     }
  640.  
  641.     deposits = atoi(data);
  642.  
  643.     /* Get the total months                                             */
  644.     if ((sa_param(sactx, saparams, "months", &data, &datalen) != SA_SUCCEED)
  645.         || (datalen == 0) || (datalen > 32))
  646.     {
  647.         *infop = SA_E_INVALIDDATA;
  648.         return (SA_FAIL);
  649.     }
  650.  
  651.     months = atoi(data);
  652.  
  653.     /* Get the nominal interest rate                                     */
  654.     if ((sa_param(sactx, saparams, "rate", &data, &datalen) != SA_SUCCEED)
  655.         || (datalen == 0) || (datalen > 32))
  656.     {
  657.         *infop = SA_E_INVALIDDATA;
  658.         return (SA_FAIL);
  659.     }
  660.  
  661.     rate = atof(data);
  662.  
  663.     if ((amount <= 0) || (rate <= 0) || (deposits <= 0) || (months <= 0))
  664.     {
  665.         *infop = SA_E_INVALIDDATA;
  666.         return (SA_FAIL);
  667.     }
  668.  
  669.     years = months / 12;
  670.     tmp1 = rate / (float)deposits / 100.0;
  671.     tmp2 = pow((float)(1+tmp1), (float)(deposits * years));
  672.     tmp2--;
  673.     tmp2 /= tmp1;
  674.     fvmd = amount * tmp2;
  675.  
  676.     if (sa_send_macro(saconn, "FINANCE_FVMDCALC") != SA_SUCCEED)
  677.         return (SA_FAIL);
  678.  
  679.     sprintf(buffer, "$%11.2f\n", fvmd);
  680.     if (sa_conn_send(saconn, buffer, SA_NULLTERM) != SA_SUCCEED)
  681.         return (SA_FAIL);
  682.  
  683.     if (sa_send_macro(saconn, "FINANCE_FOOTER") != SA_SUCCEED)
  684.         return (SA_FAIL);
  685.  
  686.     return (SA_SUCCEED);
  687. }
  688.