diff --git a/modules/src/em_mes/C_ms_com.c b/modules/src/em_mes/C_ms_com.c new file mode 100644 index 000000000..050d32c3c --- /dev/null +++ b/modules/src/em_mes/C_ms_com.c @@ -0,0 +1,9 @@ +#include +#include + +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 index 000000000..acd27c5f2 --- /dev/null +++ b/modules/src/em_mes/C_ms_ego.c @@ -0,0 +1,14 @@ +#include +#include + +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 index 000000000..f585bd29e --- /dev/null +++ b/modules/src/em_mes/C_ms_emx.c @@ -0,0 +1,11 @@ +#include +#include + +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 index 000000000..037e78ac8 --- /dev/null +++ b/modules/src/em_mes/C_ms_err.c @@ -0,0 +1,8 @@ +#include +#include + +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 index 000000000..4d63a8205 --- /dev/null +++ b/modules/src/em_mes/C_ms_flt.c @@ -0,0 +1,8 @@ +#include +#include + +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 index 000000000..d169cc1c2 --- /dev/null +++ b/modules/src/em_mes/C_ms_gto.c @@ -0,0 +1,8 @@ +#include +#include + +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 index 000000000..097c2747c --- /dev/null +++ b/modules/src/em_mes/C_ms_opt.c @@ -0,0 +1,8 @@ +#include +#include + +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 index 000000000..09e1640af --- /dev/null +++ b/modules/src/em_mes/C_ms_par.c @@ -0,0 +1,10 @@ +#include +#include + +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 index 000000000..9da6068c3 --- /dev/null +++ b/modules/src/em_mes/C_ms_reg.c @@ -0,0 +1,14 @@ +#include +#include + +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 index 000000000..fb31239d9 --- /dev/null +++ b/modules/src/em_mes/C_ms_src.c @@ -0,0 +1,12 @@ +#include +#include + +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 index 000000000..35630d82d --- /dev/null +++ b/modules/src/em_mes/em_mes.3 @@ -0,0 +1,146 @@ +.TH EM_MES 3ACK "86/03/18" +.SH NAME +em_mes \- EM-message generating routines +.SH SYNOPSIS +.nf +.B #include +.PP +.B C_ms_err() +.PP +.B C_ms_opt() +.PP +.B C_ms_emx(wsiz, psiz) +.B arith wsiz, psiz; +.PP +.B #include +.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 +.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 diff --git a/modules/src/idf/Makefile b/modules/src/idf/Makefile new file mode 100644 index 000000000..9725feeb9 --- /dev/null +++ b/modules/src/idf/Makefile @@ -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 index 000000000..eb2ff5fba --- /dev/null +++ b/modules/src/idf/idf.3 @@ -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 +.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 +.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 index 000000000..3fd6757a6 --- /dev/null +++ b/modules/src/idf/idf_pkg.body @@ -0,0 +1,159 @@ +/* SYMBOL TABLE HANDLING */ + +#include + +/* 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; + } +} diff --git a/modules/src/idf/idf_pkg.spec b/modules/src/idf/idf_pkg.spec new file mode 100644 index 000000000..95e661150 --- /dev/null +++ b/modules/src/idf/idf_pkg.spec @@ -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 index 000000000..7136fcf20 --- /dev/null +++ b/modules/src/input/AtEoIF.c @@ -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 index 000000000..ceabdebb8 --- /dev/null +++ b/modules/src/input/AtEoIT.c @@ -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 index 000000000..c0d519f01 --- /dev/null +++ b/modules/src/input/inp_pkg.body @@ -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 +#include + +#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 index 000000000..69c2248e6 --- /dev/null +++ b/modules/src/input/inp_pkg.spec @@ -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 index 000000000..82a6f452c --- /dev/null +++ b/modules/src/input/input.3 @@ -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 +.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 +.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 ...