home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / IPM_CODE.ZIP / IPM.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1985-12-07  |  38.1 KB  |  1,329 lines

  1. { Author: E. Dong - Version 1.07 - Nov 07, 1984 - 1:15pm }
  2. program ivy_league_project_mgr;
  3. const
  4.   MaxDigits = 6;        {IMPLEMENTATION DEPENDENT}
  5.   CONSOLE   = 'con:';   {IMPLEMENTATION DEPENDENT}
  6.   viewport  = 14;       {IMPLEMENTATION DEPENDENT}
  7.   MaxValue  = 100;
  8. type
  9.   textstring = string[255];
  10.   CharSet    = set of char;
  11.   Values     = 1..MaxValue;
  12.   TaskTable  = RECORD
  13.                TaskName : string[8];
  14.                TaskText : textstring;
  15.                BegNode  : integer;
  16.                EndNode  : integer;
  17.                Duration : real;
  18.                Cost     : real;
  19.                end;
  20. var
  21.   CmdCh, ch      : char;
  22.   Project        : array [Values] of TaskTable;
  23.   Start, Finish  : array [Values] of real;
  24.   Activities     : integer;
  25.   Activity       : integer;
  26.   TotalCost      : real;
  27.   PathLen        : real;
  28.   Filein,Fileout : text;
  29.   InputFile      : textstring;
  30.   OutputFile     : textstring;
  31.   CurrFile       : textstring;
  32.   ProjectName    : textstring;
  33.   OkToGo         : boolean;
  34.  
  35. procedure debug(instr: textstring);
  36. var
  37.   ch : char;
  38. begin
  39.   writeln(instr);
  40.   read(kbd,ch);
  41. end;
  42.  
  43. function Lineout(instr: textstring; linelen: integer): textstring;
  44. begin
  45.   if length(instr) <= linelen
  46.      then Lineout := instr
  47.      else Lineout := copy(instr,1,linelen);
  48. end;
  49.  
  50. function LLIMIT(limit,other : integer): integer;
  51. begin
  52.   if limit <= other
  53.      then LLIMIT := limit
  54.      else LLIMIT := other;
  55. end;
  56.  
  57. function ToSTRING(num: integer): textstring;
  58. var
  59.   ch1, ch2 : char;
  60. begin
  61.   ch1 := chr(ord('0') + (num div 10));
  62.   ch2 := chr(ord('0') + (num - 10 * (num div 10)));
  63.   ToSTRING := ch1 + ch2;
  64. end;
  65.  
  66. procedure SortCPM;
  67. var
  68.   i, j     : integer;
  69.   SWITCHED : boolean;
  70.   TempProj : TaskTable;
  71. begin
  72.   SWITCHED := FALSE;
  73.   for i := 1 to Activities-1 do begin
  74.     for j := i+1 to Activities do begin
  75.         if ((Project[i].BegNode > Project[j].BegNode) or
  76.            ((Project[i].BegNode = Project[j].BegNode) and
  77.             (Project[i].EndNode > Project[j].EndNode)))
  78.            then begin
  79.                 TempProj    := Project[i];
  80.                 Project[i]  := Project[j];
  81.                 Project[j]  := TempProj;
  82.                 SWITCHED    := TRUE;
  83.                 end;
  84.        end;
  85.   end;
  86.   if SWITCHED then SortCPM;
  87. end;
  88.  
  89. procedure DoNothing;
  90. begin
  91.   ;
  92. end;
  93. procedure Introduction;
  94. begin
  95.   LowVideo;
  96.   writeln('Ivy League Project Manager (IPM) V1.07 - (c) 1984 by Edward V. Dong');
  97.   writeln('---------------------- All Rights Reserved -------------------------');
  98.   HighVideo;
  99.   writeln('Adapted from PRACTICAL PASCAL PROGRAMS, Osborne/McGraw-Hill, by Greg');
  100.   writeln('Davidson, (c) 1982 by  McGraw-Hill, Inc.  Written  in  Turbo  Pascal');
  101.   writeln('with many extensive modifications, including PERT graphics.');
  102.   writeln;
  103.   writeln('Current commands are displayed on line 25 of your screen.  Select  a');
  104.   writeln('command by typing the first letter of the command option.   Pressing');
  105.   writeln('the return key is not necessary.   A BEEP! means an  illegal  entry.');
  106. end;
  107.  
  108. procedure EraseLine(row : integer);
  109. var
  110.   i : integer;
  111. begin
  112.   if row > 0 then gotoxy(1,row);
  113.   for i := 1 to 79 do write(' ');
  114.   for i := 1 to 79 do write(chr(8));
  115. end;
  116.  
  117. function AllCaps(instr : textstring): textstring;
  118. var
  119.   i : integer;
  120. begin
  121.   for i := 1 to length(instr) do instr[i] := UpCase(instr[i]);
  122.   AllCaps := instr;
  123. end;
  124.  
  125. procedure CapLine(row: integer; cmdstring: textstring);
  126. var
  127.   i : integer;
  128. begin
  129.   EraseLine(row); LowVideo;
  130.   for i := 1 to length(cmdstring) do begin
  131.       if cmdstring[i] in ['A'..'Z'] then HighVideo;
  132.       write(cmdstring[i]);
  133.       LowVideo;
  134.       end;
  135. end;
  136.  
  137. procedure Commands(var ch: char; cmdstring: textstring);
  138. begin
  139.   CapLine(25, 'Commands: '+cmdstring); HighVideo;
  140.   read(kbd,ch); ch := UpCase(ch);
  141. end;
  142.  
  143. procedure PageTitle(instring : textstring);
  144. var
  145.   i : integer;
  146. begin
  147.   LowVideo; write(Fileout,'PROJECT: ');
  148.   HighVideo; write(Fileout,ProjectName);
  149.   LowVideo; writeln(Fileout,' -- ',instring);
  150.   for i := 1 to 78 do write(Fileout,'-'); HighVideo;
  151.   writeln(Fileout);
  152. end; { PageTitle }
  153.  
  154. procedure ident(instr: textstring);
  155. var
  156.   i : integer;
  157. begin
  158.   EraseLine(21);
  159.   for i:=length(instr) to 78 do instr := instr + '-';
  160.   write(instr);
  161. end;
  162.  
  163. procedure Repaint(instr: textstring);
  164. begin
  165.   if OutputFile = CONSOLE
  166.      then clrscr;
  167.   PageTitle(instr);
  168. end;
  169.  
  170. procedure MainMenu;
  171. var
  172.   filestr : textstring;
  173. begin
  174.   clrscr;
  175.   assign(fileout,CONSOLE); rewrite(fileout);
  176.   if CurrFile <> CONSOLE
  177.      then filestr := 'FILE: ' + AllCaps(CurrFile)
  178.      else filestr := 'FILE: CONSOLE';
  179.   PageTitle(filestr);
  180.   Introduction;
  181. end;
  182.  
  183. procedure window(instring: textstring);
  184. var
  185.   tempstr : textstring;
  186.   i, j    : integer;
  187. begin
  188.   for i := viewport to 24 do EraseLine(i);
  189.   gotoxy(1,viewport);
  190.   tempstr := instring;
  191.   for i := length(instring) to 78 do tempstr := tempstr + '-';
  192.   writeln(tempstr);
  193. end;
  194.  
  195. function Read1Char(okchars: CharSet): char;
  196. const
  197.   BEL = 7; { ASCII char for dinging the user }
  198. var
  199.   c : char;
  200. begin
  201.   repeat
  202.     read(kbd,c);
  203.     if not (c in okchars)
  204.        then c := UpCase(c);
  205.     if not (c in okchars)
  206.        then write(chr(BEL));
  207.   until c in okchars;
  208.   writeln;
  209.   read1char := c;
  210. end; { read1char }
  211.  
  212. function Exist(filename: textstring) : boolean;
  213. var
  214.  fil : file;
  215. begin
  216.  assign(fil,filename);
  217.  {$I-}
  218.  reset(fil);
  219.  {$I+}
  220.  if IOresult <> 0
  221.     then Exist := FALSE
  222.     else Exist := TRUE;
  223. end; { Exist }
  224.  
  225. procedure GetOutputName;
  226. var
  227.   Fileok : boolean;
  228. begin
  229.   Fileok := FALSE;
  230.   repeat
  231.     EraseLine(0); write('Enter filename: '); readln(OutputFile);
  232.     if Exist(OutputFile)
  233.        then begin
  234.             EraseLine(0);
  235.             write('--> File ',OutputFile,' exists: Overwrite? (Y/N) ');
  236.             if read1char(['Y','N']) = 'Y' then Fileok := TRUE;
  237.             end
  238.        else Fileok := TRUE;
  239.   until Fileok = TRUE;
  240. end;
  241.  
  242. procedure InitOutput;
  243. begin
  244.   GetOutputName;
  245.   assign(fileout,OutputFile);
  246.   rewrite(fileout);
  247. end;
  248.  
  249. function ReadInt(var num:integer; low, high : integer): boolean;
  250. var i : char;
  251. begin
  252.   if InputFile = CONSOLE
  253.      then readln(i)
  254.      else readln(filein,i);
  255.   if (((i >= '0') or (i <= '9')) and ((i >= chr(low)) and (i <= chr(high))))
  256.      then begin
  257.          num := ord(i) - ord('0');    { input for valid integers... }
  258.          Readint := TRUE;
  259.          end
  260.      else Readint := FALSE;
  261. end;
  262.  
  263. function ReadStr(var Instring : textstring): boolean;
  264. begin
  265.   if InputFile = CONSOLE
  266.      then readln(Instring)
  267.      else readln(filein,Instring);
  268.   if length(Instring) = 0
  269.      then ReadStr := FALSE
  270.      else ReadStr := TRUE;
  271. end;
  272.  
  273. function ReadReal(var x:real): boolean;
  274. begin
  275.   if InputFile = CONSOLE
  276.      then readln(x)
  277.      else readln(filein,x);
  278.   ReadReal := TRUE;
  279. end;
  280.  
  281. procedure RecordHandler(instr : textstring; var FileOK : boolean);
  282. label
  283.   quit;
  284. var
  285.   ProjectFile   : file of TaskTable;
  286.   TempJob       : TaskTable;
  287.   filename      : textstring;
  288.   i             : integer;
  289. begin
  290.   instr := AllCaps(instr);
  291.   FileOK := FALSE;
  292.   if instr = 'OUTPUT'
  293.      then begin
  294.           EraseLine(0);
  295.           write('Enter filename: '); readln(filename);
  296.             if Exist(filename)
  297.                then begin
  298.                       EraseLine(0);
  299.                       write('File exists. Overwrite? (Y/N) ');
  300.                       if Read1Char(['Y','N']) <> 'Y' then goto quit;
  301.                     end;
  302.             CurrFile := filename;
  303.             assign(ProjectFile,filename);
  304.             rewrite(ProjectFile);
  305.             FileOK := TRUE;
  306.             TempJob.TaskText := ProjectName;
  307.             TempJob.Cost     := (Activities);
  308.             write(ProjectFile,TempJob);
  309.             for i := 1 to Activities do write(ProjectFile,Project[i]);
  310.             close(ProjectFile);
  311.           end
  312.      else begin
  313.             EraseLine(0); write('Enter filename: '); readln(filename);
  314.             if NOT Exist(filename) then goto quit;
  315.             CurrFile := filename;
  316.             assign(ProjectFile,filename);
  317.             reset(ProjectFile);
  318.             FileOK := TRUE;
  319.             seek(ProjectFile,0);
  320.             read(ProjectFile,TempJob);
  321.             ProjectName := TempJob.TaskText;
  322.             Activities   := trunc(TempJob.Cost);
  323.             for i := 1 to Activities do
  324.                 begin
  325.                   seek(ProjectFile,i);
  326.                   read(ProjectFile,Project[i]);
  327.                 end;
  328.             close(ProjectFile);
  329.           end;
  330. quit:
  331. end;
  332.  
  333. procedure SaveData;
  334. var
  335.   FileOK   : boolean;
  336. begin
  337.   EraseLine(0);
  338.   write('Save Network Data to Disk File? (Y/N) ');
  339.   if read1char(['Y','N']) = 'Y'
  340.      then RecordHandler('OUTPUT',FileOK);
  341. end; {SaveData}
  342.  
  343. procedure LotusCPM;
  344. var
  345.   i        : integer;
  346. begin
  347.   if OutputFile <> CONSOLE then begin
  348.      writeln(fileout,'"',ProjectName,'"');              { Project Title  }
  349.      writeln(fileout,'"No. Tasks = ",',Activities);     { # of Activities }
  350.      writeln(fileout,'"TaskNo"','"TaskName"','"BegNode"','"EndNode"',
  351.                      '"Duration"','"Cost"','"Description"');
  352.      for i := 1 to Activities do
  353.          begin
  354.            write(fileout,i,',');                        { index          }
  355.            write(fileout,',"',Project[i].TaskName,'"'); { Task Name      }
  356.            write(fileout,Project[i].BegNode,',');       { Starting Node  }
  357.            write(fileout,Project[i].EndNode,',');       { Finishing Node }
  358.            write(fileout,Project[i].Duration,',');      { Duration       }
  359.            write(fileout,Project[i].Cost,',');          { Cost           }
  360.            writeln(fileout,'"',Project[i].TaskText,'"');{ Task Text      }
  361.          end; { for i := 1 to Activities}
  362.     close(fileout);
  363.     OutputFile := CONSOLE;
  364.     end;
  365. end; { LotusCPM }
  366.  
  367. procedure Edit(xwindow, ywindow: integer);
  368. var
  369.   EditChar   : char;
  370.   EndOfPage  : integer;
  371.   NextPage   : integer;
  372.   RowOffset  : integer;
  373.   i, j, k    : integer;
  374.   TempStr    : textstring;
  375. procedure EditInt(instr: textstring; var item: integer; low, high: integer);
  376. begin
  377.   repeat
  378.     EraseLine(24); write('Enter ',instr,': ');
  379.   until ReadInt(item,low,high);
  380. end;
  381. procedure EditReal(instr: textstring; var item: real);
  382. begin
  383.   repeat
  384.     EraseLine(24); write('Enter ',instr,': ');
  385.   until ReadReal(item);
  386. end;
  387. procedure EditText(instr: textstring; var item: textstring);
  388. begin
  389.   repeat
  390.     EraseLine(24); write('Enter ',instr,': ');
  391.   until ReadStr(item);
  392. end;
  393. procedure GetNewEndNode;
  394. var
  395.   NewEndNode : integer;
  396. begin
  397.   EditInt('End Node',NewEndNode,0,maxint);
  398.   if ((NewEndNode >= Activities) or (NewEndNode <= Project[Activity].BegNode))
  399.      then begin
  400.           EraseLine(24); write('ILLEGAL ENTRY: Retry...');
  401.           end
  402.      else Project[Activity].EndNode := NewEndNode;
  403. end;
  404. procedure FlipPage(instr: textstring; var NextPage: integer; ywindow: integer);
  405. begin
  406.   instr := AllCaps(instr);
  407.   if instr = 'PGDN'
  408.      then begin {Page Down}
  409.           NextPage := NextPage + (19 - ywindow);
  410.           if NextPage > Activities
  411.              then NextPage := Activities;
  412.           end
  413.      else begin {Page Up}
  414.           NextPage := NextPage - (19 - ywindow);
  415.           if NextPage < 0
  416.              then NextPage := 0;
  417.           end;
  418. end;
  419. procedure KillTask(Activity: integer);
  420. var
  421.   i       : integer;
  422. begin
  423.   EraseLine(23); write('Task '); LowVideo;
  424.   write(Project[Activity].TaskName);
  425.   HighVideo; write(' DELETED.');
  426.   for i := Activity to Activities do Project[i] := Project[i+1];
  427.   Activities := Activities - 1;
  428.   SortCPM;
  429. end;
  430. function IndexTask(instr: textstring): integer;
  431. var
  432.   i,j : integer;
  433. begin
  434.   i := 0; j := 0;
  435.   REPEAT
  436.     i := succ(i);
  437.     if AllCaps(Project[i].TaskName) = AllCaps(instr) then j := i;
  438.   UNTIL ((i = Activities) or (j <> 0));
  439.   IndexTask := j;
  440. end;
  441. procedure ChangeName;
  442. var
  443.   TempStr : textstring;
  444. begin
  445.   CapLine(23,'SELECT: task Name  task Description');
  446.   if Read1Char(['N','D']) = 'N'
  447.      then begin
  448.           EditText('Task Name',TempStr);
  449.           Project[Activity].TaskName := TempStr;
  450.           end
  451.      else begin
  452.           EditText('Task Description',TempStr);
  453.           Project[Activity].TaskText := TempStr;
  454.           end;
  455.    EraseLine(23);
  456. end;
  457. procedure InsertNode;
  458. label
  459.   DoneNewNode;
  460. var
  461.   AfterNode, i : integer;
  462.   instr        : textstring;
  463. begin
  464.   i := 0;
  465.   REPEAT
  466.     EraseLine(23); write('What task goes to this new node? ');
  467.     EraseLine(24); write('Enter existing task name (or return to abort): ');
  468.     readln(instr);
  469.     if length(instr) = 0
  470.        then i := -1
  471.        else i := IndexTask(instr);
  472.   UNTIL (i <> 0);
  473.   EraseLine(23); EraseLine(24); write('Task Index = ',i);
  474.   if length(instr) = 0 then goto DoneNewNode;
  475.   AfterNode := Project[IndexTask(instr)].EndNode;
  476.   for i := IndexTask(instr)+1 to Activities do begin
  477.       with Project[i] do begin
  478.            if BegNode >= AfterNode then BegNode := BegNode + 1;
  479.            if EndNode >= AfterNode then EndNode := EndNode + 1;
  480.            end;
  481.       end;
  482. DoneNewNode:
  483. end;
  484. procedure InsertTask;
  485. var
  486.   NewTask : textstring;
  487. begin
  488.  with Project[Activities+1] do begin
  489.    REPEAT
  490.      EraseLine(24); write('Enter NAME of new task: ');
  491.    UNTIL ReadStr(NewTask);
  492.    if length(NewTask) <= 8
  493.       then TaskName := NewTask
  494.       else TaskName := copy(NewTask,1,8);
  495.    REPEAT
  496.      EraseLine(24); write('Start_node? ');
  497.    UNTIL ReadInt(BegNode,0,Activities);
  498.    REPEAT
  499.      EraseLine(24); write('End_node? ');
  500.    UNTIL ReadInt(EndNode,0,Activities+1);
  501.    EraseLine(24); write('New task ',TaskName);
  502.    write(' from Node ',BegNode:2,' to ',EndNode:2);
  503.    write('--> OK to add new task? (Y/N) ');
  504.    if read1char(['Y','N']) = 'Y'
  505.       then Activities := Activities + 1;
  506.    end;
  507. end;
  508. procedure InsertTaskNode;
  509. var
  510.   ch : char;
  511. begin
  512.   CapLine(24,'Insert: new_Node new_Task Abort');
  513.   ch := Read1Char(['N','T','A']);
  514.   if ch = 'N' then InsertNode
  515.   else if ch = 'T' then InsertTask;
  516. end;
  517. procedure EditWindow(NextPage,ywindow,RowOffset: integer);
  518. begin
  519.   EndOfPage := LLIMIT(Activities,(NextPage - ywindow + 20));
  520.   j := 1;
  521.   for i := 1+NextPage to EndOfPage do begin
  522.       gotoxy(1,j+RowOffset); j := succ(j);
  523.       if i = Activity then LowVideo else HighVideo;
  524.       write(i:5,Project[i].BegNode:5, Project[i].EndNode:5);
  525.       write(Project[i].Duration:8:2, Project[i].Cost:MaxDigits+1:2);
  526.       write(Project[i].TaskName:10);
  527.       writeln(' ',Lineout(Project[i].TaskText,38));
  528.       HighVideo;
  529.       end;
  530. end;
  531. procedure EditGlobal(EditChar: char; var Activity, NextPage, ywindow: integer);
  532. begin
  533.   case EditChar of
  534.     'T': EditInt('Task Number',Activity,1,Activities);
  535.     'U': FlipPage('PGUP',NextPage,ywindow);
  536.     'G': FlipPage('PGDN',NextPage,ywindow);
  537.     'I': InsertTaskNode;
  538.     'P': begin
  539.            EditText('Project Title', TempStr);
  540.            Project[1].TaskText := TempStr;
  541.            ProjectName := Project[1].TaskText;
  542.            if ywindow = 1 then begin
  543.               gotoxy(1,1);
  544.               PageTitle('Editing');
  545.               end;
  546.          end;
  547.     end;
  548.   if ((Activity=0) and (Pos(EditChar,'IP')>0)) then Activity := 1;
  549. end;
  550. procedure EditTask(EditChar: char; Activity: integer);
  551. begin
  552.   case EditChar of
  553.     'S': EditInt('Start Node', Project[Activity].BegNode, 0, maxint);
  554.     'E': GetNewEndNode;
  555.     'D': EditReal('Duration',Project[Activity].Duration);
  556.     'C': EditReal('Cost',Project[Activity].Cost);
  557.     'N': ChangeName;
  558.     'K': KillTask(Activity);
  559.     end;
  560. end;
  561.  
  562. begin
  563.   if ywindow = 1
  564.      then begin
  565.           Repaint('Editing');
  566.           RowOffset := 4;
  567.           end
  568.      else begin
  569.           for i := ywindow to 20 do EraseLine(i);
  570.           EraseLine(ywindow);
  571.           RowOffset := ywindow + 1;
  572.           end;
  573.   writeln('Task ':5,'Start':5,'End':5);
  574.   writeln('Node':10,'Node':5,'Duration':10,'  Cost',' Name/Description');
  575.   InputFile := CONSOLE;
  576.   Activity := 0;
  577.   NextPage := 0;
  578.   repeat
  579.     EditWindow(NextPage,ywindow,RowOffset);
  580.     CapLine(24,'          Task_no Start_node End_node Name Duration Cost');
  581.     Commands(EditChar,'Insert Kill Get_next_page Up_page Project Quit');
  582.     if Pos(EditChar,'TPUGI') > 0
  583.        then EditGlobal(EditChar, Activity, NextPage, ywindow)
  584.        else if ((Activity<>0) and (Pos(EditChar,'KSEDNC')>0))
  585.             then EditTask(EditChar,Activity);
  586.   until EditChar = 'Q';
  587.   EraseLine(24);    { erase auxiliary command line from display }
  588.   if Activity <> 0
  589.      then begin
  590.            SortCPM;
  591.             EraseLine(23);
  592.             EraseLine(24);
  593.             EraseLine(22);
  594.             SaveData;
  595.           end;
  596. end;
  597.  
  598. procedure GetData;
  599. var
  600.   i      : integer;
  601.   FileOK : boolean;
  602. begin
  603.   window('Project Setup');
  604.   writeln;
  605.   Fileok := FALSE;
  606.   write('Input from Console? (Y/N) ');
  607.   InputFile := CONSOLE; CurrFile := InputFile;
  608.   if read1char(['Y','N']) = 'Y'
  609.      then begin
  610.             repeat
  611.               writeln('Enter Project Title/Description: ');
  612.             until ReadStr(ProjectName);
  613.             repeat
  614.               write('Enter Number of Tasks on this network: ');
  615.             until ReadInt(Activities,0,maxint);
  616.           for i := 1 to Activities do
  617.             begin
  618.               Project[i].TaskName := 'Task'+ToSTRING(i);
  619.               Project[i].BegNode := 0;
  620.               Project[i].EndNode := 0;
  621.               Project[i].Duration := 0;
  622.               Project[i].Cost := 0;
  623.             end;
  624.           Edit(1,1);
  625.           end
  626.      else RecordHandler('INPUT',FileOK);
  627.   for i := 1 to Activities do begin
  628.       Start[i] := 0.0;
  629.       Finish[i] := 0.0;
  630.       end;
  631.   SortCPM;
  632. end; {GetData}
  633.  
  634. procedure FindEarlyStart;
  635. var
  636.   i : integer;
  637. begin
  638.   for i := 1 to Activities do
  639.     begin
  640.       with Project[i] do begin
  641.          if Start[EndNode] < Start[BegNode] + Duration
  642.             then Start[EndNode] := Start[BegNode] + Duration;
  643.          end; { with...}
  644.     end; { for i ... do }
  645.   with Project[Activities] do Finish[EndNode] := Start[EndNode];
  646. end; { FindEarlyStart}
  647.  
  648. procedure FindLateFinish;
  649. var
  650.   i : integer;
  651. begin
  652.   for i := Activities downto 1 do begin
  653.     with Project[i] do begin
  654.          if (Finish[BegNode] = 0) or
  655.             (Finish[BegNode] > Finish[EndNode] - Duration)
  656.             then Finish[BegNode] := Finish[EndNode] - Duration;
  657.          end;
  658.     end;
  659. end; { FindLateFinish }
  660.  
  661. procedure CalculateSlackTime;
  662. var
  663.   JobLen : real;
  664.   i      : integer;
  665. begin
  666.   Repaint('Calculated Results');
  667.   for i := 1 to Activities do begin
  668.       Start[i] := 0.0;
  669.       Finish[i] := 0.0;
  670.       end;
  671.   FindEarlyStart;
  672.   FindLateFinish;
  673.   writeln(Fileout,'Task ':8,'Start':5,'End':5,'Early':10,'Late':10);
  674.   writeln(Fileout,'Node':13,'Node':5,'Start':10,'Finish':10,
  675.                   'Duration':10,'  Slack    Cost');
  676.   for i := 1 to Activities do begin
  677.     with Project[i] do begin
  678.       write(Fileout,TaskName:8,BegNode:5);
  679.       write(Fileout,EndNode:5, Start[BegNode]:10:2);
  680.       write(Fileout,Finish[EndNode]:10:2, Duration:8:2);
  681.       JobLen := Finish[EndNode]- Start[BegNode] - Duration;
  682.       if JobLen > 0 then write(Fileout,Cost:10:2)
  683.                     else if PathLen < Finish[EndNode]
  684.                             then begin
  685.                                  write(Fileout,'  CRITICAL');
  686.                                  PathLen := PathLen + Duration;
  687.                                  end
  688.                             else write(Fileout,'          ');
  689.      writeln(Fileout,Cost:MaxDigits+1:2);
  690.      TotalCost := TotalCost + Cost;
  691.      end; { with ... }
  692.    end; { for i := 1..do }
  693.   writeln(Fileout);
  694.   writeln(Fileout,'The critical path length is ', PathLen:MaxDigits+1:3);
  695.   writeln(Fileout,'The total cost of this network is ',
  696.           TotalCost:MaxDigits+1:3);
  697.   writeln(Fileout);
  698.   if OutputFile <> CONSOLE
  699.      then begin
  700.           writeln(Fileout);
  701.           writeln(Fileout,'Task Titles & Descriptions------------------');
  702.           writeln(Fileout);
  703.           for i:=1 to Activities do begin
  704.               writeln(Fileout,'TITLE: ',Project[i].TaskName);
  705.               writeln(Fileout,'Description: ',Project[i].TaskText);
  706.               writeln(Fileout);
  707.               end;
  708.           close(Fileout);
  709.           OutputFile := CONSOLE;
  710.           end;
  711. end; { CalculateSlackTime }
  712.  
  713. procedure Gantt;
  714. label
  715.   endGANTT;
  716. const
  717.   width = 70;
  718. var
  719.   i, j               : integer;
  720.   scale, Slack       : real;
  721.   PlotChar, EndSlack : char;
  722.   SlackChar,CritChar : char;
  723.   DuraChar           : char;
  724. procedure PlotLine(num : real; ch : char);
  725. var
  726.   xnum, k : integer;
  727. begin
  728.   xnum := trunc((num + 0.5) * scale);
  729.   if xnum > 0
  730.      then begin
  731.           if ch <> SlackChar
  732.              then begin
  733.                   for k := 1 to xnum do write(Fileout,ch);
  734.                   end
  735.              else if xnum > 1
  736.                      then begin
  737.                           for k := 1 to xnum-1 do write(Fileout,ch);
  738.                           write(Fileout,EndSlack);
  739.                           end
  740.                      else write(Fileout,EndSlack);
  741.          end;
  742. end; { PlotLine }
  743. procedure ShowChar(ch : char; num : integer);
  744. var
  745.   i : integer;
  746. begin
  747.   if ch <> SlackChar
  748.      then begin
  749.           for i := 1 to num do write(Fileout,ch);
  750.           end
  751.      else begin
  752.           for i := 1 to num-1 do write(Fileout,ch);
  753.           write(Fileout,EndSlack);
  754.           end;
  755.   writeln(Fileout);
  756. end; { ShowChar }
  757. begin
  758.   if OutputFile = CONSOLE
  759.      then begin
  760.             EndSlack  := chr(191);
  761.             SlackChar := chr(196);
  762.             CritChar  := chr(175);
  763.             DuraChar  := chr(220);
  764.           end
  765.      else begin
  766.             EndSlack  := ']';
  767.             SlackChar := '.';
  768.             CritChar  := '>';
  769.             DuraChar  := '=';
  770.           end;
  771.   Repaint('GANTT Chart');
  772.   if PathLen <= 0
  773.      then begin
  774.           gotoxy(1,12);
  775.           write('You must run option '); LowVideo; write('CalcSheet');
  776.           HighVideo; write(' before running '); LowVideo;
  777.           writeln('Gantt.'); HighVideo;
  778.           goto endGANTT;
  779.           end;
  780.   scale := width / PathLen;
  781.   if scale > 1.00 then scale := 1.00;
  782.   write(Fileout,'Task No ':9);
  783.   for i := 1 to 35 do write(Fileout,'+-');
  784.   writeln(Fileout);
  785.   for i := 1 to Activities do begin
  786.       write(Fileout,Project[i].TaskName:8,' ');
  787.       PlotLine(Start[Project[i].BegNode],' ');
  788.       Slack := Finish[Project[i].EndNode]- Start[Project[i].BegNode] - Project[i].Duration;
  789.       if Slack > 0
  790.          then PlotChar := DuraChar
  791.          else PlotChar := CritChar;
  792.       PlotLine(Project[i].Duration,PlotChar);
  793.       PlotLine(Slack,SlackChar);
  794.       writeln(Fileout);
  795.       end;
  796.   writeln(Fileout);
  797.   writeln(Fileout,'Scaling = ',scale:8:2);
  798.   writeln(Fileout,'LEGEND               Graphic Characters Used');
  799.   write(Fileout,'Scheduled Activity   '); ShowChar(DuraChar,20);
  800.   write(Fileout,'Critical  Activity   '); ShowChar(CritChar,20);
  801.   write(Fileout,'Available Slack      '); ShowChar(SlackChar,20);
  802.   if OutputFile <> CONSOLE
  803.      then begin
  804.           close(Fileout);
  805.           OutputFile := CONSOLE;
  806.           end;
  807. endGANTT:
  808. end; { GANTT }
  809.  
  810. procedure DiagramCPM(AllowEdit: boolean);
  811. const
  812.   rt_arr = 1;  rt_tee = 2;
  813.   lt_tee = 3;  dn_tee = 4;
  814.   d_conn = 5;  x_conn = 6;
  815.   up_tee = 7;
  816.   maxcol = 20; maxrow = 20;
  817. type
  818.   columns = 1..maxcol;
  819.   lines   = 1..maxrow;
  820.   linkages = array [1..20] of char;
  821.   string8  = string[8];
  822.   string10 = string[10];
  823.   string12 = string[12];
  824. var
  825.   FixFlag             : boolean;
  826.   s_link              : linkages;
  827.   NodeData            : array [1..MaxValue,1..2] of integer;
  828.   space8, space10     : string10;
  829.   space12             : string12;
  830.   screen              : array [columns,lines] of string12;
  831.   ScrnUpdate          : array [lines] of boolean;
  832.   col, row, col2      : integer;
  833.   EndPath             : integer;
  834.   ReDoMap             : boolean;
  835. procedure InitLinks;
  836. begin
  837.   s_link[rt_arr] := chr(16);
  838.   s_link[rt_tee] := chr(195);
  839.   s_link[lt_tee] := chr(180);
  840.   s_link[dn_tee] := chr(194);
  841.   s_link[x_conn] := chr(196);
  842.   s_link[d_conn] := chr(179);
  843.   s_link[up_tee] := chr(217);
  844.   space8 := '          ';
  845.   space10 := space8 + '  ';
  846.   space12 := space10 + '  ';
  847. end;
  848. function Xlate(inchr : char): char;
  849. begin
  850.   if inchr = s_link[rt_arr]
  851.      then Xlate := '>'
  852.   else if inchr = s_link[rt_tee]
  853.        then Xlate := '+'
  854.   else if inchr = s_link[lt_tee]
  855.        then Xlate := '+'
  856.   else if inchr = s_link[dn_tee]
  857.        then Xlate := '|'
  858.   else if inchr = s_link[x_conn]
  859.        then Xlate := '-'
  860.   else if inchr = s_link[d_conn]
  861.        then Xlate := '|'
  862.   else if inchr = s_link[up_tee]
  863.        then Xlate := '^'
  864.   else Xlate := inchr;
  865. end;
  866. procedure InitNodes;
  867. var
  868.   i, row, col : integer;
  869. begin
  870.   for row := 1 to maxrow do begin
  871.     ScrnUpdate[row] := FALSE;
  872.     for col := 1 to maxcol do begin
  873.       screen[col,row] := space12;
  874.       end;
  875.     end;
  876. end;
  877. function connect(linechar : char): string12;
  878. var
  879.   i,j     : integer;
  880.   tempstr : string12;
  881. begin
  882.   tempstr := linechar;
  883.   for i := 1 to 11 do tempstr := tempstr + s_link[x_conn];
  884.   connect := tempstr;
  885. end;
  886. function boxpkg(BoxName : string8; ch1, ch2 : char): string12;
  887. var
  888.   i,j     : integer;
  889.   tempstr : string12;
  890. begin
  891.   tempstr := connect(s_link[x_conn]);
  892.   for i := 1 to length(BoxName) do tempstr[i+1] := BoxName[i];
  893.   tempstr[12] := ch2;
  894.   tempstr[1]  := ch1;
  895.   boxpkg := tempstr;
  896. end;
  897. function NodePkg(NodePtr : integer): string12;
  898. begin
  899.   NodePkg := BoxPkg('Node'+ToSTRING(NodePtr)+']','[',s_link[x_conn]);
  900. end;
  901. function TaskPkg(TaskPtr : integer): string12;
  902. begin
  903.   if Project[TaskPtr].TaskName = ' '
  904.      then TaskPkg := BoxPkg('Task'+ToSTRING(TaskPtr),
  905.                             s_link[x_conn],s_link[rt_arr])
  906.      else TaskPkg := BoxPkg(Project[TaskPtr].TaskName,
  907.                             s_link[x_conn],s_link[rt_arr])
  908. end;
  909. function PointUp: string12;
  910. var
  911.   tempstr : string12;
  912. begin
  913.   tempstr    := space12;
  914.   tempstr[1] := s_link[d_conn];
  915.   PointUp    := tempstr;
  916. end;
  917. function XlateStr(instr: textstring): textstring;
  918. var
  919.   i : integer;
  920.   OneWord : textstring;
  921. begin
  922.   for i := 1 to length(instr) do OneWord[i] := Xlate(instr[i]);
  923.   OneWord[0] := instr[0];
  924.   XlateStr := OneWord;
  925. end;
  926. procedure FindNode(NearestNode : string8; var Row, Col : integer);
  927. begin
  928.   ;
  929. end;
  930. procedure PaintScreen(Ywindow1,Ywindow2,xscroll,yscroll : integer);
  931. const
  932.   width = 12;   { width of screen "pixel" }
  933. var
  934.   i, j, row, col : integer;
  935.   nextline       : integer;
  936.   offset         : integer;
  937.   OneWord        : textstring;
  938. function PaintPtr(instr: textstring): integer;
  939. var
  940.   j, jptr  : integer;
  941. begin
  942.   jptr := 0;
  943.   for j := 1 to 2 do begin
  944.       if ((instr[j] = s_link[rt_tee]) or (instr[j] = s_link[d_conn]) or
  945.           (instr[j] = s_link[up_tee]))
  946.         then jptr := j;
  947.       end;
  948.   PaintPtr := jptr;
  949. end;
  950. procedure PaintToFile;
  951. var
  952.   i, j, row, col : integer;
  953.   OneWord        : textstring;
  954.   LastCol1       : integer;
  955.   LastCol2       : integer;
  956.   ScrnCopy1      : array [1..20] of textstring;
  957.   ScrnCopy2      : array [1..20] of textstring;
  958. begin
  959.   for row := 1 to 20 do begin
  960.     if ScrnUpdate[row] = TRUE
  961.        then begin
  962.             for col := 1 to 20 do begin
  963.                 ScrnCopy2[col] := screen[col,row];
  964.                 OneWord := space12;
  965.                 j := PaintPtr(ScrnCopy2[col]);
  966.                 if (j > 0) then OneWord[j] := s_link[d_conn];
  967.                 ScrnCopy1[col] := OneWord;
  968.                 ScrnCopy1[col] := XlateStr(ScrnCopy1[col]);
  969.                 ScrnCopy2[col] := XlateStr(ScrnCopy2[col]);
  970.                 end;
  971.             LastCol1 := 20; LastCol2 := 20;
  972.             Repeat
  973.               LastCol1 := pred(LastCol1);
  974.             Until ((ScrnCopy1[LastCol1] <> space12) or (LastCol1 =1));
  975.             Repeat
  976.               LastCol2 := pred(LastCol2);
  977.             Until ((ScrnCopy2[LastCol2] <> space12) or (LastCol2 = 1));
  978.             for j := 1 to LastCol1 do write(Fileout,ScrnCopy1[j]);
  979.             writeln(Fileout);
  980.             for j := 1 to LastCol2 do write(Fileout,ScrnCopy2[j]);
  981.             writeln(Fileout);
  982.             end;
  983.     end;
  984.   close(Fileout);
  985.   OutputFile := CONSOLE;
  986. end;
  987. procedure PaintToCRT(Ywindow1,Ywindow2,offset,xscroll,yscroll: integer);
  988. begin
  989.   for row := Ywindow1 to Ywindow2 do begin
  990.     if ScrnUpdate[row] = TRUE
  991.        then begin
  992.             nextline := 2 * (row - 1) + 1;
  993.             for col := 1 to (79 div width) do begin
  994.                 gotoxy(width*(col-1)+1,nextline+offset);
  995.                 write(screen[col+xscroll,row+yscroll]);
  996.                 j := PaintPtr(screen[col+xscroll,row+yscroll]);
  997.                 if j > 0
  998.                    then begin
  999.                         gotoxy(width*(col-1)+j,nextline+offset-1);
  1000.                         write(s_link[d_conn]);
  1001.                         end;
  1002.                end;
  1003.             end;
  1004.     end;
  1005. end;
  1006.  
  1007. { --------- main PaintScreen procedure ------------------------------ }
  1008. begin
  1009.   if OutputFile = CONSOLE
  1010.      then begin
  1011.             if ((Ywindow1=1) and (Ywindow2>=20))
  1012.                then clrscr
  1013.                else for i := Ywindow1 to Ywindow2 do EraseLine(i);
  1014.            gotoxy(1,Ywindow1);
  1015.          end;
  1016.   PageTitle('PERT Chart');
  1017.   offset := 3 ;
  1018.   if OutputFile <> CONSOLE
  1019.      then PaintToFile
  1020.      else PaintToCRT(Ywindow1,Ywindow2,offset,xscroll,yscroll);
  1021. end;
  1022.  
  1023. procedure EditMap(var ReDoMap: boolean);
  1024. var
  1025.   ch              : char;
  1026.   i               : integer;
  1027.   xscroll,yscroll : integer;
  1028.   xwindow,ywindow : integer;
  1029. begin
  1030.   xscroll := 0;
  1031.   yscroll := 0;
  1032.   xwindow := 1;
  1033.   ywindow := 20;
  1034.   REPEAT
  1035.     Commands(ch,'Edit Home Up Down Right Left Quit');
  1036.     if ch = 'E'
  1037.        then begin
  1038.             ywindow := 15;
  1039.             Edit(xwindow,ywindow+1);
  1040.             for i := ywindow to 24 do EraseLine(i);
  1041.             ReDoMap := TRUE;
  1042.             end;
  1043.     if Pos(ch,'HUDRL') > 0
  1044.        then begin
  1045.               case ch of
  1046.                  'H': begin
  1047.                         xscroll := 0;
  1048.                         yscroll := 0;
  1049.                       end;
  1050.                  'R': xscroll := xscroll - 2;
  1051.                  'L': xscroll := xscroll + 2;
  1052.                  'U': yscroll := yscroll - 1;
  1053.                  'D': yscroll := yscroll + 1;
  1054.                  end;
  1055.             end;
  1056.     if xscroll < 0 then xscroll := 0;
  1057.     if yscroll < 0 then yscroll := 0;
  1058.     if xscroll > 20 then xscroll := 20;
  1059.     if ch <> 'Q' then PaintScreen(xwindow,ywindow,xscroll,yscroll);
  1060.   UNTIL ((ch = 'Q') or ReDoMap);
  1061. end;
  1062.  
  1063. function FindLastNode: integer;
  1064. var
  1065.   i, LastNode    : integer;
  1066. begin
  1067.   LastNode := Project[1].EndNode;
  1068.   for i := 1 to Activities do begin
  1069.     if Project[i].EndNode <> 0
  1070.        then if Project[i].EndNode > LastNode
  1071.                then LastNode := Project[i].EndNode;
  1072.     end;
  1073.   FindLastNode := LastNode;
  1074. end;
  1075. procedure BuildMap;
  1076. label
  1077.   quit;
  1078. var
  1079.   i, StartNode, row, col : integer;
  1080.   TaskNo, j              : integer;
  1081.   TaskStack, NodesDone   : array [1..MaxValue] of boolean;
  1082. function NextBlock(xcol,yrow : integer) : integer;
  1083. var
  1084.   col2    : integer;
  1085.   OneWord : string12;
  1086. begin
  1087.   col2 := xcol;
  1088.   repeat
  1089.     OneWord := screen[col2,yrow];
  1090.     if OneWord[1] <> ' '
  1091.        then col2 := col2 + 1;
  1092.   until OneWord[1] = ' ';
  1093.   NextBlock := col2;
  1094. end;
  1095. function MultiTask(StartNode: integer) : boolean;
  1096. var
  1097.   i, j : integer;
  1098. begin
  1099.   j := 0;
  1100.   for i := 1 to Activities do begin
  1101.     if Project[i].BegNode = StartNode
  1102.        then j := succ(j);
  1103.   end;
  1104.   if j > 1
  1105.      then MultiTask := TRUE
  1106.      else MultiTask := FALSE;
  1107. end; {BuildMap: MultiTask subfunction}
  1108. procedure InitStacks;
  1109. begin
  1110.   for i := 1 to Activities do
  1111.       begin
  1112.         TaskStack[i] := FALSE;
  1113.         NodesDone[i] := FALSE;
  1114.       end;
  1115. end; { BuildMap: InitStacks subprocedure }
  1116. procedure MakeNode(ThisNode: integer; xcol,row : integer;
  1117.                    var flag: boolean; var newcol : integer);
  1118. var
  1119.   i, yrow : integer;
  1120.   OneWord : string12;
  1121. begin
  1122.   if NodesDone[ThisNode] = FALSE
  1123.      then begin
  1124.           flag := FALSE;
  1125.           screen[xcol,row] := NodePkg(ThisNode);
  1126.           if ThisNode = FindLastNode
  1127.              then begin
  1128.                   OneWord := screen[xcol,row];
  1129.                   i := length(OneWord) + 1;
  1130.                   repeat
  1131.                     i := pred(i);
  1132.                     if OneWord[i] = s_link[x_conn]
  1133.                        then OneWord[i] := ' ';
  1134.                  until OneWord[i-1] <> s_link[x_conn];
  1135.                  screen[xcol,row] := OneWord;
  1136.                  end;
  1137.           NodesDone[ThisNode] := TRUE;
  1138.           NodeData[ThisNode,1] := xcol;
  1139.           NodeData[ThisNode,2] := row;
  1140.           end
  1141.      else begin
  1142.           if xcol = NodeData[ThisNode,1]
  1143.              then begin
  1144.                   flag := FALSE;
  1145.                   end
  1146.              else begin
  1147.                   repeat
  1148.                     screen[xcol,row] := connect(s_link[x_conn]);
  1149.                     xcol := succ(xcol);
  1150.                   until xcol = NodeData[ThisNode,1];
  1151.                   flag := TRUE;
  1152.                   newcol := xcol;
  1153.                   end;
  1154.              for yrow := row downto NodeData[ThisNode,2]
  1155.                  do begin
  1156.                     if screen[xcol,yrow] = space12
  1157.                        then screen[xcol,yrow] := PointUp;
  1158.                     end;
  1159.           end;
  1160. end;
  1161. procedure InsertBlocks(ThisNode,xcol,row : integer);
  1162. var
  1163.   i, j, sel_conn : integer;
  1164.   OneWord        : string12;
  1165. begin
  1166.     j := 0;
  1167.     if MultiTask(ThisNode) = TRUE
  1168.        then sel_conn := dn_tee
  1169.        else sel_conn := x_conn;
  1170.     for i := 1 to Activities do begin
  1171.       if ((Project[i].BegNode = ThisNode) and (TaskStack[i] = FALSE))
  1172.          then begin
  1173.               TaskStack[i] := TRUE;
  1174.               ScrnUpdate[row+j] := TRUE;
  1175.               OneWord := screen[NextBlock(xcol,row+j),row+j];
  1176.               OneWord := TaskPkg(i);
  1177.               OneWord[1] := s_link[sel_conn];
  1178.               if sel_conn = dn_tee then sel_conn := rt_tee;
  1179.               screen[xcol,row+j] := OneWord;
  1180.               {use "box(NodeName[Project[i].EndNode])" for "nodepkg" later}
  1181.               MakeNode(Project[i].EndNode,xcol+1,row+j,FixFlag,col2);
  1182.               if FixFlag
  1183.                  then InsertBlocks(Project[i].EndNode,col2,row+j)
  1184.                  else InsertBlocks(Project[i].EndNode,xcol+2,row+j);
  1185.               j := succ(j);
  1186.               end;
  1187.     end;
  1188. end; { BuildMap: InsertBlocks subprocedure }
  1189. begin
  1190.   InitStacks;
  1191.   row := 1; col := 1;
  1192.   if FindLastNode > 2
  1193.      then EndPath := FindLastNode - 1
  1194.      else EndPath := FindLastNode;
  1195.   for StartNode := 1 to EndPath do begin
  1196.       if NodesDone[StartNode] = FALSE
  1197.          then begin
  1198.               {use "box(NodeName[StartNode])" for "nodepkg" later}
  1199.               col := NextBlock(col,row);
  1200.               MakeNode(StartNode,col,row,FixFlag,col2);
  1201.               ScrnUpdate[row] := TRUE;
  1202.               InsertBlocks(StartNode,col+1,row);
  1203.               end;
  1204.       end;
  1205. end;
  1206.  
  1207. begin
  1208.   REPEAT
  1209.     InitLinks;
  1210.     InitNodes;
  1211.     ReDoMap := FALSE;
  1212.     BuildMap;
  1213.     PaintScreen(1,20,0,0);
  1214.     if ((OutputFile = CONSOLE) and AllowEdit)
  1215.        then EditMap(ReDoMap);
  1216.   UNTIL ReDoMap = FALSE;
  1217. end;
  1218.  
  1219.  
  1220. procedure RunCPM;
  1221. var
  1222.   i : integer;
  1223. begin
  1224.   for i := 1 to Activities do
  1225.     begin
  1226.       Start[i]  := 0.0;
  1227.       Finish[i] := 0.0;
  1228.     end;
  1229.   FindEarlyStart;
  1230.   FindLateFinish;
  1231. end;
  1232. procedure CalcCPM;
  1233. begin
  1234.   TotalCost := 0;
  1235.   PathLen := 0;
  1236.   CalculateSlackTime;
  1237. end; { CalcCPM }
  1238.  
  1239. procedure PipeFile;
  1240. var
  1241.  ch2, ch3 : char;
  1242. procedure PipeFile2;
  1243. begin
  1244.   Commands(ch3,'CalcSheet Gantt Plot Lotus Quit');
  1245.   if ch3 <> 'Q'
  1246.      then case ch3 of
  1247.        'C': ident('Calc  Sheet for Project: '+ProjectName);
  1248.        'G': ident('Gantt Chart for Project: '+ProjectName);
  1249.        'P': ident('PERT  Chart for Project: '+ProjectName);
  1250.        'L': ident('Lotus File  for Project: '+ProjectName);
  1251.        end;
  1252.   EraseLine(22);
  1253.   EraseLine(23);
  1254.   gotoxy(1,22);
  1255.   InitOutput;
  1256.   if OutputFile <> CONSOLE
  1257.      then case ch3 of
  1258.           'C': CalcCPM;
  1259.           'G': Gantt;
  1260.           'P': DiagramCPM(FALSE);
  1261.           'L': LotusCPM;
  1262.          end;
  1263. end;
  1264. begin  { ------ PipeFile "main" procedure --------------------------------- }
  1265.   REPEAT
  1266.     Commands(ch2,'NewProject Output-to-file Quit');
  1267.     if ch2 = 'N'
  1268.        then begin
  1269.             GetData;
  1270.             RunCPM;
  1271.             end
  1272.        else if ch2 = 'O' then PipeFile2;
  1273.   UNTIL ch2 = 'Q';
  1274. end;
  1275.  
  1276. procedure SetFiles;
  1277. var
  1278.   ch2, ch3 : char;
  1279. begin
  1280.   if NOT OkToGo
  1281.      then begin
  1282.           OkToGo := TRUE;
  1283.           OutputFile := CONSOLE;
  1284.           assign(Fileout,OutputFile);
  1285.           rewrite(Fileout);
  1286.           GetData;
  1287.           RunCPM;
  1288.           end
  1289.      else PipeFile;
  1290. end;
  1291. procedure Help;
  1292. var
  1293.   i   : integer;
  1294.   ch2 : char;
  1295. begin
  1296.   window('HELP SCREEN');
  1297.   writeln('F(ile)      : (Re)Select project to process.                  ');
  1298.   writeln('            : Setup input data entry - File or Console.       ');
  1299.   writeln('            : Output results to selected File.                ');
  1300.   writeln('E(dit)      : Modify project tasks and milestones.            ');
  1301.   writeln('C(alcSheet) : Calculate project Start, End, Slack, Cost, Etc. ');
  1302.   writeln('G(antt)     : Display GANTT chart of project.                 ');
  1303.   writeln('P(lot)      : Display project tasks and milestones.           ');
  1304.   writeln('Q(uit)      : Terminate IPM and Return to DOS.                ');
  1305.   for i := 1 to 78 do write('-'); writeln;
  1306. end;
  1307. begin  { main }
  1308.   ProjectName := '--> No Project Selected <-- ';
  1309.   InputFile   := CONSOLE; CurrFile := InputFile;
  1310.   OutputFile  := CONSOLE;
  1311.   CmdCh := '\';
  1312.   OkToGo := FALSE;
  1313.   repeat
  1314.     if Pos(CmdCh,'CGEH') = 0 then MainMenu;
  1315.     Commands(CmdCh,'File CalcSheet Gantt Plot Edit Help Quit');
  1316.     If Pos(CmdCh,'FCGPEH') > 0
  1317.        then begin
  1318.             case CmdCh of
  1319.                    'F': SetFiles;
  1320.                    'C': if OkToGo then CalcCPM;
  1321.                    'G': if OkToGo then Gantt;
  1322.                    'H': Help;
  1323.                    'P': if OkToGo then DiagramCPM(TRUE);
  1324.                    'E': Edit(1,1);
  1325.                    end;
  1326.             end;
  1327.  until CmdCh = 'Q';
  1328. end. { CriticalPathMethod }
  1329.