TexSysdepImpl:
PROGRAM
IMPORTS PascalBasic, PascalWizardFiles, TexInteraction, TexScan, TexDvi, TexSysdepInline, TexRest, SirPress, FS, IO, Rope, UserProfile, BasicTime, Process, TexSymbols, TexOps, MessageWindow
EXPORTS TexSysdep, TeXExport
= BEGIN OPEN PascalBasic, PascalWizardFiles, TexTypes, TexInteraction;
RopeFromNameOfFile:
PROCEDURE []
RETURNS [fileName: Rope.
ROPE] = {
i: NAT ← 0;
P: SAFE PROC RETURNS [CHAR] = TRUSTED {i ← i+1; RETURN[TexInteraction.NameOfFile[i]]};
length: NAT ← 0;
WHILE length<TexTypes.FileNameSize
AND TexInteraction.NameOfFile[length+1]#'
DO
length ← length+1;
ENDLOOP;
fileName ← Rope.FromProc[length, P];
IF i#length THEN ERROR;
};
NameOfFileFromRope:
PRIVATE PROCEDURE [r: Rope.
ROPE] = {
NameLength ← MIN[r.Length[], FileNameSize];
FOR i: [1..FileNameSize]
IN [1..NameLength]
DO
NameOfFile[i]←r.Fetch[i-1] ENDLOOP;
FOR i: [1..FileNameSize]
IN (NameLength..
NAT[FileNameSize]]
DO
NameOfFile[i] ← ' ; ENDLOOP;
};
DefaultInputsDirectory:
PROCEDURE
RETURNS [inputs: Rope.
ROPE] = {
inputs ← UserProfile.Token[key: "TeX.DefaultInputsDirectory",
default: "/Cyan/TeX/Inputs/"];
};
ReadProfileForDirectories:
PUBLIC PROCEDURE = {
inputs: Rope.ROPE ← DefaultInputsDirectory[];
fonts: Rope.ROPE←UserProfile.Token[key: "TeX.DefaultFontMetricsDirectory",
default: "///Fonts/FontMetrics/"];
NameOfFileFromRope[inputs];
TexArea ← TexScan.MakeNameString[];
NameOfFileFromRope[fonts];
TexFontArea ← TexScan.MakeNameString[];
};
SetPoolName:
PUBLIC
PROCEDURE = {
poolName: Rope.ROPE = Rope.Cat[DefaultInputsDirectory[], "TeX.pool"];
FOR i:
NAT
IN [0 ..
NAT[poolName.Length])
DO
TexInteraction.NameOfFile[i+1] ← poolName.Fetch[i];
ENDLOOP;
FOR i:
NAT
IN [
NAT[poolName.Length] .. 127)
DO
TexInteraction.NameOfFile[i+1] ← ' ;
ENDLOOP;
};
ResetTermIn:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO AlphaFile] = {
PascalOpenTextFileTTYInput[F];
};
RewriteTermOut:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO AlphaFile] = {
PascalOpenTextFileTTYOutput[F];
};
ScreamAboutIllegalPrintFileFormat:
PRIVATE
PROC = {
MessageWindow.Append["Error in your Profile: TeX.PrintFileFormat must be Press or DVI!", TRUE];
MessageWindow.Blink[];
ERROR ABORTED;
};
ProfileAsksForPress:
PUBLIC
PROCEDURE
RETURNS [
BOOLEAN] = {
fmt: Rope.ROPE ← UserProfile.Token[key: "TeX.PrintFileFormat", default: "Press"];
SELECT
TRUE
FROM
Rope.Equal[s1: fmt, s2: "Press", case: FALSE] => RETURN[TRUE];
Rope.Equal[s1: fmt, s2: "DVI", case: FALSE] => RETURN[FALSE];
ENDCASE => ScreamAboutIllegalPrintFileFormat;
RETURN[TRUE];
};
PressOpenOut:
PUBLIC PROCEDURE
RETURNS [
BOOLEAN] = {
TexSysdepInline.pressFileStream ← FS.StreamOpen[RopeFromNameOfFile[], $create !
FS.Error => TRUSTED{GOTO openFailed}];
TexSysdepInline.pressHandle ← SirPress.Create[TexSysdepInline.pressFileStream,
RopeFromNameOfFile[], NIL, normal, NIL];
TexSysdepInline.pyping ← FALSE;
TexSysdepInline.pype ← SirPress.NewPipe[TexSysdepInline.pypePosnsLimit];
RETURN[TRUE];
EXITS
openFailed => RETURN[FALSE];
};
ReadTheClock:
PUBLIC
PROCEDURE [Ttime, Dday, Mmonth, Yyear:
LONG
POINTER
TO
INT] = {
now: BasicTime.UnpackedsicTime.Unpack[BasicTime.Now[]];
Ttime^ ← now.hour*BasicTime.minutesPerHour+now.minute;
Dday^ ← now.day;
Mmonth^ ←
SELECT now.month
FROM
January=>1, February=>2, March=>3,
April=>4, May=>5, June=>6,
July=>7, August=>8, September=>9,
October=>10, November=>11, December=>12,
ENDCASE=>ERROR;
Yyear^ ← now.year;
};
AOpenIn:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO AlphaFile]
RETURNS [AOpenInResult: PascalBoolean] = {
inStream: IO.STREAM;
AOpenInResult ← TRUE;
inStream ← FS.StreamOpen[RopeFromNameOfFile[]
! FS.Error => TRUSTED {Post[error]; AOpenInResult ← FALSE; GO TO Quit}
];
PascalOpenTextFileWithStream[F, inStream];
PascalTextRESET[F];
EXITS Quit => NULL
};
AOpenOut:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO AlphaFile]
RETURNS [AOpenOutResult: PascalBoolean] = {
outStream: IO.STREAM;
AOpenOutResult ← TRUE;
outStream ← FS.StreamOpen[RopeFromNameOfFile[], $create
! FS.Error => TRUSTED {Post[error]; AOpenOutResult ← FALSE; GO TO Quit}
];
PascalOpenTextFileWithStream[F, outStream];
PascalTextREWRITE[F];
EXITS Quit => NULL
};
BOpenIn:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO ByteFile]
RETURNS [BOpenInResult: PascalBoolean] = {
inStream: IO.STREAM;
so: FS.StreamOptions ← FS.defaultStreamOptions;
so[tiogaRead] ← FALSE;
BOpenInResult ← TRUE;
inStream ← FS.StreamOpen[fileName: RopeFromNameOfFile[], streamOptions: so
! FS.Error => TRUSTED {Post[error]; BOpenInResult ← FALSE; GO TO Quit}
];
PascalOpenFileWithStream[@(F^.baseFile), inStream];
PascalRESET[file: @(F^.baseFile), length: 1, element: @(F^.element)];
EXITS Quit => NULL
};
BOpenOut:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO ByteFile]
RETURNS [BOpenOutResult: PascalBoolean] = {
outStream: IO.STREAM;
BOpenOutResult ← TRUE;
outStream ← FS.StreamOpen[RopeFromNameOfFile[], $create
! FS.Error => TRUSTED {Post[error]; BOpenOutResult ← FALSE; GO TO Quit}
];
PascalOpenFileWithStream[@(F^.baseFile), outStream];
EXITS Quit => NULL
};
WOpenIn:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO WordFile]
RETURNS [WOpenInResult: PascalBoolean] = {
inStream: IO.STREAM;
so: FS.StreamOptions ← FS.defaultStreamOptions;
so[tiogaRead] ← FALSE;
WOpenInResult ← TRUE;
inStream ← FS.StreamOpen[fileName: RopeFromNameOfFile[], streamOptions: so
! FS.Error => TRUSTED {Post[error]; WOpenInResult ← FALSE; GO TO Quit}
];
PascalOpenFileWithStream[@(F^.baseFile), inStream];
PascalRESET[file: @(F^.baseFile), length: 4, element: @(F^.element)];
EXITS Quit => NULL
};
WOpenOut:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO WordFile]
RETURNS [WOpenOutResult: PascalBoolean] = {
outStream: IO.STREAM;
WOpenOutResult ← TRUE;
outStream ← FS.StreamOpen[RopeFromNameOfFile[], $create
! FS.Error => TRUSTED {Post[error]; WOpenOutResult ← FALSE; GO TO Quit}
];
PascalOpenFileWithStream[@(F^.baseFile), outStream];
EXITS Quit => NULL
};
Post:
PRIVATE
PROCEDURE [e:
FS.ErrorDesc] = {
IF e.group # user
THEN
{MessageWindow.Append[message: e.explanation, clearFirst: TRUE];
MessageWindow.Blink};
};
AClose:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO AlphaFile] = {
PascalCloseTextFile[F];
};
BClose:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO ByteFile] = {
PascalCloseFile[@(F^.baseFile)];
};
WClose:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO WordFile] = {
PascalCloseFile[@(F^.baseFile)];
};
AMakeNameString:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO AlphaFile]
RETURNS [AMakeNameStringResult: StrNumber] =
{RETURN[MakeNameStringFromFileStream[F^.baseFile^.str]]};
BMakeNameString:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO ByteFile]
RETURNS [BMakeNameStringResult: StrNumber] =
{RETURN[MakeNameStringFromFileStream[F^.baseFile^.str]]};
WMakeNameString:
PUBLIC
PROCEDURE [
F:
LONG
POINTER
TO WordFile]
RETURNS [WMakeNameStringResult: StrNumber] =
{RETURN[MakeNameStringFromFileStream[F^.baseFile^.str]]};
PressMakeNameString:
PUBLIC
PROCEDURE
RETURNS [PressMakeNameStringResult: StrNumber] =
{RETURN[MakeNameStringFromFileStream[TexSysdepInline.pressFileStream]]};
MakeNameStringFromFileStream:
PRIVATE
PROCEDURE [s:
IO.
STREAM]
RETURNS [StrNumber] =
{local, global, name: Rope.ROPE;
[fullFName: local, attachedTo: global] ← FS.GetName[FS.OpenFileFromStream[s]];
IF global = NIL THEN name ← local ELSE name ← global;
NameOfFileFromRope[name];
RETURN[TexScan.MakeNameString[]]};
finalDviBufLength: NAT = 8;
finalDviBuf: REF TEXT ← NEW[TEXT[finalDviBufLength]];
WriteDvi:
PUBLIC
PROCEDURE [
A,
B: DviIndex] = {
outPtr: NAT ← 0;
IF TexSymbols.UsePressFormat THEN RETURN;
finalDviBuf.length ← finalDviBufLength;
FOR i:
NAT
IN [
A..
B]
DO
finalDviBuf[outPtr] ← LOOPHOLE[TexDvi.DviBuf[i]];
outPtr ← outPtr+1;
IF outPtr=finalDviBufLength
THEN {
TexScan.DviFile.baseFile.str.PutBlock[finalDviBuf];
outPtr ← 0;
};
ENDLOOP;
IF outPtr>0
THEN {
finalDviBuf.length ← outPtr;
TexScan.DviFile.baseFile.str.PutBlock[finalDviBuf];
};
};
FileGetPos:
PUBLIC
PROC [
F: PascalTextFilePtr]
RETURNS [FileGetPosResult: PascalInteger] =
BEGIN
FileGetPosResult ← 0; -- in case of error below
FileGetPosResult ←
F.baseFile.str.GetIndex[ !
IO.Error =>
IF ec = NotImplementedForThisStream THEN CONTINUE];
END;
RopeFromStringNumber:
PROCEDURE [s: StrNumber]
RETURNS [r: Rope.
ROPE] = {
i: PoolPointer ← StrStart^[s];
length: NAT ← StrStart^[s+1]-i;
P:
SAFE
PROC
RETURNS [c:
CHAR] =
TRUSTED
{c ← Xchr[StrPool[i]]; i ← i+1};
r ← Rope.FromProc[length, P];
RETURN[r];
};
GetPypeCode:
PUBLIC
PROCEDURE [
F: InternalFontNumber, AtSizeInHnm:PascalInteger]
RETURNS [GetPypeCodeResult: CedarNat] =
{
IF TexSysdepInline.pyping THEN FlushPype[];
RETURN[SirPress.GetFontCode[
p: TexSysdepInline.pressHandle,
family: RopeFromStringNumber[TexOps.FontFamily[F]],
size: AtSizeInHnm+50, --round instead of truncating, to avoid font substitutions
face: TexOps.FontFace[F],
rotation: 0,
unit: 100]];
};
PressSetFont:
PUBLIC
PROCEDURE [
C:
NAT] = {
IF TexSysdepInline.pyping THEN FlushPype[];
SirPress.SetFontFromCode[TexSysdepInline.pressHandle, C];
};
PressShowRule:
PUBLIC
PROCEDURE [Xstart, Ystart, Xlen, Ylen:
INT] = {
IF TexSysdepInline.pyping THEN FlushPype[];
SirPress.PutRectangle[p: TexSysdepInline.pressHandle,
xstart: Xstart,
ystart: Ystart,
xlen: Xlen,
ylen: Ylen,
unit: 100]};
FlushPype:
PUBLIC PROCEDURE = {
IF TexSysdepInline.pyping
THEN
{ SirPress.ClosePipe[
p: TexSysdepInline.pressHandle,
pipe: TexSysdepInline.pype,
y: TexSysdepInline.yCoord];
TexSysdepInline.pyping ← FALSE};
};
PressWritePage:
PUBLIC
PROCEDURE = {
IF TexSysdepInline.pyping THEN FlushPype[];
SirPress.WritePage[TexSysdepInline.pressHandle];
};
PressCloseFile:
PUBLIC
PROCEDURE = {
SirPress.ClosePress[TexSysdepInline.pressHandle];
};
SetNormalPriority:
PUBLIC
PROCEDURE = {
Process.SetPriority[Process.priorityNormal];
};
SetBackgroundPriority:
PUBLIC
PROCEDURE = {
Process.SetPriority[Process.priorityBackground];
};
The following procedure reads the command line and returns one of three different values, encoded as integers: 0=> {command line was all blank}; 1=> {command line had non-blank stuff, and it has been loaded into the buffer}; -1=> {command line had so much non-blank stuff that it overflowed the buffer (which is unlikely, but we are running with bounds checks off, so it pays to be careful)}.
StuffOnCmdLine:
PUBLIC
PROCEDURE
RETURNS [StuffOnCmdLineResult:
INT] = {
tail: Rope.ROPE ← PascalBasic.commandLineTail;
cmdStr: IO.STREAM ← IO.RIS[tail];
curChar: CHAR;
myLoc: NAT ← First;
lastNonBlank: NAT;
DO
curChar ← '\n; -- in case of EndOfStream
curChar ← cmdStr.GetChar[! IO.EndOfStream => CONTINUE];
SELECT curChar
FROM
' => LOOP; -- ignore leading whitespace
'\n => RETURN[0]; -- everything was blank
ENDCASE => EXIT; -- aha, a nonblank
ENDLOOP;
IF myLoc >= BufSize-1 THEN RETURN[-1];
Buffer[myLoc] ← Xord[curChar];
myLoc ← myLoc+1;
lastNonBlank ← myLoc;
DO
curChar ← '\n; -- in case of EndOfStream
curChar ← cmdStr.GetChar[! IO.EndOfStream => CONTINUE];
IF curChar = '\n THEN EXIT;
IF myLoc >= BufSize-1 THEN RETURN[-1];
Buffer[myLoc] ← Xord[curChar];
myLoc ← myLoc+1;
IF curChar # ' THEN lastNonBlank ← myLoc;
ENDLOOP;
Last ← lastNonBlank;
TexSymbols.CurInput.LocField ← First;
RETURN[1]};
RopeFromBuffer:
PRIVATE
PROCEDURE [
A:
INT,
B:
INT]
RETURNS [Rope.
ROPE]= {
i: NAT ← A-1;
P: SAFE PROC RETURNS [CHAR] = TRUSTED {i ← i+1; RETURN[Xchr[Buffer[i]]]};
RETURN[Rope.FromProc[B-A+1, P]];
};
PackBufferedName:
PUBLIC
PROCEDURE [
A:
INT,
B:
INT] = {
NameOfFileFromRope[Rope.Cat[RopeFromBuffer[A,B], ".fmt"]];
};
DefaultFormatFile:
PROCEDURE
RETURNS [default: Rope.
ROPE] = {
default ← UserProfile.Token[key: "TeX.DefaultFormatFile",
default: "/Cyan/TeX/Formats/Plain.fmt"];
};
PackDefaultArea:
PUBLIC
PROCEDURE [
A:
INT,
B:
INT] = {
default: Rope.ROPE ← DefaultFormatFile[];
cp: FS.ComponentPositions;
fullName: Rope.ROPE;
[fullName, cp] ← FS.ExpandName[default];
NameOfFileFromRope[Rope.Cat[
fullName.Substr[start:0, len: cp.base.start],
RopeFromBuffer[A,B],
".fmt"]];
};
PackAllDefault:
PUBLIC
PROCEDURE = {
default: Rope.ROPE ← DefaultFormatFile[];
NameOfFileFromRope[default];
};
The following describes how the registration of the various TeX commands works.
The file TeX.bcd contains only one registration, the automatically-produced one that PasMesa generates for ``Tex''. That one has a clientData of NIL, useless documentation and is an ``interpreted'' command.
There are two auxillary BCD files which can be run after TeX.bcd, one for registering the Local versions of the commands (LocalTeXCommands.bcd) and one for use on the Compute Server (RemoteTeXServerCommands.bcd).
There are two reasons why things are done in this arcane way:
1) In order to be sure of overriding the default PasMesa registration, we need to wait until after TeX.bcd has been run before doing our work.
2) In order to make it easy to maintain the differences between the conventions of the CommandTool and those of the Compute Server.
ExclusiveProc:
PUBLIC Commander.CommandProc =
TRUSTED { [result, msg] ← PascalBasic.ExclusiveProc[cmd]; };
This simply makes PascalBasic.ExclusiveProc accessible to the auxillary BCDs.
TwiddlePascal:
PUBLIC
SAFE PROC =
TRUSTED {
PascalBasic.SubsystemProcRec.p ← TexOrInitexDependingUponClientData;
};
TexOrInitexDependingUponClientData: PascalBasic.UnsafeCommandProc = {
actLikeInitex: REF BOOL ← NARROW[PascalBasic.clientData];
TexRest.StartLikeInitex ← actLikeInitex^;
TexRest.TheRealTex;
};
InterruptTex:
PUBLIC Commander.CommandProc =
CHECKED {
Interrupt ← 1;
};