123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- /* $Header$ */
- /* INPUT AND BUFFER HANDLING MODULE */
- /*
- [input.c input.h]
- Input buffering module: this module contains the routines that
- offers an input buffering mechanism to the user.
- This module exports the following objects:
- InsertFile() : suspend input from current buffer and obtain the
- next input characters from the specified file
- InsertText() : suspend input from current buffer and take the
- specified text as stream of input characters
- LoadChar() : (defined in input.h) read next character from
- the input ; LoadChar() invokes loadbuf() on
- encounting a ASCII NUL character
- NoUnstack : if set to non-zero:
- loadbuf() reports "unexpected EOF" on encounting
- the end-of-file or end-of-stacked-text.
-
- Imported objects are:
- IDEPTH, DEBUG, READ_IN_ONE, PATHLENGTH: compile-time parameters
- Malloc(), Salloc(): memory allocation routines
- fatal(), lexerror(): exception handling
- FileName, LineNumber, WorkingDir: input trace for lexical analyser
- READ_IN_ONE DEFINED: every input file is read into memory completely
- and made an input buffer
- READ_IN_ONE NOT DEFINED: the input from files is buffered in
- a fixed length input buffer
- */
- #include <system.h>
- #include "nopp.h"
- #include "inputtype.h" /* UF */
- #include "interface.h"
- #include "arith.h"
- #include "LLlex.h"
- #include "input.h"
- #include "alloc.h"
- #ifndef NOPP
- #include "idepth.h" /* UF */
- #include "debug.h" /* UF */
- #include "pathlength.h" /* UF */
- #include "assert.h"
- #endif NOPP
- EXPORT char *ipp = 0; /* input pointer */
- EXPORT int NoUnstack = 0; /* if 1: report EOF */
- #ifndef READ_IN_ONE
- PRIVATE File *FilDes = 0; /* current input medium */
- #endif READ_IN_ONE
- #ifndef NOPP
- struct buffer_header {
- char *bh_name; /* file name where the text comes from */
- unsigned int bh_lineno;
- /* current lineno in file */
- long bh_size; /* = strlen (text), should be unsigned */
- char *bh_text; /* pointer to buffer containing text */
- char *bh_ipp; /* current read pointer (= stacked ipp) */
- char *bh_wdir; /* directory of current file */
- File *bh_fp; /* needed for files if !READ_IN_ONE */
- };
- PRIVATE struct buffer_header instack[IDEPTH]; /* stack of input media */
- PRIVATE struct buffer_header *head = 0; /* current input buffer */
- IMPORT char **WorkingDir; /* name of current working directory */
- #else NOPP
- long isize;
- char ibuf[BUFSIZ];
- #endif NOPP
- #ifdef READ_IN_ONE
- /* readfile() creates a buffer in which the text of the file
- is situated. A pointer to the start of this text is
- returned. *size is initialized with the buffer length.
- Note that the file input buffer is prepared for the
- preprocessor by inserting a '\n' in the beginning of the
- text and appending a '\n' at the end of the text. The
- file text start at position 1 of the input buffer. This is
- done to allow pushback.
- */
- PRIVATE char *
- readfile(filename, size)
- char *filename;
- long *size;
- {
- File *fp; /* filedescriptor for `filename' */
- char *cbuf; /* pointer to buffer to be returned */
- int tmp;
- long sys_filesize();
- if (sys_open(filename, OP_READ, &fp) == 0) /* can't open this file */
- return (char *) 0;
- if ((*size = sys_filesize(filename)) == -1L)
- fatal("(readfile) cannot get size of file");
- /* allocate enough space to store contents of the file */
- cbuf = Malloc(*size + 2);
- if (sys_read(fp, cbuf + 1, (int) *size, &tmp) == 0 || tmp != *size)
- fatal("(readfile) bad read");
- (*size)++; /* keep book of the size! */
- sys_close(fp); /* filedes no longer needed */
- cbuf[0] = '\0'; /* allow pushback of first char */
- cbuf[*size] = '\0'; /* invoke loadbuf() at end */
- return cbuf;
- }
- #endif READ_IN_ONE
- #ifndef NOPP
- #ifndef READ_IN_ONE
- /* Input buffer supplying routines: pushbuf() and popbuf()
- */
- PRIVATE char *bufstack[IDEPTH] = 0;
- PRIVATE bufstptr = 0;
- PRIVATE char *
- pushbuf()
- {
- if (bufstptr >= IDEPTH)
- fatal("ran out of input buffers");
- if (bufstack[bufstptr] == 0) {
- bufstack[bufstptr] = Malloc(BUFSIZ + 4);
- }
- return bufstack[bufstptr++];
- }
- PRIVATE
- popbuf()
- {
- bufstptr--;
- ASSERT(bufstptr >= 0);
- }
- #endif READ_IN_ONE
- #endif NOPP
- #ifndef NOPP
- /* Input buffer administration: push_bh() and pop_bh()
- */
- PRIVATE struct buffer_header *
- push_bh()
- {
- if (head) {
- if (head >= &instack[IDEPTH - 1])
- fatal("too many nested input texts");
- head->bh_ipp = ipp;
- head->bh_lineno = LineNumber;
- head++;
- }
- else
- head = &instack[0];
- return head;
- }
- #endif NOPP
- #ifndef NOPP
- /* pop_bh() uncovers the previous inputbuffer on the stack
- of headers. 0 is returned if there are no more
- inputbuffers on the stack, 1 is returned in the other case.
- */
- PRIVATE int
- pop_bh()
- {
- File *pfp = head->bh_fp;
- if (NoUnstack) {
- lexerror("unexpected EOF");
- }
- if (head <= &instack[0]) { /* no more entries */
- head = (struct buffer_header *) 0;
- return 0;
- }
- ipp = (--head)->bh_ipp; /* restore the previous input pointer */
- if (pfp != 0) { /* unstack a file */
- #ifndef READ_IN_ONE
- closefile(pfp);
- popbuf(); /* free last buffer */
- #endif READ_IN_ONE
- LineNumber = head->bh_lineno;
- FileName = head->bh_name;
- *WorkingDir = head->bh_wdir;
- }
- #ifndef READ_IN_ONE
- FilDes = head->bh_fp;
- #endif READ_IN_ONE
- return 1;
- }
- #endif NOPP
- #ifndef READ_IN_ONE
- /* low level IO routines: openfile(), readblock() and closefile()
- */
- PRIVATE File *
- openfile(filename)
- char *filename;
- {
- File *fp;
- if (filename == 0)
- return STDIN;
- if (sys_open(filename, OP_READ, &fp) == 0)
- return (File *)0;
- return fp;
- }
- PRIVATE
- closefile(fp)
- File *fp;
- {
- if (fp != STDIN)
- sys_close(fp);
- }
- PRIVATE int
- readblock(fp, buf)
- File *fp;
- char buf[];
- {
- int n;
- if (sys_read(fp, &buf[1], BUFSIZ, &n) == 0)
- fatal("(readblock) bad read");
- buf[0] = buf[n + 1] = '\0';
- return n;
- }
- #endif READ_IN_ONE
- /* Interface routines : InsertFile(), InsertText() and loadbuf()
- */
- EXPORT int
- InsertFile(filnam, table)
- char *filnam;
- char *table[];
- {
- char *mk_filename(), *newfn;
- char *strcpy();
- File *openfile();
- #ifdef READ_IN_ONE
- char *readfile(), *text;
- long size;
- #else READ_IN_ONE
- File *fp = 0;
- #endif READ_IN_ONE
- #ifdef READ_IN_ONE
- if (!filnam)
- return 0;
- #endif READ_IN_ONE
- #ifndef NOPP
- if (table == 0 || filnam[0] == '/') { /* don't look in the table! */
- #endif NOPP
- #ifdef READ_IN_ONE
- text = readfile(filnam, &size);
- #else READ_IN_ONE
- fp = openfile(filnam);
- if (filnam == 0)
- filnam = "standard input";
- #endif READ_IN_ONE
- #ifndef NOPP
- }
- else {
- ASSERT(filnam != 0);
- while (*table) { /* look in the directory table */
- newfn = mk_filename(*table++, filnam);
- #ifdef READ_IN_ONE
- if (text = readfile(newfn, &size))
- #else READ_IN_ONE
- if ((fp = openfile(newfn)) != 0)
- #endif READ_IN_ONE
- {
- /* free filnam ??? */
- filnam = Salloc(newfn, strlen(newfn) + 1);
- break;
- }
- }
- }
- #endif NOPP
- #ifdef READ_IN_ONE
- if (text)
- #else READ_IN_ONE
- if (fp != 0)
- #endif READ_IN_ONE
- #ifndef NOPP
- {
- struct buffer_header *push_bh();
- register struct buffer_header *bh = push_bh();
- setwdir(WorkingDir, filnam);
- bh->bh_lineno = LineNumber = 0;
- bh->bh_name = FileName = filnam;
- bh->bh_wdir = *WorkingDir;
- #ifdef READ_IN_ONE
- bh->bh_size = size;
- bh->bh_fp = STDIN; /* this is a file */
- ipp = bh->bh_text = text;
- #else READ_IN_ONE
- bh->bh_size = readblock(fp, ipp = bh->bh_text = pushbuf()) + 1;
- FilDes = bh->bh_fp = fp;
- #endif READ_IN_ONE
- bh->bh_text[0] = '\n'; /* wake up pp if '#' comes first */
- return 1;
- }
- #else NOPP
- {
- #ifdef READ_IN_ONE
- isize = size;
- ipp = text;
- #else READ_IN_ONE
- isize = readblock(FilDes = fp, ipp = &ibuf[0]) + 1;
- #endif READ_IN_ONE
- ibuf[0] = '\n';
- return 1;
- }
- #endif NOPP
- return 0;
- }
- #ifndef NOPP
- EXPORT
- InsertText(text, length)
- char *text;
- {
- struct buffer_header *push_bh();
- register struct buffer_header *bh = push_bh();
- bh->bh_name = FileName;
- bh->bh_lineno = LineNumber;
- bh->bh_size = (long) length;
- bh->bh_text = text;
- bh->bh_wdir = *WorkingDir;
- bh->bh_fp = 0; /* this is not a file ! */
- ipp = text + 1;
- #ifndef READ_IN_ONE
- FilDes = 0;
- #endif READ_IN_ONE
- }
- #endif NOPP
- /* loadbuf() is called if LoadChar meets a '\0' character
- which may be the end-of-buffer mark of the current input
- buffer. The '\0' could be genuine although not likely.
- Note: this routine is exported due to its occurence in the definition
- of LoadChar [input.h], that is defined as a macro.
- */
- EXPORT int
- loadbuf()
- {
- #ifndef NOPP
- if (!head) {
- /* stack exhausted, EOF on sourcefile */
- return EOI;
- }
- #endif NOPP
-
- #ifndef NOPP
- if (ipp < &(head->bh_text[head->bh_size]))
- #else NOPP
- if (ipp < &ibuf[isize])
- #endif NOPP
- {
- /* a genuine '\0' character has been seen */
- return '\0';
- }
- #ifndef READ_IN_ONE
- #ifndef NOPP
- if ( FilDes != 0
- && (head->bh_size = readblock(FilDes, head->bh_text)) > 0
- ) {
- return ipp = &(head->bh_text[1]), *ipp++;
- }
- #else NOPP
- if (FilDes != 0 && (isize = readblock(FilDes, &ibuf[0])) > 0)
- return ipp = &ibuf[1], *ipp++;
- #endif NOPP
- #endif READ_IN_ONE
- #ifdef NOPP
- if (NoUnstack)
- lexerror("unexpected EOF");
- #ifndef READ_IN_ONE
- closefile(FilDes);
- #endif READ_IN_ONE
- #endif NOPP
- return
- #ifndef NOPP
- pop_bh() ? (*ipp ? *ipp++ : loadbuf()) :
- #endif NOPP
- (ipp = &"\0\0"[1], EOI);
- }
- /* Some miscellaneous routines : setwdir() and mk_filename()
- */
- #ifndef NOPP
- /* setwdir() updates *wdir according to the old working
- directory (*wdir) and the filename fn, which may contain
- some path name. The algorithm used here is:
- setwdir(DIR, FILE):
- if (FILE == "/***")
- *DIR = "/"
- else
- if (contains(FILE, '/'))
- *DIR = directory(FILE)
- else
- *DIR remains unchanged
- */
- PRIVATE
- setwdir(wdir, fn)
- char *fn, **wdir;
- {
- register char *p;
- char *rindex();
- p = rindex(fn, '/');
- while (p && *(p + 1) == '\0') { /* remove trailing /'s */
- *p = '\0';
- p = rindex(fn, '/');
- }
- if (fn[0] == '\0' || (fn[0] == '/' && p == &fn[0])) /* absolute path */
- *wdir = "/";
- else
- if (p) {
- *p = '\0';
- *wdir = Salloc(fn, p - &fn[0] + 1);
- *p = '/';
- }
- }
- #endif NOPP
- #ifndef NOPP
- /* mk_filename() concatenates a dir and filename.
- */
- PRIVATE char *
- mk_filename(dir, file)
- register char *dir, *file;
- {
- static char newfn[PATHLENGTH];
- register char *dst = &newfn[0];
- if (!(dir[0] == '.' && dir[1] == '\0')) {
- while (*dst++ = *dir++);
- *(dst - 1) = '/';
- }
- while (*dst++ = *file++);
- return &newfn[0];
- }
- #endif NOPP
|