#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <curses.h>

#include "loantype.def"
#include "macmenu.def"

/*
*************************************************************************

 ##                                      ##   ##
 ##                                      ### ###
 ##       ####    ####   #####    #####  #######  #####   ## ###
 ##      ##  ##      ##  ##  ##  ##      ## # ## ##  ##   ####
 ##      ##  ##   #####  ##  ##   ####   ##   ## ##  ##   ###
 ##      ##  ##  ##  ##  ##  ##      ##  ##   ##  #####   ##
 ######   ####    ###### ##  ##  #####   ##   ##     ##   ##
                                                 #####

*************************************************************************

 Module:      LOANSMGR.C


 Description: This module does loan calculations for a wide variety of
              different input variables.

              The primary parameters used by this program are:

              a) Interest Rate
              b) Monthly Payment Size
              c) Number of Payment Months
              d) Total Loan Size

              Given any three of the above, this program can solve for the
              remainder.

              This program can also show the schedule of payments for a given
              loan, breaking each payment down into equity and interest, and
              showing at each payment, the total equity paid, and the balance
              remaining. Equity and interest schedules allow the ability to
              specify regular additional principal payments, and also allow
              variable payment periods.

              This routine does almost all calculations in double precision
              floating point, and therefore, may require specialized hardware
              support (floating point unit).


 Version:     2.5a1 (SuSE Linux 9.0, gcc compiler)

 Author:      Michael A. Campbell

****************************************************************************
*/

/**/

/*
-----------------------------------------------------------------------
Global DEFs for the module
-----------------------------------------------------------------------
*/

/* Constants related to init file processing                              */

#define NUM_COLORS           8
#define NUM_INIT_CMDS        7

#define MACMENU_FG_IX        0
#define MACMENU_BG_IX        1
#define ITEM_FG_IX           2
#define ITEM_BG_IX           3
#define POPUP_FG_IX          4
#define POPUP_BG_IX          5
#define BORDER_COLOR_IX      6


/* Constants related to menus                                             */

#define NUM_MENUS            9

#define MAIN_MENU_IX         0
#define LOANSIZE_MENU_IX     1
#define PAYMENTSIZE_MENU_IX  2
#define INTERESTRATE_MENU_IX 3
#define NUMPAYMENTS_MENU_IX  4
#define SCHEDULE_MENU_IX     5
#define PROFILE_MENU_IX      6
#define ABOUT_MENU_IX        7
#define SETUP_MENU_IX        8

/**/

/*
-----------------------------------------------------------------------
Global Constants for the module
-----------------------------------------------------------------------
*/

/* Menu titles for all LoansMgr menus                                       */

static char *menu_titles[] =
   { "Main Menu",
     "Loan Size Menu",
     "Payment Size Menu",
     "Interest Rate Menu",
     "Num Payments Menu",
     "Amortization Schedule Menu",
     "Profile Menu",
     "About LoansMgr Menu",
     "Amortization File Setup Menu" };

/* Prompt and response messages used by more than one menu                  */

static char *payment_size_prompt  = "Enter Payment Size";
static char *loan_size_prompt     = "Enter Loan Size";
static char *num_payments_prompt  = "Enter Number of Payments";
static char *interest_rate_prompt = "Enter Interest Rate";
static char *compound_prompt      = "Enter compounding periods per year";
static char *filename_prompt      = "Enter File Name";
static char *apa_prompt           = "Enter additional principal amount";
static char *app_prompt           = "Enter additional principal frequency (in number of payments)";

static char *not_implemented_msg  = "Command not (yet) implemented";


/* Loan parameter validation error messages                               */

static char *parm_errs[] =
   { "L, P, I, C, and N must be greater than zero",
     "Loan size must be greater than payment size",
     "Interest Rate must be less than 99",
     "Number of compounding periods must be less than 366",
     "Number of payments must be greater than 1",
     "Additional principal amount must be greater than zero",
     "Additional principal frequency must be greater than zero",
     "Additional principal amount cannot be greater than loan size",
     "For monthly payments, valid values are 1, 0.5, or 0.25",
     "For weekly payments, valid values are 1, 2, or 4",
     "Annual payments must be greater than annual interest!",
     "Num payments * payment size must be > loansize!" };


/* Month and Year name tables                                             */

char *month_names[NUM_MONTHS] =
   { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

char *year_names[NUM_YEARS] =
   { "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
     "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
     "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
     "00", "01", "02", "03", "04", "05", "06", "07", "08", "09",
     "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
     "20", "21", "22", "23", "24", "25", "26", "27", "28", "29" };


/* Color name tables. These names line up with the colors available via  */
/* ncurses.                                                              */

static char *colors[NUM_COLORS] =
   { "BLACK",     "BLUE",         "GREEN",       "CYAN",
     "RED",       "MAGENTA",      "YELLOW",      "WHITE" };


static short ncurses_color_codes[NUM_COLORS] =
   { COLOR_BLACK,  COLOR_BLUE,     COLOR_GREEN,   COLOR_CYAN,
     COLOR_RED,    COLOR_MAGENTA,  COLOR_YELLOW,  COLOR_WHITE };


/* Init file command table. This table is used to translate an init file  */
/* command to an index that can be used in a switch statement             */

static char *init_cmds [NUM_INIT_CMDS] =
   { "menu_outline_fg", "menu_outline_bg",
     "menu_item_fg",    "menu_item_bg",
     "popup_fg",        "popup_bg",
     "border_color"                          };

/* Version string for Loansmgr                                            */

char *version = "LoansMgr v2.5a1 ";

/**/

/*
-----------------------------------------------------------------------
Global Types for the module
-----------------------------------------------------------------------
*/

/* Type to hold the loan profile data                                      */

struct t_profile {
   char   version [40];         /* The version of LoansMgr that wrote file  */
   int    sig1;                 /* The first signature word                 */
   double l;                    /* The loan amount                          */
   double p;                    /* The payment amount                       */
   double i;                    /* Interest rate                            */
   double c;                    /* The number of interest compounds yearly  */
   double equiv_i;              /* Simple interest equiv for compounded i   */
   double n;                    /* The number of payments                   */
   double apa;                  /* Additional Principal Amount              */
   double app;                  /* Additional Principal Period              */
   struct t_pi   pi;            /* The payment interval                     */
   int    month_ix;             /* The index of the starting month          */
   int    year_ix;              /* The index of the starting year           */
   char   start_date_str[10];   /* The starting date as a string            */
   char   out_file_name [82];   /* The schedule filename                    */
   char   loan_name     [82];   /* User defined name of this loan           */
   int    lines_per_page;       /* Number of lines per page of sched. file  */
   int    sig2;                 /* Second signature word                    */
};

/**/

/*
-----------------------------------------------------------------------
Global Vars for the module
-----------------------------------------------------------------------
*/
BOOL debug_mode;                         /* Are we in debug mode?         */

/* State of the screen at startup of LoansMgr                             */

unsigned char  sx, sy;                   /* Width and height of screen    */


/* The current help level                                                 */

void (*help) ( char *help_lines[], unsigned char sx, unsigned char sy, 
               int popup_fg, int popup_bg, int sys_fg, int sys_bg, 
               MENU_ID menu );

BOOL help_is_rude;           /* Is the help level set to "rude"?          */


/* Menu IDs for all menus                                                 */

MENU_ID main_menu;           /* Menu id for the main menu                 */
MENU_ID loansize_menu;       /* Menu id for the loansize menu             */
MENU_ID paymentsize_menu;    /* Menu id for the paymentsize menu          */
MENU_ID interestrate_menu;   /* Menu id for the paymentsize menu          */
MENU_ID numpayments_menu;    /* Menu id for the numpayments menu          */
MENU_ID schedule_menu;       /* Menu id for the schedule menu             */
MENU_ID profile_menu;        /* Menu id for the profile menu              */
MENU_ID about_menu;          /* Menu id for the about menu                */
MENU_ID setup_menu;          /* Menu id for the setup menu                */

MENU_ID menu_ids[NUM_MENUS]; /* The above, viewed as an array             */


/* Global color selection variables (set by loansmgr.ini)                 */

short macmenu_fg;              /* MACMenu lines foreground color            */
short macmenu_bg;              /* MACMenu lines background color            */
short user_fg;                 /* User menu lines foreground color          */
short user_bg;                 /* User menu lines background color          */
short popup_fg;                /* Popup window foreground color             */
short popup_bg;                /* Popup window background color             */
short border_color;            /* Screen border color                       */


/* Amortization file formatting information                               */

struct t_fmt_ctl fmt_ctl;    /* Control structure for amort. format       */


/* The current loan profile                                               */

double l;                   /* Loan Size                                  */
double p;                   /* Payment Size                               */
double i;                   /* Quoted interest rate                       */
double c;                   /* Number of interest compounds per year      */
double equiv_i;             /* Simple interest equiv for compounded i     */
double n;                   /* The number of payments                     */
double apa;                 /* Additional principal amount                */
double app;                 /* Additional principal period                */

struct t_pi   pi;           /* The payment interval                       */

int  month_ix;              /* Index into month_names array               */
int  year_ix;               /* Index into year_names array                */
char start_date_str [10];   /* Buffer to hold starting date string        */

char profile_file_name[82]; /* String to hold profile file name           */
char out_file_name [82];    /* String to hold the schedule filename       */

char loan_name [82];        /* User defined name of this loan             */
int  lines_per_page;        /* Number of lines per page of sched. file    */

FILE *out_file;             /* Output file for loan schedule files        */

/**/

/*
-----------------------------------------------------------------------
External Variables Used
-----------------------------------------------------------------------
*/

/* Help screen data, defined in LOANHELP.C                                 */

extern char *main_help[];         /* Help lines for the main menu          */
extern char *loansize_help[];     /* Help lines for the loansize menu      */
extern char *paymentsize_help[];  /* Help lines for the paymentsize menu   */
extern char *interestrate_help[]; /* Help lines for the paymentsize menu   */
extern char *numpayments_help[];  /* Help lines for the numpayments menu   */
extern char *schedule_help[];     /* Help lines for the schedule menu      */
extern char *profile_help[];      /* Help lines for the profile menu       */
extern char *about_loansmgr[];    /* The "About LoansMgr" box              */
extern char *setup_help[];        /* Help lines for the setup menu         */

extern char *legal_disclaimer[];       /* The legal disclaimers            */
extern char *distribution_agreement[]; /* The distribution agreement       */
extern char *contact_author[];         /* The shareware agreement          */

/* ncurses data from MACMENU.C                                             */

extern WINDOW *lm_win;            /* Main ncurses window for loansmgr      */
extern WINDOW *pu_win;            /* The current popup window              */

/**/

/*
-----------------------------------------------------------------------
External Functions Used
-----------------------------------------------------------------------
*/

#include "macmenu.ext"
#include "strutil.ext"
#include "fileutil.ext"
#include "loanutil.ext"
#include "loanhelp.ext"
#include "loancalc.ext"

/**/

void set_default_profile ()

/***************************************************************************
 *                                                                         *
 * This function sets up the default loan profile, by loading all the      *
 * global profile variables. It returns no value.                          *
 *                                                                         *
 ***************************************************************************/

{
   /* Set the basic financial paramters                                    */

   l = p = i = equiv_i = n = 0.0;
   apa = app = 0.0;

   /* Set up the interest compounding and the payment interval             */

   c         = 12;
   pi.ny     = 12;
   pi.n      = 1.0;
   pi.units  = 'M';
   strcpy ( pi.str, "1.00 Months" );

   /* Set up the starting month and year, and the filename, for loan       */
   /* schedules.                                                           */

   month_ix = 0;
   year_ix  = findstr ( "04", year_names, NUM_YEARS );

   strcpy ( start_date_str, "Jan 04"   );
   strcpy ( out_file_name,  "loan.sch" );

   /* Set defaults for user supplied formatting information for schedules  */

   strcpy ( loan_name, "No Name Assigned" );
   lines_per_page = 55;

   /* Finally, set the default profile filename                            */

   strcpy ( profile_file_name, "loan.prf" );

} /* set_default_profile */

/**/

void set_default_colors ()

/***************************************************************************
 *                                                                         *
 * This function sets up the default LoansMgr screen colors.  It returns   *
 * no value.                                                               *
 *                                                                         *
 ***************************************************************************/

{
   macmenu_fg   = COLOR_WHITE;   /* Title, command, and response lines     */
   macmenu_bg   = COLOR_RED;

   user_fg      = COLOR_BLACK;   /* User menu lines                        */
   user_bg      = COLOR_CYAN;

   popup_fg     = COLOR_WHITE;   /* Popup help and information windows     */
   popup_bg     = COLOR_BLUE;

   border_color = COLOR_BLACK;   /* Color of the screen border             */

} /* set_default_colors */

/**/

BOOL get_loan_data ( file_ptr )

/***************************************************************************
 *                                                                         *
 * This function reads global loan data from the file whose open file      *
 * pointer is supplied. It then writes that data to the LoansMgr global    *
 * parms.                                                                  *
 *                                                                         *
 ***************************************************************************/

FILE *file_ptr;          /* The file to read the data from                 */

{
   BOOL   return_code;   /* The return code                                */
   struct t_profile ld;  /* The loan data                                  */

   fread ( &ld, sizeof(ld), 1, file_ptr );

   /* Verify that the data read is a legitimate profile file               */

   if ( ld.sig1 != 0x1234 || ld.sig2 != 0x5678 )

      /* This is not a valid profile file. Return an error                 */

      return_code = FALSE;

   else {
      /* This is a valid profile file. Read and load the data             */

      l         = ld.l;
      p         = ld.p;
      i         = ld.i;
      c         = ld.c;
      equiv_i   = ld.equiv_i;
      n         = ld.n;
      apa       = ld.apa;
      app       = ld.app;
      pi.n      = ld.pi.n;
      pi.units  = ld.pi.units;

      strcpy ( pi.str, ld.pi.str );

      month_ix  = ld.month_ix;
      year_ix   = ld.year_ix;

      strcpy ( start_date_str, ld.start_date_str );
      strcpy ( out_file_name,  ld.out_file_name  );

      strcpy ( loan_name, ld.loan_name );
      lines_per_page = ld.lines_per_page;

      return_code = TRUE;
   }

   return ( return_code );

} /* get_loan_data */

/**/

void put_loan_data ( file_ptr )

/***************************************************************************
 *                                                                         *
 * This function writes the global loan data to the file whose open file   *
 * pointer is supplied. The loan data is stamped with the version of this  *
 * program that wrote the data, so that in future, backward compatibility  *
 * can be ensured.                                                         *
 *                                                                         *
 ***************************************************************************/

FILE *file_ptr;          /* The file to write the data to                  */

{
   struct t_profile ld;  /* The loan data                                  */

   setmem ( (char *) &ld, sizeof(ld), '\0' );

   strcpy ( ld.version, version );

   ld.sig1      = 0x1234;

   ld.l         = l;
   ld.p         = p;
   ld.i         = i;
   ld.c         = c;
   ld.equiv_i   = equiv_i;
   ld.n         = n;
   ld.apa       = apa;
   ld.app       = app;
   ld.pi.n      = pi.n;
   ld.pi.units  = pi.units;

   strcpy ( ld.pi.str, pi.str );

   ld.month_ix  = month_ix;
   ld.year_ix   = year_ix;

   strcpy ( ld.start_date_str, start_date_str );
   strcpy ( ld.out_file_name,  out_file_name  );

   strcpy ( ld.loan_name, loan_name );
   ld.lines_per_page = lines_per_page;

   ld.sig2      = 0x5678;

   fwrite ( &ld, sizeof(ld), 1, file_ptr );

} /* put_loan_data */

/**/

void write_loan_data ( profile_file )

/***************************************************************************
 *                                                                         *
 * This function attempts to open the indicated profile file, and write    *
 * the data to it. If the file cannot be opened, an error is output to the *
 * user. If the file can be opened, the loan data in the global parms is   *
 * written to it via a call to the write_loan_data function.               *
 *                                                                         *
 ***************************************************************************/

char *profile_file;        /* The name of the profile file                */

{
   FILE *file_ptr;         /* File connection block                       */
   char result_msg[132];   /* String to hold result message               */

   if ( strlen(profile_file) == 0 )
      put_status_string ( "No profile filename specified" );

   else {
      file_ptr = (FILE *) open_file_for_writing ( profile_file, "wb" );

      if ( file_ptr != NULL ) {
         put_loan_data ( file_ptr );
         fclose ( file_ptr );
         strcpy ( result_msg, "Profile written to " );
      }

      else
         strcpy ( result_msg, "Couldn't open profile " );

      strcat ( result_msg, profile_file );
      put_status_string ( result_msg );
   }

} /* write_loan_data */

/**/

BOOL read_loan_data ( profile_file )

/***************************************************************************
 *                                                                         *
 * This function attempts to open the indicated profile file, and read in  *
 * the data in it. If the file cannot be opened, an error is output to the *
 * user. If the file can be opened, its data is loaded into the global     *
 * parms via a call to the read_loan_data function.                        *
 *                                                                         *
 ***************************************************************************/

char *profile_file;        /* The name of the profile file                */

{
   FILE *file_ptr;         /* File connection block                       */
   char result_msg[132];   /* String to hold result message               */
   BOOL ret_val = FALSE;   /* Return value: TRUE if loaded OK             */

   if ( strlen(profile_file) == 0 )
      put_status_string ( "No profile filename specified" );

   else {
      file_ptr = fopen ( profile_file, "rb" );

      if ( file_ptr != NULL ) {
         ret_val = get_loan_data ( file_ptr );
         fclose ( file_ptr );

         if ( ret_val )
            strcpy ( result_msg, "Profile read from " );
         else
            strcpy ( result_msg, "Not a valid profile: " );
      }

      else
         strcpy ( result_msg, "Couldn't open profile " );

      strcat ( result_msg, profile_file );
      put_status_string ( result_msg );
   }

   return ( ret_val );

} /* read_loan_data */

/**/

void review_loan_data ( menu )

/***************************************************************************
 *                                                                         *
 * This function creates a "pop up" window on screen, and puts all of the  *
 * relevant parameters into it, for examination by the user. The intent is *
 * that users can view the data that they are about to save, or that they  *
 * have just loaded, before proceeding.                                    *
 *                                                                         *
 ***************************************************************************/

MENU_ID menu;               /* The menu to restore after the user is done  */

{
   char sch_file[22];       /* The file name for the schedule file         */
   char prf_file[22];       /* The file name for the profile  file         */
   char title[82];          /* The window title line                       */

   filename_of ( profile_file_name, prf_file );

   /* Create the pop up window, and clear it.                              */

   create_popup_window ( sx, sy, W_CENTER, W_CENTER, 60, 12, popup_fg, popup_bg );

   /* Put out the basic loan parms (l, p, n, and i)                       */

   mvwprintw ( pu_win, 3, 1, " %s %12.2f %3s %s %12.2f",
             "Loan Size: ",    (float) l, " ", "Payment Size: ", (float) p );

   mvwprintw ( pu_win, 4, 1," %s %12.2f %3s %s %12.2f",
             "# Payments:",    (float) n, " ", "Interest Rate:", (float) i );

   mvwprintw ( pu_win, 5, 1, " %s%12s %3s %s %12.2f", "Payment Int:", pi.str, " ", "Compounds:    ", (float) c );

   /* Output the additional principal parameters                            */

   mvwprintw ( pu_win, 7, 1, " %s %12.2f %3s %s %12.2f",
             "Princ. Amt:",    (float) apa, " ", "Princ. Freq:  ", app );

   /* Output the starting date of the loan, and the name of the output file */

   strcpy_right_justify ( out_file_name, sch_file, 13, ' ' );

   mvwprintw ( pu_win, 9, 1, " %s %12s %3s %s %s",
             "Start Date:", start_date_str, " ", "Schedule File:", sch_file );

   /* Output the title and footer lines, and then wait until the user       */
   /* indicates that they are done.                                         */

   strcpy ( title, "Loan Profile Data (" );
   strcat ( title, prf_file );
   strcat ( title, ")" );

   adorn_popup_window ( 62, 12, popup_fg, popup_bg, title, "<< Press any key to continue >>" );

   getch ();

  /* Restore the original window,  and menu                              */

   destroy_popup_window ( sx, sy, menu );

} /* review_loan_data */

/**/

int validate_loan_parms ( l, p, i, c, n, apa, app, pi )

/***************************************************************************
 *                                                                         *
 * This function checks the supplied paramters to verify that they are     *
 * sane. It returns either -1 (no error) or an error code that is used as  *
 * the index to the parm_errs global error message set.                    *
 *                                                                         *
 ***************************************************************************/

double l, p, i, c, n;        /* Basic loan parameters                      */
double apa, app;       /* Additional principal payment parameters    */
struct t_pi *pi;             /* Payment interval parms                     */

{
   double tmp;               /* Intermediate calculation variable          */
   double annual_interest;   /* The annual interest on the loan            */
   double min_p;             /* The minimum payment to keep pace with int  */

   /* Basic loan parameters must be greater than zero */
   if ( l <= 0.0 || p <= 0.0 || i <= 0.0 || c <= 0.0 || n <= 0.0 )
      return (0);

   /* Loansize must be greater than Payment size */
   if ( p >= l )
      return ( 1 );

   /* Interest rate must be less than 99 */
   if ( i > 99.0 )
      return ( 2 );

   /* The number of compounding periods must be less than 365 */
   if ( c > 365 && c != 999.99 )
      return ( 3);

   /* There must be more than one payment scheduled for this loan */
   if ( n <= 1.0 )
      return ( 4 );

   /* If additional principal payments involved, both parms must be > 0 */
   if ( app > 0.0 && apa == 0.0 )
      return ( 5 );

   /* If additional principal payments involved, both parms must be > 0 */
   if ( apa > 0.0 && app == 0.0 )
      return ( 6 );

   /* Additional principal amount cannot be greater than loan size */
   if ( apa >= l )
      return ( 7 );

   /* Payment interval must divide evenly into 1, for units of months, or   */
   /* must divide evenly into 52, for units in weeks                        */

   if ( pi->units == 'M' ) {
      tmp = 1.0 / pi->n;
      if ( tmp > (int)tmp )
    return ( 8 );
   }

   if ( pi->units == 'W' ) {
      tmp = 52.0 / pi->n;
      if ( tmp > (int)tmp )
         return ( 9 );
   }

   /* The annual payments must, at a minimum, be able to keep up with the    */
   /* the annual interest.                                                   */

   annual_interest = l * ( i / 100.0 );
   min_p           = annual_interest / pi->ny;

   if ( p <= min_p )
      return (  10 );

   /* If we get to this point, all checks have passed, and so, return the    */
   /* "No Error" indication.                                                 */

   return ( -1 );

} /* validate_loan_parms */

/**/

void update_menu_titles ( profile_path_name )

/***************************************************************************
 *                                                                         *
 *  This function updates the titles of all of the menus to include the    *
 *  name of the current loan file. This is done so that all menus titles   *
 *  display the name of the currently active loan profile file.            *
 *                                                                         *
 ***************************************************************************/

char    *profile_path_name; /* The name of the newly opened profile file   */

{
   int i;                   /* Loop counter                                */
   char profile_name [20];  /* Filename portion of profile path name       */
   char version_plus [82];  /* The version string plus the profile name    */
   char menu_title   [82];  /* The new menu title                          */

   /* Extract the filename from the path given for the profile file        */

   filename_of ( profile_path_name, profile_name );

   /* Build the loop invariant part of the new menu title, which consists  */
   /* of the version string plus the profile file name                     */

   strcpy ( version_plus, version           );
   strcat ( version_plus, "("               );
   strcat ( version_plus, profile_name );
   strcat ( version_plus, ") "              );

   for ( i = 0; i < NUM_MENUS; i++ ) {

      /* For each menu, add the menu name onto the invariant portion of the */
      /* full menu title, and then update the menu itself. MACMenu will     */
      /* ensure that the currently displayed menu is dynamically updated .  */

      strcpy ( menu_title, version_plus      );
      strcat ( menu_title, menu_titles[i]    );

      change_menu_title ( menu_ids[i], menu_title );
   }

} /* update_menu_titles */

/**/

void load_fmt_ctl ()

/***************************************************************************
 * This procedure loads the fmt_ctl structure with all of the information  *
 * needed to pass user supplied amortization file formatting information   *
 * to the LOANCALC functions that actually generate the amortization file. *
 ***************************************************************************/

 {
   fmt_ctl.loan_name      = loan_name;
   fmt_ctl.version        = version;
   fmt_ctl.lines_per_page = lines_per_page;
   fmt_ctl.page_num       = 1;
   fmt_ctl.lines_printed  = 0;
   fmt_ctl.l              = l;
   fmt_ctl.p              = p;
   fmt_ctl.i              = i;
   fmt_ctl.c              = c;
   fmt_ctl.pi_str         = pi.str;
   fmt_ctl.start_date_str = start_date_str;

} /* load_fmt_ctl */

/**/

void put_payout_summary ( n, interest_paid, l, fmt_ctl, file_ptr )

/****************************************************************************
 * This function creates a popup window within the schedule menu's screen   *
 * and displays a payout summary within the window. Unlike all other popups,*
 * this one remains on screen until the user changes a loan parameter in    *
 * the schedule menu processor, at which time it is removed.                *
 *                                                                          *
 * This function puts the same payout summary to the amortization file as   *
 *                                                                          *
 * This function returns no value.                                          *
 ****************************************************************************/

double n;                  /* The number of payments for this loan          */
double interest_paid;      /* The total interest paid                       */
double l;                  /* The total principal paid                      */
struct t_fmt_ctl *fmt_ctl; /* Format control struct for amortization file   */
FILE  *file_ptr;           /* File pointer for amortization file            */

{
   double cost;         /* Total cost of the loan                          */

   /* Put out a small header in the amortization file, to separate the     */
   /* payout summary from the amortization schedule.                       */

   if ( fmt_ctl->lines_printed + 8 > fmt_ctl->lines_per_page )
      fprintf ( file_ptr, "%s", "\f" );

   fprintf ( file_ptr, "\n\n%s\n", "--------------" );
   fprintf ( file_ptr, "%s\n",     "Payout Summary" );
   fprintf ( file_ptr, "%s\n\n",   "--------------" );

   cost = l + interest_paid;

   /* Create a 52x6 window, with its upper left corner at (30, 17)        */

   create_popup_window ( sx, sy, 30,17, 52, 6, popup_fg, popup_bg );

   /* Put out the summary information, to both the window and the file    */

   mvwprintw ( pu_win, 3, 1, " %s%12.2lf  %s%12.2lf",
             "# Payments:", n,    "Principal:", l );
   fprintf ( file_ptr, "%s%12.2lf   %s%12.2lf\n",
             "# Payments:", n,    "Total Principal:", l );

   mvwprintw ( pu_win, 4, 1, " %s%12.2lf  %s%12.2lf",
             "Total Cost:", cost, "Interest: ", interest_paid );
   fprintf ( file_ptr, "%s%12.2lf   %s%12.2lf\n",
             "Total Cost:", cost, "Total Interest: ", interest_paid );

   /* Output the title and footer lines for the window.                     */

   adorn_popup_window ( 52, 6, popup_fg, popup_bg, "Payout Summary", " " );

   /* Restore the original window size                                      */

} /* put_payout_summary */

/**/

char common_menu_processor ( in_cmd, menu, done )

/***************************************************************************
 *                                                                         *
 * This function processes all of the menu selections that are common to   *
 * all menus in loansmgr. All menu selections pass through this processor  *
 * first. If this processor deals with it, it returns the special menu key *
 * '@'. If the command is not dealt with here, it is returned as the value *
 * of this function.                                                       *
 *                                                                         *
 ***************************************************************************/

char     in_cmd;          /* The incoming menu command                     */
MENU_ID  menu;            /* The menu this command was read from           */
int      *done;           /* Set to true if the Quit selection is found    */

{
   char out_cmd;                /* The outgoing command                    */
   char *ci;                    /* System command interpreter              */

   out_cmd = '@';               /* Assume we will process command here     */
   *done   = FALSE;             /* Not done until 'Q' hit                  */

   switch ( toupper(in_cmd) ) {

      case 'P':
         p = read_loan_parm ( payment_size_prompt, p );
         put_menu_item_data ( menu, 'P', D_DOUBLE, (char *) &p );
         break;

      case 'N':
         n = read_loan_parm ( num_payments_prompt, n );
         put_menu_item_data ( menu, 'N', D_DOUBLE, (char *) &n );
         break;

      case 'T':
         read_payment_interval ( &pi, menu );
         break;

      case 'I':
         i = read_loan_parm ( interest_rate_prompt, i );
         put_menu_item_data ( menu, 'I', D_DOUBLE, (char *) &i );
         break;

      case 'C':
         c = read_loan_parm ( compound_prompt, c );
         put_menu_item_data ( menu, 'C', D_DOUBLE, (char *) &c );
         break;

      case 'L':
         l = read_loan_parm ( loan_size_prompt, l );
         put_menu_item_data ( menu, 'L', D_DOUBLE, (char *) &l );
         break;

      case '$':
         apa = read_loan_parm ( apa_prompt, apa );
         put_menu_item_data ( menu, '$', D_DOUBLE, (char *) &apa );
         break;

      case '#':
         app = read_loan_parm ( app_prompt, app );
         put_menu_item_data ( menu, '#', D_DOUBLE, (char *) &app );
         break;

      case 'O':                                           /* OS Shell */
         os_ci ( menu );
         break;

      case 'Q':
         *done = TRUE;
         break;

      default:
         out_cmd = in_cmd;               /* Return unprocessed command */
         break;

   } /* switch in_cmd */

   return ( out_cmd );

} /* common_menu_processor */

/**/

void setup_menu_processor ()

/*****************************************************************************
 *                                                                           *
 * This function handles the Setup menu. This menu allows the user to        *
 * specify setup/format information for amortization schedule files.         *
 *                                                                           *
 *****************************************************************************/

{
   char   cmd   = ' ';         /* Command from user entered command line     */
   int    done = FALSE;        /* Set to TRUE when user exits this level     */
   int    length;              /* Length of the read data                    */
   double lpp;                 /* Number of lines per page                   */
   int    lpp_i;               /* The integer version of lpp                 */
   char   input[82];           /* Input buffer                               */

   /* Prompt the user with the menu of this level */

   put_menu ( setup_menu );

   while ( !done ) {

      cmd = get_menu_selection ( setup_menu );

      switch ( cmd ) {

        case 'N':  /* Read the loan name, for display in file header     */

            put_status_string ( "Enter loan name" );
            length = get_command_string ( input );
            clr_status_line ();

            if ( length >= 1 ) {
               strcpy ( loan_name, input );
               put_menu_item_data ( setup_menu, 'N', D_STRING, loan_name );
            }
            else
               put_status_string ( "Not a name" );

            break;

        case 'F':  /* Read the file name for the amortization file       */

            put_status_string ( filename_prompt );
            length = get_command_string ( input );
            clr_status_line ();

            if ( length >= 1 ) {
               strcpy ( out_file_name, input );
               put_menu_item_data ( setup_menu, 'F', D_STRING, out_file_name );
            }
            else
               put_status_string ( "Not a valid filename" );

            break;

        case 'D':  /* Set the date of the first payment                  */

            read_starting_date ( &month_ix, &year_ix, start_date_str, setup_menu );
            break;

        case 'L':  /* Set the number of lines per page in schedule file  */

            lpp = read_loan_parm ( "Enter number of lines per page", 55 );

            if ( lpp >= 20.0 && lpp <= 120.0 ) {
               lpp_i = (int) lpp;
               fmt_ctl.lines_per_page = lpp_i;
               put_menu_item_data ( setup_menu, 'L', D_INT, (char *) &lpp_i );
            }
            else
               put_status_string ("Lines per page must be between 20 and 120" );

            break;

        case 'H':   /* Help for this level                               */

            show_help ( setup_help, sx, sy, popup_fg, popup_bg, macmenu_fg,
                        macmenu_bg, setup_menu );
            break;

        case 'Q':  /* Quit this level                                    */

            done = TRUE;
            break;

        default:
            put_status_string ( not_implemented_msg );
            break;

      } /* switch cmd */

   } /* while not done */

} /* setup_menu_processor */

/**/

void about_menu_processor ()

/*****************************************************************************
 *                                                                           *
 * This function handles the About LoansMgr menu. It allows for the display  *
 * of general information about the program, legal disclaimers, and the      *
 * shareware agreement.                                                      *
 *                                                                           *
 *****************************************************************************/

{
   char cmd   = ' ';           /* Command from user entered command line     */
   int   done = FALSE;         /* Set to TRUE when user exits this level     */

   /* Prompt the user with the menu of this level */

   put_menu ( about_menu );

   while ( !done ) {

      cmd = get_menu_selection ( about_menu );

      switch ( cmd ) {

         case 'G':   /* General program information                       */

            show_help ( about_loansmgr, sx, sy, popup_fg, popup_bg, macmenu_fg,
                        macmenu_bg, about_menu );
            break;

         case 'L':  /* Legal Disclaimer                                   */

            show_help ( legal_disclaimer, sx, sy, popup_fg, popup_bg, macmenu_fg,
                        macmenu_bg, about_menu );
            break;

         case 'D':  /* Distribution Agreement                             */

            show_help ( distribution_agreement, sx, sy, popup_fg, popup_bg, macmenu_fg,
                        macmenu_bg, about_menu );
            break;

         case 'C':  /* Contact The Author                                 */

            show_help ( contact_author, sx, sy, popup_fg, popup_bg, macmenu_fg,
                        macmenu_bg, about_menu );
            break;

         case 'Q':  /* Quit this level                                    */

            done = TRUE;
            break;

         default:
            put_status_string ( not_implemented_msg );
            break;

      } /* switch cmd */

   } /* while not done */

} /* about_menu_processor */

/**/

void profile_menu_processor ()

/*****************************************************************************
 *                                                                           *
 * This function handles the profile menu for LoansMgr. It deals with the    *
 * saving and restoring of loan profile data, which is simply the complete   *
 * set of all global data related to a given loan. Reloading a loan profile  *
 * gives the user the ability to regenerate a loan schedule at any time, and *
 * later, to add unscheduled principal payments to it.                       *
 *                                                                           *
 *****************************************************************************/

{
   char cmd       = ' ';       /* Command from user entered command line     */
   char input  [82];           /* Text buffer for reading input data         */
   char output [82];           /* Text buffer for building output messages   */
   int  length;                /* The number of chars in the input buffer    */

   int   done = FALSE;         /* Set to TRUE when user exits this level     */
   BOOL  loaded;               /* TRUE if data loaded in OK, else FALSE      */


   /* Prompt the user with the menu of this level */

   put_menu ( profile_menu );

   while ( !done ) {

      cmd = get_menu_selection ( profile_menu );
      cmd = common_menu_processor ( cmd, profile_menu, &done );

      switch ( cmd ) {

         case '@':   /* Handled by the common menu processor - do nothing */
            break;

         case 'F':   /* Set the filename for loading/saving from/to       */

            put_status_string ( filename_prompt );
            length = get_command_string ( input );
            clr_status_line ();

            if ( length >= 1 ) {
               strcpy ( profile_file_name, input );
               put_menu_item_data ( profile_menu, 'F', D_STRING, profile_file_name );
            }
            else
               put_status_string ( "Not a valid filename" );

            break;

         case 'E':  /* Erase the loan profile                            */

            set_default_profile ();

            put_menu_item_data ( profile_menu, 'F', D_STRING, profile_file_name );

            update_menu_titles ( "" );
            put_status_string ( "Loan profile reset to default values" );

            break;

         case 'R':
            loaded = read_loan_data ( profile_file_name );

            if (loaded )
               update_menu_titles ( profile_file_name );

            break;

         case 'W':
            write_loan_data ( profile_file_name );
            update_menu_titles ( profile_file_name );
            break;

         case 'V':
            review_loan_data ( profile_menu );
            break;

         case 'H':
            (*help) ( profile_help, sx, sy, popup_fg, popup_bg, macmenu_fg,
                      macmenu_bg, profile_menu );
            break;

         default:
            put_status_string ( not_implemented_msg );
            break;

      } /* switch cmd */

   } /* while not done */

} /* profile_menu_processor */

/**/

void schedule_menu_processor ()

/***************************************************************************
 *                                                                         *
 * This routine handles the schedule menu of loansmgr. It computes equity  *
 * and interest tables for a loan with the parameters entered by the user. *
 *                                                                         *
 ***************************************************************************/

{
   char cmd = ' ';             /* Command from user entered command line   */
   int  length;                /* Length of read file name                 */
   char input  [82];           /* Buffer for reading filename              */
   char output [140];          /* Text buffer for building output messages */

   int done = FALSE;           /* Set to TRUE when user exits this level   */
   int j;                      /* Loop counter                             */
   int err_code;               /* Parameter validation error code          */

   BOOL clear_summary = FALSE; /* Does menu need redrawing to clr summary? */

   double interest_paid = 0.0; /* Total interest paid on the loan          */
   struct t_date_ctl date_ctl; /* Struct to specify starting date          */

   /* Prompt the user with the menu of this level */

  put_menu ( schedule_menu );

   while ( !done ) {

      cmd = get_menu_selection ( schedule_menu );
      cmd = common_menu_processor ( cmd, schedule_menu, &done );

      switch ( cmd ) {

         case '@':   /* Processed by common menu processor                   */

            /* If the clear_summary bool is set, this means that a loan      */
            /* summary has been displayed. As soon as the user changes one   */
            /* of the loan parameters (which is the primary function of the  */
            /* common_menu_processor), the displayed summary becomes invalid */
            /* and must be cleared.                                          */

            if ( clear_summary && !done ) {
               put_menu ( schedule_menu );
               clear_summary = FALSE;
            }

            break;

         case 'F':   /* Setup the format of the schedule file            */

            setup_menu_processor ();
            put_menu ( schedule_menu );
            break;

         case 'S':   /* Compute the loan schedule                         */

            err_code = validate_loan_parms ( l, p, i, 2.0, c, apa, app, &pi );

            if ( err_code != -1 )
               put_status_string ( parm_errs[err_code] );

            else {
               /* No errors in the parameters. Attempt to open file          */

               out_file = (FILE *) open_file_for_writing ( out_file_name, "w" );

               if ( out_file == NULL ) {

                   /* Can't open the file - alert the user */

                   sprintf ( output, "%s %s", "Cannot open", out_file_name );
                   put_status_string ( output );
               }
               else {
                  /* The user has entered valid parameters and the file     */
                  /* opened OK. Compute the schedule                        */

                  equiv_i = equiv_interest_rate ( i, c, pi.ny );

                  date_ctl.month = month_ix;
                  date_ctl.year  = year_ix;
                  load_fmt_ctl ();

                  n = amortization_schedule ( l, p, equiv_i, &pi, apa, app, &date_ctl, &fmt_ctl,
                                              &interest_paid, out_file );

                  sprintf ( output, "%s %s", "Amortization schedule written to", out_file_name );
                  put_status_string ( output );

                  put_payout_summary ( n, interest_paid, l, &fmt_ctl, out_file );
                  clear_summary = TRUE;

                  fclose ( out_file );
               }
            }
            
            break;

         case 'V':   /* View generated loan schedule                     */

            edit_schedule_file ( out_file_name, schedule_menu );
            break;

         case 'H':
            (*help) ( schedule_help, sx, sy, popup_fg, popup_bg, macmenu_fg,
                      macmenu_bg, schedule_menu );
            break;

         default:
            put_status_string ( not_implemented_msg );
            break;

      } /* switch cmd */

   } /* while not done */

} /* schedule_menu_processor */

/**/

void loansize_menu_processor ()

/*****************************************************************************
 *                                                                           *
 *  This function handles the loansize menu for loansmgr. It computes the    *
 *  loan size for a loan with the parameters entered by the user.            *
 *                                                                           *
 *****************************************************************************/

{
   char cmd       = ' ';       /* Command from user entered command line     */
   char output [80];           /* Text buffer for building output messages   */

   int   done = FALSE;         /* Set to TRUE when user exits this level     */
   int   err_code = -1;        /* Parameter validation error code            */

   /* Prompt the user with the menu of this level */

   put_menu ( loansize_menu );

   while ( !done ) {

      cmd = get_menu_selection ( loansize_menu );
      cmd = common_menu_processor ( cmd, loansize_menu, &done );

      switch ( cmd ) {

         case '@':   /* Handled by the common menu processor - do nothing */
            break;

         case 'S':   /* Compute the loansize                              */

            err_code = validate_loan_parms ( p+1.0, p, i, c, n, 0.0, 0.0, &pi );

            if ( err_code != -1 )
               put_status_string ( parm_errs[err_code] );

            else {

               /* The user has entered valid parameters for the loan. */
               /* Compute the loan size!                              */

               equiv_i = equiv_interest_rate ( i, c, pi.ny );

               l = loan_size ( p, n, equiv_i, pi.ny );

               sprintf ( output,  "%s %2.2f", "Loan Size =", (float) l );
               put_status_string ( output );

            } /* valid parms */

            break;

         case 'H':
            (*help) ( loansize_help, sx, sy, popup_fg, popup_bg, macmenu_fg,
                      macmenu_bg, loansize_menu );
            break;

         default:
            put_status_string ( not_implemented_msg );
            break;

      } /* switch cmd */

   } /* while not done*/

} /* loansize_menu_processor */

/**/

void paymentsize_menu_processor ()

/*****************************************************************************
 *                                                                           *
 * This function handles the paymentsize menu for loansmgr. It computes the  *
 * payment size for a loan with the parameters entered by the user.          *
 *                                                                           *
 *****************************************************************************/

{
   char cmd       = ' ';       /* Command from user entered command line     */
   char output [80];           /* Text buffer for building output messages   */

   int   done = FALSE;         /* Set to TRUE when user exits this level     */
   int   err_code = -1;        /* Parameter validation error code            */


   /* Prompt the user with the menu of this level */

   put_menu ( paymentsize_menu );

   while ( !done ) {

      cmd = get_menu_selection ( paymentsize_menu );
      cmd = common_menu_processor ( cmd, paymentsize_menu, &done );

      switch ( cmd ) {

         case '@':   /* Handled by the common menu processor - do nothing */
            break;

         case 'S':   /* Compute the payment size                          */

            err_code = validate_loan_parms ( l, l-1.0, i, c, n, 0.0, 0.0, &pi );

            if ( err_code != -1 )
               put_status_string ( parm_errs[err_code] );

            else {

               /* The user has entered valid parameters for the loan. */
               /* Compute the payment size!                           */

               equiv_i = equiv_interest_rate ( i, c, pi.ny );

               p = payment_size ( l, equiv_i, pi.ny, n );

               sprintf ( output, "%s %2.2f", "Payment Size =", (float) p );
               put_status_string ( output );

            } /* valid parms */

            break;

         case 'H':
            (*help) ( paymentsize_help, sx, sy, popup_fg, popup_bg, macmenu_fg,
                      macmenu_bg, paymentsize_menu );
            break;

         default:
            put_status_string ( not_implemented_msg );
            break;

      } /* switch cmd */

   } /* while not done */

} /* paymentsize_menu_processor */

/**/

void interestrate_menu_processor ()

/*****************************************************************************
 *                                                                           *
 * This function handles the interest rate menu for LoansMgr. It computes    *
 * interest rate for a loan with the parameters entered by the user.         *
 *                                                                           *
 *****************************************************************************/

{
   char cmd       = ' ';       /* Command from user entered command line     */
   char output [80];           /* Text buffer for building output messages   */

   int   done = FALSE;         /* Set to TRUE when user exits this level     */
   int   err_code = -1;        /* Parameter validation error code            */

   double threshold = 0.009;   /* Minimum error that must be achieved        */
   int    iterations;          /* Number of iterations to achieve result     */


   /* Prompt the user with the menu of this level */

   put_menu ( interestrate_menu );

   while ( !done ) {

      cmd = get_menu_selection ( interestrate_menu );
      cmd = common_menu_processor ( cmd, interestrate_menu, &done );

      switch ( cmd ) {

         case '@':   /* Handled by the common menu processor - do nothing */
            break;

         case 'S':   /* Compute the interest rate                         */

            err_code = validate_loan_parms ( l, p, 1.0, c, n, 0.0, 0.0, &pi );

            if ( err_code == -1 ) {

               /* No errors so far. Validate that payment size * number of */
               /* payments is at least as large as the loansize. If this   */
               /* condition is not met, no positive interest rate exists.  */

               if ( n * p <= l )
                  err_code = 10;
            }

            if ( err_code != -1 )
               put_status_string ( parm_errs[err_code] );

            else {

               /* The user has entered valid parameters for the loan. */
               /* Compute the interest rate!                          */

               i = interest_rate ( l, p, n, pi.ny, c, threshold, &iterations );

               if ( debug_mode )
                  sprintf ( output, "%s %2.2f %c%d %s%c", "Interest Rate =",
                          (float) i, '(', iterations, "Iterations", ')' );
               else
                  sprintf ( output, "%s %2.2f", "Interest Rate =", (float) i );

               put_status_string ( output );

            } /* valid parms */

            break;

         case 'H':
            (*help) ( interestrate_help, sx, sy, popup_fg, popup_bg, macmenu_fg,
                      macmenu_bg, interestrate_menu );
            break;

         default:
            put_status_string ( not_implemented_msg );
            break;

      } /* switch cmd */

   } /* while not done */

} /* interestrate_menu_processor */

/**/

void numpayments_menu_processor ()

/*****************************************************************************
 *                                                                           *
 *  This function handles the numpayments menu for loansmgr. It computes the *
 *  number of payments for a loan with the parameters entered by the user.   *
 *                                                                           *
 *****************************************************************************/

{

   char cmd       = ' ';       /* Command from user entered command line     */
   char output [80];           /* Text buffer for building output messages   */
   int month, year;            /* Dummy parameters                           */

   double n_years;             /* n viewed as years                          */
   double ip;                  /* Interest paid over life of loan            */

   int    done = FALSE;        /* Set to TRUE when user exits this level     */
   int    err_code = -1;       /* Parameter validation error code            */
   struct t_date_ctl date_ctl; /* Date parameters for equity_interest_sch    */

   /* Prompt the user with the menu of this level */

   put_menu ( numpayments_menu );

   while ( !done ) {

      cmd = get_menu_selection ( numpayments_menu );
      cmd = common_menu_processor ( cmd, numpayments_menu, &done );

      switch ( cmd ) {

         case '@':   /* Handled by common menu processor - do nothing    */
            break;

         case 'S':   /* Compute the number of payments                  */

            err_code = validate_loan_parms ( l, p, i, c, 2.0, apa, app, &pi );

            if ( err_code != -1 )
               put_status_string ( parm_errs[err_code] );

            else {
               /* The user has entered valid parameters for the loan.    */
               /* Compute the number of payments. Note that if the       */
               /* additional principal amount is greater than zero, then */
               /* we must iterate through the whole loan, via the        */
               /* equity_interest_schedule function, to determine the    */
               /* real duration of the loan.                             */

               equiv_i = equiv_interest_rate ( i, c, pi.ny );

               if ( app > 0.0 ) {
                  date_ctl.month = month_ix;
                  date_ctl.year  = year_ix;
                  load_fmt_ctl ();

                  n = amortization_schedule ( l, p, equiv_i, &pi, apa, app, &date_ctl, &fmt_ctl, &ip, out_file );
               }
               else
                  n = num_payments ( l, p, equiv_i, pi.ny );

               /* Output results in both simple number of payments, and the */
               /* number of years those payments indicate.                  */

               n_years =  n / pi.ny;

               sprintf ( output, "%s %3.2lf %c%3.2lf %s%c", "Num Payments =",
               n, '(', n_years, "Years", ')' );

               put_status_string ( output );

            } /* valid parms */

            break;

         case 'H':
            (*help) ( numpayments_help, sx, sy, popup_fg, popup_bg, macmenu_fg,
                      macmenu_bg, numpayments_menu );
            break;

         default:
            put_status_string ( not_implemented_msg );
            break;

      } /* switch cmd */

   } /* while not done */

} /* numpayments_menu_processor */

/**/

MENU_ID create_setup_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu Setup menu, and returns its menu     *
 *  ID.                                                                    *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  su_menu;            /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[SETUP_MENU_IX] );

   su_menu = create_menu ( 3, title, FALSE, border_color,
                           macmenu_fg, macmenu_bg, user_fg, user_bg );

   add_menu_item ( su_menu, 'N', "Name of Loan",                      D_STRING, loan_name                );
   add_menu_item ( su_menu, 'F', "Filename for amortization file",    D_STRING, out_file_name            );
   add_menu_item ( su_menu, 'D', "Date of first payment",             D_STRING, start_date_str           );
   add_menu_item ( su_menu, 'L', "Lines per Page",                    D_INT,    (char *) &lines_per_page );
   add_menu_item ( su_menu, 'H', "Help",                              D_NONE,   title                    );
   add_menu_item ( su_menu, 'Q', "Quit This Level",                   D_NONE,   title                    );

   alias_select_key ( su_menu, 'H', CMD_PF1 );
   alias_select_key ( su_menu, 'Q', CMD_ESC );

   return ( su_menu );

} /* create_setup_menu */

/**/

MENU_ID create_about_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu About LoansMgr menu, and returns its *
 *  menu ID.                                                               *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  ab_menu;            /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[ABOUT_MENU_IX] );

   ab_menu = create_menu ( 3, title, FALSE, border_color,
                           macmenu_fg, macmenu_bg, user_fg, user_bg );


   add_menu_item ( ab_menu, 'G', "General Information",               D_NONE,   title );
   add_menu_item ( ab_menu, 'L', "Legal Disclaimer - PLEASE READ",    D_NONE,   title );
   add_menu_item ( ab_menu, 'D', "Distribution Agreement",            D_NONE,   title );
   add_menu_item ( ab_menu, 'C', "Contacting The Author",             D_NONE,   title );
   add_menu_item ( ab_menu, 'Q', "Quit This Level",                   D_NONE,   title );

   alias_select_key ( ab_menu, 'Q', CMD_ESC );

   return ( ab_menu );

} /* create_about_menu */

/**/

MENU_ID create_profile_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu loan profile menu, and returns its   *
 *  menu ID.                                                               *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  pr_menu;            /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[PROFILE_MENU_IX] );

   pr_menu = create_menu ( 3, title, FALSE, border_color,
                           macmenu_fg, macmenu_bg, user_fg, user_bg );

   add_menu_item ( pr_menu, 'F', "Filename to Read From/Write To",   D_STRING, profile_file_name );
   add_menu_item ( pr_menu, 'E', "Erase Loan Profile",               D_NONE,   title );

   add_menu_item ( pr_menu, NIL_KEY, "",                             D_NONE,   title );
   add_menu_item ( pr_menu, 'R', "Read loan profile",                D_NONE,   title );
   add_menu_item ( pr_menu, 'W', "Write loan profile",               D_NONE,   title );
   add_menu_item ( pr_menu, 'V', "View loan profile",                D_NONE,   title );

   add_menu_item ( pr_menu, NIL_KEY, "",                             D_NONE,   title );
   add_menu_item ( pr_menu, 'O', "OS Shell",                         D_NONE,   title );
   add_menu_item ( pr_menu, 'H', "Help",                             D_NONE,   title );
   add_menu_item ( pr_menu, 'Q', "Quit This Level",                  D_NONE,   title );

   alias_select_key ( pr_menu, 'H', CMD_PF1 );
   alias_select_key ( pr_menu, 'Q', CMD_ESC );

   return ( pr_menu );

} /* create_profile_menu */

/**/

MENU_ID create_schedule_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu payment schedule menu, and returns   *
 *  its menu ID.                                                           *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  sch_menu;           /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[SCHEDULE_MENU_IX] );

   sch_menu = create_menu ( 3, title, FALSE, border_color,
                            macmenu_fg, macmenu_bg, user_fg, user_bg );

   add_menu_item ( sch_menu, 'L', "Loan Size (in dollars)",         D_DOUBLE, (char *) &l );
   add_menu_item ( sch_menu, 'P', "Payment Size (in dollars)",      D_DOUBLE, (char *) &p );
   add_menu_item ( sch_menu, 'I', "Interest Rate (%)",              D_DOUBLE, (char *) &i );
   add_menu_item ( sch_menu, 'C', "Compounding Periods Per Year",   D_DOUBLE, (char *) &c );
   add_menu_item ( sch_menu, 'T', "Time between payments",          D_STRING, pi.str );

   add_menu_item ( sch_menu, NIL_KEY, "",                           D_NONE,   title );
   add_menu_item ( sch_menu, '$', "Additional Principal Amount",    D_DOUBLE, (char *) &apa  );
   add_menu_item ( sch_menu, '#', "Additional Principal Frequency", D_DOUBLE, (char *) &app  );

   add_menu_item ( sch_menu, NIL_KEY, "",                           D_NONE,   title );
   add_menu_item ( sch_menu, 'F', "Amortization File Setup",        D_NONE,   title );
   add_menu_item ( sch_menu, 'S', "Generate Amortization Schedule", D_NONE,   title );
   add_menu_item ( sch_menu, 'V', "View Amortization Schedule",     D_NONE,   title );

   add_menu_item ( sch_menu, NIL_KEY, "",                           D_NONE,   title );
   add_menu_item ( sch_menu, 'O', "OS Shell",                       D_NONE,   title );
   add_menu_item ( sch_menu, 'H', "Help",                           D_NONE,   title );
   add_menu_item ( sch_menu, 'Q', "Quit This Level",                D_NONE,   title );

   alias_select_key ( sch_menu, 'H', CMD_PF1 );
   alias_select_key ( sch_menu, 'Q', CMD_ESC );

   return ( sch_menu );

} /* create_schedule_menu */

/**/

MENU_ID create_numpayments_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu Num Payments menu, and returns its   *
 *  menu ID.                                                               *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  np_menu;            /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[NUMPAYMENTS_MENU_IX] );

   np_menu = create_menu ( 3, title, FALSE, border_color,
            macmenu_fg, macmenu_bg, user_fg, user_bg );

   add_menu_item ( np_menu, 'L', "Loan Size (in dollars)",         D_DOUBLE, (char *) &l );
   add_menu_item ( np_menu, 'P', "Payment Size (in dollars)",      D_DOUBLE, (char *) &p );
   add_menu_item ( np_menu, 'I', "Interest Rate (%)",              D_DOUBLE, (char *) &i );
   add_menu_item ( np_menu, 'C', "Compounding Periods Per Year",   D_DOUBLE, (char *) &c );
   add_menu_item ( np_menu, 'T', "Time between payments",          D_STRING, pi.str );

   add_menu_item ( np_menu, NIL_KEY, "",                           D_NONE,   title );
   add_menu_item ( np_menu, '$', "Additional Principal Amount",    D_DOUBLE, (char *) &apa );
   add_menu_item ( np_menu, '#', "Additional Principal Frequency", D_DOUBLE, (char *) &app );

   add_menu_item ( np_menu, NIL_KEY, "",                           D_NONE,   title );
   add_menu_item ( np_menu, 'S', "Solve for Num Payments",         D_NONE,   title );

   add_menu_item ( np_menu, NIL_KEY, "",                           D_NONE,   title );
   add_menu_item ( np_menu, 'O', "OS Shell",                       D_NONE,   title );
   add_menu_item ( np_menu, 'H', "Help",                           D_NONE,   title );
   add_menu_item ( np_menu, 'Q', "Quit This Level",                D_NONE,   title );

   alias_select_key ( np_menu, 'H', CMD_PF1 );
   alias_select_key ( np_menu, 'Q', CMD_ESC );

   return ( np_menu );

} /* create_numpayments_menu */

/**/

MENU_ID create_interestrate_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu interest rate menu, and returns its  *
 *  menu ID.                                                               *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  ir_menu;            /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[INTERESTRATE_MENU_IX] );

   ir_menu = create_menu ( 3, title, FALSE, border_color,
                           macmenu_fg, macmenu_bg, user_fg, user_bg );

   add_menu_item ( ir_menu, 'L', "Loan Size (in dollars)",       D_DOUBLE, (char *) &l );
   add_menu_item ( ir_menu, 'P', "Payment Size (in dollars)",    D_DOUBLE, (char *) &p );
   add_menu_item ( ir_menu, 'C', "Compounding Periods Per Year", D_DOUBLE, (char *) &c );
   add_menu_item ( ir_menu, 'N', "Number of Payments",           D_DOUBLE, (char *) &n );
   add_menu_item ( ir_menu, 'T', "Time Between Payments",        D_STRING, pi.str );

   add_menu_item ( ir_menu, NIL_KEY, "",                         D_NONE,   title );
   add_menu_item ( ir_menu, 'S', "Solve for Interest Rate",      D_NONE,   title );

   add_menu_item ( ir_menu, NIL_KEY, "",                         D_NONE,   title );
   add_menu_item ( ir_menu, 'O', "OS Shell",                     D_NONE,   title );
   add_menu_item ( ir_menu, 'H', "Help",                         D_NONE,   title );
   add_menu_item ( ir_menu, 'Q', "Quit This Level",              D_NONE,   title );

   alias_select_key ( ir_menu, 'H', CMD_PF1 );
   alias_select_key ( ir_menu, 'Q', CMD_ESC );

   return ( ir_menu );

} /* create_interestrate_menu */

/**/

MENU_ID create_paymentsize_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu payment size menu, and returns its   *
 *  menu ID.                                                               *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  ps_menu;            /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[PAYMENTSIZE_MENU_IX] );

   ps_menu = create_menu ( 3, title, FALSE, border_color,
                           macmenu_fg, macmenu_bg, user_fg, user_bg );

   add_menu_item ( ps_menu, 'L', "Loan Size (in dollars)",       D_DOUBLE, (char *) &l );
   add_menu_item ( ps_menu, 'I', "Interest Rate (%)",            D_DOUBLE, (char *) &i );
   add_menu_item ( ps_menu, 'C', "Compounding Periods Per Year", D_DOUBLE, (char *) &c );
   add_menu_item ( ps_menu, 'N', "Number of Payments",           D_DOUBLE, (char *) &n );
   add_menu_item ( ps_menu, 'T', "Time between payments",        D_STRING, pi.str );

   add_menu_item ( ps_menu, NIL_KEY, "",                         D_NONE,   title );
   add_menu_item ( ps_menu, 'S', "Solve for Payment Size",       D_NONE,   title );

   add_menu_item ( ps_menu, NIL_KEY, "",                         D_NONE,   title );
   add_menu_item ( ps_menu, 'O', "OS Shell",                     D_NONE,   title );
   add_menu_item ( ps_menu, 'H', "Help",                         D_NONE,   title );
   add_menu_item ( ps_menu, 'Q', "Quit This Level",              D_NONE,   title );

   alias_select_key ( ps_menu, 'H', CMD_PF1 );
   alias_select_key ( ps_menu, 'Q', CMD_ESC );

   return ( ps_menu );

} /* create_paymentsize_menu */

/**/

MENU_ID create_loansize_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu loansize menu, and returns its menu  *
 *  ID.                                                                    *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  ls_menu;            /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[LOANSIZE_MENU_IX] );

   ls_menu = create_menu ( 3, title, FALSE, border_color,
            macmenu_fg, macmenu_bg, user_fg, user_bg );

   add_menu_item ( ls_menu, 'P', "Payment Size (in dollars)",     D_DOUBLE, (char *) &p );
   add_menu_item ( ls_menu, 'I', "Interest Rate (%)",             D_DOUBLE, (char *) &i );
   add_menu_item ( ls_menu, 'C', "Compounding Periods Per Year",  D_DOUBLE, (char *) &c );
   add_menu_item ( ls_menu, 'N', "Number of Payments",            D_DOUBLE, (char *) &n );
   add_menu_item ( ls_menu, 'T', "Time between payments",         D_STRING, pi.str );

   add_menu_item ( ls_menu, NIL_KEY, "",                          D_NONE,   title );
   add_menu_item ( ls_menu, 'S', "Solve for Loan Size",           D_NONE,   title );

   add_menu_item ( ls_menu, NIL_KEY, "",                          D_NONE,   title );
   add_menu_item ( ls_menu, 'O', "OS Shell",                      D_NONE,   title );
   add_menu_item ( ls_menu, 'H', "Help",                          D_NONE,   title );
   add_menu_item ( ls_menu, 'Q', "Quit This Level",               D_NONE,   title );

   alias_select_key ( ls_menu, 'H', CMD_PF1 );
   alias_select_key ( ls_menu, 'Q', CMD_ESC );

   return ( ls_menu );

} /* create_loansize_menu */

/**/

MENU_ID create_main_menu ()

/***************************************************************************
 *                                                                         *
 *  This function creates the MACMenu main menu, and returns its menu ID.  *
 *                                                                         *
 ***************************************************************************/

{
   char title [82];             /* Title string for the menu               */
   MENU_ID  main_menu;          /* Menu ID for the created menu            */

   strcpy ( title, version );
   strcat ( title, "() "   );
   strcat ( title, menu_titles[MAIN_MENU_IX] );

   main_menu = create_menu ( 3, title, FALSE, border_color,
               macmenu_fg, macmenu_bg, user_fg, user_bg );

   add_menu_item ( main_menu, 'L', "Compute Loan Size",                     D_NONE, title );
   add_menu_item ( main_menu, 'P', "Compute Payment Size",                  D_NONE, title );
   add_menu_item ( main_menu, 'I', "Compute Interest Rate",                 D_NONE, title );
   add_menu_item ( main_menu, 'N', "Compute Number of Payments",            D_NONE, title );
   add_menu_item ( main_menu, 'S', "Compute Amortization Schedule",         D_NONE, title );

   add_menu_item ( main_menu, NIL_KEY, "",                                  D_NONE, title );
   add_menu_item ( main_menu, 'F', "Read/Write Loan Profile File",          D_NONE, title );

   add_menu_item ( main_menu, NIL_KEY, "",                                  D_NONE, title );
   add_menu_item ( main_menu, 'A', "About LoansMgr",                        D_NONE, title );

   add_menu_item ( main_menu, NIL_KEY, "",                                  D_NONE, title );
   add_menu_item ( main_menu, 'O', "OS Shell",                              D_NONE, title );
   add_menu_item ( main_menu, 'H', "Help",                                  D_NONE, title );
   add_menu_item ( main_menu, 'Q', "Quit LoansMgr",                         D_NONE, title );

   alias_select_key ( main_menu, 'H', CMD_PF1 );
   alias_select_key ( main_menu, 'Q', CMD_ESC );

   return ( main_menu );

} /* create_main_menu */


/**/

void create_menus ()

/***************************************************************************
 *                                                                         *
 *  This function create MACMenu menus for all LOANSMGR levels.            *
 *                                                                         *
 ***************************************************************************/

{
   menu_ids[MAIN_MENU_IX]         = main_menu         = create_main_menu ();
   menu_ids[LOANSIZE_MENU_IX]     = loansize_menu     = create_loansize_menu ();
   menu_ids[PAYMENTSIZE_MENU_IX]  = paymentsize_menu  = create_paymentsize_menu ();
   menu_ids[INTERESTRATE_MENU_IX] = interestrate_menu = create_interestrate_menu ();
   menu_ids[NUMPAYMENTS_MENU_IX]  = numpayments_menu  = create_numpayments_menu ();
   menu_ids[SCHEDULE_MENU_IX]     = schedule_menu     = create_schedule_menu ();
   menu_ids[PROFILE_MENU_IX]      = profile_menu      = create_profile_menu ();
   menu_ids[ABOUT_MENU_IX]        = about_menu        = create_about_menu ();
   menu_ids[SETUP_MENU_IX]        = setup_menu        = create_setup_menu ();

} /* create_menus */

/**/

int init_file_processor ( loansmgr_cmd_line, init_file_error, error_token )

/***************************************************************************
 * This function processes the .lm.ini file, which contains color          *
 * selections for the menus. This function returns 1 (TRUE) if an init     *
 * file was found, or 0 (FALSE) if one was not found.                      *
 ***************************************************************************/

 char *loansmgr_cmd_line;      /* The full pathname of the loansmgr cmd    */
 int  *init_file_error;        /* Was there a syntax error in init file?   */
 char *error_token;            /* Pointer to buffer where error is stored  */

{
   int  file_found = FALSE;   /* Return value: was a file found?           */
   FILE *init_file;           /* File pointer to init file                 */

   char loansmgr_path [82];   /* String for full pathname                  */
   char cmd_buffer    [82];   /* Buffer for parsing command into           */
   char color_buffer  [82];   /* Buffer for parsing color into             */

   int  len;                  /* Length of line that has been read         */
   int  cmd, color;           /* Parsing results for the read line         */

   *init_file_error = FALSE;

   pathname_of ( loansmgr_cmd_line, loansmgr_path );

   init_file  = (FILE *) file_open ( ".lm.ini", "r", loansmgr_path );
   file_found = ( init_file == NULL ? FALSE : TRUE );

   if ( file_found ) {

      /* Found an init file. Process it, line by line. Each line will be   */
      /* parsed into a command token and a color token, and then the color */
      /* will be assigned as per the command.                              */

      while ( (fgets(loansmgr_path, 80, init_file ) != NULL) ) {

         len = strlen (loansmgr_path);

         /* Skip blank or comment lines within the file                    */

         if ( (len <= 2) || (loansmgr_path[0] == ';') )
            continue;

         /* Parse the line just read into a command and a color, and then  */
         /* lookup the color. If not recognized, quit.                     */

         sscanf ( loansmgr_path, "%s %s", cmd_buffer, color_buffer );
         color = findstr ( color_buffer, colors, NUM_COLORS );

         if ( color == -1 ) {
            *init_file_error = TRUE;
            strcpy ( error_token, color_buffer );
            break;
         }

         else {
            /* The color is recognized - attempt to process the command   */

            cmd = findstr ( cmd_buffer, init_cmds, NUM_INIT_CMDS );

            switch ( cmd ) {

               case MACMENU_FG_IX :
                  macmenu_fg = ncurses_color_codes[color];
                  break;

               case MACMENU_BG_IX :
                  macmenu_bg = ncurses_color_codes[color];
                  break;

               case ITEM_FG_IX :
                  user_fg = ncurses_color_codes[color];
                  break;

               case ITEM_BG_IX :
                  user_bg = ncurses_color_codes[color];
                  break;

               case POPUP_FG_IX :
                  popup_fg = ncurses_color_codes[color];
                  break;

               case POPUP_BG_IX :
                  popup_bg = ncurses_color_codes[color];
                  break;

               case BORDER_COLOR_IX :
                  border_color = ncurses_color_codes[color];
                  break;

               default :
                  *init_file_error = TRUE;
                  strcpy ( error_token, cmd_buffer );
                  break;

            } /* switch */

         } /* color is recognized */

      } /* while input line available */

      fclose ( init_file );

   } /* there is an init file */

   return ( file_found );

} /* init_file_processor */

/**/

void init_loansmgr ( loansmgr_cmd_line, init_file_error, error_token )

/***************************************************************************
 * This function initializes LOANSMGR by creating all the necessary menus, *
 * initializing all global vars, and setting up the menu colors.           *
 ***************************************************************************/

 char *loansmgr_cmd_line;      /* The full pathname of the loansmgr cmd    */
 int  *init_file_error;        /* Was there a syntax error in init file?   */
 char *error_token;            /* Pointer to buffer where error is stored  */

 {
   BOOL file_found;            /* Was an init file found?                  */
   unsigned char video_mode;   /* The video mode at startup                */

   debug_mode = FALSE;         /* Not in debug mode at start up            */

   help         = show_help;   /* Set up "normal" help                     */
   help_is_rude = FALSE;

   signal ( SIGINT, SIG_DFL ); /* Allow CTL-C aborts of LOANSMGR           */

   set_default_profile ();     /* Set up default profile and colors        */
   set_default_colors ();

   file_found = init_file_processor ( loansmgr_cmd_line, init_file_error,
                error_token );

   if ( !file_found || *init_file_error ) {

      /* If there was not an init file, or if there was an error in the    */
      /* file that was found, set up the default colors, so that the user  */
      /* can see the error message.                                        */

      set_default_colors ();
   }

   init_macmenu ();  /* Inits ncurses too */

   sx = COLS;
   sy = LINES;

   if ( sx < 80 || sy < 24 ) {
      endwin ();
      printf ( "\n%s\n", "LoansMgr requires at least 80x24 to run...Sorry!\n" );
      exit ( EXIT_FAILURE );
   }

   create_menus ();

} /* init_loansmgr */

/**/

int main ( argc, argv )

/*****************************************************************************
 *                                                                           *
 *  This is the mainline of the loans manager program. It outputs the        *
 *  initial menu, and calls all of the other routines accordingly.           *
 *                                                                           *
 *****************************************************************************/

int argc;                      /* The number of command line arguments     */
char *argv[];                  /* The argument strings                     */

{
   BOOL init_file_error;       /* Was there an error in the init file?     */
   char error_token [82];      /* Buffer for the errored cmd in init file  */
   BOOL loaded;                /* Was the specified data file loaded OK?   */

   char cmd = ' ';             /* User intered response character          */
   char input [82];            /* Text buffer for user input               */
   int length;                 /* Length of user's input line              */

   BOOL done = FALSE;          /* Has user quit the program?               */
   BOOL redraw_menu = FALSE;   /* Redraw the main menu?                    */


   init_loansmgr ( argv[0], &init_file_error, error_token );

   put_menu ( main_menu );        /* Present the main menu                 */
      
   if ( init_file_error ) {

      /* There was an error in the init file - present the errored command */
      /* or color to the user.                                             */

      strcpy ( input, "LOANSMGR.INI error - Bad keyword: " );
      strcat ( input, error_token );

      put_status_string ( input );
   }

   /* If there is a command line argument, it is the name of a loan        */
   /* profile file. Attempt to load it. Note that this code cannot be      */
   /* dropped into the init_loansmgr function because it assumes the       */
   /* presence of the main menu for outputting error messages.             */

   if ( argc > 1 ) {
      loaded = read_loan_data ( argv[1] );
      if ( loaded ) {
         update_menu_titles ( argv[1] );
         strcpy ( profile_file_name, argv[1] );
      }
   }

   while ( !done ) {

      cmd = get_menu_selection ( main_menu );

      switch ( toupper(cmd) ) {

         case 'L':
            loansize_menu_processor ();
            redraw_menu = TRUE;
            break;

         case 'P':
            paymentsize_menu_processor ();
            redraw_menu = TRUE;
            break;

         case 'I':
            interestrate_menu_processor ();
            redraw_menu = TRUE;
            break;

         case 'N':
            numpayments_menu_processor ();
            redraw_menu = TRUE;
            break;

         case 'S':
            schedule_menu_processor ();
            redraw_menu = TRUE;
            break;

         case 'F':
            profile_menu_processor ();
            redraw_menu = TRUE;
            break;

         case 'O' :
            os_ci ( main_menu );
            break;

         case 'A':
            about_menu_processor ();
            redraw_menu = TRUE;
            break;

         case 'H':
            (*help) ( main_help, sx, sy, popup_fg, popup_bg, macmenu_fg,
                      macmenu_bg, main_menu );
            break;

         case 'R':
            /* Nasty, nasty! Hidden "Toggle Help" command! Toggles help    */
            /* between "Rude" mode, and Normal mode. It does this by       */
            /* binding in the appropriate help/no-help function.           */

            help_is_rude = !help_is_rude;

            if ( help_is_rude ) {
               help = no_help;
               put_status_string ( "Help = Rude: Don't blame me, you asked for it!" );
            }

            else {
               help = show_help;
               put_status_string ( "Help = Normal" );
            }

            break;

         case 'M':
            /* Oh dear, another hidden command!! This one toggles the mode  */
            /* of LoansMgr, into and out of debug mode.                     */

            debug_mode = !debug_mode;

            if ( debug_mode )
               put_status_string ( "Mode is now Debug" );
            else
               put_status_string ( "Mode is now Normal" );

            break;

         case 'Q':
            done = TRUE;
            break;

         default:
            put_status_string ( "Invalid Selection - Again?" );
            break;

      } /* switch cmd */

      /* Redraw the main menu if the last command overwrote it. */

      if ( redraw_menu ) {
         put_menu (main_menu );
         redraw_menu = FALSE;
      }

   } /* while !done */

   exit_macmenu ();

} /* main */
