--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_com(str)
+ char *str;
+{
+ C_mes_begin(ms_com);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_ego(hint, offs, siz, regno)
+ int hint, regno;
+ arith offs, siz;
+{
+ C_mes_begin(ms_ego);
+ C_cst((arith)hint);
+ C_cst(offs);
+ C_cst(siz);
+ C_cst((arith)regno);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_emx(wsiz, psiz)
+ arith wsiz, psiz;
+{
+ C_mes_begin(ms_emx);
+ C_cst(wsiz);
+ C_cst(psiz);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_err()
+{
+ C_mes_begin(ms_err);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_flt()
+{
+ C_mes_begin(ms_flt);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_gto()
+{
+ C_mes_begin(ms_gto);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_opt()
+{
+ C_mes_begin(ms_opt);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_par(nparams)
+ arith nparams;
+{
+ C_mes_begin(ms_par);
+ C_cst(nparams);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_reg(offs, siz, class, prior)
+ arith offs, siz;
+ int class, prior;
+{
+ C_mes_begin(ms_reg);
+ C_cst(offs);
+ C_cst(siz);
+ C_cst((arith)class);
+ C_cst((arith)prior);
+ C_mes_end();
+}
--- /dev/null
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_src(nlines, filnam)
+ int nlines;
+ char *filnam;
+{
+ C_mes_begin(ms_src);
+ C_cst((arith)nlines);
+ C_scon(filnam, strlen(filnam) + 1);
+ C_mes_end();
+}
--- /dev/null
+.TH EM_MES 3ACK "86/03/18"
+.SH NAME
+em_mes \- EM-message generating routines
+.SH SYNOPSIS
+.nf
+.B #include <em.h>
+.PP
+.B C_ms_err()
+.PP
+.B C_ms_opt()
+.PP
+.B C_ms_emx(wsiz, psiz)
+.B arith wsiz, psiz;
+.PP
+.B #include <em_reg.h>
+.B C_ms_reg(offs, siz, class, prior)
+.B arith offs, siz;
+.B int class, prior;
+.PP
+.B C_ms_src(nlines, filnam)
+.B int nlines;
+.B char *filnam;
+.PP
+.B C_ms_flt()
+.PP
+.B C_ms_com(str)
+.B char *str;
+.PP
+.B C_ms_par(nparams)
+.B arith nparams;
+.PP
+.B #include <em_ego.h>
+.B C_ms_ego(hint, offs, siz, regno)
+.B int hint, regno;
+.B arith offs, siz;
+.PP
+.B C_ms_gto()
+.fi
+.SH DESCRIPTION
+This set of routines forms a front end for the
+.IR em_code (3L)
+module.
+The philosophy behind this package is to provide a single routine for
+each type of EM message that is generated by a front-end compiler.
+Each routine internally builds a message instruction by using the
+.BR C_mes_begin ,
+.B C_mes_end
+and the
+.BI C_ cstp
+routines from the
+.I em_code
+module.
+The actions taken by these functions depend on the type of
+.I em_code
+module that is loaded together with this module.
+The routines described here do not prevent the user from directly
+composing EM messages himself.
+.PP
+.BR C_ms_err ()
+generates a message that indicates some error during the compilation.
+.PP
+.BR C_ms_opt ()
+causes any optimization to be suppressed.
+.PP
+.BR C_ms_emx ()
+indicates the wordsize
+.I wsiz
+and pointersize
+.IR psiz .
+This must be the first code generated, or the generated code is illegal.
+.PP
+.BR C_ms_reg ()
+can be used to indicate that a local variable, having offset
+.I offs
+and size (in bytes)
+.IR siz ,
+may be stored in a register.
+.I Class
+indicates the use of the variable.
+The following classes are allowed (the names are defined in em_reg.h):
+.RS
+.IP reg_any 12
+no specific type
+.IP reg_loop 12
+loop control variable
+.IP reg_pointer 12
+pointer variable
+.IP reg_float 12
+floating point variable
+.LP
+.RE
+.I Prior
+is taken to be the priority of the variable; higher numbers indicate
+better candidates.
+.PP
+.BR C_ms_src ()
+produces an indication of the number of source lines,
+.IR nlines ,
+in file
+.IR filnam .
+This information can be used by a profiler.
+.PP
+.BR C_ms_flt ()
+produces an indication that floating-point operations are used.
+.PP
+.BR C_ms_com ()
+causes the string
+.I str
+to be inserted as comment in the resulting output.
+Note that this routine does not provide the full semantics of EM in this
+area, but the user himself can build a comment message with other types
+of comment if he likes.
+.PP
+.BR C_ms_par ()
+produces an indication that no more than
+.I nbytes
+of parameters are accessed, either directly or indirectly.
+.PP
+.BR C_ms_ego ()
+produces a hint from the EM global optimizer.
+The parameters needed are conform to the format of the message.
+.PP
+.BR C_ms_gto ()
+can be invoked to indicate that a procedure uses a non-local goto.
+.SH FILES
+.nf
+~em/modules/h/em.h
+~em/h/em_reg.h
+~em/h/em_ego.h
+~em/modules/lib/libem_mes.a
+.fi
+.SH MODULES
+em_code(3)
+.SH SEE ALSO
+em_code(3), read_em(3)
+.SH DIAGNOSTICS
+None of the functions return a value.
+.SH BUGS
+The
+.BR C_ms_ext ()
+routine has not yet been implemented, since this message uses
+a variable number of arguments.
+.PP
+Please report other bugs to the author.
+.SH AUTHOR
+Erik Baalbergen <erikb@vu44.UUCP>
--- /dev/null
+EMHOME = ../../..
+INSTALL = $(EMHOME)/modules/install
+COMPARE = $(EMHOME)/modules/compare
+
+all:
+
+install: all
+ $(INSTALL) pkg/idf_pkg.body
+ $(INSTALL) pkg/idf_pkg.spec
+ $(INSTALL) man/idf.3
+
+cmp: all
+ $(COMPARE) pkg/idf_pkg.body
+ $(COMPARE) pkg/idf_pkg.spec
+ $(COMPARE) man/idf.3
+
+clean:
--- /dev/null
+.TH IDF 3ACK "March 17, 1986"
+.UC
+.SH NAME
+init_idf, str2idf\ \-\ a namelist module
+.SH SYNOPSIS
+.PP
+.B init_idf()
+.PP
+.B struct idf *str2idf(tag, cpy)
+.br
+.B char *tag;
+.PP
+.B struct idf *findidf(tag)
+.br
+.B char *tag;
+.SH DESCRIPTION
+This is a generic namelist module. It provides a fast mechanism for
+associating information with identifiers. To get an instantiation, the
+user must provide two files \fIidf.h\fR and \fIidf.c\fR.
+\fIidf.h\fR could contain the following:
+.br
+.PP
+.RS
+.nf
+#define IDF_TYPE struct id_info
+#define IDF_HSIZE 8
+
+#include <idf_pkg.spec>
+.fi
+.RE
+.PP
+and \fIidf.c\fR could contain:
+.br
+.PP
+.RS
+.nf
+#include "id_info.h" /* contains definition for struct id_info */
+#include "idf.h"
+#include <idf_pkg.body>
+.fi
+.RE
+.PP
+IDF_TYPE denotes a type containing all information associated with
+an identifier. If it is not defined, the instantiation will not contain
+any user-defined information.
+.PP
+IDF_HSIZE denotes the number of significant characters for the hashing
+function. It's default value is 64. Notice that this value does \fBnot\fP
+denote the number of significant characters, but only the number of characters
+that are used for hashing.
+.PP
+The user can also define IDF_NAME, to give a name to the selector in the
+idf-structure. It's default value is \fIid_user\fP.
+.PP
+The routine \fIinit_idf\fR initializes the namelist.
+.PP
+The function
+\fIstr2idf\fR searches for the string \fItag\fR in the namelist, and
+creates an entry for it if necessary. A pointer to this entry is
+returned. If \fIcpy\fR is non-zero, a copy of the \fItag\fR is made,
+otherwise the \fItag\fR itself is used.
+The entry has the following structure, defined in \fIinp_pkg.spec\fR:
+.PP
+.nf
+struct idf {
+ struct idf *next; \kx/* links idf-structures together */
+ char *id_text;\h'|\nxu'/* string representing the name */
+#ifdef IDF_TYPE
+ IDF_TYPE IDF_NAME;\h'|\nxu'/* user defined type */
+#endif
+};
+.fi
+.PP
+The field \fIid_text\fR will point to a copy of \fItag\fR, or
+to the \fItag\fR itself, depending on \fIcpy\fR.
+The field \fInext\fR is used for internal information and must not
+be changed by the user of this module.
+.PP
+The function \fIfindidf\fP searches for the string \fItag\fP in the
+namelist, but returns 0 when it is'nt present.
+.SH "MODULES USED"
+alloc(3)
+.SH FILES
+~em/modules/pkg/idf_pkg.spec
+.br
+~em/modules/pkg/idf_pkg.body
+.SH DIAGNOSTICS
+\fIstr2idf\fP returns a null pointer if there is no memory available.
--- /dev/null
+/* SYMBOL TABLE HANDLING */
+
+#include <alloc.h>
+
+/* Each character of the identifier is xored with an 8-bit mask which
+ depends on the position of the character; the sum of these results
+ is the hash value. The random masks are obtained from a
+ congruence generator.
+*/
+
+#define HASHSIZE 256 /* size of hashtable, must be a power of 2 */
+#ifndef IDF_HSIZE
+#define IDF_HSIZE 64 /* # of significant characters for hashing.
+ This is NOT the number of significant
+ characters!
+ */
+#endif
+#define HASH_X 0253 /* Knuth's X */
+#define HASH_A 77 /* Knuth's a */
+#define HASH_C 153 /* Knuth's c */
+
+#define HASHMASK (HASHSIZE-1) /* since it is a power of 2 */
+#define STARTHASH() (0)
+#define ENHASH(hs,ch,hm) (hs + (ch ^ hm))
+#define STOPHASH(hs) (hs & HASHMASK)
+
+static char hmask[IDF_HSIZE];
+
+static struct idf *id_hashtable[HASHSIZE];
+ /* All identifiers can in principle be reached through
+ id_hashtable; id_hashtable[hc] is the start of a chain of
+ idf's whose tags all hash to hc.
+ Any identifier is entered into this
+ list, regardless of the nature of its declaration
+ (variable, selector, structure tag, etc.).
+ */
+
+static struct idf *
+new_idf(tg, size, cpy)
+ register char *tg;
+ register int size;
+{
+ static int nidf;
+ static struct idf *pidf;
+#define NIDS 50
+#define IBUFSIZ 2048
+ static unsigned int icnt;
+ static char *ip;
+ register char *p;
+
+
+ if (! nidf--) {
+ nidf += NIDS;
+ pidf = (struct idf *) Malloc(NIDS * sizeof (struct idf));
+ clear((char *) pidf, NIDS * sizeof(struct idf));
+ }
+
+ if (cpy) {
+ if (size > icnt) {
+ icnt = size > IBUFSIZ ? size : IBUFSIZ;
+ p = Malloc(icnt);
+ }
+ else p = ip;
+ icnt -= size;
+ pidf->id_text = p;
+ while (size--) {
+ *p++ = *tg++;
+ }
+ ip = p;
+ }
+ else pidf->id_text = tg;
+ return pidf++;
+}
+
+#ifdef DEBUG
+hash_stat()
+{
+ register int i;
+
+ print("Hash table tally:\n");
+ for (i = 0; i < HASHSIZE; i++) {
+ register struct idf *notch = id_hashtable[i];
+ register int cnt = 0;
+
+ while (notch) {
+ cnt++;
+ notch = notch->next;
+ }
+ print("%d %d\n", i, cnt);
+ }
+ print("End hash table tally\n");
+}
+#endif DEBUG
+
+struct idf *
+str2idf(tg, cpy)
+ char tg[];
+{
+ /* str2idf() returns an entry in the symbol table for the
+ identifier tg. If necessary, an entry is created.
+ */
+ register char *cp = tg;
+ register char *phm = &hmask[0];
+ struct idf **hook;
+ register struct idf *notch;
+ register int hash;
+ int size;
+
+ hash = STARTHASH();
+ while (*cp && phm < &hmask[IDF_HSIZE]) {
+ hash = ENHASH(hash, *cp++, *phm++);
+ }
+ hash = STOPHASH(hash);
+ while (*cp++) /* nothing. Find end of string */ ;
+ size = cp - tg;
+
+ /* The tag tg with length size and known hash value hash is
+ looked up in the identifier table; if not found, it is
+ entered if cpy >= 0. A pointer to it is returned.
+ Notice that the chains of idf's are sorted alphabetically.
+ */
+ hook = &id_hashtable[hash];
+
+ while ((notch = *hook)) {
+ register char *s1 = tg;
+ int cmp;
+
+ cp = notch->id_text;
+
+ while (!(cmp = (*s1 - *cp++))) {
+ if (*s1++ == '\0') {
+ break;
+ }
+ }
+
+ if (cmp == 0) return notch;
+ if (cmp < 0) break;
+ hook = ¬ch->next;
+ }
+ /* a new struct idf must be inserted at the hook */
+ if (cpy < 0) return 0;
+ notch = new_idf(tg, size, cpy);
+ notch->next = *hook;
+ *hook = notch; /* hooked in */
+ return notch;
+}
+
+init_idf() {
+ /* A simple congruence random number generator, as
+ described in Knuth, vol 2.
+ */
+ int rnd = HASH_X;
+ register char *phm;
+
+ for (phm = &hmask[0]; phm < &hmask[IDF_HSIZE];) {
+ *phm++ = rnd;
+ rnd = (HASH_A * rnd + HASH_C) & HASHMASK;
+ }
+}
--- /dev/null
+/* $Header$ */
+/* IDENTIFIER DESCRIPTOR */
+
+/* This a generic package for maintaining a name list */
+
+/* Instantiation parameters, supplied by #define, are :
+ IDF_TYPE: the type of the user-defined part of the idf-structure,
+ IDF_NAME: the selector name for this field in the idf_structure, and
+ IDF_HSIZE: the number of significant characters for hashing
+*/
+
+#ifndef IDF_NAME
+#define IDF_NAME id_user
+#endif
+
+struct idf {
+ struct idf *next; /* links idf-structures together */
+ char *id_text; /* string representing the name */
+#ifdef IDF_TYPE
+ IDF_TYPE IDF_NAME; /* user defined type and selector */
+#endif
+};
+
+/* init_idf()
+
+ Initializes the namelist
+*/
+extern init_idf();
+
+/* struct idf * str2idf(tg, cp)
+ char *tg;
+ int cp;
+
+ Adds the string indicated by "tg" to the namelist, and returns a
+ pointer to the entry.
+ If cp > 0, a copy of tg is made for id_text, otherwise tg itself
+ is used.
+ If cp < 0, the string is not entered, but only looked for.
+*/
+extern struct idf * str2idf();
+
+#define findidf(tg) str2idf(tg, -1)
--- /dev/null
+/* $Header$ */
+
+/* AtEoIF : a routine doing nothing. It is called at the end of an
+ inserted file.
+*/
+int
+AtEoIF()
+{
+ return 0;
+}
--- /dev/null
+/* $Header$ */
+
+/* AtEoIT : a routine doing nothing. It is called at the end of an
+ inserted text.
+*/
+int
+AtEoIT()
+{
+ return 0;
+}
--- /dev/null
+/* 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 PRIVATE
+#else
+#define PRIVATE static
+#endif
+
+struct buffer_header {
+ struct buffer_header *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 i_buf {
+ struct i_buf *next;
+ char ib_text[INP_BUFSIZE+INP_NPUSHBACK-1];
+};
+
+# endif not INP_READ_IN_ONE
+
+char *_ipp;
+PRIVATE struct buffer_header *head;
+
+#ifdef INP_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.
+*/
+
+PRIVATE int
+readfile(fd, fn, size, pbuf)
+ register File *fd;
+ char *fn; /* file name */
+ register long *size;
+ extern long sys_filesize();
+ char **pbuf; /* output parameter */
+{
+ int rsize;
+
+ if (
+ (*size = sys_filesize(fn)) < 0
+ ||
+ ((unsigned) (*size + 1) != (*size + 1))
+ ||
+ !(*pbuf = malloc((unsigned) (*size + 1)))) {
+ sys_close(fd);
+ return 0;
+ }
+ if (
+ !sys_read(fd, *pbuf, (int) *size, &rsize)
+ ||
+ *size != rsize
+ ) {
+ sys_close(fd);
+ free(*pbuf);
+ return 0;
+ }
+ sys_close(fd);
+ (*pbuf)[*size] = '\0'; /* invoke loadbuf() at end */
+ return 1;
+}
+#endif INP_READ_IN_ONE
+
+#ifndef INP_READ_IN_ONE
+/* Input buffer supplying routines: pushbuf()
+*/
+
+PRIVATE struct i_buf *i_ptr;
+
+PRIVATE char *
+pushbuf()
+{
+ register struct i_buf *ib =
+ (struct i_buf *) malloc(sizeof(struct i_buf));
+
+ if (!ib) return 0;
+ 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: push_bh() and pop_bh()
+*/
+PRIVATE struct buffer_header *
+push_bh()
+{
+ register struct buffer_header *bh;
+
+ if (bh = head) {
+ bh->bh_ipp = _ipp;
+#ifdef INP_TYPE
+ bh->bh_i = INP_VAR;
+#endif INP_TYPE
+ }
+ if (!(bh = (struct buffer_header *)malloc(sizeof(struct buffer_header)))) return 0;
+ bh->next = head;
+ bh->bh_eofreturned = 0;
+ head = bh;
+ return bh;
+}
+
+/* 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()
+{
+ register struct buffer_header *bh = head;
+
+ if (bh->bh_fd) { /* unstack a file */
+#ifndef INP_READ_IN_ONE
+ struct i_buf *ib;
+
+ ib = i_ptr->next;
+ free((char *) i_ptr);
+ i_ptr = ib;
+#else INP_READ_IN_ONE
+ free(bh->bh_text);
+#endif INP_READ_IN_ONE
+ }
+
+ bh = bh->next;
+ free((char *) head);
+ head = bh;
+
+ if (!bh) { /* no more entries */
+ head = (struct 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 : readblock
+*/
+
+PRIVATE int
+readblock(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 :
+ mk_filename()
+*/
+
+/* mk_filename() concatenates a dir and filename.
+*/
+PRIVATE int
+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;
+ while (*dst++ = *dir++);
+ *--dst = '/';
+ 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 (!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) {
+ struct buffer_header *push_bh();
+ register struct buffer_header *bh = push_bh();
+
+ if (!bh) {
+ if (fd != STDIN) sys_close(fd);
+ return 0;
+ }
+#ifdef INP_READ_IN_ONE
+ if (fd == STDIN) return 0; /* illegal */
+ if (!readfile(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 = pushbuf())
+ ||
+ !readblock(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 */
+ *result = filnam;
+ return 1;
+ }
+ return 0;
+}
+
+int
+InsertText(text, length)
+ char *text;
+{
+ struct buffer_header *push_bh();
+ register struct buffer_header *bh = 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 buffer_header *bh = 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';
+ }
+
+ FromFile = (bh->bh_fd != 0);
+
+#ifndef INP_READ_IN_ONE
+ if (FromFile) {
+#if INP_PUSHBACK > 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 (
+ readblock(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 (!bh->bh_eofreturned) {
+ bh->bh_eofreturned = 1;
+ _ipp--;
+ if (FromFile) {
+ if (AtEoIF()) return EOI;
+ }
+ else {
+ if (AtEoIT()) return EOI;
+ }
+ }
+
+#ifndef INP_READ_IN_ONE
+ if (FromFile && bh->bh_fd != STDIN) sys_close(bh->bh_fd);
+#endif not INP_READ_IN_ONE
+
+ if (pop_bh()) {
+ if (*_ipp) return *_ipp++;
+ return loadbuf();
+ }
+ _ipp = &buf[INP_NPUSHBACK];
+ return EOI;
+}
--- /dev/null
+/* This is the specification of the generic part of the input package.
+ It can be instantiated by #defining or not #defining
+ INP_TYPE, INP_VAR, INP_READ_IN_ONE, and INP_NPUSHBACK.
+ INP_TYPE is the type of the variable INP_VAR, which contains
+ all values the user wants to save when an InsertFile is done,
+ and restored when an input stream is continued after a suspend.
+ For instance, line numbers and position within a line might
+ be interesting.
+ Not defining INP_TYPE has the effect that the instantiation is
+ done without saving and restoring INP_VAR.
+ Defining INP_READ_IN_ONE has the effect that files will be read
+ completely with one "read". Only use this if you have lots of
+ memory. Not defining it causes files to be read in blocks, with
+ a suitable blocksize.
+ INP_NPUSHBACK is the number of PushBacks that are guaranteed
+ to work. Its default value is 1.
+*/
+
+/* INPUT PRIMITIVES */
+
+#define LoadChar(dest) ((dest = *_ipp++) || (dest = loadbuf()))
+#define PushBack() (--_ipp)
+
+/* EOF may be defined as -1 in most programs but the character -1 may
+ be expanded to the int -1 which causes troubles at the indexing in
+ the class or boolean arrays.
+*/
+#define EOI (0200)
+
+extern char *_ipp;
+
+/* int InsertFile(filename, table, result)
+ char *filename;
+ char **table;
+ char **result;
+
+ This function suspends input from the current input stream. The next
+ characters are obtained from the file indicated by "filename". This file
+ will be looked for in the directories, mentioned in the null-terminated
+ list indicated by "table". It returns 1 if it succeeds, 0 if it fails.
+ "result" will contain the full path if InsertFile returns 1.
+*/
+extern int InsertFile();
+
+/* int InsertText(text, length)
+ char *text;
+ int length;
+ This funtion suspends input from the current input stream. The next
+ input characters are obtained from the string indicated by "text",
+ whose length is indicated by "length".
+ It returns 1 if it succeeds, 0 if it fails.
+*/
+extern int InsertText();
--- /dev/null
+.TH INPUT 3 "March 25, 1986"
+.SH NAME
+LoadChar, PushBack, InsertFile, InsertText, AtEoIF, AtEoIT\ \-\ input
+module for compilers
+.SH SYNOPSIS
+.B LoadChar(ch)
+.br
+.B int ch;
+.PP
+.B PushBack()
+.PP
+.B int InsertFile(filename, table, result)
+.br
+.B char *filename;
+.br
+.B char *table[];
+.br
+.B char **result;
+.PP
+.B int InsertText(text, length)
+.br
+.B char *text;
+.br
+.B int length;
+.PP
+.B int AtEoIF()
+.PP
+.B int AtEoIT()
+.SH DESCRIPTION
+This set of variables, macros and routines provides a fast input mechanism
+for use by compilers.
+They also provide a means of inserting new input streams,
+thereby temporarily suspending an input
+stream to read another one.
+The \fBcurrent input stream\fR is the last inserted input stream that
+has not reached its end.
+.PP
+The module is generic: it must be instantiated by #defining INP_TYPE,
+INP_VAR, INP_READ_IN_ONE, INP_BUFSIZE, and INP_NPUSHBACK.
+An instantiation can be obtained by creating two files: \fIinput.c\fR and
+\fIinput.h\fR.
+\fIinput.h\fR could contain the following:
+.PP
+.RS
+.nf
+#define INP_NPUSHBACK 2
+#define INP_TYPE struct f_info
+#define INP_VAR file_info
+#define INP_BUFSIZE 4096
+
+#include <inp_pkg.spec>
+.fi
+.RE
+.PP
+and \fIinput.c\fR could contain:
+.PP
+.RS
+.nf
+#include "f_info.h" /* contains definition for struct f_info */
+#include "input.h"
+#include <inp_pkg.body>
+.fi
+.RE
+.PP
+The user may associate certain data with each input stream. The input module
+has a facility to save these data when inserting a new input stream, and
+restoring them when restoring the suspended input stream. Examples of these
+data are for instance a linenumber, a filename, etc.
+These data must be collected in a variable INP_VAR of type INP_TYPE.
+INP_VAR and INP_TYPE must be preprocessor-#defined.
+Not #defining INP_TYPE has the effect that an instantiation will be created
+that does not save and restore these data.
+.PP
+INP_NPUSHBACK is the number of PushBacks that are guaranteed to work.
+Its default value is 1. It is expected to be small.
+.PP
+INP_READ_IN_ONE can either be defined or not defined. Defining it has the
+effect that files will be read completely with one read-system call. This
+should only be used on machines with lots of memory.
+.PP
+INP_BUFSIZE defines the input buffer size that is used when INP_READ_IN_ONE
+is not defined. Its default value is BUFSIZ, from the \fIsystem\fP(3) module.
+.PP
+The macro \fILoadChar\fR stores the next character from the current input stream
+in the variable \fIch\fR,
+which is passed as a parameter.
+Note that this simulates an output parameter!
+When the end of the current input stream is reached, the next character from
+the last suspended input stream will be stored, etc.
+If there are no suspended input streams left, the constant EOI,
+which is defined in \fIinp_pkg.spec\fR, is returned.
+.PP
+The macro \fIPushBack\fR pushes the last character read back onto the
+input stream.
+.PP
+The routine \fIInsertFile\fR suspends input from the current input stream.
+The next input characters will be obtained from the specified file
+\fIfilename\fR.
+This file will be looked for in the directories, mentioned in the
+null-terminated list \fItable\fR.
+If \fIfilename\fR is a null pointer, standard input is used. In this case,
+the package may not have been instantiated with INP_READ_IN_ONE defined.
+\fIInsertFile\fR returns 1 if it succeeds, 0 if it fails.
+When it succeeds, it stores the file name in the \fIresult\fR parameter.
+.PP
+The routine \fIInsertText\fR also suspends input from the current input stream.
+The next input characters will be obtained from the string \fItext\fR,
+which is \fIlength\fR characters long.
+\fIInsertText\fR returns 1 if it succeeds, 0 if it fails.
+.PP
+The routine \fIAtEoIF\fR is called at the end of the input stream
+inserted by \fIInsertFile\fR.
+If it returns 1, the LoadChar causing the call returns EOI, otherwize
+the LoadChar returns the next character of the suspended and now restored
+input stream.
+A default \fIAtEoIF\fR is provided. It does nothing, and returns 0,
+making the "unstacking" completely transparent.
+The user of the module can write his own if this is not what he wants.
+.PP
+The routine \fIAtEoIT\fR is called at the end of the string
+inserted by \fIInsertText\fR.
+If it returns 1, the LoadChar causing the call returns EOI, otherwise
+the LoadChar returns the next character of the suspended and now restored
+input stream.
+A default \fIAtEoIT\fR is provided. It does nothing, and returns 0,
+making the "unstacking" completely transparent.
+The user of the module can write his own if this is not what he wants.
+.SH FILES
+~em/modules/pkg/inp_pkg.spec
+.br
+~em/modules/pkg/inp_pkg.body
+.br
+~em/modules/lib/libinput.a
+.SH MODULES
+system(3), alloc(3)
+.SH "SEE ALSO"
+\fIGeneric Packages in C\fR by Dick Grune.
+.SH BUGS
+A \fILoadChar\fR-call does look like a function call,
+but behaves differently. All for the sake of speed of course ...