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 >
Wrap
C/C++ Source or Header
|
1990-06-18
|
17KB
|
882 lines
/*
RED buffer routines -- Full C version
Part 3 -- file routines
Source: redbuf3.c
Version: August 8, 1986; January 18, 1990.
Written by
Edward K. Ream
166 N. Prospect
Madison WI 53705
(608) 257-0802
PUBLIC DOMAIN SOFTWARE
This software is in the public domain.
See red.h for a disclaimer of warranties and other information.
*/
#include "red.h"
/*
Declare routines local to this file.
*/
static void disk_seek (void);
static int read1 (void);
static void read2 (void);
extern void write1 (char c);
extern void wr_flush (void);
/*
Data buffer used only in this file.
*/
static char b_buff [DATA_SIZE];
/*
Kludge to allow more strict checking in swap_out.
It is usually an internal error if we swap out the current block.
The exception is in write_file, where we swap out all blocks.
*/
static int ok2swap = FALSE;
/*
Open the data file.
*/
int
data_open(void)
{
TICKB("data_open");
/* Erase the data file if it exists. */
sysunlink(DATA_FILE);
/* Create the data file. */
b_data_fd = syscreat(DATA_FILE);
if (b_data_fd == ERROR) {
disk_error("Can not open swap file.");
}
RETURN_INT("data_open", b_data_fd);
}
/*
Make the slot the MOST recently used slot.
*/
void
do_lru(struct BLOCK *bp)
{
struct BLOCK *bp1;
int i, lru;
SL_DISABLE();
/*
Change the relative ordering of all slots
which have changed more recently than slot.
*/
lru = bp -> d_lru;
/* 12/15/89: do nothing if the current slot is the most recent. */
if (lru == 0) {
return;
}
TRACEP("do_lru", sl_lpout();
sl_pout(bp); sl_sout(") before: "); dump_slots());
for (i = 0; i < DATA_RES; i++) {
bp1 = b_bpp [i];
if (bp1 -> d_lru < lru) {
bp1 -> d_lru++;
}
}
/* The slot is the most recently used. */
bp -> d_lru = 0;
TRACE("do_lru", sl_sout("after: "); dump_slots(); sl_cout('\n'));
}
/*
Disk error routines
*/
void
disk_error(char *message)
{
TRACEPB("disk_error", sl_lpout(); sl_sout(message); sl_rpout());
error(message);
/* Clear the buffer if no recovery is possible. */
if (b_fatal == TRUE) {
bufnew();
}
/* Abort the operation that caused the error. */
longjmp(DISK_ERR, ERROR);
TICKX("disk_error");
}
void
disk_full(void)
{
SL_DISABLE();
disk_error("Disk or directory full?");
}
void
disk_rdy(void)
{
SL_DISABLE();
disk_error("Drive not ready?");
}
static void
disk_seek(void)
{
SL_DISABLE();
disk_error("Bad Seek");
}
/*
Indicate that a slot must be saved on the disk.
*/
#if 0 /* a macro now */
void
is_dirty(struct BLOCK *bp)
{
TRACEPB("is_dirty", sl_lpout(); sl_pout(bp); sl_rpout());
bp -> d_status = DIRTY;
TICKX("is_dirty");
}
#endif /* 0 */
/*
Put out the block-sized buffer to the disk sector.
*/
void
put_block(struct BLOCK *bp, int diskp)
{
int s;
/* Make sure blocks are written in order. */
TRACEPB("put_block", sl_lpout();
sl_pout(bp); sl_csout();
sl_iout(diskp); sl_rpout());
if (diskp > b_max_put + 1) {
swap_sync(b_max_put + 1, diskp - 1);
}
b_max_put = max(b_max_put, diskp);
/* Seek to the correct sector of the data file. */
s = sysseek(b_data_fd, diskp);
if (s == -1) {
disk_seek();
}
/* Write the block to the data file. */
if (syswrite(b_data_fd, (char *) bp, DATA_SIZE) != DATA_SIZE) {
disk_full();
}
TICKX("put_block");
}
/*
Fill in the header fields of the output buffer and
write it to the disk.
avail is the number of free characters in the buffer.
*/
char *
put_buf(int avail)
{
struct BLOCK *bp;
/*
Fill in the back and next links immediately.
This can be done because we are not waiting
for the LRU algorithm to allocated disk blocks.
The last block that put_buf() writes will have
an incorrect next link. Read_file() will make
the correction.
*/
TRACEPB("put_buf", sl_lpout(); sl_iout(avail); sl_rpout());
bp = (struct BLOCK *) b_buff;
bp -> d_back = b_max_diskp - 1;
bp -> d_next = b_max_diskp + 1;
bp -> d_lines = b_line - b_start;
if (avail < 0) {
cant_happen("put_buf");
}
/* Update block and line counts. */
b_max_diskp++;
b_start = b_line;
/* Write the block. */
put_block( (struct BLOCK *) b_buff, b_max_diskp - 1);
TICKX("put_buf");
}
/*
Write out the slot to the data file.
*/
void
put_slot(struct BLOCK *bp)
{
TRACEPB("put_slot", sl_lpout(); sl_pout(bp); sl_rpout());
if (bp -> d_diskp == ERROR) {
cant_happen("put_slot");
}
put_block(bp, bp -> d_diskp);
TICKX("put_slot");
}
/*
Read a file into the buffer.
This version of read_file puts an index table at
the end of each block. The index table's entry
for each line tells the distance of the LAST character
of the line from the start of the data buffer.
The global variables br_count, br_bufp, and br_bufc
are used to communicate with read1(). Using these
variables speeds the code by a factor of 3!
The "global" variables br_avail and br_out are used
only by read_file() -- again, purely to speed the code.
*/
void
read_file(char file_name [])
{
struct BLOCK *bp;
/* global: char * br_bufp pointer to buffer */
/* global: int br_bufc index into buffer */
/* global: int br_count number of buffer */
/* global: int br_avail available chars */
/* global: int br_out index into outbuf */
char *outbuf; /* the output buffer */
int out_save; /* line starts here */
int c, i, j;
/* Clear the swapping buffers and the files. */
TRACEPB("read_file", sl_lpout(); sl_pout(file_name); sl_rpout());
bufnew();
b_bp -> d_status = FREE;
/* Open the user file. */
b_user_fd = sysopen(file_name);
if (b_user_fd == ERROR) {
disk_error("File not found.");
}
/* Clear the buffer on any disk error. */
b_fatal = TRUE;
/* Open the data file. */
data_open();
/* The file starts with line 1. */
b_line = 1;
b_start = 1;
/* There are no blocks in the file yet. */
b_head = b_tail = ERROR;
b_max_diskp = 0;
/* Point outbuf to start of the output data area. */
outbuf = b_buff + HEADER_SIZE;
/* Force an initial read in read1(). */
br_count = DATA_SIZE;
br_bufc = DATA_RES;
/* Zero the pointers into the output buffer. */
br_out = out_save = 0;
/* Allocate space for the first table entry. */
br_avail = BUFF_SIZE - sizeof(int);
/* Set the current line counts. */
b_line = b_start = 1;
for(;;) {
if (br_avail <= 0 && out_save == 0) {
/* The line is too long. */
error ("Line split.");
/* End the line. */
b_settab( (struct BLOCK *) b_buff,
b_line - b_start,
br_out
);
b_line++;
/* Clear the output buffer. */
put_buf(br_avail);
br_out = out_save = 0;
br_avail = BUFF_SIZE - sizeof(int);
}
else if (br_avail <= 0) {
/*
Deallocate last table entry and
reallocate space used by the
partial line.
*/
br_avail += (sizeof(int) + br_out - out_save);
/* Write out the buffer. */
put_buf(br_avail);
/* Move the remainder to the front. */
sysmove(outbuf + out_save,
outbuf,
br_out - out_save);
/* Reset restart point. */
br_out = br_out - out_save;
out_save = 0;
br_avail = BUFF_SIZE - sizeof(int) - br_out;
}
c = read1();
if (c == EOF_MARK) {
if (br_out != out_save) {
/* Finish the last line. */
b_settab( (struct BLOCK *) b_buff,
b_line-b_start,
br_out /* 3/8/85 */
);
b_line++;
out_save = br_out;
}
else {
/* No last line after all. */
br_avail += sizeof(int);
}
/* bug fix: 2/20/84, 4/2/84 */
if (br_avail != BUFF_SIZE) {
put_buf(br_avail);
}
break;
}
else if (c == '\n') {
/* Finish the line. */
b_settab( (struct BLOCK *) b_buff,
b_line - b_start,
br_out
);
br_avail -= sizeof(int);
/* Set restart point. */
b_line++;
out_save = br_out;
}
else if (c == '\r') {
/* Ignore CP/M's p