ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/ActiveDoc/Switcher.pm
Revision: 1.7
Committed: Wed Nov 10 16:21:11 1999 UTC (25 years, 6 months ago) by williamc
Content type: text/plain
Branch: MAIN
Changes since 1.6: +7 -2 lines
Log Message:
Add ability to call multiple objects

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     # checkparam($name,$par) : Exit with an error message if parameter
16     # is undefined in tag $name
17     # line() : return the current line number of the parse
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.1 sub _initialise (hash1) {
44     my $self=shift;
45     $self->{filename}=shift;
46    
47     # add a default groupchecker
48     use ActiveDoc::GroupChecker;
49     $self->{groupchecker}=GroupChecker->new();
50     $self->{groupchecker}->include("all");
51    
52     # Add a default TagContainer
53     use ActiveDoc::TagContainer;
54 williamc 1.3 $self->{tagcontainer}=ActiveDoc::TagContainer->new();
55 williamc 1.1
56     }
57    
58     sub usetags {
59     my $self=shift;
60     my $tagcontainer=shift;
61    
62     $self->{tagcontainer}=$tagcontainer;
63     }
64    
65     sub usegroupchecker {
66     my $self=shift;
67     my $ref=shift;
68    
69     $self->{groupchecker}=$ref;
70     }
71    
72     sub parse {
73     my $self=shift;
74     my $char;
75 williamc 1.4 my $buf;
76 williamc 1.1 $self->{linecount}=0;
77     $self->_resetvars();
78 williamc 1.6 $self->{streamstore}="";
79 williamc 1.1
80     # Open the file
81     use FileHandle;
82 williamc 1.6 local $filehandle;
83 williamc 1.4 $filehandle=FileHandle->new();
84 williamc 1.6 $filehandle->open("<".$self->{filename})
85 williamc 1.2 or return 1;
86 williamc 1.4 # The buffering seems all messed up - best not to use it
87 williamc 1.5 $filehandle->setvbuf($buf, _IONBF, 3000);
88 williamc 1.1
89     # Start file processing
90 williamc 1.4 while ( ($_=<$filehandle>) ) {
91 williamc 1.1 $self->{linecount}++;
92     $self->{currentline}=$_;
93     $self->{stringpos}=0;
94     while ( ($char=$self->_nextchar()) ne "" ) {
95     $self->_checkchar($char);
96     } # end char while
97     } # End String while loop
98 williamc 1.5 undef $filehandle;
99 williamc 1.6 $self->_printstream();
100 williamc 1.1 }
101    
102     sub checkparam($name, $key) {
103     my $self=shift;
104     my $name=shift;
105     my $key=shift;
106    
107     if ( ! defined $self->{tagvar}{$key} ) {
108     print "Switcher: Badly formed $name tag -".
109     " undefined $key parameter\n";
110     exit 1;
111     }
112     }
113    
114     #
115     # return the current line number
116     #
117     sub line {
118     my $self=shift;
119     return $self->{linecount};
120     }
121     # --------------- Utility routines ----------------------------
122    
123     #
124     # Some initialisation of test suites
125     #
126     sub _resetvars {
127     my $self=shift;
128     $self->{quotes}=0;
129     $self->{lastlabel}="";
130     $self->{textcontext}='none';
131     $self->{tagcontext}="text";
132     $self->_resetstore();
133     }
134    
135     #
136     # Check for control characters
137     #
138     sub _checkchar {
139     my $self=shift;
140     my $char=shift;
141     my $string;
142    
143 williamc 1.6
144 williamc 1.1 # ---- In a tag
145     if ( $self->{tagcontext}=~/tag/ ) {
146     if ( ! $self->_quotetest($char) ) {
147     if ( ! $self->_labeltest($char) ) {
148     if ( $char eq ">") { $self->_closetag(); }
149     else { $self->_putstore($char); }
150     }
151     }
152     }
153     # ------ Outside a tag
154     else {
155     if ( $char eq "<") { $self->_opentag() }
156     else { $self->_putstore($char) }
157     }
158     }
159    
160    
161     #
162     # Return the next character from the current string buffer
163     #
164     sub _nextchar() {
165     my $self=shift;
166     my $char;
167     $char=substr($self->{currentline},$self->{stringpos}++,1);
168     # print "Debug : Fetching character $char\n";
169 williamc 1.6
170     # Keep a record for any stream processes
171     $self->{streamstore}=$self->{streamstore}.$char;
172    
173 williamc 1.1 return $char;
174     }
175    
176     sub _opentag {
177     my $self=shift;
178     my $char;
179    
180     # Close the last text segment
181     $self->_calltag($self->{textcontext}, $self->{textcontext},
182     $self->_getstore());
183     $self->_resetstore();
184     $self->_resetlabels();
185    
186 williamc 1.6 $self->{scramtmp}=$self->_popstream();
187 williamc 1.1 # Do we have an opening or closing tag?
188     if ( ($char=$self->_nextchar()) eq "/" ) { #we have a closing tag
189     $self->{tagcontext}="endtag";
190     }
191     else { # an opening tag
192     $self->{tagcontext}="starttag";
193     $self->_checkchar($char);
194     }
195     #print "\nDebug : Opening $self->{tagcontext}\n";
196     }
197    
198     #
199     # Close a tag
200     #
201     sub _closetag {
202     my $self=shift;
203     my $tagroutine;
204    
205     # -- Finish off any labels/get tagname
206     $self->_closelabel();
207    
208     # -- Call the associated tag function if appropriate
209     $tagroutine=$self->{tagname}."_".$self->{tagcontext};
210     $self->_calltag($tagroutine, $self->{tagname},
211     $self->{tagvar});
212     #print "\nDebug : Closing Tag $tagroutine\n";
213    
214     # -- Now make sure the text context is set for calling routines to
215     # -- deal with text portions outside of tags
216     if ( $self->{tagcontext} eq "starttag" ) {
217     push @{$self->{textstack}} , $self->{textcontext};
218     $self->{textcontext}=$self->{tagname};
219     }
220     else {
221     if ( $#{$self->{textstack}} > -1 ) {
222     if ( $self->{textcontext} eq $self->{tagname} ) {
223     $self->{textcontext}=pop @{$self->{textstack}};
224     }
225     else { #The tag we are closing is not the last one so
226     # we keep our current context.
227     $self->_removefromstack($self->{tagname},$self->{textstack});
228     }
229    
230     }
231     else { # more close tags than open ones
232     print "Warning : Unmatched </...> tag on line ".
233     $self->line()."\n";
234     }
235     }
236     # Reset context back to text
237     $self->{tagcontext}="text";
238     }
239    
240     sub _calltag {
241     my $self=shift;
242     my $tagroutine=shift;
243     my @args=@_;
244     my $rt;
245 williamc 1.6 my $found=0;
246 williamc 1.1
247     if ( $self->{groupchecker}->status() ||
248     ( $self->{tagcontainer}->inquiregroup($tagroutine)) ) {
249 williamc 1.7 ($rt,$obj)=$self->{tagcontainer}->getroutine($tagroutine);
250 williamc 1.1 if ( $rt ne "" ) {
251 williamc 1.7 if ( ! defined $obj ) {
252 williamc 1.1 &{$rt}( $self->{allw},@_);
253 williamc 1.7 }
254     else {
255     &{$rt}( $obj,@_);
256     }
257     $found=1;
258 williamc 1.1 }
259     }
260 williamc 1.6
261     if ( ! $found ) {
262     $self->_printstream();
263     }
264     $self->_clearstream();
265     }
266    
267     sub _clearstream {
268     my $self=shift;
269     $self->{streamstore}=(($self->{streamtmp} ne "")?$self->{streamtmp}:"");
270     $self->{streamtmp}="";
271     }
272    
273     sub _popstream {
274     my $self=shift;
275     $self->{streamstore}=~s/(.*)(.)$/$1/;
276     return $2;
277     }
278    
279     sub _printstream {
280    
281     my $self=shift;
282    
283     # Stream output functionality
284     if ( defined $self->{stream} ) {
285     print {$self->{stream}} "$self->{streamstore}";
286     }
287 williamc 1.1 }
288    
289     sub _removefromstack {
290     my $self=shift;
291     my $name=shift;
292     my $stack=shift;
293     my $this;
294    
295     undef @tempstack;
296     #print "In ----".$#{$stack};
297     # Keep popping until we find our string
298     while ( ($this=(pop @{$stack})) ne "$name") {
299     push @tempstack, $this;
300     if ( $#{$stack} < 0 ) { last; }
301     }
302     # Now put them back
303     while ( $#tempstack>-1) {
304     $this=pop @tempstack;
305     push @{$stack}, $this;
306     }
307     #print " Out ----".$#{$stack};
308     }
309    
310     #
311     # Quote handling
312     #
313    
314     sub _quotetest {
315     my $self=shift;
316     my $char=shift;
317    
318     # --- Are we already in a quote context?
319     if ( $self->{quotes} ) {
320     if ( $char eq $self->{openquote} ) {
321     $self->{quotes}=0;
322     }
323     else {
324     $self->_putstore($char);
325     }
326     }
327     # --- Unquoted Context
328     elsif ( (($char eq "\"") || ($char eq "\'") || ($char eq "\`")) ) {
329     $self->{quotes}=1;
330     $self->{openquote}=$char;
331     }
332     else { return 0; } # Return zero if not quoted
333     return 1; # 1 otherwise
334     }
335    
336     #
337     # Label handling
338     #
339     sub _labeltest {
340     my $self=shift;
341     my $char=shift;
342    
343     # Spaces are markers between tags
344     if ( ($char eq " ") || ($char eq "\n") || ($char eq "\t")) {
345     $self->_closelabel();
346     }
347     # Check for a change in label status
348     elsif ( $char eq "=" ) {
349     $self->{lastlabel}=$self->_getstore();
350     $self->_resetstore();
351     }
352     else {
353     return 0;
354     }
355     return 1;
356     }
357    
358     sub _resetlabels {
359     my $self=shift;
360     undef $self->{tagvar};
361     }
362    
363     sub _closelabel {
364     my $self=shift;
365    
366     # Do we have a label name?
367     if ( $self->{lastlabel} ne "" ) {
368     $self->{tagvar}{$self->{lastlabel}}=$self->_getstore();
369     $self->{lastlabel}="";
370     }
371     elsif ( $self->_getstore() ne "") {
372     #Then it must be the tag name
373     ($self->{tagname}=$self->_getstore())=~tr/A-Z/a-z/;
374     }
375     $self->_resetstore();
376     }
377    
378     #
379     # Character Store management interface
380     #
381     sub _putstore() {
382     my $self=shift;
383     my $char=shift;
384    
385     $self->{stringbuff}=$self->{stringbuff}.$char;
386     }
387    
388     sub _getstore() {
389     my $self=shift;
390    
391     return $self->{stringbuff};
392     }
393    
394     sub _resetstore {
395     my $self=shift;
396     $self->{stringbuff}="";
397     }