#!@PERL@ # spacevpl # (C) A. J. C. Duggan 1993 # Alter sizes at sidebearings of VPL files # # actions are --- # -ht expr -wd expr -dp expr -ic expr -hs expr -vs expr # (ic = italic correction, wd = width, ht = height, dp = depth, # hs = horizontal shift, vs = vertical shift) # exprs combine these dimensions and constants with *, /, +, - # v1.2 23/9/93 AJCD # Created at vplutils release level 1.2 ($prog) = ($0 =~ /([^\/]*)$/); unshift(@INC, "@PERLLIBDIR@"); # set perl include directory require 'paths.pl'; require 'parseenc.pl'; require 'parsepl.pl'; ############################################################################### # Auxiliary routines ############################################################################### # fatal(...) # causes a fatal error with the arguments given sub fatal { print STDERR "$prog: "; printf STDERR @_; print STDERR "\n"; exit 1; } # inrange(num, range) # tests if number is in the range given # range = num[,range] | [num]-[num][,range] | [] sub inrange { local($number, $range) = @_; foreach (split(/,/, $range)) { if (/^(0x?[\da-fA-F]+)/) { next if $number < oct($1); } elsif (/^(\d+)/) { next if $number < $1; } if (/(0x?[\da-fA-F]+)$/) { next if $number > oct($1); } elsif (/(\d+)$/) { next if $number > $1; } return 1; } 0; } ############################################################################### # Property list manipulation routines ############################################################################### # PL property functions # called by parsepl with normal arguments as parameters sub printprop { # print a property &expand(&property(@_)); undef; } sub printlist { # print a property list &expand(&list(@_)); undef; } sub mapfont { # print a property list with one previous param local($first) = join(' ', shift, shift); $mapfont = 1; &expand(&list($first, @_)); undef; } sub vtitle { &expand(&property("COMMENT", @_)); undef; } sub checksum { # save checksum local($name, $number) = @_; push(@fontprops, "(FONTCHECKSUM $number)"); &expand(&property($name, $number)); undef; } sub designunits { # save designunits local($name, $number) = @_; $designunits = &number($number); &expand(&property($name, $number)); undef; } sub designsize { # save designsize local($name, $number) = @_; push(@fontprops, "(FONTDSIZE $number)"); $designsize = &number($number); &expand(&property($name, $number)); undef; } # character properties %charprop = @thismap = (); sub charprop { local($name, $number) = @_; $charprop{$name} = &number($number)*$designsize/$designunits; undef; } sub moveright { local($name, $number) = @_; if ($charprop{CHARHS} || $charprop{MARKED}) { &property(@_); } else { $charprop{CHARHS} = &number($number)*$designsize/$designunits; undef; } } sub moveleft { local($name, $number) = @_; if ($charprop{CHARHS} || $charprop{MARKED}) { &property(@_); } else { $charprop{CHARHS} = -&number($number)*$designsize/$designunits; undef; } } sub moveup { local($name, $number) = @_; if ($charprop{CHARVS} || $charprop{MARKED}) { &property(@_); } else { $charprop{CHARVS} = &number($number)*$designsize/$designunits; undef; } } sub movedown { local($name, $number) = @_; if ($charprop{CHARVS} || $charprop{MARKED}) { &property(@_); } else { $charprop{CHARVS} = -&number($number)*$designsize/$designunits; undef; } } sub mark { # MAP property which makes a mark $charprop{MARKED} = 1; &property(@_); } sub map { # deal with MAP lists shift; @thismap = @_; undef; } sub character { # add or replace character properties local($name) = shift; local($number) = shift; local($value) = &number($number); local(%props) = %charprop; if (!$mapfont) { &expand("(MAPFONT D 0", @fontprops, ")"); $mapfont = 1; } if (&inrange($value, $range)) { # adjust values print STDERR "Altering properties for character $number\n" if $debug; foreach (CHARWD, CHARHT, CHARDP, CHARIC, CHARHS, CHARVS) { $props{$_} = eval $expr{$_} if defined($expr{$_}); } } foreach (CHARWD, CHARHT, CHARDP, CHARIC) { if ($props{$_}) { push(@_, sprintf("($_ R %.5f)", $props{$_}*$designunits/$designsize)); } } push(@thismap, "(SETCHAR $number)") # add default map if necessary if !@thismap && ($props{CHARHS} || $props{CHARVS}); if ($props{CHARHS} > 0) { unshift(@thismap, sprintf("(MOVERIGHT R %.5f)", $props{CHARHS}*$designunits/$designsize)); } elsif ($props{CHARVS} < 0) { unshift(@thismap, sprintf("(MOVELEFT R %.5f)", -$props{CHARHS}*$designunits/$designsize)); } if ($props{CHARVS} > 0) { unshift(@thismap, sprintf("(MOVEUP R %.5f)", $props{CHARVS}*$designunits/$designsize)); } elsif ($props{CHARVS} < 0) { unshift(@thismap, sprintf("(MOVEDOWN R %.5f)", -$props{CHARVS}*$designunits/$designsize)); } @thismap = ("(MAP", @thismap, ")") if @thismap; &expand("(CHARACTER $number", @_, @thismap, ")"); %charprop = @thismap = (); undef; } ############################################################################### # Parsing and tokenisation ############################################################################### # list of property -> parameters_action # (N=number, S=string, P=property list, L=label or number) &plactions(CHECKSUM, checksum, DESIGNSIZE, designsize, DESIGNUNITS, designunits, CODINGSCHEME, printprop, FAMILY, printprop, FACE, printprop, SEVENBITSAFEFLAG, ignore, HEADER, printprop, BOUNDARYCHAR, printprop, VTITLE, vtitle, COMMENT, printprop, FONTDIMEN, printlist, # FONTDIMEN properties follow SLANT, property, SPACE, property, STRETCH, property, SHRINK, property, XHEIGHT, property, QUAD, property, EXTRASPACE, property, NUM1, property, NUM2, property, NUM3, property, DENOM1, property, DENOM2, property, SUP1, property, SUP2, property, SUP3, property, SUB1, property, SUB2, property, SUPDROP, property, SUBDROP, property, DELIM1, property, DELIM2, property, AXISHEIGHT, property, DEFAULTRULETHICKNESS, property, BIGOPSPACING1, property, BIGOPSPACING2, property, BIGOPSPACING3, property, BIGOPSPACING4, property, BIGOPSPACING5, property, PARAMETER, property, LIGTABLE, printlist, # LIGTABLE properties follow LABEL, property, KRN, property, STOP, property, SKIP, property, LIG, property, '/LIG', property, '/LIG>', property, 'LIG/', property, 'LIG/>', property, '/LIG/', property, '/LIG/>', property, '/LIG/>>', property, MAPFONT, mapfont, # MAPFONT properties follow FONTDSIZE, property, FONTNAME, property, FONTAREA, property, FONTCHECKSUM, property, FONTAT, property, CHARACTER, character, # CHARACTER properties follow CHARWD, charprop, CHARHT, charprop, CHARDP, charprop, CHARIC, charprop, NEXTLARGER, property, VARCHAR, list, # VARCHAR properties follow TOP, property, MID, property, BOT, property, REP, property, MAP, map, # MAP properties follow SELECTFONT, property, SETCHAR, mark, SETRULE, mark, PUSH, mark, POP, mark, MOVERIGHT, moveright, MOVELEFT, moveleft, MOVEUP, moveup, MOVEDOWN, movedown, SPECIAL, mark, SPECIALHEX, mark ); ############################################################################### # Expression checking ############################################################################### # compileexpr(expr) # sanitise and convert expression to do-form sub compileexpr { local($expr) = shift; local($paren, $operand, $newexpr) = (0, 1); foreach (split(/([-()\/*+])/, $expr)) { s/\s*//g; # drop spaces next if /^$/; # ignore empty lines if ($operand) { # operand expected if (/^\d+$/ || /^\d*\.\d+$/) { # constant $newexpr .= $_; $operand = 0; } elsif (/^wd$/ || /^ht$/ || /^dp$/ || /^ic$/ || /^hs$/ || /^vs$/) { tr/a-z/A-Z/; # uppercase $newexpr .= "\$charprop{CHAR$_}"; # character property $operand = 0; } elsif (/^ds$/) { # designsize $newexpr .= "\$designsize"; $operand = 0; } elsif (/\(/) { # open parenthesis $newexpr .= $_; $paren++; } elsif (/-/) { # unary negation $newexpr .= $_; } else { &fatal("Operand expected, got $_ in $expr\n"); } } else { # operator expected if (/[-+*\/]/) { # operator found $newexpr .= $_; $operand = 1; } elsif (/\)/) { # close parenthesis $newexpr .= $_; &fatal("Unmatched ) in $expr\n") if --$paren < 0; } else { &fatal("Operator expected, got $_ in $expr\n"); } } } &fatal("Unmatched ( in $expr\n") if $paren; print STDERR "Compiled $expr to $newexpr\n" if $debug; $newexpr; } ############################################################################### # Argument processing ############################################################################### $vtitle = join(' ', $prog, @ARGV); # set VTITLE to arguments %expr = (); # property -> expression $range = '-'; # character range while (@ARGV) { $_ = shift; ARGSW: { /^-quiet$/ && ($quiet = 1, last ARGSW); /^-debug$/ && ($debug = 1, last ARGSW); /^-range$/ && ($range = shift, last ARGSW); /^-(ic|wd|ht|dp|hs|vs)$/ && (($prop = "CHAR$1") =~ tr/a-z/A-Z/, $expr{$prop} = &compileexpr(shift), last ARGSW); if (/^-/) { /^-v$/ && print STDERR "$prog release @RELEASE@\n"; print STDERR join("\n", "Usage: $prog [-quiet] [-defenc defaultenc] [-wd expr] [-ht expr] [-dp expr]", " [-hs expr] [-vs expr] filename\n"); exit 1; } else { # filename &fatal('too many property list files specified') if defined($file); $file = $_; } } } &fatal('no property list files specified') if !defined($file); print "(VTITLE created by $vtitle)\n", "(COMMENT $prog is (C) A. J. C. Duggan 1993)\n"; @fontprops = ("(FONTNAME ".&fontname($file).")"); &parsepl($file); # process PL file exit 0; # good termination