home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / DATABASE / CHX8010B.LBR / CHECKS.CZ / CHECKS.C
Text File  |  2000-06-30  |  29KB  |  766 lines

  1. /*  checks.c -- main source file for check register program                  */
  2.  
  3. /*  copyright (c) 1986 by Jim Woolley and WoolleyWare, San Jose, CA          */
  4.  
  5. /*  vers. 1.0, 12/85 thru 5/86
  6.  */
  7.  
  8. /*  this file contains:
  9.  *      main()
  10.  *      startup()
  11.  *      getval( q)
  12.  *      getentry()
  13.  *      getinfo()
  14.  *      getyesno( def)
  15.  *      struct nlist *install( name, def)
  16.  *      struct nlist *lookup( s)
  17.  *      hash( s)
  18.  *      char *strsave( s)
  19.  *      compdate( e1, e2)
  20.  *      datecomp( d1, d2)
  21.  *      comppayee( e1, e2)
  22.  *      compcateg( e1, e2)
  23.  *      categcomp( e1, e2)
  24.  *      compamount( e1, e2)
  25.  *      compbbf( e1, e2)
  26.  *      compabrev( p1, p2)
  27.  *      isebbf( e)
  28.  *      isibbf( i)
  29.  *      char *index( s, c)
  30.  *      char *skipspace( s)
  31.  *      typcat( f, t)
  32.  *      openerr()
  33.  *      readerr()
  34.  *      writerr( s)
  35.  *      createrr( s)
  36.  *      baddisk()
  37.  */
  38.  
  39. #include    "a:checks.h"
  40.  
  41. main( argc, argv)                       /*  check register program           */
  42. int argc;
  43. char *argv[];
  44. {
  45.     char *p, *copyright, *allrights;
  46.     int i, length;
  47.  
  48.     copyright = "Check Register Program, v.1.0 (c) 1986 by WoolleyWare";
  49.                 /*  copyright must be < (COLS - FNAMSIZE - 3) chars          */
  50.     allrights = "All Rights Reserved";
  51.  
  52.     _Outdev = CONOUT;                   /*  direct putchar() to screen       */
  53.     _Lastch = 0;                        /*  used by getchar()/ungetch()      */
  54.     Speed = 5;                          /*  initial Speed for ^QW and ^QZ    */
  55.     Today.yy = 0;                       /*  initialize other globals         */
  56.     Savrecno = Oldfield = -1;
  57.     Modified = Printing = Ctrlyundo = FALSE;
  58.     for ( i = 0; i < HASHSIZE; ++i)
  59.         Hashtab[ i] = 0;
  60.     strcpy( Title, copyright);
  61.     Ftoc[ MMFIELD] = 1;                 /*  Ftoc[ f] = c                     */
  62.     Ftoc[ DDFIELD] = 4;                 /*  locates cursor for Field f       */
  63.     Ftoc[ YYFIELD] = 7;                 /*  at column c, where c = 0         */
  64.     Ftoc[ PAYFIELD] = 9;                /*  corresponds to left edge         */
  65.     Ftoc[ CATFIELD] = 52;               /*  of screen                        */
  66.     Ftoc[ AMTFIELD] = 61;
  67.     Ftoc[ DEPFIELD] = 63;
  68.     Ftoc[ CLRFIELD] = 67;
  69.  
  70.     if ( argc > 1)                      /*  get Filename root                */
  71.         p = argv[ 1];
  72.     else p = DEFNAM;
  73.     length = strlen( p);
  74.     if ( !index( p, ':'))               /*  if no drive designated           */
  75.     {
  76.         Filename[ 0] = 'A' + defdsk();
  77.         Filename[ 1] = ':';
  78.         i = 2;
  79.     }
  80.     else                                /*  drive was designated             */
  81.     {
  82.         if ( length == 2)               /*  if just d: without filename      */
  83.         {
  84.             strcpy( Filename, p);
  85.             p = DEFNAM;                 /*  use default                      */
  86.             i = 2;
  87.         }
  88.         else i = 0;
  89.     }
  90.     if ( length > ( FNAMSIZE - 5 - i))  /*  should be FALSE if p = DEFNAM    */
  91.         *( p + FNAMSIZE - 5 - i) = '\0';
  92.     strcpy(( Filename + i), p);
  93.     if ( !( p = index( Filename, '.'))) /*  add dot if none                  */
  94.         *( p = Filename + strlen( Filename)) = '.';
  95.     *( p + 1) = '\0';                   /*  truncate after dot               */
  96.  
  97.     startup();
  98.     getentry();                         /*  read entry data                  */
  99.     disheading();                       /*  initialize display               */
  100.     Recno = Maxentry + ( 1 - PAGE);     /*  initialize gobottom()            */
  101.     First = Recno - PAGE;
  102.     Last = First - 1;
  103.     Field = 0;
  104.     gobottom();
  105.     getinfo();                          /*  read title, abrev, auto entries  */
  106.     control();                          /*  never returns                    */
  107. }
  108.  
  109. startup()                               /*  startup check register program   */
  110. {
  111.     char line, *p, *q, s[ MAXLINE], f[ FNAMSIZE], buf[ BUFSIZ], *fgets();
  112.     int i;
  113.  
  114.     strcpy( f, DEFNAM);
  115.     typcat( f, SCRTYP);
  116.     if ( fopen( f, buf) == ERROR)
  117.         abort( "Cannot open ", f);      /*  never returns                    */
  118.     for ( line = 6; line; --line)       /*  skip 6 lines                     */
  119.         if ( !fgets( s, buf))
  120.             readerr( f);                /*  never returns                    */
  121.     for ( line = 0; line < 11; ++line)  /*  get cursor/screen controls       */
  122.     {
  123.         if ( !fgets(( q = s), buf))
  124.             readerr( f);                /*  never returns                    */
  125.         switch ( line)
  126.         {
  127.         case 0:
  128.             p = Clead1;
  129.             break;
  130.         case 1:
  131.             p = Clead2;
  132.             break;
  133.         case 2:
  134.             p = Ctrail;
  135.             break;
  136.         case 3:
  137.             Cb4flg = getval( &q);
  138.             Linoff = getval( &q);
  139.             Coloff = getval( &q);
  140.             if ( Ascur = getval( &q))   /*  Ascur must be 0, 2, or 3         */
  141.                 Ascur = min( 3, max( 2, Ascur));
  142.             break;
  143.         case 4:
  144.             p = Eraeol;
  145.             break;
  146.         case 5:
  147.             p = Lindel;
  148.             break;
  149.         case 6:
  150.             p = Linins;
  151.             break;
  152.         case 7:
  153.             p = Ivon;
  154.             break;
  155.         case 8:
  156.             p = Ivoff;
  157.             break;
  158.         case 9:
  159.             p = Trmini;
  160.             break;
  161.         case 10:
  162.             Dloop = (( DLOOP/10)*max( 1, min( 1000, getval( &q))))/10;
  163.             Inserton = getval( &q);
  164.             break;
  165.         default:
  166.             break;
  167.         }
  168.         if ( line != 3)                 /*  note that i may be negative      */
  169.             for ( *p++ = i = getval( &q); i > 0; --i)
  170.                 *p++ = getval( &q);
  171.     }
  172.     if ( fgets( s, buf))                /*  if more than 17 lines            */
  173.     {
  174.         clrscr();
  175.         while (( i = getc( buf)) != CPMEOF && i != ERROR)
  176.             putchar( i - 1);
  177.         if ( getchar() == CTRLC)
  178.             exit();                     /*  never returns                    */
  179.     }
  180.     fclose( buf);
  181.     clrscr();
  182. }
  183.  
  184. /*  getval( q) returns next int value from string of decimal numbers separated
  185.  *  by white space; string must be pointed to by *q; each decimal number in
  186.  *  string may be headed by white space with optional minus sign followed by
  187.  *  consecutive decimal digits; first non-digit terminates the scan; zero is
  188.  *  returned if no legal value is found; *q will be updated to point to first
  189.  *  white space char following the current decimal number; *q will not point
  190.  *  beyond end of string
  191.  *
  192.  *  sample calling program segment:
  193.  *
  194.  *      char *p;                        string pointer
  195.  *      p = " 1   -32 123   9";         point to typical space separated string
  196.  *      printf( "%d", getval( &p));     pass pointer to string pointer
  197.  */
  198.  
  199. getval( q)                              /*  return int value and update *q   */
  200. char **q;                               /*  pointer to string pointer        */
  201. {
  202.     int i;
  203.  
  204.     i = atoi( *q = skipspace( *q));
  205.     while ( !isspace( **q) && **q)
  206.         ++( *q);
  207.     return ( i);
  208. }
  209.  
  210. getentry()                              /*  get check register entries       */
  211. {
  212.     char *p, buf[ BUFSIZ];
  213.     int g, imax;
  214.  
  215.     typcat( Filename, DATTYP);
  216.     if ( fopen( Filename, buf) == ERROR)
  217.     {
  218.         openerr( Filename);
  219.         Maxentry = -1;                  /*  initialize                       */
  220.         Memory.dollar = Memory.cent = 0;
  221.         return;
  222.     }
  223.     if (( g = getw( buf)) == ERROR)
  224.         readerr( Filename);             /*  never returns                    */
  225.     imax = RECSIZ*g;
  226.     Maxentry = g - 1;
  227.     Memory.dollar = getw( buf);         /*  assume no read error             */
  228.     Memory.cent = getw( buf);
  229.     p = Entry;
  230.     while ( imax--)
  231.     {
  232.         if (( g = getc( buf)) == ERROR)
  233.             readerr( Filename);         /*  never returns                    */
  234.         *p++ = g;
  235.     }
  236.     fclose( buf);
  237.     for ( g = 0; g <= Maxentry; ++g)
  238.         newbalance( g);
  239. }
  240.  
  241. getinfo()                               /*  get title, abrev, and auto trans */
  242. {
  243.     char *p, *q, *amsg, c, new, next, def, savmodified;
  244.     char *key[ 3], buf[ BUFSIZ], s[ MAXLINE], *fgets();
  245.     char adate, adeposit, acategory;
  246.     int i, delta, count, adollar, acent, compdate();
  247.     struct record *e;
  248.     struct calendar maxdate;
  249.  
  250.     key[ 0] = "TITLE";                  /*  initialize                       */
  251.     key[ 1] = "ABREV";
  252.     key[ 2] = "AUTOM";
  253.     amsg = "Installing abreviations ... ";
  254.     typcat( Filename, INFTYP);
  255.     if ( fopen( Filename, buf) == ERROR)
  256.     {
  257.         openerr( Filename);
  258.         return;
  259.     }
  260.     next = 0;
  261.     while ( fgets( s, buf))             /*  read one line at a time          */
  262.     {
  263.         s[ strlen( s) - 1] = '\0';      /*  truncate Abc\n\0 at \n           */
  264.         if ( p = index( s, '|'))        /*  skip comment starting with |     */
  265.             *p = '\0';
  266.         if ( s[ 0] == '\0')
  267.             continue;
  268.         for ( new = 3; new; --new)      /*  look for keyword                 */
  269.         {
  270.             p = key[ new - 1];
  271.             for ( i = 0; i < 5;  ++i)
  272.                 if ( toupper( s[ i]) != *p++)
  273.                     break;
  274.             if ( i == 5)
  275.             {
  276.                 if (( next = new) == 2)
  277.                     prompt( amsg);
  278.                 break;                  /*  break for loop on new            */
  279.             }
  280.         }
  281.         if ( new)                       /*  if keyword found                 */
  282.             continue;                   /*      get next line from file      */
  283.         switch ( next)
  284.         {
  285.         case 2:                         /*  keyword was ABREV                */
  286.             if ( strlen( p = s) < 3)
  287.             {
  288.                 prompt( "Invalid abreviation ");
  289.                 goto error;
  290.             }
  291.             while ( p < ( s + 3))       /*  make abreviation upper case      */
  292.             {
  293.                 *p = toupper( *p);
  294.                 ++p;
  295.             }
  296.             *p++ = '\0';                /*  end abreviation                  */
  297.             p = skipspace( p);          /*  locate full text                 */
  298.             if ( strlen( p) > ( PAYEESIZE - 1))
  299.                 *( p + PAYEESIZE - 1) = '\0';
  300.             if ( !install( s, p))
  301.             {
  302.                 prompt( "Could not install abreviation ");
  303.                 goto error;
  304.             }
  305.             break;                      /*  break switch on next             */
  306. error:      puts( s);                   /*  complete error message           */
  307.             waitesc();
  308.             prompt( amsg);
  309.             break;                      /*  break switch on next             */
  310.         case 3:                         /*  keyword was AUTOM                */
  311.             if ( Maxentry == ( ENTRYSIZE - 1))
  312.             {
  313.                 prompt( "Number of entries is maximum allowed");
  314.                 waitesc();
  315.                 next = 0;
  316.                 break;                  /*  break switch on next             */
  317.             }
  318.             if ( !Today.yy)             /*  initialize maxdate once          */
  319.                 maxdate.mm = maxdate.dd = maxdate.yy = 0;
  320.             ++Maxentry;                 /*  create temporary entry           */
  321.             ++Last;
  322.             for ( i = 0; i < Maxentry; ++i)
  323.                 datemax( &maxdate, &( Entry[ i].date));
  324.             cursorput( Recno, 0);       /*  Recno and Maxentry are same      */
  325.             putdate( &maxdate);
  326.             e = &Entry[ Recno];         /*  setup to use eddate              */
  327.             e->date.mm = maxdate.mm;
  328.             e->date.dd = maxdate.dd;
  329.             e->date.yy = maxdate.yy;
  330.             count = Ftoc[ YYFIELD] + 4;
  331.             savmodified = Modified;
  332.             FOREVER
  333.             {
  334.                 if ( Today.yy)
  335.                     goto query;
  336.                 cursorput( Recno, count);
  337.                 puts( p = "<<<  Enter today's date");
  338.                 Field = MMFIELD;
  339.                 while ( Field < ( YYFIELD + 1))
  340.                 {
  341.                     putquery();
  342.                     putcursor( Recno, Field);
  343.                     c = eddate( getchar());
  344.                     if ( c == ESC)
  345.                         goto skipit;
  346.                     switch ( c)
  347.                     {
  348.                         case 0:
  349.                             break;
  350.                         case CTRLD:  case '\r':  case CTRLF:  case '\t':
  351.                             goright( c);
  352.                             break;
  353.                         case CTRLS:  case '\b':  case CTRLA:
  354.                             if ( Field > MMFIELD)
  355.                             {
  356.                                 goleft( c);
  357.                                 break;
  358.                             }           /*  else fall thru                   */
  359.                         default:
  360.                             putchar( BEL);
  361.                             break;
  362.                     }                   /*  end of switch on c               */
  363.                 }                       /*  end of while loop on Field       */
  364. query:          cursorput( Recno, count);
  365.                 clreol( count);
  366.                 prompt( "Do you wish to revise today's date (Y/N)? ");
  367.                 if ( getyesno( NO))
  368.                     Today.yy = 0;
  369.                 else break;             /*  break FOREVER loop               */
  370.             }                           /*  end of FOREVER loop              */
  371. skipit:     Today.mm = e->date.mm;
  372.             Today.dd = e->date.dd;
  373.             Today.yy = e->date.yy;
  374.             if ( Recno > 0)             /*  delta = last date to cur month   */
  375.             {                           /*  limit 1 year; use 32 days/month  */
  376.                 delta = ( min( 1, ( Today.yy - maxdate.yy))*12
  377.                         + ( Today.mm - maxdate.mm - 1))*32 + ( 32 - maxdate.dd);
  378.             }
  379.             else delta = 0;
  380.  
  381. /*  graphical representation of various automatic entry parameters:
  382.  *
  383.  *  when month of most recent entry (last) < current month (today):
  384.  *
  385.  *      | delta |        Today.dd        |
  386.  *      |       |  adate |               |
  387.  *  ----|-------|--------|---------------|-----------|---
  388.  *     last   32|0      auto           today       32|
  389.  *  last month  |           current month            |
  390.  *
  391.  *  when month of most recent entry (last) = current month (today):
  392.  *
  393.  *              |        Today.dd        | 
  394.  *              | -delta | delta+Today.dd|
  395.  *  ------------|--------|-----|---------|-----------|---
  396.  *            32|0      last  auto     today       32|
  397.  *  last month  |           current month            |
  398.  */
  399.             cursorput( Recno, 0);       /*  clear today's date               */
  400.             clreol( 0);
  401.             --Maxentry;                 /*  delete temporary entry           */
  402.             --Last;
  403.             Field = 0;
  404.             Modified = savmodified;
  405.             if (( delta + Today.dd) <= 0)
  406.             {
  407.                 next = 0;
  408.                 break;                  /*  break switch on next             */
  409.             }
  410.             next = 4;                   /*  prepare for next line from file  */
  411.         case 4:                         /*  interpret automatic transaction  */
  412.             adate = atoi( p = skipspace( s));
  413.             acategory = DEFCAT;
  414.             if ( q = index( p, ' '))
  415.                 acategory = *( p = skipspace( q));
  416.             if ( acategory == '-')
  417.                 acategory = DEFCAT;
  418.             else acategory = toupper( acategory);
  419.             adollar = acent = 0;
  420.             if ( q = index( p, ' '))
  421.             {
  422.                 q = skipspace( q);      /*  start of amount                  */
  423.                 while ( *q == '-')
  424.                     ++q;                /*  ignore minus signs               */
  425.                 if ( p = index( q, '.'))
  426.                     acent = atoi( p + 1);
  427.                 else p = index( q, ' ');
  428.                 if (( p - q) > 2)
  429.                 {
  430.                     p -= 2;
  431.                     acent += 100*atoi( p);
  432.                     *p = '|';           /*  mark end of adollar              */
  433.                     adollar = atoi( q);
  434.                 }
  435.                 else acent += 100*atoi( q);
  436.                 p = q;
  437.             }
  438.             adeposit = FALSE;
  439.             if ( q = index( p, ' '))
  440.                 adeposit = ( toupper( *( p = skipspace( q))) == 'D');
  441.             if ( q = index( p, ' '))
  442.                 p = skipspace( q);      /*  start of payee                   */
  443.             if ( strlen( p) > ( PAYEESIZE - 1))
  444.                 *( p + PAYEESIZE - 1) = '\0';
  445.             count = max( 0, ( delta + adate - 1)/32);
  446.             if ( Today.dd >= adate && -delta < adate)
  447.                 ++count;                /*  count is number of entries       */
  448.             while ( count--)            /*  skip if count is zero            */
  449.             {
  450.                 savmodified = Modified;
  451.                 if ( !insert())         /*  if cannot insert Recno           */
  452.                 {
  453.                     next = 0;
  454.                     break;              /*  break while loop on count        */
  455.                 }
  456.                 e = &Entry[ Recno];
  457.                 i = Today.mm - count;
  458.                 if ( Today.dd < adate)
  459.                     --i;
  460.                 e->date.yy = Today.yy;
  461.                 while ( i <= 0)
  462.                 {
  463.                     i += 12;
  464.                     --( e->date.yy);
  465.                 }
  466.                 e->date.mm = i;
  467.                 e->date.dd = adate;
  468.                 strcpy( e->payee, p);
  469.                 e->category = acategory;
  470.                 e->amount.dollar = adollar;
  471.                 e->amount.cent = acent;
  472.                 e->deposit = adeposit;
  473.                 newbalance( Recno);
  474.                 putrecord( Recno);
  475.                 def = NO;               /*  default                          */
  476.                 c = ESC;
  477.                 while ( c == ESC)
  478.                 {
  479.                     prompt( "Do you accept this automatic entry (Y/N)? ");
  480.                     def = !def;         /*  reverse                          */
  481.                     putchar( def ? 'Y' : 'N');
  482.                     putcursor( Recno, ( Field = 0));
  483.                     c = getchar();
  484.                 }
  485.                 c = toupper( c);
  486.                 if ( c == 'N' || ( !def && c != 'Y'))
  487.                 {
  488.                     delete();           /*  delete Recno                     */
  489.                     Modified = savmodified;
  490.                     Ctrlyundo = FALSE;
  491.                 }
  492.                 else godown( CTRLX);
  493.             }                           /*  end of while loop on count       */
  494.             break;                      /*  break switch on next             */
  495.         case 1:                         /*  keyword was TITLE                */
  496.             s[ COLS - FNAMSIZE - 3] = '\0';
  497.             strcpy( Title, s);          /*  s truncated at max Title length  */
  498.             cursorto( 0, 0);
  499.             putscr( Ivon);
  500.             puttitle();
  501.             putscr( Ivoff);
  502.             break;                      /*  break switch on next             */
  503.         default:
  504.             break;                      /*  break switch on next             */
  505.         }                               /*  end of switch on next            */
  506.     }                                   /*  end of while loop on fgets       */
  507.     fclose( buf);
  508. }
  509.  
  510. getyesno( def)                          /*  return YES or NO response        */
  511. char def;                               /*  default response                 */
  512. {
  513.     char c;
  514.  
  515.     def = !def;                         /*  reverse default                  */
  516.     c = ESC;
  517.     while ( c == ESC)
  518.     {
  519.         def = !def;                     /*  reverse default                  */
  520.         putchar( def ? 'Y' : 'N');      /*  display default                  */
  521.         putchar( '\b');
  522.         c = getchar();
  523.     }
  524.     c = toupper( c);
  525.     if (( def && c != 'N') || ( !def && c != 'Y'))
  526.         return ( def);
  527.     def = !def;                         /*  reverse default                  */
  528.     putchar( def ? 'Y' : 'N');          /*  display response                 */
  529.     return ( def);
  530. }
  531.  
  532. struct nlist *install( name, def)       /*  install in Hashtab               */
  533. char *name;                             /*  abrev                            */
  534. char *def;                              /*  fullname                         */
  535. {                                       /*  ref. K & R, p. 136               */
  536.     int hashval;
  537.     struct nlist *np;
  538.  
  539.     if ( !( np = lookup( name)))        /*  if not found                     */
  540.     {
  541.         if ( !( np = alloc( sizeof( *np))))
  542.             return ( 0);
  543.         if ( !( np->abrev = strsave( name)))
  544.             return ( 0);
  545.         hashval = hash( np->abrev);
  546.         np->next = Hashtab[ hashval];   /*  initialized to zero              */
  547.         Hashtab[ hashval] = np;
  548.     }
  549.     else if ( np->fullname)
  550.         free( np->fullname);
  551.     if ( !( np->fullname = strsave( def)))
  552.         return ( 0);
  553.     return ( np);
  554. }
  555.  
  556. struct nlist *lookup( s)                /*  look for s in Hashtab            */
  557. char *s;
  558. {                                       /*  ref. K & R, p. 135               */
  559.     struct nlist *np;
  560.  
  561.     for ( np = Hashtab[ hash( s)]; np; np = np->next)
  562.         if ( !strcmp( s, np->abrev))
  563.             return ( np);               /*  found                            */
  564.     return ( 0);                        /*  not found                        */
  565. }
  566.  
  567. hash( s)                                /*  determine hash value for s       */
  568. char *s;
  569. {                                       /*  ref. K & R, p. 135               */
  570.     int hashval;
  571.  
  572.     hashval = 0;
  573.     while ( *s)
  574.         hashval += *s++;
  575.     return ( hashval%HASHSIZE);
  576. }
  577.  
  578. char *strsave( s)                       /*  save s somewhere                 */
  579. char *s;
  580. {                                       /*  ref. K & R, p. 103               */
  581.     char *p;
  582.  
  583.     if ( p = alloc( strlen( s) + 1))
  584.         strcpy( p, s);
  585.     return ( p);
  586. }
  587.  
  588. compdate( e1, e2)                       /*  return  1 if date of e1 > e2     */
  589. struct record *e1, *e2;                 /*  return -1 if date of e1 < e2     */
  590. {                                       /*  else, return strcmp on payee     */
  591.     int test;
  592.  
  593.     if ( test = compbbf( e1, e2))       /*  sort BBF entries to top          */
  594.         return ( test);
  595.     if ( test = datecomp( &( e1->date), &( e2->date)))
  596.         return ( test);
  597.     return ( strcmp( e1->payee, e2->payee));
  598. }
  599.  
  600. datecomp( d1, d2)                       /*  return  1 if calendar d1 > d2    */
  601. struct calendar *d1, *d2;               /*  return -1 if calendar d1 < d2    */
  602. {                                       /*  else, return 0                   */
  603.     if ( d1->yy > d2->yy)
  604.         return ( 1);
  605.     if ( d1->yy < d2->yy)
  606.         return ( -1);
  607.     if ( d1->mm > d2->mm)
  608.         return ( 1);
  609.     if ( d1->mm < d2->mm)
  610.         return ( -1);
  611.     if ( d1->dd > d2->dd)
  612.         return ( 1);
  613.     if ( d1->dd < d2->dd)
  614.         return ( -1);
  615.     return ( 0);
  616. }
  617.  
  618. comppayee( e1, e2)                      /*  return  1 if payee of e1 > e2    */
  619. struct record *e1, *e2;                 /*  return -1 if payee of e1 < e2    */
  620. {                                       /*  else, return compdate( e1, e2)   */
  621.     int test;
  622.  
  623.     if ( test = compbbf( e1, e2))       /*  sort BBF entries to top          */
  624.         return ( test);
  625.     if ( test = strcmp( e1->payee, e2->payee))
  626.         return ( test);
  627.     return ( compdate( e1, e2));
  628. }
  629.  
  630. compcateg( e1, e2)                      /*  return  1 if category of e1 > e2 */
  631. struct record *e1, *e2;                 /*  return -1 if category of e1 < e2 */
  632. {                                       /*  else, return compdate( e1, e2)   */
  633.     int test;
  634.  
  635.     if ( test = compbbf( e1, e2))       /*  sort BBF entries to top          */
  636.         return ( test);
  637.     return ( categcomp( e1, e2));
  638. }
  639.  
  640. categcomp( e1, e2)                      /*  return  1 if category of e1 > e2 */
  641. struct record *e1, *e2;                 /*  return -1 if category of e1 < e2 */
  642. {                                       /*  else, return compdate( e1, e2)   */
  643.     if ( e1->category > e2->category)
  644.         return ( 1);
  645.     if ( e1->category < e2->category)
  646.         return ( -1);
  647.     return ( compdate( e1, e2));
  648. }
  649.  
  650. compamount( e1, e2)                     /*  return  1 if amount of e1 > e2   */
  651. struct record *e1, *e2;                 /*  return -1 if amount of e1 < e2   */
  652. {                                       /*  else, return compdate( e1, e2)   */
  653.     int test;
  654.     struct money *m1, *m2;
  655.  
  656.     if ( test = compbbf( e1, e2))       /*  sort BBF entries to top          */
  657.         return ( test);
  658.     m1 = &( e1->amount);
  659.     m2 = &( e2->amount);
  660.     if ( m1->dollar > m2->dollar)
  661.         return ( 1);
  662.     if ( m1->dollar < m2->dollar)
  663.         return ( -1);
  664.     if ( m1->cent > m2->cent)
  665.         return ( 1);
  666.     if ( m1->cent < m2->cent)
  667.         return ( -1);
  668.     return ( compdate( e1, e2));
  669. }
  670.  
  671. compbbf( e1, e2)                        /*  return  1 if e1 not BBF, e2 is   */
  672. struct record *e1, *e2;                 /*  return -1 if e1 is BBF, e2 not   */
  673. {                                       /*  return  1 if both BBF, e1 > e2   */
  674.                                         /*  return -1 if both BBF, e1 < e2   */
  675.                                         /*  else, return 0                   */
  676.     if ( isebbf( e1))                    
  677.     {
  678.         if ( isebbf( e2))               /*  note two BBF entries cannot      */
  679.             return ( categcomp( e1, e2));   /*  have the same category       */
  680.         return ( -1);
  681.     }
  682.     if ( isebbf( e2))
  683.         return ( 1);
  684.     return ( 0);
  685. }
  686.  
  687. compabrev( p1, p2)                      /*  return  1 if abrev at p1 > p2    */
  688. struct nlist **p1, **p2;                /*  return -1 if abrev at p1 < p2    */
  689. {                                       /*  else, return 0 (not possible)    */
  690.     return ( strcmp(( *p1)->abrev, ( *p2)->abrev));
  691. }
  692.  
  693. isebbf( e)                              /*  return TRUE if e is a BBF entry  */
  694. struct record *e;                       /*  else, return FALSE               */
  695. {
  696.     return ( e->category & 0x80);
  697. }
  698.  
  699. isibbf( i)                              /*  return TRUE if Entry[ i] is BBF  */
  700. {                                       /*  else, return FALSE               */
  701.     return ( isebbf( &Entry[ i]));
  702. }
  703.  
  704. char *index( s, c)                      /*  point to char c in string s      */
  705. char *s, c;
  706. {
  707.     while ( *s && ( *s != c))
  708.         ++s;
  709.     return ( *s == c ? s : NULL);
  710. }
  711.  
  712. char *skipspace( s)                     /*  point to next non-space in s     */
  713. char *s;
  714. {
  715.     while ( *s && isspace( *s))
  716.         ++s;
  717.     return ( s);
  718. }
  719.  
  720. typcat( f, t)                           /*  add filetype t to filename f     */
  721. char *f, *t;
  722. {
  723.     strcpy(( index( f, '.') + 1), t);   /*  filename f MUST have a dot       */
  724. }
  725.  
  726. openerr( f)                             /*  display file open error          */
  727. char *f;
  728. {
  729.     prompt( "Could not open ");
  730.     puts( f);
  731.     waitkey();                          /*  may never return                 */
  732. }
  733.  
  734. readerr( f)                             /*  display file read error          */
  735. char *f;
  736. {
  737.     abort( "Error reading ", f);        /*  never returns                    */
  738. }
  739.  
  740. writerr( f)                             /*  display file write error         */
  741. char *f;
  742. {
  743.     prompt( "Error writing ");
  744.     puts( f);
  745.     waitesc();
  746.     unlink( f);
  747.     baddisk();
  748. }
  749.  
  750. createrr( f)                            /*  display file write error         */
  751. char *f;
  752. {
  753.     prompt( "Could not create ");
  754.     puts( f);
  755.     waitesc();
  756.     baddisk();
  757. }
  758.  
  759. baddisk()                               /*  prompt for another disk          */
  760. {
  761.     prompt( "Try another disk in ");
  762.     putchar( Filename[ 0]);
  763.     putchar( Filename[ 1]);
  764.     waitesc();
  765. }
  766.