home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / PROGRAMS / WSTAR / WS-COL12.LBR / WS-COL12.PQS / WS-COL12.PAS
Pascal/Delphi Source File  |  2000-06-30  |  15KB  |  468 lines

  1. PROGRAM WSCOLUM; (* WS-COLUM 1.2 *)
  2.  
  3. (* Released into the public domain January 1986
  4.    by the author:
  5.  
  6.                     Steve Wilcox
  7.                  1215 South Osceola
  8.                   Denver, CO 80219
  9.                     303-936-0440
  10.  
  11.    I would appreciate being notified of any 
  12.    problems or changes in the program.
  13.  
  14.      This program will take a WordStar text file
  15.   of two pages or more and arrange consecutive
  16.   pages in sets of columns. The program keeps track
  17.   of WordStar print control toggles to keep them
  18.   associated with only the text block in which they
  19.   were begun.
  20.      The three user-input variables are the name
  21.   of the source file, the name of the destination
  22.   file, and the print column numbers that will be
  23.   the left margin for subsequent text blocks.
  24.      In the ReadNWrite Procedure, the source file
  25.   is read into memory a set of pages at a time
  26.   (depending on how many columns have been entered),
  27.   using a double-tiered linked list. Each page break
  28.   is pointed to with a PagePointer, which in turn
  29.   points to the beginning of the second linked
  30.   list (BufferStorage), the actual text in that
  31.   page.
  32.      The text is stored in a series of consecutive
  33.   arbitrary 128 byte records (BufferStorage)
  34.   rather than line-by-line records. This eliminates
  35.   the need to pre-guess the length of any line
  36.   coming in from the input file.
  37.      With a set of pages in memory, they are read
  38.   back out by following the BufferStorage linked
  39.   lists for the page sets until WordStar's page-end
  40.   character (#138) is encountered.
  41.      The set of pages is assembled side-by-side
  42.   to the final file by outputting corrresponding
  43.   lines from each page in the set, with spaces
  44.   between them for the center margins. After the
  45.   output page is done, ReadNWrite goes through
  46.   another iteration.
  47.      Screen prompts in this program are set for a
  48.   52 column screen.                    *)
  49.  
  50. (* 6/26/86  Changed the ReadNWrite Procedure to
  51.             accommodate files that don't end in a
  52.             carriage return. The program now
  53.             appends a CR/PageBreak sequence at the
  54.             end of the file if it doesn't have one.
  55.             The buffer code in ReadASet was moved
  56.             to the new Store procedure to
  57.             accommodate storing characters from
  58.             different code locations.
  59.  
  60.    8/21/86  The above modification, it turns out,
  61.             also corrects a problem when a new
  62.             LineStore record is created exactly when
  63.             the PageBreak character is encountered.
  64.             The effect was that the following page
  65.             of the source file was read into memory,
  66.             but never read out; it was discarded.
  67.               However it brought to light a similar,
  68.             though undoubtedly rare problem when a
  69.             new LineStore record is created exactly
  70.             at EOF. The problem was corrected by
  71.             filling the LineStore position after
  72.             the new record has been created.
  73.             Originally, the need for a record was
  74.             determined, and the record itself
  75.             created, after storage.
  76.               Made a minor modification to the
  77.             MergePages procedure to prevent excess
  78.             space characters from being added if
  79.             a full implement of columns is not
  80.             present on the last page.
  81.               Added provision in  ControlCheck to
  82.             adjust LineCharCount for certain
  83.             sub-printable ASCII characters that are
  84.             printable in WordStar. Originally no
  85.             character below ASCII 31 would be
  86.             counted as a printing character, thus
  87.             the column justification would be
  88.             wrong if special characters were
  89.             used.
  90.               Modified the routine to read initial
  91.             dot commands. They are now written
  92.             directly to the outputfile, rather
  93.             than stored. This accommodates much
  94.             larger headers.
  95.               Modified AbortProgram to close and
  96.             erase the output file rather than
  97.             leave it partially written. *)
  98.  
  99.  
  100. {$I-}
  101. CONST
  102.   LF=#10;                         (* LineFeed Character *)
  103.   CR=#13;                         (* Carriage Return Character *)
  104.   PageBreak=#138;                 (* WordStar's PageBreak Character *)
  105.  
  106. TYPE
  107.   StoragePointer=^BufferStorage;  (* The text of each page is  *)
  108.   BufferStorage=Record            (* stored in LineStore       *)
  109.     LineStore:String[128];
  110.     StorageLink:StoragePointer
  111.   End;
  112.  
  113.   PagePointer=^PageInfo;          (* Points to the beginning   *)
  114.   PageInfo=Record                 (* BufferStorage for each    *)
  115.     Start:StoragePointer;         (* text page                 *)
  116.     PageLink:PagePointer
  117.   End;
  118.  
  119.   WriteString=Char;            (* used for WriteDisk procedure *)
  120.  
  121. VAR
  122.   I,BuffCounter,PageCounter,Blocks:Byte;
  123.   Z:Integer;
  124.   Ch:Char;
  125.   InputFileName,OutputFileName:String[14];
  126.   InputFile,OutputFile:Text;
  127.   TempString:String[255];
  128.   BuffPrevious,BuffNext:StoragePointer;
  129.   PageHead,PagePrevious,PageNext:PagePointer;
  130.   HeapTop:^Integer;
  131.   InitialPass:Boolean;
  132.   Column:Array[1..20] of Integer;
  133.  
  134.   PROCEDURE AbortProgram (Code:Byte);
  135.   (* Dumps out of program due to fatal condition *)
  136.   CONST
  137.     AbortMessage:Array[1..3] of String[21]=
  138.       ('Source File not found',
  139.        'Destination disk full',
  140.        ' Page blocks overlap ');
  141.   Begin
  142.     GotoXY(1,22);ClrEOL;
  143.     WriteLn(#7,'>> Program Aborted <<');
  144.     WriteLn(AbortMessage[Code]);
  145.     Close(OutputFile);
  146.     Erase(OutputFile);
  147.     Halt
  148.   End;
  149.  
  150.  
  151.   PROCEDURE WriteDisk (InString:WriteString);
  152.   (* Writes to OutputFile and checks for disk write error *)
  153.   Begin
  154.     Write(OutputFile,InString);
  155.     If IOResult>0 then AbortProgram(2)  (* Fatal Error -- no return *)
  156.   End;
  157.  
  158.  
  159.   PROCEDURE Configuration;
  160.   (* Gets input information from user *)
  161.  
  162.     PROCEDURE DrawLine (Row:Byte);
  163.     (* Draws a dashed line across the screen at the specified ROW *)
  164.     Begin
  165.       GotoXY(1,Row);
  166.       For I:=1 to 52 do Write('-')
  167.     End;
  168.  
  169.   Begin (* Configuration *)
  170.     Repeat
  171.       ClrScr;
  172.  
  173.       GotoXY(17,1);
  174.       Write('C O L U M N S  1.2');
  175.       DrawLine(3);
  176.       DrawLine(20);
  177.  
  178.       GotoXY(1,5);
  179.       WriteLn('Enter the name of the SOURCE file');
  180.       ReadLn(InputFileName);
  181.  
  182.       GotoXY(1,9);
  183.       WriteLn('Enter the name of the DESTINATION file');
  184.       ReadLn(OutputFileName);
  185.  
  186.       GotoXY(1,13);
  187.       WriteLn('The program begins the first text block in column 1.');
  188.       WriteLn('Enter the STARTING COLUMN(S) for subsequent block(s),');
  189.       WriteLn('each separated by a space');
  190.       ReadLn(TempString);
  191.  
  192.       (* Now parse the line for each column number *)
  193.       Blocks:=1;
  194.       While Length(TempString)>0 do
  195.       Begin
  196.         While (Length(TempString)>0) and not (TempString[1] in ['0'..'9']) do
  197.           Delete(TempString,1,1);
  198.         I:=1;
  199.         If Length(TempString)>0 then
  200.         Begin
  201.           While (I<=Length(TempString)) and (TempString[I] in ['0'..'9']) do
  202.             I:=Succ(I);
  203.           Val(Copy(TempString,1,I-1),Column[Blocks],Z);
  204.           Blocks:=Succ(Blocks);
  205.           Delete(TempString,1,I);
  206.         End;
  207.       End;
  208.       WriteLn;
  209.       Write(Blocks,' Blocks, beginning at Columns: 1');
  210.       For I:=1 to Blocks-1 do Write(Column[I]:4);
  211.  
  212.  
  213.       (* Now subtract 2 from each Column since
  214.          Column actually controls the number of
  215.          SPACES inserted between the end of one
  216.          block and the beginning of the next *)
  217.       For I:=1 to Blocks do
  218.         Column[I]:=Column[I]-2;
  219.  
  220.       GotoXY(1,22);
  221.       Write('Are all entries correct? (Y/N) ');
  222.       Repeat
  223.         Read(Kbd,Ch);
  224.       Until UpCase(Ch) in ['Y','N'];
  225.     Until UpCase(Ch)='Y';
  226.  
  227.     Assign(InputFile,InputFileName);
  228.     Assign(OutputFile,OutputFileName)
  229.   End;
  230.  
  231.  
  232.   PROCEDURE InitializeFile;
  233.   (* Opens files and reads in any leading dot
  234.      commands *)
  235.   Begin
  236.     GotoXY(1,22);ClrEOL;
  237.     Write('Processing...');
  238.  
  239.     InitialPass:=True;
  240.     Reset(InputFile);
  241.     If IOResult>0 then AbortProgram(1); (* Fatal error -- no return *)
  242.     ReWrite(OutputFile);
  243.     If IOResult>0 then AbortProgram(2); (* Fatal Error -- no return *)
  244.  
  245.     Read(InputFile,Ch);
  246.     While Ch ='.' do
  247.     Begin
  248.       (* Looks for dot commands. Any such
  249.          formatting commands are written directly to the output. *)
  250.       ReadLn(InputFile,TempString);
  251.       WriteLn(OutputFile,Ch,TempString);
  252.       Read(InputFile,Ch);
  253.     End;
  254.     (* Note that Ch is now first character of the text *)
  255.   End;
  256.  
  257.   PROCEDURE ReadNWrite;
  258.   (* Reads in a set of pages and puts them side-by-side in proper columns *)
  259.  
  260.   VAR
  261.     BlockLoop:Byte;
  262.     BuffPosCount:Array[1..20] of Byte;
  263.     PageLine:Array[1..20] of StoragePointer;
  264.     PageDone,RealPage,UnderScore,BoldFace,DoubleStrike:Array [1..20] of Boolean;
  265.     AllPagesDone:Boolean;
  266.  
  267.     PROCEDURE ReadASet;
  268.     (* Reads a set of pages from the source file *)
  269.  
  270.       PROCEDURE Store (InChar:Char);
  271.       (* stores character in memory and allocates records *)
  272.       Begin
  273.         BuffCounter:=Succ(BuffCounter);
  274.         If BuffCounter>128 then  (* Create new record in memory *)
  275.         Begin
  276.           BuffPrevious:=BuffNext;
  277.           New(BuffNext);
  278.           BuffPrevious^.StorageLink:=BuffNext;
  279.           BuffCounter:=1
  280.         End;
  281.         BuffNext^.LineStore[BuffCounter]:=InChar;
  282.       End;
  283.  
  284.     Begin (* ReadASet *)
  285.       New(PageHead);
  286.       PageNext:=PageHead;
  287.       PageCounter:=0;
  288.       While (PageCounter<Blocks) and (Not EOF(InputFile)) do
  289.       Begin
  290.         PageCounter:=Succ(PageCounter);
  291.         New(BuffNext);                           (* Set up pointers to next *)
  292.         PagePrevious:=PageNext;                  (* page and initial storage*)
  293.         New(PageNext);                           (* location for each page  *)
  294.         PagePrevious^.PageLink:=PageNext;
  295.         PageNext^.Start:=BuffNext;
  296.         BuffCounter:=0;
  297.  
  298.         If InitialPass then  (* Store Ch left over from above Dot Search *)
  299.         Begin
  300.           Store(Ch);
  301.           InitialPass:=False
  302.         End;
  303.  
  304.         Repeat
  305.           Read(InputFile,Ch);
  306.           Store(Ch);
  307.         Until (EOF(InputFile)) or (Ch=PageBreak);
  308.  
  309.         If (Ch<>LF) and (Ch <> PageBreak) then (* EOF needs CR/PageBreak *)
  310.         Begin
  311.           Store(CR);
  312.           Store(PageBreak)
  313.         End
  314.         Else (* make sure last buffer character is PageBreak *)
  315.           BuffNext^.LineStore[BuffCounter]:=PageBreak
  316.       End
  317.     End;
  318.  
  319.  
  320.     PROCEDURE QueuePages;
  321.     (* Points to the beginning of the each page *)
  322.     Begin
  323.       PageNext:=PageHead^.PageLink;
  324.       For I:=1 to Blocks do
  325.       Begin
  326.         PageDone[I]:=(I>PageCounter);     (* In case the last page has no pair *)
  327.         If not PageDone[I] then
  328.         Begin
  329.           PageLine[I]:=PageNext^.Start;
  330.           PageNext:=PageNext^.PageLink
  331.         End
  332.       End
  333.     End;
  334.  
  335.  
  336.     PROCEDURE MergePages;
  337.     (* Assembles output page from the pages in memory *)
  338.     VAR
  339.       LineCharCount:Byte;
  340.  
  341.       FUNCTION SevenBit(InChar:Char):Char;
  342.       (* Strips high-bit off WordStar formatting *)
  343.       Begin
  344.         SevenBit:=Chr(Ord(InChar) And 127)
  345.       End;
  346.  
  347.       FUNCTION BuffChar(Block:Byte):Char;
  348.       (* Retrieves text character from page *)
  349.       Begin
  350.         BuffChar:=PageLine[Block]^.LineStore[BuffPosCount[Block]];
  351.         BuffPosCount[Block]:=Succ(BuffPosCount[Block]);
  352.         If BuffPosCount[Block]>128 then  (* get next BufferStorage *)
  353.         Begin
  354.           PageLine[Block]:=PageLine[Block]^.StorageLink;
  355.           BuffPosCount[Block]:=1
  356.         End
  357.       End;
  358.  
  359.       PROCEDURE ControlCheck (Block:Byte);
  360.       (* Toggles WordStar Print Controls *)
  361.       Begin
  362.         Case SevenBit(Ch) of
  363.           #19:UnderScore[Block]:=not UnderScore[Block];
  364.           #02:BoldFace[Block]:=not BoldFace[Block];
  365.           #04:DoubleStrike[Block]:=not DoubleStrike[Block]
  366.         End;
  367.  
  368.         If SevenBit(Ch) in [#06,#07,#15] then
  369.           (* printables: Phantom space, phantom rubout, non-break space *)
  370.           LineCharCount:=Succ(LineCharCount);
  371.         If SevenBit(Ch)=#08 then
  372.           (* Backspace, so decrement *)
  373.           LineCharCount:=Pred(LineCharCount)
  374.       End;
  375.  
  376.       PROCEDURE SetControls (Block:Byte);
  377.       (* Inserts WordStar print controls at the beginning and end of lines *)
  378.       Begin
  379.         If UnderScore[Block] then WriteDisk(#19);
  380.         If BoldFace[Block] then WriteDisk(#2);
  381.         If DoubleStrike[Block] then WriteDisk(#4)
  382.       End;
  383.  
  384.  
  385.  
  386.     Begin (* MergePages *)
  387.       For I:=1 to PageCounter do
  388.         BuffPosCount[I]:=1;
  389.       Repeat
  390.         LineCharCount:=0;
  391.         For BlockLoop:=1 to Blocks do
  392.         Begin
  393.           SetControls(BlockLoop);
  394.  
  395.           If PageDone[BlockLoop] then (* No text so make blank line *)
  396.           Begin
  397.             If BlockLoop=Blocks then (* end line with CR *)
  398.               WriteDisk(CR)
  399.           End
  400.           Else  (* print the text line *)
  401.           Begin
  402.             Repeat
  403.               Ch:=BuffChar(BlockLoop);
  404.               If SevenBit(Ch)<#31 then  (* might be a control toggle *)
  405.                 ControlCheck(BlockLoop)
  406.               Else
  407.                 LineCharCount:=Succ(LineCharCount); (* increases for ASCII only *)
  408.               If SevenBit(Ch)<>CR then WriteDisk(Ch);
  409.             Until SevenBit(Ch)=CR;    (* end of the line *)
  410.             SetControls(BlockLoop);
  411.  
  412.             If (BlockLoop<Blocks) and
  413.                (LineCharCount>Succ(Column[BlockLoop]))
  414.             then
  415.               AbortProgram(3);    (* Fatal Error -- no return *)
  416.  
  417.             If BlockLoop<Blocks then
  418.               Begin
  419.                 For I:=LineCharCount to Column[BlockLoop] do
  420.                   WriteDisk(' ');     (* Print spaces over to start of next page *)
  421.                 LineCharCount:=Column[BlockLoop]+1
  422.               End
  423.             Else
  424.               WriteDisk(CR);
  425.             Ch:=BuffChar(BlockLoop);  (* Checks for End of Page marker *)
  426.             PageDone[BlockLoop]:=(Ch=PageBreak)  (* No more on that page *)
  427.           End
  428.         End;
  429.         AllPagesDone:=True;
  430.         For I:=1 to Blocks do
  431.           AllPagesDone:=(AllPagesDone and PageDone[I]);
  432.         If AllPagesDone then
  433.           WriteDisk(PageBreak)   (* finish return page marker *)
  434.         Else
  435.           WriteDisk(LF);   (* finish return with normal return *)
  436.       Until AllPagesDone
  437.     End;
  438.  
  439.  
  440.  
  441.   Begin (* ReadNWrite *)
  442.     For I:=1 to Blocks do
  443.     Begin
  444.       UnderScore[I]:=False;
  445.       BoldFace[I]:=False;
  446.       DoubleStrike[I]:=False;
  447.     End;
  448.     Mark(HeapTop);
  449.     While not EOF(InputFile) do
  450.     Begin
  451.       ReadASet;
  452.       For I:=1 to Blocks do
  453.         PageDone[I]:=False;
  454.       QueuePages;   (* Point to Page beginnings *)
  455.       MergePages;   (* Pages are in queue, now put them together *)
  456.       Release(HeapTop)
  457.     End;
  458.     Close(OutputFile);
  459.     GotoXY(1,22);
  460.     WriteLn('The finished file is on <',OutputFileName,'>.')
  461.   End;
  462.  
  463.  
  464. Begin (* WS-COLUM *)
  465.   Configuration;
  466.   InitializeFile;
  467.   ReadNWrite
  468. End.