ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/ActiveDoc/Switcher.pm
Revision: 1.6
Committed: Tue Nov 9 11:24:54 1999 UTC (25 years, 6 months ago) by williamc
Content type: text/plain
Branch: MAIN
Changes since 1.5: +47 -3 lines
Log Message:
Add stream function

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 # 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 # 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 _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 $self->{tagcontainer}=ActiveDoc::TagContainer->new();
55
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 my $buf;
76 $self->{linecount}=0;
77 $self->_resetvars();
78 $self->{streamstore}="";
79
80 # Open the file
81 use FileHandle;
82 local $filehandle;
83 $filehandle=FileHandle->new();
84 $filehandle->open("<".$self->{filename})
85 or return 1;
86 # The buffering seems all messed up - best not to use it
87 $filehandle->setvbuf($buf, _IONBF, 3000);
88
89 # Start file processing
90 while ( ($_=<$filehandle>) ) {
91 $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 undef $filehandle;
99 $self->_printstream();
100 }
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
144 # ---- 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
170 # Keep a record for any stream processes
171 $self->{streamstore}=$self->{streamstore}.$char;
172
173 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 $self->{scramtmp}=$self->_popstream();
187 # 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 my $found=0;
246
247 if ( $self->{groupchecker}->status() ||
248 ( $self->{tagcontainer}->inquiregroup($tagroutine)) ) {
249 $rt=$self->{tagcontainer}->getroutine($tagroutine);
250 if ( $rt ne "" ) {
251 &{$rt}( $self->{allw},@_);
252 $found=1;
253 }
254 }
255
256 if ( ! $found ) {
257 $self->_printstream();
258 }
259 $self->_clearstream();
260 }
261
262 sub _clearstream {
263 my $self=shift;
264 $self->{streamstore}=(($self->{streamtmp} ne "")?$self->{streamtmp}:"");
265 $self->{streamtmp}="";
266 }
267
268 sub _popstream {
269 my $self=shift;
270 $self->{streamstore}=~s/(.*)(.)$/$1/;
271 return $2;
272 }
273
274 sub _printstream {
275
276 my $self=shift;
277
278 # Stream output functionality
279 if ( defined $self->{stream} ) {
280 print {$self->{stream}} "$self->{streamstore}";
281 }
282 }
283
284 sub _removefromstack {
285 my $self=shift;
286 my $name=shift;
287 my $stack=shift;
288 my $this;
289
290 undef @tempstack;
291 #print "In ----".$#{$stack};
292 # Keep popping until we find our string
293 while ( ($this=(pop @{$stack})) ne "$name") {
294 push @tempstack, $this;
295 if ( $#{$stack} < 0 ) { last; }
296 }
297 # Now put them back
298 while ( $#tempstack>-1) {
299 $this=pop @tempstack;
300 push @{$stack}, $this;
301 }
302 #print " Out ----".$#{$stack};
303 }
304
305 #
306 # Quote handling
307 #
308
309 sub _quotetest {
310 my $self=shift;
311 my $char=shift;
312
313 # --- Are we already in a quote context?
314 if ( $self->{quotes} ) {
315 if ( $char eq $self->{openquote} ) {
316 $self->{quotes}=0;
317 }
318 else {
319 $self->_putstore($char);
320 }
321 }
322 # --- Unquoted Context
323 elsif ( (($char eq "\"") || ($char eq "\'") || ($char eq "\`")) ) {
324 $self->{quotes}=1;
325 $self->{openquote}=$char;
326 }
327 else { return 0; } # Return zero if not quoted
328 return 1; # 1 otherwise
329 }
330
331 #
332 # Label handling
333 #
334 sub _labeltest {
335 my $self=shift;
336 my $char=shift;
337
338 # Spaces are markers between tags
339 if ( ($char eq " ") || ($char eq "\n") || ($char eq "\t")) {
340 $self->_closelabel();
341 }
342 # Check for a change in label status
343 elsif ( $char eq "=" ) {
344 $self->{lastlabel}=$self->_getstore();
345 $self->_resetstore();
346 }
347 else {
348 return 0;
349 }
350 return 1;
351 }
352
353 sub _resetlabels {
354 my $self=shift;
355 undef $self->{tagvar};
356 }
357
358 sub _closelabel {
359 my $self=shift;
360
361 # Do we have a label name?
362 if ( $self->{lastlabel} ne "" ) {
363 $self->{tagvar}{$self->{lastlabel}}=$self->_getstore();
364 $self->{lastlabel}="";
365 }
366 elsif ( $self->_getstore() ne "") {
367 #Then it must be the tag name
368 ($self->{tagname}=$self->_getstore())=~tr/A-Z/a-z/;
369 }
370 $self->_resetstore();
371 }
372
373 #
374 # Character Store management interface
375 #
376 sub _putstore() {
377 my $self=shift;
378 my $char=shift;
379
380 $self->{stringbuff}=$self->{stringbuff}.$char;
381 }
382
383 sub _getstore() {
384 my $self=shift;
385
386 return $self->{stringbuff};
387 }
388
389 sub _resetstore {
390 my $self=shift;
391 $self->{stringbuff}="";
392 }