123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- /* INPUT AND BUFFER HANDLING MODULE */
- /*
- [input.X inp_pkg.spec 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:
- input.h : an include-file, which must be included when using
- this module
- 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
- PushBack() : (defined in input.h) push last character back onto
- the input stream; NPUSHBACK characters of pushback
- are guaranteed, provided that they have all been read
- from the current input stream
- AtEoIT() : this routine is called at the end of an inserted text.
- A default one is provided, which does nothing.
- AtEoIF() : this routine is called at the end of an inserted file.
- A default one is provided, which does nothing.
-
- Imported objects are:
- INP_NPUSHBACK, INP_READ_IN_ONE, INP_TYPE, INP_VAR,
- routines from the "alloc" package, routines from the "storage"
- package, and routines from the "system" package.
- INP_READ_IN_ONE defined: every input file is read into memory completely
- and made an input buffer. Only use it if the size of a file
- fits always fits in an integer and you have lots of memory.
- INP_READ_IN_ONE not defined: the input from files is buffered in
- a fixed length input buffer
- INP_NPUSHBACK: the number of characters pushback
- */
- #include <alloc.h>
- #include <system.h>
- #ifndef INP_NPUSHBACK
- #define INP_NPUSHBACK 1
- #endif
- #if INP_NPUSHBACK < 1
- #define INP_NPUSHBACK 1
- #endif
- #ifndef INP_BUFSIZE
- #define INP_BUFSIZE BUFSIZ
- #endif
- #if INP_NPUSHBACK > INP_BUFSIZE/2
- Now this is really ridiculous! You deserve what you get!!
- #endif
- #ifdef INP_TYPE
- extern INP_TYPE INP_VAR;
- #endif /* INP_TYPE */
- #ifdef DEBUG
- #define INP_PRIVATE
- #else
- #define INP_PRIVATE static
- #endif
- struct INP_buffer_header {
- struct INP_buffer_header *bh_next;
- int bh_size; /* = strlen (text), should be unsigned */
- char *bh_text; /* pointer to buffer containing text */
- char *bh_ipp; /* current read pointer (= stacked ipp) */
- #ifdef INP_TYPE
- INP_TYPE bh_i; /* user defined */
- #endif /* INP_TYPE */
- File *bh_fd; /* A file descriptor in case of a file */
- char bh_eofreturned; /* set if we returned eof for this buffer */
- };
- #ifndef INP_READ_IN_ONE
- struct INP_i_buf {
- struct INP_i_buf *ib_next;
- char ib_text[INP_BUFSIZE+INP_NPUSHBACK];
- };
- #endif /* not INP_READ_IN_ONE */
- char *_ipp;
- INP_PRIVATE struct INP_buffer_header *INP_head, *INP_free;
- #ifdef INP_READ_IN_ONE
- /* INP_rdfile() 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.
- */
- INP_PRIVATE int
- INP_rdfile(fd, fn, size, pbuf)
- register File *fd;
- char *fn; /* file name */
- register long *size;
- char **pbuf; /* output parameter */
- {
- extern long sys_filesize();
- int rsize;
- if (
- (*size = sys_filesize(fn)) < 0
- ||
- ((unsigned) (*size + 1) != (*size + 1))
- ||
- !(*pbuf = malloc((unsigned) (*size + 1)))) {
- return 0;
- }
- if (
- !sys_read(fd, *pbuf, (int) *size, &rsize)
- ||
- *size != rsize
- ) {
- free(*pbuf);
- return 0;
- }
- (*pbuf)[rsize] = '\0'; /* invoke loadbuf() at end */
- return 1;
- }
- #endif /* INP_READ_IN_ONE */
- #ifndef INP_READ_IN_ONE
- /* Input buffer supplying routines: INP_pbuf()
- */
- INP_PRIVATE struct INP_i_buf *i_ptr;
- INP_PRIVATE char *
- INP_pbuf()
- {
- register struct INP_i_buf *ib =
- (struct INP_i_buf *) malloc(sizeof(struct INP_i_buf));
- if (!ib) return 0;
- ib->ib_next = i_ptr;
- i_ptr = ib;
- /* Don't give him all of it, we need some to implement a good
- PushBack
- */
- return &(ib->ib_text[INP_NPUSHBACK-1]);
- }
- #endif /* not INP_READ_IN_ONE */
- /* Input buffer administration: INP_push_bh() and INP_pop_bh()
- */
- INP_PRIVATE struct INP_buffer_header *
- INP_push_bh()
- {
- register struct INP_buffer_header *bh;
- if (bh = INP_head) {
- bh->bh_ipp = _ipp;
- #ifdef INP_TYPE
- bh->bh_i = INP_VAR;
- #endif /* INP_TYPE */
- }
- bh = INP_free;
- if (bh) INP_free = bh->bh_next;
- else if (!(bh = (struct INP_buffer_header *)malloc(sizeof(struct INP_buffer_header)))) return 0;
- bh->bh_next = INP_head;
- bh->bh_eofreturned = 0;
- INP_head = bh;
- return bh;
- }
- /* INP_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.
- */
- INP_PRIVATE int
- INP_pop_bh()
- {
- register struct INP_buffer_header *bh = INP_head;
- bh = bh->bh_next;
- INP_head->bh_next = INP_free;
- INP_free = INP_head;
- INP_head = bh;
- if (!bh) { /* no more entries */
- INP_head = (struct INP_buffer_header *) 0;
- return 0;
- }
- _ipp = bh->bh_ipp; /* restore previous input pointer */
- #ifdef INP_TYPE
- INP_VAR = bh->bh_i;
- #endif /* INP_TYPE */
- return 1;
- }
- #ifndef INP_READ_IN_ONE
- /* low level I/O routine : read one block from current input
- stream : INP_rdblock
- */
- INP_PRIVATE int
- INP_rdblock(fd, buf, n)
- File *fd;
- char buf[];
- int *n;
- {
- if (!sys_read(fd, buf, INP_BUFSIZE, n)) {
- return 0;
- }
- buf[*n] = '\0';
- return 1;
- }
- #endif /* not INP_READ_IN_ONE */
- /* Miscellaneous routines :
- INP_mk_filename()
- */
- /* INP_mk_filename() concatenates a dir and filename.
- */
- INP_PRIVATE int
- INP_mk_filename(dir, file, newname)
- register char *dir, *file;
- char **newname;
- {
- register char *dst;
- dst = malloc((unsigned) (strlen(dir) + strlen(file) + 2));
- if (!dst) return 0;
- *newname = dst;
- if (*dir) {
- while (*dst++ = *dir++) ;
- *(dst-1) = '/';
- }
- while (*dst++ = *file++);
- return 1;
- }
- /* Interface routines : InsertFile, InsertText, and loadbuf
- */
- int
- InsertFile(filnam, table, result)
- char *filnam;
- char *table[];
- char **result;
- {
- char *newfn = 0;
- #ifdef INP_READ_IN_ONE
- char *text;
- long size;
- #endif /* INP_READ_IN_ONE */
- File *fd = 0;
- if (!filnam) fd = STDIN;
- else {
- if (table == 0 || filnam[0] == '/') {
- /* don't look in the table! */
- if (!sys_open(filnam, OP_READ, &fd)) return 0;
- }
- else {
- while (*table) {
- /* look in the directory table */
- if (!INP_mk_filename(*table++, filnam, &newfn)) {
- return 0;
- }
- if (sys_open(newfn, OP_READ, &fd)) {
- /* free filnam ??? NO we don't know
- where it comes from!
- */
- filnam = newfn;
- break;
- }
- free(newfn);
- newfn = 0;
- }
- }
- }
- if (fd) {
- register struct INP_buffer_header *bh = INP_push_bh();
- if (!bh) {
- if (fd != STDIN) sys_close(fd);
- return 0;
- }
- #ifdef INP_READ_IN_ONE
- if (fd == STDIN) return 0; /* illegal */
- if (!INP_rdfile(fd, filnam, &size, &text)) {
- sys_close(fd);
- return 0;
- }
- bh->bh_size = size;
- _ipp = bh->bh_text = text;
- #else /* not INP_READ_IN_ONE */
- if (
- !(_ipp = bh->bh_text = INP_pbuf())
- ||
- !INP_rdblock(fd,_ipp,&(bh->bh_size))) {
- if (fd != STDIN) sys_close(fd);
- return 0;
- }
- #endif /* INP_READ_IN_ONE */
- bh->bh_fd = fd; /* this is a file */
- if (result) *result = filnam;
- return 1;
- }
- return 0;
- }
- int
- InsertText(text, length)
- char *text;
- {
- register struct INP_buffer_header *bh = INP_push_bh();
- if (!bh) return 0;
- bh->bh_size = (long) length;
- _ipp = bh->bh_text = text;
- bh->bh_fd = 0; /* No file! */
- return 1;
- }
- /* 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.
- */
- int
- loadbuf()
- {
- register struct INP_buffer_header *bh = INP_head;
- static char buf[INP_NPUSHBACK + 1];
- int FromFile;
- if (!bh) { /* stack exhausted, EOF on sourcefile */
- return EOI;
- }
- if (_ipp < &(bh->bh_text[bh->bh_size])) {
- /* a genuine '\0' character has been seen */
- return '\0';
- }
- if (!bh->bh_eofreturned) {
- FromFile = (bh->bh_fd != 0);
- #ifndef INP_READ_IN_ONE
- if (FromFile && bh->bh_size > 0) {
- #if INP_NPUSHBACK > 1
- register char *so = &(bh->bh_text[bh->bh_size]);
- register char *de = bh->bh_text;
- register int i = INP_NPUSHBACK - 1;
- while (i-- > 0) {
- /* make sure PushBack will work */
- *--de = *--so;
- }
- #endif
- if ( INP_rdblock(bh->bh_fd, bh->bh_text, &(bh->bh_size))
- &&
- bh->bh_size > 0
- ) {
- _ipp = bh->bh_text;
- return *_ipp++;
- }
- }
- #endif /* not INP_READ_IN_ONE */
- if (FromFile && bh->bh_fd != STDIN) sys_close(bh->bh_fd);
- #if INP_NPUSHBACK > 1
- {
- register char *so = &(bh->bh_text[bh->bh_size]);
- register char *de = &buf[INP_NPUSHBACK - 1];
- register int i = INP_NPUSHBACK - 1;
- for (;i > 0; i--) {
- /* make sure PushBack will work */
- *--de = *--so;
- }
- }
- #endif
- buf[INP_NPUSHBACK-1] = 0; /* make PushBack work on EOI */
- _ipp = &buf[INP_NPUSHBACK];
- if (bh->bh_fd) { /* unstack a file */
- #ifndef INP_READ_IN_ONE
- struct INP_i_buf *ib;
- ib = i_ptr->ib_next;
- free((char *) i_ptr);
- i_ptr = ib;
- #else /* INP_READ_IN_ONE */
- free(bh->bh_text);
- #endif /* INP_READ_IN_ONE */
- }
- bh->bh_text = buf;
- bh->bh_size = INP_NPUSHBACK - 1;
- if (FromFile) {
- if (AtEoIF()) {
- bh->bh_eofreturned = 1;
- return EOI;
- }
- }
- else {
- if (AtEoIT()) {
- bh->bh_eofreturned = 1;
- return EOI;
- }
- }
- }
- if (bh->bh_eofreturned && _ipp == &buf[INP_NPUSHBACK]) {
- return EOI;
- }
- if (INP_pop_bh()) {
- int c;
- LoadChar(c);
- return c;
- }
- _ipp = &buf[INP_NPUSHBACK];
- return EOI;
- }
|