Program Key;
 {[A+,B+,L-,K+,R+] Pasmat directive }

{  Program descriptor: This program may be used to program the function
   keys on a VT220 terminal.  Its function are as described below:

        >KEY F6=PA3 KEYS/ERR/NOWALK
        >KEY ?  - to obtain help 
        >KEY  - to be prompted for input 
        >KEY @  - to reprogram saved key definitions 
{

}
  { Last Edit: 29-SEP-1986 16:17:22 

    Author: Randy Baldwin
    Creation date: 5-JUN-1985 15:53:57 
    File spec: KEY.PAS
    Descr: VT2xx function key programmer.
    Version: 1.0.7
    History: 

     29-Sep-86.  Philip Hannay.  Modified to correct bug when 
       using indirect (@T acted the same as @).  Enhanced so that
       blank lines in KEYFILE.TXT are ignored and don't cause an
       error.

}

 %INCLUDE 'ex:[22,320]GENERAL3.TYP';
 %INCLUDE 'ex:[22,320]STRING.PKG';
 %INCLUDE 'EX:[22,320]CASTWO.EXT';


  PROCEDURE GMCR;
    EXTERNAL;

  VAR
    Fyle: TEXT;
    Inbuff: CH80;
    Sbuff: PACKED ARRAY [0..80] OF CHAR;
    Keybuf: CH4;
    Send: CH2;
    Search_String: PACKED ARRAY [0..1] OF CHAR;
    Count, Next, Len, x, i: INTEGER;
    Status, Index, F_key: INTEGER;
    Success: BOOLEAN;




  FUNCTION WHICH(VAR BUF: CH4): INTEGER;


    BEGIN
      CASE BUF[2] OF
        '2': i := 34; {F20}
        '6': i := 17; {F6}
        '7': i := 18; {F7}
        '8': i := 19; {F8}
        '9': i := 20; {F9}
        'O', 'o': i := 29; {DO}
        OTHERWISE i := - 1;
        END; {CASE}
      IF i = - 1 THEN
        BEGIN
        CASE BUF[3] OF
          '0': i := 21; {F10}
          '1': i := 23; {F11}
          '2': i := 24; {F12}
          '3': i := 25; {F13}
          '4': i := 26; {F14}
          'L', 'l': i := 28; {HELP}
          '7': i := 31; {F17}
          '8': i := 32; {F18}
          '9': i := 33; {F19}
          OTHERWISE i := - 1;
          END; {CASE}
        END;
      WHICH := i;
    END;



{----------------------------- FUNCTION HEX ---------------------------------}


  FUNCTION HEX(number: INTEGER): CH2;

    TYPE
      table_type = ARRAY [1..16] OF CHAR;

    VAR
      X1, X2: INTEGER;
      C1, C2: CHAR;
      temp: CH2;

    CONST
      table = table_type( { 0 } '0',
      {  1 } '1',
      {  2 } '2',
      {  3 } '3',
      {  4 } '4',
      {  5 } '5',
      {  6 } '6',
      {  7 } '7',
      {  8 } '8',
      {  9 } '9',
      { 10 } 'A',
      { 11 } 'B',
      { 12 } 'C',
      { 13 } 'D',
      { 14 } 'E',
      { 15 } 'F');


    BEGIN
      X1 := number DIV 16;
      X2 := number MOD 16;
      C1 := table[X1 + 1];
      C2 := table[X2 + 1];
      temp[1] := C1;
      temp[2] := C2;
      HEX := temp;
    END;


  PROCEDURE ASCHEX(WHAT: CHAR);


    BEGIN
      Send := HEX(ORD(WHAT));
    END;




  PROCEDURE HELP;


    BEGIN
      WRITELN;
WRITELN('  KEY - VT220 FUNCTION KEY PROGRAMMER PROGRAM -- HELP TEXT');
WRITELN;
WRITELN('  VT2XX function keys can be programmed.  This',
                ' applies only to the shifted');
WRITELN('  key (ie. <SHIFT><F7>).  Likewise, they cannot',
                 ' be programmed from set up,');
WRITELN('  but only from escape sequences sent to the',
                 ' terminal from the host.');
WRITELN('  The KEY program allows us to do this.  ');
WRITELN;
WRITELN('  You can invoke KEY in three modes.  One is',
                 ' to program your VT220 keys only,');
WRITELN('  another is to program both keys and save',
                 ' those commands is a text file, and');
WRITELN('  the third is to program the keys from commands',
                 ' in an existing text file.');
WRITELN;
WRITELN('  To program keys only, invoke KEY without',
                 ' a command line and then enter');
WRITELN('  the command after the prompt (ie. type "KEY" only).');
WRITELN;
WRITELN('  To program keys and save in text file called',
                 ' KEYFILE.TXT, type "KEY command"');
WRITELN('  where command is a valid key command.');
WRITELN;
WRITELN('  Finally, to use commands in an existing command',
                 ' file, type "KEY @filename"');
WRITELN('  where filename is a valid command file. ',
                 ' If you just type "KEY @", then');
WRITELN('  the filename "KEYFILE.TXT" will be assumed.',
                 '  This is handy if you wish');
WRITELN('  to have a KEYFILE.TXT is your login UFD that',
                 ' is invoked by your LOGIN.CMD');
WRITELN('  or if you want to switch from one group of',
                 ' keys to another by having');
WRITELN('  several command files like DTRKEY.TXT, MACROKEY.TXT,',
                 ' and PASCALKEY.TXT.');
WRITELN;
WRITELN('  KEY commands take the form "keyname=keydef"',
                 ' where keyname is a valid');
WRITELN('  VT220 key name from F6 thru f20, and HELP',
                 ' and DO, and keydef is the');
WRITELN('  string of characters that will be associated',
                 ' with the key.  The string');
WRITELN('  is not quoted, and can include non-printable',
                 ' characters by using the');
WRITELN('  Macro-11 type definition delimited by backslashes. ');
WRITELN;
WRITELN('  For example (double quotes delimit command',
                 ' and are not part of syntax):');
WRITELN;
WRITELN('    "F6=SHOW "');
WRITELN('    "F7=USERS\<13><12>\"');
WRITELN('    "F8=TERMINAL\<13><12>\"');
WRITELN('    "F9=RING BELL\<7><7><7><13><12>\"');
WRITELN('    "HELP=!SEE SYSTEM PROGRAMMER\<13><12>\"');
WRITELN;
WRITELN('  Note that the non-printable characters are',
                 ' indicated by their ascii');
WRITELN('  decimal number delimited by <>.  The nonprintable',
                 ' characters are then');
WRITELN('  delimited by backslashes (\).  Note that',
                 ' you can use EDT to imbed non');
WRITELN('  printable characters in the text of a command',
                 ' file without using this');
WRITELN('  above method of indicating nonprintable characters.  ');
WRITELN;
WRITELN('  This help file is invoked by typing "KEY ?"');
WRITELN;
      WRITELN;
    END;




  PROCEDURE DOPROG;

    VAR
      Match, Start, Stop, x: INTEGER;
      Hold: word;


    BEGIN
      Len := SLEN(Sbuff); {see how long the buffer is}
      Search_String[0] := CHR(1);
      Search_String[1] := '='; {look for an = sign in buff}
      Next := SSEARCH(Sbuff, Search_String, 1);
      IF (Next <= 5) AND (Next <> 0) THEN {if zero no find, must be <= 5 for
                                           valid keyname}
        BEGIN
        FOR x := Index TO Next - 1 DO Keybuf[x] := Sbuff[x];
        F_key := WHICH(Keybuf);
        END
      ELSE Success := FALSE;
      IF (NOT Success) OR (F_key = - 1) THEN
        BEGIN
        Success := FALSE;
        WRITELN(' ***  KEY> Unrecognized command, process aborted.');
        END
      ELSE
        BEGIN
        Start := 1;
        WRITE(CHR(144), '1;1|', F_key: 1, '/');
        x := Index + Next;
        REPEAT
          BEGIN
          IF Sbuff[x] <> '\' THEN
            BEGIN
            ASCHEX(Sbuff[x]);
            WRITE(Send);
            END
          ELSE
            BEGIN
            x := x + 1; {skip first \}
            Search_String[0] := CHR(1);
            Search_String[1] := '\'; {look for a matching \ in buff}
            Match := SSEARCH(Sbuff, Search_String, x);
            IF Match = 0 THEN
              BEGIN
              x := Len;
              WRITELN(CHR(156));
              WRITELN(' *** KEY>  Syntax error, No matching \ character.');
              END
            ELSE
              BEGIN
              WHILE (Sbuff[x] <> '\') AND (x < Len) DO
                BEGIN
                Search_String[0] := CHR(1);
                Search_String[1] := '<'; {look for an < sign in buff}
                Start := SSEARCH(Sbuff, Search_String, Start);
                Search_String[1] := '>'; {look for an > sign in buff}
                Stop := SSEARCH(Sbuff, Search_String, Start);
                IF Stop = 0 THEN
                  BEGIN
                  WRITELN(CHR(156));
                  WRITELN(' *** KEY>  Syntax Error, No matching > sign.');
                  x := Len;
                  END
                ELSE
                  BEGIN
                  Start := Start + 1;
                  Castwo(Sbuff, Hold, Start, 10);
                  Send := HEX(Hold);
                  WRITE(Send);
                  Start := Stop + 1;
                  x := Start;
                  END;
                END;
              END;
            END;
          x := x + 1;
          Count := Count + 2;
          END;
        UNTIL x > Len;
        WRITELN(CHR(156));
        END;
    END;




  PROCEDURE INDIRECT;

    VAR
      x, Start, span: INTEGER;
      fylename: CH13;


    BEGIN
      Start := 6;
      span := SLEN(Inbuff);
      IF span >= 6 THEN ssubstr(fylename, Inbuff, Start, span)
      ELSE sassign(fylename, 'KEYFILE.TXT');
      Count := 0;
      CLOSE(Fyle);
      RESET(Fyle, fylename, , Status);
      IF Status <> 1 THEN
        WRITELN(' *** KEY>  Unable to open file. Process aborted.')
      ELSE
        BEGIN
        WRITELN('  The following keys are being restored: ');
        WHILE NOT EOF(Fyle) DO
          BEGIN
          SREAD(Fyle, Sbuff);
          Len := SLEN(Sbuff);
          IF Len > 0 THEN
            BEGIN
            WRITE(' **  ');
            FOR x := 1 TO ORD(Sbuff[0]) DO WRITE(Sbuff[x]);
            IF Count + Len > 256 THEN
              WRITELN(' BUFFER OVERFLOW, UNABLE TO PROGRAM ALL STORED COMMANDS')
            ELSE
              BEGIN
              Index := 1;
              DOPROG;
              END;
            END;
          END;
        END;
    END;




  PROCEDURE DIRECT;

    VAR
      x: INTEGER;


    BEGIN
      WRITELN(' ENTER KEY AND STRING TO');
      WRITE('           PROGRAM [F20=FUBAR]: ');
      SREAD(INPUT, Inbuff);
      ssubstr(Sbuff, Inbuff, 1, 80);
      Index := 1;
      DOPROG;
    END;




  BEGIN
    Success := TRUE;
    FOR x := 1 TO 80 DO Sbuff[x] := CHR(0);
    SCLEAR(Inbuff);
    SCLEAR(Sbuff);
    GMCR;
    Index := 5;
    SREAD(INPUT, Inbuff);
    IF Inbuff[4] = CHR(0) THEN Inbuff[Index] := 'P';
    CASE Inbuff[Index] OF
      '@': INDIRECT;
      '?': HELP;
      'P': DIRECT;
      'F', 'H', 'D', 'f', 'h', 'd':
        BEGIN
        RESET(Fyle, 'KEYFILE.TXT/RW/APD', , Status);
        IF Status = - 1 THEN REWRITE(Fyle, 'KEYFILE.TXT/RW/APD', , Status);
        ssubstr(Sbuff, Inbuff, 5, 80);
        Index := 1;
        DOPROG;
        IF Success THEN
          BEGIN
          SWRITE(Fyle, Sbuff);
          WRITELN(Fyle);
          END;
        END;
      OTHERWISE
        BEGIN
        Success := FALSE;
        HELP;
        END;
      END; {case}
    CLOSE(Fyle);
  END.
