ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/ActiveDoc/Switcher.pm
Revision: 1.19.2.1
Committed: Fri Feb 27 15:34:54 2004 UTC (21 years, 2 months ago) by sashby
Content type: text/plain
Branch: SCRAM_V1_BRANCH
CVS Tags: V1_pre0, SCRAM_V1, SCRAMV1_IMPORT
Branch point for: V1_pre1
Changes since 1.19: +2 -2 lines
Log Message:
First import of new SCRAM packages into CMS cvs repos.

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