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

  1. {* ----------------------------------------------------------------- *
  2.  *                                                                   *
  3.  *       U S E R   I N T E R F A C E    P R O C E D U R E S          *
  4.  *                                                                   *
  5.  * ----------------------------------------------------------------- *}
  6.  
  7. procedure DisplayHelpInfo ;
  8. {*
  9.  * DisplayHelpInfo - Display a short description of this program on
  10.  *                   the standard output file.
  11.  *}
  12. begin
  13.    WriteLn( 'DecUF (DECode_Uuencoded_File)  v 1.3' ) ;
  14.    Write  ( 'Usage: DecUF <InputFile> [/o<OutputPath>]' ) ;
  15.    WriteLn( ' [/c{+,-}] [/s{+,-}] [/v{+,-}]' ) ;
  16.    WriteLn( '       c : Checking is strict (+) or relaxed (-).' ) ;
  17.    WriteLn( '       s : a Single file (+) or multiple files (-) are encoded.' ) ;
  18.    WriteLn( '       v : Verbose mode (+) or quiet mode (-).' ) ;
  19.    WriteLn( '       The default setting is /c- /s- /v+' ) ;
  20.    WriteLn ;
  21.    WriteLn( 'Written by W. Nelis, Nelis@NLR.NL, 199209' ) ;
  22.    WriteLn ;
  23. end ;  { of DisplayHelpInfo }
  24.  
  25. procedure Panic( Severity : ErrorTypes ; ErrorMsg : Message ) ;  forward ;
  26.  
  27. procedure CrackParameters ;
  28. {*
  29.  * CrackParameters - Proces the parameters supplied to this program.
  30.  *}
  31. type
  32.    Parameters = ( InputFile  ,    { Drive/user/name of input file }
  33.                   OutputPath ,    { Drive/user for decoded files }
  34.                   FileCount  ,    { Input file contains one encoded file }
  35.                   CheckMode  ,    { Strict or relaxed checking }
  36.                   Verbose    ) ;  { Progress report enabled }
  37. var
  38.   Specified : set of Parameters ;  { Specified parameters }
  39.   NextParam :     KeywordString ;  { Next parameter from command line }
  40.   ColonPos  :           Integer ;  { Position of ':' in path name }
  41.   I         :           Integer ;  { Loop control variable }
  42.  
  43.  procedure ParameterError ;
  44.  {*
  45.   * ParameterError : Issue an error meesage about a parameter in error.
  46.   *                  The parameter in question is ignored.
  47.   *}
  48.  begin
  49.     Panic( Informative, 'Illegal Parameter "'+NextParam+'". It is ignored' ) ;
  50.  end;  { of ParameterError }
  51.  
  52.  procedure SetFlag( var Variable : Boolean ;  VarType : Parameters ) ;
  53.  {*
  54.   * SetFlag : Set the option Variable to TRUE if the third character in the
  55.   *           parameterstring is a '+' sign and set it to FALSE if it is a
  56.   *           '-' sign.  The presence of the option is saved in Specified.
  57.   *}
  58.  begin
  59.    if VarType in Specified then
  60.      ParameterError
  61.    else
  62.      if (Length(NextParam)=3) and (NextParam[3] in ['+','-']) then
  63.       begin
  64.        Specified:= Specified + [VarType] ;
  65.        Variable := NextParam[3]='+' ;
  66.       end
  67.      else
  68.        ParameterError ;
  69.  end ;  { of SetFlag }
  70.  
  71. begin
  72.    Specified:= [] ;  { Empty set of specified parameters }
  73.    for I:= 1 to ParamCount do
  74.     begin
  75.      NextParam:= ParamStr(I) ;
  76.      if (Length(NextParam)>1) and (NextParam[1]='/') then
  77. {*
  78.  * The parameter on the command line has the format /KV, in which 'K' is
  79.  * a one-character keyword and V the associated value.
  80.  *}
  81.       begin
  82.        case NextParam[2] of
  83. {*
  84.  * Specify the path, that is the drive and the user number, to the area
  85.  * to save the decoded file(s).
  86.  *}
  87.        'O' : begin
  88.                if Outputpath in Specified then
  89.                  ParameterError
  90.                else  { OutputPath is not yet specified }
  91.                 begin
  92.                  Specified     := Specified + [OutputPath] ;
  93.                  OutputFilePath:= Copy( NextParam, 3, 255 ) ;
  94.                  ColonPos      := Pos( ':', OutputFilePath ) ;
  95.                  if ColonPos=0 then
  96.                    OutputFilePath:= OutputFilePath + ':'
  97.                  else
  98.                    OutputFilePath:= Copy( OutputFilePath, 1, ColonPos ) ;
  99.                 end ;  { of else }
  100.              end ;  { of case O }
  101. {*
  102.  * Specify whether the input file contains one (S+) or more (S-) encoded
  103.  * files.
  104.  *}
  105.        'S' : SetFlag( OnlyOneFile   , FileCount ) ;
  106. {*
  107.  * Specify whether an error in the format is a fatal error (C+) or is to
  108.  * be ignored (C-).  In the latter case email headers are allowed within
  109.  * the input file.
  110.  *}
  111.        'C' : SetFlag( StrictChecking, CheckMode ) ;
  112. {*
  113.  * Specify whether a progres report, together with statistics, is to be
  114.  * generated (V+) or not (V-).
  115.  *}
  116.        'V' : SetFlag( VerboseMode   , Verbose   ) ;
  117.  
  118.        else  { the parameter is not supported }
  119.          ParameterError ;
  120.        end ;  { of cases }
  121.       end    { of if }
  122. {*
  123.  * The parameter on the command line is not of the format /KV, thus it must
  124.  * be the name of the input file.
  125.  *}
  126.      else
  127.       begin
  128.        if InputFile in Specified then
  129.          ParameterError
  130.        else
  131.         begin
  132.          Specified    := Specified + [InputFile] ;
  133.          InputFileName:= NextParam ;
  134.          if Pos( '.', InputFileName )=0 then
  135.            InputFileName:= InputFileName + DefaultExtension ;
  136.         end ;  { of else }
  137.       end ;  { of else }
  138.     end ;  { of for }
  139.  
  140. {*
  141.  * The inputfile must have been specified.
  142.  *}
  143.    if not (InputFile in Specified) then
  144.      Panic( Catastrophic, 'No input file specified' ) ;
  145. end ;  { of CrackParameters }
  146.  
  147. procedure DisplayStatistics ;
  148. {*
  149.  * DisplayStatistics - Display the statistics of this conversion run.
  150.  *}
  151. var
  152.    ByteCount : Real ;  { Actual number of bytes written }
  153. begin
  154.    ByteCount:= 128.0 * BytesWritten ;
  155.    Write  ( ^M ) ;  ClrEol ;
  156.    WriteLn ;
  157.    WriteLn( 'Number of lines read ....... ',         LinesRead:10 ) ;
  158.    WriteLn( 'Number of lines written .... ',      LinesWritten:10 ) ;
  159.    WriteLn( 'Number of characters read .. ',    CharactersRead:10 ) ;
  160.    WriteLn( 'Number of bytes written .... ',       ByteCount:10:0 ) ;
  161.    WriteLn( 'Number of heap flushes ..... ',       HeapFlushes:10 ) ;
  162.    WriteLn( 'Number of lines skipped .... ',      LinesSkipped:10 ) ;
  163.    WriteLn( 'Number of characters skipped ', CharactersSkipped:10 ) ;
  164. end ;  { of DisplayStatistics }
  165.  
  166. procedure PresetDecodeTable ;
  167. {*
  168.  * PresetDecodeTable - Preset the character-to-sextet conversion table
  169.  *                     to its default.
  170.  *}
  171. var
  172.    I : Char ;  { Loop control variable }
  173. begin
  174.    for I:= ' ' to '_' do
  175.      DecodeTable[I]:= Ord(I) - Ord(' ') ;
  176.    for I:= Succ('_') to Chr(255) do
  177.      DecodeTable[I]:= $FF ;
  178.  
  179.    DecodeTable['`']:= DecodeTable[' '] ;
  180. end ;  { of PresetDecodeTable }
  181.  
  182. {* ----------------------------------------------------------------- *
  183.  *                                                                   *
  184.  *        P R O L O G U E S   A N D   E P I L O G U E S              *
  185.  *                                                                   *
  186.  * ----------------------------------------------------------------- *}
  187. {*
  188.  * Both the execution of this program and the conversion of one file
  189.  * are encapsulated between a prologue and an epilogue.
  190.  *}
  191.  
  192. procedure CloseOutputFile ;  forward ;
  193.  
  194. procedure FilePrologue ;
  195. {*
  196.  * FilePrologue - Preset the global variables prior to the decoding of
  197.  *                the (next) file.
  198.  *}
  199. begin
  200.    OutputFileName   := OutputFilePath + 'NoName.XYZ' ;
  201.    OutputFileOpen   := False ;
  202.  
  203.    PresetDecodeTable ;
  204.    DecodeState      := Sextet0 ;
  205.    LineFormat       := Unknown ;
  206.  
  207.    BytesWritten     := 0 ;
  208.    CharactersRead   := 0 ;
  209.    CharactersSkipped:= 0 ;
  210.    HeapFlushes      := 0 ;
  211.    LinesRead        := 0 ;
  212.    LinesSkipped     := 0 ;
  213.    LinesWritten     := 0 ;
  214.  
  215.    AllocateChunk ;  { Reserve space for output data }
  216. end ;  { of FilePrologue }
  217.  
  218. procedure FileEpilogue ;
  219. {*
  220.  * FileEpilogue - Finish processing of the current output file.  The
  221.  *                global variables, except for the options, are set to
  222.  *                their default value.
  223.  *}
  224. begin
  225. {*
  226.  * Finish processing on the current result file.
  227.  *}
  228.    CloseOutputFile ;
  229.    if VerboseMode then
  230.      DisplayStatistics ;
  231. {*
  232.  * (P)reset global variables.
  233.  *}
  234.    ReleaseChunks ;  { Reset chunklist pointers, just to be sure }
  235. end ;  { of FileEpilogue }
  236.  
  237. procedure ProgramPrologue ;
  238. {*
  239.  * ProgramPrologue - Preset the global variables and interpret the command
  240.  *                   line options.
  241.  *}
  242. begin
  243. {*
  244.  * Preset the global variables.
  245.  *}
  246.    HeadChunkList:= Nil ;
  247.    TailChunkList:= Nil ;
  248.    NextLine     := ' ' ;
  249.    LineIndex    :=   1 ;
  250.    ErrorsInLine := [ ] ;
  251. {*
  252.  * Set defaults for all the options
  253.  *}
  254.    OutputFilePath:= Chr( Bdos($19) + Ord('A') )  + ':' ;
  255.    OnlyOneFile   := False ;
  256.    StrictChecking:= False ;
  257.    VerboseMode   := True  ;
  258. {*
  259.  * Now it is time to execute the file prologue: it resets the various
  260.  * global variables, which MUST be (re)set in case the error processor
  261.  * is invoked!
  262.  *}
  263.    FilePrologue ;
  264.  
  265. {*
  266.  * Read the command line and extract the options.
  267.  *}
  268.    if ParamCount=0 then
  269.     begin
  270.      DisplayHelpInfo ;
  271.      UnInitFileNameUnit ;
  272.      Halt ;
  273.     end
  274.    else
  275.      CrackParameters ;
  276. end ;  { of ProgramPrologue }
  277.  
  278. procedure ProgramEpilogue ;
  279. {*
  280.  * ProgramEpilogue - Clean up before termination of the program.
  281.  *}
  282. begin
  283.    Close( InputFile ) ;
  284.    CloseOutputFile ;
  285. end ;  { of ProgramEpilogue }
  286.  
  287. procedure Panic ;
  288. {*
  289.  * Panic - Proces an error condition.
  290.  *}
  291. begin
  292. {*
  293.  * Exit from this routine, if the error is to be ignored.
  294.  *}
  295.    if (Severity=Warning) and (not StrictChecking) then
  296.      Exit ;
  297. {*
  298.  * Remove the progres report line from the screen.
  299.  *}
  300.    if VerboseMode then
  301.     begin
  302.      Write( ^M ) ;  { Goto left side of screen }
  303.      ClrEol      ;  { Remove progres report }
  304.     end ;  { of if }
  305. {*
  306.  * Display the errormessage, together with more detailed messages, if
  307.  * available.
  308.  *}
  309.    if LinesRead=0 then
  310.      Write( 'Error' )
  311.    else
  312.      Write( 'Error at line ', LinesRead ) ;
  313.    WriteLn( ' - ', ErrorMsg, '.' ) ;
  314.  
  315.    if IllegalCharacter in ErrorsInLine then
  316.      WriteLn( ' - Illegal character found.' ) ;
  317.    if Overflow         in ErrorsInLine then
  318.      WriteLn( ' - Internal line buffer too small.' ) ;
  319.    if IllegalFormat    in ErrorsInLine then
  320.      WriteLn( ' - Length field cannot be decoded.' ) ;
  321.    if WrongLength      in ErrorsInLine then
  322.      WriteLn( ' - Length field wrong.' ) ;
  323.    if WrongTerminator  in ErrorsInLine then
  324.      WriteLn( ' - Line terminator is not ''M''.' ) ;
  325. {*
  326.  * Take further actions, depending on the type of error.
  327.  *}
  328.    if Severity=Catastrophic then
  329.     begin
  330.      WriteLn( 'Program premature terminated.' ) ;
  331.      ProgramEpilogue ;
  332.      UnInitFileNameUnit ;
  333.      Halt ;
  334.     end
  335.    else
  336.      if Severity<>Informative then
  337.       begin
  338.        if OutputFileOpen then
  339.         begin
  340.          WriteLn( 'File ', OutputFileName, ' is erased.' ) ;
  341.          ReleaseChunks ;       { Destroy any data gathered in chunks }
  342.          CloseOutputFile ;     { Close the result file and .. }
  343.          Erase( OutputFile ) ; { destroy the result file too }
  344.         end ;  { of if }
  345.        ProcessingState:= Completed ;  { Skip rest of file }
  346.       end ;  { of if/else }
  347. end ;  { of Panic }
  348.  
  349.  
  350. {*
  351.  * FILES : Opening and closing of both the input file and the result
  352.  * file.
  353.  *}
  354.  
  355. procedure OpenInputFile ;
  356. {*
  357.  * OpenInputFile - Open the input file.
  358.  *}
  359. begin
  360. {*
  361.  * Rebuild the input file name.
  362.  *}
  363.    SplitFileName( InputFileDesc, InputFileName ) ;
  364.    InputFileName:= ExpandFileName( InputFileDesc, DUNE_Format ) ;
  365.    RegisterFile( InputFileDesc, InputFile ) ;
  366.  
  367.    Assign( InputFile, ExpandFileName(InputFileDesc,DNE_Format) ) ;
  368.    {$I-}  Reset(InputFile) ;  {$I+}
  369.    if IOResult<>0 then  { the file doesn't exists }
  370.      Panic( Catastrophic, 'Can''t find file '+InputFileName )
  371.    else
  372.      if Eof(InputFile) then
  373.        Panic( Catastrophic, 'File '+InputFileName+' is empty' ) ;
  374. end ;  { of OpenInputFile }
  375.  
  376. procedure OpenOutputFile ;
  377. {*
  378.  * OpenOutputfile - Open the result file.
  379.  *}
  380. var
  381.    Answer : Char ;  { Answer from user }
  382. begin
  383. {*
  384.  * Rebuild output file name.
  385.  *}
  386.    SplitFileName( OutputFileDesc, OutputFileName ) ;
  387.    OutputFileName:= ExpandFileName( OutputFileDesc, DUNE_Format ) ;
  388.    RegisterFile( OutputFileDesc, OutputFile ) ;
  389.  
  390.    Assign( OutputFile, ExpandFileName(OutputFileDesc,DNE_Format) ) ;
  391.    {$I-} Reset( OutputFile ) ;  {$I+}
  392.    if IOResult=0 then  { the file exists already }
  393.     begin
  394.      Close( OutputFile ) ;
  395.      repeat
  396.        Write( ^G^M'Warning - file ', OutputFileName, ' exists. ' ) ;
  397.        Write( 'Overwrite (destroy) it (y/n)? ' ) ;  ClrEol ;
  398.        Read ( Kbd, Answer ) ;
  399.        Answer:= UpCase( Answer ) ;
  400.      until Answer in ['N','Y'] ;
  401.      WriteLn( Answer ) ;
  402.      if Answer='N' then
  403.       begin
  404.        ProcessingState:= Completed ;  { Skip this encoded file }
  405.        Exit ;
  406.       end ;  { of if }
  407.     end ;  { of if }
  408.  
  409. {$I-}  Rewrite( OutputFile ) ;  {$I+}
  410.    if IOResult=0 then
  411.      OutputFileOpen:= True
  412.    else
  413.      Panic( Catastrophic, 'Can''t write on file '+OutputFilename ) ;
  414. end ;  { of OpenOutputFile }
  415.  
  416. procedure CloseOutputFile ;
  417. {*
  418.  * CloseOutputFile - Write all buffered data to the result file and
  419.  *                   close it.
  420.  *}
  421. begin
  422.    if OutputFileOpen then
  423.     begin
  424.      FlushChunks ;
  425.      Close( OutputFile ) ;
  426.      OutputFileOpen:= False ;
  427.     end ;  { of if }
  428. end ;  { of CloseOutputFile }
  429.  
  430.  
  431. {*
  432.  * Handling of the input from the input file.
  433.  *}
  434.  
  435. procedure ReadNextLine ;
  436. {*
  437.  * ReadNextLine - Read the next line from the input file into NextLine.
  438.  *                Non-printable characters are removed from the line
  439.  *                image.
  440.  *}
  441. var
  442.    LineLength : Integer ;  { Current length of line read }
  443.    I          : Integer ;  { Loop control variable }
  444. begin
  445.    NextLine    :=    '' ;
  446.    ErrorsInLine:=    [] ;
  447.    CheckSum    :=     0 ;
  448.    if not Eof(InputFile) then
  449.     begin
  450.      ReadLn( InputFile, NextLine ) ;
  451.      CharactersRead:= CharactersRead + Length(NextLine) ;
  452. {*
  453.  * Remove the trailing blanks from string : uuencoded files
  454.  * are (should be) insensitive to trailing blank removal.
  455.  *}
  456.      LineLength:= Length(NextLine) ;
  457.      while (LineLength>0) and (NextLine[LineLength]=' ') do
  458.        Dec(LineLength) ;
  459.      if LineLength<Length(NextLine) then
  460.        NextLine:= Copy( NextLine, 1, LineLength ) ;
  461. {*
  462.  * See if there are any control-characters in the line read.  Optionally
  463.  * these characters could be removed.  However, the line probably will
  464.  * be rejected without interpretation.
  465.  *}
  466.      if LineLength>0 then
  467.        for I:= LineLength downto 1 do
  468.          if NextLine[I]<' ' then
  469.           begin
  470.            ErrorsInLine:= ErrorsInLine + [IllegalCharacter] ;
  471. (*         NextLine    := Copy( NextLine,   1,        I-1 ) +
  472.                           Copy( NextLine, I+1, LineLength ) ;  *)
  473.            Inc( CharactersSkipped ) ;
  474.           end ;  { of if/for/if }
  475.  
  476.     end ;  { of if Eof() }
  477.    Inc( LinesRead ) ;
  478. end ;  { of ReadNextLine }
  479.  
  480. function NextWord : KeyWordString ;
  481. {*
  482.  * NextWord - Extract the next word from NextLine starting at character
  483.  *            offset Index.
  484.  *}
  485. var
  486.    SomeWord : KeyWordString ;
  487. begin
  488.    SomeWord:= '' ;
  489.    while (LineIndex<=Length(NextLine)) and
  490.          (NextLine[LineIndex]=' ')    do
  491.      LineIndex:= Succ(LineIndex) ;
  492.  
  493.    while (LineIndex<=Length(NextLine)) and
  494.          (NextLine[LineIndex]<>' ')    do
  495.     begin
  496.      SomeWord:= SomeWord + NextLine[LineIndex] ;
  497.      LineIndex:= Succ(LineIndex) ;
  498.     end ;  { of while }
  499.    NextWord:= SomeWord ;
  500. end ;  { of NextWord }
  501.  
  502.