Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 294 lines (233 sloc) 8.38 KB
#!/usr/bin/env perl
#
# $Id: nofake,v 1.1 2004/05/24 14:51:48 lindig Exp $
#
# Generated from nofake.nw. Do not edit! Edit nofake.nw instead and
# run nofake on it:
# ./nofake -Rnofake > nofake.pl && cp nofake.pl nofake
#
# The manual page is at the end of this file in Perl's
# POD format. You can format it using pod2man(1):
#
# pod2man nofake > nofake.1
# nroff -man nofake.1 | more
#
# This software is in the public domain; for details, see the manual
# page.
use warnings;
sub version {
print <<'EOF';
$Id: nofake,v 1.1 2004/05/24 14:51:48 lindig Exp $
(c) 2002, 2003 Christian Lindig <lindig@eecs.harvard.edu>
NoFake is derived from the public domain NegWeb 1.0.1
http://boswa.com/misc/negweb by Darrell Johnson <darrell@boswa.com>.
EOF
}
$lineformat='#line %L "%F"%N'; #default format for #line directive
$sync=0; #default: do not emit #line directives
$fname=''; #file name of noweb file
$chunk='*'; #default chunk to extract
%chunks=(); #hash table for chunks
sub line_directive {
my ($fname,$line)=@_;
my $ret=$lineformat;
$ret=~s/%F/$fname/g;
$ret=~s/%L/$line/g;
$ret=~s/%N/\n/g;
return "\n$ret";
}
sub read_file {
my ($fname,$sync)=@_;
local *INFILE;
if($fname eq ''){
*INFILE=STDIN;
$fname="Standard Input";
}else{
if(!open(INFILE, '<'.$fname)){
print STDERR "can't open file '$fname'\n";
exit(1);
}
}
my $chunk=''; # name of actual chunk, '' iff outside of chunk
my $line;
for(my $i=1;$line=<INFILE>;$i++) {
if($line =~ /^<<([^<>]+)>>=\s*$/o){
$chunk=$1;
if(!exists $chunks{$chunk}){
$chunks{$chunk}='';
}
if($sync){
$chunks{$chunk}.=line_directive($fname,$i+1);
}
} elsif($chunk ne '') {
#inside <<foo>>= ... @ chunk
if($line=~/^(@|<<[^<>]+>>=\s*)/o){
# reached end of chunk
$chunk='';
}else{
# regular line inside chunk
$chunks{$chunk}.=$line;
}
} # else outside chunk - nothing to do
}
}
%cache=();
%being_extracted=();
sub extract {
my ($chunk)=@_;
if(exists $being_extracted{$chunk} && $being_extracted{$chunk} > 0){
print STDERR
"Code chunk <<$chunk>> is used in its own definition.\n";
exit(1);
}
if(exists $cache{$chunk}){
return $cache{$chunk};
}
if(!exists $chunks{$chunk}){
print STDERR
"Code chunk <<$chunk>> is requested, but doesn't exist.\n";
exit(1);
}
$being_extracted{$chunk}++;
$cache{$chunk}='';
# obtain chunk and process it recursively
foreach my $line (split /\n/, $chunks{$chunk}){
if($line =~/^(.*[^\@]*)<<([^<>@]+)>>(.*)$/o){
my $prefix=$1;
my $postfix=$3;
my $next=$2;
my $indent = length($prefix);
my $i = 0;
# first line from $next is prefixed with $prefix
# following lines are indented by length($prefix)
# $i denotes line counter for lines from $next
$cache{$chunk} .= $prefix;
$cache{$chunk} .=
join("\n", map {$i++; ($i > 1 ? " " x $indent : "") . $_}
split(/\n/,extract($next)));
$cache{$chunk} .= "$postfix\n";
}else{
$line =~ s/\@(<<|>>)/$1/og;
$cache{$chunk}.="$line\n";
}
}
$being_extracted{$chunk}--;
return $cache{$chunk};
}
sub usage {
my $arg = shift @_;
print STDERR <<EOF;
Unknown command line argument "$arg". See the manual page for help
which is also included at the end of this Perl script.
nofake [-Rchunk] [-L[format]] [file]
nofake [-version|-v]
EOF
}
while ($_ = shift(@ARGV)) {
if(/^\-L(.*)/) { $sync=1; if ($1 ne '') {$lineformat=$1;}}
elsif(/^\-R(.+)/) { $chunk=$1 }
elsif(/^\-(v|-version)$/) { version(); exit(0); }
elsif(/^\-filter$/) { shift(@ARGV) } # ignore
elsif(/^(\-.*)$/) { usage($1); exit(1);}
else{$fname=$_}
}
read_file($fname,$sync);
print extract($chunk);
exit(0); # exit successfully
__END__
=head1 NAME
nofake - simple notangle replacement for the Noweb literate programming tool
=head1 SYNOPSIS
B<nofake> [B<-R>I<chunk>] [B<-L>[I<format>]] [I<file>]
B<nofake> [B<-version>|B<-v>]
=head1 DESCRIPTION
Noweb(1) is a literate-programming tool like Knuth's WEB. A noweb file
contains program source code interleaved with documentation. Extracting
the source code for compilation requires notangle(1). To allow source
code to be shipped to users not using noweb(1), B<nofake> offers the
most commonly used functionality of notangle(1) as a simple perl(1)
script. Alas, B<nofake> extracts source code from a file in noweb(1)
syntax: B<nofake> reads I<file> and extracts the code chunke named
I<chunk> to stdout. If no I<file> is provided, B<nofake> reads from
stdin, if no I<chunk> is named, B<nofake> extracts the chunk C<*>.
=head1 OPTIONS
=over 4
=item B<-R>I<chunk>
Extract chunk I<chunk> (recursively) from the noweb file and write it to
stdout. Unlike notangle, only one chunk can be extracted per invocation
of B<nofake>.
=item B<-L>[I<format>]
B<nofake> emits cpp(1)-style C<#line> directives to allow a compiler
emit error messages that refer to I<file> rather than the extracted
source code directly. The optional I<format> allows to provided the
format of the line directive: C<-L'#line %L "%F"%N'>. In I<format> C<%F>
indicates the name of the source file, C<%L> the line number, and C<%N>
a newline. The default C<#line %L "%F"%N> is suitable for C compilers.
=back
=head1 SYNTAX OF NOWEB FILES
The authoritive source for the syntax of noweb files is the noweb(1)
documentation. However, here is an example:
<<hello.c>>=
<<includes>>
int main(int argc, char** argv)
{
<<say hello>>
return 0;
}
<<say hello>>=
printf("Hello World!\n");
@
<<includes>>=
#include <stdio.h> /* for printf */
@
A chunk is defined by C<E<lt>E<lt>chunkE<gt>E<gt>=> and reaches up to
the next definition or a line starting with C<@>. A chunk can
recursivley refer to other chunks: chunk C<hello.c> refers to
C<includes> and C<say hello>. A chunk is referred to by
C<E<lt>E<lt>chunkE<gt>E<gt>>. To use the C<E<lt>E<lt>> and C<E<gt>E<gt>>
character literally in a program, precede them with a C<@>.
=head1 LIMITATIONS
The B<nofake> architecture is much simpler than that of notangle(1) and
therefore many things do not work. In particular:
=over 4
=item *
B<nofake> accepts the B<-R>I<chunk> option only once.
=item *
Line directives (C<#line>) are indented. In the case of cpp(1)-style
line directives this is still ANSI/ISO C conforming but might cause
problems with other directives and older versions of cpp(1).
=item *
Do not use C<@> in chunk names.
=item *
B<nofake> does not accept the B<-filter> I<command> option that
B<notangle> uses to filter chunks before they are emitted.
=item *
A noweb file must not refer to more than one chunk per line. The
following code is I<not> handled correctly by B<nofake> because the
chunk C<*> contains two chunk references in one line.
<<*>>=
<<one>> <<one>>
<<one>>=
one
@
=back
=head1 COPYING
This software is in the public domain.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND COPYRIGHT HOLDER BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
=head1 AUTHOR
Christian Lindig <lindig@eecs.harard.edu>
=head1 SEE ALSO
noweb(1), notangle(1), perl(1), cpp(1)
Norman Ramsey, Literate programming simplified, IEEE Software
11(5):97-105, September 1994.
Jump to Line
Something went wrong with that request. Please try again.