UPOpsImpl.mesa
Mik Lamming - October 29, 1984 4:09:57 pm PST
DIRECTORY IO, FS, Rope, UPOps, UserProfile;
UPOpsImpl: CEDAR PROGRAM
IMPORTS FS, UserProfile, IO
EXPORTS UPOps
= BEGIN OPEN UPOps;
Expand: PUBLIC PROC [format: Rope.ROPENIL, v1, v2, v3, v4, v5: IO.Value ← [null[]]] RETURNS [names: LIST OF Rope.ROPENIL] ~ {
KeyIndex: TYPE = [0..MaxKeys];    -- counts number of `%k' sequences encountered
keyIndex: KeyIndex ← 0;     -- counts number of %k sequences encountered
kkFormat: Rope.ROPE;     -- folds rope after %k to %%k expansion
putfFormat: Rope.ROPE;      -- holds rope after %g expansion
kSubFormat: Rope.ROPE;     -- holds format after %k substitution
in, out: IO.STREAM;
eos: BOOLEANFALSE;
keys, defaults: ARRAY [0..2] OF Rope.ROPEALL[NIL]; -- parameters to MakeOptionList
breakChar, c, k: CHAR;
-- expand %k to %%k to preserve across PutFR call
in ← IO.RIS[format];
out ← IO.ROS[];
c ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
WHILE ~eos DO
SELECT c FROM
'% => {
k ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
IF eos THEN EXIT;
IF k=KeyChar THEN out.PutF["%%%%k"]
ELSE { out.PutChar[c]; out.PutChar[k] };
};
ENDCASE => out.PutChar[c];
c ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
ENDLOOP;
kkFormat ← out.RopeFromROS[];
in.Close[];
-- now expand out the %g stuff using regular formatted IO stuff
putfFormat ← IO.PutFR[kkFormat, v1, v2, v3, v4, v5];
-- now replace the %k stuff with %g and parameters
eos ← FALSE;
in ← IO.RIS[putfFormat];
out ← IO.ROS[];
keyIndex ← 0; -- start counting keys - first is 0
c ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
WHILE ~eos DO
SELECT c FROM
'% => { -- possible %k sequence
k ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
IF eos THEN EXIT;
IF k=KeyChar THEN {     -- BINGO
keyOut: IO.STREAMIO.ROS[]; -- stream to build Key
defaultOut: IO.STREAM;     -- stream to build Default
-- set the break char
breakCharin.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
IF eos THEN EXIT;
IF keyIndex=MaxKeys THEN ERROR; -- only 3 keys allowed MAX
-- build key rope terminated by breakChar
k ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
WHILE ~eos DO
IF k=breakChar THEN EXIT;
keyOut.PutChar[k];
k ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
ENDLOOP;
keys[keyIndex] ← keyOut.RopeFromROS[];
IF eos THEN EXIT;
-- build the default rope terminated by breakChar
defaultOut ← IO.ROS[];
k ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
WHILE ~eos DO
IF k=breakChar THEN EXIT;
defaultOut.PutChar[k];
k ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
ENDLOOP;
defaults[keyIndex] ← defaultOut.RopeFromROS[];
-- substitute %k with %g in format stream
out.PutF["%%g"];
keyIndex ← keyIndex + 1;
}
ELSE {
out.PutChar[c]; out.PutChar[k]
};
};
ENDCASE => out.PutChar[c];
c ← in.GetChar[! IO.EndOfStream => {eos ← TRUE; CONTINUE}];
ENDLOOP;
kSubFormat ← out.RopeFromROS[];
in.Close[];
-- now build the name list
names ← MakeOptionList[kSubFormat, keys[0], defaults[0], keys[1], defaults[1], keys[2], defaults[2]];
};
MakeOptionList: PROC [
format:Rope.ROPE,
k1, def1: Rope.ROPENIL,
k2, def2: Rope.ROPENIL,
k3, def3: Rope.ROPENIL]
RETURNS [names: LIST OF Rope.ROPENIL] ~ {
This routine takes a format string containing 1-3 occurences of %g (like the format string
in IO.PutF) and replaces each occurence of %g with a rope extracted from the user profile.
e.g.  Given the user profile entries
   AISseparationKeys.green: "-green -grn -g"
   AISextensions: "ais pic"
MakeOptionList[
format: "Image%g.%g",
k1: "AISseparationKeys.green", def1: "-grn",
k2: "AISextension", def2:, "ais"
]
What you get is:
("Image-grn.AIS", "Image-grn.pic", "Image-green.AIS", "Image-green.pic", "Image-g.AIS", "Image-g.pic")
If the key `kN' is not found then the default "defN" string is used.
N.B. The first item in the list is guaranteed to be formed from the first element of each key list.
Reverse: PROC [l1, l2: LIST OF Rope.ROPENIL] RETURNS [LIST OF Rope.ROPE] ~ {
IF l1=NIL THEN RETURN [l2] ELSE RETURN[Reverse[l1.rest, CONS[l1.first, l2]]];
};
up1, up2, up3: LIST OF Rope.ROPE;
IF def1=NIL THEN def1←"";
IF def2=NIL THEN def2←"";
IF def3=NIL THEN def3←"";
up1 ← UserProfile.ListOfTokens[k1, LIST[def1]];
up2 ← UserProfile.ListOfTokens[k2, LIST[def2]];
up3 ← UserProfile.ListOfTokens[k3, LIST[def3]];
FOR l1:LIST OF Rope.ROPE←up1, l1.rest WHILE l1#NIL DO
FOR l2:LIST OF Rope.ROPE←up2, l2.rest WHILE l2#NIL DO
FOR l3:LIST OF Rope.ROPE←up3, l3.rest WHILE l3#NIL DO
newName: Rope.ROPE;
SELECT TRUE FROM
k1=NIL =>
newName ← IO.PutFR[format];
k2=NIL =>
newName ← IO.PutFR[format, IO.rope[l1.first]];
k3=NIL =>
newName ← IO.PutFR[format, IO.rope[l1.first], IO.rope[l2.first]];
ENDCASE =>
newName ← IO.PutFR[format, IO.rope[l1.first], IO.rope[l2.first], IO.rope[l3.first]];
names ← CONS[newName, names];
ENDLOOP;
ENDLOOP;
ENDLOOP;
names ← Reverse[names, NIL];
};
Enumerate: PUBLIC PROC [
proc: EnumerateProc,
format: Rope.ROPENIL,
v1, v2, v3, v4, v5: IO.Value ← [null[]]
] ~ {
list: LIST OF Rope.ROPE ← Expand[format, v1, v2, v3, v4,v5];
WHILE list#NIL DO
IF ~proc[list.first] THEN EXIT;
list ← list.rest;
ENDLOOP;
};
StreamOpen: PUBLIC PROC [
format: Rope.ROPENIL,
v1, v2, v3, v4, v5: IO.Value ← [null[]],
accessOptions: FS.AccessOptions ← $read,
streamOptions: FS.StreamOptions ← FS.defaultStreamOptions,
keep: CARDINAL ← 1,
createByteCount: FS.ByteCount ← 2560,
streamBufferParms: FS.StreamBufferParms ← FS.defaultStreamBufferParms,
extendFileProc: FS.ExtendFileProc ← NIL
]
RETURNS [stream: IO.STREAMNIL] ~ {
TryAndOpen: EnumerateProc ~ {
tryNext ← TRUE;
stream FS.StreamOpen[
rope, accessOptions, streamOptions, keep,
createByteCount, streamBufferParms,
extendFileProc ! FS.Error => {
tryNext ← FALSE;
CONTINUE
}];
};
Enumerate[TryAndOpen, format, v1, v2, v3, v4, v5];
};
END.