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

# 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 $self->_printstream();
109 }
110
111 #
112 # return the current line number
113 #
114 sub line {
115 my $self=shift;
116 return $self->{linecount};
117 }
118
119 # return the line the current tag was opened
120 sub tagstartline {
121 my $self=shift;
122 $self->{tagstart};
123 }
124 # --------------- 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
147 # ---- 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
173 # Keep a record for any stream processes
174 $self->{streamstore}=$self->{streamstore}.$char;
175
176 return $char;
177 }
178
179 sub _opentag {
180 my $self=shift;
181 my $char;
182
183 # Keep a record of where the tag started
184 $self->{tagstart}=$self->line();
185
186 # Close the last text segment
187 $self->{streamtmp}=$self->_popstream();
188 $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 if ( defined $self->{tagname} ) {
216 $tagroutine=$self->{tagname}."_".$self->{tagcontext};
217 $self->_calltag($tagroutine, $self->{tagname},
218 $self->{tagvar});
219 #print "\nDebug : Closing Tag $tagroutine\n";
220
221 # -- 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 push @{$self->{textstack}} , $self->{textcontext};
225 $self->{textcontext}=$self->{tagname};
226 }
227 else {
228 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 }
243 }
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 my $found=0;
254
255 if ( $self->{groupchecker}->status() ||
256 ( $self->{tagcontainer}->inquiregroup($tagroutine)) ) {
257 ($rt,$obj)=$self->{tagcontainer}->getroutine($tagroutine);
258 if ( $rt ne "" ) {
259 if ( ! defined $obj ) {
260 &{$rt}( $self->{allw},@_);
261 }
262 else {
263 &{$rt}( $obj,@_);
264 }
265 $found=1;
266 }
267 }
268
269 # stream function
270 if ( ! exists $self->{streamexclude}{$tagroutine} ) {
271 $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 }
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 undef $self->{tagname};
371 }
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 # 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 die ">Tag syntax error in $self->{tagname} on line ".
388 $self->line()." of file \n$self->{filename}";
389 }
390 }
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 }