summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/svn-multi/svn-multi-pl.dtx
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/svn-multi/svn-multi-pl.dtx
Initial commit
Diffstat (limited to 'macros/latex/contrib/svn-multi/svn-multi-pl.dtx')
-rw-r--r--macros/latex/contrib/svn-multi/svn-multi-pl.dtx570
1 files changed, 570 insertions, 0 deletions
diff --git a/macros/latex/contrib/svn-multi/svn-multi-pl.dtx b/macros/latex/contrib/svn-multi/svn-multi-pl.dtx
new file mode 100644
index 0000000000..4c92a69e4b
--- /dev/null
+++ b/macros/latex/contrib/svn-multi/svn-multi-pl.dtx
@@ -0,0 +1,570 @@
+% \iffalse
+%<*driver>
+\iffalse
+%</driver>
+#!/usr/bin/perl
+# --------------------------------------------------------------
+# svn-multi.pl for the svn-multi v2.0 LaTeX package
+# version 0.1, Mar 1st, 2009
+# --------------------------------------------------------------
+#
+# Copyright (C) 2006-2012 Martin Scharrer
+# E-mail: martin@scharrer-online.de
+# Code repository: https://bitbucket.org/martin_scharrer/svn-multi
+#
+# This program works only in combination with the LaTeX package 'svn-multi' and
+# generates .svx files with '\svnidlong' macros holding Subversion keywords for
+# files declared with '\svnexternal' inside the LaTeX document.
+#
+# This program is free software under the GPL v3 and LPPL v1.3c or later.
+#
+#
+# GPL v3:
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#
+# LPPL v1.3c:
+# This work may be distributed and/or modified under the
+# conditions of the LaTeX Project Public License, either version 1.3c
+# of this license or (at your option) any later version.
+# The latest version of this license is in
+# http://www.latex-project.org/lppl.txt
+# and version 1.3c or later is part of all distributions of LaTeX
+# version 2008/05/04 or later.
+#
+# This work has the LPPL maintenance status `maintained'.
+#
+# The Current Maintainer of this work is Martin Scharrer.
+#
+# This work consists of the files svn-multi.dtx, svn-multi-pl.dtx and
+# svn-multi.ins and the derived files svn-multi.sty, svnkw.sty and svn-multi.pl.
+#
+# The file 'svn-multi.pl' may be renamed to 'svn-multi' for installation
+# purposes.
+#
+#
+%<*driver>
+\fi
+\makeatletter
+% $Id: svn-multi-pl.dtx 1873 2010-07-26 15:31:45Z martin $
+\def\svnmultipl@version {v0.1a}
+\def\svnmultipl@rev $#1: #2 ${\def\svnmultipl@rev{#2}}
+\def\svnmultipl@date $#1: #2-#3-#4 #5 ${%
+ \def\svnmultipl@today{{\year#2\month#3\day#4\today}}%
+ \def\svnmultipl@date{#2/#3/#4}%
+}
+\svnmultipl@rev $Rev: 1873 $
+\svnmultipl@date $Date: 2010-07-26 17:31:45 +0200 (Mon, 26 Jul 2010) $
+
+\ProvidesFile{svn-multi-pl.dtx}
+ [\svnmultipl@date\space\svnmultipl@version\space SVN Keywords extractor for svn-multi]
+
+\documentclass{ltxdoc}
+\usepackage{ifpdf}
+\ifpdf
+ % use hypdoc if you have it, hyperref else
+ %\usepackage[hyperfootnotes=false]{hyperref}
+ \usepackage{hypdoc}
+\else\let\url=\texttt\fi
+\usepackage{xspace}
+\newcommand{\ie}{i.e.\@\xspace}
+\newcommand{\eg}{e.g.\@\xspace}
+
+\newenvironment{sub}{\begin{macro}}{\end{macro}}
+\newcommand{\parni}{\par\noindent}
+\newlength{\origparindent}
+\setlength{\origparindent}{\parindent}
+\setlength{\parindent}{0pt}
+\let\origpar=\par
+\def\par{\parindent=\origparindent\origpar\parindent=0pt}
+
+%\EnableCrossrefs
+\DisableCrossrefs
+\CodelineIndex
+%\PageIndex
+%\RecordChanges
+\begin{document}
+ %\OnlyDescription
+ \DocInput{\jobname.dtx}%
+ %\PrintChanges
+ %\clearpage
+ %\PrintIndex
+\end{document}
+%</driver>
+%<*script>
+%\fi
+%
+% \CheckSum{66}
+%
+% {\makeatother
+% \CharacterTable
+% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+% Digits \0\1\2\3\4\5\6\7\8\9
+% Exclamation \! Double quote \" Hash (number) \#
+% Dollar \$ Percent \% Ampersand \&
+% Acute accent \' Left paren \( Right paren \)
+% Asterisk \* Plus \+ Comma \,
+% Minus \- Point \. Solidus \/
+% Colon \: Semicolon \; Less than \<
+% Equals \= Greater than \> Question mark \?
+% Commercial at \@ Left bracket \[ Backslash \\
+% Right bracket \] Circumflex \^ Underscore \_
+% Grave accent \` Left brace \{ Vertical bar \|
+% Right brace \} Tilde \~}
+% }
+% \iffalse " \fi
+%
+% \title{The \textsf{svn-multi.pl} Script}
+% \author{Martin Scharrer \\ \url{martin@scharrer-online.de} \\
+% \url{http://latex.scharrer-online.de/svn-multi} \\
+% CTAN: \url{http://tug.ctan.org/pkg/svn-multi}}
+% \date{Version \expandafter\@gobble\svnmultipl@version\\[0.5ex]\svnmultipl@today}
+%
+%
+% \ifpdf
+% \hypersetup{
+% pdfauthor={Martin Scharrer <martin@scharrer-online.de>},
+% pdftitle={The svn-multi.pl script},
+% pdfsubject={Documentation of Perl script svn-multi.pl which allows the
+% typesetting of external Subversion keywords in multi-file LaTeX documents},
+% pdfkeywords={svn-multi, svnkw, LaTeX, Subversion, keywords, Version
+% Control, Id, script}
+% }
+% \fi
+% \maketitle
+%
+% \textbf{Note:} This document is work in progress.\par
+% \section{Usage}
+% See the section in the |svn-multi| package manual or the
+% \hyperlink{usage}{\texttt{usage}} function below.
+%
+% \StopEventually{}
+% \section{Implementation}
+%
+% \subsection{Script Head}
+% Loading of required Modules.
+% \begin{macrocode}
+use strict;
+use warnings;
+use File::Basename;
+% \end{macrocode}
+% Declaration of constants VERSION, REV and DATE for script info output:
+% \begin{macrocode}
+my $VERSION = "0.2";
+my ($REV,$DATE) =
+ (split ' ','$Id$')[2,3];
+% \end{macrocode}
+
+% Declaration of other global constants and variables:
+% \begin{macrocode}
+my $dollar = '$';
+my @PATH;
+my %EXCLUDE = map { $_ => 1 } qw(sty tex aux log out toc fff ttt svn svx);
+% \end{macrocode}
+
+% Subfunction prototypes:
+% \begin{macrocode}
+sub create_svxfile ($@);
+sub usage;
+% \end{macrocode}
+
+% Check if help was requested:
+% \begin{macrocode}
+if (!@ARGV or grep { $_ eq '--help' or $_ eq '-h' } @ARGV) {
+ usage();
+}
+% \end{macrocode}
+
+% Print identification line like other TeX related programs:
+% \begin{macrocode}
+print STDOUT "This is svn-multi.pl, Version $VERSION-$REV, $DATE\n";
+% \end{macrocode}
+
+% The first argument is taken as the jobname. To be more userfriendly the name
+% can include some standard extension and a path which are stripped.
+% \begin{macrocode}
+my ($jobname, $dir, $suffix) = fileparse(shift @ARGV, qr/\.(tex|ltx|dtx|svn)$/);
+% \end{macrocode}
+% If a directory was specified this program is changing into it because the
+% file paths in the |.aux| file are relative to it.
+% \begin{macrocode}
+if ($dir && $dir ne './') {
+ printf STDOUT "Main directory is '$dir'.\n";
+ chdir($dir);
+}
+% \end{macrocode}
+% \begin{macrocode}
+
+if ($jobname =~ /^-/) {
+ usage();
+}
+my $outfile = "$jobname.svx";
+
+my %external;
+
+% \end{macrocode}
+% Regular expressions to read the |.aux| file:
+% \paragraph{svnexternalpath:} The format is:\\
+% \hspace*{2em}|\@svnexternalpath{{patha}{pathb}{...}{pathd}}|
+% \begin{macrocode}
+my $resvnexternalpath = qr/
+ ^ # at begin of line
+ \s* # allow for spaces
+ \\\@svnexternalpath # the macro name
+ \s*
+ { # begin token group
+ \s*
+ (?: # paths:
+ { # { of first path
+ (.*) # everything else, e.g: 'patha}{pathb}{pathc'
+ } # } of last path
+ | # or nothing
+ )
+ \s*
+ } # end token group
+ \s*
+ $ # end of line
+ /x;
+% \end{macrocode}
+
+% \paragraph{svnexternal:} The format is:\\
+% \hspace*{2em}|\@svnexternal[group name]{{filea}{fileb}{...}{filed}}|
+% \begin{macrocode}
+my $resvnexternal = qr/
+ ^ # at begin of line
+ \s* # allow for spaces
+ \\\@svnexternal # the macro name
+ \s*
+ (?: # optional:
+ \[ # opening [
+ ([^\]]*) # group name (everything until ])
+ \] # closing ]
+ )?
+ \s*
+ { # begin token group
+ ([^}]+) # file name (everything until })
+ } # end token group
+ \s*
+ { # begin token group
+ \s*
+ (?: # paths:
+ { # { of first file
+ (.*) # everything else, e.g: 'filea}{fileb}{filec'
+ } # } of last file
+ | # or nothing
+ )
+ \s*
+ } # end token group
+ \s*
+ $ # end of line
+ /x;
+% \end{macrocode}
+
+% \begin{macrocode}
+if (-e "$jobname.aux" and open( my $svnfh, '<', "$jobname.aux")) {
+ print STDOUT "Reading '$jobname.aux'.\n";
+ while (<$svnfh>) {
+ chomp;
+ if (/$resvnexternalpath/) {
+ push @PATH, ( split /}\s*{/, $1 );
+ }
+ elsif (/$resvnexternal/) {
+ my ($group,$file,$list) = ($1||"",$2,$3||"");
+ $file =~ s/^\.\///;
+ push @{$external{$file}{$group} ||= []}, ( split /}\s*{/, $list );
+ }
+ }
+ close ($svnfh);
+}
+else {
+ warn "No .aux file found for '$jobname'!\n";
+}
+
+# Add TEXINPUTS to path
+push @PATH, map { $_ =~ s/(?<!\/)$/\//; $_ } grep { $_ }
+ split(':', $ENV{'TEXINPUTS'}||"");
+
+my @mainfilepairs;
+my $maintex = "$jobname.tex";
+if (exists $external{$maintex}) {
+ while ( my ($group,$list) = each %{$external{$maintex}} ) {
+ push @mainfilepairs, [ $group, [ @$list ] ];
+ }
+ delete $external{$maintex};
+}
+
+push @mainfilepairs, parse_args(@ARGV);
+create_svxfile("$jobname.svx", @mainfilepairs )
+ if @mainfilepairs;
+
+foreach my $file (keys %external) {
+ my @pairs;
+ my $svxfile = $file;
+ $svxfile =~ s/\.(tex|ltx)$/.svx/;
+ while ( my ($group,$list) = each %{$external{$file}} ) {
+ push @pairs, [ $group, [ @$list ] ];
+ }
+ create_svxfile($svxfile, @pairs);
+}
+% \end{macrocode}
+
+% \subsection{Functions}
+
+% \begin{sub}{parse args}
+% Parses the arguments and builds a list of (group,(files)) pairs.
+% \begin{macrocode}
+sub parse_args {
+ my @args = @_;
+ my $group = '';
+ my @files;
+ my $readfg;
+ my @pairs;
+
+ foreach my $arg (@args) {
+ if ($readfg) {
+ $readfg = 0;
+ $group = $arg;
+ $group =~ s/^["']|["']$//; # '
+ }
+ elsif ($arg =~ /^--group|^-?-fg/) {
+ push @pairs, [ $group, [ @files ] ];
+ @files = ();
+ if ($arg =~ /^--group=(.*)/) {
+ $group = $1;
+ $group =~ s/^["']|["']$//; # '
+ }
+ else {
+ $readfg = 1;
+ }
+ }
+ elsif ($arg =~ /^--fls/) {
+ push @files, read_fls("$jobname.fls");
+ }
+ else {
+ push @files, $arg;
+ }
+ }
+ push @pairs, [ $group, [ @files ] ] if @files;
+ return @pairs;
+}
+% \end{macrocode}
+% \end{sub}
+
+% \begin{sub}{path search}
+% Search all directories in |PATH| to find the given file and return the first
+% own found.
+% \begin{macrocode}
+sub path_search {
+ my $file = shift;
+ $file =~ s/##/#/g;
+ return $file if not $file or -e $file or not @PATH;
+
+ foreach my $dir (@PATH) {
+ if (-e "$dir$file") {
+ return "$dir$file";
+ }
+ }
+
+ return $file;
+}
+% \end{macrocode}
+% \end{sub}
+
+% \begin{sub}{ceate svxfile}
+% Creates the |.svx| file named by the first argument. The second argument is a
+% list of (group name/files) pairs.
+% \begin{macrocode}
+sub create_svxfile ($@) {
+ my ($svxfile, @fgpair) = @_;
+ my $lastgroup;
+ my $fgused = 0;
+ my %seen;
+ return if not @fgpair or not $svxfile;
+
+ open(my $svxfh, '>', $svxfile) or do {
+ warn "ERROR: Could not create SVX file '$svxfile'!\n";
+ return;
+ };
+ print STDOUT "Generating .svx file '$svxfile'.\n";
+ select $svxfh;
+ print "% Generated by svn-multi.pl v$VERSION\n\n";
+
+ while ( my ($group, $files) = @{shift @fgpair||[]}) {
+ no warnings 'uninitialized';
+ if ( (not defined $lastgroup and $group) or ($group ne $lastgroup) ) {
+ print "\\svngroup{$group}\n";
+ }
+ use warnings;
+ if ($group) {
+ $fgused = 1;
+ }
+
+ foreach my $file (@$files) {
+ $file = path_search($file);
+
+ # Only print the file once per group and .svx file
+ next if $seen{$group}{$file};
+ $seen{$group}{$file} = 1;
+
+ open(my $infoh, '-|', "svn info '$file' 2>/dev/null") or next;
+ my %info = map { chomp; split /\s*:\s*/, $_, 2 } <$infoh>;
+ close($infoh);
+ if (not keys %info) {
+ print "% Could not receive keywords for '$file'!\n\n";
+ next;
+ }
+ print "% Keywords for '$file'\n";
+ print svnidlong(\%info);
+ print "\\svnexternalfile";
+ print "[$group]" if $group;
+ print "{$file}\n";
+ print "\n"
+ }
+
+ $lastgroup = $group;
+ }
+ print "\n";
+ close ($svxfh);
+}
+% \end{macrocode}
+% \end{sub}
+
+% \begin{sub}{svnid}
+% Generates \cs{svnid} macro lines. Awaits a hash with the information
+% received from |svn|. The |$| sign is masked to avoid keyword extension by
+% Subversion inside this source file.
+% Additional modules are needed to produce the date format used by |$||Id$|.
+% \begin{macrocode}
+sub svnid {
+ use Date::Parse;
+ use Date::Format;
+ my $href = shift;
+ return "" if (not defined $href->{Name});
+ my $date = time2str("%Y-%m-%d %XZ", str2time($href->{'Last Changed Date'}), 'Z');
+ return <<"EOT";
+\\svnid{${dollar}Id: $href->{Name} $href->{'Last Changed Rev'} $date $href->{'Last Changed Author'} \$}
+EOT
+}
+% \end{macrocode}
+% \end{sub}
+
+% \begin{sub}{svnidlong}
+% Generates \cs{svnidlong} macro lines. Awaits a hash with the information
+% received from |svn|. The |$| sign is masked to avoid keyword extension by
+% Subversion inside this source file.
+% \begin{macrocode}
+sub svnidlong {
+ my $href = shift;
+ return <<"EOT";
+\\svnidlong
+{${dollar}HeadURL: $href->{URL} \$}
+{${dollar}LastChangedDate: $href->{'Last Changed Date'} \$}
+{${dollar}LastChangedRevision: $href->{'Last Changed Rev'} \$}
+{${dollar}LastChangedBy: $href->{'Last Changed Author'} \$}
+EOT
+}
+% \end{macrocode}
+% \end{sub}
+
+% \begin{sub}{read fls}
+% Reads the |.fls| file and looks for |INPUT relativedir/file| lines.
+% The file is ignored if its extension is in the |EXCLUDE| list.
+% \begin{macrocode}
+sub read_fls {
+ my $fls = shift;
+ my %stack;
+ open (my $fh, '<', $fls) or return;
+ while (<$fh>) {
+ chomp;
+ if (/^INPUT ([^\/].*)$/) {
+ my $file = $1;
+ my $ext = substr($file, rindex($file,'.')+1);
+ $stack{$1} = 1 if not exists $EXCLUDE{$ext};
+ }
+ }
+ close($fh);
+ return keys %stack;
+}
+% \end{macrocode}
+% \end{sub}
+
+% \begin{sub}{usage}
+% \hypertarget{usage}{}%
+% Prints usage information.
+% \begin{macrocode}
+sub usage {
+ print STDOUT <<'EOT';
+Usage:
+ svn-multi.pl jobname[.tex] [--fls] [--group|-g <group name>] [input_files] ...
+ ... [--group|-g <group name>] [input_files] ...
+
+Description:
+ This LaTeX helper script collects Subversion keywords from non-(La)TeX files
+ and provides it to the 'svn-multi' package using '.svx' files. It will first
+ scan the file '<jobname>.aux' for files declared by the '\svnextern' macro but
+ also allows to provide additional files including the corresponding groups. The
+ keywords for the additional files will be written in the file '<jobname>.svx'.
+
+Options:
+ jobname[.tex] : The LaTeX `jobname`, i.e. the basename of your main LaTeX file.
+ --group <GN> : Use given group name <GN> for all following files,
+ or -g <GN> including the one read by a '--fls' option, until the next
+ group is specified.
+ --fls : Read list of (additional) files from the file '<jobname>.fls'. This
+ file is produced by LaTeX when run with the '--recorder' option and
+ contains a list of all input and output files used by the LaTeX main
+ file. Only input files with a relative path will be used. A
+ previously selected group will be honoured.
+
+Examples:
+The main LaTeX file here is 'mymainlatexfile.tex'.
+
+ svn-multi.pl mymainlatexfile
+ Creates Subversion keywords for all files declared by '\svnextern' inside
+ the LaTeX code.
+
+ svn-multi.pl mymainlatexfile --group=FLS --fls
+ Creates Subversion keywords for all files declared by '\svnextern' inside
+ the LaTeX code. In addition it does the same for all relative input files
+ mentioned in the .fls file which are placed in the 'FLS' group.
+
+ svn-multi.pl mymainlatexfile a b c --group=B e d f
+ In addition to the '\svnextern' declared files the keywords for the files
+ 'a', 'b' and 'c' will be added without a specific group, i.e. the last group
+ specified in the LaTeX file before the '\svnextern' macro will be used. The
+ keywords for 'e', 'd', 'f' will be part of group 'B'.
+
+ svn-multi.pl mymainlatexfile --group=A a --group=B b --group='' c
+ File 'a' is in group 'A', 'b' is in 'B' and 'c' is not in any group.
+
+Further Information:
+See the svn-multi package manual for more information about this script.
+EOT
+ exit(0);
+}
+% \end{macrocode}
+% \end{sub}
+
+% End of File
+% \begin{macrocode}
+__END__
+% \end{macrocode}
+%
+% \Finale
+% \iffalse
+%</script>
+% \fi
+% ^^A \iffalse vim: ft=perl,sw=2,ts=2
+% ^^A \fi