home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 10
/
AU_CD10.iso
/
Updates
/
Perl
/
Non-RPC
/
!Perl
/
riscos
/
RISCOS
/
DrawFile
/
TextArea
/
Parser.pm
Wrap
Text File
|
1998-07-31
|
28KB
|
918 lines
package RISCOS::DrawFile::TextArea::Parser;
use Carp;
use strict;
use vars qw ($VERSION @ISA %parser $lax $mode);
use RISCOS::Units qw(millipoint2draw draw2millipoint point2draw);
require RISCOS::DrawFile::TextArea;
require RISCOS::Font;
$VERSION = 0.02;
@ISA = 'RISCOS::DrawFile::TextArea';
# Definately not threadable.
$mode = '' unless defined $mode;
# '' for native
# 'D' for Draw emulation
# '+' for DrawPlus emulation
# 'F' for DrawFile module emulation
# 'L' for Librarian emulation
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = RISCOS::DrawFile::TextArea->new (@_);
$self = $self->[0] if ref ($self) eq 'ARRAY';
bless ($self, $class);
my $output = [];
# foreach (@{$self->Cols()}) {
# push @$output, scalar &RISCOS::DrawFile::Path::Rectangle($_, undef, [255, 0, 0]);
# }
$self->{'__MODE'} = $mode;
$self->{'__ALIGN'} = 'L';
$self->{'__FONT'} = {};
$self->{'__PLEAD'} = $self->{'__LEAD'} = point2draw 10;
$self->StartY() if ($self->{'__MODE'} eq 'F');
# Bozo DrawFile module interprets the spec rather strictly and *always*
# starts the first line at \L10
$self->Margins (1, 1);
# $self->{'__STARTY'} is undefined, and read as __LEAD first time
# Oh, unless we're the Drawfile module in which case it is 10 points first
# time.
my $text = \$self->{'__TEXT'};
unless ($$text =~ s/^\\! 1\n//s or $lax) {
$$text =~ /^(.{1,5})/s;
warn "TextArea starts with '$1' not '\\! 1\n'";
}
$$text =~ tr/\t\n -\377//cd; # Delete unrecognised control chars.
my $current = $self->reset_block(undef, undef, undef);
my @line = $current;
my $seen_printing;
if ($self->{'__MODE'} eq 'L') {
# Some sort of cacky definition of a no-show.
# return ()
# if $self->{'__FORE'} eq 'ÿÿÿÿ' and $self->{'__BACK'} eq 'ÿÿÿÿ';
$self->{'__FORE'} = "\0\0\0\0";
$self->{'__BACK'} = "\0ÿÿÿ";
}
# 0 action (default 0x118 - underline break, text vertical and
# horizontal) shift
# Not sure whether to believe this, as rechecking what differs
# allows more sophisticated agglomeration if (say) UL is changed
# to same thickness.
# 1 x offset from left margin (draw units)
# undef means read left margin for first, or carry on using
# previous entry width
# 2 y offset from previous x,y; (draw units)
# 3 width of this object (unjustified) (draw units)
# 4 font fore
# 5 font back
# 6 font object (name, width, height)
# 7 underline position
# 8 underline thickness
# 9 text
# 10 position (relative to left margin)
# undef if it needs recalculating
# 11 position + width
# 12 number of spaces
while (length $$text) {
my ($action, $words, $para) = 0;
if ($$text =~ /^\\(.)/s) {
my $length = length $$text;
# print STDERR "$1\n"; # \ Command
if (defined (my $sub = $parser{$1})) {
($action, $words) = &$sub ($self, $text);
if (length ($$text) == $length) {
$$text =~ /^(.*)/m;
die "Mangled command in '$1'";
}
} else {
$$text =~ /^(.*)/m;
die "Undefined command in '$1'";
}
} elsif ($$text =~ s/^(\n+)//s) {
$para = length ($1) - 1;
if ($$text =~ /^[\t ]/) {
# As far as Draw is concerned "\n\t" or "\n " *is* a single
# paragraph break
$para = 1 if not $para and $self->{'__MODE'} eq 'D';
# DrawFile module attempts to emulate Draw's bug whereby
# \n\t is treated as a paragraph break, but in the
# process intruduces its own. D'oh
$para++ if $self->{'__MODE'} eq 'F';
}
if ($para) {
# print "paragraph $para \n";
$action = 0x20000;
# Bleurgh. Draw breaks the spec.
$para = int ((2 + $para) / 2) if $self->{'__MODE'} eq 'D';
} else {
# print "Embedded newline\n";
# Ingore it as per spec if it is followed by space
$words = ($$text =~ /^[\t ]/) ? '' : ' ';
# DrawFile module eats final single newline
$words = '' if $$text eq '' and $self->{'__MODE'} eq 'F';
if (not $seen_printing and not $current->[6]) {
die "No font set before single newline encountered\n";
}
}
} else {
$$text =~ s/^([^\\\n]*)//s;
($words = $1) =~ tr/\t/ /;
# Remove a single newline following text that ends with a space.
$$text =~ s/^\n(?![\n\t ])// if $words =~ / $/;
}
if (defined $words and length $words) {
if (not $seen_printing and not $current->[6]) {
carp "No font set before text '$words' encountered";
return ();
}
$seen_printing = 1;
$current->[3] # Width
= millipoint2draw
$current->[6]->StringBBox($current->[9] .= $words)->[2];
# Increase the right bbox edge if it is already calculated.
# No bozo, you can't remove this
$current->[11] = $current->[10] + $current->[3]
if defined $current->[10];
}
my $restore = 0;
if (!length $current->[9]) {
# $current points to an empty thing
pop @line;
$restore = 1;
}
if (@line) {
WRAP: while (1) {
# We have text. Check how much overflows margins
# Hike off what we can if we overflow a line
my $which = 0;
# 1 hour later - don't let it auto-vivify
while (defined $line[$which]
and defined $line[$which]->[10]) {
$which++
}
# This loop may run zero times
while (defined $line[$which]) {
# First see if we live at an absolute x offset
unless (defined ($line[$which]->[10]
= $line[$which]->[1])) {
# First object is at left margin (ie offset zero from it)
# Rest are previous object offset + previous object width
# print STDERR "'$words' $which $line[$which-1]->[10]\n";
$line[$which]->[10] = $which ? ($line[$which-1]->[10]
+ $line[$which-1]->[3])
: 0;
}
$line[$which]->[11] = $line[$which]->[10]
+ $line[$which]->[3];
$which++;
}
# Right, everything has a position
my $width = $self->Width();
for ( $which = 0 ; $which < @line ; $which++ ) {
if ($line[$which]->[11] > $width) {
# Wrap time
my $victim = $line[$which];
# print "$victim->[11] > $width\n";
# print "Overflow with $which $victim->[10] "
# ."'$victim->[9]'\n";
my ($split) =
$victim->[6]->Split($victim->[9], ' ', 0,
# Remaining width
draw2millipoint $width - $victim->[10]);
# OK, life gets messy here.
# Need to find the last space that fits in the column
# (if any).
# If $split is not '' then it's in $victim
# Otherwise seach back in the line until we hit the last
# space.
#
# Then need to run forward from the position of the
# space checking all positions of soft hyphens until
# we either find
# 1 another space [this cuts search of early]
# 2 a soft hyphen that doesn't fit
# 3 we run out of text
# hangon - actually, that means that we hit the
# end of $victim, as we know that $victim won't
# all fit, so there is no way that $victim plus
# some more stuff will.
# hangon, I don't think that we can meet a space
# until we are in $victim again.
#
# each time that we find a soft hyphen that fits record
# its position
#
# So we have variables:
# object containing last known space/soft hyphen
# $found
# offset of (start of) last known space/soft hypen
# $split
# flag ('-' for soft hyphen, '' for space)
# $flag
# object we are currently searching.
# $which
#
# soft hyphens are not marked known until we verify that
# they fit on the line
my ($length, $found);
if (length $split) {
$found = $which;
# print "Splitting on space '$split'\n";
} else {
# OK, got to find that space
while ($which) {
if ($line[--$which]->[9] =~ /(.*) /) {
$split = $1;
$found = $which;
last;
}
}
}
# Doubt this will really help until there are more
# than about 3 soft hyphens in one word.
# (Units in millipoints)
# my $remains = $width
# - $victim->[6]->CharBBox('-')->[2];
# Now loop round the possible soft hypen positions
# If you are Draw or DrawPlus you let soft hyphens
# impinge into the right margin (but not go outside the
# column)
# Skip stuff before first space
$length = length $split;
my ($offset, $flag) = (0, '');
OBJECTS: while (1) {
# Assign to pos to start matching after prefix
# (or to make damn sure we aren't confused later on
# if this position happens to fail a soft hyphen
# check and then we return here for a soft hyphen
# check on the next line)
pos $line[$which]->[9] = $length;
while ($line[$which]->[9] =~ /\025-\n/sg) {
last OBJECTS if ($width < (
$line[$which]->[10] + # Start coord
millipoint2draw
$line[$which]->[6]->StringBBox("$`-")->[2]));
# Wah, it's loads of -> -> ->
# get here if it doesn't overflow
$split = $`;
$flag = '-';
$found = $which;
# print "Found - in $found '$split'\n";
}
# Got back to the object we started at, and we know
# for sure that it doesn't fit
last if $line[$which] eq $victim;
# OK, starting a new object, so there is no prefix
# text to skip
$length = 0;
$which++;
}
# OK.
# $found is undef if we really haven't been able to
# split anywhere. In that case split victim at any
# character
# otherwise
# $found is the index of the object to split
# $split is the text to strip from the front of it
# $flag = '-' if we're splitting on a soft hyphen:
# add '-' to $split
# strip soft hyphen from front of remainder
# else strip leading whitespace
if (defined $found) {
# Fake it as if we'd terminated at this point in the
# first place.
$which = $found;
$victim = $line[$which];
$victim->[9] = substr ($victim->[9], length $split);
if ($flag) {
# Soft hyphen found
$victim->[9] =~ s/^\025-\n//s;
$split .= $flag;
} else {
$victim->[9] =~ s/^ *//s;
}
# print "'$split' '$victim->[9]'\n";
} else {
die '!' unless $victim eq $line[$which];
# Waah. Single word too long and must be split
($split)
= $victim->[6]->Split($victim->[9], '', 0,
draw2millipoint
$width - $victim->[10]);
unless (length $split) {
$victim->[6] =~ /^([^ ]+)/;
die 'First character of word \'' . $1 .
'\' too wide for margins';
}
$victim->[9] = substr ($victim->[9], length $split);
}
# print "Loose '$split' keep '$victim->[9]'\n";
my @process;
if (length $victim->[9]) {
# There is some text left
$victim->[3] = millipoint2draw
$victim->[6]->StringBBox($victim->[9])->[2];
# print "Now $victim->[3]\n";
# Remove all items up to item before the split item.
@process = splice @line, 0, $which;
# Copy the split item. The copy in @line has
# the second half of the text and the correct
# width
# Our copy referenced via $vicitm can now be
# ammended without affecting the details in @line
$victim = [@$victim];
} else {
# Remove all items including the "split" item, which
# appears to have no printable characters after
# split point.
# I don't think that we should ever end up in here.
# print "You aren't here with $which '$split' "
# ."'$victim->[9]' '$line[$which+1]->[9]'\n";
# Wrong. \C255 0 0/swings \B0 255 0
# splits on the space after swings. The space is
# then eaten by the s///; above.
# So we need to remove the empty last element, as it
# is a reference to the same array as $victim.
# (and hence when we assign to it (below) we'll be
# writing to two places)
@process = splice @line, 0, $which;
shift @line; # Remove this empty entry
unless (@line or $restore) {
# Make sure there will be at least one entry
# in the line accumulator next time round
@line = $current = $self->reset_block();
# 0x800000 hack was here. It doesn't work :-)
}
}
if (@line) {
# However, if there was a vertical move, we have it
# in our copy, so the original doesn't need it
$line[0]->[2] = 0;
# And the original is on a new line, so it can't be
# appended to the previous text.
$line[0]->[0] |= 0x101;
}
# Remove all the calculated x positions on the remaining
# items, so that next time round the loop they get
# recalculated.
foreach (@line) {
undef $_->[10];
}
# Copy the first half text into vicitm and write its
# width
$victim->[3] = millipoint2draw
$victim->[6]->StringBBox($victim->[9] = $split)->[2];
$victim->[11] = $victim->[10] + $victim->[3];
push @$output, &__doaline ($self, $self->{'__ALIGN'},
@process, $victim);
$self->PendingMargins();
return $output
unless defined $self->LeadBy($self->{'__LEAD'});
redo WRAP;
}
}
last WRAP;
}
}
# warn "$restore $#line $current $line[$#line]";
# warn "$restore $#line $current $line[$#line]";
# Force final flush
$action |= 0x10000 unless length ($$text);
if ($action) {
# Do it
# (unless we're being the DrawFile module and \A)
if ($action & 0x7F0000) {
# Line or paragraph
# printf "Flushing %8X:\n", $action;
# foreach my $chunk (@line) {
# print "\t$chunk->[8]\n";
# }
# print "\n";
if ((($action & 0x7F0000) == 0x40000)
and $self->{'__MODE'} eq 'F') {
$action = 0
} else {
# Why this not work?
# unless ($action & 0x40000 and not @line) {
unless ($action & 0x40000 and not $seen_printing) {
my $align = $self->{'__ALIGN'};
$align = 'L' if $align eq 'D';
push @$output, &__doaline ($self, $align, @line);
@line = ();
if ($action & 0x20000) {
$self->LeadBy($self->{'__LEAD'}
+ $para * $self->{'__PLEAD'})
} else {
$self->LeadBy($self->{'__LEAD'})
}
$action |= 0x101;
# Force text and underline breaks.
}
}
# warn 'Bailout' if $self->{'__BAILOUT'};
return $output if $self->{'__BAILOUT'};
if (defined $self->{'__PENDINGALIGN'}) {
$self->{'__ALIGN'} = $self->{'__PENDINGALIGN'};
delete $self->{'__PENDINGALIGN'};
}
}
if ($action & 0xFFFFFF) {
# Making a new array current
$restore = 1;
$current = $self->reset_block(($seen_printing ? $action
: undef),
undef, undef, $current->[2]);
}
}
# Do the pending margins unless we have some printing text.
$self->PendingMargins() unless @line;
push @line, $current if $restore;
}
$output
}
# Self
# Alignment
# Array of things
sub __doaline {
my $self = shift;
my $align = shift;
return () unless @_;
my ($left, $right) = ($self->StartX(), $self->EndX());
my ($extra, $x, $y) = (0, 0, $self->StartY());
# Fake the margins to acchieve the desired alignment.
if ($align eq 'D') {
# $spaces = 0;
my $j_from = @_; # Object number
my ($spaces, $width);
while ($j_from) {
last if defined $_[--$j_from][1];
}
# $object >= 0
my @done = splice @_, 0, $j_from;
# @_ now contains only the objects that need justifying.
my $j_left = $left + ($_[0][1] || 0);
@_ = (@done, map {
my $current = $_;
my $flag = $$current[0];
my $starty = $$current[2];
my @list = ();
$$current[0] = 0x20; # Text horizontal shift break
$$current[2] = 0; # no vertical move
while (length $$current[9] and $$current[9] =~ s/^([^ ]*)//) {
my $bit = [@$current];
$$bit[9] = $1;
if ($$current[9] =~ s/^( +)//) {
# Find if there are any trailing spaces and if so append
# Write the space count for this object.
$spaces += $$bit[12] = length $1;
$$bit[9] .= $1;
}
if (length $$bit[9]) {
$width += $$bit[3]
= millipoint2draw $$bit[6]->StringBBox($$bit[9])->[2];
push @list, $bit
} else {
confess "Error with '$$current[9]' remaining";
}
}
$list[0][0] = $flag; # Restore true flags for first object
$list[0][2] = $starty; # Restore true y offset for first object
@list;
} @_);
# Spaces = 0 is equivalent to left justification.
# oops. that's what happens anyway :-)
# $width gives right edge of last thing
$extra = (($right - $j_left - $width) / $spaces) if $spaces;
# Split extra space equally for each space, even if they are different
# font sizes.
# print "$spaces $extra\n" if defined $spaces;
} elsif ($align eq 'L') {
} elsif ($align eq 'R') {
# $width = $_[$#_]->[11];
$left = $right - $_[$#_]->[11];
} elsif ($align eq 'C') {
my $centre = ($left + $right) / 2;
my $width = $_[$#_]->[11];
$left = $centre - $width / 2;
$right = $centre + $width / 2;
} else {
confess "Unknown alignment code '$align'";
}
my ($starty, $nextx, @output);
$starty = $y;
$nextx = 0;
my @text;
# start x, start y, length, colour, thickness
# length is left edge of next text object.
my @underline;
foreach my $object (@_) {
$object->[9] =~ s/\025-\n//gs; # Strip still-soft hyphens
$x = defined ($object->[1]) ? $object->[1] : $nextx;
if ($object->[0] & 255) {
# Break
if (@text) {
if (my $output = RISCOS::DrawFile::Text->new (\@text, 7)) {
push @output, ref ($output) eq 'ARRAY' ? @$output : $output;
}
}
$y -= $object->[2];
# fore, back, font, h, w, x, y, text, kern, r2l, trans
# colours already packed so pass a reference
@text = (\$object->[4], \$object->[5], $object->[6], undef, undef,
$left + $x, $y, $object->[9]);
} else {
$text[7] .= $object->[9];
}
$nextx = $x + $object->[3] + $extra * ($object->[12] || 0);
# x still holds start of this object
# nextx has x for next object (possibly corrected for justification
if ($object->[0] & 0xFF00) {
# Underline break
push @output, scalar RISCOS::DrawFile::Path->new (
# Move to the start, line to the width
[[[2, $underline[0], $underline[1]],
[8, $underline[2], $underline[1]]],
# Fill, line colours, width
undef, $underline[3], $underline[4]]) if @underline;
if ($object->[8]) {
# DrawPlus is just plain inconsistent here - change the zoom!
@underline = ($left + $x, $y + $object->[7] - $object->[8] / 2,
$left + $nextx, \$object->[4], $object->[8]);
} else {
@underline = ();
}
}
elsif ($object->[8]) {
$underline[2] = $left + $nextx;
}
}
if (@text) {
if (my $output = RISCOS::DrawFile::Text->new (\@text, 7)) {
push @output, ref ($output) eq 'ARRAY' ? @$output : $output;
}
}
push @output, scalar RISCOS::DrawFile::Path->new (
[[[2, $underline[0], $underline[1]],
[8, $underline[2], $underline[1]]],
# Fill, line colours, width
undef, $underline[3], $underline[4]]) if @underline;
$starty -= $y;
# Remove this for DrawPlus-like behaviour
$self->LeadBy($starty) if $starty and ($self->{'__MODE'} ne '+' or
$self->{'__MODE'} ne 'F');
@output
}
sub reset_block ($;$$$) {
my ($self, $action, $x, $y) = @_;
# $x = $self->{'__LEFTM'} unless (@_ > 1); Don't set this.
$y = 0 unless defined $y;
if (defined ($self->{'__VERT'})) {
$y += $self->{'__VERT'};
undef $self->{'__VERT'};
}
$action = 0x118 unless defined $action;
[$action, $x, $y, 0, $self->{'__FORE'}, $self->{'__BACK'},
$self->CurrentFont(), $self->{'__UPOS'}, $self->{'__UWIDTH'}, ''];
}
sub CurrentColumn {
my $self = shift;
my $cc = \$self->{'__CURCOL'};
return $$cc if defined $$cc;
unless (defined ($$cc = $self->ShiftCols())) {
$self->{'__BAILOUT'} = 1;
} else {
$self->{'__STARTX'} = $$$cc[0] + $self->{'__LEFTM'}
if defined $self->{'__LEFTM'};
if (defined $self->{'__RIGHTM'}) {
$self->{'__ENDX'} = $$$cc[2] - $self->{'__RIGHTM'};
$self->{'__LINEWIDTH'} = $self->{'__ENDX'} - $self->{'__STARTX'}
if defined $self->{'__LEFTM'};
}
}
$$cc;
}
sub StartY {
my $self = shift;
if (defined $self->{'__CURCOL'}) {
my $y = $self->{'__STARTY'};
return $y if defined $y;
}
return undef unless defined (my $cc = $self->CurrentColumn());
$self->{'__STARTY'} = $cc->[3] - $self->{'__LEAD'};
}
sub PendingMargins() {
return unless $_[0]->{'__PENDINGM'};
$_[0]->Margins(@{$_[0]->{'__PENDINGM'}});
delete $_[0]->{'__PENDINGM'};
}
sub Margins ($$$) {
my ($self, $left, $right) = @_;
my $col = $self->CurrentColumn();
$self->{'__STARTX'} = $$col[0] + ($self->{'__LEFTM'} = point2draw $left);
$self->{'__ENDX'} = $$col[2] - ($self->{'__RIGHTM'} = point2draw $right);
$self->{'__LINEWIDTH'} = $self->{'__ENDX'} - $self->{'__STARTX'};
}
sub StartX ($) {
$_[0]->{'__STARTX'};
}
sub EndX ($) {
$_[0]->{'__ENDX'};
}
sub Width ($) {
$_[0]->{'__LINEWIDTH'}
}
sub LeadBy ($$) {
my ($self, $by) = @_;
return undef if $self->{'__BAILOUT'};
# This makes sure that __STARTY is initialised if a line break is found
# before any printing text
my $y = $self->{'__STARTY'} = $self->StartY() - $by;
return $y if ($y >= $self->CurrentColumn()->[1]);
# print "lead by $by drops off end\n";
undef $self->{'__CURCOL'}; # New column
$self->StartY();
}
sub CurrentFont {
my $self = shift;
my $font = $self->{'__FONT'}->{$self->{'__CURFONT'}}
if defined $self->{'__CURFONT'};
if (ref ($font) eq 'ARRAY') {
# Find the font now. Don't bother finding fonts that are declared but
# never used in the text area.
# Don't leave the font as an array to pass to string width because this
# will result in tons of calls to find and loose it for each call.
# Remember that the destructor looses this object correctly :-)
$font = RISCOS::Font->new(@$font);
unless ($font) {
warn $^E;
$font = RISCOS::Font->new('Trinity.Medium', 12);
}
$self->{'__FONT'}->{$self->{'__CURFONT'}} = $font if defined $font;
}
$font;
}
# Pass in self, reference to scalar
# 0x01000000 line format change (margins, centring, tabstops, leading)
# 0x00800000 internal hack to force regeneration of block
# 0x00040000 line break unless at start (or end) of line (\A)
# 0x00020000 new paragraph
# 0x00010000 forces line break (not new paragraph)
# 0x00000100 underline break
# 0x00000020 text horizontal shift break
# 0x00000010 text vertical shift break
# 0x00000008 text colour break
# 0x00000004 text size break
# 0x00000002 text font break
# 0x00000001 text new paragraph
# return param 2 (if defined) is text to add to output string
# CHECK that input string is actually shorter - fatal error if it is not.
sub A ($$) { # PRM wrong
my $self = shift;
${$_[0]} =~ s#^\\A(.)[\n/]?##s; # \n eaten here
$self->{'__PENDINGALIGN'} = $1; # align code is case sensitive
0x01040000 # Force a *conditional* line break (PRM wrong)
}
sub BC {
${$_[1]} =~ s#^\\[BC]\s*(\d+)\s+(\d+)\s+(\d+)[/\n]##s;
pack 'I', ($1 << 8) | ($2 << 16) | ($3 << 24)
}
sub B ($$) { # PRM wrong
my $self = $_[0];
$self->{'__BACK'} = BC (@_);
8 # Force a text break
}
sub C ($$) { # PRM wrong
my $self = $_[0];
$self->{'__FORE'} = BC (@_);
8 # Force a text break
}
# Don't think that we actually pay attention to this
sub D ($$) { # PRM wrong
my $self = shift;
${$_[0]} =~ s#^\\D\s*(\d+)[/\n]##s;
($self->{'__COLNUM'}) = $1;
undef
}
sub F ($$) { # PRM wrong
my $self = shift;
my $fonthash = $self->{'__FONT'};
# And the PRM says:
# ${$_[0]} =~ s#^\\F(\d\d?)(\S+)\s+(\d+)(\s+(\d+))?[/\n]##s;
# And the truth is:
${$_[0]} =~ s#^\\F\s*(\d\d?)\s*(\S+)\s+([\d.]+)(\s+([\d.]+))?[/\n]##s;
# ($num, $name, $width, $size)
$fonthash->{$1} = [$2, $5, $3]; # 5 because 4 is the outer nesting ()
2 # Don't carry on
# Pathalogical programmers write
# \0Hello\F0 Trinity.Bold 12/ W\F0 Homerton.Medium 12/orld
}
sub digit ($$) { # PRM wrong
my $self = shift;
${$_[0]} =~ s#^\\(\d\d?)[\n/]?##s; # \n eaten here
# One point where I don't want undef == 0
return 0 if defined ($self->{'__CURFONT'}) and $self->{'__CURFONT'} == $1;
# Force a canonical numeric form, so that "03" and "3" hash identically
$self->{'__CURFONT'} = 0 + $1;
0x006 # Text break. Underline does *not* change if font size changes
}
sub L ($$) { # PRM wrong
my $self = shift;
${$_[0]} =~ s#^\\L\s*(\d+)[/\n]##s;
$self->{'__LEAD'} = point2draw (0 + $1); # Mustn't pass in raw $1
0 # Carry on.
}
sub M ($$) { # PRM wrong
my $self = shift;
${$_[0]} =~ s#^\\M\s*(\d+)\s+(\d+)[/\n]##s;
$self->{'__PENDINGM'} = [$1, $2];
0x01000000 # Carry on. Mad! Well, it would be except that Draw interprets
# M commands as being relevant to the next line, not this one.
}
sub P ($$) { # PRM wrong
my $self = shift;
${$_[0]} =~ s#^\\P\s*(\d+)[/\n]##s;
$self->{'__PLEAD'} = point2draw (0 + $1);
0x01000000 # Carry on.
}
sub U ($$) { # PRM wrong
my $self = shift;
if (${$_[0]} =~ s#^\\U\.[/]?##) { # This one is strict
undef $self->{'__UPOS'};
undef $self->{'__UWIDTH'};
} else {
my $size = point2draw ($self->CurrentFont()->PointY()) / 256;
${$_[0]} =~ s#^\\U\s*((-?[\d]+)\s+(\d+))[/\n]##s; # Definately \d
# ($pos, $width)
$self->{'__UPOS'} = $2 * $size;
$self->{'__UWIDTH'} = $3 * $size;
}
0x100 # Underline break.
}
sub V ($$) { # PRM wrong
my $self = shift;
${$_[0]} =~ s#^\\V\s*(-?\d+)/?##s; # definately \d - decimals not allowed
# for text - is up, but for paper co-ordinates y positive is upwards
$self->{'__UPOS'} += $self->{'__VERT'} = point2draw (-$1); # - ensures copy
# underline does not shift!
0x010 # Text break, not underline break
}
sub hyphen ($$) { # minus/hyphen soft hyphen PRM wrong
${$_[1]} =~ s#^\\-/?##s;
# See XFont_Paint - this is comment. But perl can scan for it at split time.
(0, "\25-\n") # Carry on.
}
sub newline ($$) { # newline
${$_[1]} =~ s#^\\\n##s;
0x10000 # Force line break
}
sub backslash ($$) { # backslash
${$_[1]} =~ s#^\\\\##s;
(0, '\\') # Carry on.
}
sub semicolon ($$) { # semicolon comment
${$_[1]} =~ s#^\\;.*\n##;
0 # Carry on.
}
%parser = (
'A' => \&A,
'B' => \&B,
'C' => \&C,
'D' => \&D,
'F' => \&F,
'L' => \&L,
'M' => \&M,
'P' => \&P,
'U' => \&U,
'V' => \&V,
'-' => \&hyphen,
"\n" => \&newline,
'\\' => \&backslash,
';' => \&semicolon,
);
$parser{0} = $parser{1} = $parser{2} = $parser{3} = $parser{4} =
$parser{5} = $parser{6} = $parser{7} = $parser{8} = $parser{9} = \&digit;
if ($mode eq 'L') {
$lax = 1;
$parser{'G'} = \&G,
$parser{'T'} = \&T;
$parser{'I'} = \&I;
}
# I
# \IP/ text to here is index to page.
# \II 4/ hidden page target
sub I ($$) {
my $self = shift;
${$_[0]} =~ s#^\\IP[/\n]|^\\II\s*(\S+?)[/\n]##s;
0 # Carry on.
}
# T
# \T./ clear tabs?
# \TL 172/ set tabstop?
# \TR 351/ ditto
# \TC 1/
sub T ($$) {
my $self = shift;
undef $self->{'__TAB_S'};
if (${$_[0]} =~ s#^\\T\s*\.[/\n]##) {
undef $self->{'__TAB'};
} else {
${$_[0]} =~ s#^\\T([LRC])\s*(\d+)[/\n]##s;
$self->{'__TAB'}->{point2draw (0 + $2)} = $1 . $2;
}
0
}
sub G ($$) {
my $self = shift;
${$_[0]} =~ s#^\\G\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)[/\n]##s;
$3 ne '0' ? (0, " «Insert illustration $4 at $1, $2» ")
: (0, " «Insert illustration $4 at $1, $2 ¿$3?» ")
}
# G
# \G 357 156 0 ID0500000001
# x, y, dunno, ID never seen dunno != 0
1;
__END__
=head1 NAME
RISCOS::Drawfile::TextArea::Parser
=head1 SYNOPSIS
=head1 DESCRIPTION
=head1 BUGS
=head1 AUTHOR
Nicholas Clark <F<nick@unfortu.net>>