L L L L LLLL LLLLL L L L L LL LL LL LL L L L L L L L L L L L L L LLLL LLLL L L L L L L L L L L L L L L L L L L L LLLLL L L L L LLLL LLLLL L L LLLLL L LLL LLLL LLLL LLLLL LLLL L L LLL LLLLL L L L L L L L L L L L L L L L L L L L L L L LLLL L L LLLL L L L LLLL LLLL LLLL LLLL LL L L L L L L L L L L L L L L L L L L L L LLLL LLLLL L LLLLL LLLL LLL L L LLLLL L L L L LLL L L L L L L L L LL LL LL L L L L L L L L L L L L L L L L L L (C) 1994-96 Robert Hofmann 1. Introduction =============== 1.1 Legal stuff --------------- The MM_RexxDevelopperKit is a small collection of ARexx-functions, which I have developped for Mail Manager by Pino Aliberti while the last years. The programs and files in this distribution are freely distributable, but are also Copyright (c) Robert Hofmann. They may be freely distributed as long as no more than a nominal fee is charged to cover time and copying costs. No commercial usage is permitted without written permission from the author. Everything in this distribution must be kept together, in original unmodified form and unmodified archive. MM_RexxDevelopperKit is mailware :-). This means if you use it, please write me a short mail. You know, it is frustrating to write programs and there are no responses from the users if they like it or not... But of course money is also welcome. ;-) If you are coding tools, using this kit as basis, please drop a little note in your script & doc. Accepting these few points is the only condition for using MM_RexxDevelopper- Kit... ============================================================================= The author is not responsible for any problems caused by using this tools! ============================================================================= 1.2 General stuff ----------------- I am not the best in writing doc, but quiet good in coding I think :-) This docs are a bit short I have to appolognize, but I hope you'll understand it anyway... Especially my English and the typo's ;-) If there is anybody out there who is able to & wants translate the docs to his own language, please do so and send them to me! I'll add them to the next release. Also translators always will get the newest betas! ;-) Unfortunatly I don't have the will & time to translate my docs even to German - my time is better used for coding :-) 1.3 Author ---------- If you have suggestions or remarks about this program, or if you find any bugs, please let me know. Contacting the author: Internet .. : robert@next.amistep.osn.de (soon!) FidoNet ... : 2:2490/1015.0 (may change soon!) AmigaNet .. : 39:171/101.0 Snail-mail : Robert Hofmann Volkmannstr. 35 D-90443 Nürnberg Tel. +49-(0)-911-9941680 (18-20h German time only!!!) Germany Bank-Account: Account-holder: Robert Hofmann Account-number: 67920 Bank-ID ..... : 76090000 Bank-name ... : Volksbank Nuernberg e.G. 2. Mail Manager, ARexx, You & Me ================================ As you already know, MM has an excellent ARexx-interface. IMHO it could be better in some parts, but IMHO all could be better than it currently is ;-)). Anyway, as you might know I have already written many scripts for MM, and I think they are also very well (I hope so ;-). It took me a couple of years, to get the know-how of coding ARexx, especially my, let's say OOP-style of programing :-) This collection is the result of this work. It is thougth to help you coding tools for MM without a big know-how of ARexx & MM. It is up to you if you use my "system" or not. Just take a look into this kit and decide it you find it usefull or not... If you have also coded some usefull functions, developper-tools, or if you have any good ideas, please send it to me, so that I can implement it in a future update of this kit! Suggestions, functions, docs, hints, tips etc. are *VERY* wellcome!!! 3. Developping own tools ======================== All functions & tools described in this part are located in the Developper/ Rexx-drawer of this release. NOTE: Use TABsize 2, otherwise it is nearly impossible to read the scripts! 3.1 Concept & first steps ------------------------- IMHO the major part of this developper-kit is the understanding of my concept and the philosophy of coding my tools. You may also take a look into the scripts I've already released. First of all, load the MM_ScriptBody. This is the main part of this develop- per-kit, but don't try to understand all before reading this doc until the end :-) 3.2 MM_ScriptBody ----------------- This is the major part of this kit. It is a script-mask with all basic functions including an advanced error-handling, log-tracking, argument- parsing etc... If you use it as base for your scripts, you are able to code your scripts very fast I think. I would not be able to code so many script in such a short time without having it. It took me a long time to get it that "perfect" (of course everything can be done in many other ways, but for me this is the nearly most perfect solution I could develope ;-), so maybe you also find it usefull. I've tried to code it as object-oriented as possible as you might see. 3.2.1 First steps for writing a new script - - - - - - - - - - - - - - - - - - - - - - 1. Set the version- & copyright-info in the script-header (see also 4.9) 2. Goto the Init-function and set up your global variables (see also 4.1) 3. Goto the Parse_Args()-function and ajust it to your own needs (see 4.2) 4. If a cfg-file is needed, goto the Read_Cfg()-function (see 4.4 & 5.) and ajust it to your own needs 5. Code your own code and call it from the Main()-function 6. Remove all not-needed stuff from the script If this was done successfully, your script should work perfect! :-) 3.3 Some general things about coding in ARexx --------------------------------------------- The most common mistake I often see is that people are coding in C-style. The "problem" is that ARexx is very tolerant regarding errors. In one situation it might be an error, in the next it does work. It sometimes is hard to debug such "strange" errors. E.g. I often see functions-calls without declarations, like writeln(out, line) but the correct way would be result = writeln(out, line) or if you don't need the result call writeln(out, line) Otherwise the return-code would be sent to the current host, in our case MM. This means if a function would return with "QUIT", you would immediatly shut dowm MM. 8^( :-) The next very often made mistake is to use variable-names as strings. E.g. MM_SearchInStem test result '"Test#?"' str Looks correct, doesn't it? Well, but it is not correct! This example will work as long as you do not also use the variables "test", "result" and "str", because as long as you didn't initialise the variable (e.g. "test = 0"), test has the value "TEST" etc. If you want to code proper, you have to do it like MM_SearchInStem 'test' 'result' '"Test#?"' 'STR' Why? Well, let's say youve already used these variables and e.g. "test = 10", "result = 'My_Result'" & "str = 'STRING'". Now ARexx would interpret this as MM_SearchInStem 10 My_Result '"Test#?"' STRING and I think this is not what you want :-) If you just keep these few points in mind, you'll have no problems with ARexx I hope :-) 3.4 Debugging in ARexx ---------------------- As you might know, ARexx has very good debugging-mechanism. Here a short overview about the most important things: The ARexx-command "trace ?r" enables the interactive trace-mode. There you can even change variables in the running script! You have to confirm every command. It is very effective for error-search. The DOS-command "sys:rexxc/tco" (Trace Console Open) to open a seperat trace- window and its opposite "sys:rexxc/tcx" (Trace Console Close :-). All ARexx trace or error-output will be redirected there. Just try it out, it is very good! 4. Documentation of the used functions ====================================== In this part, you will find a more or less complete doc of the basic functions collected in this kit. All functions starting with MM_* need MM to work, the rest does also work without MM. In this manual, the functions in the script itself do not start with MM_. This was only done in the Developper/Rexx-drawer for a better read- ability. This part is not in alphabetical order but in logical order related to MM_ScriptBody. 4.1 Init -------- In this function, you should setup all your global variables and do all initial stuff. Basically I use a stem-variable called "system.". The most other things are related to it. This was mainly done not to have large Expose lists in the functions. The used variables are self-speaking I think... Usage: call Init Requires: Get_Version() Include_Lib() rexxsupport.library 4.2 Parse_Args() ---------------------- Here it gets a bit more complex from the coders point of view, but IMHO it is not necessary to completly unterstand how it works but what it does. This function offers you the possibility to set up a very powerfull command- line parsing. You only have to set up the variable "system.cmdopts" in the Init()-function, in the same manner like AmigaDOS command-masks. /A the argument MUST be given /K the argument has to be introduced with its keyword /S the argument is a switch (boolean) /N only numeric values are allowed Of course you can combine them as long as it may make sense :-) E.g. ok would be: TEST/A/K/N TEST must be given as keyword with a numeric value and bad: TEST/K/S it can not be a switch and a keyword at the same time... The values will be returned in the stem "system.arg.". E.g. TEST/A will be present in stem "system.arg.test" as alphanumeric value, MSG/N -"- "system.arg.msg" as numeric value, FORCE/S -"- "system.arg.force" as boolean value (1 if present, 0 if not present) This function also supports quotation-marks!!! This means you are able to use blanks inside an argument etc. At the end of this function, you may place additional syntax-checks. Usage: call Parse_Args() Requires: Get_Arg() Quit() Usage() 4.3 Get_Arg(KEYWORD, MODE, DEFAULT) ----------------------------------- Normally you don't need this function... KEYWORD the plain keyword to extract from args MODE 0: get (alpha)numeric string 1: get boolean value 2: get the first argument in args DEFAULT the value returned if the keyword/argument was not given Usage: result = Get_Arg(KEYWORD, MODE, DEFAULT) Requires: "args" 4.4 Read_Cfg ------------ Function to read a configuration file. This function is not ready, you have to complete it before using! This means mainly the completition of the select-statement. Usage: call Read_Cfg Requires: "system.prg.cfg" Log() Quit() 4.5 Quit(RC, TEXT) ------------------ Quit your script with all needed checks. See also 6.! RC the return-code the script shall exit with: >=5: INFO >=10: WARNING >=20: ERROR >=30: IO-ERROR >=40: INTERNAL-(ARexx-)ERROR TEXT the text to be logged at the exit Usage: call Quit(RC, TEXT) Requires: Log() Exit() [see 6.] 4.6 Command(CMD, [LOG]) ------------------------ Execute a dos-command but keep the host. If CMD valid dos-command to be executed LOG if the CMD returns with a value > LOG, print it in the log Usage: result = Command(CMD) Requires: Log() 4.7 Count(STRING, CHAR) ----------------------- Return the number of the checked CHARacter contained in the STRING. Usage: number = Count(STRING, CHAR) Requires: nothing... 4.8 ExpandPath(FILE) -------------------- Return the FILE with its complete path. This is e.g. necessary for MM-func- tions because MM always expands the path to the one MM is located (normally MM:bin/) instead of the one, the script was started of. Usage: complete_file = ExpandPath(FILE) Requires: nothing... 4.9 Get_Version(0) ------------------ Get the version of your script from the 3. word of the 3. line in the script- header. If the version could not be found, the script will be exited with RC 99. Basically, the version should be a numeric value, but may also end with ß..., /c to indicate a compressed script, /e to indicate an executable script. This function does work even with CompressRexx v2.0 if you use the VERSION- switch (-> /e ;-) Usage: system.prg.ver = Get_Version(0) Requires: a correct script-header 4.10 Include_Lib(LIBRARY, [PRIORITY]) -------------------------------------- Include an ARexx-function-library. LIBRARY name of the library to include (".library" is not needed) PRIORITY ARexx-function-priority, 0 if not given Usage: call Include_Lib(LIBRARY) Requires: nothing, except the lib to include :-) 4.11 Path(DIR) -------------- Add the trailing '/' to a directory-name. DIR directory-name Usage: dir = Path(DIR) Requires: nothing... 4.12 Replace(STRING, NEW, OLD) ------------------------------ Replace OLD with NEW in STRING. Usage: string = Replace(STRING, NEW, OLD) Requires: nothing... 4.13 Log(TEXT, [PFX], [LOGLEVEL]) --------------------------------- Add a line to MM's log. TEXT the text to log PFX override the system-logprefix with this one, but only for this line LOGLEVEL use this loglevel, default is 2 Usage: call Log(TEXT, PFX, LOGLEVEL) Requires: "system.prg.loglevel" "system.mm.logpre" "system.prg.logpre" 4.14 Request_Choice(TEXT, BUTTONS, RESULTS) ------------------------------------------- This is a very powerfull function which calls MM_Requester and directly returns your specified result. TEXT the text to be printed in the requester with the possibility of a very convenient options-handling: \c center the text \n add a line-feed \<#> use pen-number <#> BUTTONS The buttons for the requester seperated by "|", e.g. '* _OK | _QUIT |_CANCEL' RESULTS the possible results for the buttons from left to right, e.g. '1 2 0', or 'OK QUIT CANCEL', a "_" means '' Usage: result = Request_Choice(TEXT, BUTTONS, RESULTS) Requires: "system.prg.name" Replace() 4.15 Request_String(TEXT, PRESET, MODE) --------------------------------------- Request a string by using MM_RequestString. TEXT requester-text PRESET the value preset in the requester MODE 0: allow no input 1: an input must be If RC=1, the ABORT-button was pressed. Usage: result = Request_String(TEXT, PRESET, MODE) Requires: nothing... 4.16 Wait_AreasWindow --------------------- Remind the user to go back to the areas-window and wait (or quit) until the user has gone back to MM's areas-window. Usage: call Wait_AreasWindow Requires: Delay() [-> rexxsupport.library] Request_Choice() 4.17 Check_Pattern(PATTERN, STRING) ----------------------------------- Check if the (AmigaDOS-)PATTERN does match with the STRING. Usage: boolean = Check_Pattern(PATTERN, STRING) Requires: nothing... 5. The advanced config-read mechanism ===================================== IMPORTANT: If you are not a good coder, don't use it! ARexx isn't the fastest, espacially if you have to do many checks e.g. while config-reading. So I decided to find a better solution for that, and I think I've found a practicable one - read the config once and add it to the script, to prevent all that necessary checks and speed it up below ONE SECOND! :-) Of course for "compiling" your cfg, you need more time than a normal cfg- reading mechanism, but then it is fast as hell. If you only have a very small cfg, don't use it. But for a cfg like MM_Star- Track has, it is perfect! To see how it works, just take a look into MM_CompileCfg. This is a collec- tion of all needed functions for this methode. One problem of this methode is, that you have to take care about the used variable-names. Let's show it with an example: You have a stem for all areas you have configured, called "stem.area.misc" where "area" does contain the areaname. Now you have the problem that e.g. the area is called "TEST-ECHO", it would be added like "STEM.TEST-ECHO.MISC" to the compiled cfg. But ARexx would interprete this like "STEM.TEST" minus "ECHO.MISC" => Syntax error! 8^( But there is a very simple solution for that, the Make_Valid()-function (see 5.5). It translates all "unusable" chars with "_" and ARexx does accept it. But you have to use this function everywhere where you want to access that field... 5.1 Read_Cfg ------------ Now, this is not a Read_Cfg-function like described in 4.4 but only a small function which will decide if the cfg has to be compiled again (see 5.2) or the current compiled one is still valid. This will be simply done by checking the crc of your cfg & the script. Usage: call Read_Cfg Requires: "system.prg.cfg" "system.prg.script" Cfg() [the generated code] statef() [-> rexxsupport.library] 5.2 Compile_Cfg --------------- In general, this is very similar to the Read_Cfg()-function described in 4.4, except that it will add the compiled part of the cfg to your script. In addition to that, you have to use the Add_Cfg()- (see 5.3) & Add_Cfg_- Stem()-functions (see 5.4) to setup your variables & stems. Usage: call Read_Cfg Requires: "system.prg.cfg" "system.prg.script" Add_Cfg() Add_Cfg_Stem() Add_Script() Log() Quit() 5.3 Add_Cfg(VARIABLE, VALUE) ---------------------------- Add a variable to the compiled cfg. VARIABLE name of the variable, e.g. "system.test.variable" VALUE its value Usage: call Add_Cfg(VARIABLE, VALUE) Requires: nothing... 5.4 Add_Cfg_Stem(STEM, VALUE) ----------------------------- Add a stem-variable, like MM_AddToStem. STEM name of the stem, like "system.areas" VALUE the value to be added Usage: call Add_Cfg_Stem(STEM, VALUE) Requires: Add_Cfg() 5.5 Make_Valid(VALUE) --------------------- Remove all illegal characters from VALUE and return a valid variable-name. Usage: name = Make_Valid(VALUE) Requires: "system.invalid" "system.replace" 5.6 Add_Script(LINE) -------------------- Add a LINE to the cfg-code. Normally yo do not need it yourself. Usage: call Add_Script(LINE) Requires: "script." 6. Error-handling ================= I've also developped an advanced ARexx-error-handling, which of course is also included in MM_ScriptBody. It will guarantee a proper exit after an error. 6.1 Enabling error-handling --------------------------- This is done with the commands "options cache; options failat 99; options results; signal on break_c; signal on break_d; signal on break_e; signal on break_f; signal on halt; signal on ioerr; signal on syntax" at the top of MM_ScriptBody. 6.2 Exit -------- This is the real script-exit. Here you have to add all steps which have to be done in every case, even if an error happens. Usage: DO NOT CALL IT DIRECT! USE QUIT()!!! Requires: Log() 6.3 break_c:; break_d:; break_e:; break_f:; halt: ------------------------------------------------- Catch a user-break. See also your ARexx-manual regarding the signal-function. Usage: DO NOT CALL IT DIRECT! Only called by ARexx if a break was detected. Requires: Exit() 6.4 IOerr: ----------- Catch an IO-error. See also your ARexx-manual regarding the signal-function. Usage: DO NOT CALL IT DIRECT! Only called by ARexx if a break was detected. Requires: Exit() 6.5 Syntax: ----------- Catch a syntax-error. See also your ARexx-manual regarding the signal-func- tion. Usage: DO NOT CALL IT DIRECT! Only called by ARexx if a break was detected. Requires: Exit() 7. Acknowledgements =================== Pino Aliberti For his EXCELLENT Mail Manager! For implementing nearly all I wanted (this was much work I think and delayed the release of MM for some month ;-)) For our hard but fair fights in MMBETA and at least for the nice note about me in the docs 8^)))) _ o Robert Hofmann 2:2490/1015@FidoNet 37:108/220@TrekNet |<)_/# 39:171/101@AmigaNet 107:1805/230@TrekNet TT