--------------------------------- LDos V1(3) for AMOS1.3 and above. LDos is (C) Niklas Sjöberg 1992 --------------------------------- PART ONE - General file commands -------------------------------- These commands will in conjunction with the string-commands totally replace all AMOS file I/O, except for special bank- loading, like sprites music etc. They require a bit more work than the standard commands, but gives you total control over memoryusage string contents and lengths. And most important, they are very fast. Lstr for example is about 13-22 times faster than Chr$(Peek()) when compiled! (This is almost the same as a vanilla A500 vs a 33 Mhz 030 card) All loading and saving is done to/from banks meaning minimal usage of the string-buffer and you may easily decide the bank-size and change it at run-time, which is impossible with Set Buffer which is set once and for all. There is a bunch of commands which lets you process the bank before copying it to strings and thus eliminates the risk for "incorrect" strings, containing unwanted characters. (see part about string-commands for more information) ++ Since some might find Lload/Lstr a bit hard to use , I decided to ++ include some easy to change procedures which works like Line ++ Input. See the hint section. Lopen - Open a file for input and/or output. Lopen Channel,"Name",MODE where Channel can range from 1 to 3, MODE either 0 for opening an existing file or 1 for creating a new. WARNING! If the file exist and MODE is 1 the file will be erased. (the file will be 0 bytes long) Both Load- and Save-operations can be performed on files opened by Lopen (unlike AMOS standard Open). Example: _OLD=0 : Lopen 1,"s:startup-sequence",_OLD Lclose - Close a file. Lclose Channel where Channel is a previously opened file. Files opened with the standard AMOS-command Open In or Open Out can not be closed with this command. WARNING! Do not ever forget to close a file, especially those you save to, otherwise the file, or even the whole disk can be corrupt!!! (Ldos will automatically close all open files when the program exits, but if a system-crash occur your file will be lost if you haven't closed it) Example: Lclose 1 Lload - Load any number of bytes from a file. A=Lload(Channel,DEST,LENGTH) where Channel belongs to a file opened by Lopen. DEST is the startaddress of an AMOS-bank and LENGTH is the number of bytes (characters) you wish to load. A will contain the number of bytes actually read. If A is less than LENGTH you reached the end of the file. If A equals to -1, a filerror occurred. It is perfectly legal to request more data than the file contains, no error will be produced because of this. Example: BYTE=Lload(1,Start(10), Length(10)) If BYTE= -1 Then Print "FileError!" : End Print "Loaded ";BYTE;" bytes." Lsave - Save any number of bytes to a file. A=Lsave(Channel,SOURCE,LENGTH) where SOURCE is the startaddress of a bank and LENGTH the number of bytes you wish to write to disk. If A doesn't equal to LENGTH a disk-error probably occurred (like disk full, or write error) dos.library should normally return -1 on disk-error, but as soon as A doesn't equal to the length you specified you should regard this as an error. Example: BYTE=Lsave(1, Start(10), Length(10)) If BYTE <> Length(10) Then Print "FileError!" : End Lseek - Change position in a file. P=Lseek(Channel,POS) where POS is the offset you wish to move to. (Offsets are relative to the BEGINNING of the file). If the operation was successful P will contain the same value as POS. If POS is <0 no movement will take place, and the current position in the file will be returned. Example: Print Lseek(1,0) : Rem start of file Print Lseek(1,100) : Rem move to 100 Print Lseek(1,-1) : Report position Lold - MAY CURRENTLY NOT BE USED!! Lcreate - MAY CURRENTLY NOT BE USED!! These are here for future versions, currently the compiler seems to mess up values of reserved variables (or I got it all wrong) (most likely I got it wrong, but this type of "instructions" isn't explained in the PD-source that come with AMOS) Lget Comment - Get a FileNote A$=Lget Comment("FileName") where A$ will contain nothing if there was no filenote. This of course also works on directories. Lset Comment - Set a FileNote Lset Comment "FileName","Comment" where "Comment" may not be longer than 79 characters and also works on directories as well. Lget Prot - Get the protection-bits of a file A=Lget Prot("FileName") where A will contain a bit-pattern meaning : Bit 7 = H ACTIVE HIGH (Hidden) Bit 6 = S ACTIVE HIGH (Script) Bit 5 = P ACTIVE HIGH (Pure) Bit 4 = A ACTIVE HIGH (Archived) Bit 3 = R ACTIVE LOW (Readable) Bit 2 = W ACTIVE LOW (Writable) Bit 1 = E ACTIVE LOW (Executable) Bit 0 = D ACTIVE LOW (Deleteable) This command also works on directories but it seems like DOS doesn't care about some flags when it comes to directories. For instance DOS will let you read a directory even if the R-flag wasn't activated. Logically DOS shouldn't let you read a directory which isn't readable but this is the way it works. If you are running Kickstart 1.2 or 1.3 DOS neglects most flags. When a flag is active low, it means that when that bit is zero the flag is active. If, for instance, bit 0 would equal to 0 that file or directory wouldn't be deleteable. ++ Of course above should be " bit 0 would equal to 1, that file or ++ directory wouldn't be deleteable" Lset Prot - Set the protectionflags for a file. Lset Prot "FileName",MASK where MASK is a bitpattern like above. Example: Lset Prot "c:myCommand",%00000000 : Rem ----rwed Lset Prot "s:myScript",%01000000 : Rem -s--rwed Lsize - Return the size of a file. S=Lsize("FileName") where S is the filesize. The file do not need to be open. Note that it is legal to to specify a directory as well. If "FileName" is a directory zero is always returned. Lfile Type - See if the name is a file or a directory. A=Lfile Type("FileName") where A is greater than 0 if it is a directory, or negative if it is a file. You don't need to supply a directoryname with a slash ("/") it will work anyway. Example: If Lfile Type(F$) >0 Print F$;" is a directory" Else Print F$;" is a file" EndIf Lcat First - "Lock" on a directory. F$=Lcat First("Directory") where If successful F$ will contain the file- or directoryname. Lcat Next will return the next file/dir or an empty string. If the directory didn't exist the error "Invalid Filename" will be produced (this is because I wanted to keep as few error-messages as possible) Lcat Next - Get the next lock (name) in a directory. F$=Lcat Next where If F$ is empty, there are no more files/directories in this directory. Lcat Next won't work if you haven't used Lcat First. These two Lcat-commands works almost as the original AMOS- commands Dir First$ and Dir Next$ with the exception that Lcat First actually returns the path, requested by you and doesn't read in all the files and directories like Dir First$. Obviously Lcat Next, unlike Dir Next$, has to access the disk to get the next filename. To produce a directory/file-listing which lets the user stop the program at any time, you could do something like this : F$=Lcat First("SYS:") Print "Listing contents of ";F$ Repeat Exit If Inkey$<>"" F$=Lcat Next If Lcat Type>0 F$=F$+At(40,)+Pen$(5)+"(DIRECTORY)"+Pen$(1) EndIf Print F$ Until F$="" As you can see Lcat Next only returns the file/directoryname, there are no sizes or "*" which makes it harder to process the strings. Instead you can after a call to Lcat First, or Lcat Next call any of the other Lcat-commands for more information about the file/directory. Since the file/dir already is examined once, none of the other Lcat-commands actually needs to access the disk. This speed things up a bit and prevents disktrashing. Lcat Type - Find out if the name is a directory or a file. A=Lcat Type where A can be either positive, for directories, or negative for files. This is a bit easier than the "*" provided by Dir Next$ in front of the directoryname. Lcat Prot - Get the protectionflags. A=Lcat Prot where se above Lget Prot for more information. Lcat Size - Get the filesize S=Lcat Size where S will contain the number of bytes in the file. Note that it is fully legal to call this command even if the current "file" is a directory! If the current name belongs to a directory S will contain 0. (Keep in mind that files which are zero bytes do exist, so don't use this method instead of Lcat Type) Lcat Blocks - Return how many blocks the file occupies. B=Lcat Blocks (May be useful when doing size check (copy FFS -> SFS). FFS can hold 512 bytes of data in one block, SFS only 488. It is also said that 2.x/3.x shall support different block-sizes(?)) Lcat Stamp - Return the datestamp of the file/directory. S=Lcat Stamp See Ldate, Lstamp for more information on how to use and process this stamp. (The format is the same as used by AmigaDOS) Lcat Comment - Get the file- or directorynote. A$=Lcat Comment See Lget Comment for more information. *- Lcat Push - Store Lcat-info for later use. *- Lcat Push ADR *- where *- ADR points to a reserved bank where Lcat temporarily can store *- its datas. Each time you push something 264 bytes are used and *- the next datas should thus be copied to ADR+264. As some of you *- may have noticed it wasn't possible to run recursive Lcat- *- procedures before, since Lcat always uses the same memory-area *- when storing filelocks and information. Using Lcat Push you *- simply move this internal data to a bank reserved by you. You may *- now use Lcat on a different device/directory. When you're ready *- call Lcat Pull and you're back exactly where you stopped. *- Lcat Pull - Restore Lcat-info which has been stored with Lcat Push. *- Lcat Pull ADR *- where *- ADR points to the start of a block which has been created by *- Lcat Push. Please note that if this address not contains Lcat- *- data AmigaDOS MAY crash if you're unlucky!! If ADR points to *- NULLs (empty bank) you will receive the errormessage "No more *- entries in this dir!". *- WARNING! *- If you don't pull all your pushed datas DOS won't be able to *- deallocate the memory used for the pushed files/directories. This *- means that whenever your program is run available memory will *- decrease and can not be restored until the system is re-booted. *- See different recursive routines for more information. *- Ldev First - Get the first device in the systemlist *- A$=Ldev First(ADR) *- where *- A$ will contain the first device found in your system (if it *- is empty something is very wrong). ADR should point to a bank *- where optional info can be stored. The info stored in the bank is *- mostly for advanced users to be used in special cases. *- Interesting info for all users ought to be devicetype, unitnumber *- and the name of the device which handles it. Please note that the *- devicename (like DF0: etc.) NOT contains a colon (":"). The *- information stored at ADR is given below. The bank must be AT *- LEAST 80 bytes large, no checking is done to ensure this. *- See the example 'Devices.AMOS' for more information and help. *- Ldev Next - Get the next name(s) in the systemlist. *- A$=Ldev Next(ADR) *- where *- This command works almost identically to Ldev First except *- that it will return an empty string when the last device in the *- list has been returned. If you continue to call Ldev Next after *- this an errormessage will be generated. Note that it is possible *- at any time to call Ldev First if you for some reason like to *- start over in the list. *- DeviceInfo, returned at ADR and the following 40 longwords: *- (entries marked with * are explained below) *- ADR+0 Devicetype* *- ADR+4 Unitnumber *- ADR+8 Devicename* *- ADR+12 Tablesize (see includes on this) *- ADR+16 Blocksize, given in number of longwords *- ADR+20 -not used- *- ADR+24 Number of heads (surfaces) *- ADR+28 -not used- *- ADR+32 Number of blocks per track *- ADR+36 Reserved blocks (usually 2) *- ADR+40 -not used- *- ADR+44 Interleave (usually 0) *- ADR+48 Starting cylinder *- ADR+52 Max cylinder *- ADR+56 Number of buffers *- ADR+60 BuffMemType (1 for PUBLIC, 3 for FAST and 5 for CHIP) *- ADR+64 Maxtransfer *- ADR+68 MASK-value (DMA-devices) *- ADR+72 Bootpriority *- ADR+76 Dostype ($444f5300 for OFS and $444f5301 for FFS) *- DeviceTypes is zero for all true DOS-devices (like CON:, DF0:, *- DH0: etc.), 1 if it is an assignment and 2 for volumes. It can be *- a bit tricky to separate non-drive devices, like CON:/RAW: etc. *- from normal devices which you can save files to. A rather simple *- way to tell which is which is to check ADR+8 (Devicename) if it *- contains a devicename. If it does, you can count on that you can *- save files to the device. If devicename is empty and type is zero *- it is a non-filesystem device. *- Devicename (ADR+8) contains a pointer to a transformed BSTR- *- string. The first "character" shows how long the string is, or *- zero. Start of the string is thus ST=Leek(ADR+8). Length of the *- string is P=Peek(ST) and the text starts at ST+1. Note that *- Devicename normally is NULL-terminated (ends with a Chr$(0)) so *- it is wise to subtract Chr$(0) from the resulting string before *- usage. However, don't count on that all names are NULL- *- terminated, asdg.vdisk.device for example isn't! ++ Lldir$ - Change the current directory ++ LLdir$ "new-dir" ++ where ++ newdir is a device/volume/dirname. If you change the dir using ++ the Dir$-command and then try to open a file using Lopen, the ++ file probably couldn't be found, since Ldos hadn't noticed the ++ directory-change (as always, AMOS handles this internal :-(..). ++ There are two ways of using LLdir$ in your program: ++ a) Set Dir$ to desired value, and call LLdir$ Dir$. Ldos will ++ now work in the same path as AMOS. ++ b) NEVER use Dir$ in your program (or direct mode as long as ++ AMOS is running). Instead, use LLdir$, just like you would have ++ used Dir$. What LLdir$ does is to change the program's (AMOS's or ++ the compiled program) current directory using a system call. What ++ AMOS's Dir$-command does is to probably add the new path to some ++ internal variable that is appended to all subsequent calls to any ++ file related commands. However, another problem arises.. When ++ you bring up AMOS's filerequester AMOS changes the Dir$-string so ++ Ldos will once again become confused. If your compiled program ++ never uses AMOS's own filerequester (use Lfreq) stick with LLdir$ ++ If you run the interpreter, use option a). Example: LLdir$ Dir$ LLdir$ "SYS:" CONTINUED IN NEXT ARTICLE.