home *** CD-ROM | disk | FTP | other *** search
- // filebuf.c RHS 9/1/90 file-buffering and handling routines
-
- #ifdef WINDOWS
- #include<windows.h>
- #include"wsmooth.h"
- #include"wsmooth2.h"
- #endif
-
- #include<stdio.h>
- #include<stdlib.h>
- #include<string.h>
- #include<malloc.h>
- #include<dos.h>
- #include<fcntl.h>
- #include<sys\types.h>
- #include<sys\stat.h>
- #include<io.h>
- #include"filebuf.h"
-
- #define TRUE 1
- #define FALSE 0
- #define MAXSCREEN 25
- #define CTRL_Z 0x1A
- #define CR '\r'
- #define LF '\n'
- #define MYEOF 0xffff
-
- #define PAGEINDEXSIZE 50
- #define HALFBUFFER (30*1024)
- #define MAXFILESIZE ((long)PAGEINDEXSIZE*(long)HALFBUFFER)
- #define BUFFERSIZE (HALFBUFFER*2)
-
- #if defined(WINDOWS)
- HANDLE indexbufhdl = NULL, bufferhdl = NULL;
- extern HWND WinSmooth;
- #endif
-
- unsigned far *lineptr; // pointer to line index in index segment
- unsigned far *pageptr; // pointer to page index in index segment
- unsigned far *indexstart = NULL; // pointer to start of line index
- unsigned far *indexbuf = NULL; // pointer to index buffer
- char far *fileptr = NULL; // pointer to curr line
- char far *bufstart = NULL; // pointer to start of filebuffer
- char far *bufend; // point to end of buffer
- int fh = -1;
- int stripbits = FALSE;
-
- void filebuf_updateindex(int endndx);
- void filebuf_read(void);
- void filebuf_nextbuffer(void);
- void filebuf_prevbuffer(void);
- void filebuf_reset(void);
- void filebuf_stripbits(char far *buf, unsigned len);
- void error_exit(int err, char *msg);
-
- BOOL filebuf_fileisopen(void)
- {
- if(fh != -1)
- return TRUE;
- return FALSE;
- }
-
- // toggles bit stripping flag
- void filebuf_strip(int strip)
- {
- stripbits = strip;
- }
-
- // strips high bit from bytes read
- void filebuf_stripbits(char far *buf, unsigned len)
- {
- if(!stripbits)
- return;
- for( ; len; len--)
- buf[len-1] &= 0x7f;
- }
-
- // initializes file buffers
- int filebuf_init(void)
- {
- if(indexbufhdl && bufferhdl)
- {
- filebuf_reset();
- return TRUE;
- }
-
- // allocate index buffer and file buffer
- #ifdef WINDOWS
- {
- unsigned u = BUFFERSIZE+1; // use an unsigned to get over compiler bug
- // allocate index and file buffers
- if(indexbufhdl = GlobalAlloc(GMEM_MOVEABLE,u))
- indexbuf = (unsigned far *)GlobalWire(indexbufhdl);
-
- if(bufferhdl = GlobalAlloc(GMEM_MOVEABLE,u))
- bufstart = (char far *)GlobalWire(bufferhdl);
-
- if(!indexbufhdl || !bufferhdl)
- {
- Message(WinSmooth,"Unable to allocate memory buffers: hdls=%u,%u ptrs=%lp,%lp size=%ld",
- indexbufhdl,bufferhdl,indexbuf,bufstart,GlobalSize(indexbufhdl));
- return FALSE;
- }
- }
-
- if(!indexbuf || !bufstart)
- Message(WinSmooth,"Unable to re-locate memory buffers: ptrs=%lp,%lp",
- indexbuf,bufstart);
- #else
- indexbuf = (unsigned far *)_fmalloc(BUFFERSIZE+1);
- bufstart = (char far *)_fmalloc(BUFFERSIZE+1);
- if(!indexbuf || !bufstart)
- error_exit(0,"No buffer allocation");
- #endif
-
- // set line pointer to beginning of line index
- indexstart = lineptr = &indexbuf[PAGEINDEXSIZE];
- // set page pointer to beginning of page index
- pageptr = indexbuf;
- // initialize indexes
- _fmemset(indexbuf,0x0000,BUFFERSIZE);
- // set last word of line index to MYEOF
- indexbuf[BUFFERSIZE/(sizeof(unsigned))] = MYEOF;
-
- return TRUE;
- }
-
- // resets variables for new file without re-allocating buffers
- void filebuf_reset(void)
- {
- lineptr = indexstart;
- pageptr = indexbuf;
- fileptr = NULL;
- _fmemset(indexbuf,0x0000,BUFFERSIZE);
- }
-
- int filebuf_open(char *filename, int strip)
- {
- if(!(*filename))
- return FALSE;
-
- #ifdef WINDOWS
- {
- OFSTRUCT of;
- // open the file for read only, and allow others to read it (but not write)
- if((fh = OpenFile(filename,&of,
- OF_CANCEL | OF_PROMPT | OF_READ | OF_SHARE_DENY_WRITE)) == -1)
- {
- Message(WinSmooth,"Error %d opening %s",of.nErrCode,filename);
- return FALSE;
- }
- }
- #else
- if((fh = open(filename,O_BINARY | O_RDONLY)) == -1)
- error_exit(0,"Unable to open file");
- #endif
- {
- struct stat s;
-
- if(fstat(fh,&s)) // get file size
- return FALSE;
- if(s.st_size > MAXFILESIZE) // check file size
- #ifdef WINDOWS
- {
- Message(WinSmooth,"%s is too large to be handled by WinSmooth",
- filename);
- return FALSE;
- }
- #else
- error_exit(0,"File too large");
- #endif
- }
-
- filebuf_read(); // get first buffer from file
-
- {
- unsigned len; // read entire file
- for(len = 1; filebuf_nextline(&len) && len; );
- }
-
- stripbits = (strip ? TRUE : FALSE);
- return TRUE;
- }
-
- // de-allocates filebuffers and cleans up
- void filebuf_destruct(void)
- {
- #if defined(WINDOWS)
- if(indexbufhdl)
- {
- GlobalUnWire(indexbufhdl);
- GlobalFree(indexbufhdl);
- }
- if(bufferhdl)
- {
- GlobalUnWire(bufferhdl);
- GlobalFree(bufferhdl);
- }
- indexbufhdl = bufferhdl = NULL;
- #else
- if(indexbuf)
- _ffree(indexbuf);
- if(bufstart)
- _ffree(bufstart);
- bufstart = NULL;
- indexbuf = NULL;
- #endif
- if(fh != -1)
- close(fh);
- fh = -1;
- }
-
- // reads buffer from file
- void filebuf_read(void)
- {
- unsigned bytes;
-
- lseek(fh,(HALFBUFFER*(pageptr-indexbuf)),SEEK_SET);
- _dos_read(fh,&bufstart[HALFBUFFER],HALFBUFFER,&bytes);
- filebuf_stripbits(&bufstart[HALFBUFFER],HALFBUFFER);
-
- fileptr = (!fileptr ? &bufstart[HALFBUFFER] : (fileptr -= HALFBUFFER));
-
- bufend = &bufstart[HALFBUFFER+bytes]; // set to end of buffer
- *bufend = CTRL_Z;
- filebuf_updateindex((bytes != HALFBUFFER) ? TRUE : FALSE);
- }
-
- // updates line index for buffer
- void filebuf_updateindex(int endndx)
- {
- char far *buf = fileptr;
- char far *old = fileptr;
- unsigned far *ndx = lineptr;
- unsigned numlines = ((pageptr == indexbuf) ? 0 : pageptr[-1]);
-
- while(buf <= bufend) // until end of buffer
- switch(*buf)
- {
- case CR: // if CR or LF found
- case LF:
- buf++; // check next character
- if(*buf == LF) // if CR followed by line feed
- buf++;
- *ndx++ = (buf-old); // use ptr arithmetic to get length
- numlines++;
- old = buf; // set old to next line
- if(buf == bufend)
- buf++;
- break; // break so as not to fall thru
- case CTRL_Z:
- bufend = buf; // CTRL_Z found, set new buf end
- if(buf > old) // if line ends with CTRL_Z
- *ndx++ = 0;
- buf++;
- break;
- default:
- buf++;
- break;
- }
- *pageptr = numlines; // set to accumulated line count
- if(endndx) // if end of file reached
- *ndx = MYEOF; // set end of file marker in index
- }
-
- // read next buffer from file
- void filebuf_nextbuffer(void)
- {
- // copy the 2nd half of buffer to the 1st half
- _fmemcpy(bufstart,&bufstart[HALFBUFFER],HALFBUFFER);
- pageptr++; // set for next page
-
- // read HALFBUFFER bytes into 2nd half
- filebuf_read();
- }
-
- // read previous buffer from file
- void filebuf_prevbuffer(void)
- {
- if(pageptr == indexbuf) // insure we're not on 1st page
- return;
- // copy 1st buffer to 2nd
- _fmemcpy(&bufstart[HALFBUFFER],bufstart,HALFBUFFER);
- fileptr += HALFBUFFER; // adjust pointer to its position in 2nd page
- pageptr--; // seek to page
- lseek(fh,(HALFBUFFER*(pageptr-indexbuf)),SEEK_SET);
- {
- unsigned bytes;
- _dos_read(fh,bufstart,HALFBUFFER,&bytes); // read the file into the 1st buffer
- filebuf_stripbits(bufstart,HALFBUFFER);
- }
- bufend = &bufstart[BUFFERSIZE]; // set to end of buffer
- *bufend = CTRL_Z;
- }
-
- // seek to a particular line
- void filebuf_seekline(unsigned line)
- {
- unsigned far *page = indexbuf, far *buf1, far *buf2, far *ndx;
-
- // find a page with a higher accum. line count
- for( ; line > *page && *page; page++);
-
- if(page == indexbuf) // if we're on the first page (no prev. page)
- {
- buf1 = page; // set for first 2 buffers
- buf2 = page+1;
- }
- else if(*(page+1) == 0) // or not on 1st page and next page is empty
- {
- buf1 = page-1; // set for this and prev buffer
- buf2 = page;
- }
- else // or we are between two real pages
- {
- if(line > (*(page-1) + ((*(page+1) - *(page-1)) / 2)))
- {
- buf1 = page;
- buf2 = page+1;
- }
- else
- {
- buf1 = page-1;
- buf2 = page;
- }
- }
- lineptr = indexstart+line; // set lineptr to the line
- pageptr = page; // set pageptr to the page
-
- if(*buf2) // if no 2nd page, nothing to read
- {
- unsigned bytes;
- // read 1st buffer
- lseek(fh,(HALFBUFFER*(buf1-indexbuf)),SEEK_SET);
- _dos_read(fh,bufstart,HALFBUFFER,&bytes);
- lseek(fh,(HALFBUFFER*(buf2-indexbuf)),SEEK_SET);
- _dos_read(fh,&bufstart[HALFBUFFER],HALFBUFFER,&bytes);
- filebuf_stripbits(bufstart,HALFBUFFER*2);
- bufend = &bufstart[HALFBUFFER+bytes]; // set to end of buffer
- *bufend = CTRL_Z;
- fileptr = (page == buf1) ? bufstart : &bufstart[HALFBUFFER];
- }
- else
- fileptr = &bufstart[HALFBUFFER];
- ndx = indexstart;
- ndx += ((pageptr == indexbuf) ? 0 : *(pageptr-1));
-
- if(*buf2)
- if(fileptr != bufstart)
- {
- while(fileptr[-1] != CR && fileptr[-1] != LF)
- fileptr--;
- }
- else if(lineptr != indexstart)
- {
- ndx++;
- while(fileptr[1] != CR && fileptr[1] != LF)
- fileptr++;
- fileptr++;
- while(*fileptr == CR || *fileptr == LF)
- fileptr++;
- }
- for(; ndx < lineptr; fileptr += *ndx, ndx++)
- ;
- }
-
- // get next line from file
- char far *filebuf_nextline(unsigned *len)
- {
- char far *linestart;
- char far *bufptr; // local pointer
-
- *len = 0;
-
- if(*lineptr == MYEOF)
- return NULL;
- reset:
- linestart = fileptr; // set linestart to fileptr
- // read until buffer end encountered, or until CR found
- for( bufptr = fileptr; bufptr != bufend; bufptr++)
- if((*bufptr == CR) || (*bufptr == LF))
- break;
- if(bufptr == bufend) // end of buffer, line carries over
- {
- filebuf_nextbuffer(); // read more of file
- goto reset;
- }
- *len = (bufptr-fileptr); // remove CR from buf
- fileptr += *lineptr++;
- return linestart;
- }
-
-
- // get previous line from file
- char far *filebuf_prevline(unsigned *len)
- {
- char far *bufptr;
-
- *len = 0;
-
- if(lineptr == indexstart) // if at beginning of file
- return NULL;
-
- --lineptr; // set to previous line
- bufptr = bufstart+HALFBUFFER;
- if((fileptr > bufptr) && ((fileptr - *lineptr) <= bufptr))
- pageptr--; // set to prev page
- if((bufstart + *lineptr) > fileptr) // if line length extends from previous page
- filebuf_prevbuffer();
- fileptr -= (*lineptr);
-
- for(bufptr = fileptr; bufptr != bufend; bufptr++)
- if((*bufptr == CR) || (*bufptr == LF))
- break;
- *len = (bufptr - fileptr);
- return fileptr;
- }
-
- // returns number of lines line file
- unsigned filebuf_numlines(void)
- {
- unsigned far *page;
-
- for(page = indexbuf; *(page+1); page++)
- ;
- return *page;
- }
-
- // returns length of longest line in file
- unsigned filebuf_longestline(void)
- {
- unsigned far *ndx = indexstart;
- unsigned longest = 0;
-
- for( ; *ndx != MYEOF; ndx++)
- if(*ndx > longest)
- longest = *ndx;
- return longest;
- }
-
- // exit routine on fatal error
- void error_exit(int err, char *msg)
- {
- #if defined(WINDOWS)
- extern HWND WinSmooth;
-
- Message(WinSmooth,msg);
- #else
- printf("%s\n",msg);
- #endif
- exit(err);
- }
-