LDos V1(3) for AMOS1.3 and above. LDos is (C) Niklas Sjöberg 1992 What you just have received is a new fast, and efficient extension for AMOS V1.3 and higher. It is supposed to correct some misfeatures of AMOS and add some functions not available in AMOS. The official name is 'Ldos' which seemed logical when I started out, but since that a lot other functions have been added which are far from DOS-functions. I got the idea about Ldos after waiting over fifteen (15!) minutes for Line Input to read a 300 Kb textfile from floppy. After 15 minutes I stopped the program, it still wasn't finished :-) Then I thought, "while I am at it..", and I came up with some new interesting commands. Here is a small featurelist of Ldos : o New load and save routines. o Support for BOTH load and save in the same file without reopening it. o Ability to save and load from the middle of the file. o Up to three channels open simultaneously. o Commands for setting/reading : o filenotes o protectionbits o dates *- o Environmentvariables o Determine filelength without having to assign a channel to the file. o Determine if a name belongs to a file or a directory. o New, very easy to use, directorycommands. Doesn't use any bufferspace as AMOS dir-command. Only one name is read at the time, unlike AMOS dir-command, meaning no bufferover- flow, never to many files in a dir and 0 waittime before names can be displayed on screen. *- Commands for handling recursive reading and/or popping out *- of directory-reading and being able to return to the exact *- position later and continue reading. The number of different *- active "popped" directories are only limited by your memory. *- o Commands to list all system- assignments, disks, volumes and *- other devices and obtaining further information about disks. o Fast stringhandling to and from banks. Forget Peek and Poke. o Fast replace, and filter-out-function. o "Line Input"-commands from buffer. This routine manages to "Line Input" >40 Kb/sec on my machine (with an AdSpeed) and that includes loadingtime from HD in 1Kb-blocks! o Fast time and date-routines. Command for getting the current time and date, returned in strings, easy to process. Highly optimized. o Convert to and from datestamps, does not use slow library- functions. Highly optimized. o Support for the filerequester in req.library. Totally configurable with optional cache (no need to re-read the dir) for floppy-users. Pops up on the Workbench. *- Also support for font-mode which lets the user pick a *- font in a really neat way. *- Set a current dir for the requester which doesn't affect *- your programs current directory. o Commands for decrunching PowerPacker datafiles, all compression modes and known versions, without passwordlock. *- o Cryptation, DeCryptation with password using a pretty 'hard- *- to-crack'-algoritm. (see hints for more info) o Commands to handle any device using an IOSTD-stucture, specially written with trackdisk.device in mind. o Run executable programs and scripts. Support for I/O in a DOS-console window. o Load fonts from disk, making them available to Get Rom Fonts without needing to scan the whole fonts-directory (sigh!) o A complete set of ARexxsupport commands. Create your host, start scripts with any name located anywhere on the disk. You may also address and send commands to other hosts directly, without starting any scripts. All functions are completely bullet-proof (on system-level), meaning no software failures. *- o Conversion-routine from ANSI/VT100-sequences to AMOS control-codes. *- Supports the most frequently used sequences and is much faster *- than the console.device's own routines. Highly optimized. *- o Word- extraction/count which works similar to the ARexxcommands *- Word and Words.Greatly enhances the possibilities for the prog- *- rammer to parse configurationsfiles and commandlines. TO DO IN FUTURE VERSIONS ------------------------ Correct bugs and add features suggested by YOU. Also a lot of new functions will be added as soon as I find some time to read the new Autodocs. Still locale isn't supported since Commodore haven't released this library to the public. We are also waiting for the amigaguide.library to be released... Already some goodies available in Relase 2, only, has been implemented, and there are more on the way. HOW TO INSTALL LDos ------------------- Simply copy LDos.LIB to the directory where you have your other extensions. Enter LDos.LIB as extension number 10 in your *.ENV file(s). Also add LDos.LIB to the same number in your compiler-configuration(s). Make sure that you state the full path between the brackets { and } in the compiler-configuration. ++ Alexander Folkesson pointed out that in Compiler V1.34 you must ++ edit you Ramos.config in order to compile programs without error- ++ messages. Haven't had time to check this out myself.. HOW TO READ THIS MANUAL ----------------------- The manual can be read as you like. For your convenience the manual is splitted into nine general parts. 1. General file commands, directorycommands etc. 2. String commands and bufferhandling. 3. Date commands. 4. Filerequester in req.library. 5. Device commands, error codes and CMDcommands. 6. Misc commands, which didn't fit anywhere else. 7. ARexx control, making hosts and communicating. 8. Ldos Errorcodes. 9. Disclaimers and info. READ THIS! Text marked with *- are new features added in version 2, so to read the news load your favorite texteditor and search for *- if you come from version 1 of LDos. Text marked -- are new stuff for version 2.1 Text marked ++ are new stuff for version 2.5 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:" PART TWO - String commands and bufferhandling --------------------------------------------- Lstr - Get a string (line) from a bank. 1) A$=Lstr(START To MAX) where START is the address of a bank, and MAX the end of the bank (or the end of the file loaded). This function will begin at START, looking for an end-of-line-terminator (see below). When found, it will put the contents into A$. If no end-of-line- terminator is found, A$ will contain every character between START and MAX. The end-of-line-terminator is NOT copied into the string, so the new startaddress of the next line will be START+Len(A$)+1 Lstr - Get a string from a bank. 2) A$=Lstr(START,END) where A$ will contain every character between START and END. No checking for end-of-line is done and it is thus faster than the other syntax of this command. Mostly useful when processing text where "lines" have no meaning. ++ PLEASE NOTE THAT I HAVE MADE AN TYPO IN OLDER DOCS! END SHOULD ++ ACTUALLY BE _LENGTH_! A$=Lstr(START,10) will put 10 characters in ++ A$. Lset Eoln - Change end-of-line-terminator Lset Eoln NUM where NUM may range from 0 to 255. Default is 10, normal Amiga LineFeed. (Unlike AMOS which tends to use 13 for some reason (old habit from Atari ST?)) Example: Lset Eoln 13 A$=Lstr(_START,_MAX) : _START=START+Len(A$)+1 A$=A$-Chr$(10) : Rem remove Lf which AMOS use before CR. Lbstr - Copy a string to a bank Lbstr A$,START where START is a bankaddress where A$'s contents may be placed. No check is done to see whether the bufferlimit was exceeded or not so make sure there is room for the string. Example: Lbstr A$+Chr$(10),_START : _START=_START+Len(A$)+1 Lreplace - Hunt for a character and then replace it. Lreplace SEARCH,SWAP,START To STOP where START and STOP are the area to be scanned, SEARCH is an ASCII- value to search for. If SEARCH is found it will be replaced by the SWAP-value. Fx. Lreplace 9,Asc(" "),Start(10) To Start(10)+Length(10), will replace all tabs with spaces in bank number ten. Mostly useful when you want to convert specific unwanted characters, like CR (Carrige Return) or removing characters that you can't display or process. Lfilter - Replace within a specific range. Lfilter LOW,HIGH,SWAP,START To STOP. where START and STOP is the same as above, LOW and HIGH are the limits. Everything between LOW and HIGH (INCLUDING LOW and HIGH) will be replaced by SWAP. Fx. Lfilter Asc("a"),Asc("z"),Asc("- "),Start(10) To Start(10)+Length(10), will replace all lower-case characters with a minus "-" sign, leaving any other characters untouched. Very useful when parsing commandfiles. For instance you may let the user print comments anywhere in the file as long as this is done in CAPITAL letters. You then filter out all capitals and convert them to, say ASCII 0. Next when you use Lstr to be able to process the lines, just add a -Chr$(0) after it and all comments are masked out. Lskip - Find next character NOT being xx. ADR=Lskip(CHAR,START To STOP) where CHAR is the ASCII-value you want to skip, START is the startaddress of the bank, and STOP is the maxaddress where Lskip will end if it couldn't find a character which wasn't CHAR. ADR will contain the address AFTER the last CHAR. Useful if you for example would like to skip datas which have been filtered out by Lfilter of similar. ADR=Lskip(10,_START To _STOP) : Rem Skip empty lines. *- Lback Hunt - Find next character being xx, works backwards. *- ADR=Lback Hunt(CHAR,START To STOP) *- where *- CHAR is the character you wish to search for, START the *- position to start searching from and STOP the end-address. Note *- that START is greater than STOP since this routine works *- backwards. If you want to skip forwards the standard AMOS- *- function 'Hunt' is easier to use. This command is probably most *- useful in page/line-oriented applications, like a textdisplayer *- or the like. It was implemented since it is a real pain to use *- Hunt for backwards searching. Example: For I = 1 To 10 ADR=Lback Hunt(10,ADR To _STOP) Next Lupbuffer - Convert all characters to UPPER-case. Lupbuffer START To STOP where all characters between START and STOP will be converted to upper-case. Just like AMOS Upper$ this routine won't handle national characters (due to AMOS isn't using a standard keymap). Only A-Z and a-z are processed. Llowbuffer - Convert all characters to lower-case. Llowbuffer START To STOP. where everything works like above, but all characters will be converted to lower-case. *- Lmatch - Search for for patterns in strings using wildcards. *- L=Lmatch(SOURCE$,S$) THIS FUNCTION REQUIRES Release 2. *- where *- SOURCE$ is the string you want to search in and S$ contains *- the pattern. PLEASE NOTE THAT BOTH STRINGS MUST BE NULL- *- TERMINATED (+Chr$(0)). This routine is case-sensitive, so use *- Upper$ or Lower$ if required. Valid wildcards currently are : *- *- *- ? Matches a single character. *- # Matches the following expression 0 or more times. *- (ab|cd) Matches any one of the items seperated by '|'. *- ~ Negates the following expression. It matches all strings *- that do not match the expression (aka ~(foo) matches all *- strings that are not exactly "foo"). *- [abc] Character class: matches any of the characters in the class. *- [~bc] Character class: matches any of the characters not in the *- class. *- a-z Character range (only within character classes). *- % Matches 0 characters always (useful in "(foo|bar|%)"). *- * Synonym for "#?", not available by default in 2.0. Available *- as an option that can be turned on. *- "Expression" in the above table means either a single *- character (ex: "#?"), or an alternation (ex: "#(ab|cd|ef)"), or a *- character class (ex: "#[a-zA-Z]"). Example: See Lcat_pat* example. Useful for experimenting. -- Lwild - Find out if a string contains a valid wildcard -- TEST=Lwild(A$) -- THIS FUNCTION REQUIRES Release 2. -- where -- TEST will be false (zero) if A$ contains no wildcard(s), -- otherwise TEST may contain anything (usually 1). Always use Lwild -- before calling Lmatch to prevent Lmatch to cause an overflow- -- error. Example: If Lwild(A$) Then Gosub _MATCH *- Lwords - Count the number of words in a string. *- NUM=Lwords(STRING$) *- where *- NUM will contain the number of words in STRING$. Words are *- separated by either TAB (ASCII-value 9), comma (','), space or *- doublequote ('"'). If doublequotes aren't matched, all text from *- the first doublequote will be treated as one word. Two *- doublequotes without any text between them will be treated as *- one word (this is a 'NULL'-word, useful when for instance omit- *- ting a parameter). If there are more than one separator (TAB, *- SPACE, COMMA) following each other they will be ignored. You *- can thus not use ',,' to produce an empty word (use '""' in- *- stead). If STRING$ is empty zero is returned. *- Some examples (TAB means ASCII-value 9 which isn't visible): *- Lwords("TAB Hi,, this TAB is just me") -> 5 *- Lwords('Hi, "this is just" "" me') -> 4 *- Lwords('Hi "this is just" me') -> 3 *- Lwords('"Hi this is just me') -> 1 *- Do not confuse with Lword. *- Lword - Mask out any word of a string, without changing the *- source *- A$=Lword(WORD,STRING$) *- where *- WORD is the word you wish to extract. The first word in *- STRING$ is 1 (not zero) up to the value returned by Lwords.If you *- request a word which doesn't exist an error will be produced. The *- same rules as apply to Lwords applies here, with one exception *- which you might not expect: If a 'NULL'-word is specified ('""') *- an empty string will not be returned, but both the doublequotes *- will be returned. Even if there are text between the doublequotes *- they still are returned in A$. This makes it easy for the *- programmer to tell when more than one word (containing commas or *- tabs etc. just check Left$(A$,1) for '"') are to be regarded as *- ONE word. If only one doublequote is supplied the rest of A$ *- will be treated as one word. If the last character is a *- doublequote, only '"' will be returned. It is up to the *- programmer to decide how to handle this. It could be regarded as *- a 'NULL'-word, but in most cases it probably is a syntax error. *- If you do not wish TABs, spaces or commas to be treated as a word *- separator (or wish to be able to use more than one of them *- directly after each other) you simply quote the text and *- everything between the quotes will be untouched and regarded as *- one word. If WORD is zero an empty string will be returned PART THREE - Date commands -------------------------- Please note! All Ldate* commands only work within the range 1 Jan 1978 to 31 Dec 2099! Ldate - Convert a datestamp to an ACSII-string. A$=Ldate(STAMP) where stamp is the number of days since 1 Jan 1978. A$ will be in the form of "YYMMDD". Fx. 780101 or 920325. If the datestamp is less than zero (below 1 Jan 1978) the string 780101 will be returned. Also, this routine will only generate valid dates upto 2099 (which should be enough?) Lstamp - Convert year,month and day into a datestamp S=LStamp(YEAR,MONTH,DAY) where S will be in the standard datestamp-form : number of days since 1 Jan 1978. If the date is before 1 Jan 1978, 1 Jan 1978 will still be returned. Fx. Print Ldate(LStamp(1991,10,23)) --> 911023 Lsys Stamp - Get the current system-datestamp. A=Lsys Stamp where A will contain a datestamp which can be used in conjunction with Ldate to print the current date. Lsys Time - Get the current system-time. A$=Lsys Time where A$ will be in the form "HHMMSS", hours, minutes, seconds. No extra ":","." or "-" is added so that you easily can process this string to the format you like. -- Lset File Date - Change the datestamp of a file or a directory -- TEST=Lset File Date("name",STAMP,MIN,TICKS) -- THIS FUNCTION REQUIRES Release 2 -- where -- TEST will be true (-1) if the call was successful. "name" is -- of course the (path and) name of the file OR directory that is -- to be changed. STAMP is a normal datestamp like the one returned -- by Lstamp (see above), MIN are the number of minutes that have -- passed since midnight. TICKS are the number of ticks that have -- passed during the last minute (1 tick is the same as a VBL = 1/50 -- sec). I didn't mind adding conversionroutines for MIN and TICKS -- since they are so easy to calculate. It is probably harder to -- convert a userspecified datestring to a format that my routine -- could convert. The datestamp, which are a bit harder, can be -- converted easily with Lstamp. -- Please note that many filesystems (like OFS and FFS) doesn't -- allow you to change the date of the root-directory (this date is -- used to separate disks with the same name) Example: If Lset File Date("t:temp",Lstamp(1992,7,25), 480,1850) Print "Date is now 92-07-25, 08:00:37" Else Print "Set date failed!" EndIf PART FOUR - Filerequester ------------------------- Lfreq - Bring up the filerequester. A$=Lfreq("Title",FLAGS) where A$ will contain the full path and filename after the call. If the user clicked cancel, A$ will be empty. "Title" is the text you want as a headline in the requester fx. "Load an IFF-file". FLAGS decides how the requester will act. Every function is assigned to a bit, and here are their values (to choose many options, just add the values, fx. FLAGS=$2+$4+$1000) $1 - Show .info-files. Hidden otherwise $2 - Extended select. Not supported by Ldos. $4 - Dir cache. The latest used directory will be remembered so it won't have to be read again at the next call. *- $8 - Bring up font requester. Supported in V2 and above. *- Use Lfontsize Freq to get hold of the size of the *- font. A$ will contain the full path and name of the *- font and you may thus let the user select a font from *- any path and then load it using Ldisk Font. HINT, use *- Lget Freq Dir to mask out everything except the font- *- name if you intend to use Get Rom Fonts. See the inc- *- luded example Lfonts for more hints. $10 - Create a hide-'.info'-gadget $20 - Do not create any hide- and showgadgets $40 - Use absolute x,y for the requester. Otherwise it is placed directly under the mousepointer. (x and y are hard-coded to the upper left on the screen) *- Version 2 and higher allows re-position of the re- *- quester if $40-flag is used. $80 - Purge cache whenever the datestamp of the directory changes (in other words, re-read the directory whenever it is changed) $100 - Don't cache anything until the whole directory is read. $200 - Do not sort the files. $400 - Do not create a scrollbar. $800 - Used when choosing a file to save. Currently it have no function, but are reserved for future use. $1000 - Used when choosing a file to load. Currently it have no function, but are reserved for future use. $2000 - Let the user select directories only, does not display any files at all. You should ALWAYS set $800 or $1000 depending on if you are going to load or save a file. Lget Freq Dir - Get only the path which the user picked the last time the filerequester was used. A$=Lget Freq Dir where A$ will hold the LAST selected dir. A$ will NOT be empty even if the user clicked CANCEL and something has been selected through the filerequester before. Lget Freq File - Get only the filename which the user picked the last time the filerequester was active. A$=Lget Freq File where A$ will hold the LAST selected file. A$ will NOT empty even if the user clicked CANCEL, and something has been selected through the filerequester before. Lset Freq Dir - Set the default (current) directory for the filerequester. Lset Freq Dir "Path" where If you haven't set path, the filerequester will use your programs current directory. Whenever the user changes directory it will be remembered by Ldos. This path does not affect AMOS's (Dir$) path in any way. *- Lpos Freq - Change the hardcoded X and Y position of the requester. *- Lpos Freq X,Y *- where *- X and Y are specified in pixels. These positions will only be *- used if the $40-flag is specified, otherwise the requester pops *- up at the mousepointer. Default positions are 3,11. *- Lcust Freq - Change size of the requester's fields. *- Lcust Freq DEVWIDTH,FILEWIDTH,FILES *- where *- DEVWIDTH specifies how many characters wide the devicefield *- will be, FILEWIDTH does the same but affect the file-name/size *- window. FILES specifies how many files/dir that will be displayed *- (height). Default values are 12,30,14. *- Lfontsize Freq - Return the fontsize when the requester has been *- in font-mode. *- S=Lfontsize Freq *- where *- S contains the fontsize of the last chosen font. Note that *- you must set the filerequester to font-mode ($8-flag) in order to *- update this field. Currently the req.library doesn't support CG- *- fonts. Hopefully there will be a new version out soon (when/if *- CED V3 is coming?) PART FIVE - Device Commands --------------------------- Ldevice Open - Open a device for use. Only one device may be open at the same time. S=Ldevice Open("name",UNIT,FLAGS) where name is the devicename, like "trackdisk.device". UNIT is the unit number, 0 for Dh0: and Df0:, 1 for Dh1: and Df1: etc. FLAGS may be set to zero, if you're a non "pro-devicer".. A is zero if successful, non zero if the device couldn't be opened. Ldevice Close - Close the device opened by Ldevice Open. Ldevice Close Ldevice - Send a command to the currently open device. A=Ldevice(COMMAND,BUFFER,LENGTH,OFFSET) where BUFFER is a pointer to where data is to be fetched or put. LENGTH is the number of bytes you wish to read or write. OFFSET is where you wish to read or write. A is the parameter returned from the device (IO_ACTUAL) and may mean different things for different devices/commands (see below). If a read or write operation took place A will contain the number of bytes actually read or written. COMMAND is one of the following (for standard devices, for specialdevices like trackdisk, serial etc. see documentation or C= includefiles): # Description - ------------ 0 Invalid. (Does it do anything?) 1 Reset. Act as newly re-started. 2 Read 3 Write 4 Update (write all buffers) 5 Clear all buffers. 6 Stop all i/o 7 Restart after stop. 8 Flush, abort all queue The trackdisk.device has some special commands : (Remember about trackdisk : ALL buffers must be in CHIP. ALL offsets and lengths must be a multiple of 512. Offsets are always given in bytes, fx. Root-block is 880*512) Command # & Description ----------------------- 2 Read, buffer MUST be in CHIP-mem! 3 Write, buffer MUST be in CHIP-mem! 4 Update, write the (internal) buffer to disk. (You can also force this by reading another track.) 5 Clear the (internal) buffer and thus force the device to read the next block from disk, even though it may have been in the buffer (used to make sure no other process have done anything to the disk via hardware-programming without updating the buffer or if the buffer was trashed). 9 Turn motor OFF (set LENGTH to 0) or ON (LENGTH=1) 10 Seek, move head to OFFSET, but doesn't perform any read to ensure it hit the right block. 11 Format tracks. LENGTH must be 22*512(*2) bytes. (You can use format instead of write if you wish to copy to an unformatted disk) 12 Remove interrupt. Only for pro's. Do not use. 13 Return the number of diskchanges. 14 Determine if a disk is inserted. (255 = No disk in drive) 15 Determine if a disk is writeprotected. (0 it not) 16 RawRead, only for pro's. Do not use. 17 RawWrite - " " - Do not use 18 Determine drivetype. (1 = 3.5", 2=5.25") 19 Determine number of tracks. 20 Change interrupt. Only for pro's. Do not use. 21 Remove change interrupt. Only for pro's. Do not use. 22 Determine last command. Those commands marked "Only for pro's" should NOT be used from Ldos because of many things, to complicated and off-topic to explain here! Extended devicecommands are not supported by Ldos (so please use LSerial.LIB and not Ldevice to perform serial I/O). Ldevice Error - Determine if any (and if so which) error occurred during the last operation. A=Ldevice Error where A can be IF trackdisk is used : ## Description -- ----------- 0 "Operation Successful." 20 "Unknown Error." 21 "No Sector Header Present." 22 "Invalid Sector Header." 23 "Invalid Sector ID." 24 "Incorrect Header Checksum." 25 "Incorrect Sector Checksum." 26 "Not Enough Sectors Available." 27 "Illegal Sector Header." 28 "Disk Is Writeprotected." 29 "Disk Was Changed." 30 "Track Not Found." 31 "Not Enough Memory." 32 "Illegal Sector Number." 33 "Illegal Drive Type." 34 "Drive In Use." 35 "Reset Phase!!" *- Lchk Data - Calculate the checksum of a data-block. *- CHK=Lchk Data(ADR) *- where *- ADR points to a buffer containing the datablock (512 bytes). *- CHK will contain the checksum itself. *- Lchk Boot - Calculate the checksum of the bootblocks. *- CHK=Lchk Boot(ADR) *- where *- See above. *- A word about checksums : *- As you already may have guessed the bootchecksum isn't *- calculated in the same way as the checksum of other blocks *- (Udir,Data,Root etc. etc.) so you must not use Lchk Data for the *- bootblock and Lchk Boot for datablocks. Also notice that the *- bootblock actually consists of TWO blocks (which always are *- reserved on the disk) and ADR should thus point to the TWO first *- blocks of the disk when calculating this checksum. The new *- filesystem (FFS) doesn't use checksums for datablocks anymore *- since FFS uses the full 512 bytes for data (SFS uses only 488). *- To alter the checksum on a SFS disk simply call Lchk xxxx to *- obtain the new (and valid) checksum, if it is the bootblocks, *- Loke this value into the second longword, if it is a datablock *- (or other, except bitmap) longword 6 should be changed. In other *- words, for boot : Loke ADR+4,CHKSUM and for other blocks : Loke *- ADR+20,CHKSUM. PART SIX - Misc commands ------------------------ Lpp Mem - Determine how much memory a file crunched by PowerPacker will need to decrunch. SIZE=Lpp Mem(END) where END is the end of the previously loaded file. It must not be the end of the bank, but the end of the file, Start(Bank)+Lsize("FileName"). (AMOS's banks are always rounded off to the nearest multiple of 4 and may differ from the actual filesize) No check is done to see that the bank really contains a powerpacked file so make sure you have loaded one before. Lpp Decrunch - Decrunch a PowerPacked datafile. Lpp Decrunch START,END To DEST where START is the start of the loaded file, END, see above. The file will be unpacked to address DEST. This bank must be at least Lpp Mem bytes large. Again, no test is done to see if the bank really contains a powerpacked file! Be careful! Llargest Free - Return the size of largest block of free memory A=Llargest Free(TYPE) where TYPE is either 0 for CHIP-memory of 1 for FAST-memory. A will contain the size of the memoryblock. This value is NOT the same as the AMOS commands Fast Free and Chip Free, they return total unallocated memory-size, not the largest size you can allocate in one bank. Always use this command before reserving a larger amount of memory in a single bank. Lrun - Run a program. A=Lrun("command(s)","WINDOW") where "commands" is the program(s) you wish to run. Since a new CLI is opened to execute your program(s) you may wish to set the stack for the program, and you MUST set the fail-level (with failat) to a very high value, otherwise a program may fail with a returncode >0 and the Shell/CLI-window will never be closed! (at least not until the user types endcli >NIL:) After every command a linefeed, Chr$(10) MUST follow. "WINDOW" is a standard CON:/NEWCON: (please always use CON: since NEWCON: isn't used any more in Release 2) with the normal syntax : "CON:x/y/xx/yy/name" name should preferably not contain any spaces. To use Lrun you must have the following commands on the disk (system:) : c:Run c:NewCli c:EndCli (c:FailAt) You also must have assigned t: to somewhere or have a directory named "t" on the disk and have the disk write enabled. An example : T$=Chr$(10) A$="Failat 10000"+T$ A$=A$+"Stack 8000"+T$ A$=A$+"Lha l dh0:download/*.lha"+T$ A$=A$+"Wait 2 secs"+T$ : Rem, pause to read the output A=Lrun(A$,"CON:10/10/600/180/AMOS-Output") where A will contain any number (see Technote below). Please note that you should NOT use EndCli as the last command, Ldos will automatically append this. Always make sure that the requested commands exists on disk, because there is no way (that I currently know of) to ignore a "command not found"-error and your script will fail, leaving the window open and AMOS waiting. If you follow these rules you will be enable to run just about every program from AMOS! Note! Under KS1.3 a "unknown command"-error always breaks the CLI on my system. I do not know why, it works perfectly well under KS2.04 and other 1.3-systems if FailAt has been used. Technotes: Some of you might wonder why it takes so much to run a program? I will try to explain a bit.. Normally Execute() in dos.library is used to start programs. Execute() use the command Run in order to start the program (that is why you have to have it available on the boot-disk). It SHOULD also be possible to pass two channels for I/O, for example a newly opened CON:- window. Now there has always been troubles with Execute() because if you wish to use an inputchannel Execute won't complete until EOF (End Of File) is written to the inputchannel. Since an EOF never is sent the input/output-window is never closed, and Execute waits, and waits..and waits. The only way to make Execute continue is by typing EndCli >NIL: in the window. I tried sending a string like "dir dh0: opt i"+LF+"EndCli >NIL:"+LF (LF=LineFeed) but this didn't work if the program just executed fails. Failat also needed to be used. At this time I realized you would need a whole script (EndCli, Failat, Stack etc.) to execute a program. It seemed much smarter to write all the commands to a script- file, and use NewCli FROM script-file + a window specification. This way you can execute a number of commands and the I/O re- direction is taken care of automatically! All this works fine, but two new problems arose. First I haven't found any way of getting hold of the returncode from Execute() since it now returns directly after the NewCli-command is run (a new process is created). Secondly, control would return to AMOS directly, and one newer knew when the script was finished! I still have no idea of how to get hold of the returncode from the executed programs in the script but the other problems was solved in this way : 1) Your commands is written to a script-file, t:ld.t 2) Two commands are added "t:sig_ldos" and "EndCLi >NIL:" 3) A program called t:sig_ldos is created by Ldos in t:. 4) A messageport is created by Ldos. 5) A NewCli is launched FROM t:ld.t CON:?/?/?/?/Title 6) Ldos directly start to look for a message in the msg.port. 7) The script reaches the line t:sig_ldos. 8) sig_ldos send a message to Ldos that script now is at the end. 9) EndCli is executed, the window close, Ldos cleans up and control returns to AMOS. Sometimes it can be hard to start a program correctly on a multitasking computer....... Lexecute - Start a program which doesn't need CLI I/O A=Lexecute("programname") Works almost like Lrun above, but only one program may be run. The program to be run can not use any CLI-I/O. Started programs should open their own screen/window to function properly. Lexecute is perfect for starting editors, wordprocessors or just any other program which isn't designed to print or receive input to/from a CLI-window. If the program detatches itself control will return to AMOS directly. where A will be True if successful, False otherwise. Ldisk Font - Load a font from disk, making it directly available to Get Rom Fonts A=Ldisk Font("name.font",SIZE) where name is the fontname, ".font" MUST follow it. SIZE is the size of the font you wish to load. A will be >0 if the font loaded OK. If a <1 the font wasn't on the disk or already in memory. Since this routine is designed to always try to scale the sel- ected font with a best match, it may return true even though the requested font wasn't available. Say you try to load diamond/10, (which doesn't exist) then diamond/12 will be loaded instead. ++ Note that above ("designed fonts") may differ a bit depending on ++ which diskfont.library you have. A nice feature of diskfont V36+ ++ is that you may specify a full path for the fontname and thus ++ don't have to have the font located in fonts:. Always make use of ++ V36+ routines if you can.. To bad for those who haven't upgraded ++ but they probably will :) *- Lcrypt - Encode a buffer containing data. *- Lcrypt START,LONGS,"password" *- where *- START is the startaddress of a bank and LONGS is the length *- divided by four. Fx LONGS=Length(10)/4. "password" is your secret *- code which also is used to DEcode your data later. Please note *- that an error will be produced if the password is less than 4 *- characters long. Also note that the password is casesensitive! *- Ldecrypt - Decode a buffer containing coded data. *- Ldecrypt START,LONGS,"password" *- See above for more information. *- A word about cryptation : *- Using crypted data on a computer (or anywhere) is never 100 *- percent safe. If somebody really wants to decode your data he *- will simply load his favorite monitor and single-step your *- program at machine-level until he finds either the code or the *- decoded data itself. This however demands quite some skill and *- patience and can be very time consuming. Data coded with Lcrypt *- uses quite a simple formula which easily can be picked up in the *- code, however, even though the algorithm is know there a millions *- of combinations that have to be tried if the password isn't *- known. There are about 4300 millions of different combin- *- ations... To make your code VERY hard to crack try to follow any *- (or more) of these steps. *- 1) Use non-visable codes as password (linefeed, tab etc. *- etc.) *- 2) Don't type the password like A$="MyPassword". This can *- easily be spotted in the code. Try using Data's reading them with *- an special offset (use each third char or something) *- 3) If you HAVE typed your code directly in the source you could *- always do something like A$=A$-" "-"a"-"M" which makes it very *- much harder for a "single-stepper"-cracker to follow at machine- *- level. *- 4) First code half your bank with one password, the other half *- with another and then code the whole bank with a third. *- 5) Code Powerpacked files or Powerpack your coded files. *- 6) If not compiled, lock the procedure containing the code and *- decryption part. *- Normally you wont have to take any of these steps, most people *- haven't got the skill or the time to mess around in your *- programs... *- Lset Var - Assign a value to a global environmentvariable. *- T=LSet Var("Name","VALUE") *- THIS FUNCTION REQUIRES Release 2. *- where *- "Name" is the name of the variable (must not exceed 50 *- characters) and "VALUE" is a ASCII-string containing either *- digits or text. The value-string must not exceed 50 characters. *- This function will return true if successful. Name of the *- variable is not case-sensitive. *- Lget Var - Get the value from a global environmentvariable. *- A$=Lget Var("Name") *- THIS FUNCTION REQUIRES Release 2. *- where *- A$ either contains the value (or text) or is empty. If A$ is *- empty the variable didn't exist. Name of the variable is not *- case-sensitive. *- Ldelete Var - Remove a global environmentvariable from memory. *- T=Ldelete Var("Name") *- THIS FUNCTION REQUIRES Release 2. *- where *- T will be true if a variable with the name "Name" was found *- and removed. If T is zero the variable didn't exist. *- Lansi - Convert ANSI-sequences to AMOS's format. *- S$=Lansi(A$) *- where *- S$ will contain a sequence containing AMOS control characters. *- A$ is a normal ANSI-sequence which doesn't have to be complete if *- the rest of the sequence follow in the next call(s). *- Currently supported ANSI controlcodes : *- ANSI-sequence RESULT *- ------------- ------ *- $C (*) Clw/Home *- ESC[n;n;n;nm Style, foreground or background. Lansi detects *- if style or colour is to be changed. It is legal *- to omit any of the parameters as long as you *- specify at least one, and end the sequence with m. *- Supported styles are: Italics (shaded), Inverse and *- Underline, other styles are simply ignored. Please *- note that changing from one style to another *- doesn't turn off the last used style. To reset to *- pen-colour 1, background-colour 0 and no style, use *- ESC[0m. *- ESC[0 Cursor invisible, ignored *- ESC[0 p Cursor visible, ignored *- ESC[xA Cursor up x lines. x may be omitted. *- ESC[xB Cursor down x lines. x may be omitted *- ESC[xC Cursor right x columns. x may be omitted. *- ESC[xD Cursor left x columns. x may be omitted. *- ESC[y;xH Locate x,y. y may be omitted. *- ESC[x@ Insert x spaces. x may be omitted. *- ESC[L Insert line. *- $a Linefeed. Passed on to AMOS. *- $d Carrige return. Passed on to AMOS. *- $8 Backspace. passed on to AMOS. *- ESC[2J Clw. To my knowledge it isn't possible to support *- "Clear window at cursor" so even if only ESC[J is *- printed the whole window is cleared. *- ESC[K Clear line at cursor. *- ESC[M Clear line. *- (*) $C really isn't a ANSI-code but is supported since many *- BBS-programs (and AmigaDOS + others) use this. *- How it works: *- The Lansi-routine is a 'smart' routine which remembers old *- incomplete sequences and codes. This means that you may 'Print *- Lansi("ESC[0");' (ESC means Chr$(27)) and nothing is output on *- the screen! If you directly afterwards execute 'Print *- Lansi("m");' a string which resets style and colours will be *- printed (it isn't visible). Lansi doesn't buffer the actual ANSI- *- sequence but rather store datas in its own format and it is thus *- very important that the ANSI-sequence is valid since Lansi can't *- 'go back and check'. The most important thing in the ANSI- *- sequence is the sequence-terminator, like "m" for colour/style *- or @ for insert etc. Lansi will happily collect and convert data *- until a sequence-terminator is received and return nothing to *- AMOS if it isn't received. This may result in lost characters if *- no valid sequence-terminator is sent. *- Speed & Problems: *- I have tried to make the Lansi-routine as fast as possible and *- this have resulted in TOTALLY unstructured code, more labels than *- a grown up man can count and repeated codesections instead of *- slower/more general subroutines. Because of the many sections in *- the code which writes to a temporary destination it is *- (currently) almost impossible to add an effective routine which *- checks for overflow. This means that you must be very careful *- when using Lansi with files with very long lines. Programs like *- DiEd (ANSI-editor) may output an animation which is one line *- 'long' and over 10 kb big! Lansi has no way to figure out how *- big the finished string will be. The internal buffer used by *- Lansi is 2000 bytes big so in general lines up to 400-500 *- characters is ok. Sometimes the resulting string is shorter than *- the ANSI-sequence but I have still not added support for repeat$ *- so the ANSI-sequence ESC[99A will evaluate to 99 bytes. I will *- look into the possibility of making use of repeat$ later on. Right *- now I'm more than happy that this routine just works :-) (I know *- that anybody who has tried to write ANSI-emulation know what I *- mean...) *- Now, what do you gain on my sloppy and unnecessary large code? *- I made a comparison between typing an animationfile in Shell and *- printing it using Lansi in AMOS. Both routines used a 4 colour- *- screen. The file I tested with was Per-Anim_Animation which is *- included with DiEd by Per Raue. The file is 11760 bytes long and *- mostly contains movementsequences and about a half screen of *- text. I was equipped with some fastmem, an AdSpeed and a fast HD *- in both tests. *- Type Per-Anim_Animation took: 09.52 *- Type >NIL: Per-Anim_Animation took: 02.46 ----------- *- Actual time excluding loading 07.06 *- Lansi with output took: 02.02 *- Lansi without output took: 00.76 *- Please note that these figures may have changed since you got *- Ldos since I'm still changing in this part of the code. I now *- also have an A3000/25 to test with :-) *- Both Lansi-testroutines used Lset Eoln and Lstr to split the *- file into 1357 lines (every cursor movement). Lansi gained some *- hundreds of seconds since it didn't need to process bold, on the *- other hand it had to split (and load from HD) the file in 1357 *- lines, allocate stringmemory etc. The time was measured using *- 'Timer' in AMOS and the timingfunction in Csh. The AMOS-program *- was run uncompiled. PART SEVEN - ARexx control ---------- ------------- Please note! ALL STRINGS PASSED ON TO ANY Rexx-commands MUST BE NULL-TERMINATED: A$=A$+Chr$(0)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ("LRexx" in this part applies to all ARexx-commands) LRexx is an AMOS-interface to the library rexxhost. LRexx will let you set up an ARexx-port and execute an ARexx-script. Any other program may use the port created by LRexx to send commands. LRexx will also take care of some things for you, like de- allocating replies from the ARexx-server automatically etc. etc. In general, you don't have to bother with what's going on. You just have to get messages, process them and then reply to the server. To use LRexx you need the complete ARexx-package (supplied in Release 2) and the library rexxhost.library located in libs: You will also need some knowledge about ARexx, understanding how messages are sent from an ARexx-script and knowing how to get/set resultcodes. ++ Using ARexx on the Amiga by Abacus,is HIGHLY recommended! Authors ++ are Chris, Zamara and Nick, Sullivan. ISBN 1-55755-114-6 ($35). ++ This book is much better than the original ARexx-manuals and ++ comes with a free disk with lot of examples. NOTE! If you run from WB2.x you MUST use Loadlib (supplied) to load rexxhost.library into memory. Kickstart2.x simply refuses to open rexxhost.library.. WHY? I don't know! A few other libraries that I got shows the same symptoms. Under Kickstart 1.3 you won't need to use LoadLib. LRexx (and AMOS when LRexx is installed) will refuse to boot if it is unable to open rexxhost.library. *- Removed this stupid thing in V2. AMOS now boot correctly even if *- rexxhost.library couldn't be opened. ++ V37+ version of rexxhost opens just fine. Throw away Loadlib! LRexx Make Host - Create an ARexx host (port) FAIL=LRexx Make Host("Name") where FAIL will differ from zero it the port was added. (FAIL will contain a pointer to the port-structure). If FAIL equals to zero LRexx was unable to create the port, probably due to another port already existed with the same name. LRexx Remove Host - Remove an ARexx host (port) LRexx Remove LRexx Get Msg - Get a message from another host or script. A$=LRexx Get Msg(WAIT) where A$ will contain the message (see below) or be empty if no message was available. If WAIT equals to 1 LRexx Get Msg will wait until a message is received and control won't be returned to AMOS until a message is received. If A$ equals to "LRexx0" it means that the started script reached the end. This message can NOT be replied to since it actually is an answer from the Rexx-server that the script ended. LRexx will de-allocate this reply automatically. If you know that you successfully have started a script (see LRexx Execute) you may safely call LRexx Get Msg with WAIT set to 1 since LRexx0 always will be returned even if no other commands are sent. However, if your script has failed and you call with WAIT set to 1, AMOS may be locked forever! Please use WAIT in a sensible way If your program goes to "sleep" WAIT is ideal to use. ++ "Locked forever" made some of you upset :) Well, you program will ++ be locked until a command is sent to your host. Best way in AMOS ++ (if you wish to sleep but be able to react on other things) is to ++ use WAIT=0 in a mainloop which HEAVILY calls Multi Wait and also ++ checks keyboard and other things. This method isn't the best in a ++ multitasking system, but if you call Multi Wait a couple of times ++ in your main loop,nobody will notice the difference. To bad AMOS ++ never was designed like other programs... :-((( LRexx Execute - Execute an ARexx-program A=LRexx Execute("Name") where A will be true if the program was found and started successfully. Name is the full path and name of the scriptfile. NOTE that "Name" MUST be NULL-terminated (A$="Name"+Chr$(0)) LRexx Send Msg - Send a command to another host (port) directly A$=LRexx Send Msg("Host-name","Message",RESULT) where A$ will contain the result returned by the host you addressed. If RESULT is set to zero A$ will always be empty. "Host-name" is the name of the host that you wish to pass on the command to. "Message" may contain any valid command that the application that you address understand. Note that Host-name and Message MUST be NULL-terminated!! Also note that control isn't returned until the application has executed (and replied to) the sent command. LRexx Reply - Tell ARexx you are ready processing the last message and want to prepare for the next. LRexx Reply "String",Result1,Result2 where "String" may be any result/string you wish to return to ARexx. Result1 and Result2 are the results to be returned. (Result1 == rc) Note that you can not use LRexx Get Msg until you have replied to the previous message using LRexx Reply. Do NOT try to reply to a message which contains the string "LRexx0" (see above) LRexx Result1 - Get the value from rm_Result1 A=LRexx Result1 where A will hold the returncode of the last message. LRexx Result2 - Get the second result. see above PART EIGHT - Errorcodes ----------------------- As mentioned before, errorhandling isn't perfect, but I'm working on it! Ldos Errorcodes : # Description - ----------- 0 Invalid Channel = Channel not >0 and <4 1 LFile already assigned to channel = Channel not free for use 2 LFile not found = File didn't exist 3 Invalid filename = To long or short filename or file/dir didn't exist (used by some commands because I felt it was unecessary to implement even more errorcodes. See docs for some of the commands) 4 Examine failed = Some files can't be locked. May be busy while another program is writing to it or even creating it!! 5 Invalid comment = To long or short comment (MAX 79 characters) 6 Unable to set protectionflags = See 4. May be diskerror 7 No more entries in this dir = Lcat First wasn't a directory or you keep on calling Lcat Next after it has returned an empty string. 8 Start is greater than max limit = Oops, check your addresses in Lstr-calls. Otherwise your string will be as long as all your memory installed. 9 Device already open = Use Ldevice Close before opening a new device. 10 Device not open = LDevice Open may have failed, or you have closed the device. 11 Unable to open diskfont.library = diskfont.library MUST be in libs: on the boot-disk (SYS:) in order to use Ldisk Font (also required by AMOS Get Fonts) 12 Host not created = Rexxhost.lib has been expunged or a host with the same name already exists. (LREXX) 13 Old message not replied! = You tried to read the next message before the last was replied to. (LREXX) 14 No message to reply to! = You replied to a already replied message. (LREXX) *- 15 You need dos.library 37+ = You tried to use a command which *- need a higher version of this library (Kickstart 2.0-only) *- 16 "To long pattern/overflow/or no pattern" = Either you used a *- wildcard which actually doesn't contain any wildcards, or you *- used a pattern >100 chars, or there was a bufferoverflow in *- the dos.library *- 17 Password to short. Lcrypt requires at least for chars as pass- *- word. (This is not because of the algorithm, but for your own *- safety) *- 18 You can not call with an empty argument = This command req- *- uires that you do not supply an "empty" argument such as "" *- or zero. *- 19 Stop is greater than start = Think twice when using Lback Hunt *- since START actually is greater than STOP. *- 20 No more devices in system! = Stop calling Ldev Next when it has *- returned an empty string. *- 21 Not enough words in string! = You tried to extract a word with *- Lword which didn't exist. Use Lwords to find out how many words *- the string contains. ++ 22 LLdir$ can't find directory! = You tried to change the current ++ directory to something that didn't exist. ++ 23 Command need NULL-terminated string! = You forgot to add Chr$(0) ++ to a string before you called a command which doesn't terminate ++ the string itself (saves both space and time). ++ 24 Missing part of ARexx (lib/server) = rexxhost can't work if it ++ can't find rexx*-libs and the server running. This error will ++ ONLY be generated when you call Lrexx Make Host so you should ALWAYS ++ try to make a port (host) before you try any of the other Lrexx- ++ commands All LDos errors are trapable so there is no excuse for not providing your programs with an errorhandling-routine. PART NINE - Disclaimer ---------- ---------- Even though I have tested Ldos as much as possible there may be some bugs left. Many of the Ldos-commands involve access to dos and are naturally dangerous to misuse. Ldos handles most kind of errors, but I have skipped some checking in order to make the code smaller and some functions faster. Because of this Ldos can crasch if you try to call some functions with totally wild arguments. For example Ldisk Font, Lset Comment etc. will behave very strange if you call with an empty string as argument (now, why would anybody want to do that?). If you use Ldos under normal circumstances calling with valid parameters it should be stable. If you use Ldos it is understood that : o You can not hold me responsible for any kind of damage like lost file or crashed disks. o You are using it on your own risk. o If you like to use LDos in a commercial product you should contact me first. o If you use it in a Shareware-program (or anything like that) I would like to receive a registered copy of your program. This won't cost you more than a disk and a stamp. o If you are using LDos in Licensware-programs I would also like to receive a copy of the program. o LDos may not be sold for money. ++ Yack! This must be the largest bugs of all!! This text was included ++ in V1 of Ldos. Of course registered users will have FULL rights to ++ use Ldos/Lserial in any way. OF COURSE I do not require that you ++ should send SW/LW-programs to me. Please forgive me for missing this ++ part when I released the manual for 2.0/2.1!! HINTS AND TIPS FOR USING LDOS ----------------------------- If you find the protection-bits hard to handle when four of the bits are active high and four are active low you can do something like the following to make all bits active high : B=Lget Prot("FileName") T=B and %11110000 B=Not(B and %1111) T=T or(B and %1111) all flags are now active high. Do not forget to switch back before you use Lset Prot After using Lfilter on a wide range (lets say from a-z) you shall use Lskip to determine the next start-address which hasn't been filtered and swapped. Example : Lfilter Asc("a"),Asc("z"),10,START To END Since there will be a LOT of empty lines (all lower-case characters will become linefeed) Lstr may take a lot of unnecessary time only fetching empty lines. You should then use : Lskip 10,START To STOP to obtain the next address not containing a linefeed. ++ If Lload/Lstr gives you a hard time,try these procedures (they ++ will only work with one file at the time though): Set Buffer 10 ' Dedicated to Andy Whitely who thought Lload and Lstr was a bit ' rough to use, and Line Input much to slow. Using these two procedures ' You can 'emulate' AMOS's Line Input-command. To use it you must ' have LINESTART, LINESTOP (buffer "cursors"), SIZE (load-buffer given ' in Kb), FEOF (internal procedure variable), CHAN (the channel you ' wish to use) and RAD$ (where the read line is placed) GLOBAL! ' ' To use these procedures, simply: ' a) Set CHAN to a number between one and three ' b) Set SIZE to desired size. 4-8 Kb is enoough in most cases ' c0)Set Lset Eoln To desired value (normally 10) ' c) Call _LINEOPEN with the filename ' d) Check Param for errors ' e) Call _LINEINPUT in a loop, until Param is false. ' ' RAD$ will hold your read line. The procedure automatically calls ' Free every time the buffer is re-filled (ie. another block is ' loaded) to prevent AMOS from crashing due to garbage collection. ' ' Please note that these procedures erase and use buffer 8 (you might ' want to change that) and can't handle multiple files (unless you ' re-write the routines :) ' ' Have fun with AMOS! ' Global LINESTART,LINESTOP Global CHAN,RAD$,FEOF,SIZE ' ' Screen Open 1,640,256,2,Hires : Paper 0 : Clw ' CHAN=3 : Rem These you need to init SIZE=4 Lset Eoln 10 ' '---- Open a file for _Lineinput. CHAN is set to 3, buffer 4Kb. Proc _LINEOPEN["df0:docs/LdosV21.doc"] If Not Param Print "Error opening file!" End End If Do Proc _LINEINPUT Exit If Not Param : Rem End of file ' Print RAD$ : Rem Wait Key Loop Lclose CHAN ' ' Procedure _LINEINPUT If LINESTART>=LINESTOP : Rem Do we need to re-fill the buffer? If Not FEOF : Rem first check if end of file Gosub _LOAD Else SUC=False : Rem End of file & buffer reached, return FALSE Goto SLUT2 End If End If ' RAD$=Lstr(LINESTART To LINESTOP) LINESTART=LINESTART+Len(RAD$)+1 If(LINESTART>=LINESTOP) and Not(FEOF) and(Peek(LINESTOP)<>10) Gosub _LOAD : Rem A line may be splitted and we should thus D$=Lstr(LINESTART To LINESTOP): Rem pick up the rest by re-filling buffer LINESTART=LINESTART+Len(D$)+1 : RAD$=RAD$+D$ End If SUC=True Goto SLUT2 ' _LOAD: DUMMY=Free : Rem While doing heavy string usage, ALWAYS call Free! LINESTART=Start(8) A=Lload(CHAN,LINESTART,SIZE*1024) If A0 : Rem Directory won't be easy to read :-) Goto SLUT End If End If SUC=True If Lsize(F$)<1 : Rem Zero files are of no use to us because SUC=False : Rem there are nothing to "LineInput"! End If Lopen CHAN,F$,0 A=Lload(CHAN,LINESTART,SIZE*1024) : Rem Load first block If A