home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / lambda / soundpot / p / pamphlet.lbr / PAMPHLET.PZS / PAMPHLET.PAS
Encoding:
Pascal/Delphi Source File  |  1993-10-25  |  13.1 KB  |  402 lines

  1. PROGRAM Pamphlet;
  2.  
  3. (*          By Steve Wilcox
  4.             1215 South Osceola
  5.             Denver, CO 80219
  6.             303-936-0440
  7.  
  8.      This program will take a WordStar text file
  9.    of three pages or more and rearrange the
  10.    pages in the needed order for printing a
  11.    folded pamphlet. The program keeps track of
  12.    WordStar print control toggles to keep them
  13.    associated with only the page-half in which
  14.    they were begun.
  15.      The three user-input variables are the name
  16.    of the source file, the name of the destination
  17.    file, and the print column number that will be
  18.    the left margin for the right-hand page.
  19.      The entire source file is read into memory in
  20.    a double-tiered linked list. Each page break
  21.    is pointed to with a PagePointer, which in turn
  22.    points to the beginning of the second linked
  23.    list (BufferStorage), the actual text in that
  24.    page.
  25.      The text is stored in a series of consecutive
  26.    arbitrary 128 byte records (BufferStorage) rather
  27.    than line-by-line records which would have to
  28.    be defined much larger than typically needed.
  29.    As a result, the data is packed in memory with
  30.    very little wasted space.
  31.      If the number of pages in the file is not
  32.    divisible by four (needed since there are
  33.    two text pages on each side of the printed
  34.    page), "extra" logical pages are added to the
  35.    end.
  36.      In the WriteToDisk procedure, the PageLoop
  37.    alternately picks the highest and lowest
  38.    numbered pages (the Pagepointers). Then, again
  39.    alternately, as the PageLoop continues, those
  40.    pages are assigned to the left and right sides
  41.    of the output page.
  42.      The text is read out of memory by following
  43.    the BufferStorage linked lists for the left and
  44.    right pages until WordStar's page-end character
  45.    (#138) is encountered. The pages in the final
  46.    file are assembled by outputting corrresponding
  47.    lines from the left, then right pages with spaces
  48.    between them for the center fold. After the
  49.    output page is done, PageLoop is incremented
  50.    for the next pair of pages.
  51.      Screen prompts in this program are set for
  52.    a 52 column screen.                    *)
  53.  
  54.  
  55. {$I-}
  56. TYPE
  57.   StoragePointer=^BufferStorage;  (* The text of each page is  *)
  58.   BufferStorage=Record            (* stored in LineStore       *)
  59.     LineStore:String[128];
  60.     StorageLink:StoragePointer
  61.   End;
  62.  
  63.   PagePointer=^PageInfo;          (* Points to the beginning   *)
  64.   PageInfo=Record                 (* BufferStorage for each    *)
  65.     Start:StoragePointer;         (* text page                 *)
  66.     PageLink:PagePointer
  67.   End;
  68.  
  69.   UtilityString=String[50];
  70.  
  71. VAR
  72.   I,RightPageColumn,BuffCounter,PageCounter,Pages:Byte;
  73.   Ch:Char;
  74.   InputFileName,OutputFileName:String[14];
  75.   InputFile,OutputFile:Text;
  76.   DotHeader,TempString:UtilityString;
  77.   LPageLine,RPageLine,BuffPrevious,BuffNext:StoragePointer;
  78.   PageHead,PagePrevious,PageNext:PagePointer;
  79.  
  80.   PROCEDURE AbortProgram (Code:Byte);
  81.   (* Dumps out of program due to fatal condition *)
  82.   CONST
  83.     AbortMessage:Array[1..5] of String[22]=
  84.       ('Source File not found ',
  85.        'Source File too big   ',
  86.        'Destination disk full ',
  87.        'Page blocks overlap   ',
  88.        '3 or more pages needed');
  89.   Begin
  90.     GotoXY(1,22);ClrEOL;
  91.     WriteLn(#7,'>> Program Aborted <<');
  92.     WriteLn(AbortMessage[Code]);
  93.     Halt
  94.   End;
  95.  
  96.  
  97.   PROCEDURE Configuration;
  98.   (* Gets input information from user *)
  99.  
  100.     PROCEDURE DrawLine (Row:Byte);
  101.     (* Draws a dashed line across the screen at the specified ROW *)
  102.     Begin
  103.       GotoXY(1,Row);
  104.       For I:=1 to 52 do Write('-')
  105.     End;
  106.  
  107.   Begin (* Configuration *)
  108.     Repeat
  109.       ClrScr;
  110.  
  111.       GotoXY(19,2);
  112.       Write('P A M P H L E T');
  113.       DrawLine(3);
  114.       DrawLine(20);
  115.  
  116.       GotoXY(1,6);
  117.       WriteLn('Enter the name of the SOURCE file');
  118.       ReadLn(InputFileName);
  119.  
  120.       GotoXY(1,11);
  121.       WriteLn('Enter the name of the DESTINATION file');
  122.       ReadLn(OutputFileName);
  123.  
  124.       Repeat
  125.         GotoXY(1,16);
  126.         WriteLn('Enter the STARTING COLUMN for the right page half');
  127.         ReadLn(RightPageColumn)
  128.       Until IOResult=0;   (* Assures numeric input *)
  129.       (* now adjust RightPageColumn for the number of spaces needed to the right page *)
  130.       RightPageColumn:=RightPageColumn-2;
  131.  
  132.       GotoXY(1,22);
  133.       Write('Are all entries correct? (Y/N) ');
  134.       Read(Kbd,Ch);
  135.     Until UpCase(Ch)='Y';
  136.  
  137.     Assign(InputFile,InputFileName);
  138.     Assign(OutputFile,OutputFileName)
  139.   End;
  140.  
  141.   PROCEDURE ReadToMemory;
  142.   (* Reads source file into memory, keeping track
  143.      of page breaks and setting pointers to page
  144.      starts in memory *)
  145.   Begin
  146.     GotoXY(1,22);ClrEOL;
  147.     Write('Processing...');
  148.     Reset(InputFile);
  149.     If IOResult>0 then AbortProgram(1); (* Fatal error -- no return *)
  150.  
  151.     New(PageHead);
  152.     PageNext:=PageHead;
  153.     PageCounter:=0;
  154.  
  155.     DotHeader:='';
  156.     Read(InputFile,Ch);
  157.     While Ch='.' do
  158.     (* if its a period, its a dot command *)
  159.     Begin
  160.       ReadLn(InputFile,TempString);                (* Saves any initial *)
  161.       DotHeader:=DotHeader+Ch+TempString+#13#10;   (* dot commands or   *)
  162.       Read(InputFile,Ch)                           (* print controls    *)
  163.     End;                                           (* in DotHeader.     *)
  164.     (* Ch is now first character of text *)
  165.  
  166.     While not EOF(InputFile) do
  167.     Begin
  168.       New(BuffNext);                           (* Set up pointers to next *)
  169.       PagePrevious:=PageNext;                  (* page and initial storage*)
  170.       New(PageNext);                           (* location for each page  *)
  171.       PagePrevious^.PageLink:=PageNext;
  172.       PageNext^.Start:=BuffNext;
  173.       BuffCounter:=0;
  174.       PageCounter:=Succ(PageCounter);
  175.  
  176.       If PageCounter=1 then   (* Stores Ch from above Dot Command search *)
  177.       Begin
  178.         BuffNext^.LineStore[1]:=Ch;
  179.         BuffCounter:=1
  180.       End;
  181.  
  182.       Repeat
  183.         BuffCounter:=Succ(BuffCounter);
  184.         Read(InputFile,Ch);
  185.         If Ch=#30 then Ch:=#45; (* change "soft hyphen to "hard" *)
  186.         BuffNext^.LineStore[BuffCounter]:=Ch;
  187.         If BuffCounter>127 then  (* Create new record in memory *)
  188.         Begin
  189.           If (MemAvail<128) and (MemAvail>=0) then
  190.             AbortProgram(2); (* Fatal -- no return *)
  191.           BuffPrevious:=BuffNext;
  192.           New(BuffNext);
  193.           BuffPrevious^.StorageLink:=BuffNext;
  194.           BuffCounter:=0
  195.         End;
  196.       Until
  197.         (EOF(InputFile))
  198.       or
  199.         (BuffNext^.LineStore[BuffCounter]=#138); (* WordStar's Page End *)
  200.       BuffNext^.LineStore[BuffCounter]:=#138     (* Sets page break at EOF *)
  201.     End;
  202.     If PageCounter<3 then AbortProgram(5);
  203.     If PageCounter Mod 4 >0 then
  204.       Pages:=PageCounter+(4-PageCounter Mod 4)  (* Rounds up to even 4 pages *)
  205.     Else
  206.       Pages:=PageCounter;
  207.     Close(InputFile)
  208.   End;
  209.  
  210.  
  211.   PROCEDURE WriteToDisk;
  212.   (* Combines pages in proper order and writes to disk *)
  213.   TYPE
  214.     LeftRight=(L,R);
  215.  
  216.   VAR
  217.     LBuffPosCount,RBuffPosCount,PageLoop:Byte;
  218.     LPageDone,RPageDone,RealPage:Boolean;
  219.     UnderScore,BoldFace,DoubleStrike:Array [LeftRight] of Boolean;
  220.  
  221.     PROCEDURE WriteDisk (InString:UtilityString);
  222.     (* Writes to OutputFile and checks for disk write error *)
  223.     Begin
  224.       Write(OutputFile,InString);
  225.       If IOResult>0 then AbortProgram(3)  (* Fatal Error -- no return *)
  226.     End;
  227.  
  228.     PROCEDURE SetHighPage;
  229.     (* Finds pointer to highest page not yet used *)
  230.     Begin
  231.       PageNext:=PageHead;
  232.       RealPage:=(Pages-PageLoop<PageCounter); (* "extra" pages are not real *)
  233.       For I:=1 to (Pages-PageLoop)+1 do
  234.         If I<=PageCounter then         (* "extra" pages don't have pointers *)
  235.           PageNext:=PageNext^.PageLink;
  236.       If Odd(PageLoop) then            (* Checks for "extra" end page and  *)
  237.         LPageDone:=not RealPage        (* assigns them to the proper side. *)
  238.       Else
  239.         RPageDone:=not RealPage;
  240.  
  241.       If RealPage then                 (* If PageLoop is odd then the high *)
  242.       Begin                            (* page goes on the left. If it is  *)
  243.         If Odd(PageLoop) then          (* even, it goes on the right.      *)
  244.           LPageLine:=PageNext^.Start
  245.         Else
  246.           RPageLine:=PageNext^.Start
  247.       End
  248.     End;
  249.  
  250.     PROCEDURE SetLowPage;
  251.     (* Find pointer to lowest page not yet used *)
  252.     Begin
  253.       PageNext:=PageHead;
  254.       For I:=1 to PageLoop do
  255.         PageNext:=PageNext^.PageLink;
  256.       If Odd(PageLoop) then            (* If PageLoop is odd then the low  *)
  257.         RPageLine:=PageNext^.Start     (* page goes on the right. If it is *)
  258.       Else                             (* even, it goes on the left.       *)
  259.         LPageline:=PageNext^.Start
  260.     End;
  261.  
  262.     PROCEDURE MergePages;
  263.     (* Assembles output page from the chosen right and left pages *)
  264.     VAR
  265.       LineCharCount:Byte;
  266.  
  267.       FUNCTION SevenBit(InChar:Char):Char;
  268.       (* Strips high-bit off WordStar formatting *)
  269.       Begin
  270.         SevenBit:=Chr(Ord(InChar) and 127)
  271.       End;
  272.  
  273.       FUNCTION LBuffChar:Char;
  274.       (* Retrieves text character from left page *)
  275.       Begin
  276.         LBuffChar:=LPageLine^.LineStore[LBuffPosCount];
  277.         LBuffPosCount:=Succ(LBuffPosCount);
  278.         If LBuffPosCount>128 then  (* get next BufferStorage *)
  279.         Begin
  280.           LPageLine:=LPageLine^.StorageLink;
  281.           LBuffPosCount:=1
  282.         End
  283.       End;
  284.  
  285.       FUNCTION RBuffChar:Char;
  286.       (* Retrieves text character from right page *)
  287.       Begin
  288.         RBuffChar:=RPageLine^.LineStore[RBuffPosCount];
  289.         RBuffPosCount:=Succ(RBuffPosCount);
  290.         If RBuffPosCount>128 then  (* get next BufferStorage *)
  291.         Begin
  292.           RPageLine:=RPageLine^.StorageLink;
  293.           RBuffPosCount:=1
  294.         End
  295.       End;
  296.  
  297.       PROCEDURE ControlCheck (Side:LeftRight);
  298.       (* Toggles WordStar Print Controls *)
  299.       Begin
  300.         Case SevenBit(Ch) of
  301.           #19:UnderScore[Side]:=not UnderScore[Side];
  302.           #02:BoldFace[Side]:=not BoldFace[Side];
  303.           #04:DoubleStrike[Side]:=not DoubleStrike[Side]
  304.         End
  305.       End;
  306.  
  307.       PROCEDURE SetControls (Side:LeftRight);
  308.       (* Inserts WordStar print controls at the beginning and end of lines *)
  309.       Begin
  310.         If UnderScore[Side] then WriteDisk(#19);
  311.         If BoldFace[Side] then WriteDisk(#2);
  312.         If DoubleStrike[Side] then WriteDisk(#4)
  313.       End;
  314.  
  315.  
  316.  
  317.     Begin (* MergePages *)
  318.       LBuffPosCount:=1;
  319.       RBuffPosCount:=1;
  320.       Repeat
  321.         SetControls(L);
  322.         LineCharCount:=0;
  323.  
  324.         If LPageDone then (* No text so print a blank line *)
  325.         Begin
  326.           For I:=1 to RightPageColumn+1 do
  327.             WriteDisk(' ');
  328.           LineCharCount:=RightPageColumn
  329.         End
  330.         Else  (* print the text line *)
  331.         Begin
  332.           Repeat
  333.             Ch:=LBuffChar;
  334.             If SevenBit(Ch)<#32 then  (* might be a control toggle *)
  335.               ControlCheck(L)
  336.             Else
  337.               LineCharCount:=Succ(LineCharCount); (* increases for ASCII only *)
  338.             If SevenBit(Ch)<>#13 then WriteDisk(Ch);
  339.           Until SevenBit(Ch)=#13;    (* end of the line *)
  340.           SetControls(L);
  341.           If LineCharCount>Succ(RightPageColumn) then
  342.             AbortProgram(4);    (* Fatal Error -- no return *)
  343.           For I:=LineCharCount to RightPageColumn do
  344.             WriteDisk(' ');     (* Print spaces over to start of right page *)
  345.           Ch:=LBuffChar;        (* Checks for End of Page marker *)
  346.           LPageDone:=(Ch=#138)  (* No more on Left Page *)
  347.         End;
  348.  
  349.         If RPageDone then   (* No text, so terminate line *)
  350.           WriteDisk(#13#10)
  351.         Else    (* Print the text line *)
  352.         Begin
  353.           SetControls(R);
  354.           Repeat
  355.             Ch:=RBuffChar;
  356.             If SevenBit(Ch)<#32 then   (* might be a control character *)
  357.               ControlCheck(R);
  358.             If SevenBit(Ch)=#13 then SetControls(R);
  359.             WriteDisk(Ch);
  360.             RPageDone:=(Ch=#138); (* No more on Right Page *)
  361.           Until SevenBit(Ch)=#10  (* End of the line *)
  362.         End;
  363.       Until LPageDone and RPageDone
  364.     End;
  365.  
  366.  
  367.  
  368.   Begin (* WriteToDisk *)
  369.     UnderScore[L]:=False;
  370.     UnderScore[R]:=False;
  371.     BoldFace[L]:=False;
  372.     BoldFace[R]:=False;
  373.     DoubleStrike[L]:=False;
  374.     DoubleStrike[R]:=False;
  375.  
  376.     ReWrite(OutputFile);
  377.     If IOResult>0 then AbortProgram(3); (* Fatal Error -- no return *)
  378.     WriteDisk(DotHeader);  (* Begins output file with original dot commands *)
  379.  
  380.     For PageLoop:=1 to Pages div 2 do (* Sets up a pair of pages per loop *)
  381.     Begin
  382.       LPageDone:=False;
  383.       RPagedone:=False;
  384.  
  385.       SetHighPage; (* Queues up the high numbered page *)
  386.       SetLowPage;  (* Queues up the low numbered page  *)
  387.  
  388.       MergePages   (* Pages are in queue, now put them together *)
  389.  
  390.     End;
  391.     Close(OutputFile);
  392.     GotoXY(1,21);
  393.     WriteLn('The finished file is on <',OutputFileName,'>. The pages');
  394.     WriteLn('may now be printed front-back, front-back, in order.')
  395.   End;
  396.  
  397.  
  398. Begin (* PAMPHLET *)
  399.   Configuration;
  400.   ReadToMemory;
  401.   WriteToDisk
  402. End.