Google
 

Trailing-Edge - PDP-10 Archives - -
There are no other files named in the archive.
	!
	Copyright (c) 1977 by Pentti Kanerva
	All rights reserved
	;

		!******   READING   ******
		 ************************;


SUBROUTINE	finRdPage;
!		---------;
BEGIN
END
;



BOOLEAN SUBROUTINE	atEOF;
!			-----
	Can set EOF flag.
	;
RETURN (eof ORIF (eof _ outOfRange (rdPage)));



SUBROUTINE	rdPermit;
!		--------
	Make sure 'IBUFMP' is available for reading.
	Called from 'RDMAP'.
	;
IF NOT atEOF  THEN
BEGIN
   IF iBufMP GEQ maxIBufMP  THEN salvage; 
   inc (iBufMP);
 ! SALVAGE does 'iBufMP _ minIBufMP - 1';
END
;
SUBROUTINE	rdMap;
!		-----
	Map 'RDPAGE' of file to 'IBUFMP' of fork.
	Checks 'IBUFMP' availability first (RDPERMIT).
	Enters segment # to LINKS, sets input pointer and count.
	;
BEGIN "rdMap"
   rdPermit;  IF EOF OR stopOnEop  THEN RETURN;
   rd#Map (rdPage, iBufMP);

 ! Flag LINKS [RDPAGE]  with segment no.;
   START!CODE
	move	1, rdPage;
	move	 segment;
	dpb	 p.rdSeg;	! Mark the page "deleted";
   END
   ;
   loadN.xxIn;  ! Load N.FFIN, N.LFIN, N.CHIN;
   p.input _ '440700000000 + iBuf;	! Set pointer FIRST;
   n.input _ IF rightOf(rdPage) GEQ 0 THEN '5000
	     ELSE (n.chIn MIN '5000);	! Set count 2nd.  NOTE: Full
					  count unless EOF page, due
					  to FIXEOP of FINWRPAGE;
END "rdMap"
;
SUBROUTINE	turnRdPage;
!		----------
	Dismiss current read page, get next unless EOF.
	Map read page to input buffer (cycling and collecting of
	  input buffer is done from  RDMAP).
	;
BEGIN "turnRdPage"  INTEGER eofP;
   finRdPage;  rdPage _ rightOf (eofP _ rdPage);
   IF NOT atEOF  THEN rdMap  ELSE rdPage _ eofP;  ! Retains eofPage;
END "turnRdPage" 
;
STRING SUBROUTINE	lineSegment (INTEGER cnt);
!			-----------
	Get next contiguous segment of text from input file.
	Scans past initial 0-bytes.  Thereafter, terminates on
	  0-byte, LF, FF, CNT characters, EOP, or EOF.
	Zero or negative  CNT  causes a scan past initial NULL,
	  but returns an empty string.
	BREAKCHAR  will be set to LF, FF, or zero.
	Turning of read pages done elsewhere.
	Warning:  The code is rather tight.  It tries to be fast.
	;
QUICK!CODE "lineSegment"  
	acDef;  DEFINE	ch# = "2", bc# = "3", bp# = "4";
	LABEL  air, fair, txt, lfTerm, ffTerm, ffCont, nulTerm, 
		cntTerm, term, mtRet;

! Reserve string stack space for the result.
! Init BREAKCHAR _ 0, LINESEGMENT _ empty string;
	setzb	0, breakChar;
	push	sp, 0;		! Place for count;
	push	sp, 0;		! Place for pointer;

! Scan past initial NULL bytes.  NOTE: Pointer updated before count;
	move	bp#, p.input;	! Grab byte pointer..;
	skipg	bc#, n.input;	! ..and count (to EOP);
	 jrst	 mtRet;

  air:	ildb	ch#, bp#;	! Take the byte..;
	jumpn	ch#, fair;	! ..jump if past initial NULLs;
	sojg	bc#, air;	! Adjust count.  More on this page?;

! EOP or EOF;
	movem	bc#, n.input;	! Update count of remaining input;
	jrst	 mtRet;		! Will update input pointer, BREAKCHAR;

! Prepare to scan for the line.  Note: pointer is one ahead of count;
 fair:	DECBP (bp#);		! Back-up pointer to beginning of string;
	movem	bp#, (sp);	! Store LINESEGMENT pointer;
	movem	bc#, n.input;	! Store initial count for length calcul;

! BC# _ CNT min BC#,  to allow termination by  CNT  or  EOP;
	camle	bc#, cnt;	! Negative  CNT  is ok;
	 move	bc#, cnt;	! Max count restriction dominates;
	movem	bc#, -1(sp);	! Store for LINESEGMENT length calculation;

	jumple	bc#, cntTerm;

! Note:  Pointer updated before count;
 txt:	ildb	ch#, bp#;		! Get a byte;
	trne	ch#, LNOT (LF LOR FF);	! Skip if possibly terminator;
	 sojg	bc#, txt;		! Adjust count, more text?;

	jumple	bc#, cntTerm;	! Count terminates?;
! Count is one behind;
	jumpe	ch#, nulTerm;
	cain	ch#, LF;	! EOL?;
	 jrst	 lfTerm;
	cain	ch#, FF;	! Page mark?;
	 jrst	 ffTerm;	!  Yes;
! Adjust count;
	sojg	bc#, txt;	! More text?;
	jrst	 cntTerm;


ffTerm:	sos	 n.ffIn;	! DEC (N.FF remaining on input page);
	jrst	 ffCont;

lfTerm:	skipg	 n.ffIn;
	 sos	 n.lfIn;	! DEC (N.LF past last FF);
ffCont:	movem	ch#, breakChar;	! Break char _ LF or FF;
	soja	bc#, term;	! Adjust count, go to finish;

nulTerm:			! BC# one behind.  That and this SOS..;
	sos	 n.input;	! ..remove null-byte from both input..;
				! ..buffer and LINESEGMENT--tricky!;
cntTerm:
term:	sub	bc#, -1(sp);	! Compute  -LENGTH (LINESEGMENT);
	movnm	bc#, -1(sp);	! Set length of answer;
	addm	bc#, n.input;	! Subtract length from # bytes to EOP;
mtRet:
	movem	bp#, p.input;	! Save updated pointer;

! Must do our own return since result already in stack;
	sub	p, ['2000002];
	jrst	@ 2(p);

END "lineSegment"
;
STRING SUBROUTINE	pMapINPUT;
!			---------
	Line getter.
	Replaces  INPUT(CHANNEL,TABLE).
	Leaves well formed lines in mapped IBUF space as constant strings.
	The idea is:  
	  (1) No modification of input page (so read only will work).
	  (2) As little stuff to SAIL string space as possible to
		minimize SAIL garbage collection.

	Assembles line segments into full lines.
	Turns read pages as needed.
	;
BEGIN "pMapINPUT"  INTEGER len;  STRING line;
   line _ lineSegment (maxLength);

   WHILE NOT breakChar AND (len _ maxLength - length(line)) > 0  DO
   BEGIN
      IF EOP
      THEN BEGIN turnRdPage; IF EOF OR stopOnEOP THEN DONE END
      ;
      line _ line & lineSegment(len);
   END
   ;
   RETURN (line);		
END "pMapINPUT"
;


SUBROUTINE	backFF;
!		------
	Backing up by one page mark.  Called by MAPPGLN when first
	  break character of a file page is a FF.
	;
BEGIN "backFF"
   ibp (p.input);  ibp (p.input);   ibp (p.input);  ibp (p.input);
   dec (p.input);  inc (n.ffIn);  inc (n.input);
END "backFF"
;
		!******   WRITING   ******
		 ************************;


SUBROUTINE	finWrPage;
!		---------
	Finish for a write page.
	Enter FF, LF, and CHaracter counts in directory.
	Unmap 'WRPAGE' from fork.
	;
BEGIN "finWrPage"
   secure (wrPage);

   START!CODE  DEFINE n# = "2", pg# = "3"; 
! Compile dir entry for the output page;
	skipge	n#, n.output;	! # free bytes remaining on page;
	 setz	n#, ;
	movn	n#, n#;
	addi	n#, '5000;
	dpb	n#, f.nCh;	! # text bytes on page, into AC0;

	move	1, n.lfOut;
	dpb	1, f.nLF;	! LF's in this page;
	move	1, n.ffOut;
	dpb	1, f.nFF;	! FF's in page;

	move	pg#, wrPage;
	movem	 dir(pg#);	! Enter in directory;
   END
   ;
   unMap (fork (oBufMP));  ! Remove page from fork;
END "finWrPage"
;
SUBROUTINE	wrPermit;
!		--------
	Checks 'FREEP' availability for writing.
	If no space available, tries to RECTIFY to free up space.
	;
BEGIN "wrPermit"
! Make sure the file page is available for output;
   IF outOfRange (freeP) ORIF (wrSeg.(freeP) AND NOT rdSeg.(freeP))
   THEN 
 ! Bombs out;
   BEGIN
      warning ("

File is full.
You can finish the edit and restore the old file by doing:

  RESET,  to ""unbusy"" the file, and then 
  TV  the file one more time.

");
      endOfEdit _ TRUE;  badAbort;  ! Bail out;
   END
   ;
 ! File getting full, i.e., would everything in memory fit in the 
 !  remaining free pages?;
   filling _ nExtraFree LEQ 0;
END "wrPermit"
;
SUBROUTINE	wrMap;
!		-----
	Check availability of FREEP for writing.  Then move FREEP to
	  the right of old WRPAGE and make it the new WRPAGE. 
	Link and pmap (to 'OBUFMP' of fork) the new write page.
	Enter SEGMENT no. in LINKS[WRPAGE] and initializs byte pointer
	  and count.
	;
BEGIN "wrMap"  INTEGER wrP;
   wrPermit;  ! Check free page availability, etc.;

! Insert free page in text to the right of last write page;
   dir.((wrP _ freeP)) _ -1;  unMap (file(wrP));  ! Remove old crap;
   links.(freeP) _ links.(freeP) LAND '777777;    ! Clr segmnt #s;
   moveP1 (freeP0, wrPage);  dec (nFree);	  ! Insert;

! Init next write page;
   dpb (segment, p.wrSeg.((wrPage _ wrP))); ! Segment no.;
   p.output _ '440700000000 + oBuf;	  ! Pointer;
   n.output _ '5000;			  ! Count;
   n.ffOut _ n.lfOut _ 0;
   pMap (file(wrPage), fork(oBufMP), rd#+wr#);
END "wrMap"
;
SUBROUTINE	turnWrPage;
!		----------
	"Close" and detache current write page, start next one.
	;
BEGIN finWrPage; wrMap END;
FORWARD SUBROUTINE	finContinue (BOOLEAN unhold, dotF);


SUBROUTINE	pMapOUT (STRING str);
!		-------
	Replaces  OUT(CHAN,STR).
	Puts string to output page, gets "next" page when current one
	  fills up and there is more to put.
	Throws away zero-bytes, accumulates N.LF, N.FF.
	;
START!CODE "pMapOUT"  acDef;
	DEFINE  ch# = "2", bc# = "3", bp# = "4";
	LABEL  start, loop, full, incLF, bot, xit;

	jrst	 start;

 full:	aos	 n.output;	! Make count honest;
	hrrm	bc#, -1(sp);	! Save updated length;
	DECBP (bp#);		! Back-up pointer to hang on to CH;
	movem	bp#, (sp);	! Save pointer;
	pushj	p, turnWrPage;	! Detach this, get next page;

 start:	move	bp#, (sp);	! Get string pointer;
	hrre	bc#, -1(sp);	! Get string length;
	jumple	bc#, xit;	! String exhausted?;

 loop:	ildb	ch#, bp#;	! Get next character;
	jumpe	ch#, bot;	! Discard 0-bytes;
	sosge	 n.output;	! Output page full?;
	 jrst	 full;		!  Yes;
! Finish transferring non-0 byte;
	idpb	ch#, p.output;
	trne	ch#, LNOT(LF LOR FF);
	 sojg	bc#, loop;	! DEC (length), loop back if more;
	jumple	bc#, xit;	! String finished?;
! From here on, string length BC# not yet updated;
	cain	ch#, LF;	! Examin for LF/FF;
	 jrst	 incLF;
	caie	ch#, FF;
	 jrst	 bot;		! Not LF/FF, loop back;
! LF/FF updating;
	setzm	 n.lfOut;	! N.LF _ 0;
	aosa	 n.ffOut;	! INC (N.FF), skip;
 incLF:	 aos	 n.lfOut;	!  INC (N.LF);
 bot:	sojg	bc#, loop;	! Dec (length), loop back if more;
 xit:
END "pMapOUT" 
;
COMMENT  End of file  IOIO;