Browse Source

Initial revision

keie 40 years ago
parent
commit
3b4b7cac60
35 changed files with 4011 additions and 0 deletions
  1. 27 0
      lib/6500/descr
  2. 31 0
      lib/6809/descr
  3. 25 0
      lib/descr/cpm
  4. 60 0
      lib/descr/fe.src
  5. 28 0
      lib/descr/nascom
  6. 27 0
      lib/em22/descr
  7. 27 0
      lib/i80/descr
  8. 32 0
      lib/i86/descr
  9. 30 0
      lib/m68k2/descr
  10. 34 0
      lib/m68k4/descr
  11. 38 0
      lib/pdp/descr
  12. 37 0
      lib/vax4/descr.src
  13. 31 0
      lib/z80/descr
  14. 63 0
      util/ack/Makefile
  15. 88 0
      util/ack/ack.h
  16. 9 0
      util/ack/data.c
  17. 43 0
      util/ack/data.h
  18. 15 0
      util/ack/dmach.h
  19. 94 0
      util/ack/files.c
  20. 79 0
      util/ack/grows.c
  21. 19 0
      util/ack/grows.h
  22. 73 0
      util/ack/list.c
  23. 23 0
      util/ack/list.h
  24. 340 0
      util/ack/main.c
  25. 208 0
      util/ack/malloc.c
  26. 121 0
      util/ack/mktables.c
  27. 25 0
      util/ack/pc/Makefile
  28. 681 0
      util/ack/pc/em_pc.c
  29. 288 0
      util/ack/rmach.c
  30. 154 0
      util/ack/run.c
  31. 244 0
      util/ack/scan.c
  32. 125 0
      util/ack/svars.c
  33. 672 0
      util/ack/trans.c
  34. 30 0
      util/ack/trans.h
  35. 190 0
      util/ack/util.c

+ 27 - 0
lib/6500/descr

@@ -0,0 +1,27 @@
+var w=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=8
+var NAME=m6500
+var M=6500
+var LIB=mach/6500/lib/tail_
+var RT=mach/6500/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_be
+	args <
+	prop >
+	need .e
+end
+name asld
+	from .s.a
+	to a.out
+	program {EM}/lib/{M}_as
+	mapflag -l* LNAME={EM}/{LIB}*
+	args (.e:{HEAD}={EM}/{RT}em) -o > (.e:{TAIL}={EM}/{LIB}em)
+	prop C
+end

+ 31 - 0
lib/6809/descr

@@ -0,0 +1,31 @@
+var w=2
+var i=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=8
+var NAME=m6809
+var M=6809
+var LIB=mach/6809/lib/tail_
+var RT=mach/6809/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_be
+	args <
+	prop >
+	need .e
+end
+name asld
+	from .s.a
+	to a.out
+	program {EM}/lib/{M}_as
+	mapflag -l* LNAME={EM}/{LIB}*
+	args (.e:{HEAD}={EM}/{RT}em) \
+({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+(.c.p:{TAIL}={EM}/{LIB}mon) (.e:{TAIL}={EM}/{LIB}em)
+	prop C
+end

+ 25 - 0
lib/descr/cpm

@@ -0,0 +1,25 @@
+var w=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=4
+var M=cpm
+var NAME=CPM
+var LIB=mach/z80/int/lib/tail_
+var RT=mach/z80/int/lib/head_
+var SIZE_F=-sm
+var INCLUDES=-I{EM}/include
+name asld
+	from .k.m.a
+	to e.out
+	program {EM}/lib/em_ass
+	mapflag -l* LNAME={EM}/{LIB}*
+	mapflag -+* ASS_F={ASS_F?} -+*
+	mapflag --* ASS_F={ASS_F?} --*
+	mapflag -s* SIZE_F=-s*
+	args {ASS_F?} ({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+(.c.p:{TAIL}={EM}/{LIB}mon)
+	prop C
+end

+ 60 - 0
lib/descr/fe.src

@@ -0,0 +1,60 @@
+# (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+name cpp
+	# no from, it's governed by the P property
+	to .i
+	program {EM}/lib/cpp
+	mapflag -I* CPP_F={CPP_F?} -I*
+	mapflag -U* CPP_F={CPP_F?} -U*
+	mapflag -D* CPP_F={CPP_F?} -D*
+	args {CPP_F?} {INCLUDES?} -D{NAME} -DEM_WSIZE={w} -DEM_PSIZE={p} \
+-DEM_SSIZE={s} -DEM_LSIZE={l} -DEM_FSIZE={f} -DEM_DSIZE={d} <
+	prop >P
+end
+name cem
+	from .c
+	to .k
+	program {EM}/lib/em_cem
+	mapflag -p CEM_F={CEM_F?} -Xp
+	mapflag -L CEM_F={CEM_F?} -l
+	args -Vw{w}i{w}p{p}f{f}s{s}l{l}d{d} {CEM_F?}
+	prop <>p
+	rts .c
+	need .c
+end
+name pc
+	from .p
+	to .k
+	program {EM}/lib/em_pc
+	mapflag -p PC_F={PC_F?} -p
+	mapflag -w PC_F={PC_F?} -w
+	mapflag -E PC_F={PC_F?} -E
+	mapflag -e PC_F={PC_F?} -e
+	mapflag -{*} PC_F={PC_F?} -\{*}
+	mapflag -L PC_F={PC_F?} -\{l-}
+	args -Vw{w}p{p}f{d}l{l} {PC_F?} < > {SOURCE}
+	prop m
+	rts .p
+	need .p
+ end
+ name encode
+	from .e
+	to .k
+	program {EM}/lib/em_encode
+	args <
+	prop >m
+end
+name opt
+	from .k
+	to .m
+	program {EM}/lib/em_opt
+	mapflag -LIB OPT_F={OPT_F?} -L
+	args {OPT_F?} <
+	prop >O
+end
+name decode
+	from .k.m
+	to .e
+	program {EM}/lib/em_decode
+	args <
+	prop >
+end

+ 28 - 0
lib/descr/nascom

@@ -0,0 +1,28 @@
+var w=1
+var p=2
+var s=1
+var l=2
+var f=4
+var d=8
+var NAME=nascom
+var M=z80a
+var LIB=mach/z80a/lib/tail_
+var RT=mach/z80a/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_be
+	args <
+	prop >
+	need .e
+end
+name asld
+	from .s.a
+	to a.out
+	program {EM}/lib/{M}_as
+	mapflag -l* LNAME={EM}/{LIB}*
+	args (.e:{HEAD}={EM}/{RT}em) ({RTS}:.c={EM}/{RT}cc) -o > \
+(.e:{TAIL}={EM}/{LIB}em.1 {EM}/{LIB}em.2)
+	prop C
+end

+ 27 - 0
lib/em22/descr

@@ -0,0 +1,27 @@
+var w=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=8
+var M=int
+var NAME=int22
+var LIB=mach/int/lib/tail_
+var RT=mach/int/lib/head_
+var SIZE_FLAG=-sm
+var INCLUDES=-I{EM}/include
+name asld
+	from .k.m.a
+	to e.out
+	program {EM}/lib/em_ass
+	mapflag -l* LNAME={EM}/{LIB}*
+	mapflag -+* ASS_F={ASS_F?} -+*
+	mapflag --* ASS_F={ASS_F?} --*
+	mapflag -s* SIZE_FLAG=-s*
+	args {SIZE_FLAG} \
+		({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+		(.p:{TAIL}={EM}/{LIB}pc) \
+		(.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+		(.c.p:{TAIL}={EM}/{LIB}mon)
+	prop C
+end

+ 27 - 0
lib/i80/descr

@@ -0,0 +1,27 @@
+var w=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=8
+var NAME=i8080
+var M=8080
+var LIB=mach/8080/lib/tail_
+var RT=mach/8080/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_be
+	args <
+	prop >
+	need .e
+end
+name asld
+	from .s.a
+	to a.out
+	program {EM}/lib/{M}_as
+	mapflag -l* LNAME={EM}/{LIB}*
+	args ({RTS}:.c={EM}/{RT}cc) -o > <
+	prop C
+end

+ 32 - 0
lib/i86/descr

@@ -0,0 +1,32 @@
+var w=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=8
+var NAME=i8086
+var M=i86
+var LIB=mach/i86/lib/tail_
+var RT=mach/i86/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_cg
+	args <
+	prop >
+	need .e
+end
+name asld
+	from .s.a
+	to a.out
+	program {EM}/lib/{M}_as
+	mapflag -l* LNAME={EM}/{LIB}*
+	mapflag -i  IFILE={EM}/{RT}i
+	args {IFILE?} (.e:{HEAD}={EM}/{RT}em) \
+({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+(.c.p.e:{TAIL}={EM}/{LIB}alo) (.c.p:{TAIL}={EM}/{LIB}mon) \
+(.e:{TAIL}={EM}/{LIB}em)
+	prop C
+end

+ 30 - 0
lib/m68k2/descr

@@ -0,0 +1,30 @@
+var w=2
+var p=4
+var s=2
+var l=4
+var f=4
+var d=8
+var NAME=m68k2
+var M=m68k2
+var LIB=mach/m68k2/lib/tail_
+var RT=mach/m68k2/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_cg
+	args <
+	prop >
+	need .e
+end
+name asld
+	from .s.a
+	to a.out
+	program {EM}/lib/{M}_as
+	mapflag -l* LNAME={EM}/{LIB}*
+	args (.e:{HEAD}={EM}/{RT}em) \
+({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+(.e:{TAIL}={EM}/{LIB}em.rt {EM}/{LIB}mon {EM}/{LIB}em.vend)
+	prop Cm
+end

+ 34 - 0
lib/m68k4/descr

@@ -0,0 +1,34 @@
+var w=4
+var p=4
+var s=2
+var l=4
+var f=4
+var d=8
+var NAME=m68k4
+var M=m68k4
+var LIBDIR=mach/m68k4/lib
+var LIB=mach/m68k4/lib/tail_
+var RT=mach/m68k4/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_cg
+	args <
+	prop >
+	need .e
+end
+name asld
+	from .s.a
+	to a.out
+	program {EM}/lib/{M}_as
+	mapflag -l* LNAME={EM}/{LIB}*
+	args (.e:{HEAD}={EM}/{RT}em) \
+({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+(.p.c:{TAIL}={EM}/{LIBDIR}/sys1.s) (.p:{TAIL}={EM}/{LIBDIR}/sys2.s) \
+(.c:{TAIL}={EM}/{LIBDIR}/write.s) \
+(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+(.c:{TAIL}={EM}/{LIB}mon {EM}/{LIB}fake) \
+(.e:{TAIL}={EM}/{LIB}em.rt {EM}/{LIB}em.vend)
+	prop Cm
+end

+ 38 - 0
lib/pdp/descr

@@ -0,0 +1,38 @@
+var w=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=8
+var M=pdp
+var NAME=pdp
+var LIB=mach/pdp/lib/tail_
+var RT=mach/pdp/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_cg
+	args <
+	prop >
+	need .e
+end
+name as
+	from .s
+	to .o
+	program /bin/as
+	args - -o > <
+	prop m
+end
+name ld
+	from .o.a
+	to a.out
+	program /bin/ld
+	mapflag -l* LNAME={EM}/{LIB}*
+	args (.e:{HEAD}={EM}/{RT}em) \
+		({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+		(.p:{TAIL}={EM}/{LIB}pc) \
+		(.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+		(.e:{TAIL}={EM}/{LIB}em) (.c.p:{TAIL}=/lib/libc.a)
+	prop C
+end

+ 37 - 0
lib/vax4/descr.src

@@ -0,0 +1,37 @@
+var w=4
+var p=4
+var s=2
+var l=4
+var f=4
+var d=8
+var M=vax4
+var NAME=vax4
+var LIB=mach/vax4/lib/tail_
+var RT=mach/vax4/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_cg
+	args <
+	prop >
+	need .e
+end
+name as
+	from .s
+	to .o
+	program /bin/as
+	args - -o > <
+	prop m
+end
+name ld
+	from .o.a
+	to a.out
+	program /bin/ld
+	mapflag -l* LNAME={EM}/{LIB}*
+	args (.e:{HEAD}={EM}/{RT}em) \
+({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+(.e:{TAIL}={EM}/{LIB}em) (.c.p:{TAIL}={EM}/{LIB}mon)
+	prop C
+end

+ 31 - 0
lib/z80/descr

@@ -0,0 +1,31 @@
+var w=2
+var p=2
+var s=2
+var l=4
+var f=4
+var d=8
+var NAME=z80
+var M=z80
+var LIB=mach/z80/lib/tail_
+var RT=mach/z80/lib/head_
+var INCLUDES=-I{EM}/include
+name be
+	from .m
+	to .s
+	program {EM}/lib/{M}_cg
+	args <
+	prop >
+	need .e
+end
+name asld
+	from .s.a
+	to a.out
+	program {EM}/lib/{M}_as
+	mapflag -l* LNAME={EM}/{LIB}*
+	args (.e:{HEAD}={EM}/{RT}em) \
+({RTS}:.c={EM}/{RT}cc) ({RTS}:.p={EM}/{RT}pc) -o > < \
+(.p:{TAIL}={EM}/{LIB}pc) (.c:{TAIL}={EM}/{LIB}cc.1s {EM}/{LIB}cc.2g) \
+(.c.p.e:{TAIL}={EM}/{LIB}alo) (.c.p:{TAIL}={EM}/{LIB}mon) \
+(.e:{TAIL}={EM}/{LIB}em.vend)
+	prop C
+end

+ 63 - 0
util/ack/Makefile

@@ -0,0 +1,63 @@
+HFILES=ack.h list.h trans.h data.h dmach.h grows.h
+DSRC=list.c data.c main.c scan.c svars.c trans.c util.c rmach.c run.c grows.c\
+     files.c
+ISRC=dmach.c intable.c
+OBJ=list.o data.o main.o scan.o svars.o trans.o util.o rmach.o run.o \
+    dmach.o intable.o grows.o files.o
+ACKDIR=../../lib/ack
+FE=fe
+INTABLES=pdp int
+LNTABLES=6500 m68k2 m68k4 6809 8080 acc apc nascom vax2 vax4 z80 i86
+CFLAGS=-O -n
+BINDIR=../../bin
+
+head:   ack
+
+install:	ack
+		cp ack $(BINDIR)/ack
+		-cd $(BINDIR) ; \
+		for i in $(INTABLES) $(LNTABLES) ; do ln ack $$i ; done
+		(cd pc ; make install )
+
+cmp:		ack
+		cmp ack $(BINDIR)/ack
+		(cd pc ; make cmp )
+
+clean:
+		-rm -f *.old *.o ack
+		(cd pc ; make clean )
+
+ack:    $(OBJ)
+	$(CC) -o ack $(CFLAGS) $(OBJ)
+
+grows.o files.o list.o run.o \
+data.o main.o scan.o trans.o rmach.o util.o : ack.h list.h
+
+files.o data.o main.o scan.o run.o trans.o rmach.o: trans.h data.h
+
+files.o rmach.o trans.o grows.c : grows.h
+
+rmach.c: dmach.h
+
+files.o main.o rmach.o : ../../h/em_path.h
+
+main.o : ../../h/local.h
+
+malloc.o svars.o:	ack.h
+
+dmach.c intable.c: mktables dmach.h
+	: mktables $(ACKDIR) # $(FE) $(INTABLES)
+	mktables $(ACKDIR)
+
+mktables:       mktables.c
+	cc -o mktables mktables.c
+
+pr:
+	@pr Makefile $(HFILES) $(DSRC) $(ACKDIR)/*
+	@(cd pc ; make pr)
+
+opr:
+	make pr | opr
+
+lint:   $(ISRC)
+	lint -hbx $(DSRC) $(ISRC)

+ 88 - 0
util/ack/ack.h

@@ -0,0 +1,88 @@
+/****************************************************************************/
+/*                      User settable options                               */
+/****************************************************************************/
+
+#define FRONTENDS       "fe"    /* The front-end definitions */
+#define ACKNAME         "AckXXXXXX"     /* Handed to mktemp for temp. files */
+
+/****************************************************************************/
+/*         Internal mnemonics, should not be tinkered with                  */
+/****************************************************************************/
+
+/* The names of some string variables */
+
+#define HOME    "EM"
+#define RTS     "RTS"
+#define NEEDS   "NEEDS"
+#define HEAD    "HEAD"
+#define TAIL    "TAIL"
+#define SRC     "SOURCE"
+#define LIBVAR	"LNAME"
+
+/* Intended for flags, possibly in bit fields */
+
+#define YES     1
+#define NO      0
+#define MAYBE   2
+
+#define EXTERN  extern
+
+#define SUFCHAR '.'             /* Start of SUFFIX in file name */
+#define SPACE   ' '
+#define TAB     '\t'
+#define EQUAL   '='
+#define S_VAR   '{'             /* Start of variable */
+#define C_VAR   '}'             /* End of variable */
+#define A_VAR   '?'             /* Variable alternative */
+#define BSLASH  '\\'            /* Backslash */
+#define STAR    '*'             /* STAR */
+#define C_IN    '<'             /* Token specifying input */
+#define C_OUT   '>'             /* Token specifying output */
+#define S_EXPR  '('             /* Start of expression */
+#define C_EXPR  ')'             /* End of expression */
+#define M_EXPR  ':'             /* Middle of two suffix lists */
+#define T_EXPR  '='             /* Start of tail */
+
+#define NO_SCAN 0200            /* Bit set in character to defeat recogn. */
+
+typedef struct {
+	char    *p_path;        /* points to the full pathname */
+	int     p_keeps:1;      /* The string should be thrown when unused */
+	int     p_keep:1;       /* The file should be thrown away after use */
+} path ;
+
+/* Return values of setpath() */
+enum f_path { F_OK, F_NOMATCH, F_NOPATH } ;
+
+/* Library routines */
+
+extern char *index();
+extern char *rindex();
+extern char *strcpy();
+extern char *strcat();
+extern char *mktemp();
+extern int  unlink();
+extern int  close();
+extern int  open();
+extern int  creat();
+
+/* Own routines */
+enum f_path setpath();
+enum f_path scan_end();
+extern int  noodstop();
+extern char *getvar();
+extern char *keeps();
+extern char *basename();
+extern char *skipblank();
+extern char *firstblank();
+extern char *getcore();
+extern char *changecore();
+#define freecore(area)  free(area)
+
+/* #define DEBUG	1	/* Allow debugging of Ack */
+
+#ifndef DEBUG
+#  define debug 0       /* To surprise all these 'if ( debug ) 's */
+#else
+extern  int debug ;
+#endif

+ 9 - 0
util/ack/data.c

@@ -0,0 +1,9 @@
+#include "ack.h"
+#include "list.h"
+#include "trans.h"
+
+
+#undef EXTERN
+#define EXTERN
+
+#include "data.h"

+ 43 - 0
util/ack/data.h

@@ -0,0 +1,43 @@
+EXTERN  char            *stopsuffix;    /* Suffix to stop at */
+EXTERN  char            *machine;       /* The machine id */
+EXTERN  char            *rts;           /* The runtime-system id */
+
+EXTERN  list_head       arguments;      /* List of arguments */
+EXTERN  list_head       flags;          /* List of flags */
+
+EXTERN  list_head       c_arguments;    /* List of linker arguments */
+
+EXTERN  list_head       tr_list;        /* List of transformations */
+
+EXTERN  list_head       R_list;         /* List of -R flags */
+EXTERN  list_head       head_list;      /* List of suffices for headers */
+EXTERN  list_head       tail_list;      /* List of suffices for tails */
+
+EXTERN  int             k_flag;         /* Like -k of lint */
+EXTERN  int             g_flag;         /* do_run() */
+EXTERN  int             t_flag;         /* Preserve intermediate files */
+EXTERN  int             v_flag;         /* Verbose */
+EXTERN  int             w_flag;         /* Don't print warnings */
+EXTERN  int             nill_flag;      /* Don't file names */
+EXTERN  int             Optflag;        /* Optimizing */
+
+#ifdef DEBUG
+EXTERN  int             debug;          /* Debugging control */
+#endif
+
+EXTERN  int             n_error;        /* Number of errors encountered */
+
+EXTERN  char            *progname;      /* The program call name */
+
+EXTERN  char            *outfile;       /* The result file e.g. a.out */
+EXTERN  char            *template;      /* The template for temporary file
+						names */
+
+EXTERN  trf             *combiner;      /* Pointer to the Loader/Linker */
+EXTERN  trf             *cpp_trafo;     /* Pointer to C-preprocessor */
+
+EXTERN  path            in;             /* The current input pathname */
+EXTERN  path            out;            /* The current output pathname */
+EXTERN  path            orig;           /* The original input path */
+EXTERN  char            *p_basename;    /* The current basename */
+EXTERN  char            *p_suffix;      /* The current input suffix */

+ 15 - 0
util/ack/dmach.h

@@ -0,0 +1,15 @@
+/***************************************************************/
+/*                                                             */
+/*   Definition for table that maps a name on an intable index */
+/*                                                             */
+/***************************************************************/
+
+
+typedef struct {
+	char *ma_name ;         /* The name of the machine */
+	int   ma_index ;
+} dmach ;
+
+extern dmach massoc[] ;
+
+extern char  intable[] ;

+ 94 - 0
util/ack/files.c

@@ -0,0 +1,94 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include "ack.h"
+#include "list.h"
+#include "trans.h"
+#include "grows.h"
+#include "data.h"
+#include "../../h/em_path.h"
+
+setfiles(phase) register trf *phase ; {
+	/* Set the out structure according to the in structure,
+	   the transformation and some global data */
+	growstring pathname ;
+	register list_elem *elem ;
+
+	if ( phase->t_combine ) {
+		out.p_keep=YES ;
+		out.p_path=outfile ;
+		out.p_keeps=NO ;
+		in.p_path= (char *)0 ;
+		in.p_keep=YES ;
+		in.p_keeps=NO ;
+	} else {
+		gr_init(&pathname) ;
+		if ( !phase->t_keep && !t_flag ) {
+			gr_cat(&pathname,TMP_DIR) ;
+			gr_cat(&pathname,"/") ;
+			gr_cat(&pathname,template) ;
+			out.p_keep=NO ;
+		} else {
+			gr_cat(&pathname,p_basename) ;
+			out.p_keep=YES ;
+		}
+		gr_cat(&pathname,phase->t_out) ;
+		out.p_path= gr_final(&pathname) ;
+		out.p_keeps= YES ;
+	}
+	scanlist( l_first(arguments), elem) {
+		if ( strcmp(l_content(*elem),out.p_path)==0 ) {
+			error("attempt to overwrite argument file") ;
+			return 0 ;
+		}
+	}
+	return 1 ;
+}
+
+disc_files() {
+	if ( in.p_path ) {
+		if ( !in.p_keep ) {
+			if ( unlink(in.p_path)!=0 ) {
+				werror("couldn't unlink %s",in.p_path);
+			}
+		}
+		if ( in.p_keeps ) throws(in.p_path) ;
+	}
+	in=out ;
+	out.p_path= (char *)0 ;
+	out.p_keeps=NO ;
+	out.p_keep=NO ;
+}
+
+rmtemps() {
+	/* Called in case of disaster, always remove the current output file!
+	*/
+	if ( out.p_path ) {
+		unlink(out.p_path) ;
+		if ( out.p_keeps ) throws(out.p_path) ;
+		out.p_path= (char *)0 ;
+		out.p_keeps=NO ;
+		out.p_keep=NO ;
+	}
+	if ( !in.p_keep && in.p_path ) {
+		unlink(in.p_path) ;
+		if ( in.p_keeps ) throws(in.p_path) ;
+		in.p_path= (char *)0 ;
+		out.p_keeps= NO ;
+		out.p_keep=NO ;
+	}
+}

+ 79 - 0
util/ack/grows.c

@@ -0,0 +1,79 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+/**************************************************************************/
+/*                                                                        */
+/*                 Bookkeeping for growing strings                        */
+/*                                                                        */
+/**************************************************************************/
+
+#include "ack.h"
+#include "grows.h"
+
+gr_add(id,c) register growstring *id ; char c ; {
+	if ( id->gr_size==id->gr_max) {
+		if ( id->gr_size==0 ) { /* The first time */
+			id->gr_max= 2*GR_MORE ;
+			id->gr_string= getcore(id->gr_max) ;
+		} else {
+			id->gr_max += GR_MORE ;
+			id->gr_string= changecore(id->gr_string,id->gr_max ) ;
+		}
+	}
+	*(id->gr_string+id->gr_size++)= c ;
+}
+
+gr_cat(id,string) growstring *id ; char *string ; {
+	register char *ptr ;
+
+#ifdef DEBUG
+	if ( id->gr_size && *(id->gr_string+id->gr_size-1) ) {
+		vprint("Non-zero terminated %*s\n",
+			id->gr_size, id->gr_string ) ;
+	}
+#endif
+	if ( id->gr_size ) id->gr_size-- ;
+	ptr=string ;
+	for (;;) {
+		gr_add(id,*ptr) ;
+		if ( *ptr++ ) continue ;
+		break ;
+	}
+}
+
+gr_throw(id) register growstring *id ; {
+	/* Throw the string away */
+	if ( id->gr_max==0 ) return ;
+	freecore(id->gr_string) ;
+	id->gr_max=0 ;
+	id->gr_size=0 ;
+}
+
+gr_init(id) growstring *id ; {
+	id->gr_size=0 ; id->gr_max=0 ;
+}
+
+char *gr_final(id) growstring *id ; {
+	/* Throw away the bookkeeping, adjust the string to its final
+	   length and return a pointer to a string to be get rid of with
+	   throws
+	*/
+	register char *retval ;
+	retval= keeps(gr_start(*id)) ;
+	gr_throw(id) ;
+	return retval ;
+}

+ 19 - 0
util/ack/grows.h

@@ -0,0 +1,19 @@
+/* struct used to identify and do bookkeeping for growing strings */
+
+typedef struct {
+	char            *gr_string ;    /* Points to start of string */
+	unsigned        gr_size ;       /* Current string size */
+	unsigned        gr_max ;        /* Maximum string size */
+} growstring ;
+
+#define GR_MORE         50      /* Steps to grow */
+
+#define gr_start(id)    (id).gr_string  /* The start of the string */
+
+/* Routines used */
+
+extern  int     gr_throw() ;    /* To free the core */
+extern  int     gr_add() ;      /* To add one character */
+extern  int     gr_cat() ;      /* concatenate the contents and the string */
+extern  int     gr_init() ;     /* Initialize the bookkeeping */
+extern  char    *gr_final() ;   /* Transform to a stable storage string */

+ 73 - 0
util/ack/list.c

@@ -0,0 +1,73 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include "ack.h"
+#include "list.h"
+
+/* List handling, operations allowed:
+	adding strings to the list,
+	throwing away whole lists,
+	linearize a list.
+
+Routines:
+	l_add(header,string) Add an element to a list.
+		header          List header, list_head *
+		string          String pointer, char *
+					the string is NOT copied
+
+	l_clear(header)      Delete an whole list.
+		header          List header, list_head *
+
+*/
+
+
+l_add(header,string) list_head *header ; char *string ; {
+	register list_elem *new;
+
+	/* NOSTRICT */
+	new= (list_elem *)getcore(sizeof *new);
+	l_content(*new)= string ;
+	/* NOSTRICT */
+	l_next(*new)= (list_elem *)0 ;
+	if ( !header->ca_first ) {
+		header->ca_first= new ;
+	} else {
+		header->ca_last->ca_next= new ;
+	}
+	header->ca_last= new ;
+}
+
+l_clear(header) list_head *header ; {
+	register list_elem *old, *next;
+	for ( old=header->ca_first ; old ; old= next ) {
+		next= old->ca_next ;
+		freecore((char *)old) ;
+	}
+	header->ca_first= (list_elem *) 0 ;
+	header->ca_last = (list_elem *) 0 ;
+}
+
+l_throw(header) list_head *header ; {
+	register list_elem *old, *next;
+	for ( old=header->ca_first ; old ; old= next ) {
+		throws(l_content(*old)) ;
+		next= old->ca_next ;
+		freecore((char *)old) ;
+	}
+	header->ca_first= (list_elem *) 0 ;
+	header->ca_last = (list_elem *) 0 ;
+}

+ 23 - 0
util/ack/list.h

@@ -0,0 +1,23 @@
+struct ca_elem {
+	struct ca_elem          *ca_next; /* The link */
+	char                    *ca_cont; /* The contents */
+} ;
+
+struct ca_list {
+	struct ca_elem          *ca_first; /* The head */
+	struct ca_elem          *ca_last;  /* The tail */
+} ;
+
+typedef struct ca_list list_head ;         /* The decl. for headers */
+typedef struct ca_elem list_elem ;         /* The decl. for elements */
+
+/* Some operations */
+
+/* Access */
+#define l_first(header)         (header).ca_first
+#define l_next(elem)            (elem).ca_next
+#define l_content(elem)         (elem).ca_cont
+
+/* To be used for scanning lists, ptr is the running variable */
+#define scanlist(elem,ptr) \
+	for ( ptr= elem ; ptr; ptr= l_next(*ptr) )

+ 340 - 0
util/ack/main.c

@@ -0,0 +1,340 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include "ack.h"
+#include "list.h"
+#include "trans.h"
+#include "../../h/em_path.h"
+#include "../../h/local.h"
+#include "data.h"
+#include <signal.h>
+
+static int sigs[] = { SIGINT, SIGHUP, SIGTERM, 0 } ;
+
+extern  char    *getenv();
+
+main(argc,argv) char **argv ; {
+	register list_elem *elem ;
+	register char *frontend ;
+	register int *n_sig ;
+
+	progname=argv[0];
+	varinit();
+	vieuwargs(argc,argv);
+	if ( (frontend=getenv("ACKFE")) ) {
+		setlist(frontend) ;
+	} else {
+		setlist(FRONTENDS);
+	}
+	setlist(machine);
+	transini();
+	scanneeds();
+	template= mktemp(ACKNAME) ;
+	if ( n_error && !k_flag ) return n_error ;
+
+	for ( n_sig=sigs ; *n_sig ; n_sig++ ) {
+		if ( signal(*n_sig,noodstop)==SIG_IGN ) {
+			signal(*n_sig,SIG_IGN) ;
+		}
+	}
+	scanlist ( l_first(arguments), elem ) {
+		if ( !process(l_content(*elem)) && !k_flag ) return 1 ;
+	}
+	orig.p_path= (char *)0 ;
+
+	if ( !combiner && !stopsuffix ) {
+		/* Call combiner directly without any transformation */
+		scanlist(l_first(tr_list),elem) {
+			if ( t_cont(*elem)->t_combine ) {
+				combiner= t_cont(*elem) ;
+			}
+		}
+	}
+
+	if ( !combiner || n_error ) return n_error ;
+
+	if ( !do_combine() ) return 1 ;
+
+	if ( g_flag ) {
+		return do_run();
+	}
+
+	return 0 ;
+}
+
+char *srcvar() {
+	return orig.p_path ;
+}
+
+varinit() {
+	/* initialize the string variables */
+	setsvar(keeps(HOME),keeps(EM_DIR)) ;
+	setpvar(keeps(SRC),srcvar)  ;
+}
+
+/************************* flag processing ***********************/
+
+vieuwargs(argc,argv) char **argv ; {
+	register char *argp;
+	register int nextarg ;
+	register int eaten ;
+
+	firstarg(argv[0]) ;
+
+	nextarg= 1 ;
+
+	while ( nextarg<argc ) {
+		argp= argv[nextarg] ;
+		nextarg++ ;
+		if ( argp[0]!='-' || argp[1]=='l' ) {
+			/* Not a flag, or a library */
+			l_add(&arguments,argp) ;
+			continue ;
+		}
+
+		/* Flags */
+		eaten=0 ; /* Did not 'eat' tail of flag yet */
+		switch ( argp[1] ) {
+	   case 'm':    if ( machine ) fuerror("Two machines?") ;
+			machine= &argp[2];
+			eaten=1 ;
+			break ;
+	   case 'o':    if ( nextarg>=argc ) {
+				fuerror("-o can't be the last flag") ;
+			}
+			if ( outfile ) fuerror("Two results?") ;
+			outfile= argv[nextarg++] ;
+			break ;
+	   case 'O':    Optflag++ ;
+			break ;
+	   case 'v':    v_flag++ ;
+			break ;
+	   case 'g':    g_flag++ ;
+			break ;
+	   case 'c':    if ( stopsuffix ) fuerror("Two -c flags") ;
+			stopsuffix= &argp[2]; eaten=1;
+			if ( *stopsuffix && *stopsuffix!=SUFCHAR ) {
+				fuerror("-c flag has invalid tail") ;
+			}
+			break ;
+	   case 'k':    k_flag++ ;
+			break ;
+	   case 't':    t_flag++ ;
+			break ;
+	   case 'R':    do_Rflag(argp); eaten=1;
+			break ;
+	   case 'r':    if ( argp[2]!=SUFCHAR ) {
+				error("-r must be followed by %c",SUFCHAR) ;
+			}
+			keeptail(&argp[2]); eaten=1 ;
+			break ;
+	   case '.':    if ( rts ) fuerror("Two run-time systems?") ;
+			rts= &argp[1] ; eaten=1;
+			keephead(rts) ; keeptail(rts) ;
+			break ;
+#ifdef DEBUG
+	   case 'd':    debug++ ;
+			break ;
+#endif
+	   case  0 :    nill_flag++ ; eaten++ ;
+			break;
+	   case 'w':    { register char *tokeep ;
+			  w_flag++;
+			  tokeep=keeps(argp) ;
+			  *tokeep |= NO_SCAN ;
+			  l_add(&flags,tokeep) ;
+			}
+			break ;
+	   default:     /* The flag is not recognized,
+			   put it on the list for the sub-processes
+			*/
+#ifdef DEBUG
+			if ( debug ) {
+				vprint("Flag %s: phase dependent\n",argp) ;
+			}
+#endif
+			l_add(&flags,keeps(argp)) ;
+			eaten=1 ;
+		}
+		if ( argp[2] && !eaten ) {
+			werror("Unexpected characters at end of %s",argp) ;
+		}
+	}
+	if ( !machine && ! (machine=getenv("ACKM")) ) {
+#ifdef ACKM
+		machine= ACKM;          /* The default machine */
+#else
+		fuerror("No machine specified") ;
+#endif
+	}
+	return ;
+}
+
+firstarg(argp) register char *argp ; {
+	register char *name ;
+
+	name=rindex(argp,'/') ;
+	if ( name && *(name+1) ) {
+		name++ ;
+	} else {
+		name= argp ;
+	}
+	if ( strcmp(name,"ack")==0 ) return ;
+	if ( strcmp(name,"acc")==0 || strcmp(name,"cc")==0 ) {
+		rts= ".c" ; keephead(rts) ; keeptail(rts) ;
+		return ;
+	}
+	if ( strcmp(name,"apc")==0 || strcmp(name,"pc")==0 ) {
+		rts= ".p" ; keephead(rts) ; keeptail(rts) ;
+		return ;
+	}
+	machine= name;
+}
+
+/************************* argument processing ***********************/
+
+process(arg) char *arg ; {
+	/* Process files & library arguments */
+	register list_elem *elem ;
+	register trf *phase ;
+	int first=YES ;
+
+#ifdef DEBUG
+	if ( debug ) vprint("Processing %s\n",arg) ;
+#endif
+	if ( arg[0]=='-' ) { l_add(&c_arguments,keeps(arg)) ; return 1 ; }
+	p_suffix= rindex(arg,SUFCHAR) ;
+	if ( p_basename ) throws(p_basename) ;
+	orig.p_keep= YES ;      /* Don't throw away the original ! */
+	orig.p_path= arg ;
+	p_basename= keeps(basename(arg)) ;
+	if ( !p_suffix ) { l_add(&c_arguments,keeps(arg)) ; return 1 ; }
+	/* Try to find a path through the transformations */
+	switch( setpath() ) {
+	case F_NOPATH :
+		error("Incomplete internal specification for %s",arg) ;
+		l_add(&c_arguments,keeps(arg)) ;
+		return 1 ;
+	case F_NOMATCH :
+		if ( stopsuffix ) werror("Unknown suffix in %s",arg) ;
+		l_add(&c_arguments,keeps(arg)) ;
+		return 1 ;
+	case F_OK :
+		break ;
+	}
+	orig.p_keeps= NO;
+	in= orig ;
+	scanlist(l_first(tr_list), elem) {
+		phase= t_cont(*elem) ;
+		if ( phase->t_do ) { /* perform this transformation */
+			if ( first ) {
+			   if ( !nill_flag ) {
+				printf("%s\n",arg) ;
+			   }
+			   switch ( phase->t_prep ) {
+			default : if ( !mayprep() ) break ;
+			case YES: if ( !transform(cpp_trafo) ) {
+					n_error++ ;
+#ifdef DEBUG
+					vprint("Pre-processor failed\n") ;
+#endif
+					return 0 ;
+				   }
+			case NO :
+				  break ;
+			   }
+			}
+			if ( cpp_trafo && stopsuffix &&
+			     strcmp(cpp_trafo->t_out,stopsuffix)==0 ) {
+				break ;
+			}
+			if ( !transform(phase) ) {
+				n_error++ ;
+#ifdef DEBUG
+				if ( debug ) {
+					vprint("phase %s for %s failed\n",
+					       phase->t_name,orig.p_path) ;
+				}
+#endif
+				return 0 ;
+			}
+			first=NO ;
+		}
+	}
+#ifdef DEBUG
+	if ( debug ) vprint("Transformation complete for %s\n",orig.p_path) ;
+#endif
+	if ( !in.p_keep ) fatal("attempt to discard the result file") ;
+	l_add(&c_arguments,keeps(in.p_path));
+	disc_files() ;
+	return 1 ;
+}
+
+mayprep() {
+	int file ;
+	char fc ;
+	file=open(in.p_path,0);
+	if ( file<0 ) return 0 ;
+	if ( read(file,&fc,1)!=1 ) fc=0 ;
+	close(file) ;
+	return fc=='#' ;
+}
+
+keephead(suffix) char *suffix ; {
+	l_add(&head_list, suffix) ;
+}
+
+keeptail(suffix) char *suffix ; {
+	l_add(&tail_list, suffix) ;
+}
+
+scanneeds() {
+	register list_elem *elem ;
+	scanlist(l_first(head_list), elem) { setneeds(l_content(*elem),0) ; }
+	l_clear(&head_list) ;
+	scanlist(l_first(tail_list), elem) { setneeds(l_content(*elem),1) ; }
+	l_clear(&tail_list) ;
+}
+
+setneeds(suffix,tail) char *suffix ; {
+	register list_elem *elem ;
+	register trf *phase ;
+
+	p_suffix= suffix ;
+	switch ( setpath() ) {
+	case F_OK :
+		scanlist( l_first(tr_list), elem ) {
+			phase = t_cont(*elem) ;
+			if ( phase->t_do ) {
+				if ( phase->t_needed ) {
+					if ( tail )
+						add_tail(phase->t_needed) ;
+					else
+						add_head(phase->t_needed) ;
+				}
+			}
+		}
+		break ;
+	case F_NOMATCH :
+		werror("\"%s\": unrecognized suffix",suffix) ;
+		break ;
+	case F_NOPATH :
+		werror("incomplete internal specification for %s files",
+			suffix) ;
+		break ;
+	}
+}

+ 208 - 0
util/ack/malloc.c

@@ -0,0 +1,208 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+
+#include "ack.h"
+#ifdef DEBUG
+#define ASSERT(p) if(!(p))botch("p");else
+botch(s)
+char *s;
+{
+	printf("malloc/free botched: %s\n",s);
+	abort();
+}
+#else
+#define ASSERT(p)
+#endif
+
+/*      avoid break bug */
+#ifdef pdp11
+#define GRANULE 64
+#else
+#define GRANULE 0
+#endif
+/*      C storage allocator
+ *      circular first-fit strategy
+ *      works with noncontiguous, but monotonically linked, arena
+ *      each block is preceded by a ptr to the (pointer of)
+ *      the next following block
+ *      blocks are exact number of words long
+ *      aligned to the data type requirements of ALIGN
+ *      pointers to blocks must have BUSY bit 0
+ *      bit in ptr is 1 for busy, 0 for idle
+ *      gaps in arena are merely noted as busy blocks
+ *      last block of arena (pointed to by alloct) is empty and
+ *      has a pointer to first
+ *      idle blocks are coalesced during space search
+ *
+ *      a different implementation may need to redefine
+ *      ALIGN, NALIGN, BLOCK, BUSY, INT
+ *      where INT is integer type to which a pointer can be cast
+*/
+#define INT int
+#define ALIGN int
+#define NALIGN 1
+#define WORD sizeof(union store)
+#define BLOCK 1024      /* a multiple of WORD*/
+#define BUSY 1
+#define NULL 0
+#define testbusy(p) ((INT)(p)&BUSY)
+#define setbusy(p) (union store *)((INT)(p)|BUSY)
+#define clearbusy(p) (union store *)((INT)(p)&~BUSY)
+
+union store { union store *ptr;
+	      ALIGN dummy[NALIGN];
+	      int calloc;       /*calloc clears an array of integers*/
+};
+
+static  union store allocs[2];  /*initial arena*/
+static  union store *allocp;    /*search ptr*/
+static  union store *alloct;    /*arena top*/
+static  union store *allocx;    /*for benefit of realloc*/
+char    *sbrk();
+
+char *
+malloc(nbytes)
+unsigned nbytes;
+{
+	register union store *p, *q;
+	register nw;
+	static temp;    /*coroutines assume no auto*/
+
+	if(allocs[0].ptr==0) {  /*first time*/
+		allocs[0].ptr = setbusy(&allocs[1]);
+		allocs[1].ptr = setbusy(&allocs[0]);
+		alloct = &allocs[1];
+		allocp = &allocs[0];
+	}
+	nw = (nbytes+WORD+WORD-1)/WORD;
+	ASSERT(allocp>=allocs && allocp<=alloct);
+	ASSERT(allock());
+	for(p=allocp; ; ) {
+		for(temp=0; ; ) {
+			if(!testbusy(p->ptr)) {
+				while(!testbusy((q=p->ptr)->ptr)) {
+					ASSERT(q>p&&q<alloct);
+					p->ptr = q->ptr;
+				}
+				if(q>=p+nw && p+nw>=p)
+					goto found;
+			}
+			q = p;
+			p = clearbusy(p->ptr);
+			if(p>q)
+				ASSERT(p<=alloct);
+			else if(q!=alloct || p!=allocs) {
+				ASSERT(q==alloct&&p==allocs);
+				return(NULL);
+			} else if(++temp>1)
+				break;
+		}
+		temp = ((nw+BLOCK/WORD)/(BLOCK/WORD))*(BLOCK/WORD);
+		q = (union store *)sbrk(0);
+		if(q+temp+GRANULE < q) {
+			return(NULL);
+		}
+		q = (union store *)sbrk(temp*WORD);
+		if((INT)q == -1) {
+			return(NULL);
+		}
+		ASSERT(q>alloct);
+		alloct->ptr = q;
+		if(q!=alloct+1)
+			alloct->ptr = setbusy(alloct->ptr);
+		alloct = q->ptr = q+temp-1;
+		alloct->ptr = setbusy(allocs);
+	}
+found:
+	allocp = p + nw;
+	ASSERT(allocp<=alloct);
+	if(q>allocp) {
+		allocx = allocp->ptr;
+		allocp->ptr = p->ptr;
+	}
+	p->ptr = setbusy(allocp);
+	return((char *)(p+1));
+}
+
+/*      freeing strategy tuned for LIFO allocation
+*/
+free(ap)
+register char *ap;
+{
+	register union store *p = (union store *)ap;
+
+	ASSERT(p>clearbusy(allocs[1].ptr)&&p<=alloct);
+	ASSERT(allock());
+	allocp = --p;
+	ASSERT(testbusy(p->ptr));
+	p->ptr = clearbusy(p->ptr);
+	ASSERT(p->ptr > allocp && p->ptr <= alloct);
+}
+
+/*      realloc(p, nbytes) reallocates a block obtained from malloc()
+ *      and freed since last call of malloc()
+ *      to have new size nbytes, and old content
+ *      returns new location, or 0 on failure
+*/
+
+char *
+realloc(p, nbytes)
+register union store *p;
+unsigned nbytes;
+{
+	register union store *q;
+	union store *s, *t;
+	register unsigned nw;
+	unsigned onw;
+
+	if(testbusy(p[-1].ptr))
+		free((char *)p);
+	onw = p[-1].ptr - p;
+	q = (union store *)malloc(nbytes);
+	if(q==NULL || q==p)
+		return((char *)q);
+	s = p;
+	t = q;
+	nw = (nbytes+WORD-1)/WORD;
+	if(nw<onw)
+		onw = nw;
+	while(onw--!=0)
+		*t++ = *s++;
+	if(q<p && q+nw>=p)
+		(q+(q+nw-p))->ptr = allocx;
+	return((char *)q);
+}
+
+#ifdef DEBUG
+allock()
+{
+#ifdef DEBUG
+	register union store *p;
+	int x;
+	x = 0;
+	for(p= &allocs[0]; clearbusy(p->ptr) > p; p=clearbusy(p->ptr)) {
+		if(p==allocp)
+			x++;
+	}
+	ASSERT(p==alloct);
+	return(x==1|p==allocp);
+#else
+	return(1);
+#endif
+}
+#endif

+ 121 - 0
util/ack/mktables.c

@@ -0,0 +1,121 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+char *fname = 0 ;
+char dname[200] ;
+char *tail ;
+
+FILE *intab ;
+FILE *dmach ;
+
+int index ;
+
+main(argc,argv) char **argv ; {
+	register i ;
+
+	start(argv[1]) ;
+	for ( i=2 ; i<argc ; i++ ) {
+		fname= argv[i] ;
+		readm() ;
+	}
+	stop(argc>2) ;
+	return 0 ;
+}
+
+start(dir) char *dir ; {
+	tail= dname ;
+	while ( *dir ) {
+		*tail++ = *dir ++ ;
+	}
+	if ( tail!=dname ) *tail++= '/' ;
+	index=0 ;
+	intab= fopen("intable.c","w");
+	dmach= fopen("dmach.c","w");
+	if ( intab==NULL || dmach==NULL ) {
+		fprintf(stderr,"Couln't create output file(s)\n");
+		exit ( 1) ;
+	}
+	fprintf(dmach,"#include \"dmach.h\"\n\ndmach\tmassoc[] = {\n") ;
+	fprintf(intab,"char intable[] = {\n") ;
+}
+
+stop(filled) {
+	fprintf(dmach,"\t{\"\",\t-1\t}\n} ;\n") ;
+	if ( !filled ) fprintf(intab,"\t0\n") ;
+	fprintf(intab,"\n} ;\n") ;
+	fclose(dmach); fclose(intab) ;
+}
+
+FILE *do_open(file) char *file ; {
+	strcpy(tail,file) ;
+	return fopen(dname,"r") ;
+}
+
+readm() {
+	register int i ;
+	register int token ;
+	register FILE *in ;
+
+	in=do_open(fname) ;
+	if ( in==NULL ) {
+		fprintf(stderr,"Cannot open %s\n",fname) ;
+		return ;
+	}
+	i=0 ;
+	fprintf(dmach,"\t{\"%s\",\t%d\t},\n",fname,index) ;
+	fprintf(intab,"\n/* %s */\n\t",fname) ;
+	for (;;) {
+		token=getc(in) ;
+		index++ ;
+		if ( ++i == 10 ) {
+			fprintf(intab,"\n\t") ;
+			i=0 ;
+		} else {
+			fprintf(intab," ") ;
+		}
+		if ( !isascii(token) || !(isprint(token) || isspace(token)) ){
+			if ( token!=EOF ) {
+			  fprintf(stderr,"warning: non-ascii in %s\n",fname) ;
+			  fprintf(intab,"%4d,",token) ;
+			} else {
+			  fprintf(intab,"  0,",token) ;
+			  break ;
+			}
+		} else if ( isprint(token) ) {
+			switch ( token ) {
+			case '\'': fprintf(intab,"'\\''") ; break ;
+			case '\\': fprintf(intab,"'\\\\'") ; break ;
+			default:   fprintf(intab," '%c'",token) ; break ;
+			}
+		} else switch ( token ) {
+		case '\n' : fprintf(intab,"'\\n'") ; break ;
+		case '\t' : fprintf(intab,"'\\t'") ; break ;
+		case '\r' : fprintf(intab,"'\\r'") ; break ;
+		case '\f' : fprintf(intab,"'\\f'") ; break ;
+		case ' '  : fprintf(intab," ' '")  ; break ;
+		default :   fprintf(stderr,"warning: unrec. %d\n",
+				token) ;
+			    fprintf(intab,"%4d",token) ;
+			    break ;
+		}
+		fprintf(intab,",") ;
+	}
+	fclose(in) ;
+}

+ 25 - 0
util/ack/pc/Makefile

@@ -0,0 +1,25 @@
+d=../../..
+h=$d/h
+
+PC_PATH=$d/lib/em_pc
+
+em_pc:          em_pc.c $h/local.h $h/em_path.h
+		cc -n -o em_pc -O -I$h em_pc.c
+
+cmp:            em_pc
+		cmp em_pc $(PC_PATH)
+
+install:        em_pc
+		cp em_pc $(PC_PATH)
+
+lint:
+		lint -hpxc -I$h em_pc.c
+
+clean:
+		rm -f *.o *.old
+
+opr:
+		make pr ^ opr
+
+pr:
+		pr -n em_pc.c

+ 681 - 0
util/ack/pc/em_pc.c

@@ -0,0 +1,681 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+/*
+ * put all the pieces of the pascal part of the EM project together
+ *      original author: Johan Stevenson, Vrije Universiteit, Amsterdam
+ *      heavily modified by: Ed Keizer, Vrije Universiteit, Amsterdam
+ */
+
+#include        <stdio.h>
+#include        <signal.h>
+#include        <sys/types.h>
+#include        <sys/dir.h>
+#include        <em_path.h>
+#include        <pc_size.h>
+#include        <local.h>
+
+#define	MAX_FLAG		40	/* The Max. no of '{' flags allowed */
+
+#define void                    int
+
+char	*pc_path	=	PEM_PATH ;
+char    *err_path       =	ERR_PATH;
+
+int     toterr;
+int     parent;
+
+char    *eeflag;
+char    *vvflag = "-V";
+int	no_pemflag = 0 ;
+char    *pemflag[MAX_FLAG];
+char    *eflag;
+char    *wflag;
+
+int     sizes[sz_last+1] = {
+	2,      /* sz_addr */
+	8,      /* sz_real */
+	0,      /* sz_head */
+	512,    /* sz_buff */
+	4096,   /* sz_mset */
+	2,      /* sz_iset */
+};
+
+#define CALLSIZE                60
+char    *callvector[CALLSIZE];
+char    **av;
+int     ac;
+int     fileargs;               /* number of recognized, processed args */
+int     flagargs;
+char    *progname;
+char    *source;
+
+#define CHARSIZE                2500
+#define CHARMARG                50
+char    charbuf[CHARSIZE];
+char    *charp                  = charbuf;
+
+char    *tmp_dir                = TMP_DIR;
+char    *unique                 = "pcXXXXXX";
+
+char    sigs[] = {
+	SIGHUP,
+	SIGINT,
+	SIGTERM,
+	0
+};
+
+/*
+ * forward function declarations
+ */
+void    finish();
+void    pem();
+int     list();
+char    *flag();
+char    *tempfile();
+char    **initvector();
+char    *basename();
+
+/*
+ * used library routines and data
+ */
+
+extern  char    *sys_errlist[];
+extern  int     errno;
+
+int     atoi();
+void    exit();
+void    sleep();
+void    execv();
+char    *sbrk();
+int     chdir();
+int     fork();
+int     wait();
+int     getpid();
+int     open();
+int     close();
+int     read();
+
+main(argc,argv) char **argv; {
+	register char *p;
+	char *files[3] ;
+
+	for (p = sigs; *p; p++)
+		if (signal(*p,finish) == SIG_IGN)
+			signal(*p,SIG_IGN);
+	ac = argc;
+	av = argv;
+	progname = *av++;
+	init();
+	while ( --ac>0 ) {
+		p = *av++;
+		if (*p == '-') {
+			flagargs++;
+			p = flag(p);
+		} else {
+			if ( fileargs>=3 ) fatal("Too many file arguments") ;
+			files[fileargs++]= p;
+		}
+	}
+	if ( fileargs!=3 ) fatal("Not enough arguments") ;
+	source=files[2] ;
+	pem(files[0],files[1]) ;
+	finish();
+}
+
+char *flag(f) char *f; {
+	register char *p;
+
+	p = f+1;
+	switch (*p++) {
+	case 'e':
+		eflag = f;
+		break;
+	case 'E':
+		eeflag = f;
+		break;
+	case 'w':
+		wflag = f;
+		break;
+	case 'V':
+		vvflag = f;
+		return(0);
+	case '{':
+		if ( no_pemflag>=MAX_FLAG ) {
+			ermess("too many flags, ignored %s",f) ;
+		} else {
+			pemflag[no_pemflag++] = p;
+		}
+		return(0);
+	case 'R':
+		pc_path= p ;
+		return 0 ;
+	case 'r' :
+		err_path= p ;
+		return 0 ;
+	default:
+		return(f);
+	}
+	if (*p)
+		fatal("bad flag %s",f);
+	return(0);
+}
+
+initsizes(f) FILE *f; {
+	register c, i;
+	register char *p;
+
+	p = vvflag + 2;
+	while (c = *p++) {
+		i = atoi(p);
+		while (*p >= '0' && *p <= '9')
+			p++;
+		switch (c) {
+		case 'p': sz_addr = i; continue;
+		case 'f': sz_real = i; continue;
+		case 'h': sz_head = i; continue;
+		case 'b': sz_buff = i; continue;
+		case 'm': sz_mset = i; continue;
+		case 'j': sz_iset = i; continue;
+		case 'w':
+		case 'i': if (i == 2) continue; break;
+		case 'l': if (i == 4) continue; break;
+		}
+		fatal("bad V-flag %s",vvflag);
+	}
+	if (sz_head == 0)
+		sz_head = 6*sz_word + 2*sz_addr;
+	for (i = 0; i <= sz_last; i++)
+		fprintf(f, "%d\n",sizes[i]);
+}
+
+/* ------------------ calling sequences -------------------- */
+
+pem(p,q) char *p,*q; {
+	register char **v,*d;
+	int i;
+	FILE *erfil;
+
+	v = initvector(pc_path);
+	d = tempfile('d');
+	if ((erfil = fopen(d,"w")) == NULL)
+		syserr(d);
+	initsizes(erfil);
+	fprintf(erfil,"%s\n",basename(source));
+	for ( i=0 ; i<no_pemflag ; i++ ) fprintf(erfil,"%s\n",pemflag[i]);
+	fclose(erfil);
+	*v++ = q;
+	*v++ = d;
+	call(v,p,(char *)0);
+	if (toterr == 0)
+		if (list(p,d) < 0)
+			toterr++;
+	donewith(d);
+}
+
+/* ------------------- miscellaneous routines --------------- */
+
+char *basename(p) char *p; {
+	register char *q;
+
+	q = p;
+	while (*q)
+		if (*q++ == '/')
+			p = q;
+	return(p);
+}
+
+char *tempfile(suf) {
+	register char *p,*q;
+	register i;
+
+	p = charp; q = tmp_dir;
+	while (*p = *q++)
+		p++;
+	*p++ = '/';
+	q = unique;
+	while (*p = *q++)
+		p++;
+	i = fileargs;
+	do
+		*p++ = i % 10 + '0';
+	while (i /= 10);
+	*p++ = '.'; *p++ = suf; *p++ = '\0';
+	q = charp; charp = p;
+	return(q);
+}
+
+call(v,in,out) char **v,*in,*out; {
+	register pid;
+	int     status;
+
+	while ((parent = fork()) < 0)
+		sleep(1);
+	if (parent == 0) {
+		if (in) {
+			close(0);
+			if (open(in,0) != 0)
+				syserr(in);
+		}
+		if (out) {
+			close(1);
+			if (creat(out,0666) != 1)
+				syserr(out);
+		}
+		*v = 0;
+		execv(callvector[0],callvector+1);
+		syserr(callvector[0]);
+	}
+	while ((pid = wait(&status)) != parent) {
+		if (pid == -1)
+			fatal("process %d disappeared",parent);
+		fatal("unknown child %d died",pid);
+	}
+	if ((status & 0177) > 3) {
+/*
+		if ((status & 0200) && tflag==0)
+			unlink("core");
+*/
+		fatal("signal %d in %s. Ask an expert for help",
+				status&0177,callvector[0]);
+	}
+	if (status & 0177400)
+		toterr++;
+}
+
+char **initvector(path) char *path; {
+	register char *p,**v;
+
+	v = callvector;
+	p = path;
+	*v++ = p;
+	*v++ = basename(p);
+	return(v);
+}
+
+finish() {
+	register char *p,*q;
+	register fd;
+	struct direct dir;
+
+	signal(SIGINT,SIG_IGN);
+	if (parent != 0) {
+		chdir(tmp_dir);
+		fd = open(".",0);
+		while (read(fd,(char *) &dir,sizeof dir) == sizeof dir) {
+			if (dir.d_ino == 0)
+				continue;
+			p = unique;
+			q = dir.d_name;
+			while (*p++ == *q++)
+				if (*p == '\0') {
+					unlink(dir.d_name);
+					break;
+				}
+		}
+		close(fd);
+	}
+	exit(toterr ? -1 : 0);
+}
+
+
+donewith(p) char *p; {
+
+	if (p >= charbuf && p < &charbuf[CHARSIZE])
+		unlink(p);
+}
+
+init() {
+	register char *p;
+	register i,fd;
+
+	if ((fd = open(tmp_dir,0)) < 0)
+		tmp_dir = ".";
+	close(fd);
+	p = unique+2;
+	parent = i = getpid();
+	do
+		*p++ = i % 10 + '0';
+	while (i /= 10);
+	*p++ = '.'; *p = '\0';
+}
+
+/* ------------------- pascal listing ----------------------- */
+
+#define MAXERNO         300
+#define MAXERRLIST      10
+#define IDMAX           8
+
+struct errec {
+	int     erno;
+	char    mess[IDMAX+1];
+	int     mesi;
+	int     chno;
+	int     lino;
+};
+
+struct  errec   curr;
+struct  errec   next;
+
+int     *index          = 0;
+int     maxerno;
+
+int     errerr;
+int     errfat;
+
+int     listlino;
+int     listorig;
+int     listrela;
+char    *listfnam;
+
+FILE    *inpfil;
+FILE    *mesfil;
+FILE    *errfil;
+
+int     errorline();
+int     geterrec();
+int     nexterror();
+
+int list(p,q) char *p,*q; {
+
+	if ((errfil = fopen(q,"r")) == NULL)
+		syserr(q);
+	if (geterrec() == 0)
+		if (eeflag==0) {
+			fclose(errfil);
+			return(0);
+		}
+	if (index == 0) {
+		index = (int *) sbrk(MAXERNO * sizeof index[0]);
+		fillindex();
+	}
+	if ((inpfil = fopen(p,"r")) == NULL)
+		syserr(p);
+	errerr = 0;
+	errfat = 0;
+	listlino = 0;
+	listorig = 0;
+	listrela = 0;
+	listfnam = source;
+	if (eeflag)
+		listfull();
+	else if (eflag)
+		listpartial();
+	else
+		listshort();
+	fclose(errfil);
+	fclose(inpfil);
+	fflush(stdout);
+	return(errfat ? -1 : 1);
+}
+
+listshort() {
+
+	while (nexterror()) {
+		while (listlino < curr.lino)
+			nextline(0);
+		printf("%s, %d: ",listfnam,listrela);
+		string(&curr);
+	}
+}
+
+listfull() {
+
+	if (nexterror())
+		do {
+			do {
+				nextline(1);
+			} while (listlino < curr.lino);
+		} while (errorline());
+	while (nextline(1))
+		;
+}
+
+listpartial() {
+
+	if (nexterror())
+		do {
+			do {
+				nextline(listlino >= curr.lino-2);
+			} while (listlino < curr.lino);
+		} while (errorline());
+}
+
+int nextline(printing) {
+	register ch;
+
+	listlino++;
+	ch = getc(inpfil);
+	if (ch == '#') {
+		if (lineline(printing) == 0)
+			fatal("bad line directive");
+		return(1);
+	}
+	listrela++;
+	if (listfnam == source)
+		listorig++;
+	if (ch != EOF) {
+		if (printing)
+			printf("%5d\t",listorig);
+		do {
+			if (printing)
+				putchar(ch);
+			if (ch == '\n')
+				return(1);
+		} while ((ch = getc(inpfil)) != EOF);
+	}
+	return(0);
+}
+
+lineline(printing) {
+	register ch;
+	register char *p,*q;
+	static char line[100];
+
+	p = line;
+	while ((ch = getc(inpfil)) != '\n') {
+		if (ch == EOF || p == &line[100-1])
+			return(0);
+		*p++ = ch;
+	}
+	*p = '\0'; p = line;
+	if (printing)
+		printf("\t#%s\n",p);
+	if ((listrela = atoi(p)-1) < 0)
+		return(0);
+	while ((ch = *p++) != '"')
+		if (ch == '\0')
+			return(0);
+	q = p;
+	while (ch = *p++) {
+		if (ch == '"') {
+			*--p = '\0';
+			if ( source ) {
+				listfnam = strcmp(q,source)==0 ? source : q;
+				return(1);
+			}
+			source=q ; listfnam=q ;
+			return 1 ;
+		}
+		if (ch == '/')
+			q = p;
+	}
+	return(0);
+}
+
+int errorline() {
+	register c;
+	register struct errec *p,*q;
+	struct  errec   lerr[MAXERRLIST];
+	int     goon;
+
+	printf("*** ***");
+	p = lerr;
+	c = 0;
+	do {
+		if (c < curr.chno) {
+			printf("%*c",curr.chno-c,'^');
+			c = curr.chno;
+		}
+		if (p < &lerr[MAXERRLIST])
+			*p++ = curr;
+		goon = nexterror();
+	} while (goon && curr.lino==listlino);
+	putchar('\n');
+	for (q = lerr; q < p; q++)
+		string(q);
+	putchar('\n');
+	return(goon);
+}
+
+int geterrec() {
+	register ch;
+	register char *p;
+
+	ch = getc(errfil);
+	next.erno = 0;
+	next.mesi = -1;
+	next.mess[0] = '\0';
+	if (ch == EOF)
+		return(0);
+	if (ch >= '0' && ch <= '9') {
+		ch = getnum(ch,&next.mesi);
+	} else if (ch == '\'') {
+		p = next.mess;
+		while ((ch = getc(errfil)) != ' ' && ch != EOF)
+			if (p < &next.mess[IDMAX])
+				*p++ = ch;
+		*p = '\0';
+	}
+	ch = getnum(ch, &next.erno);
+	ch = getnum(ch, &next.lino);
+	ch = getnum(ch, &next.chno);
+	if (ch != '\n')
+		fatal("bad error line");
+	return(1);
+}
+
+int getnum(ch, ip) register ch; register *ip; {
+	register neg;
+
+	*ip = 0;
+	while (ch == ' ')
+		ch = getc(errfil);
+	if (neg = ch=='-')
+		ch = getc(errfil);
+	while (ch >= '0' && ch <= '9') {
+		*ip = *ip * 10 - '0' + ch;
+		ch = getc(errfil);
+	}
+	if (neg)
+		*ip = -(*ip);
+	return(ch);
+}
+
+int nexterror() {
+
+	do {    /* skip warnings if wflag */
+		curr = next;
+		if (curr.erno == 0)
+			return(0);
+		for (;;) {
+			if (geterrec() == 0)
+				break;
+			if (next.lino != curr.lino || next.chno != curr.chno)
+				break;
+			if (curr.erno < 0 && next.erno > 0)
+				/* promote warnings if they cause fatals */
+				curr.erno = -curr.erno;
+			if (next.mess[0] != '\0' || next.mesi != -1)
+				/* give all parameterized errors */
+				break;
+			if (curr.mess[0] != '\0' || curr.mesi != -1)
+				/* and at least a non-parameterized one */
+				break;
+		}
+	} while (curr.erno < 0 && wflag != 0);
+	return(1);
+}
+
+fillindex() {
+	register *ip,n,c;
+
+	if ((mesfil = fopen(err_path,"r")) == NULL)
+		syserr(err_path);
+	ip = index;
+	*ip++ = 0;
+	n = 0;
+	while ((c = getc(mesfil)) != EOF) {
+		n++;
+		if (c == '\n') {
+			*ip++ = n;
+			if (ip > &index[MAXERNO])
+				fatal("too many errors on %s",err_path);
+		}
+	}
+	maxerno = ip - index;
+}
+
+string(ep) register struct errec *ep; {
+	register i,n;
+
+	errerr++;
+	if ((i = ep->erno) < 0) {
+		i = -i;
+		printf("Warning: ");
+	} else
+		errfat++;
+	if (i == 0 || i >= maxerno)
+		fatal("bad error number %d",i);
+	n = index[i] - index[i-1];
+	fseek(mesfil,(long)index[i-1],0);
+	while (--n >= 0) {
+		i = getc(mesfil);
+		if (i == '%' && --n>=0) {
+			i = getc(mesfil);
+			if (i == 'i')
+				printf("%d", ep->mesi);
+			else if (i == 's')
+				printf("%s", ep->mess);
+			else
+				putchar(i);
+		} else
+			putchar(i);
+	}
+}
+
+/* ------------------- error routines -------------------------- */
+
+/* VARARGS1 */
+void ermess(s,a1,a2,a3,a4) char *s; {
+
+	fprintf(stderr,"%s: ",progname);
+	fprintf(stderr,s,a1,a2,a3,a4);
+	fprintf(stderr,"\n");
+}
+
+syserr(s) char *s; {
+	fatal("%s: %s",s,sys_errlist[errno]);
+}
+
+/* VARARGS1 */
+void fatal(s,a1,a2,a3,a4) char *s; {
+
+	ermess(s,a1,a2,a3,a4);
+	toterr++;
+	finish();
+}

+ 288 - 0
util/ack/rmach.c

@@ -0,0 +1,288 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include "ack.h"
+#include "../../h/em_path.h"
+#include "list.h"
+#include "trans.h"
+#include "grows.h"
+#include "dmach.h"
+#include "data.h"
+#include <stdio.h>
+
+/************************************************************************/
+/*                                                                      */
+/*           Read machine definitions and transformations               */
+/*                                                                      */
+/************************************************************************/
+
+#define COMMENT '#'
+
+#define VAR     "var"
+#define PASS    "name"
+#define IN      "from"
+#define OUT     "to"
+#define PROG    "program"
+#define MAPF    "mapflag"
+#define ARGS    "args"
+#define PROP    "prop"
+#define RUNT    "rts"
+#define NEEDT	"need"
+#define END     "end"
+
+extern growstring scanb();
+extern growstring scanvars();
+
+int getline() ;
+int getinchar() ;
+static char *ty_name ;
+static char *bol ;
+
+
+static char *inname ;
+
+setlist(name) char *name ; {
+	/* Name is sought in the internal tables,
+	   if not present, the a file of that name is sought
+	   in first the current and then the EM Lib directory
+	*/
+
+	inname=name ;
+	open_in(name) ;
+	while ( getline() ) {
+		if ( strcmp(VAR,ty_name)==0 ) {
+			doassign(bol,(char *)0,0) ;
+		} else
+		if ( strcmp(PASS,ty_name)==0 ) {
+			intrf() ;
+		} else
+			error("unknown keyword %s",ty_name) ;
+	}
+	close_in();
+#ifdef DEBUG
+	if ( debug>=3 ) vprint("End %s\n",name) ;
+#endif
+}
+
+intrf() {
+	register trf *new ;
+	register char *ptr ;
+	growstring bline, vline ;
+	int twice ;
+
+	new= (trf *)getcore(sizeof *new) ;
+	new->t_name= keeps(bol) ;
+	for (;;) {
+		if ( !getline() ) {
+			fuerror("unexpected EOF on %s",inname) ;
+		}
+		twice= NO ;
+		if ( strcmp(ty_name,IN)==0 ) {
+			if ( new->t_in ) twice=YES ;
+			new->t_in= keeps(bol);
+		} else
+		if ( strcmp(ty_name,OUT)==0 ) {
+			if ( new->t_out ) twice=YES ;
+			new->t_out= keeps(bol);
+		} else
+		if ( strcmp(ty_name,PROG)==0 ) {
+			if ( new->t_prog ) twice=YES ;
+			bline= scanb(bol);                /* Scan for \ */
+			vline= scanvars(gr_start(bline)); /* Scan for {} */
+			gr_throw(&bline);
+			new->t_prog= gr_final(&vline);
+			clr_noscan(new->t_prog);
+		} else
+		if ( strcmp(ty_name,MAPF)==0 ) {
+			/* First read the mapflags line
+				and scan for backslashes */
+			bline= scanb(bol) ;
+			l_add(&new->t_mapf,gr_final(&bline)) ;
+		} else
+		if ( strcmp(ty_name,ARGS)==0 ) {
+			if ( new->t_argd ) twice=YES ;
+			bline= scanb(bol) ;
+			new->t_argd= keeps(gr_start(bline)) ;
+			gr_throw(&bline) ;
+		} else
+		if ( strcmp(ty_name,PROP)==0 ) {
+			for ( ptr=bol ; *ptr ; ptr++ ) {
+				switch( *ptr ) {
+				case C_IN: new->t_stdin= YES ; break ;
+				case C_OUT: new->t_stdout= YES ; break ;
+				case 'P': new->t_isprep= YES ; break ;
+				case 'p': new->t_prep= YES ; break ;
+				case 'm': new->t_prep= MAYBE ; break ;
+				case 'O': new->t_optim= YES ; break ;
+				case 'C': new->t_combine= YES ; break ;
+				default :
+				  error("Unkown option %c in %s for %s",
+					*ptr,new->t_name,inname) ;
+				  break ;
+				}
+			}
+		} else
+		if ( strcmp(ty_name,RUNT)==0 ) {
+			if ( new->t_rts ) twice=YES ;
+			new->t_rts= keeps(bol) ;
+		} else
+		if ( strcmp(ty_name,NEEDT)==0 ) {
+			if ( new->t_needed ) twice=YES ;
+			new->t_needed= keeps(bol) ;
+		} else
+		if ( strcmp(ty_name,END)==0 ) {
+			break ;
+		} else {
+			fuerror("illegal keyword %s %s",ty_name,bol);
+		}
+		if ( twice ) {
+			werror("%s: specified twice for %s",
+				ty_name, new->t_name) ;
+		}
+	}
+	if ( ! ( new->t_name && new->t_out && new->t_prog ) ) {
+		fuerror("insufficient specification for %s in %s",
+			new->t_name,inname) ;
+	}
+	if ( ! new->t_argd ) new->t_argd="" ;
+#ifdef DEBUG
+	if ( debug>=3 ) {
+		register list_elem *elem ;
+		vprint("%s: from %s to %s '%s'\n",
+			new->t_name,new->t_in,new->t_out,new->t_prog) ;
+		vprint("\targs: ") ; prns(new->t_argd) ;
+		scanlist( l_first(new->t_mapf), elem ) {
+			vprint("\t%s\n",l_content(*elem)) ;
+		}
+		if ( new->t_rts ) vprint("\trts: %s\n",new->t_rts) ;
+		if ( new->t_needed ) vprint("\tneeded: %s\n",new->t_needed) ;
+	}
+#endif
+	l_add(&tr_list,(char *)new) ;
+}
+
+/************************** IO from core or file *******************/
+
+static  int             incore ;
+static  growstring      rline ;
+static  FILE            *infile ;
+static  char            *inptr ;
+
+open_in(name) register char *name ; {
+	register dmach *cmac ;
+
+	gr_init(&rline) ;
+	for ( cmac= massoc ; cmac->ma_index!= -1 ; cmac++ ) {
+		if ( strcmp(name,cmac->ma_name)==0 ) {
+			incore=YES ;
+			inptr= &intable[cmac->ma_index] ;
+			return ;
+		}
+	}
+	/* Not in core */
+	incore= NO ;
+	gr_cat(&rline,ACK_DIR); gr_cat(&rline,"/") ;
+	gr_cat(&rline,name) ;
+	infile= fopen(gr_start(rline),"r") ;
+	if ( !infile ) {
+		infile= fopen(name,"r") ;
+	}
+	if ( infile==NULL ) {
+		fuerror("Cannot find description for %s",name) ;
+	}
+}
+
+close_in() {
+	if ( !incore ) fclose(infile) ;
+	gr_throw(&rline) ;
+}
+
+char *readline() {
+	/* Get a line from the input,
+	   return 0 if at end,
+	   The line is stored in a volatile buffer,
+	   a pointer to the line is returned.
+	*/
+	register int nchar ;
+	enum { BOL, ESCAPE, SKIPPING, MOL } state = BOL ;
+
+	gr_throw(&rline) ;
+	for (;;) {
+		nchar= getinchar() ;
+		if ( nchar==EOF ) {
+			if ( state!=BOL ) {
+				werror("incomplete line in %s", inname) ;
+			}
+			return 0 ;
+		}
+		if ( state==SKIPPING ) {
+			if ( nchar=='\n' ) {
+				state= MOL ;
+			} else {
+				continue ;
+			}
+		}
+		if ( state==ESCAPE ) {
+			switch( nchar ) {
+			case '\n' :
+				break ;
+			default :
+				gr_add(&rline,BSLASH) ;
+			case COMMENT :
+			case BSLASH :
+				gr_add(&rline,nchar) ;
+				break ;
+			}
+			state= MOL ;
+			continue ;
+		}
+		switch ( nchar ) {
+		case '\n' :     gr_add(&rline,0) ;
+				return gr_start(rline) ;
+		case COMMENT :  state= SKIPPING ;
+				break ;
+		case BSLASH :   state= ESCAPE ;
+				break ;
+		default :       gr_add(&rline,nchar) ;
+				state= MOL ;
+		}
+	}
+}
+
+int getinchar() {
+	if ( incore ) {
+		if ( *inptr==0 ) return EOF ;
+		return *inptr++ ;
+	}
+	return getc(infile) ;
+}
+
+int getline() {
+	register char *c_ptr ;
+
+	do {
+		if ( (c_ptr=readline())==(char *)0 ) return 0 ;
+		ty_name= skipblank(c_ptr) ;
+	} while ( *ty_name==0 ) ;
+	c_ptr= firstblank(ty_name) ;
+	if ( *c_ptr ) {
+		*c_ptr++ =0 ;
+		c_ptr= skipblank(c_ptr) ;
+	}
+	bol= c_ptr ;
+	return 1 ;
+}

+ 154 - 0
util/ack/run.c

@@ -0,0 +1,154 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include "ack.h"
+#include "list.h"
+#include "trans.h"
+#include "data.h"
+#include <signal.h>
+
+#define ARG_MORE  40            /* The size of args chunks to allocate */
+
+static char      **arglist ;    /* The first argument */
+static unsigned  argcount ;     /* The current number of arguments */
+static unsigned  argmax;        /* The maximum number of arguments so far */
+
+int do_run() {
+	fatal("-g flag not implemeted") ;
+	/*NOTREACHED*/
+	return 0 ;
+}
+
+int runphase(phase) register trf *phase ; {
+	register list_elem *elem ;
+
+	if ( v_flag || debug ) {
+		if ( v_flag==1 && !debug ) {
+			vprint("%s",phase->t_name) ;
+			if ( !phase->t_combine ) {
+				vprint(" %s%s\n",p_basename,
+					rindex(in.p_path,SUFCHAR) ) ;
+			} else {
+				scanlist(l_first(c_arguments), elem) {
+					vprint(" %s",l_content(*elem)) ;
+				}
+				vprint("\n") ;
+			}
+		} else {
+			/* list all args */
+			vprint("%s",phase->t_prog) ;
+			scanlist(l_first(phase->t_flags), elem) {
+				vprint(" %s",l_content(*elem)) ;
+			}
+			scanlist(l_first(phase->t_args), elem) {
+				vprint(" %s",l_content(*elem)) ;
+			}
+			vprint("\n") ;
+		}
+	}
+	argcount=0 ;
+	x_arg(phase->t_name) ;
+	scanlist(l_first(phase->t_flags), elem) {
+		x_arg(l_content(*elem)) ;
+	}
+	scanlist(l_first(phase->t_args), elem) {
+		x_arg(l_content(*elem)) ;
+	}
+	x_arg( (char *)0 ) ;
+	return run_exec(phase) ;
+}
+
+int run_exec(phase) trf *phase ; {
+	int status, child, waitchild ;
+
+	do_flush();
+	while ( (child=fork())== -1 ) ;
+	if ( child ) {
+		/* The parent */
+		do {
+			waitchild= wait(&status) ;
+			if ( waitchild== -1 ) {
+				fatal("missing child") ;
+			}
+		} while ( waitchild!=child) ;
+		if ( status ) {
+			if ( status&0200 && (status&0177)!=SIGQUIT &&
+				!t_flag ) unlink("core") ;
+			switch ( status&0177 ) {
+			case 0 :
+				break ;
+			case SIGHUP:
+			case SIGINT:
+			case SIGQUIT:
+			case SIGTERM:
+				quit(-5) ;
+			default:
+				error("%s died with signal %d",
+					phase->t_prog,status&0177) ;
+			}
+			/* The assumption is that processes voluntarely
+			   dying with a non-zero status already produced
+			   some sort of error message to the outside world.
+			*/
+			n_error++ ;
+			return 0 ;
+		}
+		return 1 ; /* From the parent */
+	}
+	/* The child */
+	if ( phase->t_stdin ) {
+		if ( !in.p_path ) {
+			fatal("no input file for %s",phase->t_name) ;
+		}
+		close(0) ;
+		if ( open(in.p_path,0)!=0 ) {
+			error("cannot open %s",in.p_path) ;
+			exit(1) ;
+		}
+	}
+	if ( phase->t_stdout ) {
+		if ( !out.p_path ) {
+			fatal("no output file for %s",phase->t_name) ;
+		}
+		close(1) ;
+		if ( creat(out.p_path,0666)!=1 ) {
+			close(1); dup(2);
+			error("cannot open %s",out.p_path) ;
+			exit(1) ;
+		}
+	}
+	execv(phase->t_prog,arglist) ;
+	if ( phase->t_stdout ) { close(1) ; dup(2) ; }
+	error("Cannot execute %s",phase->t_prog) ;
+	exit(1) ;
+	/*NOTREACHED*/
+}
+
+x_arg(string) char *string ; {
+	/* Add one execute argument to the argument vector */
+	if ( argcount==argmax ) {
+		if ( argmax==0 ) {
+			argmax= 2*ARG_MORE ;
+			arglist= (char **)getcore(argmax*sizeof (char *)) ;
+		} else {
+			argmax += ARG_MORE ;
+			arglist= (char **)changecore((char *)arglist,
+					argmax*sizeof (char *)) ;
+		}
+	}
+	*(arglist+argcount++) = string ;
+}

+ 244 - 0
util/ack/scan.c

@@ -0,0 +1,244 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include "ack.h"
+#include "list.h"
+#include "trans.h"
+#include "data.h"
+
+enum f_path setpath() { /* Try to find a transformation path */
+
+	start_scan();
+	/*
+		The end result is the setting of the t_do flags
+		in the transformation list.
+		The list is scanned for possible transformations
+		stopping at stopsuffix or a combine transformation.
+		The scan flags are set by this process.
+		When a transformation is found, it is compared with
+		the last transformation found, if better (or the first)
+		the scan bits are copied to the t_do bits, except for
+		the combiner which is remembered in a global pointer.
+		At the end of all transformations for all files, the combiner
+		is called, unless errors occurred.
+	*/
+	try(l_first(tr_list),p_suffix);
+	return scan_end();
+}
+
+/******************** data used only while scanning *******************/
+
+static  int     last_ncount;    /* The # of non-optimizing transformations
+				   in the best path sofar */
+
+static  int     last_ocount;    /* The # of optimizing transformations in the
+				   best path sofar */
+static  int     com_err;        /* Complain only once about multiple linkers*/
+
+static  trf     *final;         /* The last non-combining transformation */
+
+static  int     suf_found;      /* Was the suffix at least recognized ? */
+
+/********************       The hard work          ********************/
+
+start_scan() {
+	register list_elem *scan ;
+
+	scanlist(l_first(tr_list),scan) {
+		t_cont(*scan)->t_do=NO ; t_cont(*scan)->t_scan=NO ;
+		t_cont(*scan)->t_keep=NO ;
+	}
+	final= (trf *)0 ;
+	suf_found= 0 ;
+#ifdef DEBUG
+	if ( debug>=3 ) vprint("Scan_start\n");
+#endif
+	last_ncount= -1 ;
+	last_ocount= 0 ;
+}
+
+try(f_scan,suffix) list_elem *f_scan; char *suffix; {
+	register list_elem *scan ;
+	register trf  *trafo ;
+	/* Try to find a transformation path starting at f_scan for a
+	   file with the indicated suffix.
+	   If the suffix is already reached or the combiner is found
+	   call scan_found() to OK the scan.
+	   If a transformation is found it calls itself recursively
+	   with as starting point the next transformation in the list.
+	*/
+	if ( stopsuffix && *stopsuffix && strcmp(stopsuffix,suffix)==0 ) {
+		scan_found();
+		return ;
+	}
+	scanlist(f_scan, scan) {
+		trafo= t_cont(*scan) ;
+		if ( satisfy(trafo,suffix) ) {
+			/* Found a transformation */
+			suf_found= 1;
+#ifdef DEBUG
+			if ( debug>=4 ) {
+				vprint("Found %s for %s: result %s\n",
+				       trafo->t_name,suffix,trafo->t_out);
+			}
+#endif
+			trafo->t_scan=YES ;
+			if ( trafo->t_prep ) {
+				if ( !cpp_trafo ) {
+					find_cpp() ;
+				}
+				if ( stopsuffix &&
+				     strcmp(stopsuffix,
+					cpp_trafo->t_out)==0 )
+				{
+					scan_found() ;
+					return ;
+				}
+			}
+			if ( trafo->t_combine ) {
+				if ( stopsuffix ) {
+					trafo->t_scan=NO;
+					if ( *stopsuffix ) return ;
+				} else {
+					if( combiner &&
+					    combiner!=trafo && !com_err ){
+					       com_err++ ;
+werror("Multiple linkers present %s and %s",
+	trafo->t_name,combiner->t_name) ;
+					} else {
+						combiner=trafo;
+					}
+				}
+				scan_found() ;
+			} else {
+				try(l_next(*scan),trafo->t_out);
+			}
+			trafo->t_scan= NO ;
+		}
+	}
+}
+
+scan_found() {
+	register list_elem *scan;
+	int ncount, ocount ;
+	register trf *keepit ;
+
+	keepit= (trf *)0 ;
+	suf_found= 1;
+#ifdef DEBUG
+	if ( debug>=3 ) vprint("Scan found\n") ;
+#endif
+	/* Gather data used in comparison */
+	ncount=0; ocount=0;
+	scanlist(l_first(tr_list),scan) {
+		if (t_cont(*scan)->t_scan) {
+#ifdef DEBUG
+			if ( debug>=4 ) vprint("%s-",t_cont(*scan)->t_name) ;
+#endif
+			if( t_cont(*scan)->t_optim ) ocount++ ;else ncount++ ;
+			if ( !(t_cont(*scan)->t_combine) ) {
+				keepit= t_cont(*scan) ;
+			}
+		}
+	}
+#ifdef DEBUG
+	if ( debug>=4 ) vprint("\n");
+#endif
+	/* Is this transformation better then any found yet ? */
+#ifdef DEBUG
+	if ( debug>=3 ) {
+		vprint("old n:%d, o:%d - new n:%d, o:%d\n",
+			last_ncount,last_ocount,ncount,ocount) ;
+	}
+#endif
+	if ( last_ncount== -1 ||                /* None found yet */
+	     last_ncount>ncount ||              /* Shorter nec. path */
+	     (last_ncount==ncount &&            /* Same nec. path, optimize?*/
+		(Optflag? last_ocount<ocount : last_ocount>ocount ) ) ) {
+		/* Yes it is */
+#ifdef DEBUG
+		if ( debug>=3 ) vprint("Better\n");
+#endif
+		scanlist(l_first(tr_list),scan) {
+			t_cont(*scan)->t_do=t_cont(*scan)->t_scan;
+		}
+		last_ncount=ncount; last_ocount=ocount;
+		if ( keepit ) final=keepit ;
+	}
+}
+
+int satisfy(trafo,suffix) register trf *trafo; char *suffix ; {
+	register char *f_char, *l_char ;
+	/* Check whether this transformation is present for
+	   the current machine and the parameter suffix is among
+	   the input suffices. If so, return 1. 0 otherwise
+	*/
+	if ( trafo->t_isprep ) return 0 ;
+	l_char=trafo->t_in ;
+	while ( l_char ) {
+		f_char= l_char ;
+		if ( *f_char!=SUFCHAR || ! *(f_char+1) ) {
+			fuerror("Illegal input suffix entry for %s",
+				trafo->t_name) ;
+		}
+		l_char=index(f_char+1,SUFCHAR);
+		if ( l_char ? strncmp(f_char,suffix,l_char-f_char)==0 :
+			      strcmp(f_char,suffix)==0 ) {
+			return 1 ;
+		}
+	}
+	return 0 ;
+}
+
+enum f_path scan_end() {    /* Finalization */
+	/* Return value indicating whether a transformation was found */
+	/* Set the flags for the transformation up to, but not including,
+	   the combiner
+	*/
+
+#ifdef DEBUG
+	if ( debug>=3 ) vprint("End_scan\n");
+#endif
+	if ( last_ncount== -1 ) return suf_found ? F_NOPATH : F_NOMATCH ;
+#ifdef DEBUG
+	if ( debug>=2 ) vprint("Transformation found\n");
+#endif
+	if ( cpp_trafo && stopsuffix &&
+	     strcmp(stopsuffix,cpp_trafo->t_out)==0 ) {
+		final= cpp_trafo ;
+	}
+	/* There might not be a final when the file can be eaten
+	   by the combiner
+	*/
+	if ( final ) final->t_keep=YES ;
+	if ( combiner ) {
+		if ( !combiner->t_do ) error("Combiner YES/NO");
+		combiner->t_do=NO ;
+	}
+	return F_OK ;
+}
+
+find_cpp() {
+	register list_elem *elem ;
+	scanlist( l_first(tr_list), elem ) {
+		if ( t_cont(*elem)->t_isprep ) {
+			if ( cpp_trafo ) fuerror("Multiple cpp's present") ;
+			cpp_trafo= t_cont(*elem) ;
+		}
+	}
+	if ( !cpp_trafo ) fuerror("No cpp present") ;
+}

+ 125 - 0
util/ack/svars.c

@@ -0,0 +1,125 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include "ack.h"
+
+/*      The processing of string valued variables,
+	this is an almost self contained module.
+
+	Five externally visible routines:
+
+	setsvar(name,result)
+		Associate the name with the result.
+
+		name    a string pointer
+		result  a string pointer
+
+	setpvar(name,routine)
+		Associate the name with the routine.
+
+		name    a string pointer
+		routine a routine id
+
+	   The parameters name and result are supposed to be pointing to
+	   non-volatile string storage used only for this call.
+
+	char *getvar(name)
+		returns the pointer to a string associated with name,
+		the pointer is produced by returning result or the
+		value returned by calling the routine.
+
+		name    a string pointer
+
+	Other routines called
+
+	fatal(args*)    When something goes wrong
+	getcore(size)   Core allocation
+
+*/
+
+extern  char    *getcore();
+extern          fatal();
+
+struct vars {
+	char                            *v_name;
+	enum { routine, string }        v_type;
+
+	union {
+		char    *v_string;
+		char    *(*v_routine)();
+	}                               v_value ;
+	struct vars                     *v_next ;
+};
+
+static struct vars *v_first ;
+
+static struct vars *newvar(name) char *name; {
+	register struct vars *new ;
+
+	for ( new=v_first ; new ; new= new->v_next ) {
+		if ( strcmp(name,new->v_name)==0 ) {
+			throws(name) ;
+			if ( new->v_type== string ) {
+				throws(new->v_value.v_string) ;
+			}
+			return new ;
+		}
+	}
+	new= (struct vars *)getcore( (unsigned)sizeof (struct vars));
+	new->v_name= name ;
+	new->v_next= v_first ;
+	v_first= new ;
+	return new ;
+}
+
+setsvar(name,str) char *name, *str ; {
+	register struct vars *new ;
+
+	new= newvar(name);
+#ifdef DEBUG
+	if ( debug>=2 ) vprint("%s=%s\n", name, str) ;
+#endif
+	new->v_type= string;
+	new->v_value.v_string= str;
+}
+
+setpvar(name,rout) char *name, *(*rout)() ; {
+	register struct vars *new ;
+
+	new= newvar(name);
+#ifdef DEBUG
+	if ( debug>=2 ) vprint("%s= (*%o)()\n",name,rout) ;
+#endif
+	new->v_type= routine;
+	new->v_value.v_routine= rout;
+}
+
+char *getvar(name) char *name ; {
+	register struct vars *scan ;
+
+	for ( scan=v_first ; scan ; scan= scan->v_next ) {
+		if ( strcmp(name,scan->v_name)==0 ) {
+			switch ( scan->v_type ) {
+			case string:
+				return scan->v_value.v_string ;
+			case routine:
+				return (*scan->v_value.v_routine)() ;
+			}
+		}
+	}
+	return (char *)0 ;
+}

+ 672 - 0
util/ack/trans.c

@@ -0,0 +1,672 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+#include "ack.h"
+#include "list.h"
+#include "trans.h"
+#include "grows.h"
+#include "data.h"
+
+/****************************************************************************/
+/*      Routines for transforming from one file type to another             */
+/****************************************************************************/
+
+static growstring head ;
+static int        touch_head= NO ;
+static growstring tail ;
+static int        touch_tail= NO ;
+
+char *headvar(),*tailvar() ;
+
+int transform(phase) register trf *phase ; {
+	int ok ;
+
+	if ( !setfiles(phase) ) return 0 ;
+	if ( !phase->t_visited ) {
+		/* The flags are set up once.
+		   At the first time the phase is used.
+		   The program name and flags may already be touched
+		   by vieuwargs.
+		*/
+		phase->t_visited=YES ;
+		if ( !rts && phase->t_rts ) rts= phase->t_rts ;
+		if ( phase->t_needed ) {
+			add_head(phase->t_needed) ;
+			add_tail(phase->t_needed) ;
+		}
+	}
+	getcallargs(phase) ;
+	ok= runphase(phase) ;
+	if ( !ok ) rmtemps() ;
+	/* Free the space occupied by the arguments,
+	   except for the combiner, since we are bound to exit soon
+	   and do not foresee further need of memory space */
+	if ( !phase->t_combine ) discardargs(phase) ;
+	disc_files() ;
+	return ok ;
+}
+
+int do_combine() {
+	setsvar(keeps(RTS), keeps(rts? rts : "") ) ;
+	if ( !outfile ) outfile= combiner->t_out ;
+	getmapflags(combiner);
+	return transform(combiner) ;
+}
+
+getmapflags(phase) register trf *phase ; {
+	register list_elem *elem ;
+	int scanned ;
+	register char *ptr ;
+
+	scanlist(l_first(flags),elem) {
+		scanned= *(l_content(*elem))&NO_SCAN ;
+		*(l_content(*elem)) &= ~NO_SCAN ;
+		if ( mapflag(&(phase->t_mapf),l_content(*elem)) ) {
+			scanned=NO_SCAN ;
+#ifdef DEBUG
+			if ( debug >=4 ) {
+				vprint("phase %s, added mapflag for %s\n",
+					phase->t_name,
+					l_content(*elem) ) ;
+			}
+#endif
+		}
+		*(l_content(*elem)) |= scanned ;
+	}
+	if ( phase->t_combine ) {
+		scanlist(l_first(c_arguments),elem) {
+			if ( mapflag(&(phase->t_mapf),l_content(*elem)) ) {
+				throws(l_content(*elem)) ;
+				ptr= keeps(getvar(LIBVAR)) ;
+				clr_noscan(ptr) ;
+				l_content(*elem)= ptr ;
+			}
+		}
+		scanlist(l_first(flags),elem) {
+			/* Get the flags remaining for the loader,
+			   That is: all the flags neither eaten by ack nor
+			   one of the subprograms called so-far.
+			   The last fact is indicated by the NO_SCAN bit
+			   in the first character of the flag.
+			*/
+			if ( !( *(l_content(*elem))&NO_SCAN ) ) {
+				l_add(&(phase->t_flags),l_content(*elem)) ;
+			}
+		}
+	}
+}
+
+
+do_Rflag(argp) char *argp ; {
+	l_add(&R_list,argp) ;
+}
+
+char *needvar() {
+	static growstring needed ;
+	static int been_here = NO ;
+
+	if ( !been_here ) {
+		gr_init(&needed) ;
+		been_here=YES ;
+		gr_cat(&needed,headvar()) ;
+		gr_cat(&needed,tailvar()) ;
+	}
+	return gr_start(needed) ;
+}
+
+char *headvar() {
+	if ( !touch_head) return "" ;
+	return gr_start(head) ;
+}
+
+add_head(str) char *str; {
+	if ( !touch_head) {
+		gr_init(&head) ;
+		touch_head=YES ;
+	}
+	gr_cat(&head,str) ;
+}
+
+char *tailvar() {
+	if ( !touch_tail ) return "" ;
+	return gr_start(tail) ;
+}
+
+add_tail(str) char *str ; {
+	if ( !touch_tail ) {
+		gr_init(&tail) ;
+		touch_tail=YES ;
+	}
+	gr_cat(&tail,str) ;
+}
+
+
+transini() {
+	register list_elem *elem ;
+	register trf *phase ;
+
+	scanlist(l_first(R_list), elem) {
+		set_Rflag(l_content(*elem)) ;
+	}
+	l_clear(&R_list) ;
+	scanlist(l_first(tr_list), elem) {
+		phase = t_cont(*elem) ;
+		if ( !phase->t_combine ) getmapflags(phase);
+	}
+	setpvar(keeps(NEEDS),needvar) ;
+	setpvar(keeps(HEAD),headvar) ;
+	setpvar(keeps(TAIL),tailvar) ;
+}
+
+set_Rflag(argp) register char *argp ; {
+	int     seen ;
+	register char *eos ;
+	register list_elem *prog ;
+	register int length ;
+	char *eq ;
+
+	eos= index(&argp[2],'-');
+	eq= index(&argp[2],EQUAL) ;
+	if ( !eos ) {
+		eos= eq ;
+	} else {
+		if ( eq && eq<eos ) eos= eq ;
+	}
+	if ( !eos ) fuerror("Incorrect use of -R flag") ;
+	length= eos - &argp[2] ;
+	seen=NO ;
+	scanlist(l_first(tr_list), prog) {
+		if ( strncmp(t_cont(*prog)->t_name, &argp[2], length )==0 ) {
+			if ( *eos=='-' ) {
+				l_add(&(t_cont(*prog)->t_flags),eos) ;
+			} else {
+				t_cont(*prog)->t_prog= eos+1 ;
+			}
+			seen=YES ;
+		}
+	}
+	if ( !seen ) error("Cannot find program for %s",argp) ;
+	return ;
+}
+
+/**************************************************************************/
+/*                                                                        */
+/*           The creation of arguments for exec for a transformation      */
+/*                                                                        */
+/**************************************************************************/
+
+growstring scanb(line) char *line ; {
+	/* Scan a line for backslashes, setting the NO_SCAN bit in characters
+	   preceded by a backslash.
+	*/
+	register char *in_c ;
+	register int  token ;
+	growstring result ;
+	enum { TEXT, ESCAPED } state = TEXT ;
+
+	gr_init(&result) ;
+	for ( in_c= line ; *in_c ; in_c++ ) {
+		token= *in_c&0377 ;
+		switch( state ) {
+		case TEXT :
+			if ( token==BSLASH ) {
+				state= ESCAPED ;
+			} else {
+				gr_add(&result,token) ;
+			}
+			break ;
+		case ESCAPED :
+			gr_add(&result,token|NO_SCAN) ;
+			state=TEXT ;
+			break ;
+		}
+	}
+	gr_add(&result,0) ;
+	if ( state!=TEXT ) werror("flag line ends with %c",BSLASH) ;
+	return result ;
+}
+
+growstring scanvars(line) char *line ; {
+	/* Scan a line variable replacements started by S_VAR.
+	   Two sequences exist: S_VAR name E_VAR, S_VAR name A_VAR text E_VAR.
+	   neither name nor text may contain further replacements.
+	   In the first form an error message is issued if the name is not
+	   present in the variables, the second form produces text
+	   in that case.
+	   The sequence S_VAR S_VAR is transformed into S_VAR.
+	   This to allow later recognition in mapflags, where B_SLASH
+	   would be preventing any recognition.
+	*/
+	register char *in_c ;
+	register int  token ;
+	growstring result ;
+	growstring name ;
+	register char *tr ;
+	enum { TEXT, FIRST, NAME, SKIP, COPY } state = TEXT ;
+
+	gr_init(&result) ; gr_init(&name) ;
+	for ( in_c= line ; *in_c ; in_c++ ) {
+		token= *in_c&0377 ;
+		switch( state ) {
+		case TEXT :
+			if ( token==S_VAR ) {
+				state= FIRST ;
+			} else {
+				gr_add(&result,token) ;
+			}
+			break ;
+		case FIRST :
+			switch ( token ) {
+			case S_VAR :
+				state= TEXT ;
+				gr_add(&result,token) ;
+				break ;
+			case A_VAR :
+			case C_VAR :
+				fatal("empty string variable name") ;
+			default :
+				state=NAME ;
+				gr_add(&name,token) ;
+				break ;
+			}
+			break ;
+		case NAME:
+			switch ( token ) {
+			case A_VAR :
+				gr_add(&name,0) ;
+				if ( tr=getvar(gr_start(name)) ) {
+					while ( *tr ) {
+						gr_add(&result,*tr++) ;
+					}
+					state=SKIP ;
+				} else {
+					state=COPY ;
+				}
+				gr_throw(&name) ;
+				break ;
+			case C_VAR :
+				gr_add(&name,0) ;
+				if ( tr=getvar(gr_start(name)) ) {
+					while ( *tr ) {
+					   gr_add(&result,*tr++);
+					}
+				} else {
+					werror("No definition for %s",
+						gr_start(name)) ;
+				}
+				state=TEXT ;
+				gr_throw(&name) ;
+				break ;
+			default:
+				gr_add(&name,token) ;
+				break ;
+			}
+			break ;
+		case SKIP :
+			if ( token==C_VAR ) state= TEXT ;
+			break ;
+		case COPY :
+			if ( token==C_VAR ) state= TEXT ; else {
+				gr_add(&result,token) ;
+			}
+			break ;
+		}
+	}
+	gr_add(&result,0) ;
+	if ( state!=TEXT ) {
+		werror("flag line misses %c",C_VAR) ;
+		gr_throw(&name) ;
+	}
+	return result ;
+}
+
+growstring scanexpr(line) char *line ; {
+	/* Scan a line for conditional or flag expressions,
+	   dependent on the type. The format is
+	   S_EXPR suflist M_EXPR suflist T_EXPR tail C_EXPR
+	   the head and tail are passed to treat, together with the
+	   growstring for futher treatment.
+	   Nesting is not allowed.
+	*/
+	register char *in_c ;
+	char *heads ;
+	register int  token ;
+	growstring sufs, tailval ;
+	growstring result ;
+	static list_head fsuff, lsuff ;
+	enum { TEXT, FDOT, FSUF, LDOT, LSUF, FTAIL } state = TEXT ;
+
+	gr_init(&result) ; gr_init(&sufs) ; gr_init(&tailval) ;
+	for ( in_c= line ; *in_c ; in_c++ ) {
+		token= *in_c&0377 ;
+		switch( state ) {
+		case TEXT :
+			if ( token==S_EXPR ) {
+				state= FDOT ;
+				heads=in_c ;
+			} else gr_add(&result,token) ;
+			break ;
+		case FDOT :
+			if ( token==M_EXPR ) {
+				state=LDOT ;
+				break ;
+			}
+			token &= ~NO_SCAN ;
+			if ( token!=SUFCHAR ) {
+				error("Missing %c in expression",SUFCHAR) ;
+			}
+			gr_add(&sufs,token) ; state=FSUF ;
+			break ;
+		case FSUF :
+			if ( token==M_EXPR || (token&~NO_SCAN)==SUFCHAR) {
+				gr_add(&sufs,0) ;
+				l_add(&fsuff,gr_final(&sufs)) ;
+			}
+			if ( token==M_EXPR ) {
+				state=LDOT ;
+			} else gr_add(&sufs,token&~NO_SCAN) ;
+			break ;
+		case LDOT :
+			if ( token==T_EXPR ) {
+				state=FTAIL ;
+				break ;
+			}
+			token &= ~NO_SCAN ;
+			if ( token!=SUFCHAR ) {
+				error("Missing %c in expression",SUFCHAR) ;
+			}
+			gr_add(&sufs,token) ; state=LSUF ;
+			break ;
+		case LSUF :
+			if ( token==T_EXPR || (token&~NO_SCAN)==SUFCHAR) {
+				gr_add(&sufs,0) ;
+				l_add(&lsuff,gr_final(&sufs)) ;
+			}
+			if ( token==T_EXPR ) {
+				state=FTAIL ;
+			} else gr_add(&sufs,token&~NO_SCAN) ;
+			break ;
+		case FTAIL :
+			if ( token==C_EXPR ) {
+				/* Found one !! */
+				gr_add(&tailval,0) ;
+				condit(&result,&fsuff,&lsuff,gr_start(tailval)) ;
+				l_throw(&fsuff) ; l_throw(&lsuff) ;
+				gr_throw(&tailval) ;
+				state=TEXT ;
+			} else gr_add(&tailval,token) ;
+			break ;
+		}
+	}
+	gr_add(&result,0) ;
+	if ( state!=TEXT ) {
+		l_throw(&fsuff) ; l_throw(&lsuff) ; gr_throw(&tailval) ;
+		werror("flag line has unclosed expression starting with %6s",
+			heads) ;
+	}
+	return result ;
+}
+
+condit(line,fsuff,lsuff,tailval) growstring *line ;
+	list_head *fsuff, *lsuff;
+	char *tailval ;
+{
+	register list_elem *first ;
+	register list_elem *last ;
+
+#ifdef DEBUG
+	if ( debug>=4 ) vprint("Conditional for %s, ",tailval) ;
+#endif
+	scanlist( l_first(*fsuff), first ) {
+		scanlist( l_first(*lsuff), last ) {
+			if ( strcmp(l_content(*first),l_content(*last))==0 ) {
+				/* Found */
+#ifdef DEBUG
+				if ( debug>=4 ) vprint(" matched\n") ;
+#endif
+				while ( *tailval) gr_add(line,*tailval++ ) ;
+				return ;
+			}
+		}
+	}
+#ifdef DEBUG
+	if ( debug>=4) vprint(" non-matched\n") ;
+#endif
+}
+
+int mapflag(maplist,cflag) list_head *maplist ; char *cflag ; {
+	/* Expand a flag expression */
+	/* The flag "cflag" is checked for each of the mapflags.
+	   A mapflag entry has the form
+		-text NAME=replacement or -text*text NAME=replacement
+	   The star matches anything as in the shell.
+	   If the entry matches the assignment will take place
+	   This replacement is subjected to argument matching only.
+	   When a match took place the replacement is returned
+	   when not, (char *)0.
+	   The replacement sits in stable storage.
+	*/
+	register list_elem *elem ;
+
+	scanlist(l_first(*maplist),elem) {
+		if ( mapexpand(l_content(*elem),cflag) ) {
+			return 1 ;
+		}
+	}
+	return 0 ;
+}
+
+int mapexpand(mapentry,cflag)
+	char *mapentry, *cflag ;
+{
+	register char *star ;
+	register char *ptr ;
+	register char *space ;
+	int length ;
+
+	star=index(mapentry,STAR) ;
+	space=firstblank(mapentry) ;
+	if ( star >space ) star= (char *)0 ;
+	if ( star ) {
+		length= space-star-1 ;
+		if ( strncmp(mapentry,cflag,star-mapentry) ||
+		     strncmp(star+1,cflag+strlen(cflag)-length,length) ) {
+			return 0 ;
+		}
+		/* Match */
+		/* Now set star to the first char of the star
+		   replacement and length to its length
+		*/
+		length=strlen(cflag)-(star-mapentry)-length ;
+		if ( length<0 ) return 0 ;
+		star=cflag+(star-mapentry) ;
+#ifdef DEBUG
+		if ( debug>=6 ) {
+			vprint("Starmatch (%s,%s) %.*s\n",
+				mapentry,cflag,length,star) ;
+		}
+#endif
+	} else {
+		if ( strncmp(mapentry,cflag,space-mapentry)!=0 ||
+		     cflag[space-mapentry] ) {
+			return 0 ;
+		}
+	}
+	ptr= skipblank(space) ;
+	if ( *ptr==0 ) return 1 ;
+	doassign(ptr,star,length) ;
+	return 1 ;
+}
+
+doassign(line,star,length) char *line, *star ; {
+	growstring varval, name, temp ;
+	register char *ptr ;
+
+	gr_init(&varval) ;
+	gr_init(&name) ;
+	ptr= line ;
+	for ( ; *ptr && *ptr!=SPACE && *ptr!=TAB && *ptr!=EQUAL ; ptr++ ) {
+		gr_add(&name,*ptr) ;
+	}
+	ptr= index(ptr,EQUAL) ;
+	if ( !ptr ) {
+		error("Missing %c in assignment %s",EQUAL,line);
+		return ;
+	}
+	temp= scanvars(ptr+1) ;
+	for ( ptr=gr_start(temp); *ptr; ptr++ ) switch ( *ptr ) {
+	case STAR :
+		if ( star ) {
+			while ( length-- ) gr_add(&varval,*star++|NO_SCAN) ;
+			break ;
+		}
+	default :
+		gr_add(&varval,*ptr) ;
+		break ;
+	}
+	gr_throw(&temp) ;
+	setsvar(gr_final(&name),gr_final(&varval)) ;
+}
+
+#define ISBLANK(c) ( (c)==SPACE || (c)==TAB )
+
+unravel(line,action) char *line ; int (*action)() ; {
+	/* Unravel the line, get arguments a la shell */
+	/* each argument is handled to action */
+	/* The input string is left intact */
+	register char *in_c ;
+	register int  token ;
+	enum { BLANK, ARG } state = BLANK ;
+	growstring argum ;
+
+	in_c=line ;
+	for (;;) {
+		token= *in_c&0377 ;
+		switch ( state ) {
+		case BLANK :
+			if ( token==0 ) break ;
+			if ( !ISBLANK(token) ) {
+				state= ARG ;
+				gr_init(&argum) ;
+				gr_add(&argum,token&~NO_SCAN) ;
+			}
+			break ;
+		case ARG :
+			if ( ISBLANK(token) || token==0 ) {
+				gr_add(&argum,0) ;
+				(*action)(gr_start(argum)) ;
+				gr_throw(&argum) ;
+				state=BLANK ;
+			} else {
+				gr_add(&argum,token&~NO_SCAN) ;
+			}
+			break ;
+		}
+		if ( token == 0 ) break ;
+		in_c++ ;
+	}
+}
+
+char *c_rep(string,place,rep) char *string, *place, *rep ; {
+	/* Produce a string in stable storage produced from 'string'
+	   with the character at place replaced by rep
+	*/
+	growstring name ;
+	register char *nc ;
+	register char *xc ;
+
+	gr_init(&name) ;
+	for ( nc=string ; *nc && nc<place ; nc++ ) {
+		gr_add(&name,*nc) ;
+	}
+#ifdef DEBUG
+	if ( *nc==0 ) fatal("Place is not in string") ;
+#endif
+	for ( xc=rep ; *xc ; xc++ ) gr_add(&name,*xc|NO_SCAN) ;
+	gr_add(&name,0) ;
+	gr_cat(&name,nc+1) ;
+	return gr_final(&name) ;
+}
+
+static list_head *curargs ;
+
+addargs(string) char *string ; {
+	register char *temp, *repc ;
+	register list_elem *elem ;
+
+	repc=index(string,C_IN) ;
+	if ( repc ) {
+		/* INPUT FILE TOKEN seen, replace it and scan further */
+		if ( repc==string && string[1]==0 ) {
+			if ( in.p_path ) { /* All but combiner */
+				l_add(curargs,keeps(in.p_path)) ;
+			} else {
+				scanlist( l_first(c_arguments), elem ) {
+					l_add(curargs,l_content(*elem)) ;
+				}
+			}
+			return ;
+		}
+		if ( in.p_path ) { /* Not for the combiner */
+			temp=c_rep(string,repc,in.p_path) ;
+			addargs(temp) ;
+			throws(temp) ;
+		} else {           /* For the combiner */
+			scanlist( l_first(c_arguments), elem ) {
+				temp=c_rep(string,repc,l_content(*elem)) ;
+				addargs(temp) ;
+				throws(temp) ;
+			}
+		}
+		return ;
+	}
+	repc=index(string,C_OUT) ;
+	if ( repc ) {
+		/* replace the outfile token as with the infile token */
+#ifdef DEBUG
+		if ( !out.p_path ) fatal("missing output filename") ;
+#endif
+		temp=c_rep(string,repc,out.p_path) ;
+		addargs(temp) ;
+		throws(temp) ;
+		return ;
+	}
+	temp= keeps(string) ;
+	clr_noscan(temp) ;
+	l_add(curargs,temp) ;
+}
+
+getcallargs(phase) register trf *phase ; {
+	growstring arg1, arg2 ;
+
+	arg1= scanvars(phase->t_argd) ;
+#ifdef DEBUG
+	if ( debug>=3 ) { vprint("\tvars: ") ; prns(gr_start(arg1)) ; }
+#endif
+	arg2= scanexpr(gr_start(arg1)) ;
+#ifdef DEBUG
+	if ( debug>=3 ) { vprint("\texpr: ") ; prns(gr_start(arg2)) ; }
+#endif
+	gr_throw(&arg1) ;
+	curargs= &phase->t_args ;
+	unravel( gr_start(arg2), addargs ) ;
+	gr_throw(&arg2) ;
+}
+
+discardargs(phase) register trf *phase ; {
+	l_throw(&phase->t_args) ;
+}

+ 30 - 0
util/ack/trans.h

@@ -0,0 +1,30 @@
+/* This structure is the center of all actions */
+/* It contains the description of all phases,
+   the suffices they consume and produce and various properties */
+
+typedef struct transform trf;
+
+struct transform {
+	char    *t_in ;         /* Suffices in '.o.k' */
+	char    *t_out ;        /* Result '.suffix' or 'name' */
+	char    *t_name ;       /* The name of this transformation */
+	list_head t_mapf ;      /* Mapflags argument, uses varrep */
+	char    *t_argd ;       /* Argument descriptor, uses varrep */
+	char    *t_needed ;     /* Suffix indicating the libraries needed */
+	char    *t_rts ;        /* Suffix indicating the major language used*/
+	int     t_stdin:1 ;     /* The input is taken on stdin */
+	int     t_stdout:1 ;    /* The output comes on stdout */
+	int     t_combine:1 ;   /* Transform several files to one result */
+	int     t_visited:1 ;   /* NO before setup, YES after */
+	int     t_prep:2 ;      /* Needs preprocessor YES/NO/MAYBE */
+	int     t_optim:1 ;     /* Is optimizer */
+	int     t_isprep:1 ;    /* Is preprocessor */
+	int     t_keep:1 ;      /* Keep the output file */
+	char    *t_prog ;       /* Pathname for load file */
+	list_head t_flags ;     /* List of flags */
+	list_head t_args ;      /* List of arguments */
+	int     t_scan:1 ;      /* Used while finding path's */
+	int     t_do:1 ;        /* Is in path to execute */
+} ;
+
+#define t_cont(elem) ((trf *)l_content(elem))

+ 190 - 0
util/ack/util.c

@@ -0,0 +1,190 @@
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ *          This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ *      Dr. Andrew S. Tanenbaum
+ *      Wiskundig Seminarium
+ *      Vrije Universiteit
+ *      Postbox 7161
+ *      1007 MC Amsterdam
+ *      The Netherlands
+ *
+ */
+
+/**********************************************************************/
+/*                                                                    */
+/*               Several utility routines used throughout ack         */
+/*               error handling, string handling and such.            */
+/*                                                                    */
+/**********************************************************************/
+
+#include "ack.h"
+#include <ctype.h>
+#include <stdio.h>
+
+extern  char    *progname ;
+extern  int     w_flag ;
+extern  int     n_error;
+
+extern  char    *calloc();
+extern  char    *realloc();
+
+#ifdef DEBUG
+# define STDOUT stdout
+#else
+# define STDOUT stderr
+#endif
+
+char *basename(string) char *string ; {
+	static char retval[20] ;
+	char *last_dot, *last_start ;
+	register char *store;
+	register char *fetch ;
+	register int ctoken ;
+
+	last_dot= (char *)0 ;
+	last_start= string ;
+	for ( fetch=string ; ; fetch++ ) {
+		switch ( ctoken= *fetch&0377 ) {
+		case SUFCHAR : last_dot=fetch ; break ;
+		case '/'     : last_start=fetch+1 ; break ;
+		case  0      : goto out ;
+		}
+		if ( !isascii(ctoken) || !isprint(ctoken) ) {
+			werror("non-ascii characters in argument %s",string) ;
+		}
+	}
+out:
+	if ( ! *last_start ) fuerror("empty filename \"%s\"",string) ;
+	for ( fetch= last_start, store=retval ;
+		*fetch && fetch!=last_dot && store< &retval[sizeof retval-1] ;
+		      fetch++, store++ ) {
+				*store= *fetch ;
+	}
+	*store= 0 ;
+	return retval ;
+}
+
+clr_noscan(str) char *str ; {
+	register char *ptr ;
+	for ( ptr=str ; *ptr ; ptr++ ) {
+		*ptr&= ~NO_SCAN ;
+	}
+}
+
+char *skipblank(str) char *str ; {
+	register char *ptr ;
+
+	for ( ptr=str ; *ptr==SPACE || *ptr==TAB ; ptr++ ) ;
+	return ptr ;
+}
+
+char *firstblank(str) char *str ; {
+	register char *ptr ;
+
+	for ( ptr=str ; *ptr && *ptr!=SPACE && *ptr!=TAB ; ptr++ ) ;
+	return ptr ;
+}
+
+/* VARARGS1 */
+fatal(fmt,p1,p2,p3,p4,p5,p6,p7) char *fmt ; {
+	/* Fatal internal error */
+	fprintf(STDOUT,"%s: fatal internal error, ",progname) ;
+	fprintf(STDOUT,fmt,p1,p2,p3,p4,p5,p6,p7);
+	fprintf(STDOUT,"\n") ;
+	quit(-2) ;
+}
+
+
+/* VARARGS1 */
+vprint(fmt,p1,p2,p3,p4,p5,p6,p7) char *fmt ; {
+	/* Diagnostic print, no auto NL */
+	fprintf(STDOUT,fmt,p1,p2,p3,p4,p5,p6,p7);
+}
+
+#ifdef DEBUG
+prns(s) register char *s ; {
+	for ( ; *s ; s++ ) {
+		putc((*s&0377)&~NO_SCAN,STDOUT) ;
+	}
+	putc('\n',STDOUT) ;
+}
+#endif
+
+/* VARARGS1 */
+fuerror(fmt,p1,p2,p3,p4,p5,p6,p7) char *fmt ; {
+	/* Fatal user error */
+	fprintf(STDOUT,"%s: ",progname) ;
+	fprintf(STDOUT,fmt,p1,p2,p3,p4,p5,p6,p7);
+	fprintf(STDOUT,"\n") ;
+	quit(-1) ;
+}
+
+/* VARARGS1 */
+werror(fmt,p1,p2,p3,p4,p5,p6,p7) char *fmt ; {
+	/* Warning user error, w_flag */
+	if ( w_flag ) return ;
+	fprintf(STDOUT,"%s: warning, ",progname) ;
+	fprintf(STDOUT,fmt,p1,p2,p3,p4,p5,p6,p7);
+	fprintf(STDOUT,"\n") ;
+}
+
+/* VARARGS1 */
+error(fmt,p1,p2,p3,p4,p5,p6,p7) char *fmt ; {
+	/* User error, it is the callers responsibility to quit */
+	fprintf(STDOUT,"%s: ",progname) ;
+	fprintf(STDOUT,fmt,p1,p2,p3,p4,p5,p6,p7);
+	fprintf(STDOUT,"\n") ;
+	n_error++ ;
+}
+
+do_flush() {
+	fflush(stdout) ;
+	fflush(stderr) ;
+}
+
+noodstop() {
+	quit(-3) ;
+}
+
+quit(code) {
+	rmtemps();
+	exit(code);
+}
+/******
+	char *keeps(string)
+		Keep the string in stable storage.
+	throws(string)
+		Remove the string stored by keep from stable storage.
+***********/
+
+char *keeps(str) char *str ; {
+	register char *result ;
+	result= getcore( (unsigned)(strlen(str)+1) ) ;
+	if ( !result ) fatal("Out of core") ;
+	return strcpy(result,str) ;
+}
+
+throws(str) char *str ; {
+	freecore(str) ;
+}
+
+char *getcore(size) unsigned size ; {
+	register char *retptr ;
+
+	retptr= calloc(1,size) ;
+	if ( !retptr ) fatal("Out of memory") ;
+	return retptr ;
+}
+
+char *changecore(ptr,size) char *ptr ; unsigned size ; {
+	register char *retptr ;
+
+	retptr= realloc(ptr,size) ;
+	if ( !retptr ) fatal("Out of memory") ;
+	return retptr ;
+}