CALC.INC 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582
  1. {*************************************************************************}
  2. { MicroCalc Module 000 }
  3. { Last Modified : 7-22-85 }
  4. { }
  5. { Purpose : Miscellaneous utilities and commands. }
  6. { }
  7. {*************************************************************************}
  8. procedure Help; forward; { procedure Help is forward declared in the int- }
  9. { erest of keeping all miscellaneous routines }
  10. { grouped in one module. }
  11. { procedure Center centers the string passed as the paramater on the }
  12. { screen. NOTE : This routine assumes an 80 column screen. }
  13. procedure Center(S : AnyString);
  14. var
  15. I : Integer;
  16. begin
  17. for I := 1 to ((80-Length(S)) div 2) do
  18. Write(' '); {Fill beginning of line with spaces based on the length(S)}
  19. writeln(S);
  20. end; { end Sub-procedure Center }
  21. { procedure Welcome says Welcome and activates the help procedure if the }
  22. { user presses any key other than Carriage Return. }
  23. procedure Welcome;
  24. begin { procedure Welcome }
  25. ClrScr;
  26. GotoXY(1,9);
  27. Center('Welcome to MicroCalc. A Turbo Pascal demonstration program');
  28. Center('Press any key for help or <RETURN> to start');
  29. GotoXY(40,12);
  30. Read(Kbd,Ch);
  31. { If Ch entered does not equal a carriage return then call Help routine.}
  32. if Ch <> ^M then Help;
  33. end; { end procedure Welcome }
  34. { procedure Msg outputs the string, passed in as a paramater, to the }
  35. { screen. }
  36. procedure Msg(S : AnyString);
  37. begin
  38. GotoXY(1,24);
  39. ClrEol;
  40. Write(S);
  41. ClrEol;
  42. end; { End procedure Msg }
  43. { The procedure Flash causes the string input as a paramater to flash by }
  44. { alternately writeing it to the screen in LowVideo and NormVideo. }
  45. { NOTES :
  46. 1. procedure Flash allows you to specify the column in which
  47. the string will be written. A possible extension of the
  48. routine could be to allow the user to specify the row also.
  49. 2. By setting the blink paramater to true or false the string
  50. will flash or not flash. If Blink is true the string will
  51. Flash until a key is pressed.
  52. 3. Upon exit of the procedure, the string will be written in
  53. LowVideo regardless of the value of Blink }
  54. procedure Flash(X : Integer; S : AnyString; Blink : boolean);
  55. begin
  56. NormVideo;
  57. GotoXY(X,23);
  58. Write(S);
  59. if Blink then { Check value of Blink, if true then execute the repeat }
  60. begin { until loop. }
  61. repeat
  62. GotoXY(X,23);
  63. Blink := not Blink; { By modifying the value of Blink after }
  64. if Blink then { each iteration of the loop, we can use }
  65. NormVideo { Blink's value as a test for the appro- }
  66. else { priate Video attribute value. }
  67. LowVideo;
  68. Write(S);
  69. Delay(175);
  70. until KeyPressed;
  71. end;
  72. LowVideo;
  73. end; { End procedure Flash }
  74. { procedure IBMCh determines the extended scan code read in and returns }
  75. { a one character interpolation of the characters read in. }
  76. procedure IBMCh(var Ch: Char);
  77. begin
  78. case Ch of
  79. 'H': Ch := ^E;
  80. 'P': Ch := ^X;
  81. 'M': Ch := ^D;
  82. 'K': Ch := ^S;
  83. 'S': Ch := #127;
  84. 'R': Ch := ^V;
  85. 'G', 'I', 'O',
  86. 'Q': Ch := #00;
  87. end;
  88. end; { End procedure IBMCh }
  89. procedure Auto; { Toggles automatic calculation mode on and off }
  90. begin
  91. AutoCalc:=not AutoCalc;
  92. if AutoCalc then Flash(60,'AutoCalc: ON ',false)
  93. else Flash(60,'AutoCalc: OFF',false);
  94. end;
  95. {*************************************************************************}
  96. { MicroCalc Module 001 }
  97. { Last Modified 7-22-85 }
  98. { }
  99. { Purpose : initialize Spread sheet, redraw screen, and clear current }
  100. { spread sheet }
  101. { }
  102. {*************************************************************************}
  103. { procedure Grid Displays the entire spread sheet grid and command line. }
  104. procedure Grid;
  105. var
  106. I : Integer;
  107. Count : Char;
  108. begin
  109. NormVideo;
  110. For Count := 'A' to FXMax do { Display Column Names (A..FXMax) }
  111. begin
  112. GotoXY(XPos[Count],1);
  113. Write(Count);
  114. end;
  115. GotoXY(1,2);
  116. for I := 1 to FYMax do { Display Row numbers (1..FYMax) }
  117. writeln(I:2);
  118. LowVideo;
  119. if AutoCalc then { Display Status line }
  120. Flash(60,'AutoCalc: ON' ,false)
  121. else
  122. Flash(60,'AutoCalc: OFF',false);
  123. Flash(33,' Type / for Commands',false);
  124. end; { End procedure Grid }
  125. { procedure Init initializes the values of each of the cells in the grid. }
  126. { NOTE : Initializing variables in TURBO PASCAL is very important. }
  127. procedure Init;
  128. var
  129. I : ColumnName;
  130. J : Integer;
  131. LastName : string[2];
  132. begin
  133. for I := 'A' to FXMAX do { Traverse grid Column by Column - Row }
  134. begin { by Row, initializing each cell }
  135. for J := 1 to FYMAX do
  136. begin
  137. with Sheet[I,J] do { Access record representing this cell }
  138. begin
  139. CellStatus := [Txt]; { Default cell attribute }
  140. Contents := ''; { Value of default cell attribute }
  141. Value := 0; { Default value of numeric field }
  142. DEC := 2; { Default number of decimals }
  143. FW := 10; { Default field width }
  144. end;
  145. end;
  146. end;
  147. AutoCalc := True; { AutoCalc defaults to True or ON }
  148. FX:='A'; FY:=1; { Field A1 is default current field }
  149. end; { End procedure Init }
  150. { procedure Clear clears the current worksheet. }
  151. procedure Clear;
  152. begin
  153. NormVideo;
  154. GotoXY(1,24); ClrEol;
  155. Write('Clear this worksheet? (Y/N) ');
  156. repeat
  157. Read(Kbd,Ch)
  158. until Upcase(Ch) in ['Y','N'];
  159. Write(Upcase(Ch));
  160. if UpCase(Ch)='Y' then
  161. begin
  162. ClrScr;
  163. Init;
  164. Grid;
  165. end;
  166. end; { End procedure Clear }
  167. {*************************************************************************}
  168. { MicroCalc Module 002 }
  169. { Last Modified 7-22-85 }
  170. { }
  171. { Purpose : Cursor movement whithin the spread sheet }
  172. { }
  173. {*************************************************************************}
  174. { procedure DisplayType outputs the current cell it's type and if the }
  175. { cell's type is a formula the formula is also output. }
  176. procedure DisplayType;
  177. begin
  178. with Sheet[FX,FY] do
  179. begin
  180. GotoXY(1,23);
  181. Write(FX,FY:2,' ');
  182. if Formula in CellStatus then { Determine Type of Cell }
  183. write('Formula ')
  184. else
  185. if Constant in CellStatus then
  186. Write('Numeric ')
  187. else
  188. if Txt in CellStatus then
  189. Write('Text ');
  190. GotoXY(1,24); ClrEol;
  191. if Formula in CellStatus
  192. then Write(Contents);
  193. end;
  194. end; { End procedure DisplayType }
  195. {*************************************************************************}
  196. { The following procedures move between the Cells on the calc sheet. Each }
  197. { Cell has an associated record containing its X,Y coordinates and data. }
  198. { See the type definition for "Cell". }
  199. {*************************************************************************}
  200. { procedure GotoCell goes to the cell indicated by the procedures }
  201. { paramaters and outputs it's current value. }
  202. procedure GotoCell(GX: ColumnName; GY: Integer);
  203. begin
  204. with Sheet[GX,GY] do { Get specified record (i.e. cell) }
  205. begin
  206. NormVideo;
  207. GotoXY(XPos[GX],GY+1); { Go to leftmost column of specified cell }
  208. Write(' '); { Clear the cell }
  209. GotoXY(XPos[GX],GY+1);
  210. if Txt in CellStatus then
  211. Write(Contents)
  212. else { cell does not contain text }
  213. begin
  214. if DEC >= 0 then { check if number of decimal spaces is }
  215. Write(Value:FW:DEC) { specified else output in scientific }
  216. else { notation. }
  217. Write(Value:FW);
  218. end;
  219. DisplayType;
  220. GotoXY(XPos[GX],GY+1);
  221. end;
  222. LowVideo;
  223. end;
  224. { procedure LeaveCell simply writes the current cell's contents in }
  225. { LowVideo. }
  226. procedure LeaveCell(FX : ColumnName; FY : Integer);
  227. begin
  228. with Sheet[FX,FY] do { Get record representing current cell }
  229. begin
  230. GotoXY(XPos[FX],FY + 1);
  231. LowVideo;
  232. if Txt in CellStatus then
  233. Write(Contents)
  234. else
  235. begin
  236. if DEC >= 0 then
  237. Write(Value:FW:DEC)
  238. else
  239. Write(Value:FW);
  240. end;
  241. end;
  242. end; { End procedure LeaveCell }
  243. procedure Update;
  244. var
  245. UFX : ColumnName;
  246. UFY : Integer;
  247. begin
  248. ClrScr;
  249. Grid;
  250. for UFX := 'A' to FXMax do
  251. for UFY := 1 to FYMax do
  252. if Sheet[UFX,UFY].Contents <> '' then
  253. LeaveCell(UFX,UFY);
  254. GotoCell(FX,FY);
  255. end;
  256. { procedure MoveDown updates the current cell by calling procedure }
  257. { LeaveCell. It then moves the cursor down on position. Note : The repeat }
  258. { loop in this routine does the actuall moving of the cursor. A valid cell}
  259. { must be found before the cursor can be moved. The cell is valid if it's }
  260. { CellStatus is not in [OverWritten,Locked] . }
  261. procedure MoveDown;
  262. var
  263. Start : Integer;
  264. begin
  265. LeaveCell(FX,FY);
  266. Start := FY;
  267. repeat
  268. FY := FY + 1;
  269. if FY > FYMax then
  270. FY := 1;
  271. until (Sheet[FX,FY].CellStatus * [OverWritten,Locked] = []) or (FY = Start);
  272. if FY <> Start then
  273. GotoCell(FX,FY);
  274. end; { End procedure MoveDown }
  275. { procedure MoveUp updates the current cell, then moves the cursor up one }
  276. { position. The note for the last procedure applies here also. }
  277. procedure MoveUp;
  278. var
  279. Start : Integer;
  280. begin
  281. LeaveCell(FX,FY);
  282. Start := FY;
  283. repeat
  284. FY := FY - 1;
  285. if FY < 1 then
  286. FY := FYMax;
  287. until (Sheet[FX,FY].CellStatus * [OverWritten,Locked] = []) or (FY = Start);
  288. if FY <> Start then
  289. GotoCell(FX,FY);
  290. end; { End procedure MoveUp }
  291. { procedure MoveRight acts the same as the previous two procedures with }
  292. { the exception of the direction it moves the cursor. }
  293. procedure MoveRight;
  294. var
  295. Start : ColumnName;
  296. begin
  297. LeaveCell(FX,FY);
  298. Start := FX;
  299. repeat
  300. FX := Succ(FX);
  301. if FX > FXMax then
  302. begin
  303. FX := 'A';
  304. FY := FY + 1;
  305. if FY > FYMax then
  306. FY := 1;
  307. end;
  308. until (Sheet[FX,FY].CellStatus * [OverWritten,Locked] = []) or (FX = Start);
  309. if FX <> Start then
  310. GotoCell(FX,FY);
  311. end; { End procedure MoveRight }
  312. { procedure MoveLeft acts the same as the previous three procedures with }
  313. { the exception of the direction it moves the cursor. }
  314. procedure MoveLeft;
  315. var
  316. Start : ColumnName;
  317. begin
  318. LeaveCell(FX,FY);
  319. Start := FX;
  320. repeat
  321. FX := Pred(FX);
  322. if FX < 'A' then
  323. begin
  324. FX := FXMax;
  325. FY := FY - 1;
  326. if FY < 1 then
  327. FY := FYMax;
  328. end;
  329. until (Sheet[FX,FY].CellStatus * [OverWritten,Locked] = []) or (FX = Start);
  330. if FX <> Start then
  331. GotoCell(FX,FY);
  332. end; { End procedure MoveLeft }
  333. {*************************************************************************}
  334. { MicroCalc Module 003 }
  335. { Last Modified : 7-22-85 }
  336. { }
  337. { PURPOSE: Load, Save and Print a spread sheet. }
  338. { Display on-line manual. }
  339. {*************************************************************************}
  340. { function Exist returns a boolean value indicating the existence of
  341. the file passed in as a paramater. }
  342. function Exist(FileN : AnyString): boolean;
  343. var
  344. F : file;
  345. begin
  346. {$I-}
  347. assign(F,FileN);
  348. reset(F);
  349. {$I+}
  350. if IOResult <> 0 then
  351. Exist := false
  352. else
  353. begin
  354. Exist := true;
  355. close(F);
  356. end;
  357. end; { End function Exist }
  358. { Procedure GetFileName reads a filename input by the user. The
  359. filename's extension is passed in as the second paramater of the
  360. procedure.
  361. Note : As the procedure stands, the user can not use path names. }
  362. Procedure GetFileName(var Line : AnyString; FileType : String3);
  363. var
  364. i : Integer;
  365. begin
  366. Line := '';
  367. Read(Line);
  368. clreol;
  369. if Length(Line) > 8 then
  370. begin
  371. clreol;
  372. Line[0] := chr(8);
  373. Msg('Filename Truncated to : ' + Line);
  374. end;
  375. for i := 1 to Length(Line) do
  376. begin
  377. Line[i] := UpCase(Line[i]);
  378. if not (Line[i] in ['A'..'Z','0'..'9'
  379. (*,'!','#'..')','-',',','/','@','\','_','`','{','}'*)
  380. ]) then
  381. Msg('Invalid Filename');
  382. end;
  383. if Line <> '' then
  384. Line := Line + '.' + FileType;
  385. end; { End Procedure GetFileName }
  386. { Procedure Save saves the current spreadsheet to a file.
  387. Note : this routine attaches the extension 'MCS' to the filename. }
  388. Procedure Save;
  389. var
  390. I : ColumnName;
  391. J : Integer;
  392. begin
  393. NormVideo;
  394. Msg('Save: Enter filename ');
  395. GetFileName(Filename,'MCS');
  396. if FileName <> '' then
  397. begin
  398. Assign(MCFile,FileName);
  399. Rewrite(MCFile);
  400. for I := 'A' to FXmax do
  401. for J := 1 to FYmax do
  402. write(MCfile,Sheet[I,J]);
  403. Grid;
  404. Close(MCFile);
  405. LowVideo;
  406. GotoCell(FX,FY);
  407. end;
  408. end; { End Procedure Save }
  409. { Procedure Load loads a spreadsheet from a file.
  410. Note : the procedure gives the user two chances to enter the
  411. correct filename. }
  412. Procedure Load;
  413. begin
  414. NormVideo;
  415. Msg('Load: Enter filename ');
  416. GetFileName(Filename,'MCS'); { Get filename }
  417. if (Filename <> '') then { Check if filename is legal }
  418. if (not exist(FileName)) then { if filename not legal then }
  419. repeat { prompt the user again. }
  420. Msg('File not Found: Enter another filename ');
  421. GetFileName(Filename,'MCS');
  422. until exist(FileName) or (FileName = '');
  423. if FileName <> '' then
  424. begin
  425. ClrScr;
  426. Msg('Please Wait. Loading definition...');
  427. Assign(MCFile,FileName);
  428. Reset(MCFile);
  429. for FX := 'A' to FXmax do { Read records from file }
  430. for FY := 1 to FYmax do
  431. read(MCFile,Sheet[FX,FY]);
  432. FX := 'A';
  433. FY := 1;
  434. LowVideo;
  435. UpDate;
  436. end;
  437. GotoCell(FX,FY);
  438. end; { End Procedure Load }
  439. { Procedure Print prints the current spreadsheet to a file.
  440. Note : a possible improvement might be to allow the user to specify
  441. not only the left margin of the paper, but also the width
  442. of the paper. Also allowing output to go directly to the
  443. printer. }
  444. Procedure Print;
  445. var
  446. I : ColumnName;
  447. J, Count,
  448. LeftMargin : Integer;
  449. P : string[20];
  450. MCFile : Text;
  451. begin
  452. NormVideo;
  453. Msg('Print: Enter filename "P" for Printer> ');
  454. GetFileName(Filename,'LST');
  455. Msg('Left margin > ');
  456. Read(LeftMargin);
  457. if FileName = 'P.LST' then
  458. FileName := 'LST';
  459. Msg('Printing to: ' + FileName + '....');
  460. Assign(MCFile,FileName);
  461. Rewrite(MCFile);
  462. For Count := 1 to 5 do
  463. Writeln(MCFile);
  464. for J := 1 to FYmax do
  465. begin
  466. Line := '';
  467. for I := 'A' to FXmax do
  468. begin
  469. with Sheet[I,J] do
  470. begin
  471. while (Length(Line) < XPOS[I] - 4) do
  472. Line := Line + ' ';
  473. if (Constant in CellStatus) or (Formula in CellStatus) then
  474. begin
  475. if not (Locked in CellStatus) then
  476. begin
  477. if DEC > 0 then
  478. Str(Value:FW:DEC,P)
  479. else
  480. Str(Value:FW,P);
  481. Line := Line + P;
  482. end; { End if not (Locked in CellStatus) then }
  483. end { End if or then }
  484. else
  485. Line := Line + Contents;
  486. end; { End With Statement }
  487. end; { End For Loop - have gotten one line }
  488. For Count := 1 to LeftMargin do { Insert left margin }
  489. Write(MCFile,' ');
  490. writeln(MCFile,Line);
  491. end; { End for loop - move to next line }
  492. Grid;
  493. Close(MCFile);
  494. LowVideo;
  495. GotoCell(FX,FY);
  496. end; { End Procedure Print }
  497. { Procedure Help dislpays the help file CALC.HLP for the user. }
  498. Procedure Help;
  499. type
  500. str80 = string[80];
  501. Pages = array[0..200] of str80;
  502. var
  503. H : text;
  504. Line : string[80];
  505. LineCounter, EndOfFile, ErrorResult, BeginPage,
  506. J : Integer;
  507. Bold : boolean;
  508. Buffer : ^Pages;
  509. Procedure DisplayMessage;
  510. begin
  511. GotoXY(6,24);
  512. NormVideo;
  513. write('Press ');
  514. LowVideo;
  515. Write('`P`');
  516. NormVideo;
  517. Write(' for previous page ');
  518. LowVideo;
  519. Write('`N`');
  520. NormVideo;
  521. Write(' for next,');
  522. LowVideo;
  523. Write('`Esc`');
  524. NormVideo;
  525. Write(' to exit Help file.');
  526. end;
  527. { Procedure GetPages reads the help file from disk into an array of a }
  528. { dynamicly allocated array. NOTE : the number of lines read in is kept }
  529. { in the zero'th index of the array. }
  530. Procedure GetPages;
  531. var
  532. st : string[10];
  533. count : integer;
  534. begin
  535. count := 1;
  536. Assign(H,'CALC.HLP');
  537. Reset(H);
  538. while not Eof(H) do
  539. begin
  540. Readln(H,Buffer^[count]);
  541. count := count + 1;
  542. end;
  543. close(H);
  544. Str(count,st);
  545. Buffer^[0] := st;
  546. end;
  547. begin
  548. LineCounter := 1; { Initialize line counter}
  549. if Exist('CALC.HLP') then
  550. begin
  551. New(Buffer); { Allocate dynamic array }
  552. GetPages; { Read in Help File }
  553. Val(Buffer^[0],EndOfFile,ErrorResult); { EndOfFile := # of Lines}
  554. while LineCounter < EndOfFile do
  555. begin
  556. BeginPage := LineCounter - 1;
  557. if BeginPage < 1 then { If Previous page is called while on }
  558. BeginPage := 1; { first page, Beginpage is off by 1. }
  559. ClrScr;
  560. Bold := false;
  561. LowVideo;
  562. Line := Buffer^[LineCounter]; { Get first line of current page. }
  563. { This while loop steps through the array looking for the end of }
  564. { page indicator '.PA', writing out each line as it goes. }
  565. while (LineCounter < EndOfFile) and (Line <> '.PA') do
  566. begin
  567. Write(' ');
  568. For J := 1 to Length(Line) do
  569. begin
  570. if Line[J] = ^B then { Check for bold face type }
  571. begin
  572. Bold := not Bold; { Toggle Bold type }
  573. if Bold then
  574. NormVideo
  575. else
  576. LowVideo;
  577. end
  578. else
  579. write(Line[J]);
  580. end; { End for loop - have written entire line }
  581. Writeln;
  582. LineCounter := LineCounter + 1;
  583. Line := Buffer^[LineCounter]; { Get next line }
  584. end; { end while }
  585. DisplayMessage;
  586. repeat
  587. read(Kbd,Ch);
  588. until Upcase(Ch) in ['P','N',#27];
  589. case UpCase(Ch) of
  590. 'P' : begin { Get start of previous page }
  591. repeat
  592. BeginPage := BeginPage - 1;
  593. until (Buffer^[BeginPage] = '.PA') or (BeginPage < 1);
  594. LineCounter := BeginPage + 1;
  595. end;
  596. 'N' : LineCounter := LineCounter + 1; { Get start of next page }
  597. #27 : LineCounter := EndOfFile; { force counter to end of file }
  598. end;
  599. end; { end while }
  600. Dispose(Buffer); { Deallocate dynamic array }
  601. UpDate; { Return to Spread Sheet }
  602. end { End if then statement }
  603. else { Help file did not exist }
  604. begin
  605. Msg('To get help the file CALC.HLP must be on your disk. Press <RETURN>');
  606. repeat Read(kbd,Ch) until Ch=^M;
  607. GotoCell(FX,FY);
  608. end;
  609. end; { End procedure Help }
  610. {*************************************************************************}
  611. { MicroCalc Module 004 }
  612. { Last Modified 7-22-85 }
  613. { }
  614. { PURPOSE: Evaluate formulas. }
  615. { Recalculate spread sheet. }
  616. { }
  617. { NOTE: This module contains recursive procedures }
  618. {*************************************************************************}
  619. {$A-}
  620. { procedure NextCh returns the next Character in the formula of the cell }
  621. { currently being evaluated. }
  622. procedure NextCh(var Position : Integer;
  623. var NextChar : Char;
  624. Formula : AnyString);
  625. begin
  626. repeat
  627. Position := Position + 1;
  628. if Position <= Length(Formula) then
  629. NextChar := Formula[Position]
  630. else
  631. NextChar := eofline;
  632. until NextChar <> ' ';
  633. end; { End procedure NextCh }
  634. { procedure Evaluate evaluates a string passed to it, the string }
  635. { represents an expression or formula. }
  636. procedure Evaluate(var IsFormula : Boolean;
  637. var Formula : AnyString;
  638. var Value : Real;
  639. var ErrorPosition : Integer);
  640. var
  641. Position : Integer; { Current position in formula }
  642. EvalCh : Char; { Current Character being scanned }
  643. EXY : string[3]; { Intermediate string for conversion }
  644. function Expression(var ExpressionCh : Char):Real;forward;
  645. { Sub-function Fact returns the factorial value of the integer passed in}
  646. { as it's paramater. }
  647. function Fact(I : Real): Real;
  648. {WARNING: This program will not compile using TURBO-87.COM unless you
  649. have an 8087 math coprocessor installed in your computer. Use TURBO.
  650. COM to compile}
  651. begin
  652. if ((I > 0.0) and (I < 34.0)) then { check if value is in legal range.}
  653. Fact := I * Fact(I - 1) { Fact(34) is out of range. }
  654. else
  655. Fact := 1.0;
  656. end; { End sub-function Fact }
  657. { function Factor is the meat of procedure Evaluate. Within this pro- }
  658. { -cedure the current subexpression is actualy evaluated. Using nested }
  659. { If-Then-Else statements, the function determines if the sub-expression}
  660. { is a number, the sum of a subrange of cells (i.e A1>A5), or a }
  661. { function(i.e.ABS(X) ). }
  662. function Factor(var FactorCh : Char): Real;
  663. type
  664. { Declare a set of the standard functions }
  665. Standardfunction =
  666. (fabs,fsqrt,fsqr,fsin,fcos,farctan,fln,flog,fexp,ffact);
  667. { Declare array with indices being the Standard function names. }
  668. StandardfunctionList = array[Standardfunction] of string[6];
  669. const
  670. { Declare Typed Constant array initializing it with function names }
  671. StandardfunctionNames : StandardfunctionList =
  672. ('ABS','SQRT','SQR','SIN','COS','ARCTAN','LN','LOG','EXP','FACT');
  673. var
  674. E, EE, L : Integer; { temporary variables }
  675. Found : Boolean; { boolean value - expression found or not }
  676. CellSum, F : Real; { F holds value returned by recursive }
  677. { calls to Factor }
  678. Sf : Standardfunction;
  679. OldExpFY, { ExpEFX and ExpFY hold the positions of }
  680. ExpFY, { the cells referenced to in any formulas }
  681. SumFY, { SumFX and SumFY hold the sum to be }
  682. Start : Integer; { calculated at the fromula's position }
  683. OldExpFX, ExpFX, SumFX : ColumnName;
  684. begin { begin main block of function Factor }
  685. F := -1;
  686. if FactorCh in Numbers then { Get integer or real number }
  687. begin
  688. Start := Position; { Save first position of number in string }
  689. repeat { Skip to non number character }
  690. NextCh(Position,FactorCh,Formula);
  691. until not (FactorCh in Numbers);
  692. if FactorCh = '.' then { is decimal point }
  693. repeat
  694. NextCh(Position,FactorCh,Formula);
  695. until not (FactorCh in Numbers);
  696. if FactorCh = 'E' then { is Exponent symbol }
  697. begin
  698. NextCh(Position,FactorCh,Formula);
  699. repeat
  700. NextCh(Position,FactorCh,Formula)
  701. until not (FactorCh in Numbers);
  702. end;
  703. { Get value of number }
  704. Val(Copy(Formula,Start,Position - Start),F,ErrorPosition);
  705. if FactorCh = ')' then
  706. NextCh(Position,FactorCh,Formula);
  707. end { end if FactorCh in Numbers }
  708. else { FactorCh not a number }
  709. if FactorCh = '(' then
  710. begin
  711. NextCh(Position,FactorCh,Formula);
  712. F := Expression(FactorCh);
  713. if FactorCh = ')' then {if matching paren is found then read next }
  714. NextCh(Position,FactorCh,Formula)
  715. else { else there is an error in the expression. }
  716. ErrorPosition := Position;
  717. end { End if FactorCh = '(' }
  718. else { else FactorCh <> Number or '('}
  719. {FactorCh may be a cell reference or function name or a function name }
  720. if FactorCh in ['A'..'G','L','S'] then
  721. begin
  722. ExpFX := FactorCh;
  723. NextCh(Position,FactorCh,Formula);
  724. if FactorCh in Numbers then
  725. begin
  726. F := 0;
  727. EXY := FactorCh;
  728. NextCh(Position,FactorCh,Formula);
  729. if FactorCh in Numbers then
  730. begin
  731. EXY := EXY + FactorCh;
  732. NextCh(Position,FactorCh,Formula);
  733. end;
  734. Val(EXY,ExpFY,ErrorPosition);
  735. IsFormula := true; { the expression is a formula }
  736. { Check if content of the cell referenced in the formula is a }
  737. { constant. If so then verify that it has been calculated. If the }
  738. { constant has been calculated then make a recursive call to the }
  739. { procedure Evaluate to evaluate the contents of the cell. }
  740. if (Constant in Sheet[ExpFX,ExpFY].CellStatus) and
  741. not (Calculated in Sheet[ExpFX,ExpFY].CellStatus) then
  742. begin
  743. Evaluate(Form,Sheet[ExpFX,ExpFY].contents,f,ErrorPosition);
  744. { Update CellStatus to indicate that the cells value has been }
  745. { calculated. }
  746. Sheet[ExpFX,ExpFY].CellStatus :=
  747. Sheet[ExpFX,ExpFY].CellStatus + [Calculated]
  748. end { End if ... and not ... Statement }
  749. { The cell refered to either didn't contain a constant or the }
  750. { constants value was already calculated. }
  751. else { If the contents of the cell are not text then they must be }
  752. { a constant. }
  753. if not (Txt in Sheet[ExpFX,ExpFY].CellStatus) then
  754. F := Sheet[ExpFX,ExpFY].Value;
  755. if FactorCh = '>' then { Check for formula range designator }
  756. begin
  757. OldExpFX := ExpFX;
  758. OldExpFY := ExpFY;
  759. NextCh(Position,FactorCh,Formula);
  760. ExpFX := FactorCh;
  761. NextCh(Position,FactorCh,Formula);
  762. if FactorCh in Numbers then
  763. begin
  764. EXY := FactorCh;
  765. NextCh(Position,FactorCh,Formula);
  766. if FactorCh in Numbers then
  767. begin
  768. EXY := EXY + FactorCh;
  769. NextCh(Position,FactorCh,Formula);
  770. end;
  771. if FactorCh = ')' then
  772. NextCh(Position,FactorCh,Formula);
  773. val(EXY,ExpFY,ErrorPosition);
  774. Cellsum := 0;
  775. { visit each cell specified in sub-range of formula }
  776. for SumFY := OldExpFY to ExpFY do
  777. begin
  778. for SumFX := OldExpFX to ExpFX do
  779. begin
  780. F := 0;
  781. { Note that the next few statements are identical to the }
  782. { statements about fifty lines back. }
  783. if (Constant in Sheet[SumFX,SumFY].CellStatus) and
  784. not (Calculated in Sheet[SumFX,SumFY].CellStatus) then
  785. begin
  786. Evaluate(Form,Sheet[SumFX,SumFY].contents,f,ErrorPosition);
  787. Sheet[SumFX,SumFY].CellStatus :=
  788. Sheet[SumFX,SumFY].CellStatus+[Calculated];
  789. end
  790. else
  791. if not (Txt in Sheet[SumFX,SumFY].CellStatus) then
  792. F := Sheet[SumFX,SumFY].Value;
  793. Cellsum := Cellsum + f;
  794. f := Cellsum;
  795. end; { for SumFX := OldExpFX to ExpFX do }
  796. end; { for SumFY := OldExpFY to ExpFY do }
  797. end; { if FactorCh in Numbers then }
  798. end { if FactorCh = '>' then }
  799. else { FactorCh = ')' }
  800. if FactorCh = ')' then
  801. begin
  802. NextCh(Position,FactorCh,Formula);
  803. found := true;
  804. end;
  805. end { if FactorCh in Numbers then }
  806. else {FactorCh is second letter in function name (i.e. ABS or LN )}
  807. begin
  808. found := false;
  809. for sf := fabs to ffact do { step through all possible func's }
  810. if not found then
  811. begin
  812. l := Length(StandardfunctionNames[sf]);
  813. if copy(Formula,Position - 1,l) = StandardfunctionNames[sf] then
  814. begin
  815. Position := Position + l - 1;
  816. NextCh(Position,FactorCh,Formula);
  817. F := Expression(FactorCh);
  818. case sf of
  819. fabs : f := abs(f);
  820. fsqrt : begin
  821. if f > 0 then
  822. f := sqrt(f) { WARNING: This progam will not
  823. compile with TURBOBCD.COM. (Sqrt,
  824. Sin, and similar operations are
  825. not implemented in the BCD
  826. version.) Use TURBO.COM to
  827. compile. }
  828. else
  829. F := -1;
  830. end;
  831. fsqr : begin
  832. if Abs(f) < Sqrt(exp(38) * ln(1)) then
  833. f := sqr(f)
  834. else
  835. F := -1;
  836. end;
  837. fsin : f := sin(f);
  838. fcos : f := cos(f);
  839. farctan : f := arctan(f);
  840. fln : f := ln(f);
  841. flog : f := ln(f)/ln(10);
  842. fexp : begin
  843. if abs(f) < 89 then { Exp(+/-89) will cause }
  844. f := exp(f) { floating point Overflow. }
  845. else
  846. f := -1;
  847. end;
  848. ffact : f := fact(int(f));
  849. end; { end case }
  850. Found := true;
  851. end; { if then Statement }
  852. end; { if not found Statement }
  853. if not Found then
  854. ErrorPosition := Position;
  855. end; { else statement }
  856. end; { if FactorCh in ['A'..'G'] then }
  857. Factor := F;
  858. end; { End Sub-function Factor}
  859. { Sub-function Signed Factor first determines the sign of the exp- }
  860. { -ression. It then calls the function Factor to get the value of the }
  861. { expression. }
  862. function SignedFactor(var SignedCh : Char):Real;
  863. begin { begin main block of procedure SignedFactor }
  864. if SignedCh = '-' then
  865. begin
  866. NextCh(Position,SignedCh,Formula);
  867. SignedFactor := -Factor(SignedCh);
  868. end
  869. else
  870. SignedFactor := Factor(SignedCh);
  871. end; { End Sub-function SignedFactor }
  872. { Sub-function Term returns the value of the sub-expression being eval- }
  873. { -uated. If the expression contains an exponent expression Term eval- }
  874. { -uates it. }
  875. function Term(var TermCh : Char):Real;
  876. var
  877. T : Real;
  878. begin { begin main block of procedure Term }
  879. T := SignedFactor(TermCh);
  880. while TermCh = '^' do
  881. begin
  882. NextCh(Position,TermCh,Formula);
  883. T := exp(ln(t) * SignedFactor(TermCh));
  884. end;
  885. Term := T;
  886. end; { End Sub-function Term }
  887. { Sub-function SimpleExpression calls the function term and evaluates }
  888. { the simple expression returned. }
  889. function SimpleExpression(var SimpleExpCh : Char):Real;
  890. var
  891. SimpExp : Real;
  892. Opr : Char;
  893. begin { begin main block of procedure SimpleExpression }
  894. SimpExp := Term(SimpleExpCh);
  895. while SimpleExpCh in ['*','/'] do
  896. begin
  897. Opr := SimpleExpCh;
  898. NextCh(Position,SimpleExpCh,Formula);
  899. case Opr of
  900. '*' : SimpExp := SimpExp * term(SimpleExpCh);
  901. '/' : SimpExp := SimpExp / term(SimpleExpCh);
  902. end;
  903. end;
  904. SimpleExpression := SimpExp;
  905. end; { End Sub-function SimpleExpression }
  906. { Sub-function Expression evaluates the expression contained in the }
  907. { current cell. }
  908. function Expression{(var ExpressionCh : Char):Real;forward};
  909. var
  910. E : Real;
  911. Opr : Char;
  912. begin { begin main block of function Expression }
  913. E := SimpleExpression(ExpressionCh);
  914. while ExpressionCh in ['+','-'] do
  915. begin
  916. Opr := ExpressionCh;
  917. NextCh(Position,ExpressionCh,Formula);
  918. case Opr of
  919. '+' : E := E +
  920. SimpleExpression(ExpressionCh);
  921. '-' : E := E -
  922. SimpleExpression(ExpressionCh);
  923. end;
  924. end;
  925. Expression := E;
  926. end; { End Sub-function Expression }
  927. begin { main body of procedure Evaluate }
  928. if Formula[1] = '.' then
  929. Formula := '0' + Formula;
  930. if Formula[1] = '+' then
  931. delete(Formula,1,1);
  932. IsFormula := false;
  933. Position := 0;
  934. NextCh(Position,EvalCh,Formula);
  935. Value := Expression(EvalCh);
  936. if EvalCh = EofLine then
  937. ErrorPosition := 0
  938. else
  939. ErrorPosition := Position;
  940. end; { End procedure Evaluate }
  941. { procedure Recalculate steps through the entire spreadsheet recalculating}
  942. { each cell. }
  943. procedure Recalculate;
  944. var
  945. RFX : ColumnName;
  946. RFY : Integer;
  947. OldValue : Real;
  948. Err : Integer;
  949. begin
  950. LowVideo;
  951. GotoXY(1,24);
  952. ClrEol;
  953. Write('Calculating..');
  954. for RFY := 1 to FYMax do { Reevaluate each cell updating it's }
  955. begin { contents when appropriate. }
  956. for RFX := 'A' to FXMax do
  957. begin
  958. with Sheet[RFX,RFY] do
  959. begin
  960. if (Formula in CellStatus) then
  961. begin
  962. CellStatus := CellStatus + [Calculated];
  963. OldValue := Value;
  964. Evaluate(Form,Contents,Value,Err);
  965. if OldValue <> Value then
  966. begin
  967. GotoXY(XPos[RFX],RFY + 1);
  968. if (DEC >= 0) then
  969. Write(Value:FW:DEC)
  970. else
  971. Write(Value:FW);
  972. end;
  973. end;
  974. end;
  975. end;
  976. end;
  977. GotoCell(FX,FY);
  978. end; { End procedure Recalculate }
  979. {*************************************************************************}
  980. { MicroCalc Module 005 }
  981. { Last Modified 7-22-85 }
  982. { }
  983. { PURPOSE: Read the contents of a cell and update }
  984. { associated cells. }
  985. { }
  986. {*************************************************************************}
  987. { procedure GetCell gets the contents of a cell from the user. This }
  988. { routine gets all input entered by the user. procedure GetCell }
  989. { initializes the temporary variable "S" with the last read Character. }
  990. { Depending on this character, it then calls GetFormula, GetText, or }
  991. { EditCell. }
  992. procedure GetCell(FX : ColumnName; FY : Integer);
  993. var
  994. S : AnyString;
  995. NewStatus : SetofAttri;
  996. ErrorPosition : Integer;
  997. EvalResult : Real;
  998. I : ColumnName;
  999. Abort,
  1000. IsForm : Boolean;
  1001. { Sub-procedure ClearCells clears the current cell and its associated }
  1002. { cells. An associated cell is a cell overwritten by data from the cur- }
  1003. { -rent cell. The data can be text in which case the cell has the attri-}
  1004. { -bute "OverWritten". If the data is a result from an expression and }
  1005. { the field width is larger than 11 then the associated cell is }
  1006. { "Locked." }
  1007. procedure ClearCells(FX : ColumnName; FY : Integer);
  1008. var
  1009. I : ColumnName;
  1010. begin
  1011. I := FX;
  1012. repeat
  1013. with Sheet[I,FY] do
  1014. begin
  1015. GotoXY(XPos[I],FY + 1);
  1016. write(' ');
  1017. I := Succ(I);
  1018. end;
  1019. { Cell is not OverWritten not Locked }
  1020. until ([OverWritten,Locked] * Sheet[I,FY].CellStatus = []);
  1021. end; { End Sub-procedure ClearCells }
  1022. { Sub-procedure GetLine is the routine used to get input from the user. }
  1023. { The procedure allows editing of input and checks that the input con- }
  1024. { -tains legal characters. }
  1025. procedure GetLine(ColNO, LineNO, { Where to start line }
  1026. MAX : Integer; { Max length }
  1027. UpperCase : Boolean);{ True if auto Upcase }
  1028. var
  1029. X : Integer;
  1030. InsertOn : boolean;
  1031. OkChars : set of Char;
  1032. procedure GotoX;
  1033. begin
  1034. GotoXY(X + ColNo - 1,LineNo);
  1035. end;
  1036. begin
  1037. OkChars := [' '..'}'];
  1038. InsertOn := true;
  1039. X := 1;
  1040. GotoX;
  1041. Write(S);
  1042. if Length(S) = 1 then
  1043. X := 2;
  1044. if ErrorPosition <> 0 then { there was an error found }
  1045. X := ErrorPosition;
  1046. GotoX;
  1047. repeat
  1048. Read(Kbd,Ch);
  1049. if KeyPressed then
  1050. begin
  1051. Read(kbd,Ch);
  1052. IBMCh(Ch);
  1053. end;
  1054. if UpperCase then
  1055. Ch := UpCase(Ch);
  1056. case Ch of
  1057. ^[ : begin
  1058. S := chr($FF); { abort editing }
  1059. Ch := ^M;
  1060. end;
  1061. ^D : begin { Move cursor right }
  1062. X := X + 1;
  1063. if (X > length(S) + 1) or (X > MAX) then
  1064. X := X - 1;
  1065. GotoX;
  1066. end;
  1067. ^G : begin { Delete Char under cursor }
  1068. if X <= Length(S) then
  1069. begin
  1070. Delete(S,X,1);
  1071. Write(copy(S,X,Length(S) - X + 1),' ');
  1072. GotoX;
  1073. end;
  1074. end;
  1075. ^S,^H : begin { Move cursor left }
  1076. X := X - 1;
  1077. if X < 1 then
  1078. X := 1;
  1079. GotoX;
  1080. end;
  1081. ^F : begin { Move cursor to end of line }
  1082. X := Length(S) + 1;
  1083. GotoX;
  1084. end;
  1085. ^A : begin { Move cursor to beginning of line }
  1086. X := 1;
  1087. GotoX;
  1088. end;
  1089. #127 : begin { Delete left Char }
  1090. X := X - 1;
  1091. if (Length(S) > 0) and (X > 0) then
  1092. begin
  1093. Delete(S,X,1);
  1094. Write(copy(S,X,Length(S) - X + 1),' ');
  1095. GotoX;
  1096. if X < 1 then
  1097. X := 1;
  1098. end
  1099. else
  1100. X := 1;
  1101. end;
  1102. ^V : InsertOn := not InsertOn; { Toggle Insert/Overwrite }
  1103. else { Not Upcase }
  1104. begin
  1105. if Ch in OkChars then
  1106. begin
  1107. if InsertOn then
  1108. begin
  1109. insert(Ch,S,X);
  1110. Write(copy(S,X,Length(S) - X + 1),' ');
  1111. end
  1112. else
  1113. begin
  1114. write(Ch);
  1115. if X = length(S) then
  1116. S := S + Ch
  1117. else
  1118. S[X] := Ch;
  1119. end;
  1120. if Length(S) + 1 <= MAX then
  1121. X := X + 1
  1122. else
  1123. OkChars := []; { Line too Long }
  1124. GotoX;
  1125. end { end if Ch in OkChars }
  1126. else
  1127. if Length(S) + 1 <= Max then
  1128. OkChars:= [' '..'}']; { Line ok again }
  1129. end; { end case statement's else }
  1130. end; { end case statement }
  1131. until CH = ^M;
  1132. end; { End Sub-procedure GetLine }
  1133. { Sub-procedure GetText calls the procedure GetLine with the current }
  1134. { cells X,Y position as parameters. This means that text entering takes }
  1135. { place direcly at the cells position on the Sheet. }
  1136. procedure GetText;
  1137. var
  1138. LineLength : Integer;
  1139. begin
  1140. GotoXY(5,23);
  1141. LowVideo;
  1142. if FX = 'G' then
  1143. LineLength := 10
  1144. else
  1145. LineLength := 70;
  1146. with Sheet[FX,FY] do
  1147. GetLine(XPos[FX],FY+1,LineLength,False);
  1148. end; { End Sub-procedure GetText }
  1149. { Sub-procedure GetFormula calls the routine GetLine to get a line from }
  1150. { the user. It then calls the routine Evaluate to evaluate the Formula }
  1151. { input by the user. }
  1152. procedure GetFormula;
  1153. begin
  1154. GotoXY(5,23);
  1155. LowVideo;
  1156. repeat
  1157. GetLine(1,24,70,True);
  1158. if S <> Chr($FF) then
  1159. begin
  1160. Evaluate(IsForm,S,EvalResult ,ErrorPosition);
  1161. if ErrorPosition <> 0 then
  1162. Flash(15,'GetFormula Error at cursor' + ^G,false)
  1163. else
  1164. Flash(15,'get formula ok',false);
  1165. end;
  1166. until (ErrorPosition = 0) or (S = Chr($FF));
  1167. if IsForm then
  1168. NewStatus := NewStatus + [Formula];
  1169. end; { End Sub-procedure GetFormula }
  1170. { Sub-procedure EditCell loads a copy of the current cell's contents }
  1171. { into the variable S before calling either GetText or GetFormula. In }
  1172. { this way no changes are actually made to the current cell. }
  1173. procedure EditCell;
  1174. begin
  1175. GotoXY(5,23);
  1176. with Sheet[FX,FY] do
  1177. begin
  1178. S := Contents;
  1179. if Txt in CellStatus then
  1180. GetText
  1181. else
  1182. GetFormula;
  1183. end;
  1184. end; { End procedure EditCell }
  1185. { Sub-procedure UpdateCells is a little more complicated. Basically it }
  1186. { makes sure to tag and untag cells which have been overwritten or }
  1187. { cleared by data from another cell. It also updates the current cell }
  1188. { with the new type and contents which are still in the temporary }
  1189. { variable "S". }
  1190. procedure UpdateCells;
  1191. var
  1192. I : ColumnName;
  1193. Flength : Integer;
  1194. begin
  1195. Sheet[FX,FY].Contents := S;
  1196. if Txt in NewStatus then
  1197. begin
  1198. I := FX;
  1199. FLength := Length(S);
  1200. repeat { this repeat loop checks the status of adjoining cells to }
  1201. { verify that they have or have not been overwritten. }
  1202. I := Succ(I);
  1203. with Sheet[I,FY] do
  1204. begin
  1205. FLength := Flength - 11;
  1206. if (Flength > 0) then
  1207. begin
  1208. CellStatus := [Overwritten,Txt];
  1209. Contents := '';
  1210. end
  1211. else
  1212. begin
  1213. if OverWritten in CellStatus then
  1214. begin
  1215. CellStatus := [Txt];
  1216. GotoCell(I,FY);
  1217. LeaveCell(I,FY);
  1218. end; { if OverWritten in CellStatus }
  1219. end; { else }
  1220. end; { with Sheet[I,FY] do }
  1221. until (I = FXMax) or (Sheet[I,FY].Contents <> '');
  1222. Sheet[FX,FY].CellStatus := [Txt];
  1223. end
  1224. else { string changed to formula or constant }
  1225. begin
  1226. I := FX;
  1227. repeat { this repeat loop checks whether or not the cell is }
  1228. { overwritten. }
  1229. with Sheet[I,FY] do
  1230. begin
  1231. if OverWritten in CellStatus then
  1232. begin
  1233. CellStatus := [Txt];
  1234. Contents := '';
  1235. end;
  1236. I := Succ(I);
  1237. end;
  1238. until not (OverWritten in Sheet[I,FY].CellStatus);
  1239. with Sheet[FX,FY] do
  1240. begin
  1241. CellStatus := [Constant];
  1242. if IsForm then
  1243. CellStatus := CellStatus + [Formula];
  1244. Value := EvalResult ;
  1245. end; { with }
  1246. end; { else }
  1247. end; { End Sub-procedure UpdateCells }
  1248. begin { begin main block of procedure GetCell }
  1249. S := Ch;
  1250. ErrorPosition := 0;
  1251. Abort := false;
  1252. NewStatus := [];
  1253. EvalResult := -1;
  1254. if Ch in ['0'..'9','+','-','.','(',')'] then
  1255. begin
  1256. NewStatus := [Constant];
  1257. if not (Formula in Sheet[FX,FY].CellStatus) then
  1258. begin
  1259. GotoXY(11,24);
  1260. ClrEol;
  1261. ClearCells(FX,FY);
  1262. GetFormula;
  1263. end
  1264. else { Formula in Sheet[FX,FY].CellStatus }
  1265. begin
  1266. Flash(15,'Edit formula Y/N?',true);
  1267. repeat
  1268. read(Kbd,Ch)
  1269. until UpCase(CH) in ['Y','N'];
  1270. Flash(15,' ',false);
  1271. if UpCase(Ch) = 'Y' then
  1272. begin
  1273. EditCell;
  1274. end
  1275. Else
  1276. Abort := true;
  1277. end;
  1278. end
  1279. else { Ch not in ['0'..'9','+','-','.','(',')'] }
  1280. begin
  1281. if Ch = ^[ then
  1282. begin
  1283. NewStatus := (Sheet[FX,FY].CellStatus) * [Txt,Constant];
  1284. EditCell;
  1285. end
  1286. else { Ch <> '^[' and not in ['0'..'9','+','-','.','(',')'] }
  1287. begin
  1288. if formula in Sheet[FX,FY].CellStatus then
  1289. begin
  1290. Flash(15,'Edit formula Y/N?',true);
  1291. repeat
  1292. read(Kbd,Ch)
  1293. until UpCase(CH) in ['Y','N'];
  1294. Flash(15,' ',false);
  1295. if UpCase(Ch) = 'Y' then
  1296. begin
  1297. EditCell;
  1298. end
  1299. Else
  1300. Abort := true;
  1301. end
  1302. else { formula not in Sheet[FX,FY].CellStatus }
  1303. begin
  1304. NewStatus := [Txt];
  1305. ClearCells(FX,FY);
  1306. GetText;
  1307. end; { End else }
  1308. end; { end else }
  1309. end; { end else }
  1310. if not Abort then { do neccesary bookkeeping }
  1311. begin
  1312. if S <> Chr($FF) then
  1313. UpDateCells;
  1314. GotoCell(FX,FY);
  1315. if AutoCalc and (Constant in Sheet[FX,FY].CellStatus) then
  1316. Recalculate;
  1317. if Txt in NewStatus then
  1318. begin
  1319. GotoXY(3,FY + 1);
  1320. Clreol;
  1321. For I := 'A' to FXMax do
  1322. LeaveCell(I,FY);
  1323. end;
  1324. end; { end if not abort }
  1325. Flash(15,' ',False);
  1326. GotoCell(FX,FY);
  1327. end; { End procedure GetCell }
  1328. { procedure Format is used to modify the numeric format of a range of }
  1329. { cells in the current column. }
  1330. procedure Format;
  1331. var
  1332. J, FW, DEC,
  1333. FromLine, ToLine : Integer;
  1334. Lock : Boolean;
  1335. { procedure GetInt reads an integer from the keyboard screening it for }
  1336. { illegal characters. }
  1337. procedure GetInt(var I: Integer; Max: Integer);
  1338. var
  1339. S : String[8];
  1340. Result : Integer;
  1341. Ch : Char;
  1342. begin
  1343. S := '';
  1344. repeat
  1345. repeat Read( Kbd,Ch) until Ch in ['0'..'9','-',^M];
  1346. if Ch <> ^M then
  1347. begin
  1348. Write(Ch);
  1349. S := S + Ch;
  1350. Val(S,I,Result);
  1351. end;
  1352. until (I >= Max) or (Ch = ^M);
  1353. if I > Max then I := Max;
  1354. end; { End Subprocedure GetInt }
  1355. begin
  1356. NormVideo;
  1357. Msg('Format: Enter number of places beyond decimal point (Max 11) : ');
  1358. GetInt(DEC,11);
  1359. Msg('Enter Cell width (if larger than 10 next column will be locked) : ');
  1360. GetInt(FW,20);
  1361. Msg('From which line in column '+ FX +' : ');
  1362. GetInt(FromLine,FYMax);
  1363. Msg('To which line in column '+ FX +' : ');
  1364. GetInt(ToLine,FYMax);
  1365. if FW > 10 then
  1366. Lock := true
  1367. else
  1368. Lock := False;
  1369. for J := FromLine to ToLine do { Format specified cells within }
  1370. begin { current column. }
  1371. Sheet[FX,J].DEC := DEC;
  1372. Sheet[FX,J].FW := FW;
  1373. with Sheet[Succ(FX),J] do
  1374. begin
  1375. if Lock then
  1376. begin
  1377. CellStatus := CellStatus + [Locked,Txt];
  1378. Contents := '';
  1379. end
  1380. else
  1381. CellStatus :=CellStatus - [Locked];
  1382. end; { End With Statement }
  1383. end; { End For Loop }
  1384. NormVideo;
  1385. UpDate;
  1386. GotoCell(FX,FY);
  1387. end; { End procedure Format }
  1388. { Procedure Commands is called from the program's main loop when the user }
  1389. { types a slash '/'. The procedure in turn calls the appropriate procedure}
  1390. { based on the users response to the menu displayed. }
  1391. { }
  1392. { For easy reference the source code module number is shown in a comment }
  1393. { on the right following the procedure call. }
  1394. Procedure Commands;
  1395. begin
  1396. GotoXY(1,24);
  1397. NormVideo;
  1398. Write('Update, Quit, Load, Save, Recalculate, Print, Format, AutoCalc, Help ');
  1399. ClrEol;
  1400. Read(KBD,Ch);
  1401. Ch := UpCase(Ch);
  1402. case Ch of { module # }
  1403. 'Q': Halt; { Halt execution of program }
  1404. 'F': Format; { Format a range of cells 005 }
  1405. 'S': Save; { Save the current spreadsheet to a file 003 }
  1406. 'L': Load; { Load a spreadsheet from a file 003 }
  1407. 'H': Help; { Call the Help procedure 003 }
  1408. 'R': Recalculate; { Recalculate spreadsheet 005 }
  1409. 'A': Auto; { Toggle AutoCalc On or Off 000 }
  1410. 'U': Update; { Redraw the screen 001 }
  1411. 'C': Clear; { Clear screen of spreadsheet 001 }
  1412. 'P': Print; { Print spreadsheet to a file 003 }
  1413. end;
  1414. Grid; { 001 }
  1415. GotoCell(FX,FY); { 002 }
  1416. end; { End Procedure Commands }
  1417.