From cef8f335d06ff242e0c454c173054ce85f911400 Mon Sep 17 00:00:00 2001 From: davidly Date: Tue, 2 Jul 2024 06:49:04 -0700 Subject: [PATCH] Borland Turbo Pascal v5.5 --- Borland Turbo Pascal v55/ARTY.PAS | 383 ++++ Borland Turbo Pascal v55/ATT.BGI | Bin 0 -> 6269 bytes Borland Turbo Pascal v55/BGIDEMO.PAS | 1423 ++++++++++++++ Borland Turbo Pascal v55/BGILINK.MAK | 31 + Borland Turbo Pascal v55/BGILINK.PAS | 126 ++ Borland Turbo Pascal v55/BINOBJ.EXE | Bin 0 -> 10220 bytes Borland Turbo Pascal v55/BOUNDS.PAS | 329 ++++ Borland Turbo Pascal v55/BREAKOUT.PAS | 302 +++ Borland Turbo Pascal v55/BRICKS.PAS | 151 ++ Borland Turbo Pascal v55/BUFSTM.ASM | 219 +++ Borland Turbo Pascal v55/BUFSTM.OBJ | Bin 0 -> 655 bytes Borland Turbo Pascal v55/CARDFILE.PAS | 137 ++ Borland Turbo Pascal v55/CARDGEN.PAS | 76 + Borland Turbo Pascal v55/CARDS.DTA | Bin 0 -> 690 bytes Borland Turbo Pascal v55/CARDS.PAS | 136 ++ Borland Turbo Pascal v55/CGA.BGI | Bin 0 -> 6253 bytes Borland Turbo Pascal v55/CIRCULAR.PAS | 24 + Borland Turbo Pascal v55/COUNT.PAS | 239 +++ Borland Turbo Pascal v55/CPASDEMO.C | 75 + Borland Turbo Pascal v55/CPASDEMO.PAS | 126 ++ Borland Turbo Pascal v55/CRTDEMO.PAS | 147 ++ Borland Turbo Pascal v55/CTOPAS.TC | Bin 0 -> 1711 bytes Borland Turbo Pascal v55/DIRDEMO.PAS | 240 +++ Borland Turbo Pascal v55/DISPLAY.PAS | 27 + Borland Turbo Pascal v55/DOC/CRT.DOC | 95 + Borland Turbo Pascal v55/DOC/DOS.DOC | 152 ++ Borland Turbo Pascal v55/DOC/GRAPH.DOC | 338 ++++ Borland Turbo Pascal v55/DOC/GRAPH3.DOC | 66 + Borland Turbo Pascal v55/DOC/HELPME!.DOC | 454 +++++ Borland Turbo Pascal v55/DOC/OVERLAY.DOC | 47 + Borland Turbo Pascal v55/DOC/PRINTER.DOC | 19 + Borland Turbo Pascal v55/DOC/SYSTEM.DOC | 61 + Borland Turbo Pascal v55/DOC/THELP.DOC | 334 ++++ Borland Turbo Pascal v55/DOC/TURBO3.DOC | 33 + Borland Turbo Pascal v55/DOSSTM.ASM | 221 +++ Borland Turbo Pascal v55/DOSSTM.OBJ | Bin 0 -> 653 bytes Borland Turbo Pascal v55/DOS_GT.BAK | 28 + Borland Turbo Pascal v55/DOS_GT.PAS | 27 + Borland Turbo Pascal v55/DRIVERS.PAS | 35 + Borland Turbo Pascal v55/E.PAS | 42 + Borland Turbo Pascal v55/EGAVGA.BGI | Bin 0 -> 5363 bytes Borland Turbo Pascal v55/EMS.PAS | 439 +++++ Borland Turbo Pascal v55/ERROR.PAS | 22 + Borland Turbo Pascal v55/EXECDEMO.EXE | Bin 0 -> 3040 bytes Borland Turbo Pascal v55/EXECDEMO.MAP | 71 + Borland Turbo Pascal v55/EXECDEMO.PAS | 41 + Borland Turbo Pascal v55/FDEMO.PAS | 83 + Borland Turbo Pascal v55/FIB8087.PAS | 45 + Borland Turbo Pascal v55/FIGDEMO.PAS | 94 + Borland Turbo Pascal v55/FIGURES.PAS | 201 ++ Borland Turbo Pascal v55/FONTS.PAS | 31 + Borland Turbo Pascal v55/FORMS.PAS | 571 ++++++ Borland Turbo Pascal v55/GOTH.CHR | Bin 0 -> 8560 bytes Borland Turbo Pascal v55/GRAPH.TPU | Bin 0 -> 31584 bytes Borland Turbo Pascal v55/GREP.COM | Bin 0 -> 7029 bytes Borland Turbo Pascal v55/HERC.BGI | Bin 0 -> 6125 bytes Borland Turbo Pascal v55/HILB.PAS | 246 +++ Borland Turbo Pascal v55/IBM8514.BGI | Bin 0 -> 6665 bytes Borland Turbo Pascal v55/LISTDEMO.PAS | 187 ++ Borland Turbo Pascal v55/LISTER.PAS | 212 ++ Borland Turbo Pascal v55/LITT.CHR | Bin 0 -> 2138 bytes Borland Turbo Pascal v55/MAKE.EXE | Bin 0 -> 27174 bytes Borland Turbo Pascal v55/OBJECTS.INC | 95 + Borland Turbo Pascal v55/OBJECTS.PAS | 459 +++++ Borland Turbo Pascal v55/OBJECTS.TPU | Bin 0 -> 9088 bytes Borland Turbo Pascal v55/ODEMO.PAS | 161 ++ Borland Turbo Pascal v55/OOPDEMOS.DOC | 678 +++++++ Borland Turbo Pascal v55/OVRDEMO.OVR | Bin 0 -> 100 bytes Borland Turbo Pascal v55/OVRDEMO.PAS | 53 + Borland Turbo Pascal v55/OVRDEMO1.PAS | 20 + Borland Turbo Pascal v55/OVRDEMO1.TPU | Bin 0 -> 576 bytes Borland Turbo Pascal v55/OVRDEMO2.PAS | 20 + Borland Turbo Pascal v55/OVRDEMO2.TPU | Bin 0 -> 576 bytes Borland Turbo Pascal v55/PC3270.BGI | Bin 0 -> 6029 bytes Borland Turbo Pascal v55/POINTS.PAS | 88 + Borland Turbo Pascal v55/PROCVAR.PAS | 43 + Borland Turbo Pascal v55/QSORT.PAS | 67 + Borland Turbo Pascal v55/README | 285 +++ Borland Turbo Pascal v55/README.COM | Bin 0 -> 4217 bytes Borland Turbo Pascal v55/SANS.CHR | Bin 0 -> 5438 bytes Borland Turbo Pascal v55/SCREEN.PAS | 200 ++ Borland Turbo Pascal v55/SIEVE.PAS | 31 + Borland Turbo Pascal v55/SLIDERS.PAS | 111 ++ Borland Turbo Pascal v55/STREAM.ASM | 144 ++ Borland Turbo Pascal v55/STREAM.OBJ | Bin 0 -> 388 bytes Borland Turbo Pascal v55/TCALC.DOC | 157 ++ Borland Turbo Pascal v55/TCALC.PAS | 18 + Borland Turbo Pascal v55/TCCELL.PAS | 1926 +++++++++++++++++++ Borland Turbo Pascal v55/TCCELL.TPU | Bin 0 -> 38816 bytes Borland Turbo Pascal v55/TCCELLSP.PAS | 228 +++ Borland Turbo Pascal v55/TCCELLSP.TPU | Bin 0 -> 4944 bytes Borland Turbo Pascal v55/TCCOMPAR.ASM | 41 + Borland Turbo Pascal v55/TCCOMPAR.OBJ | Bin 0 -> 190 bytes Borland Turbo Pascal v55/TCHASH.PAS | 262 +++ Borland Turbo Pascal v55/TCHASH.TPU | Bin 0 -> 4480 bytes Borland Turbo Pascal v55/TCINPUT.PAS | 334 ++++ Borland Turbo Pascal v55/TCINPUT.TPU | Bin 0 -> 6496 bytes Borland Turbo Pascal v55/TCLSTR.PAS | 243 +++ Borland Turbo Pascal v55/TCLSTR.TPU | Bin 0 -> 4432 bytes Borland Turbo Pascal v55/TCMENU.PAS | 234 +++ Borland Turbo Pascal v55/TCMENU.TPU | Bin 0 -> 4528 bytes Borland Turbo Pascal v55/TCMVSMEM.ASM | 152 ++ Borland Turbo Pascal v55/TCMVSMEM.OBJ | Bin 0 -> 371 bytes Borland Turbo Pascal v55/TCPARSER.PAS | 677 +++++++ Borland Turbo Pascal v55/TCPARSER.TPU | Bin 0 -> 11968 bytes Borland Turbo Pascal v55/TCRUN.PAS | 1366 +++++++++++++ Borland Turbo Pascal v55/TCRUN.TPU | Bin 0 -> 24592 bytes Borland Turbo Pascal v55/TCSCREEN.PAS | 523 +++++ Borland Turbo Pascal v55/TCSCREEN.TPU | Bin 0 -> 10272 bytes Borland Turbo Pascal v55/TCSHEET.PAS | 1722 +++++++++++++++++ Borland Turbo Pascal v55/TCSHEET.TPU | Bin 0 -> 33312 bytes Borland Turbo Pascal v55/TCUTIL.PAS | 379 ++++ Borland Turbo Pascal v55/TCUTIL.TPU | Bin 0 -> 7552 bytes Borland Turbo Pascal v55/THELP.COM | Bin 0 -> 28246 bytes Borland Turbo Pascal v55/THELP.SW1 | Bin 0 -> 32752 bytes Borland Turbo Pascal v55/TIMEUTIL.PAS | 66 + Borland Turbo Pascal v55/TINST.EXE | Bin 0 -> 68784 bytes Borland Turbo Pascal v55/TINSTXFR.EXE | Bin 0 -> 18106 bytes Borland Turbo Pascal v55/TINY.EXE | Bin 0 -> 1840 bytes Borland Turbo Pascal v55/TINY.PAS | 5 + Borland Turbo Pascal v55/TOUCH.COM | Bin 0 -> 5118 bytes Borland Turbo Pascal v55/TOUR.EXE | Bin 0 -> 79065 bytes Borland Turbo Pascal v55/TPC.CFG | 1 + Borland Turbo Pascal v55/TPC.EXE | Bin 0 -> 61926 bytes Borland Turbo Pascal v55/TPCONFIG.EXE | Bin 0 -> 14484 bytes Borland Turbo Pascal v55/TPTOUR1.CBT | Bin 0 -> 993 bytes Borland Turbo Pascal v55/TPTOUR2.CBT | Bin 0 -> 97656 bytes Borland Turbo Pascal v55/TPUMOVER.EXE | Bin 0 -> 33120 bytes Borland Turbo Pascal v55/TRIP.CHR | Bin 0 -> 7241 bytes Borland Turbo Pascal v55/TTT.PAS | 390 ++++ Borland Turbo Pascal v55/TURBO.EXE | Bin 0 -> 156321 bytes Borland Turbo Pascal v55/TURBO.HLP | Bin 0 -> 240493 bytes Borland Turbo Pascal v55/TURBO.TP | Bin 0 -> 1226 bytes Borland Turbo Pascal v55/TURBO.TPL | Bin 0 -> 44352 bytes Borland Turbo Pascal v55/TURBO3/BCD.PAS | 158 ++ Borland Turbo Pascal v55/TURBO3/GRAPH3.TPU | Bin 0 -> 7232 bytes Borland Turbo Pascal v55/TURBO3/TURBO3.TPU | Bin 0 -> 1808 bytes Borland Turbo Pascal v55/TURBO3/UPGRADE.DTA | Bin 0 -> 25290 bytes Borland Turbo Pascal v55/TURBO3/UPGRADE.EXE | Bin 0 -> 43168 bytes Borland Turbo Pascal v55/TURBOC.CFG | 13 + Borland Turbo Pascal v55/UNPACK.COM | Bin 0 -> 14716 bytes Borland Turbo Pascal v55/WALLS.PAS | 205 ++ Borland Turbo Pascal v55/WIN.ASM | 285 +++ Borland Turbo Pascal v55/WIN.OBJ | Bin 0 -> 671 bytes Borland Turbo Pascal v55/WIN.PAS | 131 ++ Borland Turbo Pascal v55/WINDEMO.PAS | 207 ++ Borland Turbo Pascal v55/chess/CHESS.EXE | Bin 0 -> 53776 bytes Borland Turbo Pascal v55/chess/CHESS.HLP | Bin 0 -> 30294 bytes Borland Turbo Pascal v55/chess/CHESS.PAS | 161 ++ Borland Turbo Pascal v55/chess/DISPLAY.PAS | 638 ++++++ Borland Turbo Pascal v55/chess/EGAVGA.BGI | Bin 0 -> 5363 bytes Borland Turbo Pascal v55/chess/EXAMPLE.CHS | Bin 0 -> 8191 bytes Borland Turbo Pascal v55/chess/HELPGEN.EXE | Bin 0 -> 3296 bytes Borland Turbo Pascal v55/chess/HELPGEN.PAS | 45 + Borland Turbo Pascal v55/chess/HELPTEXT.TXT | 361 ++++ Borland Turbo Pascal v55/chess/IMAGE.EXE | Bin 0 -> 20624 bytes Borland Turbo Pascal v55/chess/IMAGE.PAS | 89 + Borland Turbo Pascal v55/chess/INIT.PAS | 124 ++ Borland Turbo Pascal v55/chess/INPUT.PAS | 150 ++ Borland Turbo Pascal v55/chess/MENU.PAS | 636 ++++++ Borland Turbo Pascal v55/chess/MISC.PAS | 154 ++ Borland Turbo Pascal v55/chess/MOVES.PAS | 534 +++++ Borland Turbo Pascal v55/chess/PIECES.IMG | Bin 0 -> 63000 bytes Borland Turbo Pascal v55/chess/PIECES.TXT | 386 ++++ Borland Turbo Pascal v55/chess/PLAY.PAS | 720 +++++++ Borland Turbo Pascal v55/chess/README.BAT | 1 + Borland Turbo Pascal v55/chess/README.TXT | 53 + Borland Turbo Pascal v55/chess/SETUP.PAS | 326 ++++ Borland Turbo Pascal v55/chess/TRIP.CHR | Bin 0 -> 7241 bytes Borland Turbo Pascal v55/m.bat | 3 + 170 files changed, 24945 insertions(+) create mode 100644 Borland Turbo Pascal v55/ARTY.PAS create mode 100644 Borland Turbo Pascal v55/ATT.BGI create mode 100644 Borland Turbo Pascal v55/BGIDEMO.PAS create mode 100644 Borland Turbo Pascal v55/BGILINK.MAK create mode 100644 Borland Turbo Pascal v55/BGILINK.PAS create mode 100644 Borland Turbo Pascal v55/BINOBJ.EXE create mode 100644 Borland Turbo Pascal v55/BOUNDS.PAS create mode 100644 Borland Turbo Pascal v55/BREAKOUT.PAS create mode 100644 Borland Turbo Pascal v55/BRICKS.PAS create mode 100644 Borland Turbo Pascal v55/BUFSTM.ASM create mode 100644 Borland Turbo Pascal v55/BUFSTM.OBJ create mode 100644 Borland Turbo Pascal v55/CARDFILE.PAS create mode 100644 Borland Turbo Pascal v55/CARDGEN.PAS create mode 100644 Borland Turbo Pascal v55/CARDS.DTA create mode 100644 Borland Turbo Pascal v55/CARDS.PAS create mode 100644 Borland Turbo Pascal v55/CGA.BGI create mode 100644 Borland Turbo Pascal v55/CIRCULAR.PAS create mode 100644 Borland Turbo Pascal v55/COUNT.PAS create mode 100644 Borland Turbo Pascal v55/CPASDEMO.C create mode 100644 Borland Turbo Pascal v55/CPASDEMO.PAS create mode 100644 Borland Turbo Pascal v55/CRTDEMO.PAS create mode 100644 Borland Turbo Pascal v55/CTOPAS.TC create mode 100644 Borland Turbo Pascal v55/DIRDEMO.PAS create mode 100644 Borland Turbo Pascal v55/DISPLAY.PAS create mode 100644 Borland Turbo Pascal v55/DOC/CRT.DOC create mode 100644 Borland Turbo Pascal v55/DOC/DOS.DOC create mode 100644 Borland Turbo Pascal v55/DOC/GRAPH.DOC create mode 100644 Borland Turbo Pascal v55/DOC/GRAPH3.DOC create mode 100644 Borland Turbo Pascal v55/DOC/HELPME!.DOC create mode 100644 Borland Turbo Pascal v55/DOC/OVERLAY.DOC create mode 100644 Borland Turbo Pascal v55/DOC/PRINTER.DOC create mode 100644 Borland Turbo Pascal v55/DOC/SYSTEM.DOC create mode 100644 Borland Turbo Pascal v55/DOC/THELP.DOC create mode 100644 Borland Turbo Pascal v55/DOC/TURBO3.DOC create mode 100644 Borland Turbo Pascal v55/DOSSTM.ASM create mode 100644 Borland Turbo Pascal v55/DOSSTM.OBJ create mode 100644 Borland Turbo Pascal v55/DOS_GT.BAK create mode 100644 Borland Turbo Pascal v55/DOS_GT.PAS create mode 100644 Borland Turbo Pascal v55/DRIVERS.PAS create mode 100644 Borland Turbo Pascal v55/E.PAS create mode 100644 Borland Turbo Pascal v55/EGAVGA.BGI create mode 100644 Borland Turbo Pascal v55/EMS.PAS create mode 100644 Borland Turbo Pascal v55/ERROR.PAS create mode 100644 Borland Turbo Pascal v55/EXECDEMO.EXE create mode 100644 Borland Turbo Pascal v55/EXECDEMO.MAP create mode 100644 Borland Turbo Pascal v55/EXECDEMO.PAS create mode 100644 Borland Turbo Pascal v55/FDEMO.PAS create mode 100644 Borland Turbo Pascal v55/FIB8087.PAS create mode 100644 Borland Turbo Pascal v55/FIGDEMO.PAS create mode 100644 Borland Turbo Pascal v55/FIGURES.PAS create mode 100644 Borland Turbo Pascal v55/FONTS.PAS create mode 100644 Borland Turbo Pascal v55/FORMS.PAS create mode 100644 Borland Turbo Pascal v55/GOTH.CHR create mode 100644 Borland Turbo Pascal v55/GRAPH.TPU create mode 100644 Borland Turbo Pascal v55/GREP.COM create mode 100644 Borland Turbo Pascal v55/HERC.BGI create mode 100644 Borland Turbo Pascal v55/HILB.PAS create mode 100644 Borland Turbo Pascal v55/IBM8514.BGI create mode 100644 Borland Turbo Pascal v55/LISTDEMO.PAS create mode 100644 Borland Turbo Pascal v55/LISTER.PAS create mode 100644 Borland Turbo Pascal v55/LITT.CHR create mode 100644 Borland Turbo Pascal v55/MAKE.EXE create mode 100644 Borland Turbo Pascal v55/OBJECTS.INC create mode 100644 Borland Turbo Pascal v55/OBJECTS.PAS create mode 100644 Borland Turbo Pascal v55/OBJECTS.TPU create mode 100644 Borland Turbo Pascal v55/ODEMO.PAS create mode 100644 Borland Turbo Pascal v55/OOPDEMOS.DOC create mode 100644 Borland Turbo Pascal v55/OVRDEMO.OVR create mode 100644 Borland Turbo Pascal v55/OVRDEMO.PAS create mode 100644 Borland Turbo Pascal v55/OVRDEMO1.PAS create mode 100644 Borland Turbo Pascal v55/OVRDEMO1.TPU create mode 100644 Borland Turbo Pascal v55/OVRDEMO2.PAS create mode 100644 Borland Turbo Pascal v55/OVRDEMO2.TPU create mode 100644 Borland Turbo Pascal v55/PC3270.BGI create mode 100644 Borland Turbo Pascal v55/POINTS.PAS create mode 100644 Borland Turbo Pascal v55/PROCVAR.PAS create mode 100644 Borland Turbo Pascal v55/QSORT.PAS create mode 100644 Borland Turbo Pascal v55/README create mode 100644 Borland Turbo Pascal v55/README.COM create mode 100644 Borland Turbo Pascal v55/SANS.CHR create mode 100644 Borland Turbo Pascal v55/SCREEN.PAS create mode 100644 Borland Turbo Pascal v55/SIEVE.PAS create mode 100644 Borland Turbo Pascal v55/SLIDERS.PAS create mode 100644 Borland Turbo Pascal v55/STREAM.ASM create mode 100644 Borland Turbo Pascal v55/STREAM.OBJ create mode 100644 Borland Turbo Pascal v55/TCALC.DOC create mode 100644 Borland Turbo Pascal v55/TCALC.PAS create mode 100644 Borland Turbo Pascal v55/TCCELL.PAS create mode 100644 Borland Turbo Pascal v55/TCCELL.TPU create mode 100644 Borland Turbo Pascal v55/TCCELLSP.PAS create mode 100644 Borland Turbo Pascal v55/TCCELLSP.TPU create mode 100644 Borland Turbo Pascal v55/TCCOMPAR.ASM create mode 100644 Borland Turbo Pascal v55/TCCOMPAR.OBJ create mode 100644 Borland Turbo Pascal v55/TCHASH.PAS create mode 100644 Borland Turbo Pascal v55/TCHASH.TPU create mode 100644 Borland Turbo Pascal v55/TCINPUT.PAS create mode 100644 Borland Turbo Pascal v55/TCINPUT.TPU create mode 100644 Borland Turbo Pascal v55/TCLSTR.PAS create mode 100644 Borland Turbo Pascal v55/TCLSTR.TPU create mode 100644 Borland Turbo Pascal v55/TCMENU.PAS create mode 100644 Borland Turbo Pascal v55/TCMENU.TPU create mode 100644 Borland Turbo Pascal v55/TCMVSMEM.ASM create mode 100644 Borland Turbo Pascal v55/TCMVSMEM.OBJ create mode 100644 Borland Turbo Pascal v55/TCPARSER.PAS create mode 100644 Borland Turbo Pascal v55/TCPARSER.TPU create mode 100644 Borland Turbo Pascal v55/TCRUN.PAS create mode 100644 Borland Turbo Pascal v55/TCRUN.TPU create mode 100644 Borland Turbo Pascal v55/TCSCREEN.PAS create mode 100644 Borland Turbo Pascal v55/TCSCREEN.TPU create mode 100644 Borland Turbo Pascal v55/TCSHEET.PAS create mode 100644 Borland Turbo Pascal v55/TCSHEET.TPU create mode 100644 Borland Turbo Pascal v55/TCUTIL.PAS create mode 100644 Borland Turbo Pascal v55/TCUTIL.TPU create mode 100644 Borland Turbo Pascal v55/THELP.COM create mode 100644 Borland Turbo Pascal v55/THELP.SW1 create mode 100644 Borland Turbo Pascal v55/TIMEUTIL.PAS create mode 100644 Borland Turbo Pascal v55/TINST.EXE create mode 100644 Borland Turbo Pascal v55/TINSTXFR.EXE create mode 100644 Borland Turbo Pascal v55/TINY.EXE create mode 100644 Borland Turbo Pascal v55/TINY.PAS create mode 100644 Borland Turbo Pascal v55/TOUCH.COM create mode 100644 Borland Turbo Pascal v55/TOUR.EXE create mode 100644 Borland Turbo Pascal v55/TPC.CFG create mode 100644 Borland Turbo Pascal v55/TPC.EXE create mode 100644 Borland Turbo Pascal v55/TPCONFIG.EXE create mode 100644 Borland Turbo Pascal v55/TPTOUR1.CBT create mode 100644 Borland Turbo Pascal v55/TPTOUR2.CBT create mode 100644 Borland Turbo Pascal v55/TPUMOVER.EXE create mode 100644 Borland Turbo Pascal v55/TRIP.CHR create mode 100644 Borland Turbo Pascal v55/TTT.PAS create mode 100644 Borland Turbo Pascal v55/TURBO.EXE create mode 100644 Borland Turbo Pascal v55/TURBO.HLP create mode 100644 Borland Turbo Pascal v55/TURBO.TP create mode 100644 Borland Turbo Pascal v55/TURBO.TPL create mode 100644 Borland Turbo Pascal v55/TURBO3/BCD.PAS create mode 100644 Borland Turbo Pascal v55/TURBO3/GRAPH3.TPU create mode 100644 Borland Turbo Pascal v55/TURBO3/TURBO3.TPU create mode 100644 Borland Turbo Pascal v55/TURBO3/UPGRADE.DTA create mode 100644 Borland Turbo Pascal v55/TURBO3/UPGRADE.EXE create mode 100644 Borland Turbo Pascal v55/TURBOC.CFG create mode 100644 Borland Turbo Pascal v55/UNPACK.COM create mode 100644 Borland Turbo Pascal v55/WALLS.PAS create mode 100644 Borland Turbo Pascal v55/WIN.ASM create mode 100644 Borland Turbo Pascal v55/WIN.OBJ create mode 100644 Borland Turbo Pascal v55/WIN.PAS create mode 100644 Borland Turbo Pascal v55/WINDEMO.PAS create mode 100644 Borland Turbo Pascal v55/chess/CHESS.EXE create mode 100644 Borland Turbo Pascal v55/chess/CHESS.HLP create mode 100644 Borland Turbo Pascal v55/chess/CHESS.PAS create mode 100644 Borland Turbo Pascal v55/chess/DISPLAY.PAS create mode 100644 Borland Turbo Pascal v55/chess/EGAVGA.BGI create mode 100644 Borland Turbo Pascal v55/chess/EXAMPLE.CHS create mode 100644 Borland Turbo Pascal v55/chess/HELPGEN.EXE create mode 100644 Borland Turbo Pascal v55/chess/HELPGEN.PAS create mode 100644 Borland Turbo Pascal v55/chess/HELPTEXT.TXT create mode 100644 Borland Turbo Pascal v55/chess/IMAGE.EXE create mode 100644 Borland Turbo Pascal v55/chess/IMAGE.PAS create mode 100644 Borland Turbo Pascal v55/chess/INIT.PAS create mode 100644 Borland Turbo Pascal v55/chess/INPUT.PAS create mode 100644 Borland Turbo Pascal v55/chess/MENU.PAS create mode 100644 Borland Turbo Pascal v55/chess/MISC.PAS create mode 100644 Borland Turbo Pascal v55/chess/MOVES.PAS create mode 100644 Borland Turbo Pascal v55/chess/PIECES.IMG create mode 100644 Borland Turbo Pascal v55/chess/PIECES.TXT create mode 100644 Borland Turbo Pascal v55/chess/PLAY.PAS create mode 100644 Borland Turbo Pascal v55/chess/README.BAT create mode 100644 Borland Turbo Pascal v55/chess/README.TXT create mode 100644 Borland Turbo Pascal v55/chess/SETUP.PAS create mode 100644 Borland Turbo Pascal v55/chess/TRIP.CHR create mode 100644 Borland Turbo Pascal v55/m.bat diff --git a/Borland Turbo Pascal v55/ARTY.PAS b/Borland Turbo Pascal v55/ARTY.PAS new file mode 100644 index 0000000..6258e7e --- /dev/null +++ b/Borland Turbo Pascal v55/ARTY.PAS @@ -0,0 +1,383 @@ + +{ Turbo Art } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program Arty; +{ This program is a demonstration of the Borland Graphics Interface + (BGI) provided with Turbo Pascal 5.5. + + To run this program you will need the following files: + + TURBO.EXE (or TPC.EXE) + TURBO.TPL - The standard units + GRAPH.TPU - The Graphics unit + *.BGI - The graphics device drivers + + Runtime Commands for ARTY + ------------------------- + - changes background color + - changes drawcolor + - exits program + Any other key pauses, then regenerates the drawing + + Note: If a /H command-line parameter is specified, the highest + resolution mode will be used (if possible). +} + +uses + Crt, Graph; + +const + Memory = 100; + Windows = 4; + +type + ResolutionPreference = (Lower, Higher); + ColorList = array [1..Windows] of integer; + +var + Xmax, + Ymax, + ViewXmax, + ViewYmax : integer; + + Line: array [1..Memory] of record + LX1,LY1: integer; + LX2,LY2: integer; + LColor : ColorList; + end; + X1,X2,Y1,Y2, + CurrentLine, + ColorCount, + IncrementCount, + DeltaX1,DeltaY1,DeltaX2,DeltaY2: integer; + Colors: ColorList; + Ch: char; + BackColor:integer; + GraphDriver, GraphMode : integer; + MaxColors : word; + MaxDelta : integer; + ChangeColors: Boolean; + +procedure Frame; +begin + SetViewPort(0, 0, Xmax, Ymax-(TextHeight('M')+4)-1,ClipOn); + SetColor(MaxColors); + Rectangle(0, 0, Xmax-1, (Ymax-(TextHeight('M')+4)-1)-1); + SetViewPort(1, 1, Xmax-2, (Ymax-(TextHeight('M')+4)-1)-2,ClipOn); +end { Frame }; + +procedure FullPort; +{ Set the view port to the entire screen } +begin + SetViewPort(0, 0, Xmax, Ymax, ClipOn); +end; { FullPort } + +procedure MessageFrame(Msg:string); +begin + FullPort; + SetColor(MaxColors); + SetTextStyle(DefaultFont, HorizDir, 1); + SetTextJustify(CenterText, TopText); + SetLineStyle(SolidLn, 0, NormWidth); + SetFillStyle(EmptyFill, 0); + Bar(0, Ymax-(TextHeight('M')+4), Xmax, Ymax); + Rectangle(0, Ymax-(TextHeight('M')+4), Xmax, Ymax); + OutTextXY(Xmax div 2, Ymax-(TextHeight('M')+2), Msg); + { Go back to the main window } + Frame; +end { MessageFrame }; + +procedure WaitToGo; +var + Ch : char; +begin + MessageFrame('Press any key to continue... Esc aborts'); + repeat until KeyPressed; + Ch := ReadKey; + if Ch = #27 then begin + CloseGraph; + Writeln('All done.'); + Halt(1); + end + else + ClearViewPort; + MessageFrame('Press a key to stop action, Esc quits.'); +end; { WaitToGo } + +procedure TestGraphError(GraphErr: integer); +begin + if GraphErr <> grOk then begin + Writeln('Graphics error: ', GraphErrorMsg(GraphErr)); + repeat until keypressed; + ch := readkey; + Halt(1); + end; +end; + +procedure Init; +var + Err, I: integer; + StartX, StartY: integer; + Resolution: ResolutionPreference; + s: string; +begin + Resolution := Lower; + if paramcount > 0 then begin + s := paramstr(1); + if s[1] = '/' then + if upcase(s[2]) = 'H' then + Resolution := Higher; + end; + + CurrentLine := 1; + ColorCount := 0; + IncrementCount := 0; + Ch := ' '; + GraphDriver := Detect; + DetectGraph(GraphDriver, GraphMode); + TestGraphError(GraphResult); + case GraphDriver of + CGA : begin + MaxDelta := 7; + GraphDriver := CGA; + GraphMode := CGAC1; + end; + + MCGA : begin + MaxDelta := 7; + case GraphMode of + MCGAMed, MCGAHi: GraphMode := MCGAC1; + end; + end; + + EGA : begin + MaxDelta := 16; + If Resolution = Lower then + GraphMode := EGALo + else + GraphMode := EGAHi; + end; + + EGA64 : begin + MaxDelta := 16; + If Resolution = Lower then + GraphMode := EGA64Lo + else + GraphMode := EGA64Hi; + end; + + HercMono : MaxDelta := 16; + EGAMono : MaxDelta := 16; + PC3270 : begin + MaxDelta := 7; + GraphDriver := CGA; + GraphMode := CGAC1; + end; + + + ATT400 : case GraphMode of + ATT400C1, + ATT400C2, + ATT400Med, + ATT400Hi : + begin + MaxDelta := 7; + GraphMode := ATT400C1; + end; + end; + + VGA : begin + MaxDelta := 16; + end; + end; + InitGraph(GraphDriver, GraphMode, ''); + TestGraphError(GraphResult); + SetTextStyle(DefaultFont, HorizDir, 1); + SetTextJustify(CenterText, TopText); + + MaxColors := GetMaxColor; + BackColor := 0; + ChangeColors := TRUE; + Xmax := GetMaxX; + Ymax := GetMaxY; + ViewXmax := Xmax-2; + ViewYmax := (Ymax-(TextHeight('M')+4)-1)-2; + StartX := Xmax div 2; + StartY := Ymax div 2; + for I := 1 to Memory do with Line[I] do begin + LX1 := StartX; LX2 := StartX; + LY1 := StartY; LY2 := StartY; + end; + + X1 := StartX; + X2 := StartX; + Y1 := StartY; + Y2 := StartY; +end; {init} + +procedure AdjustX(var X,DeltaX: integer); +var + TestX: integer; +begin + TestX := X+DeltaX; + if (TestX<1) or (TestX>ViewXmax) then begin + TestX := X; + DeltaX := -DeltaX; + end; + X := TestX; +end; + +procedure AdjustY(var Y,DeltaY: integer); +var + TestY: integer; +begin + TestY := Y+DeltaY; + if (TestY<1) or (TestY>ViewYmax) then begin + TestY := Y; + DeltaY := -DeltaY; + end; + Y := TestY; +end; + +procedure SelectNewColors; +begin + if not ChangeColors then exit; + Colors[1] := Random(MaxColors)+1; + Colors[2] := Random(MaxColors)+1; + Colors[3] := Random(MaxColors)+1; + Colors[4] := Random(MaxColors)+1; + ColorCount := 3*(1+Random(5)); +end; + +procedure SelectNewDeltaValues; +begin + DeltaX1 := Random(MaxDelta)-(MaxDelta Div 2); + DeltaX2 := Random(MaxDelta)-(MaxDelta Div 2); + DeltaY1 := Random(MaxDelta)-(MaxDelta Div 2); + DeltaY2 := Random(MaxDelta)-(MaxDelta Div 2); + IncrementCount := 2*(1+Random(4)); +end; + + +procedure SaveCurrentLine(CurrentColors: ColorList); +begin + with Line[CurrentLine] do + begin + LX1 := X1; + LY1 := Y1; + LX2 := X2; + LY2 := Y2; + LColor := CurrentColors; + end; +end; + +procedure Draw(x1,y1,x2,y2,color:word); +begin + SetColor(color); + Graph.Line(x1,y1,x2,y2); +end; + +procedure Regenerate; +var + I: integer; +begin + Frame; + for I := 1 to Memory do with Line[I] do begin + Draw(LX1,LY1,LX2,LY2,LColor[1]); + Draw(ViewXmax-LX1,LY1,ViewXmax-LX2,LY2,LColor[2]); + Draw(LX1,ViewYmax-LY1,LX2,ViewYmax-LY2,LColor[3]); + Draw(ViewXmax-LX1,ViewYmax-LY1,ViewXmax-LX2,ViewYmax-LY2,LColor[4]); + end; + WaitToGo; + Frame; +end; + +procedure Updateline; +begin + Inc(CurrentLine); + if CurrentLine > Memory then CurrentLine := 1; + Dec(ColorCount); + Dec(IncrementCount); +end; + +procedure CheckForUserInput; +begin + if KeyPressed then begin + Ch := ReadKey; + if Upcase(Ch) = 'B' then begin + if BackColor > MaxColors then BackColor := 0 else Inc(BackColor); + SetBkColor(BackColor); + end + else + if Upcase(Ch) = 'C' then begin + if ChangeColors then ChangeColors := FALSE else ChangeColors := TRUE; + ColorCount := 0; + end + else if Ch<>#27 then Regenerate; + end; +end; + +procedure DrawCurrentLine; +var c1,c2,c3,c4: integer; +begin + c1 := Colors[1]; + c2 := Colors[2]; + c3 := Colors[3]; + c4 := Colors[4]; + if MaxColors = 1 then begin + c2 := c1; c3 := c1; c4 := c1; + end; + + Draw(X1,Y1,X2,Y2,c1); + Draw(ViewXmax-X1,Y1,ViewXmax-X2,Y2,c2); + Draw(X1,ViewYmax-Y1,X2,ViewYmax-Y2,c3); + if MaxColors = 3 then c4 := Random(3)+1; { alternate colors } + Draw(ViewXmax-X1,ViewYmax-Y1,ViewXmax-X2,ViewYmax-Y2,c4); + SaveCurrentLine(Colors); +end; + +procedure EraseCurrentLine; +begin + with Line[CurrentLine] do begin + Draw(LX1,LY1,LX2,LY2,0); + Draw(ViewXmax-LX1,LY1,ViewXmax-LX2,LY2,0); + Draw(LX1,ViewYmax-LY1,LX2,ViewYmax-LY2,0); + Draw(ViewXmax-LX1,ViewYmax-LY1,ViewXmax-LX2,ViewYmax-LY2,0); + end; +end; + + +procedure DoArt; +begin + SelectNewColors; + repeat + EraseCurrentLine; + if ColorCount = 0 then SelectNewColors; + + if IncrementCount=0 then SelectNewDeltaValues; + + AdjustX(X1,DeltaX1); AdjustX(X2,DeltaX2); + AdjustY(Y1,DeltaY1); AdjustY(Y2,DeltaY2); + + if Random(5)=3 then begin + x1 := (x1+x2) div 2; { shorten the lines } + y2 := (y1+y2) div 2; + end; + + DrawCurrentLine; + Updateline; + CheckForUserInput; + until Ch=#27; +end; + +begin + Init; + Frame; + MessageFrame('Press a key to stop action, Esc quits.'); + DoArt; + CloseGraph; + RestoreCrtMode; + Writeln('The End.'); +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/ATT.BGI b/Borland Turbo Pascal v55/ATT.BGI new file mode 100644 index 0000000000000000000000000000000000000000..66929e3baa21c4afce4206dfb23d2fdc65dac6e9 GIT binary patch literal 6269 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/BGIDEMO.PAS b/Borland Turbo Pascal v55/BGIDEMO.PAS new file mode 100644 index 0000000..80de871 --- /dev/null +++ b/Borland Turbo Pascal v55/BGIDEMO.PAS @@ -0,0 +1,1423 @@ + +{ Turbo Graphics } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program BGIDemo; +(* + Turbo Pascal 5.5 Borland Graphics Interface (BGI) demonstration + program. This program shows how to use many features of + the Graph unit. + + NOTE: to have this demo use the IBM8514 driver, specify a + conditional define constant "Use8514" (using the {$DEFINE} + directive or Options\Compiler\Conditional defines) and then + re-compile. + +*) + +uses + Crt, Dos, Graph; + + +const + { The five fonts available } + Fonts : array[0..4] of string[13] = + ('DefaultFont', 'TriplexFont', 'SmallFont', 'SansSerifFont', 'GothicFont'); + + { The five predefined line styles supported } + LineStyles : array[0..4] of string[9] = + ('SolidLn', 'DottedLn', 'CenterLn', 'DashedLn', 'UserBitLn'); + + { The twelve predefined fill styles supported } + FillStyles : array[0..11] of string[14] = + ('EmptyFill', 'SolidFill', 'LineFill', 'LtSlashFill', 'SlashFill', + 'BkSlashFill', 'LtBkSlashFill', 'HatchFill', 'XHatchFill', + 'InterleaveFill', 'WideDotFill', 'CloseDotFill'); + + { The two text directions available } + TextDirect : array[0..1] of string[8] = ('HorizDir', 'VertDir'); + + { The Horizontal text justifications available } + HorizJust : array[0..2] of string[10] = ('LeftText', 'CenterText', 'RightText'); + + { The vertical text justifications available } + VertJust : array[0..2] of string[10] = ('BottomText', 'CenterText', 'TopText'); + +var + GraphDriver : integer; { The Graphics device driver } + GraphMode : integer; { The Graphics mode value } + MaxX, MaxY : word; { The maximum resolution of the screen } + ErrorCode : integer; { Reports any graphics errors } + MaxColor : word; { The maximum color value available } + OldExitProc : Pointer; { Saves exit procedure address } + +{$F+} +procedure MyExitProc; +begin + ExitProc := OldExitProc; { Restore exit procedure address } + CloseGraph; { Shut down the graphics system } +end; { MyExitProc } +{$F-} + +procedure Initialize; +{ Initialize graphics and report any errors that may occur } +var + InGraphicsMode : boolean; { Flags initialization of graphics mode } + PathToDriver : string; { Stores the DOS path to *.BGI & *.CHR } +begin + { when using Crt and graphics, turn off Crt's memory-mapped writes } + DirectVideo := False; + OldExitProc := ExitProc; { save previous exit proc } + ExitProc := @MyExitProc; { insert our exit proc in chain } + PathToDriver := ''; + repeat + +{$IFDEF Use8514} { check for Use8514 $DEFINE } + GraphDriver := IBM8514; + GraphMode := IBM8514Hi; +{$ELSE} + GraphDriver := Detect; { use autodetection } +{$ENDIF} + + InitGraph(GraphDriver, GraphMode, PathToDriver); + ErrorCode := GraphResult; { preserve error return } + if ErrorCode <> grOK then { error? } + begin + Writeln('Graphics error: ', GraphErrorMsg(ErrorCode)); + if ErrorCode = grFileNotFound then { Can't find driver file } + begin + Writeln('Enter full path to BGI driver or type to quit:'); + Readln(PathToDriver); + Writeln; + end + else + Halt(1); { Some other error: terminate } + end; + until ErrorCode = grOK; + Randomize; { init random number generator } + MaxColor := GetMaxColor; { Get the maximum allowable drawing color } + MaxX := GetMaxX; { Get screen resolution values } + MaxY := GetMaxY; +end; { Initialize } + +function Int2Str(L : LongInt) : string; +{ Converts an integer to a string for use with OutText, OutTextXY } +var + S : string; +begin + Str(L, S); + Int2Str := S; +end; { Int2Str } + +function RandColor : word; +{ Returns a Random non-zero color value that is within the legal + color range for the selected device driver and graphics mode. + MaxColor is set to GetMaxColor by Initialize } +begin + RandColor := Random(MaxColor)+1; +end; { RandColor } + +procedure DefaultColors; +{ Select the maximum color in the Palette for the drawing color } +begin + SetColor(MaxColor); +end; { DefaultColors } + +procedure DrawBorder; +{ Draw a border around the current view port } +var + ViewPort : ViewPortType; +begin + DefaultColors; + SetLineStyle(SolidLn, 0, NormWidth); + GetViewSettings(ViewPort); + with ViewPort do + Rectangle(0, 0, x2-x1, y2-y1); +end; { DrawBorder } + +procedure FullPort; +{ Set the view port to the entire screen } +begin + SetViewPort(0, 0, MaxX, MaxY, ClipOn); +end; { FullPort } + +procedure MainWindow(Header : string); +{ Make a default window and view port for demos } +begin + DefaultColors; { Reset the colors } + ClearDevice; { Clear the screen } + SetTextStyle(DefaultFont, HorizDir, 1); { Default text font } + SetTextJustify(CenterText, TopText); { Left justify text } + FullPort; { Full screen view port } + OutTextXY(MaxX div 2, 2, Header); { Draw the header } + { Draw main window } + SetViewPort(0, TextHeight('M')+4, MaxX, MaxY-(TextHeight('M')+4), ClipOn); + DrawBorder; { Put a border around it } + { Move the edges in 1 pixel on all sides so border isn't in the view port } + SetViewPort(1, TextHeight('M')+5, MaxX-1, MaxY-(TextHeight('M')+5), ClipOn); +end; { MainWindow } + +procedure StatusLine(Msg : string); +{ Display a status line at the bottom of the screen } +begin + FullPort; + DefaultColors; + SetTextStyle(DefaultFont, HorizDir, 1); + SetTextJustify(CenterText, TopText); + SetLineStyle(SolidLn, 0, NormWidth); + SetFillStyle(EmptyFill, 0); + Bar(0, MaxY-(TextHeight('M')+4), MaxX, MaxY); { Erase old status line } + Rectangle(0, MaxY-(TextHeight('M')+4), MaxX, MaxY); + OutTextXY(MaxX div 2, MaxY-(TextHeight('M')+2), Msg); + { Go back to the main window } + SetViewPort(1, TextHeight('M')+5, MaxX-1, MaxY-(TextHeight('M')+5), ClipOn); +end; { StatusLine } + +procedure WaitToGo; +{ Wait for the user to abort the program or continue } +const + Esc = #27; +var + Ch : char; +begin + StatusLine('Esc aborts or press a key...'); + repeat until KeyPressed; + Ch := ReadKey; + if ch = #0 then ch := readkey; { trap function keys } + if Ch = Esc then + Halt(0) { terminate program } + else + ClearDevice; { clear screen, go on with demo } +end; { WaitToGo } + +procedure GetDriverAndMode(var DriveStr, ModeStr : string); +{ Return strings describing the current device driver and graphics mode + for display of status report } +begin + DriveStr := GetDriverName; + ModeStr := GetModeName(GetGraphMode); +end; { GetDriverAndMode } + +procedure ReportStatus; +{ Display the status of all query functions after InitGraph } +const + X = 10; +var + ViewInfo : ViewPortType; { Parameters for inquiry procedures } + LineInfo : LineSettingsType; + FillInfo : FillSettingsType; + TextInfo : TextSettingsType; + Palette : PaletteType; + DriverStr : string; { Driver and mode strings } + ModeStr : string; + Y : word; + +procedure WriteOut(S : string); +{ Write out a string and increment to next line } +begin + OutTextXY(X, Y, S); + Inc(Y, TextHeight('M')+2); +end; { WriteOut } + +begin { ReportStatus } + GetDriverAndMode(DriverStr, ModeStr); { Get current settings } + GetViewSettings(ViewInfo); + GetLineSettings(LineInfo); + GetFillSettings(FillInfo); + GetTextSettings(TextInfo); + GetPalette(Palette); + + Y := 4; + MainWindow('Status report after InitGraph'); + SetTextJustify(LeftText, TopText); + WriteOut('Graphics device : '+DriverStr); + WriteOut('Graphics mode : '+ModeStr); + WriteOut('Screen resolution : (0, 0, '+Int2Str(GetMaxX)+', '+Int2Str(GetMaxY)+')'); + with ViewInfo do + begin + WriteOut('Current view port : ('+Int2Str(x1)+', '+Int2Str(y1)+', '+Int2Str(x2)+', '+Int2Str(y2)+')'); + if ClipOn then + WriteOut('Clipping : ON') + else + WriteOut('Clipping : OFF'); + end; + WriteOut('Current position : ('+Int2Str(GetX)+', '+Int2Str(GetY)+')'); + WriteOut('Palette entries : '+Int2Str(Palette.Size)); + WriteOut('GetMaxColor : '+Int2Str(GetMaxColor)); + WriteOut('Current color : '+Int2Str(GetColor)); + with LineInfo do + begin + WriteOut('Line style : '+LineStyles[LineStyle]); + WriteOut('Line thickness : '+Int2Str(Thickness)); + end; + with FillInfo do + begin + WriteOut('Current fill style : '+FillStyles[Pattern]); + WriteOut('Current fill color : '+Int2Str(Color)); + end; + with TextInfo do + begin + WriteOut('Current font : '+Fonts[Font]); + WriteOut('Text direction : '+TextDirect[Direction]); + WriteOut('Character size : '+Int2Str(CharSize)); + WriteOut('Horizontal justify : '+HorizJust[Horiz]); + WriteOut('Vertical justify : '+VertJust[Vert]); + end; + WaitToGo; +end; { ReportStatus } + +procedure FillEllipsePlay; +{ Random filled ellipse demonstration } +const + MaxFillStyles = 12; { patterns 0..11 } +var + MaxRadius : word; + FillColor : integer; +begin + MainWindow('FillEllipse demonstration'); + StatusLine('Esc aborts or press a key'); + MaxRadius := MaxY div 10; + SetLineStyle(SolidLn, 0, NormWidth); + repeat + FillColor := RandColor; + SetColor(FillColor); + SetFillStyle(Random(MaxFillStyles), FillColor); + FillEllipse(Random(MaxX), Random(MaxY), + Random(MaxRadius), Random(MaxRadius)); + until KeyPressed; + WaitToGo; +end; { FillEllipsePlay } + +procedure SectorPlay; +{ Draw random sectors on the screen } +const + MaxFillStyles = 12; { patterns 0..11 } +var + MaxRadius : word; + FillColor : integer; + EndAngle : integer; +begin + MainWindow('Sector demonstration'); + StatusLine('Esc aborts or press a key'); + MaxRadius := MaxY div 10; + SetLineStyle(SolidLn, 0, NormWidth); + repeat + FillColor := RandColor; + SetColor(FillColor); + SetFillStyle(Random(MaxFillStyles), FillColor); + EndAngle := Random(360); + Sector(Random(MaxX), Random(MaxY), Random(EndAngle), EndAngle, + Random(MaxRadius), Random(MaxRadius)); + until KeyPressed; + WaitToGo; +end; { SectorPlay } + +procedure WriteModePlay; +{ Demonstrate the SetWriteMode procedure for XOR lines } +const + DelayValue = 50; { milliseconds to delay } +var + ViewInfo : ViewPortType; + Color : word; + Left, Top : integer; + Right, Bottom : integer; + Step : integer; { step for rectangle shrinking } +begin + MainWindow('SetWriteMode demonstration'); + StatusLine('Esc aborts or press a key'); + GetViewSettings(ViewInfo); + Left := 0; + Top := 0; + with ViewInfo do + begin + Right := x2-x1; + Bottom := y2-y1; + end; + Step := Bottom div 50; + SetColor(GetMaxColor); + Line(Left, Top, Right, Bottom); + Line(Left, Bottom, Right, Top); + SetWriteMode(XORPut); { Set XOR write mode } + repeat + Line(Left, Top, Right, Bottom); { Draw XOR lines } + Line(Left, Bottom, Right, Top); + Rectangle(Left, Top, Right, Bottom); { Draw XOR rectangle } + Delay(DelayValue); { Wait } + Line(Left, Top, Right, Bottom); { Erase lines } + Line(Left, Bottom, Right, Top); + Rectangle(Left, Top, Right, Bottom); { Erase rectangle } + if (Left+Step < Right) and (Top+Step < Bottom) then + begin + Inc(Left, Step); { Shrink rectangle } + Inc(Top, Step); + Dec(Right, Step); + Dec(Bottom, Step); + end + else + begin + Color := RandColor; { New color } + SetColor(Color); + Left := 0; { Original large rectangle } + Top := 0; + with ViewInfo do + begin + Right := x2-x1; + Bottom := y2-y1; + end; + end; + until KeyPressed; + SetWriteMode(CopyPut); { back to overwrite mode } + WaitToGo; +end; { WriteModePlay } + +procedure AspectRatioPlay; +{ Demonstrate SetAspectRatio command } +var + ViewInfo : ViewPortType; + CenterX : integer; + CenterY : integer; + Radius : word; + Xasp, Yasp : word; + i : integer; + RadiusStep : word; +begin + MainWindow('SetAspectRatio demonstration'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + CenterX := (x2-x1) div 2; + CenterY := (y2-y1) div 2; + Radius := 3*((y2-y1) div 5); + end; + RadiusStep := (Radius div 30); + Circle(CenterX, CenterY, Radius); + GetAspectRatio(Xasp, Yasp); + for i := 1 to 30 do + begin + SetAspectRatio(Xasp, Yasp+(I*GetMaxX)); { Increase Y aspect factor } + Circle(CenterX, CenterY, Radius); + Dec(Radius, RadiusStep); { Shrink radius } + end; + Inc(Radius, RadiusStep*30); + for i := 1 to 30 do + begin + SetAspectRatio(Xasp+(I*GetMaxX), Yasp); { Increase X aspect factor } + if Radius > RadiusStep then + Dec(Radius, RadiusStep); { Shrink radius } + Circle(CenterX, CenterY, Radius); + end; + SetAspectRatio(Xasp, Yasp); { back to original aspect } + WaitToGo; +end; { AspectRatioPlay } + +procedure TextPlay; +{ Demonstrate text justifications and text sizing } +var + Size : word; + W, H, X, Y : word; + ViewInfo : ViewPortType; +begin + MainWindow('SetTextJustify / SetUserCharSize demo'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + SetTextStyle(TriplexFont, VertDir, 4); + Y := (y2-y1) - 2; + SetTextJustify(CenterText, BottomText); + OutTextXY(2*TextWidth('M'), Y, 'Vertical'); + SetTextStyle(TriplexFont, HorizDir, 4); + SetTextJustify(LeftText, TopText); + OutTextXY(2*TextWidth('M'), 2, 'Horizontal'); + SetTextJustify(CenterText, CenterText); + X := (x2-x1) div 2; + Y := TextHeight('H'); + for Size := 1 to 4 do + begin + SetTextStyle(TriplexFont, HorizDir, Size); + H := TextHeight('M'); + W := TextWidth('M'); + Inc(Y, H); + OutTextXY(X, Y, 'Size '+Int2Str(Size)); + end; + Inc(Y, H div 2); + SetTextJustify(CenterText, TopText); + SetUserCharSize(5, 6, 3, 2); + SetTextStyle(TriplexFont, HorizDir, UserCharSize); + OutTextXY((x2-x1) div 2, Y, 'User defined size!'); + end; + WaitToGo; +end; { TextPlay } + +procedure TextDump; +{ Dump the complete character sets to the screen } +const + CGASizes : array[0..4] of word = (1, 3, 7, 3, 3); + NormSizes : array[0..4] of word = (1, 4, 7, 4, 4); +var + Font : word; + ViewInfo : ViewPortType; + Ch : char; +begin + for Font := 0 to 4 do + begin + MainWindow(Fonts[Font]+' character set'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + SetTextJustify(LeftText, TopText); + MoveTo(2, 3); + if Font = DefaultFont then + begin + SetTextStyle(Font, HorizDir, 1); + Ch := #0; + repeat + OutText(Ch); + if (GetX + TextWidth('M')) > (x2-x1) then + MoveTo(2, GetY + TextHeight('M')+3); + Ch := Succ(Ch); + until (Ch >= #255); + end + else + begin + if MaxY < 200 then + SetTextStyle(Font, HorizDir, CGASizes[Font]) + else + SetTextStyle(Font, HorizDir, NormSizes[Font]); + Ch := '!'; + repeat + OutText(Ch); + if (GetX + TextWidth('M')) > (x2-x1) then + MoveTo(2, GetY + TextHeight('M')+3); + Ch := Succ(Ch); + until (Ord(Ch) = Ord('~')+1); + end; + end; { with } + WaitToGo; + end; { for loop } +end; { TextDump } + +procedure LineToPlay; +{ Demonstrate MoveTo and LineTo commands } +const + MaxPoints = 15; +var + Points : array[0..MaxPoints] of PointType; + ViewInfo : ViewPortType; + I, J : integer; + CenterX : integer; { The center point of the circle } + CenterY : integer; + Radius : word; + StepAngle : word; + Xasp, Yasp : word; + Radians : real; + +function AdjAsp(Value : integer) : integer; +{ Adjust a value for the aspect ratio of the device } +begin + AdjAsp := (LongInt(Value) * Xasp) div Yasp; +end; { AdjAsp } + +begin + MainWindow('MoveTo, LineTo demonstration'); + GetAspectRatio(Xasp, Yasp); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + CenterX := (x2-x1) div 2; + CenterY := (y2-y1) div 2; + Radius := CenterY; + while (CenterY+AdjAsp(Radius)) < (y2-y1)-20 do + Inc(Radius); + end; + StepAngle := 360 div MaxPoints; + for I := 0 to MaxPoints - 1 do + begin + Radians := (StepAngle * I) * Pi / 180; + Points[I].X := CenterX + round(Cos(Radians) * Radius); + Points[I].Y := CenterY - AdjAsp(round(Sin(Radians) * Radius)); + end; + Circle(CenterX, CenterY, Radius); + for I := 0 to MaxPoints - 1 do + begin + for J := I to MaxPoints - 1 do + begin + MoveTo(Points[I].X, Points[I].Y); + LineTo(Points[J].X, Points[J].Y); + end; + end; + WaitToGo; +end; { LineToPlay } + +procedure LineRelPlay; +{ Demonstrate MoveRel and LineRel commands } +const + MaxPoints = 12; +var + Poly : array[1..MaxPoints] of PointType; { Stores a polygon for filling } + CurrPort : ViewPortType; + +procedure DrawTesseract; +{ Draw a Tesseract on the screen with relative move and + line drawing commands, also create a polygon for filling } +const + CheckerBoard : FillPatternType = (0, $10, $28, $44, $28, $10, 0, 0); +var + X, Y, W, H : integer; + +begin + GetViewSettings(CurrPort); + with CurrPort do + begin + W := (x2-x1) div 9; + H := (y2-y1) div 8; + X := ((x2-x1) div 2) - round(2.5 * W); + Y := ((y2-y1) div 2) - (3 * H); + + { Border around viewport is outer part of polygon } + Poly[1].X := 0; Poly[1].Y := 0; + Poly[2].X := x2-x1; Poly[2].Y := 0; + Poly[3].X := x2-x1; Poly[3].Y := y2-y1; + Poly[4].X := 0; Poly[4].Y := y2-y1; + Poly[5].X := 0; Poly[5].Y := 0; + MoveTo(X, Y); + + { Grab the whole in the polygon as we draw } + MoveRel(0, H); Poly[6].X := GetX; Poly[6].Y := GetY; + MoveRel(W, -H); Poly[7].X := GetX; Poly[7].Y := GetY; + MoveRel(4*W, 0); Poly[8].X := GetX; Poly[8].Y := GetY; + MoveRel(0, 5*H); Poly[9].X := GetX; Poly[9].Y := GetY; + MoveRel(-W, H); Poly[10].X := GetX; Poly[10].Y := GetY; + MoveRel(-4*W, 0); Poly[11].X := GetX; Poly[11].Y := GetY; + MoveRel(0, -5*H); Poly[12].X := GetX; Poly[12].Y := GetY; + + { Fill the polygon with a user defined fill pattern } + SetFillPattern(CheckerBoard, MaxColor); + FillPoly(12, Poly); + + MoveRel(W, -H); + LineRel(0, 5*H); LineRel(2*W, 0); LineRel(0, -3*H); + LineRel(W, -H); LineRel(0, 5*H); MoveRel(0, -5*H); + LineRel(-2*W, 0); LineRel(0, 3*H); LineRel(-W, H); + MoveRel(W, -H); LineRel(W, 0); MoveRel(0, -2*H); + LineRel(-W, 0); + + { Flood fill the center } + FloodFill((x2-x1) div 2, (y2-y1) div 2, MaxColor); + end; +end; { DrawTesseract } + +begin + MainWindow('LineRel / MoveRel demonstration'); + GetViewSettings(CurrPort); + with CurrPort do + { Move the viewport out 1 pixel from each end } + SetViewPort(x1-1, y1-1, x2+1, y2+1, ClipOn); + DrawTesseract; + WaitToGo; +end; { LineRelPlay } + +procedure PiePlay; +{ Demonstrate PieSlice and GetAspectRatio commands } +var + ViewInfo : ViewPortType; + CenterX : integer; + CenterY : integer; + Radius : word; + Xasp, Yasp : word; + X, Y : integer; + +function AdjAsp(Value : integer) : integer; +{ Adjust a value for the aspect ratio of the device } +begin + AdjAsp := (LongInt(Value) * Xasp) div Yasp; +end; { AdjAsp } + +procedure GetTextCoords(AngleInDegrees, Radius : word; var X, Y : integer); +{ Get the coordinates of text for pie slice labels } +var + Radians : real; +begin + Radians := AngleInDegrees * Pi / 180; + X := round(Cos(Radians) * Radius); + Y := round(Sin(Radians) * Radius); +end; { GetTextCoords } + +begin + MainWindow('PieSlice / GetAspectRatio demonstration'); + GetAspectRatio(Xasp, Yasp); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + CenterX := (x2-x1) div 2; + CenterY := ((y2-y1) div 2) + 20; + Radius := (y2-y1) div 3; + while AdjAsp(Radius) < round((y2-y1) / 3.6) do + Inc(Radius); + end; + SetTextStyle(TriplexFont, HorizDir, 4); + SetTextJustify(CenterText, TopText); + OutTextXY(CenterX, 0, 'This is a pie chart!'); + + SetTextStyle(TriplexFont, HorizDir, 3); + + SetFillStyle(SolidFill, RandColor); + PieSlice(CenterX+10, CenterY-AdjAsp(10), 0, 90, Radius); + GetTextCoords(45, Radius, X, Y); + SetTextJustify(LeftText, BottomText); + OutTextXY(CenterX+10+X+TextWidth('H'), CenterY-AdjAsp(10+Y), '25 %'); + + SetFillStyle(HatchFill, RandColor); + PieSlice(CenterX, CenterY, 225, 360, Radius); + GetTextCoords(293, Radius, X, Y); + SetTextJustify(LeftText, TopText); + OutTextXY(CenterX+X+TextWidth('H'), CenterY-AdjAsp(Y), '37.5 %'); + + SetFillStyle(InterleaveFill, RandColor); + PieSlice(CenterX-10, CenterY, 135, 225, Radius); + GetTextCoords(180, Radius, X, Y); + SetTextJustify(RightText, CenterText); + OutTextXY(CenterX-10+X-TextWidth('H'), CenterY-AdjAsp(Y), '25 %'); + + SetFillStyle(WideDotFill, RandColor); + PieSlice(CenterX, CenterY, 90, 135, Radius); + GetTextCoords(112, Radius, X, Y); + SetTextJustify(RightText, BottomText); + OutTextXY(CenterX+X-TextWidth('H'), CenterY-AdjAsp(Y), '12.5 %'); + + WaitToGo; +end; { PiePlay } + +procedure Bar3DPlay; +{ Demonstrate Bar3D command } +const + NumBars = 7; { The number of bars drawn } + BarHeight : array[1..NumBars] of byte = (1, 3, 2, 5, 4, 2, 1); + YTicks = 5; { The number of tick marks on the Y axis } +var + ViewInfo : ViewPortType; + H : word; + XStep : real; + YStep : real; + I, J : integer; + Depth : word; + Color : word; +begin + MainWindow('Bar3D / Rectangle demonstration'); + H := 3*TextHeight('M'); + GetViewSettings(ViewInfo); + SetTextJustify(CenterText, TopText); + SetTextStyle(TriplexFont, HorizDir, 4); + OutTextXY(MaxX div 2, 6, 'These are 3D bars !'); + SetTextStyle(DefaultFont, HorizDir, 1); + with ViewInfo do + SetViewPort(x1+50, y1+40, x2-50, y2-10, ClipOn); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + Line(H, H, H, (y2-y1)-H); + Line(H, (y2-y1)-H, (x2-x1)-H, (y2-y1)-H); + YStep := ((y2-y1)-(2*H)) / YTicks; + XStep := ((x2-x1)-(2*H)) / NumBars; + J := (y2-y1)-H; + SetTextJustify(CenterText, CenterText); + + { Draw the Y axis and ticks marks } + for I := 0 to Yticks do + begin + Line(H div 2, J, H, J); + OutTextXY(0, J, Int2Str(I)); + J := Round(J-Ystep); + end; + + + Depth := trunc(0.25 * XStep); { Calculate depth of bar } + + { Draw X axis, bars, and tick marks } + SetTextJustify(CenterText, TopText); + J := H; + for I := 1 to Succ(NumBars) do + begin + SetColor(MaxColor); + Line(J, (y2-y1)-H, J, (y2-y1-3)-(H div 2)); + OutTextXY(J, (y2-y1)-(H div 2), Int2Str(I-1)); + if I <> Succ(NumBars) then + begin + Color := RandColor; + SetFillStyle(I, Color); + SetColor(Color); + Bar3D(J, round((y2-y1-H)-(BarHeight[I] * Ystep)), + round(J+Xstep-Depth), round((y2-y1)-H-1), Depth, TopOn); + J := Round(J+Xstep); + end; + end; + + end; + WaitToGo; +end; { Bar3DPlay } + +procedure BarPlay; +{ Demonstrate Bar command } +const + NumBars = 5; + BarHeight : array[1..NumBars] of byte = (1, 3, 5, 2, 4); + Styles : array[1..NumBars] of byte = (1, 3, 10, 5, 9); +var + ViewInfo : ViewPortType; + BarNum : word; + H : word; + XStep : real; + YStep : real; + I, J : integer; + Color : word; +begin + MainWindow('Bar / Rectangle demonstration'); + H := 3*TextHeight('M'); + GetViewSettings(ViewInfo); + SetTextJustify(CenterText, TopText); + SetTextStyle(TriplexFont, HorizDir, 4); + OutTextXY(MaxX div 2, 6, 'These are 2D bars !'); + SetTextStyle(DefaultFont, HorizDir, 1); + with ViewInfo do + SetViewPort(x1+50, y1+30, x2-50, y2-10, ClipOn); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + Line(H, H, H, (y2-y1)-H); + Line(H, (y2-y1)-H, (x2-x1)-H, (y2-y1)-H); + YStep := ((y2-y1)-(2*H)) / NumBars; + XStep := ((x2-x1)-(2*H)) / NumBars; + J := (y2-y1)-H; + SetTextJustify(CenterText, CenterText); + + { Draw Y axis with tick marks } + for I := 0 to NumBars do + begin + Line(H div 2, J, H, J); + OutTextXY(0, J, Int2Str(i)); + J := Round(J-Ystep); + end; + + { Draw X axis, bars, and tick marks } + J := H; + SetTextJustify(CenterText, TopText); + for I := 1 to Succ(NumBars) do + begin + SetColor(MaxColor); + Line(J, (y2-y1)-H, J, (y2-y1-3)-(H div 2)); + OutTextXY(J, (y2-y1)-(H div 2), Int2Str(I)); + if I <> Succ(NumBars) then + begin + Color := RandColor; + SetFillStyle(Styles[I], Color); + SetColor(Color); + Bar(J, round((y2-y1-H)-(BarHeight[I] * Ystep)), round(J+Xstep), (y2-y1)-H-1); + Rectangle(J, round((y2-y1-H)-(BarHeight[I] * Ystep)), round(J+Xstep), (y2-y1)-H-1); + end; + J := Round(J+Xstep); + end; + + end; + WaitToGo; +end; { BarPlay } + +procedure CirclePlay; +{ Draw random circles on the screen } +var + MaxRadius : word; +begin + MainWindow('Circle demonstration'); + StatusLine('Esc aborts or press a key'); + MaxRadius := MaxY div 10; + SetLineStyle(SolidLn, 0, NormWidth); + repeat + SetColor(RandColor); + Circle(Random(MaxX), Random(MaxY), Random(MaxRadius)); + until KeyPressed; + WaitToGo; +end; { CirclePlay } + + +procedure RandBarPlay; +{ Draw random bars on the screen } +var + MaxWidth : integer; + MaxHeight : integer; + ViewInfo : ViewPortType; + Color : word; +begin + MainWindow('Random Bars'); + StatusLine('Esc aborts or press a key'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + MaxWidth := x2-x1; + MaxHeight := y2-y1; + end; + repeat + Color := RandColor; + SetColor(Color); + SetFillStyle(Random(CloseDotFill)+1, Color); + Bar3D(Random(MaxWidth), Random(MaxHeight), + Random(MaxWidth), Random(MaxHeight), 0, TopOff); + until KeyPressed; + WaitToGo; +end; { RandBarPlay } + +procedure ArcPlay; +{ Draw random arcs on the screen } +var + MaxRadius : word; + EndAngle : word; + ArcInfo : ArcCoordsType; +begin + MainWindow('Arc / GetArcCoords demonstration'); + StatusLine('Esc aborts or press a key'); + MaxRadius := MaxY div 10; + repeat + SetColor(RandColor); + EndAngle := Random(360); + SetLineStyle(SolidLn, 0, NormWidth); + Arc(Random(MaxX), Random(MaxY), Random(EndAngle), EndAngle, Random(MaxRadius)); + GetArcCoords(ArcInfo); + with ArcInfo do + begin + Line(X, Y, XStart, YStart); + Line(X, Y, Xend, Yend); + end; + until KeyPressed; + WaitToGo; +end; { ArcPlay } + +procedure PutPixelPlay; +{ Demonstrate the PutPixel and GetPixel commands } +const + Seed = 1962; { A seed for the random number generator } + NumPts = 2000; { The number of pixels plotted } + Esc = #27; +var + I : word; + X, Y, Color : word; + XMax, YMax : integer; + ViewInfo : ViewPortType; +begin + MainWindow('PutPixel / GetPixel demonstration'); + StatusLine('Esc aborts or press a key...'); + + GetViewSettings(ViewInfo); + with ViewInfo do + begin + XMax := (x2-x1-1); + YMax := (y2-y1-1); + end; + + while not KeyPressed do + begin + { Plot random pixels } + RandSeed := Seed; + I := 0; + while (not KeyPressed) and (I < NumPts) do + begin + Inc(I); + PutPixel(Random(XMax)+1, Random(YMax)+1, RandColor); + end; + + { Erase pixels } + RandSeed := Seed; + I := 0; + while (not KeyPressed) and (I < NumPts) do + begin + Inc(I); + X := Random(XMax)+1; + Y := Random(YMax)+1; + Color := GetPixel(X, Y); + if Color = RandColor then + PutPixel(X, Y, 0); + end; + end; + WaitToGo; +end; { PutPixelPlay } + +procedure PutImagePlay; +{ Demonstrate the GetImage and PutImage commands } + +const + r = 20; + StartX = 100; + StartY = 50; + +var + CurPort : ViewPortType; + +procedure MoveSaucer(var X, Y : integer; Width, Height : integer); +var + Step : integer; +begin + Step := Random(2*r); + if Odd(Step) then + Step := -Step; + X := X + Step; + Step := Random(r); + if Odd(Step) then + Step := -Step; + Y := Y + Step; + + { Make saucer bounce off viewport walls } + with CurPort do + begin + if (x1 + X + Width - 1 > x2) then + X := x2-x1 - Width + 1 + else + if (X < 0) then + X := 0; + if (y1 + Y + Height - 1 > y2) then + Y := y2-y1 - Height + 1 + else + if (Y < 0) then + Y := 0; + end; +end; { MoveSaucer } + +var + Pausetime : word; + Saucer : pointer; + X, Y : integer; + ulx, uly : word; + lrx, lry : word; + Size : word; + I : word; +begin + ClearDevice; + FullPort; + + { PaintScreen } + ClearDevice; + MainWindow('GetImage / PutImage Demonstration'); + StatusLine('Esc aborts or press a key...'); + GetViewSettings(CurPort); + + { DrawSaucer } + Ellipse(StartX, StartY, 0, 360, r, (r div 3)+2); + Ellipse(StartX, StartY-4, 190, 357, r, r div 3); + Line(StartX+7, StartY-6, StartX+10, StartY-12); + Circle(StartX+10, StartY-12, 2); + Line(StartX-7, StartY-6, StartX-10, StartY-12); + Circle(StartX-10, StartY-12, 2); + SetFillStyle(SolidFill, MaxColor); + FloodFill(StartX+1, StartY+4, GetColor); + + { ReadSaucerImage } + ulx := StartX-(r+1); + uly := StartY-14; + lrx := StartX+(r+1); + lry := StartY+(r div 3)+3; + + Size := ImageSize(ulx, uly, lrx, lry); + GetMem(Saucer, Size); + GetImage(ulx, uly, lrx, lry, Saucer^); + PutImage(ulx, uly, Saucer^, XORput); { erase image } + + { Plot some "stars" } + for I := 1 to 1000 do + PutPixel(Random(MaxX), Random(MaxY), RandColor); + X := MaxX div 2; + Y := MaxY div 2; + PauseTime := 70; + + { Move the saucer around } + repeat + PutImage(X, Y, Saucer^, XORput); { draw image } + Delay(PauseTime); + PutImage(X, Y, Saucer^, XORput); { erase image } + MoveSaucer(X, Y, lrx - ulx + 1, lry - uly + 1); { width/height } + until KeyPressed; + FreeMem(Saucer, size); + WaitToGo; +end; { PutImagePlay } + +procedure PolyPlay; +{ Draw random polygons with random fill styles on the screen } +const + MaxPts = 5; +type + PolygonType = array[1..MaxPts] of PointType; +var + Poly : PolygonType; + I, Color : word; +begin + MainWindow('FillPoly demonstration'); + StatusLine('Esc aborts or press a key...'); + repeat + Color := RandColor; + SetFillStyle(Random(11)+1, Color); + SetColor(Color); + for I := 1 to MaxPts do + with Poly[I] do + begin + X := Random(MaxX); + Y := Random(MaxY); + end; + FillPoly(MaxPts, Poly); + until KeyPressed; + WaitToGo; +end; { PolyPlay } + +procedure FillStylePlay; +{ Display all of the predefined fill styles available } +var + Style : word; + Width : word; + Height : word; + X, Y : word; + I, J : word; + ViewInfo : ViewPortType; + +procedure DrawBox(X, Y : word); +begin + SetFillStyle(Style, MaxColor); + with ViewInfo do + Bar(X, Y, X+Width, Y+Height); + Rectangle(X, Y, X+Width, Y+Height); + OutTextXY(X+(Width div 2), Y+Height+4, Int2Str(Style)); + Inc(Style); +end; { DrawBox } + +begin + MainWindow('Pre-defined fill styles'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + Width := 2 * ((x2+1) div 13); + Height := 2 * ((y2-10) div 10); + end; + X := Width div 2; + Y := Height div 2; + Style := 0; + for J := 1 to 3 do + begin + for I := 1 to 4 do + begin + DrawBox(X, Y); + Inc(X, (Width div 2) * 3); + end; + X := Width div 2; + Inc(Y, (Height div 2) * 3); + end; + SetTextJustify(LeftText, TopText); + WaitToGo; +end; { FillStylePlay } + +procedure FillPatternPlay; +{ Display some user defined fill patterns } +const + Patterns : array[0..11] of FillPatternType = ( + ($AA, $55, $AA, $55, $AA, $55, $AA, $55), + ($33, $33, $CC, $CC, $33, $33, $CC, $CC), + ($F0, $F0, $F0, $F0, $F, $F, $F, $F), + (0, $10, $28, $44, $28, $10, 0, 0), + (0, $70, $20, $27, $25, $27, $4, $4), + (0, 0, 0, $18, $18, 0, 0, 0), + (0, 0, $3C, $3C, $3C, $3C, 0, 0), + (0, $7E, $7E, $7E, $7E, $7E, $7E, 0), + (0, 0, $22, $8, 0, $22, $1C, 0), + ($FF, $7E, $3C, $18, $18, $3C, $7E, $FF), + (0, $10, $10, $7C, $10, $10, 0, 0), + (0, $42, $24, $18, $18, $24, $42, 0)); +var + Style : word; + Width : word; + Height : word; + X, Y : word; + I, J : word; + ViewInfo : ViewPortType; + +procedure DrawBox(X, Y : word); +begin + SetFillPattern(Patterns[Style], MaxColor); + with ViewInfo do + Bar(X, Y, X+Width, Y+Height); + Rectangle(X, Y, X+Width, Y+Height); + Inc(Style); +end; { DrawBox } + +begin + MainWindow('User defined fill styles'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + Width := 2 * ((x2+1) div 13); + Height := 2 * ((y2-10) div 10); + end; + X := Width div 2; + Y := Height div 2; + Style := 0; + for J := 1 to 3 do + begin + for I := 1 to 4 do + begin + DrawBox(X, Y); + Inc(X, (Width div 2) * 3); + end; + X := Width div 2; + Inc(Y, (Height div 2) * 3); + end; + SetTextJustify(LeftText, TopText); + WaitToGo; +end; { FillPatternPlay } + +procedure ColorPlay; +{ Display all of the colors available for the current driver and mode } +var + Color : word; + Width : word; + Height : word; + X, Y : word; + I, J : word; + ViewInfo : ViewPortType; + +procedure DrawBox(X, Y : word); +begin + SetFillStyle(SolidFill, Color); + SetColor(Color); + with ViewInfo do + Bar(X, Y, X+Width, Y+Height); + Rectangle(X, Y, X+Width, Y+Height); + Color := GetColor; + if Color = 0 then + begin + SetColor(MaxColor); + Rectangle(X, Y, X+Width, Y+Height); + end; + OutTextXY(X+(Width div 2), Y+Height+4, Int2Str(Color)); + Color := Succ(Color) mod (MaxColor + 1); +end; { DrawBox } + +begin + MainWindow('Color demonstration'); + Color := 1; + GetViewSettings(ViewInfo); + with ViewInfo do + begin + Width := 2 * ((x2+1) div 16); + Height := 2 * ((y2-10) div 10); + end; + X := Width div 2; + Y := Height div 2; + for J := 1 to 3 do + begin + for I := 1 to 5 do + begin + DrawBox(X, Y); + Inc(X, (Width div 2) * 3); + end; + X := Width div 2; + Inc(Y, (Height div 2) * 3); + end; + WaitToGo; +end; { ColorPlay } + +procedure PalettePlay; +{ Demonstrate the use of the SetPalette command } +const + XBars = 15; + YBars = 10; +var + I, J : word; + X, Y : word; + Color : word; + ViewInfo : ViewPortType; + Width : word; + Height : word; + OldPal : PaletteType; +begin + GetPalette(OldPal); + MainWindow('Palette demonstration'); + StatusLine('Press any key...'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + Width := (x2-x1) div XBars; + Height := (y2-y1) div YBars; + end; + X := 0; Y := 0; + Color := 0; + for J := 1 to YBars do + begin + for I := 1 to XBars do + begin + SetFillStyle(SolidFill, Color); + Bar(X, Y, X+Width, Y+Height); + Inc(X, Width+1); + Inc(Color); + Color := Color mod (MaxColor+1); + end; + X := 0; + Inc(Y, Height+1); + end; + repeat + SetPalette(Random(GetMaxColor + 1), Random(65)); + until KeyPressed; + SetAllPalette(OldPal); + WaitToGo; +end; { PalettePlay } + +procedure CrtModePlay; +{ Demonstrate the use of RestoreCrtMode and SetGraphMode } +var + ViewInfo : ViewPortType; + Ch : char; +begin + MainWindow('SetGraphMode / RestoreCrtMode demo'); + GetViewSettings(ViewInfo); + SetTextJustify(CenterText, CenterText); + with ViewInfo do + begin + OutTextXY((x2-x1) div 2, (y2-y1) div 2, 'Now you are in graphics mode'); + StatusLine('Press any key for text mode...'); + repeat until KeyPressed; + Ch := ReadKey; + if ch = #0 then ch := readkey; { trap function keys } + RestoreCrtmode; + Writeln('Now you are in text mode.'); + Write('Press any key to go back to graphics...'); + repeat until KeyPressed; + Ch := ReadKey; + if ch = #0 then ch := readkey; { trap function keys } + SetGraphMode(GetGraphMode); + MainWindow('SetGraphMode / RestoreCrtMode demo'); + SetTextJustify(CenterText, CenterText); + OutTextXY((x2-x1) div 2, (y2-y1) div 2, 'Back in graphics mode...'); + end; + WaitToGo; +end; { CrtModePlay } + +procedure LineStylePlay; +{ Demonstrate the predefined line styles available } +var + Style : word; + Step : word; + X, Y : word; + ViewInfo : ViewPortType; + +begin + ClearDevice; + DefaultColors; + MainWindow('Pre-defined line styles'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + X := 35; + Y := 10; + Step := (x2-x1) div 11; + SetTextJustify(LeftText, TopText); + OutTextXY(X, Y, 'NormWidth'); + SetTextJustify(CenterText, TopText); + for Style := 0 to 3 do + begin + SetLineStyle(Style, 0, NormWidth); + Line(X, Y+20, X, Y2-40); + OutTextXY(X, Y2-30, Int2Str(Style)); + Inc(X, Step); + end; + Inc(X, 2*Step); + SetTextJustify(LeftText, TopText); + OutTextXY(X, Y, 'ThickWidth'); + SetTextJustify(CenterText, TopText); + for Style := 0 to 3 do + begin + SetLineStyle(Style, 0, ThickWidth); + Line(X, Y+20, X, Y2-40); + OutTextXY(X, Y2-30, Int2Str(Style)); + Inc(X, Step); + end; + end; + SetTextJustify(LeftText, TopText); + WaitToGo; +end; { LineStylePlay } + +procedure UserLineStylePlay; +{ Demonstrate user defined line styles } +var + Style : word; + X, Y, I : word; + ViewInfo : ViewPortType; +begin + MainWindow('User defined line styles'); + GetViewSettings(ViewInfo); + with ViewInfo do + begin + X := 4; + Y := 10; + Style := 0; + I := 0; + while X < X2-4 do + begin + {$B+} + Style := Style or (1 shl (I mod 16)); + {$B-} + SetLineStyle(UserBitLn, Style, NormWidth); + Line(X, Y, X, (y2-y1)-Y); + Inc(X, 5); + Inc(I); + if Style = 65535 then + begin + I := 0; + Style := 0; + end; + end; + end; + WaitToGo; +end; { UserLineStylePlay } + + +procedure SayGoodbye; +{ Say goodbye and then exit the program } +var + ViewInfo : ViewPortType; +begin + MainWindow(''); + GetViewSettings(ViewInfo); + SetTextStyle(TriplexFont, HorizDir, 4); + SetTextJustify(CenterText, CenterText); + with ViewInfo do + OutTextXY((x2-x1) div 2, (y2-y1) div 2, 'That''s all folks!'); + StatusLine('Press any key to quit...'); + repeat until KeyPressed; +end; { SayGoodbye } + +begin { program body } + Initialize; + ReportStatus; + + AspectRatioPlay; + FillEllipsePlay; + SectorPlay; + WriteModePlay; + + ColorPlay; + { PalettePlay only intended to work on these drivers: } + if (GraphDriver = EGA) or + (GraphDriver = EGA64) or + (GraphDriver = VGA) then + PalettePlay; + PutPixelPlay; + PutImagePlay; + RandBarPlay; + BarPlay; + Bar3DPlay; + ArcPlay; + CirclePlay; + PiePlay; + LineToPlay; + LineRelPlay; + LineStylePlay; + UserLineStylePlay; + TextDump; + TextPlay; + CrtModePlay; + FillStylePlay; + FillPatternPlay; + PolyPlay; + SayGoodbye; + CloseGraph; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/BGILINK.MAK b/Borland Turbo Pascal v55/BGILINK.MAK new file mode 100644 index 0000000..874dc4b --- /dev/null +++ b/Borland Turbo Pascal v55/BGILINK.MAK @@ -0,0 +1,31 @@ +# Build sample program that uses FONTS.TPU and DRIVERS.TPU +bgilink.exe: drivers.tpu fonts.tpu + tpc bgilink /m + +# Build unit with all fonts linked in +fonts.tpu: fonts.pas goth.obj litt.obj sans.obj trip.obj + tpc fonts +goth.obj: goth.chr + binobj goth.chr goth GothicFontProc +litt.obj: litt.chr + binobj litt.chr litt SmallFontProc +sans.obj: sans.chr + binobj sans.chr sans SansSerifFontProc +trip.obj: trip.chr + binobj trip.chr trip TriplexFontProc + + +# Build unit with all drivers linked in +drivers.tpu: drivers.pas cga.obj egavga.obj herc.obj pc3270.obj att.obj + tpc drivers +cga.obj: cga.bgi + binobj cga.bgi cga CGADriverProc +egavga.obj: egavga.bgi + binobj egavga.bgi egavga EGAVGADriverProc +herc.obj: herc.bgi + binobj herc.bgi herc HercDriverProc +pc3270.obj: pc3270.bgi + binobj pc3270.bgi pc3270 PC3270DriverProc +att.obj: att.bgi + binobj att.bgi att ATTDriverProc + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/BGILINK.PAS b/Borland Turbo Pascal v55/BGILINK.PAS new file mode 100644 index 0000000..dafa1e3 --- /dev/null +++ b/Borland Turbo Pascal v55/BGILINK.PAS @@ -0,0 +1,126 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program BgiLink; +{ This program demonstrates how to link graphics driver and font files + into an EXE file. BGI graphic's drivers and fonts are kept in + separate disk files so they may be dynamically loaded at runtime. + However, sometimes it is preferable to place all auxiliary files + directly into an .EXE. This program, along with its make file + (BGILINK.MAK) and two units (DRIVERS.PAS and FONTS.PAS) links all + the drivers and fonts directly into BGILINK.EXE. + + Have these 3 programs in the current drive or directory, or + have them available via a path (both are on Disk II): + + MAKE.EXE - Make utility that will build BGILINK.EXE + BINOBJ.EXE - utility program to convert any file into an .OBJ file + + Place in the current drive or directory the following files (all + are on Disk III): + + BGILINK.PAS - this sample program + DRIVERS.PAS - Pascal unit that will link in all BGI drivers + FONTS.PAS - Pascal unit that will link in all BGI fonts + *.CHR - BGI font files + *.BGI - BGI driver files + BGILINK.MAK - "make" file that builds DRIVERS.TPU, FONT.TPU, and + finally BGILINK.EXE + + DIRECTIONS: + 1. Run MAKE on the BGILINK.MAK file by typing the following command + at a DOS prompt: + + make -fBGIlink.mak + + Using BINOBJ.EXE, this will first build .OBJ files out of the driver + files (*.BGI) and then call Turbo Pascal to compile DRIVERS.PAS. + Next, the font files (*.CHR) will be converted to .OBJs and + FONTS.PAS will be compiled. Finally, BGILINK.PAS will be compiled + (it uses DRIVERS.TPU and FONTS.TPU). + + 2. Run BGILINK.EXE. It contains all the drivers and all the fonts, so it + will run on any system with a graphics card supported by the Graph + unit (CGA, EGA, EGA 64 K, EGA monochrome, Hercules monochrome, + VGA, MCGA, IBM 3270 PC and AT&T 6400). + + EXPLANATION + + BGILINK.PAS uses DRIVERS.TPU and FONTS.TPU in its uses statement: + + uses Drivers, Fonts; + + Then, it "registers" the drivers it intends to use (in this case, + all of them, so it will run on any graphics card). Then it registers + all of the fonts it will use (again all of them, just for demonstration + purposes) and finally it does some very modest graphics. + + You can easily modify BGILINK.PAS for your own use by commenting out + the calls to RegisterBGIdriver and RegisterBGIfont for drivers and + fonts that your program doesn't use. + + For a detailed explanation of registering and linking drivers and fonts, + refer to the RegisterBGIdriver and RegisterBGIfont descriptions in + GRAPH.DOC (on Disk III). +} + +uses Graph, { library of graphics routines } + Drivers, { all the BGI drivers } + Fonts; { all the BGI fonts } +var + GraphDriver, GraphMode, Error : integer; + +procedure Abort(Msg : string); +begin + Writeln(Msg, ': ', GraphErrorMsg(GraphResult)); + Halt(1); +end; + +begin + { Register all the drivers } + if RegisterBGIdriver(@CGADriverProc) < 0 then + Abort('CGA'); + if RegisterBGIdriver(@EGAVGADriverProc) < 0 then + Abort('EGA/VGA'); + if RegisterBGIdriver(@HercDriverProc) < 0 then + Abort('Herc'); + if RegisterBGIdriver(@ATTDriverProc) < 0 then + Abort('AT&T'); + if RegisterBGIdriver(@PC3270DriverProc) < 0 then + Abort('PC 3270'); + + + { Register all the fonts } + if RegisterBGIfont(@GothicFontProc) < 0 then + Abort('Gothic'); + if RegisterBGIfont(@SansSerifFontProc) < 0 then + Abort('SansSerif'); + if RegisterBGIfont(@SmallFontProc) < 0 then + Abort('Small'); + if RegisterBGIfont(@TriplexFontProc) < 0 then + Abort('Triplex'); + + GraphDriver := Detect; { autodetect the hardware } + InitGraph(GraphDriver, GraphMode, ''); { activate graphics } + if GraphResult <> grOk then { any errors? } + begin + Writeln('Graphics init error: ', GraphErrorMsg(GraphDriver)); + Halt(1); + end; + + MoveTo(5, 5); + OutText('Drivers and fonts were '); + MoveTo(5, 20); + SetTextStyle(GothicFont, HorizDir, 4); + OutText('Built '); + SetTextStyle(SmallFont, HorizDir, 4); + OutText('into '); + SetTextStyle(TriplexFont, HorizDir, 4); + OutText('EXE '); + SetTextStyle(SansSerifFont, HorizDir, 4); + OutText('file!'); + Rectangle(0, 0, GetX, GetY + TextHeight('file!') + 1); + Readln; + CloseGraph; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/BINOBJ.EXE b/Borland Turbo Pascal v55/BINOBJ.EXE new file mode 100644 index 0000000000000000000000000000000000000000..e2b021cbd28babd43a294386a60dce1a2cd76afd GIT binary patch literal 10220 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/BOUNDS.PAS b/Borland Turbo Pascal v55/BOUNDS.PAS new file mode 100644 index 0000000..e200488 --- /dev/null +++ b/Borland Turbo Pascal v55/BOUNDS.PAS @@ -0,0 +1,329 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit Bounds; +{ Turbo Pascal 5.5 object-oriented example. + See BREAKOUT.PAS. + Contains the Paddle object type and the object types that + define the boundaries of the playfield. + This unit is part of the BREAKOUT.PAS example. +} + +interface + +uses Screen, Bricks, Count, Crt; + +type + ObstaclePtr = ^Obstacle; + + { An ObstacleList is a list of instances of objects derived from the + object Obstacle. In order to use all these instances polymorphically, + All their virtual functions have to have corresponding virtual functions + in Obstacle, even if they are never used. } + + Obstacle = object(Location) + Width : Integer; + Trap : Boolean; + NextPtr : ObstaclePtr; + constructor Init(InitX, InitY, InitWidth : Integer; SetTrap : Boolean); + destructor Done; virtual; + function Collide(var B : Ball) : Boolean; virtual; + function IsTrap : Boolean; virtual; + function GetValue : Integer; virtual; + end; + + ObstacleList = object + Head : Obstacle; + Tail : ObstaclePtr; + constructor Init; + destructor Done; virtual; + procedure Append(NewObstacle : ObstaclePtr); + procedure Show; + procedure Hide; + function CheckCollisions(var B : Ball; var Score : Counter) : Boolean; + end; + + Paddle = object(Obstacle) + Color : Integer; + constructor Init(InitX, InitY, InitColor : Integer); + destructor Done; virtual; + procedure Show; virtual; + procedure Hide; virtual; + procedure MoveTo(NewX, NewY : Integer); virtual; + function Collide(var B : Ball) : Boolean; virtual; + end; + + { There are no instances of the object Boundary. It's here to provide + a common basis for the next four objects. } + Boundary = object(Obstacle) + constructor Init(InitX, InitY, InitWidth : Integer; SetTrap : Boolean); + end; + + LeftBound = object(Boundary) + constructor Init(InitX, InitY, InitWidth : Integer; SetTrap : Boolean); + function Collide(var B : Ball) : Boolean; virtual; + end; + + UpperBound = object(Boundary) + constructor Init(InitX, InitY, InitWidth : Integer; SetTrap : Boolean); + function Collide(var B : Ball) : Boolean; virtual; + end; + + RightBound = object(Boundary) + constructor Init(InitX, InitY, InitWidth : Integer; SetTrap : Boolean); + function Collide(var B : Ball) : Boolean; virtual; + end; + + LowerBound = object(Boundary) + constructor Init(InitX, InitY, InitWidth : Integer; SetTrap : Boolean); + function Collide(var B : Ball) : Boolean; virtual; + end; + +implementation + +constructor Obstacle.Init(InitX, InitY, InitWidth : Integer; + SetTrap : Boolean); +begin + Location.Init(InitX, InitY); + Width := InitWidth; + Trap := SetTrap; + NextPtr := nil; +end; + +destructor Obstacle.Done; +begin +end; + +function Obstacle.Collide(var B : Ball) : Boolean; +begin + Collide := True; +end; + +function Obstacle.IsTrap : Boolean; +begin + IsTrap := Trap; +end; + +function Obstacle.GetValue : Integer; +begin + GetValue := 0; +end; + +constructor ObstacleList.Init; +begin + Head.Init(0, 0, 0, False); + Tail := @Head; +end; + +destructor ObstacleList.Done; +var + Temp1, Temp2 : ObstaclePtr; +begin + Temp1 := Head.NextPtr; + while Temp1 <> nil do + begin + Temp2 := Temp1; + Temp1 := Temp1^.NextPtr; + Temp2^.Done; + end; +end; + +procedure ObstacleList.Append(NewObstacle : ObstaclePtr); +begin + Tail^.NextPtr := NewObstacle; + Tail := NewObstacle; +end; + +procedure ObstacleList.Show; +var + Current : ObstaclePtr; +begin + Current := Head.NextPtr; + while Current <> nil do + begin + Current^.Show; + Current := Current^.NextPtr; + end; +end; + +procedure ObstacleList.Hide; +var + Current : ObstaclePtr; +begin + Current := Head.NextPtr; + while Current <> nil do + begin + Current^.Hide; + Current := Current^.NextPtr; + end; +end; + + +{ This function is a little more complex than I like. It checks +whether a collision occurs, and updates the score if one does. } + +function ObstacleList.CheckCollisions(var B : Ball; + var Score : Counter) : Boolean; +var + Current : ObstaclePtr; +begin + CheckCollisions := False; + Current := Head.NextPtr; + while Current <> nil do + begin + if Current^.Collide(B) then + begin + Score.Add(Current^.GetValue); + if Current^.IsTrap then + CheckCollisions := True; + end; + Current := Current^.NextPtr; + end; +end; + +constructor Paddle.Init(InitX, InitY, InitColor : Integer); +begin + Obstacle.Init(InitX, InitY, 5, False); + Color := InitColor; +end; + +destructor Paddle.Done; +begin + Obstacle.Done; +end; + +procedure Paddle.Show; +var + Str : String[10]; +begin + FillChar(Str[1], Width, Chr(223)); + Str[0] := Chr(Width); + Location.Show; + TextColor(Color); + GoToXY(X, Y); + Write(Str); +end; + +procedure Paddle.Hide; +begin + Location.Hide; + GoToXY(X, Y); + Write('' : Width); +end; + +{ The motion of Paddle is restricted to the 80-character screen } + +procedure Paddle.MoveTo(NewX, NewY : Integer); +begin + Hide; + if NewX < 1 then + X := 1 + else if NewX > 81 - Width then + X := 81 - Width + else + X := NewX; + Y := NewY; + Show; +end; + +{ If the ball hits the paddle we have to change the ball's direction. + Also, to keep the overall logic simpler, if the paddle is at the + edge of the screen and the ball would miss the paddle and go off the + edge, we call it a hit. If we don't do this here, we get into some + complications with bouncing off the sides of the screen } + +function Paddle.Collide(var B : Ball) : Boolean; +var + NewX, NewY : Integer; +begin + NewX := B.NextX; + NewY := B.NextY; + Collide := False; + if (NewY = Y) then + if ((NewX >= X) and (NewX < X + Width)) or + ((NewX < 1) and (X = 1)) or + ((NewX > 80) and (X + Width = 81)) then + begin + B.ReverseY; +{$IFDEF Test} { If the paddle is following the ball, we have to put + in some random behavior so it doesn't get boring. } + B.ChangeXVel(Integer(Random(2))*2-1); +{$ELSE} + B.ChangeXVel(B.GetX - X - 2); +{$ENDIF} + Collide := True; + end; +end; + +constructor Boundary.Init(InitX, InitY, InitWidth : Integer; + SetTrap : Boolean); +begin + Obstacle.Init(InitX, InitY, InitWidth, SetTrap); +end; + +constructor LeftBound.Init(InitX, InitY, InitWidth : Integer; + SetTrap : Boolean); +begin + Boundary.Init(InitX, InitY, InitWidth, SetTrap); +end; + +function LeftBound.Collide(var B : Ball) : Boolean; +begin + Collide := False; + if (B.NextX <= X) and (B.NextY >= Y) and (B.NextY <= Y + Width) then + begin + B.ReverseX; + Collide := True; + end; +end; + +constructor UpperBound.Init(InitX, InitY, InitWidth : Integer; + SetTrap : Boolean); +begin + Boundary.Init(InitX, InitY, InitWidth, SetTrap); +end; + +function UpperBound.Collide(var B : Ball) : Boolean; +begin + Collide := False; + if (B.NextY <= Y) and (B.NextX >= X) and (B.NextX <= X + Width) then + begin + B.ReverseY; + Collide := True; + end; +end; + +constructor RightBound.Init(InitX, InitY, InitWidth : Integer; + SetTrap : Boolean); +begin + Boundary.Init(InitX, InitY, InitWidth, SetTrap); +end; + +function RightBound.Collide(var B : Ball) : Boolean; +begin + Collide := False; + if (B.NextX >= X) and (B.NextY >= Y) and (B.NextY <= Y + Width) then + begin + B.ReverseX; + Collide := True; + end; +end; + +constructor LowerBound.Init(InitX, InitY, InitWidth : Integer; + SetTrap : Boolean); +begin + Boundary.Init(InitX, InitY, InitWidth, SetTrap); +end; + +function LowerBound.Collide(var B : Ball) : Boolean; +begin + Collide := False; + if (B.NextY >= Y) and (B.NextX >= X) and (B.NextX <= X + Width) then + begin + B.ReverseY; + Collide := True; + end; +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/BREAKOUT.PAS b/Borland Turbo Pascal v55/BREAKOUT.PAS new file mode 100644 index 0000000..c0df41c --- /dev/null +++ b/Borland Turbo Pascal v55/BREAKOUT.PAS @@ -0,0 +1,302 @@ + +{ Turbo Breakout } +{ Copyright (c) 1989 by Borland International, Inc. } + +program Breakout; +{ Turbo Pascal 5.5 object-oriented example. + + This is a version of the classic arcade game, Breakout. + + SCREEN.PAS + COUNT.PAS + BRICKS.PAS + BOUNDS.PAS + WALLS.PAS + BREAKOUT.PAS + + To build an executable file, compile from the command line with: + + tpc /b breakout + + or load BREAKOUT.PAS into the integrated development + environment and press F9. + + When testing the program, you may want to force the paddle to + follow the ball, so you'll never miss. The program contains + conditional compilation directives to produce this version, and + you can build it from the command line with: + + tpc /DTest breakout + + or load BREAKOUT.PAS into the integrated development + environment, select Alt-O/C/C, type 'Test' (without the quotes, + of course) followed by the Enter key, then select Alt-C/B to + rebuild the executable file. +} + +uses Screen, Count, Bricks, Bounds, Walls, Crt, Dos; + +var + ss : SaveScreen; + w : Wall; + b : Ball; + p : Paddle; + Speed : LimitCounter; + Left : LeftBound; + Top : UpperBound; + Right : RightBound; + Bottom : LowerBound; + Obstacles : ObstacleList; + PaddleMsg, + SpeedMsg, + StartMsg, + QuitMsg, + PauseMsg1, + PauseMsg2, + TypeMsg : TextString; + Score : Counter; + Highest : Counter; + Balls : DownCounter; + X : Integer; + Finished : Boolean; + FirstGame : Boolean; + TypeInc, + ch : Char; + +procedure Startup; +begin + { First set up the screen and the cursor } + ss.Init; + TextBackground(BLACK); + ClrScr; + + { Create the boundaries of the playfield } + Left.Init(0, 0, 27, False); + Top.Init(0, 0, 82, False); + Right.Init(81, 0, 27, False); + Bottom.Init(0, 24, 82, True); + + { Initialize the score displays } + Score.Init(0, 65, 24, 'Score', 15); + Score.Show; + Highest.Init(0, 60, 25, 'High Score', 14); + Highest.Show; + + { Set up the various menu messages } + PauseMsg1.Init(31, 18, 'Paused. Press any', 15); + PauseMsg2.Init(31, 19, ' key to continue.', 15); + SpeedMsg.Init(5, 23, #24 + #25 + ' to change speed', 14); + StartMsg.Init(5, 24, #17 + #196 + #217 + ' to begin game', 14); + PaddleMsg.Init(5, 24, #27 + #26 + ' to move paddle', 14); + QuitMsg.Init(5, 25, 'ESC to quit', 14); + QuitMsg.Show; + + { Set up the information messages } + Balls.Init(5, 40, 24, -1, 'Balls', 15); + Balls.Show; + Speed.Init(1, 40, 25, 1, 10, 'Speed', 14); + Speed.Show; + + { Build the wall } + w.Init(1, 1, 16, 10); + w.Show; + + { Need to initialize these, even though we're going to move them later } + b.Init(10, 22, 1, -1, YELLOW); + p.Init(8, 23, WHITE); + + { Put the various obstacles into a list. We don't really need + to do this, but it makes changing things around much easier } + Obstacles.Init; + Obstacles.Append(@p); + Obstacles.Append(@w); + Obstacles.Append(@Left); + Obstacles.Append(@Top); + Obstacles.Append(@Right); + Obstacles.Append(@Bottom); + + TypeMsg.Init(22, 12, 'Increase typematic rate? (y/n) ', WHITE); + TypeMsg.Show; + repeat + TypeInc := UpCase(ReadKey); + until (TypeInc = 'Y') or (TypeInc = 'N'); + TypeMsg.Hide; + + if TypeInc = 'Y' then + ss.Speedup; + + ss.SetCursor($2000); + Randomize; + FirstGame := True; +end; + +procedure NewGame; +begin + Balls.Reset; + Score.Reset; + if not FirstGame then + w.Reset; + X := Random(78) + 3; + b.MoveTo(X, 22); + p.MoveTo(X-2, 23); + b.Show; + p.Show; + Balls.Decrement; + FirstGame := False; +end; + +{ This procedure handles keystrokes between games. + It returns False if the user presses ESC, otherwise it returns True. } +function MainMenu : Boolean; +var + Done : Boolean; +begin + MainMenu := True; + Done := False; + SpeedMsg.Show; + StartMsg.Show; + while not Done do + begin + ch := ReadKey; + case ch of + Chr(27) : + begin + MainMenu := False; + Done := True; + end; + #13 : Done := True; + #0 : + begin + ch := ReadKey; + if Ord(ch) = 72 then + Speed.Increment + else if Ord(ch) = 80 then + Speed.Decrement; + end; + end; + end; + SpeedMsg.Hide; + StartMsg.Hide; +end; + +{ This procedure handles keystrokes while the game is in progress } +procedure ProcessKeyStroke; + +{ Pause the game } +procedure Pause; +begin + PauseMsg1.Show; + PauseMsg2.Show; + ch := ReadKey; + if KeyPressed then + ch := ReadKey; { Swallow extended keystrokes } + PauseMsg1.Hide; + PauseMsg2.Hide; + b.Show; +end; + +begin + ch := ReadKey; + case ch of + Chr(27) : Finished := True; + Chr(0) : + begin + ch := ReadKey; +{$IFNDEF Test} + case Ord(ch) of + 75: p.MoveTo(p.GetX - 1, p.GetY); { Left Arrow } + 77: p.MoveTo(p.GetX + 1, p.GetY); { Right Arrow } + else + Pause; + end; +{$ELSE} + Pause; +{$ENDIF} + end + else + Pause; + end; +end; + +{ This procedure checks for collisions with any of the obstacles + and updates the screen accordingly. } +procedure Update; +var + Offset : Integer; +begin + if Obstacles.CheckCollisions(b, Score) then + begin + b.MoveY; + p.MoveTo(b.GetX - 2, p.GetY); + sound(150); + Delay(300); + nosound; + Balls.Decrement; + while KeyPressed do + ch := ReadKey; + end; + + b.MoveX; + b.MoveY; + +{$IFDEF Test} + p.MoveTo(b.NextX -2, p.GetY); +{$ENDIF} +end; + +{ This procedure cleans up when we're exiting from the program } +procedure ShutDown; +begin + b.Hide; + Obstacles.Hide; + Balls.Hide; + Score.Hide; + + Obstacles.Done; + + ss.Restore; + if TypeInc = 'Y' then + ss.Slowdown; + ClrScr; +end; + +{ This procedure plays a game. The main loop allows up to ten keystrokes, + then moves the ball and checks for collisions } +procedure Play; +var + KeyLoops : Integer; +begin + NewGame; +{$IFNDEF Test} + PaddleMsg.Show; +{$ENDIF} + Finished := False; + KeyLoops := 0; + repeat + if KeyPressed then + ProcessKeyStroke; + Inc(KeyLoops); + if (KeyLoops = 10) and not Finished then + begin + KeyLoops := 0; + UpDate; + end; + Delay(12 - Speed.GetValue); + until Finished or Balls.Last; + PaddleMsg.Hide; +end; + +begin + Startup; + while MainMenu do + begin + Play; + Balls.Reset; + b.Hide; + p.Hide; + if Score.GetValue > Highest.GetValue then + Highest.SetValue(Score.GetValue); + end; + ShutDown; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/BRICKS.PAS b/Borland Turbo Pascal v55/BRICKS.PAS new file mode 100644 index 0000000..dff6cf9 --- /dev/null +++ b/Borland Turbo Pascal v55/BRICKS.PAS @@ -0,0 +1,151 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit Bricks; +{ Turbo Pascal 5.5 object-oriented example. + See BREAKOUT.PAS. + This unit contains the Ball object and the object types that + end up as bricks on the screen. +} + +interface + +uses Screen, Count; + +type + Block = object(Location) + Color : Integer; + Width : Integer; + BChar : Char; + constructor Init(InitX, InitY, InitColor, InitWidth : Integer; + InitChr : Char); + procedure Show; virtual; + procedure Hide; virtual; + end; + + Ball = object(Block) + XVel : Integer; + YVel : Integer; + constructor Init(InitX, InitY, InitXVel, InitYVel, InitColor : Integer); + function NextX : Integer; + function NextY : Integer; + procedure MoveX; + procedure MoveY; + procedure ReverseX; + procedure ReverseY; + procedure ChangeXVel(Delta : Integer); + end; + + Brick = object(Block) + Value : Integer; + constructor Init(InitX, InitY, InitColor, InitValue : Integer); + function GetValue : Integer; + end; + +implementation + +uses Crt; + +constructor Block.Init(InitX, InitY, InitColor, InitWidth : Integer; + InitChr : Char); +begin + Location.Init(InitX, InitY); + Color := InitColor; + Width := InitWidth; + BChar := InitChr; +end; + +procedure Block.Show; +var + Str : String[10]; +begin + FillChar(Str[1], Width, BChar); + Str[0] := Chr(Width); + Location.Show; + TextColor(Color); + GoToXY(X, Y); + Write(Str); +end; + +procedure Block.Hide; +begin + Location.Hide; + GoToXY(X, Y); + Write('' : Width); +end; + +constructor Brick.Init(InitX, InitY, InitColor, InitValue : Integer); +var + BlockChar : Char; +begin + BlockChar := Chr($B2); + if (LastMode = Mono) and Odd(InitX + InitY) then + BlockChar := Chr($B0); + Block.Init(InitX, InitY, InitColor, 5, BlockChar); + Value := InitValue; +end; + +function Brick.GetValue : Integer; +begin + GetValue := Value; +end; + +constructor Ball.Init(InitX, InitY, InitXVel, InitYVel, InitColor : Integer); +begin + Block.Init(InitX, InitY, InitColor, 1, Chr(15)); + XVel := InitXVel; + YVel := InitYVel; +end; + +function Ball.NextX : Integer; +begin + NextX := X + XVel; +end; + +function Ball.NextY : Integer; +begin + NextY := Y + YVel; +end; + +procedure Ball.MoveX; +begin + Hide; + X := NextX; + Show; +end; + +procedure Ball.MoveY; +begin + Hide; + Y := NextY; + Show; +end; + +procedure Ball.ReverseX; +begin + XVel := -XVel; +end; + +procedure Ball.ReverseY; +begin + YVel := -YVel; +end; + +{ This procedure introduces the variations in horizontal velocity for + the ball. Horizontal velocity ranges from -2 to 2. If you hit the + ball with the edge of the paddle, you'll get a large change in + horizontal velocity. } + +procedure Ball.ChangeXVel(Delta : Integer); +begin + Inc(XVel, Delta); + if XVel < -2 then + XVel := -2 + else if XVel > 2 then + XVel := 2 + else if XVel = 0 then + XVel := Integer(Random(2))*2 - 1; +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/BUFSTM.ASM b/Borland Turbo Pascal v55/BUFSTM.ASM new file mode 100644 index 0000000..dea52e5 --- /dev/null +++ b/Borland Turbo Pascal v55/BUFSTM.ASM @@ -0,0 +1,219 @@ +; Turbo Pascal 5.5 object-oriented example +; Assembler code for OBJECTS.PAS unit +; Copyright (c) 1989 by Borland International, Inc. + + TITLE BUFSTM + + INCLUDE OBJECTS.INC + +CODE SEGMENT BYTE PUBLIC + + EXTRN StreamError:NEAR + EXTRN DosStream@GetPos:NEAR + + ASSUME CS:CODE + + PUBLIC BufStream@Flush + +BufStream@Flush PROC FAR + +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CMP ES:[DI].Stream@Status,0 + JNE @@1 + MOV AL,2 + CALL FlushBuffer +@@1: POP BP + RET 4 + +BufStream@Flush ENDP + + PUBLIC BufStream@GetPos + +BufStream@GetPos PROC FAR + +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + PUSH ES + PUSH DI + PUSH CS + CALL DosStream@GetPos + OR DX,DX + JS @@1 + LES DI,@Self + SUB AX,ES:[DI].BufStream@BufEnd + SBB DX,0 + ADD AX,ES:[DI].BufStream@BufPtr + ADC DX,0 +@@1: POP BP + RET 4 + +BufStream@GetPos ENDP + + PUBLIC BufStream@Read + +BufStream@Read PROC FAR + +@Buf EQU (DWORD PTR [BP+12]) +@Count EQU (WORD PTR [BP+10]) +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CMP ES:[DI].Stream@Status,0 + JNE @@6 + MOV AL,1 + CALL FlushBuffer + JNE @@6 + XOR DX,DX +@@1: MOV CX,@Count + SUB CX,DX + JE @@7 + LES DI,@Self + MOV AX,ES:[DI].BufStream@BufEnd + SUB AX,ES:[DI].BufStream@BufPtr + JA @@2 + PUSH CX + PUSH DX + PUSH DS + LDS DX,ES:[DI].BufStream@Buffer + MOV CX,ES:[DI].BufStream@BufSize + MOV BX,ES:[DI].DosStream@Handle + MOV AH,3FH + INT 21H + POP DS + POP DX + POP CX + JC @@5 + MOV ES:[DI].BufStream@BufPtr,0 + MOV ES:[DI].BufStream@BufEnd,AX + OR AX,AX + JE @@4 +@@2: CMP CX,AX + JB @@3 + MOV CX,AX +@@3: PUSH DS + LDS SI,ES:[DI].BufStream@Buffer + ADD SI,ES:[DI].BufStream@BufPtr + ADD ES:[DI].BufStream@BufPtr,CX + LES DI,@Buf + ADD DI,DX + ADD DX,CX + CLD + REP MOVSB + POP DS + JMP @@1 +@@4: MOV AX,101 +@@5: CALL StreamError +@@6: LES DI,@Buf + MOV CX,@Count + XOR AL,AL + CLD + REP STOSB +@@7: POP BP + RET 10 + +BufStream@Read ENDP + + PUBLIC BufStream@Write + +BufStream@Write PROC FAR + +@Buf EQU (DWORD PTR [BP+12]) +@Count EQU (WORD PTR [BP+10]) +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CMP ES:[DI].Stream@Status,0 + JNE @@4 + MOV AL,0 + CALL FlushBuffer + JNE @@4 + XOR DX,DX +@@1: MOV CX,@Count + SUB CX,DX + JE @@4 + LES DI,@Self + MOV AX,ES:[DI].BufStream@BufSize + SUB AX,ES:[DI].BufStream@BufPtr + JA @@2 + PUSH CX + PUSH DX + MOV AL,1 + CALL FlushBuffer + POP DX + POP CX + JNE @@4 + MOV AX,ES:[DI].BufStream@BufSize +@@2: CMP CX,AX + JB @@3 + MOV CX,AX +@@3: PUSH DS + MOV AX,ES:[DI].BufStream@BufPtr + ADD ES:[DI].BufStream@BufPtr,CX + LES DI,ES:[DI].BufStream@Buffer + ADD DI,AX + LDS SI,@Buf + ADD SI,DX + ADD DX,CX + CLD + REP MOVSB + POP DS + JMP @@1 +@@4: POP BP + RET 10 + +BufStream@Write ENDP + +; Flush stream buffer +; In AL = Flush mode (0=Read,1=Write,2=Both) +; ES:DI = BufStream pointer +; Out ZF = Status test + +FlushBuffer PROC NEAR + + MOV CX,ES:[DI].BufStream@BufPtr + SUB CX,ES:[DI].BufStream@BufEnd + JE @@4 + MOV BX,ES:[DI].DosStream@Handle + JA @@1 + CMP AL,1 + JE @@4 + MOV DX,CX + MOV CX,-1 + MOV AX,4201H + INT 21H + JMP SHORT @@3 +@@1: CMP AL,0 + JE @@4 + PUSH DS + LDS DX,ES:[DI].BufStream@Buffer + MOV AH,40H + INT 21H + POP DS + JC @@2 + CMP AX,CX + JE @@3 + MOV AX,101 +@@2: CALL StreamError +@@3: XOR AX,AX + MOV ES:[DI].BufStream@BufPtr,AX + MOV ES:[DI].BufStream@BufEnd,AX + CMP AX,ES:[DI].Stream@Status +@@4: RET + +FlushBuffer ENDP + +CODE ENDS + + END + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/BUFSTM.OBJ b/Borland Turbo Pascal v55/BUFSTM.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..d1d040eb90637057c2160511ef55d445f583a693 GIT binary patch literal 655 zcmZqRVc>EKbqfyh)pHE??dp(cU|36X8cqkZht2)SLcvmJx@R94;{=vQJ-l{3=A35*ce!x{asvL zXRtG9WH2%@GM?#CVBii8337Gxbqxyg4`L8-@ehXZ9o$_*0{nv+p}`(Nhu=q+2oLfMaXrAmAT~i9s6zmu17ZWvnDP!528TtA z6Bpz#GBPlPcE34N$EMa?%fnF0x`F8hFJtT}7N{s&INu8f2JTB0f*>W@t`g0+7}S_u z#hNcMAQVBgW^Q17afzWc$@o&YAD8y2k`$1RZdVDQF0pd8z#uubqoD$7-M%7f-LZUI z?9VF7M@1GHsvUO)I!LY4Rf79KiGuZsBBt&WK$WEeYRsi#YK*>ON9uT(e=%SD^LdH< z>t#Dq8Gz0K3IVM!I`HT7s@PLpDDL;$!0^JCq0}Ab2s?-)M8J;V4-5jjQI8=ivQ!P| zG7*?<-L7Dp)Q;2&F#kAO#>4yxYTs^<@jxewscHL4l-PkBUM^t6SYpzBap(X4I~bkL zD!!JoVJJ}n`)!K@&`(9|)(1=2Anr6i0Q8p_$Zu-at~`f(=Lj&gD6laywXA1jWNZxw L5*=N@bW#EUpLfgw literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/CARDFILE.PAS b/Borland Turbo Pascal v55/CARDFILE.PAS new file mode 100644 index 0000000..b032071 --- /dev/null +++ b/Borland Turbo Pascal v55/CARDFILE.PAS @@ -0,0 +1,137 @@ + +{ Turbo Cardfile } +{ Copyright (c) 1989 by Borland International, Inc. } + +program CardFile; +{ Turbo Pascal 5.5 object-oriented example. + Demonstrates the use of the CARDS unit. + Refer to OOPDEMOS.DOC for an overview of this program. +} + +{$S-} +{$M 8192, 65536, 655360} + +uses Crt, Objects, Forms, Sliders, Cards; + +const + Signature: Longint = $44524143; + +var + F: Form; + C: CardList; + S: FStream; + +procedure Error(Message: String); +begin + WriteLn(Message, ': ', ParamStr(1)); + Halt(1); +end; + +procedure ReadCards; +var + Header: Longint; +begin + S.Init(ParamStr(1), SOpen, 1024); + if S.Status <> 0 then Error('Cannot open file'); + S.Read(Header, SizeOf(Longint)); + if Header <> Signature then Error('File format error'); + F.Load(S); + C.Load(S); + if S.Status <> 0 then Error('Disk read error'); + S.Done; +end; + +function EditCards: Boolean; +var + Ch: Char; + Start, Stop: Boolean; + +function EditForm: Boolean; +begin + Color(ForeColor); + GotoXY(1, 25); + Write(' Edit '#179' F2-Accept Esc-Cancel'); + ClrEol; + EditForm := F.Edit = CSave; +end; + +function Confirm(Message: String): Boolean; +begin + Color(ForeColor); + GotoXY(1, 25); + Write(' ', Message, ' (Y/N)? '); + ClrEol; + Confirm := UpCase(ReadChar) = 'Y'; +end; + +begin + Color(BackColor); + ClrScr; + Color(ForeColor); + GotoXY(1, 1); + Write(' File ', ParamStr(1)); + ClrEol; + Start := True; + Stop := False; + repeat + if C.Count = 0 then F.Clear else F.Put(C.CardData^); + F.Show(Start); + Color(ForeColor); + GotoXY(69, 1); + Write(C.Count: 5, ' Cards'); + GotoXY(1, 25); + Write(' Browse '#179' '#25'-Next '#24'-Prev Enter-Edit ' + + 'Ins-Insert Del-Delete Esc-Exit '); + ClrEol; + Ch := ReadChar; + if (Ch = CEnter) and (C.Count = 0) then Ch := CIns; + case Ch of + CNext: C.Next; + CPrev: C.Prev; + CEnter: if EditForm then F.Get(C.CardData^); + CIns: + begin + F.Clear; + F.Show(False); + if EditForm then + begin + C.Insert; + F.Get(C.CardData^); + end; + end; + CDel: + if C.Count > 0 then + if Confirm('Delete this card') then C.Delete; + CEsc: Stop := True; + else + Beep; + end; + Start := False; + until Stop; + EditCards := Confirm('Update card file'); + NormVideo; + ClrScr; +end; + +procedure WriteCards; +begin + S.Init(ParamStr(1), SCreate, 1024); + if S.Status <> 0 then Error('Cannot create file'); + S.Write(Signature, SizeOf(Longint)); + F.Store(S); + C.Store(S); + S.Flush; + if S.Status <> 0 then Error('Disk write error'); + S.Done; +end; + +begin + if ParamCount <> 1 then + begin + WriteLn('Usage: CARDFILE filename'); + Halt(1); + end; + ReadCards; + if EditCards then WriteCards; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/CARDGEN.PAS b/Borland Turbo Pascal v55/CARDGEN.PAS new file mode 100644 index 0000000..b839fa0 --- /dev/null +++ b/Borland Turbo Pascal v55/CARDGEN.PAS @@ -0,0 +1,76 @@ + +{ Turbo Generator } +{ Copyright (c) 1989 by Borland International, Inc. } + +program CardGen; +{ Turbo Pascal 5.5 object-oriented example. + Generates example OOP databases for CARDFILE.PAS. + Refer to OOPDEMOS.DOC for an overview of this program. +} + +{$S-} +{$M 8192, 16384, 16384} + +uses Crt, Objects, Forms, Sliders, Cards; + +const + Signature: Longint = $44524143; { unique signature for file } + +var + F: Form; + C: CardList; + S: FStream; + +procedure PeopleForm; +{ Create an example form in memory with "People" info } +begin + F.Init(10, 5, 54, 16); + F.Add(New(FStrPtr, Init(3, 2, ' Firstname ', 30))); + F.Add(New(FStrPtr, Init(3, 3, ' Lastname ', 30))); + F.Add(New(FStrPtr, Init(3, 5, ' Address ', 32))); + F.Add(New(FStrPtr, Init(3, 6, ' City ', 16))); + F.Add(New(FStrPtr, Init(25, 6, ' State ', 2))); + F.Add(New(FZipPtr, Init(34, 6, ' Zip '))); + F.Add(New(FIntPtr, Init(3, 8, ' Counter 1 ', 0, 99999999))); + F.Add(New(FIntPtr, Init(22, 8, ' 2 ', 0, 99999999))); + F.Add(New(FIntPtr, Init(33, 8, ' 3 ', 0, 99999999))); + F.Add(New(FSliderPtr, Init(3, 10, ' Slider One ', 0, 100, 5))); + F.Add(New(FSliderPtr, Init(3, 11, ' Slider Two ', 0, 100, 5))); +end; + +procedure PartsForm; +{ Create an example form in memory with "Parts" info } +begin + F.Init(12, 7, 68, 14); + F.Add(New(FStrPtr, Init(3, 2, ' Part Code ', 10))); + F.Add(New(FRealPtr, Init(24, 2, ' Cost ', 9, 2))); + F.Add(New(FRealPtr, Init(39, 2, ' Retail ', 9, 2))); + F.Add(New(FStrPtr, Init(3, 4, ' Description ', 40))); + F.Add(New(FStrPtr, Init(3, 5, ' Description ', 40))); + F.Add(New(FIntPtr, Init(3, 7, ' Units On Hand ', 0, 999999))); + F.Add(New(FIntPtr, Init(24, 7, ' Backorder ', 0, 999999))); + F.Add(New(FIntPtr, Init(41, 7, ' Shipped ', 0, 999999))); +end; + +procedure MakeFile(FileName: FNameStr); +{ Use a stream to create a cardfile with a form and no data } +begin + C.Init(F.Size); + S.Init(FileName, SCreate, 1024); + S.Write(Signature, SizeOf(Longint)); + F.Store(S); + C.Store(S); + S.Flush; + if S.Status <> 0 then WriteLn('Error creating file ', FileName); + S.Done; + C.Done; + F.Done; +end; + +begin + PeopleForm; + MakeFile('PEOPLE.DTA'); + PartsForm; + MakeFile('PARTS.DTA'); +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/CARDS.DTA b/Borland Turbo Pascal v55/CARDS.DTA new file mode 100644 index 0000000000000000000000000000000000000000..84986420d7016e836cdc5653358eafdf5407a667 GIT binary patch literal 690 zcmb_Z%}&BV5FSb?AR=B=Ogzj@X<~vWk49*Wo=PC5=h9AKrEZ(;R^tPRi7(-+_#R$- z665aT4;m9M%wcx+o0;#M+3lYWy>+O92OCg83CdtW0~$C8g~Wau6Rv>`ZG}4EC?Jt|HY#m2amSwcu35vG>D>yP-%FT7)J!pUC1T3DA)bWb!t-K)G zvH;4#;8XQcp|6|TKi};xL~)Q5Io>ik#Sst1ETR0@40yq#q=+d;NePWpK4W}>6A_M! zB$TQ6uD2JRfjaEK_ditcHQF}&?rr9xrBC_RSGR jf}~pVpI6>-T`ai%)R=B4NwaG;B)aZ0*;o8DFPZoq( nil then Current := Current^.Next; +end; + +procedure CardList.Prev; +begin + if Current <> nil then Current := Current^.Prev; +end; + +procedure CardList.Store(var S: Stream); +var + I: Integer; +begin + S.Write(Count, SizeOf(Integer) * 2); + for I := 1 to Count do + begin + S.Write(Current^.Data, DataSize); + Next; + end; +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/CGA.BGI b/Borland Turbo Pascal v55/CGA.BGI new file mode 100644 index 0000000000000000000000000000000000000000..4b590ffe49c5124a3c44b7a8e8cc4180a1f1072e GIT binary patch literal 6253 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 bR@8%fOjpnq!vvb(rqC4g4f=+H6D Minimum then + Counter.Decrement; +end; + +procedure DownCounter.Add(Incr : Integer); +var + Temp : Integer; +begin + Temp := GetValue + Incr; + if Temp >= Minimum then + SetValue(Temp); +end; + +function DownCounter.Last : Boolean; +begin + Last := (Value = Minimum); +end; + +constructor LimitCounter.Init(InitValue, + InitX, + InitY, + InitMin, + InitMax : Integer; + InitName : TextStr; + InitAttr : Byte); +begin + DownCounter.Init(InitValue, InitX, InitY, InitMin, InitName, InitAttr); + Maximum := InitMax; +end; + +procedure LimitCounter.Increment; +begin + if Value < Maximum then + Counter.Increment; +end; + +procedure LimitCounter.Add(Incr : Integer); +var + Temp : Integer; +begin + Temp := Value + Incr; + if (Temp <= Maximum) and (Temp >= Minimum) then + SetValue(Temp); +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/CPASDEMO.C b/Borland Turbo Pascal v55/CPASDEMO.C new file mode 100644 index 0000000..f8f3e19 --- /dev/null +++ b/Borland Turbo Pascal v55/CPASDEMO.C @@ -0,0 +1,75 @@ + +/* Copyright (c) 1985, 1989 by Borland International, Inc. + + This module demonstrates how to write Turbo C routines that + can be linked into a Turbo Pascal program. Routines in this + module call Turbo Pascal routines in CPASDEMO.PAS. + + See the instructions in the file CPASDEMO.PAS on running + this demonstration program */ + +typedef unsigned int word; +typedef unsigned char byte; +typedef unsigned long longword; + +extern void setcolor(byte newcolor); /* procedure defined in + Turbo Pascal program */ +extern word factor; /* variable declared in Turbo Pascal program */ + +word sqr(int i) +{ + setcolor(1); + return(i * i); +} /* sqr */ + +word hibits(word w) +{ + setcolor(2); + return(w >> 8); +} /* hibits */ + +byte suc(byte b) +{ + setcolor(3); + return(++b); +} /* suc */ + +byte upr(byte c) +{ + setcolor(4); + return((c >= 'a') && (c <= 'z') ? c - 32 : c); +} /* upr */ + +char prd(char s) +{ + setcolor(5); + return(--s); +} /* prd */ + +long lobits(long l) +{ + setcolor(6); + return((longword)l & 65535); +} /* lobits */ + +void strupr(char far *s) +{ + int counter; + + for (counter = 1; counter <= s[0]; counter++) /* Note that the routine */ + s[counter] = upr(s[counter]); /* skips Turbo Pascal's */ + setcolor(7); /* length byte */ +} /* strupr */ + +byte boolnot(byte b) +{ + setcolor(8); + return(b == 0 ? 1 : 0); +} /* boolnot */ + +word multbyfactor(word w) +{ + setcolor(9); /* note that this function accesses the Turbo Pascal */ + return(w * factor); /* declared variable factor */ +} /* multbyfactor */ + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/CPASDEMO.PAS b/Borland Turbo Pascal v55/CPASDEMO.PAS new file mode 100644 index 0000000..76a144d --- /dev/null +++ b/Borland Turbo Pascal v55/CPASDEMO.PAS @@ -0,0 +1,126 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program CPASDEMO; +(* + This program demonstrates how to interface Turbo Pascal and Turbo C. + Turbo C is used to generate an .OBJ file (CPASDEMO.OBJ). Then + this .OBJ is linked into this Turbo Pascal program using the {$L} + compiler directive. + + NOTES: + 1. Data declared in the Turbo C module cannot be accessed from + the Turbo Pascal program. Shared data must be declared in + Pascal. + + 2. If the C functions are only used in the implementation section + of a unit, declare them NEAR. If they are declared in the + interface section of a unit, declare them FAR. Always compile + the Turbo C modules using the small memory model. + + 3. Turbo C runtime library routines cannot be used because their + modules do not have the correct segment names. However, if you have + the Turbo C runtime library source (available from Borland), + you can use individual library modules by recompiling + them using CTOPAS.BAT. If you do recompile them, make sure + that you include prototypes in your C module for all C + library functions that you use. + + 4. Some of the code that Turbo C generates are calls to internal + routines. These cannot be used without recompiling the relevant + parts of the Turbo C runtime library source code. + + In order to run this demonstration program you will need the following + files: + + TCC.EXE and TURBO.CFG or + TC.EXE and CTOPAS.TC + + To run the demonstration program CPASDEMO.EXE do the following: + + 1. First create a CPASDEMO.OBJ file compatible with Turbo Pascal 5.5 + using Turbo C. + + a) If you are using the Turbo C integrated environment (TC.EXE) + then at the DOS prompt execute: + + TC /CCTOPAS.TC CPASDEMO.C + + then create the .OBJ file by pressing ALT-F9. + + b) If you are using the Turbo C command line version (TCC.EXE) + then at the DOS prompt execute: + + TCC CPASDEMO.C + + Note: Use the same configuration file (TURBO.CFG or CTOPAS.TC) + when you create your own Turbo C modules for use with + Turbo Pascal 5.5 + + 2. Compile and execute the Turbo Pascal program CPASDEMO.PAS + + This simple program calls each of the functions defined in the Turbo C + module. Each of the Turbo C functions changes the current display color + by calling the Turbo Pascal procedure SetColor. +*) + +uses Crt; + +var + Factor : Word; + +{$L CPASDEMO.OBJ} { link in the Turbo C-generated .OBJ module } + +function Sqr(I : Integer) : Word; external; +{ Change the text color and return the square of I } + +function HiBits(W : Word) : Word; external; +{ Change the text color and return the high byte of W } + +function Suc(B : Byte) : Byte; external; +{ Change the text color and return B + 1 } + +function Upr(C : Char) : Char; external; +{ Change the text color and return the upper case of C } + +function Prd(S : ShortInt) : ShortInt; external; +{ Change the text color and return S - 1 } + +function LoBits(L : LongInt) : LongInt; external; +{ Change the text color and return the low word of L } + +procedure StrUpr(var S : string); external; +{ Change the text color and return the upper case of S - Note that the Turbo } +{ C routine must skip the length byte of the string. } + +function BoolNot(B : Boolean) : Boolean; external; +{ Change the text color and return NOT B } + +function MultByFactor(W : Word) : Word; external; +{ Change the text color and return W * Factor - note Turbo C's access of } +{ Turbo Pascal's global variable. } + +procedure SetColor(NewColor : Byte); { A procedure that changes the current } +begin { display color by changing the CRT } + TextAttr := NewColor; { variable TextAttr } +end; { SetColor } + +var + S : string; + +begin + Writeln(Sqr(10)); { Call each of the functions defined } + Writeln(HiBits(30000)); { passing it the appropriate info. } + Writeln(Suc(200)); + Writeln(Upr('x')); + Writeln(Prd(-100)); + Writeln(LoBits(100000)); + S := 'abcdefg'; + StrUpr(S); + Writeln(S); + Writeln(BoolNot(False)); + Factor := 100; + Writeln(MultbyFactor(10)); + SetColor(LightGray); +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/CRTDEMO.PAS b/Borland Turbo Pascal v55/CRTDEMO.PAS new file mode 100644 index 0000000..9a87f97 --- /dev/null +++ b/Borland Turbo Pascal v55/CRTDEMO.PAS @@ -0,0 +1,147 @@ +{ Turbo Crt } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program CrtDemo; +{ Example program that uses the Crt unit. Uses the following routines + from the Crt unit: + + ClrScr + DelLine + GoToXY + InsLine + KeyPressed + ReadKey + TextBackground + TextColor + TextMode + WhereX + WhereY + Window + Write + WriteLn; + + Also uses LastMode and WindMax variables from Crt unit. + + 1. Init routine: + - Save original video mode. On an EGA or VGA, use the 8x8 font + (43 lines on an EGA, 50 on VGA). + - Setup LastRow to preserve last line on screen for messages + (preserves last 2 lines in 40-column mode). Setup LastCol. + - Initialize the random number generator. + 2. MakeWindow routine: + - Puts up random-sized, random-colored windows on screen. + 3. Program body: + - Call Init + - Loop until Contrl-C is typed: + - Echo keystrokes (Turbo Pascal windows automatically wrap + and scroll). + - Support special keys: + inserts a line at the cursor + deletes a line at the cursor + , + , + , + position the cursor in the window + generate random text until a key is pressed + creates another random window + exits the program +} + +uses Crt; + +var + OrigMode,LastCol,LastRow: Word; + Ch: Char; + Done: Boolean; + +procedure Initialize; +{ Initialize the video mode, LastCol, LastRow, and the random number } +{ generator. Paint the help line. } +begin + CheckBreak:=False; { turn off Contrl-C checking } + OrigMode:=LastMode; { Remember original video mode } + TextMode(Lo(LastMode)+Font8x8); { use 43 or 50 lines on EGA/VGA } + LastCol:=Lo(WindMax)+1; { get last column, row } + LastRow:=Hi(WindMax)+1; + GoToXY(1,LastRow); { put message line on screen } + TextBackground(Black); + TextColor(White); + Write(' Ins-InsLine ', + 'Del-DelLine ', + #27#24#25#26'-Cursor ', + 'Alt-W-Window ', + 'Alt-R-Random ', + 'Esc-Exit'); + Dec(LastRow,80 div LastCol); { don't write on message line } + Randomize; { init random number generator } +end; { Init } + +procedure MakeWindow; +{ Make a random window, with random background and foreground colors } +var + X,Y,Width,Height: Word; +begin + Width:=Random(LastCol-2)+2; { random window size } + Height:=Random(LastRow-2)+2; + X:=Random(LastCol-Width)+1; { random position on screen } + Y:=Random(LastRow-Height)+1; + Window(X,Y,X+Width,Y+Height); + if OrigMode = Mono then + begin + TextBackground(White); + TextColor(Black); + ClrScr; + Window(X+1,Y+1,X+Width-1,Y+Height-1); + TextBackground(Black); + TextColor(White); + ClrScr; + end + else + begin + TextBackground(Random(8)); + TextColor(Random(7)+9); + end; + ClrScr; +end; { MakeWindow } + +procedure RandomText; +{ Generate random text until a key is pressed. Filter out } +{ control characters. } +begin + repeat + Write(Chr(Random(256-32)+32)); + until KeyPressed; +end; { RandomText } + +begin { program body } + Initialize; + MakeWindow; + Done:=False; + repeat + Ch:=ReadKey; + case Ch of + #0: { Function keys } + begin + Ch:=ReadKey; + case Ch of + #17: MakeWindow; { Alt-W } + #19: RandomText; { Alt-R } + #45: Done:=True; { Alt-X } + #72: GotoXY(WhereX,WhereY-1); { Up } + #75: GotoXY(WhereX-1,WhereY); { Left } + #77: GotoXY(WhereX+1,WhereY); { Right } + #80: GotoXY(WhereX,WhereY+1); { Down } + #82: InsLine; { Ins } + #83: DelLine; { Del } + end; + end; + #3: Done:=True; { Ctrl-C } + #13: WriteLn; { Enter } + #27: Done:=True; { Esc } + else + Write(Ch); + end; + until Done; + TextMode(OrigMode); +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/CTOPAS.TC b/Borland Turbo Pascal v55/CTOPAS.TC new file mode 100644 index 0000000000000000000000000000000000000000..ab9e45dd0fd9ceb9d26c82b5348fef7746d58a9e GIT binary patch literal 1711 zcmd7S*G>Xa5C-5GEI|@X#0vu#W*@*p5ydV6y;Ku<0S(2qfFjrxEDvYzz3YqM{3qg# z!M#9&oA8}~W)J7=vKvC_jmF@sys3YeV`>L~{^ZZ4E2~Gnt6wV${FoHN^0tQYMRmIg-ziXz3pB+$VWm=!*_+=RLf*XS{v(Odq9)+cX~@B1$MOYja4{L%l6zXaEo I%bCbQpKT;U5C8xG literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/DIRDEMO.PAS b/Borland Turbo Pascal v55/DIRDEMO.PAS new file mode 100644 index 0000000..4394cd7 --- /dev/null +++ b/Borland Turbo Pascal v55/DIRDEMO.PAS @@ -0,0 +1,240 @@ +{ Turbo Directory } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program DirDemo; +{ Demonstration program that shows how to use: + + o Directory routines from DOS unit + o Procedural types (used by QuickSort) + + Usage: + + dirdemo [options] [directory mask] + + Options: + + -W Wide display + -N Sort by file name + -S Sort by file size + -T Sort by file date and time + + Directory mask: + + Path, Filename, wildcards, etc. + +} + +{$I-,S-} +{$M 8192,8192,655360} + +uses Dos; + +const + MaxDirSize = 512; + MonthStr: array[1..12] of string[3] = ( + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); + +type + DirPtr = ^DirRec; + DirRec = record + Attr: Byte; + Time: Longint; + Size: Longint; + Name: string[12]; + end; + DirList = array[0..MaxDirSize - 1] of DirPtr; + LessFunc = function(X, Y: DirPtr): Boolean; + +var + WideDir: Boolean; + Count: Integer; + Less: LessFunc; + Path: PathStr; + Dir: DirList; + +function NumStr(N, D: Integer): String; +begin + NumStr[0] := Chr(D); + while D > 0 do + begin + NumStr[D] := Chr(N mod 10 + Ord('0')); + N := N div 10; + Dec(D); + end; +end; + +{$F+} + +function LessName(X, Y: DirPtr): Boolean; +begin + LessName := X^.Name < Y^.Name; +end; + +function LessSize(X, Y: DirPtr): Boolean; +begin + LessSize := X^.Size < Y^.Size; +end; + +function LessTime(X, Y: DirPtr): Boolean; +begin + LessTime := X^.Time > Y^.Time; +end; + +{$F-} + +procedure QuickSort(L, R: Integer); +var + I, J: Integer; + X, Y: DirPtr; +begin + I := L; + J := R; + X := Dir[(L + R) div 2]; + repeat + while Less(Dir[I], X) do Inc(I); + while Less(X, Dir[J]) do Dec(J); + if I <= J then + begin + Y := Dir[I]; + Dir[I] := Dir[J]; + Dir[J] := Y; + Inc(I); + Dec(J); + end; + until I > J; + if L < J then QuickSort(L, J); + if I < R then QuickSort(I, R); +end; + +procedure GetCommand; +var + I,J: Integer; + Attr: Word; + S: PathStr; + D: DirStr; + N: NameStr; + E: ExtStr; + F: File; +begin + WideDir := False; + @Less := nil; + Path := ''; + for I := 1 to ParamCount do + begin + S := ParamStr(I); + if S[1] = '-' then + for J := 2 to Length(S) do + case UpCase(S[J]) of + 'N': Less := LessName; + 'S': Less := LessSize; + 'T': Less := LessTime; + 'W': WideDir := True; + else + WriteLn('Invalid option: ', S[J]); + Halt(1); + end + else + Path := S; + end; + Path := FExpand(Path); + if Path[Length(Path)] <> '\' then + begin + Assign(F, Path); + GetFAttr(F, Attr); + if (DosError = 0) and (Attr and Directory <> 0) then + Path := Path + '\'; + end; + FSplit(Path, D, N, E); + if N = '' then N := '*'; + if E = '' then E := '.*'; + Path := D + N + E; +end; + +procedure FindFiles; +var + F: SearchRec; +begin + Count := 0; + FindFirst(Path, ReadOnly + Directory + Archive, F); + while (DosError = 0) and (Count < MaxDirSize) do + begin + GetMem(Dir[Count], Length(F.Name) + 10); + Move(F.Attr, Dir[Count]^, Length(F.Name) + 10); + Inc(Count); + FindNext(F); + end; +end; + +procedure SortFiles; +begin + if (Count <> 0) and (@Less <> nil) then + QuickSort(0, Count - 1); +end; + +procedure PrintFiles; +var + I, P: Integer; + Total: Longint; + T: DateTime; + N: NameStr; + E: ExtStr; +begin + WriteLn('Directory of ', Path); + if Count = 0 then + begin + WriteLn('No matching files'); + Exit; + end; + Total := 0; + for I := 0 to Count-1 do + with Dir[I]^ do + begin + P := Pos('.', Name); + if P > 1 then + begin + N := Copy(Name, 1, P - 1); + E := Copy(Name, P + 1, 3); + end else + begin + N := Name; + E := ''; + end; + Write(N, ' ': 9 - Length(N), E, ' ': 4 - Length(E)); + if WideDir then + begin + if Attr and Directory <> 0 then + Write(' DIR') + else + Write((Size + 1023) shr 10: 3, 'k'); + if I and 3 <> 3 then + Write(' ': 3) + else + WriteLn; + end else + begin + if Attr and Directory <> 0 then + Write(' ') + else + Write(Size: 8); + UnpackTime(Time, T); + WriteLn(T.Day: 4, '-', + MonthStr[T.Month], '-', + NumStr(T.Year mod 100, 2), + T.Hour: 4, ':', + NumStr(T.Min, 2)); + end; + Inc(Total, Size); + end; + if WideDir and (Count and 3 <> 0) then WriteLn; + WriteLn(Count, ' files, ', Total, ' bytes, ', + DiskFree(Ord(Path[1])-64), ' bytes free'); +end; + +begin + GetCommand; + FindFiles; + SortFiles; + PrintFiles; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DISPLAY.PAS b/Borland Turbo Pascal v55/DISPLAY.PAS new file mode 100644 index 0000000..2f94024 --- /dev/null +++ b/Borland Turbo Pascal v55/DISPLAY.PAS @@ -0,0 +1,27 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +unit Display; +{ Sample unit for CIRCULAR.PAS } + +interface + +procedure WriteXY(x, y : integer; s : string); + +implementation +uses + Crt, Error; + +procedure WriteXY(x, y : integer; s : string); +begin + if (x in [1..80]) and (y in [1..25]) then + begin + GoToXY(x, y); + Write(s); + end + else + ShowError('Invalid WriteXY coordinates'); +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/CRT.DOC b/Borland Turbo Pascal v55/DOC/CRT.DOC new file mode 100644 index 0000000..8d9896c --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/CRT.DOC @@ -0,0 +1,95 @@ + +{*******************************************************} +{ } +{ Turbo Pascal Version 5.5 } +{ CRT Interface Unit } +{ } +{ Copyright (C) 1987, 1989 Borland International } +{ } +{*******************************************************} + +unit Crt; + +{$D-,I-,S-} + +interface + +const + +{ CRT modes } + + BW40 = 0; { 40x25 B/W on Color Adapter } + CO40 = 1; { 40x25 Color on Color Adapter } + BW80 = 2; { 80x25 B/W on Color Adapter } + CO80 = 3; { 80x25 Color on Color Adapter } + Mono = 7; { 80x25 on Monochrome Adapter } + Font8x8 = 256; { Add-in for ROM font } + +{ Mode constants for 3.0 compatibility } + + C40 = CO40; + C80 = CO80; + +{ Foreground and background color constants } + + Black = 0; + Blue = 1; + Green = 2; + Cyan = 3; + Red = 4; + Magenta = 5; + Brown = 6; + LightGray = 7; + +{ Foreground color constants } + + DarkGray = 8; + LightBlue = 9; + LightGreen = 10; + LightCyan = 11; + LightRed = 12; + LightMagenta = 13; + Yellow = 14; + White = 15; + +{ Add-in for blinking } + + Blink = 128; + +var + +{ Interface variables } + + CheckBreak: Boolean; { Enable Ctrl-Break } + CheckEOF: Boolean; { Enable Ctrl-Z } + DirectVideo: Boolean; { Enable direct video addressing } + CheckSnow: Boolean; { Enable snow filtering } + LastMode: Word; { Current text mode } + TextAttr: Byte; { Current text attribute } + WindMin: Word; { Window upper left coordinates } + WindMax: Word; { Window lower right coordinates } + +{ Interface procedures } + +procedure AssignCrt(var F: Text); +function KeyPressed: Boolean; +function ReadKey: Char; +procedure TextMode(Mode: Integer); +procedure Window(X1,Y1,X2,Y2: Byte); +procedure GotoXY(X,Y: Byte); +function WhereX: Byte; +function WhereY: Byte; +procedure ClrScr; +procedure ClrEol; +procedure InsLine; +procedure DelLine; +procedure TextColor(Color: Byte); +procedure TextBackground(Color: Byte); +procedure LowVideo; +procedure HighVideo; +procedure NormVideo; +procedure Delay(MS: Word); +procedure Sound(Hz: Word); +procedure NoSound; + + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/DOS.DOC b/Borland Turbo Pascal v55/DOC/DOS.DOC new file mode 100644 index 0000000..6df8684 --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/DOS.DOC @@ -0,0 +1,152 @@ + +{*******************************************************} +{ } +{ Turbo Pascal Version 5.5 } +{ DOS Interface Unit } +{ } +{ Copyright (C) 1987, 1989 Borland International } +{ } +{*******************************************************} + +unit Dos; + +{$D-,I-,S-} + +interface + +const + +{ Flags bit masks } + + FCarry = $0001; + FParity = $0004; + FAuxiliary = $0010; + FZero = $0040; + FSign = $0080; + FOverflow = $0800; + +{ File mode magic numbers } + + fmClosed = $D7B0; + fmInput = $D7B1; + fmOutput = $D7B2; + fmInOut = $D7B3; + +{ File attribute constants } + + ReadOnly = $01; + Hidden = $02; + SysFile = $04; + VolumeID = $08; + Directory = $10; + Archive = $20; + AnyFile = $3F; + +type + +{ String types } + + ComStr = string[127]; { Command line string } + PathStr = string[79]; { Full file path string } + DirStr = string[67]; { Drive and directory string } + NameStr = string[8]; { File name string } + ExtStr = string[4]; { File extension string } + +{ Registers record used by Intr and MsDos } + + Registers = record + case Integer of + 0: (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Word); + 1: (AL,AH,BL,BH,CL,CH,DL,DH: Byte); + end; + +{ Typed-file and untyped-file record } + + FileRec = record + Handle: Word; + Mode: Word; + RecSize: Word; + Private: array[1..26] of Byte; + UserData: array[1..16] of Byte; + Name: array[0..79] of Char; + end; + +{ Textfile record } + + TextBuf = array[0..127] of Char; + TextRec = record + Handle: Word; + Mode: Word; + BufSize: Word; + Private: Word; + BufPos: Word; + BufEnd: Word; + BufPtr: ^TextBuf; + OpenFunc: Pointer; + InOutFunc: Pointer; + FlushFunc: Pointer; + CloseFunc: Pointer; + UserData: array[1..16] of Byte; + Name: array[0..79] of Char; + Buffer: TextBuf; + end; + +{ Search record used by FindFirst and FindNext } + + SearchRec = record + Fill: array[1..21] of Byte; + Attr: Byte; + Time: Longint; + Size: Longint; + Name: string[12]; + end; + +{ Date and time record used by PackTime and UnpackTime } + + DateTime = record + Year,Month,Day,Hour,Min,Sec: Word; + end; + +var + +{ Error status variable } + + DosError: Integer; + + +function DosVersion: Word; +procedure Intr(IntNo: Byte; var Regs: Registers); +procedure MsDos(var Regs: Registers); +procedure GetDate(var Year,Month,Day,DayOfWeek: Word); +procedure SetDate(Year,Month,Day: Word); +procedure GetTime(var Hour,Minute,Second,Sec100: Word); +procedure SetTime(Hour,Minute,Second,Sec100: Word); +procedure GetCBreak(var Break: Boolean); +procedure SetCBreak(Break: Boolean); +procedure GetVerify(var Verify: Boolean); +procedure SetVerify(Verify: Boolean); +function DiskFree(Drive: Byte): Longint; +function DiskSize(Drive: Byte): Longint; +procedure GetFAttr(var F; var Attr: Word); +procedure SetFAttr(var F; Attr: Word); +procedure GetFTime(var F; var Time: Longint); +procedure SetFTime(var F; Time: Longint); +procedure FindFirst(Path: PathStr; Attr: Word; var F: SearchRec); +procedure FindNext(var F: SearchRec); +procedure UnpackTime(P: Longint; var T: DateTime); +procedure PackTime(var T: DateTime; var P: Longint); +procedure GetIntVec(IntNo: Byte; var Vector: Pointer); +procedure SetIntVec(IntNo: Byte; Vector: Pointer); +procedure SwapVectors; +procedure Keep(ExitCode: Word); +procedure Exec(Path: PathStr; ComLine: ComStr); +function DosExitCode: Word; +function FSearch(Path: PathStr; DirList: String): PathStr; +function FExpand(Path: PathStr): PathStr; +procedure FSplit(Path: PathStr; var Dir: DirStr; + var Name: NameStr; var Ext: ExtStr); +function EnvCount: Integer; +function EnvStr(Index: Integer): String; +function GetEnv(EnvVar: String): String; + + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/GRAPH.DOC b/Borland Turbo Pascal v55/DOC/GRAPH.DOC new file mode 100644 index 0000000..5306136 --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/GRAPH.DOC @@ -0,0 +1,338 @@ + +{*******************************************************} +{ } +{ Turbo Pascal Version 5.5 } +{ Graph Interface Unit } +{ } +{ Copyright (C) 1987,89 Borland International } +{ } +{*******************************************************} + +unit Graph; + +interface + +const + { GraphResult error return codes: } + grOk = 0; + grNoInitGraph = -1; + grNotDetected = -2; + grFileNotFound = -3; + grInvalidDriver = -4; + grNoLoadMem = -5; + grNoScanMem = -6; + grNoFloodMem = -7; + grFontNotFound = -8; + grNoFontMem = -9; + grInvalidMode = -10; + grError = -11; { generic error } + grIOerror = -12; + grInvalidFont = -13; + grInvalidFontNum = -14; + + { define graphics drivers } + CurrentDriver = -128; { passed to GetModeRange } + Detect = 0; { requests autodetection } + CGA = 1; + MCGA = 2; + EGA = 3; + EGA64 = 4; + EGAMono = 5; + IBM8514 = 6; + HercMono = 7; + ATT400 = 8; + VGA = 9; + PC3270 = 10; + + { graphics modes for each driver } + CGAC0 = 0; { 320x200 palette 0: LightGreen, LightRed, Yellow; 1 page } + CGAC1 = 1; { 320x200 palette 1: LightCyan, LightMagenta, White; 1 page } + CGAC2 = 2; { 320x200 palette 2: Green, Red, Brown; 1 page } + CGAC3 = 3; { 320x200 palette 3: Cyan, Magenta, LightGray; 1 page } + CGAHi = 4; { 640x200 1 page } + MCGAC0 = 0; { 320x200 palette 0: LightGreen, LightRed, Yellow; 1 page } + MCGAC1 = 1; { 320x200 palette 1: LightCyan, LightMagenta, White; 1 page } + MCGAC2 = 2; { 320x200 palette 2: Green, Red, Brown; 1 page } + MCGAC3 = 3; { 320x200 palette 3: Cyan, Magenta, LightGray; 1 page } + MCGAMed = 4; { 640x200 1 page } + MCGAHi = 5; { 640x480 1 page } + EGALo = 0; { 640x200 16 color 4 page } + EGAHi = 1; { 640x350 16 color 2 page } + EGA64Lo = 0; { 640x200 16 color 1 page } + EGA64Hi = 1; { 640x350 4 color 1 page } + EGAMonoHi = 3; { 640x350 64K on card, 1 page; 256K on card, 2 page } + HercMonoHi = 0; { 720x348 2 page } + ATT400C0 = 0; { 320x200 palette 0: LightGreen, LightRed, Yellow; 1 page } + ATT400C1 = 1; { 320x200 palette 1: LightCyan, LightMagenta, White; 1 page } + ATT400C2 = 2; { 320x200 palette 2: Green, Red, Brown; 1 page } + ATT400C3 = 3; { 320x200 palette 3: Cyan, Magenta, LightGray; 1 page } + ATT400Med = 4; { 640x200 1 page } + ATT400Hi = 5; { 640x400 1 page } + VGALo = 0; { 640x200 16 color 4 page } + VGAMed = 1; { 640x350 16 color 2 page } + VGAHi = 2; { 640x480 16 color 1 page } + PC3270Hi = 0; { 720x350 1 page } + IBM8514LO = 0; { 640x480 256 colors } + IBM8514HI = 1; { 1024x768 256 colors } + + { Colors for SetPalette and SetAllPalette: } + Black = 0; + Blue = 1; + Green = 2; + Cyan = 3; + Red = 4; + Magenta = 5; + Brown = 6; + LightGray = 7; + DarkGray = 8; + LightBlue = 9; + LightGreen = 10; + LightCyan = 11; + LightRed = 12; + LightMagenta = 13; + Yellow = 14; + White = 15; + + { colors for 8514 to set standard EGA colors w/o knowing their values } + EGABlack = 0; { dark colors } + EGABlue = 1; + EGAGreen = 2; + EGACyan = 3; + EGARed = 4; + EGAMagenta = 5; + EGABrown = 20; + EGALightgray = 7; + EGADarkgray = 56; { light colors } + EGALightblue = 57; + EGALightgreen = 58; + EGALightcyan = 59; + EGALightred = 60; + EGALightmagenta = 61; + EGAYellow = 62; + EGAWhite = 63; + + { Line styles and widths for Get/SetLineStyle: } + SolidLn = 0; + DottedLn = 1; + CenterLn = 2; + DashedLn = 3; + UserBitLn = 4; { User-defined line style } + + NormWidth = 1; + ThickWidth = 3; + + { Set/GetTextStyle constants: } + DefaultFont = 0; { 8x8 bit mapped font } + TriplexFont = 1; { "Stroked" fonts } + SmallFont = 2; + SansSerifFont = 3; + GothicFont = 4; + + HorizDir = 0; { left to right } + VertDir = 1; { bottom to top } + + UserCharSize = 0; { user-defined char size } + + { Clipping constants: } + ClipOn = true; + ClipOff = false; + + { Bar3D constants: } + TopOn = true; + TopOff = false; + + { Fill patterns for Get/SetFillStyle: } + EmptyFill = 0; { fills area in background color } + SolidFill = 1; { fills area in solid fill color } + LineFill = 2; { --- fill } + LtSlashFill = 3; { /// fill } + SlashFill = 4; { /// fill with thick lines } + BkSlashFill = 5; { \\\ fill with thick lines } + LtBkSlashFill = 6; { \\\ fill } + HatchFill = 7; { light hatch fill } + XHatchFill = 8; { heavy cross hatch fill } + InterleaveFill = 9; { interleaving line fill } + WideDotFill = 10; { Widely spaced dot fill } + CloseDotFill = 11; { Closely spaced dot fill } + UserFill = 12; { user defined fill } + + { BitBlt operators for PutImage: } + NormalPut = 0; { MOV } { left for 1.0 compatibility } + CopyPut = 0; { MOV } + XORPut = 1; { XOR } + OrPut = 2; { OR } + AndPut = 3; { AND } + NotPut = 4; { NOT } + + { Horizontal and vertical justification for SetTextJustify: } + LeftText = 0; + CenterText = 1; + RightText = 2; + + BottomText = 0; +{ CenterText = 1; already defined above } + TopText = 2; + + +const + MaxColors = 15; +type + PaletteType = record + Size : byte; + Colors : array[0..MaxColors] of shortint; + end; + + LineSettingsType = record + LineStyle : word; + Pattern : word; + Thickness : word; + end; + + TextSettingsType = record + Font : word; + Direction : word; + CharSize : word; + Horiz : word; + Vert : word; + end; + + FillSettingsType = record { Pre-defined fill style } + Pattern : word; + Color : word; + end; + + FillPatternType = array[1..8] of byte; { User defined fill style } + + PointType = record + X, Y : integer; + end; + + ViewPortType = record + x1, y1, x2, y2 : integer; + Clip : boolean; + end; + + ArcCoordsType = record + X, Y : integer; + Xstart, Ystart : integer; + Xend, Yend : integer; + end; + + +var + GraphGetMemPtr : Pointer; { allows user to steal heap allocation } + GraphFreeMemPtr : Pointer; { allows user to steal heap de-allocation } + +{ *** high-level error handling *** } +function GraphErrorMsg(ErrorCode : integer) : String; +function GraphResult : integer; + +{ *** detection, initialization and crt mode routines *** } +procedure DetectGraph(var GraphDriver, GraphMode : integer); +function GetDriverName : string; + +procedure InitGraph(var GraphDriver : integer; + var GraphMode : integer; + PathToDriver : String); + +function RegisterBGIfont(Font : pointer) : integer; +function RegisterBGIdriver(Driver : pointer) : integer; +function InstallUserDriver(DriverFileName : string; + AutoDetectPtr : pointer) : integer; +function InstallUserFont(FontFileName : string) : integer; +procedure SetGraphBufSize(BufSize : word); +function GetMaxMode : integer; +procedure GetModeRange(GraphDriver : integer; var LoMode, HiMode : integer); +function GetModeName(GraphMode : integer) : string; +procedure SetGraphMode(Mode : integer); +function GetGraphMode : integer; +procedure GraphDefaults; +procedure RestoreCrtMode; +procedure CloseGraph; + +function GetX : integer; +function GetY : integer; +function GetMaxX : integer; +function GetMaxY : integer; + +{ *** Screen, viewport, page routines *** } +procedure ClearDevice; +procedure SetViewPort(x1, y1, x2, y2 : integer; Clip : boolean); +procedure GetViewSettings(var ViewPort : ViewPortType); +procedure ClearViewPort; +procedure SetVisualPage(Page : word); +procedure SetActivePage(Page : word); + +{ *** point-oriented routines *** } +procedure PutPixel(X, Y : integer; Pixel : word); +function GetPixel(X, Y : integer) : word; + +{ *** line-oriented routines *** } +procedure SetWriteMode(WriteMode : integer); +procedure LineTo(X, Y : integer); +procedure LineRel(Dx, Dy : integer); +procedure MoveTo(X, Y : integer); +procedure MoveRel(Dx, Dy : integer); +procedure Line(x1, y1, x2, y2 : integer); +procedure GetLineSettings(var LineInfo : LineSettingsType); +procedure SetLineStyle(LineStyle : word; + Pattern : word; + Thickness : word); + +{ *** polygon, fills and figures *** } +procedure Rectangle(x1, y1, x2, y2 : integer); +procedure Bar(x1, y1, x2, y2 : integer); +procedure Bar3D(x1, y1, x2, y2 : integer; Depth : word; Top : boolean); +procedure DrawPoly(NumPoints : word; var PolyPoints); +procedure FillPoly(NumPoints : word; var PolyPoints); +procedure GetFillSettings(var FillInfo : FillSettingsType); +procedure GetFillPattern(var FillPattern : FillPatternType); +procedure SetFillStyle(Pattern : word; Color : word); +procedure SetFillPattern(Pattern : FillPatternType; Color : word); +procedure FloodFill(X, Y : integer; Border : word); + +{ *** arc, circle, and other curves *** } +procedure Arc(X, Y : integer; StAngle, EndAngle, Radius : word); +procedure GetArcCoords(var ArcCoords : ArcCoordsType); +procedure Circle(X, Y : integer; Radius : word); +procedure Ellipse(X, Y : integer; + StAngle, EndAngle : word; + XRadius, YRadius : word); +procedure FillEllipse(X, Y : integer; + XRadius, YRadius : word); +procedure GetAspectRatio(var Xasp, Yasp : word); +procedure SetAspectRatio(Xasp, Yasp : word); +procedure PieSlice(X, Y : integer; StAngle, EndAngle, Radius : word); +procedure Sector(X, Y : Integer; + StAngle, EndAngle, + XRadius, YRadius : word); + + +{ *** color and palette routines *** } +procedure SetBkColor(ColorNum : word); +procedure SetColor(Color : word); +function GetBkColor : word; +function GetColor : word; +procedure SetAllPalette(var Palette); +procedure SetPalette(ColorNum : word; Color : shortint); +procedure GetPalette(var Palette : PaletteType); +function GetPaletteSize : integer; +procedure GetDefaultPalette(var Palette : PaletteType); +function GetMaxColor : word; +procedure SetRGBPalette(ColorNum, RedValue, GreenValue, BlueValue : integer); + +{ *** bit-image routines *** } +function ImageSize(x1, y1, x2, y2 : integer) : word; +procedure GetImage(x1, y1, x2, y2 : integer; var BitMap); +procedure PutImage(X, Y : integer; var BitMap; BitBlt : word); + +{ *** text routines *** } +procedure GetTextSettings(var TextInfo : TextSettingsType); +procedure OutText(TextString : string); +procedure OutTextXY(X, Y : integer; TextString : string); +procedure SetTextJustify(Horiz, Vert : word); +procedure SetTextStyle(Font, Direction : word; CharSize : word); +procedure SetUserCharSize(MultX, DivX, MultY, DivY : word); +function TextHeight(TextString : string) : word; +function TextWidth(TextString : string) : word; + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/GRAPH3.DOC b/Borland Turbo Pascal v55/DOC/GRAPH3.DOC new file mode 100644 index 0000000..b7282ea --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/GRAPH3.DOC @@ -0,0 +1,66 @@ + +{*******************************************************} +{ } +{ Turbo Pascal Version 5.5 } +{ 3.0 Graphics Compatibility Unit } +{ } +{ Copyright (C) 1987,1989 Borland International } +{ } +{*******************************************************} + +unit Graph3; + +{$D-,I-,S-} + +interface + +uses Crt; + +const + North = 0; + East = 90; + South = 180; + West = 270; + +procedure GraphMode; +procedure GraphColorMode; +procedure HiRes; +procedure HiResColor(Color: Integer); +procedure Palette(N: Integer); +procedure GraphBackground(Color: Integer); +procedure GraphWindow(X1,Y1,X2,Y2: Integer); +procedure Plot(X,Y,Color: Integer); +procedure Draw(X1,Y1,X2,Y2,Color: Integer); +procedure ColorTable(C1,C2,C3,C4: Integer); +procedure Arc(X,Y,Angle,Radius,Color: Integer); +procedure Circle(X,Y,Radius,Color: Integer); +procedure GetPic(var Buffer; X1,Y1,X2,Y2: Integer); +procedure PutPic(var Buffer; X,Y: Integer); +function GetDotColor(X,Y: Integer): Integer; +procedure FillScreen(Color: Integer); +procedure FillShape(X,Y,FillCol,BorderCol: Integer); +procedure FillPattern(X1,Y1,X2,Y2,Color: Integer); +procedure Pattern(var P); +procedure Back(Dist: Integer); +procedure ClearScreen; +procedure Forwd(Dist: Integer); +function Heading: Integer; +procedure HideTurtle; +procedure Home; +procedure NoWrap; +procedure PenDown; +procedure PenUp; +procedure SetHeading(Angle: Integer); +procedure SetPenColor(Color: Integer); +procedure SetPosition(X,Y: Integer); +procedure ShowTurtle; +procedure TurnLeft(Angle: Integer); +procedure TurnRight(Angle: Integer); +procedure TurtleDelay(Delay: integer); +procedure TurtleWindow(X,Y,W,H: Integer); +function TurtleThere: Boolean; +procedure Wrap; +function Xcor: Integer; +function Ycor: Integer; + + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/HELPME!.DOC b/Borland Turbo Pascal v55/DOC/HELPME!.DOC new file mode 100644 index 0000000..ed45e1e --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/HELPME!.DOC @@ -0,0 +1,454 @@ + + TURBO PASCAL 5.5: ANSWERS TO COMMON QUESTIONS + --------------------------------------------- + + 1. Can I build programs bigger than 64K? + + The total size of a program's code is only limited by the + memory you have available; but each unit (module) can be + no larger than 64K, since it has to have its own code + segment. + + The data segment is still no more than 64K, but the heap + is unlimited just as in 3.0. In fact, we've rewritten the + heap manager to make it much more efficient. There's no + waste when allocating memory (in 3.0, all blocks were + rounded up to a factor of 8), and you can install a heap + error routine that gets called if an allocation request + fails. All in all, 5.5's heap manager is much faster than + version 3.0. + + 2. Can Turbo Pascal run on generic MS-DOS machines? + + TPC.EXE will run on generic machines when you use the /Q + option. The System, Overlay, Dos, and Printer standard + units will operate correctly on MS-DOS generic machines. + Generated .EXE's are MS-DOS compatible as long as you + don't use the special PC units (such as Crt, Graph, and + Graph3). + + 3. Does Turbo Pascal 5.5 support large integers? + + Yes, TP 5.5 has virtually every incarnation of 8-, 16-, and + 32-bit integers: shortint, integer, longint, byte, and + word. + + 4. Will the toolboxes for 4.0 work with 5.5? + + Yes, all 4.0 versions of the toolboxes will work with + Turbo Pascal 5.5. In a few cases, minor changes to + compiler directives are recommended. Refer to the Turbo + Pascal README file for more information. + + 5. Does Turbo Pascal version 5.5 support conditional + compilation? + + Yes, Turbo 5.5 includes conditional compilation support. + You use {$DEFINE ...} and {$UNDEF ...} for symbols and + {$IFDEF ...}. Using the {$IFOPT ...} conditional + directive, you can even test the settings of compiler + directives like R-, N+, and others. For the command-line + compiler, you can define symbols with the /D directive. In + the integrated compiler, you can also define symbols via + the Options/Compiler/Conditional Defines menu command. + + 6. How much of the 64K in the data segment is actually + available to my program? + + The amount of data segment used by the run-time library + depends on which standard units you use in your program. + Here is the data segment usage (in bytes) for each unit: + + UNIT Data Size + ---- --------- + System 664 + Overlay 24 + Crt 20 + Dos 6 + Printer 256 + Graph 1070 + Turbo3 256 + Graph3 0 + ========= + 2282 + + The total size of the data segment is 65,520 bytes. If you + used only the System unit, the amount of data segment + space left over would be + + 65520 - 664 = 64856 bytes + + 7. What is the largest global data structure you can + allocate? + + The maximum size of a single variable that can be + allocated on the heap is 65,521 bytes. + + 8. How do I find out how much code and data were generated by + the compiler for a program or unit? + + If you are using the integrated environment, build your + program or unit and then use the Get Info command in the + Compile menu. This will bring up a window of information + that includes the size of code and data. + + If you are using the command-line compiler, the size of + generated code and data is displayed on the screen at the + end of compilation. + + 9. Are the .OBJ files generated by Turbo C and Turbo + Assembler compatible with 5.5? + + You can write Turbo C or Turbo Assembler routines and link + the .OBJ files into your Turbo Pascal programs by using + {$L} compiler directives. Turbo Pascal 5.5 generates .TPU + (Turbo Pascal Unit) files, not .OBJ files. We've made that + decision for many reasons: + + A. TP 5.5's .TPU files are smaller than .OBJ's, and they + contain symbolic information important to the support + of Pascal's strict type conventions (types, constants, + etc.). + + B. .TPU files allow "smart linking" - elimination of + unused code and data on a procedure-by-procedure + basis. + + C. .TPU's allow built-in project management through + version 5.5's Make and Build commands. + + D. .TPU's allow faster compilation speeds (34,000 lines + per minute on a PS/2 Model 60). + + 10. Will the $L compiler directive work for compiler object files + other than assembler? + + That depends on the language. TURBO requires all the code + in the .OBJ to be in *one* CODE segment, and all the data + to be in *one* DATA segment. With assembly language that's + easy, but it may not work with some high-level language + compilers. You can use Turbo C to generate .OBJ files for + use by Turbo Pascal programs. An example, CPASDEMO.PAS is + included on the distribution disks. + + 11. Does the built-in linker eliminate unused data? + + Yes. Unused code AND data are stripped when you compile to + disk. + + 12. If two units use a third unit, does the third unit get + included twice in my program? + + No. All your units are "linked" together when you compile + your program. Only one copy of each procedure and function + used is generated. There is NO duplication of run-time + code. In fact, Turbo Pascal 5.5 has "smart linking," which + eliminates any unused code and data from the final .EXE. + + 13. What happens if you attempt to link another unit in which the + compiler directives are set differently? + + Compiler directives are local to the unit they are + declared in. Thus, the compiler directives in one unit, or + in the main program, have no effect on the directives set + in another unit. + + 14. Can I create my own .TPL file? + + Yes, but Turbo Pascal will only use the TURBO.TPL library + file. If you want to add your own units to the TURBO.TPL + file, you can use the unit mover program (TPUMOVER.EXE). + For example, you might want a customized version of + TURBO.TPL for each of the programs you're developing. A + corresponding configuration file for Turbo Pascal would + specify a different Turbo directory and thus fetch the + appropriate .TPL file for each of your projects. + + 15. What rules should I follow when writing an interrupt + handler? + + The following is a list of rules to keep in mind when + writing an interrupt handler: + + A. Use GetIntVec and SetIntVec to install/uninstall + interrupt handlers + + B. Use the interrupt directive + + C. Be careful about reentrancy. Don't use any calls to + DOS or to Turbo Pascal's overlay or heap management + routines in your interrupt handler + + D. Interrupt procedures and functions must use the far + call model (use the {$F+} option) + + E. Be proficient with the BIOS and assembly language + before attempting to write an interrupt handler + + F. Make sure your interrupt handler is not in an + overlaid unit. + + G. Neither static nor virtual methods can be used as + interrupt handlers. + + 16. Does a procedure or function in a program have to be of a + near or far call model? + + If you are using overlays or procedural variables, you + should probably turn {$F+} on for all units and the main + program (the extra overhead of always using far calls is + usually quite small). + + Otherwise, Turbo Pascal automatically selects the correct + call model. A routine is always a near call model unless + + 1) It is declared in the interface section of a unit + + 2) You override the default call model by using the {$F+} + compiler option + + 3) It is an object method. Methods are always far calls. + + You should also use the {$F+} option to override the + default call model if you are writing interrupt handlers, + error handlers, exit procedures, or procedures or + functions that will be called via a procedural variable. + + 17. How do I write reentrant code in Turbo Pascal? + + If a routine follows these rules, it is reentrant: + + A. All data is allocated on the stack. + + B. The routine doesn't use any global variables. + + C. The routine can be interrupted at any time without + affecting the execution of the routine. + + D. The routine doesn't call any other routines that are + not reentrant (e.g., DOS I/O). + + 18. What is the best approach to taking advantage of the new IEEE + floating-point types? + + The new IEEE floating-point types are available when you + compile your program with {$N+} and you have a math + coprocessor; they are also available if you don't have a + coprocessor, but specify {N+,E+}. The 8087 emulator has + greater precision, but is significantly slower than the + fast, 6-byte, software-only reals. When developing + programs that will be compiled and run on machines without + the 8087 coprocessor, consider the trade-offs of speed + (built-in reals) vs. precision (8087 hardware/emulation) + and make the appropriate choice. + + 19. What type is Comp? What is it useful for? + + The Comp type is a cross between an integer and a real + type and is available when 8087 code is generated {$N+}. + If no math coprocessor is available, specify {$N+,E+} and + the emulator will support the Comp type. + + The compiler treats it as a real type without an exponent. + Thus Comp is useful when you need to store extremely large + numbers but don't need a decimal point. For example, you + might use variables of type Comp to store amounts in cents + and divide the value of the variable by 100 to determine + what the value in dollars and cents would be. + + 20. How many significant digits do the 8087 floating-point types + provide? + + Type Digits of precision + -------- ------------------- + single 7-8 + double 15-16 + extended 19-20 + comp 19-20 + + 21. Are the intermediate results of real number expressions + stored in the 8087 registers? + + No. The user (8086) stack is used to store intermediate + results of real number expressions. + + 22. How does rounding work with IEEE floating point? + + The 8087 math coprocessor uses a different method for + rounding numbers than what you may be used to. In order to + achieve a more even distribution of values, the 8087 uses + a method sometimes called "Banker's Rounding." This method + dictates that a number will always be rounded to the + nearest EVEN number. Note that this is quite different + than always rounding UP. Here are a couple of examples: + + Round(0.5) = 0 + Round(1.5) = 2 + + 23. How do you do I/O redirection? + + If you want to do DOS I/O redirection when running an .EXE + file generated by Turbo Pascal, DON'T use the Crt unit. If + you do, make sure you assign a null file name to the + standard Output file handle: + + Assign(Output, ''); { Assign a null file name Output } + ReWrite(Output); { Open the file for output } + + Any Write statement that does not specify a file variable + will be redirected to the DOS standard output file. + + 24. How do you go about upgrading version 3.0 programs with + lots of chain files? + + Chaining is not possible with .EXE files. Control can be + passed to another program by use of the EXEC procedure in + the DOS unit. You can also use 5.5's overlay manager to + build very large programs. + + 25. Are overlays supported in 5.5? + + Yes! See the example program OVRDEMO.PAS and refer to the + Turbo Pascal manual for information on overlays. + + 26. Is there any support in Turbo Pascal 5.5 for file and record + locking? + + There's a standard variable in the System unit called + FileMode, which you can use to assign an open mode for use + in all subsequent Resets. There are no record-locking + routines implemented in the standard version, but they are + easily implemented through MsDos calls. + + 27. Does Turbo 5.5 support procedural parameters? + + Yes. See PROCVAR.PAS, DIRDEMO.PAS, and refer to the + Reference Guide for a complete description. + + 28. Can you use identifiers other than scalar in the case statement? + + Case statements allow the following ordinal types: + + Char, Boolean, ShortInt, Byte, Integer, Word, and + user-defined enumeration. + + 29. Is the run-time license policy the same as in version 3.0? + + YES, there are no royalties! + + 30. C has static variables, is there anything similar in 5.5? + + You can declare private global variables in the + implementation part of a unit. Such variables are only + visible within that unit. Like other globals, they retain + their values across calls. + + Typed constant declarations declared within a procedure or + function also behave exactly like C's static variables. + They are local in scope but since they are allocated in + the data segment, they retain their values from call to + call. + + 31. What Turbo Pascal 3.0 code will cause the most problems + converting to version 5.5? + + With our UPGRADE program (see appropriate Appendix in your + manual), it's not very difficult to port your code to 5.5. + It depends a lot on the type of programs you write. + + The passing of parameters on the stack is done much more + efficiently now, so changes will have to be made to inline + machine code and assembly language. Most of the changes + are optional: using new types, breaking your program into + modules to take advantage of separate compilation. (The + UPGRADE program has a special option to help you "unitize" + your program too. It does all the "typing" for you.) + + Some stricter type-checking is performed in version 5.5. + For example, the Dos unit now defines the often-seen + registers record type (AX, BX...); MsDos and Intr now take + this type. In this case, you can type-cast or change the + type identifier and recompile. + + 32. What books can I read that will help me with Turbo Pascal + 5.5? + + The Turbo Pascal Tutor is an excellent reference to Turbo + Pascal. Also, Osborne/McGraw Hill has a line of books + about Borland's products. + + 33. How do I use .BIN files provided by third-party vendors with + 5.5? + + We've included a utility on your distribution disk called + BINOBJ.EXE, which converts binary files into .OBJ files + that are linkable to your Turbo Pascal 5.5 programs. In + general this will only work if the binary files contain + data, not code. Contact your third-party vendor to see if + they also provide .OBJ versions of their programs. + + 34. Why does TURBO sometimes try to read from another drive + when I run it? + + When you leave Turbo Pascal, it saves the name and path of + the file you were last editing in a pick list. The next + time you load Turbo, it checks this pick list and tries to + load the file you were last editing. If the file you were + last editing was in another drive, Turbo will try to read + from that drive. This also occurs if you have installed + another drive as your Turbo Directory. + + 35. Does Turbo Pascal 5.5 support EMS? + + Yes, Turbo Pascal 5.5 will use up to 64K of EMS for + storing the edit buffer. In addition, you can instruct the + Overlay unit to place your overlaid units in EMS. Finally, + EMS.PAS on the distribution disk shows you how to access + EMS memory from a Turbo Pascal program. + + 36. How can I allocate my own I/O buffer for a text file? + + You can use the procedure SetTextBuf to allocate your own + text file buffer either in the data segment or on the + heap. + + 37. Why aren't the new settings used after I install TURBO.EXE + using the TINST.EXE program? + + You probably have a .TP file in the current or Turbo + directory being loaded and the settings in the .TP file + override the settings installed by TINST. Delete the .TP + file. + + 38. What is the largest string supported? + + A string can be 255 characters long. You can write your + own routines to handle strings with lengths greater than + 255 characters. + + 39. Can I still write to file 'Con' without changes? + + The 'Con' file is no longer supported, but you can still + write to the screen with a simple Write with no file + variable. The file system has been completely redesigned + to allow you to write your own text file device drivers. + With these, you can implement a Pascal-like text-file + interface to any device, such as serial ports, windowing + systems, memory, etc. + + 40. What is constant merging? + + For example, when you use the same string constant more + than once in a program block, the compiler only saves one + copy of this string. In the generated program, a pointer + is created that references the one copy of this string in + the generated .EXE file. + + 41. Have Turbo Pascal 3.0 run-time error codes changed in + Turbo Pascal 5.5? + + Yes, error codes have changed; refer to Appendix I in the + Reference Guide. The Turbo3 unit contains a version 3.0 + compatible IOResult function. + + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/OVERLAY.DOC b/Borland Turbo Pascal v55/DOC/OVERLAY.DOC new file mode 100644 index 0000000..8e749ee --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/OVERLAY.DOC @@ -0,0 +1,47 @@ + +{*******************************************************} +{ } +{ Turbo Pascal Version 5.5 } +{ Overlay Interface Unit } +{ } +{ Copyright (C) 1987, 1989 Borland International } +{ } +{*******************************************************} + +unit Overlay; + +{$D-,I-,S-} + +interface + +const + ovrOk = 0; + ovrError = -1; + ovrNotFound = -2; + ovrNoMemory = -3; + ovrIOError = -4; + ovrNoEMSDriver = -5; + ovrNoEMSMemory = -6; + +const + OvrResult: Integer = 0; + OvrTrapCount: Word = 0; + OvrLoadCount: Word = 0; + OvrFileMode: Byte = 0; + +type + OvrReadFunc = function(OvrSeg: Word): Integer; + +var + OvrReadBuf: OvrReadFunc; + +procedure OvrInit(FileName: String); +procedure OvrInitEMS; +procedure OvrSetBuf(Size: LongInt); +function OvrGetBuf: LongInt; +procedure OvrSetRetry(Size: LongInt); +function OvrGetRetry: LongInt; +procedure OvrClearBuf; + +implementation + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/PRINTER.DOC b/Borland Turbo Pascal v55/DOC/PRINTER.DOC new file mode 100644 index 0000000..29438b1 --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/PRINTER.DOC @@ -0,0 +1,19 @@ + +{*******************************************************} +{ } +{ Turbo Pascal Version 5.5 } +{ Printer Interface Unit } +{ } +{ Copyright (C) 1987, 1989 Borland International } +{ } +{*******************************************************} + +unit Printer; + +{$D-,I-,S-} + +interface + +var + Lst: Text; + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/SYSTEM.DOC b/Borland Turbo Pascal v55/DOC/SYSTEM.DOC new file mode 100644 index 0000000..ab3be75 --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/SYSTEM.DOC @@ -0,0 +1,61 @@ + +{*******************************************************} +{ } +{ Turbo Pascal Runtime Library Version 5.5 } +{ System Unit } +{ } +{ Copyright (C) 1987, 1989 Borland International } +{ } +{*******************************************************} + +unit System; + +interface + +const + OvrCodeList: Word = 0; { Overlay code segment list } + OvrHeapSize: Word = 0; { Initial overlay buffer size } + OvrDebugPtr: Pointer = nil; { Overlay debugger hook } + OvrHeapOrg: Word = 0; { Overlay buffer origin } + OvrHeapPtr: Word = 0; { Overlay buffer pointer } + OvrHeapEnd: Word = 0; { Overlay buffer end } + OvrLoadList: Word = 0; { Loaded overlays list } + OvrDosHandle: Word = 0; { Overlay DOS handle } + OvrEmsHandle: Word = 0; { Overlay EMS handle } + HeapOrg: Pointer = nil; { Heap origin } + HeapPtr: Pointer = nil; { Heap pointer } + FreePtr: Pointer = nil; { Free list pointer } + FreeMin: Word = 0; { Minimum free list size } + HeapError: Pointer = nil; { Heap error function } + ExitProc: Pointer = nil; { Exit procedure } + ExitCode: Integer = 0; { Exit code } + ErrorAddr: Pointer = nil; { Runtime error address } + PrefixSeg: Word = 0; { Program segment prefix } + StackLimit: Word = 0; { Stack pointer low limit } + InOutRes: Integer = 0; { I/O result buffer } + RandSeed: Longint = 0; { Random seed } + FileMode: Byte = 2; { File open mode } + Test8087: Byte = 0; { 8087 test result } + +var + Input: Text; { Input standard file } + Output: Text; { Output standard file } + SaveInt00: Pointer; { Saved interrupt $00 } + SaveInt02: Pointer; { Saved interrupt $02 } + SaveInt1B: Pointer; { Saved interrupt $1B } + SaveInt23: Pointer; { Saved interrupt $23 } + SaveInt24: Pointer; { Saved interrupt $24 } + SaveInt34: Pointer; { Saved interrupt $34 } + SaveInt35: Pointer; { Saved interrupt $35 } + SaveInt36: Pointer; { Saved interrupt $36 } + SaveInt37: Pointer; { Saved interrupt $37 } + SaveInt38: Pointer; { Saved interrupt $38 } + SaveInt39: Pointer; { Saved interrupt $39 } + SaveInt3A: Pointer; { Saved interrupt $3A } + SaveInt3B: Pointer; { Saved interrupt $3B } + SaveInt3C: Pointer; { Saved interrupt $3C } + SaveInt3D: Pointer; { Saved interrupt $3D } + SaveInt3E: Pointer; { Saved interrupt $3E } + SaveInt3F: Pointer; { Saved interrupt $3F } + SaveInt75: Pointer; { Saved interrupt $75 } + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/THELP.DOC b/Borland Turbo Pascal v55/DOC/THELP.DOC new file mode 100644 index 0000000..12815fa --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/THELP.DOC @@ -0,0 +1,334 @@ + TURBO HELP UTILITY + ------------------ + +This file explains how to use THELP.COM. THELP is a +memory-resident utility that provides online help for Turbo +Pascal and Turbo C. If you are using Turbo Debugger, for +example, you can load THELP, then run the debugger and get +online help for Pascal or C while you are debugging. + + +Table of Contents +----------------- +1. Starting THELP +2. Command-line Options Summary +3. Detailed Explanation of Keys Used When THELP is Active +4. Detailed Explanation of Command-line Options + + +1. Starting THELP +------------------ + +Load THELP at the DOS command-line simply by typing THELP. +Make sure the Turbo help file (TURBO.HLP for Turbo Pascal, +TCHELP.TCH for TURBO C) is in the current directory or use the /F +commandline option described below. + + +Memory Usage - THELP requires about 8K bytes (+ 32K swap file); + 40K with no swapping. + +Default hotkey - The default hotkey is Numeric-Keypad-5 (scan + code 4ch, shift state 00h). + +Paste speed - The default pasting speed is FAST. You'll have + to experiment if it pastes too quickly for your + editor. Note that you should turn off autoindent + in the integrated environment before using the + paste feature (Ctrl-Q I toggles autoindent). + +If you are using SideKick Plus or SideKick 1.x, make sure you +load THELP before you load SideKick. + + +2. Command-line Options Summary +------------------------------- + + USAGE: THELP [options] + +Here is a summary of the command line options. If you use more +than one option, they must be separated by spaces. + + /B Use BIOS for video + /C#xx Select color: #=color number, xx=hex color value + /Dname Full path for disk swapping (implies /S1) + /Fname Full path and filename of help file + /H,/?,? Display this help screen + /Kxxyy Change hotkey: xx=shift state, yy=scan code + /Lxx Force number of rows on screen: xx=25,43,50 + /M+,/M- Display help text: on monochrome screen(+), + on default screen(-) + /Px Pasting speed: 0=slow, 1=medium, 2=fast + /R Send options to resident THELP + /Sx Default Swapping Mode: 1=Use Disk, 2=Use EMS, + 3=No Swapping + /U Remove THELP from memory + /W Write Options to THELP.COM and exit + + +3. Detailed Explanation of Keys Used When THELP is Active +--------------------------------------------------------- + + Arrow keys: Move the highlight from item to item within the + current help screen. + + PgUp/PgDn: Move from screen to screen if additional screens + are available. + + ENTER: Select help entry for the item highlighted in the + current help screen. + + ESC: End Help. + + F1: Help Index. F1 from any help screen brings up + the Help Index. + + ALT-F1: Displays in reverse order the last 20 screens you + have reviewed. + + CTL-F1: Bring up help screen for THELP's hot keys. + + F key: Select new help file. 'F' or 'f' brings up a + window that allows you to change help files on the + fly. Type in the complete path name of the new + help file, and it will be read into memory and + initialized to the help index of the new file + (Page 100). If the new file does not exist, or is + in an invalid format, THELP will beep twice, and + return you to the original file. + + J key: Jump to specified help page number. 'J' or 'j' + brings up a window that allows you to jump to any + particular page (9999 max) in the help file. The + only editing key permitted in this window is + BackSpace. ESC aborts, CR (or four digits) + completes. + + K key: Search help file for specified keyword. 'K' or 'k' + brings up a window in which you can enter a + keyword (40 characters max), and have THELP search + the help file for a match. If there is no matching + keyword in the current help file, THELP will beep + twice and return you to the original help screen. + + I key: Paste highlighted keyword into application. 'I' or + 'i' inserts the current highlighted keyword into + the keyboard buffer, and immediately pops down. + + P key: Paste entire help screen into application. 'P' or + 'p' inserts the entire current help page (as it + appears in the help window) into the current + application, and then immediately pops down. + Pasting can be interrupted with ^C or ^Break. + + S Key: Save help screen to disk file (THELP.SAV). 'S' or + 's' from any help screen saves the current help + page to the disk file THELP.SAV, in the current + directory. If the file already exists, the new + help information is appended to the end. + + + Pressing the hotkey combination when using THELP + on a second monitor ends this session of the + resident help, but leaves the current help screen + on the monochrome monitor. + + +4. Detailed Explanation of Command-line Options +------------------------------------------------ + +/B -- Use BIOS for video + +This option forces THELP to use Interrupt 10h BIOS video calls +for all writing to/reading from the video display. Normally, THELP +will write directly to video RAM. Note that the use of this +option negates the effect of the /M switch described below; the +alternate monitor may not be used if /B is in effect. This option +is enabled with '/B+', and disabled with '/B-' (enable is the +default). + +/C#xx Select color: #=color number, xx=hex color value + +There are eight possible colors, described as follows: + + 1 = Color Normal Text + 2 = Monochrome Normal Text + 3 = Color Possible reference pages; top/bottom description line + 4 = Monochrome Possible reference pages; top/bottom description line + 5 = Color Border Color + 6 = Monochrome Border Color + 7 = Color Current Reference Selection + 8 = Monochrome Current Reference Selection + +Any or all of these eight colors may be specified on the command +line. + +The color numbers for a standard IBM-compatible Color Display are +as follows: + +First Digit (Background) Second Digit (Foreground) + +0 -- Black 0 -- Black +1 -- Blue 1 -- Blue +2 -- Green 2 -- Green +3 -- Cyan 3 -- Cyan +4 -- Red 4 -- Red +5 -- Magenta 5 -- Magenta +6 -- Brown 6 -- Brown +7 -- Grey 7 -- Grey + 8 -- Intense Black + ORing the color value with 9 -- Intense Blue + Hex 80 produces a blinking A -- Intense Green + color unless blinking has been B -- Intense Cyan + disabled. C -- Intense Red + D -- Intense Magenta + E -- Intense Brown (Yellow) + F -- Intense Grey (White) + +On Monochrome monitors, the attribute values can differ widely, +so some experimentation would be needed. Note that the monochrome +attributes are used in only two cases; when the current video +mode is 7, or when force mono is used (see the /M option) + + +/Dname -- Full path for disk swapping (implies /S1) + +This option is used to override where THELP will place its swap +files when swapping to disk. A full path should be specified, +but a trailing '\' is not necessary. If no /D option is +specified, under DOS 3.x swap files are placed in the directory +where THELP.COM resides. Under DOS 2.x, swap files are placed by +default in C:\. + +Using this option also sets the flag that forces disk swapping +instead of checking first for EMS. + + +/Fname -- Full path and filename of help file + +The name that follows the /F option should be the full +drive/directory pathname of the help file to use; e.g., + + THELP /FC:\TP\TURBO.HLP + THELP /FC:\TURBOC\TCHELP.TCH + +By default, THELP looks for the help file on the logged drive and +directory. + + +/H,/?,? -- Display help screen + +This option displays a summary of THELP's command-line options + + +/Kxxyy -- Change hotkey: xx=shift state, yy=scan code + +Virtually any shift state/scan code combination may be selected. +A quick summary of some common shift-states and scan codes +follows: + + + Shift States (may be OR'ed together) + + right shift 01h + left shift 02h + control 04h + alt 08h + + Scan Codes + + A --- 1eh N --- 31h 0 --- 0bh F1 --- 3bh + B --- 30h O --- 18h 1 --- 02h F2 --- 3ch + C --- 2eh P --- 19h 2 --- 03h F3 --- 3dh + D --- 20h Q --- 10h 3 --- 04h F4 --- 3eh + E --- 12h R --- 13h 4 --- 05h F5 --- 3fh + F --- 21h S --- 1fh 5 --- 06h F6 --- 40h + G --- 22h T --- 14h 6 --- 07h F7 --- 41h + H --- 23h U --- 16h 7 --- 08h F8 --- 42h + I --- 17h V --- 2fh 8 --- 09h F9 --- 43h + J --- 24h W --- 11h 9 --- 0ah F10 --- 44h + K --- 25h X --- 2dh + L --- 26h Y --- 15h + M --- 32h Z --- 2ch + + + Enhanced Keyboards only (may not work with all computers, + keyboards) + + F11 --- 57h + F12 --- 58h + + +/Lxx -- Force number of rows on screen: xx=25,43,50 + +Some video adapters do not correctly store the number of video +rows on the screen in the BIOS data location specified for the +IBM-PC. This option forces THELP to use the given value, rather +than the number the BIOS reports. + + +/M+,/M- -- Display help text: on monochrome screen(+), + on default screen(-) + +For users with dual-monitor systems, this option may be used to +instruct THELP to bring up its display on the monochrome monitor, +rather than on the color monitor. This option is enabled with +'/M+', and disabled with '/M-' (enable is the default). Note that +/M is incompatible with /B (see above). + + +/Px -- Pasting speed: 0=slow, 1=medium, 2=fast + +Some editors do not accept characters pasted into the keyboard +buffer as fast as THELP can put them there. By setting an +appropriate paste speed, virtually all possible configurations of +editors may be used. FAST speed pastes as many characters as will +fit on every timer tick; MEDIUM pastes up to four characters per +tick; and SLOW pastes a single character into the buffer ONLY +when the buffer is empty. + + +/R -- Send options to resident THELP + +The /R option is used to pass parameters (like new colors, or new +hotkeys) to the resident portion of THELP. All THELP command-line +options may be sent to the resident portion except for the +swapping mode, which cannot be modified once THELP has been +initialized. + +In combination with these options, you can create a batch file +that changes THELP's configuration as you change editors; i.e.: + + THELP /M /P0 /FC:\TP\TURBO.HLP /R + Use mono monitor, slow pasting, and the Turbo Pascal help + file. Options are not saved to disk. + + THELP /P2 /FC:\TC\TCHELP.TCH /R + Use default monitor, fast pasting, and the Turbo C help file. + Options are not saved to disk. + + +/Sx -- Default Swapping Mode: 1=Use Disk, 2=Use EMS, + 3=No Swapping + +If no '/S' parameter is used, THELP first tests to see if +Expanded Memory is available in the system. If so, and if enough +memory can be allocated, swapping is done to EMS. If EMS is not +available, disk swapping is used. See the /D parameter for +information on where the swap file will be written if disk +swapping is used. + + +/U -- Remove THELP from memory + +This option is used to remove THELP from memory. If other TSRs +have been loaded after THELP, make sure to remove them before +removing THELP. + + +/W -- Write Options to THELP.COM and exit + +The /W parameter is used to create a new version of THELP that +uses the options you desire as a default. All options, including +/S (but not /R) may be specified and made 'permanent'. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOC/TURBO3.DOC b/Borland Turbo Pascal v55/DOC/TURBO3.DOC new file mode 100644 index 0000000..a2140a0 --- /dev/null +++ b/Borland Turbo Pascal v55/DOC/TURBO3.DOC @@ -0,0 +1,33 @@ + +{*******************************************************} +{ } +{ Turbo Pascal Version 5.5 } +{ 3.0 Compatibility Unit } +{ } +{ Copyright (C) 1987, 1989 Borland International } +{ } +{*******************************************************} + +unit Turbo3; + +{$D-,I-,S-} + +interface + +uses Crt; + +var + Kbd: Text; + CBreak: Boolean absolute CheckBreak; + +procedure AssignKbd(var F: Text); +function MemAvail: Integer; +function MaxAvail: Integer; +function LongFileSize(var F): Real; +function LongFilePos(var F): Real; +procedure LongSeek(var F; Pos: Real); +procedure NormVideo; +procedure HighVideo; +procedure LowVideo; +function IOresult: Integer; + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOSSTM.ASM b/Borland Turbo Pascal v55/DOSSTM.ASM new file mode 100644 index 0000000..eaa257a --- /dev/null +++ b/Borland Turbo Pascal v55/DOSSTM.ASM @@ -0,0 +1,221 @@ +; Turbo Pascal 5.5 object-oriented example +; Assembler code for OBJECTS.PAS unit +; Copyright (c) 1989 by Borland International, Inc. + + TITLE DOSSTM + + INCLUDE OBJECTS.INC + +CODE SEGMENT BYTE PUBLIC + + EXTRN StreamError:NEAR + + ASSUME CS:CODE + + PUBLIC DosStream@GetPos + +DosStream@GetPos PROC FAR + +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CMP ES:[DI].Stream@Status,0 + JNE @@1 + XOR CX,CX + MOV DX,CX + MOV BX,ES:[DI].DosStream@Handle + MOV AX,4201H + INT 21H + JNC @@2 + CALL StreamError +@@1: MOV AX,-1 + MOV DX,AX +@@2: POP BP + RET 4 + +DosStream@GetPos ENDP + + PUBLIC DosStream@Read + +DosStream@Read PROC FAR + +@Buf EQU (DWORD PTR [BP+12]) +@Count EQU (WORD PTR [BP+10]) +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CMP ES:[DI].Stream@Status,0 + JNE @@2 + PUSH DS + LDS DX,@Buf + MOV CX,@Count + MOV BX,ES:[DI].DosStream@Handle + MOV AH,3FH + INT 21H + POP DS + JC @@1 + CMP AX,CX + JE @@3 + MOV AX,100 +@@1: CALL StreamError +@@2: LES DI,@Buf + MOV CX,@Count + XOR AL,AL + CLD + REP STOSB +@@3: POP BP + RET 10 + +DosStream@Read ENDP + + PUBLIC DosStream@SetPos + +DosStream@SetPos PROC FAR + +@Pos EQU (DWORD PTR [BP+12]) +@Mode EQU (BYTE PTR [BP+10]) +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CALL StreamFlush + JNE @@1 + MOV DX,@Pos.w0 + MOV CX,@Pos.w2 + MOV BX,ES:[DI].DosStream@Handle + MOV AL,@Mode + MOV AH,42H + INT 21H + JNC @@1 + CALL StreamError +@@1: POP BP + RET 10 + +DosStream@SetPos ENDP + + PUBLIC DosStream@Truncate + +DosStream@Truncate PROC FAR + +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CALL StreamFlush + JNE @@1 + XOR CX,CX + MOV BX,ES:[DI].DosStream@Handle + MOV AH,40H + INT 21H + JNC @@1 + CALL StreamError +@@1: POP BP + RET 4 + +DosStream@Truncate ENDP + + PUBLIC DosStream@Write + +DosStream@Write PROC FAR + +@Buf EQU (DWORD PTR [BP+12]) +@Count EQU (WORD PTR [BP+10]) +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CMP ES:[DI].Stream@Status,0 + JNE @@2 + PUSH DS + LDS DX,@Buf + MOV CX,@Count + MOV BX,ES:[DI].DosStream@Handle + MOV AH,40H + INT 21H + POP DS + JC @@1 + CMP AX,CX + JE @@2 + MOV AX,101 +@@1: CALL StreamError +@@2: POP BP + RET 10 + +DosStream@Write ENDP + + PUBLIC DosStream@Close + +DosStream@Close PROC FAR + +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + CALL StreamFlush + JNE @@1 + MOV BX,ES:[DI].DosStream@Handle + MOV AH,3EH + INT 21H +@@1: POP BP + RET 4 + +DosStream@Close ENDP + + PUBLIC DosStream@Open + +DosStream@Open PROC FAR + +@Name EQU (DWORD PTR [BP+12]) +@Mode EQU (WORD PTR [BP+10]) +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@Self + PUSH DS + LDS DX,@Name + XOR CX,CX + MOV AX,@Mode + INT 21H + POP DS + JNC @@1 + CALL StreamError + MOV AX,0FFFFH +@@1: MOV ES:[DI].DosStream@Handle,AX + POP BP + RET 10 + +DosStream@Open ENDP + +; Call stream flush procedure +; In ES:DI = Stream object pointer +; Out ZF = Status test +; Uses AX,BX,CX,DX,SI + +StreamFlush PROC NEAR + + PUSH ES + PUSH DI + PUSH ES + PUSH DI + MOV DI,ES:[DI] + CALL [DI].Stream$Flush + POP DI + POP ES + CMP ES:[DI].Stream@Status,0 + RET + +StreamFlush ENDP + +CODE ENDS + + END + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOSSTM.OBJ b/Borland Turbo Pascal v55/DOSSTM.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..d15009e4d16261e2faefffc8f80d6ec9fe6112b2 GIT binary patch literal 653 zcmZqRVc>G{4-O9T)pHE?ZS0U|U|=@$O%D|95K@2FzkB|!w@(giZ%)p?9Zk#*VIH31hCWr#H@FBDSZFA9J zU=Tw$%Gt+1*!2PfgAlp~{{UCN=L`&v9V`qEix?*^kY{9MUYS)aAyt1!My=P(6~OYKBsN)9z@Iq5vM@JA0V;53z$ku0Gs2-0RR91 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/DOS_GT.BAK b/Borland Turbo Pascal v55/DOS_GT.BAK new file mode 100644 index 0000000..fecf8c4 --- /dev/null +++ b/Borland Turbo Pascal v55/DOS_GT.BAK @@ -0,0 +1,28 @@ +type + regpack = record + ax,bx,cx,dx,bp,si,di,ds,es,flags: integer; + end; + +procedure get_time( var tt : timetype ); +var + recpack: regpack; + ah,al,ch,cl,dh: byte; + +begin + ah := $2c; + with recpack do + begin + ax := ah shl 8 + al; + end; + intr( $21, recpack ); + with recpack do + begin + tt.h := cx shr 8; + tt.m := cx mod 256; + tt.s := dx shr 8; + tt.l := dx mod 256; + end; +end; + + + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/DOS_GT.PAS b/Borland Turbo Pascal v55/DOS_GT.PAS new file mode 100644 index 0000000..5707c53 --- /dev/null +++ b/Borland Turbo Pascal v55/DOS_GT.PAS @@ -0,0 +1,27 @@ +type + regpack = record + ax,bx,cx,dx,bp,si,di,ds,es,flags: integer; + end; + +procedure get_time( var tt : timetype ); +var + recpack: registers; + ahigh: byte; + +begin + ahigh := $2c; + with recpack do + begin + ax := ahigh shl 8; + end; + intr( $21, recpack ); + with recpack do + begin + tt.h := cx shr 8; + tt.m := cx mod 256; + tt.s := dx shr 8; + tt.l := dx mod 256; + end; +end; + + diff --git a/Borland Turbo Pascal v55/DRIVERS.PAS b/Borland Turbo Pascal v55/DRIVERS.PAS new file mode 100644 index 0000000..d6313bf --- /dev/null +++ b/Borland Turbo Pascal v55/DRIVERS.PAS @@ -0,0 +1,35 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +unit Drivers; +{ Sample unit to accompany BGILINK.PAS. This unit links the BGI graphics + driver into a single TPU file. This makes it easy to link the driver files + directly into an .EXE file. See BGILINK.PAS for more information. +} +interface + +procedure ATTDriverProc; +procedure CgaDriverProc; +procedure EgaVgaDriverProc; +procedure HercDriverProc; +procedure PC3270DriverProc; + +implementation + +procedure ATTDriverProc; external; +{$L ATT.OBJ } + +procedure CgaDriverProc; external; +{$L CGA.OBJ } + +procedure EgaVgaDriverProc; external; +{$L EGAVGA.OBJ } + +procedure HercDriverProc; external; +{$L HERC.OBJ } + +procedure PC3270DriverProc; external; +{$L PC3270.OBJ } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/E.PAS b/Borland Turbo Pascal v55/E.PAS new file mode 100644 index 0000000..9290430 --- /dev/null +++ b/Borland Turbo Pascal v55/E.PAS @@ -0,0 +1,42 @@ +program e; + +const + DIGITS = 200; + +type + arrayType = array[ 0..DIGITS ] of integer; + +var + high, n, x : integer; + a : arrayType; + +begin + high := DIGITS; + x := 0; + + n := high - 1; + while n > 0 do begin + a[ n ] := 1; + n := n - 1; + end; + + a[ 1 ] := 2; + a[ 0 ] := 0; + + while high > 9 do begin + high := high - 1; + n := high; + while 0 <> n do begin + a[ n ] := x MOD n; + x := 10 * a[ n - 1 ] + x DIV n; + n := n - 1; + end; + + Write( x ); + end; + + writeln; + writeln( 'done' ); +end. + + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/EGAVGA.BGI b/Borland Turbo Pascal v55/EGAVGA.BGI new file mode 100644 index 0000000000000000000000000000000000000000..8d916b7733d4fc92361fe6075619ea8fc4044a54 GIT binary patch literal 5363 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 BoPGcR literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/EMS.PAS b/Borland Turbo Pascal v55/EMS.PAS new file mode 100644 index 0000000..e7b5b45 --- /dev/null +++ b/Borland Turbo Pascal v55/EMS.PAS @@ -0,0 +1,439 @@ +program Ems_Test; +{ ************************************************************* + * This program shows you how to use the basic functions of * + * the LIM Expanded Memory Specification. Since it does not * + * use any of the LIM EMS 4.0 function calls, you can also * + * use it on systems with EMS versions less than 4.0 * + ************************************************************* } + +{ Written by: + Peter Immarco. + Thought Dynamics + Manhattan Beach, CA + Compuserve ID# 73770,123 + *** Public Domain *** + + Used by permission of the author. +} + +{ This program does the following: + +------------------------------------------------------------+ + | * Makes sure the LIM Expanded Memory Manager (EMM) has | + | been installed in memory | + | * Displays the version number of the EMM present in memory | + | * Determines if there are enough pages (16k blocks) of | + | memory for our test program's usage. It then displays | + | the total number of EMS pages present in the system, | + | and how many are available for our usage | + | * Requests the desired number of pages from the EMM | + | * Maps a logical page onto one of the physical pages given | + | to us | + | * Displays the base address of our EMS memory page frame | + | * Performs a simple read/write test on the EMS memory given| + | to us | + | * Returns the EMS memory given to us back to the EMM, and | + | exits | + +------------------------------------------------------------|} + + +{ All the calls are structured to return the result or error + code of the Expanded Memory function performed as an integer. + If the error code is not zero, which means the call failed, + a simple error procedure is called and the program terminates.} + +uses Crt, Dos; + +Type + ST3 = string[3]; + ST80 = string[80]; + ST5 = string[5]; + +Const + EMM_INT = $67; + DOS_Int = $21; + GET_PAGE_FRAME = $41; + GET_UNALLOCATED_PAGE_COUNT= $42; + ALLOCATE_PAGES = $43; + MAP_PAGES = $44; + DEALLOCATE_PAGES = $45; + GET_VERSION = $46; + + STATUS_OK = 0; + + { We'll say we need 1 EMS page for our application } + APPLICATION_PAGE_COUNT = 1; + +Var + Regs: Registers; + Emm_Handle, + Page_Frame_Base_Address, + Pages_Needed, + Physical_Page, + Logical_Page, + Offset, + Error_Code, + Pages_EMS_Available, + Total_EMS_Pages, + Available_EMS_Pages: Word; + Version_Number, + Pages_Number_String: ST3; + Verify: Boolean; + +{ * --------------------------------------------------------- * } + { The function Hex_String converts an Word into a four + character hexadecimal number(string) with leading zeroes. } + Function Hex_String(Number: Word): ST5; + Function Hex_Char(Number: Word): Char; + Begin + If Number<10 then + Hex_Char:=Char(Number+48) + else + Hex_Char:=Char(Number+55); + end; { Function Hex_Char } + + Var + S: ST5; + Begin + S:=''; + S:=Hex_Char( (Number shr 1) div 2048); + Number:=( ((Number shr 1) mod 2048) shl 1)+ + (Number and 1) ; + S:=S+Hex_Char(Number div 256); + Number:=Number mod 256; + S:=S+Hex_Char(Number div 16); + Number:=Number mod 16; + S:=S+Hex_Char(Number); + Hex_String:=S+'h'; + end; { Function Hex_String } + +{ * --------------------------------------------------------- * } + + { The function Emm_Installed checks to see if the Expanded + Memory Manager (EMM) is loaded in memory. It does this by + looking for the string 'EMMXXXX0', which should be located + at 10 bytes from the beginning of the code segment pointed + to by the EMM interrupt, 67h } + Function Emm_Installed: Boolean; + Var + Emm_Device_Name : string[8]; + Int_67_Device_Name : string[8]; + Position : Word; + Regs : registers; + + Begin + Int_67_Device_Name:=''; + Emm_Device_Name :='EMMXXXX0'; + with Regs do + Begin + { Get the code segment pointed to by Interrupt 67h, the EMM + interrupt by using DOS call $35, 'get interrupt vector' } + AH:=$35; + AL:=EMM_INT; + Intr(DOS_int,Regs); + + { The ES pseudo-register contains the segment address pointed + to by Interrupt 67h } + { Create an 8 character string from the 8 successive bytes + pointed to by ES:$0A (10 bytes from ES) } + For Position:=0 to 7 do + Int_67_Device_Name:= + Int_67_Device_Name+Chr(mem[ES:Position+$0A]); + Emm_Installed:=True; + { Is it the EMM manager signature, 'EMMXXXX0'? then EMM is + installed and ready for use, if not, then the EMM manager + is not present } + If Int_67_Device_Name<>Emm_Device_Name + then Emm_Installed:=False; + end; { with Regs do } + end; { Function Emm_Installed } + +{ * --------------------------------------------------------- * } + + { This function returns the total number of EMS pages present + in the system, and the number of EMS pages that are + available for our use } + Function EMS_Pages_Available + (Var Total_EMS_Pages,Pages_Available: Word): Word; + Var + Regs: Registers; + Begin + with Regs do + Begin + { Put the desired EMS function number in the AH pseudo- + register } + AH:=Get_Unallocated_Page_Count; + intr(EMM_INT,Regs); + { The number of EMS pages available is returned in BX } + Pages_Available:=BX; + { The total number of pages present in the system is + returned in DX } + Total_EMS_Pages:=DX; + { Return the error code } + EMS_Pages_Available:=AH + end; + end; { EMS_Pages_Available } + +{ * --------------------------------------------------------- * } + + { This function requests the desired number of pages from the + EMM } + Function Allocate_Expanded_Memory_Pages + (Pages_Needed: Word; Var Handle: Word ): Word; + Var + Regs: Registers; + Begin + with Regs do + Begin + { Put the desired EMS function number in the AH pseudo- + register } + AH:= Allocate_Pages; + { Put the desired number of pages in BX } + BX:=Pages_Needed; + intr(EMM_INT,Regs); + { Our EMS handle is returned in DX } + Handle:=DX; + { Return the error code } + Allocate_Expanded_Memory_Pages:=AH; + end; + end; { Function Allocate_Expanded_Memory_Pages } + +{ * --------------------------------------------------------- * } + + { This function maps a logical page onto one of the physical + pages made available to us by the + Allocate_Expanded_Memory_Pages function } + Function Map_Expanded_Memory_Pages + (Handle,Logical_Page,Physical_Page: Word): Word; + Var + Regs: Registers; + Begin + with Regs do + Begin + { Put the desired EMS function number in the AH pseudo- + register } + AH:=Map_Pages; + { Put the physical page number to be mapped into AL } + AL:=Physical_Page; + { Put the logical page number to be mapped in BX } + BX:=Logical_Page; + { Put the EMS handle assigned to us earlier in DX } + DX:=Handle; + Intr(EMM_INT,Regs); + { Return the error code } + Map_Expanded_Memory_Pages:=AH; + end; { with Regs do } + end; { Function Map_Expanded_Memory_Pages } + +{ * --------------------------------------------------------- * } + + { This function gets the physical address of the EMS page + frame we are using. The address returned is the segment + of the page frame. } + Function Get_Page_Frame_Base_Address + (Var Page_Frame_Address: Word): Word; + Var + Regs: Registers; + Begin + with Regs do + Begin + { Put the desired EMS function number in the AH pseudo- + register } + AH:=Get_Page_Frame; + intr(EMM_INT,Regs); + { The page frame base address is returned in BX } + Page_Frame_Address:=BX; + { Return the error code } + Get_Page_Frame_Base_Address:=AH; + end; { Regs } + end; { Function Get_Page_Frame_Base_Address } + +{ * --------------------------------------------------------- * } + + { This function releases the EMS memory pages allocated to + us, back to the EMS memory pool. } + Function Deallocate_Expanded_Memory_Pages + (Handle: Word): Word; + Var + Regs: Registers; + Begin + with Regs do + Begin + { Put the desired EMS function number in the AH pseudo-register } + AH:=DEALLOCATE_PAGES; + { Put the EMS handle assigned to our EMS memory pages in DX } + DX:=Emm_Handle; + Intr(EMM_INT,Regs); + { Return the error code } + Deallocate_Expanded_Memory_Pages:=AH; + end; { with Regs do } + end; { Function Deallocate_Expanded_Memory_Pages } + +{ * --------------------------------------------------------- * } + + { This function returns the version number of the EMM as + a 3 character string. } + Function Get_Version_Number(Var Version_String: ST3): Word; + Var + Regs: Registers; + Word_Part,Fractional_Part: Char; + + Begin + with Regs do + Begin + { Put the desired EMS function number in the AH pseudo-register } + AH:=GET_VERSION; + Intr(EMM_INT,Regs); + { See if call was successful } + If AH=STATUS_OK then + Begin + { The upper four bits of AH are the Word portion of the + version number, the lower four bits are the fractional + portion. Convert the Word value to ASCII by adding 48. } + Word_Part := Char( AL shr 4 + 48); + Fractional_Part:= Char( AL and $F +48); + Version_String:= Word_Part+'.'+Fractional_Part; + end; { If AH=STATUS_OK } + { Return the function calls error code } + Get_Version_Number:=AH; + end; { with Regs do } + end; { Function Get_Version_Number } + +{ * --------------------------------------------------------- * } + + { This procedure prints an error message passed by the caller, + prints the error code passed by the caller in hex, and then + terminates the program with the an error level of 1 } + + Procedure Error(Error_Message: ST80; Error_Number: Word); + Begin + Writeln(Error_Message); + Writeln(' Error_Number = ',Hex_String(Error_Number) ); + Writeln('EMS test program aborting.'); + Halt(1); + end; { Procedure Error_Message } + +{ * --------------------------------------------------------- * } + +{ EMS_TEST } + +{ This program is an example of the basic EMS functions that you + need to execute in order to use EMS memory with Turbo Pascal } + +Begin + ClrScr; + Window(5,2,77,22); + + { Determine if the Expanded Memory Manager is installed, If + not, then terminate 'main' with an ErrorLevel code of 1. } + + If not (Emm_Installed) then + Begin + Writeln('The LIM Expanded Memory Manager is not installed.'); + Halt(1); + end; + + { Get the version number and display it } + Error_Code:= Get_Version_Number(Version_Number); + If Error_Code<>STATUS_OK then + Error('Error trying to get the EMS version number ', + Error_code) + else + Writeln('LIM Expanded Memory Manager, version ', + Version_Number,' is ready for use.'); + Writeln; + + { Determine if there are enough expanded memory pages for this + application. } + Pages_Needed:=APPLICATION_PAGE_COUNT; + Error_Code:= + EMS_Pages_Available(Total_EMS_Pages,Available_EMS_Pages); + If Error_Code<>STATUS_OK then + Error('Error trying to determine the number of EMS pages available.', + Error_code); + + Writeln('There are a total of ',Total_EMS_Pages, + ' expanded memory pages present in this system.'); + Writeln(' ',Available_EMS_Pages, + ' of those pages are available for your usage.'); + Writeln; + + { If there is an insufficient number of pages for our application, + then report the error and terminate the EMS test program } + If Pages_Needed>Available_EMS_Pages then + Begin + Str(Pages_Needed,Pages_Number_String); + Error('We need '+Pages_Number_String+ + ' EMS pages. There are not that many available.', + Error_Code); + end; { Pages_Needed>Available_EMS_Pages } + + { Allocate expanded memory pages for our usage } + Error_Code:= Allocate_Expanded_Memory_Pages(Pages_Needed,Emm_Handle); + Str(Pages_Needed,Pages_Number_String); + If Error_Code<>STATUS_OK then + Error('EMS test program failed trying to allocate '+Pages_Number_String+ + ' pages for usage.',Error_Code); + Writeln(APPLICATION_PAGE_COUNT, + ' EMS page(s) allocated for the EMS test program.'); + Writeln; + + { Map in the required logical pages to the physical pages + given to us, in this case just one page } + Logical_Page :=0; + Physical_Page:=0; + Error_Code:= + Map_Expanded_Memory_Pages( + Emm_Handle,Logical_Page,Physical_Page); + If Error_Code<>STATUS_OK then + Error('EMS test program failed trying to map '+ + 'logical pages onto physical pages.',Error_Code); + + Writeln('Logical Page ',Logical_Page, + ' successfully mapped onto Physical Page ', + Physical_Page); + Writeln; + + { Get the expanded memory page frame address } + Error_Code:= Get_Page_Frame_Base_Address(Page_Frame_Base_Address); + If Error_Code<>STATUS_OK then + Error('EMS test program unable to get the base Page'+ + ' Frame Address.',Error_Code); + Writeln('The base address of the EMS page frame is - '+ + Hex_String(Page_Frame_Base_Address) ); + Writeln; + + { Write a test pattern to expanded memory } + For Offset:=0 to 16382 do + Mem[Page_Frame_Base_Address:Offset]:=Offset mod 256; + + { Make sure that what is in EMS memory is what we just wrote } + Writeln('Testing EMS memory.'); + + Offset:=1; + Verify:=True; + while (Offset<=16382) and (Verify=True) do + Begin + If Mem[Page_Frame_Base_Address:Offset]<>Offset mod 256 then + Verify:=False; + Offset:=Succ(Offset); + end; { while (Offset<=16382) and (Verify=True) } + + { If it isn't report the error } + If not Verify then + Error('What was written to EMS memory was not found during '+ + 'memory verification test.',0); + Writeln('EMS memory test successful.'); + Writeln; + + { Return the expanded memory pages given to us back to the + EMS memory pool before terminating our test program } + Error_Code:=Deallocate_Expanded_Memory_Pages(Emm_Handle); + If Error_Code<>STATUS_OK then + Error('EMS test program was unable to deallocate '+ + 'the EMS pages in use.',Error_Code); + Writeln(APPLICATION_PAGE_COUNT, + ' page(s) deallocated.'); + Writeln; + Writeln('EMS test program completed.'); +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/ERROR.PAS b/Borland Turbo Pascal v55/ERROR.PAS new file mode 100644 index 0000000..e7f7f8f --- /dev/null +++ b/Borland Turbo Pascal v55/ERROR.PAS @@ -0,0 +1,22 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +unit Error; +{ Sample unit for CIRCULAR.PAS } + +interface + +procedure ShowError(Msg : string); + +implementation + +uses + Crt, Display; + +procedure ShowError(Msg : string); +begin + WriteXY(1, 25, 'Error: ' + Msg); +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/EXECDEMO.EXE b/Borland Turbo Pascal v55/EXECDEMO.EXE new file mode 100644 index 0000000000000000000000000000000000000000..6d915ba496d91f031908c84ac84c4800dfee4394 GIT binary patch literal 3040 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 Jj~Rh6{{dSjb>RR2 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/EXECDEMO.MAP b/Borland Turbo Pascal v55/EXECDEMO.MAP new file mode 100644 index 0000000..264ab33 --- /dev/null +++ b/Borland Turbo Pascal v55/EXECDEMO.MAP @@ -0,0 +1,71 @@ + + Start Stop Length Name Class + + 00000H 00151H 00152H EXECDEMO CODE + 00160H 0029EH 0013FH DOS CODE + 002A0H 00B0AH 0086BH SYSTEM CODE + 00B10H 00E1BH 0030CH DATA DATA + 00E20H 02E1FH 02000H STACK STACK + 02E20H 02E20H 00000H HEAP HEAP + + Address Publics by Value + + 0000:0048 @ + 0016:0000 SWAPVECTORS + 0016:0038 EXEC + 0016:00CC DOSEXITCODE + 0016:00D1 GETENV + 00B1:0002 OVRCODELIST + 00B1:0004 OVRHEAPSIZE + 00B1:0006 OVRDEBUGPTR + 00B1:000A OVRHEAPORG + 00B1:000C OVRHEAPPTR + 00B1:000E OVRHEAPEND + 00B1:0010 OVRLOADLIST + 00B1:0012 OVRDOSHANDLE + 00B1:0014 OVREMSHANDLE + 00B1:0016 HEAPORG + 00B1:001A HEAPPTR + 00B1:001E FREEPTR + 00B1:0022 FREEMIN + 00B1:0024 HEAPERROR + 00B1:0028 EXITPROC + 00B1:002C EXITCODE + 00B1:002E ERRORADDR + 00B1:0032 PREFIXSEG + 00B1:0034 STACKLIMIT + 00B1:0036 INOUTRES + 00B1:0038 RANDSEED + 00B1:003C FILEMODE + 00B1:003D TEST8087 + 00B1:003E COMMAND + 00B1:00BE DOSERROR + 00B1:00C4 INPUT + 00B1:01C4 OUTPUT + 00B1:02C4 SAVEINT00 + 00B1:02C8 SAVEINT02 + 00B1:02CC SAVEINT1B + 00B1:02D0 SAVEINT23 + 00B1:02D4 SAVEINT24 + 00B1:02D8 SAVEINT34 + 00B1:02DC SAVEINT35 + 00B1:02E0 SAVEINT36 + 00B1:02E4 SAVEINT37 + 00B1:02E8 SAVEINT38 + 00B1:02EC SAVEINT39 + 00B1:02F0 SAVEINT3A + 00B1:02F4 SAVEINT3B + 00B1:02F8 SAVEINT3C + 00B1:02FC SAVEINT3D + 00B1:0300 SAVEINT3E + 00B1:0304 SAVEINT3F + 00B1:0308 SAVEINT75 + +Line numbers for EXECDEMO(EXECDEMO.PAS) segment EXECDEMO + + 26 0000:0048 28 0000:0054 29 0000:0070 30 0000:008D + 32 0000:0097 33 0000:009C 34 0000:00D8 35 0000:0107 + 36 0000:010C 37 0000:0113 38 0000:012F 40 0000:013E + 41 0000:0148 + +Program entry point at 0000:0048 diff --git a/Borland Turbo Pascal v55/EXECDEMO.PAS b/Borland Turbo Pascal v55/EXECDEMO.PAS new file mode 100644 index 0000000..584a51c --- /dev/null +++ b/Borland Turbo Pascal v55/EXECDEMO.PAS @@ -0,0 +1,41 @@ +{ Turbo Exec } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program ExecDemo; + +(* + Demonstration program that shows how to use the Dos + unit's Exec procedure to execute DOS commands (including + running other programs or batch files). + + This program keeps prompting you for a DOS command until + you enter a blank line. + + When using Exec, make sure you specify a {$M} directive + so the heap leaves some memory available for the child + process. +*) + +{$M 8192,0,0} { Leave memory for child process } + +uses Dos; + +var + Command: string[127]; + +begin + repeat + Write('Enter DOS command: '); + ReadLn(Command); + if Command <> '' then + begin + SwapVectors; + WriteLn( 'comspec: ' + GetEnv('COMSPEC') ); + Exec(GetEnv('COMSPEC'), '/C ' + Command); + SwapVectors; + if DosError <> 0 then + WriteLn('Could not execute COMMAND.COM'); + WriteLn; + end; + until Command = ''; +end. diff --git a/Borland Turbo Pascal v55/FDEMO.PAS b/Borland Turbo Pascal v55/FDEMO.PAS new file mode 100644 index 0000000..6fa307f --- /dev/null +++ b/Borland Turbo Pascal v55/FDEMO.PAS @@ -0,0 +1,83 @@ + +{ Turbo Form } +{ Copyright (c) 1989 by Borland International, Inc. } + +program FDemo; +{ Turbo Pascal 5.5 object-oriented example. + Demonstrates use of the FORMS and SLIDERS units. + Refer to OOPDEMOS.DOC for an overview of this program. +} + +uses Crt, Forms, Sliders; + +type + + Person = record + Firstname: string[30]; + Lastname: string[30]; + Address: string[32]; + City: string[16]; + State: string[2]; + Zipcode: Longint; + Counter: array[1..3] of Longint; + Slider: array[1..2] of Integer; + end; + +const + + Frank: Person = ( + Firstname: 'Frank'; + Lastname: 'Borland'; + Address: '1800 Green Hills Road'; + City: 'Scotts Valley'; + State: 'CA'; + Zipcode: 95066; + Counter: (10, 1000, 65536); + Slider: (85, 25)); + +var + F: Form; + P: Person; + +begin + Color(BackColor); + ClrScr; + Color(ForeColor); + GotoXY(1, 1); ClrEol; + Write(' Turbo Pascal 5.5 Object Oriented Forms Editor'); + GotoXY(1, 25); ClrEol; + Write(' F2-Save Esc-Quit'); + F.Init(10, 5, 54, 16); + F.Add(New(FStrPtr, Init(3, 2, ' Firstname ', 30))); + F.Add(New(FStrPtr, Init(3, 3, ' Lastname ', 30))); + F.Add(New(FStrPtr, Init(3, 5, ' Address ', 32))); + F.Add(New(FStrPtr, Init(3, 6, ' City ', 16))); + F.Add(New(FStrPtr, Init(25, 6, ' State ', 2))); + F.Add(New(FZipPtr, Init(34, 6, ' Zip '))); + F.Add(New(FIntPtr, Init(3, 8, ' Counter 1 ', 0, 99999999))); + F.Add(New(FIntPtr, Init(22, 8, ' 2 ', 0, 99999999))); + F.Add(New(FIntPtr, Init(33, 8, ' 3 ', 0, 99999999))); + F.Add(New(FSliderPtr, Init(3, 10, ' Slider One ', 0, 100, 5))); + F.Add(New(FSliderPtr, Init(3, 11, ' Slider Two ', 0, 100, 5))); + P := Frank; + F.Put(P); + F.Show(True); + if F.Edit = CSave then F.Get(P); + F.Done; + NormVideo; + ClrScr; + WriteLn('Resulting Person record:'); + WriteLn; + with P do + begin + WriteLn('Firstname: ', Firstname); + WriteLn(' Lastname: ', Lastname); + WriteLn(' Address: ', Address); + WriteLn(' City: ', City); + WriteLn(' State: ', State); + WriteLn(' Zipcode: ', Zipcode); + WriteLn(' Counters: ', Counter[1], ' ', Counter[2], ' ', Counter[3]); + WriteLn(' Sliders: ', Slider[1], ' ', Slider[2]); + end; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/FIB8087.PAS b/Borland Turbo Pascal v55/FIB8087.PAS new file mode 100644 index 0000000..9448775 --- /dev/null +++ b/Borland Turbo Pascal v55/FIB8087.PAS @@ -0,0 +1,45 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +{$N+,E+} + +program Fib8087; +{ + Sample program from P-335 in the Owner's Handbook that + demonstrates how to avoid 8087 stack overflow in recursive + functions that use the 8087 math co-processor. Local variables + are used to store temporary results on the 8086 stack. +} + +var + i : integer; + +function Fib(N : integer) : extended; +{ calculate the fibonacci sequence for N } +var + F1, F2 : extended; +begin + if N = 0 then + Fib := 0.0 + else + if N = 1 then + Fib := 1.0 + else + begin + (* Use this line instead of the 3 lines that follow this + comment to cause an 8087 stack overflow for values of + N >= 8: + Fib := Fib(N - 1) + Fib(N - 2); { will cause overflow for N > 8 } + *) + + F1 := Fib(N - 1); { store results in temporaries on 8086 } + F2 := Fib(N - 2); { stack to avoid 8087 stack overflow } + Fib := F1 + F2; + end; +end; { Fib } + +begin + for i := 0 to 15 do + Writeln(i, '. ', Fib(i)); +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/FIGDEMO.PAS b/Borland Turbo Pascal v55/FIGDEMO.PAS new file mode 100644 index 0000000..4ad1521 --- /dev/null +++ b/Borland Turbo Pascal v55/FIGDEMO.PAS @@ -0,0 +1,94 @@ + +{ Copyright (c) 1989 by Borland Interational, Inc. } + +program FigureDemo; +{ From P-47 of the Object-Oriented Programming Guide. + Extending FIGURES.PAS with type Arc. +} + +uses Crt, DOS, Graph, Figures; + +type + Arc = object (Circle) + StartAngle, EndAngle : Integer; + constructor Init(InitX, InitY : Integer; + InitRadius : Integer; + InitStartAngle, InitEndAngle : Integer); + procedure Show; virtual; + procedure Hide; virtual; + end; + +var + GraphDriver : Integer; + GraphMode : Integer; + ErrorCode : Integer; + AnArc : Arc; + ACircle : Circle; + + +{--------------------------------------------------------} +{ Arc's method declarations: } +{--------------------------------------------------------} + +constructor Arc.Init(InitX,InitY : Integer; + InitRadius : Integer; + InitStartAngle, InitEndAngle : Integer); +begin + Circle.Init(InitX, InitY, InitRadius); + StartAngle := InitStartAngle; + EndAngle := InitEndAngle; +end; + +procedure Arc.Show; +begin + Visible := True; + Graph.Arc(X, Y, StartAngle, EndAngle, Radius); +end; + +procedure Arc.Hide; +var + TempColor : Word; +begin + TempColor := Graph.GetColor; + Graph.SetColor(GetBkColor); + Visible := False; + { Draw the arc in the background color to hide it } + Graph.Arc(X, Y, StartAngle, EndAngle, Radius); + SetColor(TempColor); +end; + + +{--------------------------------------------------------} +{ Main program: } +{--------------------------------------------------------} + +begin + GraphDriver := Detect; { Let the BGI determine what board + you're using } + DetectGraph(GraphDriver, GraphMode); + InitGraph(GraphDriver, GraphMode,''); + if GraphResult <> GrOK then + begin + WriteLn('>>Halted on graphics error:', + GraphErrorMsg(GraphDriver)); + Halt(1) + end; + +{ All descendents of type Point contain virtual methods and } +{ *must* be initialized before use through a constructor call. } + + ACircle.Init(151, 82, { Initial X,Y at 151,82 } + 50); { Initial radius of 50 pixels } + AnArc.Init(151, 82, { Initial X,Y at 151,82 } + 25, 0, 90); { Initial radius of 50 pixels } + { Start angle: 0; End angle: 90 } + +{ Replace AnArc with ACircle to drag a circle instead of an } +{ arc. Press Enter to stop dragging and end the program. } + + ACircle.Drag(5); { Parameter is # of pixels to drag by } + CloseGraph; + RestoreCRTMode; +end. + + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/FIGURES.PAS b/Borland Turbo Pascal v55/FIGURES.PAS new file mode 100644 index 0000000..9b825d4 --- /dev/null +++ b/Borland Turbo Pascal v55/FIGURES.PAS @@ -0,0 +1,201 @@ + +{ Turbo Figures } +{ Copyright (c) 1989 by Borland Interational, Inc. } + +unit Figures; +{ From P-42 of the Object-Oriented Programming Guide. + Virtual methods & polymorphic objects. +} + +interface + +uses Graph, Crt; + +type + Location = object + X,Y : Integer; + procedure Init(InitX, InitY : Integer); + function GetX : Integer; + function GetY : Integer; + end; + + PointPtr = ^Point; + + Point = object (Location) + Visible : Boolean; + constructor Init(InitX, InitY : Integer); + destructor Done; virtual; + procedure Show; virtual; + procedure Hide; virtual; + function IsVisible : Boolean; + procedure MoveTo(NewX, NewY : Integer); + procedure Drag(DragBy : Integer); virtual; + end; + + CirclePtr = ^Circle; + + Circle = object (Point) + Radius : Integer; + constructor Init(InitX, InitY : Integer; + InitRadius : Integer); + procedure Show; virtual; + procedure Hide; virtual; + procedure Expand(ExpandBy : Integer); virtual; + procedure Contract(ContractBy : Integer); virtual; + end; + +implementation + +{--------------------------------------------------------} +{ Location's method implementations: } +{--------------------------------------------------------} + +procedure Location.Init(InitX, InitY : Integer); + +begin + X := InitX; + Y := InitY; +end; + +function Location.GetX : Integer; +begin + GetX := X; +end; + +function Location.GetY : Integer; +begin + GetY := Y; +end; + + +{--------------------------------------------------------} +{ Points's method implementations: } +{--------------------------------------------------------} + +constructor Point.Init(InitX, InitY : Integer); +begin + Location.Init(InitX, InitY); + Visible := False; +end; + +destructor Point.Done; +begin + Hide; +end; + +procedure Point.Show; +begin + Visible := True; + PutPixel(X, Y, GetColor); +end; + +procedure Point.Hide; +begin + Visible := False; + PutPixel(X, Y, GetBkColor); +end; + +function Point.IsVisible : Boolean; +begin + IsVisible := Visible; +end; + +procedure Point.MoveTo(NewX, NewY : Integer); +begin + Hide; + X := NewX; + Y := NewY; + Show; +end; + +function GetDelta(var DeltaX : Integer; + var DeltaY : Integer) : Boolean; +var + KeyChar : Char; + Quit : Boolean; +begin + DeltaX := 0; DeltaY := 0; { 0 means no change in position; } + GetDelta := True; { True means we return a delta } + repeat + KeyChar := ReadKey; { First, read the keystroke } + Quit := True; { Assume it's a useable key } + case Ord(KeyChar) of + 0: begin { 0 means an extended, 2-byte code } + KeyChar := ReadKey; { Read second byte of code } + case Ord(KeyChar) of + 72: DeltaY := -1; { Up arrow; decrement Y } + 80: DeltaY := 1; { Down arrow; increment Y } + 75: DeltaX := -1; { Left arrow; decrement X } + 77: DeltaX := 1; { Right arrow; increment X } + else Quit := False; { Ignore any other code } + end; { case } + end; + 13: GetDelta := False; { CR pressed means no delta } + else Quit := False; { Ignore any other keystroke } + end; { case } + until Quit; +end; + +procedure Point.Drag(DragBy : Integer); +var + DeltaX, DeltaY : Integer; + FigureX, FigureY : Integer; +begin + Show; { Display figure to be dragged } + FigureX := GetX; { Get the initial position of figure } + FigureY := GetY; + + { This is the drag loop : } + while GetDelta(DeltaX, DeltaY) do + begin { Apply delta to figure X,Y: } + FigureX := FigureX + (DeltaX * DragBy); + FigureY := FigureY + (DeltaY * DragBy); + MoveTo(FigureX, FigureY); { And tell the figure to move } + end; +end; + +{--------------------------------------------------------} +{ Circle's method implementations: } +{--------------------------------------------------------} + +constructor Circle.Init(InitX, InitY : Integer; + InitRadius : Integer); +begin + Point.Init(InitX, InitY); + Radius := InitRadius; +end; + +procedure Circle.Show; +begin + Visible := True; + Graph.Circle(X, Y, Radius); +end; + +procedure Circle.Hide; +var + TempColor : Word; +begin + TempColor := Graph.GetColor; + Graph.SetColor(GetBkColor); + Visible := False; + Graph.Circle(X, Y, Radius); + Graph.SetColor(TempColor); +end; + +procedure Circle.Expand(ExpandBy : Integer); +begin + Hide; + Radius := Radius + ExpandBy; + if Radius <0 then Radius := 0; + Show; +end; + +procedure Circle.Contract(ContractBy : Integer); +begin + Expand(-ContractBy); +end; + +{ No initialization section } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/FONTS.PAS b/Borland Turbo Pascal v55/FONTS.PAS new file mode 100644 index 0000000..b76822e --- /dev/null +++ b/Borland Turbo Pascal v55/FONTS.PAS @@ -0,0 +1,31 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +unit Fonts; +{ Sample unit to accompany BGILINK.PAS. This unit links all the BGI graphics + fonts into a single TPU file. This makes it easy to incorporate the font + files directly into an .EXE file. See BGILINK.PAS for more information. +} +interface + +procedure GothicFontProc; +procedure SansSerifFontProc; +procedure SmallFontProc; +procedure TriplexFontProc; + +implementation + +procedure GothicFontProc; external; +{$L GOTH.OBJ } + +procedure SansSerifFontProc; external; +{$L SANS.OBJ } + +procedure SmallFontProc; external; +{$L LITT.OBJ } + +procedure TriplexFontProc; external; +{$L TRIP.OBJ } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/FORMS.PAS b/Borland Turbo Pascal v55/FORMS.PAS new file mode 100644 index 0000000..8c314ca --- /dev/null +++ b/Borland Turbo Pascal v55/FORMS.PAS @@ -0,0 +1,571 @@ + +{ Turbo Forms } +{ Copyright (c) 1989 by Borland International, Inc. } + +unit Forms; +{ Turbo Pascal 5.5 object-oriented example. + This unit defines field- and form-editing object types. + Refer to OOPDEMOS.DOC for an overview of this unit. +} + +{$S-} + +interface + +uses Objects; + +const + + CSkip = ^@; + CHome = ^A; + CRight = ^D; + CPrev = ^E; + CEnd = ^F; + CDel = ^G; + CBack = ^H; + CSave = ^J; + CEnter = ^M; + CUndo = ^R; + CLeft = ^S; + CIns = ^V; + CNext = ^X; + CClear = ^Y; + CEsc = ^[; + +type + + FStringPtr = ^FString; + FString = string[79]; + + FieldPtr = ^Field; + Field = object(Node) + X, Y, Size: Integer; + Title: FStringPtr; + Value: Pointer; + Extra: record end; + constructor Init(PX, PY, PSize: Integer; PTitle: FString); + constructor Load(var S: Stream); + destructor Done; virtual; + procedure Clear; virtual; + function Edit: Char; virtual; + procedure Show; virtual; + procedure Store(var S: Stream); + end; + + FTextPtr = ^FText; + FText = object(Field) + Len: Integer; + constructor Init(PX, PY, PSize: Integer; PTitle: FString; + PLen: Integer); + function Edit: Char; virtual; + procedure GetStr(var S: FString); virtual; + function PutStr(var S: FString): Boolean; virtual; + procedure Show; virtual; + end; + + FStrPtr = ^FStr; + FStr = object(FText) + constructor Init(PX, PY: Integer; PTitle: FString; PLen: Integer); + procedure GetStr(var S: FString); virtual; + function PutStr(var S: FString): Boolean; virtual; + end; + + FNumPtr = ^FNum; + FNum = object(FText) + procedure Show; virtual; + end; + + FIntPtr = ^FInt; + FInt = object(FNum) + Min, Max: Longint; + constructor Init(PX, PY: Integer; PTitle: FString; + PMin, PMax: Longint); + procedure GetStr(var S: FString); virtual; + function PutStr(var S: FString): Boolean; virtual; + end; + + FZipPtr = ^FZip; + FZip = object(FInt) + constructor Init(PX, PY: Integer; PTitle: FString); + procedure GetStr(var S: FString); virtual; + function PutStr(var S: FString): Boolean; virtual; + end; + + FRealPtr = ^FReal; + FReal = object(FNum) + Decimals: Integer; + constructor Init(PX, PY: Integer; PTitle: FString; + PLen, PDecimals: Integer); + procedure GetStr(var S: FString); virtual; + function PutStr(var S: FString): Boolean; virtual; + end; + + FormPtr = ^Form; + Form = object(Base) + X1, Y1, X2, Y2, Size: Integer; + Fields: List; + constructor Init(PX1, PY1, PX2, PY2: Integer); + constructor Load(var S: Stream); + destructor Done; virtual; + function Edit: Char; + procedure Show(Erase: Boolean); + procedure Add(P: FieldPtr); + procedure Clear; + procedure Get(var FormBuf); + procedure Put(var FormBuf); + procedure Store(var S: Stream); + end; + + FStream = object(BufStream) + procedure RegisterTypes; virtual; + end; + + ColorIndex = (BackColor, ForeColor, TitleColor, ValueColor); + +procedure Beep; +procedure Color(C: ColorIndex); +function ReadChar: Char; + +implementation + +uses Crt; + +type + Bytes = array[0..32767] of Byte; + +{ Field } + +constructor Field.Init(PX, PY, PSize: Integer; PTitle: FString); +begin + X := PX; + Y := PY; + Size := PSize; + GetMem(Title, Length(PTitle) + 1); + Title^ := PTitle; + GetMem(Value, Size); +end; + +constructor Field.Load(var S: Stream); +var + L: Byte; +begin + S.Read(X, SizeOf(Integer) * 3); + S.Read(L, SizeOf(Byte)); + GetMem(Title, L + 1); + Title^[0] := Chr(L); + S.Read(Title^[1], L); + GetMem(Value, Size); + S.Read(Extra, SizeOf(Self) - SizeOf(Field)); +end; + +destructor Field.Done; +begin + FreeMem(Value, Size); + FreeMem(Title, Length(Title^) + 1); +end; + +procedure Field.Clear; +begin + FillChar(Value^, Size, 0); +end; + +function Field.Edit: Char; +begin + Abstract; +end; + +procedure Field.Show; +begin + Abstract; +end; + +procedure Field.Store(var S: Stream); +begin + S.Write(X, SizeOf(Integer) * 3); + S.Write(Title^, Length(Title^) + 1); + S.Write(Extra, SizeOf(Self) - SizeOf(Field)); +end; + +{ FText } + +constructor FText.Init(PX, PY, PSize: Integer; PTitle: FString; + PLen: Integer); +begin + Field.Init(PX, PY, PSize, PTitle); + Len := PLen; +end; + +function FText.Edit: Char; +var + P: Integer; + Ch: Char; + Start, Stop: Boolean; + S: FString; +begin + P := 0; + Start := True; + Stop := False; + GetStr(S); + repeat + GotoXY(X, Y); + Color(TitleColor); + Write(Title^); + Color(ValueColor); + Write(S, '': Len - Length(S)); + GotoXY(X + Length(Title^) + P, Y); + Ch := ReadChar; + case Ch of + #32..#255: + begin + if Start then S := ''; + if Length(S) < Len then + begin + Inc(P); + Insert(Ch, S, P); + end; + end; + CLeft: if P > 0 then Dec(P); + CRight: if P < Length(S) then Inc(P) else; + CHome: P := 0; + CEnd: P := Length(S); + CDel: Delete(S, P + 1, 1); + CBack: + if P > 0 then + begin + Delete(S, P, 1); + Dec(P); + end; + CClear: + begin + S := ''; + P := 0; + end; + CUndo: + begin + GetStr(S); + P := 0; + end; + CEnter, CNext, CPrev, CSave: + if PutStr(S) then + begin + Show; + Stop := True; + end else + begin + Beep; + P := 0; + end; + CEsc: Stop := True; + else + Beep; + end; + Start := False; + until Stop; + Edit := Ch; +end; + +procedure FText.GetStr(var S: FString); +begin + Abstract; +end; + +function FText.PutStr(var S: FString): Boolean; +begin + Abstract; +end; + +procedure FText.Show; +var + S: FString; +begin + GetStr(S); + GotoXY(X, Y); + Color(TitleColor); + Write(Title^); + Color(ValueColor); + Write(S, '': Len - Length(S)); +end; + +{ FStr } + +constructor FStr.Init(PX, PY: Integer; PTitle: FString; PLen: Integer); +begin + FText.Init(PX, PY, PLen + 1, PTitle, PLen); +end; + +procedure FStr.GetStr(var S: FString); +begin + S := FString(Value^); +end; + +function FStr.PutStr(var S: FString): Boolean; +begin + FString(Value^) := S; + PutStr := True; +end; + +{ FNum } + +procedure FNum.Show; +var + S: FString; +begin + GetStr(S); + GotoXY(X, Y); + Color(TitleColor); + Write(Title^); + Color(ValueColor); + Write(S: Len); +end; + +{ FInt } + +constructor FInt.Init(PX, PY: Integer; PTitle: FString; + PMin, PMax: Longint); +var + L: Integer; + S: string[15]; +begin + Str(PMin, S); L := Length(S); + Str(PMax, S); if L < Length(S) then L := Length(S); + FNum.Init(PX, PY, SizeOf(Longint), PTitle, L); + Min := PMin; + Max := PMax; +end; + +procedure FInt.GetStr(var S: FString); +begin + Str(Longint(Value^), S); +end; + +function FInt.PutStr(var S: FString): Boolean; +var + N: Longint; + E: Integer; +begin + Val(S, N, E); + if (E = 0) and (N >= Min) and (N <= Max) then + begin + Longint(Value^) := N; + PutStr := True; + end else PutStr := False; +end; + +{ FZip } + +constructor FZip.Init(PX, PY: Integer; PTitle: FString); +begin + FInt.Init(PX, PY, PTitle, 0, 99999); +end; + +procedure FZip.GetStr(var S: FString); +begin + FInt.GetStr(S); + Insert(Copy('0000', 1, 5 - Length(S)), S, 1); +end; + +function FZip.PutStr(var S: FString): Boolean; +begin + PutStr := (Length(S) = 5) and FInt.PutStr(S); +end; + +{ FReal } + +constructor FReal.Init(PX, PY: Integer; PTitle: FString; + PLen, PDecimals: Integer); +begin + FNum.Init(PX, PY, SizeOf(Real), PTitle, PLen); + Decimals := PDecimals; +end; + +procedure FReal.GetStr(var S: FString); +begin + Str(Real(Value^): 0: Decimals, S); +end; + +function FReal.PutStr(var S: FString): Boolean; +var + R: Real; + E: Integer; + T: FString; +begin + Val(S, R, E); + PutStr := False; + if E = 0 then + begin + Str(R: 0: Decimals, T); + if Length(T) <= Len then + begin + Real(Value^) := R; + PutStr := True; + end; + end; +end; + +{ Form } + +constructor Form.Init(PX1, PY1, PX2, PY2: Integer); +begin + X1 := PX1; + Y1 := PY1; + X2 := PX2; + Y2 := PY2; + Size := 0; + Fields.Clear; +end; + +constructor Form.Load(var S: Stream); +begin + S.Read(X1, SizeOf(Integer) * 5); + Fields.Load(S); +end; + +destructor Form.Done; +begin + Fields.Delete; +end; + +function Form.Edit: Char; +var + P: FieldPtr; + Ch: Char; +begin + Window(X1, Y1, X2, Y2); + P := FieldPtr(Fields.First); + repeat + Ch := P^.Edit; + case Ch of + CEnter, CNext: P := FieldPtr(P^.Next); + CPrev: P := FieldPtr(P^.Prev); + end; + until (Ch = CSave) or (Ch = CEsc); + Edit := Ch; + Window(1, 1, 80, 25); +end; + +procedure Form.Show(Erase: Boolean); +var + P: FieldPtr; +begin + Window(X1, Y1, X2, Y2); + if Erase then + begin + Color(ForeColor); + ClrScr; + end; + P := FieldPtr(Fields.First); + while P <> nil do + begin + P^.Show; + P := FieldPtr(Fields.Next(P)); + end; + Window(1, 1, 80, 25); +end; + +procedure Form.Add(P: FieldPtr); +begin + Inc(Size, P^.Size); + Fields.Append(P); +end; + +procedure Form.Clear; +var + P: FieldPtr; +begin + P := FieldPtr(Fields.First); + while P <> nil do + begin + P^.Clear; + P := FieldPtr(Fields.Next(P)); + end; +end; + +procedure Form.Get(var FormBuf); +var + I: Integer; + P: FieldPtr; +begin + I := 0; + P := FieldPtr(Fields.First); + while P <> nil do + begin + Move(P^.Value^, Bytes(FormBuf)[I], P^.Size); + Inc(I, P^.Size); + P := FieldPtr(Fields.Next(P)); + end; +end; + +procedure Form.Put(var FormBuf); +var + I: Integer; + P: FieldPtr; +begin + I := 0; + P := FieldPtr(Fields.First); + while P <> nil do + begin + Move(Bytes(FormBuf)[I], P^.Value^, P^.Size); + Inc(I, P^.Size); + P := FieldPtr(Fields.Next(P)); + end; +end; + +procedure Form.Store(var S: Stream); +begin + S.Write(X1, SizeOf(Integer) * 5); + Fields.Store(S); +end; + +{ FStream } + +procedure FStream.RegisterTypes; +begin + BufStream.RegisterTypes; + Register(TypeOf(FStr), @FStr.Store, @FStr.Load); + Register(TypeOf(FInt), @FInt.Store, @FInt.Load); + Register(TypeOf(FZip), @FZip.Store, @FZip.Load); + Register(TypeOf(FReal), @FReal.Store, @FReal.Load); +end; + +{ Global routines } + +procedure Beep; +begin + Sound(500); Delay(25); NoSound; +end; + +procedure Color(C: ColorIndex); +type + Palette = array[ColorIndex] of Byte; +const + CP: Palette = ($17, $70, $30, $5E); + MP: Palette = ($07, $70, $70, $07); +begin + if LastMode = CO80 then TextAttr := CP[C] else TextAttr := MP[C]; +end; + +function ReadChar: Char; +var + Ch: Char; +begin + Ch := ReadKey; + case Ch of + #0: + case ReadKey of + #15, #72: Ch := CPrev; { Shift-Tab, Up } + #60: Ch := CSave; { F2 } + #71: Ch := CHome; { Home } + #75: Ch := CLeft; { Left } + #77: Ch := CRight; { Right } + #79: Ch := CEnd; { End } + #80: Ch := CNext; { Down } + #82: Ch := CIns; { Ins } + #83: Ch := CDel; { Del } + end; + #9: Ch := CNext; { Tab } + end; + ReadChar := Ch; +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/GOTH.CHR b/Borland Turbo Pascal v55/GOTH.CHR new file mode 100644 index 0000000000000000000000000000000000000000..714a17ae0f3514e78a30dc4c3071aad49dd8c5ea GIT binary patch literal 8560 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�n<{n|(a>C-zt$ zsbjHbYvi)`r{+Dih9{l($ip#wh&$dhYjq+{*gEg?qo|$j^d@%L<43U*$j?tk3&z*O zK4OUfqnP2!+8y~L+m8wqf>vb1(Ottm&3M2mNA|L?Cj?#Sz6dDJXeBuC$0s7H+|iK>zgu8v^k`Ew+*F$e+Q<{a7}@_c`RLTEYISUDG<=gxK(bOO z3g}|Ga4&#zc*pLsY77XmmKLKjpxeX|%{`XAE+~g*e(&Qf%)P)S6QLp=#kE(I7;%F| z;4eG+n@qgmX6LMa3XQBsAV0%ipVf4-$x5WgQNI^JDu2LH7r+)1__t?SDz@?|K+hFh z`P76RJ&nRoUQsZ+T zq9ZtG+G-p(V1Jl#*Bldh95e@d$0~~sjgEkRIQ0%TksRwN#$aHGKEDmWCZDu`+4U9_ z5tJ-Pm*6KZp!x_xGV8JhOs;dTnPnEsyP28ooN+d+f_Xl-dd4O4y66t*{gDinl!T?8WCVe|mFo zejhaVW&|Fo?MKC!pc8yEsUs{i9FsJ>#MxjistK~jSN$m-MIQ;T)#VzN$Khicvfo2T zU|jHz6PvRYGxRAysTawQ^Nign;6jl!P83l(5e>10vdJX8dmM!kzN56=2|8Eb3z+#L zd;0`$_qaae?X!Kpgtx;4Cs!lpr8gk|j7=SSR*41yg9qAo1*mJ=nLqG5HE@EEr8`dN z9hW!x`|LjL;Os-F3a}B%%MDNp`chHJLgJj4Se#Ty7}L-T>>)eh#|)hW!pU%wdrEOK z$&ckxKAlt-&$i)HNeerIO9@}Xs~wzn|46QJ+Pzi}GA3}~`qXJR8L(4HGXXv_$U0p=@vx;@AyX__?2lj3bf4CwruA7~v232|MOP*z*EsuvDCi d2Yk(r$x)C0DX&clP23njiBzP-IbM_B^FPOjWTOB8 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/GRAPH.TPU b/Borland Turbo Pascal v55/GRAPH.TPU new file mode 100644 index 0000000000000000000000000000000000000000..bc1df0c62ccc6d66d1478f6b81e3f6daf53de3e6 GIT binary patch literal 31584 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/GREP.COM b/Borland Turbo Pascal v55/GREP.COM new file mode 100644 index 0000000000000000000000000000000000000000..a970d7c4f510c288f0221f2f46cb2d9151fc9380 GIT binary patch literal 7029 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/HERC.BGI b/Borland Turbo Pascal v55/HERC.BGI new file mode 100644 index 0000000000000000000000000000000000000000..617a8cce51a0ebdb5b7979dc0f522595827c04fd GIT binary patch literal 6125 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 Bwg&(J literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/HILB.PAS b/Borland Turbo Pascal v55/HILB.PAS new file mode 100644 index 0000000..56cb580 --- /dev/null +++ b/Borland Turbo Pascal v55/HILB.PAS @@ -0,0 +1,246 @@ +{$N-} +program Hilb; +{ + + The program performs simultaneous solution by Gauss-Jordan + elimination. + + -------------------------------------------------- + From: Pascal Programs for Scientists and Engineers + + Alan R. Miller, Sybex + n x n inverse hilbert matrix + solution is 1 1 1 1 1 + double precision version + -------------------------------------------------- + + INSTRUCTIONS + 1. Compile and run the program using the $N- (Numeric Processing : + Software) compiler directive. + 2. if you have a math coprocessor in your computer, compile and run the + program using the $N+ (Numeric Processing : Hardware) compiler + directive. Compare the speed and precision of the results to those + of example 1. +} + +const + maxr = 10; + maxc = 10; + +type +{$IFOPT N+} { use extended type if using 80x87 } + real = extended; +{$ENDIF} + ary = array[1..maxr] of real; + arys = array[1..maxc] of real; + ary2s = array[1..maxr, 1..maxc] of real; + +var + y : arys; + coef : arys; + a, b : ary2s; + n, m, i, j : integer; + error : boolean; + +procedure gaussj + (var b : ary2s; (* square matrix of coefficients *) + y : arys; (* constant vector *) + var coef : arys; (* solution vector *) + ncol : integer; (* order of matrix *) + var error: boolean); (* true if matrix singular *) + +(* Gauss Jordan matrix inversion and solution *) +(* Adapted from McCormick *) +(* Feb 8, 81 *) +(* B(N,N) coefficient matrix, becomes inverse *) +(* Y(N) original constant vector *) +(* W(N,M) constant vector(s) become solution vector *) +(* DETERM is the determinant *) +(* ERROR = 1 if singular *) +(* INDEX(N,3) *) +(* NV is number of constant vectors *) + +var + w : array[1..maxc, 1..maxc] of real; + index: array[1..maxc, 1..3] of integer; + i, j, k, l, nv, irow, icol, n, l1 : integer; + determ, pivot, hold, sum, t, ab, big: real; + +procedure swap(var a, b: real); + +var + hold: real; + +begin (* swap *) + hold := a; + a := b; + b := hold +end (* procedure swap *); + + +begin (* Gauss-Jordan main program *) + error := false; + nv := 1 (* single constant vector *); + n := ncol; + for i := 1 to n do + begin + w[i, 1] := y[i] (* copy constant vector *); + index[i, 3] := 0 + end; + determ := 1.0; + for i := 1 to n do + begin + (* search for largest element *) + big := 0.0; + for j := 1 to n do + begin + if index[j, 3] <> 1 then + begin + for k := 1 to n do + begin + if index[k, 3] > 1 then + begin + writeln(' ERROR: matrix singular'); + error := true; + exit; (* abort *) + end; + if index[k, 3] < 1 then + if abs(b[j, k]) > big then + begin + irow := j; + icol := k; + big := abs(b[j, k]) + end + end (* k loop *) + end + end (* j loop *); + index[icol, 3] := index[icol, 3] + 1; + index[i, 1] := irow; + index[i, 2] := icol; + + (* interchange rows to put pivot on diagonal *) + if irow <> icol then + begin + determ := - determ; + for l := 1 to n do + swap(b[irow, l], b[icol, l]); + if nv > 0 then + for l := 1 to nv do + swap(w[irow, l], w[icol, l]) + end; (* if irow <> icol *) + + (* divide pivot row by pivot column *) + pivot := b[icol, icol]; + determ := determ * pivot; + b[icol, icol] := 1.0; + for l := 1 to n do + b[icol, l] := b[icol, l] / pivot; + if nv > 0 then + for l := 1 to nv do + w[icol, l] := w[icol, l] / pivot; + (* reduce nonpivot rows *) + for l1 := 1 to n do + begin + if l1 <> icol then + begin + t := b[l1, icol]; + b[l1, icol] := 0.0; + for l := 1 to n do + b[l1, l] := b[l1, l] - b[icol, l] * t; + if nv > 0 then + for l := 1 to nv do + w[l1, l] := w[l1, l] - w[icol, l] * t; + end (* if l1 <> icol *) + end + end (* i loop *); + + if error then exit; + (* interchange columns *) + for i := 1 to n do + begin + l := n - i + 1; + if index[l, 1] <> index[l, 2] then + begin + irow := index[l, 1]; + icol := index[l, 2]; + for k := 1 to n do + swap(b[k, irow], b[k, icol]) + end (* if index *) + end (* i loop *); + for k := 1 to n do + if index[k, 3] <> 1 then + begin + writeln(' ERROR: matrix singular'); + error := true; + exit; (* abort *) + end; + for i := 1 to n do + coef[i] := w[i, 1]; +end (* procedure gaussj *); + + +procedure get_data(var a : ary2s; + var y : arys; + var n, m : integer); + +(* setup n-by-n hilbert matrix *) + +var + i, j : integer; + +begin + for i := 1 to n do + begin + a[n,i] := 1.0/(n + i - 1); + a[i,n] := a[n,i] + end; + a[n,n] := 1.0/(2*n -1); + for i := 1 to n do + begin + y[i] := 0.0; + for j := 1 to n do + y[i] := y[i] + a[i,j] + end; + writeln; + if n < 7 then + begin + for i:= 1 to n do + begin + for j:= 1 to m do + write( a[i,j] :7:5, ' '); + writeln( ' : ', y[i] :7:5) + end; + writeln + end (* if n<7 *) +end (* procedure get_data *); + +procedure write_data; + +(* print out the answers *) + +var + i : integer; + +begin + for i := 1 to m do + write( coef[i] :13:9); + writeln; +end (* write_data *); + + +begin (* main program *) + a[1,1] := 1.0; + n := 2; + m := n; + repeat + get_data (a, y, n, m); + for i := 1 to n do + for j := 1 to n do + b[i,j] := a[i,j] (* setup work array *); + gaussj (b, y, coef, n, error); + if not error then write_data; + n := n+1; + m := n + until n > maxr; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/IBM8514.BGI b/Borland Turbo Pascal v55/IBM8514.BGI new file mode 100644 index 0000000000000000000000000000000000000000..5e0933e5cc064d9daa5640ad3057ca1133bbc380 GIT binary patch literal 6665 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 nil do + begin + N := Nodes; + Nodes := N^.Next; + Dispose(N^.Item, Done); + Dispose(N); + end; +end; + + +procedure List.Add(Item : PointPtr); +var + N : NodePtr; +begin + New(N); + N^.Item := Item; + N^.Next := Nodes; + Nodes := N; +end; + +procedure List.Report; +var + Current : NodePtr; +begin + Current := Nodes; + while Current <> nil do + begin + Str(Current^.Item^.GetX : 3, Temp); + OutTextLn('X = '+Temp); + Str(Current^.Item^.GetY : 3, Temp); + OutTextLn('Y = '+Temp); + Current := Current^.Next; + end; +end; + + +{--------------------------------------------------------} +{ Main program: } +{--------------------------------------------------------} + +begin + { Let the BGI determine what board you're using: } + DetectGraph(GraphDriver, GraphMode); + InitGraph(GraphDriver, GraphMode,''); + if GraphResult <> GrOK then + begin + WriteLn('>>Halted on graphics error: ', + GraphErrorMsg(GraphDriver)); + Halt(1); + end; + + HeapStatus('Heap space before list is allocated: '); + + { Create a list } + AList.Init; + + { Now create and add several figures to it in one operation } + AList.Add(New(ArcPtr, Init(151, 82, 25, 200, 330))); + AList.Add(New(CirclePtr, Init(400, 100, 40))); + AList.Add(New(CirclePtr, Init(305, 136, 5))); + + { Traverse the list and display X,Y of the list's figures } + AList.Report; + + HeapStatus('Heap space after list is allocated '); + + { Deallocate the whole list with one destructor call } + AList.Done; + + HeapStatus('Heap space after list is cleaned up: '); + + OutText('Press Enter to end program: '); + Readln; + + CloseGraph; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/LISTER.PAS b/Borland Turbo Pascal v55/LISTER.PAS new file mode 100644 index 0000000..7310ad5 --- /dev/null +++ b/Borland Turbo Pascal v55/LISTER.PAS @@ -0,0 +1,212 @@ + +{ Turbo List } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program SourceLister; +{ + SOURCE LISTER DEMONSTRATION PROGRAM + + This is a simple program to list your TURBO PASCAL source programs. + + PSEUDO CODE + 1. Find Pascal source file to be listed + 2. Initialize program variables + 3. Open main source file + 4. Process the file + a. Read a character into line buffer until linebuffer full or eoln; + b. Search line buffer for include file. + c. If line contains include file command: + Then process include file and extract command from line buffer + Else print out the line buffer. + d. Repeat step 4.a thru 4.c until eof(main file); + + INSTRUCTIONS + 1. Compile and run the program: + a. In the Development Environment load LISTER.PAS and + press ALT-R. + b. From the command line type TPC LISTER.PAS /R + 2. Specify the file to print. +} + +uses + Printer; + +const + PageWidth = 80; + PrintLength = 55; + PathLength = 65; + FormFeed = #12; + VerticalTabLength = 3; + +type + WorkString = string[126]; + FileName = string[PathLength]; + +var + CurRow : integer; + MainFileName: FileName; + MainFile: text; + search1, + search2, + search3, + search4: string[5]; + + procedure Initialize; + begin + CurRow := 0; + search1 := '{$'+'I'; { different forms that the include compiler } + search2 := '{$'+'i'; { directive can take. } + search3 := '(*$'+'I'; + search4 := '(*$'+'i'; + end {initialize}; + + function Open(var fp:text; name: Filename): boolean; + begin + Assign(fp,Name); + {$I-} + Reset(fp); + {$I+} + Open := IOResult = 0; + end { Open }; + + procedure OpenMain; + begin + if ParamCount = 0 then + begin + Write('Enter filename: '); + Readln(MainFileName); + end + else + MainFileName := ParamStr(1); + + if (MainFileName = '') or not Open(MainFile,MainFileName) then + begin + Writeln('ERROR: file not found (', MainFileName, ')'); + Halt(1); + end; + end {Open Main}; + + procedure VerticalTab; + var i: integer; + begin + for i := 1 to VerticalTabLength do Writeln(LST); + end {vertical tab}; + + procedure ProcessLine(PrintStr: WorkString); + begin + CurRow := Succ(CurRow); + if Length(PrintStr) > PageWidth then Inc(CurRow); + if CurRow > PrintLength then + begin + Write(LST,FormFeed); + VerticalTab; + CurRow := 1; + end; + Writeln(LST,PrintStr); + end {Process line}; + + procedure ProcessFile; + { This procedure displays the contents of the Turbo Pascal program on the } + { printer. It recursively processes include files if they are nested. } + + var + LineBuffer: WorkString; + + function IncludeIn(var CurStr: WorkString): boolean; + var + ChkChar: char; + column: integer; + begin + ChkChar := '-'; + column := Pos(search1,CurStr); + if column <> 0 then + chkchar := CurStr[column+3] + else + begin + column := Pos(search3,CurStr); + if column <> 0 then + chkchar := CurStr[column+4] + else + begin + column := Pos(search2,CurStr); + if column <> 0 then + chkchar := CurStr[column+3] + else + begin + column := Pos(search4,CurStr); + if column <> 0 then + chkchar := CurStr[column+4] + end; + end; + end; + if ChkChar in ['+','-'] then IncludeIn := False + else IncludeIn := True; + end { IncludeIn }; + + procedure ProcessIncludeFile(var IncStr: WorkString); + + var NameStart, NameEnd: integer; + IncludeFile: text; + IncludeFileName: Filename; + + Function Parse(IncStr: WorkString): WorkString; + begin + NameStart := Pos('$I',IncStr)+2; + while IncStr[NameStart] = ' ' do + NameStart := Succ(NameStart); + NameEnd := NameStart; + while (not (IncStr[NameEnd] in [' ','}','*'])) + and ((NameEnd - NameStart) <= PathLength) do + Inc(NameEnd); + Dec(NameEnd); + Parse := Copy(IncStr,NameStart,(NameEnd-NameStart+1)); + end {Parse}; + + begin {Process include file} + IncludeFileName := Parse(IncStr); + + if not Open(IncludeFile,IncludeFileName) then + begin + LineBuffer := 'ERROR: include file not found (' + + IncludeFileName + ')'; + ProcessLine(LineBuffer); + end + else + begin + while not EOF(IncludeFile) do + begin + Readln(IncludeFile,LineBuffer); + { Turbo Pascal 5.5 allows nested include files so we must + check for them and do a recursive call if necessary } + if IncludeIn(LineBuffer) then + ProcessIncludeFile(LineBuffer) + else + ProcessLine(LineBuffer); + end; + Close(IncludeFile); + end; + end {Process include file}; + + begin {Process File} + VerticalTab; + Writeln('Printing . . . '); + while not EOF(mainfile) do + begin + Readln(MainFile,LineBuffer); + if IncludeIn(LineBuffer) then + ProcessIncludeFile(LineBuffer) + else + ProcessLine(LineBuffer); + end; + Close(MainFile); + Write(LST,FormFeed); { move the printer to the beginning of the next } + { page } + end {Process File}; + + +begin + Initialize; { initialize some global variables } + OpenMain; { open the file to print } + ProcessFile; { print the program } +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/LITT.CHR b/Borland Turbo Pascal v55/LITT.CHR new file mode 100644 index 0000000000000000000000000000000000000000..35b434a84b5a1351b2f0ab6cc34dc64f83c73c34 GIT binary patch literal 2138 zcmaJ>y>A>v6rY{1M3#c0R2HIGQJ@e&a$JDZP?$)_5CsGl1w~{N0*Q3oMb;I8;{0aj z?YgrfN<@JuQc$KqDG+4}%2ZK``~eiMC{Tp%_`R8(i%lffC-3Z=_wjqb_wn(Er%!Lb zztw*F&F*N_el;0S+xD}IYisRW?Zr#&N7tv5FK+DNxbe=JmG>sMzumj__04H}{`%`# z)^1MrM!VxL+pY2R#@={$dTTP?9i3TGFO#~mwY~l1RHGX8f6p5`O0{c^@@hV)S#?&u zqSnL;JJ+)jqV3?UB`P)m?D!x~uM*8@cH2x_j<{`@=nPM^5>d{Hnj;H~dxqxxel2 z_(T7L_r`fV*5w!e<+q4Lvivx4lv_OR`E^mP+QZvfDD_~86cK4UNOHE+M<2PvIjGPl zpNMQ?X3`w9b`vNO2aYKP9H@g<&mF9&+;=^BItT}$r=AsuE_6_nJ60(~3WQ&*wy{rL z;w0{33T#pgCMMAir^JwPii#p3yr3c#V}!eWb{weTjtr;R#4g8|vx^~n*pCQ=2j*cB z_Gw-<@>@~9BPxEGv(%M*7yvWU;#CRm&?Bc#v{@0LahI~>gdN24NID5=RX?JWRO$)I z%9%ak9FaMGL#!f?9S8>I$}(kr@(h**(#dGYV=P%Uso2z74LDJ@Av)P0L8X3;@Pj90 z7L1fO-xT>GAk%V}6v1tdj$R-;@TF3!)fkv#R0w>DX41k##1C0k6o^;)0iB1cf-GWS z$(}tO%Ns}hA;Zix<=E^B=ar!oR){cY6?Vmbh&Aw?C1UemKj@kz0;v($E=>D~8Vf@) z_X*=W^|g;{bc)=A+rgs7M1Fk)P0MU?;+#eD(n&Q3VJ3TmzRZ#|59MiNbocRmqh?B& zsTZ~7Mx@KUP{rfDkuA_eu^;BtFQb>(o}vs{!G{UPXGM$NBk)(V>mq6iPo{dRommiI zTA^B|l~LgwSxG`epO}aYvvi*q`R#^@w|N@!+=V#on`K9U6#*nUqI*%1`~U6uN>i&eEJ0jIKZKQSv8vD|l)K*Z@EfJpRi5nT2^=04RE* z=wPNbP-=_>aAH>hm+ZkjTi`<0CcsEb*KUFI`BzYR>TzH3WIwY(2jEK;c=iHfiz{qZ z8MG2xJYkzg$)m6moZ!bw;s9~RWDASKEL(IyvCi_mq+y)>S(c9Ap$n?rBF*ER)lvud tr3(@`0o!0TULmaG literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/MAKE.EXE b/Borland Turbo Pascal v55/MAKE.EXE new file mode 100644 index 0000000000000000000000000000000000000000..1d1f760038895e82088f068c15f95b7d0642d1a0 GIT binary patch literal 27174 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 Bv*Z8( literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/OBJECTS.INC b/Borland Turbo Pascal v55/OBJECTS.INC new file mode 100644 index 0000000..b345571 --- /dev/null +++ b/Borland Turbo Pascal v55/OBJECTS.INC @@ -0,0 +1,95 @@ +; Turbo Pascal 5.5 object-oriented example +; Assembler include file for OBJECTS.PAS unit +; Copyright (c) 1989 by Borland International, Inc. + +; ******************************************************* +; * * +; * EQUATES AND MACROS * +; * * +; ******************************************************* + + LOCALS @@ + +; Object definition macro + +OBJECT MACRO Name,Parent + FIELD MACRO FName,FType,FCount + &Name&@&&FName EQU (FType PTR &Name&@) + &Name&@ = &Name&@ + FType * FCount + ENDM + METHOD MACRO MName + IFE &Name&$ + &Name&@VMT EQU (WORD PTR &Name&@) + &Name&@ = &Name&@ + WORD + &Name&$ = 4 + ENDIF + &Name&$&&MName EQU (DWORD PTR &Name&$) + &Name&$ = &Name&$ + DWORD + ENDM + IFNB + &Name&@ = &Parent&@ + &Name&$ = &Parent&$ + ELSE + &Name&@ = 0 + &Name&$ = 0 + ENDIF +ENDM + +; 4-Byte record + +ByteRec STRUC +b0 DB ? +b1 DB ? +b2 DB ? +b3 DB ? +ByteRec ENDS + +; 4-Word record + +WordRec STRUC +w0 DW ? +w2 DW ? +w4 DW ? +w6 DW ? +WordRec ENDS + +; Base object type + +OBJECT Base + METHOD Done + +; SProc object type + +OBJECT SProc + FIELD StoreProc,DWORD,1 + FIELD LoadProc,DWORD,1 + +; Stream object type + +OBJECT Stream,Base + FIELD TypeCount,WORD,1 + FIELD TypeList,DWORD,1 + FIELD ProcList,DWORD,1 + FIELD Status,WORD,1 + METHOD Error + METHOD Flush + METHOD GetPos + METHOD Read + METHOD RegisterTypes + METHOD SetPos + METHOD Truncate + METHOD Write + +; DosStream object type + +OBJECT DosStream,Stream + FIELD Handle,WORD,1 + +; BufStream object type + +OBJECT BufStream,DosStream + FIELD Buffer,DWORD,1 + FIELD BufSize,WORD,1 + FIELD BufPtr,WORD,1 + FIELD BufEnd,WORD,1 + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/OBJECTS.PAS b/Borland Turbo Pascal v55/OBJECTS.PAS new file mode 100644 index 0000000..34dfdcd --- /dev/null +++ b/Borland Turbo Pascal v55/OBJECTS.PAS @@ -0,0 +1,459 @@ + +{ Turbo Objects } +{ Copyright (c) 1989 by Borland International, Inc. } + +unit Objects; +{ Turbo Pascal 5.5 object-oriented example. + This unit defines some basic object types. + Refer to OOPDEMOS.DOC for an overview of this unit. +} + +{$S-} + +interface + +const + +{ Stream access modes } + + SCreate = $3C00; { Create new file } + SOpenRead = $3D00; { Read access only } + SOpenWrite = $3D01; { Write access only } + SOpen = $3D02; { Read and write access } + +{ SetPos positioning modes } + + PosAbs = 0; { Relative to beginning } + PosCur = 1; { Relative to current position } + PosEnd = 2; { Relative to end } + +type + +{ General conversion types } + + WordRec = record + Lo, Hi: Byte; + end; + + LongRec = record + Lo, Hi: Word; + end; + + PtrRec = record + Ofs, Seg: Word; + end; + +{ Abstract base object type } + + BasePtr = ^Base; + Base = object + destructor Done; virtual; + end; + +{ Stream type list } + + STypeListPtr = ^STypeList; + STypeList = array[1..256] of Word; + +{ Stream I/O procedure record } + + SProc = object + StoreProc: Pointer; + LoadProc: Pointer; + end; + +{ Stream I/O procedure list } + + SProcListPtr = ^SProcList; + SProcList = array[1..256] of SProc; + +{ Abstract stream object type } + + StreamPtr = ^Stream; + Stream = object(Base) + TypeCount: Word; + TypeList: STypeListPtr; + ProcList: SProcListPtr; + Status: Integer; + constructor Init; + destructor Done; virtual; + procedure Error(Code: Integer); virtual; + procedure Flush; virtual; + function GetPos: Longint; virtual; + procedure Read(var Buf; Count: Word); virtual; + procedure RegisterTypes; virtual; + procedure SetPos(Pos: Longint; Mode: Byte); virtual; + procedure Truncate; virtual; + procedure Write(var Buf; Count: Word); virtual; + function Get: BasePtr; + function GetSize: Longint; + procedure Put(B: BasePtr); + procedure Register(TypePtr, StorePtr, LoadPtr: Pointer); + procedure Seek(Pos: Longint); + end; + +{ DOS file name string } + + FNameStr = string[79]; + +{ Unbuffered DOS stream } + + DosStreamPtr = ^DosStream; + DosStream = object(Stream) + Handle: Word; + constructor Init(FileName: FNameStr; Mode: Word); + destructor Done; virtual; + function GetPos: Longint; virtual; + procedure Read(var Buf; Count: Word); virtual; + procedure SetPos(Pos: Longint; Mode: Byte); virtual; + procedure Truncate; virtual; + procedure Write(var Buf; Count: Word); virtual; + procedure Close; + procedure Open(var Name; Mode: Word); + end; + +{ Buffered DOS stream } + + BufStreamPtr = ^BufStream; + BufStream = object(DosStream) + Buffer: Pointer; + BufSize: Word; + BufPtr: Word; + BufEnd: Word; + constructor Init(FileName: FNameStr; Mode, Size: Word); + destructor Done; virtual; + procedure Flush; virtual; + function GetPos: Longint; virtual; + procedure Read(var Buf; Count: Word); virtual; + procedure Write(var Buf; Count: Word); virtual; + end; + +{ Abstract linked list node type } + + NodePtr = ^Node; + Node = object(Base) + Next: NodePtr; + function Prev: NodePtr; + end; + +{ Linked list type } + + ListPtr = ^List; + List = object + Last: NodePtr; + procedure Append(N: NodePtr); + procedure Clear; + procedure Delete; + function Empty: Boolean; + function First: NodePtr; + procedure Insert(N: NodePtr); + procedure Load(var S: Stream); + function Next(N: NodePtr): NodePtr; + function Prev(N: NodePtr): NodePtr; + procedure Remove(N: NodePtr); + procedure Store(var S: Stream); + end; + +{ Abstract notification procedure } + +procedure Abstract; + +implementation + +{$L STREAM} { Stream externals } +{$L DOSSTM} { DosStream externals } +{$L BUFSTM} { BufStream externals } + +procedure StreamError; external {STREAM}; + +{ Base } + +destructor Base.Done; +begin +end; + +{ Stream } + +constructor Stream.Init; +begin + TypeCount := 0; + TypeList := nil; + ProcList := nil; + Status := 0; + RegisterTypes; + GetMem(TypeList, TypeCount * SizeOf(Word)); + if TypeList = nil then Fail; + GetMem(ProcList, TypeCount * SizeOf(SProc)); + if ProcList = nil then + begin + FreeMem(TypeList, TypeCount * SizeOf(Word)); + Fail; + end; + TypeCount := 0; + RegisterTypes; +end; + +destructor Stream.Done; +begin + FreeMem(ProcList, TypeCount * SizeOf(SProc)); + FreeMem(TypeList, TypeCount * SizeOf(Word)); +end; + +procedure Stream.Error(Code: Integer); +begin + Status := Code; +end; + +procedure Stream.Flush; +begin +end; + +function Stream.GetPos: Longint; +begin + Abstract; +end; + +procedure Stream.Read(var Buf; Count: Word); +begin + Abstract; +end; + +procedure Stream.RegisterTypes; +begin +end; + +procedure Stream.SetPos(Pos: Longint; Mode: Byte); +begin + Abstract; +end; + +procedure Stream.Truncate; +begin + Abstract; +end; + +procedure Stream.Write(var Buf; Count: Word); +begin + Abstract; +end; + +function Stream.Get: BasePtr; +external {STREAM}; + +function Stream.GetSize: Longint; +var + P: Longint; +begin + P := GetPos; + SetPos(0, PosEnd); + GetSize := GetPos; + SetPos(P, PosAbs); +end; + +procedure Stream.Put(B: BasePtr); +external {STREAM}; + +procedure Stream.Register(TypePtr, StorePtr, LoadPtr: Pointer); +begin + Inc(TypeCount); + if TypeList <> nil then + begin + TypeList^[TypeCount] := PtrRec(TypePtr).Ofs; + with ProcList^[TypeCount] do + begin + StoreProc := StorePtr; + LoadProc := LoadPtr; + end; + end; +end; + +procedure Stream.Seek(Pos: Longint); +begin + SetPos(Pos, PosAbs); +end; + +{ DosStream } + +constructor DosStream.Init(FileName: FNameStr; Mode: Word); +var + L: Integer; +begin + if not Stream.Init then Fail; + L := Length(FileName); + Move(FileName[1], FileName[0], L); + FileName[L] := #0; + Open(FileName, Mode); +end; + +destructor DosStream.Done; +begin + Close; + Stream.Done; +end; + +function DosStream.GetPos: Longint; +external {DOSSTM}; + +procedure DosStream.Read(var Buf; Count: Word); +external {DOSSTM}; + +procedure DosStream.SetPos(Pos: Longint; Mode: Byte); +external {DOSSTM}; + +procedure DosStream.Truncate; +external {DOSSTM}; + +procedure DosStream.Write(var Buf; Count: Word); +external {DOSSTM}; + +procedure DosStream.Close; +external {DOSSTM}; + +procedure DosStream.Open(var Name; Mode: Word); +external {DOSSTM}; + +{ BufStream } + +constructor BufStream.Init(FileName: FNameStr; Mode, Size: Word); +begin + GetMem(Buffer, Size); + if Buffer = nil then Fail; + if not DosStream.Init(FileName, Mode) then + begin + FreeMem(Buffer, Size); + Fail; + end; + BufSize := Size; + BufPtr := 0; + BufEnd := 0; +end; + +destructor BufStream.Done; +begin + DosStream.Done; + FreeMem(Buffer, BufSize); +end; + +procedure BufStream.Flush; +external {BUFSTM}; + +function BufStream.GetPos: Longint; +external {BUFSTM}; + +procedure BufStream.Read(var Buf; Count: Word); +external {BUFSTM}; + +procedure BufStream.Write(var Buf; Count: Word); +external {BUFSTM}; + +{ Node } + +function Node.Prev: NodePtr; +var + P: NodePtr; +begin + P := @Self; + while P^.Next <> @Self do P := P^.Next; + Prev := P; +end; + +{ List } + +procedure List.Append(N: NodePtr); +begin + Insert(N); + Last := N; +end; + +procedure List.Clear; +begin + Last := nil; +end; + +procedure List.Delete; +var + P: NodePtr; +begin + while not Empty do + begin + P := First; + Remove(P); + Dispose(P, Done); + end; +end; + +function List.Empty: Boolean; +begin + Empty := Last = nil; +end; + +function List.First: NodePtr; +begin + if Last = nil then First := nil else First := Last^.Next; +end; + +procedure List.Insert(N: NodePtr); +begin + if Last = nil then Last := N else N^.Next := Last^.Next; + Last^.Next := N; +end; + +procedure List.Load(var S: Stream); +var + P: NodePtr; +begin + Clear; + P := NodePtr(S.Get); + while P <> nil do + begin + Append(P); + P := NodePtr(S.Get); + end; +end; + +function List.Next(N: NodePtr): NodePtr; +begin + if N = Last then Next := nil else Next := N^.Next; +end; + +function List.Prev(N: NodePtr): NodePtr; +begin + if N = First then Prev := nil else Prev := N^.Prev; +end; + +procedure List.Remove(N: NodePtr); +var + P: NodePtr; +begin + if Last <> nil then + begin + P := Last; + while (P^.Next <> N) and (P^.Next <> Last) do P := P^.Next; + if P^.Next = N then + begin + P^.Next := N^.Next; + if Last = N then if P = N then Last := nil else Last := P; + end; + end; +end; + +procedure List.Store(var S: Stream); +var + P: NodePtr; +begin + P := First; + while P <> nil do + begin + S.Put(P); + P := Next(P); + end; + S.Put(nil); +end; + +procedure Abstract; +begin + RunError(211); +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/OBJECTS.TPU b/Borland Turbo Pascal v55/OBJECTS.TPU new file mode 100644 index 0000000000000000000000000000000000000000..f832520a44a8562ee25c35568982787c367a8105 GIT binary patch literal 9088 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 0 then Fail; +end; + +procedure IntNode.Dump; +begin + WriteLn('Int: ', Value); +end; + +procedure IntNode.Store(var S: Stream); +begin + S.Write(Value, SizeOf(Longint)); +end; + +constructor StrNode.Init(V: String); +begin + GetMem(Value, Length(V) + 1); + Value^ := V; +end; + +destructor StrNode.Done; +begin + FreeMem(Value, Length(Value^) + 1); +end; + +constructor StrNode.Load(var S: Stream); +var + L: Byte; +begin + S.Read(L, 1); + GetMem(Value, L + 1); + Value^[0] := Chr(L); + S.Read(Value^[1], L); + if S.Status <> 0 then Fail; +end; + +procedure StrNode.Dump; +begin + WriteLn('Str: ', Value^); +end; + +procedure StrNode.Store(var S: Stream); +begin + S.Write(Value^, Length(Value^) + 1); +end; + +procedure TestList.Dump; +var + P: TestNodePtr; +begin + P := TestNodePtr(First); + while P <> nil do + begin + P^.Dump; + P := TestNodePtr(Next(P)); + end; +end; + +procedure TestStream.RegisterTypes; +begin + DosStream.RegisterTypes; + Register(TypeOf(IntNode), @IntNode.Store, @IntNode.Load); + Register(TypeOf(StrNode), @StrNode.Store, @StrNode.Load); +end; + +begin + WriteLn('Creating list.'); + L.Clear; + L.Append(New(IntNodePtr, Init(1))); + L.Append(New(IntNodePtr, Init(10))); + L.Append(New(IntNodePtr, Init(100))); + L.Append(New(IntNodePtr, Init(1000))); + L.Append(New(StrNodePtr, Init('Hello world'))); + L.Append(New(StrNodePtr, Init('Turbo Pascal version 5.5'))); + L.Append(New(IntNodePtr, Init(-1))); + L.Append(New(IntNodePtr, Init(-2))); + + WriteLn('List to be saved:'); + L.Dump; + + WriteLn('Saving list in TEST.DTA.'); + S.Init('TEST.DTA', SCreate, 1024); + L.Store(S); + S.Done; + + WriteLn('Deleting list.'); + L.Delete; + + WriteLn('Loading list from TEST.DTA.'); + S.Init('TEST.DTA', SOpen, 1024); + L.Load(S); + S.Done; + + WriteLn('List that was loaded:'); + L.Dump; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/OOPDEMOS.DOC b/Borland Turbo Pascal v55/OOPDEMOS.DOC new file mode 100644 index 0000000..59b7da1 --- /dev/null +++ b/Borland Turbo Pascal v55/OOPDEMOS.DOC @@ -0,0 +1,678 @@ + + Turbo Pascal 5.5 Documentation + Object-Oriented Programming Examples + +This file documents the Turbo Pascal 5.5 Object-Oriented +Programming (OOP) examples. There are over 12,000 lines of +examples contained in the OOPDEMOS.ARC file on the disk labeled +OOP/DEMOS/BGI/DOC. (If you have a hard disk and run the INSTALL +program to install Turbo Pascal on your system, it will place the +OOP examples in C:\TP by default.) + + +TABLE OF CONTENTS +----------------- + + 1. OBJECTS.PAS - Basic object types unit + + 2. ODEMO.PAS - An example that uses streams and lists + + 3. FORMS.PAS - Implements a form entry and edit object + + 4. SLIDERS.PAS - Implements a slider field + + 5. FDEMO.PAS - A simple forms editor example + + 6. CARDS.PAS - Implements a card file object + + 7. CARDFILE.PAS - A simple card filer applciation + + 8. CARDGEN.PAS - Card filer forms generator + + 9. TCALC.PAS - See TCALC.DOC + +10. Examples from the Object-Oriented Programming Guide + + Four examples are included from the OOP Guide for your + convenience: + + POINTS PAS - From P-20 of the OOP Guide + FIGURES PAS - From P-42 of the OOP Guide + FIGDEMO PAS - From P-47 of the OOP Guide + LISTDEMO PAS - From P-57 of the OOP Guide + + These examples are fully documented in Chapter 1 of the OOP + Guide. + + +OBJECTS.PAS - BASIC OBJECT TYPES UNIT +------------------------------------- + +The Objects unit implements two basic object types: a Stream and +a List. The Stream type is the object-oriented counterpart of a +Pascal file. Turbo Pascal 5.5 does not allow "file of object" +types, but streams may be used to implement the same +functionality, and much more as the example programs show. The +List type implements a singly-linked list of objects, each of +which must be derived from the Node type. + + +The Base type +------------- + +Base is an abstract object type, and serves only as an ultimate +ancestor for other object types. Objects of type Base are never +instantiated. Object types derived from Base are guaranteed to +have a destructor called Done. In addition, the VMT field of +descendants of Base will always be the first field in the +descendant, which is a prerequisite of types registered with a +stream. + +Unless overridden, the Done destructor in Base does nothing +except to dispose the instance when called via the extended +syntax of the Dispose standard procedure. + + +The Stream type +--------------- + +Much like an untyped file, a stream implements a number of basic +I/O capabilities, such as opening, closing, reading, writing, and +seeking. What sets a stream apart from an untyped file is its +ability to polymorphically read and write objects. This is best +demonstrated through an example. + +Assume that you have three object types, Circle, Rectangle, and +Triangle, each of which are derived from an ancestor type Shape. +In order to read and write such objects to disk you would need a +FILE OF Shape that allows reading and writing of objects of type +Shape as well as descendants of Shape. For a number of reasons, +ordinary Pascal FILE types cannot achieve this. First, objects of +type Circle, Rectangle, and Triangle are most likely not of the +same size, since each will add a varying number of fields to the +basic Shape type. Thus, it would be impossible to determine the +proper record size for a FILE OF Shape. Second, a FILE OF Shape +would need to store additional type information for each object +in the file so that when reading the file, the application can +"know" the types of the objects it is reading. + +The Stream type provides the solution to this problem: By +defining a Store and Load method in an object type, and by +registering that type with a stream, the stream can perform +polymorphic I/O through its Put and Get methods. The FORMS.PAS +unit and the CARDFILE.PAS program provide good examples on how to +use streams. + +The Stream type is the ancestor of all other streams. It defines +the basic properties of a stream, but most of its methods are +purely abstract and meant to be overridden in descendant types. + + +FIELDS + +TypeCount Number of types registered with the stream. + +TypeList Pointer to array of VMT offsets of registered types. + +ProcList Pointer to array of Store and Load method pointers. + +Status Stream status. When Status is non-zero, an error + has occurred on the stream, and all subsequent + I/O is suspended. The Status field is the + equivalent of the IOResult standard function, + except that you have to manually clear Status to + re-enable I/O operations. + + +CONSTRUCTORS AND DESTRUCTORS + +constructor Init; + + Initializes the stream by allocating TypeList and ProcList, and + calling RegisterTypes to register the types known by the + stream. + +destructor Done; virtual; + + Disposes TypeList and ProcList. + + +BASIC I/O METHODS + +procedure Read(var Buf; Count: Word); virtual; + + Reads Count bytes from the stream into Buf. In case of error, + Buf is filled with zeros. This method must be overridden. + +procedure Write(var Buf; Count: Word); virtual; + + Writes Count bytes from Buf onto the stream. This method must + be overridden. + +procedure Flush; virtual; + + Flushes the stream's I/O buffer, if any. This method does + nothing unless overridden. + +procedure Truncate; virtual; + + Truncates the stream at the current position, i.e. makes the + current position the end of the stream. This method must be + overridden. + +function GetPos: Longint; virtual; + + Returns the current position of the stream, or -1 in case of + error. + +procedure SetPos(Pos: Longint; Mode: Byte); virtual; + + Sets the current position of the stream to a new position that + is Pos bytes from the stream location given by Mode. Valid Mode + values are given by the constants PosAbs, PosCur, and PosEnd, + which represent the stream's beginning, current position, and + end. This method must be overridden. + +function GetSize: Longint; + + Returns the current size of a stream. Calls SetPos and GetPos + to find the resulting value. This method should not be + overridden. + +procedure Seek(Pos: Longint); + + Seeks to the specified position. Corresponds to a call to + SetPos with a Mode value of PosAbs. This method should not be + overridden. + + +TYPE REGISTRATION METHODS + +procedure RegisterTypes; virtual; + + Registers all types that should be known to the stream. To + register types with a stream you must override this method and + call the Register method for each type. Within an overridden + RegisterTypes, always first call the inherited RegisterTypes to + register any types required by the ancestor. A type need only + be registered if instances of the type are read and written + using the Get and Put methods. Unless overridden, this method + does nothing. + +procedure Register(TypePtr, StorePtr, LoadPtr: Pointer); + + Registers a type with the stream. This method must only be used + within a RegisterTypes method. The format of a method call is: + + Register(TypeOf(AType), @AType.Store, @AType.Load); + + where AType is an object type derived from the Base object type + (i.e. an object type whose ultimate ancestor is Base). AType + must define Store and a methods with the following headers: + + procedure Store(var S: Stream); + constructor Load(var S: Stream); + + The Store method must write a binary representation of the + object onto the stream S (using S.Write), and the Load + constructor must read such a binary representation back from + the stream S (using S.Read). + + +POLYMORPHIC I/O METHODS + +procedure Put(P: BasePtr); + + Writes the specified object to the stream. The type of the + object must have been registered with the stream (using an + overridden RegisterTypes method). Put writes a 16-bit object + type identifier number onto the stream and then calls the + object's Store method, which writes a binary copy of the + object. The 16-bit object type identifier corresponds to the + index of the object type in the TypeList and ProcList arrays. + + If the specified object pointer is NIL, a 16-bit zero is + written to the stream. If the object type has not been + registered with the stream, the stream's Error method is called + with an error code of -1. + +function Get: BasePtr; + + Reads an object from a stream and returns a pointer to it. Get + is the counterpart of Put, and can only read objects that were + written by Put. Get reads the 16-bit object type identifier + from the stream and then calls the object type's Load + constructor, which allocates an object on the heap and reads a + binary copy of it from the stream. + + If the 16-bit object type identifier is zero, Get returns a + NIL. If the object type identifier is out of range, the + stream's error method is called with an error code of -2, and + Get returns a NIL. + + +ERROR HANDLING METHODS + +procedure Error(Code: Integer); virtual; + + This method is called whenever an error occurs on the stream. + Code contains the 16-bit error code, which for DOS file streams + is a DOS error code (see the Run-time Errors in Appendix D in + the Reference Guide). Unless overridden, the Error method just + stores Code in the stream's Status field. + + +The DosStream type +------------------ + +The DosStream type implements a DOS file stream. Data written to +a DosStream is written to a DOS file, and data read from a +DosStream is read from a DOS file. + + +FIELDS + +Handle DOS file handle. + + +CONSTRUCTORS AND DESTRUCTORS + +constructor Init(FileName: FNameStr; Mode: Word); + + Calls Stream.Init and then opens the file given by FileName + using the access mode given by Mode. Valid Mode values are + defined by the constants SCreate, SOpenRead, SOpenWrite, and + SOpen. SCreate causes a new file to be created. SOpenRead, + SOpenWrite, and SOpen opens an existing file in read-only mode, + write-only mode, or read/write mode. The DOS file handle is + stored in the Handle field. + +destructor Done; virtual; + + Closes the file and then calls Stream.Done. + + +BASIC I/O METHODS + +procedure Read(var Buf; Count: Word); virtual; + + Implements Read for a DOS file. Count bytes are read from the + file into Buf using DOS function 3FH. In case of error, Buf is + filled with zeros. + +procedure Write(var Buf; Count: Word); virtual; + + Implements Write for a DOS file. Count bytes are written to the + file from Buf using DOS function 40H. + +procedure Truncate; virtual; + + Implements Truncate for a DOS file using DOS function 40H with + a count of zero. + +function GetPos: Longint; virtual; + + Implements GetPos for a DOS file using DOS function 42H. + +procedure SetPos(Pos: Longint; Mode: Byte); virtual; + + Implements SetPos for a DOS file using DOS function 42H. + +procedure Open(var Name; Mode: Word); + + Private method which creates or opens the file using DOS + function 3CH or 3DH. Called from DosStream.Init and should + never be called directly. + +procedure Close; + + Private method which flushes the stream buffer (using the Flush + method) and closes the file. Called from DosStream.Done and + should never be called directly. + + +The BufStream type +------------------ + +The BufStream type implements a buffered DOS stream. Input and +output with a BufStream is buffered in blocks of a user specified +size. When an application makes a large number of Read and Write +method calls with a small transfer size, using a BufStream rather +than a DosStream will substantially improve performance. For a +typical stream, a buffer size of 1024 bytes is suggested. + +FIELDS + +Buffer Pointer to an I/O buffer of BufSize bytes. + +BufSize Size of I/O buffer. + +BufPtr Index of current buffer position in the buffer. + +BufEnd Index of current buffer end in the buffer. BufPtr + is equal to BufEnd, the buffer is empty. When + BufPtr is less than BufEnd, the buffer is in read + mode and the bytes between BufPtr and BufEnd have + been read ahead from the file. When BufPtr is + greater than BufEnd, the file is in write mode + and the bytes between BufEnd and BufPtr have been + written to the file but not yet flushed to disk. + + +CONSTRUCTORS AND DESTRUCTORS + +constructor Init(FileName: FNameStr; Mode, Size: Word); + + Allocates a buffer of Size bytes and then calls DosStream.Init. + +destructor Done; virtual; + + Calls DosStream.Done and then disposes the stream buffer. + + +BASIC I/O METHODS + +procedure Read(var Buf; Count: Word); virtual; + + Implements Read for a buffered stream. The stream buffer is + used to buffer disk read operations in blocks of BufSize bytes. + +procedure Write(var Buf; Count: Word); virtual; + + Implements Write for a buffered stream. The stream buffer is + used to buffer disk write operations in blocks of BufSize + bytes. + +procedure Flush; virtual; + + Flushes the stream's buffer. + +function GetPos: Longint; virtual; + + +The Node type +------------- + +Node is an abstract type that serves as the ultimate ancestor of +all objects that are kept on linked lists using the List type. +The Next field points to the next node on the list. If the node +is the last node on the list, the Next field points to the first +node, thus making the list circular. The Prev method returns a +pointer to the preceding node. If the node is the first node of +the list, the Prev method returns a pointer to the last node. + + +The List type +------------- + +The List type implements the basic algorithms of a circular +linked list. The objects kept on a List must be derived from the +abstract Node type. Other abstract types, such as stacks and +queues, can be built from the List type, since they are simply +restricted versions of the functionality provided by List. + +The List type does not inherit and has no virtual methods. For +that reason, no constructors or destructors are needed in the +List object. + + +FIELDS + +Last Pointer to the last node on the list, or NIL if + the list is empty. The Next field of the last + node on a list, i.e. Last^.Next, points to the + first node on the list. + + +LIST MANAGEMENT METHODS + +procedure Clear; + + Clears the list by setting the Last field to NIL. Any nodes on + the list are not disposed. + +procedure Delete; + + Disposes all nodes on the list using their Done destructor. + +procedure Append(N: NodePtr); + + Appends a node. The new node becomes the first node on the + list. + +procedure Insert(N: NodePtr); + + Inserts a node. The new node becomes the last node on the list. + +procedure Remove(N: NodePtr); + + Removes a node. The node itself is not disposed. + +function First: NodePtr; + + Returns a pointer to the first node on the list, or NIL if the + list is empty. The last node on the list can be directly + accessed through the Last field. + +function Next(N: NodePtr): NodePtr; + + Returns a pointer to the node after N, or NIL if N is the last + node. This corresponds to N^.Next, except that the Next field + of the last node points to the first node in the list. + +function Prev(N: NodePtr): NodePtr; + + Returns a pointer to the node before N, or NIL if N is the + first node. This corresponmds to N^.Prev, except that the Prev + method of the first node will return the last node in the list. + +function Empty: Boolean; + + Returns True if the list is empty, else returns False. + + +STREAM I/O ROUTINES + +procedure Store(var S: Stream); + + Stores the list on a stream. The types of all nodes of the list + must have been registered with the stream. The list is stored + by applying S.Put to each node in the list, followed by an + S.Put(NIL). + +procedure Load(var S: Stream); + + Loads the list from a stream. The types of all nodes of the + list to be loaded must have been registered with the stream. + The list is loaded by appending the result of S.Get until S.Get + returns NIL. + + +ODEMO.PAS - AN EXAMPLE THAT USES STREAMS AND LISTS +-------------------------------------------------- + +The ODemo program demonstrates input and output of polymorphic +objects using a stream. A list of IntNode and StrNode objects is +created, written to a file, deleted, and finally reloaded from +the file. Notice how the list is built using the List type from +the Objects unit. + + +FORMS.PAS - IMPLEMENTS A FORM ENTRY AND EDIT OBJECT +--------------------------------------------------- + +The Forms unit implements two basic object types: Field and Form. +A Field represents a data entry field, and a Form represents a +collection of Fields which add up to a complete data entry form. + +A number of field types are implemented by the Forms unit. Viewed +as a whole, they form the following hierarchy: + + Field (Abstract field type) + ÀÄÄÄÄÄÄÄFText (Abstract text field) + ÃÄÄÄÄÄÄÄFStr (String field) + ÀÄÄÄÄÄÄÄFNum (Abstract numeric field) + ÃÄÄÄÄÄÄÄFInt (Integer field) + ³ ÀÄÄÄÄÄÄÄFZip (Zipcode field) + ÀÄÄÄÄÄÄÄFReal (Floating point field) + +The basic Field type defines the common properties of all fields. +It is an abstract type, which exists only so that other field +types can inherit from it. Instances of type Field are never +actually created. Field is derived from Node (defined in the +Objects unit), so that fields can be put on a linked list that +makes up a data entry form. The data fields of type Field are: + +X X coordinate in the form. +Y Y coordinate in the form. +Size Size of the data stored in the field. +Title Pointer to a title string. +Value Pointer to current value (Size bytes long). +Extra Marks location of fields defined in descendant types. + +The methods of a Field are: + +Init Allocates and initializes a field. +Load Loads a field from a stream. +Done Cleans up and disposes a field. +Clear Sets a field to its default value. +Edit Edits a field and returns termination character. +Show Displays a field. +Store Stores a field on a stream. + +The FText type is an abstract type which serves as the ancestor +of all text field types. It defines two "helper" methods, GetStr +and PutStr, and implements code for the Edit and Show methods. +GetStr converts a field's value to a string. PutStr converts a +string and stores it as the field's value. PutStr returns True if +the string represents a valid value; else it returns false and +leaves the field's value unchanged. + +The FStr type implements a String field with a user defined +maximum length. + +The FNum type is the abstract ancestor type of all numeric +fields. It changes the Show method to right justify the value +when it is displayed. + +The FInt type implements a Longint field with user defined upper +and lower bounds. + +The FZip type implements a zipcode field, which essentially is a +5-digit FInt field that gets left-padded with zeros when +displayed. + +The FReal type implements a floating point value field with a +user defined total width and number of decimals. + +The Form type defines a form, which primarily is a collection of +fields kept on a list. The data fields of type Form are: + +X1 Left coordinate of Form window. +Y1 Top coordinate of Form window. +X2 Right coordinate of Form window. +Y2 Bottom coordinate of Form window. +Size Total size of data in the form. This is the sum of + the Size fields of each field on the Fields list. +Fields List of Field objects. + +The methods of a Form are: + +Init Allocates and initializes a form. +Load Loads a form from a stream. +Done Cleans up and disposes a form. +Edit Edits a form and returns termination character. +Show Displays a form, optionally first erasing the window. +Add Adds a field to a form. +Clear Sets all fields to their default values. +Get Copies a form into a variable. +Put Copies a variable into a form. +Store Stores a form on a stream. + +The fields in a form a kept on a linked list, which is managed by +the List type in the Objects unit. Notice how the Edit, Show, +Clear, Get, and Put methods use typecasts to promote the nodes of +the list from type Node to type Field (a descendant of Node). The +Form object "knows" that the entries on the field list are always +of type Field, and can therefore safely promote them. + +The Get and Put methods are used to copy data into and out of a +form. A variable specified as a parameter to Get or Put must be +record with fields that correspond in order, type, and size to +the fields of the form. + +The FStream type implements a buffered stream that knows the +FStr, FInt, FZip, and FReal types. Notice how only the +RegisterTypes method is overridden, and how it first calls the +inherited RegisterTypes before registering any new types. + + +SLIDERS.PAS - IMPLEMENTS A SLIDER FIELD +--------------------------------------- + +The Sliders unit implements a new Field type, called FSlider, for +use with the Forms unit. Contrary to the text field types +implemented by the Forms unit, a slider shows and edits itself as +a scroll-bar like control with a knob that indicates the current +value. The FSlider type is a direct descendant of the Field type. +The current slider value, and the minimum, maximum, and delta +values of the slider are stored as 16-bit integers. + +In addition to the FSlider type, the Sliders unit defines a new +FStream type. It is a direct descendant of the FStream type in +Forms (notice how the same name can be used in two different +units). Sliders.FStream differs from Forms.FStream only in the +RegisterTypes method, which adds registration of the FSlider +type; this is required so that sliders can be stored on and +loaded from streams along with other field types. + + +FDEMO.PAS - A SIMPLE FORMS EDITOR EXAMPLE +----------------------------------------- + +The FDemo program uses the Forms and Sliders unit to implement a +simple forms editor program, which lets you edit a record using a +form. Notice how the fields in a Person record correspond in +order, type, and size to the fields in the form. The Form.Put and +Form.Get methods require this one-to-one mapping in order to work +correctly. + + +CARDS.PAS - IMPLEMENTS A CARD FILE OBJECT +----------------------------------------- + +The Cards unit implements a Rolodex-like card file object. The +cards are kept on a doubly-linked list which can be traversed +using the Next and Prev methods. + +The Insert and Delete methods allow insertion and deletion at the +current location in the card list. The current location is a +state variable maintained by the CardList object. + + +CARDFILE.PAS - A SIMPLE CARD FILER APPLCIATION +---------------------------------------------- + +The CardFile program implements a simple card filer application. +It takes a card file name as a command-line argument, loads that +file, and allows you to scroll through and edit it. A card file +contains a saved Form object followed by a saved CardList object. +The CardFile application is not limited to a specific form +layout--the form is loaded from the a disk file rather than being +statically built in CARDFILE.PAS. + +A sample card file, CARDS.DTA, is provided on the disk. To run +the card filer with that file, use the command line: + + CARDFILE CARDS.DTA + + +CARDGEN.PAS - CARD FILER FORMS GENERATOR +---------------------------------------- + +CARDGEN.PAS is a sample program that defines two forms and saves +them in disk files that can be edited using CARDFILE.PAS. If you +run CARDGEN.PAS, it will create new PARTS.DTA and PEOPLE.DTA +files (and thus overwrite any existing files with those names, so +beware). + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/OVRDEMO.OVR b/Borland Turbo Pascal v55/OVRDEMO.OVR new file mode 100644 index 0000000000000000000000000000000000000000..494c901e3aaa603da170d111504a542864171b82 GIT binary patch literal 100 zcmWFu@DF1PDbLr_(+llS>?asz?PdcKd`u@8I^V>emST`+ NP+?&6&r2mmJphdRAgBNU literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/OVRDEMO.PAS b/Borland Turbo Pascal v55/OVRDEMO.PAS new file mode 100644 index 0000000..594b3db --- /dev/null +++ b/Borland Turbo Pascal v55/OVRDEMO.PAS @@ -0,0 +1,53 @@ + +{ Turbo Overlays } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +{$F+,O+} +program OvrDemo; +(* + This is a simple example of how to use the new overlay system. For + more complete documentation, refer to the overlay chapter in the + Turbo Pascal manual. Here's a quick checklist: + + 1. Turn "far calls" on {$F+} (to be safe, in all overlaid units and + the main program). + 2. Turn "Overlays allowed" on {$O+} + 3. Use Overlay unit in main program. + 4. Issue separate {$O} directives for each overlaid unit. + 5. Make sure to call OvrInit and pass the name of the .OVR file. + 6. Test OvrResult after OvrInit calls (optional). + 7. Compile to disk (cannot run in memory). + + Here the overlay error returns for quick reference: + + const + ovrOk = 0; { Success } + ovrError = -1; { Overlay manager error } + ovrNotFound = -2; { Overlay file not found } + ovrNoMemory = -3; { Not enough memory for overlay buffer } + ovrIOError = -4; { Overlay file I/O error } + ovrNoEMSDriver = -5; { EMS driver not installed } + ovrNoEMSMemory = -6; { Not enough EMS memory } +*) + +uses + Overlay, Crt, OvrDemo1, OvrDemo2; + +{$O OvrDemo1} { overlay 'em } +{$O OvrDemo2} + +begin + TextAttr := White; + ClrScr; + OvrInit('OVRDEMO.OVR'); { init overlay system, reserve heap space } + if OvrResult <> 0 then + begin + Writeln('Overlay error: ', OvrResult); + Halt(1); + end; + repeat + Write1; + Write2; + until KeyPressed; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/OVRDEMO1.PAS b/Borland Turbo Pascal v55/OVRDEMO1.PAS new file mode 100644 index 0000000..514b234 --- /dev/null +++ b/Borland Turbo Pascal v55/OVRDEMO1.PAS @@ -0,0 +1,20 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +{$O+,F+} +unit OvrDemo1; +{ This unit is used by OVRDEMO.PAS } + +interface + +procedure Write1; + +implementation + +procedure Write1; +begin + Writeln('One...'); +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/OVRDEMO1.TPU b/Borland Turbo Pascal v55/OVRDEMO1.TPU new file mode 100644 index 0000000000000000000000000000000000000000..c87e1ed80da46c5688158ae7a75f6a5368f860b0 GIT binary patch literal 576 zcmWFu2sL8>fcLCLlQcK#3q(`jaY?X zbuX~0j^ywU3vzMw^*3Z-(9^%h05UU@EjThb#MPI9A@L%ko*q>z#s>*w4lL{7U%`E)-6gIqX};0rfA5HJg58-nP36MGsY!oa{i0Z1@%GcW{zcmfRE W1~-7T1ds+9FAJnk0BI#4h5!K7OE`o8 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/OVRDEMO2.PAS b/Borland Turbo Pascal v55/OVRDEMO2.PAS new file mode 100644 index 0000000..3e244f7 --- /dev/null +++ b/Borland Turbo Pascal v55/OVRDEMO2.PAS @@ -0,0 +1,20 @@ + +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +{$O+,F+} +unit OvrDemo2; +{ This unit is used by OVRDEMO.PAS } + +interface + +procedure Write2; + +implementation + +procedure Write2; +begin + Writeln('Two...'); +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/OVRDEMO2.TPU b/Borland Turbo Pascal v55/OVRDEMO2.TPU new file mode 100644 index 0000000000000000000000000000000000000000..50f0a5bf5cc14426312724554a6e364b6e907fb1 GIT binary patch literal 576 zcmWFu2sL8>fcLCLlHWJ!Xt)rjTl8p zYF;3*Va!Ml|F9qzS6_c41_qA%*BC%%MzRG*28X!%GB6~*gs2N<3lH)PaW!IO0rEQ; zL4s_&AT|gLyf@e&4gr$?fdClfK$aFX_>uev^%l_GH$2aT@xVN;7vLBS3L16>egfoww%oo`}KgG3k@xF-M!Ms5a%01!`r Yf!p8)kd^?_Ame3$^a&uX1jG;k0HFLiDgXcg literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/PC3270.BGI b/Borland Turbo Pascal v55/PC3270.BGI new file mode 100644 index 0000000000000000000000000000000000000000..3f14617123e369a00fd0e7f34c3829514480894f GIT binary patch literal 6029 zcmbU_ZEzDumfiEEv22ay0E)S=vLZm6tb^7O8z5L^9K12Rp#U3K_^=BHE|=V;jv|RH zd7a>x(K=vhCPyw;SIO?(rm#`vE|sts2RLGf5M%~qC=5uD0xx9oCoo1}97ANUQ8f2j zk_jOnKTf0W>G!(dN56jkUQfUD&pf|)$!{&cey;X~XP>kD+Vw*1b1ut6WhHYR^9vrf zIP3)lmN}MX8(bF0qn1Y>U$DTSFM08$S6nar<3G7A4?X)Z!Oee!bXXR@=-Rkp(?3{# zyUG2WYtshz3omZku+gALf7gsyblpTDjM4Xg-}Z4SnfHt^3wiOUwSPCEb$Q2279*sP zekFvbP>)d4(7V)oR6AuvM&#g0ZA39-#V=Do#~0{#=?(M~*oeB(m)T!u{~J1hP9qn3 z22Vpj{RA=@zuCa}g>1%e%3+j0ppTMIGipU2qkTxw?f*SeKri(S&O2@wi(bXZ!?aQ8 zcpFB?kMCtq7?01w_MHv*xJsj;l?M4MdBR3#mz3D(`%6j`byyqv+8~d}w|8sJhbbpj zqj#LP2HlKgdJRioIW7!6ZIo_H-PXZZ*x2D>4_3r0*&aSA#|=P{2=Zw0l+jnT1rLd| zO-9EC=VOR5vFK{<#c?8J~PW8 zWIM4tXFo>m7^UVxx6??087{|3L#G#mNBlj@LcmkhI!ww#GuJ#&KAq>W4x>N98t2S+ z6jV`!Zc>yx@2npfF_73qj$usHBBmO5JLottrp zdlhS76qYoQ^q25}Lz8!Wg#G4spsxWV1!g!aJ7oqc%eZq3Zr+SrxuH2!GsQSL4?Xlp z%1OI&owR$VHZPme=H)Qz1?^2Phk29BW|XvfpkdakaXyS{u_$p^d2UB2%c~ar9YQA?io#M zuCrcn)B9;Kxtp4Mp>cqgni?}eM7t5){6P8sI*LUS#vYpf%Tll_%=Q;tMY(MDVp)Kh zICN{Pbh2qHPL0xGQzKp)WwFVNOZrbK*1@_tJN?*aldyMS9Qn;#v9}N2;A$1+&Gk4O zO+G_mc+~&l)>bK+hLNUqb=Aek$DNE@?-&gCf^Y6PL;KCAXulAl@Af-lxHeMV`E8*( z(IVW59)ga4VJ2H|F$7O=pFpbzmm$=AfH_4~;Yx&Bqkwyp;Mx?xts}U$V~kVhqFSk) z6th)0}UoXL(K&cqpju@M=(mY;<7ddoiMKX1WVm} zGfx=BB8p+$hUP7JZ>B?=l_zx*ui{{c(w38~i%A`CD}YxUYTF*18=R}f+fgxi+hcR= zx+-e*Y6_gBmHzY~J={ut-ownj(2m5iit= zwrZ_H`j0`s_&3_q+Ze5kUVwG`6n%z1znik`yOeD|Kv@>OP{`?+-`!UzK%G@+&R~AW z6`C@bT8L!V8m~?D*CzZ$EK}IwqTgyd?=Ow}t0zLG*HGbk7uR$iTH;&z9sbf=P3QB^ z`>RLQUt+oRmRvnrsJL?drLo8WAoIKZ)#IePr9Oa$nvlOb7U>0=e8pcnPO4E7xOXGD zdPH6|E;rngYe(hMiCM5sH)E!TnuYZsCmAQGtYWbUf|8rcvPjP-q)o%}rr47aj%8}5 zyl-){wt}BWAtYy8Pw2aBzU&IgycvfFNKEr83t4OM6{@5}&hwiWuvN-357T&fsuBx{ z9-cm@nHI27iaz^(v4;tFg-?(YJ0f~;$&Yf69=MBz>4!*xVUqDru#lI>FYfVJic8YF|Td$tEN{=Rv5EG0vzluTGlh$BT z@so)Yo)KW@dp_Z-9hNTw+sv`j2{0K$e9&J#vYkT=2$?EZPe8be3=p4kvL0r8QyWX7 z!E6XxIs7z!IzO9#khk%yVk=;k*crWIv%otXMOJ`p)}H~w$130&_$_b;s_DEuvXkTG z+pV;qYaGxe_4ZJa0k2X{=bu~bHzB^lp-J6g!033g3^Xralsod3oh%96bT%@ki&@$~A{5I4I^ z>Wyap*&gFKp7BuIdRNI|^_Qr+&6sB5rrUVLmeYkJF8cFw`k8fAYnpn94>a}IH39LS z-9nyHAst#K^~}8P&bDhNn%|=>*)|F&&sWmreRNt9wNGc4Oe}9b`-@R2GO1zs>cY{= z*YruUCDP$Nn)Q6Lt$;$hXOAS4pRrX`it?j1B9dBO$eHXAb}t_$1uFnQY`j%H0p#I3tk$jbDFc8l)m>)zp%G* z&f7~hpU+2%ck!&;+*ymgU2{{92uB%Ge8`$CTKab``NQMo7w z;5vQbshS>hMY;N~=$UFxrLoQ);@o=PF4sMh`tCVv%)U zz}k1#=oRix^Nry4ZrvT@Itx5h>k7x9tVS-8$N7Ydac*|q=M-J^0ffCrHchmlk?p}K zC+NIKc)eKU(IfX0Hn|kpD(F18KJx&N!fNDf_!^Wblp9cnpj?M?70Phr z?Asr_z07m|!1_!@4SeG>*XUa{3C>vF0XlUMb#rixq4p#XFH&FZ3+rJnPwJCWUy$2XhvG@T1w>AA zeDbw%0fEmZhJjybBT*eG%Ja_L++38%$}LzAdODMIP80+-SsWbOvdGVg5RAU#li>0N z1-WUko@;>lz%)al%U=QxW*BTh9AHByYm;ySU~@q|;S6vCpt<_wc#xlq7JztX`kgxx z3?>bb#1cG0UBm$J2L8!6u|RzazWim7@FNTn+Vs-;_3Hs&AFSu%s30kC2Ec@@A@zp& z6ZmXmBY6`8Bw?Zt@CO6L0sepd@=qqi_k9A1$9kNMh9_OKBIbYLLn(D zwK3dG;yARW9h)=k%~OT4m8;ZzR9(5I>0)YoxH40lg3HrI+2rdFn=5>pMwj zr$Ca<4k4X%T7(}=I=`PtPB4{p{^R>er)e_jR3@iav2wLK9X(S?5=d$`B!j?gF3A^3 z4%zh-oFi4K=Zp#yGQx-*0wfaY63p?b=+%4jNQ>}8c|=H30gWSgMos6E9fIN=&`oN0 zCz;%Dyx;gI<6Fj+#zNy8#vnY8=Gbz+GJa`%Fo%2tlXM`NDaN6N2efxiW=mm5O!4+l zh5=ga$KM3iK3$?C#RMz&D0NPyQ1tXl zxig~v38p)C<=q;ZMHYFyQh^(b0HazMaYA!X6DJrKwLAUcsS_tCfUwU*3DP(mg9N{A z*bw6M0+O$JuZu{!NFuZJNn=LpNW@uVZfc*lvQ5*LE%TS6mJBApGuaBn44vGB0il*` zCXg@yt`>zjPC)808h{2Ai&Ux`Y4sKb6R>tjm#uvZ54-am*Q2wm{N|XUWz-OuFtm&q zfLLCRo_wa zDsJ#>rOC3|% z=|g6?Bi4c4{EBTRodDg^kvmgeARU4>Nom*gYLd)$FIlF|H)oQPu<1~3DEb*7OT)(| z`5%jQz$su!n!kVEs6l-lE6psCwovs1hgJu)vFYBFh%nWO=k;w3RU{a&U#(R+#dA-c;6Jgj&r z5v_*LX+iVwQor7&6Wj)|h!&9BxX{E19=&*iBEFp^sv+qZq)03Fm?oc zW{4+n<2QoqXW(wtDCvMn$AfA)Dg>Qt_@PZ2ac)hqEu7}DfwSdv*9@ecT{yDkF72;< zt6r}Hyxk9`$CgWWu=K(?gy8P!UR$g9=Vc0Te<=8ivIU=zBdB_~v5{ad0bWpK1!A2b z-qzeRk{jxs#tgZ8a!Z|dQ@b@E7)B{uIo3^c8O&^5`dW^Pz%5Co+*D3W;nZ+S>KzL) z2tFnHeZag5?wc|N8RWvzQ;z*GqEKNgjtn zyT_F!$HCpjz2nNFmlmN##f!v6!Bgmz@s#CM!A*3Nxyj$milaD=Q*n9=+9DoA2a9`9 YkL3osVH`ta{B3lb`38MM!I2gJALu%F_W%F@ literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/POINTS.PAS b/Borland Turbo Pascal v55/POINTS.PAS new file mode 100644 index 0000000..875eb4f --- /dev/null +++ b/Borland Turbo Pascal v55/POINTS.PAS @@ -0,0 +1,88 @@ + +{ Turbo Points } +{ Copyright (c) 1989 by Borland Interational, Inc. } + +unit Points; +{ From P-20 of the Object-Oriented Programming Guide. +} + +interface + +uses Graph; + +type + Location = object + X,Y : Integer; + procedure Init(InitX, InitY : Integer); + function GetX : Integer; + function GetY : Integer; + end; + + Point = object (Location) + Visible : Boolean; + procedure Init(InitX, InitY : Integer); + procedure Show; + procedure Hide; + function IsVisible : Boolean; + procedure MoveTo(NewX, NewY : Integer); + end; + +implementation + +{--------------------------------------------------------} +{ Location's method implementations: } +{--------------------------------------------------------} + +procedure Location.Init(InitX, InitY : Integer); +begin + X := InitX; + Y := InitY; +end; + +function Location.GetX : Integer; +begin + GetX := X; +end; + +function Location.GetY : Integer; +begin + GetY := Y; +end; + + +{--------------------------------------------------------} +{ Points's method implementations: } +{--------------------------------------------------------} + +procedure Point.Init(InitX, InitY : Integer); +begin + Location.Init(InitX, InitY); + Visible := False; +end; + +procedure Point.Show; +begin + Visible := True; + PutPixel(X, Y, GetColor); +end; + +procedure Point.Hide; +begin + Visible := False; + PutPixel(X, Y, GetBkColor); +end; + +function Point.IsVisible : Boolean; +begin + IsVisible := Visible; +end; + +procedure Point.MoveTo(NewX, NewY : Integer); +begin + Hide; + Location.Init(NewX, NewY); + Show; +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/PROCVAR.PAS b/Borland Turbo Pascal v55/PROCVAR.PAS new file mode 100644 index 0000000..1733d46 --- /dev/null +++ b/Borland Turbo Pascal v55/PROCVAR.PAS @@ -0,0 +1,43 @@ + +{ Copyright (c) 1988, 1989 by Borland International, Inc. } + +{$F+} +program ProcVar; +{ For an extensive discussion of procedural types, variables and + parameters, refer to Chapter 8 in the Turbo Pascal Reference + Guide (or Chapter 7 in the Turbo Pascal 5.0 Update manual). +} + +type + IntFuncType = function (x, y : integer) : integer; { No func. identifier } + +var + IntFuncVar : IntFuncType; + +procedure DoSomething(Func : IntFuncType; x, y : integer); +begin + Writeln(Func(x, y):5); { call the function parameter } +end; + +function AddEm(x, y : integer) : integer; +begin + AddEm := x + y; +end; + +function SubEm(x, y : integer) : integer; +begin + SubEm := x - y; +end; + +begin + { Directly: } + DoSomething(AddEm, 1, 2); + DoSomething(SubEm, 1, 2); + + { Indirectly: } + IntFuncVar := AddEm; { an assignment, not a call } + DoSomething(IntFuncVar, 3, 4); { a call } + IntFuncVar := SubEm; { an assignment, not a call } + DoSomething(IntFuncVar, 3, 4); { a call } +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/QSORT.PAS b/Borland Turbo Pascal v55/QSORT.PAS new file mode 100644 index 0000000..d3944d5 --- /dev/null +++ b/Borland Turbo Pascal v55/QSORT.PAS @@ -0,0 +1,67 @@ + +{ Turbo Sort } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +program qsort; +{$R-,S-} +uses Crt; + +{ This program demonstrates the quicksort algorithm, which } +{ provides an extremely efficient method of sorting arrays in } +{ memory. The program generates a list of 1000 random numbers } +{ between 0 and 29999, and then sorts them using the QUICKSORT } +{ procedure. Finally, the sorted list is output on the screen. } +{ Note that stack and range checks are turned off (through the } +{ compiler directive above) to optimize execution speed. } + +const + max = 1000; + +type + list = array[1..max] of integer; + +var + data: list; + i: integer; + +{ QUICKSORT sorts elements in the array A with indices between } +{ LO and HI (both inclusive). Note that the QUICKSORT proce- } +{ dure provides only an "interface" to the program. The actual } +{ processing takes place in the SORT procedure, which executes } +{ itself recursively. } + +procedure quicksort(var a: list; Lo,Hi: integer); + +procedure sort(l,r: integer); +var + i,j,x,y: integer; +begin + i:=l; j:=r; x:=a[(l+r) DIV 2]; + repeat + while a[i]j; + if l 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 VqTkC4K9wCx{&}pQ1vf2~@jumLzn1_2 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/SANS.CHR b/Borland Turbo Pascal v55/SANS.CHR new file mode 100644 index 0000000000000000000000000000000000000000..38eee58474e8c664ab3b27dede3caff064b5e61e GIT binary patch literal 5438 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 VsX;FVt!U8_=CVvHQ@P-+{{i>!VKV># literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/SCREEN.PAS b/Borland Turbo Pascal v55/SCREEN.PAS new file mode 100644 index 0000000..459f2f6 --- /dev/null +++ b/Borland Turbo Pascal v55/SCREEN.PAS @@ -0,0 +1,200 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit Screen; +{ Turbo Pascal 5.5 object-oriented example. + See BREAKOUT.PAS. + This unit provides several objects for dealing with the screen. +} + +interface + +uses Crt, Dos; + +type + Location = object + X, Y : Integer; + Visible : Boolean; + constructor Init(InitX, InitY : Integer); + procedure Relocate(NewX, NewY : Integer); + procedure MoveTo(NewX, NewY : Integer); virtual; + procedure Show; virtual; + procedure Hide; virtual; + function GetX : Integer; + function GetY : Integer; + function IsVisible : Boolean; + end; + + Cursor = object(Location) + OldCursor : Integer; + TempCursor : Integer; + constructor Init; + procedure Show; virtual; + procedure Hide; virtual; + procedure SetCursor(NewCursor : Integer); + function GetCursor : Integer; + procedure MoveTo(NewX, NewY : Integer); virtual; + procedure Save; + procedure Restore; + procedure Speedup; + procedure Slowdown; + end; + + SaveScreen = object(Cursor) + OldAttr : Byte; + constructor Init; + procedure Save; + procedure Restore; + end; + +implementation + +procedure SetCursorSpeed(NewSpeed : Word); +begin + Port[$60] := $F3; + Delay(200); + Port[$60] := NewSpeed; +end; + +constructor Location.Init(InitX, InitY : Integer); +begin + X := InitX; + Y := InitY; + Visible := False; +end; + +procedure Location.Relocate(NewX, NewY : Integer); +begin + X := NewX; + Y := NewY; +end; + +procedure Location.MoveTo(NewX, NewY : Integer); +var + Vis : Boolean; +begin + Vis := Visible; + if Vis then Hide; + X := NewX; + Y := NewY; + if Vis then Show; +end; + +procedure Location.Show; +begin + Visible := True; +end; + +procedure Location.Hide; +begin + Visible := False; +end; + +function Location.GetX : Integer; +begin + GetX := X; +end; + +function Location.GetY : Integer; +begin + GetY := Y; +end; + +function Location.IsVisible; +begin + IsVisible := Visible; +end; + +constructor Cursor.Init; +begin + Location.Init(WhereX, WhereY); + OldCursor := GetCursor; + Location.Show; +end; + +procedure Cursor.Show; +begin + SetCursor(TempCursor); +end; + +procedure Cursor.Hide; +begin + TempCursor := GetCursor; + SetCursor($2000); +end; + +function Cursor.GetCursor : Integer; +var + Reg : Registers; +begin + with Reg do + begin + AH := 3; + BH := 0; + Intr($10, Reg); + GetCursor := CX; + end; +end; + +procedure Cursor.SetCursor(NewCursor : Integer); +var + Reg : Registers; +begin + with Reg do + begin + AH := 1; + BH := 0; + CX := NewCursor; + Intr($10, Reg); + end; +end; + +procedure Cursor.MoveTo(NewX, NewY : Integer); +begin + Location.Relocate(NewX, NewY); + GoToXY(NewX, NewY); +end; + +procedure Cursor.Save; +begin + Location.Relocate(WhereX, WhereY); + OldCursor := GetCursor; +end; + +procedure Cursor.Restore; +begin + SetCursor(OldCursor); + GoToXY(X, Y); +end; + +procedure Cursor.Speedup; +begin + SetCursorSpeed(0); +end; + +procedure Cursor.Slowdown; +begin + SetCursorSpeed($2C); +end; + +constructor SaveScreen.Init; +begin + Cursor.Init; + OldAttr := TextAttr; +end; + +procedure SaveScreen.Save; +begin + Cursor.Save; + OldAttr := TextAttr; +end; + +procedure SaveScreen.Restore; +begin + Cursor.Restore; + TextAttr := OldAttr; + ClrScr; +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/SIEVE.PAS b/Borland Turbo Pascal v55/SIEVE.PAS new file mode 100644 index 0000000..12729cf --- /dev/null +++ b/Borland Turbo Pascal v55/SIEVE.PAS @@ -0,0 +1,31 @@ +program sieve; + +const + size = 8190; + +type + flagType = array[ 0..size ] of boolean; + +var + i, k, prime, count, iter : integer; + flags : flagType; + +begin + for iter := 1 to 10 do begin + count := 0; + for i := 0 to size do flags[ i ] := true; + for i := 0 to size do begin + if flags[ i ] then begin + prime := i + i + 3; + k := i + prime; + while k <= size do begin + flags[ k ] := false; + k := k + prime; + end; + count := count + 1; + end; + end; + end; + + writeln( 'count of primes: ', count ); +end. \ No newline at end of file diff --git a/Borland Turbo Pascal v55/SLIDERS.PAS b/Borland Turbo Pascal v55/SLIDERS.PAS new file mode 100644 index 0000000..96e3cc2 --- /dev/null +++ b/Borland Turbo Pascal v55/SLIDERS.PAS @@ -0,0 +1,111 @@ + +{ Turbo Sliders } +{ Copyright (c) 1989 by Borland International, Inc. } + +unit Sliders; +{ Turbo Pascal 5.5 object-oriented example. + This unit extends FORM.PAS' Field object type. + Refer to OOPDEMOS.DOC for an overview of this unit. +} + +{$S-} + +interface + +uses Forms; + +type + + FSliderPtr = ^FSlider; + FSlider = object(Field) + Min, Max, Delta: Integer; + constructor Init(PX, PY: Integer; PTitle: FString; + PMin, PMax, PDelta: Integer); + procedure Clear; virtual; + function Edit: Char; virtual; + procedure Show; virtual; + procedure Display(I: Integer); + end; + + FStream = object(Forms.FStream) + procedure RegisterTypes; virtual; + end; + +implementation + +uses Crt; + +{ FSlider } + +constructor FSlider.Init(PX, PY: Integer; PTitle: FString; + PMin, PMax, PDelta: Integer); +begin + Field.Init(PX, PY, 2, PTitle); + Min := PMin; + Max := PMax; + Delta := PDelta; +end; + +procedure FSlider.Clear; +begin + Integer(Value^) := (Max - Min) div 2; +end; + +function FSlider.Edit: Char; +var + I: Integer; + Ch: Char; + Stop: Boolean; +begin + I := Integer(Value^); + Stop := False; + repeat + Display(I); + GotoXY(X + Length(Title^) + 1, Y); + Ch := ReadChar; + case Ch of + CLeft: if I > Min then Dec(I, Delta); + CRight: if I < Max then Inc(I, Delta); + CHome: I := Min; + CEnd: I := Max; + CUndo: I := Integer(Value^); + CEnter, CNext, CPrev, CSave, CEsc: Stop := True; + else + Beep; + end; + until Stop; + if Ch <> CEsc then Integer(Value^) := I; + Edit := Ch; +end; + +procedure FSlider.Show; +begin + Display(Integer(Value^)); +end; + +procedure FSlider.Display(I: Integer); +var + Steps: Integer; + S: FString; +begin + Steps := (Max - Min) div Delta + 1; + S[0] := Chr(Steps); + FillChar(S[1], Steps, #176); + S[(I - Min) div Delta + 1] := #219; + GotoXY(X, Y); + Color(TitleColor); + Write(Title^); + Color(ValueColor); + Write(' ', Min, ' ', S, ' ', Max, ' '); +end; + +{ FStream } + +procedure FStream.RegisterTypes; +begin + Forms.FStream.RegisterTypes; + Register(TypeOf(FSlider), @FSlider.Store, @FSlider.Load); +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/STREAM.ASM b/Borland Turbo Pascal v55/STREAM.ASM new file mode 100644 index 0000000..e5896ff --- /dev/null +++ b/Borland Turbo Pascal v55/STREAM.ASM @@ -0,0 +1,144 @@ +; Turbo Pascal 5.5 object-oriented example +; Assembler code for OBJECTS.PAS unit +; Copyright (c) 1989 by Borland International, Inc. + + TITLE Stream + + INCLUDE OBJECTS.INC + +CODE SEGMENT BYTE PUBLIC + + ASSUME CS:CODE + + PUBLIC Stream@Get + +Stream@Get PROC FAR + +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + PUSH AX + MOV AX,SP + PUSH SS + PUSH AX + MOV AX,2 + PUSH AX + LES DI,@Self + PUSH ES + PUSH DI + MOV DI,ES:[DI] + CALL [DI].Stream$Read + POP BX + OR BX,BX + JE @@2 + LES DI,@Self + DEC BX + CMP BX,ES:[DI].Stream@TypeCount + JAE @@1 + PUSH ES + PUSH DI + LES DI,ES:[DI].Stream@TypeList + SHL BX,1 + PUSH WORD PTR ES:[DI+BX] + XOR AX,AX + PUSH AX + PUSH AX + LES DI,@Self + LES DI,ES:[DI].Stream@ProcList + SHL BX,1 + SHL BX,1 + CALL ES:[DI+BX].SProc@LoadProc + JMP SHORT @@3 +@@1: MOV AX,-2 + CALL StreamError +@@2: XOR AX,AX + MOV DX,AX +@@3: POP BP + RET 4 + +Stream@Get ENDP + + PUBLIC Stream@Put + +Stream@Put PROC FAR + +@B EQU (DWORD PTR [BP+10]) +@Self EQU (DWORD PTR [BP+6]) + + PUSH BP + MOV BP,SP + LES DI,@B + MOV CX,ES + OR CX,DI + JE @@1 + MOV AX,ES:[DI] + LES DI,@Self + MOV CX,ES:[DI].Stream@TypeCount + JCXZ @@2 + MOV BX,CX + LES DI,ES:[DI].Stream@TypeList + CLD + REPNE SCASW + JNE @@2 + NEG CX + ADD CX,BX +@@1: PUSH CX + MOV AX,SP + PUSH SS + PUSH AX + MOV AX,2 + PUSH AX + LES DI,@Self + PUSH ES + PUSH DI + MOV DI,ES:[DI] + CALL [DI].Stream$Write + POP BX + DEC BX + JS @@3 + LES DI,@Self + PUSH ES + PUSH DI + PUSH @B.w2 + PUSH @B.w0 + LES DI,ES:[DI].Stream@ProcList + SHL BX,1 + SHL BX,1 + SHL BX,1 + CALL ES:[DI+BX].SProc@StoreProc + JMP SHORT @@3 +@@2: LES DI,@Self + MOV AX,-1 + CALL StreamError +@@3: POP BP + RET 8 + +Stream@Put ENDP + +; Stream error handler +; In AX = Error code +; ES:DI = Stream object pointer +; Uses AX,BX,CX,DX,SI + + PUBLIC StreamError + +StreamError PROC NEAR + + PUSH ES + PUSH DI + PUSH AX + PUSH ES + PUSH DI + MOV DI,ES:[DI] + CALL [DI].Stream$Error + POP DI + POP ES + RET + +StreamError ENDP + +CODE ENDS + + END + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/STREAM.OBJ b/Borland Turbo Pascal v55/STREAM.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..c68647a6a647228881c11e5e87f2588b0e24dec3 GIT binary patch literal 388 zcmZqRVc-f5337Gx)pHE??eCChU|H9!0@Mo zg~4GF zRIC7$J5tMX@v+)}L*oMhAk{!V$Hm7Wkw});EXD`AFT|c=0U3Fuj;rV3V`;T+R*>y<*i#$~Y~cY=_i@Ct L9}evT22Ke8M(czD literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TCALC.DOC b/Borland Turbo Pascal v55/TCALC.DOC new file mode 100644 index 0000000..4b367c0 --- /dev/null +++ b/Borland Turbo Pascal v55/TCALC.DOC @@ -0,0 +1,157 @@ + + Turbo Pascal 5.5 + Turbo Calc Information + +Build Information +----------------- + The following files are provided in TCALC.ARC and are required + in order to build TCALC.EXE: + + TCALC PAS + TCCELL PAS + TCCELLSP PAS + TCHASH PAS + TCINPUT PAS + TCLSTR PAS + TCMENU PAS + TCPARSER PAS + TCRUN PAS + TCSCREEN PAS + TCSHEET PAS + TCUTIL PAS + TCCOMPAR OBJ + TCMVSMEM OBJ + + In addition, TCALC uses the OBJECTS module contained in the + \TP\OOPDEMOS directory. Make sure OBJECTS.TPU is available (in + the TCALC directory or in the UNIT DIRECOTRY) when building + TCALC. + +Types of Cells +-------------- + + Value: A number. + + Text: A string - start it with a space to make sure that it + doesn't get parsed. + + Formula: A string that is an expression (see explanation of + expressions below). This cell will be constantly updated (if + AutoCalc is on) to the current value of the expression. + + Repeat: A cell with a character that will repeat indefinitely + across the spreadsheet. Type in the character that you want + to repeat with a leading backslash (example: type \_ to get + an underline across the screen). + +General Information +------------------- + Columns range from A to CRXO (65535), and rows range from 1 to + 65535. + + The little dot in the upper left of a spreadsheet tells you + which of the spreadsheets is the current one. The number of the + spreadsheet is also printed, along with 'F' if formula display + is on and 'A' if AutoCalc is on. + + The file that the spreadsheet will be saved to is listed at the + bottom of each spreadsheet, along with an asterisk if the + spreadsheet has been updated. + +Expressions +----------- + + Cell names in formulas are typed in with the column followed by + the row: + + A1+A2 + B6^5 + + To compute the sum of a group of cells, put a colon between the + first cell and the last cell in the group: + + A1:A10 - Sum all of cells from A1 to A10 and puts the + result in the current cell. + + A1:C10 - Sum of all of cells from A1 to A10, B1 to B10, + and C1 to C10 and puts the result in the current + cell. + +Available Functions +------------------- + + ABS - absolute value + ACOS - arc cosine + ASIN - arc sine + ATAN - arc tangent + COS - cosine + COSH - hyperbolic cosine + EXP - exponential function + LOG - logarithm + LOG10 - base 10 logarithm + POW10 - raise argument to the 10th power + ROUND - round to the nearest whole number + SIN - sine + SINH - hyperbolic sine + SQR - square + SQRT - square root + TAN - tangent + TANH - hyperbolic tangent + TRUNC - return the whole part of a number + + Examples: + + TRUNC(A1) + SQRT(SQR(34.5)) + ABS(TRUNC(B16)) + +Shortcut Commands +----------------- + + AltX - Quit + Ins - Turn block on and off + Del - Delete current cell + F2 - Save current spreadsheet + AltF2 - Save as + F3 - Replace current spreadsheet + AltF3 - Load new spreadsheet (opens up additional window) + F4 - Delete current spreadsheet + F6 - Next spreadsheet + F7 - Toggle formula display on/off + F8 - Toggle AutoCalc on/off + F9 - Recalc + F10 - Main menu + ASCII keys - Add cell + +The Parser +---------- + + The state and goto information for the parser was created using + the UNIX YACC utility. The input to YACC was as follows: + +%token CONST CELL FUNC +%% +e : e '+' t + | e '-' t + | t + ; +t : t '*' f + | t '/' f + | f + ; +f : x '^' f + | x + ; +x : '-' u + | u + ; +u : CELL ':' CELL + | o + ; +o : CELL + | '(' e ')' + | CONST + | FUNC '(' e ')' + ; +%% + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCALC.PAS b/Borland Turbo Pascal v55/TCALC.PAS new file mode 100644 index 0000000..42a7864 --- /dev/null +++ b/Borland Turbo Pascal v55/TCALC.PAS @@ -0,0 +1,18 @@ + +{ Turbo Calc } +{ Copyright (c) 1989 by Borland International, Inc. } + +program TCalc; +{ Turbo Pascal 5.5 object-oriented example main module. + Object-oriented spreadsheet program. + See TCALC.DOC for more information about this example. +} + +{$S-} + +uses TCRun; + +begin { Call main procedure. The program is designed this way to make } + Run; { compiles faster. Since the main source file gets compiled every } +end. { every time, it makes sense to make the file as small as possible. } + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCCELL.PAS b/Borland Turbo Pascal v55/TCCELL.PAS new file mode 100644 index 0000000..1c344d7 --- /dev/null +++ b/Borland Turbo Pascal v55/TCCELL.PAS @@ -0,0 +1,1926 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit TCCell; +{ Turbo Pascal 5.5 object-oriented example cell routines. + This unit is used by TCALC.PAS. + See TCALC.DOC for an more information about this example. +} + +{$N+,S-} + +interface + +uses Objects, TCUtil, TCLStr, TCScreen, TCHash; + +const + DollarString = ' $ '; + RepeatFirstChar = '\'; + TextFirstChar = ' '; + EmptyCellName = 'Empty'; + ValueCellName = 'Value'; + TextCellName = 'Text'; + FormulaCellName = 'Formula'; + RepeatCellName = 'Repeat'; + DecPlacesPart = $0F; + JustShift = 4; + JustPart = $03; + DollarPart = $40; + CommasPart = $80; + NoMemory = 203; + +type + SSStream = object(DosStream) + procedure RegisterTypes; virtual; + end; + CellTypes = (ClEmpty, ClValue, ClText, ClFormula, ClRepeat); + CellPos = record + Col : Word; + Row : Word; + end; + FormatType = Byte; + Justification = (JLeft, JCenter, JRight); + DollarStr = String[Length(DollarString)]; + Block = object + Start, Stop : CellPos; + constructor Init(InitStart : CellPos); + function ExtendTo(NewLoc : CellPos) : Boolean; + function CellInBlock(CheckCell : CellPos) : Boolean; + end; + CellHashTablePtr = ^CellHashTable; + CellPtr = ^Cell; + CellHashTable = object(HashTable) { Keeps pointers to all cells } + CurrCell : CellPtr; { Information about the cell that is being } + CurrLoc : CellPos; { added, deleted, or searched for } + constructor Init(InitBuckets : BucketRange); + destructor Done; + function Add(ACell : CellPtr) : Boolean; + procedure Delete(DelLoc : CellPos; var DeletedCell : CellPtr); + { Removes a cell from the hash table } + function Search(SPos : CellPos) : CellPtr; + { Searches for a cell in the hash table } + function HashValue : Word; virtual; + { Computes the hash value of the cell } + function Found(Item : HashItemPtr) : Boolean; virtual; + { Returns True if the hash item being searched for is found } + procedure CreateItem(var Item : HashItemPtr); virtual; + { Fills in the information for a new hash item } + function ItemSize : HashItemSizeRange; virtual; + procedure Load(var S : SSStream; Total : Longint); + procedure Store(var S : SSStream); + function FirstItem : CellPtr; + function NextItem : CellPtr; + end; + FormatHashTable = object(HashTable) + CurrStart, CurrStop : CellPos; + CurrFormat : FormatType; + constructor Init; + destructor Done; + function Overwrite(NewStart, NewStop : CellPos) : Boolean; + function Add(NewStart, NewStop : CellPos; + NewFormat : FormatType) : Boolean; + function Delete(DStart, DStop : CellPos) : Boolean; + function Search(SPos : CellPos; var F : FormatType) : Boolean; + function HashValue : Word; virtual; + function Found(Item : HashItemPtr) : Boolean; virtual; + procedure CreateItem(var Item : HashItemPtr); virtual; + function ItemSize : HashItemSizeRange; virtual; + procedure Load(var S : SSStream; Total : Longint); + procedure Store(var S : SSStream); + end; + WidthHashTable = object(HashTable) + CurrCol : Word; + CurrWidth : Byte; + DefaultColWidth : Byte; + constructor Init(InitBuckets : BucketRange; InitDefaultColWidth : Byte); + destructor Done; + function Add(SCol : Word; NewWidth : Byte) : Boolean; + procedure Delete(Col : Word); + function Search(Col : Word) : Byte; + function HashValue : Word; virtual; + function Found(Item : HashItemPtr) : Boolean; virtual; + procedure CreateItem(var Item : HashItemPtr); virtual; + function ItemSize : HashItemSizeRange; virtual; + function GetDefaultColWidth : Byte; + procedure Load(var S : SSStream; Total : Longint); + procedure Store(var S : SSStream); + end; + OverwriteHashTable = object(HashTable) + CurrCell : CellPtr; + CurrPos : CellPos; + EndCol : Word; + constructor Init(InitBuckets : BucketRange); + destructor Done; + function Add(SCell : CellPtr; Overwritten : Word) : Boolean; + procedure Delete(SPos : CellPos); + function Change(SCell : CellPtr; Overwritten : Word) : Boolean; + function Search(SPos : CellPos) : CellPtr; + function HashValue : Word; virtual; + function Found(Item : HashItemPtr) : Boolean; virtual; + procedure CreateItem(var Item : HashItemPtr); virtual; + function ItemSize : HashItemSizeRange; virtual; + end; + GetColWidthFunc = function(var WHash : WidthHashTable; + C : Word) : Byte; + Cell = object(Base) + Loc : CellPos; + constructor Init(InitLoc : CellPos); + destructor Done; virtual; + function CellType : CellTypes; virtual; + function LegalValue : Boolean; virtual; + function Name : String; virtual; + function Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; virtual; + function Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; virtual; + function Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; var LastPos : CellPos; + MaxCols : Word; GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; virtual; + function ShouldUpdate : Boolean; virtual; + function HasError : Boolean; virtual; + function CurrValue : Extended; virtual; + function OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; EndCol : Word; + DisplayFormulas : Boolean) : Word; virtual; + procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; + function DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; virtual; + function FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; virtual; + function CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; virtual; + end; + EmptyCellPtr = ^EmptyCell; + EmptyCell = object(Cell) + constructor Init; + function CellType : CellTypes; virtual; + function LegalValue : Boolean; virtual; + function Name : String; virtual; + function Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; virtual; + function Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; virtual; + function Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; var LastPos : CellPos; + MaxCols : Word; GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; virtual; + function ShouldUpdate : Boolean; virtual; + function HasError : Boolean; virtual; + function CurrValue : Extended; virtual; + function OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; EndCol : Word; + DisplayFormulas : Boolean) : Word; virtual; + procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; + function DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; virtual; + function FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; virtual; + function CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; virtual; + end; + ValueCellPtr = ^ValueCell; + ValueCell = object(Cell) + Error : Boolean; + Value : Extended; { A cell with a numeric value } + constructor Init(InitLoc : CellPos; InitError : Boolean; + InitValue : Extended); + function CellType : CellTypes; virtual; + function LegalValue : Boolean; virtual; + function Name : String; virtual; + function Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; virtual; + function Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; virtual; + function Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; var LastPos : CellPos; + MaxCols : Word; GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; virtual; + function ShouldUpdate : Boolean; virtual; + function HasError : Boolean; virtual; + function CurrValue : Extended; virtual; + function OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; EndCol : Word; + DisplayFormulas : Boolean) : Word; virtual; + procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; + function DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; virtual; + function FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; virtual; + function CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; virtual; + constructor Load(var S : SSStream); + procedure Store(var S : SSStream); + end; + TextCellPtr = ^TextCell; + TextCell = object(Cell) + Txt : LStringPtr; { A cell with text } + constructor Init(InitLoc : CellPos; InitTxt : LStringPtr); + destructor Done; virtual; + function CellType : CellTypes; virtual; + function LegalValue : Boolean; virtual; + function Name : String; virtual; + function Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; virtual; + function Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; virtual; + function Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; var LastPos : CellPos; + MaxCols : Word; GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; virtual; + function ShouldUpdate : Boolean; virtual; + function HasError : Boolean; virtual; + function CurrValue : Extended; virtual; + function OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; EndCol : Word; + DisplayFormulas : Boolean) : Word; virtual; + procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; + function DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; virtual; + function FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; virtual; + function CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; virtual; + constructor Load(var S : SSStream); + procedure Store(var S : SSStream); + end; + FormulaCellPtr = ^FormulaCell; + FormulaCell = object(Cell) + Error : Boolean; + Value : Extended; + Formula : LStringPtr; { A cell with a formula } + constructor Init(InitLoc : CellPos; InitError : Boolean; + InitValue : Extended; InitFormula : LStringPtr); + destructor Done; virtual; + function CellType : CellTypes; virtual; + function LegalValue : Boolean; virtual; + function Name : String; virtual; + function Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; virtual; + function Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; virtual; + function Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; var LastPos : CellPos; + MaxCols : Word; GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; virtual; + function ShouldUpdate : Boolean; virtual; + function HasError : Boolean; virtual; + function CurrValue : Extended; virtual; + function OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; EndCol : Word; + DisplayFormulas : Boolean) : Word; virtual; + procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; + function DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; virtual; + function FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; virtual; + function CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; virtual; + constructor Load(var S : SSStream); + procedure Store(var S : SSStream); + function GetFormula : LStringPtr; + end; + RepeatCellPtr = ^RepeatCell; + RepeatCell = object(Cell) + RepeatChar : Char; { A cell with text that will repeat - used for + underlining, etc. } + constructor Init(InitLoc : CellPos; InitChar : Char); + function CellType : CellTypes; virtual; + function LegalValue : Boolean; virtual; + function Name : String; virtual; + function Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; virtual; + function Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; virtual; + function Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; var LastPos : CellPos; + MaxCols : Word; GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; virtual; + function ShouldUpdate : Boolean; virtual; + function HasError : Boolean; virtual; + function CurrValue : Extended; virtual; + function OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; EndCol : Word; + DisplayFormulas : Boolean) : Word; virtual; + procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; + function DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; virtual; + function FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; virtual; + function CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; virtual; + constructor Load(var S : SSStream); + procedure Store(var S : SSStream); + end; + +var + Empty : CellPtr; { This is a special cell. It is used as the return + value if a cell cannot be found so that the EmptyCell + methods can be executed instead of having special + routines that act differently depending on whether a + cell is found ot not. } + +implementation + +var + SavedExitProc : Pointer; + +procedure SSStream.RegisterTypes; +{ Registers the different cell types so that they will be written out + correctly to disk } +begin + DosStream.RegisterTypes; + Register(TypeOf(ValueCell), @ValueCell.Store, @ValueCell.Load); + Register(TypeOf(TextCell), @TextCell.Store, @TextCell.Load); + Register(TypeOf(FormulaCell), @FormulaCell.Store, @FormulaCell.Load); + Register(TypeOf(RepeatCell), @RepeatCell.Store, @RepeatCell.Load); +end; { SSStream.RegisterTypes } + +constructor Block.Init(InitStart : CellPos); +{ Initializes a block of cells, setting the end to be the same as the start } +begin + Start := InitStart; + Stop := Start; +end; { Block.Init } + +function Block.ExtendTo(NewLoc : CellPos) : Boolean; +{ Extends a block to a new position, as long as the new position is to the + right and down from the old position } +begin + if (NewLoc.Col >= Start.Col) and (NewLoc.Row >= Start.Row) then + begin + Stop := NewLoc; + ExtendTo := True; + end + else + ExtendTo := False; +end; { Block.ExtendTo } + +function Block.CellInBlock(CheckCell : CellPos) : Boolean; +{ Checks to see if a cell is inside a particular block } +begin + CellInBlock := (CheckCell.Col >= Start.Col) and + (CheckCell.Col <= Stop.Col) and + (CheckCell.Row >= Start.Row) and + (CheckCell.Row <= Stop.Row); +end; { Block.CellInBlock } + +constructor CellHashTable.Init(InitBuckets : BucketRange); +{ Initializes a cell hash table, which stores pointers to the cells in a + spreadsheet } +begin + if not HashTable.Init(InitBuckets) then + Fail; +end; { CellHashTable.Init } + +destructor CellHashTable.Done; +{ Removes a cell hash table from memory } +var + CP : CellPtr; +begin + CP := FirstItem; + while CP <> nil do + begin + Dispose(CP, Done); + CP := NextItem; + end; + HashTable.Done; +end; { CellHashTable.Done } + +function CellHashTable.Add(ACell : CellPtr) : Boolean; +{ Adds a cell to a cell hash table } +begin + CurrCell := ACell; + CurrLoc := CurrCell^.Loc; + Add := HashTable.Add; +end; { CellHashTable.Add } + +procedure CellHashTable.Delete(DelLoc : CellPos; var DeletedCell : CellPtr); +{ Deletes a cell from a cell hash table } +begin + CurrLoc := DelLoc; + HashTable.Delete(@DeletedCell); +end; { CellHashTable.Delete } + +function CellHashTable.Search(SPos : CellPos) : CellPtr; +{ Searches for a cell in a cell hash table, returning the cell if found, or + returning the Empty cell if not found } +var + I : HashItemPtr; + C : CellPtr; +begin + CurrLoc := SPos; + I := HashTable.Search; + if I = nil then + Search := Empty + else begin + Move(I^.Data, C, SizeOf(C)); + Search := C; + end; +end; { CellHashTable.Search } + +function CellHashTable.HashValue : Word; +{ Calculates the hash value of a cell } +begin + HashValue := CurrLoc.Col + CurrLoc.Row; +end; { CellHashTable.HashValue } + +function CellHashTable.Found(Item : HashItemPtr) : Boolean; +{ Checks to see if a hash item is the one searched for by comparing the + location information in both } +var + C : CellPtr; +begin + Move(Item^.Data, C, SizeOf(C)); + Found := Compare(C^.Loc, CurrLoc, SizeOf(CurrLoc)); +end; { CellHashTable.Found } + +procedure CellHashTable.CreateItem(var Item : HashItemPtr); +{ Writes the cell poionter information out to the hash item } +begin + Move(CurrCell, Item^.Data, SizeOf(CurrCell)); +end; { CellHashTable.CreateItem } + +function CellHashTable.ItemSize : HashItemSizeRange; +{ The hash item size is current - just cell pointers are stored } +begin + ItemSize := SizeOf(CurrCell); +end; { CellHashTable.ItemSize } + +procedure CellHashTable.Load(var S : SSStream; Total : Longint); +{ Loads a cell hash table from disk } +var + Counter : Longint; +begin + for Counter := 1 to Total do + begin + if not Add(CellPtr(S.Get)) then + begin + S.Error(NoMemory); + Exit; + end; + end; +end; { CellHashTable.Load } + +procedure CellHashTable.Store(var S : SSStream); +{ Writes a cell hash table to disk } +var + CP : CellPtr; +begin + CP := FirstItem; + while CP <> nil do + begin + S.Put(CP); + CP := NextItem; + end; +end; { CellHashTable.Store } + +function HashItemPtrToCellPtr(H : HashItemPtr) : CellPtr; +{ Converts a hash item pointer to a cell pointer } +var + CP : CellPtr; +begin + if H = nil then + HashItemPtrToCellPtr := nil + else begin + Move(H^.Data, CP, SizeOf(CP)); + HashItemPtrToCellPtr := CP; + end; +end; { HashItemPtrToCellPtr } + +function CellHashTable.FirstItem : CellPtr; +{ Returns the first hash item in a cell hash table } +begin + FirstItem := HashItemPtrToCellPtr(HashTable.FirstItem); +end; { CellHashTable.FirstItem } + +function CellHashTable.NextItem : CellPtr; +{ Returns the second and subsequent hash items in a cell hash table } +begin + NextItem := HashItemPtrToCellPtr(HashTable.NextItem); +end; { CellHashTable.NextItem } + +constructor WidthHashTable.Init(InitBuckets : BucketRange; + InitDefaultColWidth : Byte); +{ Initializes the width hash table, which stores column widths that are + different than the default. It stores the column and the width in the + hash table } +begin + if not HashTable.Init(InitBuckets) then + Fail; + DefaultColWidth := InitDefaultColWidth; +end; { WidthHashTable.Init } + +destructor WidthHashTable.Done; +begin + HashTable.Done; +end; { WidthHashTable.Done } + +function WidthHashTable.Add(SCol : Word; NewWidth : Byte) : Boolean; +begin + CurrCol := SCol; + CurrWidth := NewWidth; + Add := HashTable.Add; +end; { WidthHashTable } + +procedure WidthHashTable.Delete(Col : Word); +begin + CurrCol := Col; + HashTable.Delete(nil); +end; { WidthHashTable.Delete } + +function WidthHashTable.Search(Col : Word) : Byte; +var + I : HashItemPtr; + W : Byte; +begin + CurrCol := Col; + I := HashTable.Search; + if I = nil then + Search := 0 + else begin + Move(I^.Data[SizeOf(CurrCol)], W, SizeOf(W)); + Search := W; + end; +end; { WidthHashTable.Search } + +function WidthHashTable.HashValue : Word; +begin + HashValue := CurrCol; +end; { WidthHashTable.HashValue } + +function WidthHashTable.Found(Item : HashItemPtr) : Boolean; +var + C : Word; +begin + Move(Item^.Data, C, SizeOf(C)); + Found := CurrCol = C; +end; { WidthHashTable.Found } + +procedure WidthHashTable.CreateItem(var Item : HashItemPtr); +begin + Move(CurrCol, Item^.Data, SizeOf(CurrCol)); + Move(CurrWidth, Item^.Data[SizeOf(CurrCol)], SizeOf(CurrWidth)); +end; { WidthHashTable.CreateItem } + +function WidthHashTable.ItemSize : HashItemSizeRange; +begin + ItemSize := SizeOf(CurrCol) + SizeOf(CurrWidth); +end; { WidthHashTable.ItemSize } + +function WidthHashTable.GetDefaultColWidth : Byte; +begin + GetDefaultColWidth := DefaultColWidth; +end; { WidthHashTable.GetDefaultColWidth } + +procedure WidthHashTable.Load(var S : SSStream; Total : Longint); +var + Counter : Longint; + Col : Word; + Width : Byte; +begin + for Counter := 1 to Total do + begin + S.Read(Col, SizeOf(Col)); + S.Read(Width, SizeOf(Width)); + if not Add(Col, Width) then + begin + S.Error(NoMemory); + Exit; + end; + end; +end; { WidthHashTable.Load } + +procedure WidthHashTable.Store(var S : SSStream); +var + H : HashItemPtr; + Col : Word; + Width : Byte; +begin + H := FirstItem; + while H <> nil do + begin + Move(H^.Data, Col, SizeOf(Col)); + S.Write(Col, SizeOf(Col)); + Move(H^.Data[SizeOf(Col)], Width, SizeOf(Width)); + S.Write(Width, SizeOf(Width)); + H := NextItem; + end; +end; { WidthHashTable.Store } + +constructor FormatHashTable.Init; +{ Initializes a format hash table, which is used to store formatted areas + that differ from the default. The area and the format are stored in the + hash table } +begin + if not HashTable.Init(1) then { Use a single bucket so that a search + Fail; will be possible } +end; { FormatHashTable.Init } + +destructor FormatHashTable.Done; +begin + HashTable.Done; +end; { FormatHashTable.Done } + +function FormatHashTable.Overwrite(NewStart, NewStop : CellPos) : Boolean; +{ Checks to see if a new format area has overwritten an old one, requiring + the old area to be overwritten or broken into parts } +var + H : HashItemPtr; + AStart, AStop, BStart, BStop : CellPos; + OldF, F : FormatType; + P : CellPos; + Added : Boolean; +begin + Overwrite := False; + H := HashData^[1]; + while H <> nil do + begin + Move(H^.Data, BStart, SizeOf(CellPos)); + Move(H^.Data[SizeOf(CellPos)], BStop, SizeOf(CellPos)); + if ((((NewStart.Col >= BStart.Col) and (NewStart.Col <= BStop.Col)) or + ((NewStop.Col >= BStart.Col) and (NewStop.Col <= BStop.Col))) and + (((NewStart.Row >= BStart.Row) and (NewStart.Row <= BStop.Row)) or + ((NewStop.Row >= BStart.Row) and (NewStop.Row <= BStop.Row)))) or + ((((BStart.Col >= NewStart.Col) and (BStart.Col <= NewStop.Col)) or + ((BStop.Col >= NewStart.Col) and (BStop.Col <= NewStop.Col))) and + (((BStart.Row >= NewStart.Row) and (BStart.Row <= NewStop.Row)) or + ((BStop.Row >= NewStart.Row) and (BStop.Row <= NewStop.Row)))) then + begin + Move(H^.Data[SizeOf(CellPos) shl 1], F, SizeOf(F)); + CurrStart := BStart; + CurrStop := BStop; + HashTable.Delete(nil); + if BStart.Row < NewStart.Row then + begin + AStart := BStart; + AStop.Col := BStop.Col; + AStop.Row := Pred(NewStart.Row); + if not Add(AStart, AStop, F) then + Exit; + end; + if BStop.Row > NewStop.Row then + begin + AStart.Col := BStart.Col; + AStart.Row := Succ(NewStop.Row); + AStop.Col := BStop.Col; + AStop.Row := BStop.Row; + if not Add(AStart, AStop, F) then + Exit; + end; + if BStart.Col < NewStart.Col then + begin + AStart.Col := BStart.Col; + AStart.Row := Max(BStart.Row, NewStart.Row); + AStop.Col := Pred(NewStart.Col); + AStop.Row := Min(BStop.Row, NewStop.Row); + if not Add(AStart, AStop, F) then + Exit; + end; + if BStop.Col > NewStop.Col then + begin + AStart.Col := Succ(NewStop.Col); + AStart.Row := Max(BStart.Row, NewStart.Row); + AStop.Col := BStop.Col; + AStop.Row := Min(BStop.Row, NewStop.Row); + if not Add(AStart, AStop, F) then + Exit; + end; + end; + H := H^.Next; + end; + Overwrite := True; +end; { FormatHashTable.Overwrite } + +function FormatHashTable.Add(NewStart, NewStop : CellPos; + NewFormat : FormatType) : Boolean; +begin + if not Overwrite(NewStart, NewStop) then + begin + Add := False; + Exit; + end; + CurrStart := NewStart; + CurrStop := NewStop; + CurrFormat := NewFormat; + Add := HashTable.Add; +end; { FormatHashTable.Add } + +function FormatHashTable.Delete(DStart, DStop : CellPos) : Boolean; +begin + Delete := Overwrite(DStart, DStop); +end; { FormatHashTable.Delete } + +function FormatHashTable.Search(SPos : CellPos; var F : FormatType) : + Boolean; +var + H : HashItemPtr; +begin + CurrStart := SPos; + H := HashTable.Search; + if H = nil then + Search := False + else begin + Move(H^.Data[SizeOf(CellPos) shl 1], F, SizeOf(F)); + Search := True; + end; +end; { FormatHashTable.Search } + +function FormatHashTable.HashValue : Word; +{ Since the hash table has only one bucket, the hash value is always 1 } +begin + HashValue := 1; +end; { FormatHashTable.HashValue } + +function FormatHashTable.Found(Item : HashItemPtr) : Boolean; +var + P : CellPos; + B : Block; + Start, Stop : CellPos; + Good : Boolean; +begin + Move(Item^.Data, Start, SizeOf(CellPos)); + Move(Item^.Data[SizeOf(CellPos)], Stop, SizeOf(CellPos)); + B.Init(Start); + B.Stop := Stop; + Found := B.CellInBlock(CurrStart); +end; { FormatHashTable.Found } + +procedure FormatHashTable.CreateItem(var Item : HashItemPtr); +begin + with Item^ do + begin + Move(CurrStart, Data, SizeOf(CellPos)); + Move(CurrStop, Data[SizeOf(CellPos)], SizeOf(CellPos)); + Move(CurrFormat, Data[SizeOf(CellPos) shl 1], SizeOf(CurrFormat)); + end; { with } +end; { FormatHashTable.CreateItem } + +function FormatHashTable.ItemSize : HashItemSizeRange; +begin + ItemSize := (SizeOf(CellPos) shl 1) + SizeOf(FormatType); +end; { FormatHashTable.ItemSize } + +procedure FormatHashTable.Load(var S : SSStream; Total : Longint); +var + Counter : Longint; + C1, C2 : CellPos; + Format : FormatType; +begin + for Counter := 1 to Total do + begin + S.Read(C1, SizeOf(C1)); + S.Read(C2, SizeOf(C2)); + S.Read(Format, SizeOf(Format)); + if not Add(C1, C2, Format) then + begin + S.Error(NoMemory); + Exit; + end; + end; +end; { FormatHashTable.Load } + +procedure FormatHashTable.Store(var S : SSStream); +var + H : HashItemPtr; + C : CellPos; + Format : Byte; +begin + H := FirstItem; + while H <> nil do + begin + Move(H^.Data, C, SizeOf(C)); + S.Write(C, SizeOf(C)); + Move(H^.Data[SizeOf(CellPos)], C, SizeOf(C)); + S.Write(C, SizeOf(C)); + Move(H^.Data[SizeOf(CellPos) shl 1], Format, SizeOf(Format)); + S.Write(Format, SizeOf(Format)); + H := NextItem; + end; +end; { FormatHashTable.Store } + +constructor OverwriteHashTable.Init(InitBuckets : BucketRange); +{ Initializes an overwrite hash table, which keeps track of which cells are + overwritten by other cells } +begin + if not HashTable.Init(InitBuckets) then + Fail; +end; { OverwriteHashTable.Init } + +destructor OverwriteHashTable.Done; +begin + HashTable.Done; +end; { OverwriteHashTable.Done } + +function OverwriteHashTable.Add(SCell : CellPtr; + Overwritten : Word) : Boolean; +var + CP : CellPtr; +begin + if Overwritten = 0 then + begin + Add := True; + Exit; + end; + CP := Search(SCell^.Loc); + if CP <> Empty then + begin + if not Change(CP, Pred(SCell^.Loc.Col)) then + begin + Add := False; + Exit; + end; + end; + CurrCell := SCell; + CurrPos := SCell^.Loc; + EndCol := CurrPos.Col + Overwritten; + Add := HashTable.Add; +end; { OverwriteHashTable.Add } + +procedure OverwriteHashTable.Delete(SPos : CellPos); +begin + CurrPos := SPos; + HashTable.Delete(nil); +end; { OverwriteHashTable.Delete } + +function OverwriteHashTable.Change(SCell : CellPtr; + Overwritten : Word) : Boolean; +begin + if Overwritten = 0 then + begin + Delete(SCell^.Loc); + Change := True; + end + else begin + CurrCell := SCell; + CurrPos := CurrCell^.Loc; + EndCol := SCell^.Loc.Col + Overwritten; + Change := HashTable.Change; + end; +end; { OverwriteHashTable.Change } + +function OverwriteHashTable.Search(SPos : CellPos) : CellPtr; +var + I : HashItemPtr; + C : CellPtr; +begin + CurrPos := SPos; + I := HashTable.Search; + if I = nil then + Search := Empty + else begin + Move(I^.Data, C, SizeOf(C)); + Search := C; + end; +end; { OverwriteHashTable.Search } + +function OverwriteHashTable.HashValue : Word; +begin + HashValue := CurrPos.Row; +end; { OverwriteHashTable.HashValue } + +function OverwriteHashTable.Found(Item : HashItemPtr) : Boolean; +var + C : CellPtr; + E : Word; +begin + Move(Item^.Data, C, SizeOf(C)); + Move(Item^.Data[SizeOf(C)], E, SizeOf(E)); + with CurrPos do + Found := (Row = C^.Loc.Row) and (Col >= C^.Loc.Col) and + (Col <= E); +end; { OverwriteHashTable.Found } + +procedure OverwriteHashTable.CreateItem(var Item : HashItemPtr); +begin + Move(CurrCell, Item^.Data, SizeOf(CurrCell)); + Move(EndCol, Item^.Data[SizeOf(CurrCell)], SizeOf(EndCol)); +end; { OverwriteHashTable.CreateItem } + +function OverwriteHashTable.ItemSize : HashItemSizeRange; +begin + ItemSize := SizeOf(CurrCell) + SizeOf(EndCol); +end; { OverwriteHashTable.ItemSize } + +constructor Cell.Init(InitLoc : CellPos); +{ Initializes a cell's location } +begin + Loc := InitLoc; +end; { Cell.Init } + +destructor Cell.Done; +{ Frees memory used by the cell } +begin +end; { Cell.Done } + +function Cell.CellType : CellTypes; +{ Returns the type of a cell - used in copying cells } +begin + Abstract('Cell.CellType'); +end; { Cell.CellType } + +function Cell.LegalValue : Boolean; +{ Returns True if the cell has a legal numeric value } +begin + Abstract('Cell.LegalValue'); +end; { Cell.LegalValue } + +function Cell.Name : String; +{ Returns the name of the cell type } +begin + Abstract('Cell.Name'); +end; { Cell.Name } + +function Cell.Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : + FormatType; +{ Returns the format of a cell } +begin + Abstract('Cell.Format'); +end; { Cell.Format } + +function Cell.Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : + Word; +{ Returns the width of a cell (including the cells that it will overwrite) } +begin + Abstract('Cell.Width'); +end; { Cell.Width } + +function Cell.Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + var LastPos : CellPos; + MaxCols : Word; + GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; +{ Calculates how many cells a cell will overwrite } +begin + Abstract('Cell.Overwritten'); +end; { Cell.Overwritten } + +function Cell.ShouldUpdate : Boolean; +{ Returns True if the cell needs to be updated when the spreadsheet changes } +begin + Abstract('Cell.ShouldUpdate'); +end; { Cell.ShouldUpdate } + +function Cell.HasError : Boolean; +{ Returns True if the cell has a numeric error in it } +begin + Abstract('Cell.HasError'); +end; { Cell.HasError } + +function Cell.CurrValue : Extended; +{ Returns the current numeric value of a cell } +begin + Abstract('Cell.CurrValue'); +end; { Cell.CurrValue } + +function Cell.OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; EndCol : Word; + DisplayFormulas : Boolean) : Word; +{ Determines, for overwritten cells, where in the overwriting data they will + Start to display a value } +begin + Abstract('Cell.OverwriteStart'); +end; { Cell.OverwriteStart } + +procedure Cell.EditString(MaxDecPlaces : Byte; + var L : LStringPtr); +{ Sets up a long string with the cell's value that can be edited } +begin + Abstract('Cell.EditString'); +end; { Cell.EditString } + +function Cell.DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; +{ Returns the string that will be displayed just above the input line } +begin + Abstract('Cell.DisplayString'); +end; { Cell.DisplayString } + +function Cell.FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; +{ Returns the string that will be printed in a cell } +begin + Abstract('Cell.FormattedString'); +end; { Cell.FormattedString } + +function Cell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; +{ Copies a cell's string information to another cell's } +begin + Abstract('Cell.CopyString'); +end; { Cell.CopyString } + +constructor EmptyCell.Init; +var + NewLoc : CellPos; +begin + NewLoc.Col := 0; + NewLoc.Row := 0; + Cell.Init(NewLoc); +end; { EmptyCell.Init } + +function EmptyCell.CellType : CellTypes; +begin + CellType := ClEmpty; +end; { EmptyCell.CellType } + +function EmptyCell.LegalValue : Boolean; +begin + LegalValue := True; +end; { EmptyCell.LegalValue } + +function EmptyCell.Name : String; +begin + Name := EmptyCellName; +end; { EmptyCell.Name } + +function EmptyCell.Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; +begin + Format := 0; +end; { EmptyCell.Format } + +function EmptyCell.Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; +begin + Width := 0; +end; { EmptyCell.Width } + +function EmptyCell.Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + var LastPos : CellPos; + MaxCols : Word; + GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; +begin + Overwritten := 0; +end; { EmptyCell.Overwritten } + +function EmptyCell.ShouldUpdate : Boolean; +begin + ShouldUpdate := False; +end; { EmptyCell.ShouldUpdate } + +function EmptyCell.HasError : Boolean; +begin + HasError := False; +end; { Cell.HasError } + +function EmptyCell.CurrValue : Extended; +begin + CurrValue := 0; +end; { EmptyCell.CurrValue } + +function EmptyCell.OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + EndCol : Word; + DisplayFormulas : Boolean) : Word; +begin + OverwriteStart := 1; +end; { EmptyCell.OverwriteStart } + +procedure EmptyCell.EditString(MaxDecPlaces : Byte; + var L : LStringPtr); +var + Good : Boolean; +begin + Good := L^.FromString(''); +end; { EmptyCell.EditString } + +function EmptyCell.DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; +begin + DisplayString := ''; +end; { EmptyCell.DisplayString } + +function EmptyCell.FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; + FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; +var + CP : CellPtr; +begin + CP := OHash.Search(CPos); + if CP <> Empty then + FormattedString := CP^.FormattedString(OHash, FHash, WHash, GetColWidth, + Loc, FormulasDisplayed, + CP^.OverWriteStart(FHash, WHash, + GetColWidth, CPos.Col, + FormulasDisplayed), ColWidth, + DString, Color) + else begin + FormattedString := ''; + DString := ''; + Color := Colors.BlankColor; + end; +end; { EmptyCell.FormattedString } + +function EmptyCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; +begin + CopyString := L; +end; { EmptyCell.CopyString } + +constructor ValueCell.Init(InitLoc : CellPos; InitError : Boolean; + InitValue : Extended); +begin + Cell.Init(InitLoc); + Error := InitError; + Value := InitValue; +end; { ValueCell.Init } + +function ValueCell.CellType : CellTypes; +begin + CellType := ClValue; +end; { ValueCell.CellType } + +function ValueCell.LegalValue : Boolean; +begin + LegalValue := True; +end; { ValueCell.LegalValue } + +function ValueCell.Name : String; +begin + Name := ValueCellName; +end; { ValueCell.Name } + +function ValueCell.Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; +var + F : FormatType; +begin + if FHash.Search(Loc, F) then + Format := F + else + Format := (Ord(JRight) shl 4) + 4; +end; { ValueCell.Format } + +function ValueCell.Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; +var + S : String; + F : FormatType; + P, W : Word; +begin + F := Format(FHash, FormulasDisplayed); + Str(Value:1:(F and DecPlacesPart), S); + W := Length(S); + if (F and DollarPart) <> 0 then + Inc(W, Length(DollarString)); + if (F and CommasPart) <> 0 then + begin + P := Pos('.', S); + if P = 0 then + P := Length(S); + Inc(W, (P - 2) div 3); + end; + Width := W; +end; { ValueCell.Width } + +function ValueCell.Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + var LastPos : CellPos; + MaxCols : Word; + GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; +var + CellWidth : Longint; + Total : Word; + P : CellPos; +begin + P := Loc; + CellWidth := Width(FHash, FormulasDisplayed); + Total := 0; + repeat + Inc(Total); + Dec(CellWidth, GetColWidth(WHash, P.Col)); + Inc(P.Col); + until (CellWidth <= 0) or (P.Col = MaxCols) or (CHash.Search(P) <> Empty); + Dec(Total); + Overwritten := Total; +end; { ValueCell.Overwritten } + +function ValueCell.ShouldUpdate : Boolean; +begin + ShouldUpdate := False; +end; { ValueCell.ShouldUpdate } + +function ValueCell.HasError : Boolean; +begin + HasError := Error; +end; { ValueCell.HasError } + +function ValueCell.CurrValue : Extended; +begin + CurrValue := Value; +end; { ValueCell.CurrValue } + +function ValueCell.OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + EndCol : Word; + DisplayFormulas : Boolean) : Word; +var + F : FormatType; + C, Place : Word; +begin + F := Format(FHash, DisplayFormulas); + Place := 1; + C := Loc.Col; + repeat + Inc(Place, GetColWidth(WHash, C)); + Inc(C); + until C = EndCol; + if (F and DollarPart) <> 0 then + Dec(Place, Length(DollarString)); + OverwriteStart := Place; +end; { ValueCell.OverwriteStart } + +procedure ValueCell.EditString(MaxDecPlaces : Byte; + var L : LStringPtr); +var + S : String; + Good : Boolean; +begin + Str(Value:1:MaxDecPlaces, S); + Good := L^.FromString(S); +end; { ValueCell.EditString } + +function ValueCell.DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; +var + S : String; +begin + Str(Value:1:MaxDecPlaces, S); + DisplayString := S; +end; { ValueCell.DisplayString } + +function ValueCell.FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; + FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; +var + Counter : Word; + S : String; + F : FormatType; +begin + F := Format(FHash, FormulasDisplayed); + Str(Value:1:F and DecPlacesPart, S); + if (Start = 1) and ((F and DollarPart) <> 0) then + DString := ' $ ' + else + DString := ''; + if (F and CommasPart) <> 0 then + begin + Counter := Pos('.', S); + if Counter = 0 then + Counter := System.Length(S); + while Counter > 4 do + begin + System.Insert(',', S, Counter - 3); + Dec(Counter, 3); + end; + end; + Color := Colors.ValueCellColor; + FormattedString := Copy(S, Start, ColWidth); +end; { ValueCell.FormattedString } + +function ValueCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; +begin + CopyString := L; +end; { ValueCell.CopyString } + +constructor ValueCell.Load(var S : SSStream); +begin + S.Read(Loc, SizeOf(Loc)); + S.Read(Error, SizeOf(Error)); + S.Read(Value, SizeOf(Value)); +end; { ValueCell.Load } + +procedure ValueCell.Store(var S : SSStream); +begin + S.Write(Loc, SizeOf(Loc)); + S.Write(Error, SizeOf(Error)); + S.Write(Value, SizeOf(Value)); +end; { ValueCell.Store } + +constructor TextCell.Init(InitLoc : CellPos; InitTxt : LStringPtr); +begin + Cell.Init(InitLoc); + Txt := New(LStringPtr, Init); + if Txt = nil then + Fail; + if not Txt^.Assign(InitTxt^) then + begin + Done; + Fail; + end; +end; { TextCell.Init } + +destructor TextCell.Done; +begin + Dispose(Txt, Done); +end; { TextCell.Done } + +function TextCell.CellType : CellTypes; +begin + CellType := ClText; +end; { TextCell.CellType } + +function TextCell.LegalValue : Boolean; +begin + LegalValue := False; +end; { TextCell.LegalValue } + +function TextCell.Name : String; +begin + Name := TextCellName; +end; { TextCell.Name } + +function TextCell.Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; +var + F : FormatType; +begin + if FHash.Search(Loc, F) then + Format := F + else + Format := 0; +end; { TextCell.Format } + +function TextCell.Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; +begin + Width := Txt^.Length; +end; { TextCell.Width } + +function TextCell.Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + var LastPos : CellPos; + MaxCols : Word; + GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; +var + CellWidth : Longint; + Total : Word; + P : CellPos; +begin + P := Loc; + CellWidth := Width(FHash, FormulasDisplayed); + Total := 0; + repeat + Inc(Total); + Dec(CellWidth, GetColWidth(WHash, P.Col)); + Inc(P.Col); + until (CellWidth <= 0) or (P.Col = MaxCols) or (CHash.Search(P) <> Empty); + Dec(Total); + Overwritten := Total; +end; { TextCell.Overwritten } + +function TextCell.ShouldUpdate : Boolean; +begin + ShouldUpdate := False; +end; { TextCell.ShouldUpdate } + +function TextCell.HasError : Boolean; +begin + HasError := False; +end; { TextCell.HasError } + +function TextCell.CurrValue : Extended; +begin + CurrValue := 0; +end; { TextCell.CurrValue } + +function TextCell.OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + EndCol : Word; + DisplayFormulas : Boolean) : Word; +var + F : FormatType; + C, Place : Word; +begin + F := Format(FHash, DisplayFormulas); + Place := 1; + C := Loc.Col; + repeat + Inc(Place, GetColWidth(WHash, C)); + Inc(C); + until C = EndCol; + OverwriteStart := Place; +end; { TextCell.OverwriteStart } + +procedure TextCell.EditString(MaxDecPlaces : Byte; + var L : LStringPtr); +var + Good : Boolean; +begin + Good := L^.Assign(Txt^); +end; { TextCell.EditString } + +function TextCell.DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; +begin + DisplayString := Txt^.Copy(2, Scr.CurrCols); +end; { TextCell.DisplayString } + +function TextCell.FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; + FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; +begin + DString := ''; + Color := Colors.TextCellColor; + FormattedString := Txt^.Copy(Succ(Start), ColWidth); +end; { TextCell.FormattedString } + +function TextCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; +var + Good : Boolean; +begin + Good := L^.Assign(Txt^); + CopyString := L; +end; { TextCell.CopyString } + +constructor TextCell.Load(var S : SSStream); +begin + S.Read(Loc, SizeOf(Loc)); + Txt := New(LStringPtr, Init); + if Txt = nil then + begin + S.Error(NoMemory); + Exit; + end; + if not Txt^.FromStream(S) then + begin + Dispose(Txt, Done); + S.Error(NoMemory); + end; +end; { TextCell.Load } + +procedure TextCell.Store(var S : SSStream); +begin + S.Write(Loc, SizeOf(Loc)); + Txt^.ToStream(S); +end; { TextCell.Store } + +constructor FormulaCell.Init(InitLoc : CellPos; InitError : Boolean; + InitValue : Extended; InitFormula : LStringPtr); +begin + Cell.Init(InitLoc); + Formula := New(LStringPtr, Init); + if Formula = nil then + Fail; + if not Formula^.Assign(InitFormula^) then + begin + Done; + Fail; + end; + Error := InitError; + Value := InitValue; +end; { FormulaCell.Init } + +destructor FormulaCell.Done; +begin + Dispose(Formula, Done); +end; { FormulaCell.Done } + +function FormulaCell.CellType : CellTypes; +begin + CellType := ClFormula; +end; { FormulaCell.CellType } + +function FormulaCell.LegalValue : Boolean; +begin + LegalValue := True; +end; { FormulaCell.LegalValue } + +function FormulaCell.Name : String; +begin + Name := FormulaCellName; +end; { FormulaCell.Name } + +function FormulaCell.Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; +var + F : FormatType; +begin + if FHash.Search(Loc, F) then + Format := F + else if FormulasDisplayed then + Format := 0 + else + Format := (Ord(JRight) shl 4) + 4; +end; { FormulaCell.Format } + +function FormulaCell.Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; +var + S : String; + F : Byte; + P, W : Word; +begin + if FormulasDisplayed then + Width := Formula^.Length + else begin + F := Format(FHash, FormulasDisplayed); + Str(Value:1:(F and DecPlacesPart), S); + W := Length(S); + if (F and DollarPart) <> 0 then + Inc(W, Length(DollarString)); + if (F and CommasPart) <> 0 then + begin + P := Pos('.', S); + if P = 0 then + P := Length(S); + Inc(W, (P - 2) div 3); + end; + Width := W; + end; +end; { FormulaCell.Width } + +function FormulaCell.Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + var LastPos : CellPos; + MaxCols : Word; + GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; +var + CellWidth : Longint; + Total : Word; + P : CellPos; +begin + P := Loc; + CellWidth := Width(FHash, FormulasDisplayed); + Total := 0; + repeat + Inc(Total); + Dec(CellWidth, GetColWidth(WHash, P.Col)); + Inc(P.Col); + until (CellWidth <= 0) or (P.Col = MaxCols) or (CHash.Search(P) <> Empty); + Dec(Total); + Overwritten := Total; +end; { FormulaCell.Overwritten } + +function FormulaCell.ShouldUpdate : Boolean; +begin + ShouldUpdate := True; +end; { FormulaCell.ShouldUpdate } + +function FormulaCell.HasError : Boolean; +begin + HasError := Error; +end; { FormulaCell.HasError } + +function FormulaCell.CurrValue : Extended; +begin + CurrValue := Value; +end; { FormulaCell.CurrValue } + +function FormulaCell.OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + EndCol : Word; + DisplayFormulas : Boolean) : Word; +var + F : FormatType; + C, Place : Word; +begin + F := Format(FHash, DisplayFormulas); + Place := 1; + C := Loc.Col; + repeat + Inc(Place, GetColWidth(WHash, C)); + Inc(C); + until C = EndCol; + if (not DisplayFormulas) and ((F and DollarPart) <> 0) then + Dec(Place, Length(DollarString)); + OverwriteStart := Place; +end; { FormulaCell.OverwriteStart } + +procedure FormulaCell.EditString(MaxDecPlaces : Byte; + var L : LStringPtr); +var + Good : Boolean; +begin + Good := L^.Assign(Formula^); +end; { FormulaCell.EditString } + +function FormulaCell.DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; +var + S : String; +begin + if not FormulasDisplayed then + DisplayString := Formula^.ToString + else begin + Str(Value:1:MaxDecPlaces, S); + DisplayString := S; + end; +end; { FormulaCell.DisplayString } + +function FormulaCell.FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; + FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; +var + S : String; + Counter : Word; + F : FormatType; +begin + if FormulasDisplayed then + begin + DString := ''; + Color := Colors.FormulaCellColor; + FormattedString := Formula^.Copy(1, ColWidth); + end + else begin + F := Format(FHash, FormulasDisplayed); + Str(Value:1:F and DecPlacesPart, S); + if (Start = 1) and ((F and DollarPart) <> 0) then + DString := ' $ ' + else + DString := ''; + if (F and CommasPart) <> 0 then + begin + Counter := Pos('.', S); + if Counter = 0 then + Counter := Length(S); + while Counter > 4 do + begin + Insert(',', S, Counter - 3); + Dec(Counter, 3); + end; + end; + Color := Colors.ValueCellColor; + FormattedString := Copy(S, Start, ColWidth); + end; +end; { FormulaCell.FormattedString } + +function FormulaCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; +var + Good : Boolean; +begin + Good := L^.Assign(Formula^); + CopyString := L; +end; { FormulaCell.CopyString } + +constructor FormulaCell.Load(var S : SSStream); +begin + S.Read(Loc, SizeOf(Loc)); + Formula := New(LStringPtr, Init); + if Formula = nil then + begin + S.Error(NoMemory); + Exit; + end; + if not Formula^.FromStream(S) then + begin + Dispose(Formula, Done); + S.Error(NoMemory); + end; +end; { FormulaCell.Load } + +procedure FormulaCell.Store(var S : SSStream); +begin + S.Write(Loc, SizeOf(Loc)); + Formula^.ToStream(S); +end; { FormulaCell.Store } + +function FormulaCell.GetFormula : LStringPtr; +begin + GetFormula := Formula; +end; { FormulaCell.GetFormula } + +constructor RepeatCell.Init(InitLoc : CellPos; InitChar : Char); +begin + Cell.Init(InitLoc); + RepeatChar := InitChar; +end; { RepeatCell.Init } + +function RepeatCell.CellType : CellTypes; +begin + CellType := ClRepeat; +end; { RepeatCell.CellType } + +function RepeatCell.LegalValue : Boolean; +begin + LegalValue := False; +end; { RepeatCell.LegalValue } + +function RepeatCell.Name : String; +begin + Name := RepeatCellName; +end; { RepeatCell.Name } + +function RepeatCell.Format(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : FormatType; +begin + Format := 0; +end; { RepeatCell.Format } + +function RepeatCell.Width(var FHash : FormatHashTable; + FormulasDisplayed : Boolean) : Word; +begin + Width := 2; +end; { RepeatCell.Width } + +function RepeatCell.Overwritten(var CHash : CellHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + var LastPos : CellPos; + MaxCols : Word; + GetColWidth : GetColWidthFunc; + FormulasDisplayed : Boolean) : Word; +var + Total : Word; + P : CellPos; +begin + P := Loc; + Total := 0; + repeat + Inc(Total); + Inc(P.Col); + until (P.Col > LastPos.Col) or (CHash.Search(P) <> Empty) or + (P.Col = 0); + Dec(Total); + if (P.Col > LastPos.Col) or (P.Col = 0) then + Total := MaxCols - Loc.Col; + Overwritten := Total; +end; { RepeatCell.Overwritten } + +function RepeatCell.ShouldUpdate : Boolean; +begin + ShouldUpdate := False; +end; { RepeatCell.ShouldUpdate } + +function RepeatCell.HasError : Boolean; +begin + HasError := False; +end; { RepeatCell.HasError } + +function RepeatCell.CurrValue : Extended; +begin + CurrValue := 0; +end; { RepeatCell.CurrValue } + +function RepeatCell.OverwriteStart(var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + EndCol : Word; + DisplayFormulas : Boolean) : Word; +begin + OverwriteStart := 1; +end; { RepeatCell.OverwriteStart } + +procedure RepeatCell.EditString(MaxDecPlaces : Byte; + var L : LStringPtr); +var + Good : Boolean; +begin + Good := L^.FromString(RepeatFirstChar + RepeatChar); +end; { RepeatCell.EditString } + +function RepeatCell.DisplayString(FormulasDisplayed : Boolean; + MaxDecPlaces : Byte) : String; +begin + DisplayString := FillString(Scr.CurrCols, RepeatChar); +end; { RepeatCell.DisplayString } + +function RepeatCell.FormattedString(var OHash : OverwriteHashTable; + var FHash : FormatHashTable; + var WHash : WidthHashTable; + GetColWidth : GetColWidthFunc; + CPos : CellPos; + FormulasDisplayed : Boolean; + Start : Word; ColWidth : Byte; + var DString : DollarStr; + var Color : Byte) : String; +begin + DString := ''; + Color := Colors.RepeatCellColor; + FormattedString := PadChar('', RepeatChar, ColWidth); +end; { RepeatCell.FormattedString } + +function RepeatCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; + var L : LStringPtr) : LStringPtr; +begin + EditString(0, L); + CopyString := L; +end; { RepeatCell.CopyString } + +constructor RepeatCell.Load(var S : SSStream); +begin + S.Read(Loc, SizeOf(Loc)); + S.Read(RepeatChar, SizeOf(RepeatChar)); +end; { RepeatCell.Load } + +procedure RepeatCell.Store(var S : SSStream); +begin + S.Write(Loc, SizeOf(Loc)); + S.Write(RepeatChar, SizeOf(RepeatChar)); +end; { RepeatCell.Store } + +{$F+} + +procedure CellExit; +{ Removes Empty cell from memory, restores ExitProc } +begin + Dispose(Empty, Done); + ExitProc := SavedExitProc; +end; { CellExit } + +{$F-} + +begin + SavedExitProc := ExitProc; + ExitProc := @CellExit; + Empty := New(EmptyCellPtr, Init); +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCCELL.TPU b/Borland Turbo Pascal v55/TCCELL.TPU new file mode 100644 index 0000000000000000000000000000000000000000..c6ddebc9c1fb9e4b30941598101a73fb0d2ce8f9 GIT binary patch literal 38816 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 TTLDS$B0$o+7;q|LPyYE|Z{evM literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TCCELLSP.PAS b/Borland Turbo Pascal v55/TCCELLSP.PAS new file mode 100644 index 0000000..d3028a1 --- /dev/null +++ b/Borland Turbo Pascal v55/TCCELLSP.PAS @@ -0,0 +1,228 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit TCCellSp; +{ Turbo Pascal 5.5 object-oriented example cell support routines. + This unit is used by TCALC.PAS. + See TCALC.DOC for an more information about this example. +} + +{$N+,S-} + +interface + +uses TCUtil, TCLStr, TCScreen, TCInput, TCCell; + +function GetColumn(Prompt : String; MaxCols, ColSpace : Word) : Word; + +function GetRow(Prompt : String; MaxRows : Word) : Word; + +function GetCellPos(Prompt : String; MaxCols, MaxRows, ColSpace, + RowNumberSpace : Word; var P : CellPos) : Boolean; + +function FormulaStart(Inp : LStringPtr; Start, MaxCols, MaxRows : Word; + var P : CellPos; var FormLen : Word) : Boolean; + +procedure FixFormulaCol(CP : CellPtr; Diff : Longint; + MaxCols, MaxRows : Word); + +procedure FixFormulaRow(CP : CellPtr; Diff : Longint; + MaxCols, MaxRows : Word); + +implementation + +function GetColumn(Prompt : String; MaxCols, ColSpace : Word) : Word; +{ Lets the user enter a column from the keyboard } +var + I : InputField; + S : String; + C : Word; +begin + with I do + begin + if not Init(Length(Prompt) + 3, 0, -1, ColSpace, AllUpper) then + begin + GetColumn := 0; + Exit; + end; + WriteXY(Prompt + ': ', 1, Pred(Scr.CurrRows), Colors.PromptColor); + repeat + Edit(0); + S := InputData^.ToString; + if (not GetQuit) and (S <> '') then + begin + C := StringToCol(S, MaxCols); + if C = 0 then + Scr.PrintError(ErrColumnError1 + ColToString(1) + + ErrColumnError2 + ColToString(MaxCols)); + end + else + C := 0; + until (C <> 0) or (S = ''); + InputArea.Clear; + Done; + end; { with } + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor); + GetColumn := C; +end; { GetColumn } + +function GetRow(Prompt : String; MaxRows : Word) : Word; +{ Lets the user enter a row from the keyboard } +var + R : Word; + Good : Boolean; +begin + R := GetNumber(Prompt, 1, MaxRows, Good); + if Good then + GetRow := R + else + GetRow := 0; +end; { GetRow } + +function GetCellPos(Prompt : String; MaxCols, MaxRows, ColSpace, + RowNumberSpace : Word; var P : CellPos) : Boolean; +{ Lets the user enter a cell position from the keyboard } +var + I : InputField; + S : String; + FormLen : Word; +begin + GetCellPos := False; + with I do + begin + if not Init(Length(Prompt) + 3, 0, -1, Pred(ColSpace + RowNumberSpace), + AllUpper) then + Exit; + WriteXY(Prompt + ': ', 1, Pred(Scr.CurrRows), Colors.PromptColor); + repeat + Edit(0); + S := InputData^.ToString; + if (not GetQuit) and (S <> '') then + begin + if FormulaStart(InputData, 1, MaxCols, MaxRows, P, FormLen) then + GetCellPos := True + else + Scr.PrintError(ErrCellError); + end + else + FormLen := 0; + until (FormLen <> 0) or (S = ''); + InputArea.Clear; + Done; + end; { with } + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor); +end; { GetCellPos } + +function FormulaStart(Inp : LStringPtr; Start, MaxCols, MaxRows : Word; + var P : CellPos; var FormLen : Word) : Boolean; +{ Checks to see if a place in a long string is the beginning of a formula } +var + Col, Row : Word; + CS : String[10]; + RS : String[10]; +begin + with Inp^ do + begin + FormulaStart := False; + FormLen := 0; + FillChar(P, SizeOf(P), 0); + CS := ''; + while (Start <= Length) and (Data^[Start] in Letters) do + begin + CS := CS + Data^[Start]; + Inc(Start); + end; + Col := StringToCol(CS, MaxCols); + if Col = 0 then + Exit; + RS := ''; + while (Start <= Length) and (Data^[Start] in Numbers) do + begin + RS := RS + Data^[Start]; + Inc(Start); + end; + Row := StringToRow(RS, MaxRows); + if Row = 0 then + Exit; + P.Col := Col; + P.Row := Row; + FormLen := System.Length(CS) + System.Length(RS); + FormulaStart := True; + end; { with } +end; { FormulaStart } + +procedure FixFormulaCol(CP : CellPtr; Diff : Longint; + MaxCols, MaxRows : Word); +{ Adjusts a formula for a new column } +var + FormLen, Place, OldLen, NewLen : Word; + P : CellPos; + S : String[10]; + Good : Boolean; +begin + with FormulaCellPtr(CP)^, GetFormula^ do + begin + Place := 1; + Good := True; + while Good and (Place <= Length) do + begin + if FormulaStart(GetFormula, Place, MaxCols, MaxRows, P, FormLen) then + begin + OldLen := System.Length(ColToString(P.Col)); + S := ColToString(Longint(P.Col) + Diff); + NewLen := System.Length(S); + if NewLen > OldLen then + Good := Insert(FillString(NewLen - OldLen, ' '), Place) + else if NewLen < OldLen then + Delete(Place, OldLen - NewLen); + if Good then + begin + Move(S[1], Data^[Place], System.Length(S)); + Inc(Place, FormLen + NewLen - OldLen); + end; + end + else + Inc(Place); + end; + end; { with } +end; { FixFormulaCol } + +procedure FixFormulaRow(CP : CellPtr; Diff : Longint; + MaxCols, MaxRows : Word); +{ Adjusts a formula for a new row } +var + ColLen, FormLen, Place, OldLen, NewLen : Word; + P : CellPos; + S : String[10]; + Good : Boolean; +begin + with FormulaCellPtr(CP)^, GetFormula^ do + begin + Place := 1; + Good := True; + while Good and (Place <= Length) do + begin + if FormulaStart(GetFormula, Place, MaxCols, MaxRows, P, FormLen) then + begin + OldLen := System.Length(RowToString(P.Row)); + S := RowToString(P.Row + Diff); + NewLen := System.Length(S); + ColLen := System.Length(ColToString(P.Col)); + if NewLen > OldLen then + Good := Insert(FillString(NewLen - OldLen, ' '), Place + ColLen) + else if NewLen < OldLen then + Delete(Place + ColLen, OldLen - NewLen); + if Good then + begin + Move(S[1], Data^[Place + ColLen], System.Length(S)); + Inc(Place, FormLen + NewLen - OldLen); + end; + end + else + Inc(Place); + end; + end; { with } +end; { FixFormulaRow } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCCELLSP.TPU b/Borland Turbo Pascal v55/TCCELLSP.TPU new file mode 100644 index 0000000000000000000000000000000000000000..e432d9ce1ef0751801793d5c1825f567a46681fa GIT binary patch literal 4944 zcmc&&eQXow8Gr81K7Z7tAw(f9B^UysU0CP922ughH1U;`eB91XLj;H-L|e8{CP*x{ zt`;pT!wK%XP3^j=6;q{kQ}++sA1vCWj3Nsvh9-nGv`LgjSqSmcr3kSoGmgFAbMJe$ zlhCT0H0@CCz2|wKuix)^?|sii&Cd0N>l{5!-JU+r&+LC`&y42}-d8-H~Xxjc8AL+;-^JqfMRBmR6!2{TaFn9cx-6QH$ux@_;f<_C%Xn+Re@=(bt!+Qy36CazdhSt|J>j#P?)4+SJk7+19SO;PimTIrRlDBpN1- zj^nQKqqv=;hz=&0OP+DjB|*mmlzl0+fNB?v!WwF z!052rI$Ikf(MBt(lq1ARF43+|gm_ z2Nx05OJRl45?NkWn2k+gRhP>3nx(X;<8b@6TCY3>DWZa8vZJF}y$glt>JfDLYp!Q#6d5Z_eGs8;27=oPo+YHl$M)ei+Hkf`KZtF_{cUyW#YctcHktzh!+rwR~nwBa}M<3NYkeIbI zZo6}kp3py?fVG(WK8m+j;Y}EeRrq&(tEa|O?kT|BWy9RB7hvwX2h3gffLYM#;DW2o z<%KGt7m;VBE~PujGg9+sy?}gLs(uBPL_Q@|GdA+ukQn(pkRs|Bq)nbrN4^GgM}Wsh zegnpgJdca0j(C4Br)9)DUl4x}kZeK5Du2big?(A2k~zeBjohqK9Y+(HF?A(HE&K zSVa|{ZKRUE@V+uU`o!V=6nSV#t;a`h-zm5)qi%YTmLTevNE2SGbh_X1@`+RaMXDjV zxV#HpYiNt6mg}1Hp!)okF7nmdr~SJqz_XOxt|cg=dX?9^+FOa;Ab=_~jdbxza2|D* z8dZDiz12Fca;!iTk@{G0Y4^dt;DNrwy}^Ai^zJ(p+!Ne;u&3|93&Cd(9Xt?p1$z$$ zI}d!jO72FITg6*1HKLFS z9q+d<6RfMWV5a-sknC@>#_+7HC(aG0Ym2@ zIds>_lsKNv9fe4}z5zTU=!Dy*U&hwC?@Q+Oy=UKZdwPO<_x1FMhHI&K#k|z#jr{zk z4;TT>@NYHm*?BGf2?=UN*$#F8lcqNb>Nn-j+|K3C+{$q`^Re=LtSlAR8O#_KOc{0) z@7Z1*Sd@wT?FE3_XSZ_yf6~f+BhNi77d>2|rs9=}`1O;R|Jr>VWpO*d&oi|4Qt71kze=#tfTMSfal`JN6ES{l0b)tU2 z$YSpSWdlaWeh91m#z<&%;Bvn)85-5jfl|zJJ0ACbf+F1&V5 zbmM}NRRHv+ax{LEQF~!tq(6IDOHY9V$Irq-%HsXU4wsDIVdBBISW56ck2TKp=VN#5 z@^^dc`rVENTczVE?-e_cEs~xB5dLv_=4hk3K zFBW*hxH<8VFh5+08E{i?Oq)dm2G#p$GM?r&!H!}Xy?h~`*SqX|A}Tfo&EPzWk)6=; zMmGJ4y#oaVhbsk#!zYcARD5_Ahu2OT*Dt^i9NqwjH<-hEm|rU_;S4x@02;@SIm|d5 z-ewMQ78E#4gTrh0;&58%2aI_fj?Ln5j5(Zgg4~|n2<)s=8;$8$y%TJT`Es}geVUO2 zeNOQwj2ja{;c~cI&VufGW2(f6LH9N!<2RXO4gmkzG@~Sk=B#FLO2x=9&6)HiNi(0L z^74m5c-l;KnHAkcA$&5>Uh;?5U_45T@SC0JRmht#_EXL4*th5h_PCJVqMFcF=--B4 zImY+tkr4m*{2lB=7%xK4zlr}uYeV>bPLp;#ja-U|?^D)>@GG6FA#?nt3g=r+E2O+y z&VNP9k0~Pm7Ny3{*NpLD_&u*s$cr&1=i~OM(04HZIP@pr&-E-uJu5M;m-XSlRxU&2 zPdXd-K8gD!)L9PwD-!p2CGPJ@+;2$SKbE+EE^!aaxECbuE3^n7khp-W9RJO*K-O0w z>t8JE-ze*Ek@H`b^>@koccA`n;H&NtfG!~OiW9N$5_ z5aeG%{xZhP@C#!62qX6)hxw!Yk^4E~ny}}%JeJ1gd>_d8<1+rgWc(V`&+%LEC$4`3 DaA!j# literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TCCOMPAR.ASM b/Borland Turbo Pascal v55/TCCOMPAR.ASM new file mode 100644 index 0000000..423f699 --- /dev/null +++ b/Borland Turbo Pascal v55/TCCOMPAR.ASM @@ -0,0 +1,41 @@ +; Turbo Pascal 5.5 object-oriented example +; Assembler code for TCALC example +; Copyright (c) 1989 by Borland International, Inc. + +MODEL TPASCAL + +LOCALS + +CODESEG + + PUBLIC Compare + +; function Compare(var Source, Dest; Len : Word) : Boolean; +; +; Compares two areas of memory to see if they are identical. +; +; Variables: +; +; Source : Far pointer to the location of the first area of memory. +; Dest : Far pointer to the location of the second area of memory. +; Len : The amount of memory to be compared in bytes. + +Proc Compare Source : DWord, Dest : DWord, Len : Word + push ds ; Save DS + mov cx,[Len] ; Move Len to CX + jcxz @@0 ; Quit if Len = 0, returning True + lds si,[Source] ; Load source pointer into DS:SI + les di,[Dest] ; Load destination pointer into ES:DI + cld ; Set direction to forward + repz cmpsb ; Compare the two areas + jz @@0 ; Return True if the compare was completed + mov cl,1 ; +@@0: + mov al,cl ; If CL = 0, return True, otherwise return False + xor al,1 + pop ds ; Restore DS + ret +EndP + +End + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCCOMPAR.OBJ b/Borland Turbo Pascal v55/TCCOMPAR.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..46cbf8ca7d7d04749157dccf50ba342735875d7c GIT binary patch literal 190 zcmZqRW8evKcJ}uTa17FO4EFukAx{l&|1eT%4Mll#^Pdpb(Z?RGgWgr(mdO zu&YCa!Qo|;x1J!1#>XAZKw+P0ObiSe)7ThToc&!~U1zW}Xvi}#F*1sQgj^g$9NmCI z9t;f3jEo`^_!t-%*&$ZD0xb>hU}11r#5i$*G6N$6LumIKxo$tU$Gk_&c#hO@{Q11B WglQvV*Fh6T`Pfrj45?i}i%I}?Z8QM@ literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TCHASH.PAS b/Borland Turbo Pascal v55/TCHASH.PAS new file mode 100644 index 0000000..7e201e1 --- /dev/null +++ b/Borland Turbo Pascal v55/TCHASH.PAS @@ -0,0 +1,262 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit TCHash; +{ Turbo Pascal 5.5 object-oriented example hash tables. + This unit is used by TCALC.PAS. + See TCALC.DOC for an more information about this example. +} + +{$S-} + +interface + +uses TCUtil; + +{ This unit allows you to implement hash tables. Each hash table is composed + of a number of "buckets", each of which points to a linked list of data + entries. The bucket that a particular data entry goes into is determined + by the HashValue function. } + +const + MaxBuckets = 1000; + MaxHashItemSize = 256; + +type + BucketRange = 1..MaxBuckets; + HashItemSizeRange = 1..MaxHashItemSize; + HashItemData = array[0..Pred(MaxHashItemSize)] of Byte; + HashItemDataPtr = ^HashItemData; + HashItemPtr = ^HashItem; + HashItem = record + Next : HashItemPtr; + Data : HashItemData; + end; + HashItemArray = array[BucketRange] of HashItemPtr; + HashTable = object + Buckets : BucketRange; + Items : Longint; + CurrItem : HashItemPtr; + CurrBucket : BucketRange; + HashData : ^HashItemArray; + constructor Init(InitBuckets : BucketRange); + destructor Done; + function Add : Boolean; + procedure Delete(Deleted : Pointer); + function FirstItem : HashItemPtr; + function NextItem : HashItemPtr; + function Change : Boolean; + function Search : HashItemPtr; + function HashValue : Word; virtual; + function Found(Item : HashItemPtr) : Boolean; virtual; + procedure CreateItem(var Item : HashItemPtr); virtual; + function ItemSize : HashItemSizeRange; virtual; + function CurrItemSize(Item : HashItemPtr) : HashItemSizeRange; virtual; + end; + +implementation + +constructor HashTable.Init(InitBuckets : BucketRange); +{ Initialize a new hash table with a certain number of buckets } +begin + GetMem(HashData, InitBuckets * SizeOf(HashItemPtr)); + if HashData = nil then + Fail; + Buckets := InitBuckets; + FillChar(HashData^, Buckets * SizeOf(HashItemPtr), 0); + Items := 0; +end; { HashTable.Init } + +destructor HashTable.Done; +{ Removes a hash table from memory } +var + P, D : HashItemPtr; + Counter : Word; +begin + for Counter := 1 to Buckets do + begin + P := HashData^[Counter]; + while P <> nil do + begin + D := P; + P := P^.Next; + FreeMem(D, CurrItemSize(D) + SizeOf(HashItemPtr)); + end; + end; + FreeMem(HashData, Buckets * SizeOf(HashItemPtr)); +end; { HashTable.Done } + +function HashTable.Add : Boolean; +{ Adds a new item to a hash table } +var + H, A : HashItemPtr; + V : BucketRange; +begin + Add := False; + V := Succ(HashValue mod Buckets); + H := HashData^[V]; + A := H; + while H <> nil do + begin + H := H^.Next; + if H <> nil then + A := H; + end; + if A = nil then { Item will be the first element in the list } + begin + GetMem(HashData^[V], ItemSize + SizeOf(HashItemPtr)); + A := HashData^[V]; + if A = nil then + Exit; + end + else begin { Add item and end of list } + GetMem(A^.Next, ItemSize + SizeOf(HashItemPtr)); + if A^.Next = nil then + Exit; + A := A^.Next; + end; + CreateItem(A); + A^.Next := nil; + Inc(Items); + Add := True; +end; { HashTable.Add } + +procedure HashTable.Delete(Deleted : Pointer); +{ Deletes an item from a hash table, and returns the deleted item } +var + H, D : HashItemPtr; + V : BucketRange; +begin + V := Succ(HashValue mod Buckets); + H := HashData^[V]; + D := H; + while (H <> nil) and (not Found(H)) do + begin + H := H^.Next; + if not Found(H) then + D := H; + end; + if H = nil then { The item was not found } + begin + if Deleted <> nil then + FillChar(Deleted^, ItemSize, 0); + Exit; + end + else begin + if H = HashData^[V] then + HashData^[V] := HashData^[V]^.Next + else + D^.Next := H^.Next; + if Deleted <> nil then { Fill Deleted with the item's data } + Move(H^.Data, Deleted^, ItemSize); + FreeMem(H, CurrItemSize(H) + SizeOf(HashItemPtr)); + end; + Dec(Items); +end; { HashTable.Delete } + +function HashTable.FirstItem : HashItemPtr; +{ Returns the first item in a hash table. to find all of the items in a + hash table, call FirstItem to get the first one and then call NextItem to + get the rest } +var + Counter : Word; +begin + for Counter := 1 to Buckets do + begin + CurrBucket := Counter; + CurrItem := HashData^[Counter]; + if CurrItem <> nil then + begin + FirstItem := CurrItem; + Exit; + end; + end; + FirstItem := nil; +end; { HashTable.FirstItem } + +function HashTable.NextItem : HashItemPtr; +{ Returns the next item in a hash table - called after FirstItem } +begin + CurrItem := CurrItem^.Next; + if CurrItem <> nil then + begin + NextItem := CurrItem; + Exit; + end; + while CurrBucket < Buckets do + begin + Inc(CurrBucket); + CurrItem := HashData^[CurrBucket]; + if CurrItem <> nil then + begin + NextItem := CurrItem; + Exit; + end; + end; + NextItem := nil; +end; { HashTable.NextItem } + +function HashTable.Change : Boolean; +{ Changes the data of a hash item } +var + H : HashItemPtr; +begin + H := HashData^[Succ(HashValue mod Buckets)]; + while (H <> nil) and (not Found(H)) do + H := H^.Next; + if H <> nil then + begin + CreateItem(H); + Change := True; + end + else + Change := Add; +end; { HashTable.Change } + +function HashTable.Search : HashItemPtr; +{ Searches for a particular hash item } +var + H : HashItemPtr; +begin + H := HashData^[Succ(HashValue mod Buckets)]; + while (H <> nil) and (not Found(H)) do + H := H^.Next; + Search := H; +end; { HashTable.Search } + +function HashTable.HashValue : Word; +{ Returns a hash value - must be written by the user } +begin + Abstract('HashTable.HashValue'); +end; { HashTable.HashValue } + +function HashTable.Found(Item : HashItemPtr) : Boolean; +{ Returns a boolean value indicating whether the current hash item is the + one being searched for - must be written by the user } +begin + Abstract('HashTable.Found'); +end; { HashTable.Found } + +procedure HashTable.CreateItem(var Item : HashItemPtr); +{ Creates a hash item - must be written by the user } +begin + Abstract('HashTable.CreateItem'); +end; { HashTable.CreateItem } + +function HashTable.ItemSize : HashItemSizeRange; +{ Returns the size of a hash item. If the hash item size is variable, this + is based on whatever the item being searched for, added, or deleted is - + must be written by the user } +begin + Abstract('HashTable.ItemSize'); +end; { HashTable.ItemSize } + +function HashTable.CurrItemSize(Item : HashItemPtr) : HashItemSizeRange; +{ Returns the size of a particular item. This needs to be written only if + the size of hash items is variable (strings, etc.) } +begin + CurrItemSize := ItemSize; +end; { HashTable.CurrItemSize } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCHASH.TPU b/Borland Turbo Pascal v55/TCHASH.TPU new file mode 100644 index 0000000000000000000000000000000000000000..9f3dfb8b062050f9a03ba3423c396456039d8504 GIT binary patch literal 4480 zcmc&%eQaA-6+iF#`T6-Hj-94!+In50ZElK6Nwlr1lm^vJ-fNI+05t|(Wjp$S_UQ=IGH$gJUjHTkx9QxZ_|4oww`PU zmyL}=Jw5s7=xMe3(yi|M3e1qd@_@I6>PmtC02zv=!hZut1Wup66ubJ=Ymw_14R)Ul!!Wn zf-Os_;w4uUi=MQWHWI0!k!Ux> zKY@6~rM-jzcz1G%v8)lj4~S(=B~|4l{6#L~f=GMKiR}1rv=`F%HJ$cLDKAnX4pIzy z(t)9rk;oV_%7eh|^@V6c;;d9MPFuiQ7{Mne+6UALUxa2QiVp%oBOP+KRe~M_=n-Eh zL>v%>ebH#id(FG(eZ_66r)6qH)SErh6dO)J zZDW=bw=v@YHCpw4O#8PthQLxjt5%0a09DMz37!-Fpv!QhIVcT>H7iDI#%^+OGiVzo zN^8euidshUj*-@4>dm~p7&xOZZ-y^Oxa84!?YkVJ6V9SzN#S)a%5W^;E7}z|aLEO% zHJ4n#wQ zmuTL1rey{$XSbS}mDna4o4~z@OOuE%&u;Wy^gi?>=*Os&Mj%bnPC7+9=(FGv%}X57 z%h2h-d_;-R0nlfaE+BE?pcl}8jD8;dJMh8dr_o_cgKP{h4rA&sXwL*LHC42n4+OJ)jud<&(L0I$AbGPd>5ni zJsuBrKR_LNcMr8`c?tS~>nM@|d)`8A8sEo-tLlb!TWOgsT?0+St7wl&h7^deCgl-CHTv?VuT8bAv8m_0I@1Xx0kTE|-zkD$2hr zzj=qt(#b}=bQ(F@J`~HpG%BiJst#;xxKdn;m%P|~!K1PldoQr}M|oytna#XVT)T@m z-$^eLxW=0fMFWaje8CV(d?Bk6lBPUwHaU;@5aNvwxb!yV@V{=nYs2jtIMF<}-aOZE zS=05)h5oJOunh)zZdFh9Wy@Tlw`>N2W@v6tr5KQf?W`@5bSiuGH?(?*wlB|t+ntsLBuiH&lXoAEer z#%YyY$4_SgAHSMBezm8jOJ<#qUmeBBvXT+NXq%e0gaBkM8-|7&(dVMfuNZvDnZ zpgw>C{%QYZ=9ueN);9`)Hy_ssI!^CLwfZOn%LW%we84+D#(qf_OpNt+74NA#T8+Dss*Bl)vm$mAb6GjoVXx%`>J zj6Br>uX%V%)@0dSw~l-J2H1SE@Wkh~0`2AK)VTp1`pQgxZf10D=5e4mY+9Auv4LYm z`mwKlxO2;yYn2g{pdFfyZ%!-QkNkblL9z>U7GEJ#pfT{D0OhZl zr)~N@oBu;l#=mIOzk{;guR*^KI<8oHPhuPbu7rR5kAd!`jy`^>yD=XD-DS^XnDbZE tZhMZeq2wvd_t^7$Ft%IYeHg$-UoWT*dJq&o`uO`T0{S2*|GQ(g{{W{q%-;Y2 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TCINPUT.PAS b/Borland Turbo Pascal v55/TCINPUT.PAS new file mode 100644 index 0000000..af2cdb1 --- /dev/null +++ b/Borland Turbo Pascal v55/TCINPUT.PAS @@ -0,0 +1,334 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit TCInput; +{ Turbo Pascal 5.5 object-oriented example input routines. + This unit is used by TCALC.PAS. + See TCALC.DOC for an more information about this example. +} + +{$S-} + +interface + +uses Crt, TCUtil, TCScreen, TCLStr; + +const + LeftInputArrow = #17; + RightInputArrow = #16; + YesNo = 'Y/N'; + LegalYesNo = ['Y', 'N']; + AllUpper = True; + NotUpper = False; + ErrNumberError1 = 'You must enter a number from '; + ErrNumberError2 = ' to '; + ErrColumnError1 = 'You must enter a column from '; + ErrColumnError2 = ' to '; + ErrCellError = 'You must enter a legal cell'; + +type + InputField = object + StartCol : ScreenColRange; + StopCol : Integer; + InputRow : Integer; + MaxInputLen : Word; + Quit : Boolean; + InputData : LStringPtr; + UCase : Boolean; + InputArea : ScreenArea; + constructor Init(C1 : ScreenColRange; C2 : Integer; R : Integer; + InitMaxInputLen : Word; InitUCase : Boolean); + destructor Done; + function GetQuit : Boolean; + procedure Edit(StartCursor : Word); + procedure ClearInput; + end; + +function ReadString(Prompt : String; Len : Word; + var ESCPressed : Boolean) : String; + +function GetLegalChar(Prompt : String; Legal : CharSet; + var ESCPressed : Boolean) : Char; + +function GetYesNo(Prompt : String; var ESCPressed : Boolean) : Boolean; + +function GetNumber(Prompt : String; Low, High : Longint; + var Result : Boolean) : Longint; + +implementation + +constructor InputField.Init(C1 : ScreenColRange; C2 : Integer; R : Integer; + InitMaxInputLen : Word; InitUCase : Boolean); +{ Sets up an input field } +begin + InputData := New(LStringPtr, Init); + if InputData = nil then + Fail; + StartCol := C1; + StopCol := C2; + InputRow := R; + if InitMaxInputLen = 0 then + MaxInputLen := 65521 { Maximum area that a pointer can allocate } + else + MaxInputLen := InitMaxInputLen; + UCase := InitUCase; + Quit := False; +end; { InputField.Init } + +destructor InputField.Done; +{ Remove memory used by an input field } +begin + Dispose(InputData, Done); +end; { InputField.Done } + +function InputField.GetQuit : Boolean; +{ Check to see if an input field has been exited with ESC } +begin + GetQuit := Quit; +end; { InputField.GetQuit } + +procedure InputField.Edit(StartCursor : Word); +{ Edits the input field } +var + CursorPos, Start, Cursor : Word; + Ch : Word; + Good, InsMode, Finished : Boolean; + R : ScreenRowRange; + SCol, ECol, EndCol : ScreenColRange; +begin + with InputData^ do + begin + Quit := False; + SCol := StartCol; { Figure out where the field starts and stops } + if StopCol <= 0 then + EndCol := Scr.CurrCols + StopCol + else + EndCol := StopCol; + if InputRow <= 0 then + R := Scr.CurrRows + InputRow + else + R := InputRow; + if (R = Scr.CurrRows) and (ECol = Scr.CurrCols) then + Dec(EndCol); + ECol := EndCol; + InputArea.Init(SCol, R, ECol, R, Colors.InputColor); + InputArea.Clear; + if StartCursor = 0 then + CursorPos := Succ(Length) + else + CursorPos := StartCursor; + Finished := False; + InsMode := True; + Cursor := Scr.InsCursor; + Start := Max(Longint(CursorPos) - ECol - SCol + 2, 1); + repeat + if CursorPos > Length then + ECol := EndCol; + if (CursorPos < Start) or (CursorPos > Start + ECol - SCol) then + Start := Max(Longint(CursorPos) - ECol + SCol, 1); + if (Start = 2) and (SCol <> StartCol) then + begin + SCol := StartCol; + Start := 1; + end; + if Start > 1 then + begin + if SCol = StartCol then + begin + Inc(Start); + SCol := Succ(StartCol); { Text is off left side of line } + end; + end + else + SCol := StartCol; + if Length > Start + ECol - SCol then + begin + if ECol = EndCol then + begin + if SCol <> StartCol then + Inc(Start); + ECol := Pred(EndCol); { Text is off right side of line } + end; + end + else + ECol := EndCol; + GotoXY(StartCol, R); + if SCol <> StartCol then { Text is off left side of line } + WriteColor(LeftInputArrow, Colors.InputArrowColor); + WriteColor(LeftJustStr(InputData^.Copy(Start, Succ(ECol - SCol)), + Succ(ECol - SCol)), Colors.InputColor); + if ECol <> EndCol then { Text is off right side of line } + WriteColor(RightInputArrow, Colors.InputArrowColor); + GotoXY(CursorPos - Start + SCol, R); + SetCursor(Cursor); + Ch := GetKey; + SetCursor(NoCursor); + case Ch of + Ord(' ')..Ord('~') : begin + if not (InsMode and (Length = MaxInputLen)) then + begin + if UCase then + Ch := Ord(UpCase(Chr(Ch))); + if InsMode or (CursorPos > Length) then + Good := Insert(Chr(Ch), CursorPos) + else begin + Good := True; + Change(Chr(Ch), CursorPos); + end; + if Good then + Inc(CursorPos); + end; + end; + HomeKey : CursorPos := 1; + EndKey : CursorPos := Succ(Length); + BS : begin + if CursorPos > 1 then + begin + Delete(Pred(CursorPos), 1); + Dec(CursorPos); + end; + end; + DelKey : begin + if CursorPos <= Length then + Delete(CursorPos, 1); + end; + LeftKey : begin + if CursorPos > 1 then + Dec(CursorPos); + end; + RightKey : begin + if CursorPos <= Length then + Inc(CursorPos); + end; + InsKey : begin + InsMode := not InsMode; + if InsMode then + Cursor := Scr.InsCursor + else + Cursor := Scr.OldCursor; + end; + CtrlLeftKey : begin { Move back one word } + if (CursorPos > 1) and (Data^[CursorPos] <> ' ') then + Dec(CursorPos); + while (CursorPos > 1) and (Data^[CursorPos] = ' ') do + Dec(CursorPos); + while (CursorPos > 1) and (Data^[Pred(CursorPos)] <> ' ') do + Dec(CursorPos); + end; + CtrlRightKey : begin { Move forward one word } + while (CursorPos <= Length) and (Data^[CursorPos] <> ' ') do + Inc(CursorPos); + while (CursorPos <= Length) and (Data^[CursorPos] = ' ') do + Inc(CursorPos); + end; + ESC : begin + ClearInput; + Quit := True; + Finished := True; + end; + CR : Finished := True; + end; { case } + until Finished; + end; { with } +end; { InputField.Edit } + +procedure InputField.ClearInput; +{ Makes the input field data a null long string } +var + Good : Boolean; +begin + Good := InputData^.FromString(''); +end; { InputField.ClearInput } + +function ReadString(Prompt : String; Len : Word; + var ESCPressed : Boolean) : String; +{ Read a string from the input area } +var + I : InputField; +begin + with I do + begin + if not Init(Length(Prompt) + 3, 0, -1, Len, NotUpper) then + begin + ESCPressed := True; + ReadString := ''; + end; + WriteXY(Prompt + ': ', 1, Pred(Scr.CurrRows), Colors.PromptColor); + Edit(0); + ReadString := InputData^.ToString; + ESCPressed := GetQuit; + Done; + end; { with } + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor); +end; { ReadString } + +function GetLegalChar(Prompt : String; Legal : CharSet; + var ESCPressed : Boolean) : Char; +{ Read a chanracter from the input area, only reading certain ones } +var + Ch : Char; +begin + WriteXY(Prompt + ': ', 1, Pred(Scr.CurrRows), Colors.PromptColor); + Ch := GetKeyChar(Legal); + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor); + GetLegalChar := Ch; +end; { GetLegalChar } + +function GetYesNo(Prompt : String; var ESCPressed : Boolean) : Boolean; +{ Prints a "Yes/No" prompt, allowing the user to type Y or N to answer the + question } +var + Ch : Char; +begin + WriteXY(Prompt + ' (' + YesNo + ')?', 1, Pred(Scr.CurrRows), + Colors.PromptColor); + Ch := GetKeyChar(LegalYesNo); + ESCPressed := Ch = Chr(ESC); + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor); + GetYesNo := Ch = 'Y'; +end; { GetYesNo } + +function GetNumber(Prompt : String; Low, High : Longint; + var Result : Boolean) : Longint; +{ Prompts for a numeric value within a certain range } +var + I : InputField; + S : String; + Error : Integer; + L : Longint; +begin + with I do + begin + if not Init(Length(Prompt) + 3, 0, -1, + Max(Length(NumToString(Low)), + Length(NumToString(High))), NotUpper) then + begin + Result := False; + GetNumber := 0; + Exit; + end; + WriteXY(Prompt + ': ', 1, Pred(Scr.CurrRows), Colors.PromptColor); + repeat + Edit(0); + S := InputData^.ToString; + if (not GetQuit) and (S <> '') then + begin + Val(S, L, Error); + Result := (Error = 0) and (L >= Low) and (L <= High); + if not Result then + Scr.PrintError(ErrNumberError1 + NumToString(Low) + + ErrNumberError2 + NumToString(High)); + end + else begin + Result := False; + L := 0; + end; + until Result or (S = ''); + Done; + end; { with } + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor); + GetNumber := L; +end; { GetNumber } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCINPUT.TPU b/Borland Turbo Pascal v55/TCINPUT.TPU new file mode 100644 index 0000000000000000000000000000000000000000..4b41131a746d8fa8d1a0cde23dc0bddc72049e2b GIT binary patch literal 6496 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 nil then + FreeMem(Data, MaxLen); +end; { LString.Done } + +function LString.SetValue(NewLen : LStringRange; + NewData : Pointer) : Boolean; +{ Copies an area of memory to the long string } +var + Size : Word; + NData : Pointer; +begin + Size := (NewLen + 15) shr 4 shl 4; { Calculate the new size } + if NewLen > MaxLen then { Allocate new data area if the long string } + begin { needs to grow } + GetMem(NData, Size); + if NData = nil then { The allocation failed. Return False } + begin + SetValue := False; + Exit; + end; + if Data <> nil then { If there was any data in the long string, } + begin { copy it to the new data area } + Move(Data^, NData^, Len); + FreeMem(Data, MaxLen); { Free the memory used by the long string } + end; { before it was reallocated } + Data := NData; { Set Data and MaxLen to their new values } + MaxLen := Size; + end; + Move(NewData^, Data^, NewLen); { Copy the new data to the long string } + Len := NewLen; { Set the length } + SetValue := True; { Successful - Return True } +end; { LString.SetValue } + +function LString.FromString(S : String) : Boolean; +{ Converts a string into a long string } +begin + if not SetValue(System.Length(S), @S[1]) then + begin { Set the long string to be a null } + FromString := SetValue(0, nil); { string if it could not be expanded } + FromString := False; { Return False } + end + else + FromString := True; { Successful. Return True } +end; { LString.FromString } + +function LString.ToString : String; +{ Converts a long string into a string } +var + S : String; + NewLen : Byte; +begin + NewLen := Min(255, Length); { The maximum length of a string is 255 } + S[0] := Chr(NewLen); { Set the length of the new string } + Move(Data^, S[1], NewLen); { Copy the data } + ToString := S; { Return the new string } +end; { LString.ToString } + +function LString.Length : LStringRange; +{ Returns the current length of a long string } +begin + Length := Len; +end; { LString.Length } + +function LString.Copy(Start, Amt : LStringRange) : String; +{ Copies part of a long string into a string } +var + S : String; +begin + if Start > Len then { Trying to copy past the end of the long } + Amt := 0 { string - return a null string } + else + Amt := Min(Amt, Succ(Len - Start)); { Calculate length of new string } + S[0] := Chr(Amt); { Set length of new string } + Move(Data^[Start], S[1], Amt); { Copy data into new string } + Copy := S; { Return new string } +end; { LString.Copy } + +function LString.Insert(S : String; Start : LStringRange) : Boolean; +{ Inserts a string into a long string } +var + OldLen : LStringRange; + Size : Word; + NData : Pointer; +begin + OldLen := Len; + Inc(Len, System.Length(S)); + if Len > MaxLen then { Allocate new data area if the long } + begin { string needs to grow } + Size := (Len + 15) shr 4 shl 4; { Calculate the new size } + GetMem(NData, Size); { Allocate new data area } + if NData = nil then { The long string could not be expanded } + begin + Dec(Len, System.Length(S)); { Restore the old Len value } + Insert := False; { Return False } + Exit; + end; + if Data <> nil then { If there was data in the long string, } + begin { copy it to the new data area } + Move(Data^, NData^, OldLen); + FreeMem(Data, MaxLen); { Free the old data area } + end; + Data := NData; { Set new values for Data and MaxLen } + MaxLen := Size; + end; + if Start <= OldLen then { Move the part of the string after the insert to } + { the right to make space for the new string } + Move(Data^[Start], Data^[Start + System.Length(S)], Succ(OldLen - Start)); + Move(S[1], Data^[Start], System.Length(S)); { Insert the new string } + Insert := True; { Successful - return True } +end; { LString.Insert } + +procedure LString.Delete(Start, Amt : LStringRange); +{ Deletes part of a long string } +begin + Amt := Min(Amt, Succ(Len - Start)); { No characters can be deleted past + the end of the long string } + if Start + Amt <= Len then { The delete is in the middle of the long + string - move the rest of the data to the + left } + Move(Data^[Start + Amt], Data^[Start], Succ(Len - Amt - Start)); + Dec(Len, Amt); { Fix the length value } +end; { LString.Delete } + +function LString.Append(S : String) : Boolean; +{ Appends a string to a long string } +begin + Append := Insert(S, Succ(Len)); { Insert the string at the end } +end; { LString.Append } + +procedure LString.Change(Ch : Char; Start : LStringRange); +{ Change a particular character of a long string } +begin + Move(Ch, Data^[Start], 1); +end; { LString.Change } + +function LString.Assign(LS : LString) : Boolean; +{ Copy one long string to another one } +begin + Assign := SetValue(LS.Length, LS.Data); +end; { LString.Assign } + +function LString.FromStream(var S : DosStream) : Boolean; +{ Read a long string from a stream } +var + Counter, NewLen, Size : Word; + Dummy : Byte; + NData : Pointer; +begin + S.Read(NewLen, SizeOf(NewLen)); { Read the length } + Size := (NewLen + 15) shr 4 shl 4; { Calculate the new size } + if NewLen > MaxLen then { Allocate new data area if the long string } + begin { needs to grow } + GetMem(NData, Size); + if NData = nil then { The allocation failed. Return False } + begin + for Counter := 1 to NewLen do { Read the string in so that the file } + S.Read(Dummy, 1); { position is still correct } + FromStream := False; + Exit; + end; + if Data <> nil then { If there was any data in the long string, } + begin { copy it to the new data area } + Move(Data^, NData^, Len); + FreeMem(Data, MaxLen); + end; + Data := NData; { Set new values for Data and MaxLen } + MaxLen := Size; + end; + S.Read(Data^, NewLen); { Read the long string from the stream } + Len := NewLen; + FromStream := True; { Successful - return True } +end; { LString.FromStream } + +procedure LString.ToStream(var S : DosStream); +{ Write a long string to a stream } +begin + S.Write(Len, SizeOf(Len)); { Write the length } + S.Write(Data^, Len); { Write the long string } +end; { LString.ToStream } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCLSTR.TPU b/Borland Turbo Pascal v55/TCLSTR.TPU new file mode 100644 index 0000000000000000000000000000000000000000..292ef6cc018940d412aeb40317341d485ba3509e GIT binary patch literal 4432 zcmc&$Z)jWB6+iEfo}_2lv0~SDV!QLG=Qc}OWtg*2lg*m_p5x7u6-kb(jWi7#qhoAr zthUn>n}&cFMKNq&wi4*(4{cy&Y@^VSZIIZR*MP}~HtRMhTjRhM8sgH_gj6v`Z@+Wz zea}*p!oE%B`o43{@0{~H=bo#ld}e$P;d6-w=vMgA$S)$l!rvbwS0ew6?y*d2)7aW( z^8W{YW|i^=Jt~l&#Jp6ay;Nm>U0B|!(j2S7RvGB)_gU(yGzBX^IGW36iLQS39l8g{ zf|V=e@=l8A$juufP$4|_)vq~&`5e*r4&5V8%WmWOkx`;=o+4scrZJU#iX)Arhew_C zaDM*{dXGNxIKqLLGGvqKVW(faLNQBcgRnCWm^y_SO6HS4P!J}{AsC|JsYQE_o`wzZ zhAMa_pZzJck$RKZ^Bx_rl@*rPlx0c!g_VUxgKYYnc1^T{PbosLYZlEI31h`rH;A$Z zDv1z%s4-{A7S{-sPP(pCCi9J$)TA?oYg*16Nsr`vO%V!lu>(ux&#!Ff5aLI)c^lpqZ#`exADKUe6!6w^dZlty=MnizD2R15U_nic8NNiER z)n~l|ul(O+}icPXD2)5_9xD^86ZA%xEoz(~TqdhYQ->2&! zBpYT!qZ;NXnF)M5!;dT9(VTwAJL?zhBc+0Qd?!2}{ynguW7)Wse0zq&L914L&+y>b zcslQ7F;*+0HE{9gb3>_)u^+dutQ7O%Y-ngal`7~TL&Hsc(KJ;INu55C(VFT=MJ z`(eb{hy4g-_Ts3|U`^xc``EKuf?gDIBfX0K%kV#seHY^W1^XcUu3~S{+UOegFJb8# z5npb65mWFc4_@->wGF_(My?#R<-7k2nPjd>ypQ`RMD>wqeO*F``w+>fZ*52kX+O1) z)fA(K2$?$7(~eeZw5cU(Mvn^n5sFfK2R#I%8C?*nAL6=)J0tDQ){>B)$1B&0MpuP! z9Qbfum^#B<%~lw%TcV#)JGI-f?bI5#DP|hT($-4xIw1FUo6&>-{SK1RNex6#My-NS z{Rwf~cSdJ~umr*A!gn=CybR&tj_8UI-liR7H8*YJ5?VT{ifBa<{K6;tfJ<)PDQ?Ml z@jn+MbcWT>J-j??^)B`lLuz+)|H14jI@YploxW6DJG5dEykP1nIc86tV?Ec(f;Y*_ zl#jZI=tmBmPOL>rZbN7r{lTQazR&+wi|!^=?A7n+Q$O~mHic`^Ef)`Nl-zQiyD@3K z>3VeQSar$-3(GU6HL*Nf=6^`uCp^XD{alva^65)#D}r=!+$y=7QbLio3?RaJQw<`F zB2^3_w|2_)xCWaGKfb1G!e#zKrP4BS-lL3gI5k(PB>tV5pYtlGuVym{ZcQ}2kL$EJ z+1|UD>0Rut)}C}dQIuH~KH`T*%o;EYBF9MtKZSL2jyz^B7|&nOyp{=8BfWslUm$1% z$$%d7H#xzHH9pp!QmE)wN^T|4A73M_>4@^)>gMTt*X~XJ7erq(@w>4ZW9G_V_DXCGQmS|bo6QC z=F22CwIemRQSr`gR7CRP+}%p?=jBQXd)-{QGTF2hZxj$01pIE-9`H}n!;F2Jx5QLU zkQh*)KmEvXRw`$IX!^-5sp|0VKTf93r*H4Z0LY|@(yma|K|c6i$a9q;2DYvRE`YjK zVhrYIV-KqHyrynfkmkf%?6SLw_Y2?J`Pn;K!=*?R5Jxm+&KTo4IO zsL3r#srfz=od+KGvZfW?K@5KI`nJM!%X8q@h5XobSNv%3WlFT+#fKjoiPKO$g1rOs zZtN!^@525fUfSPM_G3zZ4LkqDXvJ$UhP_wq!`S%;!$Y(^(T%-B;Rh9dLg}AS`hwEq zhlPqK^Bz|AUt?!pi%Ra)B%h=v nil then + FreeMem(MenuString, Succ(Length(MenuString^))); + if CommandString <> nil then + FreeMem(CommandString, Succ(Length(CommandString^))); + LastItem := MenuItems; + while LastItem <> nil do + begin + MenuItems := LastItem; + LastItem := LastItem^.Next; + Dispose(MenuItems); + end; +end; { Menu.Done } + +procedure Menu.AddItem(NewItem : MenuItemPtr); +{ Adds a new item to a menu } +begin + if MenuItems = nil then + begin + MenuItems := NewItem; + LastItem := MenuItems; + end + else begin + LastItem^.Next := NewItem; + LastItem := LastItem^.Next; + end; +end; { Menu.AddItem } + +function Menu.AddItemProc(NewProc : ProcPtr) : Boolean; +{ Adds a procedure item to a menu } +var + NewItem : MenuItemProcPtr; +begin + NewItem := New(MenuItemProcPtr, Init(NewProc)); + if NewItem <> nil then + begin + AddItem(NewItem); + AddItemProc := True; + end + else + AddItemProc := False; +end; { Menu.AddItemProc } + +function Menu.AddItemMenu(NewMenu : MenuPtr) : Boolean; +{ Adds a new menu item to a menu } +var + NewItem : MenuItemMenuPtr; +begin + NewItem := New(MenuItemMenuPtr, Init(NewMenu)); + if NewItem <> nil then + begin + AddItem(NewItem); + AddItemMenu := True; + end + else + AddItemMenu := False; +end; { Menu.AddItemMenu } + +procedure Menu.RunMenu; +{ Run a menu system } +var + Ch, Counter, P : Word; + CurrMenu : MenuPtr; + I : MenuItemPtr; +begin + CurrMenu := @Self; + repeat + with CurrMenu^ do + begin + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.MenuLoColor); { Print the menu } + for Counter := 1 to Length(MenuString^) do + begin + if MenuString^[Counter] in ['A'..'Z'] then + WriteColor(MenuString^[Counter], Colors.MenuHiColor) + else + WriteColor(MenuString^[Counter], Colors.MenuLoColor); + end; + repeat + Ch := GetKeyUpCase; + case Ch of + ESC : CurrMenu := Parent; + Ord(' ')..Ord('~') : begin + P := Pos(Chr(Lo(Ch)), CommandString^); + if P <> 0 then { A menu item has been chosen } + begin + I := MenuItems; + for Counter := 2 to P do + begin + if I <> nil then + I := I^.Next; + end; + if I <> nil then + begin + I^.RunItem(CurrMenu); { Run the procedure or switch menus } + Ch := ESC; + end; + end; + end; + end; { case } + until Ch = ESC; + end; { with } + until CurrMenu = nil; + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.MenuLoColor); +end; { Menu.RunMenu } + +constructor MenuItem.Init; +{ Initializes a menu item } +begin + Next := nil; +end; { MenuItem.Init } + +procedure MenuItem.RunItem(var CurrMenu : MenuPtr); +begin + Abstract('MenuItem.RunItem'); +end; { MenuItem.RunItem } + +constructor MenuItemProc.Init(InitProc : ProcPtr); +{ Initializes a procedure menu item } +begin + MenuItem.Init; + Proc := InitProc; +end; { MenuItemProc.Init } + +procedure MenuItemProc.RunItem(var CurrMenu : MenuPtr); +{ Runs the procedure that a procedure menu item points to } +begin + ClrEOLXY(1, Pred(Scr.CurrRows), Colors.MenuLoColor); + if @Proc <> nil then + Proc; + CurrMenu := nil; +end; { MenuItemProc.RunItem } + +constructor MenuItemMenu.Init(InitMenu : MenuPtr); +{ Initializes a new menu menu item } +begin + MenuItem.Init; + NewMenu := InitMenu; +end; { MenuItemMenu.Init } + +procedure MenuItemMenu.RunItem(var CurrMenu : MenuPtr); +{ Changes CurrMenu so that the menu that the item points to becomes the new + current menu } +begin + CurrMenu := NewMenu; +end; { MenuItemMenu.RunItem } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCMENU.TPU b/Borland Turbo Pascal v55/TCMENU.TPU new file mode 100644 index 0000000000000000000000000000000000000000..09ef7652798283bc0625cbe0dffdc9c4dcc7648a GIT binary patch literal 4528 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 S[Counter] then + begin + IsFunc := False; + Exit; + end; + end; + CurrToken.FuncName := UpperCase(Copy(Position, SLen)); + Inc(Position, SLen); + IsFunc := True; + end; { with } +end; { IsFunc } + +function ParserObj.NextToken : TokenTypes; +{ Gets the next Token from the Input stream } +var + NumString : String[80]; + FormLen, Place, TLen, NumLen, Check : Word; + Ch, FirstChar : Char; + Decimal : Boolean; +begin + with Inp^ do + begin + while (Position <= Length) and (Data^[Position] = ' ') do + Inc(Position); + TokenLen := Position; + if Position > Length then + begin + NextToken := EOL; + TokenLen := 0; + Exit; + end; + Ch := UpCase(Data^[Position]); + if Ch in ['0'..'9', '.'] then + begin + NumString := ''; + TLen := Position; + Decimal := False; + while (TLen <= Length) and + ((Data^[TLen] in ['0'..'9']) or + ((Data^[TLen] = '.') and (not Decimal))) do + begin + NumString := NumString + Data^[TLen]; + if Ch = '.' then + Decimal := True; + Inc(TLen); + end; + if (TLen = 2) and (Ch = '.') then + begin + NextToken := BAD; + TokenLen := 0; + Exit; + end; + if (TLen <= Length) and ((Data^[TLen] = 'E') or + (Data^[TLen] = 'e')) then + begin + NumString := NumString + 'E'; + Inc(TLen); + if Data^[TLen] in ['+', '-'] then + begin + NumString := NumString + Data^[TLen]; + Inc(TLen); + end; + NumLen := 1; + while (TLen <= Length) and (Data^[TLen] in ['0'..'9']) and + (NumLen <= MaxExpLen) do + begin + NumString := NumString + Data^[TLen]; + Inc(NumLen); + Inc(TLen); + end; + end; + if NumString[1] = '.' then + NumString := '0' + NumString; + Val(NumString, CurrToken.Value, Check); + if Check <> 0 then + MathError := True; + NextToken := NUM; + Inc(Position, System.Length(NumString)); + TokenLen := Position - TokenLen; + Exit; + end + else if Ch in Letters then + begin + if IsFunc('ABS') or + IsFunc('ATAN') or + IsFunc('COS') or + IsFunc('EXP') or + IsFunc('LN') or + IsFunc('ROUND') or + IsFunc('SIN') or + IsFunc('SQRT') or + IsFunc('SQR') or + IsFunc('TRUNC') then + begin + NextToken := FUNC; + TokenLen := Position - TokenLen; + Exit; + end; + if FormulaStart(Inp, Position, PMaxCols, PMaxRows, CurrToken.CP, + FormLen) then + begin + Inc(Position, FormLen); + IsFormula := True; + NextToken := CELLT; + TokenLen := Position - TokenLen; + Exit; + end + else begin + NextToken := BAD; + TokenLen := 0; + Exit; + end; + end + else begin + case Ch of + '+' : NextToken := PLUS; + '-' : NextToken := MINUS; + '*' : NextToken := TIMES; + '/' : NextToken := DIVIDE; + '^' : NextToken := EXPO; + ':' : NextToken := COLON; + '(' : NextToken := OPAREN; + ')' : NextToken := CPAREN; + else begin + NextToken := BAD; + TokenLen := 0; + Exit; + end; + end; + Inc(Position); + TokenLen := Position - TokenLen; + Exit; + end; { case } + end; { with } +end; { ParserObj.NextToken } + +procedure ParserObj.Push(Token : TokenRec); +{ Pushes a new Token onto the stack } +begin + if StackTop = ParserStackSize then + TokenError := ErrParserStack + else begin + Inc(StackTop); + Stack[StackTop] := Token; + end; +end; { ParserObj.Push } + +procedure ParserObj.Pop(var Token : TokenRec); +{ Pops the top Token off of the stack } +begin + Token := Stack[StackTop]; + Dec(StackTop); +end; { ParserObj.Pop } + +function ParserObj.GotoState(Production : Word) : Word; +{ Finds the new state based on the just-completed production and the + top state. +} +var + State : Word; +begin + State := Stack[StackTop].State; + if (Production <= 3) then + begin + case State of + 0 : GotoState := 1; + 9 : GotoState := 19; + 20 : GotoState := 28; + end; { case } + end + else if Production <= 6 then + begin + case State of + 0, 9, 20 : GotoState := 2; + 12 : GotoState := 21; + 13 : GotoState := 22; + end; { case } + end + else if Production <= 8 then + begin + case State of + 0, 9, 12, 13, 20 : GotoState := 3; + 14 : GotoState := 23; + 15 : GotoState := 24; + 16 : GotoState := 25; + end; { case } + end + else if Production <= 10 then + begin + case State of + 0, 9, 12..16, 20 : GotoState := 4; + end; { case } + end + else if Production <= 12 then + begin + case State of + 0, 9, 12..16, 20 : GotoState := 6; + 5 : GotoState := 17; + end; { case } + end + else begin + case State of + 0, 5, 9, 12..16, 20 : GotoState := 8; + end; { case } + end; +end; { ParserObj.GotoState } + +function ParserObj.CellValue(P : CellPos) : Extended; +{ Returns the value of a cell } +var + CPtr : CellPtr; +begin + CPtr := ParserHash^.Search(P); + with CPtr^ do + begin + if (not LegalValue) or HasError then + begin + MathError := True; + CellValue := 0; + end + else + CellValue := CurrValue; + end; { with } +end; { ParserObj.CellValue } + +procedure ParserObj.Shift(State : Word); +{ Shifts a Token onto the stack } +begin + CurrToken.State := State; + Push(CurrToken); + TokenType := NextToken; +end; { ParserObj.Shift } + +procedure ParserObj.Reduce(Reduction : Word); +{ Completes a reduction } +var + Token1, Token2 : TokenRec; + Counter : CellPos; +begin + case Reduction of + 1 : begin + Pop(Token1); + Pop(Token2); + Pop(Token2); + CurrToken.Value := Token1.Value + Token2.Value; + end; + 2 : begin + Pop(Token1); + Pop(Token2); + Pop(Token2); + CurrToken.Value := Token2.Value - Token1.Value; + end; + 4 : begin + Pop(Token1); + Pop(Token2); + Pop(Token2); + CurrToken.Value := Token1.Value * Token2.Value; + end; + 5 : begin + Pop(Token1); + Pop(Token2); + Pop(Token2); + if Token1.Value = 0 then + MathError := True + else + CurrToken.Value := Token2.Value / Token1.Value; + end; + 7 : begin + Pop(Token1); + Pop(Token2); + Pop(Token2); + if Token2.Value <= 0 then + MathError := True + else if (Token1.Value * Ln(Token2.Value) < -ExpLimit) or + (Token1.Value * Ln(Token2.Value) > ExpLimit) then + MathError := True + else + CurrToken.Value := Exp(Token1.Value * Ln(Token2.Value)); + end; + 9 : begin + Pop(Token1); + Pop(Token2); + CurrToken.Value := -Token1.Value; + end; + 11 : begin + Pop(Token1); + Pop(Token2); + Pop(Token2); + CurrToken.Value := 0; + if Token1.CP.Row = Token2.CP.Row then + begin + if Token1.CP.Col < Token2.CP.Col then + TokenError := ErrBadRange + else begin + Counter.Row := Token1.CP.Row; + for Counter.Col := Token2.CP.Col to Token1.CP.Col do + CurrToken.Value := CurrToken.Value + CellValue(Counter); + end; + end + else if Token1.CP.Col = Token2.CP.Col then + begin + if Token1.CP.Row < Token2.CP.Row then + TokenError := ErrBadRange + else begin + Counter.Col := Token1.CP.Col; + for Counter.Row := Token2.CP.Row to Token1.CP.Row do + CurrToken.Value := CurrToken.Value + CellValue(Counter); + end; + end + else if (Token1.CP.Col >= Token2.CP.Col) and + (Token1.CP.Row >= Token2.CP.Row) then + begin + for Counter.Row := Token2.CP.Row to Token1.CP.Row do + begin + for Counter.Col := Token2.CP.Col to Token1.CP.Col do + CurrToken.Value := CurrToken.Value + CellValue(Counter); + end; + end + else + TokenError := ErrBadRange; + end; + 13 : begin + Pop(CurrToken); + CurrToken.Value := CellValue(CurrToken.CP); + end; + 14 : begin + Pop(Token1); + Pop(CurrToken); + Pop(Token1); + end; + 16 : begin + Pop(Token1); + Pop(CurrToken); + Pop(Token1); + Pop(Token1); + if Token1.FuncName = 'ABS' then + CurrToken.Value := Abs(CurrToken.Value) + else if Token1.FuncName = 'ATAN' then + CurrToken.Value := ArcTan(CurrToken.Value) + else if Token1.FuncName = 'COS' then + CurrToken.Value := Cos(CurrToken.Value) + else if Token1.FuncName = 'EXP' then + begin + if (CurrToken.Value < -ExpLimit) or (CurrToken.Value > ExpLimit) then + MathError := True + else + CurrToken.Value := Exp(CurrToken.Value); + end + else if Token1.FuncName = 'LN' then + begin + if CurrToken.Value <= 0 then + MathError := True + else + CurrToken.Value := Ln(CurrToken.Value); + end + else if Token1.FuncName = 'ROUND' then + begin + if (CurrToken.Value < -1E9) or (CurrToken.Value > 1E9) then + MathError := True + else + CurrToken.Value := Round(CurrToken.Value); + end + else if Token1.FuncName = 'SIN' then + CurrToken.Value := Sin(CurrToken.Value) + else if Token1.FuncName = 'SQRT' then + begin + if CurrToken.Value < 0 then + MathError := True + else + CurrToken.Value := Sqrt(CurrToken.Value); + end + else if Token1.FuncName = 'SQR' then + begin + if (CurrToken.Value < -SQRLIMIT) or (CurrToken.Value > SQRLIMIT) then + MathError := True + else + CurrToken.Value := Sqr(CurrToken.Value); + end + else if Token1.FuncName = 'TRUNC' then + begin + if (CurrToken.Value < -1E9) or (CurrToken.Value > 1E9) then + MathError := True + else + CurrToken.Value := Trunc(CurrToken.Value); + end; + end; + 3, 6, 8, 10, 12, 15 : Pop(CurrToken); + end; { case } + CurrToken.State := GotoState(Reduction); + Push(CurrToken); +end; { ParserObj.Reduce } + +procedure ParserObj.Parse; +{ Parses an input stream } +var + FirstToken : TokenRec; + Accepted : Boolean; +begin + Position := 1; + StackTop := 0; + TokenError := 0; + MathError := False; + IsFormula := False; + ParseError := False; + with Inp^ do + begin + if (Length = 2) and (Data^[1] = RepeatFirstChar) then + begin + CType := ClRepeat; + Exit; + end; + if Data^[1] = TextFirstChar then + begin + CType := ClText; + Exit; + end; + end; { with } + Accepted := False; + FirstToken.State := 0; + FirstToken.Value := 0; + Push(FirstToken); + TokenType := NextToken; + repeat + case Stack[StackTop].State of + 0, 9, 12..16, 20 : begin + if TokenType = NUM then + Shift(10) + else if TokenType = CELLT then + Shift(7) + else if TokenType = FUNC then + Shift(11) + else if TokenType = MINUS then + Shift(5) + else if TokenType = OPAREN then + Shift(9) + else begin + TokenError := ErrExpression; + Dec(Position, TokenLen); + end; + end; + 1 : begin + if TokenType = EOL then + Accepted := True + else if TokenType = PLUS then + Shift(12) + else if TokenType = MINUS then + Shift(13) + else begin + TokenError := ErrOperator; + Dec(Position, TokenLen); + end; + end; + 2 : begin + if TokenType = TIMES then + Shift(14) + else if TokenType = DIVIDE then + Shift(15) + else + Reduce(3); + end; + 3 : Reduce(6); + 4 : begin + if TokenType = EXPO then + Shift(16) + else + Reduce(8); + end; + 5 : begin + if TokenType = NUM then + Shift(10) + else if TokenType = CELLT then + Shift(7) + else if TokenType = FUNC then + Shift(11) + else if TokenType = OPAREN then + Shift(9) + else + TokenError := ErrExpression; + end; + 6 : Reduce(10); + 7 : begin + if TokenType = COLON then + Shift(18) + else + Reduce(13); + end; + 8 : Reduce(12); + 10 : Reduce(15); + 11 : begin + if TokenType = OPAREN then + Shift(20) + else + TokenError := ErrOpenParen; + end; + 17 : Reduce(9); + 18 : begin + if TokenType = CELLT then + Shift(26) + else + TokenError := ErrCell; + end; + 19 : begin + if TokenType = PLUS then + Shift(12) + else if TokenType = MINUS then + Shift(13) + else if TokenType = CPAREN then + Shift(27) + else + TokenError := ErrOpCloseParen; + end; + 21 : begin + if TokenType = TIMES then + Shift(14) + else if TokenType = DIVIDE then + Shift(15) + else + Reduce(1); + end; + 22 : begin + if TokenType = TIMES then + Shift(14) + else if TokenType = DIVIDE then + Shift(15) + else + Reduce(2); + end; + 23 : Reduce(4); + 24 : Reduce(5); + 25 : Reduce(7); + 26 : Reduce(11); + 27 : Reduce(14); + 28 : begin + if TokenType = PLUS then + Shift(12) + else if TokenType = MINUS then + Shift(13) + else if TokenType = CPAREN then + Shift(29) + else + TokenError := ErrOpCloseParen; + end; + 29 : Reduce(16); + end; { case } + until Accepted or (TokenError <> 0); + if TokenError <> 0 then + begin + with Scr do + begin + if TokenError = ErrBadRange then + Dec(Position, TokenLen); + PrintError(ErrorMessages[TokenError]); + Exit; + end; { with } + end; + if IsFormula then + CType := ClFormula + else + CType := ClValue; + if MathError then + begin + ParseError := True; + ParseValue := 0; + Exit; + end; + ParseError := False; + ParseValue := Stack[StackTop].Value; +end; { ParserObj.Parse } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCPARSER.TPU b/Borland Turbo Pascal v55/TCPARSER.TPU new file mode 100644 index 0000000000000000000000000000000000000000..4fbc0e7b0620bf1b49998282c34bb040dfedeb13 GIT binary patch literal 11968 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 ZoI7GHyblLD9Wxe+edGlCiR+-4{|ll+n{NOB literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TCRUN.PAS b/Borland Turbo Pascal v55/TCRUN.PAS new file mode 100644 index 0000000..a518a50 --- /dev/null +++ b/Borland Turbo Pascal v55/TCRUN.PAS @@ -0,0 +1,1366 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit TCRun; +{ Turbo Pascal 5.5 object-oriented example run module. + This unit is used by TCALC.PAS. + See TCALC.DOC for an more information about this example. +} + +{$N+,S-} + +interface + +uses Crt, Dos, TCUtil, TCLStr, TCScreen, TCHash, TCCell, TCCellSp, TCSheet, + TCInput, TCParser, TCMenu; + +const + FreeListItems = 1000; + MenuHeapSpace = 1000; + MaxSpreadsheets = (MinScreenRows - EmptyRowsAtTop - EmptyRowsAtBottom) div + 4; + LegalJustification = ['L', 'C', 'R']; + HelpLine = 'F2\Save\F3\Load\F7\Formula\F8\AutoCalc\F9\Recalc\F10\Menu\Ins\Block\Alt-X\Exit'; + TitleString = 'TurboCalc - Turbo Pascal Demo Program'; + MainMenuString = 'Spreadsheet, Block, Column, Row, Format, Goto, Edit, Options, Quit'; + SpreadsheetMenuString = 'Load, Save, Zap, Write, Open, Close, Next, Print'; + OpenMenuString = 'Load, New'; + BlockMenuString = 'Copy, Delete, Format, Restore default format'; + ColumnMenuString = 'Insert, Delete, Width'; + RowMenuString = 'Insert, Delete'; + UtilityMenuString1 = 'Screen lines, Recalc, Formula display, Autocalc'; + UtilityMenuString2 = 'Recalc, Formula display, Autocalc'; + PromptFileLoad = 'File to load'; + PromptGotoCell = 'Go to cell'; + PromptCopyCell = 'Copy to cell'; + PromptColLiteral = 'Copy formula columns literally'; + PromptRowLiteral = 'Copy formula rows literally'; + PromptCopySpreadsheet = 'Copy to spreadsheet number (0 = current)'; + PromptFormatPlaces = 'Number of decimal places'; + PromptFormatJustification = 'Justification - (L)eft, (C)enter, (R)ight'; + PromptFormatDollar = 'Dollar format'; + PromptFormatCommas = 'Put commas in numbers'; + ErrFreeList = 'The free list is full'; + MsgBlockCopy = 'Copying block'; + +type + ProgramObject = object + SSData, CurrSS : SpreadsheetPtr; + TotalSheets : Byte; + CellInput : InputField; + MainMenu : Menu; + SpreadsheetMenu : Menu; + OpenMenu : Menu; + BlockMenu : Menu; + ColumnMenu : Menu; + RowMenu : Menu; + UtilityMenu : Menu; + Stop : Boolean; + constructor Init; + destructor Done; + procedure GetCommands; + procedure SetDisplayAreas; + procedure DisplayAll; + function AddSheet(Name : PathStr) : Boolean; + procedure DeleteSheet; + end; + +var + Vars : ProgramObject; + +procedure Run; + +implementation + +const + RedrawYes = True; + RedrawNo = False; + +{$F+} + +function RunHeapError(Size : Word) : Integer; +{ Prints an error if the heap runs out of memory } +begin + Scr.PrintError(ErrNoMemory); + RunHeapError := 1; +end; { RunHeapError } + +{$F-} + +procedure InitMenus; forward; + +constructor ProgramObject.Init; +{ Sets up the program } +var + Counter : Word; + Good : Boolean; +begin { ProgramObject.Init } + if MaxAvail < MenuHeapSpace then + Abort(ErrNoMemory); + InitMenus; + TotalSheets := 0; + SSData := nil; + CurrSS := nil; + Stop := False; + if ParamCount = 0 then { Load spreadsheets named on command line } + begin + if not AddSheet('') then + Abort(ErrNoMemory); + end + else begin + Counter := 1; + repeat + Good := AddSheet(ParamStr(Counter)); + Inc(Counter); + until (not Good) or (Counter > Min(ParamCount, MaxSpreadsheets)); + end; + SetDisplayAreas; + DisplayAll; + with CurrSS^ do + begin + MakeCurrent; + DisplayCell(CurrPos); + end; { with } +end; { ProgramObject.Init } + +destructor ProgramObject.Done; +{ Releases all memory used by the program } +begin + CurrSS^.MakeNotCurrent; + while SSData <> nil do + begin + CurrSS := SSData; + SSData := SSData^.Next; + with CurrSS^ do + begin + MakeCurrent; + DisplayCell(CurrPos); + CheckForSave; + MakeNotCurrent; + DisplayCell(CurrPos); + Dispose(CurrSS, Done); + end; { with } + end; + MainMenu.Done; + SpreadsheetMenu.Done; + OpenMenu.Done; + BlockMenu.Done; + ColumnMenu.Done; + RowMenu.Done; + UtilityMenu.Done; +end; { ProgramObject.Done } + +function GetFormat(var Format : Byte) : Boolean; +{ Reads a format value from the keyboard } +var + Places : Byte; + J : Justification; + ESCPressed, Good, Dollar, Commas : Boolean; + Ch : Char; +begin + GetFormat := False; + Dollar := GetYesNo(PromptFormatDollar, ESCPressed); + if ESCPressed then + Exit; + if Dollar then + begin + Places := 2; + J := JRight; + end + else begin + Places := GetNumber(PromptFormatPlaces, 0, + Vars.CurrSS^.MaxDecimalPlaces, Good); + if not Good then + Exit; + Ch := GetLegalChar(PromptFormatJustification, LegalJustification, + ESCPressed); + if ESCPressed then + Exit; + case Ch of + 'L' : J := JLeft; + 'C' : J := JCenter; + 'R' : J := JRight; + end; { case } + end; + Commas := GetYesNo(PromptFormatCommas, ESCPressed); + if ESCPressed then + Exit; + Format := Places + (Ord(J) shl 4) + (Ord(Dollar) shl 6) + + (Ord(Commas) shl 7); + GetFormat := True; +end; { GetFormat } + +procedure EditInput(Ch : Word; Editing : Boolean); +{ Edits the data on the input line } +var + Good, FirstEdit, Deleted : Boolean; + P : CellPos; +begin + with Vars, CurrSS^ do + begin + if not CellInput.Init(1, 0, -1, 0, NotUpper) then + Exit; + with CellInput.InputData^ do + begin + if Editing then + begin + Good := True; + CellHash.Search(CurrPos)^.EditString(MaxDecimalPlaces, + CellInput.InputData) + end + else + Good := FromString(Chr(Ch)); + if not Good then + begin + CellInput.Done; + Exit; + end; + FirstEdit := True; + Parser.Init(@CellHash, CellInput.InputData, MaxCols, MaxRows); + repeat + if FirstEdit then + CellInput.Edit(0) + else + CellInput.Edit(Parser.Position); + if Length > 0 then + begin + Parser.Parse; + if Parser.TokenError = 0 then + begin + DeleteCell(CurrPos, Deleted); + Good := AddCell(Parser.CType, CurrPos, Parser.ParseError, + Parser.ParseValue, CellInput.InputData); + end; + end; + FirstEdit := False; + until (Length = 0) or (Parser.TokenError = 0); + if Length > 0 then + begin + SetChanged(WasChanged); + if AutoCalc then + Update(DisplayYes); + P := CurrPos; + for P.Col := CurrPos.Col to ScreenBlock.Stop.Col do + DisplayCell(P); + end; + CellInput.InputArea.Clear; + end; { with } + CellInput.Done; + DisplayMemory; + end; { with } +end; { EditInput } + +procedure OpenSpreadsheet(Name : String); +{ Opens a new spreadsheet } +begin + with Vars do + begin + if not AddSheet(Name) then + Exit; + SetDisplayAreas; + DisplayAll; + with CurrSS^ do + begin + MakeCurrent; + DisplayCell(CurrPos); + end; { with } + end; { with } +end; { OpenSpreadsheet } + +procedure ClearCurrBlock; +{ Turns off the block and redisplays the cells in it } +begin + with Vars.CurrSS^ do + begin + if BlockOn then + begin + BlockOn := False; + DisplayBlock(CurrBlock); + end; + end; +end; { ClearCurrBlock } + +{$F+} + +procedure ReplaceSpreadsheet; +{ Load a spreadsheet over the current one } +var + S : PathStr; + ESCPressed : Boolean; +begin + with Vars.CurrSS^ do + begin + S := ReadString(PromptFileLoad, Pred(SizeOf(PathStr)), ESCPressed); + if S = '' then + Exit; + CheckForSave; + Done; + if FromFile(S) then + begin + SetChanged(NotChanged); + SetScreenColStart(1); + SetScreenRowStart(1); + Display; + MakeCurrent; + DisplayCell(CurrPos); + end; + end; { with } +end; { ReplaceSpreadsheet } + +procedure NameSaveSpreadsheet; +{ Save a spreadsheet to a file other that its default } +var + St : PathStr; + ESCPressed : Boolean; +begin + with Vars.CurrSS^ do + begin + St := ReadString(PromptFileSave, Pred(SizeOf(PathStr)), ESCPressed); + if St = '' then + Exit; + if FileExists(St) then + begin + if not GetYesNo(PromptOverwriteFile, ESCPressed) then + Exit; + end; + ToFile(St); + DisplayFileName; + end; { with } +end; { NameSaveSpreadsheet } + +procedure SaveCurrSpreadsheet; +{ Save a spreadsheet to its default file } +begin + with Vars.CurrSS^ do + begin + if FileName = '' then + NameSaveSpreadsheet + else + ToFile(FileName); + end; { with } +end; { SaveCurrSpreadsheet } + +procedure ZapSpreadsheet; +{ Clear the current spreadsheet from memory } +var + S : PathStr; +begin + with Vars.CurrSS^ do + begin + CheckForSave; + S := FileName; + Done; + Init(0, DefaultMaxCols, DefaultMaxRows, DefaultMaxDecimalPlaces, + DefaultDefaultDecimalPlaces, DefaultDefaultColWidth); + MakeCurrent; + FileName := S; + SetScreenColStart(1); + SetScreenRowStart(1); + Display; + end; { with } +end; { ZapSpreadsheet } + +procedure CloseSpreadsheet; +{ Delete a spreadsheet, closing the window that it is in } +begin + with Vars, CurrSS^ do + begin + if TotalSheets = 1 then + Exit; + DeleteSheet; + end; { with } +end; { CloseSpreadsheet } + +procedure NextSpreadsheet; +{ Move to the next spreadsheet } +begin + with Vars do + begin + if TotalSheets = 1 then + Exit; + with CurrSS^ do + begin + MakeNotCurrent; + DisplayCell(CurrPos); + end; { with } + CurrSS := CurrSS^.Next; + if CurrSS = nil then + CurrSS := SSData; + with CurrSS^ do + begin + MakeCurrent; + DisplayCell(CurrPos); + end; { with } + end; { with } +end; { NextSpreadsheet } + +procedure NewSpreadsheet; +{ Create a new spreadsheet, opening a window for it and loading it } +var + S : PathStr; + ESCPressed : Boolean; +begin + with Vars do + begin + if TotalSheets >= MaxSpreadsheets then + Exit; + S := ReadString(PromptFileLoad, Pred(SizeOf(PathStr)), ESCPressed); + if S = '' then + Exit; + OpenSpreadsheet(S); + end; { with } +end; { NewSpreadsheet } + +procedure NewBlankSpreadsheet; +{ Create a new blank spreadsheet, opening a window for it } +begin + with Vars do + begin + if TotalSheets >= MaxSpreadsheets then + Exit; + OpenSpreadsheet(''); + end; { with } +end; { NewBlankSpreadsheet } + +procedure PrintSpreadsheet; +{ Print a spreadsheet to a file or a printer } +begin + Vars.CurrSS^.Print; +end; { PrintSpreadsheet } + +procedure CopyBlock; +{ Copy a block of cells from one spreadsheet to the same or a different + spreadsheet } +var + P, N, C : CellPos; + Good, ESCPressed, ColLit, RowLit, AnyChanged, Deleted : Boolean; + CP : CellPtr; + L : LStringPtr; + CopyTo : SpreadsheetPtr; + CopySheet : Byte; + Counter : Word; +begin + with Vars, CurrSS^, CurrBlock do + begin + if not BlockOn then + Exit; + if TotalSheets > 1 then + CopySheet := GetNumber(PromptCopySpreadsheet, 0, TotalSheets, Good) + else + CopySheet := 1; + if not Good then + Exit; + if not GetCellPos(PromptCopyCell, MaxCols, MaxRows, ColSpace, + RowNumberSpace, P) then + Exit; + ColLit := GetYesNo(PromptColLiteral, ESCPressed); + if ESCPressed then + Exit; + RowLit := GetYesNo(PromptRowLiteral, ESCPressed); + if ESCPressed then + Exit; + Scr.PrintMessage(MsgBlockCopy); + if CopySheet = 0 then + CopyTo := CurrSS + else begin + CopyTo := SSData; + for Counter := 2 to CopySheet do + CopyTo := CopyTo^.Next; + end; + AnyChanged := False; + C.Row := P.Row; + N.Row := Start.Row; + L := New(LStringPtr, Init); + Good := L <> nil; + while Good and (N.Row <= Stop.Row) do + begin + C.Col := P.Col; + N.Col := Start.Col; + while Good and (N.Col <= Stop.Col) do + begin + if (Longint(P.Col) + N.Col - Start.Col <= MaxCols) and + (Longint(P.Row) + N.Row - Start.Row <= MaxRows) then + begin + CopyTo^.DeleteCell(C, Deleted); + if Deleted then + AnyChanged := True; + CP := CellHash.Search(N); + if CP <> Empty then + begin + AnyChanged := True; + with CP^ do + Good := CopyTo^.AddCell(CellType, C, HasError, CurrValue, + CopyString(ColLit, RowLit, + Longint(C.Col) - N.Col, L)); + if Good and ((not ColLit) or (not RowLit)) then + begin + CP := CopyTo^.CellHash.Search(C); + if CP^.ShouldUpdate then + begin + if not ColLit then + FixFormulaCol(CP, Longint(C.Col) - N.Col, MaxCols, + MaxRows); + if not RowLit then + FixFormulaRow(CP, Longint(C.Row) - N.Row, MaxCols, + MaxRows); + end; + end; + end; + end; + Inc(C.Col); + Inc(N.Col); + end; + Inc(C.Row); + Inc(N.Row); + end; + if AnyChanged then + begin + if CopySheet = 0 then + BlockOn := False; + with CopyTo^ do + begin + SetLastPos(LastPos); + SetChanged(WasChanged); + if AutoCalc then + Update(DisplayNo); + DisplayAllCells; + DisplayMemory; + end; { with } + if CopySheet <> 0 then + ClearCurrBlock; + end + else + ClearCurrBlock; + Scr.ClearMessage; + end; { with } + if L <> nil then + Dispose(L, Done); +end; { CopyBlock } + +procedure DeleteBlock; +{ Delete a block of cells } +var + Deleted : Boolean; +begin + with Vars.CurrSS^, CurrBlock do + begin + if not BlockOn then + Exit; + DeleteBlock(CurrBlock, Deleted); + if Deleted then + begin + BlockOn := False; + SetLastPos(LastPos); + SetChanged(WasChanged); + if AutoCalc then + Update(DisplayNo); + DisplayMemory; + DisplayAllCells; + end + else + ClearCurrBlock; + end; { with } +end; { DeleteBlock } + +procedure FormatBlock; +{ Format a block of cells } +var + Format : Byte; +begin + with Vars.CurrSS^ do + begin + if not BlockOn then + Exit; + if not GetFormat(Format) then + Exit; + with CurrBlock do + begin + if not FormatHash.Add(Start, Stop, Format) then + Exit; + SetChanged(WasChanged); + DisplayAllCells; + DisplayMemory; + end; { with } + end; { with } +end; { FormatBlock } + +procedure FormatDefault; +{ Change the format of a block of cells to the default } +begin + with Vars.CurrSS^ do + begin + if not BlockOn then + Exit; + with CurrBlock do + begin + if not FormatHash.Delete(Start, Stop) then + Exit; + SetChanged(WasChanged); + DisplayAllCells; + DisplayMemory; + end; { with } + end; { with } +end; { FormatDefault } + +procedure ColInsert; +{ Insert a column into the spreadsheet } +begin + Vars.CurrSS^.InsertColumn; +end; { ColInsert } + +procedure ColDelete; +{ Delete a column from the spreadsheet } +begin + Vars.CurrSS^.DeleteColumn; +end; { ColDelete } + +procedure ChangeColWidth; +{ Change the width of a column } +begin + Vars.CurrSS^.ChangeWidth; +end; { ChangeColWidth } + +procedure RowInsert; +{ Insert a row into the spreadsheet } +begin + Vars.CurrSS^.InsertRow; +end; { RowInsert } + +procedure RowDelete; +{ Delete a row from the spreadsheet } +begin + Vars.CurrSS^.DeleteRow; +end; { RowDelete } + +procedure ToggleMaxLines; +{ Toggle 43/50-line mode } +begin + with Vars do + begin + Scr.ToggleMaxLinesMode; + SetCursor(NoCursor); + SetDisplayAreas; + DisplayAll; + end; { with } +end; { ToggleMaxLines } + +procedure Recalc; +{ Recalculate all of the cells } +begin + Vars.CurrSS^.Update(DisplayYes); +end; { Recalc } + +procedure ToggleFormulas; +{ Toggle formula display on and off } +begin + with Vars.CurrSS^ do + ToggleFormulaDisplay; +end; { ToggleFormulas } + +procedure ToggleAutoCalc; +{ Toggle AutoCalc on and off } +begin + with Vars.CurrSS^ do + begin + if AutoCalc then + begin + AutoCalc := False; + DisplayInfo; + end + else begin + AutoCalc := True; + DisplayInfo; + Update(DisplayYes); + end; + end; +end; { ToggleAutoCalc } + +procedure FormatCell; +{ Format a single cell } +var + Format : Byte; + P : CellPos; + CP : CellPtr; + Good : Boolean; +begin + with Vars.CurrSS^ do + begin + if not GetFormat(Format) then + Exit; + if not FormatHash.Add(CurrPos, CurrPos, Format) then + Exit; + CP := CellHash.Search(CurrPos); + SetChanged(WasChanged); + OverwriteHash.Delete(CurrPos); + if CP <> Empty then + Good := OverwriteHash.Add(CP, CP^.Overwritten(CellHash, FormatHash, + WidthHash, LastPos, MaxCols, GetColWidth, + DisplayFormulas)); + P := CurrPos; + for P.Col := CurrPos.Col to ScreenBlock.Stop.Col do + DisplayCell(P); + DisplayMemory; + end; { with } +end; { FormatCell } + +procedure GotoCell; +{ Go to a selected cell } +var + P, OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + if not GetCellPos(PromptGotoCell, MaxCols, MaxRows, ColSpace, + RowNumberSpace, P) then + Exit; + if not ScreenBlock.CellInBlock(P) then + begin + CurrPos := P; + SetScreenColStart(CurrPos.Col); + SetScreenRowStart(CurrPos.Row); + Display; + end + else begin + OldPos := CurrPos; + CurrPos := P; + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; { with } +end; { GotoCell } + +procedure EditCell; +{ Edit the current cell } +begin + EditInput(0, EditYes); +end; { EditCell } + +procedure Quit; +{ Exit from the program } +begin + Vars.Stop := True; +end; { Quit } + +{$F-} + +procedure ExtendCurrBlock(Redraw : Boolean); +{ Extend the current block and redraw any cells that are affected } +var + OldBlock : Block; +begin + with Vars.CurrSS^ do + begin + if BlockOn then + begin + Move(CurrBlock, OldBlock, SizeOf(CurrBlock)); + if CurrBlock.ExtendTo(CurrPos) then + begin + if Redraw then + DisplayBlockDiff(OldBlock, CurrBlock); + end + else + ClearCurrBlock; + end; + end; { with } +end; { ExtendCurrBlock } + +procedure ToggleCurrBlock; +{ Turn the block on and off } +begin + with Vars.CurrSS^ do + begin + if not BlockOn then + begin + BlockOn := True; + CurrBlock.Init(CurrPos); + end + else + ClearCurrBlock; + end; { with } +end; { ToggleCurrBlock } + +procedure RemoveCell; +{ Delete a cell } +var + P : CellPos; + Deleted : Boolean; +begin + with Vars.CurrSS^ do + begin + DeleteCell(CurrPos, Deleted); + if Deleted then + begin + SetLastPos(CurrPos); + SetChanged(WasChanged); + if AutoCalc then + Update(DisplayYes); + P.Row := CurrPos.Row; + for P.Col := CurrPos.Col to ScreenBlock.Stop.Col do + DisplayCell(P); + DisplayMemory; + end; + end; { with } +end; { RemoveCell } + +procedure MoveHome; +{ Move to the home position (1, 1) } +var + OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + OldPos := CurrPos; + CurrPos.Col := 1; + CurrPos.Row := 1; + if not ScreenBlock.CellInBlock(CurrPos) then + begin + ExtendCurrBlock(RedrawNo); + SetScreenColStart(1); + SetScreenRowStart(1); + SetBlankArea; + Display; + end + else begin + ExtendCurrBlock(RedrawYes); + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; { with } +end; { MoveHome } + +procedure MoveEnd; +{ Move to the last position used } +var + OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + OldPos := CurrPos; + CurrPos := LastPos; + if not ScreenBlock.CellInBlock(CurrPos) then + begin + ExtendCurrBlock(RedrawNo); + SetScreenColStop(CurrPos.Col); + SetScreenRowStop(CurrPos.Row); + SetBlankArea; + Display; + end + else begin + ExtendCurrBlock(RedrawYes); + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; { with } +end; { MoveEnd } + +procedure MoveUp; +{ Move up a row } +var + OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + if CurrPos.Row > 1 then + begin + OldPos := CurrPos; + Dec(CurrPos.Row); + ExtendCurrBlock(RedrawYes); + if CurrPos.Row < ScreenBlock.Start.Row then + begin + DisplayCell(OldPos); + SetScreenRowStart(CurrPos.Row); + DisplayRows; + DisplayArea.Scroll(Down, 1); + DisplayRow(CurrPos.Row); + end + else begin + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; + end; { with } +end; { MoveUp } + +procedure MoveDown; +{ Move down a row } +var + OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + if CurrPos.Row < MaxRows then + begin + OldPos := CurrPos; + Inc(CurrPos.Row); + if CurrPos.Row > ScreenBlock.Stop.Row then + begin + ExtendCurrBlock(RedrawNo); + DisplayCell(OldPos); + SetScreenRowStop(CurrPos.Row); + DisplayRows; + DisplayArea.Scroll(Up, 1); + DisplayRow(CurrPos.Row); + end + else begin + ExtendCurrBlock(RedrawYes); + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; + end; { with } +end; { MoveDown } + +procedure MovePgUp; +{ Move up a page } +var + OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + if CurrPos.Row > 1 then + begin + OldPos := CurrPos; + CurrPos.Row := Max(1, Longint(CurrPos.Row) - TotalRows); + ExtendCurrBlock(RedrawNo); + if CurrPos.Row < ScreenBlock.Start.Row then + begin + SetScreenRowStart(CurrPos.Row); + DisplayRows; + DisplayAllCells; + end + else begin + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; + end; { with } +end; { MovePgUp } + +procedure MovePgDn; +{ Move down a page } +var + OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + if CurrPos.Row < MaxRows then + begin + OldPos := CurrPos; + CurrPos.Row := Min(MaxRows, Longint(CurrPos.Row) + TotalRows); + ExtendCurrBlock(RedrawNo); + if CurrPos.Row > ScreenBlock.Start.Row then + begin + SetScreenRowStart(CurrPos.Row); + DisplayRows; + DisplayAllCells; + end + else begin + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; + end; { with } +end; { MovePgDn } + +procedure MoveLeft; +{ Move left a column } +var + C : Word; + OldPos : CellPos; + OldSCol : Word; +begin + with Vars.CurrSS^ do + begin + if CurrPos.Col > 1 then + begin + OldPos := CurrPos; + Dec(CurrPos.Col); + ExtendCurrBlock(RedrawYes); + if CurrPos.Col < ScreenBlock.Start.Col then + begin + OldSCol := ScreenBlock.Start.Col; + C := GetColStart(1); + DisplayCell(OldPos); + SetScreenColStart(CurrPos.Col); + SetBlankArea; + DisplayCols; + DisplayArea.Scroll(Right, + GetColStart(OldSCol - ScreenBlock.Start.Col) - GetColStart(0)); + if not NoBlankArea then + BlankArea.Clear; + for C := ScreenBlock.Start.Col to CurrPos.Col do + DisplayCol(C); + end + else begin + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; + end; { with } +end; { MoveLeft } + +procedure MoveRight; +{ Move right a column } +var + C : Word; + OldPos : CellPos; + SaveColStart : array[0..79] of Byte; + OldSCol : Word; +begin + with Vars.CurrSS^ do + begin + if CurrPos.Col < MaxCols then + begin + OldPos := CurrPos; + Inc(CurrPos.Col); + if CurrPos.Col > ScreenBlock.Stop.Col then + begin + ExtendCurrBlock(RedrawNo); + for C := 0 to Pred(MaxScreenCols) do + SaveColStart[C] := GetColStart(C); + OldSCol := ScreenBlock.Start.Col; + DisplayCell(OldPos); + C := ColWidth(ScreenBlock.Start.Col); + SetScreenColStop(CurrPos.Col); + SetBlankArea; + DisplayCols; + DisplayArea.Scroll(Left, + SaveColStart[ScreenBlock.Start.Col - OldSCol] - ColStart^[0]); + if not NoBlankArea then + BlankArea.Clear; + for C := CurrPos.Col to ScreenBlock.Stop.Col do + DisplayCol(C); + end + else begin + ExtendCurrBlock(RedrawYes); + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; + end; { with } +end; { MoveRight } + +procedure MovePgLeft; +{ Move left a page } +var + OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + if CurrPos.Col > 1 then + begin + OldPos := CurrPos; + CurrPos.Col := Max(1, Pred(ScreenBlock.Start.Col)); + ExtendCurrBlock(RedrawNo); + if CurrPos.Col < ScreenBlock.Start.Col then + begin + SetScreenColStop(CurrPos.Col); + SetBlankArea; + DisplayCols; + if not NoBlankArea then + BlankArea.Clear; + DisplayAllCells; + end + else begin + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; + end; { with } +end; { MovePgLeft } + +procedure MovePgRight; +{ Move right a page } +var + OldPos : CellPos; +begin + with Vars.CurrSS^ do + begin + if CurrPos.Col < MaxCols then + begin + OldPos := CurrPos; + CurrPos.Col := Min(MaxCols, Succ(ScreenBlock.Stop.Col)); + ExtendCurrBlock(RedrawNo); + if CurrPos.Col > ScreenBlock.Start.Col then + begin + SetScreenColStart(CurrPos.Col); + SetBlankArea; + DisplayCols; + if not NoBlankArea then + BlankArea.Clear; + DisplayAllCells; + end + else begin + DisplayCell(OldPos); + DisplayCell(CurrPos); + end; + end; + end; { with } +end; { MovePgRight } + +procedure HandleInput(Ch : Word); +{ Process the initial input from the keyboard } +begin + EditInput(Ch, EditNo); +end; { HandleInput } + +procedure ProgramObject.GetCommands; +{ Read the keyboard and process the next command } +var + Ch : Word; +begin + repeat + CurrSS^.DisplayCellData; + ClearInputBuffer; + Ch := GetKey; + case Ch of + F2 : SaveCurrSpreadsheet; + AltF2 : NameSaveSpreadsheet; + F3 : ReplaceSpreadsheet; + AltF3 : NewSpreadsheet; + F4 : DeleteSheet; + F6 : NextSpreadsheet; + F7 : ToggleFormulas; + F8 : ToggleAutoCalc; + F9 : Recalc; + F10 : MainMenu.RunMenu; + AltX : Stop := True; + InsKey : ToggleCurrBlock; + DelKey : RemoveCell; + HomeKey : MoveHome; + EndKey : MoveEnd; + UpKey : MoveUp; + DownKey : MoveDown; + LeftKey : MoveLeft; + RightKey : MoveRight; + PgUpKey : MovePgUp; + PgDnKey : MovePgDn; + CtrlLeftKey : MovePgLeft; + CtrlRightKey : MovePgRight; + Ord(' ')..Ord('~') : HandleInput(Ch); + end; + until Stop; +end; { ProgramObject.GetCommands } + +procedure ProgramObject.SetDisplayAreas; +{ Set the display areas of the various spreadsheets } +var + S : SpreadsheetPtr; + Total, StartRow, Amt : Word; +begin + S := SSData; + StartRow := Succ(EmptyRowsAtTop); + Amt := (Scr.CurrRows - EmptyRowsAtTop - EmptyRowsAtBottom) div + TotalSheets; + Total := 1; + repeat + if S^.Next = nil then + Amt := Succ(Scr.CurrRows - EmptyRowsAtBottom - StartRow); + S^.SetAreas(Total, 1, StartRow, Scr.CurrCols, Pred(StartRow + Amt)); + Inc(StartRow, Amt); + S := S^.Next; + Inc(Total); + until S = nil; +end; { ProgramObject.SetDisplayAreas } + +procedure ProgramObject.DisplayAll; +{ Display all of the spreadsheets } +var + S : SpreadsheetPtr; +begin + TextAttr := Colors.BlankColor; + ClrScr; + WriteColor(TitleString, Colors.TitleColor); + Scr.PrintHelpLine(HelpLine); + WriteXY(MemoryString, Scr.CurrCols - Length(MemoryString) - 5, 1, + Colors.PromptColor); + S := SSData; + repeat + S^.Display; + S := S^.Next; + until S = nil; +end; { ProgramObject.DisplayAll } + +function ProgramObject.AddSheet(Name : PathStr) : Boolean; +{ Add a new spreadsheet } +var + A, S : SpreadsheetPtr; + Good, AllocatingNext : Boolean; +begin + AddSheet := False; + if TotalSheets = MaxSpreadsheets then + Exit; + S := SSData; + while (S <> nil) and (S^.Next <> nil) do + S := S^.Next; + if SSData <> nil then + begin + A := S; + New(S^.Next); + S := S^.Next; + AllocatingNext := True; + end + else begin + New(S); + AllocatingNext := False; + end; + if S = nil then + Exit; + if Name = '' then + Good := S^.Init(0, DefaultMaxCols, DefaultMaxRows, + DefaultMaxDecimalPlaces, DefaultDefaultDecimalPlaces, + DefaultDefaultColWidth) + else + Good := S^.FromFile(Name); + if not Good then + begin + Dispose(S); + if AllocatingNext then + A^.Next := nil; + Exit; + end; + if SSData = nil then + SSData := S; + if CurrSS <> nil then + CurrSS^.Current := False; + CurrSS := S; + Inc(TotalSheets); + S^.Next := nil; + AddSheet := True; +end; { ProgramObject.AddSheet } + +procedure ProgramObject.DeleteSheet; +{ Delete a spreadsheet } +var + S : SpreadsheetPtr; +begin + if TotalSheets > 1 then + begin + S := SSData; + if S = CurrSS then + SSData := S^.Next + else begin + while S^.Next <> CurrSS do + S := S^.Next; + S^.Next := S^.Next^.Next; + end; + end; + with CurrSS^ do + begin + CheckForSave; + Done; + end; { with } + if TotalSheets > 1 then + begin + FreeMem(CurrSS, SizeOf(Spreadsheet)); + Dec(TotalSheets); + CurrSS := SSData; + end + else + CurrSS^.Init(0, DefaultMaxCols, DefaultMaxRows, + DefaultMaxDecimalPlaces, DefaultDefaultDecimalPlaces, + DefaultDefaultColWidth); + SetDisplayAreas; + DisplayAll; + with CurrSS^ do + begin + MakeCurrent; + DisplayCell(CurrPos); + end; { with } +end; { ProgramObject.DeleteSheet } + +procedure InitMenus; +{ Initialize the menu items } +var + Good : Boolean; + P : Word; +begin + with Vars do + begin + with MainMenu do + begin + Init(MainMenuString, nil); + Good := AddItemMenu(@SpreadsheetMenu); + Good := AddItemMenu(@BlockMenu); + Good := AddItemMenu(@ColumnMenu); + Good := AddItemMenu(@RowMenu); + Good := AddItemProc(FormatCell); + Good := AddItemProc(GotoCell); + Good := AddItemProc(EditCell); + Good := AddItemMenu(@UtilityMenu); + Good := AddItemProc(Quit); + end; { with } + with SpreadsheetMenu do + begin + Init(SpreadsheetMenuString, @MainMenu); + Good := AddItemProc(Replacespreadsheet); + Good := AddItemProc(SaveCurrSpreadsheet); + Good := AddItemProc(ZapSpreadsheet); + Good := AddItemProc(NameSaveSpreadsheet); + Good := AddItemMenu(@OpenMenu); + Good := AddItemProc(CloseSpreadsheet); + Good := AddItemProc(NextSpreadsheet); + Good := AddItemProc(PrintSpreadsheet); + end; { with } + with OpenMenu do + begin + Init(OpenMenuString, @SpreadsheetMenu); + Good := AddItemProc(NewSpreadsheet); + Good := AddItemProc(NewBlankSpreadsheet); + end; { with } + with BlockMenu do + begin + Init(BlockMenuString, @MainMenu); + Good := AddItemProc(CopyBlock); + Good := AddItemProc(DeleteBlock); + Good := AddItemProc(FormatBlock); + Good := AddItemProc(FormatDefault); + end; { with } + with ColumnMenu do + begin + Init(ColumnMenuString, @MainMenu); + Good := AddItemProc(ColInsert); + Good := AddItemProc(ColDelete); + Good := AddItemProc(ChangeColWidth); + end; { with } + with RowMenu do + begin + Init(RowMenuString, @MainMenu); + Good := AddItemProc(RowInsert); + Good := AddItemProc(RowDelete); + end; { with } + with UtilityMenu do + begin + if Scr.VideoType >= MCGA then + begin + Init(UtilityMenuString1, @MainMenu); + Good := AddItemProc(ToggleMaxLines); + end + else + Init(UtilityMenuString2, @MainMenu); + Good := AddItemProc(Recalc); + Good := AddItemProc(ToggleFormulas); + Good := AddItemProc(ToggleAutoCalc); + end; { with } + end; { with } +end; { InitMenus } + +procedure Run; +{ The main part of the program - it sets up the spreadsheets, reads commands, + and them releases all of the memory that it used } +begin + SetCursor(NoCursor); + with Vars do + begin + Init; + GetCommands; + Done; + end; +end; { Run } + +begin + CheckBreak := False; + FreeMin := FreeListItems shl 3; + HeapError := @RunHeapError; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCRUN.TPU b/Borland Turbo Pascal v55/TCRUN.TPU new file mode 100644 index 0000000000000000000000000000000000000000..3673b913a92c4b285154536e3a288b10c5db13a4 GIT binary patch literal 24592 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 X2) or (Y1 > Y2) then { Illegal values } + Exit; + with Reg do + begin + AX := $0600; { Clear screen through the BIOS } + BH := Attrib; + CH := Pred(Y1); + CL := Pred(X1); + DH := Pred(Y2); + DL := Pred(X2); + Intr($10, Reg); + end; { with } +end; { ClearScreen } + +{$L TCMVSMEM} + +procedure MoveToScreen(var Source, Dest; Len : Word); external; +{ Moves screen memory from normal RAM to screen memory - see TCMVSMEM.ASM + for source } + +procedure MoveFromScreen(var Source, Dest; Len : Word); external; +{ Moves screen memory to normal RAM from screen memory - see TCMVSMEM.ASM + for source } + +procedure MoveText(OldX1, OldY1, OldX2, OldY2, NewX1, NewY1 : Word); +{ Moves an area of text to a new position on the screen } +var + Counter, Len : Word; +begin + if (OldX2 < OldX1) or (OldY2 < OldY1) then + Exit; + Len := Succ(OldX2 - OldX1) shl 1; + if NewY1 < OldY1 then + begin { Move it row by row, going forwards } + for Counter := 0 to OldY2 - OldY1 do + MoveFromScreen(ScreenPtr^[OldY1 + Counter, OldX1], + ScreenPtr^[NewY1 + Counter, NewX1], Len) + end + else begin { Move it row by row, going backwards } + for Counter := OldY2 - OldY1 downto 0 do + MoveFromScreen(ScreenPtr^[OldY1 + Counter, OldX1], + ScreenPtr^[NewY1 + Counter, NewX1], Len) + end; +end; { MoveText } + +procedure ScrollText(Dir : Direction; X1, Y1, X2, Y2, Amt, Attrib : Word); +{ Scrolls the screen by an amount in a direction - it does this by moving + the text to be scrolled and then clearing the area that wasn't scrolled } +begin + case Dir of + Up : begin + MoveText(X1, Y1 + Amt, X2, Y2, X1, Y1); + ClearScreen(X1, Succ(Y2 - Amt), X2, Y2, Attrib); + end; + Down : begin + MoveText(X1, Y1, X2, Y2 - Amt, X1, Succ(Y1)); + ClearScreen(X1, Y1, X2, Pred(Y1 + Amt), Attrib); + end; + Left : begin + MoveText(X1 + Amt, Y1, X2, Y2, X1, Y1); + ClearScreen(Succ(X2 - Amt), Y1, X2, Y2, Attrib); + end; + Right : begin + MoveText(X1, Y1, X2 - Amt, Y2, X1 + Amt, Y1); + ClearScreen(X1, Y1, Pred(X1 + Amt), Y2, Attrib); + end; + end; { case } +end; { ScrollText } + +function EGAInstalled : Boolean; +{ Tests for the presence of an EGA } +var + Reg : Registers; +begin + Reg.AX := $1200; + Reg.BX := $0010; + Reg.CX := $FFFF; + Intr($10, Reg); + EGAInstalled := Reg.CX <> $FFFF; +end; { EGAInstalled } + +function PS2 : Boolean; +{ This function returns True if we are running on a PS/2 type video adapter } +var + Regs : Registers; +begin + Regs.AX := $1A00; + Intr($10, Regs); + PS2 := ((Regs.AL and $FF) = $1A) and + ((Regs.BL and $FF) in [$07, $08, $0B, $0C]); +end; { PS2 } + +procedure ClrEOLXY(Col : ScreenColRange; Row : ScreenRowRange; Color : Byte); +{ Clears to the end-of-line in a color at a specified position } +begin + GotoXY(Col, Row); + TextAttr := Color; + ClrEOL; +end; { ClrEOLXY } + +procedure WriteColor(S : String; Color : Byte); +{ Writes a string in a color } +begin + TextAttr := Color; + Write(S); +end; { WriteColor } + +procedure WriteXY(S : String; Col : ScreenColRange; Row : ScreenRowRange; + Color : Byte); +{ Writes a string in a color at a specified position } +begin + GotoXY(Col, Row); + WriteColor(S, Color); +end; { WriteXY } + +procedure WriteXYClr(S : String; Col : ScreenColRange; Row : ScreenRowRange; + Color : Byte); +{ Clears to the end-of-line in a color at a specified position and then + writes a string } +begin + ClrEOLXY(Col, Row, Color); + Write(S); +end; { WriteXYClr } + +procedure SetCursor(NewCursor : Word); +{ Sets the value of the scan lines of the cursor } +var + Reg : Registers; +begin + with Reg do + begin + AH := 1; + BH := 0; + CX := NewCursor; + Intr($10, Reg); + end; { with } +end; { SetCursor } + +function GetCursor : Word; +{ Returns the value of the scan lines of the cursor } +var + Reg : Registers; +begin + with Reg do + begin + AH := 3; + BH := 0; + Intr($10, Reg); + GetCursor := CX; + end; { Reg } +end; { GetCursor } + +constructor Screen.Init; +{ Finds what type of video adapter is being run on, and initializes various + variables based on this information } +var + Reg : Registers; +begin + OldMode := LastMode; + Reg.AH := $0F; + Intr($10, Reg); { Check for the current video mode } + if Reg.AL <> 7 then + begin + if EGAInstalled then + begin + if PS2 then + VideoType := VGA + else + VideoType := EGA; + end + else begin + if PS2 then + VideoType := MCGA + else + VideoType := CGA; + end; + ScreenPtr := Ptr($B800, 0); + if Reg.AL < 2 then + CurrCols := 40 + else + CurrCols := 80; + end + else begin + VideoType := MDA; + ScreenPtr := Ptr($B000, 0); + CurrCols := 80; + end; + CurrRows := Succ(Hi(WindMax)); + OldCursor := GetCursor; + if (CurrRows = MinScreenRows) and (VideoType <> CGA) then + InsCursor := InsCursorLarge + else + InsCursor := InsCursorSmall; +end; { Screen.Init } + +destructor Screen.Done; +{ Restores the screen mode and cursor that existed at the start of the + program } +begin + TextMode(OldMode); + SetCursor(OldCursor); + ExitProc := SavedExitProc; +end; { Screen.Done } + +procedure Screen.ToggleMaxLinesMode; +{ Toggles the display in and out of 43/50-line mode } +begin + if CurrRows = MinScreenRows then + begin + TextMode(Lo(LastMode) + Font8x8); + InsCursor := InsCursorSmall; + end + else begin + TextMode(Lo(LastMode)); + InsCursor := InsCursorLarge; + end; + CurrRows := Succ(Hi(WindMax)); +end; { Screen.ToggleMaxLinesMode } + +procedure Screen.PrintError(Error : String); +{ Prints an error message at the bottom of the screen } +var + Ch : Word; + Buffer : ScreenRow; +begin + MoveFromScreen(ScreenPtr^[CurrRows, 1], Buffer, + SizeOf(ScreenChar) * CurrCols); { Save bottom line } + WriteXYClr(CenterStr(Error + '. ' + ESCPress, Pred(CurrCols)), 1, CurrRows, + Colors.ErrorColor); + Beep; + repeat + Ch := GetKey; + until Ch = ESC; + MoveToScreen(Buffer, ScreenPtr^[CurrRows, 1], { Restore bottom line } + SizeOf(ScreenChar) * CurrCols); +end; { Screen.PrintError } + +procedure Screen.PrintMessage(Message : String); +{ Prints a message } +begin + WriteXYClr(Message + '...', 1, Pred(CurrRows), Colors.MessageColor); +end; { Screen.PrintMessage } + +procedure Screen.ClearMessage; +{ Clears the last printed message } +begin + ClrEOLXY(1, Pred(CurrRows), Colors.MessageColor); +end; { Screen.ClearMessage } + +procedure Screen.PrintHelpLine(CommandString : String); +{ Prints a help line at the bottom of the screen. The command string is + made up of a series of keys and descriptions separated by backslashes. + Example: 'F1\Help\F2\Save\F3\Load\Alt-X\Exit'} +var + P : Integer; + S : String[ScreenCols]; +begin + CommandString := CommandString + '\'; + ClrEOLXY(1, CurrRows, Colors.KeyDescColor); + while CommandString <> '' do + begin + Write(' '); + P := Pos('\', CommandString); + WriteColor(Copy(CommandString, 1, Pred(P)), Colors.KeyNameColor); + Delete(CommandString, 1, P); + P := Pos('\', CommandString); + if CommandString[1] = '\' then + S := '-' + else + S := '-' + Copy(CommandString, 1, Pred(P)); + WriteColor(S, Colors.KeyDescColor); + Delete(CommandString, 1, P); + end; +end; { Screen.PrintHelpLine } + +constructor ScreenArea.Init(InitX1 : ScreenColRange; InitY1 : ScreenRowRange; + InitX2 : ScreenColRange; InitY2 : ScreenRowRange; + InitAttrib : Byte); +{ Sets up a screen area } +begin + UpperLeft.Col := InitX1; + UpperLeft.Row := InitY1; + LowerRight.Col := InitX2; + LowerRight.Row := InitY2; + Attrib := InitAttrib; +end; { ScreenArea.Init } + +procedure ScreenArea.Scroll(Dir : Direction; Amt : Word); +{ Scrolls a screen area an certain amount in a direction } +begin + ScrollText(Dir, UpperLeft.Col, UpperLeft.Row, LowerRight.Col, + LowerRight.Row, Amt, Attrib); +end; { ScreenArea.Scroll } + +procedure ScreenArea.Clear; +{ Clears a screen area } +begin + ClearScreen(UpperLeft.Col, UpperLeft.Row, LowerRight.Col, LowerRight.Row, + Attrib); +end; { ScreenArea.Clear } + +procedure ScreenArea.Erase; +{ Erases a screen area by writing over it in black } +begin + ClearScreen(UpperLeft.Col, UpperLeft.Row, LowerRight.Col, LowerRight.Row, + Black); +end; { ScreenArea.Erase } + +constructor ColorTable.Init; +{ Initializes the color table by finding the video mode that is being used } +begin + case Lo(LastMode) of + BW40, BW80 : TableType := ColorBW; + CO40, CO80 : TableType := ColorColor; + Mono : TableType := ColorMono; + end; { case } + FillColorTable; +end; { ColorTable.Init } + +procedure ColorTable.FillColorTable; +{ Moves the correct built-in color table to the program's color table } +var + P : Pointer; +begin + case TableType of + ColorColor : P := @ColorColors; + ColorBW : P := @BWColors; + ColorMono : P := @MonoColors; + end; { case } + Move(P^, BlankColor, TotalColors); +end; { ColorTable.FillColorTable } + +{$F+} + +procedure ScreenExit; +{ Clears the screen at exit } +begin + Scr.Done; +end; { ScreenExit } + +{$F-} + +begin + SavedExitProc := ExitProc; + ExitProc := @ScreenExit; + TextMode(LastMode); + Scr.Init; + Colors.Init; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCSCREEN.TPU b/Borland Turbo Pascal v55/TCSCREEN.TPU new file mode 100644 index 0000000000000000000000000000000000000000..529b84ce8ba0b76d9040346cb7f12656f1565b61 GIT binary patch literal 10272 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TCSHEET.PAS b/Borland Turbo Pascal v55/TCSHEET.PAS new file mode 100644 index 0000000..73665f9 --- /dev/null +++ b/Borland Turbo Pascal v55/TCSHEET.PAS @@ -0,0 +1,1722 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit TCSheet; +{ Turbo Pascal 5.5 object-oriented example spreadsheet routines. + This unit is used by TCALC.PAS. + See TCALC.DOC for an more information about this example. +} + +{$N+,S-} + +interface + +uses Crt, Dos, Objects, TCUtil, TCInput, TCScreen, TCLStr, TCHash, TCCell, + TCCellSp, TCParser; + +const + DefaultMaxCols = 65535; + DefaultMaxRows = 65535; + DefaultMaxDecimalPlaces = 8; + DefaultDefaultDecimalPlaces = 4; + DefaultDefaultColWidth = 10; + EmptyRowsAtTop = 1; + EmptyRowsAtBottom = 2; + MinColWidth = 3; + CurrentChar = #4; + ChangedChar = '*'; + PrintNormalCols = 80; + PrintCompressedCols = 132; + PrintRows = 66; + PrintTopMargin = 1; + PrintBottomMargin = 1; + PrinterCompressChar = #15; + EditYes = True; + EditNo = False; + DisplayYes = True; + DisplayNo = False; + WasChanged = True; + NotChanged = False; + AutoCalcLetter = 'A'; + FormulaDisplayLetter = 'F'; + MemoryString = 'Memory: '; + FileHeader = 'TurboCalc Spreadsheet'^Z; + ErrorString = 'ERROR'; + TempFileName = 'TEMP.TMP'; { Temporary file used for rehashing } + PrinterName = 'PRN'; + PromptFileSave = 'File to save'; + PromptFilePrint = 'File to print to (ENTER = Printer)'; + PromptOverwriteFile = 'The file exists. Overwrite it'; + PromptCompressPrint = 'Compress the printing'; + PromptBorderPrint = 'Print the borders'; + PromptColumnWidth = 'Column to change'; + PromptNewWidth = 'New width'; + PromptColumnDelete = 'Column to delete'; + PromptColumnInsert = 'Insert new column before column'; + PromptRowDelete = 'Row to delete'; + PromptRowInsert = 'Insert new row before row'; + PromptSaveYN = 'Save spreadsheet'; + ErrNoOpen = 'Cannot open file'; + ErrDiskFull = 'Disk full'; + ErrPrinterError = 'Printer error'; + ErrNotSpreadsheet = 'Not a TurboCalc spreadsheet file'; + MsgRecalc = 'Recalculating cell values'; + MsgSave = 'Saving spreadsheet'; + MsgLoad = 'Loading spreadsheet'; + MsgBlockDelete = 'Deleting block'; + +type + ColStartArray = array[0..ScreenCols] of Byte; + ColStartPtr = ^ColStartArray; + SpreadsheetPtr = ^Spreadsheet; + Spreadsheet = object + Number : Byte; + MaxRows : Word; + MaxCols : Word; + MaxDecimalPlaces : Byte; + MaxColWidth : Byte; + MaxScreenCols : Byte; + DefaultColWidth : Byte; + DefaultDecimalPlaces : Byte; + RowNumberSpace : Byte; + ColSpace : Byte; + Current : Boolean; + Changed : Boolean; + CurrPos : CellPos; + LastPos : CellPos; + ScreenBlock : Block; + CurrBlock : Block; + BlockOn : Boolean; + FileName : PathStr; + TotalRows : ScreenRowRange; + DisplayArea : ScreenArea; + ColArea : ScreenArea; + RowArea : ScreenArea; + InfoArea : ScreenArea; + DataArea : ScreenArea; + ContentsArea : ScreenArea; + BlankArea : ScreenArea; + NoBlankArea : Boolean; + ColStart : ColStartPtr; + DisplayFormulas : Boolean; + AutoCalc : Boolean; + CellHash : CellHashTable; + OverwriteHash : OverwriteHashTable; + WidthHash : WidthHashTable; + FormatHash : FormatHashTable; + Next : SpreadsheetPtr; + constructor Init(InitCells : Longint; InitMaxCols, InitMaxRows : Word; + InitMaxDecimalPlaces, InitDefaultDecimalPlaces : Byte; + InitDefaultColWidth : Byte); + destructor Done; + function GetColStart(Col : Word) : Byte; + procedure SetAreas(NewNumber : Word; X1 : ScreenColRange; + Y1 : ScreenRowRange; X2 : ScreenColRange; + Y2 : ScreenRowRange); + procedure DisplayCols; + procedure DisplayRows; + procedure DisplayInfo; + procedure DisplayAllCells; + procedure Display; + procedure DisplayCell(P : CellPos); + procedure DisplayCellData; + procedure DisplayCellBlock(C1 : Word; R1 : Word; C2 : Word; + R2 : Word); + procedure DisplayBlock(B : Block); + procedure DisplayBlockDiff(B1, B2 : Block); + procedure DisplayCol(Col : Word); + procedure DisplayRow(Row : Word); + procedure DisplayMemory; + procedure DisplayFileName; + procedure SetChanged(IsChanged : Boolean); + procedure MakeCurrent; + procedure MakeNotCurrent; + procedure Update(UDisplay : Boolean); + procedure ToggleFormulaDisplay; + procedure SetScreenColStart(NewCol : Word); + procedure SetScreenColStop(NewCol: Word); + procedure SetScreenRowStart(NewRow : Word); + procedure SetScreenRowStop(NewRow : Word); + procedure FindScreenColStart; + procedure FindScreenColStop; + procedure FindScreenRowStart; + procedure FindScreenRowStop; + procedure SetBlankArea; + function AddCell(CellType : CellTypes; P : CellPos; E : Boolean; + V : Extended; I : LStringPtr) : Boolean; + procedure DeleteCell(P : CellPos; var Deleted : Boolean); + procedure DeleteBlock(B : Block; var Deleted : Boolean); + function CellToFString(P : CellPos; var Color : Byte) : String; + procedure SetLastPos(DPos : CellPos); + function GetCurrCol : Word; + function GetCurrRow : Word; + function ColToX(Col : Word) : Byte; + function RowToY(Row : Word) : Byte; + function ColWidth(Col : Word) : Byte; + function SameCellPos(P1, P2 : CellPos) : Boolean; + procedure FixOverwrite; + function FromFile(Name : PathStr) : Boolean; + procedure ToFile(Name : PathStr); + procedure CheckForSave; + procedure ChangeWidth; + function CellHashStart(TotalCells : Longint) : BucketRange; + function WidthHashStart(TotalCells : Longint) : BucketRange; + function OverwriteHashStart(TotalCells : Longint) : BucketRange; + procedure Print; + procedure DeleteColumn; + procedure InsertColumn; + procedure DeleteRow; + procedure InsertRow; + end; + +function GetColWidth(var WHash : WidthHashTable; C : Word) : Byte; + +implementation + +function GetColWidth(var WHash : WidthHashTable; C : Word) : Byte; +{ Returns the width of a column } +var + W : Word; +begin + W := WHash.Search(C); + if W = 0 then + GetColWidth := WHash.GetDefaultColWidth + else + GetColWidth := W; +end; { GetColWidth } + +constructor Spreadsheet.Init(InitCells : Longint; InitMaxCols, + InitMaxRows : Word; InitMaxDecimalPlaces, + InitDefaultDecimalPlaces : Byte; + InitDefaultColWidth : Byte); +{ Sets up a new spreadsheet } +begin + if not CellHash.Init(CellHashStart(InitCells)) then + Fail; + if not WidthHash.Init(WidthHashStart(InitCells), InitDefaultColWidth) then + begin + CellHash.Done; + Fail; + end; + if not OverwriteHash.Init(OverwriteHashStart(InitCells)) then + begin + CellHash.Done; + WidthHash.Done; + Fail; + end; + if not FormatHash.Init then + begin + CellHash.Done; + WidthHash.Done; + OverwriteHash.Done; + Fail; + end; + MaxCols := InitMaxCols; + MaxRows := InitMaxRows; + RowNumberSpace := Ord(MaxRows >= 10000) + Ord(MaxRows >= 1000) + + Ord(MaxRows >= 100) + Ord(MaxRows >= 10) + 2; + MaxColWidth := ScreenCols - RowNumberSpace; + MaxScreenCols := MaxColWidth div MinColWidth; + GetMem(ColStart, MaxScreenCols); + if ColStart = nil then + begin + CellHash.Done; + WidthHash.Done; + OverwriteHash.Done; + FormatHash.Done; + Fail; + end; + CurrPos.Col := 1; + CurrPos.Row := 1; + LastPos := CurrPos; + BlockOn := False; + FileName := ''; + DisplayFormulas := False; + AutoCalc := False; + Current := False; + Changed := False; + ScreenBlock.Start.Col := 1; + ScreenBlock.Start.Row := 1; + ColSpace := Succ(Ord(MaxCols >= 18279) + Ord(MaxCols >= 703) + + Ord(MaxCols >= 27)); + MaxDecimalPlaces := InitMaxDecimalPlaces; + DefaultColWidth := InitDefaultColWidth; + DefaultDecimalPlaces := InitDefaultDecimalPlaces; +end; { Spreadsheet.Init } + +destructor Spreadsheet.Done; +{ Removes a spreadsheet from memory } +begin + CellHash.Done; + WidthHash.Done; + OverwriteHash.Done; + FormatHash.Done; + FreeMem(ColStart, MaxScreenCols); +end; { Spreadsheet.Done } + +function Spreadsheet.GetColStart(Col : Word) : Byte; +begin + GetColStart := ColStart^[Col]; +end; { Spreadsheet.GetColStart } + +procedure Spreadsheet.SetAreas(NewNumber : Word; X1 : ScreenColRange; + Y1 : ScreenRowRange; X2 : ScreenColRange; + Y2 : ScreenRowRange); +{ Sets up a spreadsheet's display areas } +begin + Number := NewNumber; + TotalRows := Y2 - Y1 - 2; + ColArea.Init(X1 + RowNumberSpace, Y1, X2, Y1, Colors.ColColor); + RowArea.Init(X1, Succ(Y1), Pred(X1 + RowNumberSpace), Y2 - 2, + Colors.RowColor); + InfoArea.Init(X1, Y1, Pred(X1 + RowNumberSpace), Y1, Colors.InfoColor); + DisplayArea.Init(X1 + RowNumberSpace, Succ(Y1), X2, Y2 - 2, + Colors.BlankColor); + DataArea.Init(X1, Pred(Y2), X2, Pred(Y2), Colors.BlankColor); + ContentsArea.Init(X1, Y2, X2, Y2, Colors.ContentsColor); + SetScreenColStart(ScreenBlock.Start.Col); + SetScreenRowStart(ScreenBlock.Start.Row); + SetBlankArea; +end; { Spreadsheet.SetAreas } + +procedure Spreadsheet.DisplayCols; +{ Shows the column headings } +var + C : Word; +begin + ColArea.Clear; + with ScreenBlock do + begin + for C := Start.Col to Stop.Col do + WriteXY(CenterStr(ColToString(C), ColWidth(C)), + ColStart^[C - Start.Col], ColArea.UpperLeft.Row, + Colors.ColColor); + end; { with } +end; { Spreadsheet.DisplayCols } + +procedure Spreadsheet.DisplayRows; +{ Shows the row headings } +var + R : Word; +begin + RowArea.Clear; + with ScreenBlock do + begin + for R := Start.Row to Stop.Row do + with RowArea do + WriteXY(LeftJustStr(RowToString(R), RowNumberSpace), + UpperLeft.Col, R - Start.Row + UpperLeft.Row, + Colors.RowColor); + end; { with } +end; { Spreadsheet.DisplayRows } + +procedure Spreadsheet.DisplayInfo; +{ Shows the spreadsheet number, current dot, and state of AutoCalc and + formula display } +begin + InfoArea.Clear; + with InfoArea do + WriteXY(NumToString(Number), UpperLeft.Col, UpperLeft.Row, + Colors.InfoColor); + if Current then + Write(CurrentChar) + else + Write(' '); + if AutoCalc then + Write(AutoCalcLetter) + else + Write(' '); + if DisplayFormulas then + Write(FormulaDisplayLetter) + else + Write(' '); +end; { Spreadsheet.DisplayRows } + +procedure Spreadsheet.DisplayAllCells; +{ Displays all of the cells on the screen } +begin + DisplayArea.Clear; + DisplayBlock(ScreenBlock); +end; { Spreadsheet.DisplayAllCells } + +procedure Spreadsheet.DisplayCell(P : CellPos); +{ Displays a single cell } +var + S : String[ScreenCols]; + Color : Byte; +begin + S := CellToFString(P, Color); + WriteXY(S, ColToX(P.Col), RowToY(P.Row), Color); +end; { Spreadsheet.DisplayCell } + +procedure Spreadsheet.DisplayCellData; +{ Displays information about a cell - its type and its contents } +var + CP : CellPtr; +begin + CP := CellHash.Search(CurrPos); + with DataArea do + WriteXY(LeftJustStr(ColToString(CurrPos.Col) + + RowToString(CurrPos.Row) + ' ' + CP^.Name, 19), + UpperLeft.Col, UpperLeft.Row, Colors.CellDataColor); + with ContentsArea do + begin + Clear; + WriteXY(LeftJustStr(CP^.DisplayString(DisplayFormulas, + MaxDecimalPlaces), Scr.CurrCols), UpperLeft.Col, + UpperLeft.Row, Colors.ContentsColor); + end; { with } +end; { Spreadsheet.DisplayCellData } + +procedure Spreadsheet.DisplayCellBlock(C1 : Word; R1 : Word; + C2 : Word; R2 : Word); +{ Displays all cells within a range of rows and columns } +var + P : CellPos; +begin + with ScreenBlock do + begin + for P.Row := Max(R1, Start.Row) to Min(R2, Stop.Row) do + begin + for P.Col := Max(C1, Start.Col) to Min(C2, Stop.Col) do + DisplayCell(P); + end; + end; { with } +end; { Spreadsheet.DisplayCellBlock } + +procedure Spreadsheet.DisplayBlock(B : Block); +{ Displays all cells within a certain block } +begin + with B do + DisplayCellBlock(Start.Col, Start.Row, Stop.Col, Stop.Row); +end; { Spreadsheet.DisplayBlock } + +procedure Spreadsheet.DisplayBlockDiff(B1, B2 : Block); +{ When a block is extended, this will update the screen to show the new + block } +var + B : Block; + DisplayMiddle : Boolean; +begin + if Compare(B1, B2, SizeOf(Block)) then + Exit; + with B do + begin + DisplayMiddle := False; + if B1.Stop.Col <> B2.Stop.Col then + begin + B.Start.Row := B1.Start.Row; + B.Start.Col := Min(Succ(B1.Stop.Col), Succ(B2.Stop.Col)); + B.Stop.Row := Min(B1.Stop.Row, B2.Stop.Row); + B.Stop.Col := Max(B1.Stop.Col, B2.Stop.Col); + DisplayBlock(B); + DisplayMiddle := True; + end; + if B1.Stop.Row <> B2.Stop.Row then + begin + B.Start.Row := Min(Succ(B1.Stop.Row), Succ(B2.Stop.Row)); + B.Start.Col := B1.Start.Col; + B.Stop.Row := Max(B1.Stop.Row, B2.Stop.Row); + B.Stop.Col := Min(B1.Stop.Col, B2.Stop.Col); + DisplayBlock(B); + DisplayMiddle := True; + end; + if DisplayMiddle then + begin + B.Start.Row := Min(Succ(B1.Stop.Row), Succ(B2.Stop.Row)); + B.Start.Col := Min(Succ(B1.Stop.Col), Succ(B2.Stop.Col)); + B.Stop.Row := Max(B1.Stop.Row, B2.Stop.Row); + B.Stop.Col := Max(B1.Stop.Col, B2.Stop.Col); + DisplayBlock(B); + end; + end; { with } +end; { Spreadsheet.DisplayBlockDiff } + +procedure Spreadsheet.DisplayCol(Col : Word); +{ Display a column of cells } +begin + with ScreenBlock do + DisplayCellBlock(Col, Start.Row, Col, Stop.Row); +end; { Spreadsheet.DisplayCol } + +procedure Spreadsheet.DisplayRow(Row : Word); +{ Display a row of cells } +begin + with ScreenBlock do + DisplayCellBlock(Start.Col, Row, Stop.Col, Row); +end; { Spreadsheet.DisplayRow } + +procedure Spreadsheet.DisplayMemory; +{ Display the amount of free memory } +begin + WriteXY(RightJustStr(NumToString(MemAvail), 6), Scr.CurrCols - 5, 1, + Colors.MemoryColor); +end; { Spreadsheet.DisplayMemory } + +procedure Spreadsheet.DisplayFileName; +{ Display the spreadsheet's file name, and whether or not it has been + updated } +var + S : PathStr; +begin + with DataArea do + begin + if FileName = '' then + S := 'No file' + else + S := FExpand(FileName); + WriteXY(LeftJustStr(S, LowerRight.Col - UpperLeft.Col - 20), + UpperLeft.Col + 21, UpperLeft.Row, Colors.FileNameColor); + end; { with } +end; { Spreadsheet.DisplayFileName } + +procedure Spreadsheet.Display; +{ Display the entire spreadsheet } +begin + DisplayCols; + DisplayRows; + DisplayInfo; + DisplayAllCells; + DisplayMemory; + DisplayCellData; + DisplayFileName; + SetChanged(Changed); +end; { Spreadsheet.Display } + +procedure Spreadsheet.SetChanged(IsChanged : Boolean); +{ Sets a spreadsheet as being changed or not changed } +var + C : Char; +begin + Changed := IsChanged; + if Changed then + C := ChangedChar + else + C := ' '; + with DataArea.UpperLeft do + WriteXY(C, Col + 19, Row, Colors.ChangedColor); +end; { Spreadsheet.SetChanged } + +procedure Spreadsheet.MakeCurrent; +{ Make a spreadsheet the current one } +begin + Current := True; + DisplayInfo; +end; { Spreadsheet.MakeCurrent } + +procedure Spreadsheet.MakeNotCurrent; +{ Make a spreadsheet not the current one } +begin + Current := False; + DisplayInfo; +end; { Spreadsheet.MakeNotCurrent } + +procedure Spreadsheet.Update(UDisplay : Boolean); +{ Update any cells in the spreadsheet that need updating } +var + P, U : CellPos; + CP : CellPtr; + O : Word; +begin + Scr.PrintMessage(MsgRecalc); + with CellHash do + begin + for P.Row := 1 to LastPos.Row do + begin + for P.Col := 1 to LastPos.Col do + begin + CP := Search(P); + if CP^.ShouldUpdate then + begin + with FormulaCellPtr(CP)^ do + begin + Parser.Init(@CellHash, Formula, MaxCols, MaxRows); + Parser.Parse; + Value := Parser.ParseValue; + Error := Parser.ParseError; + O := CP^.Overwritten(CellHash, FormatHash, WidthHash, + LastPos, MaxCols, GetColWidth, DisplayFormulas); + if (OverwriteHash.Change(CP, O)) and UDisplay and + (CP^.Loc.Col + O >= ScreenBlock.Start.Col) then + begin + U := CP^.Loc; + for U.Col := CP^.Loc.Col to ScreenBlock.Stop.Col do + begin + if ScreenBlock.CellInBlock(U) then + DisplayCell(U); + end; + end; + end; { with } + end; + end; + end; + end; { with } + if UDisplay then + DisplayMemory; + Scr.ClearMessage; +end; { Spreadsheet.Update } + +procedure Spreadsheet.ToggleFormulaDisplay; +{ Change from showing formulas to showing values and vice versa } +var + CP : CellPtr; + OChanged : Boolean; +begin + DisplayFormulas := not DisplayFormulas; + DisplayInfo; + OChanged := True; + with CellHash do + begin + CP := FirstItem; + while (CP <> nil) and OChanged do + begin + if CP^.ShouldUpdate then + OChanged := OverwriteHash.Change(CP, CP^.Overwritten(CellHash, + FormatHash, WidthHash, LastPos, + MaxCols, GetColWidth, + DisplayFormulas)); + CP := NextItem; + end; + end; { with } + DisplayAllCells; + DisplayMemory; +end; { Spreadsheet.ToggleFormulaDisplay } + +procedure Spreadsheet.SetScreenColStart(NewCol : Word); +{ Find the starting screen column } +begin + ScreenBlock.Start.Col := NewCol; + FindScreenColStop; + FindScreenColStart; +end; { Spreadsheet.SetScreenColStart } + +procedure Spreadsheet.SetScreenColStop(NewCol : Word); +{ Find the ending screen column } +begin + ScreenBlock.Stop.Col := NewCol; + FindScreenColStart; + FindScreenColStop; +end; { Spreadsheet.SetScreenColStop } + +procedure Spreadsheet.SetScreenRowStart(NewRow : Word); +{ Find the starting screen row } +begin + ScreenBlock.Start.Row := NewRow; + FindScreenRowStop; +end; { Spreadsheet.SetScreenRowStart } + +procedure Spreadsheet.SetScreenRowStop(NewRow : Word); +{ Find the ending screen row } +begin + ScreenBlock.Stop.Row := NewRow; + FindScreenRowStart; +end; { Spreadsheet.SetScreenRowStop } + +procedure Spreadsheet.FindScreenColStart; +{ Find the starting screen column when the ending column is known } +var + Index, Place : Integer; + Temp, Width : Byte; +begin + with ScreenBlock do + begin + Index := 0; + Place := Succ(DisplayArea.LowerRight.Col); + Width := ColWidth(Stop.Col); + repeat + ColStart^[Index] := Place - Width; + Dec(Place, Width); + Inc(Index); + if Stop.Col - Index = 0 then + Width := 0 + else + Width := ColWidth(Stop.Col - Index); + until (Width = 0) or (Place - Width < DisplayArea.UpperLeft.Col); + Start.Col := Succ(Stop.Col - Index); + Dec(Index); + if ColStart^[Index] <> DisplayArea.UpperLeft.Col then + begin + Temp := ColStart^[Index] - DisplayArea.UpperLeft.Col; + for Place := 0 to Index do + Dec(ColStart^[Place], Temp); + end; + if Index > 0 then + begin + for Place := 0 to (Pred(Index) shr 1) do + begin + Temp := ColStart^[Index - Place]; + ColStart^[Index - Place] := ColStart^[Place]; + ColStart^[Place] := Temp; + end; + end; + end; { with } +end; { Spreadsheet.FindScreenColStart } + +procedure Spreadsheet.FindScreenColStop; +{ Find the ending screen column when the starting column is known } +var + Index, Place : Byte; + Width : Byte; +begin + with ScreenBlock do + begin + Index := 0; + Place := DisplayArea.UpperLeft.Col; + Width := ColWidth(Start.Col); + repeat + ColStart^[Index] := Place; + Inc(Place, Width); + Inc(Index); + if Longint(Index) + Start.Col > MaxCols then + Width := 0 + else + Width := ColWidth(Index + Start.Col); + until (Width = 0) or (Place + Width > Succ(DisplayArea.LowerRight.Col)); + Stop.Col := Pred(Start.Col + Index); + end; { with } +end; { Spreadsheet.FindScreenColStop } + +procedure Spreadsheet.FindScreenRowStart; +{ Find the starting screen row when the ending row is known } +begin + with ScreenBlock do + begin + if Longint(Stop.Row) - TotalRows < 0 then + begin + Start.Row := 1; + FindScreenRowStop; + end + else + Start.Row := Succ(Stop.Row - TotalRows); + end; { with } +end; { Spreadsheet.FindScreenRowStart } + +procedure Spreadsheet.FindScreenRowStop; +{ Find the ending screen row when the starting row is known } +begin + with ScreenBlock do + begin + if Longint(Start.Row) + TotalRows > Succ(LongInt(MaxRows)) then + begin + Stop.Row := MaxRows; + FindScreenRowStart; + end + else + Stop.Row := Pred(Start.Row + TotalRows); + end; { with } +end; { Spreadsheet.FindScreenRowStop } + +procedure Spreadsheet.SetBlankArea; +{ Find the size of the blank area (the area at the right edge of the + spreadsheet that is not used } +var + C : Word; +begin + with BlankArea do + begin + Move(DisplayArea, BlankArea, SizeOf(DisplayArea)); + with ScreenBlock do + C := ColStart^[Stop.Col - Start.Col] + ColWidth(Stop.Col); + if C > DisplayArea.LowerRight.Col then + NoBlankArea := True + else begin + NoBlankArea := False; + UpperLeft.Col := C; + end; + end; { with } +end; { Spreadsheet.SetBlankArea } + +function Spreadsheet.AddCell(CellType : CellTypes; P : CellPos; E : Boolean; + V : Extended; I : LStringPtr) : Boolean; +{ Add a new cell to the spreadsheet } +var + CP, S : CellPtr; + OldLastPos : CellPos; + Good : Boolean; +begin + AddCell := False; + case CellType of + ClValue : CP := New(ValueCellPtr, Init(P, E, V)); + ClFormula : CP := New(FormulaCellPtr, Init(P, E, V, I)); + ClText : CP := New(TextCellPtr, Init(P, I)); + ClRepeat : CP := New(RepeatCellPtr, Init(P, I^.Data^[2])); + end; { case } + if CP = nil then + Exit; + if not CellHash.Add(CP) then + begin + Dispose(CP, Done); + Exit; + end; + OldLastPos := LastPos; + LastPos.Col := Max(P.Col, LastPos.Col); + LastPos.Row := Max(P.Row, LastPos.Row); + if not OverwriteHash.Add(CP, CP^.Overwritten(CellHash, FormatHash, + WidthHash, LastPos, MaxCols, GetColWidth, + DisplayFormulas)) then + begin + LastPos := OldLastPos; + CellHash.Delete(CP^.Loc, S); + Dispose(CP, Done); + Exit; + end; + S := OverwriteHash.Search(CP^.Loc); + if S <> Empty then + Good := OverwriteHash.Change(S, S^.Overwritten(CellHash, FormatHash, + WidthHash, LastPos, MaxCols, GetColWidth, + DisplayFormulas)); + AddCell := True; +end; { Spreadsheet.AddCell } + +procedure Spreadsheet.DeleteCell(P : CellPos; var Deleted : Boolean); +{ Delete a cell from the spreadsheet } +var + CP : CellPtr; + Good : Boolean; +begin + CellHash.Delete(P, CP); + if CP <> nil then + begin + Dispose(CP, Done); + OverwriteHash.Delete(P); + if P.Col > 1 then + begin + Dec(P.Col); + CP := OverwriteHash.Search(P); + if CP = Empty then + CP := CellHash.Search(P); + if CP <> Empty then + Good := OverwriteHash.Change(CP, CP^.Overwritten(CellHash, + FormatHash, WidthHash, LastPos, MaxCols, + GetColWidth, DisplayFormulas)); + end; + Deleted := True; + end + else + Deleted := False; +end; { Spreadsheet.DeleteCell } + +procedure Spreadsheet.DeleteBlock(B : Block; var Deleted : Boolean); +{ Delete a block of cells from the spreadsheet } +var + P : CellPos; + H, D : HashItemPtr; + Counter : Word; + CP : CellPtr; +begin + Scr.PrintMessage(MsgBlockDelete); + Deleted := False; + with CellHash, B do + begin + for Counter := 1 to Buckets do + begin + H := HashData^[Counter]; + while H <> nil do + begin + D := H; + H := H^.Next; + Move(D^.Data, CP, SizeOf(CP)); + with CP^ do + begin + if CellInBlock(Loc) then + DeleteCell(Loc, Deleted); + end; { with } + end; + end; + end; { with } + Scr.ClearMessage; +end; { DeleteBlock } + +function Spreadsheet.CellToFString(P : CellPos; var Color : Byte) : String; +{ Create a formatted string from a cell } +var + CP : CellPtr; + S : String; + S1 : DollarStr; + F : FormatType; + ColorFound : Boolean; + Colr : Byte; +begin + ColorFound := True; + if Current and (SameCellPos(P, CurrPos)) then + Color := Colors.HighlightColor + else if BlockOn and (CurrBlock.CellInBlock(P)) then + Color := Colors.BlockColor + else + ColorFound := False; + CP := CellHash.Search(P); + if (CP^.HasError) then + begin + S := ErrorString; + S1 := ''; + if ColorFound then + Inc(Color, Blink) + else + Color := Colors.CellErrorColor; + F := Ord(JCenter) shl JustShift; + end + else begin + S := CP^.FormattedString(OverwriteHash, FormatHash, WidthHash, + GetColWidth, P, DisplayFormulas, 1, + ColWidth(P.Col), S1, Colr); + if not ColorFound then + Color := Colr; + F := CP^.Format(FormatHash, DisplayFormulas); + end; + case Justification((F shr JustShift) and JustPart) of + JLeft : CellToFString := S1 + LeftJustStr(S, ColWidth(P.Col) - + Length(S1)); + JCenter : CellToFString := S1 + CenterStr(S, ColWidth(P.Col) - + Length(S1)); + JRight : CellToFString := S1 + RightJustStr(S, ColWidth(P.Col) - + Length(S1)); + end; { case } +end; { Spreadsheet.CellToFString } + +procedure Spreadsheet.SetLastPos(DPos : CellPos); +{ Find the last position used in a spreadsheet } +var + CP : CellPtr; + Counter : Word; + ColFound, RowFound : Boolean; +begin + with CellHash do + begin + ColFound := DPos.Col < LastPos.Col; + RowFound := DPos.Row < LastPos.Row; + if (not ColFound) or (not RowFound) then + begin + if not ColFound then + LastPos.Col := 1; + if not RowFound then + LastPos.Row := 1; + CP := FirstItem; + while CP <> nil do + begin + if not ColFound then + begin + if CP^.Loc.Col > LastPos.Col then + begin + LastPos.Col := CP^.Loc.Col; + ColFound := LastPos.Col = DPos.Col; + if ColFound and RowFound then + Exit; + end; + end; + if not RowFound then + begin + if CP^.Loc.Row > LastPos.Row then + begin + LastPos.Row := CP^.Loc.Row; + RowFound := LastPos.Row = DPos.Row; + if ColFound and RowFound then + Exit; + end; + end; + CP := NextItem; + end; + end; + end; { with } +end; { Spreadsheet.SetLastPos } + +function Spreadsheet.GetCurrCol : Word; +{ Find the current column } +begin + GetCurrCol := CurrPos.Col; +end; { Spreadsheet.GetCurrCol } + +function Spreadsheet.GetCurrRow : Word; +{ Find the current row } +begin + GetCurrRow := CurrPos.Row; +end; { Spreadsheet.GetCurrRow } + +function Spreadsheet.ColToX(Col : Word) : Byte; +{ Find where on the screen a column starts } +begin + ColToX := ColStart^[Col - ScreenBlock.Start.Col]; +end; { Spreadsheet.ColToX } + +function Spreadsheet.RowToY(Row : Word) : Byte; +{ Find where on the screen a row starts } +begin + RowToY := Row + DisplayArea.UpperLeft.Row - ScreenBlock.Start.Row; +end; { Spreadsheet.RowToY } + +{$F+} + +function Spreadsheet.ColWidth(Col : Word) : Byte; +{ Returns the width of a column } +var + Width : Word; +begin + Width := WidthHash.Search(Col); + if Width = 0 then + ColWidth := DefaultColWidth + else + ColWidth := Width; +end; { Spreadsheet.ColWidth } + +{$F-} + +function Spreadsheet.SameCellPos(P1, P2 : CellPos) : Boolean; +{ Returns True if two cells are at the same position } +begin + SameCellPos := Compare(P1, P2, SizeOf(CellPos)); +end; { Spreadsheet.SameCellPos } + +procedure Spreadsheet.FixOverwrite; +{ Fixes the overwrite hash table when the formats have been changed } +var + CP, D : CellPtr; + Counter : Word; + Good : Boolean; +begin + with CellHash do + begin + CP := FirstItem; + while CP <> nil do + begin + if not OverwriteHash.Add(CP, CP^.Overwritten(CellHash, FormatHash, + WidthHash, LastPos, MaxCols, GetColWidth, + DisplayFormulas)) then + begin + CellHash.Delete(CP^.Loc, D); + Dispose(CP, Done); + Exit; + end; + CP := OverwriteHash.Search(CP^.Loc); + if CP <> Empty then + Good := OverwriteHash.Change(CP, CP^.Overwritten(CellHash, + FormatHash, WidthHash, LastPos, + MaxCols, GetColWidth, + DisplayFormulas)); + CP := NextItem; + end; + end; { with } +end; { Spreadsheet.FixOverwrite } + +function Spreadsheet.FromFile(Name : PathStr) : Boolean; +{ Reads a spreadsheet from disk } +var + Header : String[Length(FileHeader)]; + TotalC : Longint; + TotalW : Word; + TotalF : Longint; + S : SSStream; + NewLastPos : CellPos; +begin + FromFile := True; + Name := UpperCase(Name); + S.Init(Name, SOpen); + if S.Status <> 0 then + begin + Scr.PrintError(ErrNoOpen); + Init(0, DefaultMaxCols, DefaultMaxRows, DefaultMaxDecimalPlaces, + DefaultDefaultDecimalPlaces, DefaultDefaultColWidth); + Exit; + end + else begin + Header[0] := Chr(Length(FileHeader)); + S.Read(Header[1], Length(FileHeader)); + if (S.Status <> 0) or (Header <> FileHeader) then + begin + Scr.PrintError(ErrNotSpreadsheet); + S.Done; + Init(0, DefaultMaxCols, DefaultMaxRows, DefaultMaxDecimalPlaces, + DefaultDefaultDecimalPlaces, DefaultDefaultColWidth); + Exit; + end; + FileName := Name; + S.Read(NewLastPos, SizeOf(NewLastPos)); + S.Read(TotalW, SizeOf(TotalW)); + S.Read(TotalF, SizeOf(TotalF)); + S.Read(TotalC, SizeOf(TotalC)); + if not Init(TotalC, DefaultMaxCols, DefaultMaxRows, + DefaultMaxDecimalPlaces, DefaultDefaultDecimalPlaces, + DefaultDefaultColWidth) then + begin + S.Done; + FromFile := False; + Exit; + end; + LastPos := NewLastPos; + Scr.PrintMessage(MsgLoad); + FileName := Name; + WidthHash.Load(S, TotalW); + FormatHash.Load(S, TotalF); + CellHash.Load(S, TotalC); + S.Done; + FixOverwrite; + Update(DisplayNo); + Scr.ClearMessage; + end; + FromFile := True; +end; { Spreadsheet.FromFile } + +procedure Spreadsheet.ToFile(Name : PathStr); +{ Writes a spreadsheet to disk } +var + Header : String[Length(FileHeader)]; + S : SSStream; +begin + S.Init(Name, SCreate); + if S.Status <> 0 then + begin + Scr.PrintError(ErrNoOpen); + Exit; + end; + Scr.PrintMessage(MsgSave); + FileName := Name; + Header := FileHeader; + S.Write(Header[1], Length(Header)); + S.Write(LastPos, SizeOf(LastPos)); + S.Write(WidthHash.Items, 2); + S.Write(FormatHash.Items, SizeOf(FormatHash.Items)); + S.Write(CellHash.Items, SizeOf(CellHash.Items)); + WidthHash.Store(S); + FormatHash.Store(S); + CellHash.Store(S); + Scr.ClearMessage; + S.Done; + if S.Status <> 0 then + Scr.PrintError(ErrDiskFull) + else + SetChanged(NotChanged); +end; { Spreadsheet.ToFile } + +procedure Spreadsheet.CheckForSave; +{ Before prompting for a file name, this will check to see if you want to + save the spreadsheet } +var + S : PathStr; + GoodFile, ESCPressed : Boolean; +begin + if Changed and (GetYesNo(PromptSaveYN, ESCPressed)) then + begin + S := FileName; + repeat + GoodFile := True; + if S = '' then + begin + S := ReadString(PromptFileSave, Pred(SizeOf(PathStr)), ESCPressed); + if S = '' then + Exit; + end; + if FileExists(S) then + begin + GoodFile := GetYesNo(PromptOverwriteFile, ESCPressed); + if ESCPressed then + Exit; + if not GoodFile then + S := ''; + end; + until GoodFile; + ToFile(S); + end; +end; { Spreadsheet.CheckForSave } + +procedure Spreadsheet.ChangeWidth; +{ Changes the width of a column } +var + W, C : Word; + Good : Boolean; + P : CellPos; + O : Word; + CP : CellPtr; +begin + C := GetColumn(PromptColumnWidth, MaxCols, ColSpace); + if C = 0 then + Exit; + W := GetNumber(PromptNewWidth, MinColWidth, MaxColWidth, Good); + if not Good then + Exit; + with WidthHash do + begin + Delete(C); + if W <> DefaultColWidth then + Good := Add(C, W); + end; { with } + if not Good then + Exit; + SetScreenColStart(ScreenBlock.Start.Col); + SetChanged(WasChanged); + with OverwriteHash do + begin + Done; + Init(OverwriteHashStart(CellHash.Items)); + end; + with CellHash do + begin + CP := FirstItem; + while CP <> nil do + begin + O := CP^.Overwritten(CellHash, FormatHash, WidthHash, LastPos, + MaxCols, GetColWidth, DisplayFormulas); + if O <> 0 then + Good := OverwriteHash.Add(CP, O); + CP := NextItem; + end; + end; { with } + if CurrPos.Col > ScreenBlock.Stop.Col then + SetScreenColStart(CurrPos.Col); + Display; +end; { Spreadsheet.ChangeWidth } + +function Spreadsheet.CellHashStart(TotalCells : Longint) : BucketRange; +{ Formula that determines the number of cell hash table buckets } +begin + CellHashStart := Max(100, Min(MaxBuckets, TotalCells div 10)); +end; { Spreadsheet.CellHashStart } + +function Spreadsheet.WidthHashStart(TotalCells : Longint) : BucketRange; +{ Formula that determines the number of width hash table buckets } +begin + WidthHashStart := 10; +end; { Spreadsheet.WidthHashStart } + +function Spreadsheet.OverwriteHashStart(TotalCells : Longint) : BucketRange; +{ Formula that determines the number of overwrite hash table buckets } +begin + OverwriteHashStart := 10; +end; { Spreadsheet.OverwriteHashStart } + +procedure Spreadsheet.Print; +{ Prints a spreadsheet to a file or a printer } +var + S : PathStr; + F : Text; + PageCols : Byte; + PageV, PageH : Word; + Finished, GoodFile, Error, Compress, Border, ESCPressed : Boolean; + StartCol : Word; + StartRow : Word; + + procedure WString(S : String); + begin + Writeln(F, S); + if IOResult <> 0 then + begin + if S = PrinterName then + Scr.PrintError(ErrPrinterError) + else + Scr.PrintError(ErrDiskFull); + Error := True; + Finished := True; + end; + end; { WString } + + function RowStartString(Row : Word) : String; + begin + if (PageH = 1) and Border then + RowStartString := LeftJustStr(RowToString(Row), RowNumberSpace) + else + RowStartString := ''; + end; { RowStartString } + + procedure PrintPage; + var + Counter : Word; + S : String; + Color, Cols, Rows : Byte; + P : CellPos; + begin + for Counter := 1 to PrintTopMargin do + begin + WString(''); + if Error then + Exit; + end; + Rows := Min(PrintRows - PrintTopMargin - PrintBottomMargin, + Succ(MaxRows - StartRow)); + if Border then + Dec(Rows); + Cols := 0; + Counter := Length(RowStartString(StartRow)); + while Counter <= PageCols do + begin + Inc(Counter, ColWidth(Cols + StartCol)); + Inc(Cols); + end; + Dec(Cols); + Cols := Min(Cols, Succ(MaxCols - StartCol)); + if Border and (PageV = 1) then + begin + S := FillString(Length(RowStartString(StartRow)), ' '); + for Counter := StartCol to Pred(StartCol + Cols) do + S := S + CenterStr(ColToString(Counter), ColWidth(Counter)); + WString(S); + if Error then + Exit; + end; + for P.Row := StartRow to Pred(StartRow + Rows) do + begin + S := RowStartString(P.Row); + for P.Col := StartCol to Pred(StartCol + Cols) do + S := S + CellToFString(P, Color); + WString(S); + if Error then + Exit; + end; + Inc(StartCol, Cols); + if (StartCol > LastPos.Col) or (StartCol = 0) then + begin + Inc(StartRow, Rows); + if (StartRow > LastPos.Row) or (StartRow = 0) then + Finished := True + else begin + Inc(PageV); + PageH := 1; + StartCol := 1; + end; + end + else + Inc(PageH); + Write(F, Chr(FF)); + end; { PrintPage } + +begin { Spreadsheet.Print } + repeat + GoodFile := True; + S := ReadString(PromptFilePrint, Pred(SizeOf(PathStr)), ESCPressed); + if ESCPressed then + Exit; + if S = '' then + S := PrinterName + else begin + if FileExists(S) then + begin + GoodFile := GetYesNo(PromptOverwriteFile, ESCPressed); + if ESCPressed then + Exit; + end; + end; + until GoodFile; + Compress := GetYesNo(PromptCompressPrint, ESCPressed); + if ESCPressed then + Exit; + Border := GetYesNo(PromptBorderPrint, ESCPressed); + if ESCPressed then + Exit; + Error := False; +{$I-} + Assign(F, S); + Rewrite(F); + if IOResult <> 0 then + begin + Scr.PrintError(ErrNoOpen); + Exit; + end; + if Compress then + begin + PageCols := PrintCompressedCols; + Write(F, PrinterCompressChar); + end + else + PageCols := PrintNormalCols; + PageV := 1; + PageH := 1; + StartCol := 1; + StartRow := 1; + Finished := False; + repeat + PrintPage; + until Finished; + Close(F); +{$I+} +end; { Spreadsheet.Print } + +procedure Spreadsheet.DeleteColumn; +{ Deletes a column from the spreadsheet } +var + C : Word; + Start, Stop, P, OldPos, OldSPos : CellPos; + Deleted : Boolean; + OldName : PathStr; + CP : CellPtr; + H : HashItemPtr; + B : Block; + F : File; + Good : Boolean; +begin + C := GetColumn(PromptColumnDelete, MaxCols, ColSpace); + if C = 0 then + Exit; + OldPos := CurrPos; + OldSPos := ScreenBlock.Start; + P.Col := C; + Deleted := False; + if P.Col <= LastPos.Col then + begin + with B do + begin + Start.Col := P.Col; + Start.Row := 1; + Stop.Col := P.Col; + Stop.Row := LastPos.Row; + Good := FormatHash.Delete(Start, Stop); + end; { with } + DeleteBlock(B, Deleted); + end; + Dec(LastPos.Col); + WidthHash.Delete(C); + with CellHash do + begin + CP := FirstItem; + while CP <> nil do + begin + with CP^ do + begin + if Loc.Col > C then + Dec(Loc.Col); + if (CP^.ShouldUpdate) and (Loc.Col > C) then + FixFormulaCol(CP, -1, MaxCols, MaxRows); + end; { with } + CP := NextItem; + end; + end; { with } + with WidthHash do + begin + H := FirstItem; + while H <> nil do + begin + if WordPtr(@H^.Data)^ > C then + Dec(WordPtr(@H^.Data)^); + H := NextItem; + end; + end; { with } + with FormatHash do + begin + H := FirstItem; + while H <> nil do + begin + Move(H^.Data, Start, SizeOf(Start)); + Move(H^.Data[SizeOf(CellPos)], Stop, SizeOf(Stop)); + if (Start.Col = C) and (Stop.Col = C) then + Good := Delete(Start, Stop) + else begin + if Start.Col > C then + begin + Dec(Start.Col); + Move(Start, H^.Data, SizeOf(Start)); + end; + if Stop.Col > C then + begin + Dec(Stop.Col); + Move(Stop, H^.Data[SizeOf(CellPos)], SizeOf(Stop)); + end; + end; + H := NextItem; + end; + end; { with } + OldName := FileName; + ToFile(TempFileName); + Done; + Good := FromFile(TempFileName); + Assign(F, TempFileName); + Erase(F); + FileName := OldName; + if Deleted then + P.Row := LastPos.Row + else + P.Row := 1; + Dec(P.Col); + SetLastPos(P); + MakeCurrent; + SetChanged(WasChanged); + CurrPos := OldPos; + SetScreenColStart(OldSPos.Col); + SetScreenRowStart(OldSPos.Row); + Display; +end; { Spreadsheet.DeleteColumn } + +procedure Spreadsheet.InsertColumn; +{ Inserts a column into the spreadsheet } +var + C : Word; + Start, Stop, P, OldPos, OldSPos : CellPos; + Deleted : Boolean; + H : HashItemPtr; + OldName : PathStr; + CP : CellPtr; + B : Block; + F : File; + Good : Boolean; +begin + C := GetColumn(PromptColumnInsert, MaxCols, ColSpace); + if C = 0 then + Exit; + OldPos := CurrPos; + OldSPos := ScreenBlock.Start; + Deleted := False; + if LastPos.Col = MaxCols then + begin + with B do + begin + Start.Col := MaxCols; + Start.Row := 1; + Stop.Col := MaxCols; + Stop.Row := LastPos.Row; + Good := FormatHash.Delete(Start, Stop); + end; { with } + DeleteBlock(B, Deleted); + end + else + Inc(LastPos.Col); + P.Col := C; + WidthHash.Delete(MaxCols); + with CellHash do + begin + CP := FirstItem; + while CP <> nil do + begin + with CP^ do + begin + if Loc.Col >= C then + Inc(Loc.Col); + if (CP^.ShouldUpdate) and (Loc.Col >= C) then + FixFormulaCol(CP, 1, MaxCols, MaxRows); + end; { with } + CP := NextItem; + end; + end; { with } + with WidthHash do + begin + H := FirstItem; + while H <> nil do + begin + if WordPtr(@H^.Data)^ >= C then + Inc(WordPtr(@H^.Data)^); + H := NextItem; + end; + end; { with } + with FormatHash do + begin + H := FirstItem; + while H <> nil do + begin + Move(H^.Data, Start, SizeOf(Start)); + Move(H^.Data[SizeOf(CellPos)], Stop, SizeOf(Stop)); + if Start.Col >= C then + begin + Inc(Start.Col); + Move(Start, H^.Data, SizeOf(Start)); + end; + if Stop.Col >= C then + begin + Inc(Stop.Col); + Move(Stop, H^.Data[SizeOf(CellPos)], SizeOf(Stop)); + end; + H := NextItem; + end; + end; { with } + OldName := FileName; + ToFile(TempFileName); + Done; + Good := FromFile(TempFileName); + Assign(F, TempFileName); + Erase(F); + FileName := OldName; + if Deleted then + P.Row := LastPos.Row + else + P.Row := 1; + if LastPos.Col = MaxCols then + P.Col := MaxCols + else + Inc(P.Col); + SetLastPos(P); + MakeCurrent; + SetChanged(WasChanged); + CurrPos := OldPos; + SetScreenColStart(OldSPos.Col); + SetScreenRowStart(OldSPos.Row); + Display; +end; { Spreadsheet.InsertColumn } + +procedure Spreadsheet.DeleteRow; +{ Deletes a row from the spreadsheet } +var + R : Word; + Start, Stop, P, OldPos, OldSPos : CellPos; + Deleted : Boolean; + OldName : PathStr; + CP : CellPtr; + B : Block; + F : File; + Good : Boolean; + H : HashItemPtr; +begin + R := GetRow(PromptRowDelete, MaxRows); + if (R = 0) or (R > LastPos.Row) then + Exit; + OldPos := CurrPos; + OldSPos := ScreenBlock.Start; + P.Row := R; + if P.Row <= LastPos.Row then + begin + with B do + begin + Start.Col := 1; + Start.Row := P.Row; + Stop.Col := LastPos.Col; + Stop.Row := P.Row; + Good := FormatHash.Delete(Start, Stop); + end; { with } + DeleteBlock(B, Deleted); + end; + Dec(LastPos.Row); + with CellHash do + begin + CP := FirstItem; + while CP <> nil do + begin + with CP^ do + begin + if Loc.Row > R then + Dec(Loc.Row); + if (CP^.ShouldUpdate) and (Loc.Row > R) then + FixFormulaRow(CP, -1, MaxCols, MaxRows); + end; { with } + CP := NextItem; + end; + end; { with } + with FormatHash do + begin + H := FirstItem; + while H <> nil do + begin + Move(H^.Data, Start, SizeOf(Start)); + Move(H^.Data[SizeOf(CellPos)], Stop, SizeOf(Stop)); + if (Start.Row = R) and (Stop.Row = R) then + Good := Delete(Start, Stop) + else begin + if Start.Row > R then + begin + Dec(Start.Row); + Move(Start, H^.Data, SizeOf(Start)); + end; + if Stop.Row > R then + begin + Dec(Stop.Row); + Move(Stop, H^.Data[SizeOf(CellPos)], SizeOf(Stop)); + end; + end; + H := NextItem; + end; + end; { with } + OldName := FileName; + ToFile(TempFileName); + Done; + Good := FromFile(TempFileName); + Assign(F, TempFileName); + Erase(F); + FileName := OldName; + if Deleted then + P.Col := LastPos.Col + else + P.Col := 1; + Dec(P.Row); + SetLastPos(P); + MakeCurrent; + SetChanged(WasChanged); + CurrPos := OldPos; + SetScreenColStart(OldSPos.Col); + SetScreenRowStart(OldSPos.Row); + Display; +end; { Spreadsheet.DeleteRow } + +procedure Spreadsheet.InsertRow; +{ Inserts a row into the spreadsheet } +var + R : Word; + Start, Stop, P, OldPos, OldSPos : CellPos; + Deleted : Boolean; + OldName : PathStr; + CP : CellPtr; + B : Block; + F : File; + Good : Boolean; + H : HashItemPtr; +begin + R := GetRow(PromptRowInsert, MaxRows); + if (R = 0) or (R > LastPos.Row) then + Exit; + OldPos := CurrPos; + OldSPos := ScreenBlock.Start; + if LastPos.Row = MaxRows then + begin + with B do + begin + Start.Col := 1; + Start.Row := MaxRows; + Stop.Col := LastPos.Col; + Stop.Row := MaxRows; + Good := FormatHash.Delete(Start, Stop); + end; { with } + DeleteBlock(B, Deleted); + end + else + Inc(LastPos.Row); + P.Row := R; + with CellHash do + begin + CP := FirstItem; + while CP <> nil do + begin + with CP^ do + begin + if Loc.Row >= R then + Inc(Loc.Row); + if (CP^.ShouldUpdate) and (Loc.Row >= R) then + FixFormulaRow(CP, 1, MaxCols, MaxRows); + end; { with } + CP := NextItem; + end; + end; { with } + with FormatHash do + begin + H := FirstItem; + while H <> nil do + begin + Move(H^.Data, Start, SizeOf(Start)); + Move(H^.Data[SizeOf(CellPos)], Stop, SizeOf(Stop)); + if Start.Row >= R then + begin + Inc(Start.Row); + Move(Start, H^.Data, SizeOf(Start)); + end; + if Stop.Row >= R then + begin + Inc(Stop.Row); + Move(Stop, H^.Data[SizeOf(CellPos)], SizeOf(Stop)); + end; + H := NextItem; + end; + end; { with } + OldName := FileName; + ToFile(TempFileName); + Done; + Good := FromFile(TempFileName); + Assign(F, TempFileName); + Erase(F); + FileName := OldName; + if Deleted then + P.Col := LastPos.Col + else + P.Col := 1; + if LastPos.Row = MaxRows then + P.Row := MaxRows + else + Inc(P.Row); + SetLastPos(P); + MakeCurrent; + SetChanged(WasChanged); + CurrPos := OldPos; + SetScreenColStart(OldSPos.Col); + SetScreenRowStart(OldSPos.Row); + Display; +end; { Spreadsheet.InsertRow } + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCSHEET.TPU b/Borland Turbo Pascal v55/TCSHEET.TPU new file mode 100644 index 0000000000000000000000000000000000000000..a6218356502a5786f934eecc721992be1e5a92a9 GIT binary patch literal 33312 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 Ord(' ')) and (Ch <= Ord('~')) then + GetKeyUpCase := Ord(UpCase(Chr(Ch))) { Change the character's case } + else + GetKeyUpCase := Ch; { Leave the character alone } +end; { GetKeyUpCase } + +function GetKeyChar(Legal : CharSet) : Char; +{ Reads an ASCII key from the keyboard, only accepting keys in Legal } +var + Ch : Word; +begin + repeat + Ch := GetKeyUpCase; + until (Ch = ESC) or (Chr(Lo(Ch)) in Legal); + GetKeyChar := Chr(Lo(Ch)); +end; { GetKeyChar } + +procedure Abort(Message : String); +{ Aborts the program with an error message } +begin + AbortMessage := Message; + Halt(1); +end; { Abort } + +procedure Beep; +{ Produces a low beep on the speaker } +begin + Sound(220); + Delay(300); + NoSound; +end; { Beep } + +function FileExists(F : String) : Boolean; +{ Checks to see if a selected file exists } +var + SR : SearchRec; +begin + FindFirst(F, AnyFile, SR); + FileExists := DosError = 0; +end; { FileExists } + +function Min(N1, N2 : Longint) : Longint; +{ Returns the smaller of two numbers } +begin + if N1 <= N2 then + Min := N1 + else + Min := N2; +end; { Min } + +function Max(N1, N2 : Longint) : Longint; +{ Returns the larger of two numbers } +begin + if N1 >= N2 then + Max := N1 + else + Max := N2; +end; { Max } + +function NumToString(N : Longint) : String; +{ Converts a number to a string } +var + S : String[80]; +begin + Str(N, S); + NumToString := S; +end; { NumToString } + +function UpperCase(S : String) : String; +{ Returns an all-upper case version of a string } +var + Counter : Word; +begin + for Counter := 1 to Length(S) do + S[Counter] := UpCase(S[Counter]); + UpperCase := S; +end; { UpperCase } + +function FillString(Len : Byte; Ch : Char) : String; +var + S : String; +begin + S[0] := Chr(Len); + FillChar(S[1], Len, Ch); + FillString := S; +end; { FillString } + +function TruncStr(TString : String; Len : Byte) : String; +{ Truncates a string to a specified length } +begin + if Length(TString) > Len then + Delete(TString, Succ(Len), Length(TString) - Len); + TruncStr := TString; +end; { TruncStr } + +function PadChar(PString : String; Ch : Char; Len : Byte) : String; +{ Pads a string to a specified length with a specified character } +var + CurrLen : Byte; +begin + CurrLen := Min(Length(PString), Len); + PString[0] := Chr(Len); + FillChar(PString[Succ(CurrLen)], Len - CurrLen, Ch); + PadChar := PString; +end; { PadChar } + +function CenterStr(S : String; Width : Byte) : String; +{ Center a string within a certain width } +begin + S := LeftJustStr(LeftJustStr('', (Width - Length(S)) shr 1) + S, Width); + CenterStr := S; +end; { CenterStr } + +function LeftJustStr(S : String; Width : Byte) : String; +{ Left-justify a string within a certain width } +begin + LeftJustStr := PadChar(S, ' ', Width); +end; { LeftJustStr } + +function RightJustStr(S : String; Width : Byte) : String; +{ Right-justify a string within a certain width } +begin + S := TruncStr(S, Width); + RightJustStr := LeftJustStr('', Width - Length(S)) + S; +end; { RightJustStr } + +function ColToString(Col : Word) : String; +{ Converts a column to a string } +var + S : String[4]; + W : Word; +begin + if Col > 18278 then { Column is 4 letters } + S := Chr(Ord('A') + ((Col - 18279) div 17576)) + else + S := ''; + if Col > 702 then { Column is at least 3 letters } + S := S + Chr(Ord('A') + (((Col - 703) mod 17576) div 676)); + if Col > 26 then { Column is at least 2 letters } + S := S + Chr(Ord('A') + (((Col - 27) mod 676) div 26)); + S := S + Chr(Ord('A') + (Pred(Col) mod 26)); + ColToString := S; +end; { ColToString } + +function RowToString(Row : Word) : String; +{ Converts a row to a string } +begin + RowToString := NumToString(Row); +end; { RowToString } + +function StringToCol(S : String; MaxCols : Word) : Word; +{ Converts a string to a column } +var + L : Byte; + C : Longint; +begin + StringToCol := 0; { Return 0 by default to indicate a bad column } + L := Length(S); + if L = 0 then + Exit; + S := UpperCase(S); + for C := 1 to L do + begin + if not (S[C] in Letters) then { Bad letter - return } + Exit; + end; + C := Ord(S[L]) - Ord(Pred('A')); + if L > 1 then + Inc(C, (Ord(S[Pred(L)]) - Ord(Pred('A'))) * 26); + if L > 2 then + Inc(C, (Ord(S[L - 2]) - Ord(Pred('A'))) * 676); + if L > 3 then + Inc(C, Longint(Ord(S[L - 3]) - Ord(Pred('A'))) * 17576); + if C > MaxCols then + Exit; + StringToCol := C; { Successful - return column string } +end; { StringToCol } + +function StringToRow(S : String; MaxRows : Word) : Word; +{ Converts a string to a Rown } +var + R : Longint; + Error : Integer; +begin + StringToRow := 0; { Return 0 by default to indicate a bad row } + if S = '' then + Exit; + Val(S, R, Error); + if (Error = 0) and (R <= MaxRows) then + StringToRow := R; +end; { StringToRow } + +procedure ClearInputBuffer; +{ Clears the keyboard buffer } +var + Ch : Char; +begin + while KeyPressed do + Ch := ReadKey; +end; { ClearInputBuffer } + +{$F+} + +function UtilHeapError(Size : Word) : Integer; +{ Simple heap error handler - returns a nil pointer if allocation was not + successful } +begin + UtilHeapError := 1; +end; { UtilHeapError } + +procedure UtilExit; +{ Called on exit to print abort message and restore exit procedure } +begin + if AbortMessage <> '' then + Writeln(AbortMessage + '.'); + ExitProc := SavedExitProc; +end; { UtilExit } + +{$F-} + +begin + SavedExitProc := ExitProc; + HeapError := @UtilHeapError; + ExitProc := @UtilExit; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TCUTIL.TPU b/Borland Turbo Pascal v55/TCUTIL.TPU new file mode 100644 index 0000000000000000000000000000000000000000..7039138198aa652956285dd3923dc7b4c5bd4b74 GIT binary patch literal 7552 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/THELP.COM b/Borland Turbo Pascal v55/THELP.COM new file mode 100644 index 0000000000000000000000000000000000000000..3bde28a58dedb22b090307ff9478329a203fb21e GIT binary patch literal 28246 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

7#hI3Hx!Oc+>J7XyRTr0_ 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TINSTXFR.EXE b/Borland Turbo Pascal v55/TINSTXFR.EXE new file mode 100644 index 0000000000000000000000000000000000000000..af881b7f79d76024ecb7d33c83d36b80a7e4419a GIT binary patch literal 18106 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 E1h8oY(*OVf literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TINY.EXE b/Borland Turbo Pascal v55/TINY.EXE new file mode 100644 index 0000000000000000000000000000000000000000..28b9f50fb689e739aa11b02142742b6749d093b9 GIT binary patch literal 1840 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TOUR.EXE b/Borland Turbo Pascal v55/TOUR.EXE new file mode 100644 index 0000000000000000000000000000000000000000..38b20fcd3a2cad2b0e0ab7d7b4602c676a8a5fc4 GIT binary patch literal 79065 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 L>oDkh;qU(do|W;V literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TPC.CFG b/Borland Turbo Pascal v55/TPC.CFG new file mode 100644 index 0000000..0242334 --- /dev/null +++ b/Borland Turbo Pascal v55/TPC.CFG @@ -0,0 +1 @@ +/UE:\TP;E:\TP\TURBO3 \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TPC.EXE b/Borland Turbo Pascal v55/TPC.EXE new file mode 100644 index 0000000000000000000000000000000000000000..eedfc6eb21d383b818dd8df3ef9bb66762d8bbdf GIT binary patch literal 61926 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 Fe*u~3oJ{}# literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TPCONFIG.EXE b/Borland Turbo Pascal v55/TPCONFIG.EXE new file mode 100644 index 0000000000000000000000000000000000000000..ed6770c9343a9a24c174f95d7f7e3d2a19b0f575 GIT binary patch literal 14484 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 PfBpXRmqPA;EZ5{8NzEM^ literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TPTOUR2.CBT b/Borland Turbo Pascal v55/TPTOUR2.CBT new file mode 100644 index 0000000000000000000000000000000000000000..868fa3dcda7e79e5ca24e4aa8ee3a2860d0211a8 GIT binary patch literal 97656 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 aG-1pT=U;KyCw?& literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TPUMOVER.EXE b/Borland Turbo Pascal v55/TPUMOVER.EXE new file mode 100644 index 0000000000000000000000000000000000000000..17cae41a614592a84aa554de9919bfbb319b7aaf GIT binary patch literal 33120 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 N+yCZcs1=d#{{ga}K=A+o literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TRIP.CHR b/Borland Turbo Pascal v55/TRIP.CHR new file mode 100644 index 0000000000000000000000000000000000000000..12b58a7c9d8397c07058c8acb0507e033c7de68d GIT binary patch literal 7241 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TTT.PAS b/Borland Turbo Pascal v55/TTT.PAS new file mode 100644 index 0000000..8cdbb43 --- /dev/null +++ b/Borland Turbo Pascal v55/TTT.PAS @@ -0,0 +1,390 @@ +{ App to prove you can't win at Tic-Tac-Toe } +{ use of byte instead of integer should be faster, but it's not } + +program ttt; + +uses Dos; + +{$I timeutil.pas} +{$I dos_gt.pas} + +type TScoreFunc = function : integer; + +const + scoreWin = 6; + scoreTie = 5; + scoreLose = 4; + scoreMax = 9; + scoreMin = 2; + scoreInvalid = 0; + + pieceBlank = 0; + pieceX = 1; + pieceO = 2; + + iterations = 1; + +type + boardType = array[ 0..8 ] of integer; + funcArrayType = array[ 0..8 ] of pointer; + +var + { update evaluated after each run because longint operations are slow } + evaluated: longint; + moves: integer; + board: boardType; + timeStart, timeEnd: timetype; + scoreFuncs : funcArrayType; + +procedure dumpBoard; +var + i : integer; +begin + Write( '{' ); + for i := 0 to 8 do + Write( board[i] ); + Write( '}' ); +end; + +function func0 : integer; +var x : integer; +begin + x := board[0]; + if ( ( ( x = board[1] ) and ( x = board[2] ) ) or + ( ( x = board[3] ) and ( x = board[6] ) ) or + ( ( x = board[4] ) and ( x = board[8] ) ) ) then + func0 := x + else + func0 := pieceBlank; +end; + +function func1 : integer; +var x : integer; +begin + x := board[1]; + if ( ( ( x = board[0] ) and ( x = board[2] ) ) or + ( ( x = board[4] ) and ( x = board[7] ) ) ) then + func1 := x + else + func1 := pieceBlank; +end; + +function func2 : integer; +var x : integer; +begin + x := board[2]; + if ( ( ( x = board[0] ) and ( x = board[1] ) ) or + ( ( x = board[5] ) and ( x = board[8] ) ) or + ( ( x = board[4] ) and ( x = board[6] ) ) ) then + func2 := x + else + func2 := pieceBlank; +end; + +function func3 : integer; +var x : integer; +begin + x := board[3]; + if ( ( ( x = board[4] ) and ( x = board[5] ) ) or + ( ( x = board[0] ) and ( x = board[6] ) ) ) then + func3 := x + else + func3 := pieceBlank; +end; + +function func4 : integer; +var x : integer; +begin + x := board[4]; + if ( ( ( x = board[0] ) and ( x = board[8] ) ) or + ( ( x = board[2] ) and ( x = board[6] ) ) or + ( ( x = board[1] ) and ( x = board[7] ) ) or + ( ( x = board[3] ) and ( x = board[5] ) ) ) then + func4 := x + else + func4 := pieceBlank; +end; + +function func5 : integer; +var x : integer; +begin + x := board[5]; + if ( ( ( x = board[3] ) and ( x = board[4] ) ) or + ( ( x = board[2] ) and ( x = board[8] ) ) ) then + func5 := x + else + func5 := pieceBlank; +end; + +function func6 : integer; +var x : integer; +begin + x := board[6]; + if ( ( ( x = board[7] ) and ( x = board[8] ) ) or + ( ( x = board[0] ) and ( x = board[3] ) ) or + ( ( x = board[4] ) and ( x = board[2] ) ) ) then + func6 := x + else + func6 := pieceBlank; +end; + +function func7 : integer; +var x : integer; +begin + x := board[7]; + if ( ( ( x = board[6] ) and ( x = board[8] ) ) or + ( ( x = board[1] ) and ( x = board[4] ) ) ) then + func7 := x + else + func7 := pieceBlank; +end; + +function func8 : integer; +var x : integer; +begin + x := board[8]; + if ( ( ( x = board[6] ) and ( x = board[7] ) ) or + ( ( x = board[2] ) and ( x = board[5] ) ) or + ( ( x = board[0] ) and ( x = board[4] ) ) ) then + func8 := x + else + func8 := pieceBlank; +end; + +function lookForWinner : integer; +var + t, p : integer; +begin + {dumpBoard;} + p := pieceBlank; + t := board[ 0 ]; + if pieceBlank <> t then + begin + if ( ( ( t = board[1] ) and ( t = board[2] ) ) or + ( ( t = board[3] ) and ( t = board[6] ) ) ) then + p := t; + end; + + if pieceBlank = p then + begin + t := board[1]; + if ( t = board[4] ) and ( t = board[7] ) then + p := t + else + begin + t := board[2]; + if ( t = board[5] ) and ( t = board[8] ) then + p := t + else + begin + t := board[3]; + if ( t = board[4] ) and ( t = board[5] ) then + p := t + else + begin + t := board[6]; + if ( t = board[7] ) and ( t = board[8] ) then + p := t + else + begin + t := board[4]; + if ( ( ( t = board[0] ) and ( t = board[8] ) ) or + ( ( t = board[2] ) and ( t = board[6] ) ) ) then + p := t + end; + end; + end; + end; + end; + + lookForWinner := p; +end; + +function winner2( move: integer ) : integer; +var + x : integer; +begin + case move of + 0: begin + x := board[ 0 ]; + if not ( ( ( x = board[1] ) and ( x = board[2] ) ) or + ( ( x = board[3] ) and ( x = board[6] ) ) or + ( ( x = board[4] ) and ( x = board[8] ) ) ) + then x := PieceBlank; + end; + 1: begin + x := board[ 1 ]; + if not ( ( ( x = board[0] ) and ( x = board[2] ) ) or + ( ( x = board[4] ) and ( x = board[7] ) ) ) + then x := PieceBlank; + end; + 2: begin + x := board[ 2 ]; + if not ( ( ( x = board[0] ) and ( x = board[1] ) ) or + ( ( x = board[5] ) and ( x = board[8] ) ) or + ( ( x = board[4] ) and ( x = board[6] ) ) ) + then x := PieceBlank; + end; + 3: begin + x := board[ 3 ]; + if not ( ( ( x = board[4] ) and ( x = board[5] ) ) or + ( ( x = board[0] ) and ( x = board[6] ) ) ) + then x := PieceBlank; + end; + 4: begin + x := board[ 4 ]; + if not ( ( ( x = board[0] ) and ( x = board[8] ) ) or + ( ( x = board[2] ) and ( x = board[6] ) ) or + ( ( x = board[1] ) and ( x = board[7] ) ) or + ( ( x = board[3] ) and ( x = board[5] ) ) ) + then x := PieceBlank; + end; + 5: begin + x := board[ 5 ]; + if not ( ( ( x = board[3] ) and ( x = board[4] ) ) or + ( ( x = board[2] ) and ( x = board[8] ) ) ) + then x := PieceBlank; + end; + 6: begin + x := board[ 6 ]; + if not ( ( ( x = board[7] ) and ( x = board[8] ) ) or + ( ( x = board[0] ) and ( x = board[3] ) ) or + ( ( x = board[4] ) and ( x = board[2] ) ) ) + then x := PieceBlank; + end; + 7: begin + x := board[ 7 ]; + if not ( ( ( x = board[6] ) and ( x = board[8] ) ) or + ( ( x = board[1] ) and ( x = board[4] ) ) ) + then x := PieceBlank; + end; + 8: begin + x := board[ 8 ]; + if not ( ( ( x = board[6] ) and ( x = board[7] ) ) or + ( ( x = board[2] ) and ( x = board[5] ) ) or + ( ( x = board[0] ) and ( x = board[4] ) ) ) + then x := PieceBlank; + end; + end; + + winner2 := x; +end; + +function minmax( alpha: integer; beta: integer; depth: integer; move : integer ): integer; +var + p, value, pieceMove, score : integer; +begin + moves := moves + 1; + value := scoreInvalid; + if depth >= 4 then + begin + { p := winner2( move ); } + p := TScoreFunc( scoreFuncs[ move ] ); + { p := LookForWinner; this is 10% slower than using function pointers } + + if p <> pieceBlank then + begin + if p = pieceX then + value := scoreWin + else + value := scoreLose + end + else if depth = 8 then + value := scoreTie; + end; + + if value = scoreInvalid then + begin + if Odd( depth ) then + begin + value := scoreMin; + pieceMove := pieceX; + end + else + begin + value := scoreMax; + pieceMove := pieceO; + end; + + p := 0; + repeat + if board[ p ] = pieceBlank then + begin + board[ p ] := pieceMove; + score := minmax( alpha, beta, depth + 1, p ); + board[ p ] := pieceBlank; + + if Odd( depth ) then + begin + if ( score > value ) then + begin + value := score; + if ( value = scoreWin ) or ( value >= beta ) then p := 10 + else if ( value > alpha ) then alpha := value; + end; + end + else + begin + if ( score < value ) then + begin + value := score; + if ( value = scoreLose ) or ( value <= alpha ) then p := 10 + else if ( value < beta ) then beta := value; + end; + end; + end; + p := p + 1; + until p > 8; + end; + + minmax := value; +end; + +procedure runit( move : integer ); +var score : integer; +begin + board[move] := pieceX; + score := minmax( scoreMin, scoreMax, 0, move ); + board[move] := pieceBlank; +end; + +var + i, errpos, loops: integer; +begin + loops := Iterations; + + if 0 <> Length( ParamStr( 1 ) ) then + Val( ParamStr( 1 ), loops, errpos ); + + for i := 0 to 8 do + board[i] := pieceBlank; + + scoreFuncs[0] := @func0; + scoreFuncs[1] := @func1; + scoreFuncs[2] := @func2; + scoreFuncs[3] := @func3; + scoreFuncs[4] := @func4; + scoreFuncs[5] := @func5; + scoreFuncs[6] := @func6; + scoreFuncs[7] := @func7; + scoreFuncs[8] := @func8; + + evaluated := 0; + get_time( timeStart ); + + for i := 1 to loops do + begin + moves := 0; + runit( 0 ); + runit( 1 ); + runit( 4 ); + evaluated := evaluated + moves; + end; + + get_time( timeEnd ); + print_elapsed_time( timeStart, timeEnd ); + + WriteLn( 'moves evaluated: ', evaluated ); + WriteLn( 'iterations: ', loops ); +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TURBO.EXE b/Borland Turbo Pascal v55/TURBO.EXE new file mode 100644 index 0000000000000000000000000000000000000000..265a098594e3863671f24f13544c89f1ed1f2280 GIT binary patch literal 156321 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�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

}#qxi9obsD-pmNLe2 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 b`-w+;lShp(P&_?d*khw`ldneqW3T@Q7ogW& literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TURBO.HLP b/Borland Turbo Pascal v55/TURBO.HLP new file mode 100644 index 0000000000000000000000000000000000000000..19fcd817b696df4f8884aac93765a3536cec671e GIT binary patch literal 240493 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 mrt%5YF9X@Ws0bX}`#V zcTY~|p3I%xMyusp>V)z4dpviZ(#2=;wOYnMNxE=ellg~ZLmI8N*f2z30J;na4yaAC zM5jzv=vd?-S*2g2uIouOGWpPisbRno_bQIFPc4OY!qQV^2WQmhN8Ap#}}nz-T8My^krb_ z8pQGEK?W8_J@{iJXq?th>l#F4I`r4A;3@PSK);V)3JJ+oCC$nSb>KlrN=eE7XCfgc zO_I@=nvt@cM02^Cr0ir9g0Y^vvWZvQv{%R@11SMf0=MOsVS- z&(hAy%uG*B%Al1aD$JT^N~H|a=j1s_*>dG3b@H5)wCtD3pSfIB@|^5x4vzqlIlA64V z@}x;gO;0tYMvx7hNt=?EV+7fuWDA$2Ny*Hem7cm0gy*4T3QDFYo&&MeOoKo98mQFF z^b8+zm@}zUvy*aC6DT<$wIIzjhs@%UufS*_9xh9lT3~{pQd2%)O*09Gq_p(+NIq{= z84$Loogh|^Cr#gR1>830y!f;1D{U9c#|+EDczJp9_DlTIcZgn zM|qPfEhG7L!mCW0w2Yk8Y*Q#X1n$!^OivQMDocxp)Y+-o2f%!QDp!}5nVp)Gn{IkL z(E@R&r)JDH%~|CbqsryeGhQZ_K{h?}bM#P_Ha#!sRb|v5rsSdn{biL=56pnFbONNR3RGwS9UH#@4|rq*Y>Drx3Iy6RTFGUO zJ?9_8^YOI=6~sq$1AsriKLQst^LQ&M6achJyGLr!AiS&GR{ zndBJC=jx3~*-3MgGjlUco5)}xSI6QxrtFVN2byV2t0qVJEUhtWhBi_O(eH54$(EKrU|5k zF%h?9A-9i3io@q^3SGjhq&8we$&t zTt~h`sh&mKax%%OP4bT&4xfe1&h2I8PhVJCX>}! z8a&KSPhAi6E+H4O`Ji0j&_OCW5QZr+gJ#akjv%jNDC5DjkUXHq6KXOh{!wjGLGVu# zD@EldCqL*Yq)+)t#%+#FNQLt75@4*o$Z~Omz|smZIYH_V)~U*D3kGXQj?6d=^Rzi6n|M@`BPG7 z<<5o}II5`WNXpV=>p_R+&&;09Q8PlbcdPr+G`C(s9~Ao0P%xa2f)3I!;^~`-u&kw67k1sqjA z6c?=E9@NUXxoH_(C~&kLPiwQiC_OgpxNs%s1Db5;$TX8NJ2RP!RFDZ;8A(OTjR%q{ zAU~96WvLb7CMa1SQ)hc&iW$-hFle|KU};?%h%(2Nl>9_`+T1h~7ptI+pqrMFnQOva z;i&zfbYsB*orM_eDIE0-s6P2Ca#9sMmvS&2$ghE12Bax9$22Ww+EgxHL7vxUtJ5-! zxhBL3q2n=Am#sk^428i!Q9a;2Cn+x#lOzT_VkA&$zN5K^jU|GD{q|noM`l6$%X!z{ z!^XxD9|e0Btyk#AP9pva_S8MPag)eU1zR=%JDCJ3*sb>{#7!Z=3icPee!6i}NvMLY zzQ;q{G!mg;#|_B)D0xu9{%SyNNo0b8{dz#&StLfmelq}@OeQJVa|5s`WSWA#GXR@P z5)`bj*FAm>BvHW{?_sA-CMgOQHibG-_-jOHCUhbM!UGE=V-VILyo2xw0wL6qd60}k zcnl#OVGY6#1U2^{i9wi!un1u*8+$QiEr}t2Cr0u#ZzN?1>kxJ$>_wE3gd+$Nf)^J<#vvqdcSt6oxM>72zMm zg}951APs;GkW~X}Z6H2K8_6}3P=qq>4ARaZ&l$AGNIvFu9Hp^=Tqk2u2SJDry!e`*&RfPQrsi4))8Odlq5qT4d24M(7AVN4oB*J)vSOg#9 z04)dd*;sfAQhgBN6@)bicM*O`K7ZE<^p9KC%@c10ybEKSmnY;_>nfSL6f15-gBqBVG*dIal2eiQlVFM&} zCNz|*8vP*m6aOIhyegF3BBA6T$fM;~adcefp)LvoQI^7OkTivyY8gw{@-lut%22#c zCBt;cm&Si9yv*{Q}?Z~8X}a{1r>s0I7~<4^GoVAEe*{mKx%>?uSWlX9>Sqxj^Y0Nrest4!1AWq#{1-B!Yc5-bO_+S_^izP z%m1u?)6eQR{k(od?tT4Z_!&QjpQppS9#}tCB=^Y=3y7S7>BxRxI$hQcOixXlHsxpW z`{bEA_h;#I@0TBj7Nai@H~j7-WbKL78bac(i2Kw5WUFx0wYo{Q_pgNDe-#qw6Hot- z{0mPe5`R4HA!PTD+>Rk+U2pW~+a}kCRg7Mp%9qy)=dOqNj@kJwEXla~u$|wN>ai5Q zPpTs*JV2^v0*>q{}Qc>KX^jSDtKYIkmZ8Yx@#E}lq2?D>uxLW~g<3heuwM*BV&M+%Hvg(jCv zMG7MPgqVcsW?sW<8XGZb@|3C59-SVaFypbA)@ZqjFiZGh^@%C_m+GhNE7eR9GlkyvkJp|!tS90@ z@q~C??Cv~k%oY!Hwu;SSZRc6>;QRvBQB`AIuGr=+S)TMh`Q9t~&c@E8K0+Npq1rk$5=FtKQ%U=>#mcZ&onmS*}G}Qfa>bRAEt=21(!t3TCqkvdYC8G zb#faie#*W~&1$D>6=zl*){yFNl$3p?0z?^Ep+<*CR;2QW1p+$2Mv7{Ttw=GI$8=)j z3`wrZym&x7z7L%cHJm3==#ioa)c)jgDJ&8j1Cdd=e55K>nBh;%!bE>ED>6!5B+&Ho zTAjDYdeW87*ST(R|3)K*(HI{oE&`23eEbP>P^36lh>RLkB$U_qKM{Xosm82}KWG+c z%Vc6rE)Q2{bY12sHFa!b12QDHjkv0FZHK+Fe7y6QS@!D1`}Hr(?4i6 zRzF&a)vHg%I9)>s=2FF=$cjZg#)W`ZXq+M>U4Bhx87X!)UX}k-P2ovALb196iD;IH z>D3$giTocjS0K&`qW=d+A&)g6u0wo`CuOz7-$@Zge4Iz@EWha2cuoFKh17Ti$~2v= zMLJ59mT`&=X?`8hxD8fULaXY;;N9cHxf`DXjU*eh&03q(#C zFwZ}qUQ^85YwqR2l$VFST^)NKBfXE74`}J^P;1Z*8t+4;svR6r-H56&2P9H`;eBWY zA9pCerdT7^NPL`Qvv`nIsp}`en2EFxioNoABvBXXA`hrN_L`0cRo860oR?J=LhE7k zj%ICrX!hp`ocW=py3cR^-5Q)Jjfp)kHbym=2hTzUpIUsQ4ytZ|!sFKKaSllrbw{k7 z5;a>GbGWZwh1lnj_Hn3Y`Zs9oH~K>s4J7iZm7l&3N{(fvdasJxJjFg+*bIfy*J?eu zfj$IMX^)2FikHhS6MoHZ;u)U5uSBoOujYtRG-&3)LN>VfmH2A%eO)>aGPsoto?;E` z9Fn)XeO*_P1%*7tI$zgs+~S2rhkg2JmX~NqN%Fr@)=|pE?g0cvgHC187-gahLG&G& zsEioNsP;)h&GV{-^OwO~8H^>c5>U{uFn->>RPZ z(ZDwjxo$sLR!na0%W;S72Cid?7Vblr*diK8=MtUjdO&vop83ut8s+&0OVO+D1e^%K zGg5SY&jQUQ(G7Uks}2MlFW=|0VcsG%QY$wyt*oug)-SjsRpW`I zj{S*NU6Q>f_IAS+XPg5~XmCOZiU80@tl?A;d&f79x}IId@8n4QHLE866qLmUvu6AS zNcmc0lX-B%c?k0RqH{9ljwHDcF4JctyY<4CiPBkd?^eyxGYjU=TLeGoX!%VKxN4xH zPb;gj+1j4En<0Rq7O*y-!%C*{^yx z4Rngc=IRgOXjy$$9<5rZ@30DQ+^kyV-Ly>SKBzhw(Dce3{gq`Zj1=dFt$!Y0XU?#7 zjamAHyTY`v0dz@&kxmMP>rWgV`v%++v(Pm*{g0lMGzu4li@ zxx=tQ(!9dO&j0->VN+3>TvzP*xRbOEw&F)^UH)bt`z7(jPLBtTlCIIoHmGl^eGQxr zJb8D~8P)Iu+IM^G@v*1EFVw|4>aug7UN?DUngt8yQ6uKh;U1UwFFx;sq z?5@b`wbj@fy6|JKnJ{#f!7Uo@h=tu^Uazab~X(=3A;$e@N-SK&`rvSl;=P(n@X(a6khEgN5BwAbvg_3Vyo-y=*$9kN)e z%Lo;}%iuQd0lTH{Ya}Qbxyv$@d_sfpij9 z73HD^w`03U=ETUx6q>}l4>Bc9S^JpZp(Cy;ZeC+sk#E+HvU@F?$JdyLzHjlrzl9hN z1@cIJF?#giCm(s)Fu{GH)G}px#p_{9a}qqx=vSLoEcnyt<>RUi1y7X>@4a@{YHR8o zVSa=SBaPl+Rkbx>olC_kB!OpCO5!@=D3fNNKECE9C1vd>d3^WUwmrY`K}wO@b%jVv z_iR_~;7L|~v^XeQwDQs73IU0W=b3fowL{KbD!-;Fuhmo-x+@BMEArg;W!v5hVTguq zv9MRnbEDL~Y6p&X*Bb;Y1VBoVgjqZ2#*(m(?V9LChQHaen9FCF!TR2(&ua5)N5?pKd}EM#rC@i)9V9l3{%E-Fl=ETo$yOr;X;q@9MGfd2lVLX zJr`6v)C4?d<;(T5hPpI#OhH@7((G?)w5X28G9y~d6|(Xr|DQ`p%;*-2d&Lsk?#1)a zzH>hgX#Ryo&Y5GBtreT6bQhL(p0)7&BiCvskR6`VUM%}CY=UM?n`-r^i@$^!R-Ntq zX^?9=HD%+;v5&RpKPtrw#?iyl$>*m+Ho`eX3SLWj0vbB)`_Nq_?uZm8V)Nf1Ft~^eewqX%LtlIj? zQ#3?Ux8S$(Lk;O@2-oPyGTnQ0@iwO5NYADjmYIEI=FOY8psWX_RCw6LS%>XBNHz)9 z!8_~8CY@D}4Wdo{R@KfUWIZ|{WIuLeD%Y(W4i*d$}TFVnNPCjfg%xE5ANtyA(2+PbF&0{RnXZ$e6GI>VxRLh_lKTNgg zDo>tseddt@qRXPEah``=l^)jv1V}2aAF{E#O)uojyrNgOVaIvF#g zKRO`q2T!Xq>GEG_a?0G zY+nzr-8F@5sJ4+Ep#+M^s&8zCBY5y!d#nQ*sm?VLeEwN87kpwG)K5NJKlyI`qb>C_ z>dtzwF+%qT#DmeDk-sO6XX$@@o2pTD6f{~@NBQ=x>Z7fEyX-9}I|okn>)R$^zY!~V zx{*+q-wQ{kX~iJ;rcLEe4!&a5#Lc_2$yTrEcoVjxmik1;2N!9}4+t>Nm)$j054#=F zQNhtcCcfx)v?@3{z{DeQGg8lsM;1pNagxLD#*?$R)wYc|rkUkOK74~C{tsa9PDR*} z4LxD!5U8sX*U>sJ(l#T?qQ&n-tJ*L-t#u9_BP=PA_R%(Jy3MICda!dZxo&+V2mWJI zwvqnQut4Qp5O8!stViVp)60g;K3AV%9kAa-y&+KRrgVCKVOH6sP??_D+a`^$IW ztC1|$R!~*u_U>5bqblw;yrMf`xJ;zz&Qs-XAG2z=H?h5XdGdi-mx*~)#xg(mtjmZ$ zTI@?P($!kSh!7Z2%m^$sLAXco7gjG^F>TSJYK8nayUP4)s;Hu@)vM^(}zCQk76&bi{+KrnwSFyEv#kM~t za@9oJML*aOh#T&<{5wxoGcTZJUO=N9ot`bHEv8pua3vw3|9or{@&Dwz=e`#9918Mve!gE?HnE}p+n~KUr@EFs zI+K&4Hhr;w^qoVmefw4-)Noo>9=Z}cQx4iyZ2c?$7OD;u2AnDkI9B8>FMn+{oOz_W zZ~a@OZ9G9ST8tTcji4%==cH4dPIY=pOQ$|n0aO)Gl|WSk`wRW&?vaUjqTH>Wl=#8+ zmnlE*|0?nOPmg%g#w^==H1W*pHrt`uJ2z}fT6?PN{T``gb5?Tgo4%j^{lk&1e>IHo zv6j7IEj~17?uA7&_AiPTKUhD%@~u!ipZ(;%aaKs7c>1rsPfe$F&_DPTGXvP@da!k$h%WL zm_+S$-Q=jnNT`f{ozzciseiNt6?GbVNs`5@KH=Rd0`$V2`uO6@YYLmU3cI~X{S5mo z$$qBEWjpVO**m2|o1C0sm8MioEidUN%e~7>?nEqC*BZL7dc@*xSs&eD`ly*mQB)rd zDT=VY+6-mX+^3A15ogK>S)h!XsWQ5QjZdmBmQC(&m6&noo-VTV>7x1f>!K%I^JQJc ziZNZ3)~}0Z4%9_=`gKvY{^|7{9rjyqcif~3$$mh2V4A6Z>bd&KFS#LprlOkrRg~;% zvYta0x$`DpZ7pKTq33?(kmdRnRzj`5boxhIwNME2Nax9d_!>(}>jU?6LU5l>h?X_N z12a|ztO%d+%H@*LP!dj8DzTOHOth-%C!gu>DKBE-y6$5V6$SSxfdF)(uRz|0+Nz&! z=!Hs<&N*ig{}LbC=dY6b>4$I#ID=eY(U0g-6MvXthb8_MzOz}pUVc&Ac(L&!^1qI2 zG%otz?ocB6HoA(mKu!RO@&kHr_%q%omkEeD>!)|gS~FBM_=dF>yMfym{ZPi%*>ZQK|=}%UVC< z9y{U>A=trXdzZa&jxE(y$G5=o+k(d}Th^pnwyXwj7`J8hL7;Z{lJ+g1CuA1$RhjZh z0ZcO8Kxdo0db;^d&piOq1*txOIzZnz2Y%_39;bvmw;q>tJHI?Gsdj#KoR!1TN-95N z>v7AF8DAcUuU~cC;$I8LatVZIG7i*nV zDEmu=xI-0#s>uwQ;GinrqsHS`$1VJ}1lx)jV)0s&8&e-<&a6;Z-{9g7i7j%@hs4p< zB&9yA+Q5qkSJ!pywOI$Vf;h;EB-LR!{SaHg`j^KmQiradJG^3UV8x85xzs$qx6qfnvbwk6{DSnhBka(}K5JCu_NnEh%0K+LtNIxPLb0iIwgrKd_!HL4RinC`1ImASue{J-{#Pg; zxr$2$4NfVal^4S95a5_jC-?lKq5WNtv8Y#=U_{2iYmk}OMgOU>l zS#PQy$ z3_j^nKM}072T|qLN58IWlysY=%Eu`G<(F3CwXrG`kLS8J;#aN@6+k?`qM zx%L<9b|CLCq$dor_@WK^Z%_gQ*5Ogw6=Nz@ihV^(90F&`vfq@?r+O) zL@-4i3Z29_-3>OwD4U}!qY^@w(xFUap~XJQI)I4AK?3Lh;+yA$?{ARzOdO z%=2_X+d#LRWV$#36Z7NxN-nP!x|xeyQcU|?-bUeJ4yvGJxn0w zmlOZ57)+!LI)28WY-7NnPd|e=Pv~b6HcBrR`iObH5Olwd(*4{3JVBJ?{z0ZOSU|!*wnzH}EGY&8zTq^GWOP&R?RVC@S@{(pNC-GYq z-62y6mdC|Ny0Iu=9Q)I)N3A?c&dXLn?l%lDSts3R*UkHM9I8jD(_*S{8_rmtr1pryV_+@X~6 zcYW%y&cq;u5(*B6N4+_><@apqC8x{5>ASZY$3kTtTTtWmg4)I@9IU^26feKBfR z7tG5xQlc^!^A<3B^DNr}!j%l_0pttidt5hz1)njJNepw}wWXo{)sQZ@%?ml=$?$@;vk-lDDno zcf_LJ7Vmn3&@}?Hc$6boDB1QX_Au{9dXsI_U117R?n4{v!%{O}Rf?^o_K&GQ>kL_w zhxYXKIyL{0e8MlxnuJ%E@)JVo_9(7OvP*(!F;nRml{of0kOt1Zy!U z+QxPWutz|5E~1nq;sQ!s%?|w(`K39(=QqHdHBNjdszZo}6fS5$2S(EoZM-NaA zu^g#HdgPtXBR#Lb8~QH2OI@8uq|nb_InszTr>&HDHGE?~`au6U2N26h$m&CDTQ>G$ zrPTgO`8A)7W1RWMC`T_=1X~KW*lV_tEsLEvot-;6U&e038i7khpb2^T;$zLY^5jzi zpb62+WVDM5?@tLqlJ6KLag3ZgrJ2Zx3Ox0r)-1n8N%f)t<47TeETUUMez7vu2lqQ@ zN~9=69fE)7?O3iY_1eWbB>&FlFS)3bZzeakH8!{MQfEc39`0I2s-|MDP%)RU7~~Yw zVYvKD^<`b0qtrLbA-%F)=Xxo)n%Jb@hzm7Qj`A+DLTHp4PlzUHCsLxrF8TNx0i?^*uXVFA8iF>6{QB4?IKw8n4olTM+oHdNX8FG}P?F%9< z!X^`;F5ORS-;lNdAmKHqkE4!j$RbM9eXgYX6((l zW8Me!r}ZuNyM_1q&Pe+%KRV`Up(nAo|H?y5j=p8x=uO=W zI5;Y4_`0@dJoaxJYGTv%)Irg-<$3N%M_5KJq|^*4p?m2{)|s1!ff@&97^K4ta3}IkyidMj_gjPg4VBWTv@lF{HninbD4LB z$`Nof;1Di!+^%?0Ut!hZ`XL?Ri}(sPdNWrZ9WzTGg}@E}LEv6g;6l_DDKzSe_`NJ} z@keVQM2>Tq&hI5(h<)D3e?ja`xasR`dy|MSXfPqr3NazdVQY(7I$XbR8}Y6cdywJ# zs4G-RNYVLP>_8-6%<^PbdWsMLokQXfmD9@5!t9wY@yYqoM@kLYXE zo>C09fUba+fX0BfWv;iFOow!S55D>&(?rU@CyTdi*s^}hpSIukgR=&!Kjm!hua<>+CkJx#M7x}1@qC0cBMjx~)Uh3TGA-D{8^e3@< z_Sgoipg(E(EhrBQjN5y!@qx7QA&eaXgC337=ucS3O0!q-wh}F|&TM+8Rza zo{+Eo*xMo9@@s;#Y`G4K!V3dp&WNa{D90`jk-noyM~NEBB5nl4a8z_kj=X#g&d2Ep z=c78HG>=7{!Y%;{E@%tFJoD;|%y(}07uh7O^cGyA>wnUx=yYA@3c$lS{PK`AeVQkF~0ILTYcx)$~^)xDT>B zYK_nxw~X7!M7L^70ajC$Fhrl=?+ej~+66zgd**UKFa$fg1^q(}%MF;BD|z`L8pelX z?a8|^SZLiB8_?3$#)d78lEuGFa?jkbg;MI(Qd190vW0f`mMzlN>^w-N?3|~RSyFG4 zU=1tp@mK=ON-@Hg4;J&~#1Y>4ym!7}O}$e%-$^q(CTE!XvkVrhOXKr3OGC_~pqk?I zg{4Ey{uq7n`TSD7StAaOAF-4d+w?pQ8N;J6q zm#U9V(XYa_m=qm$rl=4eE$hLrG2XdC7duzKVP&VJ!lYW2(F5CCk29bZVB`#&bFO;%Tu&aQS!^FECG`WR{P%8@k~_j+KV)@_6j1tVZmlS=!v@VW3N^ z?x{8OVg_uZXnRLn2U%tCh-zGB!8!?7(hnHi#P*U$w|pc{B9$AXUG{qWPxfP9vxF6w zY)df0{9%dd=x%N(bh|S=*6UFo8xCr$qg6t{LOvi}2ry}io>is*&EzrkO8K_p9xh4< zTF3{b3qi;bND+!XYUn6*-wvn^I2~{#;5f_?Zc{#xVHwu2#LaFm(y?^C{Awas+$;IP zR9&L&a2zo7!2d*^zJgTapsKPGG;&2a1&)#kT*VQT=_VR_x7ZCmn->?tm*1-)+jX)$ zwA=j|LD#_{lx7sYpm|VikoK`IbYtKueVDFCH?7KWqx;Z_va|*$S%L0;REe=qb6AQtlR-Lzx~Z9YlNQ@-68p zXn?6GoQSwR!|kfQB^mL$#jTZ{u1mLY)1q9{Oad3^@=w=e-5s!$S9R@$#!V@!ySj=}AR5pvBD#ItB z*f+q#Qn*a0V}noU5LuczTMOPW_idG#C8_L}1#>Z%1X5!INGKO~V z;HU!><3~GpHahn$f7-b|+jSDZU2s((mT1qoOFM96d)xP%+_%s5nA>Fq)8rc3j!oHi z+U>}b*<(H-eN$m@L&N8Fh`4!sbEzuoSP~9pJ3EGPWJvw0j9%OiFtRz?Iv6+39x_}X zS$K0~-mQ_v9p`Qqc3!M7TwT9`-iHo2j2BDra1f?<{l?B`G^zu5iYmMwlyNi2a4RUU zqoVM7MaE4W+M=e;jyF3yqMEt__68h|YQV|u$c%1VVJ}`Npz1)W>gveC>m&1Sjx4^# zs`}sSxf+ylJ;-n~DDPH9;nj+a>lKEZKdT1^&0NNv!Fk>OdA%FOTzhn z?sn(JdsS%A6ne2cs_<%%;d)TsO-j{pU9<`+Dk*ez5mpA$U}_f{n>sr-bar4#)!cB3 zo>JVfQzy5fI<6rti0f*`XyI`{uJl(jXg!$ zWGLL`#+LGKchTsaES%fmc1Ks^sm_j!`0K?(465smr^H5hNLT4a<7R1uA^v(1w{hMA z*2k(FXmK+-`dDw&p*Q=yBJA)`vrG8IS)3{<88ZXN46?ntXAqzjaRqCIE^4`MMWB?u zZniWdb9r~;l3v-72xu|~y>d0)q=8wy6rV0E9b`TezmUhPVlDB4`Fp710s7wCQ|g4W z8e~by>?{4sZPjvJzF5+sXeI0i7~F4fu|bL2(iu?xlS&h? zD2`9nSRdT33XeWcERVrWrmvd?iYa`2DsT0--Q_J$h(f&Ds;(x9($J+?G7zi2nsAbi zK6Ri+R-xq>AbYXz7#uYkOQ9f`=7mDgB4Mc)*2S$h%RcE41^<%1p*bklcB$9$cj+q% zK9jx%X~mnAJ;}kKPuDj%T$9N=e=d+y5J-bJ1R|aJ4}}G`I8qHFJmt+}8Gn@$~f% zW-$74HnzgY=+7^7o>2%GG}MqVVgoSD$OU-%Et>}UVXZ0(Nks-8tf_M~i?PF% zOXU|Wj*iBhr+15S=~@#FH*PvM#wSG;lAsJeC{G9~))WoxJjUFnlec9n4_!EkQ#i^K zDvC9$4EjaV8m^EG&fo{<34@C@i`rIrM7ksP#fC55{9^qVZ+-Cv-4p^BCd`1_jP<;N{~dIeGy5l;Wu zmleJ`kNf^)5OQ+lCEXLX@wl2w{|+P$f9Kcii6cI#>*>cw*x&c5$CM}TXEm&%A7Ei0 zw&TdB@3PwHH7rtkQCLu=UVtZ#T#KyaMtw+kF$o#{?GGFNjPEH>yx-O*I{WxlHNQqb zdc^RqKS{3myV0I0&ke19eyGtk)$M_JptyT)Gp+4(ji#xGhgN@s)RAtd>uJfQzw7#& zuy>u6wu>bn_*lSmxUicN=klp_K*}ayS!GBTGDX>uj?{z<2 z_2p>oMK|*FJ=6TRcRe8(@_zq0&3N&pmNEbG>TaWX*1R_PUkhIUv4iF*{eCik(pK~h z&BOdB_`}q&ec4fq7)bo-k;oKB#~nN#zx#`HsqG|_bqPlk7a|M6$*}O z{@ui8HttDpS6rfsek%%pL$g(r5*1=0FZ9m=l3sNvQ_hXooP95jl5^ubc*SG-`+xrg z?>;n9wC$P_wwdi(>7vYMwO3FLyj)lAIRjO5Z@D-dJ1@$DZT52N5%sSR%2B|lmkLC& zz;q!ET?Dzz7*RcQgwYkmDJ!<1#E{4ye23Sm1g$^-9UNj7`%=W!@b&4 zE_zZSgM3%zHTpZg-8J@-7=lxh**e};de#;wBITJbU!fc-^%ma%*VW(hV8d0Z_zeW7h90V1))+x6td+Eh&#Y5N;a2lQl( z^%gT7Zr9ZdE8XQUpwgP#5!zLTUVEY2)+1Qr`NCdXt9DgkZ=+N+c%|EQK*>kBZM{m5 zU+5yUSM{pe^;x&1a+P)43ws-+21!Z)nzIbXbY6d9WhbRg%ltzr9`Id_~@(iY@f4TBK){TyUa!kbrXL~bt0}t_S2Dqs~;x)G1^j31J#pR*C++?GHkPvHq?idX5iv?$$XdU0!EBy$}wV# zJWkqeI9d`!=-akGXpSLkuPglmTC--k5A?cg)|G1Q z?}f|EsTbhTag1TwO>0U5w-d3gO5br-b!WGOlwb8JzovK9NpnkY!Ljqj=)TJD*-h>? zwpsZ0PiD`i%|Z=_4ctdQYjKKzc@ebMV@XWDMe)bF>S2|pWqremMZ z!uy22USsj|v3>L%39m^AwGJ9HufQ2miYR@k=JCOvDHS0NWXfty6S=>VDW2#Cf^ThZ z6}IDYTd=*h$<=Y;OTX~r{N9cWJFk=Qqep*I?ZvxfooBIwta8rBWeBDKBkd_(<7}kC zfxCfQ1;lhmapn7a{T}}ZIxlTlgRj|a!mBPrj)^A_6%XUZ?t?>)q1#<=(l=ll$&h1t zH0e$8Cel}Scb-$73b<29Gra7<%j+isx_5)pMOyUYMwb3_faepRvus3wX#mSw#<7DU05_8r^+Ai?^Og>r1KTag$k1fBUx6PbgSpQ zF{|q7t-|^a95j5VZ#u6(vz~!{_KRB}Io8l#x^fH_(|IhFM2i3?X!*2>31s=0(zvp2 z?^EUxOQXu%(|>LDTROI^Yi2QCK?*AGxxRGxHZnmF{7e1uJ~37^;?1Zg>ALi+^wI?X z6}~XwY}*1a5j&ROkzFGPSQ@rMG)jQJlsbNWBPlV-$Ee=}}_IlWhVft~U z<1UQ5G_FbW34ctR%nb_<4v!2U8$L07LiptHN#T9?0?idZR=bS*BK))Pl(CKBUx%N? zQ%(2{{0a?>f>f?nF~u* zV#(0R&)+x`p_O72yzu>&+LXH$=i8>M+ZNtEL;iif>?ZkkIJB1 zeM*|co-}xROl8nh+%ahqd(z-(yqsw)zK4Mv!N?0RjLz1EwasfC^vE_&8iDMqk8QMd zb5`!HwGNs@6GqwYI*L?n?~soDp?F1iD!)rZ!dpLb3Exkz!~coq8P9xG`Syd7 z=dFU!)s1Uw@amCxdJXQb?(mO{_I&zesGbUE9DAhD$O${?orSWNaJdZdS*Bf9t4@{W`0O@=|@vqq_6g6QtTZ z(uitb4yDMIoiyF6dKkkk3$4|hAU=IrmW5X9&?IjcO{T=uC}#^@*$J>NwCyDohCx;j zz9bWgjgr59hYubJe?3OFleUB&rSYyYXPNVZkJzxQAg-#O`{UnSkmGot*tLpOL-S*! z?Mt7Io7f6`Q+4R5OF18M;yxQy@sZ+-9cA^oxsspj`3n$1d9A+jLgNL?;8(6m-nfaN z#;rbzu(mt*IFS1Vq5Ob}7Qlh?l_Kx*t9tJ%)^^FS@d{jJSH=Y(8n2jdP_t8hptmi~ z^Os{}ixWLD(LuKQbaX{%x2l@Xh`!$u+l5-a>&-3rMh|?>ooCo$Lyqk484&sIyd2>o zOcBE({2~?rF2H}8fGuCEMC%S2qP|pYbkJKo({ecsdKgER?1iV$N5qP54Awe$)7bB#I zJNWPR;MgG)hLDFzBFQ4ZBt_(Pawp>Ch@*jvhUE;u&T`#}nCNdG`J~^ShzxZ+PxDhZ z!bv?1y3!l+BepcRb8UD}Z1gzOxR`M>$1NQ9n{m6wknkU)?JM7ic>66n%Rg~PC}RoM z^wS91acvg}ZGq^PNAYK$M#xdN80yPY!_HiM+IFzrT{t#!aoW&N`%wMmZ5PJa?y9Vh zV+hd-WNE8TuCeONukm-wFF&~>1_G}Sk#$l>$Nn+a8~=5%Rb==|-s`4_Q%;a6w4?hx2fzD` z`jKy>t9@G-?wNg0o|$Bp!$amEJdS{W^5FMRpX!Qh7q%mX*h=rMBk)SJyf;w!V~M-c zzQpr^+0PnHml7KGO0-J~vG~5`L!YBtG(+)f^m)mLzL4G*Yx@kiv-G`bqP#b~oe#g< zaHXH#tBqBv@O=&E@n3_`+t5I13w+IX5~1D1S=5!M+9VZTwXSTrNpDI$v`O`Sc9c>%j2)jVU0W)ttZlCR+2VJ8c$n?_wkz>`&(o=TO_mCUgSd? zt|w@O?Ka=BA1WK{$rZUIU1iH<)ZB6fj6uk#d(Dy#Q0ai2J3lb{;IkR~c*_V>E8)(^ zYhH?w1DTK`=)37s;h$Tj_hV{7lILz1?#r45gy zRpw6a*ltwVEo1CUdOp}-_P0i&B4Fqn?=Ey7dmK=IFs;As4-|h2@4=&Qn}>%IN~W^I z(31qQwp?dy)JRWK*n-|cTFYHqMvq@*%S(9dwJqssXOAcIdRe!eVZV22N1tk=8%m{b z_LFIRskg|B3NiwMJXCqwAQz#TJ8F50hE>Me3Mm@%LOKju-oo|lFXqJ*4|5rOp!Ldx zZ~t0R%u8dJMpCyV8Yn~$2$cr=zHtsM9X<`NNrCFf<_cj5S?C)~oX5^S)TeNbQwy*(BAv zDlQk_Jc8&*rC3aCOSoR0frHE-{i~Hf{DeVYQH*EA>E|Dit6`Mj#;Ztch z45}~y)7&Cm#`u&j(aCv^edM4-Q|T0o_2q8PJa}KBhJEwWs}}p+_*CH|b)o>3OSiqv zL)hmtaq6e3DAcXRF28gdV@m$|VR?z3SZL`;@eyoF)!`e6xLoW--+jjCLv(dCBl{R4 z6$mc$7HU+dBSrf4CZE+O_80rGFG5CEXcysqFL6+-Mm3km=O?S1=oQ%imw(EZ+lO?+ z7TZnuICTuZiA|x7jAT$xuq}%?PeK{=!MCVsd^o-vP2ni=5Q8E3HZ?vrjg0tE9)-k; zFcd_82N($WhK%Pb6#PcOVBp`yOT)DO9~qtTq?JKme0Q7DkHL4sDV%_R&xOKh`n72z za&wPjl~2gG#KhqD_$oiEFQ!11>!sC zl+Gvug9R8!vX%He27^hV0wFJ!?_~x9iABLzDfn#)9=j{Z7fiYp{3ynEAPG@mEQ6z{ zT#zr27?k+q42F{|1|vwW5?{pNaI&Alp`@O{QRFCtf#f8E!Q`xhpU%s46BTG+a1?o* z!C-tho~DP8r3(Hv1z)DXRSJAtf$uXINxa(tdqRfhh`n9FWq*cwlt# zW(cDj2uSIMD|ovCj{s6SE(BWc79g#c?juw9umb6U3QbP|r1}2@7=!pG1%CjL(*H(@ zw*u0CCEzL`&DX8qp%PfWS%ByZV&sW&4k_fGz&x2l2JuH2{Fr~9;kTiG_d|J#p8!b9{SuJ2;{`yPZc zPzewq%|A?mp@6g;{!JE!pRdG!EfAxT)X}f}1Ma~$`^macG!h3P7*8>D{sG40JM0wC zlo^Bng#M!OZFZpBEy~{>OY~;{@OIGQNy|TY&cS%UEHJgbUtVK1mb4! zRWbtO>1F(j1rIVv$ZQ5fi4o&11^I_ShP2#Mfa!qa0gZsK0h$2A0O{B_GyW%m1KPex zioL_XJ%akzkzrf}imf9zxY;aj;9)-y597@Y;-zM$2PdItH(%MnMv_}c(!dzJx?LO%v_!DR5y%0p+c^5|!lkB*xc;kvCxiDh01C(XH~Lff+|bFxD13hCGzJe3 z&0+AHp?M6R9QN#Rn$DAt7<_p6-x%~B-p1f7!y-q}^w)+x#Ndn(j|I~B%n?Zp&I?Q% zN#pYZ-(&EZz-|Vg4ZO=>BB=|a=?{~W4D#e!FpX~xUOk$^bHQsFoHKeIgPEh(GdObe z9~pdL^hO5Fqu*w*bo9FnjvDnIgCV0nU@&~thYYHMK4S2xppO}}27Sul%AidQ9uC^f z;E|xu89Wj6cLu9Qw=g(0EHRYwl@vCM!6(8}7|abbFt|8u4uea=9%u0Nuyh7r49j3p zKhDTt>9}kLFN`xWcxhZ7gTum~WH31VmkdURKh5CS@FfgR41bQn3E|H(I63?U1}BBT z#NZdWn{~d!(ngRwt;pa1WOuLZ5WUf$2e_2U4E9n*`y_mrQ%`yhB@UJo$t6k3E zGOmQd#L&rMR366AuNW){J>nB2GpB55U|w35HTm2g7jAE{0=r_Anfg^D@Jma`svAuUg>)7Cgw%pL5uX{|m!AbKYRM zCa2qiN38g_t?)4m9%uNEkx%B3JoyLiyo8iqPjxhAujxj8dk2CybPR10A$mlj2nfZdS?| zKBX*TxI?L6_>tmcm{2fp0i8n)GIXh7hNI~@4E$*FFa;>YeGIRowJyR=;b#adxmLK5 z;aEZQ{i%3v;2aMid~q?%fjdkJ=Zk9QKS$IuoGX?xoGvY6_^`Bs;cumz8U9|v{2uB0 zrCS-=LWmAgB(fE^a+C4{ zWxeu%@*4hT+g$=VVwO`xBtu>e1K2xI9}AI3^7^~@IWV-MGOuR_enDG-{LJgG46ts5 z4=y3Jf%GK35KrR!f=sI|Ax`l(%|OplFy*SV!wF}wq8O|8@BZwsf>>VaMG@^}gM&i< z;?v??D`h|jf?fU*jt&iih+HlD{9!M-vLtkWDjLpr{J}axe`TV{p<=mzfJdK+bukaP zJS+*8LoTAfa7oNXPUkr$=s+5{4TSeoF6ADi5rSPOhJ(cc_85xCI=LSlh#)77W&~z0 z$q15vz_XwR{0>gAgz)6^6YhoFy;7IZhO1Bmy^9GDaRg^}_ed1*yNP5%5EVKMsy0~e zD-Sy;6Z4|9bV*QKaoP~q1Bg&&2c|;Sm83(pN+BvBoJWDXgC@P^m86gaRg(OmNe1__ zM3$bUVquAZt`L<3jDq;DbI`omye?riSzJe@IiTCdlWCo-yk?3iNcN_3<0rwTN4zFuC zSGhDg73b}r6LRkf*yrqhYu$SZY5Gpsih^AW*w% zXG0b{fFfI~WJqMG+ytL3k6=NMJ3Y!ablzlC)^pu5%nY-8Cw6B8#V?F3WNm!0Apxst z|0c3KP1_Uo`B}~2*_<^4wyI&-A$ozn&Tcme^UvcK$XEEJJ*CYSv7*l{u%VJ|F*s9SnI_rW$qL~ra{1_Pzb zwq#Yq_VbGD`UBaWFwU`Uz&hE+2OuhJQ}nmagY7F=b~u-rjm=iFnU!5H7wm*_dh+5D z@v<+MBB%hSqY~19iq0ZKBBg3mhtVu3w*Fh>IIDgV+t?@o)tb!5l3uiu&VHzw{?YbT zqUTdoC%O7Dz9ZO22J`U>BtQis&L}l4$I~+)at#oO!FSK7=60hHrm=D#OBcD1Wxzex zXqYmHzE3&9ddq&w;4HcGdVSxz6XMgf4sz%Mb4OD?O~9cG*{WzRRkPw~40b%T7Y3;_ zVaqG-(u4xN!zeT~_lw+S*k>loC@!5VqkewD&idVa^OvquyVV z;OZyg$`FPQ3l`F>_NCJgu6fyxx~D4FG|nG2KFi3HjJuJ~YKa-fU87MG)DKo?E(utS z6=Rbyekj%1m7P8B*gN0nHpB~V^Wlyxo|!HRQ01$ypY=*{00^@szc3pb-}WV(>1feJ z{p4zC8iCcK?!;-cJ9OqY&Yvhgh+KfOtmo1D?5GBN zb2p6c^_*$4=RP(XcRXzFk&Wp&_xWX*sIBTz;;Tg3N0Ib`Y859`y)Zx>{V4uU&-=?s zBBUQiwU%zW%%T>e8>%z+5e)riKkf8XR@UOmGjHOkQr6=)ZiPjdwhM_KkMU!?&)#-E z(NkdjL98AgM_aUdx>mOJC3>dO4MM{z4Szq8X!zTOU+~)1q^Ue6-X;jixAp#H%3ZkU z(QZuu``cFHyd8W4yolrUP61==ePow%iRI{1aQ zbDFa34!AvMh?>V0j7(45!Nxy`UOK(Y+!ycg=F!0 zfT2duZBF+%rx)T+9L~cejqv2Bm-45bHj^*(-N3uV0}M08e=r;;{*&QY(t{&j7Of0* z@f^cE(avy~*vBw)U|;E=L~;x9S1bN+40Z87@RaWb3t}z`x^(gs4XBF@hE6etp^N-K z1Mh-P+2nUUhtp}@1AHF#H_ZB2%TN_}%Z|;&{}jjLxvx+<8T%OoRZ*;%{ID8fzAG6z z#cvg}T^_dZPl2BJyr4M5M8LN!{M#0Nj}`7`I7~?7Y#8es?1M00%yJoywD4mY>SB@= z&avSA7JP@HOT1^n$u^VUOoqe694kE6X3FVCKS{?h;NkYng!xX#b4qud$$8BKd^1pR0>oE&MtQK4Hbfuo<`KXi-F&4S6+K*tO~*TPnd0Orhthci3_jK;;;| z=~^XEustq8Zw#)d`NsbOsmg6_h##r?ln!w~u9B+dCvEr3zW^Ow*b@Fs8EyVvgv-%xu4vt%9t#XX3l;vU4nwy*;J>XQ<9CFEF9<)N@8fvq&? z@%RWaAVOU+he?E6rGOIjU`2eC*D#}`fW5M~)Z+^m6UwakfNf#WU&BezZny%Dit^I3 zaA~j@Yvuvb^^)S?;v|ml)d9k!L=K=1iGb5eZHeVfC3Rb}k-i=2btbh0G?$lwVT?@M@T7ca!}crjD-gBD9> zozWh@mn)Hw4@ki@xZw4;!`0;_9zWNmMeJbWkk4Nus78}4DvCqlN`Hxm>-7z=m?Z`E zu%|X$91aKZ1fdl?XJ)S{_mxzZ`!L$lYX7L{lY=I%xR&>!2#58tqc{{QFZH2E4!LAs z1u6}zW9MQ|T>u(~kf-F5CA%pZE&WLy0J2LK?3ohf^Oh81F-i7ImgHk7Nl&QW$*EUA*rCbxxH)QYboxdOH4^P5D0 z%ZN;bj=g1F?8E16eC9#n62#|k_>4q&0zSXN?``KkZLwW=%SIKCl6M$C7&rCGFW$T34<86T??MPegQ^I*Tsy{upP+22CC6Q&V{(Y^Yv48Aca;pSc zNaOP>46u7JgkkB+7_2)|eL_WSdo)c*@R`&Ie?o8@-AQ50Rl71HFml$F+4Duq3S+F& z;xlCpjjaEQpOxBpEz{F{r&|>qkj0A!f1;%WZ!6aqBkqNs9 zX5_vYMO~@xZxNAwiX>a4%qO% zSK!w@V)2O&dj6~6SY$Jd#v|45jXQ+<#3w!XH=<*RNQ@ZtI1L|ELeg-j+YQ6TWU`n% z6fAd=eiQZ1&b(pjep;n|@=6kx(?-+KSg_Cxlel;X_90;$h06pa;4j#Fmqm*c`Y&|D zdQpq}`x+GLTF5@D&>8usR!0oYoKIy98viUU?eC!Och^Mf!#!8Dx{M`K&nQAghWGF5 zaWGmjU={gVVW$`J`u9)=y=!d$fh9q7^+9(>rnI!KvsKAYygy88l>uy07L88b@yvk8 zhAqZk2o8ZJL7*8V41~I|)RLgk_>nL+Cpg0y#`gr++g(PdSX$RJ9$tM|q)`xQ1ay|h z+5{XxEf7Rp3R6i(PCRbR6lPunPDjdb@%cCn+oE(% zPNH*Ez}x5?44{VRn|b~gGYW*EZ|AUz?G*~k;sXvV;$w!g_?)3mJ8IzP6n$85Q92pt z;sAsWNPMx*V|axHasC%!Rp8tz=rmEuVOgwYsE}O=;C1m!hE5Syd>U=YFg^4SfDVzvP!l&=aJ~hX zSg_iH%dw=!7LK@C5S*rr$37}%5z0)43)I;RU8+YRz8dK3_gsygkLxCSJ85 z&cTAtCf>8)=N9}4^O49i6!^&kdIjctJ42^f%TN~$7K~f)-x#LB8KO!5zZU*khEDNk z3!b;|7>&VK7g-jZ#ZVDHW2lMsw$$}^)$n(QM_p0ZpIxuI($dq?Z^ZKk$x+@Sn#vD( zH2@pHTU#@+ygK5jPJ3Q^gF2A-XUDU{VDQSi8s#mr6YILSuwYZt{u}slw&BCymV~oP zUYC}QX;_E&tGvYdCuv&RXShi|1ZF!g?h>+hSdsK?X_l%>cL2Luf5tHlIoRa8dFA?B z;OdkTKX$f1bA9dlTl2b$gS2%!u->(M1I5AeFr(;>L@Au!;;P#6it=KUFdev)SRHzo zdV+pRSwvKXp!F3Y8cl@5OWSl_Yf;JTGgOJU(p}-l>WT3rqZBUtN;j0;XD`x&4))aIjo{1*$);fAKTK zP$CDagO-LjBJPk_VyB%)kVaBS{R5-{CcPDL)8!=^*f75;%>Ni8O1D>yh)0dYXr#Sb~?M=(^b zJH_1`{1$>G# zayU3fMX*e#hZn_CLr}kfnq#3#HP$E=sbN(UP3lJ~MlPx%t*qErQb7)WR;q7snjmyo zB_7DLmJwk!2>pUPRKC;$DVmZ*_5jXI6o);?`vtWH+@YhzAD_JB#*=UclZ4oexRq*9 zuL^mBCB@-leWLhCeJ>>e^=oQvc;Dm%hY3N8B*-Y;EDUv-C$8@-B^n-Yl zw8YMf?<((&DWu8%E?ND38sc8DNJ;U7AjV2*ne8^4CZ5oKiWgcbhm;!miS3dai7^6x z*X=llVAaUONurb*d75!CTTlaCz#l@t+RdojOq9o0g1*(wsHZKea1j0LjI9S^=}>-9 zNp{K(%W)G_2a&(tWu%f;+9tduqao|q~;?Erl^KCdox;QH0sbq~c!?{EG5mzNGf$}r# zA(lTySVrewZ{KLw#C!Hb_I7&Im6GB*+%xUT zuv+G?3Zj=CV#LGtpn}H?`o?=n0wv^eqhpwALom?sxa31iK+)S^RF04nNIb?u<$m8K zibJ!vf|dgUG{?mqR9z5_si<3DqKLeN3X*y0_83A1DU0t8G#4>MSxwT*^^hr~oHudhDlfXM z92O~wq2)SFu1s3;O{B!t;f2oGOS6h0^ppye6}b7h{b z7_BuqxF1=x%f5+LeheqzLN&z!a1Hx|A;-;^Q4=DhF7|i=j$1E_w6wWjrG->aEd;y$ zG78zON16*#ou|>DQd zV%Ldo^{IHNn5HFpA_p&c(Mw)eiz2`xy!==OScaEysM7_IntI92_)w$VE`BShI;j#G z@%a^h9K3MDG6^A)!u-*z!vfu;@LSex13n3rTc`f);D;?Dq;ip^h1}lD?75{t4 zOYz^g;_2y3Vd_`}7h80zEQlWS|8%KeLv617E-LJM*Zw}kj-HsJu-ECSMrR|bE^z7e z6iW@${hS)cXudc#jP%~rFb%4yVGMPH_|bSaC>~==YB+F7Jl&zG@pRXwhUpGX4b%OY z8V+Fwlp4mJ<4XYPTjmK(=1fH7WlTl%rc?9q?TScgVXMTwCwo)sV4u`9Ai18}~V5cj>We zt#x|WB+E@=>kLXoDUc2+kZvcXi|tNH7+WRP!Fh>9MD2aA_oS678FA$Ds4UZ8Tbpo`w=ej6 z?ZMH@$Jm$M{U{|%1sWYb-QcyXO(HUKTnZAayyX2iKA}z2z{QzH-sLWG=p%O_788>U zJmS@Qn*`zkE}X~u56P$8umPWP*cI~s4({1-Ja0FOH4ffhtKmWp72fKD2&f}tBKt98 z|BjH5X|h}WTt9}&ZvN^gtlygjUvK$v)FkzN{^Z$1v7P>SuMeK(wq$b|=)f6x^}*o( zQ;ydS+Y9!s^wajbF=d3HpHs34IG;*`K_-F}vw%^EIdnW(I>_$q+kWi}c5pfVo9!Sw zt{mKseWS0)g?!cIoZ0_0=lUCNoLf*hZ~lTPiuVYPu(ji8 z8df0(W9Tn42l~r~TpZ;Ce%*)te9G;S8SwP;IsCz)FdG~0g=fFiR)E957v;pZ!UiB4 zwou!&4BwKOy>W+}*l^buO)JiNH#VHu&~UEFd%jJYhW2VWyrH45$qSQB6so>=}Fonnp&O|2g8EKr4wrwdm6a9h?NO#Zy=|AIubWdA+FUY3vE!%=RHG8(1 z(aZTCDF@I&OScz%wq_)G+#3dGcNuVY=bACG$LaHt*FCkkb?(-J&my+Q!ex=EGm2sd z!LvH66`KGWxyoBnKMEeXv3IcqTcG*vpFinGeBJZ|W*@%G>5cc-(CO`wNIv|cFFhEq zTX#?Yvg@L%-`_JHKd-wkI;QcSua?0@(I-mdJ&Cyy&EGh0S(MzQ9HwxTPJ74qerNh# zKNZAua*KjwY>OStKN~-S{h$$zYZJ>N4t&pzD2tjj-S1KGJH{<3oH%zwqtbiza8RPmeMZf+jfNjJv9 z9;$U`(TxQoD6ySeEO&~0T)0`oQTRk(emm_9I~OG#F@8d~-1-kEavQTt+HHl|aHpLO z?}J70gC||vQtIZ!=PmQLWTzaHr_=Bwkt)6q2jzA1pnT5OzAo~)IAeM= zxOilm#h+$PCgs4lS`i4(#32U^j9E4Ka@9OYaUA4dw4=;E$Q$=f+yO&o@J3GO90nM0 fyEtgxipwROd7~lBD6753B24>Rn1(XlWbuCifFik# literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TURBO3/BCD.PAS b/Borland Turbo Pascal v55/TURBO3/BCD.PAS new file mode 100644 index 0000000..cb7795b --- /dev/null +++ b/Borland Turbo Pascal v55/TURBO3/BCD.PAS @@ -0,0 +1,158 @@ + +{ Turbo BCD } +{ Copyright (c) 1985, 1989 by Borland International, Inc. } + +unit BCD; + +{ The BCD version of Turbo Pascal 3.0 (TURBOBCD.COM) supports + 10-byte binary coded decimal reals with 18 significant digits + and a range of 1E-63 to 1E+63. The BCD real data type is not + supported by Turbo Pascal 5.5, and this unit provides a routine + for converting 3.0 BCD reals to 6-byte reals (software reals) + or 10-byte 8087 extended reals. + + Before you convert a Turbo Pascal 3.0 BCD program to run under + 5.5, you need to select a 5.5 real data type for your floating + point values. If you do not have an 8087, or if your program is + to run on machines without an 8087, your only option is to use + the familiar 6-byte Real, which provides 11-12 significant digits + with a range of 2.9E-39 to 1.7E+38. This type is also supported by + the standard version of Turbo Pascal 3.0. If you are planning to + use the 8087, we suggest you select the 10-byte Extended type, + which provides 19-20 significant digits with a range of 1.9E-4951 + to 1.1E+4932. Once you have selected a data type, you need to write + a conversion program that translates your old data files using the + conversion routine provided here. + + The Decimal type defined by this unit corresponds to the 3.0 BCD + Real, and the DecToFloat routine converts a Decimal variable to a + 6-byte Real or to a 10-byte Extended. + + The BCD unit uses conditional compilation constructs to define a + type Float which is equivalent to either Real or Extended, + depending on the kind of numeric processing you select (software + or hardware). To compile a program that uses the BCD unit, first + select software or hardware floating point, using the Options/ + Compiler/Numeric processing menu, and then do a Compile/Build, + which automatically recompiles BCD.PAS. + + The following program shows how to convert a 3.0 data file that + contains records with BCD fields. The program defines an equivalent + of the 3.0 record (OldDataRec) using the Decimal type for fields + that contain BCD reals. In the corresponding 5.5 record (NewDataRec), + floating point fields are declared using the Float type, which is + either Real or Extended depending on the floating point model + selected. During the conversion, all Decimal fields are converted + to Float using the DecToFloat function, whereas all non-real fields + are copied directly. + + program ConvertBCD; + uses BCD; + type + OldDataRec = record + Name: string[15]; + InPrice,OutPrice: Decimal; + InStock,MinStock: Integer; + end; + NewDataRec = record + Name: string[15]; + InPrice,OutPrice: Float; + InStock,MinStock: Integer; + end; + var + OldFile: file of OldDataRec; + NewFile: file of NewDataRec; + Old: OldDataRec; + New: NewDataRec; + begin + Assign(OldFile,'OLDFILE.DTA'); Reset(F); + Assign(NewFile,'NEWFILE.DTA'); Rewrite(F); + while not Eof(OldFile) do + begin + Read(OldFile,Old); + New.Name := Old.Name; + New.InPrice := DecToFloat(Old.InPrice); + New.OutPrice := DecToFloat(Old.OutPrice); + New.InStock := Old.InStock; + New.MinStock := Old.MinStock; + Write(NewFile,New); + end; + Close(OldFile); + Close(NewFile); + end. + + The range of a BCD real is larger than that of a 6-byte software + real. Therefore, when converting to 6-byte reals, BCD values larger + than 1E+38 are converted to 1E+38, and BCD values less than 2.9E-39 + are converted to zero. +} + +interface + +type + Decimal = array[0..9] of Byte; +{$IFOPT N-} + Float = Real; +{$ELSE} + Float = Extended; +{$ENDIF} + +function DecToFloat(var D: Decimal): Float; + +implementation + +function DecToFloat(var D: Decimal): Float; +var + E,L,P: Integer; + V: Float; + +function Power10(E: Integer): Float; +var + I: Integer; + P: Float; +begin + I:=0; P:=1.0; + repeat + if Odd(E) then + case I of + 0: P:=P*1E1; + 1: P:=P*1E2; + 2: P:=P*1E4; + 3: P:=P*1E8; + 4: P:=P*1E16; + 5: P:=P*1E32; + end; + E:=E shr 1; Inc(I); + until E=0; + Power10:=P; +end; + +begin +{$IFOPT N-} + if D[0] and $7F>38+$3F then V:=10E37 else +{$ENDIF} + begin + V:=0.0; L:=1; + while (L<=9) and (D[L]=0) do Inc(L); + if L<=9 then + begin + for P:=9 downto L do + begin + V:=V*100.0+((D[P] shr 4)*10+D[P] and $0F); + end; + E:=D[0] and $7F-($3F+(10-L)*2); + if E>=0 then V:=V*Power10(E) else + begin + if E<-32 then + begin + V:=V/1E32; E:=E+32; + end; + V:=V/Power10(-E); + end; + end; + end; + if D[0] and $80=0 then DecToFloat:=V else DecToFloat:=-V; +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/TURBO3/GRAPH3.TPU b/Borland Turbo Pascal v55/TURBO3/GRAPH3.TPU new file mode 100644 index 0000000000000000000000000000000000000000..40fe0219d6f34ea129dde247f6974297366f17ad GIT binary patch literal 7232 zcmeHMdsq}#mcRAr>Z+y(L43s*3{g~CoJ@lRK?%t17PO^FcPWY$9Cz4!*&Qd7(Z+=t zG`M63x+`iP^Nl8B@+Gr*?BZnBB+N?UBtaV`W|E1ZiKsCe&EvLhRuiFHrRmyps~e+& z+5Kbx-14igy7&C<@1Aq+x#wI;xnfx^f@?o2Lfef6Vu}9GC2oL!zfVCZjS4|_yK7Ti zaM|#tfKWfQ4l+a7$;P{xAMgl0X!xrkz-}=hG+9^-sMyuTf59Pibf^i>dktUetwciu zi_p0^at@3ex{8bl-Dmujv4r0PV}tyY!URCB6c)LPD@wBw`sL$C(U)M$O2NI-E!&nN zv?dVaT*;NVWQ5*(Ha2C2q1@?`OTR>)#;GfKTd`ZF?JB*e!r*o;ivikV9ekxN21o=0 z$1!e6pLD4c+a$0tehJjx_~lO25hYHC)1|}2Aqlz(W+*Ll+1!$OWT{D)>LgOqFbIPV zg39bl#%-)9cGzUuCXKlr2qE_D|VGg zvxnioe=eb<%vA#O+%;_6$n!KZZefv4t|%*!a)u2tpudCV623F$yEkx#P_axOmp5!2 zck8$c7M8~*W2YR8jQKYW(OGZs;A^bgWG{0#+$AoXtz0U)2}~RDF!FM4Nyn8ISJ)&x z3^uaGpm_ovRZ$G#=PH*WM>l-od00H(E28$d^?}4~-xNa+BL859#k2 z28kQ_iou-#I3S9}PTlQ*bYUsb=`NGYoaIu(Fd%zFkTvo!eW|lD?wiJ8V1%Y}ZV|-g z4x3$;9vKFR>j%?H6y+*gR4Pj?-vdjC&4q1_;+4{)w*&rMaGPVmcrJTv7;@ymevx;_ zX8@+8AWCgD)S&95kNx}=>$Z9NuZu>@xFE2;3g5ri6C2>l2o znQ+rYav1LO@n;KEps%3-u7dkN;QgeCP%_*{pj7UJviYnDp>LtTjYsHCxW~Z#G+;R> zmVba}Kgee#AT$x)e+f?k?j*Q-q5V9Jn+4BYXdi^<+i=_AeIoQvgr^JcQ!qXN_wQ5E z5Y_W~{iQ_~=9>B7wIq{XJ+kLi6uaXEe5l8{a52~szgErJCX7PxlZ=Q#HxMmTFHC*( z-L1XtsC{b(L8yB3!5O2pbMNpdD86GrLGB#^9i)c?vQOK-w+L!T|MlezI zDrT?4{;4Y#>eRjSDj|UiwNO|-f z6Usj6*v02eQQ&E2LW-+bf)M1p1(yusK3-Q zeNl9O?b+btBq2(?lFm7oj77nh$+baJCy{{ZAfAf|hXQ+|Km-)l4qwgO^qR3f9i~p8 zxYB}iR7KPU(1pjAJaVcw)Pk+5Vz$zD&%2MD@^DLneJwcK=NJvxBS96Lj}VK$)QfZL zB_Fn?<7|C|sLCetYx5RmaitH>&BtRmV4uV43xqz(@ELq(()S%p->T_g|hz!p0;T&I$HN7)*G$U<#hB!2K9P~#nx9ZaD@1&~>M9!G<7-8$r)sx zL{3ZOry{Hjk4RgDSVh&&lams0iUDVo{2@ZppvTP7T`*t8i4ZPcT&PxyoC5YIT9yl% zXMAJLg!l@R*`{rHJef@iO^Ez760YWh99b11$BjVT=$OEeKFO=FURfX)jDZV-Gr~t0zcHqi2<_0*mQs;FPTWQsp)IB3tJJ=%7waLXb!8o+@#q};K_&A6v(Cq zqAJ#=b4H=F;f@U7EYJyT&rz$*WUEO%vY2&@fhE@*IdvTiGaX}^j-kfSjE4`b|GGdH z8%Tj{e)!)qeA9d02c>9CaK6rCcjB=S#SjS7gIy%a82Bto$_7Xm-Ihac6blrw;a3HU z`Qcis!b4PlmFumA?7QOxdCBBEd`sTTryk!?7~ zE6t$9>P$b7Zx=ih^XsvBhKtzpYWQP z*$p->qT@SDs4b~O1mh?{a(c};)BS=eRNEc;*zKwezGn(~_JuxP;x5rV^MiYQ@993$ zYH~>CwdGUEO9m1aNw3(s$(+#z6@aD|he%kd*>2+OLaFL7lYY@sZYuVc3-w%JGay9O zVIpV5X1mDQc|atRBY+SA!AE>}%#K}8KswwNKKq&&`nK@`)4yYMrx)_0o!_;*S}W)4 z3YWv8sLMsoE+(c{lAR(f_ajOQEhN2acy+B=Ef=~2>zNlWzZm=*Y^BD47&`t+`H_y+ zCAC+Ae@U$-cNrk|&4|o21irdP)?6j0d2$cfAZDodu^H-8-s{LoIO#bJdK6&u!^b#( zX#o}+J_PMD@(s0JJHqE~R1RBb*~KQiDERC`sAkMGW2l!GTX11hwFu@48JvyP9dW_v zb>yp91pUYvBiOVdMLqr$Iccl}Ey+>i3dT=DK2g|L>xv-6Vj>5=+4Pw)0#@cCrgt(b=?9TnB&eoOZ zgg?%KG>9~%nYAuK6oMVgYLsihJ53EiNG-%{PnEWFLzF;6=Xvz}3 zb`jE4EKPvZvKTa$L3IUQYz?3B%6Z^}E(|9mayQaor{kRPnegFo&(##1nJbc`cYV%O` zFp)d>aJAU9NkE?0>jiiXR}0W$H@v8piwTE3&q5llXT!Y}J4qg|;wf2eXgz0mfB}uc zA0!Cgg2PCWiUluT2)c82k&Nc4=r9}vraV*6H7nM6inW2??1xcG&I)pg199Aa`3G?+ z0|Dj5*o*C3cJgdfgEebI5_tw4#-&YbtyxWLbFzZx$rj{>g1rhl^#n|N*PkbSY#nD~Odg)oZil zT+jvTQWu85VpXL`l@~he3?v5yuaIY0&5>J|NM@jU3a-60Pqx-D)ckysG=y?~;JUc4Ld9)%{ zlhgWPX)JhJ;PZYm2Hph=&It7O6S1FGMm$Ad#z0p;3HL!6z8H9`pM2d1bv7yRdOtbW zm)#M<6GRVF6nLSZ9PJ}61gLOedq3&wBQ^v;k<_3-b3fVB2U*aIX9iY;$gVyzi^^D4 zVO6NqqhZPQlI=zTrJp?7M@*Dwkd&Z+qhFsPRc)B9Ds#92ZlLKRTj?h4h*Wc{miQW{ z@~x}E`)K;u;nmW z&o-Z+zu}Ym?+H#}IavVv2k1H`(RG|a*Ksmk$27l1fy0rx1l-35KeZ@ylP(Ekli?Jruhi=?X)f)HLBRe z;lv`^1zRDb3qv1-NYD{mIttPI{Ezz-daCC`M<8bXj9bNNTNEC0)~b-7RdM>3$vf5V zA`e#@{_Gi#K~IFq#^g%Y&wobDOEb0Djvv8Wx)IF3Ebx8B8cK9jfJC6&FF-3?1M-qe2Hn&lvp-28VGtg|CFeIGo8{+6@PETkL>d zsQGO+!lI>1>7k{XFYq@oPePrt^p<$5dAhzgRxiCN=*5ip+IfG$zJFpK_qWePuFdDW zQ20dS*=YED6&(I*IRi>luc&_b>*dH5?h5=FROa*hYEsfWGtcyV{+svx3);{+4)Xtk zDzw1>&u}l-@ua$AG4rH9{s;B{KmHFqP{&^s@BhIk$ra=FPs~nz{!a5u&+OxO<>eDP%G3ir0kw^x0++E|nJz>n9?duX2LM|G1MP~(ZFe{cS|I%C_%Pt^Y| z`RSd{OnQFn3zuJZ?ArdPk6tzWc}9Ew-h1AjyKhqG<%4?SkG}r##N)p> z*>>uy)6&^HJ|F)jPd*L26jZ*}{_C+ziQm>;KHN7pv?%=dS01|hz%|FfJKMzib zJ{2`;Kha*&dbJS!T*Pt=gEaU|LqEwd^rr7OwdrRidZ7UnL4zoY00kd^S;Qe88JGw& z$Z!nL4ze6K$VEAgLmb0FgOBnWk9ZInq6W1JVjN*)(F zWYB9S`lup4_&SjJ=6rFK(81<|jKUr!dz(1!28sw$(sbW<&uO@sb>Io-{(j&0{m%ED z^WAe(DwdCd#u_GYMZKYpYNOf_EvtF-yQTvFa8Q}x=dPpC^}eHYDUmZ|rIk_2u+ig> zYM5`(oKg*``AvqmyKBx;hUmCPk+q29GTBwLRCXr|Zvc0H-2msPnqJi_*>k{qk3`O@ zHszLp+uw+it~NV)B204;4+vdzYSOi{v#IOq6LdnCwg~CElZ253_`V?4l4PcNZk{h52bGm$$v#yS9?*5q(Qp6ud8M?cGrp3!XCc z9ATV=o^8)6=^hmusz}F~skz>s`GPxF$(^tZ%E5nWfxk&HlbfCqijiFue8hZVK?n~0 zhagvQZLgd!DTjLmqDg1S$H(Tqj?iSy7|pk67HLku~boW-1}B;OoV#C)Dy; z_8)%ySZ_7V%;ih!_xI|Dzv95Ev$fLLLS0{XwqE+g+2VNXQZln@FuP?Z6c8D|nepxT z_)XvGG@XwB`1EZZVLo*iAJ_03?W<0w)o4=+_4++Q^cBk0&U|`h1y|RY`F1knm-~JI zenc4Z?G!l%qmChRycl()$#Ed+I7p6RPPcB4A-cElfH!oE-w#=L^LND7pC2~q6y`#x zk*hcTrM6$825dH$+RaL|4gW*jY9!5treijj;>}7TOzjp$1!`-8+q&{Lz3EzvL955s z>C^5D42FI>9dDj_O!B_p!H15X$pY%)Wj*=~mWtYbOG9nQN}|?p^`n-sQm7f$0P3+@ zPDeqoZ0Umkg<#1t1pgC(Yn>JRO9YPff#822IBtE&3C;}VlYNwMhHS=J8L!It zDQPcD`vUsMz93zUkpEN$2)};DK1H8ZlKejta(wX_`xmkY$zLMe4}1>jFeK6*$u{wV l!~+ry@{Ld(gVwdedM4?3rAZS=K-l{zo(}U1eVRq#cnZ7^nu`Dc literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TURBO3/UPGRADE.DTA b/Borland Turbo Pascal v55/TURBO3/UPGRADE.DTA new file mode 100644 index 0000000000000000000000000000000000000000..f2d9439dfac43119adf5200affd8c46f82bdc812 GIT binary patch literal 25290 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 QuP4oDL(*dhRv#$80vY3(AOHXW literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/TURBOC.CFG b/Borland Turbo Pascal v55/TURBOC.CFG new file mode 100644 index 0000000..e61c9f0 --- /dev/null +++ b/Borland Turbo Pascal v55/TURBOC.CFG @@ -0,0 +1,13 @@ +-c +-p +-r- +-u- +-zCCODE +-zP +-zA +-zRCONST +-zS +-zT +-zDDATA +-zG +-zB diff --git a/Borland Turbo Pascal v55/UNPACK.COM b/Borland Turbo Pascal v55/UNPACK.COM new file mode 100644 index 0000000000000000000000000000000000000000..44d6b06bd107a110b1e7ab73e429a33e2ed89b88 GIT binary patch literal 14716 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 Dx`b0Y literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/WALLS.PAS b/Borland Turbo Pascal v55/WALLS.PAS new file mode 100644 index 0000000..894a19e --- /dev/null +++ b/Borland Turbo Pascal v55/WALLS.PAS @@ -0,0 +1,205 @@ + +{ Copyright (c) 1989 by Borland International, Inc. } + +unit Walls; +{ Turbo Pascal 5.5 object-oriented example. + See BREAKOUT.PAS. + This unit defines the Wall object type. + It's a fairly complex object, because it plays such a + pivotal role in the game. +} + +interface + +uses Screen, Bricks, Bounds, Crt; + +type + BrickPtr = ^Brick; + BW = array[1..1000] of Brick; + WallPtr = ^BW; + + Wall = object(Obstacle) + BrickWall : WallPtr; + Height : Integer; + NumLeft : Integer; + Value : Integer; + NCells : Integer; + constructor Init(InitX, InitY, InitWidth, InitHeight : Integer); + destructor Done; virtual; + procedure Show; virtual; + procedure Hide; virtual; + function Collide(var B : Ball) : Boolean; virtual; + function GetValue : Integer; virtual; + procedure Reset; + end; + +implementation + +function RandomColor(MaxColors : Integer) : Integer; +var + C : Integer; +begin + C := Random(MaxColors); + while C = (TextAttr SHR 4) do + C := Random(MaxColors); + RandomColor := C; +end; + +procedure Beep; +begin + Sound(100); + Delay(20); + NoSound; +end; + +{ A wall is an array of bricks. Its constructor actually builds a + conformant array, so we don't have to hardcode the size of the + wall. } + +constructor Wall.Init(InitX, InitY, InitWidth, InitHeight : Integer); +begin + Obstacle.Init(InitX, InitY, InitWidth, False); + Height := InitHeight; + NCells := Width*5; + GetMem(BrickWall, Width*Height*SizeOf(Brick)); + Reset; +end; + +destructor Wall.Done; +begin + FreeMem(BrickWall, Width*Height*SizeOf(Block)); +end; + +{ This procedure could be made simpler, but you wouldn't get the slick + effect you see when the wall is built. } + +procedure Wall.Show; +var + CurCol : Integer; + Count : Integer; + CurBlock : Integer; +begin + Visible := True; + NumLeft := Width*Height; + for CurCol := 1 to Width + Height - 1 do + for Count := 0 to Height - 1 do + begin + CurBlock := CurCol + Count*(Width-1); + if (CurCol - Count >= 1) and (CurCol - Count <= Width) then + begin + BrickWall^[CurBlock].Show; + Delay(5); + end; + end; + GoToXY(X + (5*Width DIV 2) - 7, Y); + TextColor(WHITE); + Write('Turbo Breakout'); +end; + +procedure Wall.Hide; +var + CurCol : Integer; + Count : Integer; + CurBlock : Integer; +begin + Visible := False; + for CurCol := 1 to Width + Height - 1 do + for Count := 0 to Height - 1 do + begin + CurBlock := CurCol + Count*(Width-1); + if (CurCol - Count >= 1) and (CurCol - Count <= Width) then + begin + if BrickWall^[CurBlock].IsVisible then + begin + BrickWall^[CurBlock].Hide; + Delay(5); + end; + end; + end; +end; + +function Wall.Collide(var B : Ball) : Boolean; +var + CollideV, CollideH : Boolean; + +{ To check for a collision with a brick, first we check if the ball is in + the area where the wall is located, then we see if there's a brick that's + still visible at the ball's position. If so, we destroy the brick, grab + its value, and beep. } + +function CheckCollide(XPos, YPos : Integer) : Boolean; +var + ThisBrick : BrickPtr; +begin + CheckCollide := False; + if (YPos < Y) or (YPos > Y + Height - 1) or + (XPos < X) or (XPos > X + NCells - 1) then + Exit; + ThisBrick := @BrickWall^[1 + ((XPos-1) DIV 5) + Width*(YPos - 1)]; + if ThisBrick^.IsVisible then + begin + CheckCollide := True; + Inc(Value, ThisBrick^.GetValue); + ThisBrick^.Hide; + Dec(NumLeft); + Beep; + if NumLeft = 0 then + Show; + end +end; + +{ When checking for a collision with the wall, we have to watch out + for special cases involving corners. } + +begin + Collide := False; + Value := 0; + CollideV := CheckCollide(B.X, B.NextY); + CollideH := CheckCollide(B.NextX, B.Y); + if CollideV then + begin + Collide := True; + B.ReverseY; + end; + if CollideH then + begin + Collide := True; + B.ReverseX; + end; + if not CollideV and not CollideH then + if CheckCollide(B.NextX, B.NextY) then + begin + Collide := True; + B.ReverseX; + B.ReverseY; + end; +end; + +function Wall.GetValue : Integer; +begin + GetValue := Value; +end; + +procedure Wall.Reset; +var + CurRow : Integer; + CurCol : Integer; + MaxColors : Integer; +begin + if LastMode = Mono then + MaxColors := 4 + else + MaxColors := 16; + NumLeft := Width*Height; + for CurRow := 0 to Height - 1 do + for CurCol := 0 to Width - 1 do + BrickWall^[CurRow*Width+CurCol+1].Init(X + CurCol*5, + Y + CurRow, + RandomColor(MaxColors), + Height - Y - CurRow + 1); + if Visible then + Show; +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/WIN.ASM b/Borland Turbo Pascal v55/WIN.ASM new file mode 100644 index 0000000..b8bf0da --- /dev/null +++ b/Borland Turbo Pascal v55/WIN.ASM @@ -0,0 +1,285 @@ +; Turbo Pascal 5.5 example +; Assembler include file for WIN.PAS unit +; Copyright (c) 1989 by Borland International, Inc. + + TITLE WIN + + LOCALS @@ + +; Coordinate record + +X EQU (BYTE PTR 0) +Y EQU (BYTE PTR 1) + +; BIOS workspace equates + +CrtMode EQU (BYTE PTR 49H) +CrtWidth EQU (BYTE PTR 4AH) + +DATA SEGMENT WORD PUBLIC + +; Externals from CRT unit + + EXTRN CheckSnow:BYTE,WindMin:WORD,WindMax:WORD + +DATA ENDS + +CODE SEGMENT BYTE PUBLIC + + ASSUME CS:CODE,DS:DATA + +; procedure WriteStr(X, Y: Byte; S: String; Attr: Byte); + + PUBLIC WriteStr + +WriteStr: + + PUSH BP + MOV BP,SP + LES BX,[BP+8] + MOV CL,ES:[BX] + MOV SI,OFFSET CS:CrtWriteStr + CALL CrtWrite + POP BP + RETF 10 + +; procedure WriteChar(X, Y, Count: Byte; Ch: Char; Attr: Byte); + + PUBLIC WriteChar + +WriteChar: + + PUSH BP + MOV BP,SP + MOV CL,[BP+10] + MOV SI,OFFSET CS:CrtWriteChar + CALL CrtWrite + POP BP + RETF 10 + +; procedure FillWin(Ch: Char; Attr: Byte); + + PUBLIC FillWin + +FillWin: + + MOV SI,OFFSET CS:CrtWriteChar + JMP SHORT CommonWin + +; procedure ReadWin(var Buf); + + PUBLIC ReadWin + +ReadWin: + + MOV SI,OFFSET CS:CrtReadWin + JMP SHORT CommonWin + +; procedure WriteWin(var Buf); + + PUBLIC WriteWin + +WriteWin: + + MOV SI,OFFSET CS:CrtWriteWin + +; Common FillWin/ReadWin/WriteWin routine + +CommonWin: + + PUSH BP + MOV BP,SP + XOR CX,CX + MOV DX,WindMin + MOV CL,WindMax.X + SUB CL,DL + INC CX +@@1: PUSH CX + PUSH DX + PUSH SI + CALL CrtBlock + POP SI + POP DX + POP CX + INC DH + CMP DH,WindMax.Y + JBE @@1 + POP BP + RETF 4 + +; Write string to screen + +CrtWriteStr: + + PUSH DS + MOV AH,[BP+6] + LDS SI,[BP+8] + INC SI + JC @@4 +@@1: LODSB + MOV BX,AX +@@2: IN AL,DX + TEST AL,1 + JNE @@2 + CLI +@@3: IN AL,DX + TEST AL,1 + JE @@3 + MOV AX,BX + STOSW + STI + LOOP @@1 + POP DS + RET +@@4: LODSB + STOSW + LOOP @@4 + POP DS + RET + +; Write characters to screen + +CrtWriteChar: + + MOV AL,[BP+8] + MOV AH,[BP+6] + JC @@4 + MOV BX,AX +@@1: IN AL,DX + TEST AL,1 + JNE @@1 + CLI +@@2: IN AL,DX + TEST AL,1 + JE @@2 + MOV AX,BX + STOSW + STI + LOOP @@1 + RET +@@4: REP STOSW + RET + +; Read window buffer from screen + +CrtReadWin: + + PUSH DS + PUSH ES + POP DS + MOV SI,DI + LES DI,[BP+6] + CALL CrtCopyWin + MOV [BP+6],DI + POP DS + RET + +; Write window buffer to screen + +CrtWriteWin: + + PUSH DS + LDS SI,[BP+6] + CALL CrtCopyWin + MOV [BP+6],SI + POP DS + RET + +; Window buffer copy routine + +CrtCopyWin: + + JC @@4 +@@1: LODSW + MOV BX,AX +@@2: IN AL,DX + TEST AL,1 + JNE @@2 + CLI +@@3: IN AL,DX + TEST AL,1 + JE @@3 + MOV AX,BX + STOSW + STI + LOOP @@1 + RET +@@4: REP MOVSW + RET + +; Do screen operation +; In CL = Buffer length +; SI = Write procedure pointer +; BP = Stack frame pointer + +CrtWrite: + + MOV DL,[BP+14] + DEC DL + ADD DL,WindMin.X + JC CrtExit + CMP DL,WindMax.X + JA CrtExit + MOV DH,[BP+12] + DEC DH + ADD DH,WindMin.Y + JC CrtExit + CMP DH,WindMax.Y + JA CrtExit + XOR CH,CH + JCXZ CrtExit + MOV AL,WindMax.X + SUB AL,DL + INC AL + CMP CL,AL + JB CrtBlock + MOV CL,AL + +; Do screen operation +; In CL = Buffer length +; DX = CRT coordinates +; SI = Procedure pointer + +CrtBlock: + + MOV AX,40H + MOV ES,AX + MOV AL,DH + MUL ES:CrtWidth + XOR DH,DH + ADD AX,DX + SHL AX,1 + MOV DI,AX + MOV AX,0B800H + CMP ES:CrtMode,7 + JNE @@1 + MOV AH,0B0H +@@1: MOV ES,AX + MOV DX,03DAH + CLD + CMP CheckSnow,1 + JMP SI + +; Exit from screen operation + +CrtExit: + + RET + +; function WinSize: Word; + + PUBLIC WinSize + +WinSize: + + MOV AX,WindMax + SUB AX,WindMin + ADD AX,101H + MUL AH + SHL AX,1 + RETF + +CODE ENDS + + END + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/WIN.OBJ b/Borland Turbo Pascal v55/WIN.OBJ new file mode 100644 index 0000000000000000000000000000000000000000..ed2a18d66700c486eddf0bb541d037218d95b4ce GIT binary patch literal 671 zcmZXRU1(Ba7{{OY9C!R6W?$Py7itu?zN8!!I9ML^h-axQby|b%Vqg@k2FK|xg5jk* zCx%@#R&=p~AaX&2E@Y6{j*evzj4p~G7%Rq!S%U-@xvb~7f?yZV!~glc&!6}I@}~5l zjq(8-8}i4~W&j8$grN}&8;{4X4-LlzizN~h;@3uQSWeqc&8Lmv{9?E>z4xD|nx>KX zrYL}`Qw(U_Y?$>-YrzXZ5z?k2SFfAn5OuJGCgl4q6X;!D&UHQ%=#4h-cKi9jU%_62 z;fxWzx@eFOa~SL-z+9#kiPppWdPo2@pjvVju79^ z*$MpG20@N>BkTY;lGcFpA-O%n5scp_Rf>Z;t7y#kf$|at$_5pQ0Ym;KD09sj)w(W! z57z1Y6ZNq3mDCO(V!C5x_F^!iynw;}%Z)|H83M_TfwBfn;uWTp)Om#VS?PV{F-g>a zVjrzba<;x&G0U^r)h)9udUUua?BBVvAy>1qi7`u?#c@X20~6znSvHlDjM4%VNz_8y z)19u0Tzw>qk=90;!hAx+fqm?PnB3KPLt!+5Qv;5jvw!{6HG|m~8U@FaK#5B^CrlQ^ zMQhF41NIudu)HGu$U)AU>gGY4pq@XQEX;qPw^H2z W - 2 then Title[0] := Chr(W - 2); + WriteStr((W - Length(Title)) shr 1 + 1, 1, Title, TitleAttr); + for Y := 2 to H - 1 do + begin + WriteChar(1, Y, 1, Frame[4], FrameAttr); + WriteChar(W, Y, 1, Frame[5], FrameAttr); + end; + WriteChar(1, H, 1, Frame[6], FrameAttr); + WriteChar(2, H, W - 2, Frame[7], FrameAttr); + WriteChar(W, H, 1, Frame[8], FrameAttr); + Inc(WindMin, $0101); + Dec(WindMax, $0101); +end; + +procedure UnFrameWin; +begin + Dec(WindMin, $0101); + Inc(WindMax, $0101); +end; + +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/WINDEMO.PAS b/Borland Turbo Pascal v55/WINDEMO.PAS new file mode 100644 index 0000000..f5e04cd --- /dev/null +++ b/Borland Turbo Pascal v55/WINDEMO.PAS @@ -0,0 +1,207 @@ + +{ Turbo Windows } +{ Copyright (c) 1989 by Borland International, Inc. } + +program WinDemo; +{ Turbo Pascal 5.5 example. + This program demonstrates use of the new WIN unit. +} + +{$S-} + +uses Crt, Win; + +const + + CClose = ^C; + CRight = ^D; + CUp = ^E; + CEnter = ^M; + CInsLin = ^N; + COpen = ^O; + CRandom = ^R; + CLeft = ^S; + CDown = ^X; + CDelLin = ^Y; + CExit = ^[; + +type + + TitleStrPtr = ^TitleStr; + + WinRecPtr = ^WinRec; + WinRec = record + Next: WinRecPtr; + State: WinState; + Title: TitleStrPtr; + TitleAttr, FrameAttr: Byte; + Buffer: Pointer; + end; + +var + TopWindow: WinRecPtr; + WindowCount: Integer; + Done: Boolean; + Ch: Char; + +procedure ActiveWindow(Active: Boolean); +begin + if TopWindow <> nil then + begin + UnFrameWin; + with TopWindow^ do + if Active then + FrameWin(Title^, DoubleFrame, TitleAttr, FrameAttr) + else + FrameWin(Title^, SingleFrame, FrameAttr, FrameAttr); + end; +end; + +procedure OpenWindow(X1, Y1, X2, Y2: Byte; T: TitleStr; + TAttr, FAttr: Byte); +var + W: WinRecPtr; +begin + ActiveWindow(False); + New(W); + with W^ do + begin + Next := TopWindow; + SaveWin(State); + GetMem(Title, Length(T) + 1); + Title^ := T; + TitleAttr := TAttr; + FrameAttr := FAttr; + Window(X1, Y1, X2, Y2); + GetMem(Buffer, WinSize); + ReadWin(Buffer^); + FrameWin(T, DoubleFrame, TAttr, FAttr); + end; + TopWindow := W; + Inc(WindowCount); +end; + +procedure CloseWindow; +var + W: WinRecPtr; +begin + if TopWindow <> nil then + begin + W := TopWindow; + with W^ do + begin + UnFrameWin; + WriteWin(Buffer^); + FreeMem(Buffer, WinSize); + FreeMem(Title, Length(Title^) + 1); + RestoreWin(State); + TopWindow := Next; + end; + Dispose(W); + ActiveWindow(True); + Dec(WindowCount); + end; +end; + +procedure Initialize; +begin + CheckBreak := False; + if (LastMode <> CO80) and (LastMode <> BW80) and + (LastMode <> Mono) then TextMode(CO80); + TextAttr := Black + LightGray * 16; + Window(1, 2, 80, 24); + FillWin(#178, LightGray + Black * 16); + Window(1, 1, 80, 25); + GotoXY(1, 1); + Write(' Turbo Pascal 5.5 Window Demo'); + ClrEol; + GotoXY(1, 25); + Write(' Ins-InsLine Del-DelLine Alt-O-Open ' + + ' Alt-C-Close Alt-R-Random Esc-Exit '); + ClrEol; + Randomize; + TopWindow := nil; + WindowCount := 0; +end; + +procedure CreateWindow; +var + X, Y, W, H: Integer; + S: string[15]; + Color: Byte; +begin + W := Random(50) + 10; + H := Random(15) + 5; + X := Random(80 - W) + 1; + Y := Random(23 - H) + 2; + Str(WindowCount + 1, S); + if LastMode <> CO80 then + Color := Black else Color := WindowCount mod 6 + 1; + OpenWindow(X, Y, X + W - 1, Y + H - 1, ' Window ' + S + ' ', + Color + LightGray * 16, LightGray + Color * 16); + TextAttr := LightGray; + ClrScr; +end; + +procedure RandomText; +begin + repeat + Write(Chr(Random(95) + 32)); + until KeyPressed; +end; + +function ReadChar: Char; +var + Ch: Char; +begin + Ch := ReadKey; + if Ch = #0 then + case ReadKey of + #19: Ch := CRandom; { Alt-R } + #24: Ch := COpen; { Alt-O } + #45: Ch := CExit; { Alt-X } + #46: Ch := CClose; { Alt-C } + #72: Ch := CUp; { Up } + #75: Ch := CLeft; { Left } + #77: Ch := CRight; { Right } + #80: Ch := CDown; { Down } + #82: Ch := CInsLin; { Ins } + #83: Ch := CDelLin; { Del } + end; + ReadChar := Ch; +end; + +procedure Beep; +begin + Sound(500); Delay(25); NoSound; +end; + +begin + Initialize; + Done := False; + repeat + Ch := ReadChar; + if WindowCount = 0 then + if (Ch <> COpen) and (Ch <> CExit) then Ch := #0; + case Ch of + #32..#255: Write(Ch); + COpen: CreateWindow; + CClose: CloseWindow; + CUp: GotoXY(WhereX, WhereY - 1); + CLeft: GotoXY(WhereX - 1, WhereY); + CRight: GotoXY(WhereX + 1, WhereY); + CDown: GotoXY(WhereX, WhereY + 1); + CRandom: RandomText; + CInsLin: InsLine; + CDelLin: DelLine; + CEnter: WriteLn; + CExit: Done := True; + else + Beep; + end; + until Done; + Window(1, 1, 80, 25); + NormVideo; + ClrScr; +end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/CHESS.EXE b/Borland Turbo Pascal v55/chess/CHESS.EXE new file mode 100644 index 0000000000000000000000000000000000000000..26691f2d126ac08fed184de83dc8a7b464d9f5e3 GIT binary patch literal 53776 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 T*iEl<7w0X!@%sN|h$sICAid$C literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/chess/CHESS.HLP b/Borland Turbo Pascal v55/chess/CHESS.HLP new file mode 100644 index 0000000000000000000000000000000000000000..31ae0bf89a5090152acbc63b1092001d4432b6c7 GIT binary patch literal 30294 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 o-chgCYt*ZK grOk then begin + writeln; + writeln; + writeln ('Error using graphics driver file "EGAVGA.BGI" <> this computer does'); + writeln ('not have a VGA graphics card. Aborting'); + Halt (1); + end; + SetTextStyle (TriplexFont, HorizDir, 1); + if GraphResult <> grOk then begin + CloseGraph; + writeln ('Error in accessing font file "TRIP.CHR". Aborting!'); + Halt (1); + end; + end; + +{****************************************************************************} +{* Load Piece Images: from the file "PIECES.IMG". These are the pixel *} +{* images of all of the pieces, including the 'piece' BLANK. Checks for *} +{* I/O errors and aborts the program if there are any. *} +{****************************************************************************} + procedure LoadPieceImages; + var ImageFile : file of ImageType; + IOerror : boolean; + begin + new (ImageStore); + assign (ImageFile, 'PIECES.IMG'); + reset (ImageFile); + IOerror := IOResult <> 0; + if not IOerror then begin + read (ImageFile, ImageStore^); + IOerror := IOResult <> 0; + if not IOerror then + close (ImageFile); + end; + if IOerror then begin + CloseGraph; + writeln ('IO error trying to access images file "PIECES.IMG". Aborting!'); + Halt (1); + end; + end; + +{****************************************************************************} +{* Display Title Screen: Display the title, authors and notes on the *} +{* screen when the program starts, in a variety of fonts, sizes, and *} +{* colors. Then wait for user to type a key. The internal subroutine *} +{* CenterTitle will display its string argument, centered on the screen, *} +{* on the given pixel row. *} +{****************************************************************************} + procedure DisplayTitleScreen; + var key : char; + + procedure CenterTitle (row : integer; str : string80); + begin + OutTextXY (320 - TextWidth(str) div 2, row, str); + end; + + begin + ClearDevice; + SetColor (LightCyan); + SetTextStyle (TriplexFont, HorizDir, 26); + CenterTitle (0, 'KC CHESS'); + SetColor (LightGreen); + SetTextStyle (TriplexFont, HorizDir, 3); + CenterTitle (200, 'by Craig Bruce and Kevin Phillips, 06-Apr-90.'); + SetTextStyle (TriplexFont, HorizDir, 1); + CenterTitle (240, 'This program is Public Domain software.'); {*** that's right ***} + SetColor (LightGray); + SetTextStyle (TriplexFont, HorizDir, 1); + CenterTitle (300, 'This program was written using'); + CenterTitle (330, 'Turbo Pascal 5.5 (c) Borland International, Inc.'); {*** required message ***} + CenterTitle (360, 'as the undergraduate final project for Dr. J. D. Horton'); + CenterTitle (390, 'at the University of New Brunswick.'); + LoadPieceImages; {*** while user is reading title screen ***} + SetTextStyle (DefaultFont, HorizDir, 2); + {*** display some piece images on the title screen ***} + PutImage (320-WIDE*2, 135, ImageStore^[PAWN, C_WHITE, S_DARK], 0); + PutImage (320-WIDE*1, 135, ImageStore^[KING, C_BLACK, S_LIGHT], 0); + PutImage (320+WIDE*0, 135, ImageStore^[QUEEN, C_WHITE, S_DARK], 0); + PutImage (320+WIDE*1, 135, ImageStore^[KNIGHT, C_BLACK, S_LIGHT], 0); + SetColor (Yellow); + CenterTitle (450, 'Press any key to begin'); + key := ReadKey; + end; + +{****************************************************************************} +{* Make Sound: Will make either the "good" sound (a beep), or the "bad" *} +{* sound (a buzz), if the sound option is on. *} +{****************************************************************************} + procedure MakeSound (Good : boolean); + begin + if (Game.SoundFlag) then begin + if (Good) then begin + Sound (650); {*** beep = 650 Hz ***} + Delay (100); + end else begin + Sound (110); {*** buzz = 110 Hz ***} + Delay (350); + end; + NoSound; + end; + end; + +{****************************************************************************} +{* Display Square: and the piece on it on the main game screen, given the *} +{* row and column and whether to display it in the square's natural shade *} +{* or the cursor color. *} +{****************************************************************************} + procedure DisplaySquare (Row, Col : RowColType; cursor : boolean); + var x, y : integer; + SquareColor : SquareColorType; + Piece : PieceType; + begin + Piece := Board[Row, Col]; + {*** get the starting pixel location ***} + x := BOARD_X1 + (Col - 1) * WIDE; + y := BOARD_Y1 + (BOARD_SIZE - Row) * HIGH; + {*** get the square color ***} + if cursor then begin + SquareColor := S_CURSOR; + end else begin + if (Row + Col) mod 2 = 0 then + SquareColor := S_DARK + else + SquareColor := S_LIGHT; + end; + {*** put image onto the screen ***} + PutImage (x, y, ImageStore^ [Piece.image, Piece.color, SquareColor], 0); + end; + +{****************************************************************************} +{* Display Clear Lines: Erase all text from the given pixel row for the *} +{* given number of pixel rows, on the conversation area. *} +{****************************************************************************} + procedure DisplayClearLines (from, count : integer); + begin + SetFillStyle (SolidFill, DarkGray); + Bar (MSG_BOXX1 + 1, from, MSG_BOXX2 - 1, from + count - 1); + end; + +{****************************************************************************} +{* Center Text: Display the given string, centered, on the given pixel row *} +{* of the conversation area. *} +{****************************************************************************} + procedure CenterText (row : integer; str : string80); + begin + OutTextXY (MSG_MIDX - TextWidth(str) div 2, row, str); + end; + +{****************************************************************************} +{* Display Player Info: Display the name, elapsed time, player type and *} +{* skill level, last move, and whether in check or not, for the given *} +{* player starting at the given pixel row on the conversation area (in *} +{* the player status box). *} +{****************************************************************************} + procedure DisplayPlayerInfo (row : integer; color : PieceColorType); + var cstr : string10; + bstr : string80; + begin + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (Yellow); + with Player[color] do begin + CenterText (row, Name); + CenterText (row + MSG_CHI, TimeString (ElapsedTime)); + if IsHuman then + bstr := 'Human' + else begin + Str (LookAhead, cstr); + bstr := 'Machine Level ' + cstr; + if PosEval then bstr := bstr + '+'; + end; + CenterText (row + MSG_CHI * 2, bstr); + CenterText (row + MSG_CHI * 3, 'Last: ' + MoveStr (LastMove)); + if InCheck then + bstr := 'In Check' + else + bstr := 'Ok'; + CenterText (row + MSG_CHI * 4, bstr); + end; + end; + +{****************************************************************************} +{* Display Instructions: display the given set of instructions at the *} +{* bottom of the screen in the instruction area. OutLine will display the *} +{* given instructions on the given instruction line number. *} +{****************************************************************************} + procedure DisplayInstructions (InstrSet : InstructionType); + const CHI = 11; {*** character height ***} + + procedure OutLine (LineNum : integer; OutText : string80); + begin + OutTextXY (0, INSTR_LINE + CHI * LineNum, OutText); + end; + + begin + SetFillStyle (SolidFill, Black); + Bar (0, INSTR_LINE, GetMaxX, GetMaxY); + SetTextStyle (DefaultFont, HorizDir, 1); + SetColor (LightRed); + case InstrSet of + INS_MAIN: begin + OutLine (0, 'MAIN MENU RETURN = play, F = File System'); + OutLine (1, 'H = Help, G = Goto move, W = Watch game, O = Options, P = Player info'); + OutLine (2, 'Q = Quit, N = New game, S = Setup board, T = Take-Back Move, U = Un-takeback'); + end; + INS_GAME : begin + OutLine (0, 'GAME MENU'); + OutLine (1, 'Human Player: use Cursor Keys, BACKSPACE, and RETURN/SPACE. ESC = main menu'); + OutLine (2, 'M = force computer to Move, H = Hint, A = Attack/protect, C = Check moves'); + end; + INS_SETUP : begin + OutLine (0, 'SETUP MENU'); + OutLine (1, 'Use cursor keys. Then type K, Q, R, B, N or P to set piece or SPACE to remove.'); + OutLine (2, 'RETURN = exit, ESC = exit recalling old setup; D = default, C = clear board.'); + end; + INS_SETUP_COLOR : begin + OutLine (0, 'SETUP MENU - PIECE COLOR SET'); + OutLine (1, 'Type B to create a BLACK piece'); + OutLine (2, 'Type W to create a WHITE piece'); + end; + INS_SETUP_MOVED : begin + OutLine (0, 'SETUP MENU - PIECE MOVED SET'); + OutLine (1, 'Has this piece been moved from its starting position at any time since the'); + OutLine (2, 'start of the game (Y/N)?'); + end; + INS_SETUP_MOVENUM : begin + OutLine (0, 'SETUP MENU - SET MOVE NUMBER and COLOR'); + OutLine (1, 'Enter the number then whose turn the next move of the game will be.'); + OutLine (2, 'Use BACKSPACE to edit value, and RETURN to enter it.'); + end; + INS_PLAYER : begin + OutLine (0, 'SET PLAYER INFO'); + OutLine (1, 'Type value, use BACKSPACE to edit and press RETURN after each field.'); + OutLine (2, 'For the player type: H = Human and M = Machine. Pos Eval is part of skill level.'); + end; + INS_OPTIONS : begin + OutLine (0, 'SET OPTIONS'); + OutLine (1, 'Type value, use BACKSPACE to edit and press RETURN after each field.'); + OutLine (2, 'Press RETURN only to preserve current setting.'); + end; + INS_FILE : begin + OutLine (0, 'FILE MENU'); + OutLine (1, 'L = Load Game, S = Save Game, D = Directory, P = Print Game'); + OutLine (2, 'ESC = return to Main Menu'); + end; + INS_FILE_INPUT: begin + OutLine (0, 'FILE NAME INPUT'); + OutLine (1, 'Please enter the name of the file you wish to use.'); + OutLine (2, 'Press RETURN only for default file name.'); + end; + INS_WATCH : begin + OutLine (0, 'WATCH MODE'); + OutLine (1, 'Press any key to return to Main Menu.'); + end; + INS_GOTO : begin + OutLine (0, 'GOTO MOVE NUMBER'); + OutLine (1, 'Please enter the move number and then the color to move.'); + OutLine (2, 'to use. Press RETURN only for default file.'); + end; + INS_PAWN_PROMOTE : begin + OutLine (0, 'HUMAN PLAYER PAWN PROMOTION'); + OutLine (1, 'Press the letter of the piece you wish to promote the pawn to:'); + OutLine (2, 'Q = Queen, R = Rook, B = Bishop, N = kNight.'); + end; + end; + end; + +{****************************************************************************} +{* Display Board: call DisplaySquare for each square on the board. A *} +{* small dot is displayed on the screen immediately before the square *} +{* image is displayed to show that the screen is being updated, even if *} +{* the board is being displayed over itself with no changes. *} +{****************************************************************************} + procedure DisplayBoard; + var row, col : RowColType; + x,y : integer; + begin + SetFillStyle (SolidFill, LightCyan); + for row := 1 to BOARD_SIZE do + for col := 1 to BOARD_SIZE do begin + x := BOARD_X1 + (Col-1) * WIDE; + y := BOARD_Y1 + (BOARD_SIZE - Row) * HIGH; + Bar (x + 23, y + 23, x + 26, y + 26); + DisplaySquare (row, col, false); + end; + end; + +{****************************************************************************} +{* Get Finish Reason: given the completion status variables in the Game *} +{* global data structure, this routine returns the reason and the winner *} +{* (if any) of the game. The reason can be that a player exceeded the *} +{* time limit, there are more moves than can be stored in the game, *} +{* stalemate (fifty non-developmental moves or player cannot move, or *} +{* last but not least, checkmate. *} +{****************************************************************************} + procedure GetFinishReason (var Reason : string80; var IsWinner : boolean; + var Winner : PieceColorType); + var KingInCheck : boolean; + begin + if Game.TimeOutWhite or Game.TimeOutBlack then begin + Reason := 'Time-Out'; + if Game.TimeOutWhite and Game.TimeOutBlack then + IsWinner := false + else begin + IsWinner := true; + if Game.TimeOutWhite then + Winner := C_BLACK + else + Winner := C_WHITE; + end; + end else begin + if Game.NoStorage then begin + Reason := 'Game Too Long'; + IsWinner := false; + end else begin + KingInCheck := Player[C_WHITE].InCheck or Player[C_BLACK].InCheck; + if Game.Stalemate or not KingInCheck then begin + Reason := 'Stalemate'; + IsWinner := false; + end else begin + Reason := 'Checkmate'; + IsWinner := true; + if Player[C_WHITE].InCheck then + Winner := C_BLACK + else + Winner := C_WHITE; + end; + end; + end; + end; + +{****************************************************************************} +{* Display Whose Move: displays the move number and color of the current *} +{* move in the conversation area. If the game is finished, display the *} +{* reason, and if the fifty move stalemate is close, displays a warning. *} +{****************************************************************************} + procedure DisplayWhoseMove; + var cstr : string10; + mstr : string80; + Reason : string80; + Winner : PieceColorType; + IsWinner : boolean; + Turn : PieceColorType; + OutMove : integer; + NoDevCount : integer; + begin + {*** move number and color ***} + if Game.GameFinished then + OutMove := Game.MoveNum - 1 + else + OutMove := Game.MoveNum; + Str ((OutMove + 1) div 2, cstr); + mstr := 'Move ' + cstr + '-'; + if OutMove mod 2 = 1 then begin + mstr := mstr + 'White'; + Turn := C_WHITE; + end else begin + mstr := mstr + 'Black'; + Turn := C_BLACK; + end; + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (Yellow); + DisplayClearLines (MSG_SCORE, MSG_POS_EVAL+8-MSG_SCORE); + DisplayClearLines (MSG_MOVENUM, 80); + CenterText (MSG_MOVENUM, mstr); + + {*** if game is over, display reason ***} + if Game.GameFinished then begin + GetFinishReason (Reason, IsWinner, Winner); + SetColor (White); + CenterText (MSG_TURN + 3, Reason + ':'); + SetColor (LightGreen); + if IsWinner then + CenterText (MSG_MOVE - 1, Player[Winner].Name) + else + CenterText (MSG_MOVE, 'Neither Player'); + CenterText (MSG_HINT, 'Wins'); + end else begin + CenterText (MSG_TURN, Player[Turn].Name); + end; + + {*** warn if fifty move stalemate is close ***} + NoDevCount := Game.NonDevMoveCount[Game.MovesPointer]; + DisplayClearLines (MSG_WARN50, 17); + if (NoDevCount >= NON_DEV_MOVE_LIMIT - 10) then begin + SetColor (LightRed); + if (NoDevCount = NON_DEV_MOVE_LIMIT) then + CenterText (MSG_WARN50, '50 Move Limit') + else begin + Str(NON_DEV_MOVE_LIMIT - NoDevCount, cstr); + CenterText (MSG_WARN50, 'Stalemate in ' + cstr); + end; + end; + end; + +{****************************************************************************} +{* Display Conversation Area: display player status for black and white, *} +{* move status, and time limit, all in the conversation area. *} +{****************************************************************************} + procedure DisplayConversationArea; + var tempstr : string80; + begin + SetFillStyle (SolidFill, DarkGray); + Bar (MESSAGE_X, MSG_CONV, GetMaxX, INSTR_LINE - 8); + SetColor (White); + Rectangle (MSG_BOXX1, MSG_WHITE-2, MSG_BOXX2, MSG_WHITE + MSG_PLHI); + SetTextStyle (DefaultFont, HorizDir, 1); + OutTextXY (MSG_BOXX1 + 4, MSG_WHITE - 10, 'White'); + DisplayPlayerInfo (MSG_WHITE, C_WHITE); + SetColor (Black); + Rectangle (MSG_BOXX1, MSG_BLACK-2, MSG_BOXX2, MSG_BLACK + MSG_PLHI); + SetTextStyle (DefaultFont, HorizDir, 1); + OutTextXY (MSG_BOXX1 + 4, MSG_BLACK - 10, 'Black'); + DisplayPlayerInfo (MSG_BLACK, C_BLACK); + SetColor (Cyan); + Rectangle (MSG_BOXX1, 356, MSG_BOXX2, 438); + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (LightGreen); + if (Game.TimeLimit = 0) then + tempstr := '' + else + tempstr := TimeString (Game.TimeLimit); + CenterText (MSG_TIME_LIMIT, 'T.Limit = ' + tempstr); + DisplayWhoseMove; + end; + +{****************************************************************************} +{* Display Game Screen: clear the hires screen, display the board, *} +{* conversation area, and instructions. *} +{****************************************************************************} + procedure DisplayGameScreen; + var i : integer; + begin + ClearDevice; + {*** display board ***} + SetFillStyle (SolidFill, Blue); + Bar (BOARD_X1-4, BOARD_Y1-4, BOARD_X2+3, BOARD_Y2+3); + DisplayBoard; + + {*** display row and column letters and numbers around board ***} + SetColor (LightGreen); + SetTextStyle (TriplexFont, HorizDir, 2); + for i := 1 to 8 do begin + OutTextXY (0, BOARD_Y1+HIGH*i-8-HIGH div 2, + Copy (ROW_NAMES, BOARD_SIZE - i + 1, 1)); + OutTextXY (BOARD_X2 + 10, BOARD_Y1+HIGH*i-8-HIGH div 2, + Copy (ROW_NAMES, BOARD_SIZE - i + 1, 1)); + OutTextXY (BOARD_X1+WIDE*i-8-WIDE div 2, BOARD_Y2+4, + Copy (COL_NAMES, i, 1)); + end; + + {*** display title and conversation area ***} + SetFillStyle (SolidFill, DarkGray); + Bar (MESSAGE_X, 0, GetMaxX, MSG_CONV - 1); + SetTextStyle (TriplexFont, HorizDir, 4); + SetColor (LightCyan); + CenterText (2, 'KC CHESS'); + DisplayConversationArea; + end; + +{****************************************************************************} +{* Update Time: get the elapsed time since last call, and if there was a *} +{* change in the time, the amount of change is added to the current *} +{* player's elapsed time and the new time is displayed. *} +{****************************************************************************} + procedure UpdateTime (Turn : PieceColorType); + var Elapsed : longint; + Row : integer; + begin + Elapsed := ElapsedTime; + if (Elapsed > 0) then begin + Player[Turn].ElapsedTime := Player[Turn].ElapsedTime + Elapsed; + if (Turn = C_WHITE) then + Row := MSG_WHITE + MSG_CHI + else + Row := MSG_BLACK + MSG_CHI; + DisplayClearLines (Row, 17); + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (Yellow); + CenterText (Row, TimeString(Player[Turn].ElapsedTime)); + end; + end; + +{****************************************************************************} +{* Flash Piece: will flash the piece at the given location on the Board *} +{* alternately against the other given piece image and color. This *} +{* routine is called to highlight the piece that is moving and what it *} +{* takes when a move is being displayed. *} +{****************************************************************************} + procedure FlashPiece (row, col : RowColType; OldImage : PieceImageType; + OldColor : PieceColorType); + var NewImage : PieceImageType; + NewColor : PieceColorType; + i : integer; + begin + NewImage := Board[row, col].image; + NewColor := Board[row, col].color; + for i := 1 to Game.FlashCount do begin + Board[row,col].image := NewImage; {*** show new image ***} + Board[row,col].color := NewColor; + DisplaySquare (row, col, false); + Delay (80); + Board[row,col].image := OldImage; {*** show old image ***} + Board[row,col].color := OldColor; + DisplaySquare (row, col, false); + Delay (80); + end; + Board[row, col].image := NewImage; {*** store new image ***} + Board[row, col].color := NewColor; + DisplaySquare (row, col, false); + end; + +{****************************************************************************} +{* Display Move: displays the given move on the screen after it has *} +{* already been made to the internal data structures. The special cases *} +{* of castling and en passent are taken care of. No special case is *} +{* required for pawn promotion, since it is taken care of elsewhere. *} +{****************************************************************************} + procedure DisplayMove (Movement : MoveType); + var row, EnemyRow : integer; + cstr : string10; + begin + {*** for all moves, show the piece leaving old square and taking new square ***} + with Movement do begin + FlashPiece (FromRow, FromCol, PieceMoved.image, PieceMoved.color); + FlashPiece (ToRow, ToCol, PieceTaken.image, PieceTaken.color); + end; + case Movement.PieceMoved.image of + + {*** castling to left or right: must show rook moving ***} + KING: begin + if abs (Movement.FromCol - Movement.ToCol) > 1 then begin + if (Movement.ToCol < Movement.FromCol) then begin + FlashPiece (Movement.FromRow, 1, ROOK, Movement.PieceMoved.color); + FlashPiece (Movement.FromRow, 4, BLANK, Movement.PieceMoved.color); + end else begin + FlashPiece (Movement.FromRow, 8, ROOK, Movement.PieceMoved.color); + FlashPiece (Movement.FromRow, 6, BLANK, Movement.PieceMoved.color); + end; + end; + end; + + {*** en passent: must show the pawn being taken ***} + PAWN: if (Movement.FromCol <> Movement.ToCol) and (Movement.PieceTaken.image = BLANK) then + FlashPiece (Movement.FromRow, Movement.ToCol, PAWN, EnemyColor[Movement.PieceMoved.color]); + end; + + {*** locate and display the new last move and in-check status ***} + if Movement.PieceMoved.color = C_WHITE then begin + row := MSG_WHITE; + EnemyRow := MSG_BLACK; + end else begin + row := MSG_BLACK; + EnemyRow := MSG_WHITE; + end; + DisplayClearLines (row + MSG_CHI * 3, 34); + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (Yellow); + CenterText (row + MSG_CHI * 3, 'Last: ' + MoveStr(Player[Movement.PieceMoved.color].LastMove)); + CenterText (row + MSG_CHI * 4, 'Ok'); + if Player[EnemyColor[Movement.PieceMoved.color]].InCheck then cstr := 'In Check' else cstr := 'Ok'; + DisplayClearLines (EnemyRow + MSG_CHI * 4, 17); + CenterText (EnemyRow + MSG_CHI * 4, cstr); + end; + +{****************************************************************************} +{* Display UnMade Move: display a move being retracted after the internal *} +{* data structures have been modified. Special cases are un-castle and *} +{* un-en passent. *} +{****************************************************************************} + procedure DisplayUnMadeMove (Movement : MoveType); + var row, EnemyRow : integer; + cstr : string10; + begin + if (Movement.FromRow <> NULL_MOVE) then begin + with Movement do begin + {*** retract for all pieces ***} + FlashPiece (ToRow, ToCol, MovedImage, PieceMoved.color); + FlashPiece (FromRow, FromCol, BLANK, C_WHITE); + end; + case Movement.PieceMoved.image of + + {*** un-castle ***} + KING: begin + if abs (Movement.FromCol - Movement.ToCol) > 1 then begin + if (Movement.ToCol < Movement.FromCol) then begin + FlashPiece (Movement.FromRow, 4, ROOK, Movement.PieceMoved.color); + FlashPiece (Movement.FromRow, 1, BLANK, Movement.PieceMoved.color); + end else begin + FlashPiece (Movement.FromRow, 6, ROOK, Movement.PieceMoved.color); + FlashPiece (Movement.FromRow, 8, BLANK, Movement.PieceMoved.color); + end; + end; + end; + + {*** un-en passent ***} + PAWN: if (Movement.FromCol <> Movement.ToCol) and (Movement.PieceTaken.image = BLANK) then + FlashPiece (Movement.FromRow, Movement.ToCol, BLANK, EnemyColor[Movement.PieceMoved.color]); + end; + + {*** update status for both players ***} + if Movement.PieceMoved.color = C_WHITE then begin + row := MSG_WHITE; + EnemyRow := MSG_BLACK; + end else begin + row := MSG_BLACK; + EnemyRow := MSG_WHITE; + end; + DisplayClearLines (row + MSG_CHI * 3, 34); + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (Yellow); + CenterText (row + MSG_CHI * 3, 'Last: ' + MoveStr(Player[Movement.PieceMoved.color].LastMove)); + if Player[Movement.PieceMoved.color].InCheck then cstr := 'In Check' else cstr := 'Ok'; + CenterText (row + MSG_CHI * 4, cstr); + DisplayClearLines (EnemyRow + MSG_CHI * 4, 17); + CenterText (EnemyRow + MSG_CHI * 4, 'Ok'); + DisplayWhoseMove; + end; + end; + +{*** end of DISPLAY.PAS include file ***} + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/EGAVGA.BGI b/Borland Turbo Pascal v55/chess/EGAVGA.BGI new file mode 100644 index 0000000000000000000000000000000000000000..8d916b7733d4fc92361fe6075619ea8fc4044a54 GIT binary patch literal 5363 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 BoPGcR literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/chess/EXAMPLE.CHS b/Borland Turbo Pascal v55/chess/EXAMPLE.CHS new file mode 100644 index 0000000000000000000000000000000000000000..653417b7b7f8295dc29e9c06e7a91a331bd711b3 GIT binary patch literal 8191 zcmeHMJ9gYK3?zsTc^l^rc`g(C+0N~9lw2!)Wqi8Nfe`-u7V>D%*21urXzh z2u)W_)ZAfNScx!K5^~=-qmHqXiN`Au>3^v}YWV zK6><@tgx)?RUv>8V^@{I`J0#YFebpWlGYXNK;EEENqWg#wamlCf{ zDNqWO0;NDHPzsa+r9dfA3X}q+Kq*iPlmewdDNqWO0;NDH@c$@~U&4`2ensE^%#P_Nchq5!oK;Y!Hxm@3kcZke|`=eo++&ld0ys=G%CLJcbU0mmL@cv0- n2g=BqC%U1?9FxM+$_4hh$fc!jpOjyP`Bw^{-r6tpmRtJ+9@!3@ literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/chess/HELPGEN.EXE b/Borland Turbo Pascal v55/chess/HELPGEN.EXE new file mode 100644 index 0000000000000000000000000000000000000000..924bf6f8d154c2c98282c3c31b6e86f2829c5d67 GIT binary patch literal 3296 zcmbtVe@qm27Ju_&XP05wL!_t_ciE_uQYwdRvMLDTZA}w7>m_F|Fax1~El9sc`W@0)qzgzN zBh4W#AT1)LPyic{@{kIUYLHGMbs_nXVn|;h{T)d~x{pLbE_{Q;nsX81>9ejJpWQ7d zPM$h-^3(~kvF>%(cep?5**nZ^vhUOGmEfof9qO+eU=lr;aDp zdI8ZJ{NJ8g0P2dBw>Mq^ur=-odwSz&vbPyuS3Uqd&cNed8%wqnZXINM)RN@(cC9j$ zCC<}(0naD644T3>k6~-9j%y#EGI{_W-jp9*dp}BnuYym>lKyF+_c~F-5*C@eUnI>{ zpiRXCp5Bj$8$0lI?o-gS8m|}(3Oq_3G7r({z?!I&?2H)5(ep8olfDc(>A;zZCp&vFOxoVq>rTl9UyMzF=KU}+|7(bMvvmSZi5V|~F8Lv}A=t~K zdH;fUN4WP(yrpNK(FmNM@8OETbx)3&)T9q2C7m8=*f3ggzR! zLwY~SP3ouLP$L=e!E(Xi@Xi^he{+wU_D!%izqi{QqkjPfw#_(4zW`+mS^oseR0#{NyIuR`BzpccW{3Z>eiuMpHq z2$rY~fKuvC7-MMFOhkrjW}F29GanW?^$n=f9z;XOkrU!o8mqtP_R=C-=s|?0KrHGB z#IU`aJRx>YRT*g7`V+RWtfZA@&4JlrZpIk}`sFQKU*B2$vp3!>DJ?6n*d-m5PKhUf z(~{fL+WKB=F66!==0ZUl56kk6p84X~X-n~V2RnEvFj;i(!6)bEr`aTDyn{zBS1i}D zgC&u6IuLm(!-ISSnXC{n72RIbh@G|~mL-5bqZXGsb($HWfLY9sw63otIH^;ev}>v~ z($2{djdq1E$&-dj%k$0%fwZD~g94b^EW$OD9*8W>GLQEJ60(MSc48;t0E*tq+cQ{3 zwdQqL2Jin_%Bj;FMYrX@<Y;injboW)TtgN#DD|nkD~{JW-s#hjmP^+D(ED z3W05CrsOjW_A`D;_h3p71ak4+jnM0!~Fb zF?V8JJlCk;+>xufy;%OUE3qyc*Jx8MItr|0H5vkXJBLM#?9hr${SHM?NpH8<)c028 zZ@tsjRZL$O2VGS^Lbed(_LXM<STQapiEe z;%dRw<_hDReDTvfjE3TxWppU6F{78`$tsfFba^N)W|R-b#kBHZTuh(fis4tFZ9PcR zv=y2OL<7AFGnNkOKGMz;ZaNsp`U`?a2dO05nNAwPHVU{Ro`pc20BxgZEECjBXu>|T zj^%)w0&D7ABiAVCn{ZSx*!aiHQIeGL)2wUCpQb>00x&H|>n8lX92e=~vhGf7^OSQ9 zg)`39I=@NLO|B{VtAu2pyjg*_W}HerCr|cVU%J{YtuquQMioH$DMv)n^`W@mo!L{H z<*(i7_hwJHb40GE*6s>BFe29+3T;;C-80VZ-Qb&tHr5q(&B@d9EJ4TPbARZDk#3MT z5AT|BwqZB9zApVz%}zb?#rL&&yMJN5{1AGSK@?7TsSL?H&_L^mK72Jt?A@` zFwGNg3jpx|zjy%cyJzHGQ^N0SEkpx>TFviug)+J>6)er|cN=yv{Omo=EHK3=)`IPjK^lX3Evd3jL1i~DD^LyX3U zXpIX|8XZbr7rJn4MaogTR?zUKr3fXm=tcTcgci+ZxgA(zw-b$*z%j1*N5cfCM%D|a z#>ZtaT<)6FI0ec^DKg(;T}CC~1jr^8fvsk=FHVBjJ;o@gf#xQ`=)DX(HXrA3P2s<{ zjU$;`cY!qY<+$KC;h@EGW=UESNyi_nWW(}Jlx`bo^R=o}b3odF98#Joq%;lo+HgoZ z!X@TNba>b3anMY|m7^^Qk9qZmF1>6&IDVK*_S1~B+0n|CMnsc*6%BdO(&b$vMC)?p zNKz|Zy{JpO 22 then begin + write (OutFile, Page); + writeln ('----New Page----'); + LineNum := 1; + for i := 1 to 22 do Page[i] := ''; + end; + end; + if LineNum <> 1 then write (OutFile, Page); + writeln ('====Ending===='); + close (OutFile); + end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/HELPTEXT.TXT b/Borland Turbo Pascal v55/chess/HELPTEXT.TXT new file mode 100644 index 0000000..1647a6a --- /dev/null +++ b/Borland Turbo Pascal v55/chess/HELPTEXT.TXT @@ -0,0 +1,361 @@ +KC CHESS version 1.00.00 - by Craig Bruce and Kevin Phillips, 06-Apr-90. + +If you don't know how to play chess, read a book! +------------------------------------------------------------------------------ +MAIN MENU + +When the game starts, the board, conversation area, and main menu are +displayed on the screen. To select the options from the main menu, simply +press the key indicated on the bottom of the screen. The following options +are available: + +H = Help + Displays this help information on the screen. The PAGE_UP and PAGE_DOWN + keys allow you to view the separate pages of the help information. + RETURN or SPACE may be pressed instead of PAGE_DOWN. When finished + viewing, press the ESCAPE key to return to the main menu. + +Q = Quit + Will exit the chess program and return to DOS. If you do not wish to + lose the game currently in memory, make sure you save it (File System) + before you choose this option. + +RETURN = Play game + Places the game in PLAY MODE (see below). The players make their moves + until the end of the game or until the user presses ESCAPE to return to + the main menu. While in the main menu, the current game is merely + suspended, and using this option again will resume it from its + displayed position. + +T = Take back move + This option is used if you make a regrettable move and wish to un-do + it. If the you are currently in PLAY MODE you must press ESCAPE to + return to the main menu to make this option accessible. You may take + back as many moves as you wish, all the way back to the opening move, + since they are all stored in memory. Each move taken back will be + displayed on the game board by the piece moving back to where it came + from and the conversation area information being updated as necessary. + +U = Un take back move + If you take back more moves than you meant to, then the moves can be + made again by this option. All taken back moves are remembered until + a permanent move is made (in PLAY MODE). Takeback and Untakeback may + be used to review the last few moves of the game if you wish. + +G = Goto move + This option will allow you to go directly to any move of the game. + The game board will clear and the computer will ask you for the move + number you wish to go to. See the User Input notes below for how to + edit your input. Entering a number that is larger than the last move + of the game will make the computer go to the last move of the game, and + entering a move number that is too small will go to the first move of the + game. Then, the computer will ask you which color's turn within the + move to go to. Enter B for Black or W for White. The game board + corresponding to the selected move will then be displayed and you will + be returned to the main menu. + +W = Watch game + This option allows you to view the moves of the game without going + through them 'manually' with Takeback and Untakeback. All of the + recorded moves will be displayed from the current position in the game + to the end of the game. If you are currently at the end of the game, + the computer will go to the first move of the game and start showing the + moves from there. You will return to the main menu when the end of the + game is reached, or you may exit watch mode by pressing the ESCAPE key + at any time. + +O = Options set + This option allows you to change some of the settings of the game. The + game board will clear and you will be asked for the "Flash Count". The + default value is two. This gives the number of times that a piece + should be flashed on the screen to indicate that it is being moved. + Changing this value to zero will make it so the piece is not flashed + at all. See the User Input section for information on how to input + or change the value. Press RETURN to set the Flash Count. + + Next you will be asked if you want "Sound". Answer Y for Yes or N for + No. The default is Yes. The only sound in the game is a beep when the + computer is finished selecting its move in Play Mode or a buzz in some + places when you do something wrong. + + Next you will be asked if you want to allow the "En Passent" priviledge + in the game. The default value is Yes. Although it is rarely used, + you may wish to set it to No if you don't know what it is and you don't + want the computer to do it to you. + + Next you will be asked for the "Watch Delay" in milliseconds. This is + the time that the computer will delay between showing moves in Watch + Mode. The default value is 700 milliseconds (0.7 seconds). The minimum + and maximum allowed values are 0 and 30000. Do not enter any commas + in the number. If the number entered is improper, the default value of + 700 will be used. + + Finally, you will be asked for the "Time Limit" for the game. If either + player's elapsed time (shown in the player info blocks in the conversation + area) meets or exceeds the time limit, then that player loses and the + game is over. The default value is 00:00:00 (in HH:MM:SS format), which + means that there is no time limit. Changing this value will cause the + time limit to be enforced. The value entered must be in the exact format + of HH:MM:SS or the default value will be used. After entering this value, + the chess board will be displayed and the main menu will be re-entered. + +P = Player info + This option allows you to change the various attributes of each player. + The game board will clear and you will be asked for the white player's + Name. Enter the name you wish to use and press RETURN. You may use + BACKSPACE to eliminate any unwanted characters. + + Next you will be asked for the white player's Elapsed Time. Enter this + value in the format "HH:MM:SS" or the program will use the value 00:00:00. + In play mode, the move time will be added to this time. The move Takeback + and Untakeback options do not update or un-update the elapsed time (you + can't roll back the hands of time), so if you wish to take back moves and + resume play from some lower elapsed time, you must enter the new elapsed + time value here. + + Next you will be asked for the player type of the white player. You may + enter H for Human or M for Machine. Use BACKSPACE to delete the current + setting. If you enter an invalid character, the default of Machine will + be used. You may enter either Human or Machine for either player (white + or black), allowing four combinations. Human vs. Human would be like + playing on a real board and Machine vs. Machine would be a demonstration + of the program. + + Next you will be asked for the "Lookahead". For a Machine player this + gives the number of half-moves (plys) to look ahead of the current + board position in figuring out the best move to make, and for a Human + player this gives the number of plys to look ahead if the human asks for + a hint. To change the setting, press BACKSPACE to delete the current + value and enter the new value. Zero to three ply lookaheads will not + require much time, but four and higher lookaheads can require a + considerable lookahead time. The following table gives the ranges of the + move consideration times with Position Evaluation (below) on and off for + a 10 MHz PS/2 Model 30/286, in the format MM:SS. The true move time will + be different on different computers and will vary with the complexity of + the board configuration. + + POSITION EVALUATION OFF POSITION EVALUATION ON + PLYS Low Average High Low Average High + 0 0:00 0:00 0:00 0:00 0:00 0:01 + 1 0:00 0:00 0:01 0:00 0:01 0:02 + 2 0:00 0:01 0:01 0:01 0:03 0:05 + 3 0:01 0:07 0:13 0:05 0:15 0:45 + 4 0:06 0:45 2:55 0:19 1:20 4:25 + 5 around 8 minutes + 6 around 20 minutes + + Next you will be asked if "Position Evaluation" should be used in the + consideration of moves when the computer is looking for the best move. + This consideration is used to break 'ties' for best material score by + examining the formation of pieces, etc. and following a number of special + rules. (Please note that the rules followed and the positional score + generated are not very sound or scientific, and were designed by a definite + chess non-expert). The drawback to enabling option is that it may take + significantly more time for the computer to select a move (for technical + reasons). The default is to enable position evaluation, and this is + reflected in the conversation area by showing a "+" on the end of the + Machine Skill Level. + + Then, all of these same questions will be asked for the black player, and + after that, you will return to the main menu. + +N = New game + This option will set the pieces on the board to the startup formation of a + new game, update the move number and player status settings appropriately, + and will enter Play Move as if you had pressed RETURN. + +S = Setup board + Allows you to set up the pieces on the board how you wish. See the SETUP + MODE section below for more information. + +F = File system + Causes you to enter the file system. See the FILE SYSTEM section below. + + + +------------------------------------------------------------------------------- +PLAY MODE + +Accepts moves from the players, makes them, and continues until the game is +finished or the user presses ESCAPE to return to the main menu. The color and +name of the player whose move it is are displayed at the bottom of the screen +and the elapsed time of the player to move will tick away. + +Human Player: + +If the player to move is Human, then the cursor (green) will blink on the +game board and the computer will wait for the you to move the cursor, pick up +the piece that you want to move, and put it where you want to move it. To +move the cursor, use the cursor keys. The HOME, END, PAGE_UP, and PAGE_DOWN +keys are also active in moving the cursor. The will 'wrap-around' to the other +side of the board if you move it 'off' an edge. Move the cursor on top of the +piece you wish to move and then press RETURN or SPACE to pick it up. The +square will be displayed in the lower section of the conversation area. + +Then move the cursor to the position where you wish to move the piece and press +RETURN or SPACE. The full code for the move will be displayed in the +conversation area, and the computer will check if the move is valid. If it is +not, the computer will buzz and display "Invalid Move", and you will be put +back to the pick-up phase of selecting the move. If it is not obvious why the +move you attempted is invalid, see if moving the piece would result in you +being in check. (Please note that it is illegal to castle while in check and +it is illegal to castle "through" check). If you pick up a piece that you +decide you really do not want to move, press BACKSPACE to put it back down. + +In the event that the move you made was a pawn promotion, after displaying +the move, the computer will ask you which piece you wish to promote the pawn +to. You may press Q = Queen, R = Rook, B = Bishop, or N = kNight. The piece +will then be promoted. + +The following keys may also be used when you are entering your move: + +H = ask for Hint + Will ask the computer to suggest a move for you to make. This move will be + generated using the skill level and position evaluation setting for the + human player. The computer will display "Thinking" and will show the + suggested move a short (or long) time later. You may enter this suggestion + as above, or you may use your own choice of move. + +A = Attack/protect count + Will display the number of times the cursor square is attacked (threatened) + by enemy pieces and protected by friendly pieces. This is provided to + let you make sure you are not failing to notice that a square is attacked + or protected. + +C = Check move list + Will display the list of all of your possible moves on the screen. Press + any key after you are finished viewing the list to return to entering your + move. + +Machine Player: + +If the player to move is Machine, the computer will think about its move for +a period of time and will finally make the move. While it's thinking, it will +display the 'best' move it has found so far and that move's Score, EnemyScore, +and Positional Score. The EnemyScore is the highest score that the computer +thinks its enemy can achieve after the computer makes the move that it is +currently showing as best. For skill levels of three and above, the computer +will also display a Scan countdown (the number of moves left to analyze) and +will begin its analysis with a 'PreScan'. The written report for this project +goes into detail on exactly how the computer 'thinks'. + +If you get tired of waiting for the computer to think of its move, you may +press the M key to force the computer to make the best move it has found so +far. This key (and the ESCAPE key) is checked only when the scan count is +updated, so it may take a little time for the computer to react to your +pressing the key. BE PATIENT. If the computer is taking too long to think, +you may wish to use the Player Info option in the main menu to lower the +lookahead for the Machine player. + +------------------------------------------------------------------------------- +SETUP MODE + +This mode allows you to set the pieces on the board as you wish. The only +restrictions are that there must be exactly one king on the board for each +player and they cannot both be in check, and a pawn cannot be placed on row one +or row eight. Move the cursor around the board with the cursor keys to a +square that you wish to modify. Then use one of the following keys to place +the piece: K = King, Q = Queen, R = Rook, B = Bishop, N = kNight, P = Pawn, and +SPACE = . If you type SPACE, whatever was under the cursor will +disappear; otherwise, if you typed one of the other keys, the cursor will +disappear and you will be asked for the color of the piece you wish to add. +Type B for Black or W for White. + +If you are placing a king or a rook it its 'home' position, the computer will +ask you if the piece has moved from its starting position since the start of +the game. This is necessary for the computer to know if castling is still +possible. This question will not be asked for other pieces. Now, the new +piece will be displayed on the board under the cursor. You may move the cursor +to the next place you wish to put the next piece. + +If you wish to clear the entire board to start from scratch, press the C key. +If you wish to set pieces on the board to their startup positions, press the D +key (Default). + +When you are finished modifying the board, press RETURN to accept the setup. +You will then be asked for the current move number and then the player who is +to move next. Enter these values and use BACKSPACE to delete the current +value. After this, you will be returned to the main menu. Note that all of +the previous moves of the current game (if there are any) will be lost, and the +setup you have input will be considered as the opening board configuration. + +If you entered setup mode accidentally or you are not satisfied with the setup +you have created, you may press ESCAPE to exit back to the main menu and +restore the board configuration that was present before you entered Setup mode. + +------------------------------------------------------------------------------- +FILE SYSTEM + +The file system allows you to Load, Save, or Print out the current game, or +obtain a listing of all of the chess games in the current directory. The +options are selected with the following keys: + +ESC = return to main menu + +L = Load game + The chess board will clear and you will be asked for the name of the game + (file) to load into memory. Press RETURN to use the default filename or + use BACKSPACE and then type in another name. Note that although all games + are saved with a ".CHS" extension, you do not have to type this. After you + have entered the filename, the game will load and the final board position + will be displayed, or the message "I/O Error" will be displayed if + something went wrong. Press a key for the latter case. + +S = Save current game + The chess board will clear and you will be asked for the name to save the + current game under. Press RETURN to use the default filename or use + BACKSPACE and then type in another name. Although chess games are saved + with a ".CHS" extension, you do not have to type this. The game will then + be saved and you will return to the file menu. If anything went wrong, + "I/O Error" will be displayed; press a key to continue. + +P = Print out current game + You will be asked for the filename to print the output for the game to. + The default of "PRN" (the DOS standard printer) will be shown. You may + change this filename if you wish (to print to a disk file). The listing + will then be printed, and "I/O Error" will be displayed if something went + wrong. The listing will show all of the moves of the game and a + representation of the final board setup. + +D = show Directory listing of chess games + The screen will clear and the directory will be displayed. Press RETURN + after viewing the listing to return to the File Menu. Note that this + option calls the DOS program "COMMAND.COM" and it must be found either in + the current directory or in some directory in the PATH environmental + variable. Also, the COMMAND.COM found MUST be for the same version of DOS + that the system was booted up under, or an error may be displayed or the + system may simply crash. MAKE SURE that the chess program is installed to + use a good COMMAND.COM or do not use this option. + +------------------------------------------------------------------------------- +USER INPUT MODE + +The design objective of the User Input subroutine was simplicity of +implementation, and thus, it is fairly limited. When you are put into User +Input mode by Player Info, set Options, Filename, or other places in the +program, the only editing key that you may use is BACKSPACE (like DOS input). +This key will delete the last character of the input string and move the cursor +back one position. Usually when input mode is entered, a default string is +provided. If you wish to change the default or enter something entirely +different, you will have to BACKSPACE out what you don't want before you type +in what you do want. + +To type in new characters, simply type the key. Only the letter keys, number +keys, and a few punctuation keys are accepted. The new character will be +displayed and the cursor will move one space to the right. If this does not +happen, then you have reached the limit of the number of characters you are +allowed to input. You may still use BACKSPACE if you wish. + +When you are finished entering the string (or you have not made any changes to +the default string and you wish to use it), press RETURN. This will end the +User Input Mode and the string you have entered will be given to the computer +and processed. + +------------------------------------------------------------------------------- +FINAL NOTE + +To the best of our knowledge, this program is completely free of bugs; however, +of course, it is impossible to guarantee this. If you find any errors in this +program, we would like to know about them. Thank you much. + + - Craig Bruce & Kevin Phillips, 06-Apr-90. \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/IMAGE.EXE b/Borland Turbo Pascal v55/chess/IMAGE.EXE new file mode 100644 index 0000000000000000000000000000000000000000..e4ec0d461312a66ff4a0497b5616abeba0e6035c GIT binary patch literal 20624 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 Ay8r+H literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/chess/IMAGE.PAS b/Borland Turbo Pascal v55/chess/IMAGE.PAS new file mode 100644 index 0000000..71a8f63 --- /dev/null +++ b/Borland Turbo Pascal v55/chess/IMAGE.PAS @@ -0,0 +1,89 @@ +{****************************************************************************} +{* Get Images: this is not part of the chess program. This program reads *} +{* the text file "PIECES.PAS" and converts the piece images found there *} +{* into a format compatible with Turbo Pascal's GetImage and PutImage *} +{* graphics routines, such that the images can be displayed on the screen *} +{* quickly. The output file "PIECES.IMG" from this program is read in *} +{* when the chess program starts. To change the piece images, edit the *} +{* PIECES.PAS file and then execute this program. *} +{****************************************************************************} + +program GetImages; + uses graph, crt; + const HIGH = 52; WIDE = 52; OFFY = 100; OFFX = 10; SiImageSize = 1500; + type PieceType = (P_BLANK, P_PAWN, P_BISHOP, P_KNIGHT, P_ROOK, P_QUEEN, + P_KING); + PieceColorType = (C_WHITE, C_BLACK); + SquareColorType = (S_LIGHT, S_DARK, S_CURSOR); + SingleImageType = array [1..SiImageSize] of byte; + ImageType = array [PieceType, PieceColorType, SquareColorType] + of SingleImageType; + var GraphDriver, GraphMode :integer; + i,j,c :integer; + InLn :string[80]; + InFile :TEXT; + OutFile : file of ImageType; + ImageStore :ImageType; + CurPiece :PieceType; + schar :char; + begin + GraphDriver := VGA; + GraphMode := VGAHi; + InitGraph (GraphDriver, GraphMode, ''); + assign (InFile, 'PIECES.TXT'); + reset (InFile); + readln (InFile, InLn); + CurPiece := P_BLANK; + for c := 0 to 6 do begin + readln (InFile, InLn); + readln (InFile, InLn); + SetFillStyle (SolidFill, LightGray); + Bar (OFFX+c*WIDE,OFFY,OFFX+c*WIDE+WIDE-1,OFFY+HIGH-1); + Bar (OFFX+c*WIDE,OFFY+HIGH*2,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*3-1); + SetFillStyle (SolidFill, Brown); + Bar (OFFX+c*WIDE,OFFY+HIGH,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*2-1); + Bar (OFFX+c*WIDE,OFFY+HIGH*3,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*4-1); + SetFillStyle (SolidFill, LightGreen); + Bar (OFFX+c*WIDE,OFFY+HIGH*4,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*5-1); + Bar (OFFX+c*WIDE,OFFY+HIGH*5,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*6-1); + for i := 1 to HIGH do begin + readln (InFile, InLn); + InLn := copy (InLn, 5, 52); + for j := 0 to WIDE-1 do begin + if copy (InLn,j+1,1) = '*' then begin + PutPixel (OFFX+j+c*WIDE,OFFY+i,White); + PutPixel (OFFX+j+c*WIDE,OFFY+i+HIGH,White); + PutPixel (OFFX+j+c*WIDE,OFFY+i+HIGH*2,Black); + PutPixel (OFFX+j+c*WIDE,OFFY+i+HIGH*3,Black); + PutPixel (OFFX+j+c*WIDE,OFFY+i+HIGH*4,White); + PutPixel (OFFX+j+c*WIDE,OFFY+i+HIGH*5,Black); + end; + end; + end; + GetImage (OFFX+c*WIDE,OFFY,OFFX+c*WIDE+WIDE-1,OFFY+HIGH-1, + ImageStore[CurPiece, C_WHITE, S_LIGHT]); + GetImage (OFFX+c*WIDE,OFFY+HIGH*2,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*3-1, + ImageStore[CurPiece, C_BLACK, S_LIGHT]); + GetImage (OFFX+c*WIDE,OFFY+HIGH,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*2-1, + ImageStore[CurPiece, C_WHITE, S_DARK]); + GetImage (OFFX+c*WIDE,OFFY+HIGH*3,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*4-1, + ImageStore[CurPiece, C_BLACK, S_DARK]); + GetImage (OFFX+c*WIDE,OFFY+HIGH*4,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*5-1, + ImageStore[CurPiece, C_WHITE, S_CURSOR]); + GetImage (OFFX+c*WIDE,OFFY+HIGH*5,OFFX+c*WIDE+WIDE-1,OFFY+HIGH*6-1, + ImageStore[CurPiece, C_BLACK, S_CURSOR]); + readln (InFile, InLn); + if CurPiece <> P_KING then + CurPiece := succ(CurPiece); + end; + close (InFile); + assign (outFile, 'PIECES.IMG'); + rewrite (OutFile); + write (OutFile, ImageStore); + close (OutFile); + SetTextStyle (DefaultFont, HorizDir, 2); + OutTextXY (0,0,'Press any key to continue...'); + schar := ReadKey; + RestoreCrtMode; + end. + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/INIT.PAS b/Borland Turbo Pascal v55/chess/INIT.PAS new file mode 100644 index 0000000..32d2574 --- /dev/null +++ b/Borland Turbo Pascal v55/chess/INIT.PAS @@ -0,0 +1,124 @@ +{****************************************************************************} +{* INIT.PAS: this file contains the routines which initialize the global *} +{* variables. *} +{****************************************************************************} + +{****************************************************************************} +{* Init Possible Moves: put the constant values into the data structure *} +{* which gives the possible moves for each piece, the point values for *} +{* capturing enemy pieces, and the opposite color to the given one. *} +{****************************************************************************} + procedure InitPossibleMoves; + var index: integer; + begin + PossibleMoves [BISHOP].NumDirections := 4; + PossibleMoves [BISHOP].MaxDistance := 7; + PossibleMoves [BISHOP].UnitMove[1].DirRow := 1; + PossibleMoves [BISHOP].UnitMove[1].DirCol := -1; + PossibleMoves [BISHOP].UnitMove[2].DirRow := 1; + PossibleMoves [BISHOP].UnitMove[2].DirCol := 1; + PossibleMoves [BISHOP].UnitMove[3].DirRow := -1; + PossibleMoves [BISHOP].UnitMove[3].DirCol := -1; + PossibleMoves [BISHOP].UnitMove[4].DirRow := -1; + PossibleMoves [BISHOP].UnitMove[4].DirCol := 1; + PossibleMoves [KNIGHT].NumDirections := 8; + PossibleMoves [KNIGHT].MaxDistance := 1; + PossibleMoves [KNIGHT].UnitMove[1].DirRow := 1; + PossibleMoves [KNIGHT].UnitMove[1].DirCol := -2; + PossibleMoves [KNIGHT].UnitMove[2].DirRow := 2; + PossibleMoves [KNIGHT].UnitMove[2].DirCol := -1; + PossibleMoves [KNIGHT].UnitMove[3].DirRow := 2; + PossibleMoves [KNIGHT].UnitMove[3].DirCol := 1; + PossibleMoves [KNIGHT].UnitMove[4].DirRow := 1; + PossibleMoves [KNIGHT].UnitMove[4].DirCol := 2; + PossibleMoves [KNIGHT].UnitMove[5].DirRow := -1; + PossibleMoves [KNIGHT].UnitMove[5].DirCol := 2; + PossibleMoves [KNIGHT].UnitMove[6].DirRow := -2; + PossibleMoves [KNIGHT].UnitMove[6].DirCol := 1; + PossibleMoves [KNIGHT].UnitMove[7].DirRow := -2; + PossibleMoves [KNIGHT].UnitMove[7].DirCol := -1; + PossibleMoves [KNIGHT].UnitMove[8].DirRow := -1; + PossibleMoves [KNIGHT].UnitMove[8].DirCol := -2; + PossibleMoves [ROOK].NumDirections := 4; + PossibleMoves [ROOK].MaxDistance := 7; + PossibleMoves [ROOK].UnitMove[1].DirRow := 1; + PossibleMoves [ROOK].UnitMove[1].DirCol := 0; + PossibleMoves [ROOK].UnitMove[2].DirRow := 0; + PossibleMoves [ROOK].UnitMove[2].DirCol := -1; + PossibleMoves [ROOK].UnitMove[3].DirRow := 0; + PossibleMoves [ROOK].UnitMove[3].DirCol := 1; + PossibleMoves [ROOK].UnitMove[4].DirRow := -1; + PossibleMoves [ROOK].UnitMove[4].DirCol := 0; + PossibleMoves [QUEEN].NumDirections := 8; + PossibleMoves [QUEEN].MaxDistance := 7; + PossibleMoves [KING].NumDirections := 8; + PossibleMoves [KING].MaxDistance := 1; + for index := 1 to 4 do begin + PossibleMoves [QUEEN].UnitMove[index] := PossibleMoves [BISHOP].UnitMove[index]; + PossibleMoves [KING].UnitMove[index] := PossibleMoves [BISHOP].UnitMove[index]; + end; + for index := 1 to 4 do begin + PossibleMoves [QUEEN].UnitMove[index + 4] := PossibleMoves [ROOK].UnitMove[index]; + PossibleMoves [KING].UnitMove[index + 4] := PossibleMoves [ROOK].UnitMove[index]; + end; + + CapturePoints[BLANK] := 0; + CapturePoints[PAWN] := 10; + CapturePoints[KNIGHT] := 35; + CapturePoints[BISHOP] := 35; + CapturePoints[ROOK] := 50; + CapturePoints[QUEEN] := 90; + CapturePoints[KING] := 2000; + + EnemyColor[C_WHITE] := C_BLACK; + EnemyColor[C_BLACK] := C_WHITE; + end; + +{****************************************************************************} +{* Startup Initialize: set the default player info and options, and set *} +{* valid and invalid squares of the board. *} +{****************************************************************************} + procedure StartupInitialize; + var row, col: RowColType; + begin + Randomize; + InitPossibleMoves; + DefaultFileName := 'EXAMPLE'; + + {*** default options ***} + Game.TimeLimit := 0; + Game.EnPassentAllowed := true; + Game.SoundFlag := true; + Game.FlashCount := 2; + Game.WatchDelay := 600; + + {*** default player attributes ***} + with Player[C_WHITE] do begin + Name := 'PERSON'; + IsHuman := true; + LookAhead := 3; + PosEval := false; + end; + with Player[C_BLACK] do begin + Name := 'COMPUTER'; + IsHuman := false; + LookAhead := 3; + PosEval := false; + end; + + {*** initialize board ***} + for col := -1 to 10 do + for row := -1 to 10 do + with Board[row, col] do begin + image := BLANK; + color := C_WHITE; + HasMoved := false; + ValidSquare := false; + end; + for col := 1 to BOARD_SIZE do + for row := 1 to BOARD_SIZE do + Board[row, col].ValidSquare := true; + end; + +{*** end of INIT.PAS include file ***} + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/INPUT.PAS b/Borland Turbo Pascal v55/chess/INPUT.PAS new file mode 100644 index 0000000..885c532 --- /dev/null +++ b/Borland Turbo Pascal v55/chess/INPUT.PAS @@ -0,0 +1,150 @@ +{****************************************************************************} +{* INPUT.PAS: this file contains the routines which involve direct *} +{* input from the keyboard. *} +{****************************************************************************} + +{****************************************************************************} +{* Get Key: return the code for the key the user just typed, or a special *} +{* code if no keys have been typed. Letters are converted to uppercase *} +{* and the uppercase letter is returned. Numbers and punctuation are *} +{* returned exactly. The special codes for special keys follows: *} +{* *} +{* CODE KEY CODE KEY CODE KEY *} +{* 'u' Cursor Up 'i' Page Up 'e' Return *} +{* 'd' Cursor Down 'j' Home 'x' Escape *} +{* 'l' Cursor Left 'k' End 'b' Backspace *} +{* 'r' Cursor Right 'm' Page Down 'n' *} +{****************************************************************************} + function GetKey : char; + var key : char; + begin + if KeyPressed then begin + key := ReadKey; + if key = chr(0) then begin + key := ReadKey; + {*** special two-character keyboard codes ***} + case key of + 'H': key := 'u'; + 'P': key := 'd'; + 'K': key := 'l'; + 'M': key := 'r'; + 'I': key := 'i'; + 'Q': key := 'm'; + 'G': key := 'j'; + 'O': key := 'k'; + else + key := 'n'; + end; + GetKey := key; + end else begin + if (key >='a') and (key <='z') then + {*** letters to uppercase ***} + GetKey := chr (ord(key) - ord('a') + ord('A')) + else begin + {*** handle special single-character keyboard codes ***} + case key of + #8 : key := 'b'; + #13: key := 'e'; + #27: key := 'x'; + end; + GetKey := key; + end; + end; + end else + GetKey := 'n'; {*** no key pressed ***} + end; + +{****************************************************************************} +{* Move Cursor: moves the 'cursor' around the game board until the user *} +{* types a non-cursor key. Takes the location to initially display the *} +{* cursor and returns the final location of the cursor and the non-cursor *} +{* key that was typed. The Update and Color parameters tell if and whose *} +{* elapsed time is to be updated while waiting for a key. *} +{****************************************************************************} + procedure MoveCursor (var row, col : RowColType; Color : PieceColorType; + Update : boolean; var OutChar : char); + var key : char; + begin + OutChar := '@'; + repeat + {*** flash the cursor until a key is pressed ***} + repeat + if not KeyPressed then begin + DisplaySquare (row, col, true); + if not KeyPressed then + Delay (30); + DisplaySquare (row, col, false); + if not KeyPressed then + Delay (30); + end; + key := GetKey; + + {*** update player's elapsed time ***} + if UpDate then + UpDateTime (Color); + until key <> 'n'; + + {*** if cursor key, move cursor; else exit ***} + case key of + 'j': col := 1; + 'k': col := BOARD_SIZE; + 'i': row := BOARD_SIZE; + 'm': row := 1; + 'u': row := row mod BOARD_SIZE + 1; + 'd': row := (row + BOARD_SIZE -2) mod BOARD_SIZE + 1; + 'l': col := (col + BOARD_SIZE -2) mod BOARD_SIZE + 1; + 'r': col := col mod BOARD_SIZE + 1; + else OutChar := key; + end; + until OutChar <> '@'; + end; + +{****************************************************************************} +{* User Input: given the pixel location, prompt, default value and maximum *} +{* length, input a string from the user on the hires screen. The only *} +{* editing key is Backspace. Pressing Return terminates the input. *} +{****************************************************************************} + procedure UserInput (Xpos, Ypos, LenLim: integer; Prompt: string80; var InStr: string80); + var Key : char; + + function Input : char; + var Key : char; + begin + repeat + while not KeyPressed do; + Key := GetKey; + until Key in ['A'..'Z', '0'..'9', '!', '-', '.', 'b', 'e', ' ', ':']; + Input := Key; + end; + + begin + {*** display prompt, default input string, and cursor ***} + MoveTo (Xpos, Ypos); + OutText (Prompt + InStr + '_'); + Key := Input; + while (Key <> 'e') do begin + if (Key = 'b') then begin + {*** backspace: move cursor back and delete last character ***} + if (length (InStr) > 0) then begin + InStr := copy (InStr, 1, length (InStr) -1); + Bar (GetX - 32, GetY, GetX, GetY + 15); + MoveTo (GetX - 32, GetY); + OutText ('_'); + end; + end else + {*** new char: display and move cursor ***} + if (length (InStr) < LenLim) then begin + Bar (GetX - 16, GetY, GetX, GetY + 15); + MoveTo (GetX - 16, GetY); + OutText (Key); + InStr := InStr + Key; + OutText ('_'); + end; + Key := Input; + end; + {*** erase cursor after input ***} + Bar (GetX - 16, GetY, GetX, GetY + 15); + end; + +{*** end of INPUT.PAS include file ***} + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/MENU.PAS b/Borland Turbo Pascal v55/chess/MENU.PAS new file mode 100644 index 0000000..27e9af2 --- /dev/null +++ b/Borland Turbo Pascal v55/chess/MENU.PAS @@ -0,0 +1,636 @@ +{****************************************************************************} +{* MENU.PAS: this include file contains the routines which implement the *} +{* main menu of the game. *} +{****************************************************************************} + +{****************************************************************************} +{* Online Help: Display the information in the help file. The user is *} +{* allowed to move up and down by pages, and to exit back to the main *} +{* program. The file on the disk is in the format of 22 strings to a *} +{* page, where each string is displayed on one line of the help screen. *} +{* I/O error checking is performed to react properly if something goes *} +{* wrong. *} +{****************************************************************************} + procedure OnlineHelp; + var Page : HelpPageType; {*** currently displayed page data ***} + key : char; + HelpFile : file of HelpPageType; + i : integer; + PageNum, PageLim : longint; + SeparatorLine : string80; {*** a line of the separator character ***} + IOerror : boolean; + + begin + {*** initialize and open help file ***} + SeparatorLine := ''; + for i := 1 to 79 do SeparatorLine := SeparatorLine + #205; + assign (HelpFile, 'CHESS.HLP'); + reset (HelpFile); + IOerror := IOResult <> 0; + if not IOerror then begin + {*** read and display the current help page ***} + PageNum := 1; + PageLim := FileSize (HelpFile); + repeat + Seek (HelpFile, PageNum - 1); + read (HelpFile, Page); + IOerror := IOResult <> 0; + if not IOerror then begin + ClrScr; + TextColor (Green); + write ('Help. Use PAGE_UP and PAGE_DOWN to view and ESC to exit.'); + writeln (' Page ', PageNum, ' of ', PageLim, '.'); + writeln(SeparatorLine); + TextColor (LightGray); + for i := 1 to 22 do writeln (Page[i]); + TextColor (Green); + write (SeparatorLine); + TextColor (LightGray); + {*** get user input ***} + repeat + key := GetKey; + until key in ['i', 'm', 'x', ' ', 'e']; + case key of + 'i': if PageNum > 1 then PageNum := PageNum - 1; + 'm', ' ', 'e': if PageNum < PageLim then + PageNum := PageNum + 1; + end; + end; + until (key = 'x') or IOerror; + end; + {*** report error if one ***} + if IOerror then begin + ClrScr; + write ('IO error trying to access "CHESS.HLP". Press key...'); + key := ReadKey; + end else + close (HelpFile); + end; + +{****************************************************************************} +{* Get Player Color Info: Inputs from the user all of the attributes for *} +{* the player of the given color. This routine is called for each player *} +{* by the main menu routine when Set Player Info is selected. The pixel *} +{* location of where to start the input block is given. *} +{****************************************************************************} + procedure GetPlayerColorInfo (Color : PieceColorType; Xpos, Ypos : integer); + var TempStr : string80; {*** for user input ***} + Error : integer; + Level : integer; + + begin + {*** display player's color ***} + if (Color = C_WHITE) then + OutTextXY (Xpos - 24, Ypos - 20, 'WHITE') + else + OutTextXY (Xpos - 24, Ypos - 20, 'BLACK'); + + {*** get player's name; default is present name ***} + TempStr := Player[Color].Name; + UserInput (Xpos, Ypos, 11,'Name: ', TempStr); + Player[Color].Name := TempStr; + + {*** get player's elapsed time ***} + TempStr := TimeString (Player[Color].ElapsedTime); + UserInput (Xpos, Ypos+20, 8, 'Elapsed Time: ', TempStr); + Player[Color].ElapsedTime := StringToTime (TempStr); + + {*** get player's type (Human / Machine) ***} + if Player[Color].IsHuman then TempStr := 'H' else TempStr := 'M'; + UserInput (Xpos, Ypos+40, 1, 'Player Type (H/M): ', TempStr); + Player[Color].IsHuman := (TempStr = 'H'); + + {*** get player's lookahead ply count, set to 3 if error ***} + Str (Player[Color].LookAhead, TempStr); + UserInput (Xpos, Ypos+60, 1, 'Look Ahead (0-9): ', TempStr); + Val (TempStr, Level, Error); + if (Error = 0) then + Player[Color].LookAhead := Level + else + Player[Color].LookAhead := 3; + + {*** get player's position evaluation setting ***} + if Player[Color].PosEval then TempStr := 'Y' else TempStr := 'N'; + UserInput (Xpos, Ypos+80, 1, 'Evaluate Pos (Y/N): ', TempStr); + Player[Color].PosEval := (TempStr <> 'N'); + end; + +{****************************************************************************} +{* Get Options: Gets the values for the user settable options (global *} +{* variables) of the game. Called by the main menu. For numeric values, *} +{* if the entered value is in error, then a default is used. *} +{****************************************************************************} + procedure GetOptions (Xpos, Ypos: integer); + var TempStr: string80; {*** for user input ***} + Error: integer; + + begin + {*** set the number of times to flash a piece when it is moving ***} + Str (Game.FlashCount, TempStr); + UserInput (Xpos, Ypos, 1, 'Flash Count: ', TempStr); + Val (TempStr, Game.FlashCount, Error); + if (Error <> 0) then Game.FlashCount := 2; + + {*** set sound enable / disable ***} + if (Game.SoundFlag) then TempStr := 'Y' else TempStr := 'N'; + UserInput (Xpos, Ypos + 24, 1, 'Sound (Y/N): ', TempStr); + Game.SoundFlag := (TempStr <> 'N'); + + {*** set whether en passent move is to be allowed or not ***} + if Game.EnPassentAllowed then TempStr := 'Y' else TempStr := 'N'; + UserInput (Xpos, Ypos + 48, 1, 'En Passent (Y/N): ', TempStr); + Game.EnPassEntAllowed := (TempStr <> 'N'); + Str (Game.WatchDelay, TempStr); + + {*** set time to wait between displaying moves in watch mode ***} + UserInput (Xpos, Ypos + 72, 5, 'Watch Delay (ms): ', TempStr); + Val (TempStr, Game.WatchDelay, Error); + if (Error <> 0) or (Game.WatchDelay < 0) or (Game.WatchDelay > 30000) then + Game.WatchDelay := 700; + + {*** set the time limit for the game (00:00:00 means no time limit) ***} + TempStr := TimeString (Game.TimeLimit); + UserInput (Xpos, Ypos + 96, 8, 'Time Limit: ', TempStr); + Game.TimeLimit := StringToTime (TempStr); + end; + +{****************************************************************************} +{* Input File Name: Displays a title and asks the user to enter the name *} +{* of the file which is to be used for some operation, which is returned. *} +{* The default filename is provided to this routine. This routine is *} +{* called by Load Game, Save Game, and Print Game. *} +{****************************************************************************} + procedure InputFileName (Title : string80; var FileName : string80); + begin + DisplayInstructions (INS_FILE_INPUT); + SetFillStyle (SolidFill, DarkGray); + Bar (BOARD_X1, BOARD_Y1, BOARD_X2, BOARD_Y2); + SetColor (Yellow); + SetTextStyle (DefaultFont, HorizDir, 2); + OutTextXY (54, 20, Title); + UserInput (54, 70, 8, 'File Name: ', FileName); + end; + +{****************************************************************************} +{* Print Game: Prints a text file representation of the game. All of the *} +{* moves showing the turn number, color to move, piece moved, and piece *} +{* taken are printed, as well as the final board setup. The end of the *} +{* game is taken to be the board currently displayed on the screen (incase *} +{* the user has taken back moves and is not looking at the end of all the *} +{* moves made). The default output file is "PRN" which will print to the *} +{* printed; however, the user can change this name to print to a disk *} +{* file in standard DOS text file format. I/O error checking is performed *} +{* to respond to any errors. This routine is called from the file menu. *} +{****************************************************************************} + procedure PrintGame; + type string20 = string[20]; + var PrintFile : Text; {*** Turbo Pascal text file type ***} + i : integer; + PrintFileName : string80; + IOerror : boolean; + {*** conversions from internal piece type to external string names ***} + PieceName : array [PieceImageType] of string20; + PieceAbbrev : array [PieceImageType] of string20; + ColorName : string20; + MoveFromTo : string20; + PieceTakenStr : string20; + CurMoveNum : integer; + Movement : MoveType; + key : char; + +{----------------------------------------------------------------------------} +{ Dump Board: Prints out the text representation of the final board. } +{ Each entry in the matrix printed out shows the piece (K/Q/R/N/B/P) and } +{ color (B/W) of the piece occupying that square, or prints blanks if no } +{ piece. No error checking is performed in here (hopefully, the printer } +{ is still working after printing out the moves. } +{----------------------------------------------------------------------------} + procedure DumpBoard; + var row, col : RowColType; + SqDesc : string20; {*** square description ***} + LineDesc : string80; {*** accumulated output line ***} + + begin + writeln (PrintFile); + for row := BOARD_SIZE downto 1 do begin + {*** separator line ***} + writeln (PrintFile, ' +--+--+--+--+--+--+--+--+'); + LineDesc := ' |'; + for col := 1 to BOARD_SIZE do begin + {*** get square description ***} + SqDesc := PieceAbbrev [Board[row, col].image]; + if SqDesc = ' ' then + SqDesc := ' ' + else begin + if Board[row, col].color = C_WHITE then + SqDesc := SqDesc + 'W' + else + SqDesc := SqDesc + 'B'; + end; + {*** add square description to output line ***} + LineDesc := LineDesc + SqDesc + '|'; + end; + {*** flush line ***} + writeln (PrintFile, LineDesc); + end; + {*** print final separator line ***} + writeln (PrintFile, ' +--+--+--+--+--+--+--+--+'); + end; {DumpBoard} + +{----------------------------------------------------------------------------} + begin {PrintGame} + {*** set the names and abbreviations of the pieces ***} + PieceName[BLANK] := ' '; PieceAbbrev[BLANK] := ' '; + PieceName[PAWN] := 'Pawn '; PieceAbbrev[PAWN] := 'P'; + PieceName[KNIGHT] := 'Knight '; PieceAbbrev[KNIGHT] := 'N'; + PieceName[BISHOP] := 'Bishop '; PieceAbbrev[BISHOP] := 'B'; + PieceName[ROOK] := 'Rook '; PieceAbbrev[ROOK] := 'R'; + PieceName[QUEEN] := 'Queen '; PieceAbbrev[QUEEN] := 'Q'; + PieceName[KING] := 'King '; PieceAbbrev[KING] := 'K'; + + {*** get output file name and open it ***} + PrintFileName := 'PRN'; + InputFileName ('Print Game to File', PrintFileName); + assign (PrintFile, PrintFileName); + rewrite (PrintFile); + IOerror := IOResult <> 0; + if not IOerror then begin + writeln (PrintFile, 'Chess Game Listing - KC Chess'); + IOerror := IOResult <> 0; + end; + if not IOerror then begin + {*** print heading information ***} + writeln (PrintFile); + writeln (PrintFile, 'White: ', Player[C_WHITE].Name); + writeln (PrintFile, 'Black: ', Player[C_BLACK].Name); + writeln (PrintFile); + writeln (PrintFile, 'MOVE COLOR FROM/TO PIECE-MOVED PIECE-TAKEN'); + writeln (PrintFile); + i := 1; + {*** print each move; pad fields with blanks to make them line up ***} + while (not IOerror) and (i <= Game.MovesPointer) do begin + {*** move number and player to move ***} + CurMoveNum := i + (Game.MoveNum - 1 - Game.MovesPointer); + if CurMoveNum mod 2 = 1 then + ColorName := 'White' + else + ColorName := 'Black'; + + {*** move from/to and piece taken ***} + Movement := Game.Move[i]; + MoveFromTo := MoveStr (Movement); + if MoveFromTo = 'PxP EP' then + PieceTakenStr := 'Pawn ' + else + PieceTakenStr := PieceName[Movement.PieceTaken.image]; + MoveFromTo := MoveFromTo + Copy (' ', 1, 10-length(MoveFromTo)); + + {*** print move information ***} + writeln (PrintFile, (CurMoveNum + 1) div 2 : 4, ' ', ColorName, ' ', + MoveFromTo, PieceName[Movement.PieceMoved.image], PieceTakenStr); + IOerror := IOResult <> 0; + i := i + 1; + end; + {*** print final board ***} + DumpBoard; + close (PrintFile); + end; + {*** report I/O error if any ***} + if IOerror then begin + OutTextXY (35, 200, 'I/O Error!! Press a key.'); + key := ReadKey; + end; + {*** redisplay the game board on the main screen after filename ***} + DisplayBoard; + end; {PrintGame} + +{****************************************************************************} +{* Load Game: Given the filename of the file which contains the game to *} +{* be loaded, load it and check for I/O errors. This routine is called *} +{* from the file menu. *} +{****************************************************************************} + procedure LoadGame (FileName: string80); + var GameFile: file of GameType; + LoadGame: GameType; {*** game loaded ***} + key: char; + IOError: boolean; + + begin + {*** open file using ".CHS" extension ***} + assign (GameFile, FileName + '.CHS'); + reset (GameFile); + IOError := true; + if IOResult = 0 then begin + {*** get new game ***} + read (GameFile, LoadGame); + if IOResult = 0 then begin + IOError := false; + close (GameFile); + end; + end; + if IOerror then begin + {*** report I/O error ***} + OutTextXY (35, 200, 'I/O Error!! Press a key.'); + key := ReadKey; + end else begin + {*** make the loaded game permanent only if there were no I/O errors ***} + Game := LoadGame; + {*** unpack these two variables from the game ***} + Player := Game.Player; + Board := Game.FinalBoard; + end; + end; {LoadGame} + +{****************************************************************************} +{* Save Game: Given the filename to use, writes the Game variable to it. *} +{* This routine is called from the file menu. *} +{****************************************************************************} + procedure SaveGame (FileName: string80); + var GameFile: file of GameType; + key: char; + IOError: boolean; + + begin + {*** pack the Player and Board variables into the Game structure ***} + Game.Player := Player; + Game.FinalBoard := Board; + {*** open file for write and check for errors ***} + assign (GameFile, FileName + '.CHS'); + rewrite (GameFile); + IOError := true; + if IOResult = 0 then begin + {*** save game ***} + write (GameFile, Game); + if IOResult = 0 then begin + IOError := false; + close (GameFile); + end; + end; + + {*** indicate if any I/O errors occured ***} + if IOError then begin + OutTextXY (35, 200, 'I/O Error!! Press a key.'); + key := ReadKey; + end; + end; {SaveGame} + +{****************************************************************************} +{* Watch Game: Display all of the moves in the current game, from the *} +{* current move of the game. If the current move is the last move of the *} +{* game, then the game is shown from the beginning. If the user presses *} +{* a key or if all of the moves have been displayed, this routine exits *} +{* back to the main menu. *} +{****************************************************************************} + procedure WatchGame; + var Movement : MoveType; + DummyScore : integer; + + begin + DisplayInstructions (INS_WATCH); + + {*** go to first move if currently on the last move of the game ***} + if Game.MovesPointer = Game.MovesStored then begin + GotoMove (Game.MoveNum - Game.MovesPointer); + DisplayBoard; + DisplayConversationArea; + end; + + {*** display until user hits key or all moves displayed ***} + while (GetKey = 'n') and (Game.MovesPointer < Game.MovesStored) do begin + Movement := Game.Move[Game.MovesPointer + 1]; + MakeMove (Movement, false, DummyScore); + DisplayMove (Movement); + DisplayWhoseMove; + Delay (Game.WatchDelay); + end; + end; + +{****************************************************************************} +{* User Goto Move: Inputs the move of the game that the user wants to go *} +{* to, and goes there. This routine is called from the main menu. *} +{****************************************************************************} + procedure UserGotoMove; + var NewMoveNum : integer; + TempStr : string80; + Error : integer; + begin + {*** instructions, clear board area ***} + DisplayInstructions (INS_GOTO); + SetFillStyle (SolidFill, DarkGray); + Bar (BOARD_X1, BOARD_Y1, BOARD_X2, BOARD_Y2); + SetColor (Yellow); + SetTextStyle (DefaultFont, HorizDir, 2); + OutTextXY (54, 20, 'Goto Move Number'); + + {*** get move number and convert to ply number if valid ***} + Str ((Game.MoveNum + 1) div 2, TempStr); + UserInput (54, 70, 4, 'Move Number: ', TempStr); + Val (TempStr, NewMoveNum, Error); + if Error = 0 then begin + NewMoveNum := NewMoveNum * 2 - 1; + + {*** get whose turn to go to within move ***} + if Game.MoveNum mod 2 = 1 then + TempStr := 'W' + else + TempStr := 'B'; + UserInput (54, 100, 1, 'Player''s Turn (B/W): ', TempStr); + if TempStr = 'B' then NewMoveNum := NewMoveNum + 1; + + {*** go to move ***} + GotoMove (NewMoveNum); + end; + + {*** redisplay main screen ***} + DisplayBoard; + DisplayConversationArea; + end; + +{****************************************************************************} +{* File System: Displays options available in the file menu and gets *} +{* user's selection. Available choices are: D = display Directory of all *} +{* chess games in current directory, L = Load game, S = Save game, *} +{* P = Print game, and ESC = return to main menu. This routine is called *} +{* by the main menu. *} +{****************************************************************************} + procedure FileSystem; + var Key : char; + begin + repeat + {*** instructions and get selection ***} + DisplayInstructions (INS_FILE); + while not KeyPressed do; + Key := Getkey; + case Key of + {*** directory ***} + 'D': begin + {*** go back to text mode (cf. hires graphics) ***} + RestoreCrtMode; + {*** execute the DIR command under MS-DOS command interpreter ***} + exec (fsearch('\command.com',getenv('PATH')), '/c dir *.CHS /p'); + {*** check errors ***} + if DosExitCode <> 0 then begin + write ('I/O Error!! Press a key.'); + key := ReadKey; + end; + {*** wait until user is finished looking ***} + write ('Press any key to return to KC Chess...'); + key := ReadKey; + {*** restore hires graphics mode and redisplay main screen ***} + SetGraphMode (GraphMode); + DisplayGameScreen; + end; + + {*** load ***} + 'L': begin + {*** get filename, load, redisplay board ***} + InputFileName ('Load Game', DefaultFileName); + LoadGame (DefaultFileName); + DisplayBoard; + DisplayConversationArea; + {*** force exit from file menu ***} + key := 'x'; + end; + + {*** save ***} + 'S': begin + {*** get filename, save, redisplay board ***} + InputFileName ('Save Game', DefaultFileName); + SaveGame (DefaultFileName); + DisplayBoard; + {*** force exit from file menu ***} + key := 'x'; + end; + + {*** print ***} + 'P': PrintGame; + end; + until Key = 'x'; + end; + + +{****************************************************************************} +{* Main Menu: Display main menu instructions, get selection, and perform. *} +{* This routine is called directly from the main routine and represents *} +{* all of the time that the user is actually using the game. *} +{****************************************************************************} + procedure MainMenu; + var key : char; + Movement: MoveType; + DummyScore : integer; + + begin + DisplayInstructions (INS_MAIN); + repeat + key := GetKey; + case key of + {*** RETURN = continue current game ***} + 'e': begin + PlayGame; + DisplayWhoseMove; {*** display finish reason ***} + DisplayInstructions (INS_MAIN); + end; + + {*** N = setup board for New game ***} + 'N': begin + DefaultBoard; + DisplayBoard; + DisplayConversationArea; + PlayGame; + DisplayWhoseMove; + DisplayInstructions (INS_MAIN); + end; + + {*** S = Setup custom board configuration ***} + 'S': begin + SetupBoard; + DisplayInstructions (INS_MAIN); + end; + + {*** T = Take back move ***} + 'T': begin + UnMakeMove (Movement); + Game.GameFinished := false; + DisplayUnMadeMove (Movement); + end; + + {*** U = Un-takeback move; only if not currently at end of game ***} + 'U': if Game.MovesPointer < Game.MovesStored then begin + {*** get the stored next move ***} + Movement := Game.Move[Game.MovesPointer + 1]; + {*** make the move and display it ***} + MakeMove (Movement, false, DummyScore); + DisplayMove (Movement); + DisplayWhoseMove; + end; + + {*** P = set Player info ***} + 'P': begin + DisplayInstructions (INS_PLAYER); + {*** clear the board area ***} + SetFillStyle (SolidFill, DarkGray); + Bar (BOARD_X1, BOARD_Y1, BOARD_X2, BOARD_Y2); + SetColor (Yellow); + SetTextStyle (DefaultFont, HorizDir, 2); + {*** title, get info for each player ***} + OutTextXY (54, 20, 'Player Info'); + GetPlayerColorInfo (C_WHITE, 54, 90); + GetPlayerColorInfo (C_BLACK, 54, 255); + {*** redisplay board and new player info ***} + DisplayBoard; + DisplayConversationArea; + DisplayInstructions (INS_MAIN); + end; + + {*** O = set game Options ***} + 'O': begin + DisplayInstructions (INS_OPTIONS); + {*** clear board area ***} + SetFillStyle (SolidFill, DarkGray); + Bar (BOARD_X1, BOARD_Y1, BOARD_X2, BOARD_Y2); + SetColor (Yellow); + SetTextStyle (DefaultFont, HorizDir, 2); + {*** title and get options ***} + OutTextXY (44, 20, 'Options'); + GetOptions (44, 90); + {*** redisplay board and new options ***} + DisplayBoard; + DisplayConversationArea; + DisplayInstructions (INS_MAIN); + end; + + {*** G = Go to move ***} + 'G': begin + UserGotoMove; + DisplayInstructions (INS_MAIN); + end; + + {*** W = Watch game ***} + 'W': begin + WatchGame; + DisplayInstructions (INS_MAIN); + end; + + {*** F = enter File menu ***} + 'F': begin + FileSystem; + DisplayInstructions (INS_MAIN); + end; + + {*** H = Help ***} + 'H': begin + {*** go back to text mode (cf. hires graphics) ***} + RestoreCrtMode; + {*** display help information ***} + OnlineHelp; + {*** restore hires graphics mode and redisplay screen ***} + SetGraphMode (GraphMode); + DisplayGameScreen; + DisplayInstructions (INS_MAIN); + end; + end; + until key = 'Q'; + end; + +{*** end of MENU.PAS include file ***} + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/MISC.PAS b/Borland Turbo Pascal v55/chess/MISC.PAS new file mode 100644 index 0000000..518bbf4 --- /dev/null +++ b/Borland Turbo Pascal v55/chess/MISC.PAS @@ -0,0 +1,154 @@ +{****************************************************************************} +{* MISC.PAS: This file contains functions which do miscellaneous things. *} +{* Many of them return the output string representation of some variable. *} +{****************************************************************************} + +{****************************************************************************} +{* Sq Str: Returns the string representation of the square for the given *} +{* row and column (eg. row = 3, col = 5 would return "C5"). *} +{****************************************************************************} + function SqStr (row, col : RowColType) : string2; + begin + SqStr := copy(COL_NAMES,col,1) + copy(ROW_NAMES,row,1); + end; {SqStr} + +{****************************************************************************} +{* Move Str: Returns the string representation of the given move. The *} +{* general format is the algebraic notation - *} +{* (eg. "A5-C7"). A take (capture) is represented using an "x" instead *} +{* of the "-" (eg. "A5xC7"). Castling to the left (queen's) side is *} +{* "O-O-O" and to the right is "O-O". En passent is represented "PxP EP". *} +{* The NULL_MOVE is represented "". *} +{****************************************************************************} + function MoveStr (Movement : MoveType) : string10; + var bstr : string10; + begin + if Movement.FromRow = NULL_MOVE then + MoveStr := '' + else begin + if (Movement.PieceMoved.image = KING) and (abs (Movement.FromCol - Movement.ToCol) > 1) then begin + {*** handle castling ***} + if (Movement.FromCol > Movement.ToCol) then + MoveStr := 'O-O-O' + else + MoveStr := 'O-O'; + end else begin + {*** check if en passent ***} + if (Movement.PieceMoved.image = PAWN) and (Movement.FromCol <> Movement.ToCol) + and (Movement.PieceTaken.image = BLANK) then + MoveStr := 'PxP EP' + else begin + {*** regular move, push or take ***} + bstr := SqStr (Movement.FromRow, Movement.FromCol); + if Movement.PieceTaken.image = BLANK then + bstr := bstr + '-' + else + bstr := bstr + 'x'; + MoveStr := bstr + SqStr (Movement.ToRow, Movement.ToCol); + end; + end; + end; + end; {MoveStr} + +{****************************************************************************} +{* Time String: Returns the "HH:MM:SS" representation of the given time *} +{* (a 32-bit integer telling giving the number of seconds from zero). *} +{****************************************************************************} + function TimeString (InTime : longint) : string80; + const TIME_BASE : longint = 60; {*** 60 sec/min, 60 min/hr; force constant to be longint ***} + var Hours, Min, Sec: integer; + Time: longint; + +{----------------------------------------------------------------------------} +{ Pad Str: Returns the two-digit zero-padded string representation of the } +{ given number. (Used to make the HH, MM, and SS components of the time } +{ string two digits each. } +{----------------------------------------------------------------------------} + function PadStr (Num : integer) : string2; + var Temp: string2; + + begin + Str (Num, Temp); + if (length (Temp) = 1) then Temp := '0' + Temp; + PadStr := Temp; + end; {PadStr} + +{----------------------------------------------------------------------------} + begin {TimeString} + {*** assign given time to destructable local variable ***} + Time := InTime; + {*** extract number of seconds ***} + Sec := Time mod TIME_BASE; + {*** extract number of minutes ***} + Time := Time div TIME_BASE; + Min := Time mod TIME_BASE; + {*** extract number of hours ***} + Hours := Time div TIME_BASE; + {*** convert to string ***} + TimeString := PadStr (Hours) + ':' + PadStr (Min) + ':' + PadStr (Sec); + end; {TimeString} + +{****************************************************************************} +{* String To Time: Returns the number of seconds past zero of the given *} +{* string of format "HH:MM:SS". Also checks for conversion errors. This *} +{* routine is the complement of TimeString. *} +{****************************************************************************} + function StringToTime (Str : string80) : longint; + const SECS_IN_HOUR : longint = 3600; + SECS_IN_MIN : longint = 60; + var Hour, Min, Sec, ValError : integer; + TimeError : boolean; + + begin + TimeError := true; + {*** extract the Hour, Min, and Sec variables from the string ***} + if length(Str) = 8 then begin + Val (copy (Str, 1, 2), Hour, ValError); + if ValError = 0 then begin + Val (copy (Str, 4, 2), Min, ValError); + if ValError = 0 then begin + Val (copy (Str, 7, 2), Sec, ValError); + if ValError = 0 then TimeError := false; + end; + end; + end; + + if TimeError then + {*** if error, return zero seconds ***} + StringToTime := 0 + else + {*** return number of seconds ***} + StringToTime := (Hour * SECS_IN_HOUR) + (Min * SECS_IN_MIN) + Sec + end; {StringToTime} + +{****************************************************************************} +{* Elapsed Time: Return number of seconds according to the internal DOS *} +{* time of day clock since this routine was last called. Used to update *} +{* the elapsed time for each player. *} +{****************************************************************************} + function ElapsedTime: longint; + const SECONDS_IN_DAY : longint = 86400; {*** interestingly, this is also Mr. Phillips' student number ***} + SECONDS_IN_HOUR : longint = 3600; + SECONDS_IN_MINUTE : longint = 60; + var Hours, Min, Sec, Hundredths: word; + CurrentTime: longint; + {*** LastTime is a global variable which tells the last time this routine was called ***} + + begin + {*** read DOS clock time ***} + GetTime (Hours, Min, Sec, Hundredths); + {*** convert to seconds ***} + CurrentTime := Sec + (SECONDS_IN_MINUTE * Min) + (SECONDS_IN_HOUR * Hours); + + {*** get elapsed time from last reading ***} + if (CurrentTime < LastTime) then + {*** handle if 24-hour DOS clock roll-around has occured ***} + ElapsedTime := CurrentTime + (SECONDS_IN_DAY - LastTime) + else + ElapsedTime := CurrentTime - LastTime; + {*** re-set the global variable ***} + LastTime := CurrentTime; + end; {ElapsedTime} + +{*** end of MISC.PAS include file ***} + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/MOVES.PAS b/Borland Turbo Pascal v55/chess/MOVES.PAS new file mode 100644 index 0000000..d33d0c5 --- /dev/null +++ b/Borland Turbo Pascal v55/chess/MOVES.PAS @@ -0,0 +1,534 @@ +{****************************************************************************} +{* MOVES.PAS: This file contains the routines which generate, move, and *} +{* otherwise have to do (on a low level) with moves. *} +{****************************************************************************} + +{****************************************************************************} +{* Attacked By: Given the row and column of a square, this routine will *} +{* tally the number of other pieces which attack (enemy pieces) or protect *} +{* (friendly pieces) the piece on that square. This is accomplished by *} +{* looking around the piece to all other locations from which a piece *} +{* could protect or protect. This routine does not count an attack by *} +{* en passent. This routine is called to see if a king is in check and *} +{* as part of the position strength calculation. *} +{****************************************************************************} + procedure AttackedBy (row, col : RowColType; var Attacked, Protected : integer); + var dir, i, distance : integer; + PosRow, PosCol, IncRow, IncCol : RowColType; + FriendColor, EnemyColor : PieceColorType; + begin + {*** initialize ***} + Attacked := 0; + Protected := 0; + FriendColor := Board[row, col].color; + if (FriendColor = C_WHITE) then begin + dir := 1; {*** row displacement from which an enemy pawn would attack ***} + EnemyColor := C_BLACK; + end else begin + dir := -1; + EnemyColor := C_WHITE; + end; + + {*** count number of attacking pawns ***} + with Board[row + dir, col - 1] do + if (image = PAWN) and (color = EnemyColor) then Attacked := Attacked + 1; + with Board[row + dir, col + 1] do + if (image = PAWN) and (color = EnemyColor) then Attacked := Attacked + 1; + + {*** count number of protecting pawns ***} + with Board[row - dir, col - 1] do + if (image = PAWN) and (color = FriendColor) then Protected := Protected + 1; + with Board[row - dir, col + 1] do + if (image = PAWN) and (color = FriendColor) then Protected := Protected + 1; + + {*** check for a knight in all positions from which it could attack/protect ***} + for i := 1 to PossibleMoves[KNIGHT].NumDirections do begin + with PossibleMoves[KNIGHT].UnitMove[i] do begin + PosRow := row + DirRow; + PosCol := col + DirCol; + end; + if (Board[PosRow, PosCol].image = KNIGHT) then begin + {*** color determines if knight is attacking or protecting ***} + if (Board[PosRow, PosCol].color = FriendColor) then + Protected := Protected + 1 + else + Attacked := Attacked + 1; + end; + end; + + {*** check for king, queen, bishop, and rook attacking or protecting ***} + for i := 1 to 8 do begin + {*** get the current search direction ***} + with PossibleMoves[QUEEN].UnitMove[i] do begin + IncRow := DirRow; + IncCol := DirCol; + end; + {*** set distance countdown and search position ***} + distance := 7; + PosRow := row; + PosCol := col; + + {*** search until something is run into ***} + while distance > 0 do begin + {*** get new position and check it ***} + PosRow := PosRow + IncRow; + PosCol := PosCol + IncCol; + with Board[PosRow, PosCol] do begin + if ValidSquare then begin + if image = BLANK then + {*** continue searching if search_square is blank ***} + distance := distance - 1 + else begin + {*** separate cases of straight or diagonal attack/protect ***} + if (IncRow = 0) or (IncCol = 0) then begin + {*** straight: check for queen, rook, or one-away king ***} + if (image = QUEEN) or (image = ROOK) or + ((image = KING) and (distance = 7)) then + if (color = FriendColor) then + Protected := Protected + 1 + else + Attacked := Attacked + 1; + end else begin + {*** diagonal: check for queen, bishop, or one-away king ***} + if (image = QUEEN) or (image = BISHOP) or + ((image = KING) and (distance = 7)) then + if (color = FriendColor) then + Protected := Protected + 1 + else + Attacked := Attacked + 1; + end; + {*** force to stop searching if piece encountered ***} + distance := 0; + end; + end else + {*** force to stop searching if border of board encountered ***} + distance := 0; + end; + end; + end; + end; {AttackedBy} + +{****************************************************************************} +{* Gen Move List: Returns the list of all possible moves for the given *} +{* player. Searches the board for all pieces of the given color, and *} +{* adds all of the possible moves for that piece to the move list to be *} +{* returned. *} +{****************************************************************************} + procedure GenMoveList (Turn : PieceColorType; var Movelist : MoveListType); + var row, col : RowColType; + +{----------------------------------------------------------------------------} +{ Gen Piece Move List: Generates all of the moves for the given piece at } +{ the given board position, and adds them to the move list for the player. } +{ If the piece is a pawn then all of the moves are checked by brute force. } +{ If the piece is a king, then the castling move is checked by brute force. } +{ For all other moves, each allowed direction for the piece is checked, and } +{ each square off in that direction from the piece, up to the piece's move } +{ distance limit, is added to the list, until the edge of the board is } +{ encountered or another piece is encountered. If the piece encountered } +{ is an enemy piece, then taking that enemy piece is added to the player's } +{ move list as well. } +{----------------------------------------------------------------------------} + procedure GenPieceMoveList (Piece : PieceType; row, col : integer); + var dir : integer; + PosRow, PosCol : RowColType; {*** current scanning position ***} + OrigRow, OrigCol : RowColType; {*** location to search from ***} + IncRow, IncCol : integer; {*** displacement to add to scanning position ***} + DirectionNum : 1..8; + distance : 0..7; + EPPossible : boolean; + EnemyColor : PieceColorType; + Attacked, Protected : integer; + +{----------------------------------------------------------------------------} +{ Gen Add Move: Adds the move to be generated to the player's move list. } +{ Given the location and displacement to move the piece, takes PieceTaken } +{ and PieceMoved from the current board configuration. } +{----------------------------------------------------------------------------} + procedure GenAddMove (row, col : RowColType; drow, dcol : integer); + begin + MoveList.NumMoves := MoveList.NumMoves + 1; + with MoveList.Move[MoveList.NumMoves] do begin + FromRow := row; + FromCol := col; + ToRow := row + drow; + ToCol := col + dcol; + PieceTaken := Board [ToRow, ToCol]; + PieceMoved := Board [FromRow, FromCol]; + {*** get image of piece after it is moved... ***} + {*** same as before the movement except in the case of pawn promotion ***} + MovedImage := Board [FromRow, FromCol].image; + end; + end; {GenAddMove} + +{----------------------------------------------------------------------------} +{ Gen Add Pawn Move: Adds the move to be generated for a pawn to the } +{ player's move list and checks for pawn promotion. } +{----------------------------------------------------------------------------} + procedure GenAddPawnMove (row, col : RowColType; drow, dcol : integer); + begin + GenAddMove (row, col, drow, dcol); + {*** if pawn will move to an end row ***} + if (row + drow = 1) or (row + drow = 8) then + {*** assume the pawn will be promoted to a queen ***} + MoveList.Move[MoveList.NumMoves].MovedImage := QUEEN; + end; {GenAddPawnMove} + +{----------------------------------------------------------------------------} + begin {GenPieceMoveList} + OrigRow := row; + OrigCol := col; + + {*** pawn movement is a special case ***} + if Piece.image = PAWN then begin + {*** check for En Passent ***} + if Piece.color = C_WHITE then begin + dir := 1; + EPPossible := (row = 5); + EnemyColor := C_BLACK; + end else begin + dir := -1; + EPPossible := (row = 4); + EnemyColor := C_WHITE; + end; + {*** make sure enemy's last move was push pawn two, beside player's pawn ***} + with Player[EnemyColor].LastMove do begin + if EPPossible and Game.EnPassentAllowed and (FromRow <> NULL_MOVE) then + if (abs (FromRow - ToRow) = 2) then + if (abs (ToCol - col) = 1) and (PieceMoved.image = PAWN) then + GenAddPawnMove (row, col, dir, ToCol - col); + end; + + {*** square pawn is moving to (1 or 2 ahead) is guaranteed to be valid ***} + if (Board [row + dir, col].image = BLANK) then begin + GenAddPawnMove (row, col, dir, 0); + {*** see if pawn can move two ***} + if (not Piece.HasMoved) and (Board [row + 2*dir, col].image = BLANK) then + GenAddPawnMove (row, col, 2*dir, 0); + end; + + {*** check for pawn takes to left ***} + with Board[row + dir, col - 1] do begin + if (image <> BLANK) and (color = EnemyColor) and ValidSquare then + GenAddPawnMove (row, col, dir, -1); + end; + + {*** check for pawn takes to right ***} + with Board[row + dir, col + 1] do begin + if (image <> BLANK) and (color = EnemyColor) and ValidSquare then + GenAddPawnMove (row, col, dir, +1); + end; + end else begin + {*** check for the king castling ***} + if (Piece.image = KING) and (not Piece.HasMoved) and (not Player[Turn].InCheck) then begin + {*** check for castling to left ***} + if (Board [row, 1].image = ROOK) and (not Board [row, 1].HasMoved) then + if (Board [row, 2].image = BLANK) and (Board [row, 3].image = BLANK) + and (Board [row, 4].image = BLANK) then begin + {*** make sure not moving through check ***} + Board [row, 4].color := Turn; + AttackedBy (row, 4, Attacked, Protected); + if (Attacked = 0) then + GenAddMove (row, 5, 0, -2); + end; + + {*** check for castling to right ***} + if (Board [row, 8].image = ROOK) and (not Board [row, 8].HasMoved) then + if (Board [row, 6].image = BLANK) and (Board [row, 7].image = BLANK) then begin + {*** make sure not moving through check ***} + Board [row, 6].color := Turn; + AttackedBy (row, 6, Attacked, Protected); + if (Attacked = 0) then + GenAddMove (row, 5, 0, 2); + end; + end; + + {*** Normal moves: for each allowed direction of the piece... ***} + for DirectionNum := 1 to PossibleMoves [Piece.image].NumDirections do begin + {*** initialize search ***} + distance := PossibleMoves [Piece.image].MaxDistance; + PosRow := OrigRow; + PosCol := OrigCol; + with PossibleMoves[Piece.image].UnitMove[DirectionNum] do begin + IncRow := DirRow; + IncCol := DirCol; + end; + + {*** search until something is run into ***} + while distance > 0 do begin + PosRow := PosRow + IncRow; + PosCol := PosCol + IncCol; + with Board [PosRow, PosCol] do begin + if (not ValidSquare) then + distance := 0 + else begin + if image = BLANK then begin + {*** sqaure is empty: can move there; keep searching ***} + GenAddMove (OrigRow, OrigCol, PosRow - OrigRow, PosCol - OrigCol); + distance := distance - 1; + end else begin + {*** piece is there: can take if enemy; stop searching ***} + distance := 0; + if color <> Turn then + GenAddMove (OrigRow, OrigCol, PosRow - OrigRow, PosCol - OrigCol); + end; + end; + end; + end; + end; + end; + end; {GenPieceMoveList} + +{----------------------------------------------------------------------------} + begin {GenMoveList} + {*** empty out player's move list ***} + MoveList.NumMoves := 0; + + {*** search for player's pieces on board ***} + for row := 1 to BOARD_SIZE do + for col := 1 to BOARD_SIZE do + with Board [row, col] do begin + {*** if player's piece, add its moves ***} + if (image <> BLANK) and (color = Turn) then + GenPieceMoveList (Board [row, col], row, col); + end; + end; {GenMoveList} + +{****************************************************************************} +{* Make Move: Update the Board to reflect making the given movement. If *} +{* given is a PermanentMove, then the end of game pointers is set to the *} +{* current move. Returns the score for the move, which is given by the *} +{* number of points for the piece taken. *} +{****************************************************************************} + procedure MakeMove (Movement : MoveType; PermanentMove : boolean; var Score : integer); + var Row: RowColType; + Attacked, Protected : integer; + + begin + Score := 0; + {*** update board for most moves ***} + with Movement do begin + {*** pick piece up ***} + Board[FromRow, FromCol].image := BLANK; + {*** put piece down ***} + Board[ToRow, ToCol] := PieceMoved; + end; + + {*** check for en passent, pawn promotion, and castling ***} + case Movement.PieceMoved.image of + PAWN: begin + {*** en passent: blank out square taken; get points ***} + if (Movement.FromCol <> Movement.ToCol) and (Movement.PieceTaken.image = BLANK) then begin + Board[Movement.FromRow, Movement.ToCol].image := BLANK; + Score := Score + CapturePoints[PAWN]; + end; + + {*** pawn promotion: use the after-moved image; get trade-up points ***} + if Movement.PieceMoved.color = C_WHITE then Row := 8 else Row := 1; + if Movement.ToRow = Row then begin + Board[Movement.ToRow, Movement.ToCol].image := Movement.MovedImage; + Score := Score + CapturePoints[Movement.MovedImage] - CapturePoints[PAWN]; + end; + end; + + KING: begin + {*** update king position in player record ***} + with Player[Movement.PieceMoved.color] do begin + KingRow := Movement.ToRow; + KingCol := Movement.ToCol; + end; + + {*** castling left/right: move the rook too ***} + if abs (Movement.FromCol - Movement.ToCol) > 1 then begin + if (Movement.ToCol < Movement.FromCol) then begin + Board[Movement.FromRow, 4] := Board[Movement.FromRow, 1]; + Board[Movement.FromRow, 4].HasMoved := true; + Board[Movement.FromRow, 1].image := BLANK; + end else begin + Board[Movement.FromRow, 6] := Board[Movement.FromRow, 8]; + Board[Movement.FromRow, 6].HasMoved := true; + Board[Movement.FromRow, 8].image := BLANK; + end; + end; + end; + end; + + {*** update player attributes ***} + Player[Movement.PieceMoved.color].LastMove := Movement; + Player[Movement.PieceMoved.color].InCheck := false; + with Player[EnemyColor[Movement.PieceMoved.color]] do begin + AttackedBy (KingRow, KingCol, Attacked, Protected); + InCheck := Attacked <> 0; + end; + + {*** remember that piece has been moved, get score ***} + Board[Movement.ToRow, Movement.ToCol].HasMoved := true; + Score := Score + CapturePoints[Movement.PieceTaken.image]; + + {*** update game attributes ***} + Game.MoveNum := Game.MoveNum + 1; + Game.MovesPointer := Game.MovesPointer + 1; + Game.Move[Game.MovesPointer] := Movement; + if PermanentMove then + Game.MovesStored := Game.MovesPointer; + Game.InCheck[Game.MovesPointer] := Attacked <> 0; + + {*** update nondevelopmental moves counter ***} + if (Movement.PieceMoved.image = PAWN) or (Movement.PieceTaken.image <> BLANK) then begin + Game.NonDevMoveCount[Game.MovesPointer] := 0; + end else begin + {*** if 50 nondevelopmental moves in a row: stalemate ***} + Game.NonDevMoveCount[Game.MovesPointer] := Game.NonDevMoveCount[Game.MovesPointer-1] + 1; + if (Game.NonDevMoveCount[Game.MovesPointer] >= NON_DEV_MOVE_LIMIT) then + Score := STALE_SCORE; + end; + end; {MakeMove} + +{****************************************************************************} +{* Un Make Move: Updates the board for taking back the last made move. *} +{* This routine returns (is not given) the last made movement (so it may *} +{* be passed to DisplayUnMadeMove). *} +{****************************************************************************} + procedure UnMakeMove (var Movement: Movetype); + begin + {*** make sure there is a move to un-make ***} + if (Game.MovesPointer > 0) then begin + Movement := Game.Move[Game.MovesPointer]; + {*** restore whether player who made move was in check ***} + Player[Movement.PieceMoved.color].InCheck := Game.InCheck[Game.MovesPointer - 1]; + {*** the enemy could not have been in check ***} + Player[EnemyColor[Movement.PieceMoved.color]].InCheck := false; + {*** restore the From and To squares ***} + Board[Movement.FromRow, Movement.FromCol] := Movement.PieceMoved; + Board[Movement.ToRow, Movement.ToCol] := Movement.PieceTaken; + + {*** special cases ***} + case Movement.PieceMoved.image of + KING: begin + {*** restore position of king in player attributes ***} + with Player[Movement.PieceMoved.color] do begin + KingRow := Movement.FromRow; + KingCol := Movement.FromCol; + end; + {*** un-castle left/right if applicable ***} + if abs (Movement.FromCol - Movement.ToCol) > 1 then begin + if (Movement.FromCol < Movement.ToCol) then begin + Board[Movement.FromRow, 8] := Board[Movement.FromRow, 6]; + Board[Movement.FromRow, 6].image := BLANK; + Board[Movement.FromRow, 8].HasMoved := false; + end else begin + Board[Movement.FromRow, 1] := Board[Movement.FromRow, 4]; + Board[Movement.FromRow, 4].image := BLANK; + Board[Movement.FromRow, 1].HasMoved := false; + end; + end; + end; + + PAWN: + {*** un-en passent: restore the pawn that was taken ***} + if (Movement.FromCol <> Movement.ToCol) and (Movement.PieceTaken.image = BLANK) then + with Board[Movement.FromRow, Movement.ToCol] do begin + image := PAWN; + if Movement.PieceMoved.color = C_WHITE then + color := C_BLACK + else + color := C_WHITE; + HasMoved := true; + end; + end; + + {*** roll back move number and pointer ***} + Game.MoveNum := Game.MoveNum - 1; + Game.MovesPointer := Game.MovesPointer - 1; + + {*** restore player previous move attributes ***} + if (Game.MovesPointer > 1) then + Player[Movement.PieceMoved.color].LastMove := Game.Move[Game.MovesPointer - 1] + else + Player[Movement.PieceMoved.color].LastMove.FromRow := NULL_MOVE; + end else + {*** indicate no move to take back ***} + Movement.FromRow := NULL_MOVE; + end; {UnMakeMove} + +{****************************************************************************} +{* Trim Checks: Given a move list, remove all of the moves which would *} +{* result in the given player moving into check. This is not done *} +{* directly by GenMoveList because it is an expensive operation, since *} +{* each move will have to be made and then unmade. This routine is called *} +{* by the Human Movement routine. The Computer Movement routine *} +{* incorporates this code into its code, since the moves have to be made *} +{* and unmade there anyway. *} +{****************************************************************************} + procedure TrimChecks (Turn : PieceColorType; var MoveList : MoveListType); + var DummyMove : MoveType; + DummyScore, Attacked, Protected : integer; + ValidMoves, i : integer; + + begin + ValidMoves := 0; + for i := 1 to MoveList.NumMoves do begin + MakeMove (MoveList.Move[i], false, DummyScore); + {*** check if the king is attacked (in check) ***} + AttackedBy (Player[Turn].KingRow, Player[Turn].KingCol, Attacked, Protected); + if Attacked = 0 then begin + {*** if not in check, then re-put valid move ***} + ValidMoves := ValidMoves + 1; + MoveList.Move[ValidMoves] := MoveList.Move[i]; + end; + UnMakeMove (DummyMove); + end; + MoveList.NumMoves := ValidMoves; + end; {TrimChecks} + +{****************************************************************************} +{* Randomize Move List: Scrambles the order of the given move list. This *} +{* is done to make choosing between tie scores random. It is necassary *} +{* to scramble the moves here because the move list will always be *} +{* generated in the same order. *} +{****************************************************************************} + procedure RandomizeMoveList (var MoveList : MoveListType); + var i, Exch : integer; + ExchMove : MoveType; + begin + for i := 1 to MoveList.NumMoves do begin + {*** swap the current move with some random other one ***} + Exch := Random (MoveList.NumMoves) + 1; + ExchMove := MoveList.Move[Exch]; + MoveList.Move[Exch] := MoveList.Move[i]; + MoveList.Move[i] := ExchMove; + end; + end; {RandomizeMoveList} + +{****************************************************************************} +{* Goto Move: Rolls back/forth the game to the given move number. Each *} +{* move between the current move and the destination is made/retracted to *} +{* update the board and other game status information. If the given move *} +{* number is too small or too large, the game is rolled to the first/last *} +{* move. *} +{****************************************************************************} + procedure GotoMove (GivenMoveTo : integer); + var Movement : MoveType; + DummyScore : integer; + MoveTo, BeginMoveNum, EndMoveNum : integer; + begin + {*** check the bounds of given move number ***} + MoveTo := GivenMoveTo; + BeginMoveNum := Game.MoveNum - Game.MovesPointer; + EndMoveNum := Game.MoveNum + (Game.MovesStored - Game.MovesPointer); + if (MoveTo < BeginMoveNum) then MoveTo := BeginMoveNum; + if (MoveTo > EndMoveNum) then MoveTo := EndMoveNum; + + {*** make / retract moves of the game until the destination is reached ***} + while (Game.MoveNum <> MoveTo) do begin + if MoveTo > Game.MoveNum then begin + Movement := Game.Move[Game.MovesPointer + 1]; + MakeMove (Movement, false, DummyScore); + end else + UnMakeMove (Movement); + end; + Game.GameFinished := false; + end; + +{*** end of the MOVES.PAS include file ***} + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/PIECES.IMG b/Borland Turbo Pascal v55/chess/PIECES.IMG new file mode 100644 index 0000000000000000000000000000000000000000..613989cea2cbfac95ce005031c9b288f1bea24ef GIT binary patch literal 63000 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Νb;WhdwmBn91$t;{3s-Ygmz2|FJ+Gz#Ur6ntR^!u^HD4 zaJvas|6>;5c37i?i4GhAPBF>|mf#!yxH8Hpv|rIEO?U8Q9LPTEwci8W?tGVGCdGOu zV^Ti^xE*s6XTKqC-y!>Ca8t}L7vSk>v0m)_VgZ(4J^_DWZ@L{%zfxX$|IgxDd-W~Q zcD*J;>53Cn|0S9ZoJ(?3v3dbE zKJGeyV>JP}n_Fotb@GL&?=j3q!DU2@#w}t&6En%Nbzhm9+_9Wk>n9(4c zkh=lAlQF6P)Utbcj~9EEYPQSRc(&n`U#Je*Bt@A}C``aPrwlOeKJ8Z*ZkSiW#4xb4ihjizk;9K{<>|ir5^+rNQl$jj@b- z%OxHqF7fE*l1?97;i#y2EXuy5NZsWbllaaUF14Xb9oZC*;G|qb{lNGXolBb3tu0+k zWAFReT_3&W1N-lPaQ{bcd*2CozyJQ<{`{8;(R8%`X!I-hfByalzp(%4{^ 0) do begin + Movement := MoveList.Move[j]; + {*** make the move ***} + MakeMove (Movement, false, Score); + {*** make sure it is legal (not moving into check) ***} + AttackedBy (Player[Turn].KingRow, Player[Turn].KingCol, Attacked, Protected); + if (Attacked = 0) then begin + NoMoves := false; + if (Score = STALE_SCORE) then + {*** end the search on a stalemate ***} + LineScore := Score + else begin + TakingPiece := Movement.PieceTaken.image <> BLANK; + if (Depth <= 1) and not (AllTakes and TakingPiece and (Depth >= PLUNGE_DEPTH)) then begin + {*** have reached horizon node of tree: score points for piece taken ***} + {*** but assume own piece will be taken if enemy's piece is protected ***} + if Movement.PieceTaken.image <> BLANK then begin + AttackedBy (Movement.ToRow, Movement.ToCol, Attacked, Protected); + if Attacked > 0 then + LineScore := Score - CapturePoints[Movement.PieceMoved.image] + else + LineScore := Score; + end else + LineScore := Score; + end else begin + {*** new cutoff value ***} + STCutOff := Score - BestScore; + {*** recursive call for enemy's best countermoves score ***} + LineScore := Score - Search (EnemyColor[Turn], STCutOff, + Depth - 1, AllTakes and TakingPiece); + end; + end; + {*** remember player's maximum net score ***} + if (LineScore > BestScore) then BestScore := LineScore; + end; + {*** un-do the move and check for cutoff ***} + UnMakeMove (Movement); + if BestScore >= CutOff then j := 0 else j := j - 1; + end; + if (BestScore = STALE_SCORE) then + BestScore := -STALE_SCORE; {stalemate means both players lose} + if NoMoves then + {*** player cannot move ***} + if Player[Turn].InCheck then + {*** if he is in check and cannot move, he loses ***} + BestScore := - CapturePoints[KING] + else + {*** if he is not in check, then both players lose ***} + BestScore := -STALE_SCORE; {prefer stalemate to checkmate} + Search := BestScore; + end; {Search} + +{----------------------------------------------------------------------------} +{ Pre Search: Returns the given move list of the given player, sorted into } +{ the order of ascending score for the given depth to look ahead. The } +{ main computer move routine calls this routine to sort the move list such } +{ that it will probably find a good move early in a greater depth search. } +{----------------------------------------------------------------------------} + procedure PreSearch (Turn : PieceColorType; Depth : integer; var MoveList : MoveListType); + var i, j, Attacked, Protected : integer; + Score : integer; + Movement : MoveType; + TempScore : integer; + Temp : string80; + PreScanScore : array [1..MOVE_LIST_LEN] of integer; + BestScore : integer; + begin + + {*** display message ***} + if Display then begin + DisplayClearLines (MSG_HINT, 21); + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (LightGreen); + CenterText (MSG_HINT, 'Pre Scanning...'); + end; + BestScore := NegInfinity; + + {*** scan each move in same order as main routine ***} + for i := MoveList.NumMoves downto 1 do begin + {*** get points for move as in Search routine ***} + Movement := MoveList.Move[i]; + MakeMove (Movement, false, Score); + AttackedBy (Player[Turn].KingRow, Player[Turn].KingCol, Attacked, Protected); + if (Attacked = 0) then begin + Score := Score - Search (EnemyColor[Turn], Score - BestScore, Depth - 1, false); + {*** remember the score of the move ***} + PreScanScore[i] := Score; + end else + {*** invalid moves get lowest score ***} + PreScanScore[i] := NegInfinity; + UnMakeMove (Movement); + {*** remember best score for purpose of making cutoffs ***} + if (Score > BestScore) then BestScore := Score; + end; + + {*** sort the movelist by score: O(n^2) selection sort used ***} + for i := 1 to MoveList.NumMoves do + for j := i + 1 to MoveList.NumMoves do + if PreScanScore[i] > PreScanScore[j] then begin + Movement := MoveList.Move[i]; + MoveList.Move[i] := MoveList.Move[j]; + MoveList.Move[j] := Movement; + TempScore := PreScanScore[i]; + PreScanScore[i] := PreScanScore[j]; + PreScanScore[j] := TempScore; + end; + end; {PreSearch} + +{----------------------------------------------------------------------------} +{ Eval Pos Strength: Use a number of ad-hoc rules to evaluate the } +{ positional content (rather than material content) of the given move, } +{ considering the current board configuration. Generally important } +{ considerations are friendly piece protection and enemy piece threatening, } +{ as well as number of possible future moves allowed for the player. } +{----------------------------------------------------------------------------} + function EvalPosStrength (Turn : PieceColorType; Movement : MoveType) : integer; + var PosMoveList : MoveListType; + PosStrength : integer; + row, col, KingRow, KingCol : RowColType; + Attacked, Protected : integer; + CumOwnAttacked, CumOwnProtected : integer; + CumEnemyAttacked, CumEnemyProtected : integer; + PawnDir, KingProtection, KingFront : integer; + CheckCol : RowColType; + CastlePossible, IsDevMove : boolean; + NoDevCount : integer; + + begin + {*** points for putting enemy in check ***} + NoDevCount := Game.NonDevMoveCount[Game.MovesPointer]; + if Player[EnemyColor[Turn]].InCheck then begin + if NoDevCount < 9 then + PosStrength := 40 + else begin + if NoDevCount < 12 then + PosStrength := 4 + else + PosStrength := 0; + end; + end else + PosStrength := 0; + + {*** points for pieces in front of king if he is (probably) in castled position ***} + KingProtection := 0; + KingRow := Player[Turn].KingRow; + KingCol := Player[Turn].KingCol; + if ((KingRow = 1) or (KingRow = 8)) and (KingCol <> 5) then begin + if KingRow = 1 then KingFront := 2 else KingFront := 7; + for CheckCol := KingCol - 1 to KingCol + 1 do + with Board[KingFront, CheckCol] do begin + if ValidSquare and (image <> BLANK) and (color = Turn) then + KingProtection := KingProtection + 1; + end; + end; + PosStrength := PosStrength + KingProtection * 3; + + {*** determine if castling is still possible ***} + with Board[KingRow, 1] do + CastlePossible := (image = ROOK) and (not HasMoved); + with Board[KingRow, 8] do + CastlePossible := CastlePossible or ((image = ROOK) and (not HasMoved)); + CastlePossible := CastlePossible and (not Board[KingRow, KingCol].HasMoved); + + {*** points for castling or not moving king/rook if castling still possible ***} + if Movement.PieceMoved.image = KING then begin + if (abs(Movement.FromCol - Movement.ToCol) > 1) + and (KingProtection >= 2) then + PosStrength := PosStrength + 140 + else + if CastlePossible then PosStrength := PosStrength - 80; + end; + + {*** points for pushing a pawn; avoids pushing potential castling protection ***} + IsDevMove := false; + if Movement.PieceMoved.image = PAWN then begin + if ((Movement.FromCol <= 3) or (Movement.FromCol >= 6)) + and ((Movement.FromRow = 1) or (Movement.FromRow = 8)) + and CastlePossible then + PosStrength := PosStrength - 12 + else + PosStrength := PosStrength + 1; + IsDevMove := true; + end; + + {*** points for developmental move if one has not happened in a while ***} + IsDevMove := IsDevMove or (Movement.PieceTaken.image <> BLANK); + if IsDevMove then begin + if NoDevCount >= 9 then + PosStrength := PosStrength + NoDevCount; + end; + + {*** points for number of positions that can be moved to ***} + GenMoveList (Turn, PosMoveList); + PosStrength := PosStrength + PosMoveList.NumMoves; + + {*** points for pieces attacked / protected ***} + CumOwnAttacked := 0; + CumOwnProtected := 0; + CumEnemyAttacked := 0; + CumEnemyProtected := 0; + for row := 1 to BOARD_SIZE do + for col := 1 to BOARD_SIZE do + if (Board[row, col].image <> BLANK) then begin + AttackedBy (row, col, Attacked, Protected); + if (Board[row, col].color = Turn) then begin + CumOwnAttacked := CumOwnAttacked + Attacked; + CumOwnProtected := CumOwnProtected + Protected; + end else begin + CumEnemyAttacked := CumEnemyAttacked + Attacked; + CumEnemyProtected := CumEnemyProtected + Protected; + end; + end; + PosStrength := PosStrength + 2 * CumOwnProtected + - 2 * CumOwnAttacked + 2 * CumEnemyAttacked; + EvalPosStrength := PosStrength; + end; {EvalPosStrength} + +{----------------------------------------------------------------------------} + begin {GetComputerMove} + {*** initialize ***} + PosEvalOn := Player[Turn].PosEval; + MaxDepth := Player[Turn].LookAhead; + NegInfinity := - CapturePoints[KING] * 5; + Escape := false; + HiScore := NegInfinity; + HiPosStrength := -maxint; + HiMovement.FromRow := NULL_MOVE; + + {*** get the move list and scramble it (to randomly choose between ties) ***} + GenMoveList (Turn, MoveList); + RandomizeMoveList (MoveList); + key := GetKey; {*** check for user pressing ESCape ***} + if key <> 'x' then begin + {*** perform pre-scan of two or three-ply if feasible ***} + if MaxDepth >= 3 then begin + if MaxDepth = 3 then + PreSearch (Turn, 2, MoveList) + else + PreSearch (Turn, 3, MoveList); + end; + i := MoveList.NumMoves; + key := GetKey; + end; + {*** check for user pressing ESCape after pre-scan ***} + if key = 'x' then begin + Escape := true; + i := 0; + end; + + {*** check each possible move - same method as in Search ***} + while (i > 0) do begin + UpDateTime (Turn); {*** player's elapsed time ***} + Movement := MoveList.Move[i]; + MakeMove (Movement, false, InitialScore); + AttackedBy (Player[Turn].KingRow, Player[Turn].KingCol, Attacked, Protected); + if (Attacked = 0) then begin + if (InitialScore = STALE_SCORE) then + SubHiScore := STALE_SCORE + else begin + {*** display scan count-down ***} + if Display and (MaxDepth >= 3) then begin + DisplayClearLines (MSG_HINT, 21); + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (LightGreen); + Str (i, cstr); + CenterText (MSG_HINT, 'Scan=' + cstr); + end; + + {*** calculate one-ply score ***} + if (MaxDepth <= 1) then begin + if Movement.PieceTaken.image <> BLANK then begin + AttackedBy (Movement.ToRow, Movement.ToCol, Attacked, Protected); + if Attacked > 0 then + SubEnemyMaxScore := CapturePoints[Movement.PieceMoved.image] + else + SubEnemyMaxScore := 0; + end else + SubEnemyMaxScore := 0; + end else begin + {*** get net score ***} + if PosEvalOn then + {*** position evaluation needs to check all scores tying for best ***} + L1CutOff := InitialScore - HiScore + 1 + else + L1CutOff := InitialScore - HiScore; + SubEnemyMaxScore := Search (EnemyColor[Turn], L1CutOff, MaxDepth - 1, + Movement.PieceTaken.image <> BLANK); + end; + {*** subtree score ***} + SubHiScore := InitialScore - SubEnemyMaxScore; + end; + + {*** check if new score is highest ***} + if (SubHiScore > HiScore) or (PosEvalOn and (SubHiScore = HiScore)) then begin + if PosEvalOn then + PosStrength := EvalPosStrength (Turn, Movement) + else + PosStrength := 0; + if (SubHiScore > HiScore) or (PosStrength > HiPosStrength) then begin + {*** remember new high score ***} + HiMovement := Movement; + HiScore := SubHiScore; + HiPosStrength := PosStrength; + {*** display new best movement ***} + if Display then begin + DisplayClearLines (MSG_MOVE, 15); + SetTextStyle (DefaultFont, HorizDir, 2); + SetColor (White); + CenterText (MSG_MOVE, MoveStr (HiMovement)); + DisplayClearLines (MSG_SCORE, MSG_POS_EVAL+8-MSG_SCORE); + SetTextStyle (DefaultFont, HorizDir, 1); + SetColor (LightCyan); + Str (HiScore, cstr); + CenterText (MSG_SCORE, 'Score=' + cstr); + Str (SubEnemyMaxScore, cstr); + CenterText (MSG_ENEMY_SCORE, 'EnemyScore=' + cstr); + Str (HiPosStrength, cstr); + CenterText (MSG_POS_EVAL, 'Pos=' + cstr); + end; + {*** for zero-ply lookahead, take first move looked at ***} + if MaxDepth = 0 then i := 1; + end; + end; + end; + UnMakeMove (Movement); + i := i - 1; + + {*** check for escape or forced move by user ***} + key := GetKey; + if key = 'x' then begin + Escape := true; + i := 0; + end else + if (key = 'M') and (HiScore <> NegInfinity) then i := 0; + end; + {*** beep when done thinking ***} + MakeSound (true); + end; {GetComputerMove} + +{****************************************************************************} +{* Get Human Move: Returns the movement as input by the user. Invalid *} +{* moves are screened by this routine. The user moves the cursor to the *} +{* piece to pick up and presses RETURN, and then moves the cursor to the *} +{* location to which the piece is to be moved and presses RETURN. *} +{* Pressing ESCape will exit this routine and return a flag indicating *} +{* escape; pressing H will make the computer suggest a move (hint); and *} +{* pressing A will report the attack/protect count of the cursor square. *} +{* BACKSPACE will delete the from-square and allow the user to select a *} +{* different piece. *} +{****************************************************************************} + procedure GetHumanMove (Turn : PieceColorType; var Movement : MoveType; + var Escape : boolean); + const MSG1X = 510; + var key : char; + HumanMoveList : MoveListType; + ValidMove, BadFromSq, PickingUp : boolean; + i : integer; + +{----------------------------------------------------------------------------} +{ Move Cursor With Hint: Moves the cursor around until the player presses } +{ RETURN or SPACE. Also handles keys A (Attack/protect) and H (Hint). } +{----------------------------------------------------------------------------} + procedure MoveCursorWithHint; + var HintMove : MoveType; + Att, Pro, i : integer; + cstr : string10; + bstr : string80; + + begin + repeat + {*** position cursor ***} + MoveCursor(Player[Turn].CursorRow, Player[Turn].CursorCol, Turn, true, key); + if key = ' ' then key := 'e'; + + {*** check your move list ***} + if key = 'C' then begin + RestoreCrtMode; + writeln ('Your list of possible moves:'); + writeln; + for i := 1 to HumanMoveList.NumMoves do + write (i:2, '.', copy(MoveStr(HumanMoveList.Move[i]) + ' ',1,7)); + writeln; + writeln; + write ('Press any key to continue...'); + key := ReadKey; + SetGraphMode (GraphMode); + DisplayGameScreen; + if not PickingUp then begin + SetTextStyle (DefaultFont, HorizDir, 2); + SetColor (White); + OutTextXY (MSG1X, MSG_MOVE, SqStr(Movement.FromRow, Movement.FromCol) + '-'); + end; + DisplayInstructions (INS_GAME); + end; + + {*** attack / protect count ***} + if key = 'A' then begin + DisplayClearLines (MSG_HINT, 17); + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (LightRed); + with Player[Turn] do begin + if Board[CursorRow, CursorCol].image = BLANK then + Board[CursorRow, CursorCol].color := Turn; + AttackedBy (CursorRow, CursorCol, Att, Pro); + end; + Str (Att, cstr); + bstr := 'Attk=' + cstr; + Str (Pro, cstr); + bstr := bstr + ' Prot=' + cstr; + CenterText (MSG_HINT, bstr); + end; + + {*** ask computer for hint ***} + if key = 'H' then begin + DisplayClearLines (MSG_HINT, 17); + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (LightRed); + CenterText (MSG_HINT, 'Thinking...'); + GetComputerMove (Turn, false, HintMove, Escape); + if not Escape then begin + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (LightRed); + DisplayClearLines (MSG_HINT, 21); + CenterText (MSG_HINT, 'Hint: ' + MoveStr (HintMove)); + end; + end else begin + Escape := key = 'x'; + end; + until (key = 'e') or (key = 'b') or Escape; + end; {MoveCursorWithHint} + +{----------------------------------------------------------------------------} +{ Sq Move: Returns whether the given two moves are equal on the basis of } +{ the from/to squares. } +{----------------------------------------------------------------------------} + function EqMove (M1, M2 : MoveType) : boolean; + begin + EqMove := (M1.FromRow = M2.FromRow) and (M1.FromCol = M2.FromCol) + and (M1.ToRow = M2.ToRow) and (M1.ToCol = M2.ToCol); + end; {EqMove} + +{----------------------------------------------------------------------------} + begin {GetHumanMove} + Escape := false; + + {*** make sure the human has a move to make ***} + GenMoveList (Turn, HumanMoveList); + TrimChecks (Turn, HumanMoveList); + if HumanMoveList.NumMoves = 0 then + Movement.FromRow := NULL_MOVE + else begin + repeat + repeat + {*** get the from-square ***} + DisplayClearLines (MSG_MOVE, 15); + PickingUp := true; + MoveCursorWithHint; + DisplayClearLines (MSG_HINT, 21); + if not Escape then begin + {*** make sure there is a piece of player's color on from-square ***} + with Player[Turn] do + BadFromSq := (Board[CursorRow, CursorCol].image = BLANK) + or (Board[CursorRow, CursorCol].color <> Turn); + if (BadFromSq) then + MakeSound (false); + end; + if (not Escape) and (key <> 'b') and (not BadFromSq) then begin + {*** if all is well, display the from square ***} + Movement.FromRow := Player[Turn].CursorRow; + Movement.FromCol := Player[Turn].CursorCol; + SetTextStyle (DefaultFont, HorizDir, 2); + SetColor (White); + OutTextXY (MSG1X, MSG_MOVE, SqStr(Movement.FromRow, Movement.FromCol) + '-'); + {*** get the to-square ***} + PickingUp := false; + MoveCursorWithHint; + end; + {*** if user typed Backspace, go back to getting the from-square ***} + until ((key = 'e') and (not BadFromSq)) or Escape; + ValidMove := false; + if not Escape then begin + {*** store rest of move attributes ***} + Movement.ToRow := Player[Turn].CursorRow; + Movement.ToCol := Player[Turn].CursorCol; + Movement.PieceMoved := Board[Movement.FromRow, Movement.FromCol]; + Movement.MovedImage := Board[Movement.FromRow, Movement.FromCol].image; + Movement.PieceTaken := Board[Movement.ToRow, Movement.ToCol]; + {*** display the move ***} + DisplayClearLines (MSG_MOVE, 15); + SetTextStyle (DefaultFont, HorizDir, 2); + SetColor (White); + CenterText (MSG_MOVE, MoveStr (Movement)); + + {*** search for the move in the move list ***} + ValidMove := false; + for i := 1 to HumanMoveList.NumMoves do + if EqMove(HumanMoveList.Move[i], Movement) then ValidMove := true; + DisplayClearLines (MSG_HINT, 17); + {*** if not found then move is not valid: give message ***} + if not ValidMove then begin + SetTextStyle (TriplexFont, HorizDir, 1); + SetColor (LightRed); + CenterText (MSG_HINT, 'Invalid Move'); + MakeSound (false); + end; + end; + {*** keep trying until the user gets it right ***} + until ValidMove or Escape; + end; + end; {GetHumanMove} + +{****************************************************************************} +{* Get Player Move: Updates the display, starts the timer, figures out *} +{* whose turn it is, calls either GetHumanMove or GetComputerMove, stops *} +{* the timer, and returns the move selected by the player. *} +{****************************************************************************} + procedure GetPlayerMove (var Movement : MoveType; var Escape : boolean); + var Turn : PieceColorType; + Dummy: longint; + begin + DisplayWhoseMove; + {*** start timer ***} + Dummy := ElapsedTime; + {*** which color is to move ***} + if Game.MoveNum mod 2 = 1 then + Turn := C_WHITE + else + Turn := C_BLACK; + {*** human or computer ***} + if Player[Turn].IsHuman then + GetHumanMove (Turn, Movement, Escape) + else + GetComputerMove (Turn, true, Movement, Escape); + {*** stop timer ***} + UpDateTime (Turn); + end; {GetPlayerMove} + +{****************************************************************************} +{* Play Game: Call for the move of the current player, make it, and go on *} +{* to the next move and the next player. Continue until the game is over *} +{* (for whatever reason) or the user wishes to escape back to the main *} +{* menu. When making the move, this routine checks if it is a pawn *} +{* promotion of a human player. This routine is called from the main menu.*} +{****************************************************************************} + procedure PlayGame; + var Movement : MoveType; + DummyScore : integer; + NoMoves, Escape : boolean; + TimeOutWhite, TimeOutBlack, Stalemate, NoStorage : boolean; + +{----------------------------------------------------------------------------} +{ Check Finish Status: Updates the global variables which tell if the } +{ game is over and for what reason. This routine checks for a player } +{ exceeding the set time limit, the 50-move stalemate rule occuring, or } +{ the game being too long and there being not enough room to store it. } +{----------------------------------------------------------------------------} + procedure CheckFinishStatus; + begin + Game.TimeOutWhite := (Game.TimeLimit > 0) and (Player[C_WHITE].ElapsedTime >= Game.TimeLimit); + Game.TimeOutBlack := (Game.TimeLimit > 0) and (Player[C_BLACK].ElapsedTime >= Game.TimeLimit); + Game.Stalemate := Game.NonDevMoveCount[Game.MovesPointer] >= NON_DEV_MOVE_LIMIT; + Game.NoStorage := Game.MovesStored >= GAME_MOVE_LEN - MAX_LOOKAHEAD + PLUNGE_DEPTH - 2; + end; {CheckFinishStatus} + +{----------------------------------------------------------------------------} +{ Check Human Pawn Promotion: Checks if the given pawn move is a promotion } +{ by a human player. If not, the move is displayed. If so, the move is } +{ displayed as usual, but then the player is asked what piece he wants to } +{ promote the pawn to. The possible responses are: Q = Queen, R = Rook, } +{ B = Bishop, and N = kNight. Then, the piece is promoted. Note that the } +{ computer will always promote to a queen. } +{----------------------------------------------------------------------------} + procedure CheckHumanPawnPromotion (var Movement : MoveType); + var Turn : PieceColorType; + LegalPiece : boolean; + key : char; + NewImage : PieceImageType; + row, col : RowColType; + + begin + {*** check if the destination row is an end row ***} + row := Movement.ToRow; + col := Movement.ToCol; + if (row = 1) or (row = 8) then begin + {*** see if the player is a human ***} + Turn := Movement.PieceMoved.color; + if Player[Turn].IsHuman then begin + {*** show the pawn trotting up to be promoted ***} + Board[row, col].image := PAWN; + DisplayMove (Movement); + DisplaySquare (row, col, true); + DisplayInstructions (INS_PAWN_PROMOTE); + + {*** wait for the user to indicate what to promote to ***} + repeat + repeat key := GetKey until key <> 'n'; + LegalPiece := true; + case key of + 'Q': NewImage := QUEEN; + 'R': NewImage := ROOK; + 'B': NewImage := BISHOP; + 'N': NewImage := KNIGHT; + else begin + {*** buzz at user for pressing wrong key ***} + LegalPiece := false; + MakeSound (false); + end; + end; + until LegalPiece; + + {*** put in the new piece image ***} + Board[row, col].image := NewImage; + Game.Move[Game.MovesPointer].MovedImage := NewImage; + DisplaySquare (row, col, false); + DisplayInstructions (INS_GAME); + end else + DisplayMove (Movement); + end else + DisplayMove (Movement); + end; {CheckHumanPawnPromotion} + +{----------------------------------------------------------------------------} + begin {PlayGame} + Game.GameFinished := false; + DisplayInstructions (INS_GAME); + Escape := false; + NoMoves := false; + CheckFinishStatus; + + {*** play until escape or game over ***} + while not (NoMoves or Escape or Game.TimeOutWhite or Game.TimeOutBlack + or Game.Stalemate or Game.NoStorage) do begin + GetPlayerMove (Movement, Escape); + CheckFinishStatus; + NoMoves := Movement.FromRow = NULL_MOVE; + if not (NoMoves or Escape or Game.TimeOutWhite or Game.TimeOutBlack) then begin + {*** display the move if everything is ok ***} + MakeMove (Movement, true, DummyScore); + if (Movement.PieceMoved.image = PAWN) then + CheckHumanPawnPromotion (Movement) + else + DisplayMove (Movement); + end; + CheckFinishStatus; + end; + + {*** game is over unless the exit reason is the user pressing ESCape ***} + if not Escape then Game.GameFinished := true; + end; {PlayGame} + +{*** end of PLAY.PAS include file ***} + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/README.BAT b/Borland Turbo Pascal v55/chess/README.BAT new file mode 100644 index 0000000..01108ce --- /dev/null +++ b/Borland Turbo Pascal v55/chess/README.BAT @@ -0,0 +1 @@ +type README.TXT | more \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/README.TXT b/Borland Turbo Pascal v55/chess/README.TXT new file mode 100644 index 0000000..4e31c37 --- /dev/null +++ b/Borland Turbo Pascal v55/chess/README.TXT @@ -0,0 +1,53 @@ +KC Chess 1.00.00 - by Craig Bruce and Kevin Phillips, 06-Apr-90. + +Execution of this program requires a 100% IBM PC-DOS compatible computer with +640K of RAM and the VGA graphics card. + +The following files are required in the current directory: + CHESS.EXE { main program } + EGAVGA.BGI { Turbo Pascal 5.5 graphics driver } + TRIP.CHR { Turbo Pascal 5.5 character font file } + PIECES.IMG { binary piece images } + CHESS.HLP { online help information } + + The DOS file COMMAND.COM must also be present either in the current + directory or in some directory specified in the PATH environmental + variable, and it MUST BE COMPATIBLE with the version of DOS the + computer was booted up under. + +The following non-required chess program source files are also included: + CHESS.PAS { main program } + MISC.PAS { miscellaneous functions } + INIT.PAS { initialization of global variables } + DISPLAY.PAS { display-oriented routines } + INPUT.PAS { keyboard input routines } + MOVES.PAS { move generation and making routines } + SETUP.PAS { default board and custom setup routines } + PLAY.PAS { computer thinking and player input routines } + MENU.PAS { main menu routines } + +And the following non-required other files are also included: + README.BAT { batch file to display README.TXT } + README.TXT { this file, containing program notes } + HELPTEXT.TXT { help information in text format } + HELPGEN.EXE { program to convert HELPTEXT.TXT to CHESS.HLP } + HELPGEN.PAS { source of HELPGEN.EXE } + PIECES.TXT { piece images in text format } + IMAGE.EXE { program to convert PIECES.TXT to PIECES.IMG } + IMAGE.PAS { source code of IMAGE.EXE } + EXAMPLE.CHS { example saved game of chess } + +To change the help information, edit the file HELPTEXT.TXT and then execute +the HELPGEN.EXE program; this will give the updated CHESS.HLP file. To change +the piece images, edit the file PIECES.TXT and then execute the IMAGE.EXE +program; this will give the updated PIECES.IMG file. + +To modify the chess program or any of the other source files, Turbo Pascal 4.0 +or higher must be used to recompile the .EXE files. + +The chess program is 3417 lines long and the project took 220 hours to +complete. The work was carried out from JAN - APR 1990 as our CS 4993 +undergraduate project. The program may be distributed freely and is considered +Public Domain software. A 30 page written report was also produced and +submitted with the rest of the work to Dr. J. D. Horton who was our project +supervisor. \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/SETUP.PAS b/Borland Turbo Pascal v55/chess/SETUP.PAS new file mode 100644 index 0000000..5031f93 --- /dev/null +++ b/Borland Turbo Pascal v55/chess/SETUP.PAS @@ -0,0 +1,326 @@ +{****************************************************************************} +{* SETUP.PAS: This file contains the routines to either put the board in *} +{* its normal start of game setup or a custom user defined setup. *} +{****************************************************************************} + +{****************************************************************************} +{* Default Board Set Pieces: Puts the pieces on the board for the normal *} +{* initial configuration. *} +{****************************************************************************} + procedure DefaultBoardSetPieces; + var row, col : RowColType; + begin + {*** put in the row of pawns for each player ***} + for col := 1 to BOARD_SIZE do begin + Board[2,col].image := PAWN; + Board[7,col].image := PAWN; + end; + + {*** blank out the middle of the board ***} + for row := 3 to 6 do + for col := 1 to BOARD_SIZE do + Board[row,col].image := BLANK; + + {*** put in white's major pieces and then copy for black ***} + Board[1,1].image := ROOK; + Board[1,2].image := KNIGHT; + Board[1,3].image := BISHOP; + Board[1,4].image := QUEEN; + Board[1,5].image := KING; + Board[1,6].image := BISHOP; + Board[1,7].image := KNIGHT; + Board[1,8].image := ROOK; + for col := 1 to BOARD_SIZE do + Board[8,col] := Board[1,col]; + + {*** set the piece colors for each side ***} + for row := 1 to 4 do + for col := 1 to BOARD_SIZE do begin + Board[row,col].color := C_WHITE; + Board[row,col].HasMoved := false; + Board[row+4,col].color := C_BLACK; + Board[row+4,col].HasMoved := false; + end; + end; {DefaultBoardSetPieces} + +{****************************************************************************} +{* Default Board: Sets the pieces in their default positions and sets *} +{* some of the player attributes to their defaults. Some of the *} +{* attributes of the game are also set to their startup values. *} +{****************************************************************************} + procedure DefaultBoard; + var row,col : RowColType; + begin + DefaultBoardSetPieces; + + {*** player attributes ***} + with Player[C_WHITE] do begin + CursorRow := 2; + CursorCol := 4; + InCheck := false; + KingRow := 1; + KingCol := 5; + ElapsedTime := 0; + LastMove.FromRow := NULL_MOVE; + end; + + with Player[C_BLACK] do begin + CursorRow := 7; + CursorCol := 4; + InCheck := false; + KingRow := 8; + KingCol := 5; + ElapsedTime := 0; + LastMove.FromRow := NULL_MOVE; + end; + + {*** game attributes ***} + Game.MoveNum := 1; + Game.MovesStored := 0; + Game.GameFinished := false; + Game.MovesPointer := 0; + Game.InCheck[0] := false; + Game.NonDevMoveCount[0] := 0; + end; {DefaultBoard} + +{****************************************************************************} +{* Setup Board: Input a custom configuration of the pieces on the board *} +{* from the user. Will anyone actually read these comments. The user *} +{* moves the cursor to the square to be changed, and presses the key to *} +{* select the piece to put there. The standards K Q R B N P select a *} +{* piece and SPACE blanks out the square. The user can also clear the *} +{* board or ask for the default setup. RETURN saves the changes and asks *} +{* the user for the move number to continue the game from. ESCAPE *} +{* restores the setup upon entry to this routine and exits back to the *} +{* main menu. This routine is called from the main menu. *} +{****************************************************************************} + procedure SetupBoard; + var row, col, ClearRow, ClearCol : RowColType; + key : char; + image : PieceImageType; + LegalKey, InvalidSetup : boolean; + KingCount, Attacked, Protected, Error, NewMoveNum : integer; + TempStr : string80; + SaveGame : GameType; + +{----------------------------------------------------------------------------} +{ Put Piece On Board: Puts the global Image onto the board at the cursor } +{ position. If the image is not a blank, then the user is asked for the } +{ color (B or W). If the piece is a rook or king being placed in the } +{ piece's startup position, the user is asked if the piece has been moved } +{ since the start of the game. } +{----------------------------------------------------------------------------} + procedure PutPieceOnBoard; + var KingHomeRow, PawnHomeRow : RowColType; + begin + Board[row,col].image := image; + if (image = BLANK) then begin + Board[row,col].color := C_WHITE; + Board[row,col].HasMoved := false; + end else begin + {*** get color ***} + DisplayInstructions (INS_SETUP_COLOR); + repeat + key := GetKey; + until (key = 'B') or (key = 'W'); + + {*** check if piece has moved ***} + if key = 'W' then begin + Board[row,col].color := C_WHITE; + KingHomeRow := 1; + PawnHomeRow := 2; + end else begin + Board[row,col].color := C_BLACK; + KingHomeRow := 8; + PawnHomeRow := 7; + end; + {*** may have to ask if piece has been moved ***} + if ((image = KING) and (row = KingHomeRow) and (col = 5)) + or ((image = ROOK) and (row = KingHomeRow) and ((col = 1) or (col = 8))) then begin + DisplayInstructions (INS_SETUP_MOVED); + repeat + key := GetKey; + until (key = 'Y') or (key = 'N'); + Board[row,col].HasMoved := key = 'Y'; + end else + Board[row, col].HasMoved := not ((image = PAWN) and (row = PawnHomeRow)); + DisplaySquare (row, col, false); + DisplayInstructions (INS_SETUP); + end; + end; {PutPieceOnBoard} + +{----------------------------------------------------------------------------} +{ Check Valid Setup: Makes sure that each player has exactly one king on } +{ the board and updates the Player's King location attributes. Both kings } +{ cannot be in check. The other relevant player attributes are set to. } +{----------------------------------------------------------------------------} + procedure CheckValidSetup; + const NULL_ROW = NULL_MOVE; + var row, col : RowColType; + begin + {*** locate kings ***} + Player[C_WHITE].KingRow := NULL_ROW; + Player[C_BLACK].KingRow := NULL_ROW; + KingCount := 0; + for row := 1 to BOARD_SIZE do + for col := 1 to BOARD_SIZE do + if (Board[row, col].image = KING) then begin + KingCount := KingCount + 1; + Player[Board[row, col].color].KingRow := row; + Player[Board[row, col].color].KingCol := col; + end; + InvalidSetup := (KingCount <> 2) or (Player[C_WHITE].KingRow = NULL_ROW) + or (Player[C_BLACK].KingRow = NULL_ROW); + + {*** make sure both kings are not in check ***} + if not InvalidSetup then begin + AttackedBy (Player[C_WHITE].KingRow, Player[C_WHITE].KingCol, Attacked, Protected); + Player[C_WHITE].InCheck := (Attacked <> 0); + AttackedBy (Player[C_BLACK].KingRow, Player[C_BLACK].KingCol, Attacked, Protected); + Player[C_BLACK].InCheck := (Attacked <> 0); + InvalidSetup := (Player[C_WHITE].InCheck) and (Player[C_BLACK].InCheck); + end; + + {*** set other player attributes ***} + Game.GameFinished := false; + with Player[C_WHITE] do begin + CursorRow := 2; + CursorCol := 4; + LastMove.FromRow := NULL_MOVE; + end; + with Player[C_BLACK] do begin + CursorRow := 7; + CursorCol := 4; + LastMove.FromRow := NULL_MOVE; + end; + DisplayConversationArea; + + {*** report invalid setup ***} + if InvalidSetup then begin + SetColor (White); + SetFillStyle (SolidFill, Black); + Bar (0,INSTR_LINE, GetMaxX, GetMaxY); + SetTextStyle (TriplexFont, HorizDir, 3); + OutTextXY (0,INSTR_LINE, 'Illegal Setup - King(s) not set correctly. Press Key.'); + MakeSound (false); + while GetKey = 'n' do ; + DisplayInstructions (INS_SETUP); + end; + end; {CheckValidSetup} + +{----------------------------------------------------------------------------} +{ Get Move Num: Asks the user for the next move number of the game and } +{ whose turn it is to move next. If one of the players is in check, then } +{ that player is the one who must move next and the latter question is not } +{ asked. } +{----------------------------------------------------------------------------} + procedure GetMoveNum; + const ex = 190; ey = 40; + var cx, cy : integer; + begin + DisplayInstructions (INS_SETUP_MOVENUM); + Game.MovesStored := 0; + Game.MovesPointer := 0; + Game.InCheck[0] := (Player[C_WHITE].InCheck) or (Player[C_BLACK].InCheck); + + {*** open up 'window' ***} + cx := (BOARD_X1 + BOARD_X2) div 2; + cy := (BOARD_Y1 + BOARD_Y2) div 2; + SetFillStyle (SolidFill, DarkGray); + Bar (cx - ex, cy - ey, cx + ex, cy + ey); + + {*** ask for move number ***} + SetTextStyle (DefaultFont, HorizDir, 2); + SetColor (Yellow); + Str ((Game.MoveNum + 1) div 2, TempStr); + UserInput (67, cy - 18, 4, 'Move Number: ', TempStr); + Val (TempStr, NewMoveNum, Error); + if Error <> 0 then + NewMoveNum := 1 + else + NewMoveNum := NewMoveNum * 2 - 1; + + {*** ask for whose turn to move next if not in check ***} + if Game.InCheck[0] then begin + if Player[C_BLACK].InCheck then NewMoveNum := NewMoveNum + 1 + end else begin + if Game.MoveNum mod 2 = 1 then + TempStr := 'W' + else + TempStr := 'B'; + UserInput (67, cy + 4, 1, 'Next Player (B/W): ', TempStr); + if TempStr = 'B' then NewMoveNum := NewMoveNum + 1; + end; + + Game.MoveNum := NewMoveNum; + Game.NonDevMoveCount[0] := 0; + DisplayWhoseMove; + end; {GetMoveNum} + +{----------------------------------------------------------------------------} + begin {SetupBoard} + DisplayInstructions (INS_SETUP); + {*** remember old setup incase of escape ***} + SaveGame := Game; + SaveGame.Player := Player; + SaveGame.FinalBoard := Board; + row := 4; + col := 4; + repeat + repeat + {*** move cursor and get key ***} + MoveCursor (row, col, C_WHITE, false, key); + LegalKey := true; + {*** interpret key ***} + case key of + 'K': image := KING; + 'Q': image := QUEEN; + 'R': image := ROOK; + 'B': image := BISHOP; + 'N': image := KNIGHT; + 'P': begin + image := PAWN; + if (row = 1) or (row = 8) then begin + LegalKey := false; + MakeSound (false); + end; + end; + ' ': image := BLANK; + {*** clear board ***} + 'C': begin + for ClearRow := 1 to BOARD_SIZE do + for ClearCol := 1 to BOARD_SIZE do + Board[ClearRow, ClearCol].image := BLANK; + DisplayBoard; + LegalKey := false; + end; + {*** default setup of pieces ***} + 'D': begin + DefaultBoardSetPieces; + DisplayBoard; + LegalKey := false; + end; + else LegalKey := false; + end; + if LegalKey then PutPieceOnBoard; + until (key = 'e') or (key = 'x'); + + {*** make sure setup is valid and repeat above if not ***} + if (key = 'x') then + InvalidSetup := false + else + CheckValidSetup; + until not InvalidSetup; + + if (key = 'x') then begin + {*** restore the old setup if user presses escape ***} + Game := SaveGame; + Player := SaveGame.Player; + Board := SaveGame.FinalBoard; + end else + GetMoveNum; + DisplayBoard; + end; {SetupBoard} + +{*** end of SETUP.PAS include file ***} + \ No newline at end of file diff --git a/Borland Turbo Pascal v55/chess/TRIP.CHR b/Borland Turbo Pascal v55/chess/TRIP.CHR new file mode 100644 index 0000000000000000000000000000000000000000..12b58a7c9d8397c07058c8acb0507e033c7de68d GIT binary patch literal 7241 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 literal 0 HcmV?d00001 diff --git a/Borland Turbo Pascal v55/m.bat b/Borland Turbo Pascal v55/m.bat new file mode 100644 index 0000000..25fd43b --- /dev/null +++ b/Borland Turbo Pascal v55/m.bat @@ -0,0 +1,3 @@ +ntvdm -r:. -c tpc %1.pas /$S- /GD + +