-- File: RedirectDFDriver.mesa -- Shoup, July 25, 1986 11:46:00 am PDT DIRECTORY Commander USING [CommandProc, Handle, Register], CommandTool USING [ArgN, NumArgs], Rope USING [ROPE, Equal, Substr, Fetch, Length, Cat, FromChar], IO USING [STREAM, GetLineRope, EndOf, PutF, rope, Close], FS USING [AccessOptions, Error, StreamOpen, Delete, Rename] ; RedirectDFDriver: CEDAR PROGRAM IMPORTS Commander, CommandTool, Rope, IO, FS = { OPEN Commander, CommandTool, Rope, IO, FS; Abort: ERROR = CODE; Main: CommandProc = { ENABLE Abort => GOTO Quit; sourceDF: ROPE; targetGiven: BOOL; targetPrefix: ROPE; topSuffix: ROPE; docSuffix: ROPE; impSuffix: ROPE; [sourceDF, targetGiven, targetPrefix, topSuffix, docSuffix, impSuffix] ← ProcessCommandLine[cmd]; IF targetGiven THEN ProcessSourceWithTarget[cmd, sourceDF, targetPrefix, topSuffix, docSuffix, impSuffix] ELSE ProcessSourceWithoutTarget[cmd, sourceDF]; EXITS Quit => NULL; }; ProcessCommandLine: PROC [cmd: Handle] RETURNS [sourceDF: ROPE, targetGiven: BOOL, targetPrefix: ROPE, topSuffix: ROPE, docSuffix: ROPE, impSuffix: ROPE] = { IF NumArgs[cmd] < 2 THEN CommandLineError[cmd]; sourceDF ← ArgN[cmd, 1]; IF Length[sourceDF] < 3 OR NOT Equal[Substr[sourceDF, Length[sourceDF]-3, 3], ".df", FALSE] THEN sourceDF ← Cat[sourceDF, ".df"]; targetGiven ← FALSE; IF NumArgs[cmd] = 2 THEN RETURN; targetGiven ← TRUE; targetPrefix ← ArgN[cmd, 2]; topSuffix ← NIL; docSuffix ← NIL; impSuffix ← NIL; FOR i: INT IN [3..NumArgs[cmd]) DO IF Equal[s1: Substr[base: ArgN[cmd, i], start: 0, len: 2], s2: "t=", case: FALSE] THEN topSuffix ← Substr[base: ArgN[cmd, i], start: 2] ELSE IF Equal[s1: Substr[base: ArgN[cmd, i], start: 0, len: 2], s2: "d=", case: FALSE] THEN docSuffix ← Substr[base: ArgN[cmd, i], start: 2] ELSE IF Equal[s1: Substr[base: ArgN[cmd, i], start: 0, len: 2], s2: "i=", case: FALSE] THEN impSuffix ← Substr[base: ArgN[cmd, i], start: 2] ELSE CommandLineError[cmd]; ENDLOOP; }; CommandLineError: PROC [cmd: Handle] = { PutF[cmd.out, "Usage: RedirectDF sourceDF [targetPrefix [t=Top>] [d=Documentation>] [i=sourceDF>]\n"]; ERROR Abort; }; ProcessSourceWithTarget: PROC [cmd: Handle, sourceDF: ROPE, targetPrefix: ROPE, topSuffix: ROPE, docSuffix: ROPE, impSuffix: ROPE] = { topTarget, docTarget, impTarget: ROPE; topSource, docSource, impSource: ROPE; line, sourceRoot, sourcePrefix: ROPE; input, output: STREAM; args: LIST OF ROPE; tempFile: ROPE; sourceRoot ←ExtractRoot[sourceDF]; sourcePrefix ← NIL; topTarget ← MakeDirectory[targetPrefix, topSuffix, "Top>"]; docTarget ← MakeDirectory[targetPrefix, docSuffix, "Documentation>"]; impTarget ← MakeDirectory[targetPrefix, impSuffix, Cat[sourceRoot, ">"]]; tempFile ← Cat["RedirectDF$", sourceRoot]; input ← OpenFile[cmd, sourceDF, $read]; output ← OpenFile[cmd, tempFile, $create ! Abort => {Close[input]; ERROR Abort}]; WHILE NOT EndOf[input] DO line ← GetLineRope[input]; args ← GetArgs[line]; IF ListLength[args] = 2 AND (Equal[args.first, "Directory"] OR Equal[args.first, "Exports"]) THEN { keyword: ROPE ← args.first; sourceDir: ROPE ← args.rest.first; targetDir: ROPE; IF sourcePrefix = NIL THEN { sourcePrefix ← GetPrefix[sourceDir]; topSource ← Cat[sourcePrefix, "Top>"]; docSource ← Cat[sourcePrefix, "Documentation>"]; impSource ← Cat[sourcePrefix, sourceRoot, ">"]; }; IF Equal[sourceDir, topSource, FALSE] THEN targetDir ← topTarget ELSE IF Equal[sourceDir, docSource, FALSE] THEN targetDir ← docTarget ELSE IF Equal[sourceDir, impSource, FALSE] THEN targetDir ← impTarget ELSE { PutF[cmd.out, "inconsistent directory: %g\n", rope[sourceDir]]; BadCleanUp[input, output, tempFile]; ERROR Abort; }; PutF[output, "%g %g\n", rope[keyword], rope[targetDir]]; PutF[output, "--Was %g\n", rope[sourceDir]]; } ELSE IF NOT IsWasLine[line] THEN PutF[output, "%g\n", rope[line]]; ENDLOOP; GoodCleanUp[input, output, tempFile, sourceDF, cmd]; }; BadCleanUp: PROC [input, output: STREAM, tempFile: ROPE] = { Close[input]; Close[output]; Delete[tempFile]; }; GoodCleanUp: PROC [input, output: STREAM, tempFile, sourceDF: ROPE, cmd: Handle] = { Close[input]; Close[output]; Rename[from: tempFile, to: sourceDF ! Error => { PutF[cmd.out, "could not create %g\n", rope[sourceDF]]; Delete[tempFile]; ERROR Abort; }]; }; ProcessSourceWithoutTarget: PROC [cmd: Handle, sourceDF: ROPE] = { sourceRoot, tempFile, line: ROPE; input, output: STREAM; args: LIST OF ROPE; sourceRoot ← ExtractRoot[sourceDF]; tempFile ← Cat["RedirectDF$", sourceRoot]; input ← OpenFile[cmd, sourceDF, $read]; output ← OpenFile[cmd, tempFile, $create ! Abort => {Close[input]; ERROR Abort}]; WHILE NOT EndOf[input] DO line ← GetLineRope[input]; args ← GetArgs[line]; IF ListLength[args] = 2 AND (Equal[args.first, "Directory"] OR Equal[args.first, "Exports"]) THEN { keyword: ROPE ← args.first; sourceDir: ROPE ← args.rest.first; targetDir: ROPE; IF EndOf[input] THEN { PutF[cmd.out, "CameFrom line missing\n"]; BadCleanUp[input, output, tempFile]; ERROR Abort; }; line ← GetLineRope[input]; args ← GetArgs[line]; IF ListLength[args] # 2 OR NOT Equal[args.first, "--Was"] THEN { PutF[cmd.out, "--Was line missing\n"]; BadCleanUp[input, output, tempFile]; ERROR Abort; }; targetDir ← args.rest.first; PutF[output, "%g %g\n", rope[keyword], rope[targetDir]]; PutF[output, "--Was %g\n", rope[sourceDir]]; } ELSE IF NOT IsWasLine[line] THEN PutF[output, "%g\n", rope[line]]; ENDLOOP; GoodCleanUp[input, output, tempFile, sourceDF, cmd]; }; IsWasLine: PROC [line: ROPE] RETURNS [BOOLEAN] = { args: LIST OF ROPE; args ← GetArgs[line]; RETURN [ListLength[args] = 2 AND Equal[args.first, "--Was"]]; }; ExtractRoot: PROC [sourceDF: ROPE] RETURNS [ROPE] = { i : INT; i ← Length[sourceDF] - 4; WHILE i >= 0 AND Fetch[sourceDF, i] # '> AND Fetch[sourceDF, i] # '/ DO i ← i - 1; ENDLOOP; RETURN [Substr[sourceDF, i+1, Length[sourceDF]-4-i]]; }; ListLength: PROC [list: LIST OF ROPE] RETURNS [INT] = { IF list = NIL THEN RETURN [0] ELSE RETURN [ListLength[list.rest]+1]; }; GetArgs: PROC[from: ROPE] RETURNS [LIST OF ROPE] = { pos: INT ← 0; len: INT ← Length[from]; GetOneArg: PROC [] RETURNS [result: ROPE] = { WHILE (pos < len) AND ((Fetch[from, pos] = ' ) OR (Fetch[from, pos] = '\t)) DO pos ← pos + 1; ENDLOOP; IF pos >= len THEN RETURN [NIL]; result ← ""; WHILE (pos < len) AND (Fetch[from, pos] # ' ) AND (Fetch[from, pos] # '\t) DO result ← Cat[result, FromChar[Fetch[from, pos]]]; pos ← pos + 1; ENDLOOP; }; RGetArgs: PROC [] RETURNS [LIST OF ROPE] = { arg: ROPE; arg ← GetOneArg[]; IF arg = NIL THEN RETURN [NIL] ELSE RETURN [CONS[arg, RGetArgs[]]]; }; RETURN [RGetArgs[]]; }; OpenFile: PROC [cmd: Handle, fname: ROPE, mode: AccessOptions] RETURNS [STREAM] = { ENABLE Error => { IF error.group = user THEN PutF[cmd.out, "%g\n", rope[error.explanation]] ELSE PutF[cmd.out, "can't open %g\n", rope[fname]]; ERROR Abort}; RETURN [StreamOpen[fname, mode]]; }; GetPrefix: PROC [s: ROPE] RETURNS [ROPE] = { i: INT; i ← Length[s]-2; WHILE (i >= 0) AND (Fetch[s, i] # '>) AND (Fetch[s, i] # '/) DO i ← i - 1; ENDLOOP; RETURN [Substr[s, 0, i+1]]; }; MakeDirectory: PROC [prefix, suffix, default: ROPE] RETURNS [res: ROPE] = { IF suffix = NIL THEN suffix ← default; res ← Cat[prefix, suffix]; }; -- start code Register["///Commands/RedirectDF", Main]; }.