diff options
author | rmanfredi <rmanfredi@2592e710-e01b-42a5-8df0-11608a6cc53d> | 2006-08-24 12:32:52 +0000 |
---|---|---|
committer | rmanfredi <rmanfredi@2592e710-e01b-42a5-8df0-11608a6cc53d> | 2006-08-24 12:32:52 +0000 |
commit | 0e57f0c510b7d7eb688695359048a1f0a585e26a (patch) | |
tree | dee05e98bc53766d609ef2a3a07a5672627d812c /bin |
Moving project to sourceforge.
git-svn-id: svn://svn.code.sf.net/p/dist/code/trunk/dist@1 2592e710-e01b-42a5-8df0-11608a6cc53d
Diffstat (limited to 'bin')
-rw-r--r-- | bin/Jmakefile | 45 | ||||
-rwxr-xr-x | bin/Makefile.SH | 216 | ||||
-rwxr-xr-x | bin/manicheck.SH | 82 | ||||
-rw-r--r-- | bin/manicheck.man | 51 | ||||
-rwxr-xr-x | bin/manilist.SH | 484 | ||||
-rw-r--r-- | bin/manilist.man | 332 | ||||
-rwxr-xr-x | bin/packinit.SH | 447 | ||||
-rw-r--r-- | bin/packinit.man | 148 | ||||
-rwxr-xr-x | bin/perload | 648 |
9 files changed, 2453 insertions, 0 deletions
diff --git a/bin/Jmakefile b/bin/Jmakefile new file mode 100644 index 0000000..795cb7b --- /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 ram $ +;# +;# Copyright (c) 1991-1997, 2004-2006, 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 4.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 100755 index 0000000..977ce80 --- /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-1997, 2004-2006, 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 4.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..a2ea9dd --- /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$ +# +# Copyright (c) 1991-1997, 2004-2006, 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 4.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..e17352a --- /dev/null +++ b/bin/manicheck.man @@ -0,0 +1,51 @@ +''' $Id: manicheck.man,v 3.0 1993/08/18 12:04:02 ram Exp ram $ +''' +''' Copyright (c) 1991-1997, 2004-2006, 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 4.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..75dd073 --- /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$ +# +# Copyright (c) 1991-1997, 2004-2006, 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 4.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..f7dcd0d --- /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 ram $ +''' +''' Copyright (c) 1991-1997, 2004-2006, 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 4.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 100755 index 0000000..c161093 --- /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$ +# +# Copyright (c) 1991-1997, 2004-2006, 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 4.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..a43abdc --- /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 ram $ +''' +''' Copyright (c) 1991-1997, 2004-2006, 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 4.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..2354790 --- /dev/null +++ b/bin/perload @@ -0,0 +1,648 @@ +: # 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 ram $ +# +# Copyright (c) 1991-1997, 2004-2006, 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 4.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] +:# +: +:$ENV{LC_ALL} = 'C'; +: +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). |