-- RopeEdit.mesa
-- written by Bill Paxton, February 1981
-- last edit by Bill Paxton, 17-Jan-82 15:44:31

-- This module provides editing and filing operations for ropes

-- The edit functions are
	-- Replace, Delete, Insert, Copy, Move, Transpose
	-- ReplaceByChar, InsertChar, AppendChar,
	-- ReplaceByString, InsertString, AppendString

-- The filing functions are
	-- ToFile[fileName] and ToFileC[fileCapability]
	-- FromFile[fileName] and FromFileC[fileCapability]
	
-- There are also two routines for use with FileByteStreams
	-- PutRope[fileByteStream,rope] and GetRope[fileByteStream,length]

-- Finally, there are a few miscellaneous Rope operations
	-- Size, Fetch, Flatten
	
DIRECTORY
Rope,
IOStream,
Mopcodes,
RopeFrom;

RopeEdit: DEFINITIONS
IMPORTS Rope, Mopcodes, RopeFrom
SHARES Rope =
BEGIN OPEN r:Rope, fromI:RopeFrom;

ROPE: TYPE = Rope.ROPE;
Offset: TYPE = INT;
MaxLen: Offset = LAST[Offset];
MaxNat: NAT = LAST[NAT];


-- **** Editing Operations ****

Substr: PROC [base: ROPE, start: Offset ← 0, len: Offset ← MaxLen]
	RETURNS [ROPE];
	-- returns a subrope of the base

Concat: PROC [base, rest: ROPE, baseLen, restLen: Offset ← MaxLen]
	RETURNS [ROPE];
	-- returns the concatenation of two ropes

Replace: PROC [
	base: ROPE, start: Offset ← 0, len: Offset ← MaxLen, replace: ROPE ← NIL,
	baseSize, repSize: Offset ← MaxLen]
	RETURNS [ROPE];
	-- returns a new rope with the given range replaced

Delete: PROC [base: ROPE, start, len, baseSize: Offset]
	RETURNS [ROPE] = INLINE { RETURN [
	Replace[base,start,len,NIL,baseSize,0]] };

Insert: PROC [
	dest: ROPE, destLoc: Offset ← 0, source: ROPE,
	destSize, sourceSize: Offset ← MaxLen]
	RETURNS [ROPE] = INLINE { RETURN [
	Replace[dest,destLoc,0,source,destSize,sourceSize]] };

Copy: PROC [
	dest: ROPE, destLoc: Offset ← 0,
	source: ROPE, start: Offset ← 0, len: Offset ← MaxLen,
	destSize: Offset ← MaxLen]
	RETURNS [ROPE];

Move: PROC [base: ROPE, dest, start: Offset ← 0, len, baseSize: Offset ← MaxLen]
	RETURNS [ROPE];
	-- no-op if dest in [start..start+len]

Transpose: PROC [
	base: ROPE, astart, alen, bstart, blen: Offset,
	baseSize: Offset ← MaxLen]
	RETURNS [ROPE];
	-- [astart..astart+alen) must not intersect [bstart..bstart+blen)
BadTranspose: ERROR;

ReplaceByChar: PROC [
	base: ROPE, char: CHAR,
	start: Offset ← 0, len, baseSize: Offset ← MaxLen]
	RETURNS [ROPE];

InsertChar: PROC [
	base: ROPE, char: CHAR, loc: Offset ← 0, baseSize: Offset ← MaxLen]
	RETURNS [ROPE] =
	INLINE { RETURN [ReplaceByChar[base,char,loc,0,baseSize]] };

AppendChar: PROC [base: ROPE, char: CHAR, baseSize: Offset ← MaxLen]
	RETURNS [ROPE] = 
	INLINE { RETURN [ReplaceByChar[base,char,MaxLen,0,baseSize]] };

AppendByte: PROC [base: ROPE, x: UNSPECIFIED, baseSize: Offset ← MaxLen]
	RETURNS [ROPE] = INLINE {
	RETURN [AppendChar[base,LOOPHOLE[x,CHAR],baseSize]] };

String: TYPE = REF READONLY TEXT;

ReplaceByString: PROC [
	base: ROPE, string: String,
	stringStart: NAT ← 0, stringNum: NAT ← MaxNat,
	start: Offset ← 0, len, baseSize: Offset ← MaxLen]
	RETURNS [new: ROPE];

InsertString: PROC [
	base: ROPE, string: String,
	stringStart: NAT ← 0, stringNum: NAT ← MaxNat,
	loc: Offset ← 0, baseSize: Offset ← MaxLen]
	RETURNS [ROPE] = INLINE { RETURN [
	-- string is inserted at loc
	-- inserts stringNum chars from string starting with stringStart
	ReplaceByString[base,string,stringStart,stringNum,loc,0,baseSize]] };

AppendString: PROC [
	base: ROPE,
	string: String,
	stringStart:NAT ← 0,
	stringNum: NAT ← MaxNat,
	baseSize: Offset ← MaxLen] RETURNS [ROPE] = INLINE { RETURN [
	ReplaceByString[base,string,stringStart,stringNum,MaxLen,0,baseSize]] };
	

-- **** Filing Operations ****

ToFile: PROC [fileName, rope: ROPE, start: Offset ← 0];
	-- write the rope on the specified file
	-- starts writing at given address in file
	-- truncates file to end of rope
	
FromFile: PROC [fileName: ROPE, start: Offset ← 0, len: Offset ← MaxLen,
	okToMapFile: BOOLEAN ← FALSE]
	RETURNS [ROPE];
	-- create rope from the contents of a file
	-- starts reading at given start address in file
	-- pretends that start+len is the end of the file
	-- set okToMapFile to TRUE if you will not want to overwrite the contents later

-- **** IOStream Operations ****

PutRope: PROC [stream: IOStream.Handle, rope: ROPE];
	-- does a series of IOStream.PutBlock's

GetRope: PROC [stream: IOStream.Handle, len: Offset ← MaxLen]
	RETURNS [rope: ROPE];
	-- reads up to len chars from stream (via GetBlock's) and makes a rope

	
-- **** Miscellaneous Operations

Size: PROC [base: ROPE] RETURNS [Offset] = INLINE { -- copied from RopeInline.Mesa
	OPEN Rope;
	ExtendPositive: PROC [x: INTEGER] RETURNS [Offset] = MACHINE CODE {Mopcodes.zLI0};
	FirstPtr: TYPE = LONG POINTER TO INTEGER;
	Tobject: TYPE = object node RopeRep;
	first: INTEGER;
	IF base = NIL THEN RETURN [0];
	IF (first ← LOOPHOLE[base,FirstPtr]↑) >= 0 THEN RETURN [ExtendPositive[first]];
	RETURN [LOOPHOLE[base, REF Tobject].size] };

Fetch: PROC [rope: ROPE, index: Offset] RETURNS [CHAR] = INLINE {
	RETURN [Rope.Fetch[rope,index]] };

CountPieces: PROC [rope: ROPE] RETURNS [count: Offset] = INLINE {
	[,count,] ← RopeStats[rope] };

RopeStats: PROC [base: ROPE, start: Offset ← 0, len: Offset ← MaxLen]
	RETURNS [size, pieces, depth: Offset];

Flatten: PROC [rope: ROPE] RETURNS [ROPE] = INLINE {
	RETURN [fromI.FlatSubstr[rope,0,MaxLen]] };
	-- create a flat version of rope

Depth: PROC [rope: ROPE] RETURNS [depth: INTEGER];

-- ***** Character property information

CharProperty: TYPE = {white, alphaNumeric, punctuation, illegal};
CharPropertyTable: TYPE = PACKED ARRAY CHAR OF CharProperty;
charPropertyTable: REF READONLY CharPropertyTable;

WhiteChar, BlankChar: PROC [char: CHAR] RETURNS [BOOLEAN] = INLINE {
-- Returns TRUE iff char has property=white.
  RETURN [charPropertyTable[char] = white] };

AlphaNumericChar: PROC [char: CHAR] RETURNS [BOOLEAN] = INLINE {
-- Returns TRUE iff char has property=alphaNumeric.
  RETURN [charPropertyTable[char] = alphaNumeric] };

PunctuationChar: PROC [char: CHAR] RETURNS [BOOLEAN] = INLINE {
-- Returns TRUE iff char has property=punctuation.
  RETURN [charPropertyTable[char] = punctuation] };

IllegalChar: PROC [char: CHAR] RETURNS [BOOLEAN] = INLINE {
-- Returns TRUE iff char has property=illegal.
  RETURN [charPropertyTable[char] = illegal] };

TestCharProp: PROC [char: CHAR, property: CharProperty] RETURNS [BOOLEAN] = INLINE {
-- Returns TRUE iff char has property.
  RETURN [charPropertyTable[char] = property] };

GetCharProp: PROC [char: CHAR] RETURNS[property: CharProperty] = INLINE {
-- Returns property {white, alphaNumeric, punctuation, illegal} for char.
  RETURN [charPropertyTable[char]] };

CR: CHAR = 'M-100B;
TAB: CHAR = 'I-100B;
SP: CHAR = ' ;

UpperCase: PROC [c: CHAR] RETURNS [CHAR] = INLINE {
  RETURN [IF c IN ['a..'z] THEN c-40B ELSE c] };
  
LowerCase: PROC [c: CHAR] RETURNS [CHAR] = INLINE {
  RETURN [IF c IN ['A..'Z] THEN c+40B ELSE c] };


-- ***** Initialization

Start: PROC; -- for initialization only

END.