ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/ActiveDoc/Switcher.pm
Revision: 1.5
Committed: Wed Sep 29 15:25:32 1999 UTC (25 years, 7 months ago) by williamc
Content type: text/plain
Branch: MAIN
Changes since 1.4: +2 -6 lines
Log Message:
No buffering - use filehandle operators rather than open close etc

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