home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 318_01 / redbuf1.c < prev    next >
C/C++ Source or Header  |  1990-06-18  |  14KB  |  760 lines

  1. /*
  2.     RED buffer routines -- Full C version
  3.     Part 1 -- goto, output and status routines.
  4.  
  5.      Source:  redbuf1.c
  6.     Version: February 4, 1985; January 18, 1990.
  7.  
  8.     Written by
  9.     
  10.         Edward K. Ream
  11.         166 N. Prospect
  12.         Madison WI 53705
  13.         (608) 257-0802
  14.  
  15.  
  16.     PUBLIC DOMAIN SOFTWARE
  17.  
  18.     This software is in the public domain.
  19.  
  20.     See red.h for a disclaimer of warranties and other information.
  21. */
  22.  
  23. #include "red.h"
  24.  
  25. /*
  26.     Boundary conditions:
  27.  
  28.     1.  Only bufins() can extend the buffer, NOT
  29.         bufgo() and bufdn().
  30.  
  31.     2.  bufatbot() is true when the current line is
  32.         PASSED the last line of the buffer.  Both
  33.         bufgo() and bufdn() can cause bufatbot() to
  34.         become true.  bufgetln() returns a zero length
  35.         line if bufatbot() is true.
  36.  
  37.     3.  b_max_line is the number of lines in the buffer.
  38.         However, b_line == b_max_line + 1 is valid and
  39.         it means that b_line points at a null line.
  40.  
  41.     4.  All buffer routines assume that the variables
  42.             b_bp, b_line and b_start describe the current
  43.         line when the routine is called.  Thus, any
  44.         routine which changes the current line must
  45.         update these variables.
  46. */
  47.  
  48. /*
  49.     Define the format of the status line used only by
  50.     the bufsusp() and bufinit() routines.
  51. */
  52.  
  53. #define MAGIC 1234
  54. #define STATUS_LENGTH (25+SYSFNMAX)
  55.  
  56. struct STATUS {
  57.     char stype      [5];    /* Magic byte        */
  58.     char stail      [5];    /* saved b_tail        */
  59.     char smax_diskp [5];    /* saved b_max_diskp    */
  60.     char smax_line  [5];    /* saved b_max_line    */
  61.     char sfree      [5];    /* saved b_free        */
  62.     char sfile [SYSFNMAX];    /* saved file name    */
  63. };
  64.  
  65. /*
  66.     Return TRUE if at bottom of buffer (past the last line).
  67. */
  68. #if 0 /* a macro now. */
  69. int
  70. bufatbot(void)
  71. {
  72.     TRACEP("bufatbot",
  73.         sl_sout("returns ");
  74.         sl_bout(b_line > b_max_line);
  75.         sl_cout('\n'));
  76.  
  77.     return b_line > b_max_line;
  78. }
  79. #endif /* 0 */
  80.  
  81. /*
  82.     Return TRUE if at top of buffer.
  83. */
  84. #if 0 /* a macro now */
  85. int
  86. bufattop(void)
  87. {
  88.     TRACEP("bufattop",
  89.         sl_sout("returns ");
  90.         sl_bout(b_line == 1);
  91.         sl_cout('\n'));
  92.  
  93.     return b_line == 1;
  94. }
  95. #endif /* 0 */
  96.  
  97. /*
  98.     Return TRUE if the buffer has been changed.
  99. */
  100. #if 0 /* now a macro */
  101. int
  102. bufchng(void)
  103. {
  104.     TRACEP("bufchng",
  105.         sl_sout("returns ");
  106.         sl_bout(b_cflag);
  107.         sl_cout('\n'));
  108.  
  109.     return b_cflag;
  110. }
  111. #endif /* 0 */
  112.  
  113. /*
  114.     Clear the slot table.  This should be done after
  115.     read_file() overwrites  the slot table.
  116. */
  117. void
  118. buf_clr(void)
  119. {
  120.     struct BLOCK *bp;
  121.     int i;
  122.  
  123.     TICK("buf_clr");
  124.  
  125.     for (i = 0; i < DATA_RES; i++) {
  126.         bp = b_bpp [i];
  127.         bp -> d_back   = ERROR;
  128.         bp -> d_next   = ERROR;
  129.         bp -> d_lines  = 0;
  130.         bp -> d_status = FREE;
  131.         bp -> d_lru    = i;
  132.         bp -> d_diskp  = ERROR;
  133.     }
  134. }
  135.  
  136. /*
  137.     Move towards end of buffer.
  138. */
  139. void
  140. bufdn(void)
  141. {
  142.     TICKB("bufdn");
  143.  
  144.     if (bufatbot()) {
  145.         RETURN_VOID("bufdn");
  146.     }
  147.     else {
  148.         b_line++;
  149.         buf_gofw();
  150.     }
  151.  
  152.     TICKX("bufdn");
  153. }
  154.  
  155. /*
  156.     Clean up any temporary files.
  157. */
  158. void
  159. bufend(void)
  160. {
  161.     TICKB("bufend");
  162.  
  163.     if (b_data_fd != ERROR) {
  164.         sysclose(b_data_fd);    /* Bug fix: 6/17/84 */
  165.         b_data_fd = ERROR;    /* Bug fix: 6/17/84 */
  166.         sysunlink(DATA_FILE);
  167.     }
  168.  
  169.     TICKX("bufend");
  170. }
  171.  
  172. /*
  173.     Go to line n.
  174.     Set b_bp, b_line, b_start.
  175. */
  176. void
  177. bufgo(int n)
  178. {
  179.     int distance, oldline;
  180.  
  181.     TRACEPB("bufgo", sl_lpout(); sl_iout(n); sl_rpout());
  182.  
  183.     /* Put the request in range. */
  184.     oldline  = b_line;
  185.     b_line   = min(n, b_max_line + 1);
  186.     b_line   = max(1, b_line);
  187.     distance = b_line - oldline;
  188.  
  189.     if (distance == 0) {
  190.  
  191.         /* We are already at the requested line. */
  192.  
  193.         RETURN_VOID("bufgo");
  194.     }
  195.     else if (distance == 1) {
  196.  
  197.         /* Go forward from here. */
  198.         buf_gofw();
  199.  
  200.         RETURN_VOID("bufgo");
  201.     }
  202.     else if (distance == -1) {
  203.  
  204.         /* Go back from here. */
  205.         buf_gobk();
  206.  
  207.         RETURN_VOID("bufgo");
  208.     }
  209.     else if (distance > 0) {
  210.         if ( b_line >
  211.              oldline + ((b_max_line - oldline) / 2)
  212.            ) {
  213.  
  214.             /* Search back from end of file. */
  215.             b_bp  = swap_in(b_tail);
  216.             b_start =
  217.                 1 + b_max_line - b_bp -> d_lines;
  218.             buf_gobk();
  219.  
  220.             RETURN_VOID("bufgo");
  221.         }
  222.         else {
  223.  
  224.             /* Search forward from here. */
  225.             buf_gofw();
  226.  
  227.             RETURN_VOID("bufgo");
  228.         }
  229.     }
  230.     else {
  231.         if (b_line < oldline / 2) {
  232.  
  233.             /* Search from start of file. */
  234.             b_bp    = swap_in(b_head);
  235.             b_start = 1;
  236.             buf_gofw();
  237.  
  238.             RETURN_VOID("bufgo");
  239.         }
  240.         else {
  241.  
  242.             /* Search back from here. */
  243.             buf_gobk();
  244.  
  245.             RETURN_VOID("bufgo");
  246.         }
  247.     }
  248. }
  249.  
  250. /*
  251.     Search backwards from block for b_line.
  252.     The starting line number of the block is b_start.
  253.     Set b_bp and b_start.
  254. */
  255. void
  256. buf_gobk(void)
  257. {
  258.     int diskp;
  259.  
  260.     TRACEPB("buf_gobk",
  261.         sl_sout("b_start: ");    sl_iout(b_start);
  262.         sl_sout(", b_line: ");    sl_iout(b_line);
  263.         sl_cout('\n'));
  264.  
  265.     if (b_bp == (struct BLOCK *) ERROR ||
  266.         b_start < 1 || b_start > b_max_line ||
  267.         b_line  < 1 || b_line  > b_max_line + 1) {
  268.  
  269.         cant_happen("buf_gobk 1");
  270.     }
  271.  
  272.     /* Scan backward for the proper block. */
  273.     while (b_start > b_line) {
  274.  
  275.         TRACEP("buf_bobk",
  276.             sl_sout("***** go back to block ");
  277.             sl_iout(b_bp -> d_back);
  278.             sl_cout('\n'));
  279.  
  280.         /* Get the previous block in memory. */
  281.         diskp = b_bp -> d_back;
  282.         if (diskp == ERROR) {
  283.             cant_happen("buf_gobk 2");
  284.         }
  285.         b_bp = swap_in(diskp);
  286.  
  287.         /* Calculate the start of the next block. */
  288.         b_start -= b_bp -> d_lines;
  289.         if (b_start <= 0) {
  290.             cant_happen("buf_gobk 3");
  291.         }
  292.     }
  293.  
  294.     TICKX("buf_gobk");
  295. }
  296.  
  297. /*
  298.     Search forward from parcel par for line n.
  299.     Set b_bp and b_start.
  300. */
  301. void
  302. buf_gofw(void)
  303. {
  304.     int diskp;
  305.  
  306.     TRACEPB("buf_gofw",
  307.         sl_sout("b_start: ");    sl_iout(b_start);
  308.         sl_sout(", b_line: ");    sl_iout(b_line);
  309.         sl_cout('\n'));
  310.  
  311.     /* The last line is always null. */
  312.     if (bufatbot()) {
  313.         RETURN_VOID("buf_gofw");
  314.     }
  315.  
  316.     if (b_bp == (struct BLOCK *) ERROR ||
  317.         b_start < 1 || b_start > b_max_line ||
  318.         b_line  < 1 || b_line  > b_max_line + 1) {
  319.  
  320.         cant_happen("buf_gofw 1");
  321.     }
  322.  
  323.     /* Scan forward to the proper block. */
  324.     while (b_start + b_bp -> d_lines <= b_line) {
  325.  
  326.         TRACEP("buf_bofw",
  327.             sl_sout("***** go forward to block ");
  328.             sl_iout(b_bp -> d_next);
  329.             sl_cout('\n'));
  330.  
  331.         /* Get the start of the next block. */
  332.         b_start += b_bp -> d_lines;
  333.  
  334.         /* Swap in the next block. */
  335.         diskp = b_bp -> d_next;
  336.         if (diskp == ERROR || b_start > b_max_line) {
  337.             cant_happen("buf_gofw 2");
  338.         }
  339.         b_bp = swap_in(diskp);
  340.     }
  341.  
  342.     TICKX("buf_gofw");
  343. }
  344.  
  345. /*
  346.     Initialize the buffer module.
  347.     If the work file exists,  read block 0 into slot 0.
  348.     Otherwise,  call bufnew to clear everything.
  349. */
  350. void
  351. bufinit(void)
  352. {
  353.     struct BLOCK *bp;
  354.     struct STATUS *sp;
  355.     int i, type;
  356.     char *p;
  357.  
  358.     TICKB("bufinit");
  359.  
  360.     /* The data file has not been opened yet. */
  361.     b_data_fd = ERROR;
  362.  
  363.     /* Dynamically allocate all slots. */
  364.     for (i = 0; i < MAX_RES; i++) {
  365.  
  366.         p = sysalloc (BLOCK_SIZE);
  367.         if (p == NULL) {
  368.             break;
  369.         }
  370.         b_bpp [i] = (struct BLOCK *) p;
  371.     }
  372.  
  373.     /* Set pseudo constant. */
  374.     DATA_RES = i;
  375.  
  376.     /* The code requires at least three buffers. */
  377.     if (DATA_RES < MIN_RES) {
  378.         error("Not enough room for buffers.");
  379.         exit(1);
  380.     }
  381.  
  382. #ifdef SUSPEND
  383.     /* Do nothing if no work file. */
  384.     if (sysexists(DATA_FILE) == FALSE) {
  385.         bufnew();
  386.         RETURN_VOID("bufinit");
  387.     }
  388.     else {
  389.         b_data_fd = sysopen(DATA_FILE);
  390.         if (b_data_fd == ERROR) {
  391.             error("Can not re-open work file.");
  392.             exit(1);
  393.         }
  394.     }
  395.  
  396.     /* Read the first block of the work file. */
  397.     b_bp = b_bpp [0];
  398.  
  399.  
  400.     sysread(b_data_fd, (char *) b_bp);
  401.  
  402.     /*
  403.         Restore RED's status which was written by
  404.         the bufsusp() routine.
  405.     */
  406.     b_head = 0;
  407.  
  408. #if 0
  409.     sscanf(b_bp -> d_data, "%x %x %x %x %x %s\0",
  410.         &type,
  411.         &b_tail, &b_max_diskp, &b_max_line, &b_free,
  412.         g_file);
  413.     b_max_put = b_max_diskp;
  414. #endif
  415.  
  416.     sp = (struct STATUS *) b_bp -> d_data;
  417.     type        = atoi(sp -> stype);
  418.     b_tail      = atoi(sp -> stail);
  419.     b_max_diskp = atoi(sp -> smax_diskp);
  420.     b_max_line  = atoi(sp -> smax_line);
  421.     b_free      = atoi(sp -> sfree);
  422.     strcpy(g_file, sp -> sfile);
  423.  
  424.     b_max_put   = b_max_diskp;    /* Bug fix: 5/24/84 */
  425.  
  426.     if (type != MAGIC) {
  427.         /* Do NOT erase the work file!! */
  428.         error("Previous work file garbled.");
  429.         exit(1);
  430.     }
  431.  
  432.     /* Free all slots. */
  433.     buf_clr();
  434.  
  435.     /* Delete the status line. */
  436.     b_line = b_start = 1;
  437.     swap_in(0);
  438.     bufdel();
  439.  
  440.     /* Make sure that the buffer will be saved. */
  441.     b_cflag = TRUE;
  442.  
  443.     /* Do not erase work file on disk error. */
  444.     b_fatal = FALSE;
  445. #else
  446.     bufnew();
  447. #endif
  448.  
  449.     TICKX("bufinit");
  450. }
  451.  
  452. /*
  453.     Return the current line number.
  454. */
  455. #if 0 /* now a macro */
  456. int
  457. bufln(void)
  458. {
  459.     TRACEP("bufln",
  460.         sl_sout("returns b_line: ");
  461.         sl_iout(b_line);
  462.         sl_cout('\n'));
  463.  
  464.     return b_line;
  465. }
  466. #endif /* 0 */
  467.  
  468. /*
  469.     Return the maximum line number.
  470. */
  471.  
  472. #if 0 /* now a macro */
  473. int
  474. bufmax(void)
  475. {
  476.     TRACEP("bufmax",
  477.         sl_sout("returns b_max_line: ");
  478.         sl_iout(b_max_line);
  479.         sl_cout('\n'));
  480.  
  481.     return b_max_line;
  482. }
  483. #endif /* 0 */
  484.  
  485. /*
  486.     Clear the buffer module.
  487. */
  488. void
  489. bufnew(void)
  490. {
  491.     struct BLOCK *bp;
  492.  
  493.     /* Free all slots. */
  494.  
  495.     TICKB("bufnew");
  496.  
  497.     buf_clr();
  498.  
  499.     /* Allocate the first slot. */
  500.     b_bp        = b_bpp [0];
  501.     b_head      = 0;
  502.     b_tail      = 0;
  503.     b_max_diskp = 0;
  504.     b_max_put   = 0;
  505.     b_bp -> d_diskp  = 0;
  506.     b_bp -> d_status = DIRTY;
  507.  
  508.     /* Make sure temp file is erased. */
  509.     if (b_data_fd != ERROR) {
  510.         sysclose(b_data_fd);
  511.         b_data_fd = ERROR;
  512.         sysunlink(DATA_FILE);
  513.     }
  514.     b_free = ERROR;
  515.  
  516.     /* Set the current and last line counts. */
  517.     b_line     = 1;
  518.     b_max_line = 0;
  519.     b_start    = 1;
  520.  
  521.     /* Indicate that the buffer has not been changed */
  522.     b_cflag = FALSE;
  523.  
  524.     /* Do not erase work file on disk error. */
  525.     b_fatal = FALSE;
  526.  
  527.     TICKX("bufnew");
  528. }
  529.  
  530. /*
  531.     Return TRUE if buffer is near the bottom line.
  532. */
  533. #if 0 /* now a macro */
  534. int
  535. bufnrbot(void)
  536. {
  537.     TRACEP("bufnrbot",
  538.         sl_sout("returns b_line >= b_max_line: ");
  539.         sl_bout(b_line >= b_max_line);
  540.         sl_cout('\n'));
  541.  
  542.     return b_line >= b_max_line;
  543. }
  544. #endif
  545.  
  546. /*
  547.     Put nlines lines from buffer starting with line topline at
  548.     position topy of the screen.
  549. */
  550. void
  551. bufout(int topline, int topy, int nlines)
  552. {
  553.     int l, x, y;
  554.  
  555.     SL_DISABLE();
  556.  
  557.     x = outx;
  558.     y = outy;
  559.     l = b_line;
  560.  
  561.     while (nlines > 0) {
  562.         outxy(0, topy++);
  563.         bufoutln(topline++);
  564.         nlines--;
  565.         if (hasint == TRUE) {
  566.             sysintr(topline,topy,nlines);
  567.             break;
  568.         }
  569.     }
  570.     outxy(x,y);
  571.     bufgo(l);
  572. }
  573.     
  574. /*
  575.     Print one line on screen.
  576. */
  577. void
  578. bufoutln(line)
  579. int line;
  580. {
  581.     char buffer [MAXLEN1];
  582.     int n;
  583.  
  584.     SL_DISABLE();
  585.  
  586.     bufgo(line);
  587.  
  588.     if ( (b_max_line == 0 && line == 2) ||
  589.          (b_max_line >  0 && line == b_max_line + 1)) {
  590.         fmtsout("---------------- End of file. ----------------",0);
  591.         outdeol();
  592.     }
  593.     else if (line > b_max_line) {
  594.         outdeol();
  595.     }
  596.     else {
  597.         n = bufgetln(buffer, MAXLEN);
  598.         n = min(n, MAXLEN);
  599.         buffer [n] = '\n';
  600.         fmtsout(buffer, 0);
  601.         outdeol();
  602.     }
  603. }
  604.  
  605. /*
  606.     Replace current line with the line that p points to.
  607.     The new line is of length n.
  608. */
  609. void
  610. bufrepl(char line [], int n)
  611. {
  612.     TRACEPB("bufrepl", sl_lpout();
  613.         sl_pout(line); sl_csout();
  614.         sl_iout(n);    sl_rpout());
  615.  
  616.     /* Do not replace null line.  Just insert. */
  617.     if (bufatbot()) {
  618.         bufins(line, n);
  619.         RETURN_VOID("bufrepl");
  620.     }
  621.  
  622.     /* Do not combine blocks until after insertion. */
  623.     buf_d(1);
  624.     bufins(line, n);
  625.     combine();
  626.  
  627.     TICKX("bufrepl");
  628. }
  629.  
  630. /*
  631.     Save the work file in a temporary file in preparation
  632.     for changing windows on the screen.
  633.  
  634.     NOTE:  This routine is not used at present.
  635. */
  636. void
  637. bufreset(char *window_file)
  638. {
  639.     TRACEPB("bufreset", sl_lpout(); sl_sout(window_file); sl_rpout());
  640.  
  641.     /* Make sure the work file is written. */
  642.     swap_all();
  643.  
  644.     /* Close the work file. */
  645.     sysclose(b_data_fd);
  646.     b_data_fd = ERROR;
  647.     
  648.     /* Rename the work file to be the window file. */
  649.     sysrename(DATA_FILE, window_file);
  650.  
  651.     TICKX("bufreset");
  652. }
  653.  
  654. /*
  655.     Indicate that the file has been saved.
  656. */
  657. void
  658. bufsaved(void)
  659. {
  660.     TRACEP("bufsaved", sl_sout("b_cflag = FALSE\n"));
  661.  
  662.     b_cflag = FALSE;
  663. }
  664.  
  665. /*
  666.     Suspend RED's execution for restart later.
  667. */
  668.  
  669. #ifdef SUSPEND
  670. void
  671. bufsusp(void)
  672. {
  673.     struct STATUS *sp;
  674.     int length, i;
  675.     char line [MAXLEN];
  676.  
  677.     TICKB("bufsusp");
  678.  
  679.     /* Bug fix 2/4/85: make sure the data file is open. */
  680.     if (b_data_fd == ERROR) {
  681.         b_data_fd = data_open();
  682.     }
  683.  
  684.     /*
  685.         Allocate space for the line.
  686.         (This will ALWAYS be in block 0.)
  687.     */
  688.     bufgo(1);
  689.     for (i = 0; i < STATUS_LENGTH; i++) {
  690.         line [i] = ' ';
  691.     }
  692.     bufins(line, STATUS_LENGTH);
  693.  
  694.     /*
  695.         Set up the file status line.
  696.         The bufinit() routines reads this line.
  697.  
  698.         The call to sprintf will also work but takes
  699.         up about 400 hex bytes more space.
  700.     */
  701.  
  702. #if 0 /* avoid using printf */
  703.     sprintf(line, "%4x %4x %4x %4x %4x %s\0",
  704.         MAGIC, b_tail, b_max_diskp, b_max_line,
  705.         b_free, g_file);
  706. #endif
  707.  
  708.     sp = (struct STATUS *) line;
  709.  
  710.     length = itoc(MAGIC, sp -> stype, 5);
  711.     sp -> stype [length] = '\0';
  712.  
  713.     length = itoc(b_tail, sp -> stail, 5);
  714.     sp -> stail [length] = '\0';
  715.  
  716.     length = itoc(b_max_diskp, sp -> smax_diskp, 5);
  717.     sp -> smax_diskp [length] = '\0';
  718.  
  719.     length = itoc(b_max_line, sp -> smax_line, 5);
  720.     sp -> smax_line [length] = '\0';
  721.  
  722.     length = itoc(b_free, sp -> sfree, 5);
  723.     sp -> sfree [length] = '\0';
  724.  
  725.     strcpy(sp -> sfile, g_file);
  726.  
  727.     /*
  728.         Rewrite the status line WITHOUT changing
  729.         the disk status.  This is fairly tricky;
  730.         a call to bufrepl() here would not work.
  731.     */
  732.     sysmove(line, b_bp -> d_data, STATUS_LENGTH);
  733.     
  734.     /* Make sure that work file is completely written. */
  735.     swap_all();
  736.     sysclose(b_data_fd);
  737.  
  738.     TICKX("bufsusp");
  739. }
  740. #endif
  741.  
  742. /*
  743.     Move towards the head of the file.
  744. */
  745. void
  746. bufup(void)
  747. {
  748.     TICKB("bufup");
  749.  
  750.     if (bufattop()) {
  751.         RETURN_VOID("bufup");
  752.     }
  753.     else {
  754.         b_line--;
  755.         buf_gobk();
  756.     }
  757.  
  758.     TICKX("bufup");
  759. }
  760.