    ! EDWIN driver for the HP plotter range of HP-GL based plotters

    !############################################################################
    !#                                                                          #
    !#  This is a module from the EDWIN Graphics Package, which was developed   #
    !#  in the Department of Computer Science, at Edinburgh University, from    #
    !#  1978 to the present day, release 5 of EDWIN in October 1984.            #
    !#                                                                          #
    !#  The principal author of the EDWIN Graphics Package was J Gordon Hughes, #
    !#  while working for the Edinburgh University Computer Sceince Department. #
    !#  Parts of EDWIN have been produced by many different people, too many    #
    !#  too mention, working for different departments of Edinburgh and Leeds   #
    !#  Universities.                                                           #
    !#                                                                          #
    !#  This module is regarded as being in the public domain, and the authors  #
    !#  and accept no responsibility regarding the uses to which the software   #
    !#  will be put.                                                            #
    !#                                                                          #
    !############################################################################

    from Edwin include device
    from Edwin include icodes
    from Edwin include consts
    from Imp include Maths
    from Imp include Lognames
    from Imp include Textutils
    !%external %string (31) %spec Fname

    ! Control characters
    const integer ETX = 3
    const integer ESC =27
    const integer DEL = 127
    ! The following should be an external integer spec to the UTILITY module.
    const integer BUFF SIZE = 251

    ! Screen information
    own integer PLOT ACTIVE = FALSE;    ! FALSE => using terminal, TRUE => PLOTTER active
    own integer LAST COM = 0;     ! Used to optimise lines in the HP protocol
    own integer SX = 0;           ! Current device position
    own integer SY = 0
    own integer XL = 0, YB = 0;   ! Lower window bounds.
    own integer YT = 25 * 400;    ! Upper device window bound.
    own integer XR = 40 * 400;    ! Right hand side of device window
    own byte CUR COL = 1;         ! Current colour.
    own byte PM = FALSE;          ! Pending move.
    own byte PC = FALSE;          ! Pending colour change.
    own byte NEWFRAMED = FALSE;   ! TRUE => NEW FRAME done
    own byte TEXT MODE = FALSE;   ! TRUE while in text mode
    own byte Fill Mode = 0;       ! 0 => Outline
    own integer Char Size = 250 { Character size, <6 => don't draw characters
    own integer Char Rot  = 0
    own integer Char Font = 0
    own integer Char Mirror = 0
    own integer Char Qual = 0
    own integer Char Slant = 0
    own byte Need Char Size = True
    own byte Need Char Rot = True
    own byte Need Char Font = True
    own byte Need Char Slant = False
    own byte Need Limits = False
    own byte Line Mode = 1;       ! Line style
    own byte Rmode     = 0      { shade polygons = 3, Normal lines = 1
    own byte Escapes     = True { Add escape sequences to HPGL
    own byte Fill Required = True { Can be used to generally suppress shape fill
    own integer NLINES  = 0;      ! Number of lines drawn ( = size of polygon)
    own integer INBUFF = 32;      ! This is the initialisation code
    own string (255) Temp = "", Str = ""
    own byte Any Speed = False
    own byte Any Force = False
    own byte Any Acceleration = False
    own byte Any Thickness = False

    ! Configuration parameters -

    const integer MAX COLOUR = 16
    const integer MAX LINE = 6
    const integer MAX Fill = 7
    const integer NUM HP = 9
    const integer HPunk  = 0, HP7220 = 1, HP7580 = 2, HP7585 = 3, HP7440 = 4
    const integer HP7586 = 5, HP7470 = 6, HP7475 = 7, HP7550 = 8, HP7570 = 9
    own integer current dev = False
    const short array DEV NUMS (0:NUM HP) = -7221,  7220,   7580,   7585,   7440,   7586,   7470,   7475,   7550,  7570
    own   byte array  NUM PENS (0:NUM HP) =     4,     4,      8,      8,      8,      8,      2,      6,      8,     8
    own   integer array  MAX X (0:NUM HP) = 16000, 16000,  30240,  44380,  10900,  44380,  10900,  16158,  15970, 40000
    own   integer array  MAX Y (0:NUM HP) = 11400, 11400,  21520,  31480,   7650,  31480,   7650,  11040,  10870, 33600
    const byte array Has Fill  (0:NUM HP) =     0,     0,      0,      1,      1,      1,      1,      1,      1,     1
    const byte array Has Poly  (0:NUM HP) =     0,     0,      0,      1,      1,      1,      0,      0,      1,     1
    const byte array Has Force (0:NUM HP) =     0,     0,      1,      1,      1,      1,      0,      0,      1,     1
    const byte array Has NR    (0:NUM HP) =     0,     0,      1,      1,      0,      1,      0,      0,      0,     1
    const byte array True Origin (0:NUM HP) =   1,     1,      0,      0,      1,      0,      1,      1,      1,     0
    own string (15) array COLOUR NAME (1:MAX COLOUR) =
       "black", "blue", "green", "red", "magenta", "orange", "cyan", "brown",
       "orange", "violet", "pen 11", "pen 12", "pen 13", "pen 14", "pen 15", "pen 16"
    own byte array          SLOT USED (0:MAX COLOUR) = 0, 4, 3, 2, 1, 0 (*)
    own byte array        SLOT TO USE (0:MAX COLOUR) = 0, 4, 3, 2, 1, 3, 1, 2, 4, 3, 4, 1 (*)
    const byte array  TWO SLOT TO USE (0:MAX COLOUR) = 0, 2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 2
    const byte array FOUR SLOT TO USE (0:MAX COLOUR) = 0, 4, 3, 2, 1, 3, 1, 2, 4, 3, 4, 3, 2, 1, 4, 3, 2
    const byte array  SIX SLOT TO USE (0:MAX COLOUR) = 0, 4, 3, 2, 1, 5, 6, 2, 4, 3, 6, 5, 4, 3, 2, 1, 6
    const byte array EIGHTSLOT TO USE (0:MAX COLOUR) = 0, 4, 3, 2, 1, 5, 6, 7, 8, 3, 6, 5, 4, 3, 2, 1, 7
    own   byte array        PEN SPEED (0:MAX COLOUR) = 0(*)
    own   byte array        PEN FORCE (0:MAX COLOUR) = 0(*)
    own   byte array PEN ACCELERATION (0:MAX COLOUR) = 0(*)
    own   real array    PEN THICKNESS (0:MAX COLOUR) = 0(*)
    const byte array  LINE STYLE MAP  (0:MAX LINE)   = '0','1','4','2','3','5','6'
    const real array  LINE STYLE LEN  (0:MAX LINE)   = 0.0, 0.5, 5.0, 1.0, 5.0, 5.0, 5.0
    const byte array       Fill style (1:MAX Fill)   = '1','3','3','3','3','4','4'
    const short array      Fill Angle (1:MAX Fill)   =  0,  0, 90, 45, -45, 45, 0

    const string (127) HP NEW FRAME MESSAGE STR = "Enter a sheet of paper, type YES to go on: "

    external routine HP SET PEN alias "EDWIN_HP_SETPEN" (string (15) NAME, integer LOG NO, SLOT NO)
       return unless 1<=LOGNO<=MAX COLOUR
       COLOUR NAME (LOG NO) = NAME
       SLOT TO USE (LOG NO) = SLOT NO
    end

    external routine HP NEW FRAME MESSAGE alias "EDWIN_HP_MESSAGE" (string (127) MESSAGE)
       Oper Message ("Please remove the call to HP NEW FRAME MESSAGE!")
    end

    routine ADD (integer ONE, TWO)
       TTPUT (';')
       TTPUT (ONE)
       TTPUT (TWO)
    end

    routine ADD STR (string (255) STR)
       integer I
       TTPUT (CHARNO(STR,I)) for I = 1, 1, LENGTH(STR)
    end

    routine HP OUT NUM (integer I)
       ADD STR (ITOS (I, 0))
    end

    routine HP LINE (integer X, Y);       ! Go the the current X Y point
       own byte PATH COUNT = 0
       PATH COUNT = (PATH COUNT + 1) & 7
       if LAST COM = DEV LINE start
          TTPUT (',') if Path Count # 0
       else
          ADD ('P', 'D')
          return if SX=X and SY=Y;    ! Just a point
          ADD ('P', 'R')
          PATH COUNT = 1
       finish
       TTPUT (NL) and ADD ('P', 'R') if PATH COUNT = 0
       HP OUT NUM (X - SX)
       TTPUT (',')
       HP OUT NUM (Y - SY)
       LAST COM = DEV LINE
    end

    ! Protocol Handling routines

    routine HP INSTRUCTION (integer WHICH)
       return if Escapes = False
       TTPUT (ESC);   TTPUT ('.');   TTPUT (WHICH)
    end

    routine END TEXT MODE
       TTPUT (ETX)
       TEXT MODE = FALSE
    end

    routine RESERVE (integer N)
       ! Test to see if N chars. will fit in the buffer
       if Viewing # 0 or CURRENT DEV#HP7220 start
           { No action }
       else
           IN BUFF = IN BUFF + N
           if IN BUFF>BUFF SIZE start
               END TEXT MODE if TEXT MODE = TRUE
               HP INSTRUCTION ('L')
               FLUSH OUTPUT
               N = TTREAD until N > ' '
               N = TTREAD until N < ' ';  ! Ignore the response
               IN BUFF = 0
           finish
       finish
    end

    routine PON
       return if Viewing # 0
       HP INSTRUCTION ('(')
       PLOT ACTIVE = TRUE
    end

    routine POF
       TTPUT (';')
       RESERVE (BUFF SIZE); ! force out anything which is present.
       TTPUT (NL)
       if Escapes = True start
          HP INSTRUCTION (')')
          TTPUT (13)
       finish
       FLUSH OUTPUT
       PLOT ACTIVE = FALSE
    end

    routine SET GRAPHICS LIMITS (integer LX, LY, HX, HY)
       integer X Base, Y Base
       RESERVE (25)
       PON if PLOT ACTIVE # TRUE
       END TEXT MODE if TEXT MODE = TRUE
       if True Origin(CURRENT DEV) = True start
           X Base = 0
           Y Base = 0
       else
           X Base = MAXX(CURRENT DEV) // 2
           Y Base = MAXY(CURRENT DEV) // 2
       finish
       TTPUT (NL)
       ADD ('I', 'P')
       HP OUT NUM (LX-X Base); TTPUT (','); HP OUT NUM (LY-Y Base); TTPUT (',')
       HP OUT NUM (HX-X Base); TTPUT (','); HP OUT NUM (HY-Y Base)
       ADD ('S', 'C')
       TTPUT ('0');   TTPUT (',');   HP OUT NUM (HX-LX);   TTPUT (',')
       TTPUT ('0');   TTPUT (',');   HP OUT NUM (HY-LY)
       ADD ('I', 'W')
       if X Base = 0 start
          HP OUT NUM (LX); TTPUT (','); HP OUT NUM (LY); TTPUT (',')
          HP OUT NUM (HX); TTPUT (','); HP OUT NUM (HY)
       else
          HP OUT NUM (0); TTPUT (','); HP OUT NUM (0); TTPUT (',')
          HP OUT NUM (HX-LX); TTPUT (','); HP OUT NUM (HY-LY)
       finish
       Need Char Size = True
       TTPUT (NL)
       Need Limits = False
    end

    routine CHECK PLOTTING AND NO TEXT
       PON if PLOT ACTIVE # TRUE
       SET GRAPHICS LIMITS (XL, YB, XR, YT) if Need Limits = True
       END TEXT MODE if TEXT MODE = TRUE
    end

    routine CHECK FOR PENDING COLOURS AND MOVES
       integer I

       routine COLOUR (integer I)
          I = I - NUM PENS (CURRENT DEV) while I > NUM PENS (CURRENT DEV)
          ADD ('S', 'P');   TTPUT (I + '0')
          return if I = 0
          if Has Force (Current Dev) = True start
             if Any Acceleration = true start
                Add ('A', 'S')
                Add Str (Itos(Pen Acceleration(Cur Col),0)) if Pen Acceleration(Cur Col)#0
             finish
             if Any Force = true start
                Add ('F', 'S')
                Add Str (Itos(Pen Force(Cur Col),0)) if Pen Force(Cur Col)#0
             finish
             if Any Thickness = true start
                Add ('P', 'T')
                Add Str (Rtos(Pen Thickness(Cur Col),-1,1)) if Pen Thickness(Cur Col) >= 0.1
             finish
          finish
          if Any Speed = true start
             Add ('V', 'S')
             Add Str (Itos(Pen Speed(Cur Col),0)) if Pen Speed(Cur Col)#0
          finish
       end

       PON if PLOT ACTIVE # TRUE
       if PC = TRUE start
           if Viewing = 0 and CUR COL > 0 and SLOT USED(CUR COL)=0 start
               ! Ask the user to change to a new pen
               COLOUR (0)
               POF
               OPER INTERACT ("Enter a ".COLOUR NAME(CUR COL)." pen in slot ".ITOS(SLOT TO USE (CUR COL),0).", YES to go on: ")
               for I = 1, 1, MAX COLOUR cycle
                    SLOT USED (I) = 0 if SLOT USED (I) = SLOT TO USE (CUR COL)
               repeat
               SLOT USED (CUR COL) = SLOT TO USE (CUR COL)
               PON
           finish
           ADD ('P', 'U')
           COLOUR (SLOT USED (CUR COL))
       finish
       if PC=TRUE or PM=TRUE start
          ADD ('P', 'U')
          ADD ('P', 'A');   HP OUT NUM (SX)
          TTPUT (',');   HP OUT NUM (SY)
          TTPUT (NL)
       finish
       COLOUR (SLOT USED (CUR COL)) if PC=TRUE
       PC = FALSE
       PM = FALSE
    end

    routine UPDATE
       if PLOT ACTIVE=TRUE start
           RESERVE (10)
           PC = TRUE
           PM = TRUE
           CHECK FOR PENDING COLOURS AND MOVES
           POF
       finish
    end

    routine NEW FRAME
       integer OLD COL

       on 9 start
           CUR COL = OLD COL;   SX = XL;   SY = YB;   PM = TRUE;   PC = TRUE
           signal 9
       finish

       PON if PLOT ACTIVE # TRUE
       SX = XR;   SY = YT;   PM = TRUE; ! Goto the edge.
       OLD COL = CUR COL;               ! remember current colour.
       PC = TRUE;  CUR COL = 0;         ! Drop pen
       if Has NR (CURRENT DEV) = True start
           if NEWFRAMED=TRUE start
               ADD ('N', 'R');   TTPUT (';');   FLUSH OUTPUT
               OPER MESSAGE ("Press REMOTE on the plotter to continue")
           finish
       else if CURRENT DEV = HP7550 or Current Dev = HP7586
           ADD ('P','G');   TTPUT (';')
       else
           if VIEWING = 0 start
               UPDATE
    !           %unless Fname = "DRAFT" %or Fname = "WAVE" %start
                   OPER INTERACT (HP NEW FRAME MESSAGE STR)
    !           %finish
           finish
       finish
       NEW FRAMED = TRUE
       ! Restore default state after newframe.
       CUR COL = OLD COL;   SX = XL;   SY = YB;   PM = TRUE;   PC = TRUE
    end

    external routine HPPLOT alias "EDWIN___H" (integer COM, X, Y)
       own integer WX = 0,   WY = 0
       switch SW (0:MAX COM)

       routine SWAP (integer name  A, B)
          integer C
          C = A;   A = B;   B = C
       end

       routine New HPGL Char settings
          const string (5) array ANGLE (0: 7) =  "1,0",  "1,1",   "0,1", "-1,1",
                                                    "-1,0", "-1,-1", "0,-1", "1,-1"
          real X, Y
          return if Char Size < 20 { Text too small to draw }
          if Need Char Size = True start
             ADD ('S', 'R')
             TTPUT ('-') if Char Mirror & Mirror in Y Axis # 0
             ADD STR (Rtos(Char Size*67/(XR-XL),0,3))
             TTPUT (',')
             TTPUT ('-') if Char Mirror & Mirror in X Axis # 0
             ADD STR (RtoS(Char Size*100/(YT-YB),0,3))
             Need Char Size = False
          finish
          if Need Char Rot = True start
             ADD ('D', 'I')
             if Char Rot # 0 start
                if Rem(Char Rot,45)=0 start
                   ADD STR (ANGLE((Char Rot//45)&7))
                else
                   x = 100*Cos(Char Rot/DtoR)
                   y = 100*Sin(Char Rot/DtoR)
                   ADD STR (Rtos(x,0,3))
                   TTPUT (',')
                   ADD STR (Rtos(y,0,3))
                finish
             finish
             Need Char Rot = False
          finish
          if Need Char Font = True start
             ADD ('C', 'C') and TTPUT ('1') if Dev Nums (Current Dev) > 7500
             ADD ('C', 'A')
             TTPUT ('1') if Char Qual >= 2
             TTPUT (Char Font + '0')
             ADD ('C', 'S')
             TTPUT ('1') if Char Qual >= 2
             TTPUT (Char Font + '0')
             Need Char Font = False
          finish
          if Need Char Slant = True start
             ADD ('S', 'L')
             TTPUT ('-') if Char Slant<0
             ADD STR (RtoS(TAN(|Char Slant| / DtoR), 0, 3)) if Char Slant#0
             Need Char Slant = False
          finish
       end

       routine NEW HP ATTRIBUTE (integer X, Y)
          switch AS (0:Att Maximum)

          -> AS (X)

       AS(att colour):
              Y = 1 unless 0<=Y<=MAX COLOUR
              CUR COL = Y
              PC = TRUE
              return

       AS(att Line Style):
              Line mode = Y
              ADD ('L', 'T')
              if 0<Y<=MAX LINE start
                  TTPUT ('-') if Dev Nums (CURRENT DEV) > 7500
                  TTPUT (LINE STYLE MAP (Y))
                  TTPUT (',')
                  ADD STR (RtoS(LINE STYLE LEN (Y), 0, 3))
              finish
              return

       AS(att Char Size):
              Char Size = Y
              Need char Size = True
              return

       AS(att char rot):
              Char Rot = Y
              Need Char Rot = True
              return

       AS(att char quality):
              ! <2 => low quality, 5' tolerance, >2 => highest quality.
              Char Qual = Y
              Need Char Font = True
              return

       AS(att char font):
              Y = 0 unless 0 <= Y <= 5
              Char Font = Y
              Need Char Font = True
              return

       AS(att char slant): ! Char slant
              Char Slant = Y
              Need Char Slant = True
              return

       AS(att shade mode):
              Fill Mode = Y
              if Fill Required = True and Has Fill (CURRENT DEV) = True start
                 if 1<=y<=Max fill start
                    Add ('F', 'T')
                    if y = 1 and 0 < Pen Speed (Cur Col) < 30 start
                       TTPUT ('2')   { High Quality shading }
                    else
                       TTPUT (Fill style(y))
                    finish
                    Add Str (",50,".Itos(Fill angle(y),0))
                 else
                    Add Str (";FT4,".Itos(Y*10,0).",0")
                 finish
              else
                 Fill Mode = 0
              finish
              return

       AS(att char mirror):
              Char Mirror = Y
              Need Char Size = True

       AS(*):
       end

       END TEXT MODE if LAST COM = DEV CHAR and COM#DEV CHAR
       LAST COM = COM if COM # DEV LINE
    !   select output (0); write (com,1); write (x,1); write (y,1); newline
       -> SW (COM)

    SW(0): ! Initialise
           CURRENT DEV = -1
           Y = 0
           Y = 8 and X=X//10 if REM(X,10)=8
           for COM = 0, 1, NUM HP cycle
                CURRENT DEV = COM if DEV NUMS (COM) = X
           repeat
           signal 14, 0 if CURRENT DEV < 0
           NUM PENS (CURRENT DEV)=8 if Y=8
           Temp = ItoS (X, 0)
           DEV DATA_TYPE = X
           DEV DATA_NAME = "an HP ".Temp." plotter"
           begin
              on 3,4 start
                 Oper Message ("Error in HP Plotter Paper size specification")
                 signal 14, 1
              finish

              Str = "EDWIN_".ItoS(X,0)."_X"
              Temp = Translate(Str)
              if Temp # Str start
                  Max X (Current Dev) = Stoi (Temp) * 40
              finish
              Str = "EDWIN_".ItoS(X,0)."_Y"
              Temp = Translate (Str)
              if Temp # Str start
                  Max Y (Current Dev) = Stoi (Temp) * 40
              finish
              signal 4 if Max X (Current Dev) < 1000 or Max Y (Current Dev) < 1000
           end
           DEV DATA_DVX = MAX X (CURRENT DEV)
           DEV DATA_DVY = MAX Y (CURRENT DEV)
           DEV DATA_MVX = MAX X (CURRENT DEV)
           DEV DATA_MVY = MAX Y (CURRENT DEV)
           DEV DATA_UNITS PER CM = 400
           DEV DATA_X UNITS PER CM = 400
           DEV DATA_Y UNITS PER CM = 400
           DEV DATA_MAX COLOUR = NUM PENS (CURRENT DEV)
           DEV DATA_NUM CHAR SIZES = 255
           DEV DATA_NUM CHAR ROTS = 255
           if NUM PENS(CURRENT DEV)=2 start
               SLOT USED (Y) = 0 and SLOT TO USE (Y) = TWO SLOT TO USE (Y) for Y = 3,1,8
           finish else if NUM PENS (CURRENT DEV) = 4 start
               SLOT USED (Y) = 0 and SLOT TO USE (Y) = FOUR SLOT TO USE (Y) for Y = 5,1,8
           finish else if NUM PENS (CURRENT DEV) = 6 start
               SLOT USED (Y) = 0 and SLOT TO USE (Y) = SIX SLOT TO USE (Y) for Y = 5,1,8
               SLOT USED (Y) = SLOT TO USE (Y) for Y = 5,1,6
           finish else if NUM PENS (CURRENT DEV) = 8 start
               SLOT USED (Y) = 0 and SLOT TO USE (Y) = EIGHT SLOT TO USE (Y) for Y = 5,1,8
               SLOT USED (Y) = SLOT TO USE (Y) for Y=5,1,8
           finish
           Temp = "EDWIN_HP_NOESCAPES"
           if Translate(Temp) # Temp start
              Oper Message ("EDWIN_HP_NOESCAPES is obsolete definition, use EDWIN_".-
                            ItoS(Dev Data_Type,0)."_ESCAPES")
              signal 14, 1
           finish
           Temp = "EDWIN_".ItoS(Dev Data_Type,0)."_ESCAPES"
           if Temp = Translate (Temp) start
              Escapes = True
           else
              Temp = Translate (Temp)
              To Upper (Temp)
              if Temp="ON" start
                 Escapes = True
              else if Temp="OFF"
                 Escapes = False
              else
                 Oper Message ("Unknown setting """.Temp.""" for EDWIN_". -
                               ItoS(DevData_Type,0)."_ESCAPES must be ON or OFF")
                 signal 14, 1
              finish
           finish
           Temp = "EDWIN_HP_FILL"
           if Translate(Temp) # Temp start
              Temp = Translate (Temp)
              To Upper (Temp)
              if Temp = "YES" start
                 Fill Required = True
              else if Temp = "NO"
                 Fill Required = False
              else
                 Oper Message ("Unknown setting """.Temp.""" for EDWIN_HP_FILL".-
                               " must be YES or NO")
                 signal 14, 1
              finish
           else
              Fill Required = True
           finish
           Temp = "EDWIN_".ItoS(Dev Data_Type,0)
           if TRANSLATE(Temp)#Temp and Viewing = 0 start
              SET DEVICE (Temp)
           finish
           TTMODE (1)
           if ESCAPES = TRUE start
               PON
               HP INSTRUCTION ('J')    { Cancel any current device control info   }
               HP INSTRUCTION ('K')    { Zap anything else which is in the buffer }
               HP INSTRUCTION ('M');   ADD STR ("0;;10;:"); ! Set output mode
               unless CURRENT DEV = HP7220 start
                   ! Place plotter in ^S ^Q mode
                   HP INSTRUCTION ('I');   ADD STR (";;17;:")
                   HP INSTRUCTION ('N');   ADD STR (";19;:")
               finish
           finish
           ADD ('P', 'U');    ADD ('I', 'N')
           INBUFF = 32
           SX = XL;   SY = YB;   PM = TRUE
           NEW FRAMED = FALSE
           Need Limits = True
           POF;   PON
           Temp = Temp."_PEN_MAP"
           if Translate (Temp)#Temp start
               Com = Input Stream
               begin
                  integer I
                  on 9 start
                     Oper Message ("Cannot open HP PEN MAP file """.Temp.-
                                   """ (default pen mapping will be used)")
                     return
                  finish
                  Temp = Translate (Temp)
                  Open Input (3, Temp)
                  Select Input (3)
                  Slot Used (I) = 0 for I = 1, 1, Max Colour
                  Any Speed = False
                  Any Force = False
                  Any Acceleration = False
                  Any Thickness = False
                  begin
                     string (23) Concept
                     integer I, Slot, Speed, Acceleration, Force
                     real Thickness
                     routine Skip Spaces
                        Skip Symbol while Next Symbol # NL and Next Symbol <= ' '
                     end
                     on 3,4,9 start
                        if Event_Event # 9 start
                           Oper Message ("Invalid ".concept." for colour """.temp."""")
                           Read Symbol (Temp) until Temp=Nl
                        else
                           Close Input
                           Select Input (Com)
                           return
                        finish
                     finish
                     cycle
                        Speed = 0;   Force = 0;   Acceleration = 0;  Thickness = 0
                        Read (Temp)
                        To Upper (Temp)
                        Concept = "slot number"
                        Read (Slot)
                        skip spaces
                        if Next Symbol # NL start
                           Concept = "pen speed"
                           Read (Speed)
                           Any Speed = true if Speed # 0
                           Skip Spaces
                           if Next Symbol # NL start
                              Concept = "pen force"
                              Read (force)
                              Any Force = true if Force # 0
                              Skip Spaces
                              if Next Symbol # NL start
                                 Concept = "pen acceleration"
                                 Read (acceleration)
                                 Any Acceleration = true if acceleration # 0
                                 Skip Spaces
                                 if Next Symbol # NL start
                                    Concept = "pen thickness"
                                    Read (thickness)
                                    Any Thickness = True
                                 finish
                              finish
                           finish
                        finish
                        Skip Symbol while Next Symbol # NL
                        Skip Symbol
                        for I = 1, 1, Max Edwin Colour cycle
                           if Edwin Colours (I) = Temp or Temp = "BLACK" start
                              I = 1 if Temp = "BLACK"
                              if Slot <= Num Pens (Current dev) start
                                 Slot to Use (I) = Slot
                                 Slot Used (Slot) = I
                                 Pen Speed (I) = Speed
                                 Pen Force (I) = Force
                                 Pen Acceleration (I) = Acceleration
                                 Pen Thickness (I) = Thickness
                              else
                                 Oper Message ("Slot number ".ItoS(Slot,0). -
                                         " in HP PEN MAP is too large (ignored)")
                              finish
                              exit
                           else if I=Max Edwin Colour
                              Oper Message ("Unknown Colour """.Temp.-
                                            """ in HP PEN MAP file (ignored)")
                           finish
                        repeat
                     repeat
                  end
               end
           finish
           return

    SW(1): ! Terminate
           SET GRAPHICS LIMITS (XL, YB, XR, YT)
           ADD ('D', 'F')
           CUR COL = 0;   PC = TRUE
           RESERVE (10)
           CHECK FOR PENDING COLOURS AND MOVES
           if Viewing = 0 and Escapes = True start
              ! Wait for plot to complete
              POF
              HP INSTRUCTION ('L')
              FLUSH OUTPUT
              COM = TTREAD until COM > ' '
              COM = TTREAD until COM < ' ';  ! Ignore the response
              PON
           finish
           if Has NR (CURRENT DEV) = True start
              ADD ('N', 'R')
           else if Current Dev = HP7550
              ADD ('P','G')
           finish
           TTPUT (';')
           if Viewing = 0 start
               POF
               TTMODE (0)
           else
               TTPUT (NL)
               FLUSH OUTPUT
               CLOSE OUTPUT
           finish
           return

    SW(2): ! Update
           UPDATE
           if Viewing = 0 and Escapes = True start
              ! Wait for plot to complete
              HP INSTRUCTION ('L')
              FLUSH OUTPUT
              COM = TTREAD until COM > ' '
              COM = TTREAD until COM < ' ';  ! Ignore the response
           finish
           return

    SW(3): ! New frame
           SET GRAPHICS LIMITS (XL, YB, XR, YT) if Need Limits = True
           NEW FRAME
           return

    SW(4): ! Move Abs
           NEW FRAME if NEW FRAMED # TRUE
           SX = X - XL;   SY = Y - YB;   PM = TRUE
           if Rmode=3 {polygons} start
              Add ('L', 'T') if Line Mode # 0
              Check for Pending Colours and Moves
              Add ('P', 'M') and TTput ('0') if Fill Required = True
           finish
           return

    SW(5): ! Line Abs
           NEW FRAME if NEW FRAMED # TRUE
           PON if PLOT ACTIVE # TRUE
           SET GRAPHICS LIMITS (XL, YB, XR, YT) if Need Limits = True
           RESERVE (30) if Viewing = 0 or LAST COM # DEV LINE
           CHECK FOR PENDING COLOURS AND MOVES
           X = X - XL;   Y = Y - YB
           HP LINE (X, Y)
           NLINES = NLINES + 1
           SX = X;   SY = Y
           return

    SW(6): ! Character
           return if Char Size < 20
           NEW FRAME if NEWFRAMED # TRUE
           PON if PLOT ACTIVE # TRUE
           SET GRAPHICS LIMITS (XL, YB, XR, YT) if Need Limits = True
           RESERVE (3) if Viewing = 0 or TEXT MODE # TRUE
           if TEXT MODE # TRUE start
               CHECK FOR PENDING COLOURS AND MOVES
               NEW HPGL Char Settings {if required}
               TTPUT (NL)
               ADD ('L', 'B')
               TEXT MODE = TRUE
           finish
           TTPUT (X)
           return

    SW(7): ! New attribute
           PON if PLOT ACTIVE # TRUE
           return if X > Att Maximum
           RESERVE (10) if Viewing = 0
           NEW HP ATTRIBUTE (X, Y)
           return

    SW(8): ! Lower window bounds
           X = 0 if X<0
           XL = X
           Y = 0 if Y<0
           YB = Y
           return

    SW(9): ! Upper window bounds
           X = MAXX (CURRENT DEV) if X > MAXX (CURRENT DEV)
           XR = X
           Y = MAXY (CURRENT DEV) if Y > MAXY (CURRENT DEV)
           YT = Y
           Need Limits = True
           return

    SW(10): ! Polygons?
            if Has Poly (Current Dev) = True start
               if RMODE = 3 start
                  if Fill Required = True start
                     ADD ('P', 'M');  TTPUT ('2')
                     if Nlines > 1 start
                        ADD ('F', 'P');
                        ADD ('E', 'P');
                     finish
                     Nlines = 0
                  finish
                  New HP Attribute (1, Line Mode) if Line Mode # 0
               finish
               RMODE = X
            finish
            return

    SW(11): return { ignore mode settings }

    SW(12): ! Lower box bounds
            WX = X;   WY = Y
            return

    SW(13): ! Upper box bounds, and do box
            SWAP (WX, X) if WX > X
            SWAP (WY, Y) if WY > Y
            return if WX > XR or X < XL or WY > YT or Y < YB
            WX = XL if WX < XL
            WY = YB if WY < YB
            X = XR if X > XR
            Y = YT if Y > YT
            ! Box now clipped into the screen.
            NEW FRAME if NEW FRAMED # TRUE
            PON if PLOT ACTIVE # TRUE
            SET GRAPHICS LIMITS (XL, YB, XR, YT) if Need Limits = True
            RESERVE (30) if Viewing = 0 or LAST COM # DEV LINE
            Add ('L','T') if Line Mode # 0
            if Fill Mode = 0 start
                HPPLOT (4, WX, WY)
                HPPLOT (5, X, WY)
                HPPLOT (5, X, Y)
                HPPLOT (5, WX, Y)
                HPPLOT (5, WX, WY)
            else
                SX = WX - XL;   SY = WY - YB;   PM = TRUE
                CHECK FOR PENDING COLOURS AND MOVES
                SX = X - XL;   SY = Y - YB;   PM = TRUE
                Add ('R','R'); HP Out Num (X-WX); TTput (','); HP Out Num (Y-WY)
                Add ('E','R'); HP Out Num (X-WX); TTput (','); HP Out Num (Y-WY)
            finish
            New HP Attribute (1, Line Mode) if Line Mode # 0
            return

    SW(14): { Hardware circles }
            { X is the Radius, and Y is used as a temp }
            RESERVE (20)
            if Fill Mode # 0 start
                CHECK FOR PENDING COLOURS AND MOVES
                ADD ('W', 'G');   Add Str (Itos(X,0).",0,360")
                ADD ('E', 'W');   Add Str (Itos(X,0).",0,360")
            else
                CHECK FOR PENDING COLOURS AND MOVES
                ADD ('C', 'I');   HP OUT NUM (X)
            finish
            return

    SW(15): return
    end

    external routine HP C ARC alias "EDWIN_HP_C_ARC" (integer RAD, integer IA, FA)
       integer OX, OY
       RESERVE (20)
       OX = SX;   OY = SY
       SX = SX + INT (RAD * COS (IA / DtoR));  SY = SY + INT (RAD * SIN (IA / DtoR));   PM = TRUE
       NEWFRAME if NEWFRAMED # TRUE
       CHECK PLOTTING AND NO TEXT
       CHECK FOR PENDING COLOURS AND MOVES
       ADD ('P', 'D')
       ADD ('A', 'R')
       HP OUT NUM (OX-SX);   TTPUT (',');   HP OUT NUM (OY-SY);   TTPUT (',')
       FA = FA - 360 if FA > IA
       HP OUT NUM (FA-IA)
       ADD ('P', 'U')
       SX = OX;   SY = OY;   PM = TRUE
    end

    external routine HP AC ARC alias "EDWIN_HP_AC_ARC" (integer RAD, integer IA, FA)
       integer OX, OY
       RESERVE (20)
       OX = SX;   OY = SY
       SX = SX + INT (RAD * COS (IA / DtoR));  SY = SY + INT ( RAD * SIN (IA / DtoR));   PM = TRUE
       NEWFRAME if NEWFRAMED # TRUE
       CHECK PLOTTING AND NO TEXT
       CHECK FOR PENDING COLOURS AND MOVES
       ADD ('P', 'D')
       ADD ('A', 'R')
       HP OUT NUM (OX-SX);   TTPUT (',');   HP OUT NUM (OY-SY);   TTPUT (',')
       FA = FA + 360 if FA<IA
       HP OUT NUM (FA-IA)
       ADD ('P', 'U')
       SX = OX;   SY = OY;   PM = TRUE
    end

    external routine H REQ alias "EDWIN___H_REQ" (integer name STATE, X, Y)
       integer I, S

       on 1,2,3,4,5,6,7,8 start
           signal 14, 4
       finish

       routine RAS (integer name V)
          ! Read and Skip symbol
          integer I
          V = 0
          I = TTREAD
          if I='-' then S=-1 and I=0 else S=1
          cycle
             V = V*10+(I-'0')
             I = TTREAD
             exit unless '0'<=I<='9'
          repeat
          V = V * S
       end

       signal 14, 8 if Viewing # 0

       CHECK PLOTTING AND NO TEXT
       CHECK FOR PENDING COLOURS AND MOVES
       ADD ('D', 'P')
       cycle
          ADD ('O', 'S');   TTPUT (';');   FLUSH OUTPUT
          RAS (I)
       repeat until I&4#0
       ADD ('O', 'D');   TTPUT (';');   FLUSH OUTPUT
       RAS (X);   RAS (Y);   RAS (STATE)
       STATE = STATE << 4       { for compatability }
       POF
       FLUSH OUTPUT
    end

    end of file