ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/ActiveDoc/Switcher.pm
Revision: 1.14
Committed: Fri Apr 7 13:39:46 2000 UTC (25 years, 1 month ago) by williamc
Content type: text/plain
Branch: MAIN
CVS Tags: ProtoEnd
Changes since 1.13: +5 -2 lines
Log Message:
Bug fix

File Contents

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