#!/usr/bin/perl -w # # $Id: xtractCode.pl,v 1.38 2003/04/04 15:28:46 robert Exp $ # # Robert Wenner (rwenner@cpan.org) # # History: # 2002-10-09 First working code. Unindent feature. Customizable prefix and # suffix. # 2002-10-25 Allowed adding file contents as prefix and suffix. # 2002-11-07 Duplicate labels may be used. # 2002-11-11 Added introLabel / outroLabel. Made file name prefix and # suffix customizable. # 2002-11-25 Issues warning on unindenting "strange" formatted code. # Allowed config comments in the parsed files. # Implemented --append option. # 2002-11-30 Some refactorings and bug fixes. # 2002-12-07 Added --indentation and --language options and configurable # markers. Allowed defining comments on the fly. # 2003-01-15 Broke code up into sub routines. Added --error option. # Added --blanklines option. # 2003-02-?? Further code refinement into subs. Replaced die with error # calls for better error handling. # 2003-02-12 Added --version option. Added --fail option. # 2003-02-15 Refactored into subs, bundled snippet information in hash # of hashes. Changed intro / outro to be written just in before # exiting. # 2003-02-16 Appended $prefix to intro and outro label files, too. # 2003-02-17 Added more default extensions (thanks to Holger Jakobs). # 2003-02-20 Added missing documentation. Fixed problem with empty intro # or outro files in combination with prefix and suffix. Fixed # problem with missing file name extensions. # 2003-03-08 Added --makedep option. # 2003-03-29 Fixed end of comment detection for xtract markers. # Split --comment option in --commentStart and --commentStop. # # Todo: # - Allow (properly) nested label blocks? # - Allow multiple xtractStart and xtractStop labels in one comment? # - Allow more than one comment per line? # - Allow config file ~/.xtractCode.conf? # - Get some unit tests in place! # - Allow extracting only snippets given on command line? # - Optionally remove all comments from input. (Nested?) # use strict; use Getopt::Long; use Pod::Usage; use Text::ParseWords; # ----- Configure defaults here as needed; see POD for details. ----- my $introText = ""; # "% Generated by $me, do not edit.\n"; my $outroText = ""; # "% EOF\n"; my $introFile = ""; my $outroFile = ""; my $introLabel = ""; my $outroLabel = ""; my $unindent = ""; my $converttabs = ""; my $verbose = ""; my $warningsAsErrors = ""; my $prefix = ""; my $suffix = ""; my $allowDuplicates = ""; my $append = ""; my $indentation = ""; my $language = ""; my $startMarker = "xtractStart"; my $endMarker = "xtractStop"; my $configMarker = "xtractConfig"; my $blankLines = "yes"; my $failOnError = ""; my $debug = ""; my $depFile = ""; # ----- No configuration should be required below this line. ----- # Program identification, see also POD on CPAN classification. my $me = "xtractCode"; my $VERSION = 0.75; # Comments (start, end) pairs to accept in programming languages (language # is determined by filename extension). Make sure to quote perl regexp # characters. Some language style comments are extracted to extra lists # to avoid duplication. my @cComments = ("/\\\*", "\\\*/"); my @cppComments = ("//", "\n", @cComments); my @javaComments = ("/\\\*\\\*", "\\\*/", @cppComments); my @shellComments = ("#", "\n"); my @vbComments = ("'", "\n", "(?i)REM", "\n"); my @texComments = ("%", "\n"); my @xmlComments = (""); my %comment = ( "java" => [ @javaComments ], "aj" => [ @javaComments ], "cpp" => [ @cppComments ], "cxx" => [ @cppComments ], "C" => [ @cppComments ], "hxx" => [ @cppComments ], "hpp" => [ @cppComments ], "c" => [ @cComments ], "h" => [ @cComments ], "pl" => [ @shellComments ], "tcl" => [ @shellComments ], "py" => [ @shellComments ], "bash" => [ @shellComments ], "sh" => [ @shellComments ], "vb" => [ @vbComments ], "vba" => [ @vbComments ], "bas" => [ @vbComments ], "tex" => [ @texComments ], "latex" => [ @texComments ], "html" => [ @xmlComments ], "shtml" => [ @xmlComments ], "htm" => [ @xmlComments ], "xhtml" => [ @xmlComments ], "xml" => [ @xmlComments ], "xslt" => [ @xmlComments ] ); # # Parse command line arguments. # my $help = 0; my %options = ( "a|append!" => \$append, "b|blanklines!" => \$blankLines, "commentStart=s" => \&setCommentStart, "commentStop=s" => \&setCommentStop, "d|duplicates!" => \$allowDuplicates, "debug!" => \$debug, "e|errors!" => \$warningsAsErrors, "f|failonerror!" => \$failOnError, "it|introtext=s" => \&setIntroText, "ot|outrotext=s" => \&setOutroText, "if|introfile=s" => \&setIntroFile, "of|outrofile=s" => \&setOutroFile, "il|introlabel=s" => \&setIntroLabel, "ol|outrolabel=s" => \&setOutroLabel, "u|unindent!" => \$unindent, "i|indentation=s" => \&setIndentation, "m|makedep=s" => \$depFile, "v|verbose!" => \$verbose, "version" => \&showVersion, "s|suffix=s" => \$suffix, "p|prefix=s" => \$prefix, "l|language=s" => \$language, "sm|startmarker=s" => \$startMarker, "em|endmarker=s" => \$endMarker, "cm|configmarker=s" => \$configMarker, "t|tabs=s" => \$converttabs, "h|help|?" => \$help); GetOptions(%options) or pod2usage(-verbose => 0); pod2usage(-msg => "$me $VERSION\n", -verbose => 2) if $help; # # Global variables # my $returnCode = 0; my $xtract = ""; my %snippet; my %dependency; # # Prototypes # sub xtractFrom($); sub writeIntro(); sub writeOutro(); sub writeDependencies(); sub comment($); # # Main # while (my $src = shift) { xtractFrom($src); } writeIntro(); writeOutro(); writeDependencies(); comment("$returnCode errors."); exit $returnCode; # # Extraction code subs # sub xtractFrom($) { my $src = shift; comment("Processing $src...\n"); my $ext = getLanguage($src); return if ($ext eq ""); open SRC, "<$src" or error($src, $., "Can't read: $!"); LINE: while () { for (my $i = 0; $i < scalar(@{$comment{$ext}}); $i += 2) { my ($commentStart, my $commentStop) = @{$comment{$ext}}[$i, $i+1]; next LINE if (handleConfig($src, $_, $commentStart, $commentStop)); next LINE if (handleEnd($src, $_, $commentStart, $commentStop)); next LINE if (handleBegin($src, $_, $commentStart, $commentStop)); } writeLine($src, $_) if ($xtract); } error($src, $., "End of file while processing $xtract (started on $snippet{$xtract}{fromFile}:$snippet{$xtract}{startLine}).") if ($xtract); close SRC or error($src, $., "Can not close file after extracting: $!"); } sub getLanguage($) { my $src = shift; my $ext = $1 if ($src =~ /\.(.*)$/); $ext = $language if ($language); if (! $ext) { error($src, $., "No extension, can not determine source language."); return ""; } error($src, $., "Unrecognized source language $ext.") unless ($comment{$ext}); return $ext; } sub handleConfig($$$$) { my ($src, $line, $commentStart, $commentStop) = @_; if ($line =~ /$commentStart\s*$configMarker\s+(.*)($commentStop)?/) { comment("$src:$.: re-configuring."); my $cfgline = $1; chomp($cfgline); $cfgline =~ s/$commentStop.*$//; my @oldArgs = @ARGV; @ARGV = (); my $strange = 0; $cfgline =~ s/\s/ /g; foreach my $arg(quotewords(" ", 1, $cfgline)) { @ARGV = (@ARGV, $arg) if ($arg); $strange ++ if ($arg && $arg =~ /^\W+$/); } GetOptions(%options) or warning($src, $., "Warning: bad $configMarker; ignored some option(s)."); comment("New files: @ARGV\n") if (scalar(@ARGV) > 0); comment("($strange strange file name(s) -- did you use quotes correctly?)") if ($strange); @ARGV = (@oldArgs, @ARGV); return 1; } return 0; } sub handleBegin($$$$) { my ($src, $line, $commentStart, $commentStop) = @_; if ($line =~ /$commentStart\s*$startMarker\s+(\S+)\s*(.*?)($commentStop)?/) { my $extra = $2; if (!defined($1) || $1 eq "") { error($src, $., "No code snippet name found."); return 1; } if ($xtract) { error($src, $., "Found beginning of \"$1\" while extracting \"$xtract\" started on $snippet{$xtract}{fromFile}:$snippet{$xtract}{startLine}."); return 1; } if ($extra && $extra =~ /\S/) { warning($src, $., "Extra text \"$extra\" behind snippet name ignored."); } $indentation = "none yet" if ($indentation eq ""); $xtract = $1; my $file = "$prefix$xtract$suffix"; if ($snippet{$xtract}) { if ($allowDuplicates) { comment("Appending $xtract to $file from $src:$.."); if ($depFile ne "") { open CODE, ">>$file" or error($src, $., "Can not append to $file: $!"); } } else { error($src, $., "Duplicate label \"$xtract\" (first occurred in $snippet{$xtract}{fromFile}:$snippet{$xtract}{startLine})"); $xtract = ""; return 1; } } else { comment("Extracting $xtract to $file from $src."); my $openMode = $append ? ">>$file" : ">$file"; my $msg = $append ? "append to" : "write"; if ($depFile eq "") { if (!(open CODE, $openMode)) { error($src, $., "Can not $msg $file: $!"); $xtract = ""; return 1; } } } $snippet{$xtract}{"fromFile"} = $src; $snippet{$xtract}{"toFile"} = $file; $snippet{$xtract}{"startLine"} = $.; $snippet{$xtract}{"introText"} = $introText; $snippet{$xtract}{"introLabel"} = $introLabel; if ($introFile) { $snippet{$xtract}{"introFile"} = "$prefix$introFile$suffix"; } else { $snippet{$xtract}{"introFile"} = ""; } $snippet{$xtract}{"outroText"} = $outroText; $snippet{$xtract}{"outroLabel"} = $outroLabel; if ($outroFile) { $snippet{$xtract}{"outroFile"} = "$prefix$outroFile$suffix"; } else { $snippet{$xtract}{"outroFile"} = ""; } dumpSnippet($xtract) if ($debug); $dependency{$xtract} .= "$src "; return 1; } return 0; } sub handleEnd($$$$) { my ($src, $line, $commentStart, $commentStop) = @_; if ($line =~ /$commentStart\s*$endMarker\s+(\S+)\s+(.*?)($commentStop)?/) { if ($xtract eq "") { error($src, $., "End marker found before beginning."); return 1; } if ($xtract ne $1) { error($src, $., "Found end marker for \"$1\" while extracting \"$xtract\" started on $snippet{$xtract}{fromFile}:$snippet{$xtract}{startLine}."); return 1; } if ($depFile eq "") { close CODE or error($snippet{$xtract}{"fromFile"}, $., "Can not close file: $!"); } $xtract = ""; return 1; } return 0; } sub writeLine($$) { my ($src, $line) = @_; if (!(!$blankLines && $line =~ /^\s*$/)) { $line =~ s/\t/$converttabs/g if ($converttabs); ($indentation) = $line =~ /(^\s*)/ if ($indentation eq "none yet"); if ($unindent && !($line =~ /^$indentation.*/) && !($line =~ /^\s*$/)) { warning($src, $., "Expected more indentation; I may have messed up your extracted code by unindenting."); } $line =~ s/^$indentation// if ($unindent); print CODE $line if ($depFile eq ""); } } # # Intro / outro writing # sub writeIntro() { return if ($depFile ne ""); foreach my $xtract (keys %snippet) { my $intro = ""; $intro .= grabFile($xtract, $snippet{$xtract}{"introFile"}, "intro file"); $intro .= $snippet{$xtract}{"introText"}; $intro .= grabFile($xtract, $snippet{$xtract}{"introLabel"}, "intro label file"); my $file = $snippet{$xtract}{"toFile"}; my $snippetBody = grabFile($xtract, $file, "generated snippet"); if (! open SNIPPET, ">$file") { error($xtract, $., "Can not insert intro: $!"); next; } print SNIPPET "$intro$snippetBody"; close SNIPPET or error($xtract, $., "Can not close $file after writing intro: $!"); } } sub writeOutro() { return if ($depFile ne ""); foreach my $xtract (keys %snippet) { my $outro = ""; $outro .= grabFile($xtract, $snippet{$xtract}{"outroLabel"}, "outro label file"); $outro .= $snippet{$xtract}{"outroText"}; $outro .= grabFile($xtract, $snippet{$xtract}{"outroFile"}, "outro file"); my $file = $snippet{$xtract}{"toFile"}; if (! open SNIPPET, ">>$file") { error($xtract, $., "Can not append outro: $!"); next; } print SNIPPET "$outro"; close SNIPPET or error($xtract, $., "Can not close $file after appending outro: $!"); } } sub writeDependencies() { return if ($depFile eq ""); if (! open DEPFILE, ">$depFile") { error($depFile, $., "Can not create $depFile: $!"); return 0; } print DEPFILE "# Generated dependency file, do not edit.\n\n"; print DEPFILE "GENERATEDSNIPPETS= \\\n"; foreach my $rm (keys %dependency) { print DEPFILE " $rm \\\n"; } print DEPFILE "\n"; foreach my $dep (keys %dependency) { print DEPFILE "$dep: $dependency{$dep}\n\t$0 "; print DEPFILE "--duplicates " if ($allowDuplicates); print DEPFILE "\$(XTRACTOPTS) \$?\n\n"; } close DEPFILE or error($depFile, $., "Can not close $depFile: $!"); } sub grabFile($$$) { my ($xtract, $file, $infoText) = @_; return "" if ($file eq ""); if (!(open CONTENTS, "<$file")) { error($xtract, $., "Can not read $infoText $file: $!"); return ""; } undef $/; my $contents .= ; close CONTENTS or error($xtract, $., "Can not close $infoText $file: $!"); return $contents; } # # Command line argument handling subs # sub setTextOrEmpty($$) { my ($what, $arg) = @_; $arg =~ s/^"//; $arg =~ s/"$//; comment(" Setting $what to \"$arg\""); return $arg; } sub setIntroFile { $introFile = setTextOrEmpty("introFile", $_[1]); } sub setOutroFile { $outroFile = setTextOrEmpty("outroFile", $_[1]); } sub setIntroLabel { $introLabel = setTextOrEmpty("introLabel", $_[1]); } sub setOutroLabel { $outroLabel = setTextOrEmpty("outroLabel", $_[1]); } sub setIntroText { $introText = setTextOrEmpty("introText", $_[1]); } sub setOutroText { $outroText = setTextOrEmpty("outroText", $_[1]); } sub setCommentStart { error("", $., "Need to know the language before defining comments.") unless ($language); comment(" Adding possible comment start $_[1] for $language"); push @{$comment{$language}}, $_[1]; } sub setCommentStop { error("", $., "Need to know the language before defining comments.") unless ($language); my $count = scalar(@{$comment{$language}}); if ($count % 2 == 0) { error("", $., "Need to have comment start before comment stop."); return; } my $start = ${$comment{$language}}[$count - 1]; ${$comment{$language}}[$count] = $_[1]; comment(" Completing possible comment $start with $_[1] for $language"); } sub setIndentation { $indentation = setTextOrEmpty("indentation", $_[1]); } sub showVersion { print "$me $VERSION\n"; print '$Id: xtractCode.pl,v 1.38 2003/04/04 15:28:46 robert Exp $'. "\n"; exit 0; } # # Output helper subs # sub error($$$) { my ($src, $line, $msg) = @_; print STDERR "$src:$line Error: $msg\n"; $returnCode ++; exit $returnCode if ($failOnError); } sub warning($$$) { my ($src, $line, $msg) = @_; print STDERR "$src:$line Warning: $msg\n"; $returnCode ++ if ($warningsAsErrors); exit $returnCode if ($failOnError); } sub comment($) { print STDERR "$_[0]\n" if ($verbose); } sub dumpSnippet($) { my $what = shift; print "\nDumping \"$what\":\n"; foreach my $key qw(fromFile toFile startLine introText introLabel introFile outroText outroLabel outroText) { print STDERR " $key: \"$snippet{$what}{$key}\"\n"; } } # # Documentation # __END__ =head1 NAME xtractCode - Extract code snippets to files. =head1 SYNOPSIS xtractCode.pl [options] [file...] Options: -a, --append Open all files for appending. -b, --blanklines Skip blank lines. --commentStart Define comment start. --commentStop Define comment stop. -cm, --configmarker Set config marker. -d --duplicates Allow duplicate labels. --debug Display debugging information. -em, --endmarker Set end marker. -e, --errors Warnings as errors. -f, --failonerror Stop at first error. -h, --help Show this help. -i, --indentation Force indentation width. -if, --introfile Obtain intro text from file. -il, --introlabel Obtain intro text from label. -it, --introtext Set intro text. -l, --language Force language (extension). -m, --makedep Make dependencies. -of, --outrofile Obtain outro text from file. -ol, --outrolabel Obtain outro text from label. -ot, --outrotext Set outro text. -p, --prefix Set file name prefix. -s, --suffix Set file name suffix. -sm, --startmarker Set start marker. -t, --tabs Convert tabs. -u, --unindent Unindent code. -v, --verbose Verbose messages. --version Print version and exit. =head1 DESCRIPTION xtractCode.pl extracts code snippets from source code. This is used for \including source code in LaTeX, the extracted code does not need to be a complete program (or even compilable). By using this approach the code can be compiled as one, but be presented in parts. If used within a Makefile the code snippets in the text are always up to date and correct (or at least compilable). To use xtractCode.pl mark your source code with special comments, the startMarker and the endMarker. Everything between these markers will be copied to a new file. The files name is expected right after the markers. Example: Your Java source code in F looks like this: // xtraxtStart ClassStart import some.package; class SomeClass { int someMember; // xtractStop ClassStart // xtractConfig --introlabel=ClassStart --outrolabel=ClassEnd // xtractStart functionOne public void theFunction(int theArgument) { // whatever } // xtractStop functionOne // xtractStart functionTwo public void theOtherFunction() { // whatever } // xtractStop functionTwo // xtractConfig --introlabel="" --outrolabel="" // xtractStart ClassEnd } // xtractStop ClassEnd Then xtractCode.pl SomeClass.java will create (or overwrite) the files F, F, F, and F. Both F and F will have the import statements and the class definition as well as the closing brace, since these are extracted to files that are used as intro and outro labels. The labels are set to empty just in front of the outro label to avoid having intro and outro appended to the outro label as well. xtractCode.pl is configured via command line arguments. These arguments may also be used in the source code files parsed. A comment xtractConfig grabs the trailing arguments and uses them as if they were given on the command line, expect these 'in file' config only work from the point they are encountered (but not only on the current file). Or, to put it the other way 'round: options given on the command line are considered to be given before the file starts. Note that options remain set when the end of the file is reached, i.e. if you process more than one file you may want to reset certain options. Again an example for Java: class SomeOtherClass { // xtractConfig --verbose // turn on verbose mode // ... // xtractConfig --noverbose // this turns verbose off again } To have xtractCode recognize markers these must follow the comment indicator (whitespaces are ignored). Thus, these comments are recognized as xtractCode markers (in Java files): // xtractStart thisIsOk /* xtactStop thisIsOk */ // xtractConfig --verbose /* xtractStart someCode */ For the above reasons the following comments are not recognized as xtractCode markers (example for Java): // ... xtractStart NotRecognizedDueToTextInFrontOfxtractStart /* xtractStart MultiLineOnlyWorksWithFirstLine */ // xtractConfig -v xtractStart EatenByConfigMarker /* xtractStart noSpaceBeforeClosingComment*/ xtractCode program returns 0 on success or the number of errors found. =head1 OPTIONS =over 8 =item B<-a> =item B<--append> =item B<--noappend> Appends to snippet files, i.e. won't overwrite existing files. If the file does not exist, it will be created, otherwise appended. This is useful if you do not want to allow duplicate labels but merge snippets from multiple source files, as you can start the first run without and the later ones with the append option. If used with intro{File|Label|Text} or outro{File|Label|Text} all snippets will be appended and after that the intro and outro settings from the last snippet processed will be used. =item B<-b> =item B<--blanklines> =item B<--noblanklines> Keep or skip blank lines from snippets. By default, blank lines are copied to the snippets. =item B<--commentStart> text Defines text to be used as comment introduction (in addition to those defined by default or previously defined comments). The --language must be set before. Prefix the comment with "(?i)" for a case insensitive comment start. =item B<--commentStop> text Defines text to be used to close the last defined comment start. This option must not be used without the --commentStart before. Use "\n" to indicate comments terminated by the end of the line. Prefix the comment stop with "(?i)" for case-insensitivity. =item B<-cm> text =item B<--configmarker> text Set the configuration marker to the given text (default is xtractConfig). =item B<-d> =item B<--duplicates> =item B<--noduplicates> Allows or disallows duplicate labels. Usually a code snippet name may occur only once. If this option is given a duplicate name will not be considered an error but further snippets will be appended to the earlier ones. Label names are considered the same if they will / would get written to the same file. That is, changing the file name prefix or suffix does have an impact on labels. Note that introFile, introText, and introLabel as well as outroFile, outroText, and outroLabel are determined for the first snippet found. =item B<--debug> =item B<--nodebug> Switches whether to display debugging information. Currently the snippet information is dumped when starting a new snippet. =item B<-e> =item B<--errors> =item B<--noerrors> Tread warnings as errors, i.e. warnings result in a non-zero exit status. Useful for signaling errors to calling programs like make. The negation only treads warnings as non-critical, errors are always reported as such. =item B<-em> text =item B<--endmarker> text Set the end marker to text (default is xtractStop). =item B<-f> =item B<--failonerror> =item B<--nofailonerror> If set xtractCode will stop at the first error encountered returning a non-zero exit code. If used with --errors a warning will abort extraction. =item B<-h> =item B<--help> Shows this help. =item B<--i> =item B<--indentation> text Force indentation text to given text. This option only has an effect if the --unindent option is used. xtractCode will unindent all snippets by the ammount of whitespace found on the first line of the snippet. This guessing can be prevented by giving (forcing) the indentation width. Place blanks in double quotes to prevent the shell from discarding them. Make sure to use blanks only since tab conversion will be done before unindenting. =item B<-if> filename =item B<--introfile> filename Obtain the intro text from the given file. This option should be used for longer intro texts like some LaTeX commands or a copyright notice or comment. If more than one of --introlabel, --introfile, and --introtext are used these are written to the snippet file in the order file, text, label. =item B<-il> labelname =item B<--introlabel> labelname Obtain intro text from given label. The --introlabel option is useful to provide working example code snippets without having to duplicate code, for example you can label the class delcaration and import statements as introlabel and the final class closing brace as outro label. This gets you a compilable program (the whole source code file) and a number of code snippets (all as well working) without the need for ugly names like CodeVariant123. [In Java the compiler insists on a class being named as the file and if you show different stages of the program in development you can easily run out of sensible names.] There may be more than one introlabel in a source file. Each intro label is used until it is redefined. An introlabel can be undefined by setting it to "". If more than one of --introlabel, --introfile, and --introtext are used these are written to the snippet file in the order file, text, label. =item B<-it> text =item B<--introtext> text Writes the given intro text in the beginning of each file. This may be a short warning to not edit the generated file or a comment to the reader like "// shortened for brevity", for example. Perl commands are allowed. Include a \n for a newline. If more than one of --introlabel, --introfile, and --introtext are used these are written to the snippet file in the order file, text, label. =item B<-l> extension =item B<--language> extension Force the given language instead of determining it from the file extension. The given extension must be an extension known to xtractCode, e.g. java or pl (without a leading dot). Using this option snippets may be extracted from files wihout an extension (e.g. Makefiles) by forcing the language to a known language with the same comment conventions (e.g. sh for Makefiles). =item B<-of> filename =item B<--outrofile> filename Obtain the outro text from the given file, as in the --introfile option. If more than one of --outrolabel, --outrofile, and --outrotext are used these are written to the snippet file in the order label, text, file. =item B<-ol> labelname =item B<--outrolabel> labelname Obtain the outro text from the given label, as in the --introlabel option. An outro label is used for all snippets after the outrolabel option was used. An outro label can be undefined by setting it to "". If more than one of --outrolabel, --outrofile, and --outrotext are used these are written to the snippet file in the order label, text, file. =item B<-ot> text =item B<--outrotext> text Writes the given text at the end of each file generated. See the introtext option. If more than one of --outrolabel, --outrofile, and --outrotext are used these are written to the snippet file in the order label, text, file. =item B<-m> filename =item B<--makedep> filename Make / gather dependencies and write them to given file (which can be included in Makefiles). xtractCode will also generate a special target GENERATEDSNIPPETS to allow a) defining dependencies on all snippets (if not done automatically) and b) removing the extracted snippets easily in a make clean. xtractCode will also generate a rule to rebuild the dependencies automatically, but this may be supported by GNU make only. Note that this option does not generate the snippets as usual, it just gathers dependency information. It may still encounter errors, so you may want to give the --append option if you gather snippets from multiple files together. Take care not to forget to give a filename for --makedep, if you miss it and pass on the files to check the first of these will be overwritten! =item B<-p> text =item B<--prefix> text Set a prefix to use in the generated snippet file names. The prefix string is used as a first part to the file name. Useful for putting all extracted snipptes in a special directory to keep the overview of what is where. (Do not forget a trailing / or \ on the prefix.) =item B<-s> text =item B<--suffix> text Set a suffix for the generated snippet file names. This suffix is appended to the generated file name. Useful if other programs requires some suffix on the files they work with. =item B<-sm> text =item B<--startmarker> text Set the start marker to text. Useful if you don't want the default xtractStart. =item B<-t> replacement =item B<--tabs> replacement Converts tabs in source code (usually to spaces). Make sure to include the replacement text in quotes if it contains special characters like spaces to prevent the shell from discarding or interpreting them. This holds also true for in-file configuration. =item B<-u> =item B<--unindent> =item B<--nounindent> Unindent the code snippets, i.e., when writing them remove an equal amount of white space in front of each line. May be turned off with --nounindent (which is the default behaviour). =item B<-v> =item B<--verbose> =item B<--noverbose> Produce verbose output, i.e., a message for each snippet processed. May be used as --noverbose to suppress these messages. =item B<--version> Print version information and exit sucessfully. =back =head1 TROUBLESHOOTING To set argument values to empty (e.g. to stop using an input label) use empty double quotes like this: // xtractConfig --introlabel="" To localize problems use the --verbose option and call xtractCode with only one file at any given time. The --debug option will dump all data it has for a snippet when xtractCode starts working on that snippet. =head1 RESTRICTIONS There may only be one marker on one line. Everything after the first marker will be ignored. If the first marker is xtractConfig all other text on that line will be treated as settings. Marker labels may not include characters that have a special meaning to the shell, like quotes, the asterisk, question mark, and the like. Path names are allowed, though. White space are not allowed (not even quoted), even if the OS allows them. The programming language of the source files is determined from the file extension. Make sure your files follow certain Unix naming conventions or use the --language option to force the language mode. All labels are case sensitive, even if you use DOS which does not discriminate case in file names. =head1 AUTHOR Robert Wenner (rwenner@cpan.org) xtractCode is published under the GNU General Public License 2.0 which can be found at the GNU website at http://www.fsf.org/licenses/gpl.txt The latest version of xtractCode is avaliable from CPAN at http://www.cpan.org/ =head1 README Extracts code snippets from source code for presenting code in parts, e.g., when printing code snippets with LaTeX. See POD (xtractCode.pl --help) for details. This an alpha version -- use on your own risk! =head1 PREREQUISITES This script requires C, C and C. =pod OSNAMES any =pod SCRIPT CATEGORIES Educational/ComputerScience =head1 SEE The listings package for typesetting source code in Latex, available from http://www.ctan.org/tex-archive/macros/latex/contrib/supported/listings/ =cut