home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / filutl / decuf13.ark / DECUF.IF2 < prev    next >
Text File  |  1989-09-27  |  11KB  |  310 lines

  1.  
  2. {* ----------------------------------------------------------------- *
  3.  *                                                                   *
  4.  *      S T A T E   P R O C E S S O R    P R O C E D U R E S         *
  5.  *                                                                   *
  6.  * ----------------------------------------------------------------- *}
  7.  
  8. procedure ProcesBegin ;
  9. {*
  10.  * ProcesBegin - Extract the result file name from the 'begin'
  11.  *               statement and open a file with that name.
  12.  *}
  13. const
  14.    PathDelimiter : array[0..2] of char = ':\/' ;
  15. var
  16.    KeyWord  : KeyWordString ;  { Keyword from line }
  17.    Mode     : KeyWordString ;  { Octal encoded permission flags }
  18.    FileName : KeyWordString ;  { Original file name }
  19.    I        :       Integer ;  { Loop control variable }
  20. begin
  21.    LineIndex:= 1 ;  { Preset index for interpretation of header }
  22.    Keyword:= NextWord ;
  23.    if KeyWord='begin' then
  24.     begin
  25.      Mode    := NextWord ;
  26.      FileName:= NextWord ;
  27.      if FileName<>'' then
  28.       begin
  29. {*
  30.  * Remove any path indication from the file name.  CP/M paths, MS-DOS
  31.  * paths as well as UNIX paths are removed from the supplied name.
  32.  *}
  33.        for I:= 0 to 2 do
  34.          while Pos( PathDelimiter[I], FileName ) <> 0 do
  35.            FileName:= Copy( Filename,
  36.                             Succ(Pos(PathDelimiter[I],FileName)), 255 ) ;
  37. {*
  38.  * Open the output file and swap to the Reading_Data state.  WARNING: The
  39.  * procedure OpenOutputFile might change the processing state as well, in
  40.  * case of an error. Thus the order of the 4 statements below is crucial!
  41.  *}
  42.        OutputFileName := OutputFilePath + FileName ;
  43.        ProcessingState:= Reading_Data ;
  44.        OpenOutputFile ;
  45.        if ProcessingState=Reading_Data then
  46.          WriteLn( 'Decoding to file ', OutputFileName ) ;
  47.       end
  48.      else  { there is no filename on begin statement }
  49.        Panic( Fatal, 'File name missing in begin statement' ) ;
  50.     end
  51.    else  { the line is not a begin statement }
  52.      Panic( Fatal, 'Expecting a begin statement' ) ;
  53. end ;  { of ProcesBegin }
  54.  
  55. procedure CheckForStart ;
  56. {*
  57.  * CheckForStart - Check the line read for the keywords TABLE or BEGIN,
  58.  *                 which indicate the start of the encoded file.
  59.  *}
  60. var
  61.    KeyWord : KeyWordString ;  { Keyword from line }
  62. begin
  63.    if ErrorsInLine=[] then
  64.      if Length(NextLine)>=5 then
  65.       begin
  66.        KeyWord:= Copy( NextLine, 1, 5 ) ;
  67.        if Keyword='table' then
  68.          ProcessingState:= Reading_Table
  69.        else
  70.          if KeyWord='begin' then
  71.            ProcesBegin ;
  72.       end ;  { of if/if }
  73. end ;  { of CheckForStart }
  74.  
  75. procedure ReadConversionTable ;
  76. {*
  77.  * ReadConversionTable - Read the conversion table from the input file
  78.  *                       and save it in the DecodeTable.
  79.  *}
  80. var
  81.    EntryCount : Integer ;  { Number of entries in conversion table }
  82.    I0         :    Char ;  { Loop control variable }
  83.    I1         : Integer ;  { Loop control variable }
  84. begin
  85.    for I0:=' ' to Chr(255) do   { Preset conversion table .. }
  86.      DecodeTable[I0]:= $FF ;    { with invalid entriers }
  87.  
  88.    if (ErrorsInLine<>[]) or (Length(NextLine)<>32) then
  89.     begin
  90.      Panic( Fatal, 'Illegal conversion table' ) ;
  91.      Exit ;
  92.     end ;  { of if }
  93.    for I1:= 1 to 32 do
  94.      DecodeTable[NextLine[I1]]:= Pred(I1) ;
  95.  
  96.    ReadNextLine ;
  97.    if (ErrorsInLine<>[]) or (Length(NextLine)<>32) then
  98.     begin
  99.      Panic( Fatal, 'Illegal conversion table' ) ;
  100.      Exit ;
  101.     end ;  { of if }
  102.    for I1:= 1 to 32 do
  103.      DecodeTable[NextLine[I1]]:= Pred(I1) + 32 ;
  104.  
  105.    EntryCount:= 0 ;
  106.    for I0:= ' ' to Chr(255) do
  107.      if DecodeTable[I0]<>$FF then
  108.        Inc( EntryCount ) ;
  109.    if EntryCount<>64 then
  110.     begin
  111.      Panic( Fatal, 'Ambiguous conversion table' ) ;
  112.      Exit ;
  113.     end ;  { of if }
  114.  
  115.    ProcessingState:= Reading_Begin ;
  116. end ;  { of ReadConversionTable }
  117.  
  118. procedure ProcesData ;
  119. {*
  120.  * ProcesData - Decode the (encoded) line read if the end of input
  121.  *              is not encountered.  The end of input is signalled
  122.  *              by the END statement.
  123.  *}
  124. var
  125.    ExpectedLength : Integer ;  { Length encoded in line image }
  126.    DeltaLength    : Integer ;  { Expected minus actual length }
  127.    Byte1          :    Byte ;  { Decode bytes }
  128.    Byte2          :    Byte ;
  129.    Byte3          :    Byte ;
  130.    I              : Integer ;  { Loop control variable }
  131.  
  132.  procedure DecodeCharacter( NextChar : Char ) ;
  133.  {*
  134.   * DecodeCharacter - Decode one character.
  135.   *}
  136.  var
  137.     Sextet : Byte ;  { One decoded character }
  138.  begin
  139.     Sextet  := DecodeTable[NextChar] ;
  140.     CheckSum:= CheckSum + Sextet ;
  141.     if Sextet<>$FF then
  142.       case DecodeState of
  143.         Sextet0 : begin
  144.                     Byte1:= Sextet shl 2 ;
  145.                     DecodeState:= Sextet1 ;
  146.                   end ;  { of case 0 }
  147.         Sextet1 : begin
  148.                     Byte1:= Byte1 + ( (Sextet shr 4) and $03 ) ;
  149.                     Byte2:=           (Sextet shl 4) and $F0   ;
  150.                     WriteByteToChunk( Byte1 ) ;
  151.                     DecodeState:= Sextet2 ;
  152.                   end ;  { of case 1 }
  153.         Sextet2 : begin
  154.                     Byte2:= Byte2 + (Sextet          shr 2) ;
  155.                     Byte3:=         (Sextet and $03) shl 6  ;
  156.                     WriteByteToChunk( Byte2 ) ;
  157.                     DecodeState:= Sextet3 ;
  158.                   end ;  { of case 2 }
  159.         Sextet3 : begin
  160.                     Byte3:= Byte3 + Sextet ;
  161.                     WriteByteToChunk( Byte3 ) ;
  162.                     DecodeState:= Sextet0 ;
  163.                   end ;  { of case 3 }
  164.       end   { of cases }
  165.     else  { character cannot be decoded }
  166.       ErrorsInLine:= ErrorsInLine + [IllegalCharacter] ;
  167.  end ;  { of DecodeCharacter }
  168.  
  169. begin
  170. {*
  171.  * If in verbose mode, give an indication of the progres.
  172.  *}
  173.    if VerboseMode then
  174.      if (LinesRead and $000F)=0 then
  175.        Write( ^M'Line ', LinesRead ) ;
  176. {*
  177.  * Check if the current line contains the statement 'end'.  If so,
  178.  * swap to the processingstate Completed.
  179.  *}
  180.    if Length(NextLine)=3 then
  181.      if NextLine='end' then
  182.       begin
  183.        FileEpilogue ;  { Finish processing current file }
  184.        FilePrologue ;  { Setup to convert next file }
  185.        ProcessingState:= Completed ;
  186.        Exit ;
  187.       end ;  { of if }
  188.  
  189. {*
  190.  * Extract the length of the line from the line itself: it is encoded
  191.  * in the first character of the line.  This length should match the
  192.  * actual length of the line.
  193.  *}
  194.    if ErrorsInLine=[] then
  195.     begin
  196.      ExpectedLength:= (DecodeTable[NextLine[1]]*4) div 3 ;
  197.      if (ExpectedLength>=0) then
  198.       begin
  199.        DeltaLength:= Length(NextLine) - ExpectedLength ;
  200.        Terminator := ' ' ;
  201.        case LineFormat of
  202.          Unknown : case DeltaLength of
  203.                      1 : begin
  204.                           LineFormat:= Basic ;
  205.                           NextLine:= Copy( NextLine, 2, ExpectedLength ) ;
  206.                          end ;  { of case 1 }
  207.                      2 : begin
  208.                           LineFormat:= Extended ;  { Either Trmntr or ChckSm }
  209.                           Terminator:= NextLine[Length(NextLine)] ;
  210.                           CheckSum  := -DecodeTable[Terminator] ;
  211.                           NextLine  := Copy( NextLine, 2, ExpectedLength ) ;
  212.                          end ;  { of case 2 }
  213.                    else
  214.                      ErrorsInLine:= ErrorsInLine + [WrongLength] ;
  215.                    end ;  { of case Unknown }
  216.          Basic   : if DeltaLength=1 then
  217.                      NextLine:= Copy( NextLine, 2, ExpectedLength )
  218.                    else
  219.                      ErrorsInLine:= ErrorsInLine + [WrongLength] ;
  220.          Extended: if DeltaLength<>2 then
  221.                      ErrorsInLine:= ErrorsInLine + [WrongLength]
  222.                    else
  223.                     begin
  224.                      Terminator:= NextLine[Length(NextLine)] ;
  225.                      CheckSum  := -DecodeTable[Terminator] ;
  226.                      NextLine  := Copy( NextLine, 2, ExpectedLength ) ;
  227.                     end ;  { of case Extended }
  228.          Trmntr  : if DeltaLength<>2 then
  229.                      ErrorsInLine:= ErrorsInLine + [WrongLength]
  230.                    else
  231.                      if NextLine[Length(NextLine)]<>'M' then
  232.                        ErrorsInLine:= ErrorsInLine + [WrongTerminator]
  233.                      else
  234.                        NextLine:= Copy( NextLine, 2, ExpectedLength ) ;
  235.          ChckSm  : if DeltaLength<>2 then
  236.                      ErrorsInLine:= ErrorsInLine + [WrongLength]
  237.                    else
  238.                     begin
  239.                      Terminator:= NextLine[Length(NextLine)] ;
  240.                      CheckSum  := -DecodeTable[Terminator] ;
  241.                      NextLine  := Copy( NextLine, 2, ExpectedLength ) ;
  242.                     end ;  { of case ChckSm }
  243.        end ;  { of cases }
  244.       end
  245.      else  { the length field cannot be decoded }
  246.        ErrorsInLine:= ErrorsInLine + [IllegalFormat] ;
  247.    end ;  { of if }
  248.  
  249. {*
  250.  * If any errors are found, the reaction will depend on the checking mode:
  251.  * strict or relaxed.  In the latter case the line and the error(s) are
  252.  * ignored.
  253.  *}
  254.    if ErrorsInLine<>[] then
  255.     begin
  256.      Inc( LinesSkipped ) ;
  257.      Panic( Warning, 'Illegal format of line' ) ;
  258.     end
  259.    else  { there are no errors found }
  260. {*
  261.  * Decode the line.
  262.  *}
  263.     begin
  264.      I:= 0 ;
  265.      while (ErrorsInLine=[]) and (I<Length(NextLine)) do
  266.       begin
  267.        Inc( I ) ;
  268.        DecodeCharacter( NextLine[I] ) ;
  269.        if ErrorsInLine<>[] then
  270.          Panic( Fatal, 'Illegal character : '+NextLine[I] ) ;
  271.       end ;  { of while }
  272. {*
  273.  * if no errors are encountered while decoding the line, and the line format
  274.  * is extended, that is it is either Trmntr or ChckSm, check both the
  275.  * checksum and the line terminator to determine the actual line format.
  276.  * The following table shows the decision algorithm:
  277.  *
  278.  *    Terminator   CheckSum   New LineFormat   Remarks
  279.  *         = 'M'      Match         Extended   No change in line format
  280.  *         = 'M'   No match           Trmntr
  281.  *        <> 'M'      Match           ChckSm
  282.  *        <> 'M'   No match                ?   Some other format ?
  283.  *}
  284.      CheckSum:= CheckSum and $003F ;  { Finsh checksum computation }
  285.      if LineFormat=Extended then
  286.        if ErrorsInLine=[] then
  287.          if Terminator='M' then
  288.           begin
  289.            if CheckSum<>0 then
  290.              LineFormat:= Trmntr
  291.           end
  292.          else
  293.           begin
  294.            if CheckSum=0 then
  295.              LineFormat:= ChckSm
  296.            else
  297.              Panic( Fatal, 'Unknown line format' ) ;
  298.           end ;  { of if/if/if }
  299. {*
  300.  * If the line includes a checksum, it is now the time to see if the checksum
  301.  * is correct.
  302.  *}
  303.      if LineFormat=ChckSm then
  304.        if ErrorsInLine=[] then
  305.          if CheckSum<>0 then
  306.            Panic( Fatal, 'Checksum error' ) ;
  307.     end ;  { of else }
  308. end ;  { of ProcesData }
  309.  
  310.