home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / FIBMCM.ZIP / IOERROR.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-05-09  |  11.3 KB  |  357 lines

  1. unit IOERROR;
  2.   (* Error handling and other infrequent services.
  3.      When driver output is to be shunted into a file, the file is opened here.
  4.   Each such file contains one or more 512-character blocks of unaltered byte
  5.   stream. *)
  6.  
  7.   interface
  8.     uses
  9.       DOS      (* FExpand, pathstr *);
  10.  
  11.     const
  12.       LAST_WAITING = 24 (* MAX_WAITING - 1                *);
  13.       MAX_WAITING  = 25 (* size of printer-channel buffer *);
  14.  
  15.     type
  16.       destination = (TO_CONSOLE, TO_FILE, TO_PRINTER, TO_TRASH);
  17.       record_number = 0 .. maxint;
  18.  
  19.     var
  20.       WAITING_CHAR   (* 0 .. CHARS_WAITING-1 are real *):
  21.                        packed array[0 .. LAST_WAITING] of char;
  22.       OUTPUT_SINK    (* printer redirection           *): destination;
  23.       CHARS_WAITING  (* printer-channel traffic       *): 0 .. MAX_WAITING;
  24.       OUT_LINE_COUNT (* counts calls of HW_STABILIZE  *),
  25.       PAGE_COUNT     (* total page count              *): integer;
  26.       HEAP_USED      (* bytes of heap now in use      *),
  27.       HEAP_ZENITH    (* most heap ever used           *),
  28.       IN_LINE_COUNT  (* part of # of input lines      *): longint;
  29.       SINK_FILE_NAME (* if non-null, output to file   *): pathstr;
  30.  
  31.     procedure BUILD_MESSAGE(RAW, NAME: string);
  32.     function CAN_SHUNT_TO(TENTATIVE_FILE_NAME: string): boolean;
  33.     procedure CLOSE_DEFER;
  34.     procedure DEFER_TEXT;
  35.     procedure INIT_IOERROR;
  36.     procedure REPORT_IO_ERROR(F_NAME: pathstr; ERROR_NUMBER: integer);
  37.     procedure SHUNT_TO_CONSOLE;
  38.     procedure STATISTICS;
  39.     procedure TIGHT_WRITE(R: real);
  40.     procedure UNSHUNT;
  41.     
  42.   implementation
  43.     uses
  44.       CRT      (* ClrEol, GotoXY, WhereY *),
  45.       SCRN_MGR (* ERROR_EXIT, INIT_SCREEN_MGR, LOUD_WRITE, nullstring,
  46.                     READ_TIMER, STR_FN *);
  47.       
  48.     const
  49.       DQUOTE  = '"';
  50.       LPAR    = '(';
  51.       RPAR    = ')';
  52.       
  53.       LAST_BYTE = 511 (* last in block of deferred file *);
  54.  
  55.       (* eject *)
  56.     type
  57.       defer_record = record
  58.         NEXT_CHAR: integer;
  59.             STUFF: packed array[0 .. LAST_BYTE] of char
  60.         end (* defer_record *);
  61.  
  62.       defer_ptr = ^defer_record;
  63.     
  64.     var
  65.       INITIALIZED  (* don't reinit SCRN_MGR *): boolean;
  66.       DEFER_STATUS (* allocate iff used     *): defer_ptr;
  67.       DEFER_FILE   (* redirected output     *): file;
  68.     
  69.     procedure WRITE_BUFFER; forward;
  70.  
  71.     procedure BUILD_MESSAGE(RAW, NAME: string);
  72.       (* LOUD_WRITE the string RAW, replacing
  73.            leading FFF by 'File <NAME>'
  74.            XXX by NAME
  75.       *)
  76.       
  77.       var
  78.         XXX_POS: integer;
  79.            
  80.       begin (* BUILD_MESSAGE *)
  81.         ClrEol;
  82.         writeln;
  83.         ClrEol;
  84.         
  85.         if pos('FFF', RAW) = 1 then
  86.           begin (* File xxx ... *)
  87.             LOUD_WRITE('File ');
  88.             write(NAME);
  89.             LOUD_WRITE(copy(RAW, 4, maxint))
  90.           end   (* File xxx ... *)
  91.         
  92.         else
  93.           begin (* assume that XXX present *)
  94.             XXX_POS := pos('XXX', RAW);
  95.  
  96.             LOUD_WRITE(copy(RAW, 1, pred(XXX_POS)));
  97.             write(NAME);
  98.             LOUD_WRITE(copy(RAW, XXX_POS+3, maxint))
  99.           end   (* assume that XXX present *);
  100.         
  101.         writeln;
  102.         ClrEol
  103.       end   (* BUILD_MESSAGE *);
  104.  
  105.       (* eject *)
  106.     function CAN_SHUNT_TO(TENTATIVE_FILE_NAME: string): boolean;
  107.       (* Open the named file for shunting, if possible; report success *)
  108.       
  109.       begin (* CAN_SHUNT_TO *)
  110.         CAN_SHUNT_TO := false;
  111.         SINK_FILE_NAME := FExpand(TENTATIVE_FILE_NAME);
  112.         assign(DEFER_FILE, SINK_FILE_NAME);
  113.  
  114.         {$I-}
  115.         rewrite(DEFER_FILE);
  116.         if ioresult = 0 then
  117.           begin (* file opened *)
  118.             new(DEFER_STATUS);
  119.             inc(HEAP_USED, sizeof(defer_record));
  120.             if HEAP_USED > HEAP_ZENITH then
  121.               HEAP_ZENITH := HEAP_USED;
  122.             with DEFER_STATUS^ do
  123.               begin (* fill defer_record *)
  124.                 fillchar(STUFF[0], succ(LAST_BYTE), #0);
  125.                 NEXT_CHAR := 0
  126.               end   (* fill defer_record *);
  127.             CAN_SHUNT_TO := true
  128.           end   (* file opened *)
  129.         {$I+}
  130.       end   (* CAN_SHUNT_TO *);
  131.     
  132.     procedure CLOSE_DEFER;
  133.       (* Finish up the open file of output whose printing will be deferred.
  134.       *)
  135.  
  136.       var
  137.         MY_IORESULT: integer;
  138.  
  139.       begin (* CLOSE_DEFER *);
  140.         with DEFER_STATUS^ do
  141.           begin (* with *)
  142.             if NEXT_CHAR > 0 then
  143.               WRITE_BUFFER;
  144.             {$I-}
  145.             close(DEFER_FILE);
  146.             {$I+}
  147.             
  148.             MY_IORESULT := ioresult;
  149.             if MY_IORESULT <> 0 then
  150.               begin (* close failed *)
  151.                 REPORT_IO_ERROR(SINK_FILE_NAME, MY_IORESULT);
  152.                 ERROR_EXIT(nullstring)
  153.               end   (* close failed *)
  154.           end   (* with *)
  155.       end   (* CLOSE_DEFER *);
  156.     
  157.       (* eject *)
  158.     procedure DEFER_TEXT;
  159.       (* Copy the contents of the CHARS_WAITING buffer into the file of
  160.       deferred output *)
  161.     
  162.       var
  163.         CHS_LEFT: 0 .. MAX_WAITING;
  164.         CHS_MOVED, FIRST_REMAINING: integer;
  165.  
  166.       begin (* DEFER_TEXT *)
  167.         CHS_LEFT := CHARS_WAITING;
  168.         FIRST_REMAINING := 0;
  169.  
  170.         with DEFER_STATUS^ do
  171.           while CHS_LEFT > 0 do
  172.             begin (* move as many as we can into buffer *)
  173.               CHS_MOVED := LAST_BYTE + 1 - NEXT_CHAR;
  174.               if CHS_MOVED > CHS_LEFT then
  175.                 CHS_MOVED := CHS_LEFT;
  176.  
  177.               move(WAITING_CHAR[FIRST_REMAINING],
  178.                    STUFF[NEXT_CHAR],
  179.                    CHS_MOVED);
  180.               dec(CHS_LEFT, CHS_MOVED);
  181.               inc(NEXT_CHAR, CHS_MOVED);
  182.               inc(FIRST_REMAINING, CHS_MOVED);
  183.               
  184.               if NEXT_CHAR > LAST_BYTE then
  185.                 WRITE_BUFFER
  186.             end   (* move as many as we can into buffer *)
  187.       end   (* DEFER_TEXT *);
  188.     
  189.     procedure INIT_IOERROR;
  190.       (* Initialize the IOERROR unit and all underlying units *)
  191.       
  192.       begin (* INIT_IOERROR *)
  193.         if not INITIALIZED then
  194.           begin (* initialize *)
  195.             INIT_SCRN_MGR;
  196.             
  197.             CHARS_WAITING := 0;
  198.             HEAP_USED := 0;
  199.             HEAP_ZENITH := 0;
  200.             INITIALIZED := true;
  201.             IN_LINE_COUNT := 0;
  202.             OUT_LINE_COUNT := 0;
  203.             PAGE_COUNT := 0
  204.           end   (* initialize *)
  205.       end   (* INIT_IOERROR *);
  206.     
  207.       (* eject *)
  208.     procedure REPORT_IO_ERROR(F_NAME: pathstr; ERROR_NUMBER: integer);
  209.       (* Decode ERROR_NUMBER (an IORESULT, arising during attempted
  210.       reading of file F_NAME) to the console *)
  211.       
  212.       var
  213.         RAW: string;
  214.  
  215.       begin (* REPORT_IO_ERROR *)
  216.         case ERROR_NUMBER of
  217.             2,
  218.           102: RAW := 'FFF is improperly named or cannot be found.';
  219.             3: RAW := '''XXX'' includes an illegal path name.';
  220.             5: RAW := 'Access denied to file XXX.';
  221.           100: RAW := 'FFF cannot be read.';
  222.           101: RAW := 'FFF cannot be written.';
  223.           103: RAW := 'FFF cannot be opened.';
  224.           104: RAW := 'FFF not opened for reading.';
  225.           105: RAW := 'FFF not opened for writing.'
  226.           else RAW := 'I/O error #' + STR_FN(ERROR_NUMBER) +
  227.                                ' signalled during reading of file XXX.'
  228.           end (* case on ERROR_NUMBER *);
  229.         
  230.         BUILD_MESSAGE(RAW, F_NAME)
  231.       end   (* REPORT_IO_ERROR *);
  232.     
  233.     procedure SHUNT_TO_CONSOLE;
  234.       (* Copy the characters of CHARS_WAITING to the console *)
  235.  
  236.       var
  237.         I: 0 .. MAX_WAITING;
  238.  
  239.       begin (* SHUNT_TO_CONSOLE *)
  240.         for I := 0 to pred(CHARS_WAITING) do
  241.           case WAITING_CHAR[I] of
  242.             #32 .. #126: write(WAITING_CHAR[I])
  243.                     else LOUD_WRITE(LPAR + STR_FN(ord(WAITING_CHAR[I])) + RPAR)
  244.             end (* case on WAITING_CHAR[I] *);
  245.         writeln
  246.       end   (* SHUNT_TO_CONSOLE *);
  247.  
  248.       (* eject *)
  249.     procedure STATISTICS;
  250.       (* Print summary at end of document *)
  251.  
  252.       var
  253.         SECONDS: longint;
  254.         TOTAL_HOURS, TOTAL_MINUTES: real;
  255.  
  256.       begin (* STATISTICS *)
  257.         writeln;
  258.         writeln('Job size:');
  259.  
  260.         writeln(   HEAP_ZENITH:10, ' bytes of heap storage used at peak.');
  261.         writeln( IN_LINE_COUNT:10, ' lines processed.');
  262.         writeln(OUT_LINE_COUNT:10, ' lines composed.');
  263.  
  264.         write(PAGE_COUNT:10, ' page');
  265.         if PAGE_COUNT <> 1 then
  266.           write('s');
  267.         writeln(' composed.');
  268.  
  269.         SECONDS := READ_TIMER;
  270.         if SECONDS > 0 then
  271.           begin (* we got timing data *)
  272.             TOTAL_HOURS := SECONDS / 3600.0;
  273.             TOTAL_MINUTES := SECONDS / 60.0;
  274.  
  275.             writeln;
  276.             writeln('Job time:');
  277.             writeln(nullstring:3,
  278.                     SECONDS div 3600, 'h ',
  279.                     (SECONDS mod 3600) div 60, ''' ',
  280.                     SECONDS mod 60, DQUOTE);
  281.  
  282.             writeln;
  283.             writeln('Job statistics:');
  284.             writeln(round(IN_LINE_COUNT/TOTAL_MINUTES):10,
  285.                     ' lines processed/minute');
  286.             writeln(round(OUT_LINE_COUNT/TOTAL_MINUTES):10,
  287.                     ' lines composed/minute');
  288.             writeln(round(PAGE_COUNT/TOTAL_HOURS):10, ' pages composed/hour');
  289.             writeln
  290.           end   (* we got timing data *)
  291.       end   (* STATISTICS *);
  292.       
  293.     procedure TIGHT_WRITE(R: real);
  294.       (* Write R in integer format if possible, otherwise in F10.0 format *)
  295.       
  296.       begin (* TIGHT_WRITE *)
  297.         if R > maxint then
  298.           write(R:10:0)
  299.         else
  300.           write(trunc(R))
  301.       end   (* TIGHT_WRITE *);
  302.     
  303.       (* eject *)
  304.     procedure UNSHUNT;
  305.       (* Reconsider shunting to file.  May be used ONLY if OUTPUT_SINK
  306.       is about to be safely set *)
  307.       
  308.       begin (* UNSHUNT *)
  309.         {$I-}
  310.         close(DEFER_FILE);
  311.         if ioresult > 0 then
  312.           (* ignore it *);
  313.         erase(DEFER_FILE);
  314.         if ioresult > 0 then
  315.           (* ignore it *);
  316.         dispose(DEFER_STATUS);
  317.         dec(HEAP_USED, sizeof(defer_record));
  318.         {$I+}
  319.         OUTPUT_SINK := TO_TRASH
  320.       end   (* UNSHUNT *);
  321.           
  322.     procedure WRITE_BUFFER;
  323.       (* Flush the buffer  *)
  324.       
  325.       var
  326.         BLOCKS_WRITTEN, MY_IORESULT: integer;
  327.       
  328.       begin (* WRITE_BUFFER *)
  329.         with DEFER_STATUS^ do
  330.           begin (* with *)
  331.             {$I-}
  332.             blockwrite(DEFER_FILE, STUFF, 1, BLOCKS_WRITTEN);
  333.             {$I+}
  334.             MY_IORESULT := ioresult;
  335.             if (MY_IORESULT <> 0) or (BLOCKS_WRITTEN <> 1) then
  336.               begin (* failed to write *)
  337.                 REPORT_IO_ERROR(SINK_FILE_NAME, MY_IORESULT);
  338.                 ERROR_EXIT(nullstring)
  339.               end   (* failed to write *)
  340.             else
  341.               begin (* succeeded, ready for next block *)
  342.                 fillchar(STUFF[0], succ(LAST_BYTE), #0);
  343.                 NEXT_CHAR := 0
  344.               end   (* succeeded, ready for next block *)
  345.           end   (* with *)
  346.       end   (* WRITE_BUFFER *);
  347.       
  348.     begin (* IOERROR *)
  349.       INITIALIZED := false
  350.     end   (* IOERROR *).
  351.  
  352. END
  353. T-------T-------T-------T-------T-------T-------T-------T-------T-------T-------T
  354. $cursor=11521,10;$tag=2053,19;$last=11525,13;
  355. FTL0R79P5.F0B7
  356.  
  357.