aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2020-11-11 15:13:38 +0100
committerJohn Ankarström <john@ankarstrom.se>2020-11-11 15:13:44 +0100
commitcd225683d4414006c9422ff23076d88638af1794 (patch)
treedfc713cd15b0379310418f4d67c7642cfc55b42e
parentcd6d3a48204415f4547048db0f4d0ac7b9414ffc (diff)
downloadrf-cd225683d4414006c9422ff23076d88638af1794.tar.gz
add backslash escaping, auto-remove more punctuation
-rwxr-xr-xrf71
-rw-r--r--rf.128
2 files changed, 73 insertions, 26 deletions
diff --git a/rf b/rf
index 754bc70..535affb 100755
--- a/rf
+++ b/rf
@@ -16,11 +16,25 @@ my @lines;
my $i = 0;
my @refs;
+# Load entire file
+
while (<>) {
# Formats
- if (/^\.Ff +(.*)/) { $format_full = $1; next; }
- if (/^\.Fx +(.*)/) { $format_extra = $1; next; }
- if (/^\.Fl +(.*)/) { $format_list = $1; next; }
+ if (/^\.F([fxl])(\\?) +(.*)/) {
+ my ($type, $join, $line) = ($1, $2, $3);
+ chomp $line;
+ $line = "\n$line" if not $join;
+ while (not eof()) {
+ last if not $line =~ s/\\$//;
+ $line .= "\n" . <>;
+ chomp $line;
+ }
+ $line .= "\n";
+ $format_full = $line if $type eq 'f';
+ $format_list = $line if $type eq 'l';
+ $format_extra = $line if $type eq 'x';
+ next;
+ }
# Reference definitions
if (/^\.R([a-z]) +(.*)/) {
@@ -46,28 +60,33 @@ while (<>) {
push @lines, $_;
}
+# Print processed file
+
$i = -1;
+my $last = '';
for (@lines) {
- $i++;
# Inline reference
if (/^\.R([fx]) +(.*)/) {
my ($suffix, $prefix, @points);
- my ($fld, $def) = ($1, $2);
- if ($def =~ s/ ([.,:;\])]) ?([\[(])?$//) {
+ my ($fld, $def) = ($1, $2, $3);
+
+ # find potential prefix/suffix and split into words
+ if ($def =~ s/ ([.,?!:;\])]) ?([\[(])?$//) {
($suffix, $prefix) = ($1, $2);
}
- my $winner = 0;
my @words = split /\s/, $def;
- # replace '' with preceding word
+ # replace '' with last word on preceding line
for (@words) {
if ($_ eq "''") {
- $_ = $lines[$i-1];
+ $_ = $last;
chomp;
$_ =~ s/^.*\s(\S+)\s*$/$1/;
}
}
+ # find matching reference list entry
+ my $winner = 0;
for (my $i = 0; $i < scalar @refs; $i++) {
$points[$i] = 0 if not defined $points[$i];
$points[$i] += 100 if likeness($refs[$i]{a}, @words);
@@ -81,44 +100,54 @@ for (@lines) {
print STDERR "Error: Reference '$def' could not be resolved.\n";
exit 1;
}
+
if ($points[$winner] < 150) {
print STDERR "Warning: Guessing that reference '$def' refers to " . fmt($format_full, $winner) . " (match = $points[$winner]).\n";
}
+ # Print formatted reference
+ my $fmt;
if ($fld eq 'f') {
- no warnings;
- print $prefix . fmt($format_full, $winner) . "$suffix\n";
+ $fmt = fmt($format_full, $winner);
} else {
- no warnings;
- print $prefix . fmt($format_extra, $winner) . "$suffix\n";
+ $fmt = fmt($format_extra, $winner);
}
+ $prefix = '' if not $prefix;
+ $suffix = '' if not $suffix;
+ chomp $last;
+ print $last;
+ $last = $prefix . substr($fmt, 0, index($fmt, "\n")) . "$suffix";
+ $last .= substr($fmt, index($fmt, "\n"));
next;
}
# Reference definition
if (/^\.R! (\d+)/) {
- print fmt($format_list, $1, 1) . "\n";
+ print $last;
+ $last = fmt($format_list, $1, 1) . "\n";
next;
}
# Non-rf line
- print "$_";
+ print $last;
+ $last = $_;
}
+# Format a given reference after $fmt
sub fmt {
my ($fmt, $i, $full) = @_;
my %ref = %{$refs[$i]};
- for my $fld (split //, 'acdnpqtwy') {
- if ($ref{$fld}) {
+ for my $fld (split //, 'Aacdnpqtwy') {
+ if ($ref{lc $fld}) {
no warnings;
- my $val = $ref{$fld};
+ my $val = $ref{lc $fld};
$val = fmta($val) if $fld eq 'a' and not $full;
$fmt =~ s/\{([^{}%]*)%\Q$fld\E([^{}]*)}/$1$val$2/g;
$fmt =~ s/%\Q$fld\E/$val/g;
} else {
no warnings;
- $fmt =~ s/[.(]?\{([^{}%]*)%\Q$fld\E([^{}]*)}[.,:;)]?//g;
- $fmt =~ s/[.(]?%\Q$fld\E[.,:;)]?//g;
+ $fmt =~ s/[.([]?\{([^{}%]*)%\Q$fld\E([^{}]*)}[.,?!:;\])]?//g;
+ $fmt =~ s/[.([]?%\Q$fld\E[.,?!:;\])]?//g;
}
}
$fmt =~ s/ +/ /g;
@@ -129,6 +158,7 @@ sub fmt {
return $fmt;
}
+# Remove forenames from a given string of authors
sub fmta {
my ($a) = @_;
my $r;
@@ -144,6 +174,7 @@ sub fmta {
return $r;
}
+# Calculate a basic likeness value a string and a list of strings
sub likeness {
my ($string, @strings) = @_;
my $r = 0;
diff --git a/rf.1 b/rf.1
index d85121b..fbf429f 100644
--- a/rf.1
+++ b/rf.1
@@ -189,16 +189,32 @@ For example:
\&.Ff (%a{, %y}). \\" Here, ', ' is removed if there is no year.
.Ed
.Pp
-Note that all fields are inserted literally, except
-.Em %a ,
-from which the forenames of the authors are removed.
+You can include a newline in your format by ending the line with a backslash and continuing on the next line.
+If you add a backslash immediately following the macro name, the interpolated format will be joined to the preceding line.
+By using backslashes, you can implement footnote-based references.
+For example, using the ms macro package:
+.Bd -literal -offset indent
+\&.Fx\\ \\**\\
+\&.FS\\
+%A, {\\fI%t\\fR}, {\\*Q%q\\*U}, %y.\\
+\&.FE
+.Ed
.Pp
-Note also that you can use troff requests and other macros in your format by starting with a dot. This will expand to a valid request/macro in the output of
+As you can see above, you can use troff requests and other macros in your format.
+This will expand to a valid request/macro in the output of
.Nm .
.Pp
-Finally, you usually don't need to worry about excessive spaces and stray punctuation marks, as
+Note that all fields are inserted literally, with one exception:
+when
+.Em %a
+is used in an inline reference format, the forenames of the authors are automatically removed.
+To include the forenames, use
+.Em %A
+instead.
+.Pp
+Finally, you usually don't need to worry about excessive spaces and stray punctuation marks.
.Nm
-removes many of these these automatically.
+removes common punctuation immediately preceding and following an unsuccessful interpolation.
.
.Sh EXAMPLE
Below is an example of an ms-based troff document using