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 / BEEHIVE / UTILITYS / CHX8012B.ARC / CHECKC.C < prev    next >
Text File  |  1990-07-21  |  27KB  |  909 lines

  1. /*  checkc.c -- 4th 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.  *  vers. 1.2, 7/86
  8.  *  saveclr() for CHECKS: add "Saving ... " display, avoid discarding SUMMARY
  9.  *      entries, and add getw, getc, and fclose error tests
  10.  *  savedat(): add fclose error test and argument TRUE if CR before display
  11.  *  savedat() for CLEARS: add count of SUMMARY entries to CLR file
  12.  *  help(): avoid writing '\n' after column 80 resulting in scrolling, add call
  13.  *      to putquery(), and display entry number
  14.  *  moved createrr(), writerr(), and baddisk() from checks.c
  15.  *  added renamerr() and puterrmsg()
  16.  *  integrated CLEARS using #ifdef
  17.  */
  18.  
  19. /*  this file contains:
  20.  *      putcursor( i, f)
  21.  *      cursorput( i, c)
  22.  *      cursorto( r, c)
  23.  *      putpos( i)
  24.  *      puttitle()
  25.  *      disheading()
  26.  *      recheading( s1, s2)
  27.  *      putquery()
  28.  *      prompt( s)
  29.  *      char putcommand( c)
  30.  *      char putcntrl( c)
  31.  *      char putnext()
  32.  *      addmoney( m3, m1, m2, add)
  33.  *      movmoney( m2, m1, credit)
  34.  *      putmoney( m)
  35.  *      putdate( d)
  36.  *      formatd( s, n, d)
  37.  *      printd( d)
  38.  *      sign( i)
  39.  *      char witch( c)
  40.  *      iscntrl( c)
  41.  *      waitesc()
  42.  *      waitkey()
  43.  *      done()
  44.  *      saveclr()
  45.  *      savedat( addcr)
  46.  *      calcbbf()
  47.  *      char help()
  48.  *      createrr( f)
  49.  *      writerr( f)
  50.  *      renamerr( f1, f2)
  51.  *      puterrmsg( s1, s2)
  52.  *      baddisk()
  53.  *      abort( s1, s2)
  54.  *      aexit()
  55.  */
  56.  
  57. #include    "a:checks.h"
  58.  
  59. putcursor( i, f)                        /*  put cursor in entry i, field f   */
  60. int i, f;
  61. {
  62. #ifndef CLEARS
  63.     if ( f == PAYFIELD)
  64.         Character = min( Character, strlen( Entry[ i].payee));
  65.     else Character = 0;
  66.     cursorto(( i - First + HEAD), ( Ftoc[ f] + Character));
  67. #else
  68.     cursorto(( i - First + HEAD), Ftoc[ f]);
  69. #endif
  70. }
  71.  
  72. cursorput( i, c)                        /*  put cursor in entry i, column c  */
  73. int i, c;
  74. {
  75.     cursorto(( i - First + HEAD), c);
  76. }
  77.  
  78. cursorto( r, c)                         /*  put cursor at row r, column c    */
  79. int r, c;                               /*  0, 0 is upper-left corner        */
  80. {
  81.     int i;
  82.  
  83.     if ( Printing)
  84.         putchar( '\n');
  85.     else
  86.     {
  87.         r += Linoff;                    /*  add offset                       */
  88.         c += Coloff;
  89.         if ( Cb4flg)
  90.         {
  91.             i = r;                      /*  swap                             */
  92.             r = c;
  93.             c = i;
  94.         }
  95.         putscr( Clead1);
  96.         putpos( r);
  97.         putscr( Clead2);
  98.         putpos( c);
  99.         putscr( Ctrail);
  100.     }
  101. }
  102.  
  103. putpos( i)                              /*  send cursor position i           */
  104. int i;                                  /*  ( 0 + offset) is home            */
  105. {
  106.     char *p, s[ 4];
  107.  
  108.     if ( Ascur)                         /*  if ASCII wanted                  */
  109.     {
  110.         strcpy(( p = s), "000");        /*  template                         */
  111.         if ( Ascur < 3)
  112.             ++p;
  113.         formatd( p, Ascur, i);
  114.         puts( p);
  115.     }
  116.     else putchar( i);
  117. }
  118.  
  119. puttitle()
  120. {
  121.     char f[ FNAMSIZE];
  122.     int i, length;
  123.  
  124.     strcpy( f, Filename);
  125.     *( index( f, '.')) = '\0';          /*  truncate at dot                  */
  126.  
  127. /*  display 5 spaces on left, right justify f on column (COLS - 1), precede
  128.  *  f with 2 spaces, then center Title in the remaining area; i.e.,
  129.  *  _____<<<<<<<<<<<<<<<<<<<<<<< center Title >>>>>>>>>>>>>>>>>>>>>__A:FILENAME
  130.  */
  131.     length = strlen( Title);
  132.     i = 5 + (( COLS - FNAMSIZE - 3) - length)/2;
  133.     length += i;
  134.     while ( i--)                        /*  center title                     */
  135.         putchar( ' ');
  136.     puts( Title);
  137.     i = ( COLS - 1) - length - strlen( f);
  138.     while ( i--)                        /*  fill title line (with Ivon)      */
  139.         putchar( ' ');
  140.     puts( f);
  141.     i = HEAD - 2;
  142.     while ( i--)
  143.         putchar( '\n');
  144. }
  145.  
  146. disheading()                            /*  display heading for display()    */
  147. {
  148.     if ( !Printing)
  149.     {
  150.         cursorto( 0, 0);
  151.         putscr( Ivon);
  152.     }
  153.     puttitle();
  154. #ifdef  CLEARS
  155.     puts( 
  156. "  Date   Payee                                      C  Amount  DEP <M>  Balance"
  157.          );
  158. #else
  159.     puts( 
  160. "  Date   Payee                                      C  Amount  DEP CLR  Balance"
  161.          );
  162. #endif
  163.     putchar( '\n');
  164.     puts( 
  165. "-------- ------------------------------------------ - -------- --- --- --------"
  166.          );
  167.     if ( !Printing)
  168.         putscr( Ivoff);
  169. }
  170.  
  171. recheading( s1, s2)                     /*  display heading for reconcile()  */
  172. char *s1, *s2;
  173. {
  174.     if ( !Printing)
  175.     {
  176.         clrscr();
  177.         putscr( Ivon);
  178.     }
  179.     puttitle();
  180. #ifdef  CLEARS
  181.     puts( 
  182. "  Last      Summary  _____ <M>arked Entries _____  _______ All Entries ________"
  183.          );
  184.     putchar( '\n');
  185.     puts(
  186. "  Date   C  Forward   Checks   Deposits   Summary   Checks   Deposits   Summary"
  187.          );
  188. #else
  189.     puts( 
  190. "  Last      Balance  _____ Cleared Entries ______  _______ All Entries ________"
  191.          );
  192.     putchar( '\n');
  193.     puts(
  194. "  Date   C  Forward   Checks   Deposits   Balance   Checks   Deposits   Balance"
  195.          );
  196. #endif
  197.     putchar( '\n');
  198.     puts( s1);
  199.     puts( s2);
  200.     if ( !Printing)
  201.         putscr( Ivoff);
  202. }
  203.  
  204. putquery()                              /*  select and display query         */
  205. {
  206.     char test, cwitch, dep;
  207.  
  208.     if ( Recno > Maxentry)
  209.     {
  210. #ifdef  CLEARS
  211.         prompt( "Press ^J for help");
  212. #else
  213.         prompt( "Press RETURN to start a new entry, or ^J for help");
  214. #endif
  215.         return;
  216.     }
  217.     if ( isibbf( Recno))                /*  if a BBF entry                   */
  218.     {
  219.         prompt( "Do you wish to void this entry's status as ");
  220.         puts( BBF);
  221.         puts( " (Y/N)? N");
  222.         return;
  223.     }
  224.     test = ( Field == Oldfield);
  225.     cwitch = Field;
  226. #ifdef  CLEARS
  227.     if ( test && cwitch != CLRFIELD)
  228.         return;
  229.     switch ( cwitch)
  230.     {
  231.     case CATFIELD:
  232.         prompt( "Enter category");
  233.         break;
  234.     case CLRFIELD:
  235.         prompt( "<M>ark this entry for summary/delete (Y/N)? ");
  236.         dep = Entry[ Recno].clear;
  237. yesno:  putchar( dep ? 'N' : 'Y');
  238.         break;
  239.     }
  240. #else
  241.     if ( test && cwitch != DEPFIELD && cwitch != CLRFIELD)
  242.         return;
  243.     switch ( cwitch)
  244.     {
  245.     case MMFIELD:
  246.         prompt( "Enter month");
  247.         break;
  248.     case DDFIELD:
  249.         prompt( "Enter date");
  250.         break;
  251.     case YYFIELD:
  252.         prompt( "Enter year");
  253.         break;
  254.     case PAYFIELD:
  255.         prompt( "Enter/edit payee    ( INSERT ");
  256.         puts( Inserton ? "ON )" : "OFF )");
  257.         break;
  258.     case CATFIELD:
  259.         prompt( "Enter category");
  260.         break;
  261.     case AMTFIELD:
  262.         prompt( "Enter/calculate amount");
  263.         cursorto(( HEAD - 4), ( AMTCOL - 9));
  264.         puts( "MEMORY = ");
  265.         putmoney( &Memory);
  266.         break;
  267.     case DEPFIELD:
  268.         prompt( "Is entry a deposit (Y/N)? ");
  269.         dep = Entry[ Recno].deposit;
  270.         goto yesno;
  271.     case CLRFIELD:
  272.         prompt( "Has entry cleared the bank (Y/N)? ");
  273.         dep = Entry[ Recno].clear;
  274. yesno:  putchar( dep ? 'Y' : 'N');
  275.         break;
  276.     }
  277. #endif
  278.     return;
  279. }
  280.  
  281. prompt( s)                              /*  prompt for entry                 */
  282. char *s;
  283. {
  284.     int c;
  285.  
  286.     cursorto(( HEAD - 4), 0);
  287.     puts( s);
  288.     clreol( c = strlen( s));
  289.     if ( !( *Eraeol))                   /*  if no Eraeol string              */
  290.         cursorto(( HEAD - 4), c);       /*  return cursor                    */
  291.     Oldfield = -1;
  292. }
  293.  
  294. char putcommand( c)                     /*  display command                  */
  295. char c;                                 /*  return TRUE if cursor moved      */
  296. {
  297.     switch ( c)
  298.     {
  299.     case CTRLK:  case CTRLQ:  case CTRLC:  case CTRLR:
  300.     case CTRLB:  case CTRLO:  case CTRLP:
  301.         cursorto( 0, 0);
  302.         putscr( Ivon);
  303.         puts( CLRCOM);
  304.         putchar( '\r');
  305.         putcntrl( c);
  306.         putscr( Ivoff);
  307.         return ( TRUE);
  308.     default:
  309.         return ( FALSE);
  310.     }
  311. }
  312.  
  313. char putcntrl( c)                       /*  display control char             */
  314. char c;                                 /*  return ( c + CTRLTOA) or DEL     */
  315. {
  316.     if ( c != DEL)
  317.     {
  318.         putchar( '^');
  319.         putchar( c += CTRLTOA);
  320.     }
  321.     else puts( "DEL");
  322.     return ( c);
  323. }
  324.  
  325. char putnext()                          /*  display next command character   */
  326. {                                       /*  return upper case character      */
  327.     char c;
  328.  
  329.     putscr( Ivon);
  330.     if ( isprint( c = getchar()))
  331.     {
  332.         putchar( c);
  333.         c = toupper( c);
  334.     }
  335.     else c = putcntrl( c);
  336.     putscr( Ivoff);
  337.     return ( c);
  338. }
  339.  
  340. addmoney( m3, m1, m2, add)              /*  get m3 = m1 + m2 if add = TRUE   */
  341. struct money *m3, *m1, *m2;             /*  get m3 = m1 - m2 if add = FALSE  */
  342. char add;
  343. {
  344.     int d, c, sd;
  345.  
  346.     if ( add)
  347.     {
  348.         d = m1->dollar + m2->dollar;
  349.         c = m1->cent + m2->cent;
  350.     }
  351.     else
  352.     {
  353.         d = m1->dollar - m2->dollar;
  354.         c = m1->cent - m2->cent;
  355.     }
  356.     if ( d && ( sd = sign( d)) != sign( c))
  357.     {
  358.         d -= sd;
  359.         if ( sd < 0)
  360.             c -= 10000;
  361.         else c += 10000;
  362.     }
  363.     m3->dollar = d + c/10000;
  364.     m3->cent = c%10000;
  365. }
  366.  
  367. movmoney( m2, m1, credit)               /*  set m2 = m1 if credit = TRUE     */
  368. struct money *m2, *m1;                  /*  else, set m2 = abs( m1)          */
  369. char credit;
  370. {
  371.     if ( credit)
  372.     {
  373.         m2->dollar = m1->dollar;
  374.         m2->cent = m1->cent;
  375.     }
  376.     else
  377.     {
  378.         m2->dollar = abs( m1->dollar);
  379.         m2->cent = abs( m1->cent);
  380.     }
  381. }
  382.  
  383. putmoney( m)                            /*  format and display money         */
  384. struct money *m;
  385. {
  386.     char s[ 10];
  387.     int is, id, ic;                     /*  int is assumed to be 16 bits     */
  388.     struct money w;
  389.  
  390.     if (( id = m->dollar) < -99 || 999 < id)
  391.     {
  392.         w.dollar = 0;
  393.         w.cent = 50;                    /*  round-off to nearest dollar      */
  394.         addmoney( &w, m, &w, ( id > 0));
  395.         id = w.dollar;
  396.         ic = w.cent;
  397.         is = 6;
  398.         strcpy( s, "       0 ");        /*  template                         */
  399.     }
  400.     else
  401.     {
  402.         ic = m->cent;
  403.         is = 3;
  404.         strcpy( s, "    0.00 ");        /*  template                         */
  405.     }
  406.     if ( id < 0 || ic < 0)
  407.     {
  408.         id = abs( id);
  409.         ic = abs( ic);
  410.         s[ 0] = '(';
  411.         s[ 8] = ')';
  412.     }
  413.     if ( id)
  414.     {
  415.         formatd( s, is, id);
  416.         s[ is] = '0';                   /*  fill                             */
  417.     }
  418.     formatd(( s + is), 2, ic/100);
  419.     if ( is == 3)
  420.         formatd(( s + 6), 2, ic%100);
  421.     puts( s);
  422. }
  423.  
  424. putdate( d)                             /*  format and display date          */
  425. struct calendar *d;
  426. {
  427.     char s[ 10];
  428.  
  429.     strcpy( s, " 0/00/00 ");            /*  template                         */
  430.     formatd( s, 2, d->mm);
  431.     formatd(( s + 3), 2, d->dd);
  432.     formatd(( s + 6), 2, d->yy);
  433.     puts( s);
  434. }
  435.  
  436. formatd( s, n, d)                       /*  format n digits of d into s      */
  437. char s[];                               /*  like sprintf( s, "%nd", d)       */
  438. int n, d;                               /*  d is assumed to be positive      */
  439. {                                       /*  and n decimal digits or less     */
  440.     while ( d && n--)                   /*  s is assumed to be initialized   */
  441.     {                                   /*  with an appropriate template     */
  442.         s[ n] = '0' + d%10;
  443.         d /= 10;
  444.     }
  445. }
  446.  
  447. printd( d)                              /*  print d in decimal               */
  448. int d;                                  /*  like printf( "%d", d)            */
  449. {                                       /*  d is assumed to be positive      */
  450.     int n;                              /*  see K & R, p. 85                 */
  451.  
  452.     if ( n = d/10)
  453.         printd( n);                     /*  recursion for leading digits     */
  454.     putchar( '0' + d%10);               /*  trailing digit                   */
  455. }
  456.  
  457. sign( i)                                /*  return 1 with sign of i          */
  458. {
  459.     return ( i < 0 ? -1 : 1);
  460. }
  461.  
  462. char witch( c)                          /*  return control character         */
  463. char c;                                 /*  else return CR                   */
  464. {
  465.     if ( iscntrl( c))
  466.         return ( c);
  467.     return ( '\r');
  468. }
  469.  
  470. iscntrl( c)                             /*  is c a control char?             */
  471. char c;
  472. {
  473.     return ( c < ' ' || c == DEL);
  474. }
  475.  
  476. waitesc()                               /*  wait for ESCAPE key              */
  477. {
  478.     puts( "  --  Press ESCAPE to continue");
  479.     putchar( BEL);
  480.     while ( getchar() != ESC)
  481.         continue;
  482. }
  483.  
  484. waitkey()                               /*  wait for CTRL-C or other key     */
  485. {
  486.     puts( "  --  ^C to quit, or any other key to continue");
  487.     putchar( BEL);
  488.     if ( getchar() == CTRLC)
  489.         aexit();                        /*  never return                     */
  490. }
  491.  
  492. done()                                  /*  save and archive check register  */
  493. {
  494. #ifdef  CLEARS
  495.     saveclr();
  496. #else
  497.     if ( saveclr())
  498.         return;
  499. #endif
  500.     calcbbf();
  501.     if ( savedat( FALSE))
  502.     {
  503.         Recno = Maxentry + 1 - PAGE;    /*  initialize gobottom()            */
  504.         First = Recno - PAGE;
  505.         Last = First - 1;
  506.         Field = 0;
  507.         gobottom();                     /*  redisplay                        */
  508.         return;
  509.     }
  510.     aexit();                            /*  no return                        */
  511. }
  512.  
  513. #ifdef  CLEARS
  514.  
  515. saveclr()                               /*  audit marked entries             */
  516. {
  517.     int i, count, compdate();
  518.  
  519.     reorder( 0, compdate);
  520.     count = 0;                          /*  count number of marked entries   */
  521.     for ( i = 0; i <= Maxentry; ++i)
  522.         if ( !Entry[ i].clear)
  523.             ++count;
  524.     if ( !count)
  525.         return;
  526.     prompt( "Print an audit trail of <M>arked entries before deletion (Y/N)? ");
  527.     if ( getyesno( NO) && setlst())
  528.     {
  529.         disheading();
  530.         for ( i = 0; i <= Maxentry; ++i)
  531.         {
  532.             if ( !Entry[ i].clear)
  533.             {
  534.                 Balance[ i].dollar = Balance[ i].cent = 0;
  535.                 putrecord( i);          /*  print cleared entry              */
  536.             }
  537.         }
  538.         resetlst();
  539.     }
  540. }
  541.  
  542. #else   /*  not CLEARS  */
  543.  
  544. saveclr()                               /*  save cleared entries             */
  545. {                                       /*  return TRUE if bad disk          */
  546.     char *p, *msg;
  547.     char tempname[ FNAMSIZE], bufin[ BUFSIZ], bufout[ BUFSIZ];
  548.     int i, j, k, count, oldcount, sumcount, imax, total, compdate();
  549.  
  550.     typcat( Filename, CLRTYP);
  551.     count = 0;                          /*  count number of cleared entries  */
  552.     for ( i = 0; i <= Maxentry; ++i)
  553.         if ( Entry[ i].clear)
  554.             ++count;
  555.     if ( !count)
  556.     {
  557.         prompt( "No change necessary to ");
  558.         puts( Filename);
  559.         puts( " - ");
  560.         return ( FALSE);
  561.     }
  562.     reorder( 0, compdate);
  563.     prompt( msg = "Saving ... ");
  564.     strcpy( tempname, Filename);
  565.     typcat( tempname, TMPTYP);
  566.     resetdsk();
  567.     if ( fcreat( tempname, bufout) == ERROR)
  568.     {
  569.         createrr( tempname);
  570.         return ( TRUE);
  571.     }
  572.     if ( fopen( Filename, bufin) == ERROR)
  573.         sumcount = oldcount = 0;
  574.     else
  575.     {
  576.         oldcount = getw( bufin);        /*  total records in CLR file        */
  577.         sumcount = getw( bufin);        /*  SUMMARY records                  */
  578.         if ( oldcount < 0 || sumcount < 0)
  579.             goto errin1;
  580.         getw( bufin);                   /*  filler                           */
  581.     }
  582.     if ( imax = max( 0, ( oldcount + count - CLRSIZE)))
  583.     {
  584.         prompt( Filename);
  585.         puts( " is full.  OK to discard ");
  586.         printd( imax);
  587.         puts( " oldest cleared entries (Y/N)? ");
  588.         if ( !getyesno( YES))
  589.         {
  590.             fclose( bufin);
  591.             fclose( bufout);
  592.             return ( FALSE);
  593.         }
  594.         else prompt( msg);
  595.     }
  596.     imax += sumcount;
  597.     total = min( CLRSIZE, ( oldcount + count));
  598.     putw( total, bufout);               /*  record new total record count    */
  599.     putw( sumcount, bufout);
  600.     putw( 0, bufout);                   /*  filler                           */
  601.     for ( i = 0; i < oldcount; ++i)     /*  transfer old records             */
  602.     {
  603.         for ( j = RECSIZ; j; --j)
  604.         {
  605.             if (( k = getc( bufin)) == ERROR)
  606.                 goto errin1;
  607.             if (( i < sumcount ||       /*  discard oldest records           */
  608.                 imax <= i) && ( putc( k, bufout) == ERROR))
  609.                 goto errin2;
  610.         }
  611.     }
  612.     if ( oldcount && ( fclose( bufin) == ERROR))
  613.         goto errin1;
  614.     for ( i = 0; i <= Maxentry; ++i)
  615.     {
  616.         if ( Entry[ i].clear)
  617.         {
  618.             p = &Entry[ i];
  619.             for ( j = RECSIZ; j; --j)
  620.                 if ( putc( *p++, bufout) == ERROR)
  621.                     goto errout;
  622.         }
  623.     }
  624.     if ( fflush( bufout) == ERROR ||    /*  make sure it is all saved        */
  625.          fclose( bufout) == ERROR)
  626.         goto errout;
  627.     prompt( "Do you wish to print an audit trail of cleared entries (Y/N)? ");
  628.     if ( getyesno( NO) && setlst())
  629.     {
  630.         disheading();
  631.         for ( i = 0; i <= Maxentry; ++i)
  632.         {
  633.             if ( Entry[ i].clear)
  634.             {
  635.                 Balance[ i].dollar = Balance[ i].cent = 0;
  636.                 putrecord( i);          /*  print cleared entry              */
  637.             }
  638.         }
  639.         resetlst();
  640.     }
  641.     unlink( Filename);
  642.     if ( rename( tempname, Filename) == ERROR)
  643.         renamerr( tempname, Filename);
  644.     prompt( Filename);
  645.     puts( " has ");
  646.     printd( count);
  647.     puts( " new entries (");
  648.     printd( total);
  649.     puts( " total) - ");
  650.     return ( FALSE);                    /*  normal return                    */
  651.  
  652. errin1:
  653.     puterrmsg( "reading ", Filename);
  654. errin2:
  655.     fclose( bufin);
  656. errout:
  657.     fclose( bufout);
  658.     writerr( tempname);
  659.     return( TRUE);
  660. }
  661.  
  662. #endif
  663.  
  664. savedat( addcr)                         /*  save all entries                 */
  665. int addcr;                              /*  TRUE if CR before display        */
  666. {                                       /*  return TRUE if bad disk          */
  667.     char *p, tempname[ FNAMSIZE], bufout[ BUFSIZ];
  668.     int i, j;
  669. #ifndef CLEARS
  670.     char backname[ FNAMSIZE];
  671.  
  672.     typcat( Filename, DATTYP);
  673.     strcpy( tempname, Filename);
  674.     typcat( tempname, TMPTYP);
  675.     strcpy( backname, Filename);
  676.     typcat( backname, BAKTYP);
  677. #else
  678.     typcat( Filename, CLRTYP);
  679.     strcpy( tempname, Filename);
  680.     typcat( tempname, TMPTYP);
  681.     i = Memory.dollar = 0;              /*  use Memory to count SUMMARY      */
  682.     while (( i <= Maxentry) && ( Entry[ i++].category & 0x80))
  683.         ++( Memory.dollar);
  684.     prompt( "Saving ... ");
  685. #endif
  686.     resetdsk();
  687.     if ( fcreat( tempname, bufout) == ERROR)
  688.     {
  689.         createrr( tempname);
  690.         return ( TRUE);
  691.     }
  692.     putw(( Maxentry + 1), bufout);      /*  record number of entries         */
  693.     putw( Memory.dollar, bufout);       /*  record Memory                    */
  694.     putw( Memory.cent, bufout);         /*  if putw error, also putc later   */
  695.     for ( i = 0; i <= Maxentry; ++i)
  696.     {
  697.         p = &Entry[ i];
  698.         for ( j = RECSIZ; j; --j)
  699.             if ( putc( *p++, bufout) == ERROR)
  700.                 goto errout;
  701.     }
  702.     if ( fflush( bufout) == ERROR ||    /*  make sure it is all saved        */
  703.          fclose( bufout) == ERROR)
  704.         goto errout;
  705. #ifdef  CLEARS
  706.     unlink( Filename);
  707.     if ( rename( tempname, Filename) == ERROR)
  708.         renamerr( tempname, Filename);
  709.     prompt( Filename);
  710. #else
  711.     unlink( backname);
  712.     rename( Filename, backname);
  713.     if ( rename( tempname, Filename) == ERROR)
  714.     {
  715.         renamerr( tempname, Filename);
  716.         prompt( "");
  717.     }
  718.     if ( addcr)
  719.         putchar( '\r');
  720.     puts( Filename);
  721. #endif
  722.     puts( " has ");
  723.     printd( Maxentry + 1);
  724.     puts( " entries");
  725.     return ( FALSE);                    /*  normal return                    */
  726.  
  727. errout:
  728.     fclose( bufout);
  729.     writerr( tempname);
  730.     return( TRUE);
  731. }
  732.  
  733. calcbbf()                               /*  calculate BBF for each category  */
  734. {                                       /*  BBF = BALANCE BROUGHT FORWARD    */
  735.     char c, nbr[ DEL];
  736.     int i, j, count, new;
  737.     struct record *e;
  738.     struct money sum;
  739.     struct calendar maxdate;
  740.  
  741.     setmem( nbr, DEL, 0);               /*  initialize                       */
  742.     for ( j = 0; j <= Maxentry; ++j)    /*  identify categories              */
  743.     {
  744.         e = &Entry[ j];
  745.         c = e->category;
  746. #ifdef  CLEARS
  747.         if ( c & 0x80)                  /*  if BBF category                  */
  748.             e->clear = FALSE;           /*      mark for summation           */
  749.         if ( !e->clear)                 /*  count marked entries             */
  750.             ++nbr[ c & 0x7f];           /*      for each category            */
  751. #else
  752.         if ( c & 0x80)                  /*  if BBF category                  */
  753.             e->clear = TRUE;            /*      mark for summation           */
  754.         if ( e->clear)                  /*  count cleared entries            */
  755.             ++nbr[ c & 0x7f];           /*      for each category            */
  756. #endif
  757.     }
  758.     new = 0;
  759.     for ( i = ' '; i < DEL; ++i)        /*  sum cleared categories           */
  760.     {                                   /*      in ASCII order               */
  761.         if ( !nbr[ i])                  /*  if category does not exist       */
  762.             continue;                   /*      next category                */
  763.         count = 0;
  764.         maxdate.mm = maxdate.dd = maxdate.yy = sum.dollar = sum.cent = 0;
  765.         for ( j = 0; j <= Maxentry; ++j)
  766.         {
  767.             e = &Entry[ j];
  768. #ifdef  CLEARS
  769.             if ( e->clear || ( e->category & 0x7f) != i)
  770.                 continue;               /*  next entry                       */
  771. #else
  772.             if ( !( e->clear) || ( e->category & 0x7f) != i)
  773.                 continue;               /*  next entry                       */
  774. #endif
  775.             addmoney( &sum, &sum, &( e->amount), e->deposit);
  776.             datemax( &maxdate, &( e->date));
  777.             if ( j < Maxentry)          /*  delete cleared category          */
  778.                 movmem( &Entry[ j + 1], e, ( Maxentry - j)*RECSIZ);
  779.             --Maxentry;
  780.             --j;                        /*  Entry[ j + 1] moved up           */
  781.             if ( ++count == nbr[ i])    /*  if all entries for this category */
  782.                 break;                  /*      break j loop over entries    */
  783.         }                               /*  end j loop over entries          */
  784.         e = &Entry[ new];               /*  insert new BBF category          */
  785.         if ( new <= Maxentry)
  786.             movmem( e, &Entry[ new + 1], ( Maxentry - new + 1)*RECSIZ);
  787.         ++Maxentry;
  788.         ++new;
  789.         if ( sum.dollar < 0 || sum.cent < 0)
  790.             e->deposit = FALSE;
  791.         else e->deposit = TRUE;
  792.         movmoney( &( e->amount), &sum, e->deposit);
  793.         e->date.mm = maxdate.mm;
  794.         e->date.dd = maxdate.dd;
  795.         e->date.yy = maxdate.yy;
  796. #ifdef  CLEARS
  797.         e->clear = TRUE;
  798. #else
  799.         e->clear = FALSE;
  800. #endif
  801.         e->category = i | 0x80;
  802.         strcpy( e->payee, BBF);
  803.     }                                   /*  end i loop over categories       */
  804. }
  805.  
  806. char help()                             /*  display help screen              */
  807. {
  808.     char c, s[ MAXLINE], f[ FNAMSIZE], buf[ BUFSIZ], *fgets();
  809.     int i;
  810.  
  811.     strcpy( f, DEFNAM);
  812.     typcat( f, SCRTYP);
  813.     if ( fopen( f, buf) == ERROR)
  814.     {
  815.         openerr( f);
  816.         return( 0);
  817.     }
  818.     cursorto( 0, 0);
  819.     putscr( Ivon);
  820.     for ( i = 0; i < HEAD && fgets( s, buf); )
  821.     {
  822.         s[ strlen( s) - 1] = '\0';      /*  truncate Abc\n\0 at \n           */
  823.         puts( s);
  824.         cursorto( ++i, 0);
  825.     }
  826.     putscr( Ivoff);
  827.     fclose( buf);
  828.     putcursor( Recno, Field);
  829.     c = getchar();                      /*  wait for another command         */
  830.     for ( i = 0; i < HEAD; ++i)         /*  clear top of screen              */
  831.     {
  832.         cursorto( i, 0);
  833.         clreol( 0);
  834.     }
  835.     disheading();
  836.     strcpy( s, CLRCOM);
  837.     formatd( s, 3, ( Recno + 1));
  838.     cursorto( 0, 0);
  839.     putscr( Ivon);
  840.     puts( s);                           /*  display entry number             */
  841.     putscr( Ivoff);
  842.     Oldfield = -1;
  843.     putquery();
  844.     putcursor( Recno, Field);
  845.     return ( c);
  846. }
  847.  
  848. createrr( f)                            /*  display error creating file f    */
  849. char *f;
  850. {
  851.     puterrmsg( "creating ", f);
  852.     baddisk();
  853. }
  854.  
  855. writerr( f)                             /*  display error writing file f     */
  856. char *f;
  857. {
  858.     puterrmsg( "writing ", f);
  859.     baddisk();
  860. }
  861.  
  862. renamerr( f1, f2)                       /*  display error renaming f1 to f2  */
  863. char *f1, *f2;
  864. {
  865.     prompt( "Could not rename ");
  866.     puts( f1);
  867.     puts( " to ");
  868.     puts( f2);
  869.     waitesc();
  870.     strcpy( f2, f1);
  871. }
  872.  
  873. puterrmsg( s1, s2)                      /*  display two part error message   */
  874. char *s1, *s2;
  875. {
  876.     prompt( "Error ");
  877.     puts( s1);
  878.     puts( s2);
  879.     waitesc();
  880. }
  881.  
  882. baddisk()                               /*  prompt for another disk          */
  883. {
  884.     prompt( "Try another disk in ");
  885.     putchar( Filename[ 0]);
  886.     putchar( Filename[ 1]);
  887.     waitesc();
  888. }
  889.  
  890. abort( s1, s2)                          /*  abort with two part message      */
  891. char *s1, *s2;
  892. {
  893.     cursorto(( ROWS - 2), 0);
  894.     clreol( 0);
  895.     putchar( '\r');
  896.     puts( s1);
  897.     puts( s2);
  898.     putchar( BEL);
  899.     aexit();                            /*  no return                        */
  900. }
  901.  
  902. aexit()                                 /*  clear last line and exit         */
  903. {
  904.     cursorto(( ROWS - 1), 0);
  905.     clreol( 0);
  906.     cursorto(( ROWS - 2), 0);
  907.     exit();
  908. }
  909.