{$title: 'Command Line Filename Parser' $linesize:79} MODULE parse; {$debug- $stackck+} { command line filename parsing; Bob Wallace Microsoft 7/81 } CONST maxfile = 32; {NOTE: must be set same as caller} dfprf = 'PRF'; msprf = 'Profile filename ['; dfhst = 'HST'; mshst = 'Histogram filename ['; dfmap = 'MAP'; msmap = 'Map file ['; nuln = 'NUL '; TYPE filenam = lstring (maxfile); {filename parameter type} setsw = ARRAY [wrd(0)..3] OF byte; {switches parameter type} sets = set of 0..31; {caller's parameter type} setc = set of chr(0)..chr(127); {set of characters} cpmex = string (3); cpmnm = string (8); cpmfn = RECORD cfd [0]: string (2); cfn [2]: cpmnm; cfp [10]: char; cfe [11]: cpmex; END; setbitt = ARRAY [wrd(0)..7] OF byte; CONST setbit = setbitt (128, 64, 32, 16, 8, 4, 2, 1); VAR idset:setc; VALUE idset:=setc ['A'..'Z','a'..'z','0'..'9', '$', '&', '#', '@', '!', '%', '-', '_', '`', '''', '(', ')', '<', '>', '{', '}', '\', '^', '~', '|']; VAR drset:setc; VALUE drset:=setc ['A'..'O','a'..'o']; PROCEDURE fillc (dst: adrmem; len: word; chc: char); extern; PROCEDURE movel (prf: adrmem; dst: adrmem; len: word); extern; PROCEDURE ptyuqq (len: word; prf: adsmem); extern; PROCEDURE plyuqq; extern; FUNCTION gtyuqq (len: word; dst: adsmem): word; extern; PROCEDURE filbm (VAR prffil,hstfil,mapfil: filenam; VAR oldsw: setsw); (* sets the filenames for source, hstect, listing, and second listing (hstect list or cross ref); also sets any switches, allowing those in the oldsw set and returning them in oldsw *) VAR prf, hst, map: cpmfn; {target filenames in CPM format} newsw: setsw; {new switches, return in oldsw} qq: lstring (128); iq: word; {command line, current index} pqq: ads of lstring (128); {address CPM-type command line} cesxqq [extern]: word; {segment val} c: char; l: word; iscomma: boolean; i: word; {other stuff} FUNCTION parchr (ch: char): boolean; {true iff CH found} BEGIN parchr := (iq <= qq.len) AND (qq [iq] = ch); IF result (parchr) THEN iq := iq+1; END; FUNCTION upperc: char; {return current char, in upper case} BEGIN upperc := qq[iq]; IF result (upperc) >= 'a' THEN upperc := chr (ord (result (upperc)) - 32); END; PROCEDURE blanks; {skip blanks and set any switches} BEGIN WHILE parchr (' ') DO {nothing}; IF parchr ('/') THEN BEGIN IF (iq <= qq.len) AND THEN (ord (upperc) - 64) IN retype (sets, oldsw) THEN BEGIN i := wrd (upperc) - 64; iq := iq + 1; newsw[i DIV 8] := newsw[i DIV 8] OR setbit[i MOD 8]; blanks; {recurse for more} END ELSE iq := iq - 1; {put "/" back on line to get error} END; END; FUNCTION parset (VAR dst: string; CONST chs: setc): boolean; (* Move characters from qq to DST as long as they are in CHS Deletes from qq, blanks DST, returns true if any moved *) VAR i: word; BEGIN fillc (adr dst, wrd (upper (dst)), ' '); parset := false; FOR i := 1 TO wrd (upper (dst)) DO IF (iq > qq.len) OR ELSE NOT (qq [iq] IN chs) THEN BREAK ELSE BEGIN dst [i] := upperc; parset := true; iq := iq + 1; END; END; FUNCTION filenm (CONST prompt: string; VAR nam: filenam; VAR fcb: cpmfn; defext: cpmex): boolean; (* Get a filename into the FCB, setting defaults as appropriate; return true iff a filename found *) VAR i: word; p: adrmem; defile: cpmnm; BEGIN blanks; IF iscomma THEN defile := prf.cfn ELSE defile := nuln; IF iq > qq.len THEN BEGIN ptyuqq (wrd (upper (prompt)), ads prompt); FOR i := 1 TO 8 DO IF defile [i] <> ' ' THEN ptyuqq (1, ads defile [i]); ptyuqq (1, ads '.'); ptyuqq (3, ads defext); ptyuqq (3, ads ']: '); qq.len := gtyuqq (upper (qq), ads qq [1]); iq := 1; END; fcb.cfp := '.'; IF (iq < qq.len) AND (qq [iq+1] = ':') AND THEN parset (c, drset) THEN BEGIN fcb.cfd[1] := c; fcb.cfd[2] := ':'; iq := iq+1; defile := prf.cfn; {default to source name now} END ELSE fcb.cfd := ' '; filenm := parset (fcb.cfn, idset); IF parchr (':') THEN BEGIN fcb.cfe := ': '; fcb.cfp := ' '; END ELSE IF parchr ('.') THEN [eval (parset (fcb.cfe, idset)); defile := prf.cfn] ELSE fcb.cfe := defext; IF NOT result (filenm) THEN fcb.cfn := defile; blanks; nam.len := 0; p := adr fcb; FOR i := 0 TO 13 DO IF p^[i] <> wrd (' ') THEN [nam.len := nam.len+1; nam[nam.len] := chr (p^[i])]; END; FUNCTION conso (CONST fn: cpmnm): boolean; BEGIN conso := (fn = 'CON ') OR (fn = 'USER '); END; BEGIN newsw := setsw (do 4 of 0); pqq.r := 128; pqq.s := cesxqq; FOR i := 0 TO pqq^.len+1 DO qq[i] := pqq^[i]; iq := 1; REPEAT iscomma := true; prf.cfn := ' '; IF filenm (msprf, prffil, prf, dfprf) THEN BEGIN eval (parchr (',')); eval (filenm (mshst, hstfil, hst, dfhst)); iscomma := parchr (','); eval (filenm (msmap, mapfil, map, 'map')); blanks; eval (parchr (';')); blanks; IF hst.cfn <> nuln THEN newsw[3] := newsw[3] OR 8; IF map.cfn <> nuln THEN newsw[3] := newsw[3] OR 04; IF conso (map.cfn) THEN newsw[3] := newsw[3] OR 01; IF iq > qq.len THEN [oldsw := newsw; return]; END; ptyuqq (15, ads 'Line invalid: '''); i := qq.len - iq + 1; IF i > 0 THEN ptyuqq (i, ads qq [iq]); ptyuqq (15, ads ''', start again.'); plyuqq; iq := 256; UNTIL FALSE; END; END.