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