English Amiga Board


Go Back   English Amiga Board > Coders > Coders. System > Coders. Scripting

 
 
Thread Tools
Old 05 July 2015, 02:46   #21
daxb
Registered User
 
Join Date: Oct 2009
Location: Germany
Posts: 3,303
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.
daxb is offline  
Old 05 July 2015, 13:42   #22
BigFan
Registered User
 
BigFan's Avatar
 
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.
BigFan is offline  
Old 05 July 2015, 13:47   #23
BigFan
Registered User
 
BigFan's Avatar
 
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"
--> absolutly 10 = 10.0
--> 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.
BigFan is offline  
Old 05 July 2015, 13:50   #24
BigFan
Registered User
 
BigFan's Avatar
 
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?
  1. ARexx first searches its set of built-in commands.
  2. Next it looks at the table of internal (built-in) functions.
  3. Then any additional library is scanned.
  4. External functions (like procedures) get checked.
  5. Finally, in case of no find, ARexx simply decides that this has to be sent to a host as a possible command.
If no host is addressed (that is your current host is still REXX), an error occures.

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
presuming DirOpus is running, this will be our new host.
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
Running this from shell displays something like this

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
BigFan is offline  
Old 05 July 2015, 13:52   #25
BigFan
Registered User
 
BigFan's Avatar
 
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'
Both, Index() and Pos(), return the position of the first occurance of pattern or 0
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'
But what if sparta.3 is running, not sparta.1 ?

Code:
/**/

port0 = Address()
If Abbrev(port0,'SPARTA') Then Say 'This is SPARTAAAA'
Else Say 'Romans go home'
Think of running GoldEd. Rewrite code from above inside GoldEd:

Code:
/**/
port0 = Address()
If Abbrev(port0,'GOLDED') Then Say 'This is GOOLDEEEEED'
Else Say 'Romans go home'
Select menu "Makros / Text as macro". GEd will run the code no matter if started
from GOLDED.1 or .2 or .x

Last edited by BigFan; 05 July 2015 at 18:39.
BigFan is offline  
Old 05 July 2015, 14:45   #26
tolkien
AmigaMan
 
tolkien's Avatar
 
Join Date: Oct 2012
Location: Castro Urdiales/Spain
Posts: 760
Very good and interesting thread! Thanks!
tolkien is offline  
Old 05 July 2015, 17:06   #27
daxb
Registered User
 
Join Date: Oct 2009
Location: Germany
Posts: 3,303
Quote:
Originally Posted by BigFan View Post
@daxb

if you do not know about ARexx, Piping, debugging, why don't you simply ask here ???
If I have a question then I will ask. Comments are unwanted? It seem you feel attacked but that wasn`t my intention. I just wanted to help and wrote what I`ve experienced. But thanks for the info about Pipe. I`ll try to fix the problem where I noticed the lock.


Quote:
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?
Analyzing file itself is overkill IMHO. I only wrote that you cannot trust the version output always (in most case it works, yes). Version number isn`t always the second word or can have chars and or spaces for example.

Quote:
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
Hmm... when I read this I`ve to suppose that you just understand me wrong. Do you really feel attacked?! I just was pointing to debug output that is clipped and that "trace i" gives the most information.

Quote:
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.
If you found a bug, why you don`t report it? Only judging is bad style. OpenWin.rexx: "Copy a directory to Ram:" is a feature but can be disabled if wished. Further, it is not a good idea doing anything while it is running (RTFM ). While the DOpus5 test you can do anything. For WB test should apply the same but I cannot test it here. Maybe you just misunderstood the function of it?

Quote:
In short: I am really pissed atm
Ok, but for what reason?
daxb is offline  
Old 05 July 2015, 17:56   #28
BigFan
Registered User
 
BigFan's Avatar
 
Join Date: Feb 2014
Location: Germany
Posts: 261
Quote:
Originally Posted by daxb View Post
Ok, but for what reason?
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.
BigFan is offline  
Old 05 July 2015, 18:01   #29
BigFan
Registered User
 
BigFan's Avatar
 
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.
BigFan is offline  
Old 05 July 2015, 18:04   #30
BigFan
Registered User
 
BigFan's Avatar
 
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
BigFan is offline  
Old 05 July 2015, 18:15   #31
BigFan
Registered User
 
BigFan's Avatar
 
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.
BigFan is offline  
Old 05 July 2015, 22:35   #32
daxb
Registered User
 
Join Date: Oct 2009
Location: Germany
Posts: 3,303
Quote:
Originally Posted by BigFan View Post
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.
Yes, and I have not said anything of that! Notice, all was positive. Misunderstanding or you do not want to understand.

Quote:
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.
Using any version command.

Quote:
I had a really disappointing weekend. Nothing to do with you personally.
I apoligize for my harsh and maybe offending words.
That explains your words. I thought already you are a bad guy.
daxb is offline  
Old 06 July 2015, 15:52   #33
BigFan
Registered User
 
BigFan's Avatar
 
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
Starting this code gives us:

4.Ram Disk:> rx pull
Hello, user!
Please enter your name:
Chris
Funny, my name is CHRIS, too!
How old are you?
35
Ooh, 35 is my handicap.
4.Ram Disk:>


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
with
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
The opposite to Pull is Push. Push copies a string to stdin.
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"
Pull fetches the last string first that has been copied to input buffer.
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
The content of the buffer is not deleted when our program exits.
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.
BigFan is offline  
Old 06 July 2015, 16:03   #34
BigFan
Registered User
 
BigFan's Avatar
 
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'
further more you need

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 */
Congratulations for your first rexx program

Last edited by BigFan; 08 July 2015 at 16:59.
BigFan is offline  
Old 06 July 2015, 16:22   #35
BigFan
Registered User
 
BigFan's Avatar
 
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.
  • Again we open a textfile.
  • We search the file for specific content.
  • If exists and requested, we replace the old with new text.
  • If not exists, add an updated string.
  • Close file and exit from program.

***************** 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
  • Space is used as delimiter.
  • Version number is always version;dot;revision.
  • No leading zeros in numbering.
  • Date format is (dd.mm.yy).
  • Description is optional.
  • Version string shouldn't exceed 80 characters in total.
  • Version string is not allowed to span over many lines.
  • No linefeed or newline character or any other special character is allowed,
or DOS command will fail to read and interprete the string (and most other tools too).
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
There is a lot of room for improvements.
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.
BigFan is offline  
Old 06 July 2015, 16:57   #36
BigFan
Registered User
 
BigFan's Avatar
 
Join Date: Feb 2014
Location: Germany
Posts: 261
Quote:
Originally Posted by Korodny View Post
Code:
pseudo code:

lang = 50
select 
  when francais then lang=lang
  when espanol then lang=lang+25
  when italiano then lang=lang+50
  when deutsch then lang=lang+75
  otherwise lang=lang+100

welcome.msg = sourceline(lang)
abort.msg = sourceline(lang + 1)
check.msg = sourceline(lang + 2)
Wow, that's extremely confusing and error prone - it relies on strings having the right line number - every time you edit your script, you'd have to check that the string definitions still start at the right line numbers. Not to mention what a nightmare adding a new string would be...

Ouch, sorry - seems I posted a test version of the script, it enforces German strings ('la="DEUTSCH"). I'll edit my first posting.
So my code is error prone, while yours is ... ?

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
BigFan is offline  
Old 07 July 2015, 14:36   #37
BigFan
Registered User
 
BigFan's Avatar
 
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
Now when pressing Ctrl+C no error is posted as we told to just exit in this case.
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*/
BigFan is offline  
Old 07 July 2015, 14:38   #38
BigFan
Registered User
 
BigFan's Avatar
 
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"
But if addressed host is offline, or Options Results is not set ,
RESULT becomes a string itself
Code:
Logfile = "RESULT"
Never do a boolean check for 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.
BigFan is offline  
Old 07 July 2015, 14:49   #39
BigFan
Registered User
 
BigFan's Avatar
 
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
Doing so prevents ARexx from sending command to shell. Delete won't get executed.
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" There is no blonde woman in a
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.
BigFan is offline  
Old 07 July 2015, 14:57   #40
BigFan
Registered User
 
BigFan's Avatar
 
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 ..."
>+>
Read output like this =>
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
Translated to english =>

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
Missing lines contain empty expression or comments. Nothing to do
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.
BigFan is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
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

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 03:29.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.11700 seconds with 14 queries