home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / FILE / XLAT11.ZIP / CONFXLAT.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1990-08-12  |  36.1 KB  |  1,112 lines

  1. Program confxlat;
  2. { Customize a XLAT(R).COM programme                                          }
  3. { FreeWare by TapirSoft Gisbert W.Selke, Oct 1989/Aug 1990                   }
  4.  
  5. {$UNDEF  DEBUG }        { DEFINE while debugging }
  6.  
  7. {$A+,B-,D+,E+,F-,I+,L+,N-,O-,V- }
  8. {$M 16384,0,16384 }
  9. {$IFDEF DEBUG }
  10.   {$R+,S+ }
  11. {$ELSE }
  12.   {$R-,S- }
  13. {$ENDIF }
  14.  
  15.   Uses Dos, Crt;
  16.  
  17.   Const progname  = 'ConfXlat';
  18.         version   = '1.1';
  19.         copyright = 'FreeWare by TapirSoft Gisbert W.Selke, Oct 1989/Aug 1990';
  20.         idstring10= 'XLAT10';
  21.         idstring11= 'XLAT11';
  22.         idlength  = Length(idstring10);
  23.         hexnibble : string[16] = '0123456789ABCDEF';
  24.         digits    : string[10] = '0123456789';
  25.  
  26.   Const fbufsize = 4096;
  27.         width    = 18;
  28.         videoint = $10;
  29.         blockcur = $010C;          { normcur  defined dynamically! }
  30.         nocur    = $2B0C;
  31.         F1       = #59;              F2       = #60;
  32.         F3       = #61;              F4       = #62;
  33.         F5       = #63;              F6       = #64;
  34.         F7       = #65;              F8       = #66;
  35.         F9       = #67;              F10      = #68;
  36.         CtrlC    = #3;               Esc      = #27;
  37.         Return   = #13;
  38.         Home     = #71;              UpAr     = #72;
  39.         PgUp     = #73;              LfAr     = #75;
  40.         RtAr     = #77;              EndK     = #79;
  41.         DnAr     = #80;              PgDn     = #81;
  42.         Ins      = #82;              Del      = #83;
  43.         CHome    = #119;             CEndK    = #117;
  44.  
  45.   Type tabletype = Array [byte] Of byte;
  46.  
  47.   Var fname : string;
  48.       xlat  : File;
  49.       tabf  : text;
  50.       fbuf  : Array [1..fbufsize] Of byte;
  51.       fsize : word;
  52.       descript, intername : string;
  53.       tstart, tabstart, interstart : word;
  54.       desclen : byte;
  55.       xlatid : byte;
  56.       table : tabletype;
  57.       changed, floaded : boolean;
  58.       ch : char;
  59.       maxlin, maxcol : byte;
  60.       row : byte;
  61.       col, leftcol : integer;
  62.       normcur : word;
  63.       exitsave : Pointer;
  64.  
  65.   Function hexbyte(b : byte) : string;
  66.   { convert a byte to a string                                               }
  67.   Begin                                                            { hexbyte }
  68.     hexbyte := hexnibble[Succ(b ShR 4)] + hexnibble[Succ(b And $0F)];
  69.   End;                                                             { hexbtye }
  70.  
  71.   Procedure beep;
  72.   { error noise                                                              }
  73.   Begin                                                               { beep }
  74.     Sound(440);
  75.     Delay(100);
  76.     NoSound;
  77.   End;                                                                { beep }
  78.  
  79.   Procedure putchar(b : byte);
  80.   { show a character on the screen, without interpreting control chars       }
  81.   Inline($B4/$0F/                {Mov ah, $0F       ; get current video mode }
  82.          $CD/$10/                {Int $10           ; in bh                  }
  83.          $58/                    {Pop ax            ; get char in al         }
  84.          $B4/$0A/                {Mov ah, $0A       ; output char            }
  85.          $B3/$70/                {Mov bl, $70       ; white on black         }
  86.          $B9/$01/$00/            {Mov cx, $01       ; just one copy          }
  87.          $CD/$10);               {Int $10                                    }
  88.  
  89.   Procedure setcursor(curtype : word);
  90.   { set cursor start and end line and blink bits                             }
  91.     Var regs : Registers;
  92.   Begin                                                          { setcursor }
  93.     With regs Do
  94.     Begin
  95.       ah := $0F;
  96.       Intr(videoint,regs);
  97.       cx := curtype;
  98.       ah := $01;
  99.       Intr(videoint,regs);
  100.     End;
  101.   End;                                                           { setcursor }
  102.  
  103.   Procedure getcursor;
  104.   { get cursor start and end line and blink bits, put them into normcur      }
  105.     Var regs : Registers;
  106.   Begin                                                          { setcursor }
  107.     With regs Do
  108.     Begin
  109.       ah := $0F;
  110.       Intr(videoint,regs);
  111.       ah := $03;
  112.       Intr(videoint,regs);
  113.       normcur := cx;
  114.     End;
  115.   End;                                                           { setcursor }
  116.  
  117.   Procedure moreprompt;
  118.   { wait for key press at bottom of 'list' window                            }
  119.     Var ch : char;
  120.   Begin                                                         { moreprompt }
  121.     GoToXY(maxcol-25,8);
  122.     write('Hit space bar...');
  123.     ch := ReadKey;
  124.     While KeyPressed Do ch := ReadKey;
  125.     GoToXY(1,8);
  126.     ClrEoL;
  127.   End;                                                          { moreprompt }
  128.  
  129.   Procedure openlistwindow;
  130.   { open a window in central part of screen                                  }
  131.     Var i : byte;
  132.   Begin                                                     { openlistwindow }
  133.     Window(1,11,maxcol,20);
  134.     ClrScr;
  135.     GoToXY(2,1);
  136.     write(#218);
  137.     For i := 3 To 78 Do write(#196);
  138.     write(#191);
  139.     For i := 2 To 9 Do
  140.     Begin
  141.       GoToXY(2,i);
  142.       write(#179);
  143.       GoToXY(79,i);
  144.       write(#179);
  145.     End;
  146.     GoToXY(2,10);
  147.     write(#192);
  148.     For i := 3 To 78 Do write(#196);
  149.     write(#217);
  150.     Window(4,12,maxcol-4,19);
  151.   End;                                                      { openlistwindow }
  152.  
  153.   Procedure errmsg(s : string);
  154.   { display an error message                                                 }
  155.     Var i : byte;
  156.         ch : char;
  157.   Begin                                                             { errmsg }
  158.     SetCursor(nocur);
  159.     Window(1,11,maxcol,13);
  160.     ClrScr;
  161.     GoToXY(1,1);
  162.     write(#218);
  163.     For i := 1 To Length(s)+2 Do write(#196);
  164.     write(#191);
  165.     GoToXY(1,2);
  166.     write(#179,' ',s,' ',#179);
  167.     GoToXY(1,3);
  168.     write(#192);
  169.     For i := 1 To Length(s)+2 Do write(#196);
  170.     write(#217);
  171.     While KeyPressed Do ch := ReadKey;
  172.     ch := ReadKey;
  173.     While KeyPressed Do ch := ReadKey;
  174.     ClrScr;
  175.     Window(1,1,maxcol,maxlin);
  176.     SetCursor(normcur);
  177.   End;                                                              { errmsg }
  178.  
  179.   Function showfiles(mask : string) : boolean;
  180.   { if mask contains wildcards, show all files that match, then return True  }
  181.     Var wild : boolean;
  182.         i, linct, colct : byte;
  183.         sr : SearchRec;
  184.   Begin                                                          { showfiles }
  185.     wild := False;
  186.     For i := 1 To Length(mask) Do wild := wild Or (mask[i] = '?') Or
  187.                                                   (mask[i] = '*');
  188.     showfiles := wild;
  189.     If Not wild Then Exit;
  190.     openlistwindow;
  191.     FindFirst(mask,Archive+ReadOnly+Hidden,sr);
  192.     linct := 0;
  193.     colct := 0;
  194.     wild := False;
  195.     While DosError = 0 Do
  196.     Begin
  197.       wild := True;
  198.       i := Pos('.',sr.name);
  199.       write(' ':(10-i),sr.name,' ':(4-Length(sr.name)+i));
  200.       Inc(colct);
  201.       If colct >= 5 Then
  202.       Begin
  203.         writeln;
  204.         Inc(linct);
  205.         If linct >= 7 Then
  206.         Begin
  207.           moreprompt;
  208.           linct := 0;
  209.         End;
  210.         colct := 0;
  211.       End;
  212.       FindNext(sr);
  213.     End;
  214.     If Not wild Then
  215.     Begin
  216.       writeln('No files matching "',mask,'"');
  217.       linct := 1;
  218.     End;
  219.     If (linct > 0) Or (colct > 0) Then
  220.     Begin
  221.       writeln;
  222.       moreprompt;
  223.     End;
  224.     Window(1,11,maxcol,20);
  225.     ClrScr;
  226.     Window(1,1,maxcol,maxlin);
  227.   End;                                                           { showfiles }
  228.  
  229.   Procedure initdisplay;
  230.   { initialize display                                                       }
  231.     Var i : byte;
  232.   Begin                                                        { initdisplay }
  233.     Window(1,1,maxcol,maxlin);
  234.     ClrScr;
  235.     GoToXY(3,1);
  236.     write('Internal name: ',intername);
  237.     Case xlatid Of
  238.       10 : write('  (filter)');
  239.       11 : write('  (resident)');
  240.       Else ;
  241.     End;
  242.     While (descript <> '') And (descript[Length(descript)] = ' ') Do
  243.                                          Delete(descript,Length(descript),1);
  244.     GoToXY(79 - Length(descript),1);
  245.     write(descript);
  246.     GoToXY(1,2);
  247.     write(#214);
  248.     For i := 2 To 79 Do write(#196);
  249.     write(#183);
  250.     For i := 1 To 3 Do
  251.     Begin
  252.       GoToXY( 1,i+2); write(#186);
  253.       GoToXY(80,i+2); write(#186);
  254.       GoToXY( 1,i+6); write(#186);
  255.       GoToXY(80,i+6); write(#186);
  256.     End;
  257.     GoToXY(2,4);
  258.     write('From:');
  259.     GoToXY(2,8);
  260.     write('To:');
  261.     GoToXY(1,6);
  262.     write(#199);
  263.     For i := 2 To 79 Do write(#196);
  264.     write(#182);
  265.     GoToXY(1,10);
  266.     write(#211);
  267.     For i := 2 To 79 Do write(#196);
  268.     write(#189);
  269.     GoToXY(1,21);
  270.     write(#201);
  271.     For i := 2 To 79 Do write(#205);
  272.     write(#187);
  273.     GoToXY(1,22);
  274.     write(#186,' F1 clear to 0    F3 quit      F5 load com   ',
  275.           'F7 load table   F9  check invert ',#186);
  276.     GoToXY(1,23);
  277.     write(#186,' F2 clear to id                F6 save com   ',
  278.           'F8 save table   F10 invert table ',#186);
  279.     GoToXY(1,24);
  280.     write(#200);
  281.     For i := 2 To 79 Do write(#205);
  282.     write(#188);
  283.     GoToXY(40-(Length(progname)+Length(version)+Length(copyright)+7) Div 2,25);
  284.     write(progname,' ',version,'  --  ',copyright);
  285.     leftcol := 1;
  286.     col := 3;
  287.     row := 1;
  288.   End;                                                         { initdisplay }
  289.  
  290.   Procedure showone(b, col : byte; upper : boolean);
  291.   { show one byte in its three incarnations; upper or lower row              }
  292.     Var row : byte;
  293.         incr : shortint;
  294.   Begin                                                            { showone }
  295.     col := col + 8;
  296.     If upper Then
  297.     Begin
  298.       row := 3;
  299.       incr := 1;
  300.     End
  301.     Else
  302.     Begin
  303.       row := 9;
  304.       incr := -1;
  305.     End;
  306.     GoToXY(col,row);
  307.     write(b:3);
  308.     GoToXY(col,row+incr);
  309.     write('x',hexbyte(b):2);
  310.     GoToXY(col+2,row+incr+incr);
  311.     putchar(b);
  312.   End;                                                             { showone }
  313.  
  314.   Procedure adjustdisplay;
  315.   { show proper segment of table                                             }
  316.     Var i, k, start, ende : byte;
  317.   Begin                                                      { adjustdisplay }
  318.     setcursor(nocur);
  319.     If col < leftcol Then leftcol := Succ(4*(col Div 4));
  320.     If col > leftcol+4*width Then leftcol := Succ(4*(((col+3) Div 4) - width));
  321.     start := Pred(leftcol) Div 4;
  322.     ende  := start + width - 1;
  323.     GoToXY(8,3);
  324.     k := 4*integer(start)-leftcol+1;
  325.     For i := start To ende Do
  326.     Begin
  327.       showone(i,k,True);
  328.       showone(table[i],k,False);
  329.       k := k + 4;
  330.     End;
  331.     setcursor(normcur);
  332.   End;                                                       { adjustdisplay }
  333.  
  334.   Function dialog(prompt : string; len : byte; proto : string) : string;
  335.   { show prompt, read answer, with default answer                            }
  336.     Var s : string;
  337.         ch : char;
  338.         i, k, w : byte;
  339.         insmode : boolean;
  340.   Begin                                                             { dialog }
  341.     If Length(prompt) + len > 74 Then len := 74 - Length(prompt);
  342.     proto := Copy(proto,1,len);
  343.     s := proto;
  344.     While Length(s) < len Do s := s + ' ';
  345.     w := Length(prompt) + len + 5;
  346.     Window(1,14,maxcol,16);
  347.     ClrScr;
  348.     GoToXY(1,1);
  349.     write(#218);
  350.     For i := 2 To Pred(w) Do write(#196);
  351.     write(#191);
  352.     GoToXY(1,2);
  353.     write(#179,' ',prompt,' ',s);
  354.     GoToXY(w,2);
  355.     write(#179);
  356.     GoToXY(1,3);
  357.     write(#192);
  358.     For i := 2 To Pred(w) Do write(#196);
  359.     write(#217);
  360.     w := Length(prompt) + 3;
  361.     i := 1;
  362.     insmode := False;
  363.     SetCursor(normcur);
  364.     Repeat
  365.       GoToXY(w+i,2);
  366.       ch := ReadKey;
  367.       Case ch Of
  368.         ' '..#254 : Begin { ordinary char }
  369.                If insmode Then
  370.                Begin
  371.                  For k := Pred(len) DownTo i Do s[Succ(k)] := s[k];
  372.                  s[i] := ch;
  373.                  For k := i To len Do write(s[k]);
  374.                  Inc(i);
  375.                End
  376.                Else
  377.                Begin
  378.                  s[i] := ch;
  379.                  write(ch);
  380.                  Inc(i);
  381.                End;
  382.              End;
  383.         #8 : Begin { backspace }
  384.                If i > 1 Then
  385.                Begin
  386.                  GoToXY(w+Pred(i),2);
  387.                  For k := i To len Do
  388.                  Begin
  389.                    s[Pred(k)] := s[k];
  390.                    write(s[k]);
  391.                  End;
  392.                  s[len] := ' ';
  393.                  write(' ');
  394.                  Dec(i);
  395.                End;
  396.              End;
  397.         #0 : Begin { extended key }
  398.                ch := ReadKey;
  399.                Case ch Of
  400.                  LfAr : If i > 1 Then Dec(i);   { leftarrow }
  401.                  RtAr : If i < len Then Inc(i); { rightarrow }
  402.                  Home : i := 1;                 { home }
  403.                  EndK : Begin                   { end }
  404.                           i := len;
  405.                           While (i > 1) And (s[Pred(i)] = ' ') Do Dec(i);
  406.                         End;
  407.                  Ins  : Begin                   { insert }
  408.                           insmode := Not insmode;
  409.                           If insmode Then SetCursor(blockcur)
  410.                                      Else SetCursor(normcur);
  411.                         End;
  412.                  Del  : Begin                   { delete }
  413.                           For k := i To Pred(len) Do
  414.                           Begin
  415.                             s[k] := s[Succ(k)];
  416.                             write(s[k]);
  417.                           End;
  418.                           s[len] := ' ';
  419.                           write(' ');
  420.                         End;
  421.                  CHome: Begin                   { Control-Home }
  422.                           GoToXY(w+1,2);
  423.                           For k := Succ(i) To len Do
  424.                           Begin
  425.                             s[k-i] := s[k];
  426.                             write(s[k]);
  427.                           End;
  428.                           For k := len-i+1 To len Do
  429.                           Begin
  430.                             s[k] := ' ';
  431.                             write(' ');
  432.                           End;
  433.                           i := 1;
  434.                         End;
  435.                  CEndK: Begin                   { Control-End }
  436.                           For k := i To len Do
  437.                           Begin
  438.                             s[k] := ' ';
  439.                             write(s[k]);
  440.                           End;
  441.                         End;
  442.                  F3   : ch := Esc;              { general QUIT key }
  443.                  Else   ch := #0;
  444.                End;
  445.              End;
  446.         Else ;
  447.       End;
  448.     Until (i >= len) Or (ch In [CtrlC,Esc,Return]);
  449.     If ch In [CtrlC,Esc] Then s := '';
  450.     While (s <> '') And (s[Length(s)] = ' ') Do Delete(s,Length(s),1);
  451.     dialog := s;
  452.     ClrScr;
  453.     Window(1,1,maxcol,maxlin);
  454.     SetCursor(normcur);
  455.   End;                                                              { dialog }
  456.  
  457.   Procedure edittable;
  458.   { edit a translation table                                                 }
  459.  
  460.     Var cn, dig : byte;
  461.         d : Array [1..3] Of byte;
  462.         ok : boolean;
  463.  
  464.   Begin                                                          { edittable }
  465.     If leftcol >= 1024 Then initdisplay;
  466.     adjustdisplay;
  467.     Repeat
  468.       Case row Of
  469.         1 : While col Mod 4 < 3 Do Inc(col);
  470.         2 : If col Mod 4 = 1 Then Inc(col);
  471.         3 : ;
  472.       End;
  473.       If (col < leftcol) Or (col > leftcol+4*width) Then adjustdisplay;
  474.       GoToXY(col-leftcol+8,row+6);
  475.       ch := ReadKey;
  476.       ok := True;
  477.       If ch <> #0 Then
  478.       Begin
  479.         cn := col Div 4;
  480.         Case row Of
  481.           1 : table[cn] := Ord(ch);
  482.           2 : Begin
  483.                 ch := UpCase(ch);
  484.                 dig := Pos(ch,hexnibble);
  485.                 If dig > 0 Then
  486.                 Begin
  487.                   d[2] := Ord(table[cn]) ShR 4;
  488.                   d[3] := Ord(table[cn]) And $0F;
  489.                   d[col Mod 4] := Pred(dig);
  490.                   table[cn] := (d[2] ShL 4) Or d[3];
  491.                 End
  492.                 Else ok := False;
  493.               End;
  494.           3 : Begin
  495.                 ch := UpCase(ch);
  496.                 If ch In ['0'..'9'] Then
  497.                 Begin
  498.                   dig := Ord(ch) - 48;
  499.                   d[1] := Ord(table[cn]) Div 100;
  500.                   d[2] := (Ord(table[cn]) Div 10) Mod 10;
  501.                   d[3] := table[cn] Mod 10;
  502.                   d[col Mod 4] := dig;
  503.                   table[cn] := (d[1]*10+d[2])*10+d[3];
  504.                 End
  505.                 Else ok := False;
  506.               End;
  507.         End;
  508.         If ok Then
  509.         Begin
  510.           changed := True;
  511.           showone(table[cn],4*((col-leftcol) Div 4),False);
  512.           ch := RtAr;
  513.         End
  514.         Else
  515.         Begin
  516.           beep;
  517.           ch := #0;
  518.         End;
  519.       End
  520.         Else ch := ReadKey;
  521.       Case ch Of
  522.         #0, F1..F10 : ;
  523.         Home : col := 0;
  524.         UpAr : If row > 1 Then Dec(row);
  525.         PgUp : If col >= 4*width Then col := col - 4*width Else col := 0;
  526.         LfAr : Begin
  527.                  Case row Of
  528.                    1 : Dec(col,4);
  529.                    2 : If col Mod 4 = 2 Then Dec(col,3) Else Dec(col);
  530.                    3 : If col Mod 4 = 1 Then Dec(col,2) Else Dec(col);
  531.                  End;
  532.                  If col < 1 Then col := 1;
  533.                End;
  534.         RtAr : Begin
  535.                  Case row Of
  536.                    1 : Inc(col,4);
  537.                    2 : If col Mod 4 = 3 Then Inc(col,3) Else Inc(col);
  538.                    3 : If col Mod 4 = 3 Then Inc(col,2) Else Inc(col);
  539.                  End;
  540.                  If col > 1023 Then col := 1023;
  541.                End;
  542.         EndK : col := 1023;
  543.         DnAr : If row < 3 Then Inc(row);
  544.         PgDn : If col+4*width <= 1023 Then col := col + 4*width
  545.                                       Else col := 1023;
  546.         Else   beep;
  547.       End;
  548.     Until ch In [F1..F10];
  549.   End;                                                           { edittable }
  550.  
  551.   Procedure checkinvert;
  552.   { check table for invertibility                                            }
  553.  
  554.     Var i, k, found, firstval, outct : byte;
  555.         noprob1, noprob2 : boolean;
  556.         nofound : Array [0..255] Of boolean;
  557.  
  558.   Begin                                                        { checkinvert }
  559.     openlistwindow;
  560.     noprob1 := True;
  561.     noprob2 := True;
  562.     outct := 0;
  563.     For i := 0 To 255 Do
  564.     Begin
  565.       nofound[i] := True;
  566.       found := 0;
  567.       For k := 0 To 255 Do
  568.       Begin
  569.         If table[k] = i Then
  570.         Begin
  571.           nofound[i] := False;
  572.           If found = 0 Then firstval := k
  573.           Else
  574.           Begin
  575.             If found = 1 Then write('Multi image: x',hexbyte(i),': x',
  576.                                     hexbyte(firstval));
  577.             If WhereX > 66 Then
  578.             Begin
  579.               writeln;
  580.               Inc(outct);
  581.               If outct >= 7 Then
  582.               Begin
  583.                 moreprompt;
  584.                 outct := 0;
  585.               End;
  586.               write(' ':17);
  587.             End;
  588.             write(' x',hexbyte(k));
  589.           End;
  590.           Inc(found);
  591.         End;
  592.       End;
  593.       If found > 1 Then
  594.       Begin
  595.         noprob1 := False;
  596.         writeln;
  597.         Inc(outct);
  598.         If outct >= 7 Then
  599.         Begin
  600.           moreprompt;
  601.           outct := 0;
  602.         End;
  603.       End;
  604.     End;
  605.     writeln;
  606.     Inc(outct);
  607.     If outct >= 7 Then
  608.     Begin
  609.       moreprompt;
  610.       outct := 0;
  611.     End;
  612.     write('No images: ');
  613.     For i := 0 To 255 Do
  614.     Begin
  615.       If nofound[i] Then
  616.       Begin
  617.         noprob2 := False;
  618.         If WhereX > 66 Then
  619.         Begin
  620.           writeln;
  621.           Inc(outct);
  622.           If outct >= 7 Then
  623.           Begin
  624.             moreprompt;
  625.             outct := 0;
  626.           End;
  627.           write(' ':11);
  628.         End;
  629.         write(' x',hexbyte(i));
  630.       End;
  631.     End;
  632.     If noprob2 Then writeln('none')
  633.                Else writeln;
  634.     If noprob1 And noprob2 Then writeln('Table is invertible.');
  635.     moreprompt;
  636.     Window(1,11,maxcol,20);
  637.     ClrScr;
  638.     Window(1,1,maxcol,maxlin);
  639.   End;                                                         { checkinvert }
  640.  
  641.   Procedure invert;
  642.   { invert a translation table                                               }
  643.     Var temp : tabletype;
  644.         i : byte;
  645.   Begin                                                             { invert }
  646.     For i :=   0     To   255 Do temp[i] := 0;
  647.     For i := 255 DownTo     0 Do temp[table[i]] := i;
  648.     table := temp;
  649.     changed := True;
  650.   End;                                                              { invert }
  651.  
  652.   Procedure checksave; Forward;
  653.  
  654.   Procedure cleartable(tonull : boolean);
  655.   { clear table to 0 or to id                                                }
  656.     Var i : byte;
  657.   Begin                                                         { cleartable }
  658.     checksave;
  659.     If tonull Then
  660.     Begin
  661.       For i := 0 To 255 Do table[i] := 0;
  662.       fname := 'NULL';
  663.       descript := 'Maps all to 0';
  664.     End
  665.     Else
  666.     Begin
  667.       For i := 0 To 255 Do table[i] := i;
  668.       fname := 'IDENT';
  669.       descript := 'Identity mapping';
  670.     End;
  671.     intername := fname;
  672.     leftcol := 9999;
  673.   End;                                                          { cleartable }
  674.  
  675.   Procedure loadcom;
  676.   { load a translation table from a COM file                                 }
  677.  
  678.     Const proginfoptr = 4;
  679.  
  680.     Var i, xinterstart : word;
  681.         temp, fname1 : string;
  682.         dodialog : boolean;
  683.  
  684.   Begin                                                            { loadcom }
  685.     checksave;
  686.     dodialog := floaded;
  687.     Repeat
  688.       fname1 := fname;
  689.       If dodialog Or (fname1 = '') Then
  690.                              fname1 := dialog('Name of COM file:',80,fname1);
  691.       If fname  = '' Then fname := fname1;
  692.       If fname1 = '' Then
  693.       Begin
  694.         errmsg('Load COM operation cancelled');
  695.         Exit;
  696.       End;
  697.       If Pos('.',fname1) = 0 Then fname1 := fname1 + '.COM';
  698.       dodialog := True;
  699.     Until Not showfiles(fname1);
  700.     i := FileMode;
  701.     FileMode := 0;
  702.     Assign(xlat,fname1);
  703.     {$I- }
  704.     Reset(xlat,1);
  705.     FileMode := i;
  706.     If IOResult <> 0 Then
  707.     Begin
  708.       errmsg('File ' + fname1 + ' not found');
  709.       Exit;
  710.     End;
  711.     BlockRead(xlat,fbuf,fbufsize,fsize);
  712.     Close(xlat);
  713.     {$I+ }
  714.     If IOResult <> 0 Then
  715.     Begin
  716.       errmsg('Error reading file ' + fname1);
  717.       Exit;
  718.     End;
  719.     i := fbuf[proginfoptr] + 1;
  720.     temp[0] := Chr(idlength);
  721.     Move(fbuf[i],temp[1],idlength);
  722.     xlatid := 0;
  723.     If temp = idstring10 Then xlatid := 10;
  724.     If temp = idstring11 Then xlatid := 11;
  725.     If xlatid = 0 Then
  726.     Begin
  727.       errmsg('Unknown programme version ' + temp);
  728.       Exit;
  729.     End;
  730.     Move(fbuf[i+8],xinterstart,2);
  731.     If xinterstart >= fsize Then
  732.     Begin
  733.       errmsg('File ' + fname1 + ' has invalid format');
  734.       Exit;
  735.     End;
  736.     interstart := Succ(xinterstart);
  737.     tstart := Succ(fbuf[i+6]);
  738.     desclen := fbuf[i+7];
  739.     Move(fbuf[i+10],tabstart,2);
  740.     Inc(tabstart);
  741.     Move(fbuf[tstart],descript[1],desclen);
  742.     descript[0] := Chr(desclen);
  743.     Move(fbuf[tabstart],table,256);
  744.     Move(fbuf[interstart],intername[1],8);
  745.     intername[0] := #8;
  746.     col := 1;
  747.     row := 3;
  748.     leftcol := 9999;
  749.     changed := False;
  750.     floaded := True;
  751.     fname := fname1;
  752.   End;                                                             { loadcom }
  753.  
  754.   Procedure savecom;
  755.   { save a translation table as a COM file                                   }
  756.     Const cancelcomsave = 'Save COM operation cancelled';
  757.     Var c : char;
  758.         s : string;
  759.         iwrite : word;
  760.   Begin                                                            { savecom }
  761.     {$I- }
  762.     s := dialog('Enter short description:',desclen,descript);
  763.     If s = '' Then
  764.     Begin
  765.       errmsg(cancelcomsave);
  766.       Exit;
  767.     End;
  768.     descript := s;
  769.     While Length(descript) < desclen Do descript := descript + ' ';
  770.     s := dialog('Enter name of com file:',60,fname);
  771.     If s = '' Then
  772.     Begin
  773.       errmsg(cancelcomsave);
  774.       Exit;
  775.     End;
  776.     fname := s;
  777.     If Pos('.',fname) = 0 Then fname := fname + '.COM';
  778.     intername := fname;
  779.     While (intername <> '') And (Pos(':',intername) > 0) Do
  780.                                   Delete(intername,1,Pos(':',intername));
  781.     While (intername <> '') And (Pos('\',intername) > 0) Do
  782.                                   Delete(intername,1,Pos('\',intername));
  783.     While (intername <> '') And (Pos('.',intername) > 0) Do
  784.                                   Delete(intername,Pos('.',intername),255);
  785.     While Length(intername) < 8 Do intername := intername + ' ';
  786.     Assign(xlat,fname);
  787.     Reset(xlat,1);
  788.     If IOResult = 0 Then
  789.     Begin
  790.       Close(xlat);
  791.       Repeat
  792.         s := dialog('File '+fname+' already exists. Continue? (y/n)',1,'N');
  793.         If s = '' Then c := Esc Else c := UpCase(s[1]);
  794.       Until c In ['Y','J','1','N','0',CtrlC,Esc];
  795.       If c In ['N','0',CtrlC,Esc] Then
  796.       Begin
  797.         errmsg(cancelcomsave);
  798.         Exit;
  799.       End;
  800.     End;
  801.     Rewrite(xlat,1);
  802.     If IOResult <> 0 Then
  803.     Begin
  804.       errmsg('Cannot open '+fname+' for output.');
  805.       Exit;
  806.     End;
  807.     Move(descript[1],fbuf[tstart],desclen);
  808.     Move(table,fbuf[tabstart],256);
  809.     Move(intername[1],fbuf[interstart],8);
  810.     BlockWrite(xlat,fbuf,fsize,iwrite);
  811.     If iwrite <> fsize Then errmsg('Error writing file '+fname);
  812.     Close(xlat);
  813.     fname := '';
  814.     changed := False;
  815.     leftcol := 9999;
  816.     {$I+ }
  817.   End;                                                             { savecom }
  818.  
  819.   Procedure loadtable;
  820.   { load a translation table from an ASCII table file                        }
  821.  
  822.     Var i : byte;
  823.         tab1 : tabletype;
  824.         descript1, lin, cmd, froms, tos, tname : string;
  825.         fromval, toval : byte;
  826.         ok : boolean;
  827.  
  828.     Function gettok(s : string; Var ptr : byte) : string;
  829.     { returns next token from s, or ''                                       }
  830.       Var beg : byte;
  831.     Begin                                                           { gettok }
  832.       While (ptr <= Length(s)) And ((s[ptr] = ' ') Or (s[ptr] = #9)) Do
  833.                                                                      Inc(ptr);
  834.       beg := ptr;
  835.       While (ptr <= Length(s)) And (s[ptr] <> ' ') And (s[ptr] <> #9) Do
  836.       Begin
  837.         s[ptr] := UpCase(s[ptr]);
  838.         Inc(ptr);
  839.       End;
  840.       gettok := Copy(s,beg,ptr-beg);
  841.     End;                                                            { gettok }
  842.  
  843.     Function decoval(s : string; Var ok : boolean) : byte;
  844.     { decodes a decimal or hexadecimal (prefixed by 'x') value               }
  845.       Var i1, i2, num : byte;
  846.     Begin                                                          { decoval }
  847.       num := 0;
  848.       ok := False;
  849.       If s <> '' Then
  850.       Begin
  851.         If (s[1] = 'X') And (Length(s) >= 1) And (Length(s) <= 3) Then
  852.         Begin
  853.           If Length(s) = 2 Then
  854.           Begin
  855.             s[1] := '0';
  856.             i2 := 1;
  857.           End
  858.             Else i2 := 2;
  859.           i1 := Pos(s[i2],hexnibble);
  860.           i2 := Pos(s[Succ(i2)],hexnibble);
  861.           ok := (i1 > 0) And (i2 > 0);
  862.           If ok Then num := Pred(i1) ShL 4 + Pred(i2);
  863.         End
  864.         Else
  865.         Begin
  866.           For i2 := 1 To Length(s) Do
  867.           Begin
  868.             i1 := Pos(s[i2],digits);
  869.             ok := ok And (i1 > 0);
  870.             If ok Then
  871.             Begin
  872.               If 10*word(num)+ i1 <= 256 Then num := 10*num + Pred(i1);
  873.             End;
  874.           End;
  875.         End;
  876.       End;
  877.       decoval := num;
  878.     End;                                                           { decoval }
  879.  
  880.   Begin                                                          { loadtable }
  881.     checksave;
  882.     Repeat
  883.       tname := dialog('Enter name of table file:',60,
  884.                       Copy(fname,1,Pred(Pos('.',fname))));
  885.       If tname = '' Then
  886.       Begin
  887.         errmsg('Load TABLE operation cancelled');
  888.         Exit;
  889.       End;
  890.       If Pos('.',tname) = 0 Then tname := tname + '.TBL';
  891.       If (tname <> '') And (Pos('.',tname) = 0) Then tname := tname + '.TBL';
  892.     Until Not showfiles(tname);
  893.     i := FileMode;
  894.     FileMode := 0;
  895.     Assign(tabf,tname);
  896.     {$I- }
  897.     Reset(tabf);
  898.     FileMode := i;
  899.     If IOResult <> 0 Then
  900.     Begin
  901.       errmsg('File ' + tname + ' not found');
  902.       Exit;
  903.     End;
  904.     descript1 := '';
  905.     For i := 0 To 255 Do tab1[i] := i;
  906.     While Not EoF(tabf) Do
  907.     Begin
  908.       readln(tabf,lin);
  909.       If Pos(';',lin) > 0 Then Delete(lin,Pos(';',lin),255);
  910.       While (lin <> '') And ((lin[1] = ' ') Or (lin[1] = #9)) Do
  911.                                                            Delete(lin,1,1);
  912.       i := 1;
  913.       cmd := gettok(lin,i);
  914.       If cmd = '' Then cmd := ' ';
  915.       If Length(cmd) > 1 Then cmd := '?';
  916.       Case UpCase(cmd[1]) Of
  917.         'V' : Begin { version string }
  918.                 If (gettok(lin,i) <> idstring10) And
  919.                    (gettok(lin,i) <> idstring11) Then
  920.                 Begin
  921.                   errmsg('Version must be ' + idstring10 + ' or ' + idstring11);
  922.                   Close(tabf);
  923.                   Exit;
  924.                 End;
  925.               End;
  926.         'D' : Begin { description }
  927.                 If descript1 <> '' Then
  928.                   errmsg('Warning: multiple descriptions not supported');
  929.                 descript1 := Copy(lin,i,255);
  930.                 While (descript1 <> '') And ((descript1[1] = ' ') Or
  931.                        (descript1[1] = #9)) Do Delete(descript1,1,1);
  932.                 While (descript1 <> '') And
  933.                       ((descript1[Length(descript1)] = ' ')
  934.                         Or (descript1[Length(descript1)] = #9))
  935.                       Do Delete(descript1,Length(descript1),1);
  936.                 If Length(descript1) > desclen Then
  937.                   Delete(descript1,Succ(desclen),255);
  938.               End;
  939.         'T' : Begin { translation pair }
  940.                 froms := gettok(lin,i);
  941.                 tos   := gettok(lin,i);
  942.                 ok := (Length(froms) >= 1) And (Length(froms) <= 3) And
  943.                       (Length(tos) >= 1)   And (Length(tos) <= 3);
  944.                 If ok Then
  945.                 Begin
  946.                   fromval := decoval(froms,ok);
  947.                   If ok Then toval := decoval(tos,ok);
  948.                   If ok then tab1[fromval] := toval;
  949.                 End;
  950.                 If Not ok Then errmsg('Illegal translation directive ' +
  951.                                       Copy(lin,1,20));
  952.               End;
  953.         ' ' : ; { ignore empty lines }
  954.         Else errmsg('Illegal directive ' + Copy(lin,1,20));
  955.       End;
  956.     End;
  957.     Close(tabf);
  958.     fname := Copy(tname,1,Pred(Pos('.',tname)));
  959.     intername := fname;
  960.     descript := descript1;
  961.     table := tab1;
  962.     col := 1;
  963.     row := 3;
  964.     leftcol := 9999;
  965.     changed := False;
  966.   End;                                                           { loadtable }
  967.  
  968.   Procedure savetable;
  969.   { save a translation table to an ASCII table file                          }
  970.     Const canceltablesave = 'Save TABLE operation cancelled';
  971.     Var i : byte;
  972.         c : char;
  973.         s, tname : string;
  974.   Begin                                                          { savetable }
  975.     {$I- }
  976.     s := dialog('Enter short description:',desclen,descript);
  977.     If s = '' Then
  978.     Begin
  979.       errmsg(canceltablesave);
  980.       Exit;
  981.     End;
  982.     descript := s;
  983.     While Length(descript) < desclen Do descript := descript + ' ';
  984.     s := dialog('Enter name of table file:',60,
  985.                     Copy(fname,1,Pred(Pos('.',fname))));
  986.     If s = '' Then
  987.     Begin
  988.       errmsg(canceltablesave);
  989.       Exit;
  990.     End;
  991.     tname := s;
  992.     If Pos('.',tname) = 0 Then tname := tname + '.TBL';
  993.     intername := tname;
  994.     While (intername <> '') And (Pos(':',intername) > 0) Do
  995.                                   Delete(intername,1,Pos(':',intername));
  996.     While (intername <> '') And (Pos('\',intername) > 0) Do
  997.                                   Delete(intername,1,Pos('\',intername));
  998.     While (intername <> '') And (Pos('.',intername) > 0) Do
  999.                                   Delete(intername,Pos('.',intername),255);
  1000.     While Length(intername) < 8 Do intername := intername + ' ';
  1001.     Assign(tabf,tname);
  1002.     Reset(tabf);
  1003.     If IOResult = 0 Then
  1004.     Begin
  1005.       Close(tabf);
  1006.       Repeat
  1007.         s := dialog('File '+tname+' already exists. Continue? (y/n)',1,'N');
  1008.         If s = '' Then c := Esc Else c := UpCase(s[1]);
  1009.       Until c In ['Y','J','1','N','0',CtrlC,Esc];
  1010.       If c In ['N','0',CtrlC,Esc] Then
  1011.       Begin
  1012.         errmsg(canceltablesave);
  1013.         Exit;
  1014.       End;
  1015.     End;
  1016.     Rewrite(tabf);
  1017.     If IOResult <> 0 Then
  1018.     Begin
  1019.       errmsg('Cannot open '+tname+' for output.');
  1020.       Exit;
  1021.     End;
  1022.     writeln(tabf,'; Translation table for use with ConfXLat');
  1023.     writeln(tabf,'; Everything after a '';'' is a comment.');
  1024.     writeln(tabf,'; Values are decimal by default, and hexadecimal if ',
  1025.                  'preceded by ''x''.');
  1026.     writeln(tabf,'V ',idstring10,' ':20,'; version');
  1027.     writeln(tabf,'D ',descript,'   ; description (max length: ',desclen,
  1028.                  ')');
  1029.     writeln(tabf,'; Translation table follows.');
  1030.     writeln(tabf,'; Start each row with a ''T''; first value is mapped to ',
  1031.                  'second value.');
  1032.     writeln(tabf,'; Missing values will be mapped to themselves.');
  1033.     For i := 0 To 255 Do writeln(tabf,'T  x',hexbyte(i):2,
  1034.                                       ' x',hexbyte(table[i]):2);
  1035.     writeln(tabf,'; End of translation table');
  1036.     If IOResult <> 0 Then errmsg('Error writing file '+tname);
  1037.     Close(tabf);
  1038.     fname := intername;
  1039.     changed := False;
  1040.     leftcol := 9999;
  1041.     {$I+ }
  1042.   End;                                                           { savetable }
  1043.  
  1044.   Procedure checksave;
  1045.   { check if we should save the changed table                                }
  1046.     Var ch : char;
  1047.         s : string;
  1048.   Begin                                                          { checksave }
  1049.     If changed Then
  1050.     Begin
  1051.       Repeat
  1052.         s := Dialog('Table has been changed. Save to COM or table file? (C/T/N)'
  1053.                     ,1,' ');
  1054.         If s = '' Then ch := Esc Else ch := UpCase(s[1]);
  1055.       Until ch In ['C', 'T', 'N',CtrlC,Esc];
  1056.       If ch = 'C' Then savecom;
  1057.       If ch = 'T' Then savetable;
  1058.     End;
  1059.   End;                                                           { checksave }
  1060.  
  1061.   {$F+ } Procedure myexit; {$F- }
  1062.   { exit procedure - clear screen etc.                                       }
  1063.   Begin                                                             { myexit }
  1064.     ExitProc := exitsave;
  1065.     SetCursor(normcur);
  1066.     Window(1,1,maxcol,maxlin);
  1067.     ClrScr;
  1068.     writeln(progname,' ',version,' - translation filter/driver configurator');
  1069.     writeln;
  1070.     writeln(copyright);
  1071.     writeln;
  1072.     writeln('This programme, and the filters, resident drivers, and tables,');
  1073.     writeln('may be used and copied freely.');
  1074.     writeln('However, it comes without any guarantees;');
  1075.     writeln('the whole risk of its use lies with the user.');
  1076.     writeln;
  1077.   End;                                                              { myexit }
  1078.  
  1079. Begin                                                                 { main }
  1080.   exitsave := ExitProc;
  1081.   ExitProc := @myexit;
  1082.   maxcol := Succ(Lo(WindMax));
  1083.   maxlin := Succ(Hi(WindMax));
  1084.   getcursor;
  1085.   ClrScr;
  1086.   If ParamCount = 0 Then fname := ''
  1087.                     Else fname := ParamStr(1);
  1088.   floaded := False;
  1089.   changed := False;
  1090.   Repeat
  1091.     loadcom;
  1092.     If fname = '' Then Halt(1);
  1093.     If Not floaded Then fname := '';
  1094.   Until floaded;
  1095.   Repeat
  1096.     edittable;
  1097.     Case ch Of
  1098.       F1 : cleartable(True);
  1099.       F2 : cleartable(False);
  1100.       F3 : ;
  1101.       F5 : loadcom;
  1102.       F6 : savecom;
  1103.       F7 : loadtable;
  1104.       F8 : savetable;
  1105.       F9 : checkinvert;
  1106.       F10: invert;
  1107.       Else beep;
  1108.     End;
  1109.   Until ch = F3;
  1110.   checksave;
  1111. End.
  1112.