#!/usr/local/bin/perl -w use strict; # we at least try to ;) use Class::Struct; # This file is part of the wvWare 2 project # Copyright (C) 2001-2003 Werner Trobin # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License version 2 as published by the Free Software Foundation. # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # You should have received a copy of the GNU Library General Public License # along with this library; see the file COPYING.LIB. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # A script to generate code which converts Word95 structures to Word97 ones # as good as possible. # If you add a convert comment to the Word 6 HTML you can "losen" the # restrictions a bit: # - convert="string(fieldname)" converts between U8[] and XCHAR[] # In case you want to limit the string size just write # "string(fieldname:XY)" where XY is the length to copy. # - convert="type" losens the type restrictions and simply tries to assign # even if the types are not exactly the same (U32 <- U16,...) # - convert="(fieldname)" relates the fieldnames and losens the type # restrictions # - convert="unused" skips this field ############################################################################### # To discuss with Shaheed: # - CHP::chse - I think we should map that to the Word97 CHP::fMacChs (70) # - I disabled (unused) DOP::fReadOnlyRecommended and DOP::fWriteReservation # as this should normally go into the Word97 FIB, but well, I doubt we need # that flags. # - I mapped the things like cpnBtePap to the "active" Word97 structures # instead of mapping it to the blah_W6 compatibility ones. # - PAP::fAutoHyph -> ? Maybe it's Word97::PAP::fAutoWrap? # - PAP::rgdxaTab, PAP::rgtbd? # - PGD: We should create a PGD2 structure for the 2nd table and have # conversion function like for PRM -> PRM2. The we can map Word95::PGD to # the Word97::PGD2. For now I disabled the structure. # - PHE: What to do with the Height/Line field? Have a union for them? ############################################################################### # This structure holds one "variable" struct Item => { name => '$', # The name of this variable type => '$', # The type (e.g. U16, S32[42],...) bits => '$', # The amount of bits (e.g. 3), if any comment => '$', # The comment for this variable initial => '$', # The initial value of this field, if any len => '$', # If the item is a dynamic array we store its length # here. length can be a plain C++ expression. compareSizeLHS => '$', # If the item is a dynamic array we need to compare the # left-hand-side (lhs) and the rhs in their size. This # is a plain C++ expression returning the size of the LHS. compareSizeRHS => '$', # If the item is a dynamic array we need to compare the # left-hand-side (lhs) and the rhs in their size. This # is a plain C++ expression returning the size of the RHS. startNew => '$', # This field is used for debugging purposes. It # is set to 1 if this variable should start a new # bitfield (and close the last one). We simply # check whether we filled the last field completely here matched => '$', # This field is used to indicate that this item already was "matched" convert => '$', # The conversion options - if any }; struct Structure => { name => '$', # The name of the structure comment => '$', # The comment for this struct items => '@', # All the data members hidden => '$', # Set to "//" if we want to comment that structure out dynamic => '$', # Do we have dynamic memory? Then we need a Copy CTOR, # DTOR, assignment op, op==,... }; # This array of strings contains the whole HTML # documentation file. It's used twice when reading the spec in # All the parsing subs will read/modify that global array # Note: All the tags we use are already converted to # uppercase. my @document; # The current index in the document-array (used during parsing) my $i; # These arrays hold all the structures we want to write out my @structs95; my @structs97; # The current struct we're working on (only used during parsing) my $struct; # The current item we're working on (only used during parsing) my $item; # Parses all the structures sub parseStructures { my ($doc)=@_; my ($tmp); print "Parsing $doc...\n"; $i=0; while($i<=$#document) { if($document[$i] =~ m,\,) { if($document[$i-1] =~ m/\/) { # Safe, as can't be in the first line # looks okay $struct=Structure->new(); # create a new structure element $document[$i] =~ m,^(.*)\,; $struct->comment($1); } elsif($document[$i] =~ m/\/) { # looks okay, too $struct=Structure->new(); # create a new structure element $document[$i] =~ m,\(.*)\,; $struct->comment($1); } else { if($document[$i-1] !~ m/Algorithm/) { # huh? Shouldn't happen at all print "####### ERROR #######\n"; print $document[$i-1], "\n", $document[$i], "\n"; } $i++; # don't forget that one here :)) next; } $struct->comment =~ m,.*\((.*)\),; # get the name of the structure $tmp=$1; # store it in a $tmp var as I'm too clueless :) $tmp =~ s/\s/_/; # replace the spaces with underscores $struct->name($tmp); # ...and set it as name #print "found: name: '", $struct->name, "' comment: '", $struct->comment, "'\n"; $struct->hidden(""); # initialize that with a sane value #print "Checking for a "; while($document[$i] !~ m,\
we found if(parseStructure()) { if($doc eq "Word95") { push(@structs95, $struct); # append the new structure } elsif($doc eq "Word97") { push(@structs97, $struct); } else { print "Error: Word95 or Word97?\n"; } } else { print "####### ERROR #######\n"; print " name: '", $struct->name, "' comment: '", $struct->comment, "'\n"; } } $i++; } print "Done.\n"; } # Parses one structure (
...
) sub parseStructure { # eat the first row (headline) while($document[$i] !~ m,^\$,) { $i++; } while($document[$i] !~ m,^\$,) { $i++; } # parse all the variables till we encounter while($document[$i] !~ m,^\$,) { if(parseItem()) { push(@{$struct->items}, $item); $i++; } else { print "####### ERROR #######\n"; print " Error while parsing an item!\n"; return 0; # uh-oh :} } } #print "count: ", $#{$struct->items}+1, "\n"; return 1; # success } # Parses one row of the table ( ... ) to get one # data item out of it. Does some trivial error checking sub parseItem { my ($myState, $tmp); $myState=0; while($document[$i] !~ m,^\$,) { $i++; } $item=Item->new(); while($document[$i] !~ m,^\$,) { if($document[$i] =~ m,^\(.*)\$,) { if($myState==0) { # this is used for debugging/sanity checking $item->startNew($1); #print " startNew: ", $1, "\n"; } # yes, I left out $myState==1 on purpose elsif($myState==2) { $item->name($1); #print " name: ", $1, "\n"; } elsif($myState==3) { $item->type($1); #print " type: ", $1, "\n"; } elsif($myState==4) { $tmp=$1; if($tmp =~ m/^:(.*)/) { $item->bits($1); #print " bits: ", $1, "\n"; } else { #print " no bits but a plain size attribute!\n"; } } # yes, I left out $myState==5 on purpose elsif($myState==6) { $item->comment($1); #print " (short) comment: ", $1, "\n"; } $myState++; } # The comment can expand across several lines elsif($document[$i] =~ m,^\(.*)$, && $myState==6) { $tmp=$1; # Insert a
for "newlines" (consistency) if($document[$i+1] !~ m,\,) { $tmp .= "
"; } $i++; while($document[$i] !~ m,(.*)\
$,) { $tmp .= $document[$i]; # Insert a
for "newlines" (consistency) if($document[$i+1] !~ m,\,) { $tmp .= "
"; } $i++; } $document[$i] =~ m,(.*)\$,; $tmp .= $1; $item->comment($tmp); #print " (long) comment: ", $tmp, "\n"; $myState++; } elsif($document[$i] =~ m,\<\!--\s*initial=\"(.*?)\"\s*--\>,) { #print "initial found: ", $document[$i], " filtered: ", $1, "\n"; $item->initial($1); } elsif($document[$i] =~ m,\<\!--\s+compareSizeLHS=\"(.*?)\"\s+compareSizeRHS=\"(.*?)\"\s+--\>,) { #print "compareSize found: ", $document[$i], " filtered: ", $1, ", ", $2, "\n"; $item->compareSizeLHS($1); $item->compareSizeRHS($2); } elsif($document[$i] =~ m,\<\!--\s*convert=\"(.*?)\"\s*--\>,) { #print "convert found: ", $document[$i], " filtered: ", $1, "\n"; $item->convert($1); } elsif($document[$i] =~ m,^\$,) { print "Error: Found a table end where I didn't expect it!\n"; return 0; } $i++; } #print "$myState==7 ? ", $myState==7, "\n"; return $myState==7; } # Parse the template file sub parseTemplate { my($name) = @_; # name of the template my($license, $includes, $before, $after, $myState); open(TEMPLATE, "<$name") or die "Couldn't open the template: " . $!; # initialize all the template vars $myState=0; $license=""; $includes=""; $before=""; $after=""; # read in the information... while(