summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bin')
-rw-r--r--bin/Jmakefile45
-rw-r--r--bin/Makefile.SH216
-rwxr-xr-xbin/manicheck.SH82
-rw-r--r--bin/manicheck.man51
-rwxr-xr-xbin/manilist.SH484
-rw-r--r--bin/manilist.man332
-rw-r--r--bin/packinit.SH447
-rw-r--r--bin/packinit.man148
-rwxr-xr-xbin/perload646
9 files changed, 2451 insertions, 0 deletions
diff --git a/bin/Jmakefile b/bin/Jmakefile
new file mode 100644
index 0000000..d9d80d5
--- /dev/null
+++ b/bin/Jmakefile
@@ -0,0 +1,45 @@
+/*
+ * Jmakefile for bin subdirectory.
+ */
+
+;# $Id: Jmakefile,v 3.0.1.1 1994/01/24 13:42:53 ram Exp $
+;#
+;# Copyright (c) 1991-1993, Raphael Manfredi
+;#
+;# You may redistribute only under the terms of the Artistic Licence,
+;# as specified in the README file that comes with the distribution.
+;# You may reuse parts of this distribution only within the terms of
+;# that same Artistic Licence; a copy of which may be found at the root
+;# of the source tree for dist 3.0.
+;#
+;# $Log: Jmakefile,v $
+;# Revision 3.0.1.1 1994/01/24 13:42:53 ram
+;# patch16: added dependency generation stage
+;#
+;# Revision 3.0 1993/08/18 12:04:00 ram
+;# Baseline for dist 3.0 netwide release.
+;#
+
+BINPL = packinit manilist
+BIN = manicheck $(BINPL)
+
+ShellScriptTarget($(BIN))
+
+BINSH = \
+|expand f!$(BINPL)!
+ !f.SH \
+-expand \\
+
+>SED
+>RM
+>MKDEP
+
+depend::
+ ($(SED) '/^# DO NOT DELETE/q' Makefile && \
+ grep '^\$$grep' $(BINSH) | \
+ $(SED) -e "s/^.*' \([^ ]*\) >>[ ]*\([^ ]*\)/\2: \1/" \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ $(RM) Makefile.new
+
diff --git a/bin/Makefile.SH b/bin/Makefile.SH
new file mode 100644
index 0000000..49f9770
--- /dev/null
+++ b/bin/Makefile.SH
@@ -0,0 +1,216 @@
+: Makefile.SH generated from Jmake.tmpl and Jmakefile [jmake 3.0 PL44]
+: $X-Id: Jmake.tmpl,v 3.0.1.1 1993/08/20 07:36:36 ram Exp ram $
+
+case $CONFIG in
+'')
+ if test -f config.sh; then TOP=.;
+ elif test -f ../config.sh; then TOP=..;
+ elif test -f ../../config.sh; then TOP=../..;
+ elif test -f ../../../config.sh; then TOP=../../..;
+ elif test -f ../../../../config.sh; then TOP=../../../..;
+ else
+ echo "Can't find config.sh."; exit 1
+ fi
+ . $TOP/config.sh
+ ;;
+esac
+case "$0" in
+*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
+esac
+CURRENT=bin
+DIR=`echo $CURRENT/ | sed -e 's/\.\///g'`
+echo "Extracting ${DIR}Makefile (with variable substitutions)"
+
+INSTALL=`echo $install | sed -e 's,\./i,\$(TOP)/i,'`
+DATE=`date`
+
+$spitshell >Makefile <<!GROK!THIS!
+########################################################################
+# Makefile generated from Makefile.SH on $DATE
+
+SHELL = /bin/sh
+JMAKE = jmake
+TOP = ..
+CURRENT = $CURRENT
+DIR = $DIR
+INSTALL = $INSTALL
+
+########################################################################
+# Parameters set by Configure -- edit config.sh if changes are needed
+
+CTAGS = ctags
+L = $manext
+MANSRC = $installmansrc
+MAKE = make
+MKDEP = $mkdep \$(DPFLAGS) --
+MV = $mv
+RM = $rm -f
+SCRIPTDIR = $installscript
+SED = $sed
+
+########################################################################
+# Automatically generated parameters -- do not edit
+
+SCRIPTS = \$(BIN)
+
+!GROK!THIS!
+$spitshell >>Makefile <<'!NO!SUBS!'
+########################################################################
+# Jmake rules for building libraries, programs, scripts, and data files
+# $X-Id: Jmake.rules,v 3.0.1.1 1994/10/29 15:46:30 ram Exp ram $
+
+########################################################################
+# Force 'make depend' to be performed first -- do not edit
+
+.FORCE_DEPEND::
+
+all:: .FORCE_DEPEND
+
+########################################################################
+# Start of Jmakefile
+
+# $X-Id: Jmakefile,v 3.0.1.1 1994/01/24 13:42:53 ram Exp ram $
+#
+# Copyright (c) 1991-1993, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic Licence,
+# as specified in the README file that comes with the distribution.
+# You may reuse parts of this distribution only within the terms of
+# that same Artistic Licence; a copy of which may be found at the root
+# of the source tree for dist 3.0.
+#
+# $X-Log: Jmakefile,v $
+# Revision 3.0.1.1 1994/01/24 13:42:53 ram
+# patch16: added dependency generation stage
+#
+# Revision 3.0 1993/08/18 12:04:00 ram
+# Baseline for dist 3.0 netwide release.
+#
+
+BINPL = packinit manilist
+BIN = manicheck $(BINPL)
+
+all:: $(BIN)
+
+local_realclean::
+ $(RM) $(BIN)
+
+manicheck: manicheck.SH
+ /bin/sh manicheck.SH
+
+packinit: packinit.SH
+ /bin/sh packinit.SH
+
+manilist: manilist.SH
+ /bin/sh manilist.SH
+
+
+install:: $(SCRIPTS) $(LSCRIPTS)
+ @for file in $(SCRIPTS) $(LSCRIPTS); do \
+ case '${MFLAGS}' in *[i]*) set +e;; esac; \
+ (set -x; $(INSTALL) -c -m 555 $$file $(SCRIPTDIR)); \
+ done
+
+deinstall::
+ @for file in $(SCRIPTS) $(LSCRIPTS); do \
+ case '${MFLAGS}' in *[i]*) set +e;; esac; \
+ (set -x; $(RM) $(SCRIPTDIR)/$$file); \
+ done
+
+install.man::
+ @if test "$(MANSRC)"; then \
+ case '${MFLAGS}' in *[i]*) set +e;; esac; \
+ for file in $(SCRIPTS); do \
+ (set -x; \
+ $(INSTALL) -c -m 444 $$file.man $(MANSRC)/$$file.$(L)); \
+ done; \
+ else exit 0; fi
+
+deinstall.man::
+ @if test "$(MANSRC)"; then \
+ case '${MFLAGS}' in *[i]*) set +e;; esac; \
+ for file in $(SCRIPTS); do \
+ (set -x; $(RM) $(MANSRC)/$$file.$(L)); \
+ done; \
+ else exit 0; fi
+
+BINSH = \
+ packinit.SH \
+ manilist.SH
+
+depend::
+ ($(SED) '/^# DO NOT DELETE/q' Makefile && \
+ grep '^\$$grep' $(BINSH) | \
+ $(SED) -e "s/^.*' \([^ ]*\) >>[ ]*\([^ ]*\)/\2: \1/" \
+ ) > Makefile.new
+ cp Makefile Makefile.bak
+ cp Makefile.new Makefile
+ $(RM) Makefile.new
+
+########################################################################
+# Common rules for all Makefiles -- do not edit
+
+emptyrule::
+
+clean: local_clean
+realclean: local_realclean
+clobber: local_clobber
+
+local_clean::
+ $(RM) core *~ *.o
+
+local_realclean:: local_clean
+
+local_clobber:: local_realclean
+ $(RM) Makefile config.sh
+
+Makefile.SH: Jmakefile
+ -@if test -f $(TOP)/.package; then \
+ if test -f Makefile.SH; then \
+ echo " $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~"; \
+ $(RM) Makefile.SH~; $(MV) Makefile.SH Makefile.SH~; \
+ fi; \
+ echo " $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT)" ; \
+ $(JMAKE) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT) ; \
+ else touch $@; exit 0; fi
+
+Makefile: Makefile.SH
+ /bin/sh Makefile.SH
+
+tags::
+ $(CTAGS) -w *.[ch]
+ $(CTAGS) -xw *.[ch] > tags
+
+local_clobber::
+ $(RM) tags
+
+########################################################################
+# Empty rules for directories with no sub-directories -- do not edit
+
+install::
+ @echo "install in $(CURRENT) done."
+
+deinstall::
+ @echo "deinstall in $(CURRENT) done."
+
+install.man::
+ @echo "install.man in $(CURRENT) done."
+
+deinstall.man::
+ @echo "deinstall.man in $(CURRENT) done."
+
+Makefiles::
+
+Makefiles.SH::
+
+########################################################################
+# Dependencies generated by make depend
+# DO NOT DELETE THIS LINE -- make depend relies on it
+
+# Put nothing here or make depend will gobble it up
+.FORCE_DEPEND::
+ @echo "You must run 'make depend' in $(TOP) first."; exit 1
+!NO!SUBS!
+chmod 644 Makefile
+$eunicefix Makefile
+
diff --git a/bin/manicheck.SH b/bin/manicheck.SH
new file mode 100755
index 0000000..f2aa5a6
--- /dev/null
+++ b/bin/manicheck.SH
@@ -0,0 +1,82 @@
+case $CONFIG in
+'')
+ if test -f config.sh; then TOP=.;
+ elif test -f ../config.sh; then TOP=..;
+ elif test -f ../../config.sh; then TOP=../..;
+ elif test -f ../../../config.sh; then TOP=../../..;
+ elif test -f ../../../../config.sh; then TOP=../../../..;
+ else
+ echo "Can't find config.sh."; exit 1
+ fi
+ . $TOP/config.sh
+ ;;
+esac
+case "$0" in
+*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
+esac
+echo "Extracting bin/manicheck (with variable substitutions)"
+$spitshell >manicheck <<!GROK!THIS!
+$startsh
+!GROK!THIS!
+$spitshell >>manicheck <<'!NO!SUBS!'
+# $Id: manicheck.SH,v 3.0.1.1 1993/08/19 06:41:51 ram Exp $
+#
+# Copyright (c) 1991-1993, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic Licence,
+# as specified in the README file that comes with the distribution.
+# You may reuse parts of this distribution only within the terms of
+# that same Artistic Licence; a copy of which may be found at the root
+# of the source tree for dist 3.0.
+#
+# Original Author: Harlan Stenn <harlan@mumps.pfcs.com>
+#
+# $Log: manicheck.SH,v $
+# Revision 3.0.1.1 1993/08/19 06:41:51 ram
+# patch1: leading config.sh searching was not aborting properly
+#
+# Revision 3.0 1993/08/18 12:04:02 ram
+# Baseline for dist 3.0 netwide release.
+#
+
+find . ! -type d -print | sed -e '
+s|^./||
+/RCS\//d
+/UU\//d
+/core$/d
+/\.bak$/d
+/\.orig$/d
+' | sort > check.present
+
+manifest=''
+if test -r MANIFEST.new; then
+ manifest='MANIFEST.new'
+else
+ if test -r MANIFEST; then
+ manifest='MANIFEST'
+ else
+ echo "No MANIFEST.new or MANIFEST file--don't know what to look for."
+ fi
+fi
+
+awk '{print $1}' $manifest | sort > check.expected
+
+comm -23 check.expected check.present > check.want
+comm -13 check.expected check.present > check.extra
+
+rm -f check.expected check.present
+
+if test -s check.want; then
+ echo "Some files listed in $manifest are missing; see check.want."
+else
+ rm check.want
+fi
+
+if test -s check.extra; then
+ echo "Some files not listed in $manifest are present; see check.extra."
+else
+ rm check.extra
+fi
+!NO!SUBS!
+chmod 755 manicheck
+$eunicefix manicheck
diff --git a/bin/manicheck.man b/bin/manicheck.man
new file mode 100644
index 0000000..fdee36c
--- /dev/null
+++ b/bin/manicheck.man
@@ -0,0 +1,51 @@
+''' $Id: manicheck.man,v 3.0 1993/08/18 12:04:02 ram Exp $
+'''
+''' Copyright (c) 1991-1993, Raphael Manfredi
+'''
+''' You may redistribute only under the terms of the Artistic Licence,
+''' as specified in the README file that comes with the distribution.
+''' You may reuse parts of this distribution only within the terms of
+''' that same Artistic Licence; a copy of which may be found at the root
+''' of the source tree for dist 3.0.
+'''
+''' $Log: manicheck.man,v $
+''' Revision 3.0 1993/08/18 12:04:02 ram
+''' Baseline for dist 3.0 netwide release.
+'''
+'''
+.TH MANICHECK 1 ram
+.SH NAME
+manicheck \- check manifest accuracy
+.SH SYNOPSIS
+.B manicheck
+.SH DESCRIPTION
+.I Manicheck
+compares the files listed in your MANIFEST.new (or MANIFEST if that file
+is not present) with the files within your distribution. It will report
+files listed in the manifest but not present or files missing from your
+manifest file.
+.SH FILES
+.I Manicheck
+produces the following temporary files:
+.TP 20
+.PD 0
+check.expected
+lists filenames from manifest
+.TP
+check.present
+lists all potential source files
+.PD
+.PP
+If MANIFEST is not 100% accurate, the following files may be created:
+.TP 20
+.PD 0
+check.extra
+files not listed in manifest
+.TP
+check.want
+files missing from manifest
+.PD
+.SH AUTHOR
+Harlan Stenn <harlan@mumps.pfcs.com>
+.SH "SEE ALSO"
+manifake(1), makedist(1), manilist(1).
diff --git a/bin/manilist.SH b/bin/manilist.SH
new file mode 100755
index 0000000..991365a
--- /dev/null
+++ b/bin/manilist.SH
@@ -0,0 +1,484 @@
+case $CONFIG in
+'')
+ if test -f config.sh; then TOP=.;
+ elif test -f ../config.sh; then TOP=..;
+ elif test -f ../../config.sh; then TOP=../..;
+ elif test -f ../../../config.sh; then TOP=../../..;
+ elif test -f ../../../../config.sh; then TOP=../../../..;
+ else
+ echo "Can't find config.sh."; exit 1
+ fi
+ . $TOP/config.sh
+ ;;
+esac
+case "$0" in
+*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
+esac
+echo "Extracting bin/manilist (with variable substitutions)"
+$spitshell >manilist <<!GROK!THIS!
+$startperl
+ eval 'exec perl -S \$0 "\$@"'
+ if \$running_under_some_shell;
+
+# $Id: manilist.SH,v 3.0.1.3 1994/10/29 15:42:42 ram Exp $
+#
+# Copyright (c) 1991-1993, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic Licence,
+# as specified in the README file that comes with the distribution.
+# You may reuse parts of this distribution only within the terms of
+# that same Artistic Licence; a copy of which may be found at the root
+# of the source tree for dist 3.0.
+#
+# $Log: manilist.SH,v $
+# Revision 3.0.1.3 1994/10/29 15:42:42 ram
+# patch36: fixed open precedence problem for perl5
+#
+# Revision 3.0.1.2 1994/01/24 13:52:33 ram
+# patch16: added ~/.dist_profile awareness
+#
+# Revision 3.0.1.1 1993/08/19 06:41:52 ram
+# patch1: leading config.sh searching was not aborting properly
+#
+# Revision 3.0 1993/08/18 12:04:03 ram
+# Baseline for dist 3.0 netwide release.
+#
+
+\$version = '$VERSION';
+\$pl = '$PATCHLEVEL';
+!GROK!THIS!
+$spitshell >>manilist <<'!NO!SUBS!'
+
+# This script scans the MANIFEST.new file and builds some reports.
+
+# The output can be somewhat changed to produce other kind of reports.
+# The format is specified with a leading set of activation character, followed
+# by a ':', and then a set of formatting macros. The leading characters tell
+# when a report line shall be issued:
+# a: all files (shortcut for 'ix')
+# A: all files but the excluded ones
+# f: report for files only
+# d: report for directories only
+# m: report for files/directories found in the MANIFEST.new
+# n: report for files/directories not found in the MANIFEST.new
+# i: included files are listed
+# x: excluded files are listed
+# Then a set of macros introduced by %:
+# %c: the leading one character code defined as follows:
+# . if the file is up to date (i.e. not newer than patchlevel.h)
+# - if the file is present in the manifest but is missing
+# > if the file has changed since last patch.
+# + if the file is not present in the manifest but exists
+# o if the file is not listed but exists and is older than patchlevel.h
+# x if the file in manifest and exists but was excluded
+# ? if the file in manifest but was excluded and does not exist
+# %n: the name of the file (its path from the top directory)
+# %t: time stamp of last modification
+# %d: description from MANIFEST.new file, if any
+# %s: size of the file, in bytes
+
+$format = 'A:%c %n';
+
+# By default, only the source files whith the following extensions are reported
+# (but a -a option will report ALL the files, and a -i option can specify some
+# other extensions as well).
+# .sh .SH .c .h .l .y .man
+
+@include = ('.sh', '.SH', '.c', '.h', '.l', '.y', '.man');
+
+# By default, the following extensions are excluded from the list. More
+# exclusions can be added with the -x option:
+# ^core .o .bak .rej .new .old .orig ,v
+
+@exclude = ('^core', '.o', '.bak', '.rej', '.new', '.old', '.orig', ',v');
+
+# The column separator character (or string) is used to separate each formatted
+# column on the output. Formatting is requested by adding a '|' character in
+# the format string. A new separator can be specified via the -C option.
+# The maximum column size is fixed by the -L.
+
+$col_separator = ' ';
+$col_size = '';
+
+&profile; # Read ~/.dist_profile
+require 'getopts.pl';
+require 'stat.pl';
+&usage unless &Getopts('abcdhntVi:f:p:s:w:x:C:L:I:X:');
+
+&usage if $opt_h;
+if ($opt_V) {
+ print "manilist $version PL$pl\n";
+ exit 0;
+}
+
+# Go to the top of the package, and update any file name given as argument
+# by prepending the needed path. The process then performs a chdir to the
+# top.
+unless ($opt_b) {
+ chop($pwd = `pwd`) unless -f '.package';
+ until (-f '.package') {
+ die "No .package file! Run packinit.\n" unless $pwd;
+ chdir '..' || die "Can't cd ..\n";
+ $pwd =~ s|(.*)/(.*)|$1|;
+ $prefix = $2 . '/' . $prefix;
+ }
+ if ($prefix) {
+ for (@ARGV) {
+ s/^\.$/$prefix/ && next;
+ s/^/$prefix/ unless m|^[-/]|;
+ }
+ }
+}
+
+# We now are at the top level
+
+# Build up the file hierarchy filter in @filter
+foreach $entry (@ARGV) {
+ $entry =~ s|/$||; # Remove final / in directory names
+ if (-d $entry) {
+ push(@filter, "d:$entry");
+ } elsif (-f $entry) {
+ push(@filter, "f:$entry");
+ } else {
+ die "$entry: No such file or directory.\n";
+ }
+}
+
+$prefix = '.' unless $prefix;
+($top = $prefix) =~ s|/$||;
+$top = '.' if $opt_t; # Start from top, not from original dir
+@ARGV = ($top) unless @ARGV;
+
+if ($opt_n) { # "manifest" files are found by scanning the directory
+ open(MANIFEST, "find @ARGV -print|") || die "Can't run find: $!\n";
+ while (<MANIFEST>) {
+ chop;
+ s|^./||;
+ push(@manifest, $_);
+ }
+ close MANIFEST;
+} else {
+ $MANIFEST = $opt_f;
+ $MANIFEST = 'MANIFEST.new' unless $opt_f;
+ open(MANIFEST, $MANIFEST) || die "Can't open $MANIFEST: $!\n";
+ while (<MANIFEST>) {
+ chop;
+ s|^./||;
+ s|^(\S+)||;
+ local($name) = $1;
+ push(@manifest, $name);
+ m|^\s+(\d+)*\s*(.*)| && ($comment{$name} = $2);
+ }
+ close MANIFEST;
+}
+
+# If we have to compare the files in the MANIFEST with the actual files on
+# the file system, then grab them...
+if ($opt_c && !$opt_n) {
+ open(FILES, "find @ARGV -print|") || die "Can't run find: $!\n";
+ while (<FILES>) {
+ chop;
+ s|^./||;
+ push(@files, $_);
+ }
+ close FILES;
+}
+
+# If there is a patchlevel.h file, get its time stamp.
+$pl_mtime = 0;
+$pl_mtime = (stat('patchlevel.h'))[$ST_MTIME] if -f 'patchlevel.h';
+
+# Dealing with command-line options
+$format = $opt_p if $opt_p;
+$col_separator = $opt_C if $opt_C;
+$col_size = $opt_L if $opt_L;
+unless ($opt_p) { # -p may be used as a shortcut for -w and -s
+ local($which) = ($format =~ /^(\w+):/);
+ local($string) = ($format =~ /^\w+:(.*)/);
+ $which = $opt_w if $opt_w;
+ $string = $opt_s if $opt_s;
+ $format = "$which:$string";
+}
+@include = split(' ', $opt_I) if $opt_I; # First reset included with -I
+@exclude = split(' ', $opt_X) if $opt_X; # and excluded with -X
+push(@include, split(' ', $opt_i)) if $opt_i; # before applying additions
+push(@exclude, split(' ', $opt_x)) if $opt_x;
+&mode_opt; # Compute $mode_xxx variables
+&init_functions; # Compile &included and &excluded
+
+# Option -d requests dumping of inclusion and exclusion lists on stderr
+if ($opt_d) {
+ print STDERR "Included: ", join(' ', @include), "\n";
+ print STDERR "Excluded: ", join(' ', @exclude), "\n";
+}
+
+@manifest = sort @manifest;
+@files = sort @files if defined(@files);
+
+# Build up the %manifest array so that we quickly know whether a file is in the
+# manifest or not.
+foreach (@manifest) {
+ ++$manifest{$_};
+}
+
+# Now loop other the files held in @manifest and perform your job...
+foreach $mani (@manifest) {
+ if ($opt_c && !$opt_n) { # Check MANIFEST with actual files on disk
+ for (;;) {
+ $disk = $files[0]; # Next file coming up
+ last unless $disk;
+ last if $disk gt $mani; # Past the current point
+ shift(@files); # Remove the file from list
+ last if $disk eq $mani; # Reached the manifest point
+ # This means the file is before the current MANIFEST point
+ &report($disk); # File exists and not in MANIFEST
+ }
+ }
+ &report($mani);
+}
+
+&flush_report; # Flush the @Report array if formatting is needed
+
+# Print usage and exit with a non-zero status
+sub usage {
+ print STDERR <<EOH;
+Usage: manilist [-abcdhnptV] [-i ext] [-f manifest] [-p format] [-s string]
+ [-w which] [-x ext] [-C separator] [-I included] [-L colsize]
+ [-X excluded] [files]
+ -a : report for all the files, regardless of (dis)allowed extensions.
+ -b : take current directory as base top (do not look for .package).
+ -c : check files against those in manifest and report differences.
+ -d : dump include and exclude lists on stderr.
+ -f : specify an alternate MANIFEST.new file.
+ -h : print this help message.
+ -i : specify a new extension to be included in the list of scanned files.
+ -n : do not use any MANIFEST file, rather scan directories for files.
+ -p : set new printing format (default is '$format'), shortcut for -s and -w.
+ -s : set string to be printed (with escapes) for each file on report.
+ -t : start from top directory, regardless of current dir.
+ -w : give leading letter(s) for printing format (file selection on report).
+ -x : give a new extension to be excluded from the list of scanned files.
+ -C : specify column separator (replaces '|' in format string).
+ -I : override default include list (space separated).
+ -L : specify maximum column size before truncation (',' separated).
+ -V : print version number.
+ -X : override default exclude list (space separated).
+EOH
+ exit 1;
+}
+
+# Set up $mode_xxx variables, where xxx is one of the options which may be set
+# in the printing mode. For instance, $mode_i is true if and only if 'i' is
+# mentionnned in the printing mode.
+sub mode_opt {
+ local($fmt) = $format;
+ $fmt =~ s/^(\w+)://;
+ local($mode) = $1;
+ $mode .= 'ix' if $mode =~ /a/;
+ local($mode_eval) = '';
+ foreach (split(//, $mode)) {
+ $mode_eval .= "\$mode_$_ = 1;"
+ }
+ eval $mode_eval;
+ chop($@) && die "Can't set mode variables: $@.\n";
+}
+
+# Write a report about a file, either on stdout or into @Report if some
+# formatting post-processing is needed (aligned on '|' characters in the
+# report format string).
+sub report {
+ local($file) = @_;
+ return unless &report_wanted($file);
+
+ local($fmt) = $format;
+ local($postproc) = 0; # Do we need formatting post-processing ?
+ $fmt =~ s/^\w+://;
+ $fmt =~ s/\|/\02/g && ($postproc = 1); # Formatted colum separator
+
+ # If neither 'd' nor 'f' is specified, then all the files are candidate
+ # for report. Specifying 'df' is the same, but is less efficient.
+ if (($mode_d || $mode_f) && -e $file) { # File exists on disk
+ return if -f _ && !$mode_f;
+ return if -d _ && !$mode_d;
+ }
+
+ # Mode 'm' and 'n', if present, respectively ask for a report when a file
+ # is in the manifest and when a file is not in the manifest. Not specifying
+ # any of those modes is the same as specifying both of them.
+ local($in_mani) = defined $manifest{$file};
+ if ($mode_m || $mode_n) {
+ return if $in_mani && !$mode_m;
+ return if !$in_mani && !$mode_n;
+ }
+
+ # Mode 'i' and 'x' are used to control included and excluded files. By
+ # default all the files not excluded are reported. Specifying 'x' also asks
+ # for excluded files. The 'i' restricts the report to included files.
+ local($included) = $mode_i ? &included($file) : 1;
+ local($excluded) = &excluded($file);
+ if (!$included || $excluded) {
+ return if !$mode_x && $excluded;
+ return if ($mode_i && !$included) && !$excluded;
+ }
+
+ local($c_macro);
+ local($mtime) = (stat($file))[$ST_MTIME];
+ if ($in_mani) { # File in MANIFEST
+ if (-e $file) { # And file exists
+ $c_macro = '.' if $mtime <= $pl_mtime;
+ $c_macro = '>' if $mtime > $pl_mtime;
+ $c_macro = 'x' if &excluded($file);
+ } else {
+ $c_macro = '-';
+ $c_macro = '?' if &excluded($file);
+ }
+ } else { # File not in MANIFEST
+ if (-e $file) { # And file exists
+ $c_macro = $mtime < $pl_mtime ? 'o' : '+';
+ } else {
+ return if -l $file;
+ warn "$file seems to have been removed...\n";
+ }
+ }
+
+ # Perform the macro substitution
+ $fmt =~ s/%%/\0/g; # Escape %%
+ $fmt =~ s/%/\01/g; # Transform %, in case substitution add some
+ $fmt =~ s/\01c/$c_macro/g; # %c is the code
+ $fmt =~ s/\01n/$file/g; # %n is the file name
+ $fmt =~ s/\01t/&fstamp/ge; # %t is the time stamp
+ $fmt =~ s/\01s/&fsize/ge; # %s is the file size, in bytes
+ $fmt =~ s/\01d/&mdesc/ge; # %d is the manifest description
+ $fmt =~ s/\01/%/g; # All other %'s are left undisturbed
+
+ print "$fmt\n" unless $postproc;
+ push(@Report, $fmt) if $postproc;
+}
+
+# Format and flush report on stdout. Columns are aligned on what was originally
+# a '|' character in the format string, translated into a ^B by the reporting
+# routine.
+sub flush_report {
+ return unless @Report; # Early return if nothing to be done
+ local(@length); # Stores maximum length for each field
+ local(@max); # Maximum allowed column sizes
+ local($i);
+ local($report);
+ local($len);
+ local(@fields);
+ @max = split(',', $col_size);
+ foreach $report (@Report) { # First pass: compute fields lengths
+ $i = 0;
+ foreach (split(/\02/, $report)) {
+ $len = length($_);
+ $length[$i] = $length[$i] < $len ? $len : $length[$i];
+ $i++;
+ }
+ }
+ for ($i = 0; $i < @length; $i++) { # Adapt to maximum specified length
+ $length[$i] = $max[$i] if $max[$i] > 0 && $length[$i] > $max[$i];
+ }
+ foreach $report (@Report) { # Second pass: formats each line
+ @fields = split(/\02/, $report);
+ $i = 0;
+ foreach (@fields) {
+ $len = length($_);
+ if ($max[$i] > 0 && $len > $max[$i]) {
+ $_ = substr($_, 0, $max[$i]); # Truncate field
+ } else {
+ $_ .= ' ' x ($length[$i] - $len); # Pad with blanks
+ }
+ $i++;
+ }
+ print join($col_separator, @fields), "\n";
+ }
+}
+
+# The following macro subsitution functions are called with $file set
+
+# Return the modification time on file
+sub fstamp {
+ (stat($file))[$ST_MTIME];
+}
+
+# Return the file size, in bytes
+sub fsize {
+ (stat($file))[$ST_SIZE];
+}
+
+# Return the description from the MANIFEST file, if any
+sub mdesc {
+ return '' unless defined $comment{$file};
+ $comment{$file};
+}
+
+# Do we have to report informations on the specified file?
+sub report_wanted {
+ return 1 unless @filter;
+ local($file) = @_;
+ local($filter);
+ foreach (@filter) {
+ $filter = $_; # Work on a copy
+ if ($filter =~ s/^d://) {
+ return 1 if $file =~ m|^$filter(/[^/]*)*|;
+ } else {
+ $filter =~ s/^f://;
+ return 1 if $filter eq $file;
+ }
+ }
+ return 0;
+}
+
+# Build up the 'included' and 'excluded' functions which return true if a file
+# is in the include or exclude set.
+sub init_functions {
+ &build_function('included', *include, 1);
+ &build_function('excluded', *exclude, 0);
+}
+
+# Build a function which returns true if a given name is found in the array
+# list of regular expression. Each regular expression is applied on the file
+# name, anchored at the end. False is returned only if none of the expressions
+# match. The purpose of building such a function dynamically is to avoid the
+# costly pattern recompilation every time.
+sub build_function {
+ local($name) = shift(@_); # The name of the function to be built
+ local(*array) = shift(@_); # The extension array we have to check with
+ local($dflt) = shift(@_); # Default value when -a is used
+ local($fn) = &q(<<EOF); # Function being built.
+:sub $name {
+: return $dflt if \$opt_a; # All files are included, none excluded.
+: local(\$_) = \@_;
+: study;
+EOF
+ foreach (@array) {
+ $ext = $_; # Work on a copy
+ # Convert shell-style globbing into perl's RE meta-characters
+ $ext =~ s/\./\\./g; # Escape .
+ $ext =~ s/\?/./g; # ? turns into .
+ $ext =~ s/\*/.*/g; # And * turns into .*
+ $fn .= &q(<<EOL);
+: return 1 if /$ext\$/;
+EOL
+ }
+ $fn .= &q(<<EOF);
+: 0; # None of the extensions can be applied to the file
+:}
+EOF
+ eval $fn;
+ chop($@) && die "Can't compile '$name':\n$fn\n$@.\n";
+}
+
+# Remove ':' quotations in front of the lines
+sub q {
+ local($_) = @_;
+ local($*) = 1;
+ s/^://g;
+ $_;
+}
+
+!NO!SUBS!
+$grep -v '^;#' ../pl/tilde.pl >> manilist
+$grep -v '^;#' ../pl/profile.pl >> manilist
+chmod 755 manilist
+$eunicefix manilist
diff --git a/bin/manilist.man b/bin/manilist.man
new file mode 100644
index 0000000..3aaa934
--- /dev/null
+++ b/bin/manilist.man
@@ -0,0 +1,332 @@
+''' $Id: manilist.man,v 3.0.1.3 1995/05/12 11:57:31 ram Exp $
+'''
+''' Copyright (c) 1991-1993, Raphael Manfredi
+'''
+''' You may redistribute only under the terms of the Artistic Licence,
+''' as specified in the README file that comes with the distribution.
+''' You may reuse parts of this distribution only within the terms of
+''' that same Artistic Licence; a copy of which may be found at the root
+''' of the source tree for dist 3.0.
+'''
+''' $Log: manilist.man,v $
+''' Revision 3.0.1.3 1995/05/12 11:57:31 ram
+''' patch54: updated my e-mail address
+'''
+''' Revision 3.0.1.2 1994/01/24 13:52:55 ram
+''' patch16: typo fix
+'''
+''' Revision 3.0.1.1 1993/08/24 12:11:02 ram
+''' patch3: typo fix
+'''
+''' Revision 3.0 1993/08/18 12:04:04 ram
+''' Baseline for dist 3.0 netwide release.
+'''
+'''
+.TH MANILIST 1 ram
+.SH NAME
+manilist \- report status of files in a source directory
+.SH SYNOPSIS
+.B manilist
+[
+.B \-abcdhnptV
+] [
+.B \-i
+.I extension
+] [
+.B \-f
+.I manifest
+] [
+.B \-p
+.I format
+] [
+.B \-s
+.I string
+] [
+.B \-w
+.I which
+] [
+.B \-x
+.I extension
+] [
+.B \-C
+.I separator
+] [
+.B \-I
+.I included
+] [
+.B \-L
+.I colsize
+] [
+.B \-X
+.I excluded
+] [
+.I files or directories
+]
+.SH DESCRIPTION
+.I Manilist
+scans a source directory and produces a report on the status of each file:
+whether it is up-to-date or not with respect to
+.I patchlevel.h ,
+if it is missing from MANIFEST.new, and some other useful information which
+may be dynamically configured. It can be use to maintain a MANIFEST.new file,
+produce a detailed listing and status of a group of directories, etc... The
+rich set of options concur to make \fImanilist\fR a perfect low-level tool.
+.PP
+Under its simplest invocation form at the top level directory of a package,
+with no arguments, \fImanilist\fR will scan the MANIFEST.new and produce
+a report on the status of each file listed there. Each line starts with a
+single character flag which indicates the state of the file, followed by the
+name of the file.
+.PP
+What happens in fact is more complex than that. \fIManilist\fR scans the
+MANIFEST.new file and then loops over all the files listed there. Internally,
+\fImanilist\fR maintains an inclusion and an exclusion list, both specifying
+extensions for files. For instance, the inclusion list could be ('.c', '.h')
+and the exclusion ('.o', ',v') so that C sources are included and object
+or RCS files excluded. By default, all files but those excluded are used.
+Some other selections may be applied at this stage, as will be explained later
+on. For those files which pass this selection process, a report is issued
+according to a report \fIformat\fR, which by default is "\fIA:%c %n\fR".
+The letter \fIA\fR (or anything before the initial ':' character is the
+file selection specification we've been talking about. The remaining is the
+formatting, a string which is printed as-is, modulo some escape sequences.
+It so happens that \fI%c\fR is the character flag and \fI%n\fR is the name
+of the current file.
+.PP
+Generally speaking, \fImanilist\fR should be regarded as a tool which emits
+configurable reports on a set of files, selectively picking them among a list
+or by directly scanning the directories to see what's out there...
+.PP
+By specifying a set of directories or files as arguments on the command line,
+you restrict the scanning area, limiting to reports concerning those files
+or directories. If you do not specify any, manilist restricts its report to
+the current directory and its subdirectories, unless the \fB\-t\fR option is
+given.
+.SH OPTIONS
+.I Manilist
+recognizes the following options:
+.TP 15
+.B \-a
+Make a report for \fIall\fR the files, regardless of what is specified by
+the \fIincluded\fR and \fIexcluded\fR suffix lists.
+.TP
+.B \-b
+Assume current directory is the base (root) of the package tree. When this
+option is not specified, \fImanilist\fR will look for a \fI.package\fR file
+to indicate the root directory of the package (also called the top) and
+complain if it does not find it.
+.TP
+.B \-c
+Check files against those listed in MANIFEST.new (or whatever file specified
+via the \fB\-f\fR option) and report discrepancies via the \fI%c\fR macro.
+.TP
+.B \-d
+Dump included and excluded suffix lists on stderr, extensions being space
+separated. A good way to know the default lists is to run: \fImanilist
+\-f /dev/null \-bd.
+.TP
+.B \-f\fI manifest
+Specify an alternate manifest file, the default being to use MANIFEST.new.
+.TP
+.B \-h
+Print the usage help message and exit.
+.TP
+.B \-i\fI extensions
+Add new extensions to the included suffix list. The \fIextensions\fR argument
+must list the suffixes separated by spaces, as in \fB\-i\fI '.ph .pl'\fR to add
+both \fI.ph\fR and \fI.pl\fR to the existing suffixes. Note that the argument
+needs to be quoted to protect spaces against shell interpretation.
+.TP
+.B \-n
+Do not use any manifest file. Rather scan the directories and act as with all
+the files there were already listed in a manifest.
+.TP
+.B \-p\fI format
+Set the new printing format, which has the form \fIselection\fR:\fIstring\fR,
+with \fIselection\fR being a list of single letters specifying which files
+from the manifest are to be used for reports, and \fIstring\fR being a
+message to print as report, with some macro substitutions. It is also possible
+to have column formatting by specifying a '|' inside the string to delimit
+the different columns you wish to see. See also \fB\-C\fR and \fB\-L\fR for
+more formatting parameters.
+.TP
+.B \-s\fI string
+Specify the \fIstring\fR part of the printing format (see \fB\-p\fR for a
+general description of the \fIformat\fR). Available macros are listed further
+down the manual page.
+.TP
+.B \-t
+Start from the top directory (the root directory of the distribution) regardless
+of the current directory. There must be a \fI.package\fR file to indicate
+what the top directory is.
+.TP
+.B \-w\fI selection
+Specifiy the \fIselection\fR part of the printing format. Available selections
+will be discussed later.
+.TP
+.B \-x\fI extensions
+Add new extensions to the excluded suffix list. The \fIextensions\fR argument
+must list the suffixes separated by spaces, as in \fB\-x\fI '.s .p'\fR to add
+both \fI.s\fR and \fI.p\fR to the existing list. Note that the argument
+needs to be quoted to protect spaces against shell interpretation.
+.TP
+.B \-C\fI separator
+Give the column separator, which is to be used in place of the '|' character
+in the report format string. By default, it is a single space.
+.TP
+.B \-I\fI included
+Specify a new list of suffixes to be included in the reports. This overrides
+the original default list (whereas \fB\-i\fR is used to \fIadd\fR suffixes to
+the list). Suffixes must be space separated.
+.TP
+.B \-L\fI colsize
+When using column formatting (the '|' character being used to denote columns),
+this option may be used to specify the maximum column width, separating each
+width by a single ','. Leaving a width unspecified does not impose any limit
+on its width. For instance, if the format string is \fI%n|%d|%t\fR, one could
+limit the middle column (descriptions from MANIFEST.new) to 40 characters and
+the name column (first one) to 15 characters, leaving the last one with no
+imposed limits, by using \fB\-L\fI 15,40,\fR.
+.TP
+.B \-V
+Print version number and exit.
+.TP
+.B \-X\fI excluded
+Specify a new list of suffixes to be excluded in the reports. This overrides
+the original default list (whereas \fB\-x\fR is used to \fIadd\fR suffixes to
+the list). Suffixes must be space separated.
+.SH USING FORMATS
+The flexibility of \fImanilist\fR is brought by its use of a dynamic formatting
+string for providing its reports. It is possible to specify a format via the
+\fB\-p\fR option or just parts of it: the text string via \fB\-s\fR and the
+file selection with \fB\-w\fR.
+.SS "File Selection"
+.PP
+The leading part of the formatting string tells \fImanilist\fR which files you
+wish to see in the final report. Available selectors are:
+.sp
+.PD 0
+.TP 5
+.B A
+All the files but the excluded ones (i.e. those files whose suffix is listed
+in the exclusion list). This is the default action.
+.TP
+.B a
+All the files included and/or excluded (shortcut for \fIix\fR). Note that files
+which are neither included nor excluded will not appear in the report.
+.TP
+.B d
+Report only for directories.
+.TP
+.B f
+Report only for files.
+.TP
+.B i
+Only included files are listed.
+.TP
+.B m
+Only those files or directories found in the manifest are listed.
+.TP
+.B n
+Only those files or directories \fInot\fR found in the manifest are listed.
+.TP
+.B x
+Only excluded files are listed.
+.PD
+.PP
+When you specify more than one letter, the resulting report depends on the
+nature of the selection. For \fId\fR, \fIf\fR, \fIm\fR and \fIn\fR, a logical
+union is performed. This means specifying \fIfd\fR or \fImn\fR is the same
+as not specifying anything, but it's less efficient since \fImanilist\fR is
+forced to perform the checks it would otherwise bypass. The \fIi\fR and \fIx\fR
+selectors are special: by default, all the files not excluded are reported.
+Specifying \fIx\fR also asks for excluded files. Specifying \fIi\fR restricts
+the report to the included files. Using both at the same time (\fIix\fR) will
+force a report for files which are included or excluded.
+.SS "Macro Substitution"
+.PP
+The string part of the report format can make use of the following macros:
+.sp
+.PD 0
+.TP 5
+%c
+A character coding the status of the file.
+.TP
+%d
+Description from the manifest file, if any.
+.TP
+%n
+Name of the file (its path from the top directory).
+.TP
+%s
+Size of the file, in bytes.
+.TP
+%t
+Time stamp of the last modification.
+.PD
+.SS "File Status"
+.PP
+The \fI%c\fR macro, giving a single character coding the file status, can
+expand into one of the following.
+.PD 0
+.TP 5
+\&.
+The file is up to date (not newer than \fIpatchlevel.h\fR).
+.TP
+-
+The file is present in the manifest but is missing.
+.TP
+>
+The file has been modified since last patch (newer than \fIpatchlevel.h\fR).
+.TP
++
+The file exists but is not listed in the manifest.
+.TP
+o
+The file exists but is not listed in the manifest and is older than
+\fIpatchlevel.h\fR
+.TP
+x
+The file is listed in the manifest and exists, but has been excluded. Naturally,
+this will appear in the report only if the \fIx\fR selector is given in the
+report format.
+.TP
+?
+The file is listed in the manifest, does not exist, and was excluded.
+.PD
+.SH EXAMPLES
+The command
+.in +5
+.nf
+.sp
+\fImanilist -ct -p 'ni:%n'\fR
+.sp
+.fi
+.in -5
+will list all the source files from your distribution which are not listed
+in your MANIFEST.new file. Note that this includes only "source" files, that
+is to say files whose extension is listed in the inclusion list.
+If you do not wish this restriction, replace the formatting string with
+\fIn:%n\fR (only the excluded files will not appear).
+.PP
+To build an initial MANIFEST file, use:
+.in +5
+.nf
+.sp
+\fImanilist -n -p 'Af:%n' > MANIFEST\fR
+.sp
+.fi
+.in -5
+from the top directory. You will eventually want to fill in descriptions for
+each file listed in the manifest.
+.SH FILES
+.PD 0
+.TP 20
+MANIFEST.new
+Default manifest file, listing files and giving a small description for each
+of them.
+.PD
+.SH AUTHOR
+Raphael Manfredi <ram@hptnos02.grenoble.hp.com>
+.SH "SEE ALSO"
+manifake(1), makedist(1), pat(1).
diff --git a/bin/packinit.SH b/bin/packinit.SH
new file mode 100644
index 0000000..55dee75
--- /dev/null
+++ b/bin/packinit.SH
@@ -0,0 +1,447 @@
+case $CONFIG in
+'')
+ if test -f config.sh; then TOP=.;
+ elif test -f ../config.sh; then TOP=..;
+ elif test -f ../../config.sh; then TOP=../..;
+ elif test -f ../../../config.sh; then TOP=../../..;
+ elif test -f ../../../../config.sh; then TOP=../../../..;
+ else
+ echo "Can't find config.sh."; exit 1
+ fi
+ . $TOP/config.sh
+ ;;
+esac
+case "$0" in
+*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
+esac
+echo "Extracting bin/packinit (with variable substitutions)"
+cat >packinit <<!GROK!THIS!
+# feed this into perl
+ eval "exec perl -S \$0 \$*"
+ if \$running_under_some_shell;
+
+# $Id: packinit.SH,v 3.0.1.4 1997/02/28 14:55:14 ram Exp $
+#
+# Copyright (c) 1991-1993, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic Licence,
+# as specified in the README file that comes with the distribution.
+# You may reuse parts of this distribution only within the terms of
+# that same Artistic Licence; a copy of which may be found at the root
+# of the source tree for dist 3.0.
+#
+# $Log: packinit.SH,v $
+# Revision 3.0.1.4 1997/02/28 14:55:14 ram
+# patch61: fixed one wrong ':' comment in .package
+#
+# Revision 3.0.1.3 1994/10/29 15:43:49 ram
+# patch36: added support for user-defined C and shell file extensions
+# patch36: now asks whether a ChangeLog file is to be managed
+#
+# Revision 3.0.1.2 1994/01/24 13:54:07 ram
+# patch16: can now configure mailing list knowledge from packinit
+#
+# Revision 3.0.1.1 1993/08/19 06:41:53 ram
+# patch1: leading config.sh searching was not aborting properly
+#
+# Revision 3.0 1993/08/18 12:04:05 ram
+# Baseline for dist 3.0 netwide release.
+#
+
+\$orgname='$orgname';
+\$myhostname='$myhostname';
+\$mydomain='$mydomain';
+\$nametype='$nametype';
+!GROK!THIS!
+cat >>packinit <<'!NO!SUBS!'
+
+print <<EOM;
+
+This program designates the current directory as the top level directory
+of a package on which you want to use the programs metaconfig, makedist,
+or the patch generation programs. It will not damage the current directory
+in any way except to create a .package file.
+
+EOM
+
+$mypackver = 3.036; # Base revision number plus patchlevel
+
+if (-f '.package') {
+ &readpackage;
+ if ($packver > $mypackver) {
+ die "This .package file was produced by a newer packinit than I am.\n".
+ "Please find a packinit of version $packver or greater.\n";
+ }
+} elsif (-f '../.package' || -f '../../.package' || -f '../../../.package') {
+ die "Run in top level directory only.\n";
+}
+
+# Now set up to do reads with possible shell escape.
+sub myread {
+ ($rp,$dflt) = @_;
+ $rp .= " [$dflt]";
+ print "$rp ";
+ $ans='!';
+ while ($ans =~ /^!/) {
+ $ans = <STDIN>;
+ chop($ans);
+ if ($ans eq '!') {
+ system '/bin/sh';
+ print "\n$rp ";
+ } elsif ($ans =~ s/^!//) {
+ system '/bin/sh', '-c', $ans;
+ print "\n$rp ";
+ }
+ }
+ $ans = $dflt if $ans eq '';
+ $ans = '' if $ans eq 'none';
+ $ans;
+}
+
+$dflt = $package;
+($dflt) = (`pwd | tr "[A-Z]" "[a-z]"` =~ m|.*/(.*)|) unless $package;
+
+print <<EOM;
+Your package will be known by some name, which should be a single word.
+Generally it is the name of the chief executable program.
+
+EOM
+$package = &myread('What is the name of your package?',$dflt);
+
+if ($baserev ne '') {
+ $dflt=$baserev;
+} else {
+ print "\n";
+ $dflt='';
+ print "Checking RCS files for current version...";
+ @rcs = <RCS/*,v *,v>;
+ $rcs = shift(@rcs);
+ if (! -f $rcs) {
+ $rcs = shift(@rcs);
+ if (! -f $1) {
+ print "I don't see any RCS files there (yet).";
+ $dflt='1.1';
+ }
+ }
+ $revs=0;
+ if ($dflt eq '') {
+ $rlog = `rlog $rcs`;
+ ($dflt) = ($rlog =~ /\nhead:\s*(\d+\.\d+)/);
+ $rlog = `rlog -r$dflt.1- -r$dflt.2- -r$dflt.3- -r$dflt.4- $rcs`;
+ ($revs) = ($rlog =~ /selected revisions:\s*([\d.]+)/);
+ $dflt='1.1' if $dflt eq '';
+ }
+
+ print <<EOM;
+
+To use the patch generating portion of the system, you must have RCS. You
+must begin with a freshly checked-in trunk revision (n.n) and choose a branch
+number for patches. The trunk revision upon which the patch branch is based
+is called the base revision.
+
+EOM
+
+ if ($revs > 1) {
+ print <<EOM;
+(The current revision ($dflt) has branches--you may have to check in a new
+trunk revision, or use patbase to mark the base revisions.)
+EOM
+ ($first,$second) = split(/\./,$dflt);
+ ++$second;
+ $dflt="$first.$second";
+ }
+}
+
+print "\n";
+$foo = &myread('What is or will be the base revision number?', $dflt);
+if ($baserev ne $foo) {
+ $baserev = $foo;
+ $ftpdir = ''; # invalidate ftp directory on version change
+}
+
+print "\n";
+$dflt = ($patchbranch ne '' ? $patchbranch : 1);
+$patchbranch =
+ &myread('What branch number do you want to use for patches?', $dflt);
+
+$dflt = $cext eq '' ? 'none' : $cext;
+print <<EOM;
+
+Metaconfig will lookup for files listed in MANIFEST.new to scan for
+known symbols. If you have non-standard extensions containing some
+C symbols, you may wish to list them there, separating them with white
+spaces and using shell regular expressions, such as '.xs .p .t' to let
+metaconfig know about them. Say "none" for none.
+
+EOM
+$cext = &myread('Additional file extensions to identify C files?', $dflt);
+$cext = '' if $cext eq 'none';
+
+$dflt = $shext eq '' ? 'none' : $shext;
+print <<EOM;
+
+Likewise, metaconfig needs to know about the files containing at least
+some shell symbols. Automatic symbol substitution will be performed on
+the .SH files only, but you may want metaconfig to scan other files as
+well, provided you ensure proper variable substitutions by your own
+means. Please add extensions using shell-style regexps. Say "none" if
+no specific file extensions are used.
+
+EOM
+$shext = &myread('Additional file extensions to identify SH files?', $dflt);
+$shext = '' if $shext eq 'none';
+
+$dflt = $copyright eq ' ' ? 'n' : 'y';
+print <<'EOM';
+
+If you wish, you may use a generic copyright. This is appropriate if all
+your source file have to be distributed under the same conditions. Using
+this facility means you will not be able to change the copyright notice
+between patches (i.e. while in the same version number). All you need to
+do is write a copyright file containing the proper copyright notice, and
+then use @COPYRIGHT@ within your source code (before any RCS marker). That
+will be extended to the full copyright, preserving any leading comment.
+
+EOM
+$use_copyright = &myread('Do you wish to use a generic copyright?', $dflt);
+if ($use_copyright =~ /^y/i) {
+ print "\n";
+ $copyright = '' if $copyright eq ' '; # They changed their mind!
+ $dflt = $copyright || 'COPYRIGHT';
+ $copyright = &myread('What file do you wish to store it in?', $dflt);
+} else {
+ $copyright = ' '; # Remember they don't want it
+}
+
+if ($use_copyright =~ /^y/i) {
+ $ans = 'yes'; # Yes, use our own diff (have to expand copyright)
+} else {
+ print "\n";
+ $dflt = ($mydiff eq '' ? 'n' : 'y');
+ $ans = &myread(
+ 'Do you want to use your own diff (rather than rcsdiff -c) for patches?',
+ $dflt);
+}
+if ($ans =~ /^n/i) {
+ $mydiff='';
+} else {
+ print "\n";
+ $dflt = $mydiff || 'diff -c';
+ $mydiff = &myread('What diff command do you want to use?', $dflt);
+}
+
+$dflt = $changelog eq ' ' ? 'n' : 'y';
+print <<'EOM';
+
+I can set up things so that a ChangeLog file is maintained automatically.
+This file will contain the description which is filled in into every issued
+patches, and optionally, the list of RCS logs for each modified file. The
+ChangeLog file is sorted in reverse order of issued patches, i.e. the most
+recent changes are at the top of the file.
+
+EOM
+$use_changelog = &myread('Do you wish me to maintain a ChangeLog file?', $dflt);
+if ($use_changelog =~ /^y/i) {
+ print "\n";
+ $changelog = '' if $changelog eq ' '; # They changed their mind!
+ $dflt = $changelog || 'ChangeLog';
+ $changelog = &myread('What file do you wish to store changes in?', $dflt);
+ $dflt = $changercs ? 'y' : 'n';
+ print "\n";
+ $ans = &myread('Do you wish to include RCS logs as well?', $dflt);
+ $changercs = $ans =~ /^y/i;
+} else {
+ $changelog = ' '; # Remember they don't want it
+ $changercs = 0;
+}
+
+print <<EOM;
+
+Over the lifetime of the $package package, people will want to request
+distribution kits and patches. In particular, automatically generated
+patches will say where to get previous patches from.
+
+EOM
+$logname = &getlogname;
+$dflt = $maintname || &getfullname($logname);
+$maintname = &myread('Who should requests be sent to (full name)?', $dflt);
+
+print <<EOM;
+
+Now you need to give a one-line network mailing address for $maintname.
+It does not need to be parseable by machine, but can be of the form:
+
+ {name1,name2,name3}!myhost!myname
+
+ or
+
+ myname\@myhost.domain
+
+EOM
+$dflt = $maintloc || "$logname\@$myhostname$mydomain";
+$maintloc = &myread('What is the network mailing address?', $dflt);
+
+print "\n";
+$dflt = $ftpsite ? 'y' : 'n';
+$ans = &myread(
+ 'Will you put patches where they can be acquired by anonymous FTP?',$dflt);
+if ($ans =~ /^n/i) {
+ $ftpsite='';
+} else {
+ print "\n";
+ $dflt = $ftpsite;
+ ($dflt = $maintloc) =~ s/.*@([^\s,()]*).*/$1/ unless $dflt;
+ $ftpsite = &myread('What is the Internet sitename for that?',$dflt);
+}
+
+print <<EOM;
+
+If you have mailagent installed (posted in comp.sources.misc), you may choose
+to distribute patches via e-mail and have all the issued patches mention
+this, as well as instructions telling how to get those (missing) patches.
+
+EOM
+$dflt = $mailagent eq 'true' ? 'y' : 'n';
+$mailagent = &myread(
+ 'Do you wish to let people retrieve patches via mailagent?', $dflt);
+$mailagent = ($mailagent =~ /^y/i) ? 'true' : 'false';
+
+print "\n";
+$dflt = $list_users eq 'true' ? 'y' : 'n';
+$list_users = &myread(
+ "Do you have a mailing list set up for $package users?", $dflt);
+$list_users = ($list_users =~ /^y/i) ? 'true' : 'false';
+
+if ($list_users eq 'true') {
+ print "\n";
+ $dflt = $list_name || "$package-users";
+ $list_name = &myread('How is the mailing list named?', $dflt);
+
+ print <<EOM;
+
+The $list_name mailing list is now to be defined in terms of e-mail
+addresses where users can send messages to the whole list (that's the
+mailing list address) or send administrative requests to subscribe or
+unsubscribe among other things (that's the administrative mailing
+address). Usually, this last address will turn out to be that of a
+mailing list manager program like majordomo or listserv.
+
+EOM
+ $dflt = $list_addr || "$list_name\@$myhostname$mydomain";
+ $list_addr = &myread('What is Internet mailing list address?', $dflt);
+
+ print "\n";
+ ($list_domain) = $list_addr =~ /^[\w-]+\@(.*)/;
+ $list_domain = "$myhostname$mydomain" unless $list_domain;
+ $dflt = $list_request || "$list_name-request\@$list_domain";
+ $list_request = &myread('What is administrative mailing address?', $dflt);
+
+ %mlm = (
+ 'majordomo',
+ "subscribe $list_name \$cf_email;unsubscribe $list_name \$cf_email",
+ 'listserv',
+ "SUBSCRIBE $package \$cf_name;UNSUBSCRIBE $package",
+ 'human',
+ "subscribe $list_name \$cf_email;unsubscribe $list_name \$cf_email",
+ );
+
+ print "\n";
+ ($dflt) = $list_request =~ /^([\w-]+)\@/;
+ $dflt =~ tr/A-Z/a-z/;
+ $list_cmds = $mlm{$dflt};
+ $dflt = 'human' if $list_cmds eq '';
+ $old_list_manager = $list_manager;
+ $list_manager = &myread(
+ 'What type of mailing list manager are you using?', $dflt);
+ $list_manager =~ tr/A-Z/a-z/;
+ $list_sub = $list_unsub = '' if $old_list_manager ne $list_manager;
+
+ $list_cmds = $mlm{$list_manager};
+ $list_cmds = $mlm{'human'} if $list_cmds eq '';
+ @list_cmds = split(/;/, $list_cmds);
+
+ print <<'EOM';
+
+In the next two questions, you may use the following variables in your
+answers:
+
+ $cf_email e-mail address of the user
+ $cf_name full name of the user
+
+Those variables will be set by Configure prior sending the requests to
+the administrative mailing list address.
+
+EOM
+ $dflt = $list_sub || $list_cmds[0];
+ $list_sub = &myread('Subscribe command?', $dflt);
+ print "\n";
+ $dflt = $list_unsub || $list_cmds[1];
+ $list_unsub = &myread('Unsubscribe command?', $dflt);
+}
+
+print "\n";
+$dflt = $orgname || $ENV{'ORGANIZATION'};
+$orgname = &myread('Organization:',$dflt);
+$orgname = &tilda_expand($orgname); # Can specify filename with ~user
+
+print "\n";
+$dflt = $newsgroups || 'comp.sources.bugs';
+$newsgroups = &myread('Newsgroup(s) to post patches to:', $dflt);
+
+print "\n";
+$dflt = $recipients || 'source-archives@mirror.TMC.COM';
+$recipients = &myread('Recipient(s) to send patches to:',$dflt);
+
+if ($ftpsite) {
+ print "\n";
+ $dflt = $ftpdir || "/usr/spool/ftp/pub/$package.$baserev/patches";
+ $ftpdir = &myread('FTP directory to copy patches to:',$dflt);
+} else {
+ $ftpdir = '';
+}
+
+print "\nCreating .package...\n";
+open(PACKAGE, '>.package') || die "Can't create .package";
+chop($date = `date`);
+print PACKAGE <<EOF;
+: This file was created by running packinit on $date.
+: Do not hand edit -- run packinit again if changes are to be made.
+packver='$mypackver'
+: Basic variables
+package=$package
+baserev=$baserev
+patchbranch=$patchbranch
+copyright='$copyright'
+mydiff='$mydiff'
+maintname='$maintname'
+maintloc='$maintloc'
+ftpsite='$ftpsite'
+orgname='$orgname'
+newsgroups='$newsgroups'
+recipients='$recipients'
+ftpdir='$ftpdir'
+mailagent='$mailagent'
+changelog='$changelog'
+changercs=$changercs
+: File lookup extensions
+cext='$cext'
+shext='$shext'
+: Mailing list variables
+list_users='$list_users'
+list_name='$list_name'
+list_addr='$list_addr'
+list_request='$list_request'
+list_manager='$list_manager'
+list_sub='$list_sub'
+list_unsub='$list_unsub'
+: Derivative variables -- do not change
+revbranch=\"\$baserev.\$patchbranch\"
+EOF
+
+!NO!SUBS!
+$grep -v '^;#' ../pl/package.pl >>packinit
+$grep -v '^;#' ../pl/logname.pl >>packinit
+$grep -v '^;#' ../pl/fullname.pl >>packinit
+$grep -v '^;#' ../pl/tilde.pl >>packinit
+chmod 755 packinit
+$eunicefix packinit
diff --git a/bin/packinit.man b/bin/packinit.man
new file mode 100644
index 0000000..002b25e
--- /dev/null
+++ b/bin/packinit.man
@@ -0,0 +1,148 @@
+''' $Id: packinit.man,v 3.0.1.4 1995/07/25 13:31:38 ram Exp $
+'''
+''' Copyright (c) 1991-1993, Raphael Manfredi
+'''
+''' You may redistribute only under the terms of the Artistic Licence,
+''' as specified in the README file that comes with the distribution.
+''' You may reuse parts of this distribution only within the terms of
+''' that same Artistic Licence; a copy of which may be found at the root
+''' of the source tree for dist 3.0.
+'''
+''' $Log: packinit.man,v $
+''' Revision 3.0.1.4 1995/07/25 13:31:38 ram
+''' patch56: fixed a typo
+'''
+''' Revision 3.0.1.3 1995/05/12 11:57:38 ram
+''' patch54: updated my e-mail address
+'''
+''' Revision 3.0.1.2 1994/10/29 15:45:17 ram
+''' patch36: added new variables cext, shext, changelog and changercs
+'''
+''' Revision 3.0.1.1 1994/01/24 13:54:31 ram
+''' patch16: now documents variables set in .package by packinit
+'''
+''' Revision 3.0 1993/08/18 12:04:06 ram
+''' Baseline for dist 3.0 netwide release.
+'''
+'''
+.TH PACKINIT 1 ram
+.SH NAME
+packinit \- initialize or update your .package file
+.SH SYNOPSIS
+.B packinit
+.SH DESCRIPTION
+.B Packinit
+will create (or update) a \fI.package\fR file, so that all the
+.B dist
+tools can be smart and know some basic things about your package,
+such as its revision number, or the e-mail address of its maintainer.
+.PP
+.I Packinit
+should be run from the top level directory of your package, before
+using any other \fIdist\fR tool. Later on, you may rerun it to
+update some of its values.
+.I Packinit
+will create a single file and leave the remaining of
+your directory undisturbed.
+.SH VARIABLES
+.I Packinit
+defines the following variables in your \fI.package\fR file:
+.TP 15
+.PD 0
+baserev
+The baseline revision number.
+.TP
+cext
+The list (space separated) of file extensions identifying potential holders of
+C symbols. This is added to the default .[chyl] extension lookup.
+Shell-style patterns may be used.
+.TP
+changelog
+The name of the \fIChangeLog\fR file managed by \fIpatlog\fR.
+.TP
+changercs
+Boolean stating whether RCS logs are to be made part of \fIChangeLog\fR.
+.TP
+copyright
+Name of the file used for Copyright expansion.
+.TP
+ftpdir
+Directory where patches are located on the FTP site.
+.TP
+ftpsite
+Name of the FTP site where patches may be retrieved from.
+.TP
+list_addr
+Address of the package mailing list where users may post messages to.
+.TP
+list_manager
+Type of list manager attached to the list administrative request address.
+.TP
+list_name
+Name of the package users mailing list.
+.TP
+list_request
+Address where subscribe and unsubscribe requests for the package mailing
+list should be sent to.
+.TP
+list_sub
+Format of the subscribe requests.
+.TP
+list_unsub
+Format of the unsubscribe requests.
+.TP
+list_users
+A boolean string set to 'true' when there is a mailing list set up for
+discussion about the package.
+.TP
+mailagent
+A boolean string set to 'true' when people are allowed to retrieve
+patches via mailagent \fI@SH mailpatch\fR commands.
+.TP
+maintloc
+E-mail address of the package maintainer, preferably in Internet format.
+.TP
+maintname
+Full name of the package maintainer.
+.TP
+mydiff
+Name of the \fIdiff\fR program to be used when computing a patch.
+.TP
+newsgroups
+Newsgroup list where new patches should be posted to, empty for no
+postings.
+.TP
+orgname
+Full name of the organization where the package maitainer resides, or
+path to a file containing that name.
+.TP
+package
+Name of the package.
+.TP
+packver
+Version of the \fIpackinit\fR program that built the \fI.package\fR file.
+.TP
+patchbranch
+Name of the RCS branch used to store subsequent updates of a file after
+a baseline has been released.
+.TP
+recipients
+People who should be sent newly issued patches.
+.TP
+shext
+The list (space separated) of file extensions identifying potential holders of
+shell symbols. This is added to the default .SH extension lookup.
+Shell-style patterns may be used. Note that only .SH extensions are looked
+up by Configure for automatic shell extraction with variable substitutions,
+no matter what this variable is set to.
+.PD
+.SH FILE
+.TP 15
+\&.package
+File holding all the package-related values
+.SH AUTHORS
+Larry Wall <lwall@netlabs.com> (version 2.0)
+.br
+Raphael Manfredi <ram@hptnos02.grenoble.hp.com>
+.SH "SEE ALSO"
+dist(1).
diff --git a/bin/perload b/bin/perload
new file mode 100755
index 0000000..6b426fa
--- /dev/null
+++ b/bin/perload
@@ -0,0 +1,646 @@
+: # feed this into perl
+'/bin/true' && eval 'exec perl -S $0 "$@"'
+ if $running_under_some_shell;
+'di';
+'ig00';
+
+#
+# This perl script is its own manual page [generated by wrapman]
+#
+
+# $Id: perload,v 3.0.1.1 1994/10/29 15:45:36 ram Exp $
+#
+# Copyright (c) 1991-1993, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic Licence,
+# as specified in the README file that comes with the distribution.
+# You may reuse parts of this distribution only within the terms of
+# that same Artistic Licence; a copy of which may be found at the root
+# of the source tree for dist 3.0.
+#
+# $Log: perload,v $
+# Revision 3.0.1.1 1994/10/29 15:45:36 ram
+# patch36: added minimal support for perl5 dataloading
+#
+# Revision 3.0 1993/08/18 12:04:06 ram
+# Baseline for dist 3.0 netwide release.
+#
+
+# Replace each function definition in a loading section by two stubs and
+# reject the definition into the DATA part of the script if in a dataload
+# section or into a FILE if in an autoload section.
+
+$in_load = 0; # In a loading section
+$autoload = ''; # Name of autoloaded file
+$has_invocation_stub = 0; # True if we detect a #! stub
+$current_package = 'main'; # Current package
+$init_emitted = 0; # True when dataloading stamp was emitted
+$in_function = 0;
+
+require 'getopt.pl';
+&Getopt;
+
+while (<>) {
+ if ($. == 1 && /^(:|#).*perl/) { # Invocation stub
+ $has_invocation_stub = 1;
+ print;
+ next;
+ }
+ if ($. <= 3 && $has_invocation_stub) {
+ print;
+ next;
+ }
+ if (/^\s*$/) {
+ &flush_comment;
+ print unless $in_function;
+ print if $in_function && !$in_load;
+ if ($in_function && $in_load) {
+ push(@Data, "\n") unless $autoload;
+ $Auto{$autoload} .= "\n" if $autoload;
+ }
+ next;
+ }
+ if (/^\s*;?#/) {
+ if (/#\s*perload on/i) { # Enter a loading section
+ print unless /:$/;
+ $in_load = 1;
+ next;
+ }
+ if (/#\s*perload off/i) { # End a loading section
+ print unless /:$/;
+ $in_load = 0;
+ next;
+ }
+ if (/#\s*autoload (\S+)/i) { # Enter autoloading section
+ print unless /:$/;
+ push(@autoload, $autoload); # Directives may be nested
+ $autoload = $1;
+ $in_load += 2;
+ next;
+ }
+ if (/#\s*offload/i) { # End autoloading section
+ print unless /:$/;
+ $autoload = pop(@autoload); # Revert to previously active file
+ $in_load -= 2;
+ next;
+ }
+ &emit_init unless $init_emitted;
+ push(@Comment, $_) unless $in_function;
+ print if $in_function && !$in_load;
+ next unless $in_function;
+ push(@Data, $_) unless $autoload;
+ $Auto{$autoload} .= $_ if $autoload;
+ next;
+ }
+ &emit_init unless $init_emitted;
+ /^package (\S+)\s*;/ && ($current_package = $1);
+ unless ($in_load) {
+ &flush_comment;
+ print;
+ next;
+ }
+ # We are in a loading section
+ if (/^sub\s+([\w']+)\s*\{(.*)/) {
+ die "line $.: function $1 defined within another function.\n"
+ if $in_function;
+ # Silently ignore one-line functions
+ if (/\}/) {
+ &flush_comment;
+ print;
+ next;
+ }
+ $comment = $2;
+ $in_function = 1;
+ $function = $1;
+ ($fn_package, $fn_basename) = $function =~ /^(\w+)'(\w+)/;
+ unless ($fn_package) {
+ $fn_package = $current_package;
+ $fn_basename = $function;
+ }
+ # Keep leading function comment
+ foreach (@Comment) {
+ push(@Data, $_) unless $autoload;
+ $Auto{$autoload} .= $_ if $autoload;
+ }
+ @Comment = ();
+ # Change package context for correct compilation: the name is visible
+ # within the original function package while the body of the function
+ # is compiled within the current package.
+ $declaration = "sub $fn_package" . "'load_$fn_basename {$comment\n";
+ $package_context = "\tpackage $current_package;\n";
+ if ($autoload) {
+ $Auto{$autoload} .= $declaration . $package_context;
+ } else {
+ push(@Data, $declaration, $package_context);
+ }
+ # Emit stubs
+ print "sub $fn_package", "'$fn_basename";
+ print " { &auto_$fn_package", "'$fn_basename; }\n";
+ print "sub auto_$fn_package", "'$fn_basename { ";
+ print '&main\'dataload' unless $autoload;
+ print '&main\'autoload(' . "'$autoload'" . ', @_)' if $autoload;
+ print "; }\n";
+ next;
+ }
+ unless ($in_function) {
+ &flush_comment;
+ print;
+ next;
+ }
+ # We are in a loading section and inside a function body
+ push(@Data, $_) unless $autoload;
+ $Auto{$autoload} .= $_ if $autoload;
+ $in_function = 0 if /^\}/;
+ if (/^\}/) {
+ push(@Data, "\n") unless $autoload;
+ $Auto{$autoload} .= "\n" if $autoload;
+ }
+}
+
+@auto = keys %Auto;
+if (@auto > 0) {
+ print &q(<<'EOC');
+:# Load the calling function from file and call it. This function is called
+:# only once per file to be loaded.
+:sub main'autoload {
+: local($__file__) = shift(@_);
+: local($__packname__) = (caller(1))[3];
+: $__packname__ =~ s/::/'/;
+: local($__rpackname__) = $__packname__;
+: local($__saved__) = $@;
+: $__rpackname__ =~ s/^auto_//;
+: &perload'load_from_file($__file__);
+: $__rpackname__ =~ s/'/'load_/;
+: $@ = $__saved__; # Restore value $@ had on entrance
+: &$__rpackname__(@_); # Call newly loaded function
+:}
+:
+:# Load file and compile it, substituing the second stub function with the
+:# loaded ones. Location of the file uses the @AUTO array.
+:sub perload'load_from_file {
+: package perload;
+: local($file) = @_; # File to be loaded
+: local($body) = ' ' x 1024; # Pre-extent
+: local($load) = ' ' x 256; # Loading operations
+: # Avoid side effects by protecting special variables which will be
+: # changed by the autoloading operation.
+: local($., $_, $@);
+: $body = '';
+: $load = '';
+: &init_auto unless defined(@'AUTO); # Make sure we have a suitable @AUTO
+: &locate_file unless -f "$file"; # Locate file if relative path
+: open(FILE, $file) ||
+: die "Can't load $'__rpackname__ from $file: $!\n";
+: while (<FILE>) {
+: $load .= '*auto_' . $1 . '\'' . $2 . '= *' . $1 . '\'' . "load_$2;\n"
+: if (/^sub\s+(\w+)'load_(\w+)\s*\{/);
+: $body .= $_;
+: }
+: close FILE;
+EOC
+ if ($opt_t) {
+ print &q(<<'EOC');
+: # Untaint body when running setuid
+: $body =~ /^([^\0]*)/;
+: # No need to untaint $load, as it was built using trusted variables
+: eval $1 . $load;
+EOC
+ } else {
+ print &q(<<'EOC');
+: eval $body . $load;
+EOC
+ }
+ print &q(<<'EOC');
+: chop($@) && die "$@, while parsing code of $file.\n";
+:}
+:
+:# Initialize the @AUTO array. Attempt defining it by using the AUTOLIB
+:# environment variable if set, otherwise look in auto/ first, then in the
+:# current directory.
+:sub perload'init_auto {
+: if (defined $ENV{'AUTOLIB'} && $ENV{'AUTOLIB'}) {
+: @AUTO = split(':', $ENV{'AUTOLIB'});
+: } else {
+: @AUTO = ('auto', '.');
+: }
+:}
+:
+:# Locate to-be-loaded file held in $file by looking through the @AUTO array.
+:# This variable, defined in 'load_from_file', is modified as a side effect.
+:sub perload'locate_file {
+: package perload;
+: local($fullpath);
+: foreach $dir (@'AUTO) {
+: $fullpath = $dir . '/' . $file;
+: last if -f "$fullpath";
+: $fullpath = '';
+: }
+: $file = $fullpath if $fullpath; # Update var from 'load_from_file'
+:}
+:
+EOC
+}
+
+if (@Data > 0) {
+ print &q(<<'EOC');
+:# Load the calling function from DATA segment and call it. This function is
+:# called only once per routine to be loaded.
+:sub main'dataload {
+: local($__packname__) = (caller(1))[3];
+: $__packname__ =~ s/::/'/;
+: local($__rpackname__) = $__packname__;
+: local($__at__) = $@;
+: $__rpackname__ =~ s/^auto_//;
+: &perload'load_from_data($__rpackname__);
+: local($__fun__) = "$__rpackname__";
+: $__fun__ =~ s/'/'load_/;
+: eval "*$__packname__ = *$__fun__;"; # Change symbol table entry
+: die $@ if $@; # Should not happen
+: $@ = $__at__; # Restore value $@ had on entrance
+: &$__fun__; # Call newly loaded function
+:}
+:
+:# Load function name given as argument, fatal error if not existent
+:sub perload'load_from_data {
+: package perload;
+: local($pos) = $Datapos{$_[0]}; # Offset within DATA
+: # Avoid side effects by protecting special variables which will be changed
+: # by the dataloading operation.
+: local($., $_, $@);
+: $pos = &fetch_function_code unless $pos;
+: die "Function $_[0] not found in data section.\n" unless $pos;
+: die "Cannot seek to $pos into data section.\n"
+: unless seek(main'DATA, $pos, 0);
+: local($/) = "\n}";
+: local($body) = scalar(<main'DATA>);
+: local($*) = 1;
+: die "End of file found while loading $_[0].\n" unless $body =~ /^\}$/;
+EOC
+ if ($opt_t) {
+ print &q(<<'EOC');
+: # Untaint body when running setuid
+: $body =~ /^([^\0]*)/;
+: # Now we may safely eval it without getting an insecure dependency
+: eval $1; # Load function into perl space
+EOC
+ } else {
+ print &q(<<'EOC');
+: eval $body; # Load function into perl space
+EOC
+ }
+ print &q(<<'EOC');
+: chop($@) && die "$@, while parsing code of $_[0].\n";
+:}
+:
+EOC
+ print &q(<<'EOC') unless $opt_o;
+:# Parse text after the END token and record defined loadable functions (i.e.
+:# those whose name starts with load_) into the %Datapos array. Such function
+:# definitions must be left adjusted. Stop as soon as the function we want
+:# has been found.
+:sub perload'fetch_function_code {
+: package perload;
+: local($pos) = tell main'DATA;
+: local($in_function) = 0;
+: local($func_name);
+: local($., $_);
+: while (<main'DATA>) {
+: if (/^sub\s+(\w+)'load_(\w+)\s*\{/) {
+: die "DATA line $.: function $1'$2 defined within $func_name.\n"
+: if $in_function;
+: $func_name = $1 . '\'' . $2;
+: $Datapos{$func_name} = $pos;
+: $in_function = 1;
+: next;
+: }
+: $in_function = 0 if /^\}/;
+: next if $in_function;
+: return $pos if $func_name eq $_[0];
+: $pos = tell main'DATA;
+: }
+: 0; # Function not found
+:}
+:
+EOC
+ print &q(<<'EOC') if $opt_o;
+:# This function is called only once, and fills in the %Datapos array with
+:# the offset of each of the dataloaded routines held in the data section.
+:sub perload'fetch_function_code {
+: package perload;
+: local($start) = 0;
+: local($., $_);
+: while (<main'DATA>) { # First move to start of offset table
+: next if /^#/;
+: last if /^$/ && ++$start > 2; # Skip two blank line after end token
+: }
+: $start = tell(main'DATA); # Offsets in table are relative to here
+: local($key, $value);
+: while (<main'DATA>) { # Load the offset table
+: last if /^$/; # Ends with a single blank line
+: ($key, $value) = split(' ');
+: $Datapos{$key} = $value + $start;
+: }
+: $Datapos{$_[0]}; # All that pain to get this offset...
+:}
+:
+EOC
+ print &q(<<'EOC');
+:#
+:# The perl compiler stops here.
+:#
+:
+:__END__
+:
+:#
+:# Beyond this point lie functions we may never compile.
+:#
+:
+EOC
+ # Option -o directs us to optimize the function location by emitting an
+ # offset table, which lists all the position within DATA for each possible
+ # dataloaded routine.
+ if ($opt_o) {
+ print &q(<<'EOC');
+:#
+:# DO NOT CHANGE A IOTA BEYOND THIS COMMENT!
+:# The following table lists offsets of functions within the data section.
+:# Should modifications be needed, change original code and rerun perload
+:# with the -o option to regenerate a proper offset table.
+:#
+:
+EOC
+ $trailing_message = &q(<<'EOC');
+:
+:#
+:# End of offset table and beginning of dataloading section.
+:#
+:
+EOC
+ $pos = 0; # Offset relative to this point (start of table)
+ foreach (@Data) {
+ $Datapos{"$1\'$2"} = $pos - $now
+ if /^sub\s+(\w+)'load_(\w+)\s*\{/; # } for vi
+ $pos += length;
+ }
+ @poskeys = keys %Datapos; # Array of routine names (fully qualified)
+
+ # Write out a formatted table, each entry stored on $entry bytes and
+ # formatted with the $format string.
+ ($entry, $format) = &get_format(*poskeys);
+
+ # The total size occupied by the table is the size of one item times
+ # the number of items plus the final trailing message at the end of
+ # the table.
+ $table_size = $entry * @poskeys + length($trailing_message);
+
+ # Output formatted table
+ foreach (sort @poskeys) {
+ printf($format, $_, $table_size + $Datapos{$_});
+ }
+ print $trailing_message;
+ }
+
+ # Output code for each dataloaded function
+ foreach (@Data) {
+ print;
+ }
+ print &q(<<'EOC');
+:#
+:# End of dataloading section.
+:#
+:
+EOC
+}
+
+if (@auto > 0) {
+ mkdir('auto',0755) unless -d 'auto';
+ foreach $file (@auto) {
+ unless (open(AUTO, ">auto/$file")) {
+ warn "Can't create auto/$file: $!\n";
+ next;
+ }
+ print AUTO &q(<<'EOC');
+:# This file was generated by perload
+:
+EOC
+ print AUTO $Auto{$file};
+ close AUTO;
+ }
+}
+
+# Compute optimum format for routine offset table, returning both the size of
+# each entry and the formating string for printf.
+sub get_format {
+ local(*names) = @_;
+ local($name_len) = 0;
+ local($max_len) = 0;
+ foreach (@names) {
+ $name_len = length;
+ $max_len = $name_len if $name_len > $max_len;
+ }
+ # The size of each entry (preceded by one tab, followed by 12 chars)
+ $name_len = $max_len + 1 + 12;
+ ($name_len, "\t%${max_len}s %10d\n");
+}
+
+sub emit_init {
+ print &q(<<'EOC');
+:#
+:# This perl program uses dynamic loading [generated by perload]
+:#
+:
+EOC
+ $init_emitted = 1;
+}
+
+sub flush_comment {
+ print @Comment if @Comment > 0;
+ @Comment = ();
+}
+
+sub q {
+ local($_) = @_;
+ local($*) = 1;
+ s/^://g;
+ $_;
+}
+
+#
+# These next few lines are legal in both perl and nroff.
+#
+
+.00; # finish .ig
+
+'di \" finish diversion--previous line must be blank
+.nr nl 0-1 \" fake up transition to first page again
+.nr % 0 \" start at page 1
+'; __END__ \" the perl compiler stops here
+
+'''
+''' From here on it's a standard manual page.
+'''
+
+.TH PERLOAD 1 "June 20, 1992"
+.AT 3
+.SH NAME
+perload \- builds up autoloaded and dataloaded perl scripts
+.SH SYNOPSIS
+.B perload
+[ \fB\-ot\fR ]
+[ \fIfile\fR ]
+.SH DESCRIPTION
+.I Perload
+takes a perl script as argument (or from stdin if no argument is supplied)
+and prints out on stdout an equivalent script set-up to perform autoloading
+or dataloading. The translation is directed by special comments within the
+original script. Using dynamic loading can drastically improve start-up
+performances, both in time and in memory, as perl does not need to compile
+the whole script nor store its whole compiled form in memory.
+.PP
+.I Autoloading
+delays compilation of some functions until they are needed. The code for these
+functions is loaded dynamically at run-time. The atomicity of loading is a
+file, which means that putting more than one function into a file will cause
+all these functions to be loaded and compiled as soon as one among them is
+needed.
+.PP
+.I Dataloading
+is a form of autoloading where no extra file are needed. The script carries
+all the functions whose compilation is to be delayed in its data segment
+(in the \fIperl\fR sense, i.e. they are accessible via the DATA filehandle).
+The scripts parses the data segment and extracts only the code for the needed
+subroutine, which means granularity is better than with autloading.
+.PP
+It is possible for a single script to use both autoloading and dataloading at
+the same time. However, it should be noted that a script using only dataloading
+is self contained and can be moved or shared accross different platforms without
+fear. On the contrary, a script using only autoloading relies on some externally
+provided files. Sharing this script among different platforms requires sharing
+of these external files. The script itself cannot be redistributed without
+also giving the extra files holding the autoloaded functions.
+.PP
+The major drawback with dataloading is that the DATA filehandle cannot be used
+for anything else and may result in code duplication when two scripts could
+share the same pieces of code. Autoloading appears as the perfect solution in
+this case since two scripts may freely share the same functions without
+actually duplicating them on the disk (hence saving some precious disk blocks
+:-).
+.SH CRITERIA
+Functions to be dataloaded or autoloaded must meet the following layout
+criteria:
+.TP 5
+\-
+They must not be one-line functions like \fIsub sorter { $a <=> $b }\fR.
+Those functions are simply output verbatim, as they are already so
+small that it would not be worth to dynamically load them,
+.TP
+\-
+The first line must be of the form \fIsub routine_name {\fR, with an optional
+comment allowed after the '{'.
+.TP
+\-
+The function definition must end with a single '}' character left aligned.
+.TP
+\-
+Package directives outside any function must be left aligned.
+.PP
+All the above restrictions should not be source of a problem if "standard"
+writing style is used. There are also some name restrictions: the package
+name \fIperload\fR is reserved, as is the \fI@AUTO\fR array when autoloading
+is used. Packages must not start with \fIauto_\fR, as this is prepended to
+user's package names when building the stubs. Furthermore, the subroutines
+names \fImain'autoload\fR and
+\fImain'dataload\fR must not be used by the original script. Again, these
+should not cause any grief.
+.SH DIRECTIVES
+The translation performed by
+.I Perload
+is driven by some special comment directives placed directly within the code.
+Ending those directives with a ':' character will actually prevent them from
+being output into the produced script. Case is irrelevant for all the directives
+and the comment need not be left-aligned, although it must be the first
+non-space item on the line.
+.PP
+The following directives are available:
+.TP 10
+# Perload ON
+Turns on the \fIperload\fR processing. Any function definition which meets
+the criteria listed in the previous section will be replaced by two stubs and
+its actual definition will be rejected into the data segment (default) or a
+file when inside an autoloading section.
+.TP
+# Perload OFF
+Turns off any processing. The script is written as-is on the standard output.
+.TP
+# Autoload \fIpath\fR
+Requests autoloading from file \fIpath\fR, which may be an absolute path or
+a relative path. The file will be located at run-time using the @AUTO array
+if a non-absolute path is supplied or if the file does not exist as listed.
+Autoloading directives may be nested.
+.TP
+# Offload \fIpath\fR
+The argument is not required. The directive ends the previous autoloading
+directive (the inmost one). This does not turn off the \fIperload\fR processing
+though. The \fIpath\fR name is optional here (in fact, it has only a comment
+value).
+.SH OPTIONS
+Perload accepts only two options. Using \fB\-o\fR is meaningful only when
+dataloading is used. It outputs an offset table which lists the relative
+offset of the dataloaded functions within the data section. This will spare
+perl the run-time parsing needed to locate the function, and results in an good
+speed gain. However, it has one major drawback: it prevents people from
+actually modifying the source beyond the start of the table. But anything
+before can be freely edited, which is particulary useful when tailoring the
+script.
+.PP
+This option should not be used when editing of functions within the data
+section is necessary for whatever reason. When \fB\-o\fR is used, any
+change in the dataloaded function must be committed by re-running perload
+on the original script.
+.PP
+The other option \fB\-t\fR is to be used when producing a script which is
+going to run setuid. The body of the loaded function is untainted before being
+fed to eval, which slightly slows down loading (the first time the function is
+called), but avoids either an insecure dependency report or weird warnings from
+taintperl stating something is wrong (which is the behaviour with 4.0 PL35).
+.SH FILES
+.TP 10
+auto
+the subdirectory where all produced autoloaded files are written.
+.SH ENVIRONMENT
+No environment variables are used by \fIperload\fR. However, the autoloaded
+version of the script pays attention to the \fIAUTOLIB\fR variable as a colon
+separated set of directories where the to-be-loaded files are to be found
+when a non-absolute path was specified. If the \fIAUTOLIB\fR variable is not
+set, the default value 'auto:.' is used (i.e. look first in the auto/
+subdirectory, then in the current directory.
+.SH CAVEAT
+Special care is required when using an autoloading script, especially when
+executed by the super-user: it would be very easy for someone to leave a
+special version of a routine to be loaded, in the hope the super-user (or
+another suitable target) executes the autoloaded version of the script with
+some \fIad hoc\fR changes...
+.PP
+The directory holding the to-be-loaded files should therefore be protected
+against unauthorized access, and no file should have write permission on them.
+The directory itself should not be world-writable either, or someone might
+substitute his own version.
+It should also be considered wise to manually set the @AUTO variable to a
+suitable value within the script itself.
+.PP
+The \fB\-o\fR option uses \fIperl\fR's special variable \fI$/\fR with a
+multi-character value. I suspect this did not work with versions of \fIperl\fR
+prior to 4.0, so any script using this optimized form of dataloading will not
+be 100% backward compatible.
+.SH AUTHOR
+Raphael Manfredi <ram@acri.fr>
+.SH CREDITS
+Valuable input came from Wayne H. Scott <wscott@ecn.purdue.edu>. He is
+merely the author of the optimizing offset table (\fB\-o\fR option).
+.PP
+.I Perload
+is based on an article from Tom Christiansen <tchrist@convex.com>,
+.I Autoloading in Perl,
+explaining the concept of dataloading and giving a basic implementation.
+.SH "SEE ALSO"
+perl(1).