MaxZ80 - Chapter 9 A program that copies a file needs to know the name of the source file and optionally the name to give the copy and whether to overwrite an existing target. CP/M uses the 128 bytes of memory starting at hex location 80 for several purposes. This "Transient Buffer Area" (TBA) provides a place to store what is typed after a command. CP/M puts the tail of your command into the TBA. MOTYL.BAS and CMD.MAC (Chapter 3 and 4) rely on the TBA. Here are two lines of code from CMD.MAC. LD A,(0080H) ;COMMAND TAIL LENGTH IN A LD HL,0081H CP/M figures out the number of characters in your command tail and puts this number into location hex 80. From hex 81 up to hex FF, CP/M puts a copy of the command tail itself. The Z80 microprocessor's registers are addressed in assembler language with the letters A, F, B, C, D, E, H and L. Certain pairs of registers can be used together, which is useful when you need to track 16 bit addresses. HL is the H and L register pair. The above two lines are storing the length in register A and the address that holds the tail itself in the HL register pair. Joe Wright, who was mentioned in Chapter 7 when we talked about NZ-TOOL.DEF, NZ-TOOL.BOX, CHICKEN.PAS and the speed field in the environment record, wrote CPY.PAS, a file copy program. He used Turbo Pascal 3.0, which has a builtin ParamStr() function. ParamStr(0) returns the name of the command, ParamStr(1) returns the first element in the tail of the command, ParamStr(2) returns the second, etc. The builtin ParamStr() parses what it finds in the Transient Buffer Area. Turbo Pascal 2.0, which is what we use here, does not have a builtin ParamStr() function, so I wrote one. CPY DEVELOP:EBC.ASC FLOPPY:FLIER.NEW should copy the file EBC.ASC onto my floppy and call it FLIER.NEW. It made the copy but when a directory was done on the floppy a file called FLIER.NE (no 'W') was found. This was due to the fact that the above command is longer than 32 characters which is a problem because CP/M also uses the bytes in the TBA from offset 32 on for another purpose and this was what was causing the target file to lose its "W." Z-System supports a "Multiple Command Line Buffer." Commands are separated with a semicolon. The Multiple Command Line Buffer is like the TBA, but it's about twice as long and is used only for command line tracking. I rewrote ParamStr() to use the Z-System segment that supports the Multiple Command Line Buffer (see PARAMSTR.INC). It uses the ENVREC record structure and the variable Z3EADR Absolute $0109 which is a pointer to this structure. Although ParamStr() was later revised to use a different method than what we show below, it is still worth mentioning the older approach. MCLPTR = ^MCLREC; MCLREC = Record NXTCHR : Integer; MCLMAX : Byte; MCL : String[203]; End; The first three bytes of this structure are overhead to track the address of the first character in the next command to run (NXTCHR) and to hold the size of the maximum number of characters allowed. Function GETMCL:Integer; { get multiple command line } Begin getmcl := Ord(z3eadr^.z3cl) End; Function ParamStr(i:integer):str80; Var j,j1,lcmd,lc,p : Integer; whatsleft : str80; cl : mclptr; { from nz-tool.box } Begin cl := Ptr(getmcl); { point to multiple command line, } { using nz-tool.box } { determine end of command and its offset } { in multiple command line } lc := cl^.nxtchr - 1; j := lc - Ord(cl) - 3; lcmd := 0; While (cl^.mcl[j]<>';') And (j<>0) Do Begin { back up to start of command } j:=j-1;lcmd:=lcmd+1;End; { load work string with it } For j1:=j+1 To j+1+lcmd-1 Do whatsleft[j1-(j+1)+1]:=cl^.mcl[j1]; whatsleft[0]:=Chr(lcmd); p:=Pos(' ',whatsleft); { locate first space } If (i>0) And (p=0) Then whatsleft:=''; While (i<>0) And (p<>0) Do Begin { grab the ith parm } i:=i-1; { decrement parm counter } Delete(whatsleft,1,p); { lop off the leading parm } p:=Pos(' ',whatsleft); { locate next space } End; If p=0 Then { if at end, use what's left } ParamStr:=whatsleft Else ParamStr:=Copy(whatsleft,1,p-1); { else, what's at the beginning } End; CPY was written to demonstrate how to write programs in a high level language and take advantage of Z-System. It makes no attempt to be both CP/M and Z-System compatible, unlike other programs which we'll encounter later. It exits gracefully if Z-System is not detected by invoking z3exist (see Chapter 7). Begin {ning of CPY.PAS} If not z3exist Then Begin Write('Z3 not found.',cr,lf); Goto 100; End; To test the behaviour of CPY under CP/M, you may issue the command NZCPM which will exit from Z-System and put you in a CP/M environment, or, more accurately, a "ZCPR1" environment. To get to user area 6, type 6: Then type CPY To get back to Z-System, type Ctrl-Break and then select the B option (reBoot). |