ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/ActiveDoc/Switcher.pm
Revision: 1.13
Committed: Wed Mar 1 11:48:11 2000 UTC (25 years, 2 months ago) by williamc
Content type: text/plain
Branch: MAIN
Branch point for: V0_9branch
Changes since 1.12: +10 -8 lines
Log Message:
Extra error checking

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.6 $self->_printstream();
109 williamc 1.1 }
110    
111     #
112     # return the current line number
113     #
114     sub line {
115     my $self=shift;
116     return $self->{linecount};
117     }
118 williamc 1.12
119     # return the line the current tag was opened
120     sub tagstartline {
121     my $self=shift;
122     $self->{tagstart};
123     }
124 williamc 1.1 # --------------- Utility routines ----------------------------
125    
126     #
127     # Some initialisation of test suites
128     #
129     sub _resetvars {
130     my $self=shift;
131     $self->{quotes}=0;
132     $self->{lastlabel}="";
133     $self->{textcontext}='none';
134     $self->{tagcontext}="text";
135     $self->_resetstore();
136     }
137    
138     #
139     # Check for control characters
140     #
141     sub _checkchar {
142     my $self=shift;
143     my $char=shift;
144     my $string;
145    
146 williamc 1.6
147 williamc 1.1 # ---- In a tag
148     if ( $self->{tagcontext}=~/tag/ ) {
149     if ( ! $self->_quotetest($char) ) {
150     if ( ! $self->_labeltest($char) ) {
151     if ( $char eq ">") { $self->_closetag(); }
152     else { $self->_putstore($char); }
153     }
154     }
155     }
156     # ------ Outside a tag
157     else {
158     if ( $char eq "<") { $self->_opentag() }
159     else { $self->_putstore($char) }
160     }
161     }
162    
163    
164     #
165     # Return the next character from the current string buffer
166     #
167     sub _nextchar() {
168     my $self=shift;
169     my $char;
170     $char=substr($self->{currentline},$self->{stringpos}++,1);
171     # print "Debug : Fetching character $char\n";
172 williamc 1.6
173     # Keep a record for any stream processes
174     $self->{streamstore}=$self->{streamstore}.$char;
175    
176 williamc 1.1 return $char;
177     }
178    
179     sub _opentag {
180     my $self=shift;
181     my $char;
182 williamc 1.12
183     # Keep a record of where the tag started
184     $self->{tagstart}=$self->line();
185 williamc 1.1
186     # Close the last text segment
187 williamc 1.8 $self->{streamtmp}=$self->_popstream();
188 williamc 1.1 $self->_calltag($self->{textcontext}, $self->{textcontext},
189     $self->_getstore());
190     $self->_resetstore();
191     $self->_resetlabels();
192    
193     # Do we have an opening or closing tag?
194     if ( ($char=$self->_nextchar()) eq "/" ) { #we have a closing tag
195     $self->{tagcontext}="endtag";
196     }
197     else { # an opening tag
198     $self->{tagcontext}="starttag";
199     $self->_checkchar($char);
200     }
201     #print "\nDebug : Opening $self->{tagcontext}\n";
202     }
203    
204     #
205     # Close a tag
206     #
207     sub _closetag {
208     my $self=shift;
209     my $tagroutine;
210    
211     # -- Finish off any labels/get tagname
212     $self->_closelabel();
213    
214     # -- Call the associated tag function if appropriate
215 williamc 1.13 if ( defined $self->{tagname} ) {
216     $tagroutine=$self->{tagname}."_".$self->{tagcontext};
217     $self->_calltag($tagroutine, $self->{tagname},
218 williamc 1.1 $self->{tagvar});
219 williamc 1.13 #print "\nDebug : Closing Tag $tagroutine\n";
220 williamc 1.1
221 williamc 1.13 # -- Now make sure the text context is set for calling routines to
222     # -- deal with text portions outside of tags
223     if ( $self->{tagcontext} eq "starttag" ) {
224 williamc 1.1 push @{$self->{textstack}} , $self->{textcontext};
225     $self->{textcontext}=$self->{tagname};
226 williamc 1.13 }
227     else {
228 williamc 1.1 if ( $#{$self->{textstack}} > -1 ) {
229     if ( $self->{textcontext} eq $self->{tagname} ) {
230     $self->{textcontext}=pop @{$self->{textstack}};
231     }
232     else { #The tag we are closing is not the last one so
233     # we keep our current context.
234     $self->_removefromstack($self->{tagname},$self->{textstack});
235     }
236    
237     }
238     else { # more close tags than open ones
239     print "Warning : Unmatched </...> tag on line ".
240     $self->line()."\n";
241     }
242 williamc 1.13 }
243 williamc 1.1 }
244     # Reset context back to text
245     $self->{tagcontext}="text";
246     }
247    
248     sub _calltag {
249     my $self=shift;
250     my $tagroutine=shift;
251     my @args=@_;
252     my $rt;
253 williamc 1.6 my $found=0;
254 williamc 1.1
255     if ( $self->{groupchecker}->status() ||
256     ( $self->{tagcontainer}->inquiregroup($tagroutine)) ) {
257 williamc 1.7 ($rt,$obj)=$self->{tagcontainer}->getroutine($tagroutine);
258 williamc 1.1 if ( $rt ne "" ) {
259 williamc 1.7 if ( ! defined $obj ) {
260 williamc 1.1 &{$rt}( $self->{allw},@_);
261 williamc 1.7 }
262     else {
263     &{$rt}( $obj,@_);
264     }
265     $found=1;
266 williamc 1.1 }
267     }
268 williamc 1.6
269 williamc 1.8 # stream function
270     if ( ! exists $self->{streamexclude}{$tagroutine} ) {
271 williamc 1.6 $self->_printstream();
272     }
273     $self->_clearstream();
274     }
275    
276     sub _clearstream {
277     my $self=shift;
278     $self->{streamstore}=(($self->{streamtmp} ne "")?$self->{streamtmp}:"");
279     $self->{streamtmp}="";
280     }
281    
282     sub _popstream {
283     my $self=shift;
284     $self->{streamstore}=~s/(.*)(.)$/$1/;
285     return $2;
286     }
287    
288     sub _printstream {
289    
290     my $self=shift;
291    
292     # Stream output functionality
293     if ( defined $self->{stream} ) {
294     print {$self->{stream}} "$self->{streamstore}";
295     }
296 williamc 1.1 }
297    
298     sub _removefromstack {
299     my $self=shift;
300     my $name=shift;
301     my $stack=shift;
302     my $this;
303    
304     undef @tempstack;
305     #print "In ----".$#{$stack};
306     # Keep popping until we find our string
307     while ( ($this=(pop @{$stack})) ne "$name") {
308     push @tempstack, $this;
309     if ( $#{$stack} < 0 ) { last; }
310     }
311     # Now put them back
312     while ( $#tempstack>-1) {
313     $this=pop @tempstack;
314     push @{$stack}, $this;
315     }
316     #print " Out ----".$#{$stack};
317     }
318    
319     #
320     # Quote handling
321     #
322    
323     sub _quotetest {
324     my $self=shift;
325     my $char=shift;
326    
327     # --- Are we already in a quote context?
328     if ( $self->{quotes} ) {
329     if ( $char eq $self->{openquote} ) {
330     $self->{quotes}=0;
331     }
332     else {
333     $self->_putstore($char);
334     }
335     }
336     # --- Unquoted Context
337     elsif ( (($char eq "\"") || ($char eq "\'") || ($char eq "\`")) ) {
338     $self->{quotes}=1;
339     $self->{openquote}=$char;
340     }
341     else { return 0; } # Return zero if not quoted
342     return 1; # 1 otherwise
343     }
344    
345     #
346     # Label handling
347     #
348     sub _labeltest {
349     my $self=shift;
350     my $char=shift;
351    
352     # Spaces are markers between tags
353     if ( ($char eq " ") || ($char eq "\n") || ($char eq "\t")) {
354     $self->_closelabel();
355     }
356     # Check for a change in label status
357     elsif ( $char eq "=" ) {
358     $self->{lastlabel}=$self->_getstore();
359     $self->_resetstore();
360     }
361     else {
362     return 0;
363     }
364     return 1;
365     }
366    
367     sub _resetlabels {
368     my $self=shift;
369     undef $self->{tagvar};
370 williamc 1.9 undef $self->{tagname};
371 williamc 1.1 }
372    
373     sub _closelabel {
374     my $self=shift;
375    
376     # Do we have a label name?
377     if ( $self->{lastlabel} ne "" ) {
378     $self->{tagvar}{$self->{lastlabel}}=$self->_getstore();
379     $self->{lastlabel}="";
380     }
381     elsif ( $self->_getstore() ne "") {
382 williamc 1.9 # Then it must be the tag name
383     if ( ! defined $self->{tagname} ) {
384     ($self->{tagname}=$self->_getstore())=~tr/A-Z/a-z/;
385     }
386     else {
387 williamc 1.10 die ">Tag syntax error in $self->{tagname} on line ".
388 williamc 1.11 $self->line()." of file \n$self->{filename}";
389 williamc 1.9 }
390 williamc 1.1 }
391     $self->_resetstore();
392     }
393    
394     #
395     # Character Store management interface
396     #
397     sub _putstore() {
398     my $self=shift;
399     my $char=shift;
400    
401     $self->{stringbuff}=$self->{stringbuff}.$char;
402     }
403    
404     sub _getstore() {
405     my $self=shift;
406    
407     return $self->{stringbuff};
408     }
409    
410     sub _resetstore {
411     my $self=shift;
412     $self->{stringbuff}="";
413     }