// F E D I T (PREPRESS)
//
// FEDIT -- font editor for low resolution fonts.
//
//Bcpl/f FEdit.bcpl
//

//Last modified September 16, 1980 5:13 PM by Kerry LaPrade:
// "Improved" handling when dotsize eq 1.

//Modified June 13, 1980 10:13 PM by Lyle Ramshaw:
// Added explicit dependence on dsp to call on ShowDisplayStream,
// because of Junta

//Modified: March 26, 1980 11:48 AM (by LaPrade)

//Modified: December 18, 1979 1:58 PM (by LaPrade)
// Stripped out loop stuff to FEditLoop.bcpl

//Date: December 18, 1979 1:29 PM (by LaPrade)

get "AuxiliaryMenuDefs.d"
get "FEdit.DFS"
get "FEditNames.d"

// outgoing procedure
external
[
FEdit
]

// incoming procedures
external
[
CompareIX
GetPosRelative
ReadIXTempFile
WriteIXTempFile
SetPosRelative

//FEDITFILE
EditCharExists
EditFindChar
IndexACFile

//FEDITLOOP
ClearEditWindow
FEditLoop
WriteCharCodes

//FEDITUTIL
DPAD
SetUpBBT

//PREPRESS
PrePressWindowInit

//PREPRESSUTIL
FSGetX
FSPut
IllCommand

//PREPRESSWINDOW
WindowClose
WindowCopy
WindowGetPosition
WindowRead
WindowReadBlock
WindowWriteBlock
WindowSetPosition

//SCAN
StrEq
TypeForm
]

// incoming statics
external
[
@BackgroundFileName
@bigfilename
@dotsize
@InputFileName

//FEDITFILE
@DPzero
//Double-precision zero.
@EbackgroundFile
@EeditFile
@EscratchFile
//EFILE structures for the files.
@LastCharCodeWritten //State of the scratch file.
@LastPos
//File pos where char began.
@PreviousWPos
//File pos of current char previous to this edit
@PreviousBPos
@TrailerPos
//Position of -1 trailer in file.

//FEDITLOOP
@backgroundOn
@backgroundView
@bits
@currentCharacterWidths
@currentCharacterCode
@editBox
@editBoxXSize
@editBoxYSize
@EFactorX
@EFactorY
@FEditMenu
@foregroundView
@readBBT
@readBit
@showBox
@showBoxXSize
@showBoxYSize
@showTypeInString
@UnsampledWX
@UnsampledWY
@updateBox
@WidthMarker
]


manifest
[
memorySpaceNeeded =
3 * (size BBT/16) + 2 + 2 * (size VIEW/16) + 1 + 128 + size CharWidth / 16
]

//Procedures

//*********************************************************
//let FEdit(noBackground,inputFile;numargs na) be
let FEdit() be
//*********************************************************
[
let FEditMenuBuffer = nil
let FEditMenuStream = nil

// FEditStart(noBackground,inputFile, na, lv FEditMenuBuffer, lv FEditMenuStream)
FEditStart(lv FEditMenuBuffer, lv FEditMenuStream)
// FEditLoop()
EraseMenu(lv FEditMenuBuffer, lv FEditMenuStream)

EFileFinish()
//Go finish off files.
]

//*********************************************************
//and FEditStart(noBackground,inputFile, na, lvFEditMenuBuffer, lvFEditMenuStream) be
and FEditStart(lvFEditMenuBuffer, lvFEditMenuStream) be
//*********************************************************
[FEditStart
until Endofs(keys) do Gets(keys)
bits =
(table
[ 0;
#100000; #40000; #20000; #10000;
#4000; #2000; #1000; #400;
#200; #100; #40; #20;
#10; #4; #2; #1; 0
]
) + 1

//Initialize files.
// let u = dotsize
// if na ls 2 then
// [
// if bigfilename!0 eq 0 then IllCommand()
// inputFile = 2
//Big file
// BackgroundFileName = -1
//ACtemp
//// if (params&gotresolution) ne 0 then u = resolutionx

// if (params & gotresolution) ne 0 then
// dotsize = resolutiony
////If /D or /E switch was read from command line, then
//// set dotsize accordingly
////Software sleuths: gotresolution comes from ix.dfs. K.L.
// ]

let inputFile =
(InputFileName>> STRING.length eq 0) ? -1, InputFileName
//-1 means "ACtemp" in PrepressWindowInit()

// let factor = EFileStart(noBackground, inputFile)
let factor = EFileStart(BackgroundFileName>> STRING.length eq 0, inputFile)
//Initialize view parameters.
EFactorX = factor
EFactorY = factor

test factor eq 0
ifso factor = 10000
ifnot
[
if (dotsize rem factor) ne 0 then
[
Wl("Background enlargement factor does not divide dotsize.")
EFileFinish(); return
]
if dotsize/factor ls 2 then
[
Wl("Dotsize too small or background enlargement too large")
EFileFinish(); return
]
]

//Misc.
WidthMarker = table [ 0; 2;2;2;2;0;0 ] //Why in the hell these are the initial values is beyond me. K.L.

// let v = vec 127; v!0=0
// previousShowString = v
// let v = vec 127; v!0=0
// showTypeInString = v
// let v = vec (size CharWidth / 16)
// currentCharacterWidths = v
// widthsMode = false

//Get Menu
// let FEditMenuBuffer = nil
// let FEditMenuStream = nil
GetMenu(lvFEditMenuBuffer, lvFEditMenuStream)
FEditMenu = MenuData>>DATA.menu
editBox = FEditMenu!bEditBox
showBox = FEditMenu!bShowBox
updateBox = FEditMenu!bUpdateBox
FillBox(FEditMenu!bSymbolStrip, flip, 0)
FillBox(FEditMenu!bOctalStrip, flip, 0)
FillBox(FEditMenu!bFileStrip, flip, 0)
FillBox(FEditMenu!bEditStrip, flip, 0)
//FillBox(FEditMenu!bShowStrip, flip, 0)

editBoxXSize = BoxDimensionX(editBox)
editBoxYSize = BoxDimensionY(editBox)

showBoxXSize = BoxDimensionX(showBox)
showBoxYSize = BoxDimensionY(showBox)

//Get memory space for odds and ends.
// let v = vec memorySpaceNeeded + 1
// FEditMemoryAlloc(v, memorySpaceNeeded)
let memory = FEditMemoryAlloc(memorySpaceNeeded)

// SetUpView(foregroundView, dotsize, 052525b, 125252b)
// SetUpView(backgroundView, dotsize/factor, 0, 52525b)
// SetUpBBT(readBBT, sBitMapAndGrayBlock, opReplace, readBit, 1, 0, 0, 2, 2)

let temp1, temp2, temp3 = 052525b, 125252b, 2
if dotsize ls 2 then
temp1, temp2, temp3 = -1, -1, 1

SetUpView(foregroundView, dotsize, temp1, temp2)
SetUpView(backgroundView, dotsize/factor, 0, not temp2)
//SetUpBBT(BBT, sourcetype, operation, dbca, dbmr, dlx, dty, dw, dh)
SetUpBBT(readBBT, sBitMapAndGrayBlock, opReplace, readBit, 1, 0, 0, temp3, temp3)

if foregroundView>>VIEW.dotSize gr 3 then
[
// let magicXnum = (BoxDimensionX(updateBox) - foregroundView>>VIEW.nDotsX) / 2
// let magicYnum = (BoxDimensionY(updateBox) - foregroundView>>VIEW.nDotsY) / 2

//updateBox>>BOX.bits = 0
updateBox>>BOX.xorigin = updateBox>>BOX.xorigin + (BoxDimensionX(updateBox) - foregroundView>>VIEW.nDotsX) / 2
updateBox>>BOX.yorigin = updateBox>>BOX.yorigin + (BoxDimensionY(updateBox) - foregroundView>>VIEW.nDotsY) / 2
updateBox>>BOX.xcorner = updateBox>>BOX.xorigin + foregroundView>>VIEW.nDotsX + 2 * updateBox>>BOX.bits - 1
updateBox>>BOX.ycorner = updateBox>>BOX.yorigin + foregroundView>>VIEW.nDotsY + 2 * updateBox>>BOX.bits - 1

//OutlineBox(updateBox, updateBox>>BOX.bits - 1)
]

WriteCharCodes(currentCharacterCode)
// changes = false
// changesPending = false
// gridIsOn = false
// backgroundOn = true
// WidthChanged = false
ClearEditWindow()

// ShowGrid()

// EditLoop()
FEditLoop()

Free(sysZone, memory)

]FEditStart

//*********************************************************
and GetMenu(lvbuffer, lvstream) be
//*********************************************************
[
MenuData = 0
//Avoid conflicts with menu in other overlay
let length = MenuSize() + 1
//Ws("length = "); Wos(dsp, length); Wl("")
@lvbuffer = FSGetX(length)
@lvstream = CreateMenuDisplayStream(@lvbuffer, length - 1)
ShowDisplayStream(@lvstream,DSbelow,dsp)
]

//*********************************************************
and SetUpView(view, squareSize, g0, g1) be
//*********************************************************
[
view>>VIEW.dotSize = squareSize
view>>VIEW.nDotsX = editBoxXSize/squareSize
view>>VIEW.nDotsY = editBoxYSize/squareSize

//SetUpBBT(BBT, sourcetype, operation, dbca, dbmr, dlx, dty, dw, dh, sbca, sbmr, slx, sty, g0, g1)
SetUpBBT(view>>VIEW.BBT, sGrayBlock, opInvert, 0, 0, 0, 0, squareSize, squareSize, 0, 0, 0, 0, g0, g1)
]

//*********************************************************
and EraseMenu(lvbuffer, lvstream) be
//*********************************************************
[
ShowDisplayStream(@lvstream, DSdelete)
FSPut(@lvbuffer)
]

//Comments about the format of the ACedits file. First comes the usual preamble
// stuff to an ACtemp file (i.e. read and written with ReadIXTempFile,...). Then
// comes a collection of characters, followed by a -1 (end of the update file).
// Each character is the CharWidth structure (containing width goodies) followed
// by the bit map (in ACtemp format, i.e. FHEAD is first).
// The CharWidth structure may have H=HNonExCode, in which case
// we are to delete the character from the font.

//Start up all file aspects of the edit.
// NoBackground is true if we are not to use background.
// There are three files involved:
// xxxx/B Edit file.
// ACedits File of changes, deleted at end normally.
// ACtemp Background file.
// Returns reduction factor for background (0 if no background).

//*********************************************************
and EFileStart(NoBackground,inputFile) = valof [
//*********************************************************
DPzero=table [ 0;0 ]

//Set up edit file.
//CROCK CROCK having to do with window stuff -- need better opening control
//Open read-only to be sure it exists:
let s=PrePressWindowInit(inputFile, false)
Closes(s)
//Now open read-write:
s=PrePressWindowInit(inputFile)
let fn=vec IXLName
let ix=vec IXLMax
ReadIXTempFile(s, fn, ix) //Get info.
EeditFile=IndexACFile(s, 3)

//Set up scratch file.
let sc=nil
[
sc=PrePressWindowInit("ACedits", true)
// if WindowEnd(sc) then break //No previous version!
if Endofs(sc) then break //No previous version!
unless GetConfirmation("Edits recorded during the last use of the EDIT command appear not to *nhave been merged into the edit file. Do you wish to merge them?") do break
Closes(sc)
MergeEdits() //Assumes editfile indexed.
FSPut(EeditFile) //No longer indexed
EeditFile=IndexACFile(s, 2) // so redo it
TypeForm("Merge finished.*N")
] repeat
EscratchFile=IndexACFile(sc,1) //Index it.
LastPos=table [ 0;0 ]
TrailerPos=table [ 0;0 ]
PreviousWPos=table [ 0;0 ]
PreviousBPos=table [ 0;0 ]
LastCharCodeWritten=-1
WriteIXTempFile(sc, fn, ix) //Write header.
WindowGetPosition(sc, TrailerPos)
// WindowWrite(sc,-1) //Write trailer.
Puts(sc,-1) //Write trailer.
// WindowFlush(sc) // and make sure on disk.
CleanupDiskStream(sc) // and make sure on disk.

//Set up ACtemp (background) file.
EbackgroundFile = 0
let factor = 0
// unless NoBackground do
unless NoBackground % dotsize ls 2 do
[
let cd = PrePressWindowInit(BackgroundFileName)
let fnb = vec IXLName
let ixb = vec IXLMax
ReadIXTempFile(cd, fnb, ixb)
test
ix>>IX.resolutionx eq ixb>>IX.resolutionx &
ix>>IX.resolutiony eq ixb>>IX.resolutiony &
StrEq(lv fn>>IXN.Name, lv fnb>>IXN.Name)
ifso
// factor=(ixb>>IX.siz+1)/ix>>IX.siz
factor = (ixb>> IX.siz + 5) / ix>> IX.siz
ifnot
[
TypeForm("Illegal background file*N")
factor = 1
]
EbackgroundFile=IndexACFile(cd, 2) //Index it.
]
resultis factor
]

//*********************************************************
and EFileFinish() be [
//*********************************************************
Closes(EscratchFile>>EFILE.window)
MergeEdits()
let s=EeditFile>>EFILE.window
WindowSetPosition(s, DPzero)
let fn=vec IXLName
let ix=vec IXLMax
ReadIXTempFile(s, fn, ix)
DPAD(lv ix>>IX.sa, lv ix>>IX.len)
// DoubleAdd(lv ix>>IX.sa, lv ix>>IX.len)
WindowClose(s, lv ix>>IX.sa)
]

and

//MergeEdits -- merge the edited characters recorded in the scratch (ACedits) file
// with the original version in the edit file. Save the results on a
// new edit file; delete the ACedits file.
// Assumes edit file is open and indexed. Leaves edit file open,
// but index will have been destroyed.


//*********************************************************
MergeEdits() be [
//*********************************************************
let exists=vec 256
Zero(exists, 256) //0 => not mentioned
let scd=EeditFile>>EFILE.window
WindowSetPosition(scd, DPzero)
let fn=vec IXLName
let ix=vec IXLMax
ReadIXTempFile(scd, fn, ix)

let scr=PrePressWindowInit("ACedits", false)
unless scr do return
//Build an index for the ACedits file.
let a=IndexACFile(scr, 1) //Just get dummy entries.
let fne=vec IXLName
let ixe=vec IXLMax
ReadIXTempFile(scr, fne, ixe) //Read header.
unless StrEq(lv fn>>IXN.Name, lv fne>>IXN.Name) &
CompareIX(ix, ixe) then
[
TypeForm("ACedits and ",bigfilename," do not match! Update aborted.*N")
finish
]

let edited=false
[
let c = Gets(scr) //Char code.
if c eq -1 then break
unless edited do
Wl("Merging ACEdits file into original file.")
edited=true
// Wl("Merging ACEdits file into original file.")
let n=c-a>>EFILE.bc
WindowGetPosition(scr, n*2+a>>EFILE.wp) //Width pos.
let w=vec CharWidthsize
WindowReadBlock(scr, w, CharWidthsize)
exists!c=(w>>CharWidth.H eq HNonExCode)? -1,1
WindowGetPosition(scr, n*2+a>>EFILE.bp)
let b=WindowRead(scr)
let d=vec 1; d!0=0; d!1=b<<FHEAD.ns*b<<FHEAD.hw+1
SetPosRelative(scr, d, n*2+a>>EFILE.bp)
] repeat
EscratchFile=a

if edited then [ //Some edited chars!
let bc,ec=255,-1
for c=0 to 255 do
[
if (exists!c eq 0 & EditCharExists(c, 2)) %
exists!c eq 1 then
[
if c ls bc then bc=c
if c gr ec then ec=c
]
]
ixe>>IX.bc=bc //Update char ranges.
ixe>>IX.ec=ec

//Now build new edit file.
let nc=ec-bc+1
let AC=FSGetX(nc*2)
SetBlock(AC, -1, nc*2)
let WD=FSGetX(nc*CharWidthsize)
Zero(WD, nc*CharWidthsize)
let p=WD
for i=1 to nc do [ p>>CharWidth.H=HNonExCode; p=p+CharWidthsize ]

let sout=PrePressWindowInit(0) //Scratch file!
WriteIXTempFile(sout, fne, ixe)
WindowGetPosition(sout, lv ixe>>IX.sa)
WindowWriteBlock(sout, WD, nc*CharWidthsize) //dummy
let off=vec 1
WindowGetPosition(sout, off) //Offset
WindowWriteBlock(sout, AC, nc*2)

for c=bc to ec do
[
let w=vec CharWidthsize
let a=EditFindChar(c, w, 1) //Look on scratch file.
if a eq 0 then
a=EditFindChar(c, w, 2) //Look on original ACtemp file.
if a then
[ //Write it out!
MoveBlock(WD+(c-bc)*CharWidthsize,w,CharWidthsize)
if w>>CharWidth.H ne HNonExCode then
[
GetPosRelative(sout, off, AC+(c-bc)*2)
let b=WindowRead(a) //FHEAD
// WindowWrite(sout, b)
Puts(sout, b)
let d=vec 1; d!0=0; d!1=b<<FHEAD.ns*b<<FHEAD.hw
WindowCopy(a, sout, d) //Copy encoding.
]
]
]

Closes(scr) //ACedits.
FSPut(EscratchFile)

let tl=vec 1
WindowGetPosition(sout, tl) //Total length
GetPosRelative(sout, lv ixe>>IX.sa, lv ixe>>IX.len) //get length
WindowSetPosition(sout, DPzero)
WriteIXTempFile(sout, fne, ixe)
WindowWriteBlock(sout, WD, nc*CharWidthsize)
WindowWriteBlock(sout, AC, nc*2)
FSPut(AC); FSPut(WD)
WindowSetPosition(sout, DPzero)
WindowSetPosition(scd, DPzero)
//Critical section:::::
WindowCopy(sout, scd, tl) //Copy entire scratch
// file to new edit file.
] //Some edited chars.
DeleteFile("ACedits")
//Done :::::

]

//Utilities....

//*********************************************************
and FEditMemoryAlloc(memorySpaceNeeded) = valof
//*********************************************************
[
let memory = Allocate(sysZone, memorySpaceNeeded)
let memorySpace = memory
Zero(memorySpace, memorySpaceNeeded)

foregroundView = memorySpace
memorySpace = memorySpace + (size VIEW/16)

backgroundView = memorySpace
memorySpace = memorySpace + (size VIEW/16)

//Make even
memorySpace = (memorySpace + 1) & not 1

foregroundView>>VIEW.BBT = memorySpace
memorySpace = memorySpace + (size BBT/16) //Still even

backgroundView>>VIEW.BBT = memorySpace
memorySpace = memorySpace + (size BBT/16) //Still even

readBBT = memorySpace
memorySpace = memorySpace + (size BBT/16) //Still even

readBit = memorySpace
memorySpace = memorySpace + 2 //Still even

showTypeInString = memorySpace
memorySpace = memorySpace + 128

currentCharacterWidths = memorySpace
memorySpace = memorySpace + size CharWidth / 16

resultis memory //So that it can be Free()ed later.
]