(* This module initializes the DVI file parameter and command line options. Highly SYSDEP! *) #include 'globals.h'; #include 'options.h'; VAR option : CHAR; (* current command option *) value : string; (* current option's value *) vlength : INTEGER; (* current value's length *) argnum : INTEGER; (* 0..argc-1; used in argv calls *) FUNCTION sscanf (VAR s, format : string; VAR r : real) : integer; EXTERNAL; (******************************************************************************) FUNCTION Cap (ch : CHAR) : CHAR; (* If ch is in 'a'..'z' then return capitalized letter else return ch. *) BEGIN IF (ch < 'a') OR (ch > 'z') THEN Cap := ch ELSE Cap := CHR(ORD(ch) - 32); END; (* Cap *) (******************************************************************************) FUNCTION Len (str : string) : INTEGER; (* Return length of given string, assumed to be padded with blanks. *) LABEL 888; VAR i : INTEGER; BEGIN i := maxstring; WHILE i > 0 DO BEGIN IF str[i-1] <> ' ' THEN goto 888; i := i - 1; END; 888: Len := i; END; (* Len *) (******************************************************************************) FUNCTION ExplicitExt (fname : string; len : INTEGER) : BOOLEAN; (* SYSDEP: Check for an extension of the form ".*" where * is any string not containing "/". len is length of fname. If "." found then TRUE is returned, otherwise FALSE. *) LABEL 999; BEGIN WHILE len > 0 DO BEGIN (* search backwards looking for . *) len := len - 1; IF fname[len] = '/' THEN BEGIN (* handle file names like ../myfiles/foo *) ExplicitExt := FALSE; goto 999; END ELSE IF fname[len] = '.' THEN BEGIN ExplicitExt := TRUE; goto 999; END; END; ExplicitExt := FALSE; 999: END; (* ExplicitExt *) (******************************************************************************) PROCEDURE GetValue; (* Get parameter following current option and store in value. *) VAR i : integer; BEGIN IF vlength > 2 THEN BEGIN (* allow things like -m1000 *) FOR i := 0 TO vlength - 1 DO value[i] := value[i+2]; (* shift value left 2 places *) vlength := vlength - 2; END ELSE BEGIN (* option should be followed by value *) value := ' '; IF argnum < argc THEN argv(argnum,value); vlength := Len(value); (* 0 if no more args *) argnum := argnum + 1; IF vlength <= 0 THEN BEGIN writeln('Missing value after -',option); exit(1); END; END; END; (* GetValue *) (******************************************************************************) PROCEDURE GetCardinal (VAR n : INTEGER); (* If current value represents a positive integer then return via n. *) VAR result : integer; r : real; fmt : string; BEGIN fmt := '%f'; result := sscanf(value,fmt,r); n := trunc(r); IF (ABS(result) <> 1) OR (n <= 0) THEN BEGIN writeln('Bad -',option,' value: ',value:vlength); writeln('Specify a positive integer.'); exit(1); END; END; (* GetCardinal *) (******************************************************************************) PROCEDURE GetPosDimen (VAR r : REAL; VAR un : validunits); (* A valid +ve dimension consists of a positive integer or real number followed by a two-letter unit: cm, mm, in, pc, pt, bp or px (or in uppercase). If current value represents a valid +ve dimension, we return number part in r and validunits part in un. *) VAR i, result : INTEGER; ch1, ch2 : CHAR; fmt : string; BEGIN (* extract un *) IF vlength > 1 THEN i := vlength-1 ELSE i := 1; IF (Cap(value[i-1]) = 'I') AND (Cap(value[i]) = 'N') THEN un := ic ELSE IF (Cap(value[i-1]) = 'C') AND (Cap(value[i]) = 'M') THEN un := cm ELSE IF (Cap(value[i-1]) = 'M') AND (Cap(value[i]) = 'M') THEN un := mm ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'C') THEN un := pc ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'T') THEN un := pt ELSE IF (Cap(value[i-1]) = 'B') AND (Cap(value[i]) = 'P') THEN un := bp ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'X') THEN un := px ELSE BEGIN writeln('Bad units in -',option,' value: ',value:vlength); writeln('Last two letters should be cm, mm, in, pc, pt, bp or px.'); exit(1); END; ch1 := value[i-1]; (* remember letters in units *) ch2 := value[i]; value[i] := ' '; (* remove units *) value[i-1] := ' '; fmt := '%f'; result := sscanf(value,fmt,r); IF (ABS(result) <> 1) OR (r <= 0.0) THEN BEGIN value[i-1] := ch1; (* restore units *) value[i] := ch2; writeln('Bad -',option,' value: ',value:vlength); writeln('Specify a positive dimension.'); exit(1); END; END; (* GetPosDimen *) (******************************************************************************) PROCEDURE GetDimen (VAR r : REAL; VAR un : validunits); (* A valid dimension consists of an integer or real number followed by a two-letter unit: cm, mm, in, pc, pt, bp or px (or in uppercase). If current value represents a valid dimension, we return number part in r and validunits part in un. *) VAR i, result : INTEGER; ch1, ch2 : CHAR; fmt : string; BEGIN (* extract un *) IF vlength > 1 THEN i := vlength-1 ELSE i := 1; IF (Cap(value[i-1]) = 'I') AND (Cap(value[i]) = 'N') THEN un := ic ELSE IF (Cap(value[i-1]) = 'C') AND (Cap(value[i]) = 'M') THEN un := cm ELSE IF (Cap(value[i-1]) = 'M') AND (Cap(value[i]) = 'M') THEN un := mm ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'C') THEN un := pc ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'T') THEN un := pt ELSE IF (Cap(value[i-1]) = 'B') AND (Cap(value[i]) = 'P') THEN un := bp ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'X') THEN un := px ELSE BEGIN writeln('Bad units in -',option,' value: ',value:vlength); writeln('Last two letters should be cm, mm, in, pc, pt, bp or px.'); exit(1); END; ch1 := value[i-1]; (* remember letters in units *) ch2 := value[i]; value[i] := ' '; (* remove units *) value[i-1] := ' '; fmt := '%f'; result := sscanf(value,fmt,r); IF (ABS(result) <> 1) THEN BEGIN value[i-1] := ch1; (* restore units *) value[i] := ch2; writeln('Bad -',option,' value: ',value:vlength); writeln('Specify a dimension.'); exit(1); END; END; (* GetDimen *) (******************************************************************************) PROCEDURE GetUnits; (* Make sure current value is valid and set units if so. *) VAR ch1, ch2 : CHAR; BEGIN ch1 := Cap(value[0]); ch2 := Cap(value[1]); IF (ch1 = 'I') AND (ch2 = 'N') THEN units := ic ELSE IF (ch1 = 'C') AND (ch2 = 'M') THEN units := cm ELSE IF (ch1 = 'M') AND (ch2 = 'M') THEN units := mm ELSE IF (ch1 = 'P') AND (ch2 = 'C') THEN units := pc ELSE IF (ch1 = 'P') AND (ch2 = 'T') THEN units := pt ELSE IF (ch1 = 'B') AND (ch2 = 'P') THEN units := bp ELSE IF (ch1 = 'P') AND (ch2 = 'X') THEN units := px ELSE BEGIN writeln('Bad -',option,' value: ',value:vlength); writeln('Specify cm, mm, in, pc, pt, bp or px.'); exit(1); END; END; (* GetUnits *) (******************************************************************************) PROCEDURE GetPages; (* Parse -p value. If valid then subrange will become TRUE. -p can have any value of the form "first:final" where first and/or final can be a DVI page (positive integer), or TeX page ([i0. ... .i9]), or empty. If first empty then firstDVIpage = 1; if final empty then finalDVIpage = maxint. If ":final" is omitted then finalDVIpage = firstDVIpage. If first/final is a TeX page specification (i.e., starts with '[') then first/finalDVIpage is set to 0 and first/finalTeXpage contains the given string (and parsing is done by the main module). *) LABEL 888; VAR i, j, result : INTEGER; r : real; fmt : string; BEGIN subrange := TRUE; firstTeXpage := ' '; finalTeXpage := ' '; i := 0; (* extract first page *) WHILE i < vlength DO BEGIN IF value[i] = ':' THEN goto 888; firstTeXpage[i] := value[i]; i := i + 1; END; 888: IF value[0] = ':' THEN (* first page not given *) firstDVIpage := 1 ELSE IF firstTeXpage[0] = '[' THEN (* TeX page given *) firstDVIpage := 0 ELSE BEGIN (* DVI page given *) fmt := '%f'; result := sscanf(firstTeXpage,fmt,r); firstDVIpage := trunc(r); IF (ABS(result) <> 1) OR (firstDVIpage <= 0) THEN BEGIN writeln('Bad first page in -',option,' value: ',value:vlength); writeln('Specify a positive integer.'); exit(1); END; END; IF i = vlength THEN BEGIN (* no colon; n or [t] *) IF firstTeXpage[0] = '[' THEN BEGIN finalTeXpage := firstTeXpage; (* [t] = [t]:[t] *) finalDVIpage := 0; END ELSE finalDVIpage := firstDVIpage; (* n = n:n *) END ELSE BEGIN (* value[i] = ':' *) i := i + 1; j := 0; WHILE i < vlength DO BEGIN (* extract final page *) finalTeXpage[j] := value[i]; i := i + 1; j := j + 1; END; IF j = 0 THEN (* no page after ':' *) finalDVIpage := maxint ELSE IF finalTeXpage[0] = '[' THEN (* TeX page given *) finalDVIpage := 0 ELSE BEGIN (* DVI page given *) fmt := '%f'; result := sscanf(finalTeXpage,fmt,r); finalDVIpage := trunc(r); IF (ABS(result) <> 1) OR (finalDVIpage <= 0) THEN BEGIN writeln('Bad final page in -',option,' value: ',value:vlength); writeln('Specify a positive integer.'); exit(1); END; END; END; END; (* GetPages *) (******************************************************************************) FUNCTION DimenPixels (r : REAL; u : validunits) : INTEGER; (* Return given dimension in terms of pixels. *) BEGIN CASE u OF ic : DimenPixels := TRUNC(r * resolution + 0.5); cm : DimenPixels := TRUNC((r / 2.54) * resolution + 0.5); mm : DimenPixels := TRUNC((r / 25.4) * resolution + 0.5); bp : DimenPixels := TRUNC((r / 72.0) * resolution + 0.5); pt : DimenPixels := TRUNC((r / 72.27) * resolution + 0.5); pc : DimenPixels := TRUNC((r / 72.27) * 12.0 * resolution + 0.5); px : DimenPixels := TRUNC(r + 0.5) END; END; (* DimenPixels *) (******************************************************************************) PROCEDURE InitOptions; (* Get DVI file and any options from command line. If an option appears more than once then we return the last value. *) VAR hoffu, voffu, xu, yu : validunits; hoffr, voffr, xr, yr : REAL; landscape : boolean; temp, strlen, i : integer; str : string; BEGIN (* initialize option values with defaults; note that the psprint script can set up different defaults *) resolution := 300; (* LaserWriter resolution *) hoffu := ic; voffu := ic; hoffr := 0.0; (* no margin shifting *) voffr := 0.0; xu := ic; (* paper dimensions in inches *) yu := ic; xr := 8.3; (* A4 paper is 8.3" wide *) yr := 11.7; (* A4 paper is 11.7" high *) mag := 0; (* use DVI mag *) fontdir := '/tex/pk/'; (* location of PK files *) dummyfont := 'cmr10.300pk'; (* typical font *) tfmdir := '/tex/fonts/'; (* location of PS TFM files *) psprefix := 'ps-'; (* prefix in PS font names *) DVIname := ' '; (* SYSDEP: empty string *) (* above are same as DVItoVDU options *) header := '/usr/users/applied/staff/atrevorr/psdvi/tex.ps'; PSname := 'out.ps'; (* output file (-o) *) units := ic; (* inches (-u) *) stats := FALSE; (* display stats? (-s) *) reverse := FALSE; (* reverse page order? (-b) *) conserveVM := FALSE; (* conserve VM? (-c) *) landscape := FALSE; (* reverse -x and -y? (-l) *) subrange := FALSE; (* -p value given? *) firstDVIpage := 0; finalDVIpage := 0; firstTeXpage := '[]'; finalTeXpage := '[]'; argnum := 1; (* 0 is command *) WHILE argnum < argc DO BEGIN value := ' '; argv(argnum,value); vlength := Len(value); argnum := argnum + 1; IF value[0] = '-' THEN BEGIN IF vlength > 1 THEN option := value[1] ELSE option := ' '; CASE option OF 'r' : BEGIN GetValue; GetCardinal(resolution); END; 'm' : BEGIN GetValue; GetCardinal(mag); END; 'i' : BEGIN GetValue; GetCardinal(increment); END; 'x' : BEGIN GetValue; GetPosDimen(xr,xu); END; 'y' : BEGIN GetValue; GetPosDimen(yr,yu); END; 'H' : BEGIN GetValue; GetDimen(hoffr,hoffu); END; 'V' : BEGIN GetValue; GetDimen(voffr,voffu); END; 'T' : BEGIN GetValue; tfmdir := value; END; 'P' : BEGIN GetValue; psprefix := value; END; 'd' : BEGIN GetValue; dummyfont := value; END; 'f' : BEGIN GetValue; fontdir := value; END; 'h' : BEGIN GetValue; header := value; END; 'o' : BEGIN GetValue; PSname := value; END; 'u' : BEGIN GetValue; GetUnits; END; 'p' : BEGIN GetValue; GetPages; END; 's' : stats := TRUE; 'b' : reverse := TRUE; 'c' : conserveVM := TRUE; 'l' : landscape := TRUE; (* bad string values will be detected in other modules *) OTHERWISE writeln('Unknown option: -',option); exit(1); END; END ELSE BEGIN (* value doesn't start with '-', so assume it is DVI file *) DVIname := value; IF NOT ExplicitExt(DVIname,vlength) THEN (* append .dvi *) IF vlength + 3 < maxstring THEN BEGIN DVIname[vlength] := '.'; DVIname[vlength+1] := 'd'; DVIname[vlength+2] := 'v'; DVIname[vlength+3] := 'i'; END ELSE BEGIN (* user has given a mighty long file name *) writeln('DVI file name too long: ',DVIname:maxstring); exit(1); END; (* bad DVIname will be detected upon open in main module *) END; END; IF DVIname[0] = ' ' THEN BEGIN (* no file name on command line *) writeln('DVI file not given!'); exit(1); END; (* prepend fontdir to dummyfont *) str := fontdir; strlen := Len(fontdir); FOR i := 1 TO Len(dummyfont) DO BEGIN IF strlen < maxstring THEN BEGIN str[strlen] := dummyfont[i-1]; strlen := strlen + 1; END; END; dummyfont := str; (* set h/voffset and paperwd/ht only after resolution has been decided *) hoffset := DimenPixels(hoffr,hoffu); voffset := DimenPixels(voffr,voffu); paperwd := DimenPixels(xr,xu); paperht := DimenPixels(yr,yu); IF landscape THEN BEGIN (* swap paperwd and paperht *) temp := paperwd; paperwd := paperht; paperht := temp; END; IF increment = 0 THEN increment := 1; (* do normal page selection *) END; (* InitOptions *)