-- 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];
}.