LnSOS BOOT 1.1 SOS.KERNEL SOS KRNLI/O ERRORFILE 'SOS.KERNEL' NOT FOUND%INVALID KERNEL FILE: xةw,@  ȱlmi8#)!)  ACIA NOTES  by Andrea Mennini When I bought my Apple /// in the early part of November 1981, I soon had some troubles using my serial printer (a Centronics 739-4BL) in Apple ][ Emulati5! *PRINT.MENU6! RUNAROUND6!6-READ.ME.FIRSTY88ARTICLESu' *ACIA.NOTES/Z+!CHEERS.BYLINES6\+!*-CONTENTS.MENU8 +! +EDITORIAL.2; +! MAGELLANB-!-&NEWS.2 >dLԡm#i㰼m#iЕOLԡȱfg hi !dLԡ憦  Ljmkm l y`2 Lԡ8(Je稽)ʈ@Lon. It didn't work. At the first I thought it was some human error, but on the contrary, it was the Emulation that didn't work. I phoned this problem to Apple Italy, and they said to me, "Sorry, we didn't know. Use the printer only in native Apple  !"#$%&'()*+,-./012345rocessor controls this pin via bit 0 of the Command Register. 12-RxD: RECEIVE DATA. The Rxd input line is used to transfer serial NRZ (No Return to Zero) data into the ACIA from the modem, LSB first. The receiver data rate is either the programmedf an external clock (as selected by the Control Register). 11-DTR*: DATA TERMINAL READY. This output pin is used to indicate the status of R6551 to the modem. A low on DTR* indicates the R6551 is enabled and a high indicates it is disabled. The p TxD output line is used to transfer serial NRZ (No Return to Zero) data to the modem. The LSB of the Transmit Data register is the first data bit transmitted and the rate of data transmission is determined by the baud rate selected, or under control othe Command register (see below). 9-CTS*: CLEAR TO SEND. The CTS* input pin is used to control the transmitter operation. The enable state is with CTS* low. The transmitter is automatically disabled if CTS* is high. 10-TxD: TRANSMIT DATA. THE XTLI pin, in which case the XTLO pin must float. XTLI is the input pin for the transmit clock. 8-RTS*: REQUEST TO SEND. The RTS* output pin is used to control the modem from the processor. The state of RTS* pin is determined by the contents of ted for receiver data clocking. 6-XTLI 7-XTLO: CRYSTAL PINS. These pins are normally directly connected to the external crystal (1.8432 Mhz) used to derive the various baud rates. Alternatively, an external generated clock may be used to drive thel cause internal registers to be cleared. 5-RxC: RECEIVE CLOCK. The RxC is a bidirectional pin which serves as either the receiver 16xclock input or the receiver 16xclock output. The latter mode results if the internal baud rate generator is selecSELECTS. The two chip select input are normally connected to the processor address lines, either directly or through decoders. R6551 is selected when CS0 is high and CS1* low. 4-RES*: RESET. During system initialization a low on the RES* input wilor at 16 times an external clock rate. It has also programmable word length of 5,6,7 and 8 bits; even, odd or no parity; 1, 1-1/2, 2 stop bits.  INTERFACE SIGNAL DESCRIPTION  [pin A negate is written as A*.] 1-Vss :Ground 2-CS0 3-CS1*: CHIP lled interface between 6502B and serial communications with the outside world. It also has an on-chip baud rate generator, and is capable of transmitting at 15 different rates, ranging from 50 to 19,200 baud, and receiving at either the transmit rate ll, Inc. So I quickly found the data sheet and "tryin'n'tryin" I discovered where its four registers have been mapped. The R6551 is a very useful and versatile circuit and provides, with only a crystal as external support component, a program-controthis idea until I discovered that by disassembling the ROM and studying the printed circuit board (a work of patience), that serial and RS 232-C interfaces are made with the same IC: an R6551 ACIA (Asyncronous Communication Interface Adapter) by Rockwe /// mode". What a strange thing that Apple didn't know something like that. From this phone call I understood that if an Apple user, and particularly an Apple /// one, has a problem, this has to be resolved by himself. I tried and tried following baud rate or the rate of an external generated receiver clock (as selected by the Control Register). 13-RS0 14-RS1: REGISTER SELECTS. The two register select lines are normally connected to the processor address lines to allow the processor to select the various R6551 internal registers. The following table indicates the internal register select coding: __________________________________________________ | | | | | | RS1 | RS0 | WRITE | er is characterized in a similar fashion: - Bit 0 is the leading bit to be received. - Unused data bits are high order bits and are "don't care" for the receiver. - Parity bits are not contnsmit Data Register is characterized as follows: - Bit 0 is the leading bit to be transmitted. - Unused data bits are the high-order bits and are "don't care" for transmission. The Receiver Data Regist/W* pin allows a write to the R6551.  TRANSMIT AND RECEIVE DATA REGISTERS  In the Apple /// they are mapped at $C0F0 (a unique bi-directional register). They are used as temporary data storage for the R6551 transmit and receive circuits. The Traoprocessor and the R6551. 28-R/W*: READ/WRITE. The R/W* is generated by the microprocessor and is used to control the direction of data transfers. A high on the R/W* pin allows the processor to read the data supplied by the R6551. A low on the Rto be connected to the common IRQ* microprocessor input. Normally at high level, IRQ* goes low when an interrupt occurs. 27-@2: INPUT CLOCK. The input clock is the system @2 clock and is used to syncronize all data transfers between the system micrl and are normally high-impedance, except during Read cycles when R6551 is selected. 26-IRQ*: INTERRUPT REQUEST. The IRQ* pin is an interrupt output from the internal interrupt control logic. It is an open drain output, permitting several devices ed it should be driven high or low, but not switched. 18-D0 19-D1 20-D2 21-D3 22-D4 23-D5 24-D6 25-D7: DATA BUS. The D0-D7 pins are the eight data lines used to transfer data between the processor and the R6551. These lines are bi-directionanput and must be connected. 17-DSR*: DATA SET READY. The DSR* input is used to indicate to the R6551 the status of the modem. A low indicates the 'ready' state, and a high 'not ready'. DSR* is a high-impedance input and must be connected. If unus DATA CARRIER DETECT. The DCD* input pin is used to indicate to the R6551 the status of the carrier detect output of the modem. A low indicates that the modem carrier signal is present, and a high that it is not. Like DSR*, DCD* is a high-impedance i through 4 in the Command register and bit 2 in the Status register. The Programmed Reset is slightly different from the Hardware Reset RES*; these differences are described in the individual register definitions. 15-Vcc:+5V power supply. 16-DCD*: 1 | Control register | |_______|_______|__________________________________| Note that only the Command and Control registers are read/write.The Programmed Reset operation does not cause any data transfer, but is used to clear bits 0________________|________________| | | | | | 1 | 0 | Command register | |_______|_______|__________________________________| | | | | | 1 |_______|________________| | | | | | | 0 | 1 | Programmed | Status | | | | reset (Data is | Register | | | | 'Don't care') | | |_______|_______|_ READ | |_______|_______|_________________|________________| | | | | | | 0 | 0 | Transmit data | Receive data | | | | Register | Register | |_______|_______|__________ained in the Receiver Data Register, but are stripped off after being used for external parity checking. Parity and all unused high order bits are "0".  STATUS REGISTER  The Status register is mapped in the Apple /// at $C0F1 and reports the status of various R6551 functions: 7 6 5 4 3 2 1 0 _______________________________________________ | | | | | | | | | |_____|_____|_____|_____|_____|_____|_____| | | | | |-------------------- Transm. interr. control | | | | | | 3 2 | | | --- | | | | |---------- Interrupt req. disabled | | | | | | | | 0= IRQ Enabled | | | | 1= IRQ Disabled | | | | | | | | | | | | 0= Ready [DTR* high] | | | | | 1= Not ready [DTR* low] | | | | | | | | | | |______|______|_____|_____|______|______|_____|_____| |______| | | |______| | | | | | | | | | | | | | |---- Data Terminal Ready | | | | | | | | PMC | | | TIC | | | |_____________| PME | REM |_____________| IRD | DTR | | | | | | | | | | | PNC1 | PNC0 | | | TIC1 | TIC0 | Interrupt has occurred (*) No interrupt occurs for these conditions.  COMMAND REGISTER  The Command register is mapped in the Apple /// at $C0F2 and controls specific modes and functions: ___________________________________________________ | 1= DSR* high (not ready) | |---------------------------------------------- Interrupt IRQ* 0= No interrupt 1=etect) | | 1= DCD* high (not detected) | | | |---------------------------------------- Data Set Ready DSR* | | 0= DSR* low (ready) | 0= Not empty | | | 1= Empty | | | | | |---------------------------------- Data Carrier Detect [DCD*] | | | | 0= DCD* low (d 0= Not full | | | | 1= Full | | | | | | | |---------------------------- Transm. data register empty | | | | | | 0= No overrun | | | | | 1= Overrun has occurred | | | | | | | | | |---------------------- Receiver data register full | | | | | | | | raming error | | | | | | 1= Framing error detected | | | | | | | | | | | |---------------- Overrun (*) | | | | | | | | | | | | | 1= Parity error detected | | | | | | | | | | | | | |---------- Framing Error (*) | | | | | | | | | | | | 0= No f_____| | | | | | | | | | | | | | | | |---- Parity Error (*) | | | | | | | | | | | | | | 0= No parity error | | | | 0 0 RTS*=Hi,interr.dis. | | | 0 1 RTS*=Low, " en. | | | 1 0 RTS*= " " " | | | 1 1 RTS*= " " dis. | | | Transmit brk | | | on TxD | | | | | |------------------------- | 1 1 1 1 19,200 "" | | | | | |-------------------------------- Receiver clock source | | | | 0= Ext. receiver clock |600 "" | | | 1 1 0 0 4800 "" | | | 1 1 0 1 7200 "" | | | 1 1 1 0 9600 "" | | 1 0 0 0 1200 "" | | | 1 0 0 1 1800 "" | | | 1 0 1 0 2400 "" | | | 1 0 1 1 3 | | 0 1 0 1 150 "" | | | 0 1 1 0 300 "" | | | 0 1 1 1 600 "" | | | 0 0 1 50 Baud | | | 0 0 1 0 75 "" | | | 0 0 1 1 109.92 "" | | | 0 1 0 0 134.58 "" | | | 3 2 1 0 | | | ------- | | | 0 0 0 0 16xext. clock | | | 0 0 | |_____|_____|_____|_____|______|______|______|______| | |_____| | |______|______|______| | | | | | | | |--------------- Selected Baud Rate (SBR) | | | | | | | | | WL | | SBR | | SBN |___________| RCS |___________________________| | | | | | | | | | | | WL1 | WL0 | | SBR3 | SBR2 | SBR1 | SBR check dis.  CONTROL REGISTER  The Control Register is mapped in the Apple /// at $C0F3 and selects the desired baud rate, frequency source, word length, and the number of stop bits: ___________________________________________________ | | 1 0 Mark parity bit TX Parity check dis. 1 1 Space parity bit TX Parity --- 0 0 Odd parity TX/RX 0 1 Even parity TX/RX Parity check disabled | 1= Parity mode enabled | |---------------------------------------------- Parity mode control 7 6----------------------- Parity mode enabled | | 0= Parity mode disabled | No parity bit gener. | ----- Receiver echo mode (REM) | | | | 0= Receiver normal mode | | 1= Receiver echo mode | | | |------------- | 1= Baud rate | | | |----------------------------------------- Word length (WL) | | 6 5 | --- | 0 0 8 bits | 0 1 7 bits | 1 0 6 bits | 6F Sets CSW to $9316 (beginning of this routine). 9308- 8D F1 C0 Sta $C0F1 Reset ACIA. 930B- A9 0B Lda #$0B Sets 8 bit, no parity, RTS* low. therwise send a LF. LDA #$8A JSR SENDCHR END RTS Listing 2 - Commented Apple /// version program 9300- A9 16 Lda #$16 9302- 85 6E Sta $6E 9304- A9 93 Lda #$93 9306- 85 6F Sta $ STA RTREG ;Writes character onto receive/transmit ;ACIA register. CMP #$8D ;Is it a CR ? BNE END ;If not,return to caller. PHA ;O LDA #$2B STA CMDREG LDA #$28 STA CNTREG ;Sets ACIA environment (see article ). RTS SENDCHR PHA EOR #$10 AND #$70 BNE LOOP ;Verifies parity and AKN. PLA QU $C0F2 ;ACIA Command Register. CNTREG EQU $C0F3 ;ACIA Control Register. LDA #$19 STA CSWL LDA #$03 STA CSWH ;Sets intercept point routine. JSR SETPTR STA STSREG ***************************** ORG $C500 OBJ $300 CSWL EQU $36 CSWH EQU $37 SETPTR EQU $3EA RTREG EQU $C0F0 ;Receive/Transmit ACIA Register. STSREG EQU $C0F1 ;ACIA Status Register. CMDREG E ** ** PRINTER DRIVER ROUTINE ** ** ** ** BY ANDREA MENNINI ** ** ** tor version of this program is NOT supplied here (I don't know where to put it). Here are program listings: Listing 1 - Apple ][ version program ***************************** ** disk, which may contain other files, instead of an Apple ][ one. However, this program may be easily converted into an Apple ][ text file with the Apple Writer /// utilities or with ProDOS convert utilities. Also for editorial reasons, Apple /// monihen a PR#5 will enable the printer and a PR#0 will disable it. A brief note: For editorial reasons this program is available on this disk in Apple /// text file form with the name A2.PRINTER, as it is more useful to have it on an Apple /// formattedve and writing ORiGin $300. The second is written instead as a patch for the emulation program, and that's why it has ORiGin at $C500, but OBJect at $300. To patch the emulation disk, simply write this routine at track 5 sector 1 with a disk zapper; t (For WL=8 and parity) With this information it was easy to write a routine that solves my problem, and I have done this in two versions. The first routine may be loaded at $300 simply by eliminating the OBJect directi stop bits = 1-1/2 stop bits (For WL=5 and no parity) = 1 stop bit 1 1 5 bits | |-------------------------------------------------- Stop bit number (SBN) 0= 1 stop bit 1= 2 Transmit interrupt enabled. 930D- 8D F2 C0 Sta $C0F2 9310- A9 0E Lda #$0E Sets for 8 bit, no parity, 9600 baud. 9312- 8D F3 C0 Sta $C0F3 9315- 60 Rts 9316- 48 Pla COUT routine comes here with character to be printed in A:save it. 9317- AD F1 C0 Lda $C0F1 Take status register. 931A- 49 10 Eor #$10 931C- 29 70 And #$70 Transmitter data register NOTMENU Contents Arrival Positional, Alpha BEGIN Editorial Text Editorial.2 /Articles New Products and News Text News.2 /Articles Magellan: From SOS to CP/M and Back Again Menu Magellan/Magellan.Menu /ArticIssue Two Released May l985 Marlys Christensen Mike Christensen Bill Janes Andrea Mennini NINI VIA E.MANFREDI 2/II I-40138 BOLOGNA (ITALY) the beginning of this article, the Apple /// situation in Italy is very poor, so I would like and appreciate everyone writing to me to exchange information about the Apple ///. My address is: ANDREA MENrse you can save the program in any block you want, even if not number 0. Type 9300G to enable the printer, 9333G to disable, and have fun. /// /// /// /// /// /// /// /// /// /// /// /// /// /// A footnote: As I have said at ith comments. The use of Apple /// version is simple. Write it exactly like listing 3, and save it on a non-SOS disk (I use a disk formatted by System Utilities without SOS, where I have a Disassembler for Apple /// Monitor) with 0<9300.933DW. Of cou0: A9 0E 8D F3 C0 60 48 AD F1 C0 49 10 29 70 D0 F7 9320: 68 8D F0 C0 C9 8D D0 07 48 A9 8A 20 16 93 68 60 9330: EA EA EA B5 04 BD B3 FF 95 6D CA D0 F8 60 I think these routines need no further explanation, since they are very simple and also explained w into 9339- CA Dex zero page locations CSW and KSW. 933B- D0 F8 Bne $9335 933D- 60 Rts Listing 3 - Apple /// version hex listing 9300: A9 16 85 6E A9 93 85 6F 8D F1 C0 A9 0B 8D F2 C0 931 for best remainder. 9333- B5 04 Ldx #$04 This routine gets addresses of CSW and 9335- BD B3 FF Lda $FFB3,X KSW stored in the ROM at $FFB4, 5 and 9337- 95 6D Sta $6D,X $FFB6 respectively,and stores them. Get character. 932F- 60 Rts End. 9330- EA Nop These three NOP's are dummy code 9331- EA Nop in order to have reset routine at $9333 9332- EA Nop p #$8D It's a CR? 9326- D0 07 Bne $932F No, stop. 9328- 48 Pla Yes, save character. 9329- A9 8A Lda #$8A 932B- 20 16 93 Jsr $9316 Send a LF. 932E- 68 Pha empty and no interrupt? 931E- D0 F7 Bne $9317 No, retry. 9320- 68 Pha Yes, take character. 9321- 8D F0 C0 Sta $C0F0 Send to printer. 9324- C9 8D Cmles Run Around: A Game for the Apple /// Menu Runaround/Runaround.Menu /Articles ACIA Notes: Using Your Printer In Emulation Text ACIA.Notes /Articles Print Articles on Paper Menu Print.Menu /Articles Goodbye 79e (my in-house programmer and co-producer of /// Cheers!) has reworked it to fit in the software style of the magazine itself, and it now includes a CP/M diskette maker for you to experiment with, even if you don't ordinarily use CP/M. Run Around ifor it for quite some time, and we hope you'll find both challenge and fun as you work your way through it. The article "Magellan: CP/M to SOS and Back Again" is an adaptation of a very good Pascal program submitted by Bill Janes some time ago. Mik As you do, we would appreciate your sharing them with us in a letter, or as a submission for publication. (Don't forget to read the Author Guidelines at the end of the magazine.) Well, here's Issue Two of /// Cheers. Some of you have been waiting ncreasing your knowledge and experience, even if you have been using your Apple /// for a long time. Even "old pros" can get excited about new discoveries, or about delving into a new area of the computer world that they have up to now left untouched. in the big world of microcomputers. I am making "discoveries" almost every day. /// Cheers, being born in the summer of 1984, could be thought of as being a toddler too. We're gaining experience and wisdom as we go. We hope that the magazine is iving my Multiplan equation come out right, or being able to interpret a little piece of code than about anything else I can think of happening lately. And just as a toddler may say a new word almost every day, I too am learning to communicate a little in the big world is still brand new and wonderful. In the world of the Apple ///, and in the whole world of computers for that matter, I feel somewhat like a toddler. I get more excited about getting my print-out to look just the way I want it, or ha:<=>?@Awn a step with no one holding on, make a six-block tower without having it fall, "draw" a picture with a fat red crayon, spot Grandpa in the photo album and say his name so that anyone could understand. When you aren't even two years old yet, so much  E D I T O R I A L  by Marlys Christensen If you have ever been around a toddler much, you probably know the excitement of seeing them learn something new -- go do Exit None /None END. s a mini-game that your whole family can play. It's based the game of the same name that can be found in the old Apple ][ Software Library. I have never been much of a game enthusiast, but I'm still trying to beat Mike at this one. Andrea Mennini, an Apple /// user in Italy, has an article in this issue about talking with printers in emulation mode. There is a good deal of technical information about the Asynchronous Communications Interface Adapter chip used in the ///, and a program to supportng as DOS 3.3 and Pascal: 35 tracks (numbered 0..34) of 16 sectors each (0..15). See the "Apple // DOS Programmer's Manual (#A2L2012)" for more detail. Pascal disks are logically organized into blocks, not individual sectors. Each block contains twwrite(ln). However, some additional outlay is necessary to move the text in and out of the blocks. Input and output to the CP/M diskette is more difficult, but is made possible by the fact that Apple CP/M disks have the same track and sector formattifiles can be done via standard Pascal procedures. The medium level procedures blockread and blockwrite are used to transfer whole blocks of text at a time, which is considerably faster than transferring one character or line at a time with read(ln) or d by the programs as currently written, but it would be easy to revise the programs to transfer binary data. [This feature has since been incorporated -- Editor] Since these programs are written in Pascal, transfer of text into and out of the Pascal s a bridge for the conversion of numeric files. However, additional processing may be needed in the case of numeric files, and this topic is beyond the scope of this article. Binary files (such as high resolution graphics pictures) can not be processeCEFGHIJKLMNOPQRSTUVWXYZ[\he CP/M based word processing program WordStar, while maintaining compatibility with standard CP/M text files. Since MBASIC CP/M sequential files store numeric data as text and Pascal can store numeric data in a text file, the programs could be used a  M A G E L L A N: A TECHNICAL OVERVIEW  By Bill Janes My chief goal in writing the conversion programs described in this article was to gain the capacity to interchange text files between Pascal and t2!#B-MAGELLAN.TEXT<3!(BPARTSETS3! B,PROCSEC.TEXT4! BSOURCE.MENU4!BTRANSFER.TEXTp5! BMAGELLAN.DATAh8 h8 BMAGELLANv-' ',CPMTOPAS.DOCD00! B-MAGELLAN.CODE^,0!2BMAGELLAN.DATAt1h8 B,MAGELLAN.DOCv.2!BMAGELLAN.LIB#2!BMAGELLAN.MENUd library is stored as SYSTEM.STAR.LIB on the /CHEERS diskette, and a map of its interface has been included on /CHEERSBOOT. In the next issue, we'll clue you in on how the programs interact with "Boats". printing in emulation mode. At press time, not all of the Magellan source code would fit on the disk. The remaining source will be published in the next issue. Both Magellan and Run Around source code reference a library called "Boats". The kruncheo sectors (but the sectors aren't necessarily adjacent on the disk). The blocks can be read from or written to with the low level Pascal procedures unitread and unitwrite respectively, and these procedures can also be used with CP/M disks. Once the relationship between blocks and sectors is known, one can read or write to any desired sector. When reading, a whole block is read, but only the pertinent sector is used. Writing is slightly more difficult, since writing a block (two sectors) would oveten to, free blocks are allocated to the file, starting with the first free block. When files are written to a freshly formatted disk the blocks in each file will be in ascending order and begin at block 2, but as files are erased and new files added, or data (tracks 0-2 are reserved), a disk contains a total of 128 blocks. Blocks 0 and 1 contain the directory and the remaining blocks are available for data storage. The block indices are simply a list of the blocks in the file. When a file is writis size allocation is known as a block (not to be confused with a Pascal block). The block is the smallest amount of space that can be allocated, the minimum size of a file is therefore four sectors (1024 bytes). Since there are 32 tracks available f. The next two bytes (13-14) are not used on the Apple. Byte 15 is the record count (each sector contains two records). The next 16 bytes (16..31) are the block indices. CP/M allocates disk space in groups of 8 records (four Apple sectors), and thng information is unaltered. The next eight bytes (1-8) constitute the file name (padded with blanks if necessary) and the succeeding three bytes (9- 11) the file type, which is optional and also padded with blanks. Byte (byte 12) is the extent numbert occupies 32 bytes. Byte zero is the user number; in the Apple, a user number of 0 indicates that the slot is in use, while a number of 229 (hex E5) indicates an open slot. If a directory entry is erased, the user number is set to 229 and the remainieaving two sectors unused-- see below about blocks). Eight directory entries (directory slots) fit into each sector, giving a maximum of 48 directory entries. However, a large file may use more than one directory slot (see below). Each directory slo adjacent records and not bother any further with records. The first three tracks (0..2) of the CP/M disk are reserved for system use (the CP/M image is stored there). The directory starts on track 3 and occupies six sectors (actually 2 CP/M blocks, land the interested reader should refer to the above references for more information. Although the CP/M file structure is logically arranged into records whose size is 128 bytes each, for practical purposes one can assume that each sector contains two the May/June 1982 issue of Microsystems contains the necessary information. Another useful source is "The CP/M Handbook" authored by Rodnay Zaks and published by Sybex. The following comments are only a brief summary of the CP/M directory structure, occupies. The most difficult part of this project was the problem of unravelling the directory structure of CP/M, which is not well documented in the CP/M literature. The article by Andrew Klossner "CP/M Disk Directory and Table Secrets Revealed" ine must first check the directory to determine the sequence of sectors to be read. In writing to a file, one must check the directory to find free sectors, write to them, and then update the directory to reflect the name of the file and which sectors itram "Puffin" by Tom Woteki, in the November/December 1981 issue of Call-A.P.P.L.E.. He uses the same approach in converting DOS files to Pascal. The key to the whole process is an understanding of the directory structure of CP/M. To read a file, onrwrite a sector. To avoid this, one first reads the appropriate block into a buffer, transfers the sector to be written into the buffer, and writes the buffer back to the file. For additional details, the interested reader is referred article and progthe ordering may become chaotic. Each directory slot contains a maximum of 8 block indices, and so each slot can represent a maximum of 16k of data. For larger files one directory slot is needed for each 16k of the file, and these 16k segments are termed extents. The extents are numbered from 0 upwards, and the extent number is recorded in the directory (vide supra). In a multi-extent file, the file name and file type are duplicated in each slot, but when the directory is listed, only the data ined during the conversion process. WordStar also introduces control characters into the text for special formatting purposes. These do not print, but have no meaning in Pascal, and are best removed. In the conversion process any non-printing characterSCII code is normally clear in both CP/M and Pascal (seven bits are sufficient to represent all the ASCII characters, and bit 7 can be used for special purposes). WordStar often sets the high bit for various special purposes and this bit is best clearase you might be concerned about a feature you don't need, the overhead required to support WordStar is minimal. To preserve compatibility with WordStar a few more alterations are necessary when going from CP/M to Pascal. The high bit (bit 7) of the A to the required length. CP/M uses a control-Z to indicate the end of the file, and any unused space in the sector is padded out with control Z's. The few paragraphs are concerned with WordStar. If you don't use WordStar, just skip over them. In cs terminated by a carriage return (ASCII 0D), while a CP/M line of text is terminated by carriage return plus a linefeed (ASCII 0A). The Pascal text file must have an even number of blocks, and the file is padded out with nulls (ASCII 0) to bring it ups to bring the text pointer over to the next tab location (the tab locations are spaced 8 spaces apart). The Pascal editor does not use tabs, so expansion of control-I's to blanks is necessary when going from CP/M to Pascal. A line of text in Pascal ind the DLE's into blank spaces when going from Pascal to CP/M. In CP/M files, tab spaces (frequently found in assembly language listings) are coded as control-I's (ASCII 0B). When such a character is encountered it is necessary to insert enough blankding blanks that are associated with the frequent indentations used in Pascal programs. If present, the DLE is followed by a byte indicating the number of blank spaces that the code represents. This code is not used in CP/M, so it is necessary to expa conversion process, it is sufficient to fill the header with ASCII nulls. The editor also requires that the file have the suffix '.text'. Each line of text in Pascal is optionally preceded by a DLE (ASCII 10) which is used for compression of the lea in the formatting of text files in the two systems, and these differences must be taken into account in the conversion process. In Pascal, a text file is preceded by a 1024 byte header (two Pascal blocks) that is reserved for use by the editor; in thefor the logical-to- physical mapping. [See the March 1985 issue of Call-A.P.P.L.E. for an excellent, illustrated treatment of Pascal and ProDOS sector interleaving: ProDOS and SOS have exactly the same mapping -- Editor] There are a few differences is stored in an array. To find the physical sector corresponding to the n-th logical sector, one merely accesses the n-th element of the array. This is equivalent to a lookup table in assembly language, where such a table is the method usually used e ordered consecutively on the disk, and logical sectors are ordered consecutively in the file. Of course, Pascal and CP/M use different sector interleaving! In these programs the relationship between the logical and physical sectors of the CP/M disk the first slot are printed. One final complication involves what is known as sector interleaving. The sectors on a diskette are not written to consecutively, but in a staggered fashion, a process known as "sector interleaving". Physical sectors ar is removed, so the control characters are removed without the need of checking for them specifically. One final WordStar feature involves the representation of hyphens and carriage returns. Hard hyphens are immutable and not affected by the reforming process. They are represented by the usual ASCII code 2D. Soft hyphens are hyphens represented by a special code and printed only if they fall at the end of a line. A soft hyphen within a line (and not printed) is represented by 1E, and one aعIllegal filenameתPצNo room on volumePצVolume not on linePFile not in directoryתPpDiskette is write protectedתPLhO =P ++ I/O Error# +[+P+צError,!a ]_`abcdefghijklmnopqrs@Pn_d6ac?;TNNff[[sCopyright 1981 1982 1983 Apple Computer Inc.(MAGELLAN human interface. You'll probably want to read the companion article "Magellan: Sailing Around the Horn of CP/M" before running the program. -- Editor] ing is done; otherwise, the text would be converted to one large paragraph. [The balance of Bill's original article discussed the operation of the programs. The programs have been combined and altered quite a bit to conform to the Apple /// and our ovides this optional conversion. If this option is employed, the program still tries to place a hard carriage return between paragraphs. Nonetheless, the user should make certain that paragraphs are delimited by hard carriage returns before any reforma WordStar paragraph. If no subsequent editing of the file by WordStar is to be done, this is of no consequence. However, if editing by WordStar is contemplated, the Pascal carriage returns are best converted to soft carriage returns. The program prand are not affected by reforming, thus preventing the merging of paragraphs during the reforming process. Pascal files use only regular carriage returns (0D), and if these were brought over to WordStar directly, each Pascal line would be converted to bit set) respectively. Soft carriage returns are used to delimit lines within a paragraph, and may be converted to blanks if they no longer fall at the end of a line when the paragraph is reformed. Hard carriage returns are used to delimit paragraphs , soft hyphen at the end of a line (1F) must be changed to regular hyphens (2D). Soft hyphens within a paragraph are non-printing characters and are removed automatically. Carriage returns may be hard or soft, and are represented as 0D and 8D (high t the end of a line (where it is printed) by 1F. When a paragraph is reformed by WordStar, previously introduced soft hyphens may no longer fall at the end of a line, and these are converted to the non-printing type. During the file conversion processښڕ4ƁƁʁʁ:        ȡá ȡ ݢݢǀĻݢǀĻȡ$ݢˡ$~⨃`f^ߨ5ݪP ܪPƉkƋ ̃̃̃̃Ɖk á6ƃ Pƃ',& ƃƋ ƋƃƋ ۹_̃iƄk  ̃̃̋ʃʋȡ3ƉkƄk ʃ̃"̃ʃʃƃʃ̃ަ R/W ̃̇ʃʇȡ1ʇʃ ˡʇʃʃ̃ʇ ˡ.ʇ ʃ̃ʃ̃١ʃʃá , %̃ʃʃ̃ٓ~~ʃʃʃƇQƃƇw*-=ág...ƃ١ ʃʃ(̃̃ʃȡ ʃƃƃ ʃ///ÓٓʃÓʃ ƃʃƃCD>Hპ̃ʃʃ̃ʃ kʃ ʃ//̇ʇצ R/O ilable ( צ% free)   ܨ`ۨ̃(̃̃̃ƃצRecs Bytes Ext Acc FilenameṖƃʃʇʇ! Ƈ*ʇ CP/M DirectoryתPʃʃƃƇw*١(%ƃʃƃ%, PrintinKBytes available ( צ%) , ަ  ަ files listed using  ަ KBytesצ' If standard CP/M-Apple diskette, thenަ  ަ of  ަ KBytes avaound in CP/M directory.vƃ,!d܆ء %ݢ( ƃ*  צ files listed using  צ KBytesަ& If standard CP/M-Apple diskette, then  ަ of  ަ ȡޛ ȡޛDh Jߨ`2ި ݪP ƃƃȄ8J2//̃ƃʃ ƃʃ  J2W+צFile Not Found̃ƃ Pƃ& could not be f//ʃ// ̃ʃ*ʃ//ʃ̃ !.á ܕȄߓ.+ErrorצInvalid CP/M directory entry.,!ߡ  á  ȡޛH#Hl ߡh /Ȅ&/    1+צMessage to UserצFile already exists,!h ݨ`ܨ̃̃ʃ//ʃʃʃ//ʃ// ʃ.D1P0ئ.D2תP%צ.D3Pئ.D4תP3*!*=ƃ*^ !.á ޕȄ y  á  ȡ H  ȡ  ȡ  ޥ [C. r*آRead CP/M files from where?תPآ,צBuilt-in drive *צDrive 2*ئDrive 3*צDrive 4* ̄1=ƃ(=ǃ](=ƃ(%%  * ,٣M צ.D2Pڹ,צ}////   Q//// .////ɡ   0  ȡK ȡ* ؍/  @ڶ/ڶ/ڶ/ڶ/> ȡ/ބݕȡ////   //// ݢݢݢݢȡݢ ݢ ݢ Í?ݢ ˡݢ ݢ ǀݢ áݢ ݢ ˡݢ gckm̃̋ʃʋȡ̃~f//̋̃̋ʃʋȡʋ ʃˡʋ ʃ̃ʃ̃ʃ̃ʃ̃ʃʃʃʋɄʃʃ^ʃ Ƅkƃƃƃ& Ƅkʃ ʃ̃̃ʃšʃ儡ʃƄk ̃ʃʃɄTʃߕ̃Ƅkʃ Ƅkʃʃނ ʃʃނƄkʃ ʃ ʃʃނ̃ƉkƄk ʃ̃"̃ʃʃƃʃ̃ʃˡƄk Ƅk ʃʃ̃ʃ̃ʃ̃ʃ̃*צCP/M SOS Pascal Text*צCP/M SOS Data or Binary*ئ*צSOS Ascii CP/M*ئSOS Pascal Text CP/M*צSOS Data or Binary CP/M*ئ*צQuit*# ,̀ʀ<.!6Message to UserצDiskette is now a CP/M blank.,!ƀƄs(  * *آMagellanתPآ,ئList CP/M directory*צPrint CP/M file*ئMake new CP/M diskette*ئ*צCP/M SOS Asciiine will replace the SOS directoryצ)of the diskette you've just inserted withצa blank CP/M directory.%'Any files on the diskette will be lost!%צ"Are you sure you want to do this? 6 ʁ ʁ́O !6ۨQ.ڨتP:VצMake a Blank CP/M DisketteP6F ƀƄs*ƀ̄Ƅצ+Insert a blank SOS formatted diskette into +Ƅ{ƄPƀ 6,ʀÓF (%צ+This rout́́ʁʁȡ# ʁʁ́ʁ́́́ʁʁȡ# ʁʁ́ʁ́ ʁʁ́ ʁʁ́ ʁʁ́ ʁʁ́́́ʁʁȡ# ʁʁ́ʁ́uƆuƆ}ƈ̈ƈ;Pƈצ Sƈǣƈ̪PƈHšƈƈƈHƈ̪Pƈ!+Transfer Completeƈ,!Ɔ}4$٨́/́ʁʁȡʁ́ ʁ Ɓ Ɓ  ʁ ʁ ʁ ́ ʁʁ́ rƆ}ƅurrڹ#uƅust#uƅutuƅu-pšQu  dƆuqomnpppˡu u ppˡ;u ppp  dƆuqomn domnƅ۶p Ǎ۶p pp۶p pp ppd;ߪPުPݨ ܨƆ}ƈonڹ rr  ptƆumƆ};"llˡ l +NƆ}ݳܶp ppS áNܶp Ǎܶp ppܶp pp ȡܳ۶p ppS áNdr oáݶooooo@á) ޶ouݮoݮ ȡá1 ȡܶp pp%%%%%%%%%%%$&$&ȡ$% $%%$$">8 |ȡ'No more room on disk directory slot.,!^ lߨި ب/&&&##"!" !%%%%$&$&ȡ&%$%%$$$&$&ȡ&%$%%$$%leteƄ,!ʃƉk-;=S>j#ƁƁʁʁʁLȡ(/ȡ*/á/+צErrorצNo freeʃˡ>Ƅkʃ ʃ ƉkƄk ʃ̃"̃ʃʃƃʃ˄8Ƅk  ƉkƄk ʃ̃"̃ʃʃƃƉk"̃ʃánƄ̋Ƌ5PƋ SƋ ǣƋPƄHšƄƄƋHƋPƄ!+צTransfer CompتPƅgƇƁ#*Ɓtƅ6(Ɓtǃnj(Ɓtƅ6(ƀ#ƀ * ƀ,̀Má ̀ʀ Óʀ"7ƀ5Ƈ.7ƀ5Ƈ )+135(*,̀ʀ{ݦCP/M file to transfer? @,&MÓ5643ƀLצSOS path of file to transfer? ,̀ FHJMʀʀ Send outputצ to .CONSOLE?,)MÓ 5@ƀ,5MÓ-ƅg+[ƅg5ʀƅgƅgƀ,MÓ7ƀ6ݧ+[43System Utilities, it is not possible to see (or even imagine) a CP/M diskette file. On the other coast, CP/M has no notion of a SOS diskette or its directory. We don't know for certain whether this program, Magellan, and its routines are the first euwxyz{|}~aps the first Europeans to sail around the world. CP/M and SOS, though both run on the Apple ///, are worlds apart. They are separated by vast oceans of structural differences. From the shores of programs like  M A G E L L A N: SAILING AROUND THE HORN OF CP/M  by D. Michael Christensen As you probably remember, Ferdinand Magellan and his companions were perhHELP/HELP.MENU78@ 1984 by Donovan's ReefVersion 1.2 With AccessoriesBoatsA6REMOUT8::!I.D1  .PRINTERLESTULONGINTICHAINSTUPGRAF PGRAF STANDARD.PRINT CHAR/CHAR.MENUDINGTIUlLUMSECS JDAINCREMUU#DATE LDALASTDAKV#DATE LDAMONTHI& >Lʀ áƀ*Ɓtƅ6(Ɓ#Qƅg(*,LPRTV " !"7ƀ643ܦSave as what CP/M file? @,&MÓƇƇ MÓʀ=Substitute soft carriageצreturns for Wordstar?,)̇MÓƀ̇ƇBe sure Ƈ XƇצ* holds the CP/M diskette to be writƀ צSave as what SOS Ascii file?,"MÓ7ƀ643צSave as what SOS text file?צ,"NMÓFצ.TEXTá!̇ƇPƇצ.TEXTUƇP7ƀ643צSave as what SOS data file?צ,"MÓxploration party to sail from SOS around the horn of CP/M and back home again; but we are certain that it can help make the distance between the two continents smaller. And Magellan can as easily port ProDOS files from shore to shore, since ProDOS and SOS directories share the same file format. If you're thinking you need a special board to run this program, you're mostly wrong. Having a Z-80 board may make this program more useful to you, but it is not a requirement. Everything about Magellan hl three of these routines move SOS files to a CP/M diskette. You must provide a valid CP/M destination file name. CP/M file names are from 1 to 8 characters long, begin with an alphabetic character, and may be followed by a '.' and a suffix of 1 to 3g CP/M directory. It's really only clears the directory, but at that point the old files are lost and the CP/M "DIR" command shows an empty diskette.  SOS Ascii File -> CP/M   SOS Pascal Text File -> CP/M   SOS Data or Binary File -> CP/M  Aled blank diskette into a blank, CP/M diskette. Follow the prompting, being careful to get the right diskettes in the right drives. After about 20 seconds, the job is complete. This option is also useful for quickly clearing the contents of an existinback to SOS, and see if your file looks anything like what it did before it left.  MAKE A NEW CP/M DISKETTE  Let's suppose you don't have any CP/M diskettes to work with. You can use the option "Make a New CP/M Diskette" to convert a SOS formattgood idea to backup any diskettes you will be using with this program before you begin. To experiment, you may want to create a CP/M diskette, copy a SOS file to the new CP/M diskette, and list the CP/M directory. Then try moving the file from CP/M with CONTROL A). Each option has prompting, so you should be able to learn much of the program by exploring. Follow the prompts carefully, because a mistake could result in losing part or all of the information on your diskette. It's probably a s menu, the CP/M diskette's directory is read into memory. You can switch CP/M diskettes if you want, but remember to do it BEFORE you select an option. Otherwise, the menu works just like any other /// Cheers menu (you can even call the AccessoriesOS Pascal Text File -> CP/M SOS Data or Binary File -> CP/M Quit Now this is important: always insert the CP/M diskette in the drive you designated BEFORE you select an option. Every time you pick something from thiry Print a CP/M File Make a New CP/M Diskette CP/M -> SOS Ascii File CP/M -> SOS Pascal Text File CP/M -> SOS Data or Binary File SOS Ascii File -> CP/M Ss, but not CP/M. If you called Magellan from /// Cheers, and Magellan is in drive 2, it will be most convenient for you to select the built-in drive to read CP/M diskettes from. The main menu looks sort of like this: List a CP/M Directodouble density floppy. Only standard 16-sector diskette drives are supported; we were squeamish about "unitwriting" CP/M files to larger and less familiar devices like Profiles. You will be able to use Profiles and the like to read and write SOS filete drive you want to read CP/M information from. Read CP/M diskette from where? Built-in drive  Drive 2 Drive 3 Drive 4 There are only 4 choices, and not one of them is a harddisk or a e must be a diskette drive. Sorry, no canoes.  A BRIEF OVERVIEW  When you first run the program, a greeting will appear. As always, press the SPACE BAR and the greeting will roll into something more interesting. You are asked which disketappens in SOS. We even went to some trouble to let you convert a blank, formatted SOS diskette into a CP/M formatted blank diskette. It's like going to America without getting wet. This program does, however, require at least 2 disk devices, and on characters. The suffix is called the "file type". Here are some examples to give you a start: ABCDEFGH.ABC is valid A is valid because you don't have to include a file type ABC. is invalid because the file type needs at least 1 character ABCDEFGHI is invalid because the file name is too long (8 chars max) ABCDEFGH.ABCD is invalid because the file type is too long (3 chars max) 123 is invalid because the file name must begin with an alpha A123 is va file type is a text file. To test this option, try moving a Pascal file from SOS to CP/M and bring it back. Then, if you have Pascal, try to compile it. It should compile. This transfer (as well as the Ascii transfer) goes quite a bit quicker than [Technical note: This problem occurs because Magellan pads the unused portion of the last block of data transferred with null characters, and sends the whole last block all at once.]  CP/M -> SOS Pascal Text File  With this option, the resultingthis option will show null characters at the end of the file (they may look like little "NU"s or like solid Apples). If this happens, just delete the characters, and save the file; when you load the file in the next time, the characters will be gone. The program adjusts funny characters that may have come from WordStar (things like tabs, soft carriage returns, hyphen markers, and others). The transfer ends when a CONTROL-Z is encountered in the CP/M file. Sometimes a file brought up from CP/M with ers that your printer will interpret as tabs and form feeds. Files with the suffix ".TXT" usually waste a lot less paper and are easier on the platen.  CP/M -> SOS Ascii File  This option takes your CP/M file and turns it into a SOS Ascii file. print to the screen. You probably don't want to try to print any files with a file type of ".COM" or ".OVR", since these are usually programs, overlays and binary files -- they make a terrible mess when you try to print them since they contain characts available (87% free) The program pauses for a SPACE BAR as the window becomes full. Output can be directed to the printer or to a file.  Print a CP/M File  You can print a file to the printer with this option, but it doesn't allow you tobytes the file takes up (1 kilobyte = 2 SOS blocks) | Number of 128 byte records the file takes up (4 record per SOS block) This message is also added: 2 files listed using 17 KBytes If standard CP/M-Apple diskette, then 109 of 126 KByteead/Write (unlocked) and R/O is | | | Read Only (locked) | | | | | Number of directory entries used up (48 maximum -- large files | | may use more than 1 entry slot) | | | Number of kiloion does just what is says. The format appears as it might from CP/M; like this: Recs Bytes Ext Acc Filename 72 9k 1 R/W DRIVER.SOS 58 8k 1 R/W MYFILE.TXT | | | | | | | Access: R/W is Rlls: the specifics are detailed in the companion article "SOS Plus CP/M: A Technical Description". Binary files (like programs, data files, code files, foto files, et. al.) are transferred without alterations.  List a CP/M Directory  This opt answer is more likely to be "No", which will not substitute soft carriage returns at the end of each line. Pascal text files are reworked quite a bit as they are sent, but the program manages all this. Blank suppression, page breaks, padding with nueach line, and puts what it calls a "hard" carriage return (our normal carriage return) at the end of a paragraph. The usual answer to this question is "Yes" if you will be using WordStar with the file. If you aren't using WordStar with the file, the lid because numbers are acceptable A.1 is valid With the Ascii and Pascal Text options, you are asked if you want to "Substitute soft carriage returns?": this is for WordStar. WordStar hides soft carriage return characters at the end of from SOS to CP/M since much of the processing is done in machine code instead of Pascal. This is in spite of the fact that there is more work involved in the processing. People are not always exactly the same after seeing the world, and Pascal text files returning to SOS aren't entirely as small as they were when they left. The text is all the same, but when lines are indented, the Pascal blank suppression codes are regrettably not put back into the text file. This often results in a larger teMENU Magellan: From SOS to CP/M and Back Again Arrival Positional, Alpha BEGIN Magellan: Sailing Around the Horn of CP/M Text Magellan/Magellan.Doc /Articles Run Magellan Chain Magellan/Magellan.Code /Articles MagLIBRARY FILES: System.Star.Lib $$ . There are merits to CP/M, yes, but we're talking about a trip around the world: with SOS, you already live in a beautiful country. ximum 8Mb per volume, a limited number of entries per volume, and requires a warm boot every time you change diskettes you want to write to. Many of the popular CP/M applications are difficult to learn; for many people the expense is not worth the tripways greener in another computer environment; after living in the world of CP/M for a year and a half, we feel a great deal more at comfortable in SOS. The CP/M that runs on the Apple /// has no subdirectories, a somewhat cryptic human interface, a maackup before you transfer, and pay close attention to which diskettes you insert into drives.  Life in the New World  Please don't construe the development of this program as an endorsement for moving everything you have to CP/M. The grass is alterically around the diskette for free space (the effect is that you wait a very long time to get a "No Room" message).  Life Boats  Don't underestimate the possibility of calamity. When a diskette goes overboard, there isn't much you can do. BSOS directories can be sent to your printer.  Preventing Cabin Fever  Keep an eye on diskette space. It's frustrating to begin a long transfer and have it die near the end. SOS get claustrophobic as space begins to run out -- it often looks hysay  You may often want to look at a SOS file or a SOS directory. This application supports the Accessories Menu, so you can use the "Directory" and "Files" options to examine SOS directories and SOS files and . Also remember that both the CP/M and the Filer which lets you set the file type to any valid SOS type. If you have WordStar, you might try moving the WS.COM file (WordStar itself!) from CP/M to SOS and then back. It runs the same in spite of the long journey.  Maps to Guide Your Well for Pascal text files and things bound for word processing. The routine creates a SOS file of the type data file. If you need the SOS file to be some other type (like foto file or code file) and you have Pascal, you can use the A(lter command in xt file, a problem for which we know no cure (yet).  CP/M -> SOS Data or Binary File  Like its counterpart going the other way, this routine moves the data without alteration. Its great for moving programs and data files, but its won't work wellan: A Technical Description Text Magellan/CPMToPas.Doc /Articles Source Code for Magellan Menu Magellan/Source.Menu /Articles Quit Exit None /None END. 2 3 /.3K^de&{ Display message } &BoWindMessage(WindowSetup, 'Error', Message) $END; { ReportError } "{$INCLUDE Transfer} "PROCEDURE CPMMakeNewDirectory(WindowSetup: BoWindowEnvironment; @TransTable: TranArr; @CPMUnitNo: Integer; @CPMDevice: String); ${ $T(9: Message := 'Volume not on line'; (10: Message := 'File not in directory'; (16: Message := 'Diskette is write protected'; (OTHERWISE BEGIN *Str(Err, Message); *Message := Concat('I/O Error# ', Message); (END { OTHERWISE } &END; { CASE } >VAR WrkIndex, CharCnt: Integer; >VAR EndFile: Boolean); $EXTERNAL; "PROCEDURE ReportError(Err: Integer); $VAR &Message: String; $BEGIN &{ Prepare message } &CASE Err OF (7: Message := 'Illegal filename'; (8: Message := 'No room on volume'; nCode: Integer; $MessageRecdFromCaller, CurrentPathname, CPMDevice, CPMSource, CPMDestination, $SOSSource, SOSDestination: String; $Directory: CPMDirectory; $DirList: CPMDirList; "PROCEDURE ProcessTextSector(SectBuff: SectArr; >VAR WrkBuff: WrkArr;$CharSet = SET OF Char; $CPMBlkMap = PACKED ARRAY [2..127] OF Boolean; $CPMDirectory = PACKED ARRAY [0..MaxFilesLessOne] OF DirEntry; $CPMDirList = PACKED ARRAY [0..MaxFilesLessOne] OF Byte; "VAR $Done, Terminate: Boolean; $SosNum, CPMUnitNo, ReturArr = PACKED ARRAY [0..15] OF Byte; $DirEntry = /PACKED RECORD 1UserNo: Byte; 1FileNm: FileNmArr; 1FileTp: FileTpArr; 1Ex, S1, S2, Rc: Byte; 1Index: PACKED ARRAY [0..15] OF Byte; 1ReadOnly, SysFile: Boolean; /END; { RECORD } [BlockSize] OF Byte; $SectArr = PACKED ARRAY [SectSize] OF Byte; $WrkArr = PACKED ARRAY [0..2559] OF Byte; $FileNmArr = PACKED ARRAY [1..8] OF Char; $FileTpArr = PACKED ARRAY [1..3] OF Char; $OutDev = (AsciiFile, TextFile, BinaryFile, Printer); $Tran TypeAids, DateAids, CharacterSetAids, 'ConsoleAids, PathAids, PortAids, BoatsOne, BoatsTwo; "CONST $MaxFilesLessOne = 47; { Maximum of 48 files in directory } "TYPE $BlockSize = 0..511; $SectSize = 0..255; $Byte = 0..255; $BlkArr = PACKED ARRAY  {$E+}  PROGRAM Magellan; "{ "Written by Bill Janes "Adapted for the Apple /// by D. Michael Christensen " "Program to convert CPM files to SOS files and back. "} "USES Applestuff, Chainstuff, ${$USING .Profile/Boats.Lib} 'SosAids, StringAids,urn a SOS formatted blank diskette into a CP/M formatted diskette. $The proprietary CP/M system information is NOT copied. $ $WARNING &This routine writes directly to a volume; carelessness could result &in loss of a wanted SOS directory. $} $ $VAR &Continue: Boolean; &St: String; &UnderScreen: PoPort; &UnderStatus: CoStatusTable; $PROCEDURE ClearDirectory(TransTable: TranArr; =CPMUnitNo: Integer); &TYPE (CPMBlock = PACKED ARRAY [0..511] OF Byte; & &VAR (BlockBuff: CPMBlock; (Slot, I, (BoInitMenuEnvironment(Menu); (Menu.MenuTitle := FilesTitle; (Menu.Sequence := BoArrival; (BoAddOptionToMenu(WindowSetup, Menu, 'List CP/M directory'); (BoAddOptionToMenu(WindowSetup, Menu, 'Print CP/M file'); (BoAddOptionToMenu(WindowSetup, Menu, 'MPoPort; &UnderStatus: CoStatusTable; &P: Interactive; &FileName: FileNmArr; &FileType: FileTpArr; &BlkMap: CPMBlkMap; &SoftCr: Boolean; $PROCEDURE InitMenu(VAR WindowSetup: BoWindowEnvironment; 7VAR Menu: BoMenuEnvironment); &BEGIN $VAR &FileIndex, NumEntries, NumExtents, RecordCnt: Integer; &SectBuff: SectArr; &TransTable: TranArr; &Choice: Integer; &FileFound, CouldBePrinter: Boolean; &St: String; &Menu: BoMenuEnvironment; &SetupBuffer: BoWindowEnvironment; &UnderScreen: ertMenu(VAR WindowSetup: BoWindowEnvironment; 8VAR Directory: CPMDirectory; 8VAR DirList: CPMDirList; 8VAR CPMSource, CPMDestination, SOSSource, 8SOSDestination: String; 8CPMUnitNo: Integer; 8CPMDevice: String); $CONST &FilesTitle = 'Magellan'; ,BoWindMessage(WindowSetup, BoUserMessage, :'Diskette is now a CP/M blank.'); *END { IF } (END; { IF } ({ Restore calling conditions } (PoRefreshPreviousScreen(UnderScreen, UnderStatus) &END { WITH } $END; { CPMMakeNewDirectory } "PROCEDURE ConvAre you sure you want to do this? '); *Continue := BoKeyYes(WindowSetup, False, False); *IF Continue THEN BEGIN ,{ Blank the 6 sectors of the directory } ,ClearDirectory(TransTable, CPMUnitNo); ,{ Completion message } S directory'); *Gotoxy(0, 1); *Write('of the diskette you''ve just inserted with'); *Gotoxy(0, 2); *Write('a blank CP/M directory.'); *CoInverse; *Gotoxy(0, 4); *Write('Any files on the diskette will be lost!'); *CoNormal; *Gotoxy(0, 7); *Write('oKeySpacebar(WindowSetup, False); (IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN *{ Display warning about risk of diskette directory damage } *PoOpenPort(4, 6, 70, 10); *CoClearViewport; *Gotoxy(0, 0); *Write('This routine will replace the SO(BoOpenWindow(WindowSetup, 4, 4, 70, 12, UnderScreen, UnderStatus); ({ Tell the user to insert a SOS formatted, blank diskette } (St := Concat('Insert a blank SOS formatted diskette into ', 5CPMDevice); (Gotoxy(0, 2); (Write(St); (Gotoxy(0, 9); (Bo, BlockBuff[0], 512, Blk) (END { FOR } &END; { ClearDirectory } $BEGIN { CPMMakeNewDirectory } &WITH WindowSetup DO BEGIN ({ Open a large window } (WithTitle := True; (Title := 'Make a Blank CP/M Diskette'; [I] := 0; *I := I + 1; *BlockBuff[I] := 0; *I := I + 1; *{ SecCnt * 2 } *BlockBuff[I] := 0; *I := I + 1; *{ Map } *FOR J := 0 TO 15 DO BEGIN ,BlockBuff[I] := 0; ,I := I + 1 *END; { FOR } *{ Now write the block back out } *Unitwrite(CPMUnitN29; *I := I + 1; *{ Filename and type } *FOR J := 1 TO 8 DO BEGIN ,BlockBuff[I] := 0; ,I := I + 1 *END; { FOR } *FOR J := 1 TO 3 DO BEGIN ,BlockBuff[I] := 0; ,I := I + 1 *END; { FOR } *{ Extent } *BlockBuff[I] := 0; *I := I + 1; *BlockBuff*{ Read the SOS block in } *Unitread(CPMUnitNo, BlockBuff[0], 512, Blk); *{ Calculate the position of this directory slot in block } *I := (Slot MOD 8) * 32 + Ofst; *{ *Assign values to slot. *UserNo of 229 says slot is free *} *BlockBuff[I] := 2J, Sec, Blk, Ofst: Integer; &BEGIN (FOR Slot := 0 TO MaxFilesLessOne DO BEGIN *{ Get sector from slot } *Sec := TransTable[Slot DIV 8]; *{ Get SOS block from track and sector; sector offset 0 or 256 } *GetBlkData(3, Sec, Blk, Ofst); ake new CP/M diskette'); (BoAddOptionToMenu(WindowSetup, Menu, ''); (BoAddOptionToMenu(WindowSetup, Menu, 'CP/M SOS Ascii'); (BoAddOptionToMenu(WindowSetup, Menu, 'CP/M SOS Pascal Text'); (BoAddOptionToMenu(WindowSetup, Menu, 'CP/M SOS Data or Binary'); (BoAddOptionToMenu(WindowSetup, Menu, ''); (BoAddOptionToMenu(WindowSetup, Menu, 'SOS Ascii CP/M'); (BoAddOptionToMenu(WindowSetup, Menu, 'SOS Pascal Text CP/M'); (BoAddOptionToM6SOSDestination := Concat(SOSDestination, '.TEXT'); 4CPMTransferFile(Directory, DirList, SectBuff, DTransTable, FileIndex, CPMSource, DSOSDestination, TextFile, NumExtents, DRecordCnt, CPMUnitNo); 2END { IF } 0END { IF } .END; { CASE-CLAUSE } .7:; { CASE-CLAUSE } .6: BEGIN 0IF BoWindNewPath(WindowSetup, SOSDestination, A'Save as what SOS text file?', 2'') THEN BEGIN 2IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN 4IF Pos('.TEXT', SOSDestination) = 0 THEN tination, A'Save as what SOS Ascii file?', '') THEN 2IF NOT (WindowSetup.ExitCode = BoEscape) THEN 4CPMTransferFile(Directory, DirList, SectBuff, DTransTable, FileIndex, CPMSource, DSOSDestination, AsciiFile, NumExtents, DRecordCnt, CPMUnitNo); .ENDDTransTable, FileIndex, CPMSource, DProgramSetup.PrintPath, Printer, DNumExtents, RecordCnt, CPMUnitNo) .END; { CASE-CLAUSE } .3: 0CPMMakeNewDirectory(WindowSetup, TransTable, CPMUnitNo, DCPMDevice); .5: BEGIN 0IF BoWindNewPath(WindowSetup, SOSDes6Writeln(P); 6Close(P, Lock) 4END { IF } 2END { IF } 0END { ELSE } .END; { CASE-CLAUSE } .2: BEGIN 0IF BoPrintStartup(WindowSetup, CouldBePrinter) THEN 2IF NOT (WindowSetup.ExitCode = BoEscape) THEN 4CPMTransferFile(Directory, DirList, SectBuff, owSetup.ExitCode = BoEscape) THEN BEGIN 6{ Open output file } 6Rewrite(P, ProgramSetup.PrintPath); 6{ Actually print the directory } 6PrintDirectory(P, WindowSetup, Directory, DirList, ENumEntries, False, CouldBePrinter); 6{ Close output file } ?', =True) THEN BEGIN 2IF NOT (WindowSetup.ExitCode = BoEscape) THEN 4PrintDirectory(Output, WindowSetup, Directory, DirList, CNumEntries, True, False) 0END { IF } 0ELSE BEGIN 2IF BoPrintStartup(WindowSetup, CouldBePrinter) THEN BEGIN 4IF NOT (WindSOS path of file to transfer? ' O, '')) ,END { CASE-CLAUSE } *END; { CASE } *IF (WindowSetup.ExitCode <> BoEscape) AND (FileFound) THEN BEGIN ,CASE Choice OF .1: BEGIN 0{ List CP/M directory } 0IF BoWindYes(WindowSetup, 'Send output', 'to .CONSOLE.IF NOT (WindowSetup.ExitCode = BoEscape) THEN 0GetFileInfo(Directory, DirList, CPMSource, NumEntries, A]E]A>[~~]? ?_{00|}@  >?U U I**I@B@@@@@@@@|t;zzz (C) 1985 by Donovan's Reef  } ( MDestination, SOSSource, SOSDestination, CPMUnitNo, 4CPMDevice) &END; { IF } &BoLeaveProgram(WindowSetup, ProgramSetup.ProgramName, 5MessageRecdFromCaller, '', Done, Terminate) $END { WHILE } "END.  {  (C) 1982 by Bill Janes e = BoEscape) THEN BEGIN ({ Find out Pascal device number of drive housing CP/M diskette } (SosGetDNum(CPMDevice, SosNum, ReturnCode); (CPMUnitNo := SosGetPascalNum(SosNum); ({ Main menu } (ConvertMenu(WindowSetup, Directory, DirList, CPMSource, 4CP', 2'Originally Written by Bill Janes', 2'@ 1985 Donovan''s Reef', 2Co80BlackAndWhite, '', Done, Terminate); 3 $WHILE NOT Done DO BEGIN &{ Find out where to read diskettes from } &GetCPMDevice(WindowSetup, CPMDevice); &IF NOT (WindowSetup.ExitCod${ Initialize } $CPMSource := ''; $CPMDestination := ''; $SOSSource := ''; $SOSDestination := ''; $BoStartProgram(WindowSetup, MessageRecdFromCaller, CurrentPathname, 2BoChainReturn, 2'Magellan', 2'From SOS to CP/M and Back Again', 2'Version 1.0END { IF } 0END { IF } .END { CASE-CLAUSE } ,END { CASE } *END { IF } (END { IF } &UNTIL (Choice = 13); &BoCloseMenu(Menu); &PoRefreshPreviousScreen(UnderScreen, UnderStatus); &WindowSetup := SetupBuffer $END; { ConvertMenu } "BEGIN { Main } ileType, BlkMap, TextFile, NCPMUnitNo, SoftCr); <11: >PASTransferFile(Directory, SectBuff, NTransTable, SOSSource, NCPMDestination, FileName, NFileType, BlkMap, BinaryFile, NCPMUnitNo, SoftCr) :END { CASE } 8END { IF } 6END { IF } 4END { IF } 2e OF <9: >PASTransferFile(Directory, SectBuff, NTransTable, SOSSource, NCPMDestination, FileName, NFileType, BlkMap, AsciiFile, NCPMUnitNo, SoftCr); <10: >PASTransferFile(Directory, SectBuff, NTransTable, SOSSource, NCPMDestination, FileName, NF6IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN 8St := Concat('Be sure ', CPMDevice, ?' holds the CP/M diskette to be written to!' E); 8BoWindMessage(WindowSetup, 'Caution', St); 8IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN :CASE ChoicName(CPMDestination, Directory, FileName, BFileType) THEN BEGIN 4IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN 6IF (Choice IN [9, 10]) THEN 8SoftCr := BoWindYes(WindowSetup, L'Substitute soft carriage', L'returns for Wordstar?', True); t|xp`zz{xzzz~~zzzz  T*J>!4BZIUB 2~~B@....X......X.....XXXXX..X...X...X...X...X....X...XXXX...........txBZIUB.2 1 3 4 O^Ye0POP CharCnt 0POP WrkIndex 0POP WrkBuff 0POP SectBuff 0  JMP START ;jump to start of main routine 0  STORE LDY #0 0STA @WKBUF,Y ;store in working buffer 0INC WKBUF ;increment double precision poin ;MSB 0.ENDM 0 0.MACRO PUSH 0LDA %1+1 ;MSB 0PHA 0LDA %1 ;LSB 0PHA 0.ENDM  ; ; ( .PROC ProcessTextSector, 5 0 0POP Return ;pull return address from stack @ 0POP EndFile ;pull in parameters .EQU 0EA ;working buffer address COUNT .EQU 02C ;counter SECPOS .EQU 02F ;position in sector buffer  ;  ;  ; Macros  ; 0.MACRO POP 0PLA 0STA %1 ;LSB 0PLA 0STA %1+1 ; EndFile: boolean. Indicates end of file condition. ;  ; Declarations  ;  Return .EQU 028  SectBuff .EQU 0E0  WrkBuff .EQU 0E2  WrkIndex .EQU 0E4  CharCnt .EQU 0E6  EndFile .EQU 0E8 WKBUF  ; WrkBuff: working buffer (0..2047) to accommodate blanks  ; from tab expansion into spaces.  ; WrkIndex: double precision index for the wrkbuffer.  ; CharCnt: number of chars since last tab space.  Replaces US (1F) with '-'  ; 6. Skips over nonprintable charactes not listed above.  ;  ; Use the following passed variables:  ; SectBuff: sector buffer (0..255) to hold sector contents. and deposits results in WrkBuff.  ; 1. Zeroes high bit of each byte (for use with Wordstar).  ; 2. Removes line feeds from file.  ; 3. Checks for end of file indicator (0A).  ; 4. Expands tab char (09) into spaces.  ; 5.URE ProcessTextSector (SectBuff: SectArr; ; VAR WrkBuff: WrkArr; ; VAR WrkIndex, CharCnt: Integer; ; VAR EndFile: Boolean);  ;  ; ProcessTextSector processes SectBuff ; Program Magellan  ; Assembly Source File ProcSec.Text  ;  ; Written by Bill Janes, June 1982 ; Adapted for the Apple /// by D. Michael Christensen, April 1985 ;  ; (C) Copyright 1982 by Bill Janes  ; (C) Copyright 1985 by Donovan's Reef ; ; PROCEDter ( BNE $01 0INC WKBUF+1  $01 CLC 0LDY #0 ;increment double precision index 0LDA @WrkIndex,Y 0ADC #1 0STA @WrkIndex,Y ( BNE $02 0CLC 0LDY #1 0LDA @WrkIndex,Y 0ADC #1  STA @WrkIndex,Y  $02 RTS  START CLC ;compute position in WrkBuff array ( LDA WrkBuff ; begin with WrkIndex passed in, 0LDY #0 ; and return the revised WrkIndex back ( ADC @WrkIndex,Y ; when complete. ( MENU Source Code for Magallen Arrival Positional, Alpha BEGIN Examine the Main Source [Pascal] Text Magellan/Magellan.Text /Articles Examine the Transfer Include File [Pascal] Text Magellan/Transfer.Text /Articles Ex counter; done when SECPOS returns to 0 ( BNE FETCH  EXIT PUSH Return ;push return address back onto stack 0RTS 0.END ( BCS NEXT ; if non-printable char, branch ahead  JSR STORE ;store byte in work buffer 0LDY #0 ( LDA @CharCnt,Y ;increment tab counter 0ADC #1 ( STA @CharCnt,Y  NEXT INC SECPOS ;inc ; and continue with next byte  CHKBYT CMP #20 ;space = first printable char in charset ( BCC NEXT ; if non-printable char, branch ahead ( CMP #7F ;7F = first non-printable char after charset I space  JSR STORE ( DEC COUNT ( BNE AGAIN  ZEROCT LDY #0 ;zero tab count 0TAX ; buffer accumulator 0LDA #0 0STA @CharCnt,Y 0TXA ; restore accumulator ( JMP NEXT STA @CharCnt,Y ;save CharCnt mod 8 ( LDA #8 ( SBC @CharCnt,Y ;subtract CharCnt from 8 ( BEQ ZEROCT ;if num spc = 0, zero counter & cont ( STA COUNT ; else print spaces  AGAIN LDA #20 ;ASCI( CMP #09 ;check for Horizontal tab ( BNE CHKBYT ; if not h.t., check for printable char 0LDY #0 ( LDA @CharCnt,Y ; else number of spaces to print  AND #07 ; = 8 - CharCnt mod 8 ( ; buffer accumulator 0LDA #0 ( STA @CharCnt,Y 0TXA ; restore accumulator ( JMP NEXT ;jump to next byte  NOTCR CMP #0A ;check for line feed ( BEQ NEXT ;if lf, go to next char #2D ; else print hyphen ( JSR STORE ( JMP NEXT  NOTUS CMP #0D ;check for CR ( BNE NOTCR ( JSR STORE ;store the carriage return 0LDY #0 ;zero char count for tabs 0TAX LDA #1 ;set file-end flag 0LDY #0 ( STA @EndFile,Y ( JMP EXIT ; and exit subroutine  NOTDON CMP #1F ;check for US (1F) ( BNE NOTUS ; if not US (unit separator), branch ( LDA( STY SECPOS ;prepare to process 256 bytes  FETCH LDY SECPOS ;get byte to be processed 0LDA @SectBuff,Y ( AND #7F ;clear high bit ( CMP #01A ;check for end of file ( BNE NOTDON  STA WKBUF ;store lsb WKBUF 0 ( LDA WrkBuff+1 0LDY #1 ( ADC @WrkIndex,Y ( STA WKBUF+1 ;store msb WKBUF ( ( LDY #0 ;Y remains at zero throughout subroutine amine the Process Sector External Procedure [6502] Text Magellan/ProcSec.Text /Articles Quit Exit None /None END. At press time, there was not adequate room for this text file. The file will be included in the next issue. ProDOS, but discovered that a third party developer had a working, wire-wrapped version of a board that would do just that. Apple apparently pushed hard to get the board developed for the sake of the /// users, making a large initial purchase of the fi be expanded to 64K or 128K that is available as a RAM disk in Apple /// native mode. The board supports a fix for lower case, but does not support an 80-column screen. Rumor has it that Apple Computer thought that the /// would probably never run OS development without having an Apple ][. The board also supports a game paddle port for paddles, joysticks and devices like the Koala Pad (yes, the Koala pad software works with the card). The 16K for the language card that comes with /// + // canxpands the range of Apple // software available for the ///. Before, nothing written with ProDOS, Apple ][ Pascal or Apple Logo could be run on the ///, since the Emulation mode only supports 48K. This board means that Apple /// owners can now do ProD /// /// /// /// /// /// /// /// /// /// /// If you hadn't heard already, Titan Technologies is now producing and marketing a card that lets you emulate an Apple ][ Plus with a language card. The card, called /// + //, radically e On Three 5550 Telegraph Road, Suite B-4 Ventura, CA 93003 Orders: (805) 644-3514 /// ///m for the data. The board also has a driver for a RAM disk, which lets you use part of the memory as though it were another disk drive. The big advantage here is that memory is much faster than conventional diskette drives. // or VisiCalc (either version), this product will give you a great deal more room. However, many programs that run in Pascal still have data memory partitioned in a 64K space, so any memory upgrades may add only to room for the Pascal program, not roo advantage of the extra memory, thanks largely to the forethought that went into SOS (if the Apple //e had such an upgrade, it is likely that no software could take advantage of the memory). If you've run out of memory for /// EZ-Pieces, AppleWriter /nd $50 more if you have a 128K machine). The replacement memory board uses the newer 256K-bit RAM chips, and is exchanged for the existing board so that none of your valuable card slots are consumed. Most of the software written for the /// can take  NEW PRODUCTS AND NEWS  /// /// /// /// /// /// /// /// /// /// /// /// /// On Three! has slashed the price of their 512K Memory Upgrade from $999 to $499 (plus $50 if you don't return your old chips arst manufacturing run. Remember that the board emulates a 64K Apple ][ Plus, not a //e or //c. Apple (and others) supposedly wanted //e emulation, but decided it was necessary to get the product out, rather than risk a very long wait for design and development of a //e card. /// /// /// /// /// /// /// /// /// /// /// /// /// AppleWorks, /// E-Z Pieces' Apple // look alike, has become one of Apple Computer's best selling software products ever. Its sales have topped all /// /// /// /// /// /// Apple has dropped the /// from its developer price list. In the next issue, we hope to give you an update on the long-term availability of Apple software and accessories for the ///... mberships are available. For more information contact: Ronald A. Wallace, President Association of Independent Microdealers 3010 North Sterling Avenue Peoria, Illinois (309) 685-4843 /// /// /// /// /// /// /// have been withdrawn. Their plan is to set up a centralized inventory pool of software and hardware, and to advertise and promote it nationally to all Apple /// owners. Purchases can be made from AIM headquarters, or through AIM members. Associate mesional independent computer dealers, has announced a program called "Apple /// Is For Me". It is their intention to smooth out any ill feelings among association members and Apple /// owners who may be feeling that their original support and resources developers will come out with a card for the /// to support the network. /// /// /// /// /// /// /// /// /// /// /// /// /// We learned this past month that The Association of Independent Microdealers (AIM), a group of profesde the /// and the //e in their AppleTalk network, but only the //c, Lisa, Mac and IBM-PC. Part of this may be because the later 3 Apple machines already have an important chip used in the network built in. Many people are hoping that some third partybecoming an orphan; could this hurt IBM's credibility with their third party developers? It certainly has hurt their position with some owners. /// /// /// /// /// /// /// /// /// /// /// /// /// Apple has elected not to incluey take the heat from the user community. Apple's departure from production of the /// was pretty gradual (many sensed it coming for a long time) compared to the abrupt decision on IBM's part. Apparently a lot of people are very upset about the PCjr few changes to make in file handling, but had to write a ProDOS reduction of the SOS console driver. /// /// /// /// /// /// /// /// /// /// /// /// /// Now that IBM has dropped the PCjr, it will be interesting to see how thed "QuickerFile". Also much faster than QuickFile, /// E-Z Pieces was written in 6502 by QuickFile's author, Rupert Lissner. Lissner apparently wrote the program on the /// first, and moved it down to ProDOS for AppleWorks; in the process, Lissner hadkette with data from /// E-Z Pieces, AppleWorks won't know the difference. This is because ProDOS and SOS directory formats are identical. There was once a rumor running around about Apple having an in-house 6502-based version of QuickFile they callE-Z Pieces includes a program to move files from QuickFile to /// E-Z Pieces. Another point that hasn't dawned on many people yet is that /// E-Z Pieces files can be shared directly with an Apple ][, //e or //c. If you feed AppleWorks an Apple /// disE-Z Pieces is virtually identical to QuickFile; you won't have to learn very much new if you move from QuickFile to /// E-Z Pieces. The word processor and spreadsheet aspects of the program also have a command syntax very similar to QuickFile's. /// other microcomputer software sold at dealerships, displacing Lotus 1-2-3 in that area. But the sales don't include Lotus' sales from mail order houses, an area in which Apple does not participate. Many people don't realize that the database in /// MENU Print Arrival Positional, Alpha BEGIN Editorial Print Editorial.2 /Articles New Products and News Print News.2 /Articles Magellan: Sailing Around the Horn of CP/M Print Magellan/Magellan.Doc /Articles ȡb ٚۢ תۢۢۢۢ ۢٹۢ 1ۢ 2ۢ 3ۢ iz&( % (بQ(")%̄GʄGʄGʄG צ Run Around P&TƄ@Pn_d6ac?;TNNff[[sCopyright 1981 1982 1983 Apple Computer Inc.dRUN t|xp`zz{xzzz~~zzzz  T*J>!4BZIUB 2~~B@....X......X.....XXXXX..X...X...X...X...X....X...XXXX...........txBZIUB.@>A]E]A>[~~]? ?_{00|}@  >?U U I**I@B@@@@@@@@|t;zzz-X9!!RUNAROUND.DATAthhRUNAROUND.DATA_hRUNAROUNDv6'  'PARTSETS8! .RUNAROUND.CODE 8!-RUNAROUND.DOC/ 8! RUNAROUND.LIB#8!RUNAROUND.MENUD9!9.RUNAROUND.TEXTnd.Text /Articles ACIA Notes: Using Your Printer In Emulation Print ACIA.Notes /Articles Quit Exit None /None END. /Articles Magellan: Process Sector External Procedure [6502] Print Magellan/ProcSec.Text /Articles Run Around: Instructions Print RunAround/RunAround.Doc /Articles Run Around: Source [Pascal] Print RunAround/RunArou Magellan: A Technical Description Print Magellan/CPMtoPas.Doc /Articles Magellan: Main Source [Pascal] Print Magellan/Magellan.Text /Articles Magellan: Transfer Include File [Pascal] Print Magellan/Transfer.Text *ʄG % TƄ*צ  צ  Qب$%%)%%'T'Tȡo' UU***U +!*)+U+!*)+''x%%% Initials of ÓNٹ=צfirst 7צsecond "third E3 player? Run Around is a simple game program designed to be fun yet challenging for the whole family. Two or three players must move about within a limited area without running into either each other or any one of the four outer walls. Varying the speed create$%'&)(+*,.7q<d@x`4^ h   n0---&&&',&,ȡ5& -- ----- - **&&++*)ġ+'cZ !"#$%&(*,+.RETURNING FROM CHAINצ Run AroundA Game For the Apple ///צ Version 1.0צ@ 1985 Donovan's Reef ,+NÓ#(")++.ǜ,ꍡ,*+()&'%$#"! 2 !"#&',&,ȡ+& -- ----- (&&&',&,ȡ& ----&&&',&,ȡ5& -- ----- - **&&++*)ġ+'cZ !%%%ݢצ wins    %%%%%צAnother round? *%4+,%\+'()+NÓ+'+*+NÓ  ڮ%%    Speed is ( % ȡ ݣ Íݢ ݣ ݢݣ؂%%%  %%%צHit SPACE BAR to start , MÓ %f,   ݂   %     %  ݕ ,x[ 3QH2 "$&(*,.02468:<>@BDFHJWNPRTVXZ\^`bdfhjnp tvxz' T%- ÓS ? %%* 2  *ڹ@ Ó>%Ó-ÓÓ%8KZٹ           ! Ó11ܣMÍܣMÓ-ܣMÓ!ڮ X H ġ/ ġ ġ6+  J%% ɡpeed? <1-  >  ,%^(")ܮצNumber of players? <1-3> ,ܣMÓݹ1 ܣMÓt ܣMÓa % %޹%צ Color for ܢצ?  ,ڣMÓܢ %%%%צBackground color for ܢ?   ,ڣMÓܢ %% %%% S%@%% looks like this...%%iV ٹPrmhc^YTOJ E @ ; 6 1,' WTQNKHEB?<9630-* %%צP, آR %%% ++ȡ9%@ ) AVb %%%,,ȡ* ) ,,ȡY%%s different skill levels appropriate for small children or the accomplished video game enthusiast. Score accumulates relative to the length of each game and goes to the player who manages to elude his opponent(s) and the walls the longest. 2 m%K^enAround.Text /Articles Quit Exit None /None END. MENU Run Around Arrival Positional, Alpha BEGIN Run Around Instructions Text RunAround/RunAround.Doc /Articles Run the Program Chain Runaround/RunAround.Code /Articles Run Around Source Code Menu RunAround/RuLIBRARY FILES: System.Star.Lib $$ except while the game is actually in motion. core, you must not run into any wall, any other player, or reverse direction on yourself. The longer the game, the higher the score to the player who avoids such a collision. Note: /// Cheers! Accessories may be called from Run Around at any time J L key pad 4 6 down X < key pad 2 To s Player 3 up W I key pad 8 left right A D is considered average, 1 is about right for a young child, 9 is fairly fast, and 10 takes a hyper-leap from there.  Playing the Game  Each player gets ready on his direction keys as shown below. Player 1 Player 2 me appear very brightly and others more subdued. Just make sure you can see it clearly and that you can tell one player from another.  Selecting the Speed  Here again, the program gives a suggested speed, which you may accept or change. Speed 5tor). The program makes a choice for you which you may accept by pressing RETURN, or you may change and press RETURN. Next choose a contrasting color. The screen lets you see what your choice will look like based on the first color you chose. So  I N S T R U C T I O N S   Entering Initials and Choosing Colors  Each player should identify himself by entering his initials so that the computer can keep his score. Then choose a color (yes, even if you don't have a color moni yingField + 1, BottomPlayingField - 3TopPlayingField + 1) &END; { OpenPlayingField } $PROCEDURE InitScreen(VAR WindowSetup: BoWindowEnvironment); & &VAR (Line: Integer; (SetupBuffer: BoWindowEnvironment; (UnderScreen: PoPort; (UnderStatus: CoStatrd - 3LeftScoreboard, BottomScoreboard - TopScoreboard + 1) &END; { OpenScoreboard } $PROCEDURE OpenPlayingField; %{ Open the port for the area to "run around" in } &BEGIN (PoOpenPort(LeftPlayingField, TopPlayingField, RightPlayingField - 3LeftPla.Thr: MarkChar := '3' ,END; { CASE } ,Crashed := False *END { WITH } (END { FOR } &END; { Initialize } $PROCEDURE OpenScoreboard; %{ Open the port for the scores to be written in } &BEGIN (PoOpenPort(LeftScoreboard, TopScoreboard, RightScoreboaITH Players[Number] DO BEGIN ,PlayerNumber := Number; ,PlayerInitials := ' '; ,CurrDirection := Right; ,Fore := CoWhite; ,Back := CoBlack; ,Rounds := 0; ,Points := 0; ,CASE Number OF .One: MarkChar := '1'; .Two: MarkChar := '2'; ze(VAR Players: PlayersArray); &{ &Establish setup conditions. &} & &VAR (Number: PlayersRange; &BEGIN ({ Get a new seed for the random number generator } (Randomize; ({ Initialize the player conditions } (FOR Number := One TO Thr DO BEGIN *Wlean 4END; { RECORD } &PlayersArray = ARRAY [One..Thr] OF PlayersType; $ $VAR &Ch: Char; &Players: PlayersArray; &NumberOfPlayers, PlayerNumber: PlayersRange; &Speed: SpeedRange; &Mileage, CrashCount, CrashThreshold: Integer; $PROCEDURE Initiali&PlayersName = String[3]; &PlayersType = 4RECORD 6PlayerNumber: PlayersRange; 6PlayerInitials: PlayersName; 6CurrColumn, CurrLine: Integer; 6CurrDirection: Direction; 6Fore, Back: CoColor; 6Rounds, Points: Integer; 6MarkChar: Char; 6Crashed: Booreboard = 2; &BottomScoreboard = 6; &LeftPlayingField = 1; &RightPlayingField = 37; &TopPlayingField = 9; &BottomPlayingField = 22; $ $TYPE &SpeedRange = 1..MaxSpeed; &Direction = (Left, Right, Down, Up); &PlayersRange = (One, Two, Thr); ist of these enhancements as $well as the instructions for this program are in a separate document. " $Written by D. Michael Christensen $(C) 1985 by Donovan's Reef $} $CONST &MaxSpeed = 10; &LeftScoreboard = 1; &RightScoreboard = 38; &TopSco CurrentPathname: String; "PROCEDURE RunAround; ${ $RunAround $ $This is a game for the Apple ///. It is patterned after an old game $that is in the public domain libraries for the Apple //. A number of $small enhancements have been added; a l {$E+}  PROGRAM Run; "USES Applestuff, Chainstuff, ${$USING .Profile/Boats.Lib} 'SosAids, StringAids, TypeAids, DateAids, CharacterSetAids, 'ConsoleAids, PathAids, PortAids, BoatsOne, BoatsTwo; "VAR $Done, Terminate: Boolean; $MessageFromCaller,usTable; &BEGIN ({ Preserve calling environment } (SetupBuffer := WindowSetup; ({ Turn forty column color mode on } (GlobalTextMode := PoSetTextMode(Co40Color); (CoCursorMotion([CoAdvance]); (WITH WindowSetup DO BEGIN *{ Draw a box around the area to write scores in } *WithTitle := True; *FrameTitle := True; *Title := ' Run Around '; *BoOpenWindow(WindowSetup, LeftScoreboard, TopScoreboard, 7RightScoreboard - LeftScoreboard, BottomScoreboard - 7TopScoreboard + 1,OR Index := CoDarkBlue TO CoWhite DO BEGIN .Gotoxy(0, (Ord(Index) MOD 16) - 2); .Write(Ord(Index) MOD 16: 2, ') '); ,END; { FOR } ,{ Display each of the background colors } ,FOR Index := CoDarkBlue TO CoWhite DO BEGIN .CoForeground(CoWhite); .CoBac. (The foreground Fore should be the color the player selected. (} * *VAR ,Index: CoBlack..CoWhite; ,St: String; *BEGIN ,{ Display the selection numbers } ,OpenPlayingField; ,CoClearViewport; ,CoForeground(CoWhite); ,CoBackGround(CoBlack); ,F.CoConvColorToString(Index, St); .Gotoxy(0, (Ord(Index) MOD 16)); .Write(Ord(Index) MOD 16: 2, ') ', St) ,END { FOR } *END; { DispForeColors } (PROCEDURE DispBackColors(Fore: CoColor); ({ (This routine displays a numbered list of background colorst of colors. (} * *VAR ,Index: CoBlack..CoWhite; ,St: String; *BEGIN ,{ Display the selection numbers } ,OpenPlayingField; ,CoClearViewport; ,CoForeground(CoWhite); ,CoBackGround(CoBlack); ,FOR Index := CoBlack TO CoYellow DO BEGIN erInitials := St (END; { GetPlayer } &PROCEDURE GetColors(VAR WindowSetup: BoWindowEnvironment; :PlayerNumber: PlayersRange; :VAR Player: PlayersType); ( (VAR *Choice: Integer; (PROCEDURE DispForeColors; ({ (This routine displays a numbered listials of '); *IF NOT (NumberOfPlayers = One) THEN ,CASE PlayerNumber OF .One: Write('first '); .Two: Write('second '); .Thr: Write('third '); ,END; { CASE } *Write('player? '); *St := ''; *BoAskString(WindowSetup, St, 3, ['A'..'Z']); *Player.Play:NumberOfPlayers, PlayerNumber: PlayersRange; :VAR Player: PlayersType); ( (VAR *St: String; (BEGIN *{ Get initials } *OpenScoreboard; *CoForeground(CoWhite); *CoBackground(CoBlack); *Gotoxy(0, BottomScoreboard - 2); *CoClearLine; *Write('Ini: PlayersArray; 6VAR Speed: Integer; 6VAR CrashThreshold: Integer); & &VAR (N: Integer; (PlayerNumber: PlayersRange; (St: String; (Done: Boolean; &PROCEDURE GetPlayer(VAR WindowSetup: BoWindowEnvironment; ); ,Write(St); ,StOdometerFromInteger(Points, St, 5); ,Gotoxy(Column, Line + 1); ,Write(St) *END { WITH } (END { FOR } &END; { DispScores } $PROCEDURE Startup(VAR WindowSetup: BoWindowEnvironment; 6VAR NumberOfPlayers: PlayersRange; 6VAR Players; (FOR PlayerNumber := One TO NumberOfPlayers DO BEGIN *WITH Players[PlayerNumber] DO BEGIN ,CASE PlayerNumber OF .One: Column := 17; .Two: Column := 24; .Thr: Column := 31 ,END; { CASE } ,StOdometerFromInteger(Rounds, St, 5); ,Gotoxy(Column, Line9Players: PlayersArray); & &VAR (PlayerNumber: PlayersRange; (N: Integer; (Column, Line: Integer; (St: String; &BEGIN (OpenScoreboard; (CoForeground(CoWhite); (CoBackground(CoBlack); (Line := 1; (CoForeground(CoWhite); (CoBackground(CoBlack)); *Gotoxy(16, 3); Write(' '); *{[F+] Pasmat formatting on } *{ Restore calling environment } *WindowSetup := SetupBuffer (END { WITH } &END; { InitScreen } $PROCEDURE DispScores(NumberOfPlayers: PlayersRange; UnderScreen, UnderStatus); *{ Fill in the scoreboard headers } *OpenScoreboard; *{[F-] Pasmat formatting off } *Gotoxy(16, 0); Write(' '); *Gotoxy(16, 1); Write(' '); *Gotoxy(16, 2); Write(' ' UnderScreen, UnderStatus); *{ Draw a box around the area to "run around" in } *WithTitle := False; *BoOpenWindow(WindowSetup, LeftPlayingField, TopPlayingField, 7RightPlayingField - LeftPlayingField + 1, 7BottomPlayingField - TopPlayingField + 1, 7kground(CoBlack); .CoConvColorToString(Index, St); .Gotoxy(3, (Ord(Index) MOD 16) - 2); .Write(St); .CoForeground(Fore); .CoBackground(Index); .Gotoxy(14, (Ord(Index) MOD 16) - 2); .Write(' looks like this...') ,END; { FOR } ,CoForeground(CoWhite); ,CoBackground(CoBlack) *END; { DispBackColors } (PROCEDURE ConvChoiceToColor(Choice: Integer; DVAR Color: CoColor); ){ Given a choice, return its corresponding color. } *BEGIN ,CASE Choice OF .0: Color := CoBlack; .1: CondowSetup.ExitCode = BoEscape) THEN BEGIN ,{ Get initial speed } ,GetSpeed(WindowSetup, Speed); , ,IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN $ .{ Display starting scores } .DispScores(NumberOfPlayers, Players); & .{ Determine crash thres CASE } 0Write(Players[PlayerNumber].PlayerInitials); 0 0IF NOT (PlayerNumber = NumberOfPlayers) THEN 2PlayerNumber := Succ(PlayerNumber) 0ELSE Done := True .END { IF } ,END { IF } *UNTIL (Done) OR (WindowSetup.ExitCode = BoEscape); ( *IF NOT (Wi.IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN 0OpenScoreboard; 0CoForeground(Players[PlayerNumber].Fore); 0CoBackground(Players[PlayerNumber].Back); 0CASE PlayerNumber OF 2One: Gotoxy(19, 0); 2Two: Gotoxy(26, 0); 2Thr: Gotoxy(33, 0) 0END; {" *Done := False; *PlayerNumber := One; *REPEAT ,GetPlayer(WindowSetup, NumberOfPlayers, PlayerNumber, 6Players[PlayerNumber]); ,IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN .GetColors(WindowSetup, PlayerNumber, Players[PlayerNumber]); 2); (Write('Number of players? <1-3> '); (N := BoAskInteger(WindowSetup, 2, 1, 3, 3); (IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN *CASE N OF ,1: NumberOfPlayers := One; ,2: NumberOfPlayers := Two; ,3: NumberOfPlayers := Thr *END; { CASE } xtMode(Co40Color); (InitScreen(WindowSetup); ({ (Get the number of players, their initials, (and any other player information needed. (Display their initials on the scoreboard as they are entered. (} (OpenScoreboard; (Gotoxy(0, BottomScoreboard - *Speed := BoAskInteger(WindowSetup, 5, 1, MaxSpeed, 4); *{ Clear message } *Gotoxy(0, BottomScoreboard - 2); *CoClearLine; (END; { GetSpeed } &BEGIN { Startup } ({ Establish 40 column color and put up frames and titles } (GlobalTextMode := PoSetTeD; { GetColors } &PROCEDURE GetSpeed(VAR WindowSetup: BoWindowEnvironment; 9VAR Speed: Integer); (BEGIN *CoForeground(CoWhite); *CoBackground(CoBlack); *Gotoxy(0, BottomScoreboard - 2); *CoClearLine; *Write('Speed? <1-', MaxSpeed: 1, '> '); ice := BoAskInteger(WindowSetup, 12, 0, 15, 4); .IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN 0ConvChoiceToColor(Choice, Back); 0CoClearFromCursorToEndOfViewport; 0OpenPlayingField; 0CoClearViewport .END { IF } ,END { IF } *END { WITH } (ENckground(CoBlack); .Gotoxy(0, BottomScoreboard - 2); .CoClearLine; .Write('Background color for ', PlayerInitials: 3, '? '); .DispBackColors(Fore); .{ Get the users choice from the keyboard } .OpenScoreboard; .Gotoxy(26, BottomScoreboard - 2); .Cho,Choice := BoAskInteger(WindowSetup, 3, 0, 15, 4); ,IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN .ConvChoiceToColor(Choice, Fore); .CoClearFromCursorToEndOfViewport; " .{ Get background color } .OpenScoreboard; .CoForeground(CoWhite); .CoBand(CoWhite); ,CoBackground(CoBlack); ,Gotoxy(0, BottomScoreboard - 2); ,CoClearLine; ,Write('Color for ', PlayerInitials: 3, '? '); ,DispForeColors; ,{ Get the users choice from the keyboard } ,OpenScoreboard; ,Gotoxy(15, BottomScoreboard - 2); or := CoPink; .12: Color := CoGreen; .13: Color := CoYellow; .14: Color := CoAqua; .15: Color := CoWhite ,END { CASE } *END; { ConvChoiceToColor } (BEGIN { GetColors } *WITH Player DO BEGIN ,{ Get foreground color } ,OpenScoreboard; ,CoForegroulor := CoMagenta; .2: Color := CoDarkBlue; .3: Color := CoPurple; .4: Color := CoDarkGreen; .5: Color := CoGray; .6: Color := CoMediumBlue; .7: Color := CoLightBlue; .8: Color := CoBrown; .9: Color := CoOrange; .10: Color := CoLightGray; .11: Colhold } .CASE NumberOfPlayers OF 0One, Two: CrashThreshold := 1; 0Thr: CrashThreshold := 2 .END { CASE } ,END { IF } *END { IF } (END { IF } &END; { Startup } $PROCEDURE PlaceMark(CurrColumn, CurrLine: Integer; 8Fore, Back: CoColor; 8MarkChar: Char; 8Speed: SpeedRange); &{ &Display the players position on the playing field. &Use a "1" for player one, a "2" for player two, &and a "3" for player three. &} &PROCEDURE Delay(Speed: SpeedRange); ({ (Pause. (The length paused deporeboard - 2); *Write('Hit SPACE BAR to start '); *{ Wait for response } *BoAskQuietlyForSpacebarReturnOrEscape(WindowSetup); * *IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN " ,{ Clear message line } ,Gotoxy(0, BottomScoreboard - 2); ,ser to hit the SPACE BAR to begin. &} & &VAR (Offset: Integer; &PROCEDURE Go; ( (BEGIN *{ Display question } *OpenScoreboard; *CoForeground(CoWhite); *CoBackground(CoBlack); *Gotoxy(0, BottomScoreboard - 2); *CoClearLine; *Gotoxy(0, BottomSc8VAR Mileage, CrashCount: Integer); &{ &Get ready to begin the next round. &This means setting up the starting coordinates, &initializing variables, removing winner banner, displaying the ¤t speed, clearing the playing field, &and asking the u} *CoForeground(CoWhite); *CoBackground(CoMagenta); *Write('*') (END { IF } &END; { MoveIntoPosition } $PROCEDURE OpenRound(VAR WindowSetup: BoWindowEnvironment; 8NumberOfPlayers: PlayersRange; 8VAR Players: PlayersArray; mn, CurrLine); ({ If this position is already 'used', a collision has occurred } (IF NOT (CoStsReadTextScreen = ' ') THEN BEGIN *{ Mark users record as having collided } *Crashed := True; *{ Noise } *Sound(83, 10, 63); *{ Display crash character ge; ?CurrColumn, CurrLine: Integer; ?CurrDirection: Direction; ?VAR Crashed: Boolean); &{ &Advance to the next screen position for the player, &and test to see if a collision has occurred. &} &BEGIN ({ Advance to next position } (Gotoxy(CurrColu*'6': Players[Thr].CurrDirection := Right; *'2': Players[Thr].CurrDirection := Down; *'8': Players[Thr].CurrDirection := Up; *{TEMP} *'Q': EXIT(PROGRAM); (END { CASE } &END; { ChangeDirection } $PROCEDURE MoveIntoPosition(PlayerNumber: PlayersRan'j': Players[Two].CurrDirection := Left; *'l': Players[Two].CurrDirection := Right; *',': Players[Two].CurrDirection := Down; *'i': Players[Two].CurrDirection := Up; *'4': Players[Thr].CurrDirection := Left; input. &Each player can chose between four directions. &} &BEGIN (CASE Ch OF *'a': Players[One].CurrDirection := Left; *'d': Players[One].CurrDirection := Right; *'x': Players[One].CurrDirection := Down; *'w': Players[One].CurrDirection := Up; *umn = 0) THEN CurrColumn := CurrColumn - 1; *Up: IF NOT (CurrLine = 0) THEN CurrLine := CurrLine - 1 (END { CASE } &END; { GetNextCursorPosition } $PROCEDURE ChangeDirection(Ch: Char; >VAR Players: PlayersArray); &{ &Change direction based on user (CASE CurrDirection OF *Down: ,IF NOT (CurrLine = BottomPlayingField - TopPlayingField) THEN .CurrLine := CurrLine + 1; *Right: ,IF NOT (CurrColumn = RightPlayingField - LeftPlayingField) THEN .CurrColumn := CurrColumn + 1; *Left: ,IF NOT (CurrColition(CurrDirection: Direction; DVAR CurrColumn, CurrLine: Integer); &{ &Given a direction, find the next cursor coordinates in that direction. &If direction would move outside borders, do not change the &coordinates. &} &BEGIN (Gotoxy(CurrColumn, CurrLine); (CoForeground(Fore); (CoBackground(Back); ({ Put down the appropriate character - "1", "2" or "3" } (Write(MarkChar); ({ Pause } (IF Speed < MaxSpeed THEN Delay(Speed) &END; { PlaceMark } $PROCEDURE GetNextCursorPosends on the speed selected. (} ( (VAR *I, J, K: Integer; (BEGIN *FOR I := (MaxSpeed + 1) DOWNTO Speed DO ,FOR J := (MaxSpeed + 1) DOWNTO Speed DO .FOR K := (MaxSpeed + 1) DOWNTO Speed DO BEGIN .END { FOR } (END; { Delay } &BEGIN { PlaceMark } CoClearLine; " ,{ Re-open playing field } ,OpenPlayingField *END { IF } (END; { Go } &BEGIN { OpenRound } ({ Setup for this round } (Mileage := 0; (CrashCount := 0; (Offset := BoRandomFromRange( - 5, 5); (Players[One].CurrColumn := 0; (Players[One].CurrLine := ( A(BottomPlayingField - TopPlayingField) DIV A2) + Offset; (Players[One].CurrDirection := Right; (Players[One].Crashed := False; (Players[Two].CurrColumn := ((RightPlayingField - LeftPlayingField) CDIV 2) + (Offset * 2);  key has been pressed } .IF Keypress THEN BEGIN 0{ Get the character pressed by the user } 0Read(Keyboard, Ch); 0{ Change direction based on user input } 0ChangeDirection(Ch, Players) .END; { IF } " .{ Get new cursor coordinates } .FOR PlayerNumbehe action } ,REPEAT .{ Place the mark at the current cursor position } .FOR PlayerNumber := One TO NumberOfPlayers DO 0WITH Players[PlayerNumber] DO 2IF NOT Crashed THEN 4PlaceMark(CurrColumn, CurrLine, Fore, Back, MarkChar, >Speed); " .{ See if a({ Start the round } (REPEAT *OpenRound(WindowSetup, NumberOfPlayers, Players, Mileage, CrashCount); *IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN ,{ Turn off rangechecking in this area to improve performance } ,{$RANGECHECK-} " ,{ Start tlize data for each player } &Initialize(Players); &{ Get startup info from user and paint screen components } &Startup(WindowSetup, NumberOfPlayers, Players, Speed, .CrashThreshold); &IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN ; ({ Wait for response } (BoPause(1); (CoCtlFlushTypeaheadBuffer; (AnotherRound := BoAskYes(WindowSetup, True, False); ({ Clear message line } (Gotoxy(0, BottomScoreboard - 2); (CoClearLine &END; { AnotherRound } $BEGIN { RunAround } &{ Initiaif the users want to play another round. &} &BEGIN ({ Display question } (OpenScoreboard; (CoForeground(CoWhite); (CoBackground(CoBlack); (Gotoxy(0, BottomScoreboard - 2); (CoClearLine; (Gotoxy(0, BottomScoreboard - 2); (Write('Another round? ')&BEGIN { CloseRound } ({ Revert to full screen and moving cursor } (CoResetViewport; (CoCursorMotion([CoAdvance]); ({ Display winner } (DispWinner(NumberOfPlayers, Players, Mileage) &END; { CloseRound } $FUNCTION AnotherRound: Boolean; &{ &See '); 0Gotoxy(2, 3); 0Write(''); 0CoNormal; 0CoForeground(Fore); 0CoBackground(Back); 0Gotoxy(2, 2); 0Write(PlayerInitials: 3, ' wins ', Mileage: 4); .END { ELSE } ,END { WITH } *END { FOR } (END; { DispWinner } shed) OR (NumberOfPlayers = One) THEN BEGIN 0{ This player won } 0Rounds := Rounds + 1; 0Points := Points + Mileage; 0{ Display results } 0OpenScoreboard; 0CoForeground(CoBlack); 0CoBackground(CoWhite); 0CoInverse; 0Gotoxy(2, 1); 0Write('pdated scores. &} &PROCEDURE DispWinner(NumberOfPlayers: PlayersRange; ;VAR Players: PlayersArray; ;Mileage: Integer); ( (VAR *Index: PlayersRange; (BEGIN *FOR Index := One TO NumberOfPlayers DO BEGIN ,WITH Players[Index] DO BEGIN .IF NOT (Cra(CoClearViewport; ({ Wait for SPACE BAR or RETURN to begin } (Go &END; { OpenRound } $PROCEDURE CloseRound(Mileage: Integer; 9NumberOfPlayers: PlayersRange; 9VAR Players: PlayersArray); &{ &Display the winner, update the scores, &and show the u(CoBackground(CoBlack); (Gotoxy(0, 1); (Write(' ': 16); (Gotoxy(0, 2); (Write(' ': 16); (Gotoxy(0, 3); (Write(' ': 16); ({ Display the speed } (Gotoxy(2, 2); (Write('Speed is ', Speed); ({ Clear the playing field } (OpenPlayingField; opPlayingField) DIV A2) - Offset; (Players[Thr].CurrDirection := Left; (Players[Thr].Crashed := False; ({ Display updated scores } (DispScores(NumberOfPlayers, Players); ({ Clear the winner information } (OpenScoreboard; (CoForeground(CoWhite); (Players[Two].CurrLine := BottomPlayingField - TopPlayingField; (Players[Two].CurrDirection := Up; (Players[Two].Crashed := False; (Players[Thr].CurrColumn := (RightPlayingField - LeftPlayingField); (Players[Thr].CurrLine := ( A(BottomPlayingField - Tr := One TO NumberOfPlayers DO 0WITH Players[PlayerNumber] DO 2GetNextCursorPosition(CurrDirection, CurrColumn, CurrLine); " .{ Move into the right position and test for crashes } .FOR PlayerNumber := One TO NumberOfPlayers DO 0WITH Players[PlayerNumber] DO BEGIN 2IF NOT Crashed THEN BEGIN 4MoveIntoPosition(PlayerNumber, CurrColumn, CurrLine, ECurrDirection, Crashed); 4IF Crashed THEN CrashCount := CrashCount + 1 2END { IF } 0END; { WITH } " .{ Bump mileage } .Mileage nter in emulation mode, a game (Runaround) and "Magellan: CP/M to SOS and Back Again."  Apple /// News, reviews of Versaform and /// EZ Pieces, as well as Basic and Pascal programs (Three Cheers is Pascal based and can not run Basic programs). Issue Two (On Side Two) includes more News and information, an article about using your Serial pri WAP /// SIG PUBLIC DOMAIN LIBRARY PDS NAME: Three Cheers Issues One and Two DISK ID#: 3APL-02 BOOTABLE? NO The only two issues ever produced for Three Cheers, an Apple /// magazine on disk. Requires 3APL-01 to operate. Issue One (On Side One) includest;#/CHEEn/HELP/HELP.MENUIBRARYHEERS/SYSTEM.STAR.LIB> """""@ 1984 by Donovan's Reef#:'t;Version 1.2 With Accessories""eBoatsCHEERS:SYSTEM.LIBRARYHEERS:SYSTEM.SEERS:SYSTEM.LIBARYHEERS:SYSTEM.D1R.LIBt|xp`zz{xCHEERSYSTEM.L.PRINTEREERSYSTEM.STAR.LIBT*J>!HGRSTANDARD.PRINT$t;v$  CHEERS:SYSTEM.LIBRARYHEERS:SYSTCHAR/CHAR.MENUC$(BoLeaveProgram(WindowSetup, ProgramSetup.ProgramName, MessageFromCaller, 7'', Done, Terminate) &UNTIL (Done OR Terminate) $END { IF } "END. {$C (C) 1985 by Donovan's Reef } pple ///', 'Version 1.0', '', 3'@ 1985 Donovan''s Reef', Co40BlackAndWhite, ' ', Done, 3Terminate); $IF NOT (WindowSetup.ExitCode = BoEscape) THEN BEGIN &REPEAT (RunAround; (GlobalTextMode := PoSetTextMode(Co40BlackAndWhite); rounds } (UNTIL NOT AnotherRound; ({ Turn rangechecking back on } ({$RANGECHECK+} &END { IF } $END; { RunAround } "BEGIN { Main } $BoStartProgram(WindowSetup, MessageFromCaller, CurrentPathname, 3BoChainReturn, 3'Run Around', 3'A Game For the A:= Mileage + 1 " .{ Stop when all but one player has crashed } ,UNTIL (CrashCount >= CrashThreshold); " ,{ Record and display results of this round } ,CloseRound(Mileage, NumberOfPlayers, Players) *END { IF } *{ Keep going until users say no more