about summary refs log tree commit diff
path: root/Src/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/parse.c')
-rw-r--r--Src/parse.c657
1 files changed, 576 insertions, 81 deletions
diff --git a/Src/parse.c b/Src/parse.c
index df7671c5d..0b11668c2 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -131,10 +131,11 @@ struct heredocs *hdocs;
  *     - if (type == PIPE), followed by pipe
  *
  *   WC_FUNCDEF
- *     - data contains offset to after body-strings
+ *     - data contains offset to after body
  *     - followed by number of names
  *     - followed by names
- *     - followed by number of codes for body
+ *     - followed by offset to first string
+ *     - followed by length of string table
  *     - followed by number of patterns for body
  *     - follwoed by codes for body
  *     - followed by strings for body
@@ -230,28 +231,7 @@ Wordcode ecbuf;
 /**/
 Eccstr ecstrs;
 /**/
-int ecsoffs;
-
-/* Make at least n bytes free (aligned to sizeof(wordcode)). */
-
-static int
-ecspace(int n)
-{
-    n = (n + sizeof(wordcode) - 1) / sizeof(wordcode);
-
-    if (ecfree < n) {
-	int a = (n > 256 ? n : 256);
-
-	ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode),
-				    (eclen + a) * sizeof(wordcode));
-	eclen += a;
-	ecfree += a;
-    }
-    ecused += n;
-    ecfree -= n;
-
-    return ecused - 1;
-}
+int ecsoffs, ecssub, ecnfunc;
 
 /* Insert n free code-slots at position p. */
 
@@ -323,7 +303,7 @@ ecstrcode(char *s)
 	Eccstr p, q = NULL;
 
 	for (p = ecstrs; p; q = p, p = p->next)
-	    if (!strcmp(s, p->str))
+	    if (p->nfunc == ecnfunc && !strcmp(s, p->str))
 		return p->offs;
 
 	p = (Eccstr) zhalloc(sizeof(*p));
@@ -332,8 +312,9 @@ ecstrcode(char *s)
 	    q->next = p;
 	else
 	    ecstrs = p;
-	p->offs = (ecsoffs << 2) | (t ? 1 : 0);
+	p->offs = ((ecsoffs - ecssub) << 2) | (t ? 1 : 0);
 	p->str = s;
+	p->nfunc = ecnfunc;
 	ecsoffs += l;
 
 	return p->offs;
@@ -370,6 +351,8 @@ init_parse(void)
     ecused = 0;
     ecstrs = NULL;
     ecsoffs = ecnpats = 0;
+    ecssub = 0;
+    ecnfunc = 0;
 }
 
 /* Build eprog. */
@@ -393,7 +376,8 @@ bld_eprog(void)
     ret->prog = (Wordcode) (ret->pats + ecnpats);
     ret->strs = (char *) (ret->prog + ecused);
     ret->shf = NULL;
-    ret->heap = 1;
+    ret->alloc = EA_HEAP;
+    ret->dump = NULL;
     for (l = 0; l < ecnpats; l++)
 	ret->pats[l] = dummy_patprog1;
     memcpy(ret->prog, ecbuf, ecused * sizeof(wordcode));
@@ -1288,8 +1272,8 @@ par_subsh(int *complex)
 static void
 par_funcdef(void)
 {
-    int oecused = ecused, oldlineno = lineno, num = 0, sbeg, onp, p, c = 0;
-    Eccstr ostrs;
+    int oecused = ecused, oldlineno = lineno, num = 0, onp, p, c = 0;
+    int so, oecssub = ecssub;
 
     lineno = 0;
     nocorrect = 1;
@@ -1311,6 +1295,7 @@ par_funcdef(void)
     }
     ecadd(0);
     ecadd(0);
+    ecadd(0);
 
     nocorrect = 0;
     if (tok == INOUTPAR)
@@ -1318,10 +1303,8 @@ par_funcdef(void)
     while (tok == SEPER)
 	yylex();
 
-    sbeg = ecsoffs;
-    ecsoffs = 0;
-    ostrs = ecstrs;
-    ecstrs = NULL;
+    ecnfunc++;
+    ecssub = so = ecsoffs;
     onp = ecnpats;
     ecnpats = 0;
 
@@ -1330,43 +1313,28 @@ par_funcdef(void)
 	par_list(&c);
 	if (tok != OUTBRACE) {
 	    lineno += oldlineno;
-	    ecsoffs = sbeg;
-	    ecstrs = ostrs;
 	    ecnpats = onp;
+	    ecssub = oecssub;
 	    YYERRORV(oecused);
 	}
 	yylex();
     } else if (unset(SHORTLOOPS)) {
 	lineno += oldlineno;
-	ecsoffs = sbeg;
-	ecstrs = ostrs;
 	ecnpats = onp;
+	ecssub = oecssub;
 	YYERRORV(oecused);
     } else
 	par_list1(&c);
 
     ecadd(WCB_END());
-    ecbuf[p + num + 2] = ecused - num - p;
-    ecbuf[p + num + 3] = ecnpats;
+    ecbuf[p + num + 2] = so - oecssub;
+    ecbuf[p + num + 3] = ecsoffs - so;
+    ecbuf[p + num + 4] = ecnpats;
     ecbuf[p + 1] = num;
 
-    if (ecsoffs) {
-	int beg = ecused, l;
-	Eccstr sp;
-	char *sq;
-
-	ecspace(ecsoffs);
-
-	for (sp = ecstrs, sq = (char *) (ecbuf + beg); sp;
-	     sp = sp->next, sq += l) {
-	    l = strlen(sp->str) + 1;
-	    memcpy(sq, sp->str, l);
-	}
-    }
     lineno += oldlineno;
-    ecsoffs = sbeg;
-    ecstrs = ostrs;
     ecnpats = onp;
+    ecssub = oecssub;
 
     ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
 }
@@ -1481,8 +1449,7 @@ par_simple(int *complex, int nr)
 	    p += 3;		/* 3 codes per redirection */
 	    sr++;
 	} else if (tok == INOUTPAR) {
-	    int oldlineno = lineno, sbeg, onp;
-	    Eccstr ostrs;
+	    int oldlineno = lineno, onp, so, oecssub = ecssub;
 
 	    *complex = c;
 	    lineno = 0;
@@ -1496,11 +1463,10 @@ par_simple(int *complex, int nr)
 	    ecbuf[p + 1] = argc;
 	    ecadd(0);
 	    ecadd(0);
+	    ecadd(0);
 
-	    sbeg = ecsoffs;
-	    ecsoffs = 0;
-	    ostrs = ecstrs;
-	    ecstrs = NULL;
+	    ecnfunc++;
+	    ecssub = so = ecsoffs;
 	    onp = ecnpats;
 	    ecnpats = 0;
 
@@ -1512,9 +1478,8 @@ par_simple(int *complex, int nr)
 		if (tok != OUTBRACE) {
 		    cmdpop();
 		    lineno += oldlineno;
-		    ecsoffs = sbeg;
-		    ecstrs = ostrs;
 		    ecnpats = onp;
+		    ecssub = oecssub;
 		    YYERROR(oecused);
 		}
 		yylex();
@@ -1532,26 +1497,13 @@ par_simple(int *complex, int nr)
 	    cmdpop();
 
 	    ecadd(WCB_END());
-	    ecbuf[p + argc + 2] = ecused - argc - p;
-	    ecbuf[p + argc + 3] = ecnpats;
-
-	    if (ecsoffs) {
-		int beg = ecused, l;
-		Eccstr sp;
-		char *sq;
+	    ecbuf[p + argc + 2] = so - oecssub;
+	    ecbuf[p + argc + 3] = ecsoffs - so;
+	    ecbuf[p + argc + 4] = ecnpats;
 
-		ecspace(ecsoffs);
-
-		for (sp = ecstrs, sq = (char *) (ecbuf + beg); sp;
-		     sp = sp->next, sq += l) {
-		    l = strlen(sp->str) + 1;
-		    memcpy(sq, sp->str, l);
-		}
-	    }
 	    lineno += oldlineno;
-	    ecsoffs = sbeg;
-	    ecstrs = ostrs;
 	    ecnpats = onp;
+	    ecssub = oecssub;
 
 	    ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
 
@@ -2020,7 +1972,8 @@ zdupeprog(Eprog p)
 	return p;
 
     r = (Eprog) zalloc(sizeof(*r));
-    r->heap = 0;
+    r->alloc = EA_REAL;
+    r->dump = NULL;
     r->len = p->len;
     r->npats = p->npats;
     pp = r->pats = (Patprog *) zcalloc(r->len);
@@ -2056,7 +2009,11 @@ freeeprogs(void)
     while ((p = (Eprog) getlinknode(eprog_free))) {
 	for (i = p->npats, pp = p->pats; i--; pp++)
 	    freepatprog(*pp);
-	zfree(p->pats, p->len);
+	if (p->dump) {
+	    decrdumpcount(p->dump);
+	    zfree(p->pats, p->npats * sizeof(Patprog));
+	} else
+	    zfree(p->pats, p->len);
 	zfree(p, sizeof(*p));
     }
 }
@@ -2083,6 +2040,17 @@ ecgetstr(Estate s, int dup, int *tok)
     }
     if (tok)
 	*tok = (c & 1);
+
+    /*** Since function dump files are mapped read-only, avoiding to
+     *   to duplicate strings when they don't contain tokens may fail
+     *   when one of the many utility functions happens to write to
+     *   one of the strings (without really modifying it).
+     *   If that happens to you and you don't feel like debugging it,
+     *   just change the line below to:
+     *
+     *     return (dup ? dupstring(r) : r);
+     */
+
     return ((dup == EC_DUP || (dup && (c & 1)))  ? dupstring(r) : r);
 }
 
@@ -2193,3 +2161,530 @@ init_eprog(void)
 
     eprog_free = znewlinklist();
 }
+
+/* Code for function dump files.
+ *
+ * Dump files consist of a header and the function bodies (the wordcode
+ * plus the string table) and that twice: once for the byte-order of the
+ * host the file was created on and once for the other byte-order. The
+ * header describes where the beginning of the `other' version is and it
+ * is up to the shell reading the file to decide which version it needs.
+ * This is done by checking if the first word is FD_MAGIC (then the 
+ * shell reading the file has the same byte order as the one that created
+ * the file) or if it is FD_OMAGIC, then the `other' version has to be
+ * read.
+ * The header is the magic number, a word containing the flags (if the
+ * file should be mapped or read and if this header is the `other' one),
+ * the version string in a field of 40 characters and the descriptions
+ * for the functions in the dump file.
+ * Each description consists of a struct fdhead followed by the name,
+ * aligned to sizeof(wordcode) (i.e. 4 bytes).
+ */
+
+#include "version.h"
+
+#define FD_EXT ".zwc"
+#define FD_MINMAP 4096
+
+#define FD_PRELEN 12
+#define FD_MAGIC  0x01020304
+#define FD_OMAGIC 0x04030201
+
+#define FDF_MAP   1
+#define FDF_OTHER 2
+
+typedef struct fdhead *FDHead;
+
+struct fdhead {
+    wordcode start;		/* offset to function definition */
+    wordcode len;		/* length of wordcode/strings */
+    wordcode npats;		/* number of patterns needed */
+    wordcode strs;		/* offset to strings */
+    wordcode hlen;		/* header length (incl. name) */
+    wordcode tail;		/* offset to name tail */
+};
+
+#define fdheaderlen(f) (((Wordcode) (f))[FD_PRELEN])
+
+#define fdmagic(f)       (((Wordcode) (f))[0])
+#define fdbyte(f, i)     ((wordcode) (((unsigned char *) (((Wordcode) (f)) + 1))[i]))
+#define fdflags(f)       fdbyte(f, 0)
+#define fdother(f)       (fdbyte(f, 1) + (fdbyte(f, 2) << 8) + (fdbyte(f, 3) << 16))
+#define fdsetother(f, o) \
+    do { \
+        fdbyte(f, 1) = (o & 0xff); \
+        fdbyte(f, 2) = (o >> 8) & 0xff; \
+        fdbyte(f, 3) = (o >> 16) & 0xff; \
+    } while (0)
+#define fdversion(f)     ((char *) ((f) + 2))
+
+#define firstfdhead(f) ((FDHead) (((Wordcode) (f)) + FD_PRELEN))
+#define nextfdhead(f)  ((FDHead) (((Wordcode) (f)) + (f)->hlen))
+
+#define fdname(f)      ((char *) (((FDHead) (f)) + 1))
+
+/* Try to find the description for the given function name. */
+
+static FDHead
+dump_find_func(Wordcode h, char *name)
+{
+    FDHead n, e = (FDHead) (h + fdheaderlen(h));
+
+    for (n = firstfdhead(h); n < e; n = nextfdhead(n))
+	if (!strcmp(name, fdname(n) + n->tail))
+	    return n;
+
+    return NULL;
+}
+
+/**/
+int
+bin_zcompile(char *nam, char **args, char *ops, int func)
+{
+    int map;
+
+    if (ops['t']) {
+	Wordcode f;
+
+	if (!*args) {
+	    zerrnam(nam, "too few arguments", NULL, 0);
+	    return 1;
+	}
+	if (!(f = load_dump_header(*args))) {
+	    zerrnam(nam, "invalid dump file: %s", *args, 0);
+	    return 1;
+	}
+	if (args[1]) {
+	    for (args++; *args; args++)
+		if (!dump_find_func(f, *args))
+		    return 1;
+	    return 0;
+	} else {
+	    FDHead h, e = (FDHead) (f + fdheaderlen(f));
+
+	    printf("function dump file (%s) for zsh-%s\n",
+		   ((fdflags(f) & FDF_MAP) ? "mapped" : "read"), fdversion(f));
+	    for (h = firstfdhead(f); h < e; h = nextfdhead(h))
+		printf("%s\n", fdname(h));
+	    return 0;
+	}
+    }
+    if (!*args) {
+	zerrnam(nam, "too few arguments", NULL, 0);
+	return 1;
+    }
+    map = (ops['m'] ? 2 : (ops['r'] ? 0 : 1));
+
+    if (!args[1])
+	return build_dump(nam, dyncat(*args, FD_EXT), args, ops['U'], map);
+
+    return build_dump(nam, *args, args + 1, ops['U'], map);
+}
+
+/* Load the header of a dump file. Returns NULL if the file isn't a
+ * valid dump file. */
+
+/**/
+static Wordcode
+load_dump_header(char *name)
+{
+    int fd;
+    wordcode buf[FD_PRELEN + 1];
+
+    if ((fd = open(name, O_RDONLY)) < 0)
+	return NULL;
+
+    if (read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) !=
+	((FD_PRELEN + 1) * sizeof(wordcode)) ||
+	strcmp(ZSH_VERSION, fdversion(buf))) {
+	close(fd);
+	return NULL;
+    } else {
+	int len;
+	Wordcode head;
+
+	if (fdmagic(buf) == FD_MAGIC) {
+	    len = fdheaderlen(buf) * sizeof(wordcode);
+	    head = (Wordcode) zhalloc(len);
+	}
+	else {
+	    int o = fdother(buf);
+
+	    if (lseek(fd, o, 0) == -1 ||
+		read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) !=
+		((FD_PRELEN + 1) * sizeof(wordcode))) {
+		close(fd);
+		return NULL;
+	    }
+	    len = fdheaderlen(buf) * sizeof(wordcode);
+	    head = (Wordcode) zhalloc(len);
+	}
+	memcpy(head, buf, (FD_PRELEN + 1) * sizeof(wordcode));
+
+	if (read(fd, head + (FD_PRELEN + 1),
+		 len - ((FD_PRELEN + 1) * sizeof(wordcode))) !=
+	    len - ((FD_PRELEN + 1) * sizeof(wordcode))) {
+	    close(fd);
+	    return NULL;
+	}
+	close(fd);
+	return head;
+    }
+}
+
+/* Swap the bytes in a wordcode. */
+
+static void
+fdswap(Wordcode p, int n)
+{
+    wordcode c;
+
+    for (; n--; p++) {
+	c = *p;
+	*p = (((c & 0xff) << 24) |
+	      ((c & 0xff00) << 8) |
+	      ((c & 0xff0000) >> 8) |
+	      ((c & 0xff000000) >> 24));
+    }
+}
+
+/* Write a dump file. */
+
+/**/
+static int
+build_dump(char *nam, char *dump, char **files, int ali, int map)
+{
+    int dfd, fd, hlen, tlen, flen, tmp, ona = noaliases, other = 0, ohlen;
+    LinkList progs;
+    LinkNode node;
+    struct fdhead head;
+    wordcode pre[FD_PRELEN];
+    char *file, **ofiles = files, **oofiles = files, *name, *tail;
+    Eprog prog;
+
+    if ((dfd = open(dump, O_WRONLY|O_CREAT, 0600)) < 0) {
+	zerrnam(nam, "can't write dump file: %s", dump, 0);
+	return 1;
+    }
+    progs = newlinklist();
+    noaliases = ali;
+
+    for (hlen = FD_PRELEN, tlen = 0; *files; files++) {
+	if ((fd = open(*files, O_RDONLY)) < 0 ||
+	    (flen = lseek(fd, 0, 2)) == -1) {
+	    if (fd >= 0)
+		close(fd);
+	    close(dfd);
+	    zerrnam(nam, "can't open file: %s", *files, 0);
+	    noaliases = ona;
+	    return 1;
+	}
+	file = (char *) zalloc(flen + 1);
+	file[flen] = '\0';
+	lseek(fd, 0, 0);
+	if (read(fd, file, flen) != flen) {
+	    close(fd);
+	    close(dfd);
+	    zfree(file, flen);
+	    zerrnam(nam, "can't read file: %s", *files, 0);
+	    noaliases = ona;
+	    return 1;
+	}
+	close(fd);
+	file = metafy(file, flen, META_REALLOC);
+
+	if (!(prog = parse_string(file, 1)) || errflag) {
+	    close(dfd);
+	    zfree(file, flen);
+	    zerrnam(nam, "can't read file: %s", *files, 0);
+	    noaliases = ona;
+	    return 1;
+	}
+	zfree(file, flen);
+
+	addlinknode(progs, prog);
+
+	flen = (strlen(*files) + sizeof(wordcode)) / sizeof(wordcode);
+	hlen += (sizeof(head) / sizeof(wordcode)) + flen;
+
+	tlen += (prog->len - (prog->npats * sizeof(Patprog)) +
+		 sizeof(wordcode) - 1) / sizeof(wordcode);
+    }
+    noaliases = ona;
+
+    tlen = (tlen + hlen) * sizeof(wordcode);
+    if (map == 1)
+	map = (tlen >= FD_MINMAP);
+
+    for (ohlen = hlen; ; hlen = ohlen) {
+	fdmagic(pre) = (other ? FD_OMAGIC : FD_MAGIC);
+	fdflags(pre) = (map ? FDF_MAP : 0) | other;
+	fdsetother(pre, tlen);
+	strcpy(fdversion(pre), ZSH_VERSION);
+	write(dfd, pre, FD_PRELEN * sizeof(wordcode));
+
+	for (node = firstnode(progs), ofiles = oofiles; node;
+	     ofiles++, incnode(node)) {
+	    prog = (Eprog) getdata(node);
+	    head.start = hlen;
+	    hlen += (prog->len - (prog->npats * sizeof(Patprog)) +
+		     sizeof(wordcode) - 1) / sizeof(wordcode);
+	    head.len = prog->len - (prog->npats * sizeof(Patprog));
+	    head.npats = prog->npats;
+	    head.strs = prog->strs - ((char *) prog->prog);
+	    head.hlen = (sizeof(struct fdhead) / sizeof(wordcode)) +
+		(strlen(*ofiles) + sizeof(wordcode)) / sizeof(wordcode);
+	    for (name = tail = *ofiles; *name; name++)
+		if (*name == '/')
+		    tail = name + 1;
+	    head.tail = tail - *ofiles;
+	    if (other)
+		fdswap((Wordcode) &head, sizeof(head) / sizeof(wordcode));
+	    write(dfd, &head, sizeof(head));
+	    tmp = strlen(*ofiles) + 1;
+	    write(dfd, *ofiles, tmp);
+	    if ((tmp &= (sizeof(wordcode) - 1)))
+		write(dfd, &head, sizeof(wordcode) - tmp);
+	}
+	for (node = firstnode(progs); node; incnode(node)) {
+	    prog = (Eprog) getdata(node);
+	    tmp = (prog->len - (prog->npats * sizeof(Patprog)) +
+		   sizeof(wordcode) - 1) / sizeof(wordcode);
+	    if (other)
+		fdswap(prog->prog, (((Wordcode) prog->strs) - prog->prog));
+	    write(dfd, prog->prog, tmp * sizeof(wordcode));
+	}
+	if (other)
+	    break;
+	other = FDF_OTHER;
+    }
+    close(dfd);
+    return 0;
+}
+
+#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
+
+#include <sys/mman.h>
+
+#if defined(MAP_SHARED) && defined(PROT_READ)
+
+#define USE_MMAP 1
+
+#endif
+#endif
+
+#ifdef USE_MMAP
+
+/* List of dump files mapped. */
+
+static FuncDump dumps;
+
+/* Load a dump file (i.e. map it). */
+
+static void
+load_dump_file(char *dump, int other, int len)
+{
+    FuncDump d;
+    Wordcode addr;
+    int fd, off;
+
+    if (other) {
+	static size_t pgsz = 0;
+
+	if (!pgsz) {
+
+#ifdef _SC_PAGESIZE
+	    pgsz = sysconf(_SC_PAGESIZE);     /* SVR4 */
+#else
+# ifdef _SC_PAGE_SIZE
+	    pgsz = sysconf(_SC_PAGE_SIZE);    /* HPUX */
+# else
+	    pgsz = getpagesize();
+# endif
+#endif
+
+	    pgsz--;
+	}
+	off = len & ~pgsz;
+    } else
+	off = 0;
+
+    if ((fd = open(dump, O_RDONLY)) < 0)
+	return;
+
+    fd = movefd(fd);
+
+    if ((addr = (Wordcode) mmap(NULL, len, PROT_READ, MAP_SHARED, fd, off)) ==
+	((Wordcode) -1)) {
+	close(fd);
+	return;
+    }
+    d = (FuncDump) zalloc(sizeof(*d));
+    d->next = dumps;
+    dumps = d;
+    d->name = ztrdup(dump);
+    d->fd = fd;
+    d->map = addr + (other ? (len - off) / sizeof(wordcode) : 0);
+    d->addr = addr;
+    d->len = len;
+    d->count = 0;
+}
+
+/* See if `dump' is the name of a dump file and it has the definition
+ * for the function `name'. If so, return an eprog for it. */
+
+/**/
+Eprog
+try_dump_file(char *dump, char *name, char *func)
+{
+    int isrec = 0;
+    Wordcode d;
+    FDHead h;
+    FuncDump f;
+
+ rec:
+
+    d = NULL;
+    for (f = dumps; f; f = f->next)
+	if (!strcmp(dump, f->name)) {
+	    d = f->map;
+	    break;
+	}
+    if (!f && (isrec || !(d = load_dump_header(dump)))) {
+	if (!isrec) {
+	    struct stat stc, stn;
+	    char *p = (char *) zhalloc(strlen(dump) + strlen(name) +
+				       strlen(FD_EXT) + 2);
+
+	    sprintf(p, "%s/%s%s", dump, name, FD_EXT);
+
+	    /* Ignore the dump file if it is older than the normal one. */
+	    if (stat(p, &stc) || stat(func, &stn) || stn.st_mtime > stc.st_mtime)
+		return NULL;
+
+	    if (!(d = load_dump_header(dump = p)))
+		return NULL;
+
+	} else
+	    return NULL;
+    }
+    if ((h = dump_find_func(d, name))) {
+	/* Found the name. If the file is already mapped, return the eprog,
+	 * otherwise map it and just go up. */
+	if (f) {
+	    Eprog prog = (Eprog) zalloc(sizeof(*prog));
+	    Patprog *pp;
+	    int np;
+
+	    prog->alloc = EA_MAP;
+	    prog->len = h->len;
+	    prog->npats = np = h->npats;
+	    prog->pats = pp = (Patprog *) zalloc(np * sizeof(Patprog));
+	    prog->prog = f->map + h->start;
+	    prog->strs = ((char *) prog->prog) + h->strs;
+	    prog->shf = NULL;
+	    prog->dump = f;
+
+	    incrdumpcount(f);
+
+	    while (np--)
+		*pp++ = dummy_patprog1;
+
+	    return prog;
+	} else if (fdflags(d) & FDF_MAP) {
+	    load_dump_file(dump, (fdflags(d) & FDF_OTHER), fdother(d));
+	    isrec = 1;
+	    goto rec;
+	} else {
+	    Eprog prog;
+	    Patprog *pp;
+	    int np, fd, po = h->npats * sizeof(Patprog);
+
+	    if ((fd = open(dump, O_RDONLY)) < 0 ||
+		lseek(fd, ((h->start * sizeof(wordcode)) +
+			   ((fdflags(d) & FDF_OTHER) ? fdother(d) : 0)), 0) < 0) {
+		if (fd >= 0)
+		    close(fd);
+		return NULL;
+	    }
+	    d = (Wordcode) zalloc(h->len + po);
+
+	    if (read(fd, ((char *) d) + po, h->len) != h->len) {
+		close(fd);
+		zfree(d, h->len);
+
+		return NULL;
+	    }
+	    close(fd);
+
+	    prog = (Eprog) zalloc(sizeof(*prog));
+
+	    prog->alloc = EA_MAP;
+	    prog->len = h->len + po;
+	    prog->npats = np = h->npats;
+	    prog->pats = pp = (Patprog *) d;
+	    prog->prog = (Wordcode) (((char *) d) + po);
+	    prog->strs = ((char *) prog->prog) + h->strs;
+	    prog->shf = NULL;
+	    prog->dump = f;
+
+	    while (np--)
+		*pp++ = dummy_patprog1;
+
+	    return prog;
+	}
+    }
+    return NULL;
+}
+
+/* Increment the reference counter for a dump file. */
+
+/**/
+void
+incrdumpcount(FuncDump f)
+{
+    f->count++;
+}
+
+/* Decrement the reference counter for a dump file. If zero, unmap the file. */
+
+/**/
+void
+decrdumpcount(FuncDump f)
+{
+    f->count--;
+    if (!f->count) {
+	FuncDump p, q;
+
+	for (q = NULL, p = dumps; p && p != f; q = p, p = p->next);
+	if (p) {
+	    if (q)
+		q->next = p->next;
+	    else
+		dumps = p->next;
+	    munmap((void *) f->addr, f->len);
+	    zclose(f->fd);
+	    zfree(f, sizeof(*f));
+	}
+    }
+}
+
+#else
+
+Eprog
+try_dump_file(char *dump, char *name, char *func)
+{
+    return NULL;
+}
+
+void
+incrdumpcount(FuncDump f)
+{
+}
+
+void
+decrdumpcount(FuncDump f)
+{
+}
+
+#endif