File Coverage

blib/lib/Convert/Context.pm
Criterion Covered Total %
statement 378 417 90.6
branch 172 224 76.7
condition 41 55 74.5
subroutine 39 42 92.8
pod 24 27 88.8
total 654 765 85.4


line stmt bran cond sub pod time code
1             #
2             # $Id: Context.pm,v 1.77 1998/10/03 22:21:23 martin Exp $
3             #
4             # Convert::Context, an attributed text data type
5             #
6             # Copyright (C) 1996, 1997 Martin Schwartz
7             #
8             # This program is free software; you can redistribute it and/or modify
9             # it under the terms of the GNU General Public License as published by
10             # the Free Software Foundation; either version 2 of the License, or
11             # (at your option) any later version.
12             #
13             # This program is distributed in the hope that it will be useful,
14             # but WITHOUT ANY WARRANTY; without even the implied warranty of
15             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16             # GNU General Public License for more details.
17             #
18             # You should have received a copy of the GNU General Public License
19             # along with this program; if not, you should find it at:
20             #
21             # http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/COPYING
22             #
23              
24             package Convert::Context;
25 1     1   751 use strict;
  1         3  
  1         5413  
26             my $VERSION=do{my@R=('$Revision: 1.77 $'=~/\d+/g);sprintf"%d."."%d"x$#R,@R};
27              
28             sub CS () {"C"};
29             my $Debug = 0;
30             my $default_acmp = sub { $_[0] cmp $_[1] };
31              
32 456     456 1 859 sub acmp { shift->_member("A", @_) }
33 244 50   244 0 602 sub docmode { shift->_mode(@_ ? ("DOC"):()) eq "DOC" }
34 207 50   207 0 477 sub textmode { shift->_mode(@_ ? ("TEXT"):()) eq "TEXT" }
35              
36 1305     1305   2321 sub _attrib { shift->_member("ATT", @_) }
37 1853     1853   3913 sub _charsize { shift->_member(CS, @_) }
38 455     455   857 sub _mode { shift->_member("MOD", @_) }
39 1336     1336   2246 sub _offset { shift->_member("O", @_) }
40 2873     2873   5189 sub _text { shift->_member("T", @_) }
41              
42 8278 100   8278   8988 sub _member { my $S=shift; my $n=shift; $S->{$n}=shift if @_; $S->{$n} }
  8278         8719  
  8278         15805  
  8278         23756  
43              
44             sub append {
45             #
46             # $Ct1 = $Ct1 -> append (($Ctn||$strn||$strRn)*)
47             #
48 76     76 1 171 my $S = shift;
49 76         132 my $acmp = $S->acmp();
50              
51 76         105 my ($Ct2, $o);
52 76         156 while (@_) {
53 137         156 $Ct2 = shift;
54 137 100       331 if (!ref($Ct2)) {
    50          
55 56         61 ${$S->_text} .= $Ct2;
  56         96  
56 56         133 next;
57             } elsif (ref ($Ct2) =~ /^SCALAR$/) {
58 0         0 ${$S->_text} .= $$Ct2;
  0         0  
59 0         0 next;
60             }
61 81         168 $o = $S->length();
62              
63 81 100       172 if (!$o) {
64 6         8 ${$S->_text} .= ${$Ct2->_text};
  6         11  
  6         11  
65 6         10 @{$S->_offset}=();
  6         11  
66 6         10 @{$S->_attrib}=();
  6         11  
67 6         8 push (@{$S->_offset}, @{$Ct2->_offset});
  6         11  
  6         16  
68 6         10 push (@{$S->_attrib}, @{$Ct2->_attrib});
  6         10  
  6         11  
69 6         16 next;
70             }
71              
72 75         81 ${$S->_text} .= ${$Ct2->_text};
  75         117  
  75         117  
73 75 50       138 next if $S->textmode;
74 75         163 my $cs = $S->_charsize;
75 75         136 my $cs2 = $Ct2->_charsize;
76 75         120 my $flag = ($cs==$cs2);
77              
78 75 100       176 if (! &$acmp ($S->_attrib->[$#{$S->_attrib}], $Ct2->_attrib->[0])) {
  75         122  
79 19         19 my $end = $#{$Ct2->_offset};
  19         29  
80 19 0       35 push (@{$S->_offset}, map
  0         0  
81 19         24 {$flag ? $_+$o : $o+$_/$cs2*$cs} @{$Ct2->_offset}[1..$end]
  19         32  
82             );
83 19         22 push (@{$S->_attrib}, @{$Ct2->_attrib}[1..$end]);
  19         27  
  19         27  
84             } else {
85 56 100       96 push (@{$S->_offset}, map
  58         203  
86 56         68 {$flag ? $_+$o : $o+$_/$cs2*$cs} @{$Ct2->_offset}
  56         92  
87             );
88 56         75 push (@{$S->_attrib}, @{$Ct2->_attrib});
  56         114  
  56         95  
89             }
90             }
91 76         266 $S;
92             }
93              
94             sub attrib {
95             #
96             # (1) $attrib = $Ct -> attrib ($o, [$attrib])
97             # (2) ([@attrib], [@o]) = $Ct -> attrib ($o, $l)
98             # (3) $attrib = $Ct -> attrib ($o, $l, $attrib)
99             # (4) 1 || undef = $Ct -> attrib ($o1, $l1, [@attrib], [@o])
100             # (5) 1 || undef = $Ct -> attrib ($o1, $l1, [@attrib], [@o], $o2, $l2)
101             # (6) 1 || undef = $Ct1 -> attrib ($o, $l, $Ct2)
102             # (7) 1 || undef = $Ct1 -> attrib ($o1, $l1, $Ct2, $o2, $l2)
103             #
104 102     102 1 217 my $S = shift;
105 102 50       162 return undef if $S->textmode;
106              
107 102 100 100     533 if (!$#_ || ($#_==1) && ref($_[1])) {
      66        
108             # case (1)
109 19 50       40 my $o = @_ ? shift : 0;
110 19 100       42 $o += $S->length() if $o<0;
111 19 100       43 return undef if $o<0;
112              
113 18         33 my $i = $S->_index($o);
114 18 100       38 $S->_attrib->[$i] = shift->[0] if @_;
115 18         34 return $S->_attrib->[$i];
116             }
117              
118 83 50       177 my $o1 = @_ ? shift : 0;
119 83 50       167 $o1 += $S->length() if $o1<0;
120 83 50       139 return undef if $o1<0;
121 83 50       126 my $l1 = @_ ? shift : 0;
122 83 100       148 if (!@_) {
123             # case (2)
124 66   100     131 my $il = $S->_index($o1) || 0;
125 66   100     155 my $ir = $S->_index($o1+$l1-1) || 0;
126             return (
127 66         109 [@{$S->_attrib}[$il, $il+1..$ir]],
  66         165  
128 66         114 [0, map $_-$o1, @{$S->_offset}[$il+1..$ir]]
129             );
130             }
131              
132 17 50       42 my $ref = @_ ? ref($_[0]) : "";
133 17 100       76 if (!$ref) {
    100          
134             # case (3)
135 1 50       3 my $attrib = @_ ? shift: 0;
136 1   33     7 return $S->_subattr($o1, $l1, [$attrib], [0]) && $attrib;
137             } elsif ($ref =~ /^ARRAY$/) {
138             # case (4) and (5)
139 12         29 return $S->_subattr($o1, $l1, @_);
140             } else {
141             # case (6) and (7)
142 4         6 my $Ct2 = shift;
143 4 50       10 push (@_, $_[2]) if $#_==2;
144 4         10 return $S->_subattr($o1, $l1, $Ct2->_attrib, $Ct2->_offset, @_);
145             }
146              
147 0         0 undef;
148             }
149              
150             sub charsize {
151 652     652 1 845 my ($S, $cs) = @_;
152 652         1033 my $cs_orig = $S->_charsize();
153 652 100 66     2154 return $cs_orig if !$cs || $cs_orig==$cs;
154 3         6 my $O = $S->_offset;
155 3         7 for (@$O) {
156 6         7 $_*=$cs_orig; $_/=$cs;
  6         13  
157             }
158 3         8 $S->_charsize($cs);
159             }
160              
161             sub chunks {
162             #
163             # [ [$str1, $attr1], [$str2, $attr2], [$str3, $attr3] ...] = $S->chunks
164             #
165 1     1 1 9 my $S = shift;
166 1         3 my $A = $S->_attrib;
167 1         4 my $O = $S->_offset;
168 1         3 my $T = $S->_text;
169 1         2 my $n = $#{$S->_offset};
  1         3  
170 1         3 my $left = 0;
171 1         3 my $cs = $S->_charsize;
172 1         22 [ map (
173             [substr($$T, $O->[$_-1]*$cs, $O->[$_]*$cs-$O->[$_-1]*$cs), $A->[$_-1]],
174             (1..$n)
175             ),
176             [ substr($$T, $O->[$n]*$cs, $S->length()*$cs-$O->[$n]*$cs), $A->[$n] ]
177             ];
178             }
179              
180             sub clone {
181 2     2 1 11 my $S = shift;
182 2         5 my $N = $S->new(
183             $S->_charsize,
184 2         5 \(my $text = ${$S->_text}),
185 2         5 [@{$S->_attrib}],
186 2         6 [@{$S->_offset}],
187             1
188             );
189 2         7 $N->_mode($S->_mode);
190 2         5 $N->acmp($S->acmp);
191 2         8 $N;
192             }
193              
194             sub dump {
195 0     0 1 0 my ($S, $mode) = @_;
196 0         0 print "Dumping (mode $mode), object ".
197             (($S =~ /(^[^=]*)/) && $1).
198 0   0     0 "\n" . ${$S->sdump($mode)} . "Done.\n\n\n"
199             ;
200 0         0 $S;
201             }
202              
203             sub eq {
204             #
205             # 1||0 = $Ct1 -> eq ($Ct2)
206             #
207 84     84 1 154 my ($S, $Ct2) = @_;
208 84 50       180 return undef if !$Ct2;
209 84 100       248 return 1 if $S eq $Ct2;
210 80 50       169 return 0 if !ref($Ct2);
211 80 50       168 return 0 if ref($S) ne ref($Ct2);
212 80 100       136 return 0 if $S->_charsize != $Ct2->_charsize;
213 77 100       103 return 0 if ${$S->_text} ne ${$Ct2->_text};
  77         126  
  77         132  
214 75         167 $S->_cmp_attribs($Ct2);
215             }
216              
217             sub index {
218             #
219             # $pos = $Ct -> index ($string [,$pos])
220             #
221 379     379 1 2118 my ($S, $str, $pos) = @_;
222 379         636 my $cs = $S->charsize;
223 379   100     1214 my $i = ($pos||0) * $cs - $cs;
224 379         391 while (1) {
225 1219   66     1148 $i = index(${$S->_text}, $str, $i+(($i%$cs)||$cs));
  1219         2033  
226 1219 100       2287 return $i if $cs == 1;
227 1166 100       1968 return $i if $i == -1;
228 1153 100       2052 if (!($i % $cs)) {
229 313         839 return $i / $cs;
230             }
231             }
232             }
233              
234             sub join {
235             #
236             # $Ct = Convert::Context -> join ($expr, ($Ctn||$strn||$strRn)*)
237             #
238             # $Ct1 = $Ct1 -> join ($expr, ($Ctn||$strn||$strRn)*)
239             #
240 6     6 1 30 my $S = shift;
241 6 50       17 return undef if !@_;
242 6         8 my $expr = shift;
243 6         11 my @extra = ();
244              
245 6 100       14 if (!ref($S)) {
246 5         9 $S = $S -> new (eval {$_[0]->charsize});
  5         33  
247             } else {
248 1         2 @extra = ($expr);
249             }
250 6 50       16 return $S if !@_;
251              
252 6         14 $S->append( @extra, shift, map {($expr, $_)} @_ );
  28         58  
253             }
254              
255 1     1 1 12 sub lc { shift->_apply_f_to_t("CORE::lc") }
256 1     1 1 8 sub lcfirst { shift->_apply_f_to_t("CORE::lcfirst") }
257              
258             sub length {
259             #
260             # $len = $Ct -> length ()
261             #
262 450     450 1 852 length(${$_[0]->_text}) / $_[0]->_charsize();
  450         817  
263             }
264              
265             sub ne {
266 72     72 1 209 !shift->eq(@_);
267             }
268              
269             sub new {
270 244     244 1 1914 my $proto = shift;
271 244   66     1071 my $S = bless ({}, ref($proto) || $proto);
272 244         537 $S->docmode (1);
273 244         482 $S->acmp ($default_acmp);
274              
275 244 100 100     990 if (@_ && !ref($_[0])) {
276 104         199 $S->_charsize(shift());
277             } else {
278 140         310 $S->_charsize(1);
279             }
280              
281 244 100 100     1110 if (@_ && ref($_[0])=~ /^ARRAY/) {
282 5         8 $S->_entry(@{shift()});
  5         14  
283 5         13 for (@_) { $S->append( $S->new(@{$_}) ) }
  34         44  
  34         87  
284             } else {
285 239         515 $S->_entry(@_);
286             }
287              
288             # Offsets and Attribute pairs doesn't match
289 244 50       226 return 0 if $#{$S->_offset} != $#{$S->_attrib};
  244         439  
  244         379  
290              
291 244         1311 $S;
292             }
293              
294             sub replace {
295 24     24 1 84 my ($S, $pattern, $replace, $option) = @_;
296 24 50       60 return 0 if !defined $pattern;
297 24 50       54 $replace = "" if !defined $replace;
298 24 100       44 $option = "" if !defined $option;
299              
300 24         44 my @L = ();
301 24         36 my %R_Context = ();
302 24         30 my %R_scalar = ();
303 24         38 my $array = "";
304 24         27 my $code = "";
305 24         32 my $Ct = "";
306 24         25 my $s_pattern = "";
307 24         30 my $s_replace = "";
308              
309 24 100       86 if ($array = ref ($pattern) =~ /^ARRAY/) {
    100          
310 3         4 for (0..$#{$pattern}) {
  3         11  
311 13 100       28 if (ref($pattern->[$_])) {
312 2         3 $R_Context {${$pattern->[$_]->_text}} = $_;
  2         6  
313 2         3 $s_pattern .= ${$pattern->[$_]->_text};
  2         7  
314             } else {
315 11         18 $R_scalar {$pattern->[$_]} = $_;
316 11         13 $s_pattern .= $pattern->[$_];
317             }
318 13         19 $s_pattern .= '|';
319             };
320 3         15 $s_pattern =~ s/\|$//;
321             } elsif (ref ($pattern)) {
322 4         6 $Ct = $pattern;
323 4         7 $s_pattern = ${$pattern->_text};
  4         8  
324 4         9 $code = (ref ($replace) =~ /^CODE/);
325             } else {
326 17         27 $s_pattern = $pattern;
327 17         31 $code = (ref ($replace) =~ /^CODE/);
328             }
329 24         32 $s_replace=$replace;
330              
331 24         28 my ($i, $m, $n, $oc, $lc);
332 24         45 my $cs = $S ->_charsize;
333 24   100     8810 $n = eval '${$S->text} =~ '.
334             's#$s_pattern#{
335             $oc=CORE::length($`); return $& if ($oc%$cs); $oc/=$cs;
336             $lc=CORE::length($&);
337             if ($lc%$cs) {
338             $lc+=($lc%$cs);
339             $m = CORE::substr(${$S->_text}, $oc*$cs, $lc);
340             } else {
341             $m = $&;
342             }
343             $lc/=$cs;
344             if ($array) {
345             if (defined ($i = $R_Context{$&})) {
346             $Ct = $pattern->[$i];
347             $s_replace = $replace->[$i];
348             } elsif (defined ($i = $R_scalar{$&})) {
349             $Ct = "";
350             $s_replace = $replace->[$i];
351             } else {
352             $Ct = "";
353             $s_replace = "";
354             }
355             $code = (ref ($s_replace) =~ /^CODE/);
356             }
357             if (!$Ct || $Ct->_cmp_attribs($S->attrib($oc, $lc))) {
358             push (@L, [$oc, $lc, $code ? &$s_replace($m, $S, $oc):$s_replace]);
359             }
360             $&;
361             }#e'.($option||"")
362             ;
363 24         190 while (@L) {
364 68         79 $S->substr(@{pop(@L)});
  68         245  
365             }
366 24         94 $n;
367             }
368              
369             sub sdump {
370             #
371             # \$buf = $S->sdump($mode)
372             #
373 0     0 0 0 my ($S, $mode) = @_;
374 0         0 my $n;
375 0         0 my $buf="";
376              
377 0 0       0 if ($mode) {
378 0         0 $buf .= "\"";
379 0         0 for (@{$S->chunks}) {
  0         0  
380 0 0       0 $buf .= sprintf ("<%s>", $_->[1]) if defined $_->[1];
381 0         0 $buf .= $_->[0];
382             }
383 0         0 $buf .= "\"\n";
384             } else {
385 0         0 $buf .= " text => \"" . ${$S->_text} . "\"\n";
  0         0  
386             }
387 0 0       0 if ($S->charsize()!=1) {
388 0         0 $buf .= sprintf (" charsize=%d, textlen=%d\n",
389             $S->charsize(), $S->length()
390             );
391             }
392 0         0 $n = $#{$S->_attrib}+1;
  0         0  
393 0         0 $buf .= sprintf (" attrib => [ " . ("%3s " x $n) . "]\n", @{$S->_attrib});
  0         0  
394 0         0 $n = $#{$S->_offset}+1;
  0         0  
395 0         0 $buf .= sprintf (" offset => [ " . ("%03x " x $n) . "]\n", @{$S->_offset});
  0         0  
396 0         0 \$buf;
397             }
398              
399             sub split {
400             #
401             # @Ct = $Ct -> split ($pattern, $option, $limit)
402             #
403 3     3 1 6 my ($S, $pattern, $option, $limit) = @_;
404 3         6 my @L = ();
405              
406 3 50       9 my $Ct = ref ($pattern) ? $pattern : "";
407 3 50       5 $pattern = ${$Ct->_text} if $Ct;
  0         0  
408 3         8 my $cs = $S->_charsize;
409              
410 3         6 my $o = 0;
411 3         5 my ($l, $ml);
412 3   50     548 eval '${$S->text} =~ '.
413             's#$pattern#{
414             $l = CORE::length($`);
415             $ml = CORE::length($&); $ml+=($ml%$cs); $ml/=$cs;
416             if (!($l % $cs) &&
417             (!$Ct ||
418             $Ct->_cmp_attribs($S->attrib($l/$cs, $ml))
419             )
420             ) {
421             push (@L, $S->substr($o, $l/$cs-$o));
422             $o = ($l/$cs+$ml);
423             }
424             $&;
425             }#e'."g".($option||"")
426             ;
427 3         20 push (@L, $S->substr($o));
428 3 50       8 if ($limit) {
429             # no better idea, how to limit, sigh...
430 0         0 @L[0..$limit-1];
431             } else {
432             # Split strips "trailing null fields", when no $limit given.
433 3 100       8 while (@L) { last if $L[$#L]->length(); pop(@L) }
  4         10  
  1         5  
434 3         19 @L;
435             }
436             }
437              
438             sub substr {
439             #
440             # $Context1 = $Context1 -> substr (
441             # $o1||undef, $l1||undef, $Context2, $o2||undef, $l2||undef
442             # )
443             #
444             # Substitutes $Context1->substr($o1, $l1) with $Context2->substr($o2, $l2)
445             #
446             # o1|o2: undef => 0
447             # l1|l2: undef => length($Contextn)
448             #
449 115     115 1 223 my ($S, $o1, $l1, $Ct2, $o2, $l2) = @_;
450              
451 115         191 my $len1 = $S->length();
452 115 50       262 $o1 = 0 if !defined $o1;
453 115 100       204 $o1 += $len1 if $o1<0;
454 115 100       181 return undef if $o1<0;
455 114         206 my $cs = $S->_charsize;
456              
457 114 100       226 $l1 = $len1 - $o1 if !defined $l1;
458              
459             #
460             # Case 1: Return a new partial Context
461             #
462 114 100       189 if (!$Ct2) {
463 41         66 return $S->new(
464             $cs,
465 41         43 \(my $text = substr(${$S->_text}, $o1*$cs, $l1*$cs)),
466             $S->attrib($o1, $l1),
467             1
468             );
469             }
470              
471 73         77 my $len2;
472              
473             #
474             # Case 2: Substitute argument is a simple string
475             #
476 73 100       156 if (!ref $Ct2) {
477 56         53 $len2 = CORE::length($Ct2);
478 56 50       107 $o2 = 0 if !defined $o2;
479 56 50       93 $o2 += $len2 if $o2<0;
480 56 50       102 $l2 = $len2 - $o2 if !defined $l2;
481              
482             # Special case: same string lengths: change only string.
483 56 100       117 if ($l1*$cs == $l2) {
484 43         64 substr(${$S->_text}, $o1*$cs, $l1*$cs) =
  43         75  
485             substr($Ct2, $o2, $l2)
486             ;
487 43         155 return $S;
488             }
489             # Normal case: different string lengths: create Context on the fly.
490 13         29 $Ct2 = $S->new(
491             $S->_charsize, \substr($Ct2, $o2, $l2), $S->attrib($o1, $l1)
492             );
493 13         37 $o2 = 0;
494 13         24 $l2 /= $cs;
495             }
496              
497             #
498             # Case 3: Substitute argument is another Context
499             #
500             #
501             # Note: The following 3 lines could do a similar job like the messy
502             # looking code afterwards. Everything would look fine and easy.
503             # The problem: That code would construct a new Context and would not
504             # change the old Context; further more I suspect it to be slower.
505             #
506             # return = $S->substr(0, $o1)
507             # ->join($Ct2)
508             # ->join($S->substr($o1+$l1))
509             # ;
510             #
511              
512 30         53 my $cs2 = $Ct2->_charsize;
513 30         66 $len2 = $Ct2->length();
514 30 100       80 $o2 = 0 if !defined $o2;
515 30 50       64 $o2 += $len2 if $o2<0;
516 30 100       60 $l2 = $len2 - $o2 if !defined $l2;
517              
518 30 50       57 if (!$S->textmode) {
519 30         61 $S->_subattr($o1, $l1, $Ct2->_attrib, $Ct2->_offset, $o2, $l2, $l2);
520             }
521              
522 30         53 substr(${$S->_text}, $o1*$cs, $l1*$cs) =
  30         55  
523 30         47 substr(${$Ct2->_text}, $o2*$cs2, $l2*$cs2)
524             ;
525              
526 30         142 $S;
527             }
528              
529             sub rindex {
530             #
531             # $pos = $Ct -> rindex ($string [,$pos])
532             #
533 265     265 1 1518 my ($S, $str, $pos) = @_;
534 265 100       678 $pos = $S->length() if !defined $pos;
535 265         520 my $cs = $S->charsize;
536 265         412 my $i = $pos * $cs + $cs;
537 265         272 while (1) {
538 365   66     342 $i = rindex(${$S->_text}, $str, $i-(($i%$cs)||$cs));
  365         610  
539 365 100       766 return $i if $cs == 1;
540 312 100       522 return $i if $i == -1;
541 308 100       602 if (!($i % $cs)) {
542 208         626 return $i / $cs;
543             }
544             }
545             }
546              
547             sub text {
548 39     39 1 136 shift->_text();
549             }
550              
551 3     3 1 18 sub tr { goto &y }
552 1     1 1 4 sub uc { shift->_apply_f_to_t("CORE::uc") }
553 1     1 1 3 sub ucfirst { shift->_apply_f_to_t("CORE::ucfirst") }
554              
555             sub y {
556             #
557             # $Ct -> y ($search_str, $replace_str, $mode)
558             # $Ct -> y (\@search[0..n], \@replace[0..n], $mode)
559             #
560 3     3 1 5 my ($S, $search, $replace, $mode) = @_;
561 3 50       8 $search = "" if !defined $search;
562 3 50       5 $replace = "" if !defined $replace;
563 3 50       7 $mode = "" if !defined $mode;
564 3         6 my $cs = $S->_charsize;
565 3 100       8 if (ref($search)) {
    100          
566 1         5 $S->replace($search, $replace, "g$mode");
567             } elsif ($cs==1) {
568 1         2 $mode =~ s/g//g;
569 1   50     109 eval '${$S->_text} =~ y/'.
      50        
      50        
570             ($search||"")."/".($replace||"")."/".($mode||"")
571             ;
572             } else {
573 1         14 $S->replace(
574             [map CORE::substr($search, $_*$cs, $cs), (0..(CORE::length($search)/$cs-1))],
575             [map CORE::substr($replace, $_*$cs, $cs), (0..(CORE::length($replace)/$cs-1))],
576             "g$mode"
577             );
578             }
579 3         11 $S;
580             }
581 0     0   0 sub _dl { my ($lR,$str)=@_;
582 0 0       0 print "$str: " if $str; printf "(".("'%s', "x($#{$lR}+1)).")\n", @{$lR};
  0         0  
  0         0  
  0         0  
583             }
584              
585             sub _apply_f_to_t {
586             #
587             # lc, lcfirst, uc, ucfirst
588             #
589 4     4   8 my ($S, $apply) = @_;
590 4         9 $S->new (
591             $S->_charsize,
592             \(eval "$apply".'(${$S->_text})'),
593 4         9 [@{$S->_attrib}], [@{$S->_offset}],
  4         9  
594             1
595             );
596             }
597              
598             sub _cmp_attribs {
599             #
600             # 1||0 = $Ct1 -> _cmp_attribs ($Ct2)
601             # 1||0 = $Ct1 -> _cmp_attribs ([@attrib], [@offset])
602             #
603 85     85   120 my ($S, $a2R, $o2R) = @_;
604 85 100       297 if (!defined $o2R) {
605 75         75 my $Ct2 = $a2R;
606 75         127 $a2R = $Ct2->_attrib;
607 75         130 $o2R = $Ct2->_offset;
608             }
609 85 100       162 return 0 if !$S->_cmp_slist($S->_attrib, $a2R);
610 75 100       147 return 0 if !$S->_cmp_nlist($S->_offset, $o2R);
611 74         396 1}
612              
613             sub _cmp_nlist {
614             #
615             # 1||0 = _cmp_nlist ([@list1], [@list2])
616             #
617 75     75   110 my ($S, $aR, $bR) = @_;
618 75 50       152 return 0 unless @$aR == @$bR;
619 75 100       146 for (0..$#$aR) { return 0 if $aR->[$_] != $bR->[$_] }
  215         562  
620 74         209 1}
621             sub _cmp_slist {
622             #
623             # 1||0 = _cmp_slist ([@list1], [@list2])
624             #
625 85     85   128 my ($S, $aR, $bR) = @_;
626 85         137 my $acmp = $S->acmp();
627 85 100       195 return 0 unless @$aR == @$bR;
628 84 100       192 for (0..$#$aR) { return 0 if &$acmp ($aR->[$_], $bR->[$_]) }
  224         434  
629 75         205 1}
630              
631             sub _entry {
632             #
633             # 1 = $S -> entry (\$text, [@attrib], [@offset], $mode)
634             #
635             # mode = 0: make copies of text, attrib and offset (store values)
636             # 1: use given references (store references)
637             #
638 244     244   363 my ($S, $textR, $attribR, $offsetR, $mode) = @_;
639            
640 244 100       374 if (!$mode) {
641 197 100       606 $S->_text (\(my $text = $textR ? $$textR : ""));
642 197 100       685 $S->_attrib ($attribR ? [@$attribR] : [0]);
643 197 100       630 $S->_offset ($offsetR ? [@$offsetR] : [0]);
644             } else {
645 47 50       110 $S->_text ($textR ? $textR : \(""));
646 47 50       101 $S->_attrib ($attribR ? $attribR : [0]);
647 47 50       99 $S->_offset ($offsetR ? $offsetR : [0]);
648             }
649 244         356 1}
650              
651             sub _index {
652             #
653             # $context_index = -> _index ($position [,[@offset]])
654             #
655 317     317   428 my ($S, $pos, $oR) = @_;
656 317 100       617 return 0 if !$pos;
657 266 100       478 return undef if $pos < 0;
658 265 100       598 $oR = $S->_offset if !defined $oR;
659              
660 265         305 my $og = $#{$oR};
  265         374  
661 265 100       690 return $og if $pos >= ($oR->[$og]);
662 163         168 my $ug = 0;
663 163         156 my $step;
664              
665 163         318 while ($step = ($og-$ug) >> 1) {
666 462 100       808 if ($oR->[$ug+$step] <= $pos) {
667 219         447 $ug += $step;
668             } else {
669 243         475 $og -= $step;
670             }
671             }
672              
673 163         931 $ug;
674             }
675              
676             sub _subattr {
677             #
678             # ([@attrib], [@o]) =
679             # $Ct -> _subattr ($o1, $l1, [@attrib], [@o] [,$o2, $al2 [,$tl2]])
680             #
681             # Substitutes $Ct's attributes from position o1 and length l1 with
682             # @attrib and @o. The substituted textlength will stay l1, unless tl2 given.
683             #
684 47     47   86 my ($S, $o1, $l1, $aR2, $oR2, $o2, $al2, $tl2) = @_;
685 47 50       93 return undef if !defined $oR2;
686              
687 47         100 my $len1 = $S->length();
688 47 50       119 $o1 += $len1 if $o1<0;
689 47 50       87 return undef if $o1<0;
690 47 50       107 return undef if ($o1+$l1) > $len1;
691 47 100 100     172 return 1 if ($o1 && ($o1==$len1));
692              
693 46 100       99 $al2 = $l1 if !defined $al2;
694 46 100       86 $tl2 = $l1 if !defined $tl2;
695 46 100       80 $o2 = 0 if !defined $o2;
696 46 50       82 return undef if $o2<0;
697            
698 46 100       117 my $i1_right = $o1 ? $S->_index($o1-1) : 0;
699 46         101 my $i2_left = $S->_index($o2, $oR2);
700 46 100       145 my $i2_right = ($o2+$al2-1) ? $S->_index($o2+$al2-1, $oR2) : 0;
701 46         145 my $i3_left = $S->_index($o1+$l1);
702              
703 46         93 my $a1_right = $S->_attrib->[$i1_right];
704 46         73 my $a2_left = $aR2->[$i2_left];
705 46         63 my $a2_right = $aR2->[$i2_right];
706 46         90 my $a3_left = $S->_attrib->[$i3_left];
707              
708 46         95 my $o1_right = $S->_offset->[$i1_right];
709 46         128 my $o2_left = $oR2->[$i2_left];
710              
711 46         76 my @a_left=(); my @o_left=();
  46         58  
712 46         55 my @a_right=(); my @o_right=();
  46         59  
713              
714 46         71 my $diff_middle = $tl2 - $l1;
715 46         51 my $diff_right = $o1 - $o2;
716              
717 46         84 my $acmp = $S->acmp();
718              
719 46 100       99 if ($o1) {
720 33         64 push (@a_left, $a1_right);
721 33         44 push (@o_left, $o1_right);
722             }
723              
724 46 100 100     144 if ((!$o1) || &$acmp($a1_right, $a2_left)) {
725 31         54 push (@a_left, $a2_left);
726 31         86 push (@o_left, $o1);
727             }
728              
729 46 100 100     144 if ( (($o1+$l1) < $len1) &&
730             &$acmp ($a2_right, $a3_left)
731             ) {
732 25         42 push (@a_right, $a3_left);
733 25         35 push (@o_right, $o1+$tl2);
734             }
735             #print "a1r=$a1_right a2l=$a2_left a2r=$a2_right a3l=$a3_left\n";
736             #print "i1r=$i1_right i2l=$i2_left i2r=$i2_right i3l=$i3_left\n";
737             #print "o1=$o1 l1=$l1 o2=$o2 al2=$al2 tl2=$tl2 o1r=$o1_right o2l=$o2_left\n";
738             #print "len1=$len1\n";
739             #print "al=(@a_left) ar=(@a_right) ol=(@o_left) or=(@o_right)\n\n";
740              
741 46         84 splice (@{$S->_attrib},
  46         152  
742             $i1_right,
743             $i3_left-$i1_right+1,
744             (@a_left,
745 46         53 @{$aR2}[$i2_left+1..$i2_right],
746             @a_right
747             )
748             );
749              
750 46         82 for (@{$S->_offset}[$i3_left+1 .. $#{$S->_offset}]) {
  46         84  
  46         89  
751 142         190 $_ += $diff_middle
752             }
753            
754 46         83 splice (@{$S->_offset},
  30         133  
755             $i1_right,
756             $i3_left-$i1_right+1,
757             (@o_left,
758 46         77 (map {$_+$diff_right} @{$oR2}[$i2_left+1..$i2_right]),
  46         111  
759             @o_right
760             )
761             );
762 46         183 1}
763              
764             "Atomkraft? Nein, danke!"
765              
766             __END__