Received: (at submit) by bugs.debian.org; 27 Jun 2000 08:11:40 +0000 From karlheg@bittersweet.inetarena.com Tue Jun 27 03:11:40 2000 Return-path: Received: from bittersweet.inetarena.com [209.102.107.172] by master.debian.org with esmtp (Exim 3.12 2 (Debian)) id 136qT5-0002uL-00; Tue, 27 Jun 2000 03:11:39 -0500 Received: by bittersweet.inetarena.com (Postfix, from userid 1000) id A62B622AF13; Tue, 27 Jun 2000 01:11:38 -0700 (PDT) Sender: karlheg@bittersweet.intra To: submit@bugs.debian.org Subject: [patch] add `dpkg-substvars', make `dpkg-gencontrol' perform substvars on Package field. From: karlheg@debian.org (Karl M. Hegbloom) X-Face: /Q}=yl}1_v7nP)xXo5XjG8+tl@=uVu7o5u6)f]zN?+/\\R>qDt(t8w!-i{(y0\"`jFw^uk8inzO9wXabd'CdjUWfC\\GHi:6nO*YC89#-qD>Q4r%9!V\" Mime-Version: 1.0 (generated by tm-edit 1.5) Content-Type: multipart/mixed; boundary="Multipart_Tue_Jun_27_01:11:38_2000-1" Content-Transfer-Encoding: 7bit Lines: 713 Delivered-To: submit@bugs.debian.org --Multipart_Tue_Jun_27_01:11:38_2000-1 Content-Type: text/plain; charset=US-ASCII Package: dpkg Version: 1.6.13 Severity: wishlist The following script and patch should be applied while standing in the "scripts" subdirectory of the `dpkg' sources. This allows `control' to contain a variable expansion in the "Package:" field, like "Package: guile${GUILE_SHORTVERSION}", where GUILE_SHORTVERSION is defined in a substvars file. I have updated the manual also, this behaviour and how to use it some are explained there. For my version of the `guile' packages, what I'm doing is using the upstream "GUILE-VERSION" includer from "debian/rules", with GNU Make's "include" instruction, and then also using it as the base for a substvars file. When I (or debhelper) call any of the `dpkg-*' scripts that needs to know what package to act on (via the -p option), the real name of the package is given, by way of a Make macro expansion that amounts to the same expansion the substvars on the "Package:" field will do, so they match: foopkg = foo${FOO_SHORTVERSION} sometarget: dh_dosomething --package=${foopkg} ${foopkg}.postinst: foo.postinst.in dpkg-substvars -p${foopkg} < $< > $@ This avoids hard-coding package names like "guile1.4", or "libguile9" in "debian/control", thus improving maintainability. There are other Debian packages out there that could benefit from this backwards compatible (afaict) modification. Please see the "debian/rules" from my version of the Guile "debian/*" scripts for a more complex example, if you've time and curiosity. Included is `dpkg-substvars', which reads stdin, performs variable substitutions, and writes to stdout. It is derived directly from `dpkg-gencontrol'. You can give it the `-@' option to have it replace variables enclosed in "@varname@", rather than the usual "${varname}", so that it can work on shell scripts and makefile includers. It is very useful for generating maintainer scripts that have version numbers, etc. inside of them, yet again, avoiding a possibly missed edit on upstream version upgrade, and thus improving package maintainability. My version of the Guile debian/* scripts may be viewed via ... if you are curious. I plan to share them with the real Guile package maintainer, but cannot do so until after the attached changes are part of the distributed `dpkg'. --Multipart_Tue_Jun_27_01:11:38_2000-1 Content-Type: application/octet-stream Content-Disposition: attachment; filename="dpkg-substvars" Content-Transfer-Encoding: 8bit #! /usr/bin/perl $dpkglibdir="/usr/lib/dpkg"; $version="1.0.0"; # This line modified by Makefile $controlfile= 'debian/control'; $changelogfile= 'debian/changelog'; $fileslistfile= 'debian/files'; $varlistfile= 'debian/substvars'; $at = 0; $infile = '&STDIN'; $outfile = '&STDOUT'; use POSIX; use POSIX qw(:errno_h); push(@INC,$dpkglibdir); require 'controllib.pl'; sub usageversion { print STDERR "Debian GNU/Linux dpkg-substvars $version. Copyright (C) 2000 Karl M. Hegbloom. This is free software; see the GNU General Public Licence version 2 or later for copying conditions. There is NO warranty. Usage: dpkg-substvars [options ...] infile defaults to STDIN, outfile defaults to STDOUT. Options: -i take input from infile -o write output to outfile -\@ subst \@VAR\@ rather than \${VAR} -p use control file data for package -c get control info from this file -l get per-version info from this file -F force change log format -v set version of binary package -D= override or add a field and value -U remove a field -V= set a substitution variable -T read variables here, not debian/substvars -h print this message "; } $i=100;grep($fieldimps{$_}=$i--, qw(Package Version Section Priority Architecture Essential Pre-Depends Depends Recommends Suggests Enhances Optional Conflicts Replaces Provides Installed-Size Maintainer Source Description Build-Depends Build-Depends-Indep Build-Conflicts Build-Conflicts-Indep Source)); while (@ARGV) { $_=shift(@ARGV); if (m/^-p([-+0-9a-z.]+)$/) { $oppackage= $1; } elsif (m/^-c/) { $controlfile= $'; } elsif (m/^-l/) { $changelogfile= $'; } elsif (m/^-v(.+)$/) { $forceversion= $1; } elsif (m/^-F([0-9a-z]+)$/) { $changelogformat=$1; } elsif (m/^-D([^\=:]+)[=:]/) { $override{$1}= $'; } elsif (m/^-U([^\=:]+)$/) { $remove{$1}= 1; } elsif (m/^-V(\w[-:0-9A-Za-z]*)[=:]/) { $substvar{$1}= $'; } elsif (m/^-T/) { $varlistfile= $'; } elsif (m/^-i/) { $infile= $'; } elsif (m/^-o/) { $outfile= $'; } elsif (m/^-\@/) { $at=1; } elsif (m/^-h$/) { &usageversion; exit(0); } elsif (m/^-/) { &usageerr("unknown option \`$_'"); } } &findarch; &parsechangelog; &parsevarlistfile; &parsecontrolfile; &expandsubstvars; if (length($oppackage)) { defined($p2i{"C $oppackage"}) || &error("package $oppackage not in control info"); $myindex= $p2i{"C $oppackage"}; } else { @packages= grep(m/^C /,keys %p2i); @packages==1 || &error("must specify package since control info has many (@packages)"); $myindex=1; $oppackage= &substvars($f{'Package'}); } #print STDERR "myindex $myindex\n"; for $_ (keys %fi) { $v= $fi{$_}; if (s/^C //) { #print STDERR "G key >$_< value >$v<\n"; if (m/^Maintainer$/) { $f{$_}=$v; } elsif (m/^Source$/) { &setsourcepackage; } elsif (s/^X[CS]*B[CS]*-//i) { $f{$_}= $v; } elsif (m/^X[CS]+-|^Standards-Version$|^Build-(Depends|Conflicts)(-Indep)?$/i) { } elsif (m/^Section$|^Priority$/) { $spdefault{$_}= $v; } else { &unknown('general section of control info file'); } } elsif (s/^C$myindex //) { #print STDERR "P key >$_< value >$v<\n"; if (m/^Package$/) { $f{&substvars($_)}= $v; } elsif (m/^(Description|Essential|Pre-Depends|Depends)$/ || m/^(Recommends|Suggests|Enhances|Optional|Conflicts|Provides|Replaces)$/) { $f{$_}= $v; } elsif (m/^Section$|^Priority$/) { $spvalue{$_}= $v; } elsif (m/^Architecture$/) { if ($v eq 'all') { $f{$_}= $v; } elsif ($v eq 'any') { $f{$_}= $arch; } else { @archlist= split(/\s+/,$v); grep($arch eq $_, @archlist) || &error("current build architecture $arch does not". " appear in package's list (@archlist)"); $f{$_}= $arch; } } elsif (s/^X[CS]*B[CS]*-//i) { $f{$_}= $v; } elsif (!m/^X[CS]+-/i) { &unknown("package's section of control info file"); } } elsif (m/^C\d+ /) { #print STDERR "X key >$_< value not shown<\n"; } elsif (s/^L //) { #print STDERR "L key >$_< value >$v<\n"; if (m/^Source$/) { &setsourcepackage; } elsif (m/^Version$/) { $sourceversion= $v; $f{$_}= $v unless length($forceversion); } elsif (m/^(Maintainer|Changes|Urgency|Distribution|Date|Closes)$/) { } elsif (s/^X[CS]*B[CS]*-//i) { $f{$_}= $v; } elsif (!m/^X[CS]+-/i) { &unknown("parsed version of changelog"); } } else { &internerr("value from nowhere, with key >$_< and value >$v<"); } } $f{'Version'}= $forceversion if length($forceversion); for $f (qw(Section Priority)) { $spvalue{$f}= $spdefault{$f} unless length($spvalue{$f}); $f{$f}= $spvalue{$f} if $spinclude{$f} && length($spvalue{$f}); } for $f (qw(Package Version)) { defined($f{$f}) || &error("missing information for output field $f"); } for $f (qw(Maintainer Description Architecture)) { defined($f{$f}) || &warn("missing information for output field $f"); } $verdiff= $f{'Version'} ne $sourceversion; if ($oppackage ne $sourcepackage || $verdiff) { $f{'Source'}= $sourcepackage; $f{'Source'}.= " ($sourceversion)" if $verdiff; } $sversion=$f{'Version'}; $sversion =~ s/^\d+://; for $f (keys %override) { $f{&capit($f)}= $override{$f}; } for $f (keys %remove) { delete $f{&capit($f)}; } open (IN, "<$infile") or die "Cannot open $infile for input"; open (OUT, ">$outfile") or die "Cannot open $outfile for output"; while () { print OUT &substvars($_,$at); } exit (0); sub spfileslistvalue { $r= $spvalue{$_[0]}; $r= '-' if !length($r); return $r; } --Multipart_Tue_Jun_27_01:11:38_2000-1 Content-Type: text/plain; charset=US-ASCII --Multipart_Tue_Jun_27_01:11:38_2000-1 Content-Type: text/plain; type=patch; charset=US-ASCII Content-Disposition: attachment; filename="thediff.diff" Content-Transfer-Encoding: 8bit --- dpkg-source.1 2000/06/27 05:42:50 1.1 +++ dpkg-source.1 2000/06/27 07:34:13 @@ -2,9 +2,9 @@ .\" Authors: Ian Jackson .TH DPKG\-SOURCE 1 "7th August" "Debian Project" "Debian GNU/Linux manual" .SH NAME -dpkg\-source, dpkg\-gencontrol, dpkg\-shlibdeps, dpkg\-genchanges, -dpkg\-buildpackage, dpkg\-distaddfile, dpkg\-parsechangelog -\- Debian source package tools +dpkg\-source, dpkg\-gencontrol, dpkg\-substvars, dpkg\-shlibdeps, +dpkg\-genchanges, dpkg\-buildpackage, dpkg\-distaddfile, +dpkg\-parsechangelog \- Debian source package tools .SH SYNOPSIS .B dpkg-source .BI "-x " filename .dsc @@ -15,6 +15,9 @@ .B dpkg-gencontrol .RI [ options ] .br +.B dpkg-substvars +.RI [ options ] +.br .B dpkg-shlibdeps .IR options .br @@ -39,6 +42,13 @@ for the binary package to .BR debian/files . +.B dpkg-substvars +parses +.B debian/substvars +then reads an input file, performs variable substitution on it, and +writes the result back out. See below for a discussion of output +substitution. + .B dpkg-shlibdeps calculates shared library dependencies for executables named in its arguments. The dependencies are added to the substitution @@ -148,7 +158,7 @@ .BI -V name = value Set an output substitution variable. This option is understood by -.BR dpkg-source ", " dpkg-gencontrol " and " dpkg-genchanges . +.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-substvars " and " dpkg-genchanges . See below for a discussion of output substitution. .TP .BI -T substvarsfile @@ -159,17 +169,17 @@ the default is .BR debian/substvars . This option is understood by -.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-shlibdeps " and " dpkg-genchanges . +.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-substvars ", " dpkg-shlibdeps " and " dpkg-genchanges . .TP .BI -D field = value Override or add an output control file field. This option is understood by -.BR dpkg-source ", " dpkg-gencontrol " and " dpkg-genchanges . +.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-substvars " and " dpkg-genchanges . .TP .BI -U field Remove an output control file field. This option is understood by -.BR dpkg-source ", " dpkg-gencontrol " and " dpkg-genchanges . +.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-substvars " and " dpkg-genchanges . .TP .BR -b | -B For @@ -200,14 +210,14 @@ default is .BR debian/control . This option is understood by -.BR dpkg-source ", " dpkg-gencontrol " and " dpkg-genchanges . +.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-substvars " and " dpkg-genchanges . .TP .BI -l changelogfile Specifies the change log file to read information from. The default is .BR debian/changelog . This option is understood by -.BR dpkg-source ", " dpkg-gencontrol " and " dpkg-genchanges . +.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-substvars " and " dpkg-genchanges . .TP .BI -f fileslistfile Read or write the list of files to be uploaded here, rather than using @@ -223,7 +233,7 @@ the standard format described in the .IR "Debian packaging manual" . This option is understood by -.BR dpkg-source ", " dpkg-gencontrol " and " dpkg-genchanges . +.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-substvars " and " dpkg-genchanges . .SH DPKG-SOURCE OPTIONS When the common options .BR -c " and " -l @@ -409,7 +419,7 @@ .TP .BI -P packagebuilddir Tells -.B dpkg-source +.B dpkg-gencontrol that the package is being built in .I packagebuilddir instead of @@ -429,6 +439,27 @@ if .B -P was used). +.SH DPKG-SUBSTVARS OPTIONS +.B dpkg-substvars +does not take any non-option arguments. +.TP +.BI -i infile +Read input from +.IR infile . +By default, it reads from standard input. +.TP +.BI -o outfile +Write output to +.IR outfile . +By default, it writes to standard output, with warnings about +undefined variables being printed to standard error. +.TP +.BI -p package +Generate information for the binary package +.IR package . +If the source control file lists only one binary package then this +option may be omitted; otherwise it is essential to select which +binary package's information to generate. .SH DPKG-SHLIBDEPS OPTIONS .B dpkg-shlibdeps interprets non-option arguments as executable names, just as if they'd @@ -488,7 +519,7 @@ .RB ( debian/substvars by default). .SH DPKG-GENCHANGES OPTIONS -.B dpkg-gencontrol +.B dpkg-genchanges does not take any non-option arguments. .TP .BI -u uploadfilesdir @@ -580,8 +611,7 @@ .TP .B -i[] Passed unchanged to -.B dpkg-source -.TP +.BR dpkg-source . .SH DPKG-DISTADDFILE ARGUMENTS .B dpkg-distaddfile does not take any non-common options. It takes three non-option @@ -601,28 +631,77 @@ does not take any non-common options or non-option arguments. .SH VARIABLE SUBSTITUTION Before -.BR dpkg-source ", " dpkg-gencontrol " and " dpkg-genchanges +.BR dpkg-source ", " dpkg-gencontrol ", " dpkg-substvars " and " dpkg-genchanges write their control information (to the source control file .B .dsc for .B dpkg-source and to standard output for -.BR dpkg-gencontrol " and " dpkg-genchanges ) +.BR dpkg-gencontrol ", " dpkg-substvars " and " dpkg-genchanges ) they perform some variable substitutions on the output file. A variable substitution has the form .BI ${ variable-name }\fR. -Variable names consist of alphanumerics, hyphens and colons and start -with an alphanumeric. Variable substitutions are performed repeatedly -until none are left; the full text of the field after the substitution -is rescanned to look for more substitutions. +Variable names consist of alphanumerics, underscores, hyphens and +colons, and start with an alphanumeric. Variable substitutions are +performed repeatedly until none are left; the full text of the field +after the substitution is rescanned to look for more substitutions. + +The +.B Package +field of +.B debian/control +is also transformed, so it is possible, for example, to add a major +version number to the name of a package, by saying something like: +.B Package: foo${FOO_MAJOR_VERSION} +in +.BR debian/control , +and then, in +.BR debian/substvars ", define " FOO_MAJOR_VERSION=3 . +When you do this, use the +.B -p +switch, like +.BI -p foo3\fR, +perhaps by using a macro expansion from a makefile to fill in the +variable part (the 3 in this example) of the \fB-p\fR option's +argument. + +For the most part, the syntax of the +.B debian/substvars +file is compatible with GNU Make, so you can use the +.B include +instruction in your +.B debian/rules +to bring in the +.B debian/substvars +values if you like. Note that +.B dpkg-shlibdeps +will generate entries that are \fBnot\fR compatible with Make. A good +workaround is to include a substvars file by a different name, then +use it as a base for the actual \fBdebian/substvars\fR (which you +generate) to be used by the \fBdpkg-*\fR scripts. That is a good time +to add values to the \fBdebian/substvars\fR that have been computed by +your \fBdebian/rules\fR. + +If +.B dpkg-substvars +is given the +.B -@ +switch, a variable substitution will have the form +.BI @ variable-name @ +so that substitutions can be made in shell scripts or makefiles +without disturbing normal shell or make variables in them. The +.B debian/substvars +file maintains the same syntax as before though, with dollar signs and +curly braces, not `at' signs. -After all the substitutions have been done each occurence of the +For all of these utilities except for +.BR dpkg-substvars , +after all the substitutions have been done, each occurence of the string .B ${} -(which is not a legal substitution) is replaced with a -.B $ -sign. +is replaced with +.BR $ . Variables can be set using the .B -V @@ -653,7 +732,8 @@ .B dpkg-gencontrol will use .B du -k debian/tmp -to find the default value. +to find the default value. This variable is \fBnot\fR defined by +.BR dpkg-substvars . .TP .B Extra-Size Additional disk space used when the package is installed. If this @@ -662,7 +742,8 @@ variable (whether set explicitly or using the default value) before it is copied into the .B Installed-Size -control file field. +control file field. This variable is not defined for +.BR dpkg-substvars . .TP .BI F: fieldname The value of the output field --- controllib.pl 2000/06/25 10:16:25 1.1 +++ controllib.pl 2000/06/25 21:45:40 @@ -76,11 +76,56 @@ $substvar{'Arch'}= $arch; } +sub parsevarlistfile { + if (length($varlistfile)) { + $varlistfile="./$varlistfile" if $varlistfile =~ m/\s/; + if (open(SV,"< $varlistfile")) { + while () { + next if m/^\#/ || !m/\S/; + s/\s*\n$//; + m/^(\w[-_:0-9A-Za-z]*)\=/ || + &error("bad line in substvars file $varlistfile at line $."); + $substvar{$1}= $'; + } + close(SV); + } elsif ($! != ENOENT ) { + &error("unable to open substvars file $varlistfile: $!"); + } + } +} + +# This must be done when -@ is given otherwise if, for instance, +# substvars contains: +# BLAH=a +# FOO=b +# VAR=${BLAH}.${FOO} +# ... a maint script contains: +# @VAR@ +# ... and it would expand to: +# ${BLAH}.${FOO} +# ... rather than to +# a.b +# ... without calling &expandsubstvars; first. +# See: dpkg-substvars for an example of where this is used. +sub expandsubstvars { + for $f (keys %f) { $substvar{"F:$f"}= $f{$f}; } + for $sv (keys %substvar) { + $substvar{$sv} = &substvars($substvar{$sv}); + } +} + sub substvars { - my ($v) = @_; - my ($lhs,$vn,$rhs,$count); + my ($v,$at) = @_; + my ($lhs,$vn,$rhs,$count,$re); $count=0; - while ($v =~ m/\$\{([-:0-9a-z]+)\}/i) { + $re = "([-_:0-9a-z]+)"; + if ($at) { + $re = '\@'.$re.'\@'; + } + else { + $re = '\$\{'.$re.'\}'; + } + while ($v =~ m/$re/i) { $count < $maxsubsts || &error("too many substitutions - recursive ? - in \`$v'"); $lhs=$`; $vn=$1; $rhs=$'; @@ -97,22 +142,7 @@ sub outputclose { my ($dosubstvars) = @_; - for $f (keys %f) { $substvar{"F:$f"}= $f{$f}; } - if (length($varlistfile) and $dosubstvars) { - $varlistfile="./$varlistfile" if $varlistfile =~ m/\s/; - if (open(SV,"< $varlistfile")) { - while () { - next if m/^\#/ || !m/\S/; - s/\s*\n$//; - m/^(\w[-:0-9A-Za-z]*)\=/ || - &error("bad line in substvars file $varlistfile at line $."); - $substvar{$1}= $'; - } - close(SV); - } elsif ($! != ENOENT ) { - &error("unable to open substvars file $varlistfile: $!"); - } - } + &parsevarlistfile if $dosubstvars; for $f (sort { $fieldimps{$b} <=> $fieldimps{$a} } keys %f) { $v= $f{$f}; if ($dosubstvars) { 8$1; $v=$2; $cf= &capit($cf); $fi{"$source$index $cf"}= $v; - if (lc $cf eq 'package') { $p2i{"$source $v"}= $index; } + if (lc $cf eq 'package') { + $v = &substvars($v); + $p2i{"$source $v"}= $index; + } } elsif (m/^\s+\S/) { length($cf) || &syntax("continued value line not in field"); $fi{"$source$index $cf"}.= "\n$_"; --- dpkg-genchanges.pl 2000/06/25 10:27:18 1.1 +++ dpkg-genchanges.pl 2000/06/25 10:51:21 @@ -97,6 +97,7 @@ &findarch; &parsechangelog; +&parsevarlistfile; &parsecontrolfile; $fileslistfile="./$fileslistfile" if $fileslistfile =~ m/^\s/; 8('general section of control info file'); } } elsif (s/^C(\d+) //) { #print STDERR "P key >$_< value >$v<\n"; - $i=$1; $p=$fi{"C$i Package"}; $a=$fi{"C$i Architecture"}; + $i=$1; $p=&substvars($fi{"C$i Package"}); $a=$fi{"C$i Architecture"}; if (!defined($p2f{$p})) { if ($a eq 'any' || ($a eq 'all' && !$archspecific) || grep($_ eq $substvar{'Arch'}, split(/\s+/, $a))) { --- dpkg-gencontrol.pl 2000/06/25 10:19:07 1.1 +++ dpkg-gencontrol.pl 2000/06/25 10:26:54 @@ -91,8 +91,9 @@ &findarch; &parsechangelog; +&parsevarlistfile; &parsecontrolfile; - + if (length($oppackage)) { defined($p2i{"C $oppackage"}) || &error("package $oppackage not in control info"); $myindex= $p2i{"C $oppackage"}; @@ -101,6 +102,7 @@ @packages==1 || &error("must specify package since control info has many (@packages)"); $myindex=1; + $oppackage= &substvars($f{'Package'}); } #print STDERR "myindex $myindex\n"; @@ -117,7 +119,9 @@ else { &unknown('general section of control info file'); } } elsif (s/^C$myindex //) { #print STDERR "P key >$_< value >$v<\n"; - if (m/^(Package|Description|Essential|Pre-Depends|Depends)$/ || + if (m/^Package$/) { + $f{&substvars($_)}= $v; + } elsif (m/^(Description|Essential|Pre-Depends|Depends)$/ || m/^(Recommends|Suggests|Enhances|Optional|Conflicts|Provides|Replaces)$/) { $f{$_}= $v; } elsif (m/^Section$|^Priority$/) { @@ -161,6 +165,8 @@ $f{'Version'}= $forceversion if length($forceversion); +for $f (keys %f) { $substvar{"F:$f"}= $f{$f}; } + for $f (qw(Section Priority)) { $spvalue{$f}= $spdefault{$f} unless length($spvalue{$f}); $f{$f}= $spvalue{$f} if $spinclude{$f} && length($spvalue{$f}); 8ainer Description Architecture)) { defined($f{$f}) || &warn("missing information for output field $f"); } -$oppackage= $f{'Package'}; $verdiff= $f{'Version'} ne $sourceversion; if ($oppackage ne $sourcepackage || $verdiff) { --- dpkg-source.pl 2000/06/25 10:33:13 1.1 +++ dpkg-source.pl 2000/06/25 10:37:13 @@ -115,6 +115,7 @@ $controlfile= "$dir/debian/control" unless defined($controlfile); &parsechangelog; + &parsevarlistfile; &parsecontrolfile; $f{"Format"}=$dscformat; --Multipart_Tue_Jun_27_01:11:38_2000-1--