/* * Software virtual memory system * Copyright * (C) 1992 Joseph H. Allen * * This file is part of JOE (Joe's Own Editor) */ #ifndef _JOE_VFILE_H #define _JOE_VFILE_H 1 /* Page header */ struct vpage { VPAGE *next; /* Next page with same hash value */ VFILE *vfile; /* Owner vfile */ off_t addr; /* Address of this page */ int count; /* Reference count */ int dirty; /* Set if page changed */ unsigned char *data; /* The data in the page */ }; /* File structure */ struct vfile { LINK(VFILE) link; /* Doubly linked list of vfiles */ off_t size; /* Number of bytes in physical file */ off_t alloc; /* Number of bytes allocated to file */ int fd; /* Physical file */ int writeable; /* Set if we can write */ unsigned char *name; /* File name. 0 if unnamed */ int flags; /* Set if this is only a temporary file */ /* For array I/O */ unsigned char *vpage1; /* Page address */ long addr; /* File address of above page */ /* For stream I/O */ unsigned char *bufp; /* Buffer pointer */ unsigned char *vpage; /* Buffer pointer points in here */ int left; /* Space left in bufp */ int lv; /* Amount of append space at end of buffer */ }; /* Additions: * * Should we remove size checking from rc()? Would make it faster... * * Should be able to open more than one stream on a file so that vseek * doesn't have to get called so much when more than one user is involed * * Also should have dupopen call to make more streams for a file * * Make vputs faster * * Should have a version which will use memory mapped files, if they exist * in the os. * * Would be nice if we could transparantly open non-file streams and pipes. * Should there be an buffering option for that? So we can seek on pipes to * get previously read data? */ extern unsigned char *vbase; /* Data first entry in vheader refers to */ extern VPAGE **vheaders; /* Array of headers */ /* VFILE *vtmp(V); * * Open a temporary virtual file. File goes away when closed. No actual * file is generated if everything fits in memory. */ VFILE *vtmp PARAMS((void)); #ifdef junk /* VFILE *vopen(char *name); * * Open a file for reading and if possible, writing. If the file could not * be opened, NULL is returned. */ VFILE *vopen PARAMS(()); #endif /* off_t vsize(VFILE *); * * Return size of file */ #define vsize(vfile) \ ( \ (vfile)->left<(vfile)->lv ? \ (vfile)->alloc+(vfile)->lv-(vfile)->left \ : \ (vfile)->alloc \ ) /* void vclose(VFILE *vfile); * * Close a file. */ void vclose PARAMS((VFILE *vfile)); #ifdef junk /* void vlimit(long amount); * * Set limit (in bytes) on amount of memory the virtual file system may * use. This limit can be exceeded if all existing vpages are being referenced * and a new vpage is requested. * * When vlimit is called, the limit is immediatly enforced by elimiting * non-referenced vpages. */ void vlimit PARAMS(()); #endif /* void vflsh(void); * * Write all changed pages to the disk */ void vflsh PARAMS((void)); /* void vflshf(VFILE *vfile); * * Write changed pages for a specific file to the disk */ void vflshf PARAMS((VFILE *vfile)); /* char *vlock(VFILE *vfile,off_t addr); * * Translate virtual address to physical address. 'addr' does not have * to be on any particular alignment, but if you wish to access more than * a single byte, you have to be aware of where page boundaries are (virtual * address multiples of PGSIZE). * * The page containing the data is locked in memory (so that it won't be * freed or used for something else) until 'vunlock' is used. * * Warning: If you allocate more than one page and use (change) them out of * order, vflsh will screw up if writing past the end of a file is illegal * in the host filesystem. * * Also: This function does not allocate space to the file. Use valloc() * for that. You can vlock() pages past the allocated size of the file, but * be careful when you do this (you normally shouldn't- the only time you * ever might want to is to implement your own version of valloc()). */ unsigned char *vlock PARAMS((VFILE *vfile, off_t addr)); /* VPAGE *vheader(char *); * Return address of page header for given page */ #define vheader(p) (vheaders[(physical((unsigned char *)(p))-physical(vbase))>>LPGSIZE]) /* void vchanged(char *); * * Indicate that a vpage was changed so that it will be written back to the * file. Any physical address which falls within the page may be given. */ #define vchanged(vpage) ( vheader(vpage)->dirty=1 ) /* void vunlock(char *); * Unreference a vpage (call one vunlock for every vlock) * Any physical address which falls within the page may be given. */ #define vunlock(vpage) ( --vheader(vpage)->count ) /* void vupcount(char *); * Indicate that another reference is being made to a vpage */ #define vupcount(vpage) ( ++vheader(vpage)->count ) /* long valloc(VFILE *vfile,long size); * * Allocate space at end of file * * Returns file address of beginning of allocated space */ off_t my_valloc PARAMS((VFILE *vfile, off_t size)); #ifdef junk /****************************************************************************** * The folloing functions implement stream I/O on top of the above software * * virtual memory system * ******************************************************************************/ /* void vseek(VFILE *vfile,long addr); * * Seek to a file address. Allocates space to the file if you seek past the * end. */ void vseek PARAMS(()); /* int vrgetc(VFILE *); * int vgetc(VFILE *); * * Get next character / Get previous character functions. * They return NO_MORE_DATA for end of file / beginning of file. */ int _vgetc PARAMS(()); int _vrgetc PARAMS(()); #define vrgetc(v) \ ( (v)->left!=PGSIZE ? ( ++(v)->left, (int)(unsigned)*(--(v)->bufp) ) : _vrgetc(v) ) #define vgetc(v) \ ( (v)->left>(v)->lv ? ( --(v)->left, (int)(unsigned)*((v)->bufp++) ) : _vgetc(v) ) /* int vputc(VFILE *,I); * * Put character. Returns character which is written. */ int _vputc PARAMS(()); #define vputc(v,c) \ ( \ (v)->left ? \ ( \ --(v)->left, \ vchanged((v)->vpage), \ (int)(unsigned)(*((v)->bufp++)=(c)) \ ) \ : \ _vputc((v),(c)) \ ) /* long vtell(VFILE *); * * Return current file position */ #define vtell(v) \ ( \ (v)->vpage ? \ ( vheader((v)->vpage)->addr+(v)->bufp-(v)->vpage ) \ : \ 0L \ ) /* long vgetl(VFILE *); * * Get long. No alignment requirements. Returns -1 if goes past end of file. */ long vgetl PARAMS(()); /* short vgetw(VFILE *); * * Get short. No alignment requirements. Returns -1 if goes past end of file. */ short vgetw PARAMS(()); /* long vputl(VFILE *,long); * * Put long. No alignment requirements. * Returns value written. */ long vputl PARAMS(()); /* short vputw(VFILE *,short); * * Put long. No alignement requirements. * Returns value written. */ short vputw PARAMS(()); /* char *vgets(VFILE *v,char *s); * * Read up to next '\n' or end of file into a variable length string. If 's' * is 0, a new string is created. The \n is not copied into the string. * * Eliminates the variable length string and returns NULL if * vgets is called on the end of the file. * * This requires that you use the 'vs.h' / 'vs.c' library. */ unsigned char *vgets PARAMS(()); /* void vputs(VFILE *v,char *s); * * Write zero terminated string. \n is not appended */ void vputs PARAMS(()); /* void vread(VFILE *,char *,int size); * * Read bytes from a virtual file into a local data block */ void vread PARAMS(()); /* void vwrite(VFILE *,char *,int size); * * Write bytes from a local data block into a virtual file */ void vwrite PARAMS(()); /*************************************************************************** * The following functions implement array I/O on top of the above virtual * * memory system (cheap memory mapped files) * ***************************************************************************/ /* int rc(VFILE *vfile,long addr); * * Read character. Returns NO_MORE_DATA if past end of file. */ int _rc(); #define rc(v,a) \ ( \ (a)>=vsize(v) ? NO_MORE_DATA : \ ( \ (v)->addr==((a)&~(PGSIZE-1)) ? \ (v)->vpage1[(a)&(PGSIZE-1)] \ : \ _rc((v),(a)) \ ) \ ) /* int wc(VFILE *vfile,long addr,char c); * * Write character. Return character written. This automatically allocates * space to the file. */ int _wc(); #define wc(v,a,c) \ ( \ (v)->addr==((a)&~(PGSIZE-1)) ? \ ( \ vheader((v)->vpage1)->dirty=1, \ ((a)+1>vsize(v) && my_valloc(v,(a)+1-vsize(v))), \ (v)->vpage1[(a)&(PGSIZE-1)]=(c) \ ) \ : \ _wc((v),(a),(c)) \ ) /* long rl(VFILE *vfile,long addr); * Read big-endian long. No alignment requirements. Returns -1 if goes past * end of file. */ long rl PARAMS(()); /* long wl(VFILE *vfile,long addr,long c); * Write big-endian long. No alignment requirements. Automatically expands * file if necessary. */ long wl PARAMS(()); /* short rw(VFILE *vfile,long addr); * Read big-endian short. No alignment requirements. Returns -1 if goes past * end of file. */ short rw PARAMS(()); /* short ww(VFILE *vfile,long addr,short c); * Write big-endian short. No alignment requirements. Automatically expands * file if necessary. */ short ww PARAMS(()); #endif /* junk */ #endif