ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/ActiveDoc/Switcher.pm
Revision: 1.16
Committed: Tue Nov 14 15:20:55 2000 UTC (24 years, 5 months ago) by williamc
Content type: text/plain
Branch: MAIN
CVS Tags: V0_19_3, V0_19_2, V0_19_1, V0_19_0, V0_18_5, V0_18_4, V_18_3_TEST, VO_18_3, V0_18_2, V0_18_1
Changes since 1.15: +19 -2 lines
Log Message:
import from v0_18_0

File Contents

# User Rev Content
1 williamc 1.1 # Switcher Module
2     #
3     # Look for elements given in input has in a string
4     # If found then call a routine name with the same name
5     # Implemented as an object to maintain state info between each line
6     # processed.
7     # Interface
8     # ---------
9     # new(file,objectref) : A new object - filename of file to parse
10     # objectref->of the methods
11     # usetags(tagobjref) : Specify a tagcontainer set to direct to
12     # to the desired routines
13     # usegroupchecker(groupchecker) : Set a groupchecker
14     # parse() : Parse the file
15     # line() : return the current line number of the parse
16 williamc 1.12 # tagstartline() : return the line number on which the current
17     # tag was opened
18 williamc 1.6 # stream(filehandle) : stream output to the filehandle if not handled
19     # in any other way
20 williamc 1.3 package ActiveDoc::Switcher;
21 williamc 1.1 require 5.001;
22     use Carp;
23    
24     sub new {
25     my $class=shift;
26     my $file=shift;
27     my $objectname=shift;
28     my $groupchecker=shift;
29    
30 williamc 1.4 $self = {};
31 williamc 1.1 $self->{allw}=$objectname;
32     bless $self, $class;
33     $self->_initialise($file);
34     return $self;
35     }
36    
37 williamc 1.6 sub stream {
38     my $self=shift;
39    
40     $self->{stream}=shift;
41     }
42    
43 williamc 1.8 sub streamexclude {
44     my $self=shift;
45     my $tag=shift;
46    
47     $tag=~tr/A-Z/a-z/;
48     $self->{streamexclude}{$tag}=1;
49     }
50    
51 williamc 1.1 sub _initialise (hash1) {
52     my $self=shift;
53     $self->{filename}=shift;
54    
55     # add a default groupchecker
56     use ActiveDoc::GroupChecker;
57     $self->{groupchecker}=GroupChecker->new();
58     $self->{groupchecker}->include("all");
59    
60     # Add a default TagContainer
61     use ActiveDoc::TagContainer;
62 williamc 1.3 $self->{tagcontainer}=ActiveDoc::TagContainer->new();
63 williamc 1.1
64     }
65    
66     sub usetags {
67     my $self=shift;
68     my $tagcontainer=shift;
69    
70     $self->{tagcontainer}=$tagcontainer;
71     }
72    
73     sub usegroupchecker {
74     my $self=shift;
75     my $ref=shift;
76    
77     $self->{groupchecker}=$ref;
78     }
79    
80     sub parse {
81     my $self=shift;
82     my $char;
83 williamc 1.4 my $buf;
84 williamc 1.1 $self->{linecount}=0;
85     $self->_resetvars();
86 williamc 1.6 $self->{streamstore}="";
87 williamc 1.8 $self->{streamtmp}="";
88 williamc 1.1
89     # Open the file
90     use FileHandle;
91 williamc 1.6 local $filehandle;
92 williamc 1.4 $filehandle=FileHandle->new();
93 williamc 1.6 $filehandle->open("<".$self->{filename})
94 williamc 1.2 or return 1;
95 williamc 1.4 # The buffering seems all messed up - best not to use it
96 williamc 1.5 $filehandle->setvbuf($buf, _IONBF, 3000);
97 williamc 1.1
98     # Start file processing
99 williamc 1.4 while ( ($_=<$filehandle>) ) {
100 williamc 1.1 $self->{linecount}++;
101     $self->{currentline}=$_;
102     $self->{stringpos}=0;
103     while ( ($char=$self->_nextchar()) ne "" ) {
104     $self->_checkchar($char);
105     } # end char while
106     } # End String while loop
107 williamc 1.5 undef $filehandle;
108 williamc 1.14 # make sure we close the last buffer
109     $self->_calltag($self->{textcontext}, $self->{textcontext},
110     $self->_getstore());
111     #$self->_printstream();
112 williamc 1.1 }
113    
114     #
115     # return the current line number
116     #
117     sub line {
118     my $self=shift;
119     return $self->{linecount};
120     }
121 williamc 1.12
122     # return the line the current tag was opened
123     sub tagstartline {
124     my $self=shift;
125     $self->{tagstart};
126     }
127 williamc 1.1 # --------------- Utility routines ----------------------------
128    
129     #
130     # Some initialisation of test suites
131     #
132     sub _resetvars {
133     my $self=shift;
134     $self->{quotes}=0;
135     $self->{lastlabel}="";
136     $self->{textcontext}='none';
137     $self->{tagcontext}="text";
138     $self->_resetstore();
139     }
140    
141     #
142     # Check for control characters
143     #
144     sub _checkchar {
145     my $self=shift;
146     my $char=shift;
147     my $string;
148    
149 williamc 1.6
150 williamc 1.1 # ---- In a tag
151     if ( $self->{tagcontext}=~/tag/ ) {
152 williamc 1.16 $self->{tagbuff}=$self->{tagbuff}.$char;
153 williamc 1.1 if ( ! $self->_quotetest($char) ) {
154     if ( ! $self->_labeltest($char) ) {
155     if ( $char eq ">") { $self->_closetag(); }
156     else { $self->_putstore($char); }
157     }
158     }
159     }
160     # ------ Outside a tag
161     else {
162     if ( $char eq "<") { $self->_opentag() }
163     else { $self->_putstore($char) }
164     }
165     }
166    
167    
168     #
169     # Return the next character from the current string buffer
170     #
171     sub _nextchar() {
172     my $self=shift;
173     my $char;
174     $char=substr($self->{currentline},$self->{stringpos}++,1);
175 williamc 1.14 #print "Debug : Fetching character $char\n";
176 williamc 1.6
177     # Keep a record for any stream processes
178     $self->{streamstore}=$self->{streamstore}.$char;
179    
180 williamc 1.1 return $char;
181     }
182    
183     sub _opentag {
184     my $self=shift;
185     my $char;
186 williamc 1.12
187     # Keep a record of where the tag started
188     $self->{tagstart}=$self->line();
189 williamc 1.1
190     # Close the last text segment
191 williamc 1.8 $self->{streamtmp}=$self->_popstream();
192 williamc 1.1 $self->_calltag($self->{textcontext}, $self->{textcontext},
193     $self->_getstore());
194     $self->_resetstore();
195     $self->_resetlabels();
196    
197     # Do we have an opening or closing tag?
198     if ( ($char=$self->_nextchar()) eq "/" ) { #we have a closing tag
199 williamc 1.16 $self->{tagbuff}="<".$char;
200 williamc 1.1 $self->{tagcontext}="endtag";
201     }
202     else { # an opening tag
203 williamc 1.16 $self->{tagbuff}="<";
204 williamc 1.1 $self->{tagcontext}="starttag";
205     $self->_checkchar($char);
206     }
207     #print "\nDebug : Opening $self->{tagcontext}\n";
208     }
209    
210     #
211     # Close a tag
212     #
213     sub _closetag {
214     my $self=shift;
215     my $tagroutine;
216    
217     # -- Finish off any labels/get tagname
218     $self->_closelabel();
219    
220     # -- Call the associated tag function if appropriate
221 williamc 1.13 if ( defined $self->{tagname} ) {
222     $tagroutine=$self->{tagname}."_".$self->{tagcontext};
223     $self->_calltag($tagroutine, $self->{tagname},
224 williamc 1.1 $self->{tagvar});
225 williamc 1.13 #print "\nDebug : Closing Tag $tagroutine\n";
226 williamc 1.1
227 williamc 1.13 # -- Now make sure the text context is set for calling routines to
228     # -- deal with text portions outside of tags
229 williamc 1.15 if ( ($self->{tagcontext} eq "starttag") ) {
230     if ( $self->{tagcontainer}->definescontext($self->{tagname}) ) {
231     push @{$self->{textstack}} , $self->{textcontext};
232     $self->{textcontext}=$self->{tagname};
233     }
234 williamc 1.13 }
235     else {
236 williamc 1.1 if ( $#{$self->{textstack}} > -1 ) {
237 williamc 1.15 if ( $self->{textcontext} eq $self->{tagname} ) {
238     if ( $self->{tagcontainer}->definescontext($self->{tagname}) ) {
239     # -- watch out for valid tags we ignore in this parse
240     $self->{textcontext}=pop @{$self->{textstack}};
241     }
242     }
243 williamc 1.1 else { #The tag we are closing is not the last one so
244     # we keep our current context.
245     $self->_removefromstack($self->{tagname},$self->{textstack});
246     }
247    
248     }
249     else { # more close tags than open ones
250 williamc 1.15 if ( $self->{tagcontainer}->definescontext($self->{tagname}) ) {
251 williamc 1.1 print "Warning : Unmatched </...> tag on line ".
252     $self->line()."\n";
253 williamc 1.15 }
254 williamc 1.1 }
255 williamc 1.13 }
256 williamc 1.1 }
257     # Reset context back to text
258     $self->{tagcontext}="text";
259     }
260    
261     sub _calltag {
262     my $self=shift;
263     my $tagroutine=shift;
264     my @args=@_;
265     my $rt;
266 williamc 1.6 my $found=0;
267 williamc 1.1
268     if ( $self->{groupchecker}->status() ||
269     ( $self->{tagcontainer}->inquiregroup($tagroutine)) ) {
270 williamc 1.7 ($rt,$obj)=$self->{tagcontainer}->getroutine($tagroutine);
271 williamc 1.1 if ( $rt ne "" ) {
272 williamc 1.7 if ( ! defined $obj ) {
273 williamc 1.1 &{$rt}( $self->{allw},@_);
274 williamc 1.7 }
275     else {
276     &{$rt}( $obj,@_);
277     }
278     $found=1;
279 williamc 1.1 }
280     }
281 williamc 1.6
282 williamc 1.8 # stream function
283     if ( ! exists $self->{streamexclude}{$tagroutine} ) {
284 williamc 1.6 $self->_printstream();
285     }
286     $self->_clearstream();
287     }
288    
289     sub _clearstream {
290     my $self=shift;
291     $self->{streamstore}=(($self->{streamtmp} ne "")?$self->{streamtmp}:"");
292     $self->{streamtmp}="";
293     }
294    
295     sub _popstream {
296     my $self=shift;
297     $self->{streamstore}=~s/(.*)(.)$/$1/;
298     return $2;
299     }
300    
301     sub _printstream {
302    
303     my $self=shift;
304    
305     # Stream output functionality
306     if ( defined $self->{stream} ) {
307     print {$self->{stream}} "$self->{streamstore}";
308     }
309 williamc 1.1 }
310    
311     sub _removefromstack {
312     my $self=shift;
313     my $name=shift;
314     my $stack=shift;
315     my $this;
316    
317     undef @tempstack;
318     #print "In ----".$#{$stack};
319     # Keep popping until we find our string
320     while ( ($this=(pop @{$stack})) ne "$name") {
321     push @tempstack, $this;
322     if ( $#{$stack} < 0 ) { last; }
323     }
324     # Now put them back
325     while ( $#tempstack>-1) {
326     $this=pop @tempstack;
327     push @{$stack}, $this;
328     }
329     #print " Out ----".$#{$stack};
330     }
331    
332     #
333     # Quote handling
334     #
335    
336     sub _quotetest {
337     my $self=shift;
338     my $char=shift;
339    
340     # --- Are we already in a quote context?
341     if ( $self->{quotes} ) {
342     if ( $char eq $self->{openquote} ) {
343     $self->{quotes}=0;
344     }
345     else {
346     $self->_putstore($char);
347     }
348     }
349     # --- Unquoted Context
350     elsif ( (($char eq "\"") || ($char eq "\'") || ($char eq "\`")) ) {
351     $self->{quotes}=1;
352     $self->{openquote}=$char;
353     }
354     else { return 0; } # Return zero if not quoted
355     return 1; # 1 otherwise
356     }
357    
358     #
359     # Label handling
360     #
361     sub _labeltest {
362     my $self=shift;
363     my $char=shift;
364    
365     # Spaces are markers between tags
366     if ( ($char eq " ") || ($char eq "\n") || ($char eq "\t")) {
367     $self->_closelabel();
368     }
369     # Check for a change in label status
370     elsif ( $char eq "=" ) {
371     $self->{lastlabel}=$self->_getstore();
372     $self->_resetstore();
373     }
374     else {
375     return 0;
376     }
377     return 1;
378     }
379    
380     sub _resetlabels {
381     my $self=shift;
382     undef $self->{tagvar};
383 williamc 1.9 undef $self->{tagname};
384 williamc 1.1 }
385    
386     sub _closelabel {
387     my $self=shift;
388    
389     # Do we have a label name?
390     if ( $self->{lastlabel} ne "" ) {
391 williamc 1.15 (my $label=$self->{lastlabel})=~tr[A-Z][a-z];
392     $self->{tagvar}{$label}=$self->_getstore();
393 williamc 1.1 $self->{lastlabel}="";
394     }
395     elsif ( $self->_getstore() ne "") {
396 williamc 1.9 # Then it must be the tag name
397     if ( ! defined $self->{tagname} ) {
398     ($self->{tagname}=$self->_getstore())=~tr/A-Z/a-z/;
399     }
400     else {
401 williamc 1.16 # do not die anymore - breaks non tag documents
402     #die ">Tag syntax error in $self->{tagname} on line ".
403     # $self->line()." of file \n$self->{filename}";
404     # -- assume that this is plain text
405     $self->{tagcontext}="text";
406     $self->_resetstore();
407     $self->_unshiftstore($self->{tagbuff});
408     $self->{tagbuff}="";
409     return;
410 williamc 1.9 }
411 williamc 1.1 }
412     $self->_resetstore();
413     }
414    
415     #
416     # Character Store management interface
417     #
418     sub _putstore() {
419     my $self=shift;
420     my $char=shift;
421    
422     $self->{stringbuff}=$self->{stringbuff}.$char;
423 williamc 1.16 }
424    
425     sub _unshiftstore() {
426     my $self=shift;
427     my $char=shift;
428    
429     $self->{stringbuff}=$char.$self->{stringbuff};
430 williamc 1.1 }
431    
432     sub _getstore() {
433     my $self=shift;
434    
435     return $self->{stringbuff};
436     }
437    
438     sub _resetstore {
439     my $self=shift;
440     $self->{stringbuff}="";
441     }