home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource5 / 318_01 / redbuf3.c < prev    next >
C/C++ Source or Header  |  1990-06-18  |  17KB  |  882 lines

  1. /*
  2.     RED buffer routines -- Full C version
  3.     Part 3 -- file routines
  4.  
  5.     Source:  redbuf3.c
  6.     Version: August 8, 1986; 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.     Declare routines local to this file.
  27. */
  28. static void    disk_seek    (void);
  29. static int    read1        (void);
  30. static void    read2        (void);
  31. extern void    write1        (char c);
  32. extern void    wr_flush    (void);
  33.  
  34. /*
  35.     Data buffer used only in this file.
  36. */
  37. static char b_buff [DATA_SIZE];
  38.  
  39. /*
  40.     Kludge to allow more strict checking in swap_out.
  41.     It is usually an internal error if we swap out the current block.
  42.     The exception is in write_file, where we swap out all blocks.
  43. */
  44. static int ok2swap = FALSE;
  45.  
  46. /*
  47.     Open the data file.
  48. */
  49. int
  50. data_open(void)
  51. {
  52.     TICKB("data_open");
  53.  
  54.     /* Erase the data file if it exists. */
  55.     sysunlink(DATA_FILE);
  56.  
  57.     /* Create the data file. */
  58.     b_data_fd = syscreat(DATA_FILE);
  59.     if (b_data_fd == ERROR) {
  60.         disk_error("Can not open swap file.");
  61.     }
  62.  
  63.     RETURN_INT("data_open", b_data_fd);
  64. }
  65.  
  66. /*
  67.     Make the slot the MOST recently used slot.
  68. */
  69. void
  70. do_lru(struct BLOCK *bp)
  71. {
  72.     struct BLOCK *bp1;
  73.     int i, lru;
  74.  
  75.     SL_DISABLE();
  76.     
  77.     /*
  78.         Change the relative ordering of all slots
  79.          which have changed more recently than slot.
  80.      */
  81.     lru = bp -> d_lru;
  82.  
  83.     /* 12/15/89:  do nothing if the current slot is the most recent. */
  84.     if (lru == 0) {
  85.         return;
  86.     }
  87.  
  88.     TRACEP("do_lru", sl_lpout();
  89.         sl_pout(bp); sl_sout(") before: "); dump_slots());
  90.  
  91.     for (i = 0; i < DATA_RES; i++) {
  92.         bp1 = b_bpp [i];
  93.         if (bp1 -> d_lru < lru) {
  94.             bp1 -> d_lru++;
  95.         }
  96.     }
  97.  
  98.     /* The slot is the most recently used. */
  99.     bp -> d_lru = 0;
  100.  
  101.     TRACE("do_lru", sl_sout("after: "); dump_slots(); sl_cout('\n'));
  102. }
  103.  
  104. /*
  105.     Disk error routines
  106. */
  107. void
  108. disk_error(char *message)
  109. {
  110.     TRACEPB("disk_error",  sl_lpout(); sl_sout(message); sl_rpout());
  111.  
  112.     error(message);
  113.  
  114.     /* Clear the buffer if no recovery is possible. */
  115.     if (b_fatal == TRUE) {
  116.         bufnew();
  117.     }
  118.  
  119.     /* Abort the operation that caused the error. */
  120.     longjmp(DISK_ERR, ERROR);
  121.  
  122.     TICKX("disk_error");
  123. }
  124.  
  125. void
  126. disk_full(void)
  127. {
  128.     SL_DISABLE();
  129.  
  130.     disk_error("Disk or directory full?");
  131. }
  132.  
  133. void
  134. disk_rdy(void)
  135. {
  136.     SL_DISABLE();
  137.  
  138.     disk_error("Drive not ready?");
  139. }
  140.  
  141. static void
  142. disk_seek(void)
  143. {
  144.     SL_DISABLE();
  145.  
  146.     disk_error("Bad Seek");
  147. }
  148.  
  149. /*
  150.     Indicate that a slot must be saved on the disk.
  151. */
  152. #if 0 /* a macro now */
  153. void
  154. is_dirty(struct BLOCK *bp)
  155. {
  156.     TRACEPB("is_dirty",  sl_lpout(); sl_pout(bp); sl_rpout());
  157.  
  158.     bp -> d_status = DIRTY;
  159.  
  160.     TICKX("is_dirty");
  161. }
  162. #endif /* 0 */
  163.  
  164. /*
  165.     Put out the block-sized buffer to the disk sector.
  166. */
  167. void
  168. put_block(struct BLOCK *bp, int diskp)
  169. {
  170.     int s;
  171.  
  172.     /* Make sure blocks are written in order. */
  173.  
  174.     TRACEPB("put_block",  sl_lpout();
  175.         sl_pout(bp);    sl_csout();
  176.         sl_iout(diskp); sl_rpout());
  177.  
  178.     if (diskp > b_max_put + 1) {
  179.         swap_sync(b_max_put + 1, diskp - 1);
  180.     }
  181.     b_max_put = max(b_max_put, diskp);
  182.     
  183.     /* Seek to the correct sector of the data file. */
  184.     s = sysseek(b_data_fd, diskp);
  185.     if (s == -1) {
  186.         disk_seek();
  187.     }
  188.  
  189.     /* Write the block to the data file. */
  190.     if (syswrite(b_data_fd, (char *) bp, DATA_SIZE) != DATA_SIZE) {
  191.         disk_full();
  192.     }
  193.  
  194.     TICKX("put_block");
  195. }
  196.  
  197. /*
  198.     Fill in the header fields of the output buffer and
  199.     write it to the disk.
  200.     avail is the number of free characters in the buffer.
  201. */
  202. char *
  203. put_buf(int avail)
  204. {
  205.     struct BLOCK *bp;
  206.  
  207.     /*
  208.         Fill in the back and next links immediately.
  209.         This can be done because we are not waiting
  210.         for the LRU algorithm to allocated disk blocks.
  211.         The last block that put_buf() writes will have
  212.         an incorrect next link.  Read_file() will make
  213.         the correction.
  214.     */
  215.  
  216.     TRACEPB("put_buf", sl_lpout(); sl_iout(avail); sl_rpout());
  217.  
  218.     bp = (struct BLOCK *) b_buff;
  219.     bp -> d_back  = b_max_diskp - 1;
  220.     bp -> d_next  = b_max_diskp + 1;
  221.     bp -> d_lines = b_line - b_start;
  222.  
  223.     if (avail < 0) {
  224.         cant_happen("put_buf");
  225.     }
  226.  
  227.     /* Update block and line counts. */
  228.     b_max_diskp++;
  229.     b_start = b_line;
  230.  
  231.     /* Write the block. */
  232.     put_block( (struct BLOCK *) b_buff, b_max_diskp - 1);
  233.  
  234.     TICKX("put_buf");
  235. }
  236.  
  237. /*
  238.     Write out the slot to the data file.
  239. */
  240. void
  241. put_slot(struct BLOCK *bp)
  242. {
  243.     TRACEPB("put_slot", sl_lpout(); sl_pout(bp); sl_rpout());
  244.  
  245.     if (bp -> d_diskp == ERROR) {
  246.         cant_happen("put_slot");
  247.     }
  248.     put_block(bp, bp -> d_diskp);
  249.  
  250.     TICKX("put_slot");
  251. }
  252.  
  253. /*
  254.     Read a file into the buffer.
  255.  
  256.     This version of read_file puts an index table at
  257.     the end of each block.  The index table's entry
  258.     for each line tells the distance of the LAST character
  259.     of the line from the start of the data buffer.
  260.  
  261.     The global variables br_count, br_bufp, and br_bufc
  262.     are used to communicate with read1().  Using these
  263.     variables speeds the code by a factor of 3!
  264.  
  265.     The "global" variables br_avail and br_out are used
  266.     only by read_file() -- again, purely to speed the code.
  267. */
  268. void
  269. read_file(char file_name [])
  270. {
  271.     struct BLOCK *bp;
  272.  
  273.     /* global:  char * br_bufp   pointer to buffer    */
  274.     /* global:  int    br_bufc   index into buffer    */
  275.     /* global:  int    br_count  number of buffer    */
  276.  
  277.     /* global:  int    br_avail  available chars    */
  278.     /* global:  int    br_out    index into outbuf    */
  279.  
  280.     char    *outbuf;    /* the output buffer    */
  281.     int    out_save;    /* line starts here    */
  282.     int    c, i, j;
  283.  
  284.     /* Clear the swapping buffers and the files. */
  285.  
  286.     TRACEPB("read_file", sl_lpout(); sl_pout(file_name); sl_rpout());
  287.  
  288.     bufnew();
  289.     b_bp -> d_status = FREE;
  290.  
  291.     /* Open the user file. */
  292.     b_user_fd = sysopen(file_name);
  293.     if (b_user_fd == ERROR) {
  294.         disk_error("File not found.");
  295.     }
  296.  
  297.     /* Clear the buffer on any disk error. */
  298.     b_fatal = TRUE;
  299.  
  300.     /* Open the data file. */
  301.     data_open();
  302.  
  303.     /* The file starts with line 1. */
  304.     b_line = 1;
  305.     b_start = 1;
  306.  
  307.     /* There are no blocks in the file yet. */
  308.     b_head = b_tail = ERROR;
  309.     b_max_diskp = 0;
  310.  
  311.     /* Point outbuf to start of the output data area. */
  312.     outbuf = b_buff + HEADER_SIZE;
  313.  
  314.     /* Force an initial read in read1(). */
  315.     br_count = DATA_SIZE;
  316.     br_bufc  = DATA_RES;
  317.  
  318.     /* Zero the pointers into the output buffer. */
  319.     br_out = out_save = 0;
  320.  
  321.     /* Allocate space for the first table entry. */
  322.     br_avail = BUFF_SIZE - sizeof(int);
  323.     
  324.     /* Set the current line counts. */
  325.     b_line = b_start = 1;
  326.  
  327.     for(;;) {
  328.  
  329.         if (br_avail <= 0 && out_save == 0) {
  330.             /* The line is too long. */
  331.             error ("Line split.");
  332.  
  333.             /* End the line. */
  334.             b_settab( (struct BLOCK *) b_buff,
  335.                   b_line - b_start,
  336.                   br_out
  337.                 );
  338.             b_line++;
  339.  
  340.             /* Clear the output buffer. */
  341.             put_buf(br_avail);
  342.             br_out = out_save = 0;
  343.             br_avail = BUFF_SIZE - sizeof(int);
  344.         }
  345.  
  346.         else if (br_avail <= 0) {
  347.  
  348.             /*
  349.                 Deallocate last table entry and
  350.                 reallocate space used by the
  351.                 partial line.
  352.             */
  353.             br_avail += (sizeof(int) + br_out - out_save);
  354.  
  355.             /* Write out the buffer. */
  356.             put_buf(br_avail);
  357.  
  358.             /* Move the remainder to the front. */
  359.             sysmove(outbuf + out_save,
  360.                 outbuf,
  361.                 br_out - out_save);
  362.  
  363.             /* Reset restart point. */
  364.             br_out   = br_out - out_save;
  365.             out_save = 0;
  366.             br_avail = BUFF_SIZE - sizeof(int) - br_out;
  367.         }
  368.  
  369.         c = read1();
  370.  
  371.         if (c == EOF_MARK) {
  372.  
  373.             if (br_out != out_save) {
  374.  
  375.                 /* Finish the last line. */
  376.                 b_settab( (struct BLOCK *) b_buff,
  377.                       b_line-b_start,
  378.                       br_out    /* 3/8/85 */
  379.                     );
  380.                 b_line++;
  381.                 out_save = br_out;
  382.             }
  383.             else {
  384.                 /* No last line after all. */
  385.                 br_avail += sizeof(int);
  386.             }
  387.  
  388.             /* bug fix:  2/20/84, 4/2/84 */
  389.             if (br_avail !=  BUFF_SIZE) {
  390.                 put_buf(br_avail);
  391.             }
  392.             break;
  393.         }
  394.  
  395.         else if (c == '\n') {
  396.  
  397.             /* Finish the line. */
  398.             b_settab( (struct BLOCK *) b_buff,
  399.                   b_line - b_start,
  400.                   br_out
  401.                 );
  402.             br_avail -= sizeof(int);
  403.  
  404.             /* Set restart point. */
  405.             b_line++;
  406.             out_save = br_out;
  407.         }
  408.  
  409.         else if (c == '\r') {
  410.             /* Ignore CP/M's p