Author: amc
Date: Sat Aug 4 16:54:00 2012
New Revision: 1369371
URL: http://svn.apache.org/viewvc?rev=1369371&view=rev
Log:
Doxygen linkage - alpha version
Added:
trafficserver/site/trunk/lib/DoxygenSymbol.pm (with props)
trafficserver/site/trunk/lib/WikiVar.pm
trafficserver/site/trunk/lib/doxy-link.pm
trafficserver/site/trunk/lib/doxy-sym-generate.pl (with props)
Modified:
trafficserver/site/trunk/content/docs/trunk/sdk/index.en.mdtext
trafficserver/site/trunk/content/docs/trunk/sdk/io-guide/net-vconnections.en.mdtext
trafficserver/site/trunk/lib/view.pm
Modified: trafficserver/site/trunk/content/docs/trunk/sdk/index.en.mdtext
URL:
http://svn.apache.org/viewvc/trafficserver/site/trunk/content/docs/trunk/sdk/index.en.mdtext?rev=1369371&r1=1369370&r2=1369371&view=diff
==============================================================================
--- trafficserver/site/trunk/content/docs/trunk/sdk/index.en.mdtext (original)
+++ trafficserver/site/trunk/content/docs/trunk/sdk/index.en.mdtext Sat Aug 4
16:54:00 2012
@@ -35,3 +35,4 @@ sections may refer to functionality that
If you find any such issues, you may want to submit a [bug or a
patch](https://issues.apache.org/jira/secure/CreateIssue!default.jspa?pid=12310963).
Or find out how to [find bugs](), [create useful bug reports]() or
[patches]().
+
Modified:
trafficserver/site/trunk/content/docs/trunk/sdk/io-guide/net-vconnections.en.mdtext
URL:
http://svn.apache.org/viewvc/trafficserver/site/trunk/content/docs/trunk/sdk/io-guide/net-vconnections.en.mdtext?rev=1369371&r1=1369370&r2=1369371&view=diff
==============================================================================
---
trafficserver/site/trunk/content/docs/trunk/sdk/io-guide/net-vconnections.en.mdtext
(original)
+++
trafficserver/site/trunk/content/docs/trunk/sdk/io-guide/net-vconnections.en.mdtext
Sat Aug 4 16:54:00 2012
@@ -25,7 +25,7 @@ about the Traffic Server abstraction for
The netvconnection functions are listed below:
-* [TSNetAccept](link/to/doxygen)
-* [TSNetConnect](link/to/doxygen)
+* [dox 'TSNetAccept'] in [dox "TSNetAccept" :src_file]
+* [dox %TSNetConnect%] in [dox <TSNetConnect> :src_file]
Added: trafficserver/site/trunk/lib/DoxygenSymbol.pm
URL:
http://svn.apache.org/viewvc/trafficserver/site/trunk/lib/DoxygenSymbol.pm?rev=1369371&view=auto
==============================================================================
--- trafficserver/site/trunk/lib/DoxygenSymbol.pm (added)
+++ trafficserver/site/trunk/lib/DoxygenSymbol.pm Sat Aug 4 16:54:00 2012
@@ -0,0 +1,21 @@
+use Class::Struct DoxygenSymbol =>
+ [ name => '$' # symbol name
+ , id => '$' # Doxygen assigned ID
+ , text => '$' # Descriptive text
+ , src_idx => '$' # index of source file in global array
+ , arg_text => '$' # argument signature text, if any
+ ]
+;
+
+package doxy;
+
+sub unmangle_file_name {
+ my $file = shift;
+ $file =~ s/[.]html$//;
+ $file =~ s/_1/:/g;
+ $file =~ s/_8/./g;
+ $file =~ s/__/_/g;
+ return $file;
+}
+
+1;
\ No newline at end of file
Propchange: trafficserver/site/trunk/lib/DoxygenSymbol.pm
------------------------------------------------------------------------------
svn:executable = *
Added: trafficserver/site/trunk/lib/WikiVar.pm
URL:
http://svn.apache.org/viewvc/trafficserver/site/trunk/lib/WikiVar.pm?rev=1369371&view=auto
==============================================================================
--- trafficserver/site/trunk/lib/WikiVar.pm (added)
+++ trafficserver/site/trunk/lib/WikiVar.pm Sat Aug 4 16:54:00 2012
@@ -0,0 +1,1026 @@
+#
+# WikiVar - A class for doing Wiki style variable processing on text.
+# by Alan M. Carroll
+# http://thought-mesh.net
+#
+# Version 1.2.1
+# 04 Dec 2008
+#
+# See the readme or POD for details, installation instructions, and
+# license information.
+#
+# Copyright (c) 2008-2010, Network Geographics, Inc.
+#
+# -----------------------------------------------------------------------------
+use strict;
+# -----------------------------------------------------------------------------
+package Text::WikiVar::CodeRef;
+# This is a specialized class for handling references to subroutines.
+# Bad things happen with AUTOLOAD if we try to capture a CODE reference before
+# the symbol is defined. As a result, we need to pass in an object that has
+# the name and can cache a CODE pointer so that we can lazy eval the CODE
+# reference and potentially pull in the supporting package to avoid AUTOLOAD
+# entirely.
+
+# Two members, the fully qualified name and the CODE reference
+use constant NAME_IDX => 0;
+use constant CODE_IDX => 1;
+
+# First argument is fully qualified name.
+# Optional second is a CODE pointer. This is useful for closures
+sub new {
+ bless [ $_[1], $_[2]], $_[0];
+}
+
+sub name {
+ my ($self, $value) = @_;
+ return defined($value) ? ($self->[NAME_IDX] = $value) : $_[0]->[NAME_IDX];
+}
+
+# Get a CODE pointer from the CodeRef.
+# Returns a CODE object if it found the subroutine, or a string with
+# an error condition if not.
+sub getCode {
+ my ($self) = @_;
+ my $status;
+
+ if (not $self->[CODE_IDX]) { # no cached pointer
+ no strict 'refs';
+ # see if it's there already
+ my $name = $self->[NAME_IDX];
+ $self->[CODE_IDX] = *{$name}{CODE};
+ if (not $self->[CODE_IDX]) {
+ # not there, try to bring in the package
+ $self->[NAME_IDX] =~ m!(.*)::(?:[^:]+)$!o;
+ my $p = $1; # package name
+ eval "require $p;";
+ if ($@) {
+ $status = 'Defun Error: Failed to load package "' . $p
+ . '" for subroutine "' . $name
+ . '" because "' . $@ . '"';
+ } else {
+ $self->[CODE_IDX] = *{$name}{CODE};
+ if (not $self->[CODE_IDX]) {
+ $status = 'Defun Error: Undefined subroutine "'.$name.'"';
+ }
+ }
+ }
+ }
+ return $status ? $status : $self->[CODE_IDX];
+}
+# -----------------------------------------------------------------------------
+package Text::WikiVar::Arguments;
+# Struct for holding the arguments to a WikiVar function.
+# It can be used as an array reference to access required arguments, with
+# argv[0] being the WikiWord and argv[1]..argv[n] the arguments supplied in
+# the text. argc() returns the number of positional arguments.
+# The structure can be dereferenced as a hash to access named and keyword
+# arguments. Keyword arguments always have a value of '1' if present, undefined
+# if not.
+#
+# Funky implementation notes
+# We use an array as the base implementation type but we can't use that
+# directly because we want to override subscripting for clients. The actual
+# blessed object is a reference to a reference to the array payload. We can
+# then use scalar dereference in methods to get to the array payload,
+# bypassing the subscript overload.
+
+# Class array indices
+use constant POSITIONAL => 0; # Positional arguments
+use constant NAMED => 1; # Named and keyword arguments
+use constant REQUIRED_ARGS => 2; # Arguments 1..N only as an array (cache)
+use constant SUPPLIED_ARGS => 3; # All supplied arguments as an array (cache)
+
+use overload '%{}' => sub { return ${$_[0]}->[NAMED]; },
+ '@{}' => sub { return ${$_[0]}->[POSITIONAL]; }
+ ;
+
+sub new {
+ my $class = shift;
+ $class = ref($class) || $class; # force to string (name of class)
+ my ($word, $required, $named) = @_;
+ my $payload = [ [ $word, @$required ] , $named ];
+ my $self = \$payload;
+ bless $self, $class;
+ my $debug = ref $self;
+ my $debug2 = ref $$self;
+ return $self;
+}
+
+# Required argument value
+sub argv {
+ my ($self, $n) = @_;
+ return $self->[$n];
+}
+
+# Number of positional arguments
+sub argc { return scalar ${$_[0]}->[POSITIONAL]; }
+
+# Value for named argument.
+sub value {
+ my ($self, $name) = @_;
+ return $self->{$name};
+}
+
+# WikiWord invoked.
+sub word { return $_[0]->[0]; }
+
+# For each name in the arguments, force that named argument (if present)
+# to be an array.
+sub force_array {
+ my $payload = ${shift()};
+ my $args = $payload->[NAMED];
+ for my $key (@_) {
+ $args->{$key} = [$args->{$key}] if exists $args->{$key} and ref
$args->{$key} ne 'ARRAY';
+ }
+}
+
+# Return a list of the required arguments without the WikiWord.
+sub required_args {
+ my $payload = ${shift()};
+ if (not defined $payload->[REQUIRED_ARGS]) {
+ # fault in the positional args less arg[0]
+ my $tmp = $payload->[POSITIONAL];
+ shift @$tmp;
+ $payload->[REQUIRED_ARGS] = $tmp;
+ }
+ return $payload->[REQUIRED_ARGS];
+}
+# -----------------------------------------------------------------------------
+package Text::WikiVar;
+our $VERSION = "1.2.3";
+
+use constant TRUE => 1;
+use constant FALSE => 0;
+
+# A bit ugly, but Class::Struct, fields, and Class::Struct::Fields don't do
what
+# I really need done, which is default values.
+
+BEGIN {
+ # Field for a WikiVar instance.
+ our %_FIELDS = ( DELIMITER => { default => '$' } # Character that
marks WikiVar expressions
+ , KEYWORD_MARK => { default => '' } # Character that
marks a keyword argument to a function.
+ , PRE_ERROR_TEXT => { default => '<!-- WikiVar Error: ' }
# Lead text for error output
+ , POST_ERROR_TEXT => { default => ' -->' } # Trail text
for error output
+ , VALUE_RXP => { private => 1 } # A value
+ , ARG_RXP => { private => 1} # An argument to a
function
+ , ARG_PARSE_RXP => { private => 1 } # Pick apart an
argument for handling
+ , INVOCATION_RXP => { private => 1 } # A WikiVar
invocation
+ , SCOPE => { default => [] , private => 1 } #
Stack of scopes
+ , TABLE => { default => {} , private => 1 } # Symbol table
+ , FALLBACK => { } # Fallback to call
when a WikiVar name is not found.
+ );
+
+ # I originally used the Enum package, but that's not installed by default
+ # and it only saves me one line of code (I have to walk over the fields
+ # anyway, to get the index data correct). Also, Enum uses closures instead
+ # of eval, so I am not sure its values get optimized by the compiler.
+ no strict "refs";
+ my $idx = 0;
+ foreach my $key (sort(keys(%_FIELDS))) {
+ $_FIELDS{$key}{index} = $idx;
+ *{"$key"} = eval "sub () { $idx }"; # use eval to force the constant,
avoid a closure
+ ++$idx;
+ }
+ use strict "refs";
+}
+our %_FIELDS; # Declaration from BEGIN doesn't propagate, so we have to
declare again (it's still the same variable)
+# Special name used to scope fallback assignments
+use constant FALLBACK_NAME => '*Fallback';
+
+## Class constants
+# The format for a name, either a function or an argument
+our $NAME_RXP = qr/[_[:alpha:]](?:-?[_[:alpha:][:digit:]])*/o;
+# Base set of symmetric quote marks accepted
+our $QUOTE_MARKS = q('"@`~!#%^&*=+;:/\\?*|$);
+# Table of supported assymmetric quotes
+our %QUOTE_TABLE = ( '[' => ']' , '(' => ')' , '{' => '}' , '<' => '>' );
+# Asymmetric quoted value RE
+#our $PAREN_VALUE_RXP = qr/\([^)]*\)|<[^>]*>|\[[^]]*\]|{[^}]*}/o;
+# ---------------------------------------------------------------------------
+sub new {
+ my $class = shift;
+ $class = ref($class) || $class; # force to string (name of class)
+ my $self = [];
+ bless $self, $class;
+
+ # Convert argument keys to upper case.
+ my $flip = FALSE;
+ my %args = map { $flip = not $flip; $flip ? uc : $_; } @_;
+
+ # Initial values. Use argument if present, otherwise the default if
available
+ while (my ($key, $value) = each %_FIELDS) {
+ my $idx = $value->{index};
+ if (not $value->{private} and exists $args{$key}) {
+ $self->[$idx] = $args{$key};
+ } elsif (exists $value->{default}) {
+ $self->[$idx] = $value->{default};
+ }
+ }
+
+ # Build up the regular expressions we need.
+ # We do many of these in two steps because we don't do the string
construction
+ # in the same line that we compile it to a RE.
+ my $marks = $QUOTE_MARKS;
+ my $dl = $self->[DELIMITER]; # non-RE base delimiter.
+ my $dl_right;
+ my $dl_left = quotemeta($dl);
+ if (exists $QUOTE_TABLE{$dl}) {
+ $dl_right = quotemeta($QUOTE_TABLE{$dl});
+ } else {
+ $dl_right = $dl_left;
+ }
+ # Clip delimiter from any quote matching
+ $marks =~ s/$dl_left//;
+ delete $QUOTE_TABLE{$dl};
+ # Clip out the keyword mark if set (only symmetric quotes supported)
+ my $kw = $self->[KEYWORD_MARK];
+ if ($kw) {
+ $kw = quotemeta($kw);
+ $marks =~ s/$kw//;
+ $kw .= $NAME_RXP;
+ } else {
+ $kw = ''; # force to null string so $kw is always a string after this
+ }
+ # RE that matches a value quoted by any of the allowed symmetric quote
marks
+ my $quoted_value_rxp = join('|', map { my $c = quotemeta($_);
$c.'[^'.$c.']*'.$c} split(//,$marks));
+ # Generate an RE for the assymmetric quotes
+ my @paren_rxp;
+ while (my ($left, $right) = each %QUOTE_TABLE) {
+ push(@paren_rxp, "[$left][^$left]*[$right]");
+ }
+ my $paren_rxp = join('|', @paren_rxp);
+ $paren_rxp = qr/$paren_rxp/;
+ # Any quoted value, symmetric or asymmetric
+ $self->[VALUE_RXP] = qr<$quoted_value_rxp|$paren_rxp>;
+ # An argument to an invocation, syntax checking version
+ my $text = "(?:$NAME_RXP\\s*)?" . $self->[VALUE_RXP];
+ $text = '(?:' . $text . ')|(?:' . $kw . ')' if $kw;
+ $self->[ARG_RXP] = qr<$text>;
+ # An argument to an invocation, processing version
+ $text = "(?:($NAME_RXP)\\s*)?(" . $self->[VALUE_RXP] . ')';
+ $text = '(?:' . $text . ')|(' . $kw . ')' if $kw;
+ $self->[ARG_PARSE_RXP] = qr<$text>;
+ # If the delimiter is symmetric we want to match double instances and
convert them to a single instance
+ # as a convenience. We do that by marking the content with a 0,1 marker
and checking for it being empty
+ # during processing. We do not do this if the delimiter is assymmetric.
+ $text = $dl_left . '(?:' . '(' . $NAME_RXP . ')(?:(=' . $self->[VALUE_RXP]
. ')|((?:\s*' . $self->[ARG_RXP] . ')*)))';
+ $text .= '?' if $dl_left eq $dl_right;
+ $text .= $dl_right;
+ $self->[INVOCATION_RXP] = qr<$text>;
+
+ return $self;
+}
+
+# Now we can create a static instance for convenience.
+our $STATIC_INSTANCE = __PACKAGE__->new();
+
+# ---------------------------------------------------------------------------
+# Self extraction for class methods.
+# Handle three cases:
+# - Called directly as a subroutine (Text::WikiVar::method)
+# - Called as class method (Text::WikiVar->method)
+# - Called from instance ($instance->method)
+# An appropriate value for $self is returned, and removed from the argument
+# list if present.
+sub _self {
+ my $self = $_[0][0]; # Get the first argument
+ if (not ref $self) { # not a reference, need to fix it up
+ shift @{$_[0]} if $self eq __PACKAGE__; # drop only if it's the package
+ $self = $STATIC_INSTANCE; # use static instance
+ } else {
+ shift @{$_[0]}; # was an instance, so drop it
+ }
+ return $self;
+}
+# ---------------------------------------------------------------------------
+sub assign ($$$) {
+ my $self = _self(\@_);
+ my ($name, $value) = @_;
+
+ my $table = $self->[TABLE]; # should be hash ref
+ my $scope = $self->[SCOPE]; # stack of hash refs
+ my $status = '';
+
+ if ($name =~ m/^$NAME_RXP$/) { # verify legal name
+ # fault in the definition hash if it's not there.
+ if (ref $table ne 'HASH') {
+ $table = {};
+ $self->[TABLE] = $table;
+ }
+
+ # Store the old value so we can unwind this scope later.
+ # Don't save the value if it's already there. That means it's
+ # already been changed in this scope.
+ # Note that if it wasn't defined already then we'll store undef in the
+ # scope table. This indicates that we need to delete the value when
+ # the scope is exited.
+ # Note that scope is a stack with the innermost scope at
+ # index 0.
+ $scope->[0]->{$name} = $table->{$name} if $scope and not exists
$scope->[0]->{$name};
+
+ if (not defined($value)) {
+ delete $table->{$name}; # assigning undef deletes assignment
+ } else {
+ # be backwards compatible for now
+ $value = new Text::WikiVar::CodeRef('*',$value) if ref $value eq
'CODE';
+
+ if (! ref $value || $value->isa('Text::WikiVar::CodeRef')) {
+ $table->{$name} = $value;
+ } else { # not a valid value
+ $status = 'Bad value type - "' . ref($value)
+ . '" - in WikiVar assignment to variable "' . $name .
'"';
+ }
+ }
+ } else {
+ $status = 'Invalid name for function: "' . $name . '"';
+ }
+ return $status ? ( $self->[PRE_ERROR_TEXT] . $status .
$self->[POST_ERROR_TEXT] ) : '';
+}
+
+sub fallback {
+ my $self = _self(\@_);
+ if (scalar @_){
+ my $value = shift;
+ my $scope = $self->[SCOPE];
+ $scope->[0]->{FALLBACK_NAME()} = $self->[FALLBACK] if $scope and not
exists $scope->[0]->{FALLBACK_NAME()};
+ if (ref $value eq 'CODE') {
+ $self->[FALLBACK] = new
Text::WikiVar::CodeRef(FALLBACK_NAME,$value);
+ } elsif (not ref $value) {
+ $self->[FALLBACK] = $value;
+ } elsif (value->isa('Text::WikiVar::CodeRef')) {
+ $value->name(FALLBACK_NAME);
+ $self->[FALLBACK] = $value;
+ } else {
+ warn "Fallback not set because value was an inappropriate type.\n";
+ }
+ } else {
+ return $self->[FALLBACK];
+ }
+}
+
+sub _invoke {
+ my ($name, $func) = (shift,shift);
+ my $debug = $_[0];
+ my $debug2 = ref $debug;
+ my $output = '';
+ my $errText;
+ if (not ref $func) { # simple text, just use it
+ $output = $func;
+ } elsif ($func->isa('Text::WikiVar::CodeRef')) { # something to call
+ my $code = $func->getCode();
+ if (ref $code eq 'CODE') { # found the code
+ $output = eval { &$code(@_); }; # wrap in eval to trap exceptions
+ $errText = 'Error: Invocation of "' . $name
+ . '" as defun "' . $func->name
+ . '" failed because "' . $@ . '"'
+ if $@; # failure during invocation
+ } else { # something went wrong, use as error text
+ $errText = "Error: CodeRef for '$name' has bad type: " .
ref($code);
+ }
+ } else { # something went wrong, use as error text
+ $errText = "Error: WikiVar '$name' has bad type: " . ref($func);
+ }
+ return ( $errText, $output );
+}
+
+# Invoke a macro with arguments.
+# Parameters:
+# Macro Name
+# Argument structure
+sub invoke {
+ my $self = _self(\@_);
+ my $name = shift;
+ my $output = '';
+ my $errText = '';
+ my $macro;
+
+ # get our table out of the context
+ my $table = $self->[TABLE];
+
+ if (ref $table eq 'HASH' && defined ($macro = $table->{$name})) {
+ ($errText, $output) = _invoke($name, $macro, @_);
+ } elsif ($self->[FALLBACK]) {
+ ($errText, $output) = _invoke($name, $self->[FALLBACK], @_);
+ } else {
+ $errText = 'Error: WikiVar "' . $name . '" not defined' if not exists
$table->{$name};
+ }
+ $errText = $self->[PRE_ERROR_TEXT] . $errText . $self->[POST_ERROR_TEXT]
if $errText;
+ return wantarray() ? ($output , $errText) : ($errText ? $errText :
$output);
+}
+
+# This sets up a new scope which saves old values of macros. These values
+# are restored by a LeaveScope call.
+sub enter_scope {
+ my $self = _self(\@_);
+ my $scope = $self->[SCOPE];
+ if (ref $scope ne 'ARRAY') {
+ $self->[SCOPE] = [ {} ]; # seed original array of single hash
+ } else {
+ unshift @$scope, {}; # push an empty hash to save changes in scope
+ }
+}
+
+# Restore saved values for macros.
+sub leave_scope {
+ my $self = _self(\@_);
+ my $scope = $self->[SCOPE];
+ if ($scope) { # is there a scope to leave?
+ my $table = $self->[TABLE];
+ my $values = shift @$scope;
+ # For each value in the scope, if it's set restore $table
+ # to that otherwise delete the element from table
+ foreach my $key (keys %$values) {
+ my $v = $values->{$key};
+ if ($v) {
+ $table->{$key} = $v;
+ } else {
+ delete $table->{$key};
+ }
+ }
+ }
+}
+
+# Takes an argument string and returns an argument object.
+sub string_to_args {
+ my $self = _self(\@_);
+ my ($word, $text, $flags) = @_;
+ my @required;
+ my %named;
+ my $rxp = $self->[ARG_PARSE_RXP];
+
+ while ($text =~ /$rxp/g) {
+ my $name = $1; # save these before they get scrozzled
+ my $value = $2;
+ my $keyword = $3;
+
+ if ($keyword){
+ $named{$keyword} = 1;
+ } else {
+ $value = substr($2, 1, length($2)-2); # strip quotes
+ $value = $self->process($value, $flags);
+ if ($name) {
+ if (exists $named{$name}) {
+ if (ref $named{$name} eq 'ARRAY') { push(@{$named{$name}},
$value); }
+ else { $named{$name} = [ $named{$name} , $value ]; }
+ } else {
+ $named{$name} = $value;
+ }
+ } else {
+ push(@required, $value);
+ }
+ }
+ }
+ return Text::WikiVar::Arguments->new( $word, \@required , \%named );
+}
+
+# Perform text substitution for a single invocation match
+sub _process {
+ my ($self, $flags, $name, $assign_text, $arg_text) = @_;
+ my $zret = '';
+
+ if (not $name) {
+ # Matched empty content -> it's a double delimiter.
+ # Generate a single delimiter as the result.
+ $zret = $self->[DELIMITER];
+ } elsif ($assign_text){
+ my $value = '';
+ $value = $self->process(substr($assign_text, 2, length($assign_text) -
3), $flags) if length $assign_text > 2;
+ $self->assign($name, $value);
+ } else { # if it's not an assignment, it's a call
+ $arg_text = '' unless defined($arg_text);
+ $zret = $self->invoke($name, $self->string_to_args($name, $arg_text,
$flags));
+ }
+ return $zret;
+}
+
+# Process the text, substituting the results for the invocations.
+# Parameters
+# Text
+# Flags
+# scope - create a scope around this transform
+
+sub process {
+ my $self = _self(\@_);
+ my ($zret, $flags) = @_;
+ my $rxp = $self->[INVOCATION_RXP];
+ $flags = {} if ref $flags ne 'HASH'; # force hash ref
+
+ my $inScope = $flags->{scope};
+ delete $flags->{scope}; # don't pass this down via recursion
+ $self->enter_scope() if $inScope;
+
+ $zret =~ s/$rxp/$self->_process($flags, $1, $2, $3)/eg;
+
+ if ($inScope) {
+ $self->leave_scope();
+ $flags->{scope} = $inScope; # restore original state of flags
+ }
+
+ return $zret;
+}
+
+sub error_bounding_text {
+ my $self = _self(\@_);
+ return ($self->[PRE_ERROR_TEXT], $self->[POST_ERROR_TEXT]);
+}
+
+# Return our version
+sub Version {
+ return $VERSION;
+}
+
+1;
+__END__
+
+
+=pod
+
+=head1 Name
+
+B<WikiVar>
+
+=head1 Synopsis
+
+WikiVar is a text formatter that provides roughly the same functionality as
both
+Wiki variables and macros. That is, both simple text substitution and code
+invocation. Text substitutions (macros) can be defined programmatically or
+inline. Code invocations ("functions") can only be defined programmatically but
+used inline (thereby providing a mechanism for calling pre-existing Perl
+subroutines from text input).
+
+Stylistically WikiVar is based on Wiki variables but extends the syntax to
+provide better function invocation capabilities. It supports both positional,
+named, and keyword arguments with robust quoting mechanisms.
+
+=head1 Description
+
+=head2 Background
+
+WikiVar was originally intended as a module for an actual Wiki to improve
+variable handling, which for that Wiki code was scattered among numerous
regular
+expressions in many modules, leading to a disturbing lack of consistency.
+Instead of that, WikiVar would provide a single place for registering all Wiki
+functions and, because it was easy and consistent to add, macros. Bad
+interactions between the variables would be minimized because they would all be
+processed in one pass, not each in its own separate pass, and much faster for
+the same reason. That project was sidelined but I kept WikiVar because
+it was useful in other circumstances.
+
+=head2 Overview
+
+WikiVar supports two types of usage, "macros" and "functions".
+Stylistically these are very similar, but the implementation / API differ.
+
+Macros are simple text substitution. The invocation of a macro is replaced by
+the text for that macro. Macros can be defined inline or via the API. This
makes
+them handy for predefined terms or local abbrevations.
+
+Functions are calls to Perl subroutines. Arguments (both positional and named)
+are passed to the subroutines. The invocation is replaced by the output
+of the subroutine. Functions must be defined via the API, they cannot be
+assigned inline (only invoked).
+
+=head2 Inline Usage
+
+Inline usage is use of WikiVar by character sequences in the processed text.
+
+=head3 Using a macro inline
+
+The macro "name" is invoked by the character sequence C<$name$>. This set of
+characters is replaced by the value of the macro. As a special case, two
+adjacent delimiters are converted to a single delimiter. That is, C<$$> is
+turned in to C<$>.
+
+=head3 Defining a macro inline
+
+To define the macro "name" to have the value "value", use the text
+C<$name=@value@$> where C<@> is a E<delimiter>. The delimiter can be any
+printable non-whitespace character that is not a valid macro name character
+except C<$>, C< > >, C< ) >, C< ] >, or C< } >. The terminal delimiter is the
+same as the initial one, except for C< < >, C< ( >, C< [ >, C < { >. In these
+cases the terminal delimiter is C< > >, C< ) >, C< ] >, or C< } > respectively.
+The value must not contain any instances of the delimiter. Because of the wide
+variety of delimiters that can be used, this is rarely a problem. Even when it
+is, there is a work around described after the following examples.
+
+Examples:
+
+=over 4
+
+C<$name="value"$>
+
+C<$name=(value)$>
+
+C<$name=|value|$>
+
+=back
+
+The name must start with a letter or an underscore, and can contain letters,
underscores, numbers and dashes. It
+may not end with a dash.
+
+Note that no white space is allowed in the syntax. The variable delimiter C<$>
+must immediately precede the initial name character and immediately follow the
+terminal value delimiter. This avoids problems with the use of the variable
+delimiter in normal text.
+
+The actual text of the assignment (everything between the C<$> characters
+and those characters as well) is removed completely the output text.
+
+The value itself is evaluated so that any variables in the value are evaluated.
+This is intended to allow defining a macro in terms of one or more other
macros.
+However, it does mean that you can define new macros in the value part of a
macro
+definition. This nested define must use a different delimiter than the outer
define,
+limiting the possible recursion depth. However, such use is generally more
trouble
+than benefit and is mentioned only to warn you to no do it.
+
+There is no provision for escaping characters in the value. This is acceptable
+because of the ability to select from a larger number of delimiters. If that's
+not sufficient then another macro consisting of just the problematic character
can be
+defined and used to put the delimiter in to the macro value.
+
+=over 4
+
+C<$dq='"'$> C<$name="A double quote $dq$"$>
+
+=back
+
+=head3 Using a function inline
+
+To invoke the function "func", use the text C<$func$>. This calls the Perl
subroutine
+associated with the name "func" and replaces the text with the output of the
subroutine.
+
+Arguments can be passed. Such arguments are of three types, positional, named,
+and keyword. In general, positional arguments are required and named / keyword
+arguments are optional, but this is by convention. Each argument value is
+delimited in the same way as macro text. Named arguments are indicated by
+putting the undelimited name in front of the argument value E<without
+intervening whitespace>. Keyword arguments are names with a leading keyword
mark
+character if keywords have been enabled (keyword arguments are disabled by
+default). Named arguments have values, keyword arguments don't, and positional
+arguments are just values.
+
+Named and keyword arguments can be in any order, interspersed among the
+positional arguments in any fashion, but positional arguments are
+passed in the same order as they occur in the text. Named and keyword arguments
+are ignored for the purposes of positional arguments, so that the following are
+equivalent (presuming ':' has been set as the keyword marking character):
+
+=over 4
+
+C<$func (arg1) 'arg2' <arg3E<gt> name1(value1) name2%value2% :key1 :key2$>
+
+C<$func :key2 {arg1} name2<value2E<gt> "arg2" :key1 name1[value1] (arg3)$>
+
+=back
+
+Conventionally the positional arguments are placed first, followed by named
+arguments, then keyword arguments. This is simply to reduce confusion, however,
+and you can use a different system if that works better for you.
+
+=head2 Programmatic API
+
+WikiVar supports two interfaces, object oriented and functional. These work the
+same way except that the functional interface uses a single pre-allocated
global
+instance while the object oriented styles lets the client create and control
+multiple instances. Both of these are useful in different circumstances. The
+primary advantage of the OO interface is that the different instances can be
set
+to have different processing styles (e.g. different variable delimiters) or
+different sets of defined macros / functions.
+
+=head3 Text::WikiVar
+
+=head4 Method new
+
+Create a new instance of WikiVar. The argument list is treated as a hash with
+the following keys examined.
+
+=over 4
+
+=item DELIMITER
+
+The variable delimiter which must be a single printable
+non-alphanumeric/underscore/dash character. Default value is '$'. Setting this
+to '%' will make invocations look more like normal Wiki variables. Note that
the
+value for this will be forbidden for use as a value delimiter (and if set to
+something other than '$', then '$' can be used for delimiting values).
+
+=item KEYWORD_MARK
+
+Character mark for keywords. This has the same limitations as
+B<DELIMITER> and is similarly removed from the pool of valid value delimiters.
+The default is the empty string which disables keyword arguments. If set,
+keyword arguments will be processed. Of course, this and C<DELIMITER> must be
+different characters.
+
+=item FALLBACK
+
+This is used when text contains what looks like a WikiVar invocation but the
+name is not defined. If this is a string, then that string is used as the value
+of the variable. If B<FALLBACK> is a C<CODE> reference then it is called as if
+the undefined name was a function and B<FALLBACK> the code for that function.
+Note that as with C<AUTOLOAD>, this function can change the set of defined
+variable names. If an undefined name is use and B<FALLBACK> is not set (the
+default) then an error message is generated.
+
+This can be changed later using the C<fallback> method.
+
+=item PRE_ERROR_TEXT, POST_ERROR_TEXT
+
+If an error occurs, an error message is
+generated and used as the value of the variable causing the error. These values
+are prepended and appended to that message. The default is C<E<lt>!-- WikiVar
+Error:> and C< --E<gt>> respectively, so that if used to process HTML the
errors
+are findable but not visible.
+
+=back
+
+=head4 Method assign
+
+This defines a macro or a function. The arguments are
+
+=over 4
+
+=item name
+
+The name of the variable. This must consist only of alphanumeric, dash or
+underscore characters. The name must start with a letter or an underscore, and
+must not end with a dash.
+
+=item value
+
+The value of the variable. This should be one of
+
+=over 4
+
+=item *
+
+A scalar. The result is a macro and the printable version of the value is used
as
+the substitution text for the macro.
+
+=item *
+
+A reference to a subroutine. The result is a function. When the function is
+invoked the subroutine is called with the arguments provided by the inline
+invocation as an instance of the C<Text::WikiVar::Arguments> class.
+
+=item *
+
+An instance of C<Text::WikiVar::CodeRef>. This allows a subroutine to be
+specified by name. The actual code reference is not accessed until the function
+is invoked. This is useful if there are initialization ordering problems and
the
+module with the subroutine may not be loaded when C<assign> is called. If a
+subroutine is defined at the point of assignment, it is generally preferable to
+just pass a reference to it instead of using C<CodeRef>.
+
+=item *
+
+C<undef>. This will erase the definition of the variable.
+
+=back
+
+=back
+
+=head4 Method fallback
+
+This has the same semantics as C<assign> except that it stores the variable in
a
+special slot in the WikiVar instance and invokes it whenever a WikiWord is used
+that is not defined. The default behavior in such a case is to generate an
+error message as the output text but if the C<fallback> is set then it is
called
+instead and its return value used.
+
+=head4 Method invoke
+
+This performs the substitution for the variable. The return value is the
+substitution string for the variable. The arguments are
+
+=over 4
+
+=item name
+
+The name of the variable.
+
+=item arguments
+
+If I<name> is a not a function then I<arguments> is ignored and may be omitted.
+Otherwise the arguments are passed on to the subroutine as is. Since the
+function is likely to be expecting a C<Text::WikiVar::Arguments> object you may
+want to use the C<string_to_args> method.
+
+=back
+
+=head4 Method string_to_args
+
+Convert an argument I<string> to an instance C<Text::WikiVar::Arguments>. The
+string format is as described for inline invocation. The argument list can be
+passed directly to a subroutine or passed, along with a name, to C<invoke>.
Note
+that argument values are processed for further WikiVar substitutions.
+
+=head4 process
+
+This transforms a string, performing all macro substitutions and updating the
+context for any new macro definitions. It returns the transformed string. It
+takes two arguments.
+
+=over 4
+
+=item text
+
+The text string to transform.
+
+=item flags
+
+A reference to a hash containing processing flags. The currently defined
+flags are
+
+=over 4
+
+=item scope
+
+If set to a C<true> value, a scope is entered before processing and
+left after processing, isolating any inline definitions in the text.
+
+=back
+
+=back
+
+=head4 Method enter_scope
+
+Creates a new scope for definitions. Any definitions made in this scope can be
+reverted with C<leave_scope>. This is handy when processing multiple chunks of
+user text so that inline definitions in one chunk do not propagate to other
chunks.
+
+=head4 Method leave_scope
+
+Destroys the current definition scope. All definitions (both inline and via
C<assign>)
+made in the scope are reverted to their state before the scope was entered.
+
+=head3 Text::WikiVar::CodeRef
+
+As noted previously, this class is useful when intialization ordering means
that
+a subroutine to be used as a function may not be loaded when C<assign> is
+called. In that case, a C<CodeRef> wrapper can be used to delay access to the
+C<CODE> reference until the function is invoked during text processing.
+
+=head4 Method new
+
+=over 4
+
+=item *
+
+I<name> The fully qualified name of the subroutine.
+
+=back
+
+=head3 Text::WikiVar::Arguments
+
+An instance of this class is passed to the subroutine for a function. It
+contains all of the arguments supplied in the text that invoked the function.
It
+can be treated as an array reference for positional arguments or a hash
+reference for named and keyword arguments. If C<$args> is an instance of this
+class passed to a function, then
+
+=over 4
+
+=item *
+
+C<$args-E<gt>[0]> is the name of the function.
+
+=item *
+
+C<$args-E<gt>[$n]> is the C<n>th positional argument.
+
+=item *
+
+C<$args-E<gt>{name}> The value for the named or keyword argument C<name>. The
value
+for a keyword argument is a true value if the keyword was present, and a false
+value if not. The value for a named argument is C<undef> if the argument was
not
+present, the value if it was. The C<exists> keyword can also be used to check
if
+a named or keyword argument was present.
+
+=back
+
+An instance is also a class with various utility methods.
+
+=over 4
+
+=item *
+
+I<argc> Return the number of positional arguments.
+
+=item *
+
+I<argv> Identical to C<$args-E<gt>[]>. Gotta give my fellow C/C++ programmers
some love.
+
+=item *
+
+I<value> The same as C<$args-E<gt>{}> except that the argument is not
implicitly
+quoted. Useful when the argument name is in a variable and not a literal.
+
+=item *
+
+I<word> The WikiVar variable name invoked. Identical to C<$args-E<gt>[0]> but
+a bit clearer in context.
+
+=item *
+
+I<force_array> Force values for named arguments to be C<ARRAY> references. The
+arguments to I<force_array> are names that name named arguments. If the value
+for one of the names is already an C<ARRAY> reference it is unchanged. If it is
+not, it is converted to a reference to an C<ARRAY> of length 1.
+
+=item *
+
+I<required_args> Return a reference to an array of the positional arguments.
The
+invoking word is not included. Cached so it's very low marginal cost to call
+multiple times.
+
+=back
+
+=head2 Example
+
+Here is some example text illustrating the basic usage.
+
+ $Bob='<a href="mailto:[email protected]">Bob</a>'$
+ $BobHomePage=(<a href="http://nowhere.com/~bob">Home Page</a>)$
+ $Bobco="Bob's Organic Software and Vegetables"$
+
+ I first met $Bob$ a about 10 years ago. You can check out his biography at his
+ $BobHomePage$. Shortly after I met him he started $Bobco$ to combine his
talent
+ for software development with his wife's green thumb. $Bobco$ has been a
rousing
+ success, their "free onion with every download" marketing scheme taking the
+ market by storm. I see a good future for $Bob$ and $Bobco$.
+
+After processing, this yields
+
+ I first met <a href="mailto:[email protected]">Bob</a> a about 10 years ago.
You
+ can check out his biography at his
+ <a href="http://nowhere.com/~bob">Home Page</a>. Shortly after I met him he
+ started Bob's Organic Software and Vegetables to combine his talent for
software
+ development with his wife's green thumb. Bob's Organic Software and Vegetables
+ has been a rousing success, their "free onion with every download" marketing
+ scheme taking the market by storm. I see a good future for <a
+ href="mailto:[email protected]">Bob</a> and Bob's Organic Software and
Vegetables.
+
+=head1 Version History
+
+ 0.1: 10 Oct 2003
+ 1.0: 19 Nov 2004
+ 1.1 : 16 May 2008
+ 1.2 : 26 Oct 2008
+ 1.2.1 : 04 Dec 2008
+
+=head1 Author
+
+ Alan M. Carroll
+ https://network-geographics.com
+
+=head1 Additional Credits
+
+The original goal of this project was to extend Textile so that I could do
+inline text macros (particularly, predefined ones for links). Originally I had
+hacked the Textile source to define the macros, which made maintenance
+difficult. WikiVar was started to generalize that. Eventually most of that
+functionality was provided by Webiki, but I still use WikiVar for inline macros
+and certain Perl based functionality.
+
+While doing the design I started working with Wiki and decided to expand the
+functionality enough to handle Wiki variables as well. This was part of an
effort
+to support Textile formatting in a Wiki. The base logic for handling Wiki
+variables was a complete hack, not generalized and scattered about the source
+code. WikiVar supports all of the required utility in one place, in an easily
+customized, more consistent, and more efficient way.
+
+=head1 Copyright and License
+
+ Copyright (c) 2008 Network Geographics Inc.
+ (https://network-geographics.com/)
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name "WikiVar" nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "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 copyright owner or contributors 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.
+
+=cut
Added: trafficserver/site/trunk/lib/doxy-link.pm
URL:
http://svn.apache.org/viewvc/trafficserver/site/trunk/lib/doxy-link.pm?rev=1369371&view=auto
==============================================================================
--- trafficserver/site/trunk/lib/doxy-link.pm (added)
+++ trafficserver/site/trunk/lib/doxy-link.pm Sat Aug 4 16:54:00 2012
@@ -0,0 +1,82 @@
+package doxy;
+use strict;
+use warnings;
+
+require 'WikiVar.pm';
+require 'DoxygenSymbol.pm';
+
+use File::Spec;
+use Carp;
+use JSON;
+use LWP::Simple ();
+
+# URL for Doxygen content
+use constant DOXY_URL => 'http://people.apache.org/~amc/ats/doc/html';
+# Local file system path for symbol table
+use constant SYMBOL_TABLE_PATH => 'doxy-sym.json';
+# URL for externally base symbol table
+use constant SYMBOL_TABLE_URL =>
'http://people.apache.org/~amc/ats/doxy-sym.json';
+# Flag for data loaded
+our $LOADED_P = 0;
+# The symbol table
+our $SYMBOLS;
+# Array of source files
+our $FILES;
+# Our instance of WikiVar
+our $WV = Text::WikiVar->new(KEYWORD_MARK => ':', DELIMITER => '[');
+
+sub load_symbol_table {
+ my $path = SYMBOL_TABLE_PATH;
+ my $content;
+
+ # Try to get an up to date copy.
+ my $http_code = LWP::Simple::mirror(SYMBOL_TABLE_URL, $path);
+
+ if (open(my $f,"<",$path)) {
+ local $/ = undef;
+ my $content = <$f>;
+ my $data = from_json($content);
+ $SYMBOLS = $data->{symbols};
+ $FILES = $data->{files};
+ # Need the symbol elements to be of the right type
+ while (my ($key, $value) = each %$SYMBOLS) {
+ bless $value, 'DoxygenSymbol';
+ }
+ close $f;
+ } else {
+ warn "Failed to open Doxygen symbol table.\n";
+ }
+ $LOADED_P = 1;
+}
+
+$WV->assign('dox', sub {
+ load_symbol_table unless $LOADED_P;
+
+ my $args = shift;
+ my $link; # output is constructed here
+ my $name = $args->[1];
+ my $data = $SYMBOLS->{$name};
+
+ return "[Symbol $name not found]" unless $data;
+
+ # Check to see if we want the source file instead.
+ my $file = $FILES->[$data->src_idx];
+ if ($args->{':src_file'}) {
+ my $src = unmangle_file_name($file);
+ $data = $SYMBOLS->{$src};
+ return "[Source file $src for symbol $name not found]" unless $data;
+ }
+ # Generate the link
+ my $url = DOXY_URL . '/' . $file;
+ $url .= '#' . $data->id if $data->id;
+ $link = "<a href=\"$url\"";
+ if ($data->arg_text) {
+ $link .= ' alt="'. $data->name . $data->arg_text . '"';
+ } elsif ($data->text) {
+ $link .= ' alt="' . $data->text . '"'
+ }
+ $link .= '>' . $data->name . '</a>';
+ return $link;
+});
+
+1;
Added: trafficserver/site/trunk/lib/doxy-sym-generate.pl
URL:
http://svn.apache.org/viewvc/trafficserver/site/trunk/lib/doxy-sym-generate.pl?rev=1369371&view=auto
==============================================================================
--- trafficserver/site/trunk/lib/doxy-sym-generate.pl (added)
+++ trafficserver/site/trunk/lib/doxy-sym-generate.pl Sat Aug 4 16:54:00 2012
@@ -0,0 +1,91 @@
+# Scrape the Doxygen output to get a symbol table
+# This is a stand alone script to be run against the Doxygen output to
+# generate a symbol table. That table is loaded during a documentation
+# build. It should be stored in an HTTP acccessible location and the
+# build script tweaked to know that location so it can update its local
+# copy as needed.
+
+use strict;
+use JSON qw(-convert_blessed_universally);
+use File::Basename;
+
+require 'DoxygenSymbol.pm';
+
+our %SYMBOLS; # Symbol table, name -> DoxygenSymbol
+our @FILES; # Array of files.
+
+use constant DOXYGEN_BASE_DIR => '/sys/cygwin/home/amc/ats/doc/html';
+
+sub obtain_sym {
+ my ($table, $key, $src_idx) = @_;
+ my $zret = $table->{$key};
+ $zret = $table->{$key} = DoxygenSymbol->new(id => $key, src_idx =>
$src_idx) unless $zret;
+ return $zret;
+}
+
+sub load_doxy_file {
+ my $zret = 1;
+ my ($src_idx) = @_;
+ my $path = $FILES[$src_idx];
+ my %items; # temp hash keyed by ID
+ if (open(my $f,"<",$path)) {
+ # Gather the pieces of the method data together.
+ while (<$f>) {
+ my $sym = undef;
+ if (m/class="mdescRight">([^<]*)<.*href="#([^"]*)"/) {
+ my $text = $1;
+ $text =~ m/(\S+(?:\s+\S+)*)/;
+ $text = $1;
+ $sym = obtain_sym(\%items, $2, $src_idx);
+ $sym->text($text);
+ } elsif (m/doxytag:
member="([^"]*)".*ref="([^"]*)".*args="([^"]*)"/) {
+ $sym = obtain_sym(\%items, $2, $src_idx);
+ $sym->name($1);
+ $sym->arg_text($3);
+ }
+ }
+
+ # Put the source file in as a symbol
+ my $name = doxy::unmangle_file_name(basename($path));
+ if ($name =~ m/[.](?:cc|h|hpp)$/) {
+ $SYMBOLS{$name} = DoxygenSymbol->new(name => $name, src_idx =>
$src_idx, text => 'source file');
+ }
+
+ # Load the actual symbols in to the symbol table
+ while (my ($key, $value) = each %items) {
+ my $name = $value->name;
+ $name =~ s/^[[:alnum:]]+[.](?:h|cc|hpp):://; # strip file name as
leading namespace
+ $value->name($name);
+
+ my $sym = $SYMBOLS{$name};
+ if (not $sym) {
+ $SYMBOLS{$name} = $value;
+ } elsif (ref $sym) {
+ push(@$sym, $value);
+ } else {
+ $SYMBOLS{$name} = [ $sym, $value ];
+ }
+ }
+ close $f;
+ } else {
+ $zret = 0;
+ }
+ return $zret;
+}
+
+sub load_sym_file {
+
+}
+
+chdir(DOXYGEN_BASE_DIR);
+for (glob('*.html')) {
+ push(@FILES, $_);
+}
+for (my $idx = 0 ; $idx < scalar(@FILES) ; ++$idx) {
+ load_doxy_file($idx);
+}
+
+if (open(my $f,">",'/tmp/doxy-sym.json')) {
+ print $f to_json({files => \@FILES , symbols => \%SYMBOLS}, {
allow_blessed => 1, convert_blessed => 1, indent => 1 });
+}
+exit 0;
Propchange: trafficserver/site/trunk/lib/doxy-sym-generate.pl
------------------------------------------------------------------------------
svn:executable = *
Modified: trafficserver/site/trunk/lib/view.pm
URL:
http://svn.apache.org/viewvc/trafficserver/site/trunk/lib/view.pm?rev=1369371&r1=1369370&r2=1369371&view=diff
==============================================================================
--- trafficserver/site/trunk/lib/view.pm (original)
+++ trafficserver/site/trunk/lib/view.pm Sat Aug 4 16:54:00 2012
@@ -2,6 +2,7 @@ package view;
use strict;
use warnings;
+require 'doxy-link.pm';
use Dotiac::DTL qw/Template/;
use Dotiac::DTL::Addon::markup;
use ASF::Util qw/read_text_file shuffle/;
@@ -427,9 +428,14 @@ sub GetSource {
my ($stem, $lang, $ext) = view::_SplitContentName($file);
if ($node->langToFile($lang) ne $file) {
my $idx = $node->indexOfStem($stem);
- die "Failed to find source for '$path'.\n" if $idx < 0;
- $src = $node->srcAt($idx);
- die "Failed to find source for '$path'.\n" unless $file eq
$src->langToFile($lang);
+ $src = undef;
+ if ($idx >= 0) {
+ # If we don't find it in the index, that's tolerable
+ # it means the file is there but it's not in order.txt
+ # so just ignore it by return undef
+ $src = $node->srcAt($idx);
+ die "Failed to find source for '$path'.\n" unless $file eq
$src->langToFile($lang);
+ }
}
return wantarray ? ( $src , $lang ) : $src;
}
@@ -468,6 +474,11 @@ sub single_narrative {
$TARGET_BASE = $ENV{TARGET_BASE};
my ($src, $lang) = view::Node::GetSource($file);
+ if (not $src) {
+ warn "Ignoring '$file' because an order.txt was present without this
stem.\n";
+ return '';
+ }
+
$args{langs} = langs($src, $lang);
$args{lang} = $lang;
# copy over file local vars, including content.
@@ -478,7 +489,7 @@ sub single_narrative {
# Compute page local nav links.
nav_links($src, \%args) if $args{headers}{navigation};
- return Dotiac::DTL::Template($template)->render(\%args), html => \%args;
+ return
$doxy::WV->process(Dotiac::DTL::Template($template)->render(\%args)), html =>
\%args;
}
# Similar to single_narrative but does no auto navigation.