--- /dev/null
+dot-forward reads sendmail's .forward files under qmail. You can run it
+in the qmail startup script to support all your existing .forward files
+automatically. Individual users can switch to the .qmail mechanism at
+their leisure.
+
+dot-forward supports forwarding, program deliveries, and comments. It
+does not support file deliveries or :include:. (However, it recognizes
+file delivery attempts, and defers delivery to give you a chance to set
+up a .qmail file.)
--- /dev/null
+19980519 version: dot-forward 0.71, beta.
+19980519 doc: simplified INSTALL.
+19980519 doc: documented -n in dot-forward.1.
+19980519 code: eliminated home+df.
+19980519 doc: put version and home page into dot-forward.1.
+19980519 code: switched to new install.
+19980421 dot-forward 0.70, beta.
+19980421 code: recognized $USER@$HOST the same way as $USER.
+19980421 doc: reorganized compatibility warnings in dot-forward.0.
+19980421 doc: eliminated *.3.
+19980421 doc: added note about file deferrals to BLURB.
+19980421 code: added home+df.sh; updated INSTALL accordingly.
+19980421 code: moved installation from /usr/local to /var/qmail.
+19971001 doc: eliminated hassgprm.h from SYSDEPS. tnx JB.
+19971001 dot-forward 0.51, alpha.
+19971001 doc: changed ./forward to .forward in man page and INSTALL.
+19970930 dot-forward 0.50, alpha.
--- /dev/null
+BLURB
+README
+TODO
+THANKS
+CHANGES
+FILES
+VERSION
+SYSDEPS
+Makefile
+TARGETS
+dot-forward.1
+dot-forward.c
+conf-cc
+conf-ld
+find-systype.sh
+make-compile.sh
+make-load.sh
+make-makelib.sh
+trycpp.c
+warn-auto.sh
+conf-qmail
+auto_qmail.h
+qmail.h
+qmail.c
+INSTALL
+hier.c
+auto-str.c
+install.c
+instcheck.c
+sgetopt.h
+sgetopt.c
+subgetopt.h
+subgetopt.c
+substdio.h
+substdio.c
+substdi.c
+substdo.c
+substdio_copy.c
+subfd.h
+subfderr.c
+readwrite.h
+exit.h
+strerr.h
+strerr_sys.c
+strerr_die.c
+byte.h
+byte_chr.c
+byte_copy.c
+byte_cr.c
+str.h
+str_diffn.c
+str_len.c
+error.h
+error.c
+error_str.c
+wait.h
+wait_pid.c
+trywaitp.c
+fork.h1
+fork.h2
+tryvfork.c
+fd.h
+fd_copy.c
+fd_move.c
+getln.h
+getln.c
+getln2.c
+gen_alloc.h
+gen_allocdefs.h
+stralloc.h
+stralloc_eady.c
+stralloc_pend.c
+stralloc_copy.c
+stralloc_opyb.c
+stralloc_opys.c
+stralloc_cat.c
+stralloc_catb.c
+stralloc_cats.c
+alloc.h
+alloc.c
+alloc_re.c
+env.h
+envread.c
+open.h
+open_read.c
+open_trunc.c
+sig.h
+sig_catch.c
+sig_pipe.c
+trysgact.c
+token822.h
+token822.c
+control.h
+control.c
+fmt.h
+fmt_ulong.c
+scan.h
+scan_ulong.c
+case.h
+case_diffb.c
+seek.h
+seek_set.c
--- /dev/null
+Like any other piece of software (and information generally),
+dot-forward comes with NO WARRANTY.
+
+
+Things you have to decide before starting:
+
+* The location of the qmail home directory, normally /var/qmail. (To
+change this directory, edit conf-qmail now.)
+
+
+How to install:
+
+ 1. Create and install the programs and man pages:
+ # make setup check
+
+ 2. With qmail 1.02 and above: To set up .forward handling for all
+ users, install a /var/qmail/rc script that invokes dot-forward.
+ Several scripts are supplied in /var/qmail/boot/*+df.
+
+
+That's it! To report success:
+ % ( echo 'First M. Last'; cat `cat SYSDEPS` ) | mail djb-qst@cr.yp.to
+Replace First M. Last with your name.
--- /dev/null
+# Don't edit Makefile! Use conf-* for configuration.
+
+SHELL=/bin/sh
+
+default: it
+
+alloc.a: \
+makelib alloc.o alloc_re.o
+ ./makelib alloc.a alloc.o alloc_re.o
+
+alloc.o: \
+compile alloc.c alloc.h error.h
+ ./compile alloc.c
+
+alloc_re.o: \
+compile alloc_re.c alloc.h byte.h
+ ./compile alloc_re.c
+
+auto-ccld.sh: \
+conf-cc conf-ld warn-auto.sh
+ ( cat warn-auto.sh; \
+ echo CC=\'`head -1 conf-cc`\'; \
+ echo LD=\'`head -1 conf-ld`\' \
+ ) > auto-ccld.sh
+
+auto-str: \
+load auto-str.o substdio.a error.a str.a
+ ./load auto-str substdio.a error.a str.a
+
+auto-str.o: \
+compile auto-str.c substdio.h readwrite.h exit.h
+ ./compile auto-str.c
+
+auto_qmail.c: \
+auto-str conf-qmail
+ ./auto-str auto_qmail `head -1 conf-qmail` > auto_qmail.c
+
+auto_qmail.o: \
+compile auto_qmail.c
+ ./compile auto_qmail.c
+
+byte_chr.o: \
+compile byte_chr.c byte.h
+ ./compile byte_chr.c
+
+byte_copy.o: \
+compile byte_copy.c byte.h
+ ./compile byte_copy.c
+
+byte_cr.o: \
+compile byte_cr.c byte.h
+ ./compile byte_cr.c
+
+case.a: \
+makelib case_diffb.o
+ ./makelib case.a case_diffb.o
+
+case_diffb.o: \
+compile case_diffb.c case.h
+ ./compile case_diffb.c
+
+check: \
+it instcheck
+ ./instcheck
+
+compile: \
+make-compile warn-auto.sh systype
+ ( cat warn-auto.sh; ./make-compile "`cat systype`" ) > \
+ compile
+ chmod 755 compile
+
+control.o: \
+compile control.c readwrite.h open.h getln.h stralloc.h gen_alloc.h \
+substdio.h error.h control.h alloc.h scan.h
+ ./compile control.c
+
+dot-forward: \
+load dot-forward.o control.o qmail.o auto_qmail.o token822.o env.a \
+getln.a getopt.a strerr.a error.a substdio.a stralloc.a alloc.a \
+case.a str.a sig.a seek.a open.a wait.a fd.a fs.a
+ ./load dot-forward control.o qmail.o auto_qmail.o \
+ token822.o env.a getln.a getopt.a strerr.a error.a \
+ substdio.a stralloc.a alloc.a case.a str.a sig.a seek.a \
+ open.a wait.a fd.a fs.a
+
+dot-forward.0: \
+dot-forward.1
+ nroff -man dot-forward.1 > dot-forward.0
+
+dot-forward.o: \
+compile dot-forward.c sgetopt.h subgetopt.h substdio.h readwrite.h \
+stralloc.h gen_alloc.h getln.h strerr.h error.h exit.h open.h wait.h \
+seek.h env.h str.h fmt.h token822.h gen_alloc.h control.h qmail.h \
+substdio.h auto_qmail.h
+ ./compile dot-forward.c
+
+env.a: \
+makelib envread.o
+ ./makelib env.a envread.o
+
+envread.o: \
+compile envread.c env.h str.h
+ ./compile envread.c
+
+error.a: \
+makelib error.o error_str.o
+ ./makelib error.a error.o error_str.o
+
+error.o: \
+compile error.c error.h
+ ./compile error.c
+
+error_str.o: \
+compile error_str.c error.h
+ ./compile error_str.c
+
+fd.a: \
+makelib fd_copy.o fd_move.o
+ ./makelib fd.a fd_copy.o fd_move.o
+
+fd_copy.o: \
+compile fd_copy.c fd.h
+ ./compile fd_copy.c
+
+fd_move.o: \
+compile fd_move.c fd.h
+ ./compile fd_move.c
+
+find-systype: \
+find-systype.sh auto-ccld.sh
+ cat auto-ccld.sh find-systype.sh > find-systype
+ chmod 755 find-systype
+
+fmt_ulong.o: \
+compile fmt_ulong.c fmt.h
+ ./compile fmt_ulong.c
+
+fork.h: \
+compile load tryvfork.c fork.h1 fork.h2
+ ( ( ./compile tryvfork.c && ./load tryvfork ) >/dev/null \
+ 2>&1 \
+ && cat fork.h2 || cat fork.h1 ) > fork.h
+ rm -f tryvfork.o tryvfork
+
+fs.a: \
+makelib fmt_ulong.o scan_ulong.o
+ ./makelib fs.a fmt_ulong.o scan_ulong.o
+
+getln.a: \
+makelib getln.o getln2.o
+ ./makelib getln.a getln.o getln2.o
+
+getln.o: \
+compile getln.c substdio.h byte.h stralloc.h gen_alloc.h getln.h
+ ./compile getln.c
+
+getln2.o: \
+compile getln2.c substdio.h stralloc.h gen_alloc.h byte.h getln.h
+ ./compile getln2.c
+
+getopt.a: \
+makelib subgetopt.o sgetopt.o
+ ./makelib getopt.a subgetopt.o sgetopt.o
+
+hassgact.h: \
+trysgact.c compile load
+ ( ( ./compile trysgact.c && ./load trysgact ) >/dev/null \
+ 2>&1 \
+ && echo \#define HASSIGACTION 1 || exit 0 ) > hassgact.h
+ rm -f trysgact.o trysgact
+
+haswaitp.h: \
+trywaitp.c compile load
+ ( ( ./compile trywaitp.c && ./load trywaitp ) >/dev/null \
+ 2>&1 \
+ && echo \#define HASWAITPID 1 || exit 0 ) > haswaitp.h
+ rm -f trywaitp.o trywaitp
+
+hier.o: \
+compile hier.c auto_qmail.h
+ ./compile hier.c
+
+install: \
+load install.o hier.o auto_qmail.o strerr.a substdio.a error.a open.a \
+str.a
+ ./load install hier.o auto_qmail.o strerr.a substdio.a \
+ error.a open.a str.a
+
+install.o: \
+compile install.c substdio.h strerr.h error.h open.h readwrite.h \
+exit.h
+ ./compile install.c
+
+instcheck: \
+load instcheck.o hier.o auto_qmail.o strerr.a substdio.a error.a \
+str.a
+ ./load instcheck hier.o auto_qmail.o strerr.a substdio.a \
+ error.a str.a
+
+instcheck.o: \
+compile instcheck.c strerr.h error.h readwrite.h exit.h
+ ./compile instcheck.c
+
+it: \
+prog man
+
+load: \
+make-load warn-auto.sh systype
+ ( cat warn-auto.sh; ./make-load "`cat systype`" ) > load
+ chmod 755 load
+
+make-compile: \
+make-compile.sh auto-ccld.sh
+ cat auto-ccld.sh make-compile.sh > make-compile
+ chmod 755 make-compile
+
+make-load: \
+make-load.sh auto-ccld.sh
+ cat auto-ccld.sh make-load.sh > make-load
+ chmod 755 make-load
+
+make-makelib: \
+make-makelib.sh auto-ccld.sh
+ cat auto-ccld.sh make-makelib.sh > make-makelib
+ chmod 755 make-makelib
+
+makelib: \
+make-makelib warn-auto.sh systype
+ ( cat warn-auto.sh; ./make-makelib "`cat systype`" ) > \
+ makelib
+ chmod 755 makelib
+
+man: \
+dot-forward.0
+
+open.a: \
+makelib open_read.o open_trunc.o
+ ./makelib open.a open_read.o open_trunc.o
+
+open_read.o: \
+compile open_read.c open.h
+ ./compile open_read.c
+
+open_trunc.o: \
+compile open_trunc.c open.h
+ ./compile open_trunc.c
+
+prog: \
+dot-forward
+
+qmail.o: \
+compile qmail.c substdio.h readwrite.h wait.h exit.h fork.h fd.h \
+qmail.h substdio.h auto_qmail.h
+ ./compile qmail.c
+
+scan_ulong.o: \
+compile scan_ulong.c scan.h
+ ./compile scan_ulong.c
+
+seek.a: \
+makelib seek_set.o
+ ./makelib seek.a seek_set.o
+
+seek_set.o: \
+compile seek_set.c seek.h
+ ./compile seek_set.c
+
+setup: \
+it install
+ ./install
+
+sgetopt.o: \
+compile sgetopt.c substdio.h subfd.h substdio.h sgetopt.h subgetopt.h \
+subgetopt.h
+ ./compile sgetopt.c
+
+sig.a: \
+makelib sig_catch.o sig_pipe.o
+ ./makelib sig.a sig_catch.o sig_pipe.o
+
+sig_catch.o: \
+compile sig_catch.c sig.h hassgact.h
+ ./compile sig_catch.c
+
+sig_pipe.o: \
+compile sig_pipe.c sig.h
+ ./compile sig_pipe.c
+
+str.a: \
+makelib str_len.o str_diffn.o byte_chr.o byte_copy.o byte_cr.o
+ ./makelib str.a str_len.o str_diffn.o byte_chr.o \
+ byte_copy.o byte_cr.o
+
+str_diffn.o: \
+compile str_diffn.c str.h
+ ./compile str_diffn.c
+
+str_len.o: \
+compile str_len.c str.h
+ ./compile str_len.c
+
+stralloc.a: \
+makelib stralloc_eady.o stralloc_pend.o stralloc_copy.o \
+stralloc_opys.o stralloc_opyb.o stralloc_cat.o stralloc_cats.o \
+stralloc_catb.o
+ ./makelib stralloc.a stralloc_eady.o stralloc_pend.o \
+ stralloc_copy.o stralloc_opys.o stralloc_opyb.o \
+ stralloc_cat.o stralloc_cats.o stralloc_catb.o
+
+stralloc_cat.o: \
+compile stralloc_cat.c byte.h stralloc.h gen_alloc.h
+ ./compile stralloc_cat.c
+
+stralloc_catb.o: \
+compile stralloc_catb.c stralloc.h gen_alloc.h byte.h
+ ./compile stralloc_catb.c
+
+stralloc_cats.o: \
+compile stralloc_cats.c byte.h str.h stralloc.h gen_alloc.h
+ ./compile stralloc_cats.c
+
+stralloc_copy.o: \
+compile stralloc_copy.c byte.h stralloc.h gen_alloc.h
+ ./compile stralloc_copy.c
+
+stralloc_eady.o: \
+compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \
+gen_allocdefs.h
+ ./compile stralloc_eady.c
+
+stralloc_opyb.o: \
+compile stralloc_opyb.c stralloc.h gen_alloc.h byte.h
+ ./compile stralloc_opyb.c
+
+stralloc_opys.o: \
+compile stralloc_opys.c byte.h str.h stralloc.h gen_alloc.h
+ ./compile stralloc_opys.c
+
+stralloc_pend.o: \
+compile stralloc_pend.c alloc.h stralloc.h gen_alloc.h \
+gen_allocdefs.h
+ ./compile stralloc_pend.c
+
+strerr.a: \
+makelib strerr_sys.o strerr_die.o
+ ./makelib strerr.a strerr_sys.o strerr_die.o
+
+strerr_die.o: \
+compile strerr_die.c substdio.h subfd.h substdio.h exit.h strerr.h
+ ./compile strerr_die.c
+
+strerr_sys.o: \
+compile strerr_sys.c error.h strerr.h
+ ./compile strerr_sys.c
+
+subfderr.o: \
+compile subfderr.c readwrite.h substdio.h subfd.h substdio.h
+ ./compile subfderr.c
+
+subgetopt.o: \
+compile subgetopt.c subgetopt.h
+ ./compile subgetopt.c
+
+substdi.o: \
+compile substdi.c substdio.h byte.h error.h
+ ./compile substdi.c
+
+substdio.a: \
+makelib substdio.o substdi.o substdo.o subfderr.o substdio_copy.o
+ ./makelib substdio.a substdio.o substdi.o substdo.o \
+ subfderr.o substdio_copy.o
+
+substdio.o: \
+compile substdio.c substdio.h
+ ./compile substdio.c
+
+substdio_copy.o: \
+compile substdio_copy.c substdio.h
+ ./compile substdio_copy.c
+
+substdo.o: \
+compile substdo.c substdio.h str.h byte.h error.h
+ ./compile substdo.c
+
+systype: \
+find-systype trycpp.c
+ ./find-systype > systype
+
+token822.o: \
+compile token822.c stralloc.h gen_alloc.h alloc.h str.h token822.h \
+gen_alloc.h gen_allocdefs.h
+ ./compile token822.c
+
+wait.a: \
+makelib wait_pid.o
+ ./makelib wait.a wait_pid.o
+
+wait_pid.o: \
+compile wait_pid.c error.h haswaitp.h
+ ./compile wait_pid.c
--- /dev/null
+dot-forward 0.71, beta.
+19980519
+Copyright 1998
+D. J. Bernstein, djb@pobox.com
+
+dot-forward reads sendmail's .forward files under qmail. See BLURB for a
+more detailed advertisement.
+
+INSTALL says how to set up dot-forward.
+
+You may distribute unmodified copies of the dot-forward package.
+
+The rest of this file is a list of systypes where various versions of
+dot-forward have been reported to work.
+
+0.70: bsd.os-2.0.1-:i386-:-:pentium-:-
+0.51: freebsd-2.2.2-release-:i386-:-:i486-dx-:- (tnx MM)
+0.51: freebsd-3.0-current-:i386-:-:pentium-:- (tnx KB)
+0.70: irix-5.3-11091811-:-:-:ip19-:- (tnx JB)
+0.51: linux-2.0.30-:i386-:-:pentium-:- (tnx MAP)
+0.51: linux-2.0.30-:i386-:-:ppro-:- (tnx LN)
+0.51: netbsd-1.2g-:i386-:-:intel.pentium.(p54c).(586-class)-:- (tnx GW)
+0.51: sunos-5.5.1-generic_103640-08-:sparc-:sun4-:sun4m-:sun4m- (tnx ESM)
--- /dev/null
+VERSION
+systype
+fork.h
+hassgact.h
+haswaitp.h
--- /dev/null
+auto-ccld.sh
+make-load
+find-systype
+systype
+load
+make-compile
+compile
+dot-forward.o
+control.o
+fork.h
+qmail.o
+auto-str.o
+make-makelib
+makelib
+substdio.o
+substdi.o
+substdo.o
+subfderr.o
+substdio_copy.o
+substdio.a
+error.o
+error_str.o
+error.a
+str_len.o
+str_diffn.o
+byte_chr.o
+byte_copy.o
+byte_cr.o
+str.a
+auto-str
+auto_qmail.c
+auto_qmail.o
+token822.o
+envread.o
+env.a
+getln.o
+getln2.o
+getln.a
+subgetopt.o
+sgetopt.o
+getopt.a
+strerr_sys.o
+strerr_die.o
+strerr.a
+stralloc_eady.o
+stralloc_pend.o
+stralloc_copy.o
+stralloc_opys.o
+stralloc_opyb.o
+stralloc_cat.o
+stralloc_cats.o
+stralloc_catb.o
+stralloc.a
+alloc.o
+alloc_re.o
+alloc.a
+case_diffb.o
+case.a
+hassgact.h
+sig_catch.o
+sig_pipe.o
+sig.a
+seek_set.o
+seek.a
+open_read.o
+open_trunc.o
+open.a
+haswaitp.h
+wait_pid.o
+wait.a
+fd_copy.o
+fd_move.o
+fd.a
+fmt_ulong.o
+scan_ulong.o
+fs.a
+dot-forward
+prog
+dot-forward.0
+man
+it
+install.o
+hier.o
+install
+setup
+instcheck.o
+instcheck
+check
--- /dev/null
+ESM = Edward S. Marshall
+GW = Geoff Wing
+JB = Jos Backus
+KB = Keith Burdis
+LN = Lukas Nellen
+MAP = Michael A. Peck
+MM = Martin Mersberger
--- /dev/null
+dot-forward 0.71
--- /dev/null
+#include "alloc.h"
+#include "error.h"
+extern char *malloc();
+extern void free();
+
+#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */
+#define SPACE 4096 /* must be multiple of ALIGNMENT */
+
+typedef union { char irrelevant[ALIGNMENT]; double d; } aligned;
+static aligned realspace[SPACE / ALIGNMENT];
+#define space ((char *) realspace)
+static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */
+
+/*@null@*//*@out@*/char *alloc(n)
+unsigned int n;
+{
+ char *x;
+ n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */
+ if (n <= avail) { avail -= n; return space + avail; }
+ x = malloc(n);
+ if (!x) errno = error_nomem;
+ return x;
+}
+
+void alloc_free(x)
+char *x;
+{
+ if (x >= space)
+ if (x < space + SPACE)
+ return; /* XXX: assuming that pointers are flat */
+ free(x);
+}
--- /dev/null
+#ifndef ALLOC_H
+#define ALLOC_H
+
+extern /*@null@*//*@out@*/char *alloc();
+extern void alloc_free();
+extern int alloc_re();
+
+#endif
--- /dev/null
+#include "alloc.h"
+#include "byte.h"
+
+int alloc_re(x,m,n)
+char **x;
+unsigned int m;
+unsigned int n;
+{
+ char *y;
+
+ y = alloc(n);
+ if (!y) return 0;
+ byte_copy(y,m,*x);
+ alloc_free(*x);
+ *x = y;
+ return 1;
+}
--- /dev/null
+#include "substdio.h"
+#include "readwrite.h"
+#include "exit.h"
+
+char buf1[256];
+substdio ss1 = SUBSTDIO_FDBUF(write,1,buf1,sizeof(buf1));
+
+void puts(s)
+char *s;
+{
+ if (substdio_puts(&ss1,s) == -1) _exit(111);
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ char *name;
+ char *value;
+ unsigned char ch;
+ char octal[4];
+
+ name = argv[1];
+ if (!name) _exit(100);
+ value = argv[2];
+ if (!value) _exit(100);
+
+ puts("char ");
+ puts(name);
+ puts("[] = \"\\\n");
+
+ while (ch = *value++) {
+ puts("\\");
+ octal[3] = 0;
+ octal[2] = '0' + (ch & 7); ch >>= 3;
+ octal[1] = '0' + (ch & 7); ch >>= 3;
+ octal[0] = '0' + (ch & 7);
+ puts(octal);
+ }
+
+ puts("\\\n\";\n");
+ if (substdio_flush(&ss1) == -1) _exit(111);
+ _exit(0);
+}
--- /dev/null
+#ifndef AUTO_QMAIL_H
+#define AUTO_QMAIL_H
+
+extern char auto_qmail[];
+
+#endif
--- /dev/null
+#ifndef BYTE_H
+#define BYTE_H
+
+extern unsigned int byte_chr();
+extern unsigned int byte_rchr();
+extern void byte_copy();
+extern void byte_copyr();
+extern int byte_diff();
+extern void byte_zero();
+
+#define byte_equal(s,n,t) (!byte_diff((s),(n),(t)))
+
+#endif
--- /dev/null
+#include "byte.h"
+
+unsigned int byte_chr(s,n,c)
+char *s;
+register unsigned int n;
+int c;
+{
+ register char ch;
+ register char *t;
+
+ ch = c;
+ t = s;
+ for (;;) {
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ if (!n) break; if (*t == ch) break; ++t; --n;
+ }
+ return t - s;
+}
--- /dev/null
+#include "byte.h"
+
+void byte_copy(to,n,from)
+register char *to;
+register unsigned int n;
+register char *from;
+{
+ for (;;) {
+ if (!n) return; *to++ = *from++; --n;
+ if (!n) return; *to++ = *from++; --n;
+ if (!n) return; *to++ = *from++; --n;
+ if (!n) return; *to++ = *from++; --n;
+ }
+}
--- /dev/null
+#include "byte.h"
+
+void byte_copyr(to,n,from)
+register char *to;
+register unsigned int n;
+register char *from;
+{
+ to += n;
+ from += n;
+ for (;;) {
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ if (!n) return; *--to = *--from; --n;
+ }
+}
--- /dev/null
+#ifndef CASE_H
+#define CASE_H
+
+extern void case_lowers();
+extern void case_lowerb();
+extern int case_diffs();
+extern int case_diffb();
+extern int case_starts();
+extern int case_startb();
+
+#define case_equals(s,t) (!case_diffs((s),(t)))
+
+#endif
--- /dev/null
+#include "case.h"
+
+int case_diffb(s,len,t)
+register char *s;
+unsigned int len;
+register char *t;
+{
+ register unsigned char x;
+ register unsigned char y;
+
+ while (len > 0) {
+ --len;
+ x = *s++ - 'A';
+ if (x <= 'Z' - 'A') x += 'a'; else x += 'A';
+ y = *t++ - 'A';
+ if (y <= 'Z' - 'A') y += 'a'; else y += 'A';
+ if (x != y)
+ return ((int)(unsigned int) x) - ((int)(unsigned int) y);
+ }
+ return 0;
+}
--- /dev/null
+cc -O2
+
+This will be used to compile .c files.
--- /dev/null
+cc -s
+
+This will be used to link .o files into an executable.
--- /dev/null
+/var/qmail
+
+This is the qmail home directory.
+
+The dot-forward program will be installed in the bin subdirectory; it
+also needs to know where qmail is so that it can handle unqualified host
+names and forward mail properly.
--- /dev/null
+#include "readwrite.h"
+#include "open.h"
+#include "getln.h"
+#include "stralloc.h"
+#include "substdio.h"
+#include "error.h"
+#include "control.h"
+#include "alloc.h"
+#include "scan.h"
+
+static char inbuf[64];
+static stralloc line = {0};
+static stralloc me = {0};
+static int meok = 0;
+
+static void striptrailingwhitespace(sa)
+stralloc *sa;
+{
+ while (sa->len > 0)
+ switch(sa->s[sa->len - 1])
+ {
+ case '\n': case ' ': case '\t':
+ --sa->len;
+ break;
+ default:
+ return;
+ }
+}
+
+int control_init()
+{
+ int r;
+ r = control_readline(&me,"control/me");
+ if (r == 1) meok = 1;
+ return r;
+}
+
+int control_rldef(sa,fn,flagme,def)
+stralloc *sa;
+char *fn;
+int flagme;
+char *def;
+{
+ int r;
+ r = control_readline(sa,fn);
+ if (r) return r;
+ if (flagme) if (meok) return stralloc_copy(sa,&me) ? 1 : -1;
+ if (def) return stralloc_copys(sa,def) ? 1 : -1;
+ return r;
+}
+
+int control_readline(sa,fn)
+stralloc *sa;
+char *fn;
+{
+ substdio ss;
+ int fd;
+ int match;
+
+ fd = open_read(fn);
+ if (fd == -1) { if (errno == error_noent) return 0; return -1; }
+
+ substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf));
+
+ if (getln(&ss,sa,&match,'\n') == -1) { close(fd); return -1; }
+
+ striptrailingwhitespace(sa);
+ close(fd);
+ return 1;
+}
+
+int control_readint(i,fn)
+int *i;
+char *fn;
+{
+ unsigned long u;
+ switch(control_readline(&line,fn))
+ {
+ case 0: return 0;
+ case -1: return -1;
+ }
+ if (!stralloc_0(&line)) return -1;
+ if (!scan_ulong(line.s,&u)) return 0;
+ *i = u;
+ return 1;
+}
+
+int control_readfile(sa,fn,flagme)
+stralloc *sa;
+char *fn;
+int flagme;
+{
+ substdio ss;
+ int fd;
+ int match;
+
+ if (!stralloc_copys(sa,"")) return -1;
+
+ fd = open_read(fn);
+ if (fd == -1)
+ {
+ if (errno == error_noent)
+ {
+ if (flagme && meok)
+ {
+ if (!stralloc_copy(sa,&me)) return -1;
+ if (!stralloc_0(sa)) return -1;
+ return 1;
+ }
+ return 0;
+ }
+ return -1;
+ }
+
+ substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf));
+
+ for (;;)
+ {
+ if (getln(&ss,&line,&match,'\n') == -1) break;
+ if (!match && !line.len) { close(fd); return 1; }
+ striptrailingwhitespace(&line);
+ if (!stralloc_0(&line)) break;
+ if (line.s[0])
+ if (line.s[0] != '#')
+ if (!stralloc_cat(sa,&line)) break;
+ if (!match) { close(fd); return 1; }
+ }
+ close(fd);
+ return -1;
+}
--- /dev/null
+#ifndef CONTROL_H
+#define CONTROL_H
+
+extern int control_init();
+extern int control_readline();
+extern int control_rldef();
+extern int control_readint();
+extern int control_readfile();
+
+#endif
--- /dev/null
+.TH dot-forward 1
+.SH NAME
+dot-forward \- read a .forward file under qmail
+.SH SYNOPSIS
+in
+.BR ~/.qmail :
+.B | dot-forward
+[
+.B \-nN
+]
+.I file ...
+.SH OVERVIEW
+.B dot-forward
+forwards incoming messages according to
+sendmail-style
+instructions in
+.IR file ,
+if
+.I file
+exists.
+Normally
+.I file
+is
+.BR .forward .
+
+.B WARNING:
+If you create a
+.B .qmail
+file to enable
+.BR dot-forward ,
+make sure to add a second line specifying delivery to your normal mailbox.
+For example:
+
+.EX
+ |dot-forward .forward
+.br
+ ./Mailbox
+.EE
+
+.B COMPATIBILITY WARNING:
+.B dot-forward
+does not support
+.B :include:
+or mbox deliveries.
+You can use the delivery mechanism described in
+.BR dot-qmail (5)
+instead.
+.SH OPTIONS
+.TP 5
+.B \-N
+(Default.)
+Read and forward a message.
+.TP
+.B \-n
+Parse
+.I file
+and print the forwarding instructions in it, one per line;
+do not follow the instructions.
+You can use this option from the command line to see how your
+.B .forward
+file will be interpreted:
+
+.EX
+ dot-forward -n .forward
+.EE
+.SH "FILE HANDLING"
+When a message arrives,
+.B dot-forward
+opens
+.I file
+and handles it as discussed below.
+It exits 99, so
+.B qmail-local
+will ignore further instructions in
+.BR .qmail .
+Exception: If
+.I file
+specifies delivery directly to you,
+.B dot-forward
+exits 0, so
+.B qmail-local
+will read further instructions in
+.BR .qmail .
+
+If
+.I file
+does not exist,
+.B dot-forward
+exits 0.
+You can list several
+.IR file s;
+then
+.B dot-forward
+will try each one in turn,
+using the first one that exists,
+or exiting 0 if none exist.
+
+.B COMPATIBILITY WARNING:
+.B dot-forward
+treats an empty
+.I file
+as if it did not exist.
+Versions of
+sendmail
+before V8 would throw away the incoming message.
+
+.B COMPATIBILITY WARNING:
+If
+.B dot-forward
+encounters a temporary error opening
+.IR file ,
+it exits 111, so that
+.B qmail-local
+will try again later.
+sendmail
+assumes incorrectly that
+.I file
+does not exist.
+
+.B COMPATIBILITY WARNING:
+.I file
+must be readable by
+.BR dot-forward ,
+which is normally running as the user.
+sendmail
+places different constraints on its
+.B .forward
+permissions,
+since it is normally running as root.
+.SH "FORWARDING"
+Normally
+.I file
+contains an address.
+.B dot-forward
+forwards the message to that address.
+
+The address is parsed as if it were in an RFC 822 message header.
+Parenthesized comments and bracketed addresses are permitted:
+
+.EX
+ bob (Bob, the postmaster) @heaven.af.mil
+.EE
+
+Addresses with special characters must be quoted:
+
+.EX
+ "spaced out mailbox"@heaven.af.mil
+.EE
+
+Address groups are not permitted.
+
+.I file
+can contain any number of lines,
+each line containing any number of addresses.
+.B dot-forward
+forwards the message to each address:
+
+.EX
+ bob, fred, susan
+.br
+ Joe Shmoe <shmoe@heaven.af.mil>
+.EE
+
+An address without a fully qualified domain name is handled
+as described in
+.BR qmail-header (5).
+Exception: Certain addresses without domain names are handled specially,
+as described below.
+.SH "DIRECT DELIVERY"
+If an address does not contain a domain name,
+and matches the environment variable
+.B $USER
+(without regard to case),
+it specifies delivery directly to you.
+
+If an address matches
+.B $USER@$HOST
+(without regard to case),
+it specifies delivery directly to you.
+
+.B COMPATIBILITY WARNING:
+sendmail's
+handling of quotes and backslashes violates RFC 821 and RFC 822,
+and is not supported by
+.BR dot-forward .
+.B dot-forward
+treats
+.B \ejoe
+the same way as
+.BR joe .
+The
+.B dot-qmail
+delivery mechanism
+lets each user manage several addresses,
+so there is no need for a special syntax to get around forwarding.
+.SH "COMMANDS"
+If an address does not contain a domain name,
+and begins with a vertical bar,
+.B dot-forward
+takes the rest of the address as a command to run:
+
+.EX
+ bob, "|vacation bob"
+.EE
+
+.B dot-forward
+feeds the message to the command,
+preceded by the environment variables
+.BR $UFLINE ,
+.BR $RPLINE ,
+and
+.BR $DTLINE .
+
+.B COMPATIBILITY WARNING:
+Internet addresses can legitimately start with a slash or vertical bar.
+.B dot-forward
+treats anything with an unquoted @ as an address.
+sendmail
+appears to have various problems coping with these addresses,
+and with commands that contain @ signs.
+.SH "COMMENTS"
+Any line in
+.I file
+that begins with # is ignored:
+
+.EX
+ # this is a comment
+.EE
+
+.B COMPATIBILITY WARNING:
+Versions of
+sendmail
+before V8 did not allow comments in
+.B .forward
+files.
+.SH VERSION
+This is
+.B dot-forward
+0.71.
+The
+.B dot-forward
+home page is
+.BR http://pobox.com/~djb/dot-forward.html .
+.SH "SEE ALSO"
+qmail-header(5),
+dot-qmail(5)
--- /dev/null
+#include "sgetopt.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "stralloc.h"
+#include "getln.h"
+#include "strerr.h"
+#include "error.h"
+#include "exit.h"
+#include "open.h"
+#include "wait.h"
+#include "seek.h"
+#include "env.h"
+#include "str.h"
+#include "fmt.h"
+#include "token822.h"
+#include "control.h"
+#include "qmail.h"
+#include "auto_qmail.h"
+
+#define FATAL "dot-forward: fatal: "
+#define INFO "dot-forward: info: "
+
+void die_nomem()
+{ strerr_die2x(111,FATAL,"out of memory"); }
+void die_control()
+{ strerr_die2sys(111,FATAL,"unable to read controls: "); }
+void die_qq()
+{ strerr_die2sys(111,FATAL,"unable to run qq: "); }
+void die_readmess()
+{ strerr_die2sys(111,FATAL,"unable to read message: "); }
+
+stralloc line = {0};
+
+void die_parse()
+{
+ if (!stralloc_0(&line)) die_nomem();
+ strerr_die3x(111,FATAL,"unable to parse this line: ",line.s);
+}
+
+int flagdoit = 1;
+int flagacted;
+int flagdirect;
+
+char *ufline;
+char *rpline;
+char *dtline;
+char *sender;
+char *user;
+int userlen;
+char *host;
+int hostlen;
+
+char messbuf[1024];
+substdio ssmess;
+char childbuf[1024];
+substdio sschild;
+
+int blindwrite(fd,buf,len)
+int fd; char *buf; int len;
+{
+ write(fd,buf,len);
+ return len;
+}
+
+void run(cmd)
+char *cmd;
+{
+ int child;
+ int pi[2];
+ char *args[4];
+ int wstat;
+
+ if (!flagdoit) {
+ strerr_warn2("pipe through ",cmd,0);
+ return;
+ }
+
+ if (pipe(pi) == -1)
+ strerr_die2sys(111,FATAL,"unable to create pipe: ");
+
+ switch (child = fork()) {
+ case -1:
+ strerr_die2sys(111,FATAL,"unable to fork: ");
+ case 0:
+ close(pi[1]);
+ if (fd_move(0,pi[0]) == -1)
+ strerr_die2sys(111,FATAL,"unable to set fd: ");
+ args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmd; args[3] = 0;
+ sig_pipedefault();
+ execv(*args,args);
+ strerr_die2sys(111,FATAL,"unable to run /bin/sh: ");
+ }
+
+ close(pi[0]);
+
+ substdio_fdbuf(&ssmess,read,0,messbuf,sizeof messbuf);
+ substdio_fdbuf(&sschild,blindwrite,pi[1],childbuf,sizeof childbuf);
+
+ substdio_puts(&sschild,ufline);
+ substdio_puts(&sschild,rpline);
+ substdio_puts(&sschild,dtline);
+ if (substdio_copy(&sschild,&ssmess) != 0) die_readmess();
+ substdio_flush(&sschild);
+
+ close(pi[1]);
+
+ wait_pid(&wstat,child);
+ if (wait_crashed(wstat))
+ strerr_die2x(111,FATAL,"child crashed");
+
+ switch(wait_exitcode(wstat)) {
+ case 100:
+ case 64: case 65: case 70: case 76: case 77: case 78: case 112:
+ _exit(100);
+ case 0:
+ break;
+ default:
+ _exit(111);
+ }
+
+ if (seek_begin(0) == -1)
+ strerr_die2sys(111,FATAL,"unable to rewind input: ");
+}
+
+stralloc targets = {0};
+
+stralloc me = {0};
+stralloc defaulthost = {0};
+stralloc defaultdomain = {0};
+stralloc plusdomain = {0};
+
+void readcontrols()
+{
+ int r;
+ int fddir;
+
+ fddir = open_read(".");
+ if (fddir == -1)
+ strerr_die2sys(111,FATAL,"unable to open current directory: ");
+
+ if (chdir(auto_qmail) == -1)
+ strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": ");
+
+ r = control_readline(&me,"control/me");
+ if (r == -1) die_control();
+ if (!r) if (!stralloc_copys(&me,"me")) die_nomem();
+
+ r = control_readline(&defaultdomain,"control/defaultdomain");
+ if (r == -1) die_control();
+ if (!r) if (!stralloc_copy(&defaultdomain,&me)) die_nomem();
+
+ r = control_readline(&defaulthost,"control/defaulthost");
+ if (r == -1) die_control();
+ if (!r) if (!stralloc_copy(&defaulthost,&me)) die_nomem();
+
+ r = control_readline(&plusdomain,"control/plusdomain");
+ if (r == -1) die_control();
+ if (!r) if (!stralloc_copy(&plusdomain,&me)) die_nomem();
+
+ if (fchdir(fddir) == -1)
+ strerr_die2sys(111,FATAL,"unable to set current directory: ");
+}
+
+stralloc cbuf = {0};
+token822_alloc toks = {0};
+token822_alloc tokaddr = {0};
+stralloc address = {0};
+
+void gotaddr()
+{
+ int i;
+ int j;
+ int flaghasat;
+
+ token822_reverse(&tokaddr);
+ if (token822_unquote(&address,&tokaddr) != 1) die_nomem();
+
+ flaghasat = 0;
+ for (i = 0;i < tokaddr.len;++i)
+ if (tokaddr.t[i].type == TOKEN822_AT)
+ flaghasat = 1;
+
+ tokaddr.len = 0;
+
+ if (!address.len) return;
+
+ if (!flaghasat)
+ if (address.len == userlen)
+ if (!case_diffb(address.s,address.len,user)) {
+ flagacted = 1;
+ flagdirect = 1;
+ return;
+ }
+
+ if (flaghasat)
+ if (address.len == userlen + 1 + hostlen)
+ if (!case_diffb(address.s,userlen,user))
+ if (address.s[userlen] == '@')
+ if (!case_diffb(address.s + userlen + 1,hostlen,host)) {
+ flagacted = 1;
+ flagdirect = 1;
+ return;
+ }
+
+ if (!flaghasat)
+ if (address.s[0] == '/') {
+ if (!stralloc_0(&address)) die_nomem();
+ strerr_die4x(111,FATAL,"file delivery ",address.s," not supported");
+ }
+
+ if (!flaghasat)
+ if (address.s[0] == '|') {
+ if (!stralloc_0(&address)) die_nomem();
+ flagacted = 1;
+ run(address.s + 1);
+ return;
+ }
+
+ if (!flaghasat) {
+ if (!stralloc_cats(&address,"@")) die_nomem();
+ if (!stralloc_cat(&address,&defaulthost)) die_nomem();
+ }
+ if (address.s[address.len - 1] == '+') {
+ address.s[address.len - 1] = '.';
+ if (!stralloc_cat(&address,&plusdomain)) die_nomem();
+ }
+ j = 0;
+ for (i = 0;i < address.len;++i) if (address.s[i] == '@') j = i;
+ for (i = j;i < address.len;++i) if (address.s[i] == '.') break;
+ if (i == address.len) {
+ if (!stralloc_cats(&address,".")) die_nomem();
+ if (!stralloc_cat(&address,&defaultdomain)) die_nomem();
+ }
+
+ if (!stralloc_0(&address)) die_nomem();
+
+ if (!stralloc_cats(&targets,"T")) die_nomem();
+ if (!stralloc_cats(&targets,address.s)) die_nomem();
+ if (!stralloc_0(&targets)) die_nomem();
+
+ if (!flagdoit)
+ strerr_warn2("forward ",address.s,0);
+}
+
+void parseline()
+{
+ int wordok;
+ struct token822 *t;
+ struct token822 *beginning;
+ int r;
+
+ r = token822_parse(&toks,&line,&cbuf);
+ if (r == -1) die_nomem();
+ if (r == 0) die_parse();
+
+ beginning = toks.t;
+ t = toks.t + toks.len;
+ wordok = 1;
+
+ if (!token822_readyplus(&tokaddr,1)) die_nomem();
+ tokaddr.len = 0;
+
+ while (t > beginning)
+ switch((--t)->type) {
+ case TOKEN822_SEMI:
+ break; /*XXX*/
+ case TOKEN822_COLON:
+ break; /*XXX*/
+ case TOKEN822_RIGHT:
+ if (tokaddr.len) gotaddr();
+ while ((t > beginning) && (t[-1].type != TOKEN822_LEFT))
+ if (!token822_append(&tokaddr,--t)) die_nomem();
+ gotaddr();
+ if (t <= beginning) die_parse();
+ --t;
+ while ((t > beginning) && ((t[-1].type == TOKEN822_COMMENT) || (t[-1].type == TOKEN822_ATOM) || (t[-1].type == TOKEN822_QUOTE) || (t[-1].type == TOKEN822_AT) || (t[-1].type == TOKEN822_DOT)))
+ --t;
+ wordok = 0;
+ continue;
+ case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
+ if (!wordok) if (tokaddr.len) gotaddr();
+ wordok = 0;
+ if (!token822_append(&tokaddr,t)) die_nomem();
+ continue;
+ case TOKEN822_COMMENT:
+ /* comment is lexically a space; shouldn't affect wordok */
+ break;
+ case TOKEN822_COMMA:
+ if (tokaddr.len) gotaddr();
+ wordok = 1;
+ break;
+ default:
+ wordok = 1;
+ if (!token822_append(&tokaddr,t)) die_nomem();
+ continue;
+ }
+ if (tokaddr.len) gotaddr();
+}
+
+struct qmail qq;
+unsigned long qp;
+char *qqx;
+char strnum[FMT_ULONG];
+
+int mywrite(fd,buf,len)
+int fd; char *buf; int len;
+{
+ qmail_put(&qq,buf,len);
+ return len;
+}
+
+char qqbuf[256];
+substdio ssqq = SUBSTDIO_FDBUF(mywrite,-1,qqbuf,sizeof qqbuf);
+
+char inbuf[256];
+
+void try(fn)
+char *fn;
+{
+ int fd;
+ int match;
+ substdio ss;
+
+ fd = open_read(fn);
+ if (fd == -1) {
+ if (errno == error_noent) return;
+ strerr_die4sys(111,FATAL,"unable to open ",fn,": ");
+ }
+
+ if (!stralloc_copys(&targets,"")) die_nomem();
+ flagacted = 0;
+ flagdirect = 0;
+
+ substdio_fdbuf(&ss,read,fd,inbuf,sizeof inbuf);
+
+ for (;;) {
+ if (getln(&ss,&line,&match,'\n') == -1)
+ strerr_die4sys(111,FATAL,"unable to read ",fn,": ");
+ if (!line.len) break;
+ if (line.s[0] != '#') parseline();
+ if (!match) break;
+ }
+
+ close(fd);
+
+ if (targets.len) {
+ flagacted = 1;
+ if (flagdoit) {
+ if (qmail_open(&qq) == -1)
+ strerr_die2sys(111,FATAL,"unable to run qmail-queue: ");
+ qp = qmail_qp(&qq);
+ qmail_puts(&qq,dtline);
+
+ substdio_fdbuf(&ssmess,read,0,messbuf,sizeof messbuf);
+ if (substdio_copy(&ssqq,&ssmess) != 0) die_readmess();
+ substdio_flush(&ssqq);
+
+ qmail_from(&qq,sender);
+ qmail_put(&qq,targets.s,targets.len);
+
+ qqx = qmail_close(&qq);
+ if (*qqx == 'D')
+ strerr_die3x(100,FATAL,"unable to forward message: ",qqx + 1);
+ if (*qqx)
+ strerr_die3x(111,FATAL,"unable to forward message: ",qqx + 1);
+ strnum[fmt_ulong(strnum,qp)] = 0;
+ strerr_warn3(INFO,"qp ",strnum,0);
+ }
+ }
+
+ if (flagdirect) {
+ if (!flagdoit) strerr_warn1("direct delivery",0);
+ _exit(0);
+ }
+ if (!flagacted) {
+ if (!flagdoit) strerr_warn2("skipping empty file ",fn,0);
+ return;
+ }
+ _exit(99);
+}
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ int opt;
+ int fddir;
+
+ sig_pipeignore();
+
+ while ((opt = getopt(argc,argv,"nN")) != opteof)
+ switch(opt) {
+ case 'n':
+ flagdoit = 0; break;
+ case 'N':
+ flagdoit = 1; break;
+ default:
+ strerr_die1x(100,"dot-forward: usage: dot-forward [ -nN ] file ...");
+ }
+ argv += optind;
+
+ ufline = env_get("UFLINE"); if (!ufline) ufline = "";
+ rpline = env_get("RPLINE"); if (!rpline) rpline = "";
+ dtline = env_get("DTLINE"); if (!dtline) dtline = "";
+ sender = env_get("NEWSENDER"); if (!sender) sender = "";
+
+ user = env_get("USER"); if (!user) user = "";
+ userlen = str_len(user);
+ host = env_get("HOST"); if (!host) host = "";
+ hostlen = str_len(host);
+
+ readcontrols();
+
+ while (*argv)
+ try(*argv++);
+
+ if (!flagdoit) strerr_warn1("direct delivery",0);
+ _exit(0);
+}
--- /dev/null
+#ifndef ENV_H
+#define ENV_H
+
+extern int env_isinit;
+
+extern int env_init();
+extern int env_put();
+extern int env_put2();
+extern int env_unset();
+extern /*@null@*/char *env_get();
+extern char *env_pick();
+extern void env_clear();
+extern char *env_findeq();
+
+extern char **environ;
+
+#endif
--- /dev/null
+#include "env.h"
+#include "str.h"
+
+extern /*@null@*/char *env_get(s)
+char *s;
+{
+ int i;
+ unsigned int slen;
+ char *envi;
+
+ slen = str_len(s);
+ for (i = 0;envi = environ[i];++i)
+ if ((!str_diffn(s,envi,slen)) && (envi[slen] == '='))
+ return envi + slen + 1;
+ return 0;
+}
+
+extern char *env_pick()
+{
+ return environ[0];
+}
+
+extern char *env_findeq(s)
+char *s;
+{
+ for (;*s;++s)
+ if (*s == '=')
+ return s;
+ return 0;
+}
--- /dev/null
+#include <errno.h>
+#include "error.h"
+
+/* warning: as coverage improves here, should update error_{str,temp} */
+
+int error_intr =
+#ifdef EINTR
+EINTR;
+#else
+-1;
+#endif
+
+int error_nomem =
+#ifdef ENOMEM
+ENOMEM;
+#else
+-2;
+#endif
+
+int error_noent =
+#ifdef ENOENT
+ENOENT;
+#else
+-3;
+#endif
+
+int error_txtbsy =
+#ifdef ETXTBSY
+ETXTBSY;
+#else
+-4;
+#endif
+
+int error_io =
+#ifdef EIO
+EIO;
+#else
+-5;
+#endif
+
+int error_exist =
+#ifdef EEXIST
+EEXIST;
+#else
+-6;
+#endif
+
+int error_timeout =
+#ifdef ETIMEDOUT
+ETIMEDOUT;
+#else
+-7;
+#endif
+
+int error_inprogress =
+#ifdef EINPROGRESS
+EINPROGRESS;
+#else
+-8;
+#endif
+
+int error_wouldblock =
+#ifdef EWOULDBLOCK
+EWOULDBLOCK;
+#else
+-9;
+#endif
+
+int error_again =
+#ifdef EAGAIN
+EAGAIN;
+#else
+-10;
+#endif
+
+int error_pipe =
+#ifdef EPIPE
+EPIPE;
+#else
+-11;
+#endif
+
+int error_perm =
+#ifdef EPERM
+EPERM;
+#else
+-12;
+#endif
+
+int error_acces =
+#ifdef EACCES
+EACCES;
+#else
+-13;
+#endif
--- /dev/null
+#ifndef ERROR_H
+#define ERROR_H
+
+extern int errno;
+
+extern int error_intr;
+extern int error_nomem;
+extern int error_noent;
+extern int error_txtbsy;
+extern int error_io;
+extern int error_exist;
+extern int error_timeout;
+extern int error_inprogress;
+extern int error_wouldblock;
+extern int error_again;
+extern int error_pipe;
+extern int error_perm;
+extern int error_acces;
+
+extern char *error_str();
+extern int error_temp();
+
+#endif
--- /dev/null
+#include <errno.h>
+#include "error.h"
+
+#define X(e,s) if (i == e) return s;
+
+char *error_str(i)
+int i;
+{
+ X(0,"no error")
+ X(error_intr,"interrupted system call")
+ X(error_nomem,"out of memory")
+ X(error_noent,"file does not exist")
+ X(error_txtbsy,"text busy")
+ X(error_io,"input/output error")
+ X(error_exist,"file already exists")
+ X(error_timeout,"timed out")
+ X(error_inprogress,"operation in progress")
+ X(error_again,"temporary failure")
+ X(error_wouldblock,"input/output would block")
+ X(error_pipe,"broken pipe")
+ X(error_perm,"permission denied")
+ X(error_acces,"access denied")
+#ifdef ESRCH
+ X(ESRCH,"no such process")
+#endif
+#ifdef ENXIO
+ X(ENXIO,"device not configured")
+#endif
+#ifdef E2BIG
+ X(E2BIG,"argument list too long")
+#endif
+#ifdef ENOEXEC
+ X(ENOEXEC,"exec format error")
+#endif
+#ifdef EBADF
+ X(EBADF,"file descriptor not open")
+#endif
+#ifdef ECHILD
+ X(ECHILD,"no child processes")
+#endif
+#ifdef EDEADLK
+ X(EDEADLK,"operation would cause deadlock")
+#endif
+#ifdef EFAULT
+ X(EFAULT,"bad address")
+#endif
+#ifdef ENOTBLK
+ X(ENOTBLK,"not a block device")
+#endif
+#ifdef EBUSY
+ X(EBUSY,"device busy")
+#endif
+#ifdef EXDEV
+ X(EXDEV,"cross-device link")
+#endif
+#ifdef ENODEV
+ X(ENODEV,"device does not support operation")
+#endif
+#ifdef ENOTDIR
+ X(ENOTDIR,"not a directory")
+#endif
+#ifdef EISDIR
+ X(EISDIR,"is a directory")
+#endif
+#ifdef EINVAL
+ X(EINVAL,"invalid argument")
+#endif
+#ifdef ENFILE
+ X(ENFILE,"system cannot open more files")
+#endif
+#ifdef EMFILE
+ X(EMFILE,"process cannot open more files")
+#endif
+#ifdef ENOTTY
+ X(ENOTTY,"not a tty")
+#endif
+#ifdef EFBIG
+ X(EFBIG,"file too big")
+#endif
+#ifdef ENOSPC
+ X(ENOSPC,"out of disk space")
+#endif
+#ifdef ESPIPE
+ X(ESPIPE,"unseekable descriptor")
+#endif
+#ifdef EROFS
+ X(EROFS,"read-only file system")
+#endif
+#ifdef EMLINK
+ X(EMLINK,"too many links")
+#endif
+#ifdef EDOM
+ X(EDOM,"input out of range")
+#endif
+#ifdef ERANGE
+ X(ERANGE,"output out of range")
+#endif
+#ifdef EALREADY
+ X(EALREADY,"operation already in progress")
+#endif
+#ifdef ENOTSOCK
+ X(ENOTSOCK,"not a socket")
+#endif
+#ifdef EDESTADDRREQ
+ X(EDESTADDRREQ,"destination address required")
+#endif
+#ifdef EMSGSIZE
+ X(EMSGSIZE,"message too long")
+#endif
+#ifdef EPROTOTYPE
+ X(EPROTOTYPE,"incorrect protocol type")
+#endif
+#ifdef ENOPROTOOPT
+ X(ENOPROTOOPT,"protocol not available")
+#endif
+#ifdef EPROTONOSUPPORT
+ X(EPROTONOSUPPORT,"protocol not supported")
+#endif
+#ifdef ESOCKTNOSUPPORT
+ X(ESOCKTNOSUPPORT,"socket type not supported")
+#endif
+#ifdef EOPNOTSUPP
+ X(EOPNOTSUPP,"operation not supported")
+#endif
+#ifdef EPFNOSUPPORT
+ X(EPFNOSUPPORT,"protocol family not supported")
+#endif
+#ifdef EAFNOSUPPORT
+ X(EAFNOSUPPORT,"address family not supported")
+#endif
+#ifdef EADDRINUSE
+ X(EADDRINUSE,"address already used")
+#endif
+#ifdef EADDRNOTAVAIL
+ X(EADDRNOTAVAIL,"address not available")
+#endif
+#ifdef ENETDOWN
+ X(ENETDOWN,"network down")
+#endif
+#ifdef ENETUNREACH
+ X(ENETUNREACH,"network unreachable")
+#endif
+#ifdef ENETRESET
+ X(ENETRESET,"network reset")
+#endif
+#ifdef ECONNABORTED
+ X(ECONNABORTED,"connection aborted")
+#endif
+#ifdef ECONNRESET
+ X(ECONNRESET,"connection reset")
+#endif
+#ifdef ENOBUFS
+ X(ENOBUFS,"out of buffer space")
+#endif
+#ifdef EISCONN
+ X(EISCONN,"already connected")
+#endif
+#ifdef ENOTCONN
+ X(ENOTCONN,"not connected")
+#endif
+#ifdef ESHUTDOWN
+ X(ESHUTDOWN,"socket shut down")
+#endif
+#ifdef ETOOMANYREFS
+ X(ETOOMANYREFS,"too many references")
+#endif
+#ifdef ECONNREFUSED
+ X(ECONNREFUSED,"connection refused")
+#endif
+#ifdef ELOOP
+ X(ELOOP,"symbolic link loop")
+#endif
+#ifdef ENAMETOOLONG
+ X(ENAMETOOLONG,"file name too long")
+#endif
+#ifdef EHOSTDOWN
+ X(EHOSTDOWN,"host down")
+#endif
+#ifdef EHOSTUNREACH
+ X(EHOSTUNREACH,"host unreachable")
+#endif
+#ifdef ENOTEMPTY
+ X(ENOTEMPTY,"directory not empty")
+#endif
+#ifdef EPROCLIM
+ X(EPROCLIM,"too many processes")
+#endif
+#ifdef EUSERS
+ X(EUSERS,"too many users")
+#endif
+#ifdef EDQUOT
+ X(EDQUOT,"disk quota exceeded")
+#endif
+#ifdef ESTALE
+ X(ESTALE,"stale NFS file handle")
+#endif
+#ifdef EREMOTE
+ X(EREMOTE,"too many levels of remote in path")
+#endif
+#ifdef EBADRPC
+ X(EBADRPC,"RPC structure is bad")
+#endif
+#ifdef ERPCMISMATCH
+ X(ERPCMISMATCH,"RPC version mismatch")
+#endif
+#ifdef EPROGUNAVAIL
+ X(EPROGUNAVAIL,"RPC program unavailable")
+#endif
+#ifdef EPROGMISMATCH
+ X(EPROGMISMATCH,"program version mismatch")
+#endif
+#ifdef EPROCUNAVAIL
+ X(EPROCUNAVAIL,"bad procedure for program")
+#endif
+#ifdef ENOLCK
+ X(ENOLCK,"no locks available")
+#endif
+#ifdef ENOSYS
+ X(ENOSYS,"system call not available")
+#endif
+#ifdef EFTYPE
+ X(EFTYPE,"bad file type")
+#endif
+#ifdef EAUTH
+ X(EAUTH,"authentication error")
+#endif
+#ifdef ENEEDAUTH
+ X(ENEEDAUTH,"not authenticated")
+#endif
+#ifdef ENOSTR
+ X(ENOSTR,"not a stream device")
+#endif
+#ifdef ETIME
+ X(ETIME,"timer expired")
+#endif
+#ifdef ENOSR
+ X(ENOSR,"out of stream resources")
+#endif
+#ifdef ENOMSG
+ X(ENOMSG,"no message of desired type")
+#endif
+#ifdef EBADMSG
+ X(EBADMSG,"bad message type")
+#endif
+#ifdef EIDRM
+ X(EIDRM,"identifier removed")
+#endif
+#ifdef ENONET
+ X(ENONET,"machine not on network")
+#endif
+#ifdef ERREMOTE
+ X(ERREMOTE,"object not local")
+#endif
+#ifdef ENOLINK
+ X(ENOLINK,"link severed")
+#endif
+#ifdef EADV
+ X(EADV,"advertise error")
+#endif
+#ifdef ESRMNT
+ X(ESRMNT,"srmount error")
+#endif
+#ifdef ECOMM
+ X(ECOMM,"communication error")
+#endif
+#ifdef EPROTO
+ X(EPROTO,"protocol error")
+#endif
+#ifdef EMULTIHOP
+ X(EMULTIHOP,"multihop attempted")
+#endif
+#ifdef EREMCHG
+ X(EREMCHG,"remote address changed")
+#endif
+ return "unknown error";
+}
--- /dev/null
+#ifndef EXIT_H
+#define EXIT_H
+
+extern void _exit();
+
+#endif
--- /dev/null
+#ifndef FD_H
+#define FD_H
+
+extern int fd_copy();
+extern int fd_move();
+
+#endif
--- /dev/null
+#include <fcntl.h>
+#include "fd.h"
+
+int fd_copy(to,from)
+int to;
+int from;
+{
+ if (to == from) return 0;
+ if (fcntl(from,F_GETFL,0) == -1) return -1;
+ close(to);
+ if (fcntl(from,F_DUPFD,to) == -1) return -1;
+ return 0;
+}
--- /dev/null
+#include "fd.h"
+
+int fd_move(to,from)
+int to;
+int from;
+{
+ if (to == from) return 0;
+ if (fd_copy(to,from) == -1) return -1;
+ close(from);
+ return 0;
+}
--- /dev/null
+# oper-:arch-:syst-:chip-:kern-
+# oper = operating system type; e.g., sunos-4.1.4
+# arch = machine language; e.g., sparc
+# syst = which binaries can run; e.g., sun4
+# chip = chip model; e.g., micro-2-80
+# kern = kernel version; e.g., sun4m
+# dependence: arch --- chip
+# \ \
+# oper --- syst --- kern
+# so, for example, syst is interpreted in light of oper, but chip is not.
+# anyway, no slashes, no extra colons, no uppercase letters.
+# the point of the extra -'s is to ease parsing: can add hierarchies later.
+# e.g., *:i386-*:*:pentium-*:* would handle pentium-100 as well as pentium,
+# and i386-486 (486s do have more instructions, you know) as well as i386.
+# the idea here is to include ALL useful available information.
+
+exec 2>/dev/null
+sys="`uname -s | tr '/:[A-Z]' '..[a-z]'`"
+if [ x"$sys" != x ]
+then
+ unamer="`uname -r | tr /: ..`"
+ unamem="`uname -m | tr /: ..`"
+ unamev="`uname -v | tr /: ..`"
+
+ case "$sys" in
+ bsd.os)
+ # in bsd 4.4, uname -v does not have useful info.
+ # in bsd 4.4, uname -m is arch, not chip.
+ oper="$sys-$unamer"
+ arch="$unamem"
+ syst=""
+ chip="`sysctl -n hw.model`"
+ kern=""
+ ;;
+ freebsd)
+ # see above about bsd 4.4
+ oper="$sys-$unamer"
+ arch="$unamem"
+ syst=""
+ chip="`sysctl -n hw.model`" # hopefully
+ kern=""
+ ;;
+ netbsd)
+ # see above about bsd 4.4
+ oper="$sys-$unamer"
+ arch="$unamem"
+ syst=""
+ chip="`sysctl -n hw.model`" # hopefully
+ kern=""
+ ;;
+ linux)
+ # as in bsd 4.4, uname -v does not have useful info.
+ oper="$sys-$unamer"
+ syst=""
+ chip="$unamem"
+ kern=""
+ case "$chip" in
+ i386|i486|i586|i686)
+ arch="i386"
+ ;;
+ alpha)
+ arch="alpha"
+ ;;
+ esac
+ ;;
+ aix)
+ # naturally IBM has to get uname -r and uname -v backwards. dorks.
+ oper="$sys-$unamev-$unamer"
+ arch="`arch | tr /: ..`"
+ syst=""
+ chip="$unamem"
+ kern=""
+ ;;
+ sunos)
+ oper="$sys-$unamer-$unamev"
+ arch="`(uname -p || mach) | tr /: ..`"
+ syst="`arch | tr /: ..`"
+ chip="$unamem" # this is wrong; is there any way to get the real info?
+ kern="`arch -k | tr /: ..`"
+ ;;
+ unix_sv)
+ oper="$sys-$unamer-$unamev"
+ arch="`uname -m`"
+ syst=""
+ chip="$unamem"
+ kern=""
+ ;;
+ *)
+ oper="$sys-$unamer-$unamev"
+ arch="`arch | tr /: ..`"
+ syst=""
+ chip="$unamem"
+ kern=""
+ ;;
+ esac
+else
+ $CC -c trycpp.c
+ $LD -o trycpp trycpp.o
+ case `./trycpp` in
+ nextstep)
+ oper="nextstep-`hostinfo | sed -n 's/^[ ]*NeXT Mach \([^:]*\):.*$/\1/p'`"
+ arch="`hostinfo | sed -n 's/^Processor type: \(.*\) (.*)$/\1/p' | tr /: ..`"
+ syst=""
+ chip="`hostinfo | sed -n 's/^Processor type: .* (\(.*\))$/\1/p' | tr ' /:' '...'`"
+ kern=""
+ ;;
+ *)
+ oper="unknown"
+ arch=""
+ syst=""
+ chip=""
+ kern=""
+ ;;
+ esac
+ rm -f trycpp.o trycpp
+fi
+
+case "$chip" in
+80486)
+ # let's try to be consistent here. (BSD/OS)
+ chip=i486
+ ;;
+i486DX)
+ # respect the hyphen hierarchy. (FreeBSD)
+ chip=i486-dx
+ ;;
+i486.DX2)
+ # respect the hyphen hierarchy. (FreeBSD)
+ chip=i486-dx2
+ ;;
+Intel.586)
+ # no, you nitwits, there is no such chip. (NeXTStep)
+ chip=pentium
+ ;;
+i586)
+ # no, you nitwits, there is no such chip. (Linux)
+ chip=pentium
+ ;;
+i686)
+ # STOP SAYING THAT! (Linux)
+ chip=ppro
+esac
+
+echo "$oper-:$arch-:$syst-:$chip-:$kern-" | tr ' [A-Z]' '.[a-z]'
--- /dev/null
+#ifndef FMT_H
+#define FMT_H
+
+#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */
+#define FMT_LEN ((char *) 0) /* convenient abbreviation */
+
+extern unsigned int fmt_uint();
+extern unsigned int fmt_uint0();
+extern unsigned int fmt_xint();
+extern unsigned int fmt_nbbint();
+extern unsigned int fmt_ushort();
+extern unsigned int fmt_xshort();
+extern unsigned int fmt_nbbshort();
+extern unsigned int fmt_ulong();
+extern unsigned int fmt_xlong();
+extern unsigned int fmt_nbblong();
+
+extern unsigned int fmt_plusminus();
+extern unsigned int fmt_minus();
+extern unsigned int fmt_0x();
+
+extern unsigned int fmt_str();
+extern unsigned int fmt_strn();
+
+#endif
--- /dev/null
+#include "fmt.h"
+
+unsigned int fmt_ulong(s,u) register char *s; register unsigned long u;
+{
+ register unsigned int len; register unsigned long q;
+ len = 1; q = u;
+ while (q > 9) { ++len; q /= 10; }
+ if (s) {
+ s += len;
+ do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */
+ }
+ return len;
+}
--- /dev/null
+#ifndef FORK_H
+#define FORK_H
+
+extern int fork();
+#define vfork fork
+
+#endif
--- /dev/null
+#ifndef FORK_H
+#define FORK_H
+
+extern int fork();
+extern int vfork();
+
+#endif
--- /dev/null
+#ifndef GEN_ALLOC_H
+#define GEN_ALLOC_H
+
+#define GEN_ALLOC_typedef(ta,type,field,len,a) \
+ typedef struct ta { type *field; unsigned int len; unsigned int a; } ta;
+
+#endif
--- /dev/null
+#ifndef GEN_ALLOC_DEFS_H
+#define GEN_ALLOC_DEFS_H
+
+#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \
+int ta_ready(x,n) register ta *x; register unsigned int n; \
+{ register unsigned int i; \
+ if (x->field) { \
+ i = x->a; \
+ if (n > i) { \
+ x->a = base + n + (n >> 3); \
+ if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \
+ x->a = i; return 0; } \
+ return 1; } \
+ x->len = 0; \
+ return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); }
+
+#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \
+int ta_rplus(x,n) register ta *x; register unsigned int n; \
+{ register unsigned int i; \
+ if (x->field) { \
+ i = x->a; n += x->len; \
+ if (n > i) { \
+ x->a = base + n + (n >> 3); \
+ if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \
+ x->a = i; return 0; } \
+ return 1; } \
+ x->len = 0; \
+ return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); }
+
+#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \
+int ta_append(x,i) register ta *x; register type *i; \
+{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; }
+
+#endif
--- /dev/null
+#include "substdio.h"
+#include "byte.h"
+#include "stralloc.h"
+#include "getln.h"
+
+int getln(ss,sa,match,sep)
+register substdio *ss;
+register stralloc *sa;
+int *match;
+int sep;
+{
+ char *cont;
+ unsigned int clen;
+
+ if (getln2(ss,sa,&cont,&clen,sep) == -1) return -1;
+ if (!clen) { *match = 0; return 0; }
+ if (!stralloc_catb(sa,cont,clen)) return -1;
+ *match = 1;
+ return 0;
+}
--- /dev/null
+#ifndef GETLN_H
+#define GETLN_H
+
+extern int getln();
+extern int getln2();
+
+#endif
--- /dev/null
+#include "substdio.h"
+#include "stralloc.h"
+#include "byte.h"
+#include "getln.h"
+
+int getln2(ss,sa,cont,clen,sep)
+register substdio *ss;
+register stralloc *sa;
+/*@out@*/char **cont;
+/*@out@*/unsigned int *clen;
+int sep;
+{
+ register char *x;
+ register unsigned int i;
+ int n;
+
+ if (!stralloc_ready(sa,0)) return -1;
+ sa->len = 0;
+
+ for (;;) {
+ n = substdio_feed(ss);
+ if (n < 0) return -1;
+ if (n == 0) { *clen = 0; return 0; }
+ x = substdio_PEEK(ss);
+ i = byte_chr(x,n,sep);
+ if (i < n) { substdio_SEEK(ss,*clen = i + 1); *cont = x; return 0; }
+ if (!stralloc_readyplus(sa,n)) return -1;
+ i = sa->len;
+ sa->len = i + substdio_get(ss,sa->s + i,n);
+ }
+}
--- /dev/null
+#include "auto_qmail.h"
+
+void hier()
+{
+ h(auto_qmail,-1,-1,0755);
+
+ d(auto_qmail,"bin",-1,-1,0755);
+ d(auto_qmail,"man",-1,-1,0755);
+ d(auto_qmail,"man/man1",-1,-1,0755);
+ d(auto_qmail,"man/cat1",-1,-1,0755);
+
+ c(auto_qmail,"bin","dot-forward",-1,-1,0755);
+
+ c(auto_qmail,"man/man1","dot-forward.1",-1,-1,0644);
+ c(auto_qmail,"man/cat1","dot-forward.0",-1,-1,0644);
+}
--- /dev/null
+#include "substdio.h"
+#include "strerr.h"
+#include "error.h"
+#include "open.h"
+#include "readwrite.h"
+#include "exit.h"
+
+extern void hier();
+
+#define FATAL "install: fatal: "
+
+int fdsourcedir = -1;
+
+void h(home,uid,gid,mode)
+char *home;
+int uid;
+int gid;
+int mode;
+{
+ if (mkdir(home,0700) == -1)
+ if (errno != error_exist)
+ strerr_die4sys(111,FATAL,"unable to mkdir ",home,": ");
+ if (chown(home,uid,gid) == -1)
+ strerr_die4sys(111,FATAL,"unable to chown ",home,": ");
+ if (chmod(home,mode) == -1)
+ strerr_die4sys(111,FATAL,"unable to chmod ",home,": ");
+}
+
+void d(home,subdir,uid,gid,mode)
+char *home;
+char *subdir;
+int uid;
+int gid;
+int mode;
+{
+ if (chdir(home) == -1)
+ strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+ if (mkdir(subdir,0700) == -1)
+ if (errno != error_exist)
+ strerr_die6sys(111,FATAL,"unable to mkdir ",home,"/",subdir,": ");
+ if (chown(subdir,uid,gid) == -1)
+ strerr_die6sys(111,FATAL,"unable to chown ",home,"/",subdir,": ");
+ if (chmod(subdir,mode) == -1)
+ strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",subdir,": ");
+}
+
+char inbuf[SUBSTDIO_INSIZE];
+char outbuf[SUBSTDIO_OUTSIZE];
+substdio ssin;
+substdio ssout;
+
+void c(home,subdir,file,uid,gid,mode)
+char *home;
+char *subdir;
+char *file;
+int uid;
+int gid;
+int mode;
+{
+ int fdin;
+ int fdout;
+
+ if (fchdir(fdsourcedir) == -1)
+ strerr_die2sys(111,FATAL,"unable to switch back to source directory: ");
+
+ fdin = open_read(file);
+ if (fdin == -1)
+ strerr_die4sys(111,FATAL,"unable to read ",file,": ");
+ substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof inbuf);
+
+ if (chdir(home) == -1)
+ strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+ if (chdir(subdir) == -1)
+ strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": ");
+
+ fdout = open_trunc(file);
+ if (fdout == -1)
+ strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+ substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof outbuf);
+
+ switch(substdio_copy(&ssout,&ssin)) {
+ case -2:
+ strerr_die4sys(111,FATAL,"unable to read ",file,": ");
+ case -3:
+ strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+ }
+
+ close(fdin);
+ if (substdio_flush(&ssout) == -1)
+ strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+ if (fsync(fdout) == -1)
+ strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+ if (close(fdout) == -1) /* NFS silliness */
+ strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": ");
+
+ if (chown(file,uid,gid) == -1)
+ strerr_die6sys(111,FATAL,"unable to chown .../",subdir,"/",file,": ");
+ if (chmod(file,mode) == -1)
+ strerr_die6sys(111,FATAL,"unable to chmod .../",subdir,"/",file,": ");
+}
+
+void main()
+{
+ fdsourcedir = open_read(".");
+ if (fdsourcedir == -1)
+ strerr_die2sys(111,FATAL,"unable to open current directory: ");
+
+ umask(077);
+ hier();
+ _exit(0);
+}
--- /dev/null
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "strerr.h"
+#include "error.h"
+#include "readwrite.h"
+#include "exit.h"
+
+extern void hier();
+
+#define FATAL "instcheck: fatal: "
+#define WARNING "instcheck: warning: "
+
+void perm(prefix1,prefix2,prefix3,file,type,uid,gid,mode)
+char *prefix1;
+char *prefix2;
+char *prefix3;
+char *file;
+int type;
+int uid;
+int gid;
+int mode;
+{
+ struct stat st;
+
+ if (stat(file,&st) == -1) {
+ if (errno == error_noent)
+ strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," does not exist",0);
+ else
+ strerr_warn4(WARNING,"unable to stat .../",file,": ",&strerr_sys);
+ return;
+ }
+
+ if ((uid != -1) && (st.st_uid != uid))
+ strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong owner",0);
+ if ((gid != -1) && (st.st_gid != gid))
+ strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong group",0);
+ if ((st.st_mode & 07777) != mode)
+ strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong permissions",0);
+ if ((st.st_mode & S_IFMT) != type)
+ strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong type",0);
+}
+
+void h(home,uid,gid,mode)
+char *home;
+int uid;
+int gid;
+int mode;
+{
+ perm("","","",home,S_IFDIR,uid,gid,mode);
+}
+
+void d(home,subdir,uid,gid,mode)
+char *home;
+char *subdir;
+int uid;
+int gid;
+int mode;
+{
+ if (chdir(home) == -1)
+ strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+ perm("",home,"/",subdir,S_IFDIR,uid,gid,mode);
+}
+
+void c(home,subdir,file,uid,gid,mode)
+char *home;
+char *subdir;
+char *file;
+int uid;
+int gid;
+int mode;
+{
+ if (chdir(home) == -1)
+ strerr_die4sys(111,FATAL,"unable to switch to ",home,": ");
+ if (chdir(subdir) == -1)
+ strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": ");
+ perm(".../",subdir,"/",file,S_IFREG,uid,gid,mode);
+}
+
+void main()
+{
+ hier();
+ _exit(0);
+}
--- /dev/null
+echo exec "$CC" -c '${1+"$@"}'
--- /dev/null
+echo 'main="$1"; shift'
+echo exec "$LD" '-o "$main" "$main".o ${1+"$@"}'
--- /dev/null
+echo 'main="$1"; shift'
+echo 'rm -f "$main"'
+echo 'ar cr "$main" ${1+"$@"}'
+
+case "$1" in
+sunos-5.*) ;;
+unix_sv*) ;;
+irix64-*) ;;
+irix-*) ;;
+dgux-*) ;;
+hp-ux-*) ;;
+sco*) ;;
+*)
+ echo 'ranlib "$main"'
+ ;;
+esac
--- /dev/null
+#ifndef OPEN_H
+#define OPEN_H
+
+extern int open_read();
+extern int open_excl();
+extern int open_append();
+extern int open_trunc();
+extern int open_write();
+
+#endif
--- /dev/null
+#include <sys/types.h>
+#include <fcntl.h>
+#include "open.h"
+
+int open_read(fn) char *fn;
+{ return open(fn,O_RDONLY | O_NDELAY); }
--- /dev/null
+#include <sys/types.h>
+#include <fcntl.h>
+#include "open.h"
+
+int open_trunc(fn) char *fn;
+{ return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); }
--- /dev/null
+#include "substdio.h"
+#include "readwrite.h"
+#include "wait.h"
+#include "exit.h"
+#include "fork.h"
+#include "fd.h"
+#include "qmail.h"
+#include "auto_qmail.h"
+
+static char *binqqargs[2] = { "bin/qmail-queue", 0 } ;
+
+int qmail_open(qq)
+struct qmail *qq;
+{
+ int pim[2];
+ int pie[2];
+
+ if (pipe(pim) == -1) return -1;
+ if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; }
+
+ switch(qq->pid = vfork()) {
+ case -1:
+ close(pim[0]); close(pim[1]);
+ close(pie[0]); close(pie[1]);
+ return -1;
+ case 0:
+ close(pim[1]);
+ close(pie[1]);
+ if (fd_move(0,pim[0]) == -1) _exit(120);
+ if (fd_move(1,pie[0]) == -1) _exit(120);
+ if (chdir(auto_qmail) == -1) _exit(61);
+ execv(*binqqargs,binqqargs);
+ _exit(120);
+ }
+
+ qq->fdm = pim[1]; close(pim[0]);
+ qq->fde = pie[1]; close(pie[0]);
+ substdio_fdbuf(&qq->ss,write,qq->fdm,qq->buf,sizeof(qq->buf));
+ qq->flagerr = 0;
+ return 0;
+}
+
+unsigned long qmail_qp(qq) struct qmail *qq;
+{
+ return qq->pid;
+}
+
+void qmail_fail(qq) struct qmail *qq;
+{
+ qq->flagerr = 1;
+}
+
+void qmail_put(qq,s,len) struct qmail *qq; char *s; int len;
+{
+ if (!qq->flagerr) if (substdio_put(&qq->ss,s,len) == -1) qq->flagerr = 1;
+}
+
+void qmail_puts(qq,s) struct qmail *qq; char *s;
+{
+ if (!qq->flagerr) if (substdio_puts(&qq->ss,s) == -1) qq->flagerr = 1;
+}
+
+void qmail_from(qq,s) struct qmail *qq; char *s;
+{
+ if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
+ close(qq->fdm);
+ substdio_fdbuf(&qq->ss,write,qq->fde,qq->buf,sizeof(qq->buf));
+ qmail_put(qq,"F",1);
+ qmail_puts(qq,s);
+ qmail_put(qq,"",1);
+}
+
+void qmail_to(qq,s) struct qmail *qq; char *s;
+{
+ qmail_put(qq,"T",1);
+ qmail_puts(qq,s);
+ qmail_put(qq,"",1);
+}
+
+char *qmail_close(qq)
+struct qmail *qq;
+{
+ int wstat;
+ int exitcode;
+
+ qmail_put(qq,"",1);
+ if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1;
+ close(qq->fde);
+
+ if (wait_pid(&wstat,qq->pid) != qq->pid)
+ return "Zqq waitpid surprise (#4.3.0)";
+ if (wait_crashed(wstat))
+ return "Zqq crashed (#4.3.0)";
+ exitcode = wait_exitcode(wstat);
+
+ switch(exitcode) {
+ case 115: /* compatibility */
+ case 11: return "Denvelope address too long for qq (#5.1.3)";
+ case 31: return "Dmail server permanently rejected message (#5.3.0)";
+ case 51: return "Zqq out of memory (#4.3.0)";
+ case 52: return "Zqq timeout (#4.3.0)";
+ case 53: return "Zqq write error or disk full (#4.3.0)";
+ case 0: if (!qq->flagerr) return ""; /* fall through */
+ case 54: return "Zqq read error (#4.3.0)";
+ case 55: return "Zqq unable to read configuration (#4.3.0)";
+ case 56: return "Zqq trouble making network connection (#4.3.0)";
+ case 61: return "Zqq trouble in home directory (#4.3.0)";
+ case 63:
+ case 64:
+ case 65:
+ case 66:
+ case 62: return "Zqq trouble creating files in queue (#4.3.0)";
+ case 71: return "Zmail server temporarily rejected message (#4.3.0)";
+ case 72: return "Zconnection to mail server timed out (#4.4.1)";
+ case 73: return "Zconnection to mail server rejected (#4.4.1)";
+ case 74: return "Zcommunication with mail server failed (#4.4.2)";
+ case 91: /* fall through */
+ case 81: return "Zqq internal bug (#4.3.0)";
+ case 120: return "Zunable to exec qq (#4.3.0)";
+ default:
+ if ((exitcode >= 11) && (exitcode <= 40))
+ return "Dqq permanent problem (#5.3.0)";
+ return "Zqq temporary problem (#4.3.0)";
+ }
+}
--- /dev/null
+#ifndef QMAIL_H
+#define QMAIL_H
+
+#include "substdio.h"
+
+struct qmail {
+ int flagerr;
+ unsigned long pid;
+ int fdm;
+ int fde;
+ substdio ss;
+ char buf[1024];
+} ;
+
+extern int qmail_open();
+extern void qmail_put();
+extern void qmail_puts();
+extern void qmail_from();
+extern void qmail_to();
+extern void qmail_fail();
+extern char *qmail_close();
+extern unsigned long qmail_qp();
+
+#endif
--- /dev/null
+#ifndef READWRITE_H
+#define READWRITE_H
+
+extern int read();
+extern int write();
+
+#endif
--- /dev/null
+#ifndef SCAN_H
+#define SCAN_H
+
+extern unsigned int scan_uint();
+extern unsigned int scan_xint();
+extern unsigned int scan_nbbint();
+extern unsigned int scan_ushort();
+extern unsigned int scan_xshort();
+extern unsigned int scan_nbbshort();
+extern unsigned int scan_ulong();
+extern unsigned int scan_xlong();
+extern unsigned int scan_nbblong();
+
+extern unsigned int scan_plusminus();
+extern unsigned int scan_0x();
+
+extern unsigned int scan_whitenskip();
+extern unsigned int scan_nonwhitenskip();
+extern unsigned int scan_charsetnskip();
+extern unsigned int scan_noncharsetnskip();
+
+extern unsigned int scan_strncmp();
+extern unsigned int scan_memcmp();
+
+extern unsigned int scan_long();
+
+#endif
--- /dev/null
+#include "scan.h"
+
+unsigned int scan_ulong(s,u) register char *s; register unsigned long *u;
+{
+ register unsigned int pos; register unsigned long result;
+ register unsigned long c;
+ pos = 0; result = 0;
+ while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10)
+ { result = result * 10 + c; ++pos; }
+ *u = result; return pos;
+}
--- /dev/null
+#ifndef SEEK_H
+#define SEEK_H
+
+typedef unsigned long seek_pos;
+
+extern seek_pos seek_cur();
+
+extern int seek_set();
+extern int seek_end();
+
+extern int seek_trunc();
+
+#define seek_begin(fd) (seek_set((fd),(seek_pos) 0))
+
+#endif
--- /dev/null
+#include <sys/types.h>
+#include "seek.h"
+
+#define SET 0 /* sigh */
+
+int seek_set(fd,pos) int fd; seek_pos pos;
+{ if (lseek(fd,(off_t) pos,SET) == -1) return -1; return 0; }
--- /dev/null
+/* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer
+D. J. Bernstein, djb@pobox.com.
+Depends on subgetopt.h, substdio.h, subfd.h.
+No system requirements.
+19970208: Cleanups.
+931201: Baseline.
+No known patent problems.
+
+Documentation in sgetopt.3.
+*/
+
+#include "substdio.h"
+#include "subfd.h"
+#define SGETOPTNOSHORT
+#include "sgetopt.h"
+#define SUBGETOPTNOSHORT
+#include "subgetopt.h"
+
+#define getopt sgetoptmine
+#define optind subgetoptind
+#define opterr sgetopterr
+#define optproblem subgetoptproblem
+#define optprogname sgetoptprogname
+
+int opterr = 1;
+char *optprogname = 0;
+
+int getopt(argc,argv,opts)
+int argc;
+char **argv;
+char *opts;
+{
+ int c;
+ char *s;
+
+ if (!optprogname) {
+ optprogname = *argv;
+ if (!optprogname) optprogname = "";
+ for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1;
+ }
+ c = subgetopt(argc,argv,opts);
+ if (opterr)
+ if (c == '?') {
+ char chp[2]; chp[0] = optproblem; chp[1] = '\n';
+ substdio_puts(subfderr,optprogname);
+ if (argv[optind] && (optind < argc))
+ substdio_puts(subfderr,": illegal option -- ");
+ else
+ substdio_puts(subfderr,": option requires an argument -- ");
+ substdio_put(subfderr,chp,2);
+ substdio_flush(subfderr);
+ }
+ return c;
+}
--- /dev/null
+#ifndef SGETOPT_H
+#define SGETOPT_H
+
+#ifndef SGETOPTNOSHORT
+#define getopt sgetoptmine
+#define optarg subgetoptarg
+#define optind subgetoptind
+#define optpos subgetoptpos
+#define opterr sgetopterr
+#define optproblem subgetoptproblem
+#define optprogname sgetoptprogname
+#define opteof subgetoptdone
+#endif
+
+#include "subgetopt.h"
+
+extern int sgetoptmine();
+extern int sgetopterr;
+extern char *sgetoptprogname;
+
+#endif
--- /dev/null
+#ifndef SIG_H
+#define SIG_H
+
+extern void sig_catch();
+extern void sig_block();
+extern void sig_unblock();
+extern void sig_blocknone();
+extern void sig_pause();
+
+extern void sig_dfl();
+
+extern void sig_miscignore();
+extern void sig_bugcatch();
+
+extern void sig_pipeignore();
+extern void sig_pipedefault();
+
+extern void sig_contblock();
+extern void sig_contunblock();
+extern void sig_contcatch();
+extern void sig_contdefault();
+
+extern void sig_termblock();
+extern void sig_termunblock();
+extern void sig_termcatch();
+extern void sig_termdefault();
+
+extern void sig_alarmblock();
+extern void sig_alarmunblock();
+extern void sig_alarmcatch();
+extern void sig_alarmdefault();
+
+extern void sig_childblock();
+extern void sig_childunblock();
+extern void sig_childcatch();
+extern void sig_childdefault();
+
+extern void sig_hangupblock();
+extern void sig_hangupunblock();
+extern void sig_hangupcatch();
+extern void sig_hangupdefault();
+
+#endif
--- /dev/null
+#include <signal.h>
+#include "sig.h"
+#include "hassgact.h"
+
+void sig_catch(sig,f)
+int sig;
+void (*f)();
+{
+#ifdef HASSIGACTION
+ struct sigaction sa;
+ sa.sa_handler = f;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(sig,&sa,(struct sigaction *) 0);
+#else
+ signal(sig,f); /* won't work under System V, even nowadays---dorks */
+#endif
+}
--- /dev/null
+#include <signal.h>
+#include "sig.h"
+
+void sig_pipeignore() { sig_catch(SIGPIPE,SIG_IGN); }
+void sig_pipedefault() { sig_catch(SIGPIPE,SIG_DFL); }
--- /dev/null
+#ifndef STR_H
+#define STR_H
+
+extern unsigned int str_copy();
+extern int str_diff();
+extern int str_diffn();
+extern unsigned int str_len();
+extern unsigned int str_chr();
+extern unsigned int str_rchr();
+extern int str_start();
+
+#define str_equal(s,t) (!str_diff((s),(t)))
+
+#endif
--- /dev/null
+#include "str.h"
+
+int str_diffn(s,t,len)
+register char *s;
+register char *t;
+unsigned int len;
+{
+ register char x;
+
+ for (;;) {
+ if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ if (!len--) return 0; x = *s; if (x != *t) break; if (!x) break; ++s; ++t;
+ }
+ return ((int)(unsigned int)(unsigned char) x)
+ - ((int)(unsigned int)(unsigned char) *t);
+}
--- /dev/null
+#include "str.h"
+
+unsigned int str_len(s)
+register char *s;
+{
+ register char *t;
+
+ t = s;
+ for (;;) {
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ if (!*t) return t - s; ++t;
+ }
+}
--- /dev/null
+#ifndef STRALLOC_H
+#define STRALLOC_H
+
+#include "gen_alloc.h"
+
+GEN_ALLOC_typedef(stralloc,char,s,len,a)
+
+extern int stralloc_ready();
+extern int stralloc_readyplus();
+extern int stralloc_copy();
+extern int stralloc_cat();
+extern int stralloc_copys();
+extern int stralloc_cats();
+extern int stralloc_copyb();
+extern int stralloc_catb();
+extern int stralloc_append(); /* beware: this takes a pointer to 1 char */
+extern int stralloc_starts();
+
+#define stralloc_0(sa) stralloc_append(sa,"")
+
+#endif
--- /dev/null
+#include "byte.h"
+#include "stralloc.h"
+
+int stralloc_cat(sato,safrom)
+stralloc *sato;
+stralloc *safrom;
+{
+ return stralloc_catb(sato,safrom->s,safrom->len);
+}
--- /dev/null
+#include "stralloc.h"
+#include "byte.h"
+
+int stralloc_catb(sa,s,n)
+stralloc *sa;
+char *s;
+unsigned int n;
+{
+ if (!sa->s) return stralloc_copyb(sa,s,n);
+ if (!stralloc_readyplus(sa,n + 1)) return 0;
+ byte_copy(sa->s + sa->len,n,s);
+ sa->len += n;
+ sa->s[sa->len] = 'Z'; /* ``offensive programming'' */
+ return 1;
+}
--- /dev/null
+#include "byte.h"
+#include "str.h"
+#include "stralloc.h"
+
+int stralloc_cats(sa,s)
+stralloc *sa;
+char *s;
+{
+ return stralloc_catb(sa,s,str_len(s));
+}
--- /dev/null
+#include "byte.h"
+#include "stralloc.h"
+
+int stralloc_copy(sato,safrom)
+stralloc *sato;
+stralloc *safrom;
+{
+ return stralloc_copyb(sato,safrom->s,safrom->len);
+}
--- /dev/null
+#include "alloc.h"
+#include "stralloc.h"
+#include "gen_allocdefs.h"
+
+GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready)
+GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus)
--- /dev/null
+#include "stralloc.h"
+#include "byte.h"
+
+int stralloc_copyb(sa,s,n)
+stralloc *sa;
+char *s;
+unsigned int n;
+{
+ if (!stralloc_ready(sa,n + 1)) return 0;
+ byte_copy(sa->s,n,s);
+ sa->len = n;
+ sa->s[n] = 'Z'; /* ``offensive programming'' */
+ return 1;
+}
--- /dev/null
+#include "byte.h"
+#include "str.h"
+#include "stralloc.h"
+
+int stralloc_copys(sa,s)
+stralloc *sa;
+char *s;
+{
+ return stralloc_copyb(sa,s,str_len(s));
+}
--- /dev/null
+#include "alloc.h"
+#include "stralloc.h"
+#include "gen_allocdefs.h"
+
+GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append)
--- /dev/null
+#ifndef STRERR_H
+#define STRERR_H
+
+struct strerr
+ {
+ struct strerr *who;
+ char *x;
+ char *y;
+ char *z;
+ }
+;
+
+extern struct strerr strerr_sys;
+extern void strerr_sysinit();
+
+extern char *strerr();
+extern void strerr_warn();
+extern void strerr_die();
+
+#define STRERR(r,se,a) \
+{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; }
+
+#define STRERR_SYS(r,se,a) \
+{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; }
+#define STRERR_SYS3(r,se,a,b,c) \
+{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; }
+
+#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \
+strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se))
+#define strerr_warn5(x1,x2,x3,x4,x5,se) \
+strerr_warn((x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se))
+#define strerr_warn4(x1,x2,x3,x4,se) \
+strerr_warn((x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_warn3(x1,x2,x3,se) \
+strerr_warn((x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_warn2(x1,x2,se) \
+strerr_warn((x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_warn1(x1,se) \
+strerr_warn((x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+
+#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) (se))
+#define strerr_die5(e,x1,x2,x3,x4,x5,se) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) (se))
+#define strerr_die4(e,x1,x2,x3,x4,se) \
+strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_die3(e,x1,x2,x3,se) \
+strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_die2(e,x1,x2,se) \
+strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+#define strerr_die1(e,x1,se) \
+strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) (se))
+
+#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys)
+#define strerr_die5sys(e,x1,x2,x3,x4,x5) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,&strerr_sys)
+#define strerr_die4sys(e,x1,x2,x3,x4) \
+strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,&strerr_sys)
+#define strerr_die3sys(e,x1,x2,x3) \
+strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
+#define strerr_die2sys(e,x1,x2) \
+strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
+#define strerr_die1sys(e,x1) \
+strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,&strerr_sys)
+
+#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(struct strerr *) 0)
+#define strerr_die5x(e,x1,x2,x3,x4,x5) \
+strerr_die((e),(x1),(x2),(x3),(x4),(x5),(char *) 0,(struct strerr *) 0)
+#define strerr_die4x(e,x1,x2,x3,x4) \
+strerr_die((e),(x1),(x2),(x3),(x4),(char *) 0,(char *) 0,(struct strerr *) 0)
+#define strerr_die3x(e,x1,x2,x3) \
+strerr_die((e),(x1),(x2),(x3),(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
+#define strerr_die2x(e,x1,x2) \
+strerr_die((e),(x1),(x2),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
+#define strerr_die1x(e,x1) \
+strerr_die((e),(x1),(char *) 0,(char *) 0,(char *) 0,(char *) 0,(char *) 0,(struct strerr *) 0)
+
+#endif
--- /dev/null
+#include "substdio.h"
+#include "subfd.h"
+#include "exit.h"
+#include "strerr.h"
+
+void strerr_warn(x1,x2,x3,x4,x5,x6,se)
+char *x1; char *x2; char *x3; char *x4; char *x5; char *x6;
+struct strerr *se;
+{
+ strerr_sysinit();
+
+ if (x1) substdio_puts(subfderr,x1);
+ if (x2) substdio_puts(subfderr,x2);
+ if (x3) substdio_puts(subfderr,x3);
+ if (x4) substdio_puts(subfderr,x4);
+ if (x5) substdio_puts(subfderr,x5);
+ if (x6) substdio_puts(subfderr,x6);
+
+ while(se) {
+ if (se->x) substdio_puts(subfderr,se->x);
+ if (se->y) substdio_puts(subfderr,se->y);
+ if (se->z) substdio_puts(subfderr,se->z);
+ se = se->who;
+ }
+
+ substdio_puts(subfderr,"\n");
+ substdio_flush(subfderr);
+}
+
+void strerr_die(e,x1,x2,x3,x4,x5,x6,se)
+int e;
+char *x1; char *x2; char *x3; char *x4; char *x5; char *x6;
+struct strerr *se;
+{
+ strerr_warn(x1,x2,x3,x4,x5,x6,se);
+ _exit(e);
+}
--- /dev/null
+#include "error.h"
+#include "strerr.h"
+
+struct strerr strerr_sys;
+
+void strerr_sysinit()
+{
+ strerr_sys.who = 0;
+ strerr_sys.x = error_str(errno);
+ strerr_sys.y = "";
+ strerr_sys.z = "";
+}
--- /dev/null
+#ifndef SUBFD_H
+#define SUBFD_H
+
+#include "substdio.h"
+
+extern substdio *subfdin;
+extern substdio *subfdinsmall;
+extern substdio *subfdout;
+extern substdio *subfdoutsmall;
+extern substdio *subfderr;
+
+extern int subfd_read();
+extern int subfd_readsmall();
+
+#endif
--- /dev/null
+#include "readwrite.h"
+#include "substdio.h"
+#include "subfd.h"
+
+char subfd_errbuf[256];
+static substdio it = SUBSTDIO_FDBUF(write,2,subfd_errbuf,256);
+substdio *subfderr = ⁢
--- /dev/null
+/* subgetopt.c, subgetopt.h: (yet another) improved getopt clone, inner layer
+D. J. Bernstein, djb@pobox.com.
+No dependencies.
+No system requirements.
+19970228: Cleanups.
+931129: Adapted from getopt.c.
+No known patent problems.
+
+Documentation in subgetopt.3.
+*/
+
+#define SUBGETOPTNOSHORT
+#include "subgetopt.h"
+
+#define sgopt subgetopt
+#define optind subgetoptind
+#define optpos subgetoptpos
+#define optarg subgetoptarg
+#define optproblem subgetoptproblem
+#define optdone subgetoptdone
+
+int optind = 1;
+int optpos = 0;
+char *optarg = 0;
+int optproblem = 0;
+int optdone = SUBGETOPTDONE;
+
+int sgopt(argc,argv,opts)
+int argc;
+char **argv;
+char *opts;
+{
+ int c;
+ char *s;
+
+ optarg = 0;
+ if (!argv || (optind >= argc) || !argv[optind]) return optdone;
+ if (optpos && !argv[optind][optpos]) {
+ ++optind;
+ optpos = 0;
+ if ((optind >= argc) || !argv[optind]) return optdone;
+ }
+ if (!optpos) {
+ if (argv[optind][0] != '-') return optdone;
+ ++optpos;
+ c = argv[optind][1];
+ if ((c == '-') || (c == 0)) {
+ if (c) ++optind;
+ optpos = 0;
+ return optdone;
+ }
+ /* otherwise c is reassigned below */
+ }
+ c = argv[optind][optpos];
+ ++optpos;
+ s = opts;
+ while (*s) {
+ if (c == *s) {
+ if (s[1] == ':') {
+ optarg = argv[optind] + optpos;
+ ++optind;
+ optpos = 0;
+ if (!*optarg) {
+ optarg = argv[optind];
+ if ((optind >= argc) || !optarg) { /* argument past end */
+ optproblem = c;
+ return '?';
+ }
+ ++optind;
+ }
+ }
+ return c;
+ }
+ ++s;
+ if (*s == ':') ++s;
+ }
+ optproblem = c;
+ return '?';
+}
--- /dev/null
+#ifndef SUBGETOPT_H
+#define SUBGETOPT_H
+
+#ifndef SUBGETOPTNOSHORT
+#define sgopt subgetopt
+#define sgoptarg subgetoptarg
+#define sgoptind subgetoptind
+#define sgoptpos subgetoptpos
+#define sgoptproblem subgetoptproblem
+#define sgoptprogname subgetoptprogname
+#define sgoptdone subgetoptdone
+#endif
+
+#define SUBGETOPTDONE -1
+
+extern int subgetopt();
+extern char *subgetoptarg;
+extern int subgetoptind;
+extern int subgetoptpos;
+extern int subgetoptproblem;
+extern char *subgetoptprogname;
+extern int subgetoptdone;
+
+#endif
--- /dev/null
+#include "substdio.h"
+#include "byte.h"
+#include "error.h"
+
+static int oneread(op,fd,buf,len)
+register int (*op)();
+register int fd;
+register char *buf;
+register int len;
+{
+ register int r;
+
+ for (;;) {
+ r = op(fd,buf,len);
+ if (r == -1) if (errno == error_intr) continue;
+ return r;
+ }
+}
+
+static int getthis(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int r;
+ register int q;
+
+ r = s->p;
+ q = r - len;
+ if (q > 0) { r = len; s->p = q; } else s->p = 0;
+ byte_copy(buf,r,s->x + s->n);
+ s->n += r;
+ return r;
+}
+
+int substdio_feed(s)
+register substdio *s;
+{
+ register int r;
+ register int q;
+
+ if (s->p) return s->p;
+ q = s->n;
+ r = oneread(s->op,s->fd,s->x,q);
+ if (r <= 0) return r;
+ s->p = r;
+ q -= r;
+ s->n = q;
+ if (q > 0) /* damn, gotta shift */ byte_copyr(s->x + q,r,s->x);
+ return r;
+}
+
+int substdio_bget(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int r;
+
+ if (s->p > 0) return getthis(s,buf,len);
+ r = s->n; if (r <= len) return oneread(s->op,s->fd,buf,r);
+ r = substdio_feed(s); if (r <= 0) return r;
+ return getthis(s,buf,len);
+}
+
+int substdio_get(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int r;
+
+ if (s->p > 0) return getthis(s,buf,len);
+ if (s->n <= len) return oneread(s->op,s->fd,buf,len);
+ r = substdio_feed(s); if (r <= 0) return r;
+ return getthis(s,buf,len);
+}
+
+char *substdio_peek(s)
+register substdio *s;
+{
+ return s->x + s->n;
+}
+
+void substdio_seek(s,len)
+register substdio *s;
+register int len;
+{
+ s->n += len;
+ s->p -= len;
+}
--- /dev/null
+#include "substdio.h"
+
+void substdio_fdbuf(s,op,fd,buf,len)
+register substdio *s;
+register int (*op)();
+register int fd;
+register char *buf;
+register int len;
+{
+ s->x = buf;
+ s->fd = fd;
+ s->op = op;
+ s->p = 0;
+ s->n = len;
+}
--- /dev/null
+#ifndef SUBSTDIO_H
+#define SUBSTDIO_H
+
+typedef struct substdio {
+ char *x;
+ int p;
+ int n;
+ int fd;
+ int (*op)();
+} substdio;
+
+#define SUBSTDIO_FDBUF(op,fd,buf,len) { (buf), 0, (len), (fd), (op) }
+
+extern void substdio_fdbuf();
+
+extern int substdio_flush();
+extern int substdio_put();
+extern int substdio_bput();
+extern int substdio_putflush();
+extern int substdio_puts();
+extern int substdio_bputs();
+extern int substdio_putsflush();
+
+extern int substdio_get();
+extern int substdio_bget();
+extern int substdio_feed();
+
+extern char *substdio_peek();
+extern void substdio_seek();
+
+#define substdio_fileno(s) ((s)->fd)
+
+#define SUBSTDIO_INSIZE 8192
+#define SUBSTDIO_OUTSIZE 8192
+
+#define substdio_PEEK(s) ( (s)->x + (s)->n )
+#define substdio_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) )
+
+#define substdio_BPUTC(s,c) \
+ ( ((s)->n != (s)->p) \
+ ? ( (s)->x[(s)->p++] = (c), 0 ) \
+ : substdio_bput((s),&(c),1) \
+ )
+
+extern int substdio_copy();
+
+#endif
--- /dev/null
+#include "substdio.h"
+
+int substdio_copy(ssout,ssin)
+register substdio *ssout;
+register substdio *ssin;
+{
+ register int n;
+ register char *x;
+
+ for (;;) {
+ n = substdio_feed(ssin);
+ if (n < 0) return -2;
+ if (!n) return 0;
+ x = substdio_PEEK(ssin);
+ if (substdio_put(ssout,x,n) == -1) return -3;
+ substdio_SEEK(ssin,n);
+ }
+}
--- /dev/null
+#include "substdio.h"
+#include "str.h"
+#include "byte.h"
+#include "error.h"
+
+static int allwrite(op,fd,buf,len)
+register int (*op)();
+register int fd;
+register char *buf;
+register int len;
+{
+ register int w;
+
+ while (len) {
+ w = op(fd,buf,len);
+ if (w == -1) {
+ if (errno == error_intr) continue;
+ return -1; /* note that some data may have been written */
+ }
+ if (w == 0) ; /* luser's fault */
+ buf += w;
+ len -= w;
+ }
+ return 0;
+}
+
+int substdio_flush(s)
+register substdio *s;
+{
+ register int p;
+
+ p = s->p;
+ if (!p) return 0;
+ s->p = 0;
+ return allwrite(s->op,s->fd,s->x,p);
+}
+
+int substdio_bput(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int n;
+
+ while (len > (n = s->n - s->p)) {
+ byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n;
+ if (substdio_flush(s) == -1) return -1;
+ }
+ /* now len <= s->n - s->p */
+ byte_copy(s->x + s->p,len,buf);
+ s->p += len;
+ return 0;
+}
+
+int substdio_put(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ register int n;
+
+ n = s->n;
+ if (len > n - s->p) {
+ if (substdio_flush(s) == -1) return -1;
+ /* now s->p == 0 */
+ if (n < SUBSTDIO_OUTSIZE) n = SUBSTDIO_OUTSIZE;
+ while (len > s->n) {
+ if (n > len) n = len;
+ if (allwrite(s->op,s->fd,buf,n) == -1) return -1;
+ buf += n;
+ len -= n;
+ }
+ }
+ /* now len <= s->n - s->p */
+ byte_copy(s->x + s->p,len,buf);
+ s->p += len;
+ return 0;
+}
+
+int substdio_putflush(s,buf,len)
+register substdio *s;
+register char *buf;
+register int len;
+{
+ if (substdio_flush(s) == -1) return -1;
+ return allwrite(s->op,s->fd,buf,len);
+}
+
+int substdio_bputs(s,buf)
+register substdio *s;
+register char *buf;
+{
+ return substdio_bput(s,buf,str_len(buf));
+}
+
+int substdio_puts(s,buf)
+register substdio *s;
+register char *buf;
+{
+ return substdio_put(s,buf,str_len(buf));
+}
+
+int substdio_putsflush(s,buf)
+register substdio *s;
+register char *buf;
+{
+ return substdio_putflush(s,buf,str_len(buf));
+}
--- /dev/null
+#include "stralloc.h"
+#include "alloc.h"
+#include "str.h"
+#include "token822.h"
+#include "gen_allocdefs.h"
+
+static struct token822 comma = { TOKEN822_COMMA };
+
+void token822_reverse(ta)
+token822_alloc *ta;
+{
+ int i;
+ int n;
+ struct token822 temp;
+
+ n = ta->len - 1;
+ for (i = 0;i + i < n;++i)
+ {
+ temp = ta->t[i];
+ ta->t[i] = ta->t[n - i];
+ ta->t[n - i] = temp;
+ }
+}
+
+GEN_ALLOC_ready(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_ready)
+GEN_ALLOC_readyplus(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus)
+GEN_ALLOC_append(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus,token822_append)
+
+static int needspace(t1,t2)
+int t1;
+int t2;
+{
+ if (!t1) return 0;
+ if (t1 == TOKEN822_COLON) return 1;
+ if (t1 == TOKEN822_COMMA) return 1;
+ if (t2 == TOKEN822_LEFT) return 1;
+ switch(t1)
+ {
+ case TOKEN822_ATOM: case TOKEN822_LITERAL:
+ case TOKEN822_QUOTE: case TOKEN822_COMMENT:
+ switch(t2)
+ {
+ case TOKEN822_ATOM: case TOKEN822_LITERAL:
+ case TOKEN822_QUOTE: case TOKEN822_COMMENT:
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int atomok(ch)
+char ch;
+{
+ switch(ch)
+ {
+ case ' ': case '\t': case '\r': case '\n':
+ case '(': case '[': case '"':
+ case '<': case '>': case ';': case ':':
+ case '@': case ',': case '.':
+ return 0;
+ }
+ return 1;
+}
+
+static void atomcheck(t)
+struct token822 *t;
+{
+ int i;
+ char ch;
+ for (i = 0;i < t->slen;++i)
+ {
+ ch = t->s[i];
+ if ((ch < 32) || (ch > 126) || (ch == ')') || (ch == ']') || (ch == '\\'))
+ {
+ t->type = TOKEN822_QUOTE;
+ return;
+ }
+ }
+}
+
+int token822_unparse(sa,ta,linelen)
+stralloc *sa;
+token822_alloc *ta;
+unsigned int linelen;
+{
+ struct token822 *t;
+ int len;
+ int ch;
+ int i;
+ int j;
+ int lasttype;
+ int newtype;
+ char *s;
+ char *lineb;
+ char *linee;
+
+ len = 0;
+ lasttype = 0;
+ for (i = 0;i < ta->len;++i)
+ {
+ t = ta->t + i;
+ newtype = t->type;
+ if (needspace(lasttype,newtype))
+ ++len;
+ lasttype = newtype;
+ switch(newtype)
+ {
+ case TOKEN822_COMMA:
+ len += 3; break;
+ case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT: case TOKEN822_RIGHT:
+ case TOKEN822_SEMI: case TOKEN822_COLON:
+ ++len; break;
+ case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT:
+ if (t->type != TOKEN822_ATOM) len += 2;
+ for (j = 0;j < t->slen;++j)
+ switch(ch = t->s[j])
+ {
+ case '"': case '[': case ']': case '(': case ')':
+ case '\\': case '\r': case '\n': ++len;
+ default: ++len;
+ }
+ break;
+ }
+ }
+ len += 2;
+
+ if (!stralloc_ready(sa,len))
+ return -1;
+
+ s = sa->s;
+ lineb = s;
+ linee = 0;
+
+ lasttype = 0;
+ for (i = 0;i < ta->len;++i)
+ {
+ t = ta->t + i;
+ newtype = t->type;
+ if (needspace(lasttype,newtype))
+ *s++ = ' ';
+ lasttype = newtype;
+ switch(newtype)
+ {
+ case TOKEN822_COMMA:
+ *s++ = ',';
+#define NSUW \
+ s[0] = '\n'; s[1] = ' '; \
+ if (linee && (!linelen || (s - lineb <= linelen))) \
+ { while (linee < s) { linee[0] = linee[2]; ++linee; } linee -= 2; } \
+ else { if (linee) lineb = linee + 1; linee = s; s += 2; }
+ NSUW
+ break;
+ case TOKEN822_AT: *s++ = '@'; break;
+ case TOKEN822_DOT: *s++ = '.'; break;
+ case TOKEN822_LEFT: *s++ = '<'; break;
+ case TOKEN822_RIGHT: *s++ = '>'; break;
+ case TOKEN822_SEMI: *s++ = ';'; break;
+ case TOKEN822_COLON: *s++ = ':'; break;
+ case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT:
+ if (t->type == TOKEN822_QUOTE) *s++ = '"';
+ if (t->type == TOKEN822_LITERAL) *s++ = '[';
+ if (t->type == TOKEN822_COMMENT) *s++ = '(';
+ for (j = 0;j < t->slen;++j)
+ switch(ch = t->s[j])
+ {
+ case '"': case '[': case ']': case '(': case ')':
+ case '\\': case '\r': case '\n': *s++ = '\\';
+ default: *s++ = ch;
+ }
+ if (t->type == TOKEN822_QUOTE) *s++ = '"';
+ if (t->type == TOKEN822_LITERAL) *s++ = ']';
+ if (t->type == TOKEN822_COMMENT) *s++ = ')';
+ break;
+ }
+ }
+ NSUW
+ --s;
+ sa->len = s - sa->s;
+ return 1;
+}
+
+int token822_unquote(sa,ta)
+stralloc *sa;
+token822_alloc *ta;
+{
+ struct token822 *t;
+ int len;
+ int i;
+ int j;
+ char *s;
+
+ len = 0;
+ for (i = 0;i < ta->len;++i)
+ {
+ t = ta->t + i;
+ switch(t->type)
+ {
+ case TOKEN822_COMMA: case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT:
+ case TOKEN822_RIGHT: case TOKEN822_SEMI: case TOKEN822_COLON:
+ ++len; break;
+ case TOKEN822_LITERAL:
+ len += 2;
+ case TOKEN822_ATOM: case TOKEN822_QUOTE:
+ len += t->slen;
+ }
+ }
+
+ if (!stralloc_ready(sa,len))
+ return -1;
+
+ s = sa->s;
+
+ for (i = 0;i < ta->len;++i)
+ {
+ t = ta->t + i;
+ switch(t->type)
+ {
+ case TOKEN822_COMMA: *s++ = ','; break;
+ case TOKEN822_AT: *s++ = '@'; break;
+ case TOKEN822_DOT: *s++ = '.'; break;
+ case TOKEN822_LEFT: *s++ = '<'; break;
+ case TOKEN822_RIGHT: *s++ = '>'; break;
+ case TOKEN822_SEMI: *s++ = ';'; break;
+ case TOKEN822_COLON: *s++ = ':'; break;
+ case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
+ if (t->type == TOKEN822_LITERAL) *s++ = '[';
+ for (j = 0;j < t->slen;++j)
+ *s++ = t->s[j];
+ if (t->type == TOKEN822_LITERAL) *s++ = ']';
+ break;
+ case TOKEN822_COMMENT: break;
+ }
+ }
+ sa->len = s - sa->s;
+ return 1;
+}
+
+int token822_parse(ta,sa,buf)
+token822_alloc *ta;
+stralloc *sa;
+stralloc *buf;
+{
+ int i;
+ int salen;
+ int level;
+ struct token822 *t;
+ int numtoks;
+ int numchars;
+ char *cbuf;
+
+ salen = sa->len;
+
+ numchars = 0;
+ numtoks = 0;
+ for (i = 0;i < salen;++i)
+ switch(sa->s[i])
+ {
+ case '.': case ',': case '@': case '<': case '>': case ':': case ';':
+ ++numtoks; break;
+ case ' ': case '\t': case '\r': case '\n': break;
+ case ')': case ']': return 0;
+ /* other control chars and non-ASCII chars are also bad, in theory */
+ case '(':
+ level = 1;
+ while (level)
+ {
+ if (++i >= salen) return 0;
+ switch(sa->s[i])
+ {
+ case '(': ++level; break;
+ case ')': --level; break;
+ case '\\': if (++i >= salen) return 0;
+ default: ++numchars;
+ }
+ }
+ ++numtoks;
+ break;
+ case '"':
+ level = 1;
+ while (level)
+ {
+ if (++i >= salen) return 0;
+ switch(sa->s[i])
+ {
+ case '"': --level; break;
+ case '\\': if (++i >= salen) return 0;
+ default: ++numchars;
+ }
+ }
+ ++numtoks;
+ break;
+ case '[':
+ level = 1;
+ while (level)
+ {
+ if (++i >= salen) return 0;
+ switch(sa->s[i])
+ {
+ case ']': --level; break;
+ case '\\': if (++i >= salen) return 0;
+ default: ++numchars;
+ }
+ }
+ ++numtoks;
+ break;
+ default:
+ do
+ {
+ if (sa->s[i] == '\\') if (++i >= salen) break;
+ ++numchars;
+ if (++i >= salen)
+ break;
+ }
+ while (atomok(sa->s[i]));
+ --i;
+ ++numtoks;
+ }
+
+ if (!token822_ready(ta,numtoks))
+ return -1;
+ if (!stralloc_ready(buf,numchars))
+ return -1;
+ cbuf = buf->s;
+ ta->len = numtoks;
+
+ t = ta->t;
+ for (i = 0;i < salen;++i)
+ switch(sa->s[i])
+ {
+ case '.': t->type = TOKEN822_DOT; ++t; break;
+ case ',': t->type = TOKEN822_COMMA; ++t; break;
+ case '@': t->type = TOKEN822_AT; ++t; break;
+ case '<': t->type = TOKEN822_LEFT; ++t; break;
+ case '>': t->type = TOKEN822_RIGHT; ++t; break;
+ case ':': t->type = TOKEN822_COLON; ++t; break;
+ case ';': t->type = TOKEN822_SEMI; ++t; break;
+ case ' ': case '\t': case '\r': case '\n': break;
+ case '(':
+ t->type = TOKEN822_COMMENT; t->s = cbuf; t->slen = 0;
+ level = 1;
+ while (level)
+ {
+ ++i; /* assert: < salen */
+ switch(sa->s[i])
+ {
+ case '(': ++level; break;
+ case ')': --level; break;
+ case '\\': ++i; /* assert: < salen */
+ default: *cbuf++ = sa->s[i]; ++t->slen;
+ }
+ }
+ ++t;
+ break;
+ case '"':
+ t->type = TOKEN822_QUOTE; t->s = cbuf; t->slen = 0;
+ level = 1;
+ while (level)
+ {
+ ++i; /* assert: < salen */
+ switch(sa->s[i])
+ {
+ case '"': --level; break;
+ case '\\': ++i; /* assert: < salen */
+ default: *cbuf++ = sa->s[i]; ++t->slen;
+ }
+ }
+ ++t;
+ break;
+ case '[':
+ t->type = TOKEN822_LITERAL; t->s = cbuf; t->slen = 0;
+ level = 1;
+ while (level)
+ {
+ ++i; /* assert: < salen */
+ switch(sa->s[i])
+ {
+ case ']': --level; break;
+ case '\\': ++i; /* assert: < salen */
+ default: *cbuf++ = sa->s[i]; ++t->slen;
+ }
+ }
+ ++t;
+ break;
+ default:
+ t->type = TOKEN822_ATOM; t->s = cbuf; t->slen = 0;
+ do
+ {
+ if (sa->s[i] == '\\') if (++i >= salen) break;
+ *cbuf++ = sa->s[i]; ++t->slen;
+ if (++i >= salen)
+ break;
+ }
+ while (atomok(sa->s[i]));
+ atomcheck(t);
+ --i;
+ ++t;
+ }
+ return 1;
+}
+
+static int gotaddr(taout,taaddr,callback)
+token822_alloc *taout;
+token822_alloc *taaddr;
+int (*callback)();
+{
+ int i;
+
+ if (callback(taaddr) != 1)
+ return 0;
+
+ if (!token822_readyplus(taout,taaddr->len))
+ return 0;
+
+ for (i = 0;i < taaddr->len;++i)
+ taout->t[taout->len++] = taaddr->t[i];
+
+ taaddr->len = 0;
+ return 1;
+}
+
+int token822_addrlist(taout,taaddr,ta,callback)
+token822_alloc *taout;
+token822_alloc *taaddr;
+token822_alloc *ta;
+int (*callback)();
+{
+ struct token822 *t;
+ struct token822 *beginning;
+ int ingroup;
+ int wordok;
+
+ taout->len = 0;
+ taaddr->len = 0;
+
+ if (!token822_readyplus(taout,1)) return -1;
+ if (!token822_readyplus(taaddr,1)) return -1;
+
+ ingroup = 0;
+ wordok = 1;
+
+ beginning = ta->t + 2;
+ t = ta->t + ta->len - 1;
+
+ /* rfc 822 address lists are easy to parse from right to left */
+
+#define FLUSH if (taaddr->len) if (!gotaddr(taout,taaddr,callback)) return -1;
+#define FLUSHCOMMA if (taaddr->len) { \
+if (!gotaddr(taout,taaddr,callback)) return -1; \
+if (!token822_append(taout,&comma)) return -1; }
+#define ADDRLEFT if (!token822_append(taaddr,t--)) return -1;
+#define OUTLEFT if (!token822_append(taout,t--)) return -1;
+
+ while (t >= beginning)
+ {
+ switch(t->type)
+ {
+ case TOKEN822_SEMI:
+ FLUSHCOMMA
+ if (ingroup) return 0;
+ ingroup = 1;
+ wordok = 1;
+ break;
+ case TOKEN822_COLON:
+ FLUSH
+ if (!ingroup) return 0;
+ ingroup = 0;
+ while ((t >= beginning) && (t->type != TOKEN822_COMMA))
+ OUTLEFT
+ if (t >= beginning)
+ OUTLEFT
+ wordok = 1;
+ continue;
+ case TOKEN822_RIGHT:
+ FLUSHCOMMA
+ OUTLEFT
+ while ((t >= beginning) && (t->type != TOKEN822_LEFT))
+ ADDRLEFT
+ /* important to use address here even if it's empty: <> */
+ if (!gotaddr(taout,taaddr,callback)) return -1;
+ if (t < beginning) return 0;
+ OUTLEFT
+ while ((t >= beginning) && ((t->type == TOKEN822_COMMENT) || (t->type == TOKEN822_ATOM) || (t->type == TOKEN822_QUOTE) || (t->type == TOKEN822_AT) || (t->type == TOKEN822_DOT)))
+ OUTLEFT
+ wordok = 0;
+ continue;
+ case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
+ if (!wordok)
+ FLUSHCOMMA
+ wordok = 0;
+ ADDRLEFT
+ continue;
+ case TOKEN822_COMMENT:
+ /* comment is lexically a space; shouldn't affect wordok */
+ break;
+ case TOKEN822_COMMA:
+ FLUSH
+ wordok = 1;
+ break;
+ default:
+ wordok = 1;
+ ADDRLEFT
+ continue;
+ }
+ OUTLEFT
+ }
+ FLUSH
+ ++t;
+ while (t > ta->t)
+ if (!token822_append(taout,--t)) return -1;
+
+ token822_reverse(taout);
+ return 1;
+}
--- /dev/null
+#ifndef TOKEN822_H
+#define TOKEN822_H
+
+struct token822
+ {
+ int type;
+ char *s;
+ int slen;
+ }
+;
+
+#include "gen_alloc.h"
+GEN_ALLOC_typedef(token822_alloc,struct token822,t,len,a)
+
+extern int token822_parse();
+extern int token822_addrlist();
+extern int token822_unquote();
+extern int token822_unparse();
+extern void token822_free();
+extern void token822_reverse();
+extern int token822_ready();
+extern int token822_readyplus();
+extern int token822_append();
+
+#define TOKEN822_ATOM 1
+#define TOKEN822_QUOTE 2
+#define TOKEN822_LITERAL 3
+#define TOKEN822_COMMENT 4
+#define TOKEN822_LEFT 5
+#define TOKEN822_RIGHT 6
+#define TOKEN822_AT 7
+#define TOKEN822_COMMA 8
+#define TOKEN822_SEMI 9
+#define TOKEN822_COLON 10
+#define TOKEN822_DOT 11
+
+#endif
--- /dev/null
+void main()
+{
+#ifdef NeXT
+ printf("nextstep\n"); exit(0);
+#endif
+ printf("unknown\n"); exit(0);
+}
--- /dev/null
+#include <signal.h>
+
+void main()
+{
+ struct sigaction sa;
+ sa.sa_handler = 0;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(0,&sa,(struct sigaction *) 0);
+}
--- /dev/null
+void main()
+{
+ vfork();
+}
--- /dev/null
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void main()
+{
+ waitpid(0,0,0);
+}
--- /dev/null
+#ifndef WAIT_H
+#define WAIT_H
+
+extern int wait_pid();
+extern int wait_nohang();
+extern int wait_stop();
+extern int wait_stopnohang();
+
+#define wait_crashed(w) ((w) & 127)
+#define wait_exitcode(w) ((w) >> 8)
+#define wait_stopsig(w) ((w) >> 8)
+#define wait_stopped(w) (((w) & 127) == 127)
+
+#endif
--- /dev/null
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "error.h"
+#include "haswaitp.h"
+
+#ifdef HASWAITPID
+
+int wait_pid(wstat,pid) int *wstat; int pid;
+{
+ int r;
+
+ do
+ r = waitpid(pid,wstat,0);
+ while ((r == -1) && (errno == error_intr));
+ return r;
+}
+
+#else
+
+/* XXX untested */
+/* XXX breaks down with more than two children */
+static int oldpid = 0;
+static int oldwstat; /* defined if(oldpid) */
+
+int wait_pid(wstat,pid) int *wstat; int pid;
+{
+ int r;
+
+ if (pid == oldpid) { *wstat = oldwstat; oldpid = 0; return pid; }
+
+ do {
+ r = wait(wstat);
+ if ((r != pid) && (r != -1)) { oldwstat = *wstat; oldpid = r; continue; }
+ }
+ while ((r == -1) && (errno == error_intr));
+ return r;
+}
+
+#endif
--- /dev/null
+#!/bin/sh
+# WARNING: This file was auto-generated. Do not edit!