![]() |
![]() |
#21 |
Registered User
Join Date: Oct 2009
Location: Germany
Posts: 3,326
|
IMHO there isn`t a way of getting always a corrrect version number. In most cases it works but you get in trouble.
Don`t misunderstand. ARexx has no problems with ". In its simplest form you can use " or '. See BigFans examples. ![]() Pipe is good but my experiences was that it can sometimes lock the script. AWNPipe instead seems to work. Interesting if you want to release stuff. About debuging: I would recommend using "Trace i" because you geht the most information. Annoying is that the trace output will cut away after some length. Especially stupid if you deal with long strings or command lines. |
![]() |
![]() |
#22 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
@daxb
if you do not know about ARexx, Piping, debugging, why don't you simply ask here ??? First Pipe: has by default a limit to 4 kb. If you need more then tell Pipe: like Open('temp','PIPE:myspace/32768/1') This will reserve 32kb of space in 1 chunk. Access is done using "file name" myspace. version command is not ARexx, it is AmigaDOS. Version prior to 40.5 has a Y2K bug. This is ARexx tutorial !!! Besides: Version recognizes always all information if the version string is + not longer than 80 byte + has no special char like $10 (hex val 10 for linefeed) + uses "string version date" with no additional white spaces in string. If you doubt version command to give you all information correctly then do a Rexx procedure that analyzes the file itself. Or are you incapable to do? Debugging Nothing vanishes if you use the debugging tools correctly. Obviously you are too lazy to RTFM or follow this tut. Otherwise you would know that tracing can be set on and off using TS TE for INTERACTIVE MODE And judging from your scripts (like buggy icon benchmark, that copies a complete folder to RAM: rendering the machine useless as you can no longer click icons or menus (where did i found same mistake recently)), i have to say that you really should learn a bit more than just the basics to give any recommendations here. In short: I am really pissed atm Last edited by BigFan; 05 July 2015 at 13:49. |
![]() |
![]() |
#23 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Small overview
What kind of data is ARexx aware of? Symbols - a symbol is set of one or more alphanumerics. x is a symbol, A10 too. 7 is a "fixed" symbol. That is, a the name represents its value. Simple said, it is a number. Stems - a stem symbol starts with alphanumerics followed by a period and numbers or more characters e.g. msg.1, msg.2 are stems name.user too. Using more periods and chararcters is then called Compounds - a compound is a sequence of chars, nums and dots, like Book.Author.SKU if SKU is a symbol for 10337 then the compound will be translated to BOOK.AUTHOR.10337. While Cube.x.y.z (for x=10,y=3,z=8) becomes CUBE.10.3.8 Remember, ARexx is using UPPER case except for strings. A string is any set of characters wrapped in single quotes. 'This is a string!' or double quotes like "Hello kitty!" '12345678' <-- another string '0f'x <-- a string with qualifier to tell ARexx this is hexadecimal '0101'b <-- again a string with qualifier this time for a binary value "simple" <-- what to say Your variables are inkarnations of symbols. They got a name that represents a value. Looking closer at stems and compounds and you see it is quite similar to what is called an 'array' in other languages. The memory for symbols, stems and compounds is taken from ARexx internal memory pool. Operators The typical list of operators to compute your stuff is arithmetic operators = assignment + addition - substraction * multiplication % integer division // modulo (division remainder) ** exponantiation || concatenation of strings logical operators & and | or ^ xor ~ not comparison operators = equal ~= not equal == exactly equal >= greater or equal <= less or equal > greater < less ~== exactly not equal ~> not greater (same as <=) ~< not less (same as >=) What is exact equality? All other comparisons between numbers are done after translating a string into a number regarding the default numeric format. This format can be set using the command "Numeric". Let's have a look at the default behavior: Code:
/**/ a = 10 b = '10.0' c = "10" if a=b then say 'absolutly ' a '=' b if a~==b then say a" don't matches " b" exactly" if a='10.0' then say 'really' a 'is equal to 10.0' if 10.0=='10.0' then say '10.0 matches 10.0 perfectly' if b==c then say "Ooops" --> 10 don't matches 10.0 exactly --> really 10 is equal to 10.0 --> 10.0 matches 10.0 perfectly --> b does not match c exactly as well as a is exact inequal to b. What would be the result for an exact/fuzzy comparison between a and c ? The floating point makes the difference. In exact comparison, numbering formats don't change. Setting fuzz will "harmonize" translated numbers, say, it will ignore the decimals to a certain degree. Of course fuzz can't be bigger than precision ![]() Last edited by BigFan; 06 July 2015 at 17:02. |
![]() |
![]() |
#24 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
commands - ARexx has a restricted set of commands. Why? Because it uses functions for almost everything.
functions - the heart of the beast. ARexx offers a lot of string function. The amount of functions is not limited and can be extended using addtitional libraries or coding your own procedures. How does ARexx knows about commands from hosts or external functions?
But what happens if the command is not known to the given host ? Nothing. Sending a command named "goof" to a host that can't process it, gets answered with return code 5 (warn). e.g. Code:
/* */ Address dopus.1 verify "hello" say rc goof 'you are' say rc DOpus opens a requester containing "hello", clicking ok or abort returns 0 or 1. goof does nothing as DOpus do not know it and returns 5. The script then continues. It's up to you as the author to catch errors. ARexx will help you a bit. See later chapter So, with what we have learned yet (you did, didn't you?) we'll create a small script that shows us, what ports are available and who is the caller. Try yourself first. Code:
/**/ Say 'The name of the caller 'Address() Say 'A list of current open ports:';Say Show('p') Exit 0 4.Ram Disk:> rx test3 The name of the caller REXX A list of current open ports: SFS DosList handler FBlit REXX AREXX SWAZINFO DOPUS.1 GOLDED.1 ConClip.rendezvous FPPrefs Port Now this is a long list of ports, isn't it? No. The reason is that Show() uses white space as delimiter, and you cannot distuingish one port from another. Let's correct this. Show() takes 3 arguments, Option, Name, Delimiter, hence Show('p',,';') will do it --> SFS DosList handler;FBlit;REXX;AREXX;SWAZINFO;DOPUS.1;GOLDED.1;ConClip.rendezvous;FPPrefs Port See "SFS" is not a port, but "SFS DosList handler" is. Have a look at those arguments. Option can be any of 'c'lips - names the clips stored in clipboard 'f'iles - names recent open files 'l'ibraries - names libs you opened in rexx 'p'orts - lists current available ports. Name can be any portname you want to query: Say Show('p',swazinfo) --> 1 The result is 1 and this says the port has been found. If you want to check, whether or not a required program has its rexx port open use Show(). But wait, what if the port is dopus.2 while we were asking for dopus.1 ? The answer is simple, we scan the entire output for the name without trailing '.#' ARexx got a lot of string functions for good reason, almost everything is handled as a string. Single characters, integer values, floating point, bitfield, hex values, memory addresses etc. When the interpreter has to do calculations or bit changes or addressing the value will be transformed internally, you don't have to care. You have to care about your symbols (var names) because you can pick keywords like show or numeric as a symbol name, which causes errors when you try to use them for their original purpose. How to circumvent this will be explained after we got pass the basics. -> Last edited by BigFan; 06 July 2015 at 17:49. Reason: correct spelling |
![]() |
![]() |
#25 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Back to topic. There are 3 or 4 functions that could do the job to find a name in string:
Abbrev(string,pattern,[start]) , check if pattern ist the first part of the string Find(string, pattern) , but needs exact pattern to match or we have to convert the string before Index(string, pattern,[start]) , searches string for any pattern Pos(pattern, string,[start]) , almost identical to Index() example code: Code:
/**/ pattern0 = 'DOPUS' /* as said before, ARexx converts results to upper case, so do we*/ string0 = Show('p') /* store the output */ If Pos('DOPUS',string0) > 0 Then Say 'Yes, found it !' Else Say 'Sorry, nothing there' if no match. Another simple code is to check for a specific caller Code:
/**/ port0 = Address() If port0 = 'SPARTA.1' Then Say 'This is SPARTAAAA' Else Say 'Romans go home' Code:
/**/ port0 = Address() If Abbrev(port0,'SPARTA') Then Say 'This is SPARTAAAA' Else Say 'Romans go home' Code:
/**/ port0 = Address() If Abbrev(port0,'GOLDED') Then Say 'This is GOOLDEEEEED' Else Say 'Romans go home' from GOLDED.1 or .2 or .x Last edited by BigFan; 05 July 2015 at 18:39. |
![]() |
![]() |
#26 |
AmigaMan
Join Date: Oct 2012
Location: Castro Urdiales/Spain
Posts: 766
|
Very good and interesting thread! Thanks!
|
![]() |
![]() |
#27 | |||||
Registered User
Join Date: Oct 2009
Location: Germany
Posts: 3,326
|
Quote:
Quote:
Quote:
Quote:
![]() Quote:
|
|||||
![]() |
![]() |
#28 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Simply because you didn't help. Summarize of your posting
* version does not work * pipe does not work * tracing does not work All negative. All to avoid. Where is your help hidden in there? AWNPipe? Want users of vanilla 3.0/1 to get this running too? No special installations required so far. Is AWN Pipe saving you from buggy code? Does AWN make ARexx scripting easier? Trace('i') is really overkill especially for beginners who will get problems with host communication mostly. Yet there is no chapter written about debugging. What do i have to think if one is proposing functions for non-existing problems so far ? Debug output is not getting clipped in interactive mode. You step through line by line. All easy to read, especially for beginners. Reading a file and scanning the content is not overkill if all other options fail. It is an advanced procedure, nothing to bother beginners with. So the easiest way to get version information is what exactly? Tell me. Yes, i might have misinterpreted your posting. Yes, i might have misunderstood your intensions. Still i do not like your explanations. Last thing. I expect code to run without hazzles. User should be warned about any hazardous operation . Code should be aware of system ressources. Memory limitations explicitly. There are enough ways to solve this. I had a really disappointing weekend. Nothing to do with you personally. I apoligize for my harsh and maybe offending words. I still appreciate any help. Wish you all best and have a nice and sunny weekend . Last edited by BigFan; 05 July 2015 at 18:10. |
![]() |
![]() |
#29 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Dear user,
if your dog has eaten your Arexx manual, then here is a List of commands ADDRESS - Specify host or switch between ARG - Shorthand for Parse Upper Arg, takes arguments BREAK - Exit from Do... block or loop (valid for all Do...) CALL - Call a function DO .. END - Do a set of instructions and optionally repeat them DROP - Reset variables as uninitialised ECHO - Display expression result on console ELSE - Alternative branch of an IF statement END - End a Do or Select block or iterates a loop EXIT - Stops a program IF - Conditional block INTERPRET - Execute a string as a statement ITERATE - Restart loop with next iteration LEAVE - Exit from loop or nested loop (only valid for iterations) NOP - No Operation NUMERIC - Set numeric format OPTIONS - Set various internal defaults OTHERWISE - Alternative instruction to When statement PARSE - Extract substrings from string and assign to variables PROCEDURE - Protect symbols in a function or expose them PULL - Reads string from stdin PUSH - Write string to stdout in LIFO order QUEUE - Write string to stdout in FIFO order RETURN - Return to caller with or without return code SAY - Display value of expression or string on stdout SELECT - Block of WHEN conditions SHELL - similar to ADDRESS SIGNAL - Control state of internal interrupt flags WHEN - Like If, but leaves block it true Taken and partially rewritten from p.j.hutchison's wb31.guide, who condensed the content of the manual ![]() Last edited by BigFan; 05 July 2015 at 18:19. |
![]() |
![]() |
#30 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Let's continue with what the dog had for dinner:
Numeric funcions ABS() - Absolute value DIGITS() - Return current NUMERIC setting FORM() - Returns current NUMERIC FORM setting FUZZ() - Returns current NUMERIC FUZZ setting MAX() - Returns maximum of given values MIN() - Returns minimum of given values RANDOM() - Returns pseudo-random number RANDU() - Returns pseodo-random number between 0 and 1 SIGN() - Returns sign of value TRUNC() - Returns integer part of value (optionally to number of decimal places) VALUE() - Returns value of a symbol or character String functions ABBREV() - Returns 1 or 0 if string2 is an abbrev of string1 CENTER() - Center string with in a number of characters CENTRE() - See CENTER COMPARE() - Compare two strings COMPRESS() - Remove leading, trailing, embedded blanks COPIES() - Produces multiple copies of string DATATYPE() - Tests string and returns type of string DELSTR() - Delete substring from string DELWORD() - Delete a substring in words FIND() - Locates substring and returns word number HASH() - Returns hash attribute of a string INDEX() - Searches for a string in another string INSERT() - Insert a new string into old string LASTPOS() - Searches backwards for first occurance of string LEFT() - Returns left mose string LENGTH() - Returns length of string LINES() - Returns no. of lines queued or typed ahead OVERLAY() - Overlays new string onto old string POS() - Searches for first occurance of pattern in string REVERSE() - Reverse sequence of characters RIGHT() - Return right most characters of string SPACE() - Reformat string with number of n spaces between words STRIP() - Removes leading, trailing or both spaces from string SUBSTR() - Returns a substring or a string SUBWORD() - Returns a substring of words in a string TRANSLATE() - Constructs a translation table and uses it to replace characters in a string. TRIM() - Removes trailing spaces from a string UPPER() - Converts string to uppercase VERIFY() - Returns index of first char in string which is not in the list argument string or vice versa if MATCH spec. WORD() - Returns nth word in string WORDINDEX() - Returns position of nth word in a string WORDLENGTH() - Returns length of nth word in string WORDS() - Returns number of words in string XRANGE() - Generates a string between start and end values Bitfield functions BITAND() - Bit wise AND BITCHG() - Bit wise change BITCLR() - Bit wise clear BITCOMP() - Bit wise compare BITOR() - Bit wise OR BITSET() - Bit wise set BITTST() - Bit wise test BITXOR() - Bit wise Exclusive OR Conversion functions B2C() - Binary to character C2B() - Character to binary C2D() - Character to decimal C2X() - Character to hex D2C() - Decimal to ASCII character D2X() - Decimal to hex X2C() - Converts hex to packed character X2D() - Converts hex to decimal File functions CLOSE() - Close file EOF() - End of file ERRORTEXT() - Returns error message from error code EXISTS() - Test if file exists OPEN() - Opens an external file READCH() - Reads number of characters from file READLN() - Read characters from file until LF found SEEK() - Move to new position in file WRITECH() - Writes string to a file WRITELN() - Writes string to a file with a LF added Control functions ARG() - Returns number of arguements supplied in current env. ADDRESS() - Returns current host address string ADDLIB() - Adds function library or host to library list PRAGMA() - Change attributes of system environment REMLIB() - Remove an entry from Library List SHOW() - Returns names in resource list specified by option SOURCELINE() - Returns test for specified line in program or number of lines SYMBOL() - Test if name argument is a valid ARexx symbol TRACE() - Sets tracing mode Time functions DATE() - Current date TIME() - Returns current time Memory functions EXPORT() - Copies data from string to allocated memory FREESPACE() - Returns block of memory in interpreter`s memory pool GETCLIP() - Returns value of entry in Clip List GETSPACE() - Allocates a block of memory IMPORT() - Create a string from data from given address SETCLIP() - Add name-value pair to Clip List STORAGE() - Returns free system memory or copy string to memory RexxSupport.Library Functions ALLOCMEM() - Allocates a block of memory CLOSEPORT() - Closes a message port FREEMEM() - Releases a block of Allocated memory GETARG() - Extracts command, function name or string from message pkt OPENPORT() - Creates a public message port REPLY() - Returns a msg pkt to the sender with a value SHOWDIR() - Returns contents of directory as strings of names SHOWLIST() - Returns a string of names depending on option STATEF() - Returns a string containing file information WAITPKT() - Waits for a msg pkt from port |
![]() |
![]() |
#31 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Copy the lists and store them on your harddrive for quick access.
These lists do not provide information about the parameters or arguments handled by those commands and functions as this would definitly go beyond the scope of this tutorial. Thank for your listening. |
![]() |
![]() |
#32 | |||
Registered User
Join Date: Oct 2009
Location: Germany
Posts: 3,326
|
Quote:
Quote:
Quote:
![]() |
|||
![]() |
![]() |
#33 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Now we are doing more simple stuff. Question: If i ran my script from shell,
is there any way to interact? Yes, because actual console becomes standard i/o stream. ARexx directs its output to it, and reads from it too. The 3 streams are stdin, stdout, stderr. You can redirect them to any file handling device. The command desired is "Pull <string>". Pull reads what has been put to the input buffer and stores it in a variable. Pull is shorthand for "Parse upper pull". Code:
/* pull from console*/ Say "Hello, user!" Say "Please enter your name:" Pull user.name /* using stem symbol*/ Say "Funny, my name is "user.name", too!" Say "How old are you?" Pull user.age /* to store related data */ Say "Ooh, "user.age" is my handicap." Exit
See what happened to the user name. All capitals. As said "Pull" is shortened form of "Parse upper pull" we replace Code:
Pull user.name Code:
Parse Pull user.name Now the name appears as typed before: => Funny, my name is Chris, too! Pull can be called many times, each Pull waits for input Pull name Pull age Pull weight Pull height needs 4 inputs from console to get satisfied. Reading more than one word from input is possible: Code:
Say "Enter name, age, weight, height in one line" Pull user.name user.age user.weight user.height You can push everything to it but think of console has to deal with it or you have to pull it back before exiting and releasing input buffer to console handler. Code:
Push "I smack you" Push "Twice" Push "Call mom" The order is now reversed Code:
Say Pull a;Say Pull a;Say Pull a Call mom Twice I smack you If you like to get it in same order as pushed, than you have to queue it. Code:
Queue "I smack you" Queue "Twice" Queue "Call mom" Code:
Say Pull y;Say Pull y;Say Pull y I smack you Twice Call mom Lets do some more serious stuff. Code:
/* queued */ Queue echo "Content of Sys:" Queue requestchoice '"Queued" "Ready to go?" OK' Queue "list >pipe:list Sys:" Queue "more <pipe:list" Queue echo "Thank you for your attention" Exit In fact, the console handler will process whats in the buffer the same way as if it has been typed in directly. Pushing or queuing text only to the buffer may cause error messages. Console handler interpretes input as command, when not redirecting input to another stream (e.g. sending to NIL: ). Check it out yourself. Last edited by BigFan; 07 July 2015 at 15:20. |
![]() |
![]() |
#34 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Counting words
So we have a list of command and functions, now we need a problem to solve,
a task, or some more examples. Your task is : Open a file and count the words. Perform the following: open a filerequester or use command line arguments open a file on success process file display result ARexx has no built-in GUI. If we want a nifty little requester we can borrow this from a DOS command. DOS commands do not have ARexx ports. We cannot communicate directly. We have to redirect the output and let our program fetch it. Again we use pipe: for this. Code:
Address command 'requestfile >pipe:a DRAWER SYS: TITLE "Select a text file" NOICONS' If ... Then to deal with results Open(filehandle, filename) where filehandle is any name which will serve as a reminder to the opened file and filename is a string with path and name of file to open Close(filehandle) to shut the file Eof(filehandle) to test for end of file Do While a loop for file processing ... End Readln(filehandle) read characters until linefeed Words(string) counting words in a string in quotes or a variable containing a string this function has limited capabilities. Everything before a white space is considered being a word ranging from numbers to letters to signs. To deal with DOS command "requestfile" we need to prepare the output as it has additional unwanted quotes. We need to remove those double quotes before using the string in our functions I suggest to use Compress(string,pattern) to remove pattern from string. If you think you can do, stop reading. Try yourself first. Extend your code with additional line counter. Here comes a possible solution Code:
/* simple word and line counter */ pipe = 'pipe:a' linecount = 0 /* if you want to calc with vars then fill */ count = 0 /* them first or they remain void symbols*/ Address command 'requestfile >' pipe' DRAWER Sys: TITLE "Select a text file" NOICONS' Open(phandle,pipe) fil0 = Readln(phandle) /*no error checking required*/ Close(phandle) fil0 = compress(fil0,'"') /*a must have, delete unwanted chars*/ If Open(fhandle,fil0) Then Do /* check if file exists and open it*/ Do While ~Eof(fhandle) /* loop to end of file */ lin0 = Readln(fhandle) /* naa, i don't comment this */ linecount = linecount + 1 count = count + Words(lin0) /*count words and increase result on every step*/ End Close(fhandle) /* we are tidy, not needed but good style*/ Say "In file "fil0 Say "Number of words: "count Say "number of lines: "linecount - 1 End /* if file cannot be opened we get here*/ Exit /*not needed but again good style */ ![]() Last edited by BigFan; 08 July 2015 at 16:59. |
![]() |
![]() |
#35 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
String searching and replacing
After we had counted words which is not very productive nor often requested,
let us do some text manipulations.
***************** Attention please ******************************** We are dealing with text files !! Don't do this on binaries (programs). Leave that to advanced users. *************************************************************** What text is often used and altered? Well, the startup-sequence, user-startup as well. Create a directory for your projects (use harddisk or floppy, not ramdrive). Copy s:startup-sequence,s:user-startup to new directory. You might use that directory directly in code or ask user on start to load the file. We design the code to add a version string to the file if there is none. Remember that this string has to be a comment or DOS tries to execute it. Place a semicolon in front. We have to clarify what a version string is. This is mandatory because other programs use it and we don't want do cause any incompatabilites. It has to look like this $VER: programname version.revision (date) [description] e.g. " $VER: user-startup 40.14 (06.07.15) my personalized user-startup " $ sign; VER in capital letters; colon; space; text (without space); space; version.rev; space; date (in parenthesis); space; any text
We are able to identify unallowed characters but this is more advanced. We stick to simple code for now. functions we need: open() close() readln() writeln() eof() pos() delstr() insert() We do not check for free mem or file size. This is up to you to enhance the code or elaborate in later chapter. Feel lucky? Try yourself before continuing. Code:
/* Example script to find and update version string * $VER: VersionUpdater 1.1 (07.07.15) * * Updates current version string * or adds a new verion string if none * has been found. We focus on version * string only. No additional description * is added or replaced. */ filename = 'sys:t/user-startup' newversion = 'user-startup 40.14 (06.07.15)' identifier = '$VER:' i = 1 /* read file */ If Open(infile,filename,'r') Then Do Do While ~Eof(infile) i = i + 1 /* we start with line index 2, intentionly */ line.i = Readln(infile) End i = i - 1 /* <== wuut? This can't be done better? :D */ End Else Do Echo "Cannot find "filename"!" Exit 20 End Close(infile) Address command 'rename ' filename' ' filename'.bak' /*create backup file*/ /* scan the input */ found = 0 Do j = 2 to i p1 = Pos(identifier,line.j) /*search for VER: */ If p1 = 0 Then Iterate Else Do found = 1 p2 = Pos(')',line.j) + 1 /* get closing parentheses */ p1 = p1 + 6 /* our replacement has no VER so we step forward */ Leave End End /* replace or add */ If found = 1 Then Do line.j = Delstr(line.j,p1,p2-p1) /* delete what is between : and ) */ line.j = Insert(newversion,line.j,p1-1) /* and replace */ End Else line.1 = "; " identifier" "newversion /* or create a new one, auto concatenated*/ /* write file to disk */ start = found + 1 /* start is 1 or 2 */ If Open(outfile,filename,'W') Then Do Do j = start to i Writeln(outfile,line.j) End Close(outfile) Address command 'Delete' filename'.bak' /* <== this is not fail safe !! */ End Else Do Echo "Cannot write to file" Echo "Restoring backup" Address command 'rename ' filename'.bak 'filename /* restore backup file*/ End Exit Dynamic creation of replacement string. Error check on read and write (disk might be full while writing) Better coding style. Reduce code to avoid many loops. Maybe one is enough ? Clean up after failure or request user to delete the waste. ... to be continued Last edited by BigFan; 07 July 2015 at 15:35. |
![]() |
![]() |
#36 | |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Quote:
![]() I'm sorry, but i think you misunderstood. There is one line number only, follow ups are calculated. What prevents you from placing this on top of code? But there is more than one way to skin a cat ![]() Each to his own |
|
![]() |
![]() |
#37 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Interrupt Signals
Before we continue to clean up the code from the previous example, we inspect
the tools provided to debug our code. First those options from inside code: Signal On <option> This allows your code to be aware of interupts caused by errors or signals from outside, like Ctrl+C to interupt program execution Each option has to be triggered in a single statement. When signal is on, you need a label of same name to jump at. The label has to be outside of loops or conditional blocks. Code:
/**/ Signal on error Signal on break_c Signal on break_d Options Results Address ..... blablabla your code runs here .... Error: /* label for signal on error*/ Echo "Damn it" Echo sigl /* sigl is special variable, stores the source line that causes an error*/ Break_c: /* label for ctrl+c*/ Exit Break_d: /* label for ctrl+d*/ Echo "Why?? Don't you like me?" Exit With Ctrl+D we interrupt scripts and receive a message from our wailer, then exit. If an error occurs during runtime, we swear, then ask for the line where the error occured. An error is every return code (stored in internal var "RC") greater than zero. Pobably you know those error levels from DOS : 5 , 10 , 20. Same for ARexx. You can lower or raise the error level with Options Failat. Signal on [] reacts to BREAK_C; BREAK_D; BREAK_E ;BREAK_F ERROR HALT /* interrupt call from outside*/ IOERR /*device io like disk access */ NOVALUE /* code uses uninitialized symbol */ SYNTAX /* execution error, useful for internal syntax errors*/ |
![]() |
![]() |
#38 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Return code checking
A very simple way to check your code is to periodically ask the value of one
of both of the internal variables "RC" and "RESULT". RC keeps track of all commands, functions both internal and external. RESULT stores the message, the current host replied when sending a command. The content of RESULT heavily depends on whom we talked to. While RC always represents a positive numeric value of 0 or higher, RESULT can store anything from numbers to strings to nothing. To make use of RESULT, enable it by calling "Options RESULTS" before results are received. Place on top of script for general purpose. If RESULT wasn't returned the symbol becomes a string. E.g.: Adress fcheck.1 Log Logfile = RESULT /* assume result is a string like "20150701-1002-entry.45-kill"*/ then Code:
Logfile = "20150701-1002-entry.45-kill" RESULT becomes a string itself Code:
Logfile = "RESULT" Use 'Say rc' or 'Say result' to display them in current console, or redirect them anywhere you like, e.g. in a log file, pipe, clipboard, conbuffer. Be more precise and place a string as explanation next to it. One or two return codes or results aren't big problem. 24 or hundreds of them and you start pulling your hair ![]() Last edited by BigFan; 07 July 2015 at 15:56. |
![]() |
![]() |
#39 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Tracing
Tracing
A powerful feature is ARexx ability to trace all steps taken. The very first console to send the output is the shell from which rx command has been invoked. External interactive tracing Before starting your code with "rx <name>" start tracing by typing "ts" in your shell. The program detaches immediatelly and you can continue. Now run your code. Your are in interactive mode und every iteration is prompted. You need to confirm by entering a null string to continue execution (hir return ![]() Beware that a loop of 1000 iterations forces you hit 1000 times the return key ![]() TS sets interactive mode globally. If TS is not needed any longer, then switch it off using command "te". Internal interactiv tracing Use Trace() in your code to trigger the mode individually. If you want to start interactive tracing at a certain line, then put Trace(?'r') f.e. before your buggy section. This saves you a lot of time. Controlling interactive mode Work with TCO console ! Don't type in shell, it won't help ![]() In interactive mode you can enter an equal sign "=" to repeat preceding expression. Type in "trace r" or "trace i" to change output level. "trace ?" stops interactive mode and continues execution. If you are in normal mode, switch to interactive using "trace ?#" where # is an option like r or i. Command inhibition There is another option called command inhibition. Using explanation mark suppresses a command to be send to the host. Useful if you want to avoid dangerous ops like file deletion or disk formatting. In our previous script we used DOS command 'delete' to kill backup file. To avoid this, set before that line a Trace(?'r') followed by an empty symbol as a tracemarker. When this marker appears in outout window then type "trace !" (without quotation marks) in interactive console window. See example below: Code:
/* write file to disk */ start = found + 1 If Open(outfile,filename,'W') Then Do Do j = start to i Writeln(outfile,line.j) End Trace(?'r') Close(outfile) tracemarker Address command 'Delete' filename'.bak' End Else Do Echo "Cannot write to file" Echo "Restoring backup" Address command 'rename ' filename'.bak 'filename /* restore backup file*/ End Press Ctrl+C to terminate execution. Global tracing To keep your shell clean, open a dedicated console with "tco" which directs TraCeOutput to a new window. Use "tcc" for TraCeClose. TCO is useful if the host is other than ARexx and does not supply its on ouput window. TCO switches all running rexx programs in trace mode. Use background option for those you don't want to scan. In the past TCO and TCE had been translated differently. TraceConsoleOpen and TraceConsoleClose sounds more reasonable ![]() Within your code you can specify the level of tracing with Trace('option'). Option is one of 'A'll clauses are traced. 'B'ACKGROUND No tracing, program cannot be forced into interactive mode 'C'OMMANDS command clauses are traced 'E'RRORS non-zero return codes are traced 'I'NTERMEDIATES All clauses are traced and intermediate results are displayed 'L'ABELS label clauses are traced 'N'ORMAL (Default) rc that exceeds the current error failure level 'O'FF Tracing is turned off. 'R'ESULTS results including parsed args are traced (good for general-purpose). 'S'CAN special option suppresses execution messages but shows errors. Good for quick check of newly written code. As with most ARexx options only first letter is evaluated. 'r' is same as 'results'. In the very beginning it is hard to understand what is reported. Use tracing often, even with working code, to get familiar with the output. After a while it looks less cryptic and you focus automagically on the "1"s in output ![]() No you won't see the code as in "Matrix" ![]() red dress ![]() Why ones, not zeros? A 1 is considered as success, 0 means fail. Whether this is good or bad belongs to the code, but very often 0 is a bad sign due to most functions that reported 0 just failed. Think of opening a file, reading an argument etc. Conditional clauses (like IF) on the other hand do not necessarily fail when they fail ![]() If you check for 0 as failure, a returned 1 means success, what pitty. ![]() Last edited by BigFan; 08 July 2015 at 17:19. |
![]() |
![]() |
#40 |
Registered User
Join Date: Feb 2014
Location: Germany
Posts: 261
|
Decrypting trace output
Tracing output from previous example "update.rexx"
Code:
1 *-* ; 3 *-* filename = 'sys:t/user-startup'; >>> "sys:t/user-startup" >+> 4 *-* newversion = 'user-startup 40.14 (06.07.15) my persona... >>> "user-startup 40.14 (06.07.15) my personalized user-sta..." >+> 5 *-* identifier = '$VER:'; >>> "$VER:" >+> 6 *-* i = 2; >>> "2" >+> 8 *-* ; 10 *-* If Open(infile,filename) Then >>> "INFILE" >>> "sys:t/user-startup" >>> "1" >+> 10 *-* Do; 11 *-* Do While ~Eof(infile); >>> "INFILE" >>> "1" 12 *-* line.i = Readln(infile); >>> "INFILE" >>> "; $VER: user-startup 40.14 (06.07.15) my personalized ..." >+> Code:
>+> = interactive mode; requires key stroke 1 = line number *-* = marker with source code >>> = a value has been assigned or returned +++ = command or syntax error , execution halted Code:
line 10 code is: If Open(infile,filename) Then infile became INFILE filename contains "sys:t/user-startup" now if condition returned true (1) = file open success means nothing to say. Entering a block of statements or iterating a loop is indicated by the repetition of according line numbers. Conditional clauses Call, If, Do, Select, When, Otherwise aren't interupted. See example above. ----------------------------------------------------------------------- With Trace('I') >?> is one of >C> Expanded compound (line.j -> line.2) >F> Result of a function call >L> Label clause >O> Result of a dyadic operation (0 or 1) >P> Result of a prefix operation >U> Uninitialized variable >V> Value of a variable >>> Expression or template result >.> "Place holder" token value Last edited by BigFan; 08 July 2015 at 16:18. |
![]() |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
AmigaDOS scripting resources | Photon | Coders. System | 26 | 19 March 2018 14:51 |
Very Basic Scripting. Confused. | marduk_kurios | Coders. System | 5 | 06 February 2014 11:13 |
UAE Scripting Layer | FrodeSolheim | support.FS-UAE | 15 | 26 January 2014 15:56 |
C= 64 BASIC as a Scripting Language | Charlie | Retrogaming General Discussion | 2 | 17 November 2008 14:23 |
|
|