Initial revision
authorceriel <none@none>
Mon, 5 Jan 1987 17:20:13 +0000 (17:20 +0000)
committerceriel <none@none>
Mon, 5 Jan 1987 17:20:13 +0000 (17:20 +0000)
20 files changed:
modules/src/em_mes/C_ms_com.c [new file with mode: 0644]
modules/src/em_mes/C_ms_ego.c [new file with mode: 0644]
modules/src/em_mes/C_ms_emx.c [new file with mode: 0644]
modules/src/em_mes/C_ms_err.c [new file with mode: 0644]
modules/src/em_mes/C_ms_flt.c [new file with mode: 0644]
modules/src/em_mes/C_ms_gto.c [new file with mode: 0644]
modules/src/em_mes/C_ms_opt.c [new file with mode: 0644]
modules/src/em_mes/C_ms_par.c [new file with mode: 0644]
modules/src/em_mes/C_ms_reg.c [new file with mode: 0644]
modules/src/em_mes/C_ms_src.c [new file with mode: 0644]
modules/src/em_mes/em_mes.3 [new file with mode: 0644]
modules/src/idf/Makefile [new file with mode: 0644]
modules/src/idf/idf.3 [new file with mode: 0644]
modules/src/idf/idf_pkg.body [new file with mode: 0644]
modules/src/idf/idf_pkg.spec [new file with mode: 0644]
modules/src/input/AtEoIF.c [new file with mode: 0644]
modules/src/input/AtEoIT.c [new file with mode: 0644]
modules/src/input/inp_pkg.body [new file with mode: 0644]
modules/src/input/inp_pkg.spec [new file with mode: 0644]
modules/src/input/input.3 [new file with mode: 0644]

diff --git a/modules/src/em_mes/C_ms_com.c b/modules/src/em_mes/C_ms_com.c
new file mode 100644 (file)
index 0000000..050d32c
--- /dev/null
@@ -0,0 +1,9 @@
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_com(str)
+       char *str;
+{
+       C_mes_begin(ms_com);
+       C_mes_end();
+}
diff --git a/modules/src/em_mes/C_ms_ego.c b/modules/src/em_mes/C_ms_ego.c
new file mode 100644 (file)
index 0000000..acd27c5
--- /dev/null
@@ -0,0 +1,14 @@
+#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();
+}
diff --git a/modules/src/em_mes/C_ms_emx.c b/modules/src/em_mes/C_ms_emx.c
new file mode 100644 (file)
index 0000000..f585bd2
--- /dev/null
@@ -0,0 +1,11 @@
+#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();
+}
diff --git a/modules/src/em_mes/C_ms_err.c b/modules/src/em_mes/C_ms_err.c
new file mode 100644 (file)
index 0000000..037e78a
--- /dev/null
@@ -0,0 +1,8 @@
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_err()
+{
+       C_mes_begin(ms_err);
+       C_mes_end();
+}
diff --git a/modules/src/em_mes/C_ms_flt.c b/modules/src/em_mes/C_ms_flt.c
new file mode 100644 (file)
index 0000000..4d63a82
--- /dev/null
@@ -0,0 +1,8 @@
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_flt()
+{
+       C_mes_begin(ms_flt);
+       C_mes_end();
+}
diff --git a/modules/src/em_mes/C_ms_gto.c b/modules/src/em_mes/C_ms_gto.c
new file mode 100644 (file)
index 0000000..d169cc1
--- /dev/null
@@ -0,0 +1,8 @@
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_gto()
+{
+       C_mes_begin(ms_gto);
+       C_mes_end();
+}
diff --git a/modules/src/em_mes/C_ms_opt.c b/modules/src/em_mes/C_ms_opt.c
new file mode 100644 (file)
index 0000000..097c274
--- /dev/null
@@ -0,0 +1,8 @@
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_opt()
+{
+       C_mes_begin(ms_opt);
+       C_mes_end();
+}
diff --git a/modules/src/em_mes/C_ms_par.c b/modules/src/em_mes/C_ms_par.c
new file mode 100644 (file)
index 0000000..09e1640
--- /dev/null
@@ -0,0 +1,10 @@
+#include <em.h>
+#include <em_mes.h>
+
+C_ms_par(nparams)
+       arith nparams;
+{
+       C_mes_begin(ms_par);
+       C_cst(nparams);
+       C_mes_end();
+}
diff --git a/modules/src/em_mes/C_ms_reg.c b/modules/src/em_mes/C_ms_reg.c
new file mode 100644 (file)
index 0000000..9da6068
--- /dev/null
@@ -0,0 +1,14 @@
+#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();
+}
diff --git a/modules/src/em_mes/C_ms_src.c b/modules/src/em_mes/C_ms_src.c
new file mode 100644 (file)
index 0000000..fb31239
--- /dev/null
@@ -0,0 +1,12 @@
+#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();
+}
diff --git a/modules/src/em_mes/em_mes.3 b/modules/src/em_mes/em_mes.3
new file mode 100644 (file)
index 0000000..35630d8
--- /dev/null
@@ -0,0 +1,146 @@
+.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>
diff --git a/modules/src/idf/Makefile b/modules/src/idf/Makefile
new file mode 100644 (file)
index 0000000..9725fee
--- /dev/null
@@ -0,0 +1,17 @@
+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:
diff --git a/modules/src/idf/idf.3 b/modules/src/idf/idf.3
new file mode 100644 (file)
index 0000000..eb2ff5f
--- /dev/null
@@ -0,0 +1,88 @@
+.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.
diff --git a/modules/src/idf/idf_pkg.body b/modules/src/idf/idf_pkg.body
new file mode 100644 (file)
index 0000000..3fd6757
--- /dev/null
@@ -0,0 +1,159 @@
+/*     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 = &notch->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;
+       }
+}
diff --git a/modules/src/idf/idf_pkg.spec b/modules/src/idf/idf_pkg.spec
new file mode 100644 (file)
index 0000000..95e6611
--- /dev/null
@@ -0,0 +1,42 @@
+/* $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)
diff --git a/modules/src/input/AtEoIF.c b/modules/src/input/AtEoIF.c
new file mode 100644 (file)
index 0000000..7136fcf
--- /dev/null
@@ -0,0 +1,10 @@
+/* $Header$ */
+
+/*     AtEoIF : a routine doing nothing. It is called at the end of an
+       inserted file.
+*/
+int
+AtEoIF()
+{
+       return 0;
+}
diff --git a/modules/src/input/AtEoIT.c b/modules/src/input/AtEoIT.c
new file mode 100644 (file)
index 0000000..ceabdeb
--- /dev/null
@@ -0,0 +1,10 @@
+/* $Header$ */
+
+/*     AtEoIT : a routine doing nothing. It is called at the end of an
+       inserted text.
+*/
+int
+AtEoIT()
+{
+       return 0;
+}
diff --git a/modules/src/input/inp_pkg.body b/modules/src/input/inp_pkg.body
new file mode 100644 (file)
index 0000000..c0d519f
--- /dev/null
@@ -0,0 +1,413 @@
+/*     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;
+}
diff --git a/modules/src/input/inp_pkg.spec b/modules/src/input/inp_pkg.spec
new file mode 100644 (file)
index 0000000..69c2248
--- /dev/null
@@ -0,0 +1,53 @@
+/*     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();
diff --git a/modules/src/input/input.3 b/modules/src/input/input.3
new file mode 100644 (file)
index 0000000..82a6f45
--- /dev/null
@@ -0,0 +1,140 @@
+.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 ...