8.5.2 The SHVBLOCK structure
All requests to manipulate the REXX variable pool are controlled
by a structure which is called SHVBLOCK, having the definition:
typedef struct shvnode {
struct shvnode *shvnext ; /* ptr to next in blk in
chain */
RXSTRING shvname ; /* name of variable */
RXSTRING shvvalue ; /* value of variable */
ULONG shvnamelen ; /* length of shvname.strptr */
ULONG shvvaluelen ; /* length of shvvalue.strptr */
UCHAR shvcode ; /* operation code */
UCHAR shvret ; /* return code */
} SHVBLOCK ;
typedef SHVBLOCK *PSHVBLOCK ;
The fields shvnext and shvcode are purely input, while shvret is
purely output. The rest of the fields might be input or output,
depending on the requested operation, and the value of the fields.
The significance of each field is:
[shvnext]
One call to RexxVariablePool() may sequentially process
many requests. The shvnext field links one request to
the next in line. The last request must have set
shvnext to NULL. The requests are handled individually
and thus, calling RexxVariablePool() with several
requests is equivalent to making one call to
RexxVariablePool() for each request.
[shvname]
Contains the name of the variable to operate on, as a
RXSTRING. This field is only relevant for some requests,
and its use may differ.
[shvvalue]
Contains the value of the variable to operate on as a
RXSTRING. Like shvname, this might not be relevant for
all types of requests.
[shvnamelen]
The length of the array that shvname.strptr points to.
This field holds the maximum possible number of
characters in shvname.strptr. While shvname.strlength
holds the number of characters that are actually in use
(i.e. defined).
[shvvaluelen]
The length of the array that shvvalue.strptr points to.
Relates to shvvalue, like shvnamelen relates to shvname.
[shvcode]
The code of operation; decides what type of request to
perform. A list of all the available requests is given
below.
[shvret]
A return code describing the outcome of the request.
This code is a bit special. The lower seven bits are
flags which are set depending on whether some condition
is met or not. Values above 127 are not used in this
field.
There is a difference between shvnamelen and shvname.strlength.
The former is the total length of the array of characters pointed
to by shvname.strptr (if set). While the latter is the number of
these characters that are actually in use. When a SHVBLOCK is
used to return data from RexxVariablePool(), and a pre-allocated
string space has been supplied, both these will be used;
shvname.strlength will be set to the length of the data returned,
while shvnamelen is never changed, only read to find the maximum
number of characters that shvname can hold.
Even though shvnamelen is not really needed when shvname is used
for input, it is wise to set it to its proper value (or at least
set it to the same as shvname.strlength). The same applies for
shvvalue and shvvaluelen.
The field shvcode can take one of the following symbolic values:
[RXSHV_DROPV]
The variable named by the direct variable name shvname
is dropped (i.e. becomes undefined). The fields shvvalue
and shvvaluelen do not matter.
[RXSHV_EXIT]
This is used to set the return value for an external
function or exit handler.
[RXSHV_FETCH]
The value of the variable named by the direct variable
name shvname is retrieved and stored in shvvalue. If
shvvalue.strptr is NULL, the interpreter will allocate
sufficient space to store the value (but it is the
responsibility of the application programmer to release
that space). Else, the value will be stored in the area
allocated for shvvalue, and shvvaluelen is taken to be
the maximum size of that area.
[RXSHV_NEXTV]
This code is used to retrieve the names and values of
all variables at the current procedure level; i.e.
excluding variables shadowed by PROCEDURE. The name and
value of each variable are retrieved
simultaneously into shvname and shvvalue, respectively.
Successive requests for RXSHV_NEXTV will traverse the
interpreter's internal data structure for storing
variables, and return a new pair of variable name and
value for each request. Each variable that is visible in
the current scope, is returned once and only once, but
the order is non-deterministic.
When all available variables in the REXX interpreter
have already been retrieved, subsequent RXSHV_NEXTV
requests will set the flag RXSHV_LVAR in the shvret
field. There are a few restrictions. The traversal will
be reset whenever the interpreter resumes execution, so
an incomplete traversal can not be continued in a later
external function, exit handler, or subcommand handler.
Also, any set, fetch or drop operation will reset the
traversal. These restrictions have been added to ensure
that the variable pool is static throughout one
traversal.
[RXSHV_PRIV]
Retrieves some piece of information from the
interpreter, other than a variable value, based on the
value of the shvname field. The value is stored in
shvvalue as for a normal fetch. A list of possible
names is shown below.
[RXSHV_SET]
The variable named by the direct variable name shvname
is set to the value given by shvvalue.
[RXSHV_SYFET]
Like RXSHV_FETCH, except that shvname is a symbolic
variable name.
[RXSHV_SYDRO]
Like RXSHV_DROPV, except that shvname is a symbolic
variable name.
[RXSHV_SYSET]
Like RXSHV_SET, except that shvname is a symbolic
variable name.
One type of request that needs some special attention is the
RXSHV_PRIV, which retrieves a kind of meta-variable. Depending on
the value of shvname, it returns a value in shvvalue describing
some aspect of the interpreter. For RXSHV_PRIV the possible
values for shvname are:
[PARM]
Returns the ASCII representation of the number of
parameters to the currently active REXX procedure. This
may not be the same value as the built-in function
ARG() returns, but is the number ArgCount in
RexxStart(). The two might differ if a routine was
called with trailing omitted parameters.
[PARM.n]
The n must be a positive integer; and the value
returned will be the n'th parameter at the current
procedure level. This is not completely equivalent to
the information that the built-in function ARG()
returns. For parameters where ARG() would return the
state omitted, the returned value is a null string,
while for parameters where ARG() would return the state
existing, the return value will be the parameter string
(which may be a zero length string.
[QUENAME]
The name of the currently active external data queue.
This feature has not yet been implemented in Regina,
which always return default.
[SOURCE]
Returns the same string that is used in the PARSE SOURCE
clause in REXX, at the current procedure level of
interpretation.
[VERSION]
Returns the same string that is used in the PARSE
VERSION clause in REXX.
The value returned by a variable pool request is a bit uncommon. A
return value is computed for each request, and stored in the
shvret field. This is a one-byte field, of which the most
significant bit is never set. A symbolic value RXSHV_OK is
defined as the value zero, and the shvret field will be equal to
this name if none if the flags listed below is set. The symbolic
value for these flags are:
[RXSHV_BADF]
The shvcode of this request contained a bad function
code.
[RXSHV_BADN]
The shvname field contained a string that is not valid
in this context. What exactly is a valid value depends
on whether the operation is a private, a symbolic
variable, or direct variable operation.
[RXSHV_LVAR]
Set if and only if the request was RXSHV_NETXV, and all
available variables have already been retrieved by
earlier requests.
[RXSHV_MEMFL]
There was not enough memory to complete this request.
[RXSHV_NEWV]
Set if and only if the referenced variable did not
previously have a value. It can be returned for any
set, fetch or drop operation.
[RXSHV_TRUNC]
Set if the retrieved value was truncated when it was
copied into either the shvname or shvvalue fields. See
below.
These flags are directly suitable for logical OR, without
shifting, e.g. to check for truncation and no variables left, you
can do something like:
if (req->shvret & (RXSHV_TRUNC | RXSHV_LVAR))
printf("Truncation or no vars left\n") ;
RXSHV_TRUNC can only occur when the interface is storing a
retrieved value in a SHVBLOCK, and the pre-allocated space is
present, but not sufficiently large. As described for RXSHV_FETCH,
the
interpreter will allocate enough space if shvvalue.strptr is NULL,
and then RXSHV_TRUNC will never be set. Else the space supplied
by shvvalue.strptr is used, and shvvaluelen is taken as the
maximum length of shvvalue, and truncation will occur if the
supplied space is too small.
Some implementations will consider SHV_MEMFL to be so severe as to
skip the rest of the operations in a chain of requests. In order
to write compatible software, you should never assume that
requests
following in a chain after a request that returned SHV_MEMFL have
been performed.
RXSHV_BADN is returned if the supplied shvname contains a value
that is not legal in this context. For the symbolic set, fetch and
drop operations, that means a symbol that is a legal variable
name; both upper and lower case letters are allowed. For the
direct set, fetch and drop operations, that means a variable name
after normalization and tail substitution is not a legal variable
name. For RXSHV_PRIV, it must be one of the values listed above.
There is a small subtlety in the above description. TRL states
that when a REXX assignment assigns a value to a stem variable,
all possible variables having that stem are assigned a new value
(independent of whether they had an explicit value before). So,
strictly speaking, if a stem is set, then a RXSHV_NETV sequence
should return an (almost) infinite sequence of compound variables
for that stem. Of course, that is completely useless, so you can
assume that only compound variables of that stem given an explicit
value after the stem was assigned a value will be returned by
RXSHV_NEXTV. However, because of that subtlety, the variables
returned by RXSHV_NEXTV for compound variables might not be
representative for the state of the variables.
e.g. what would a sequence of RXSHV_NEXT requests return after the
following REXX code ?:
foo. = 'bar'
drop foo.bar
The second statement here, might not change the returned values!
After the first statement, only the stem foo. would probably have
been returned, and so also if all variables were fetched after the
second statement.
PREV NEXT