/************************************************************
*          Generalized Printer Device Driving Program       *
*************************************************************
*                                                           *
* See introductory comments in header source file.          *
*                                                           *
* This module contains procedures that are specific to the  *
* handling of 'plain' input files.                          *
*                                                           *
* P. Hazel, July 1984                                       *
* Last modified: January 1985                               *
************************************************************/


SECTION "PLAIN"

GET "LIBHDR"
GET "GTHDR"



/***********************************************************
*               Set up for plain input                     *
***********************************************************/

/* This procedure is called when the input file is not recognized
as either GCODE or DVI. ICH contains the first character of the file,
and RDCH() will read the next character. */

LET setupplain() BE
$(proc
icode := systemcode
iprotocol := iprot.plain
cmask |:= cmask.plain
readinitem := p.readinitem

charwidth := defaultplaincharwidth
linedepth := defaultplainlinedepth
pagedepth := defaultplainpagelines * linedepth

  /* Set up a manufactured "font 0" */
  /* ------------------------------ */

  $(1
  LET fb = newfont(0,0,0,0,charwidth,0)
  FOR i = fb!font.chwidths TO fb!font.chwidths+255 DO !i := charwidth
  selectfont(0)
  $)1

/* Unless quiet, verify what is going on. */
/* -------------------------------------- */

UNLESS quiet DO writes("Input is in plain format*n")
$)proc



/***********************************************************
*                Read plain input item                     *
***********************************************************/

/* This procedure returns the address of an item or zero if the
end of a page is reached. A page ends (a) at end of file, (b) at
a formfeed, and (c) when the pagedepth is exceeded. Vertical and
horizontal distances are measured in RSU (like everywhere else),
using LINEDEPTH for the linedepth and the manufactured font's
character width table pointed to by CHWIDTHS. For the moment, we
do not translate from the systemcode to ASCII. This may be
required as the program develops, though it seems a bit of a
waste. The three arguments are all addresses. The first is the
address of a word into which the vertical position of the
returned item is placed; the other two are used to maintain the
current position on the page as set by the input characters read
so far. The variable ICH contains the next input character to be
processed. It is in effect a 1-character lookahead buffer.
In ASCII worlds, there is no separate 'newline' character: linefeed
is most commonly used, but this may vary from system to system.
Hence the conditional assembly switches are system-based. */

AND p.readinitem(avpos, aivpos, aihpos) = VALOF
$(proc
LET item, str, count = ?, ?, ?

  /* Loop till found a printing character */
  /* ------------------------------------ */

  $(1

  /* Check for page overflow */
  /* ----------------------- */

  IF !aivpos > pagedepth - linedepth RESULTIS 0

  /* Process first character */
  /* ----------------------- */

  SWITCHON ich INTO
    $(2
    CASE endstreamch:
    RESULTIS 0

    CASE '*n':
    !aivpos +:= linedepth
    !aihpos := 0
    ENDCASE

    CASE '*p':
    !aivpos := pagedepth         // Force end of page, but
    !aihpos := 0                 // ensure next char is read first.
    ENDCASE

    CASE '*c':                   // carriage return
    !aihpos := 0
    ENDCASE

$<PANOS'                         // linefeed=newline in PANOS
    CASE linefeed:
    !aivpos +:= linedepth
    ENDCASE
$>PANOS'

    CASE '*b':
    UNLESS !aihpos = 0 DO !aihpos -:= 1
    ENDCASE

    DEFAULT:
    BREAK
    $)2

  ich := rdch()
  $)1
  REPEAT

/* Set up a control block for the item */
/* ----------------------------------- */

item := getpstore(maxitemsize)
str := item + item.bytes

item!item.hpos := !aihpos    // horiz position of item
!avpos := !aivpos            // vertical ditto

item!item.width := 0
item!item.bytes := 0         // default to font 0
count := 4                   // minimum count

  /* Loop for item's characters */
  /* -------------------------- */

  $(1

  /* A switch is used here, even though the branch is only
  two-way, because the compiled code (on the 3081 at least)
  is more efficient. */

  SWITCHON ich INTO
    $(2
    CASE '*n': CASE '*p': CASE endstreamch:
    CASE '*c': CASE '*b':
$<PANOS'
    CASE linefeed:    // linefeed=newline in PANOS
$>PANOS'
    BREAK

    DEFAULT:
    IF count >= maxitemcount THEN BREAK
    !aihpos +:= chwidths!ich
    str%count := ich
    item!item.width +:= chwidths!ich
    count +:= 1
    ENDCASE
    $)2

  ich := rdch()
  $)1
  REPEAT    // Until special character found

item!item.count := count
item!item.next := 0
releasepstore(maxitemsize - (length.item.hd + (count+3)/4))

RESULTIS item
$)proc


// End of PLAIN section.
