\begindata{text, 1222184}
\textdsversion{12}
\template{default}
\bigger{\bigger{\bold{\center{RXGEN:

 A Stub Generator for the \italic{R\subscript{x}} Remote Procedure Call 
Package}}}}\majorheading{


}
\bold{Rxgen} is a tool that generates C code to implement the 
\italic{R\subscript{x} }RPC protocol; it takes as input a description of an 
application interface similar to C and produces a number of server and/or 
client stub routines to be linked with RPC-based programs.  These stubs allow 
programs to invoke remote procedures through local procedure calls. 
 \italic{Rxgen} is an extension of Sun's \italic{rpcgen} (version 3.9) and 
retains full \italic{rpcgen} functionality.  Please refer to \italic{rpcgen}'s 
documentation (ask for help on \italic{rpcgen(1)}) for more details on the 
Sun's RPC specific flags, and to the RPC programming guide regarding the RPC 
language along with useful examples.



\heading{Synopsis/Reference}


\bold{rxgen -h} [options] [\bold{-o} \italic{outfile}] [\italic{infile}]

\bold{rxgen -c}  [options] [\bold{-o}\italic{ outfile}] [\italic{infile}]

\bold{rxgen -C} [options] [\bold{-o} \italic{outfile}] [\italic{infile}]

\bold{rxgen -S}  [options] [\bold{-o} \italic{outfile}] [\italic{infile}]

\bold{rxgen -r }[options] \italic{[\bold{-o} outfile]} [\italic{infile}]

\bold{rxgen}  [options] [\bold{-o} \italic{outfile}] [\italic{infile}] 


The following are intended for Sun's RPC usage (ignored on this document):

\bold{rxgen -s }\italic{transport} [\bold{-o} \italic{outfile}] 
[\italic{infile}]

\bold{rxgen -l} [\bold{ -o} \italic{outfile}] [\italic{infile}]

\bold{rxgen -m} [\bold{ -o} \italic{outfile}] [\italic{infile}]


\heading{Options}


\bold{\italic{Rxgen}} operates in several different modes.  The generated 
output files can be produced individually (using one of \italic{-h}, 
\italic{-c}, \italic{-C}, or \italic{-S}) or collectively.  All output files 
are created when the default is used (i.e., no options), or the output is 
limited to the server stubs (\italic{-C} and \italic{-S}) when the \italic{-r} 
flag is used.  The following describes the types of generated output files 
(for simplicity, \italic{filename} refers to the main output filename):


\indent{\description{\bold{-h}	Generate C data definitions (a header file) 
from standard RPCL definitions (default extension: \italic{filename}.h).}


\description{\bold{-c}	Compile the XDR routines required to serialize the 
protocol described by RPCL.  Generate XDR routines for all declarations 
(default extension: \italic{filename}.xdr.c).}


\description{\bold{-C}	Generate all the client-side stub routines (default 
extension: \italic{filename}.cs.c).  Calling a routine in this file will cause 
the arguments to be packed up and sent via \italic{R\subscript{x }}(or R). 

}
\description{\bold{-S}	Generate all the server-side stub routines (default 
extension: \italic{filename}.ss.c).  Arguments are unpacked, and the 
corresponding server routine is called.}


\description{\bold{-r}	Generate the two default extension files produced by 
the \italic{-C} and \italic{-S} options.


}}The following options can be used on any combination of \italic{rxgen} 
calls:


\description{\indent{\bold{-R}	Generate code for the older \italic{R} 
protocol, as opposed to \italic{R\subscript{x}}, which is the default.


\bold{-k}	Must be specified when the generated code is intended to be used by 
the kernel; special "includes" and other specifics are produced when the 
target output is for the kernel.


\bold{-p}	Package combination flag: when multiple packages are included within 
a single specification file, a single Execute Request routine will be used for 
all of them as a result of this flag.  The default is to generate individual 
Execute Request stubs for each package.


\bold{-I\italic{dir} }Similar to the \italic{-I} flag in the C compiler 
(\italic{cc}). This flag is passed to the pre-processor (\italic{cpp}) so that 
directory \italic{dir} is searched before the standard lookup list for 
#include files.  As expected, multiple \italic{-I} flags can be used 
simultaneously.


\bold{-P\italic{prefix}} The \italic{prefix} string following this switch is 
prepended to all generated output files; useful when multiple runs want to 
produce different versions of the same interface (say, kernel and non-kernel 
versions).


\bold{-d}	Debugging mode; only needed when \italic{rxgen} is to be debugged 
(say, via \italic{dbx}).


\bold{-o \italic{outfile}}  Specify the name of the output file.  If none is 
specified, the standard output is used (\italic{-c}, \italic{-h}, \italic{-C}, 
and \italic{-S} modes only).  Note that if an output file is specified in a 
multi-output file option (such as the default, or with option \italic{-r}), 
then the \italic{outfile} replaces the name generated by default (which is 
based on the configuration's main file name).}}



\heading{RXGEN syntax summary}



Specification file:

	<Package description option> |

	<Prefix description option> |

	<StartingOpcode description option> |

	<SplitPrefix description option> |

	<Procedure description option> |

	<RPCL language description option>.


<Package description option>:

	\bold{\italic{package}} <Package_ident>


<Prefix description option>:

	\bold{\italic{prefix}} <Prefix_ident>


<StartingOpcode description option>:

	\italic{\bold{startingopcode}} <constant>

	

<SplitPrefix description option>:

	\bold{\italic{splitprefix}} <split options> \italic{\bold{;}}


<Split options>:

	\italic{\bold{IN}} \italic{\bold{=}} <Start_prefix_ident> | \italic{\bold{OUT}} 
\italic{\bold{=}} <End_prefix_ident> |	<Split options>


<Procedure description option>:

	[\italic{\bold{proc}}] [<Procedure_ident>] [ <ServerStub_ident> ] <Argument 
list> [ \italic{\bold{split }}| \italic{\bold{multi}}] [ \italic{\bold{=}} 
<Opcode_ident> ] \italic{\bold{;}}


<Argument list>:

	\italic{\bold{(}} <Argument definition> <Comma_joined argument> 
\italic{\bold{)}}


<Argument definition>:

	<Direction option> <Standard RPCL type decl> <Arg_ident> [\italic{\bold{<}} 
<Max_size> \italic{\bold{>}} | \italic{\bold{[}} <Max_size> \italic{\bold{]}} 
]  |  NULL


<Comma_joined argument>:

	\italic{\bold{,}} <Argument definition> | NULL


<Direction option>:

	\bold{\italic{IN}}  | \bold{\italic{OUT}} | \bold{\italic{INOUT}} | NULL


<Max_size>:

	<constant> | NULL


<Package_ident>, <Prefix_ident>, <String_ident>, <Start_prefix_ident>, 
<End_prefix_ident>, <Procedure_ident>, <ServerStub_ident>, <Arg_ident>, 
<Opcode_ident>:

	<identifier>


<RPCL language description option>,

<Standard RPCL type decl>:

	Sun's RPCL language syntax  (see \italic{rpcgen}'s man page for details)


\heading{RXGEN command analysis }


\italic{\bold{Comments/Preprocessing:}}

The input interface may contain preprocessor directives which are passed 
through the C preprocessor (i.e. \italic{cpp}).  Since the preprocessor runs 
on all input files before they are actually interpreted by \italic{rxgen}, all 
\italic{cpp} directives (#include, #ifdefs, #defines, etc.) are legal and 
welcomed within an \italic{rxgen} input file.  Of course, none of these 
preprocessor directives will be included in any of the generated  files.  To 
facilitate distinctions between the different types of output files, 
\italic{rxgen} defines certain special \italic{cpp} symbols for use by the 
\italic{rxgen} programmer.  These are \italic{RPC_HDR} (defined when compiling 
into header, \italic{filename}.h, files), \italic{RPC_XDR} (defined when 
compiling into \italic{xdr}, \italic{filename}.xdr.c, files), 
\italic{RPC_CLIENT} (defined when compiling into client stubs, 
\italic{filename}.cs.c, files), and \italic{RPC_SERVER} (defined when 
compiling into server stubs, \italic{filename}.ss.c, files). 


In addition, \italic{rxgen} does a little preprocessing of its own.  Any line 
beginning with \bold{%} is passed directly into the output file, uninterpreted 
by \italic{rxgen}.  For a more heavy, \italic{en masse}, dumping of 
uninterpreted code, it would be adviced to include all such code in an 
"#include" file and pass it in preceded by \italic{\bold{%}}. The input 
interface may also contain any C-style comments which are, of course, ignored. 
 Interpretation is token-based, thus special line-orientation of separate 
statements is not necessary.  \italic{Rxgen} also provides a quite rich and 
helpful set of error reports, identifying them by exact line location and 
error type.  Also, \italic{rxgen} will automatically generate #include lines 
for standard include files, such as \italic{rx/xdr.h} and \italic{rx/rx.h}, 
along with the generated header file from this interface.


\italic{\bold{Prefixing stub procedures;}}

\italic{Package statement:} The\italic{\bold{ }}\italic{package} statement 
tells \italic{rxgen} the name of the interface package.  It is used for 
prefixing the naming of all generated stub routines and the execute request 
procedure.  For example:


\leftindent{\italic{package AFS_}}


causes the execute request procedure to be named AFS_ExecuteRequest (Warning: 
in the older version an additional "_" was appended after the package name to 
the ExecuteRequest name; thus make sure you don't have an ExecuteRequest 
interface routine) and a given stub routine, say Fetch, to be actually named 
AFS_Fetch.  Multiple package statements (current maximum size is 10) per 
configuration are permitted and are useful when multiple sets of interfaces 
are implemented (see the example at the end).  Note that in such cases, use of 
the \italic{-p} flag results in the generation of just one ExecuteRequest 
procedure which recognizes the multiple interfaces and whose name is prefixed 
by the \italic{first} package statement.  In the default case, independent 
ExecuteRequest procedures will be created for each packaged group of remote 
procedure calls.


\italic{Prefix statement:} The \italic{prefix }statement supplies a name to 
prepend to all calls to remote procedure names in the ExecuteRequest stub 
routine.  It is useful when the server makes RPC calls to other servers (say, 
for debugging purposes).  For example:


\leftindent{\italic{prefix S}}


causes the name \italic{S} to be prepended to the name of all routines called 
from the server stubs.  The server can then call the original name and get the 
client stubs.



\italic{\bold{Rxgen Procedure declaration:}}

\italic{Proc statement:} The\italic{ proc} statement is the most common (and 
meaningful) in the \italic{rxgen} interface.  Its syntax description is:


\italic{\indent{[proc] [<proc_name>] [server_stub] ( [<argument-1>, ..., 
<argument-n>]) [split | multi] [= <opcode>];}}


where:


\indent{\italic{\bold{Proc}} is an optional prefix of the procedure statement. 
 This is just a stylistic item and not a required procedure delimiter.


\italic{\bold{Proc_name}} is the name of the procedure.  Note that even the 
name of the procedure is optional.  This only makes sense when the name of the 
given procedure is identical to the name of the last \italic{package} 
statement (i.e., package RCallBack and the declaration of the RCallBack 
procedure!)


\italic{\bold{Server_stub},} if present, causes the ExecuteRequest procedure 
to call that stub instead of the automatically generated stub when a call with 
that opcode is decoded.


\italic{\bold{Opcode}} is a constant or symbol that is the opcode for that 
procedure.  One might use the preprocessor features (i.e., #define), the 
\italic{const} RPC-language feature, or the old good constants as opcodes. 
 Some further evaluation/processing of opcodes is done.  Particularly, checks 
for duplicate and non-existent opcodes are performed, along with checks for 
"holes" (i.e., gaps in consecutive opcodes) in the opcode sequences.  For 
example, we use the fact that when "holes" in opcodes exist, the 
ExecuteRequest procedure uses the \italic{case} statement rather than the 
faster (and smaller, codewise) indexed array method.  Also, \italic{rxgen} 
defines (i.e., appends to the header file) three valuable macros for each 
package group:


\indent{\italic{<package-name>LOWEST_OPCODE,}

\italic{<package-name>HIGHEST_OPCODE,} and 

\italic{<package-name>NUMBER_OPCODES} }


These may be useful to the \italic{rxgen} programmer.  Also, notice that the 
\italic{opcode} statement is an optional feature, and can be omitted.  In such 
cases, automatic opcode numbers are generated sequentially, starting from 0.}


\italic{Startingopcode statement}: One can change the initial opcode number by 
using the \italic{startingopcode} (for lack of a better name) \italic{rxgen} 
command.  Its syntax is


\leftindent{\italic{startingopcode <constant>}}


where <constant> must be reasonable!  Note that one can not mix procedures, 
some with opcodes and some without, nor allow opcodes after the specification 
of the \italic{startingopcode} statement.  \italic{Rxgen} will complain in all 
such cases.


\italic{Argument option}: The a\italic{rgument} entry represents a given 
parameter of the procedure.  Its syntax is:


\leftindent{\italic{[IN | INOUT | OUT | <null> ] <type_decl> 
<arg_name>[<max>|<>|[max]|[]]}}


If the type is an indirect type (i.e., is followed by *), it is assumed that 
the pointer should be followed one level and the data pointed to is to be 
transmitted. This should normally be used for all structures/arrays and out 
parameters.  A noticeable exception is when explicit array/structure maximum 
size is given; since no array-of-pointer declarations are allowed one should 
use typedefs to achieve the similar effect.  The parameters could be input 
parameters (preceded by IN), output parameters (preceded by OUT), or 
input/output parameters (preceded by INOUT).  If not specified, then the 
direction of the previous parameter in the procedure is used (Note: the first 
parameter must be preceded by the directional primitive!)


\italic{Split option:} \italic{Split} is a hack to handle stub routines that 
do things such as file transfers or any other operation that has to exchange 
information (e.g., length of a file) before the call returns its output 
parameters.  Because of the particular handshake that is involved when doing 
remote file transfer, we currently break all such calls into two client-side 
stub routines.  The first (with the default prefix of \italic{Begin}) is used 
to pass all IN and INOUT parameters to the server side.  The second (with the 
default prefix of \italic{End}) is used to get back the INOUT and OUT 
parameters from the server.  Between the two calls, the user is supposed to do 
the appropriate calls for the file transfer. For example, the following 
procedure declaration in package AFS_


	\typewriter{Fetch (IN a, b,INOUT c, OUT d) split = FETCHOPCODE;}


will roughly generate the two independent client stub routines:

	

	\typewriter{BeginAFS_Fetch (IN a, b, c)}

and

	\typewriter{EndAFS_Fetch(OUT c, d)}



\italic{Splitprefix statement: }The \italic{splitprefix} statement is used to 
change the default prefix names used by the two client-side stub generated 
routines when dealing with file transfer-related procedure calls.  For 
example:


\leftindent{\italic{splitprefix IN=Before_ OUT=After_;

}}
will cause the naming of the two client stubs for a file transfer-related 
routine, say Fetch(), to be Before_AFS_Fetch() and After_AFS_Fetch(), 
respectively.


\italic{Multi option:} The \italic{multi }option is nearly identical to the 
\italic{split} feature described above.  The only significant visible 
difference is that along with the two client stubs, the standard client stub 
is also generated.  Since the intention is to handle the 
multi-\italic{R\subscript{x}} calls, we need the whole standard procedure stub 
in the cases where no multi-\italic{R\subscript{x}} call of the procedure is 
performed.  A side effect of the \italic{multi} option is the generation of a 
special macro (i.e., \italic{multi_<Procedure-name>}) which passes back as 
arguments the \italic{Begin} and \italic{End} stubs in the header output file. 
 This macro is used directly by the \italic{R\subscript{x}} code when a 
multi-\italic{R\subscript{x}} call of this procedure is performed.


\subheading{\heading{ \italic{\bold{OBSOLETE rxgen features:}}}}

[\italic{Although the following rxgen commands are still in effect, they will 
\bold{soon} be removed since there are better alternatives. \bold{***DO NOT 
USE THEM!***}]}


\italic{Special statement}: The \italic{special} statement is a temporary hack 
used to handle certain inefficiencies of standard xdr routines to handle some 
user-customized declarations.  In particular, this applies to a string pointer 
specified as part of a declaration.  For example,


	\typewriter{special struct BBS SeqBody;}


tells \italic{rxgen} that the entry \smaller{\italic{SeqBody}} in the 
user-defined BBS xdr routine is a string (note that more than one string can 
be "special" per structure -- multiple ones are separated by commas); it will 
thus allocate and de-allocate space properly in the server-generated stubs 
that contain this structure as an IN or INOUT parameter.


\italic{Customized statement:} A better alternative to \italic{special} is the 
\italic{customized\bold{ }}statement, which is simply the \italic{customized} 
token followed by the regular declaration of a struct based on the RPCL rules. 
 In this case, the declaration will be included in the generated header file 
(\italic{-h} option) but no xdr routine will be generated for this structure - 
the user will supply this.  All pointer entries in this structure will be 
remembered so when the structure is used as an IN or INOUT in the server stub, 
no core leaks will occur! For example, consider

\typewriter{
	customized struct CBS \{

		long Seqlen;

		char *SeqBody;

	\}

}
The xdr_CBS routine would be provided by the user where during the DECODE xdr 
opcode, appropriate space for the SeqBody string is allocated.  Similarly, 
that space is freed during the FREE xdr opcode.


Note: Old style "\italic{Array parameter specifications" }are\italic{ 
\bold{n\bold{o}}\bold{t supported} any more.}


\heading{\italic{Rxgen} Language by examples}


In case there are some requirements not available by the current RPC language, 
one can customize some XDR routines by leaving those data types undefined. 
 For every data type that is undefined, it will be assumed that a routine 
exists with the name \italic{xdr_} prepended to it.  A selected set of 
\italic{rxgen} features is presented below, but for a more comprehensive one 
(unions, complex examples, etc) please refer to the \italic{rpcgen Programming 
Guide} and \italic{eXternal Data Representation: Sun Technical Notes}.


\bold{Typedefs:}

The RPC typedef statement is identical to the C typedef (i.e. 
\italic{"typedef" <declaration>}).  By default, most user declarations (i.e. 
structs, unions, etc) are automatically typedef'ed by \italic{rxgen}.  Since 
it makes parsing simpler, its usage is recommended by \italic{rxgen} scripts. 


\bold{Strings:}

The C "char *" string convention is kind of ambiguous, since it is usually 
intended to mean a null-terminated string of characters, but it could also 
represent a pointer to a single character, a pointer to an array of 
characters, etc.  In the RPC language, a null-terminated string is 
unambiguously called a "string".  Examples,


\italic{\indent{string bigname<>;

string name<MAXNAMELEN>;

typedef string volname<MAXVOLNAME>;}

}
Notice that the maximum size of string can be arbitrary (like \italic{bigname} 
above) or, preferably, or specified in angle brackets (i.e. \italic{name} and 
\italic{volname} above).  In practice, one should always use only bounded 
strings in interfaces.  A sample calling proc using the declarations above 
would be:


\italic{\indent{GetEntryByName (IN volname name, 

	OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;}


}or, of course,\italic{


\indent{GetEntryByName (IN string volname<MAXVOLNAME>, 

	OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;}}


	

It is very important for the user to understand when the string parameters 
should be allocated and/or freed by the his/her client and/or server programs. 
A short analysis on string parameters handling follows (note that a similar 
method is used for the handling of variable length arrays as it will be shown 
later on):


In the \italic{\bold{client}} side: 		\description{IN and INOUT string 
parameters are the programmer's responsibility and should be allocated (static 
or via malloc) before calling the rpc and freed (if malloc was used) after the 
rpc's return in the user's client program; of course, for INOUT parameters, 
the returned string can't be bigger than the malloced input string.

	OUT string parameters are automatically malloced (based on the length of the 
returned string and not the maxsize) by the rxgen client stubs (in 
filename.cs.c) and must be freed by the client program; admittedly, this could 
be somewhat confusing since the user needs to free something that he/she 
didn't allocate.}


In the \italic{\bold{server}} side: 	\description{IN and INOUT string 
parameters are automatically malloced (based on the size of incoming strings) 
by the rxgen server stubs (in filename.ss.c) before they are passed to the 
user's server procedure; that space is automatically freed just before the 
rxgen server stub returns; therefore the user need not do anything special for 
IN and INOUT string parameters. 

	OUT string parameters must be malloced by the user's server procedure (i.e. 
null pointer is passed to it by the rxgen server stub) and it is automatically 
freed at the end of the rxgen server stub. Like in the client side, the OUT 
parameters are somewhat unorthodox (i.e. the server routine must malloc a 
string without ever freeing it itself; this is done by the rxgen server stub).}


Note that for INOUT and OUT string parameters, in both the client and server 
sides their arguments must be char of pointers (i.e. char **)


\bold{Pointers:}

Pointer declarations in RPC are also exactly as they are in C (i.e. 
\italic{struct single_vldbentry *vldblist};). Of course, one can't send 
pointers over the network, but one can use XDR pointers for sending recursive 
data types such as lists and trees (an example of a linked list will be 
demonstrated shortly). 


\bold{Arrays:}

Fixed arrays are just like standard C array declarations (i.e. \italic{struct 
UpdateEntry entries[20]}) without any side effect problems in \italic{rxgen}. 
 Since variable-length arrays have no explicit syntax in C, the angle-brackets 
are used for it and the array declarations are actually compiled into 
"struct"s. For example, declarations such as:


\indent{const	MAXBULKSIZE	= 10000;

const	MAXENTRIES	= 100;

opaque	bulk<MAXBULKSIZE>;	\italic{/* At most 10000 items */}

int	 hosts<>;			\italic{/* any number of items */}

typedef	vldbentry blkentries<100>;	\italic{/* Preferable array decl */}

}
are compiled into the following structs:


\indent{struct	\{

	u_int	bulk_len;		\italic{/* no of items */}

	char	*bulk_val;	/\italic{* pointer to array */}

\} bulk;}


for the \italic{bulk }array, and similarly for the \italic{blkentries}<100> 
array,


\indent{struct	\{

	u_int	blkentries_len;	\italic{/* no of items in array */}

	vldbentry	*blkentries_val;	\italic{/* pointer to array */}

\} blkentries;}


Therefore the user should be aware of the "magically" generated structure 
entries such as the number of items in the array (<array_name>_len) and the 
pointer to the array (<array_name>_val) since some of the entries will have to 
be filled in from the client/server programs.  A sample proc would be:


\italic{\indent{typedef vldbentry blkentries<MAXENTRIES>;

proc GetBlk (OUT blkentries *vlentries) = VL_GETBLK;}}


or, more directly,


\italic{\indent{GetBlk(OUT vldbentry vlentries<MAXENTRIES>) = VL_GETBLK;}}


Note that although the latest method is preferable since one does not have to 
first use the typedef statement (and admittedly, programmers prefer avoiding 
typedefs), one should realize that \italic{rxgen} does the structure expansion 
and the xdr creation implicitly; therefore the user should be aware of the 
vldbentries_val and vldbentries_len fields as before (see following examples).


\italic{\bold{Array example I (***LEAST*** desirable):}}


Procedure declaration in the interface configuration:


proc ListAttributes (IN vldblistbyattributes *attributes, 

		 INOUT blkentries *vldbentries) = VL_LISTATTRIBUTES;


	Sample CLIENT code:


blkentries entries, *pnt;


entries.blkentries_len = 10;				\italic{/* max # returned entries */}

entries.blkentries_val = (vldbentry *)malloc(LEN);	\italic{/* It must be set 
 */}

code = VL_ListAttributes(&attributes, &entries);

if (!code) \{

	pnt = entries.blkentries_val;

	for (i=0; i < entries.blkentries_len; i++, pnt++)

		display_vldbentry(pnt);

	\italic{/* Make sure you free the allocated space */}

	free((char *)entries.blkentries_val);	

\}


	Sample SERVER code:


VL_ListAttributes(attributes, entries)

\{	vldbentry *singleentry = entries->blkentries_val;

	entries->blkentries_len = 0;

	

	while (copy_to_vldbentry(&vlentry, singleentry))

		singleentry++, vldbentries->entries_len++;

\}


\italic{Comments:} Although this method for variable-size arrays works fine, 
there are some \bold{major} drawbacks.  The array parameter (i.e. vldbentries 
above) must be declared as INOUT since we need to pass the max length of the 
expected returned array; more importantly, a big (depending on the value of 
"_len") chunk of junk code is going to be transferred to the server as result 
of the IN(out) side-effect of the array.  It's an easy and convenient method 
if the returned array size can be predicted from the start and when the size 
is quite high.  This method is included as an example of erroneous use (and 
abuse) of \italic{rxgen}\bold{ and should NOT be used.}


\italic{\bold{Array example II (Desirable method):

}}
Procedure declaration in the interface configuration (using Example I above):


proc ListAttributes (IN vldblistbyattributes *attributes, 

		OUT blkentries *vldbentries) = VL_LISTATTRIBUTES;


	Sample CLIENT code:


blkentries entries, *pnt;


code = VL_ListAttributes(&attributes, &entries);

if (!code) \{

	pnt = entries.blkentries_val;

	for (i=0; i < entries.blkentries_len; i++, pnt++)

		display_vldbentry(pnt);

	\italic{/* Make sure you free the allocated space (by rxgen) */}

	free((char *)entries.blkentries_val);	

\}


	Sample SERVER code:


VL_ListAttributes(attributes, entries)

\{	vldbentry *singleentry;


	entries->blkentries_len = 0;

	singleentry = entries->blkentries_val = (vldbentry *)malloc(MAXENTRIES * 
sizeof(vldbentry));

	while (copy_to_vldbentry(&vlentry, singleentry))

		singleentry++, vldbentries->entries_len++;

\}


\italic{Comments: }This is the best (and simplest) way of using variable-size 
arrays as an output parameter.  It is the responsibility of the server-side 
stub to \italic{malloc} the adequate space which is automatically freed by the 
\italic{rxgen} stub; the client side should free the space allocated by the 
\italic{rxgen}-calling stub.



\italic{\bold{Array example III (Linked Lists):}}


Considering the following 3 declarations (could have applied some 
optimizations) in the configuration file:


typedef struct single_vldbentry *vldblist;


struct single_vldbentry \{

	vldbentry vlentry;

	vldblist	next_vldb;

\};


struct vldb_list\{

	vldblist node;

\};


and the rxgen procedure declaration:


LinkedList (IN vldblistbyattributes *attributes, 

	   OUT vldb_list *linkedentries) = VL_LINKEDLIST;


		Sample CLIENT code:


vldb_list	linkedvldbs;

vldblist	vllist, vllist1;


bzero(&linkedvldbs, sizeof(vldb_list));

code = VL_LinkedList(&attributes, &nentries, &linkedvldbs);

if (!code) \{

	printf("We got %d vldb entries\\n", nentries);

	for (vllist = linkedvldbs.node; vllist; vllist = vllist1) \{

		vllist1 = vllist->next_vldb;

		display_entry(&vllist->vlentry);

		free((char *)vllist);

	\}

\}


		Sample SERVER code:


VL_LinkedList(rxcall, attributes, nentries, linkedvldbs);

\{	vldblist vllist, *vllistptr = &linkedvldbs->node;

		

	while (...) \{

		vllist = *vllistptr = (single_vldbentry *) 

			malloc (sizeof (single_vldbentry));

		copy_to_vldbentry(&tentry, &vllist->vlentry);

		nentries++;	

		vllistptr = &vllist->next_vldb;

	\};

	*vllistptr = NULL;

\}


\italic{Comments:} Using a linked list offers many advantages: Nothing is 
passed to the server (the parameter is OUT), no additional overhead is 
involved, and the caller doesn't have to explicitly prepare for an arbitrary 
return size.  A drawback is that the caller has the responsibility of 
\italic{malloc} (on the server) and free (on the client) of each entry (to 
avoid unwanted core-leaks).  Another drawback is that since it's a recursive 
call, the C stack will grow linearly with respect to the number of nodes in 
the list (so it's wise to increase the \italic{R\subscript{x}} LWP stack if 
huge amounts of data are expected back -- default stack size is 4K!)  The 
advantages should outweight the disadvantages here.


It's important to pay attention to the comments of the three array examples 
above particularly when they're references to when the user should 
allocate/free space for the variable length arrays. The mechanism is very 
similar to the handling of strings thus you might need to review the strings 
section above; note that the linked lists are handled somewhat differently...


\bold{Miscellaneous examples:}


Below is an abbreviated version of a random interface file which shows some of 
the common cases.

\typewriter{
}\italic{/* Declaration of all structures used by the R.xg script interface 
 */}\typewriter{

}
\typewriter{struct AFSFid \{

	unsigned long Volume;

	unsigned long Vnode;

	unsigned long Unique;

\};



typedef long ViceDataType;


}\italic{/* Note that TEST would be equivalent to "HEADER" only during the 
processing of the header, *.h, file */}

\typewriter{#ifdef	RPC_HDR

#define TEST	"HEADER"

#else

#define TEST	"REST"

#endif}


\italic{/* This is the standard *.xg specification file */}\typewriter{

package AFS_

splitprefix IN=BEFORE_ OUT=AFTER_;

Prefix Test


proc Remove(IN struct AFSFid *Did, IN string volname<64>,

	OUT struct AFSStatus *Status) = AFS_REMOVE;


DisconnectFS  AUX_disconnectFS() = AFS_DISCONNECTFS;


proc GetVolumeInfo(IN string Vid, 

	OUT struct VolumeInfo *Info) = AFS_GETVOLUMEINFO;


}\italic{/* You could have more than an interface per configuration 
*/}\smaller{\italic{

}}\typewriter{package VOTE_


}\italic{/* Using the "multi" feature; thus VOTE_Beacon can be called as an 
multi-Rx call or as a regular call */}\typewriter{

Beacon	(IN long state, long voteStart, 

	net_version *version, net_tid *tid) 

	multi = VOTE_BEACON;


package DISK_


}\italic{/* Using the "split" feature */}\typewriter{

SendFile (IN long file, long offset, 

	long length, net_version *version) 

	split = DISK_SENDFILE;



}\heading{Output of an actual Interface configuration:}


We'll demonstrate some of the actual output generated by \italic{rxgen} by 
following an abbreviated actual interface configuration.


\italic{\bold{Configuration file:}}

Contents of the interface configuration file (\italic{vldbint.xg}):


package	VL_


#include	"vl_opcodes.h"	\italic{/* The opcodes are included here */}

%#include "vl_opcodes.h"	/\italic{* directly to other places */}


\italic{/* Current limitations on parameters that affect other packages (i.e. 
volume) */}

const	MAXNAMELEN	=	65;

const	MAXNSERVERS	=	8;

const	MAXTYPES	=	3;


\italic{/* External (visible) representation of an individual vldb entry */}

struct vldbentry   \{

	char	name[MAXNAMELEN];	

	long	volumeType;		

	long	nServers;		

	long	serverNumber[MAXNSERVERS];

	long	serverPartition[MAXNSERVERS];

	long	serverFlags[MAXNSERVERS];

	u_long	volumeId[MAXTYPES];	

	long	flags;			

\};


typedef struct single_vldbentry  *vldblist;


struct single_vldbentry \{

	vldbentry VldbEntry;

	vldblist next_vldb;

\};


struct vldb_list \{

vldblist node;

\};


\italic{/* vldb interface calls */}

CreateEntry	(IN long Volid, 

		vldbentry *newentry) = VLCREATEENTRY;


GetEntryByName	(IN string volumename<MAXNAMELEN>, 

		OUT vldbentry *entry) = VLGETENTRYBYNAME;


GetNewVolumeId	(IN long bumpcount,

		OUT long *newvolumid) = VLGETNEWVOLUMEID;


ReplaceEntry	(IN long Volid, 

		long voltype,

		vldbentry *newentry,

		long ReleaseType) multi = VLREPLACEENTRY;


ListAttributes	(IN VldbListByAttributes *attributes, 

		OUT long *nentries, 

		OUT vldbentry bulkentries<MAXVLDBLEN>) 

		= VLLISTATTRIBUTES;


LinkedList	(IN VldbListByAttributes *attributes, 

		OUT long *nentries, 

		OUT vldb_list *linkedentries) = VLLINKEDLIST;


We'll concentrate only on the \italic{R\subscript{x}} generated code since the 
\italic{R} generated code (\italic{-R} option) will soon be obsolete.  For a 
detailed description on the \italic{R\subscript{x}}-related calls inside the 
generated stubs (i.e., \italic{rx_NewCall, rx_EndCall}), along with details on 
what happens inside certain calls (like \italic{xdrrx_create}) please refer to 
the \italic{R\subscript{x}} documentation (do help on rx). Typing 
\italic{rxgen vldbint.xg} will result in the creation of four files: 
\italic{vldbint.h, vldbint.xdr.c, vldbint.cs.c} and \italic{vldbint.ss.c}.  A 
closer look at these files follows.


\italic{\bold{Header file (vldbint.h):}}

\italic{/* Machine generated file -- Do NOT edit */}


#include	"vl_opcodes.h"	\italic{/* directly to other places */}

#define MAXNAMELEN 65

#define MAXNSERVERS 8

#define MAXTYPES 3


struct vldbentry \{

	char name[MAXNAMELEN];

	long volumeType;

	long nServers;

	long serverNumber[MAXNSERVERS];

	long serverPartition[MAXNSERVERS];

	long serverFlags[MAXNSERVERS];

	u_long volumeId[MAXTYPES];

	long flags;

\};

typedef struct vldbentry vldbentry;

bool_t xdr_vldbentry();


typedef struct single_vldbentry *vldblist;

bool_t xdr_vldblist();


struct single_vldbentry \{

	vldbentry VldbEntry;

	vldblist next_vldb;

\};

typedef struct single_vldbentry single_vldbentry;

bool_t xdr_single_vldbentry();



struct vldb_list \{

	vldblist node;

\};

typedef struct vldb_list vldb_list;

bool_t xdr_vldb_list();


#include <rx/rx_multi.h>

#define multi_VL_ReplaceEntry(Volid, voltype, newentry, ReleaseType) \\

	multi_Body(StartVL_ReplaceEntry(multi_call, Volid, voltype, newentry, 
ReleaseType), EndVL_ReplaceEntry(multi_call))


typedef struct bulkentries \{

	u_int bulkentries_len;

	vldbentry *bulkentries_val;

\} bulkentries;

bool_t xdr_bulkentries();


\italic{/* Opcode-related useful stats for package: VL_ */}

#define VL_LOWEST_OPCODE	501

#define VL_HIGHEST_OPCODE	506

#define VL_NUMBER_OPCODES	6


\italic{Comments:} Notice that all structures are automatically typedef'ed and 
all "const"s are converted to "#defines". Some data structures, such as 
bulkentries, are taken from procedure params (from ListAttributes proc). 
 Thus, this should be kept in mind when creating stubs piecemeal with 
\italic{rxgen} (i.e., using the \italic{-c}, \italic{-h}, \italic{-C}, or 
\italic{-S} flags).  Also, one of the side effects of the "multi" option (in 
ReplaceEntry proc) is the generation of the multi_VL_ReplaceEntry above.


\italic{\bold{XDR routines for structures (vldbint.xdr.c):}}

\italic{/* Machine generated file -- Do NOT edit */}


#include <rx/xdr.h>

#include "vldbint.h"

#include	"vl_opcodes.h"	\italic{/* directly to other places */}


bool_t

\bold{xdr_vldbentry}(xdrs, objp)

	XDR *xdrs;

	vldbentry *objp;

\{

	if (!xdr_vector(xdrs, (char *)objp->name, MAXNAMELEN, sizeof(char), 
xdr_char))

		return (FALSE);

	if (!xdr_long(xdrs, &objp->volumeType))

		return (FALSE);

	if (!xdr_long(xdrs, &objp->nServers))

		return (FALSE);

	if (!xdr_vector(xdrs, (char *)objp->serverNumber, MAXNSERVERS, sizeof(long), 
xdr_long))

		return (FALSE);

	if (!xdr_vector(xdrs, (char *)objp->serverPartition, MAXNSERVERS, 
sizeof(long), xdr_long))

		return (FALSE);

	if (!xdr_vector(xdrs, (char *)objp->serverFlags, MAXNSERVERS, sizeof(long), 
xdr_long))

		return (FALSE);

	if (!xdr_vector(xdrs, (char *)objp->volumeId, MAXTYPES, sizeof(u_long), 
xdr_u_long))

		return (FALSE);

	if (!xdr_long(xdrs, &objp->flags))

		return (FALSE);

	return (TRUE);

\}


bool_t

\bold{xdr_vldblist}(xdrs, objp)

	XDR *xdrs;

	vldblist *objp;

\{

	if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct single_vldbentry), 
xdr_single_vldbentry))

 		return (FALSE);

	return (TRUE);

\}


bool_t

\bold{xdr_single_vldbentry}(xdrs, objp)

	XDR *xdrs;

	single_vldbentry *objp;

\{

	if (!xdr_vldbentry(xdrs, &objp->VldbEntry))

		return (FALSE);

	if (!xdr_vldblist(xdrs, &objp->next_vldb))

		return (FALSE);

	return (TRUE);

\}


bool_t

\bold{xdr_vldb_list}(xdrs, objp)

	XDR *xdrs;

	vldb_list *objp;

\{

	if (!xdr_vldblist(xdrs, &objp->node))

		return (FALSE);

	return (TRUE);

\}


bool_t

\bold{xdr_bulkentries}(xdrs, objp)

	XDR *xdrs;

	bulkentries *objp;

\{

	if (!xdr_array(xdrs, (char **)&objp->bulkentries_val, (u_int 
*)&objp->bulkentries_len, MAXVLDBLEN, sizeof(vldbentry), xdr_vldbentry))

		return (FALSE);

	return (TRUE);

\}


\italic{Comments:} Note that the xdr_bulkentries() is automatically generated 
as a side effect of a procedure parameter declaration.  Thus, if identical 
multiple type parameter declarations are used, then multiply-defined xdr_* 
stubs will be created!  We felt this was a better alternative to having the 
\italic{rxgen} programmer deal with types such as bulkentries_1, 
bulkentries_2...


\italic{\bold{Client-Side stub routines (vldbint.cs.c):}}

\italic{/* Machine generated file -- Do NOT edit */}


#include <rx/xdr.h>

#include <rx/rx.h>

#include <afs/rxgen_consts.h>

#include "vldbint.h"


#include	"vl_opcodes.h"	/* directly to other places */

int \bold{VL_CreateEntry}(z_conn, Volid, newentry)

	register struct rx_connection *z_conn;

	long Volid;

	vldbentry * newentry;

\{

	struct rx_call *z_call = rx_NewCall(z_conn);

	static int z_op = 501;

	int z_result;

	XDR z_xdrs;


	xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);


	\italic{/* Marshal the arguments */}

	if ((!xdr_int(&z_xdrs, &z_op))

	     || (!xdr_long(&z_xdrs, &Volid))

	     || (!xdr_vldbentry(&z_xdrs, newentry))) \{

		z_result = RXGEN_CC_MARSHAL;

		goto fail;

	\}


	z_result = RXGEN_SUCCESS;

fail:

	return rx_EndCall(z_call, z_result);

\}



int \bold{VL_GetEntryByName}(z_conn, volumename, entry)

	register struct rx_connection *z_conn;

	char * volumename;

	vldbentry * entry;

\{

	struct rx_call *z_call = rx_NewCall(z_conn);

	static int z_op = 504;

	int z_result;

	XDR z_xdrs;


	xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);


	\italic{/* Marshal the arguments */}

	if ((!xdr_int(&z_xdrs, &z_op))

	     || (!xdr_string(&z_xdrs, &volumename, 65))) \{

		z_result = RXGEN_CC_MARSHAL;

		goto fail;

	\}


	\italic{/* Un-marshal the reply arguments */}

	z_xdrs.x_op = XDR_DECODE;

	if ((!xdr_vldbentry(&z_xdrs, entry))) \{

		z_result = RXGEN_CC_UNMARSHAL;

		goto fail;

	\}


	z_result = RXGEN_SUCCESS;

fail:

	return rx_EndCall(z_call, z_result);

\}


int \bold{VL_GetNewVolumeId}(z_conn, bumpcount, newvolumid)

	register struct rx_connection *z_conn;

	long bumpcount;

	long * newvolumid;

\{

	struct rx_call *z_call = rx_NewCall(z_conn);

	static int z_op = 505;

	int z_result;

	XDR z_xdrs;


	xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);


	/* Marshal the arguments */

	if ((!xdr_int(&z_xdrs, &z_op))

	     || (!xdr_long(&z_xdrs, &bumpcount))) \{

		z_result = RXGEN_CC_MARSHAL;

		goto fail;

	\}


	/* Un-marshal the reply arguments */

	z_xdrs.x_op = XDR_DECODE;

	if ((!xdr_long(&z_xdrs, newvolumid))) \{

		z_result = RXGEN_CC_UNMARSHAL;

		goto fail;

	\}


	z_result = RXGEN_SUCCESS;

fail:

	return rx_EndCall(z_call, z_result);

\}


int \bold{VL_ReplaceEntry}(z_conn, Volid, voltype, newentry, ReleaseType)

	register struct rx_connection *z_conn;

	long Volid, voltype, ReleaseType;

	vldbentry * newentry;

\{

	struct rx_call *z_call = rx_NewCall(z_conn);

	static int z_op = 506;

	int z_result;

	XDR z_xdrs;


	xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);


	\italic{/* Marshal the arguments */}

	if ((!xdr_int(&z_xdrs, &z_op))

	     || (!xdr_long(&z_xdrs, &Volid))

	     || (!xdr_long(&z_xdrs, &voltype))

	     || (!xdr_vldbentry(&z_xdrs, newentry))

	     || (!xdr_long(&z_xdrs, &ReleaseType))) \{

		z_result = RXGEN_CC_MARSHAL;

		goto fail;

	\}


	z_result = RXGEN_SUCCESS;

fail:

	return rx_EndCall(z_call, z_result);

\}


int \bold{StartVL_ReplaceEntry}(z_call, Volid, voltype, newentry, ReleaseType)

	register struct rx_call *z_call;

	long Volid, voltype, ReleaseType;

	vldbentry * newentry;

\{

	static int z_op = 506;

	int z_result;

	XDR z_xdrs;


	xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);


	\italic{/* Marshal the arguments */}

	if ((!xdr_int(&z_xdrs, &z_op))

	     || (!xdr_long(&z_xdrs, &Volid))

	     || (!xdr_long(&z_xdrs, &voltype))

	     || (!xdr_vldbentry(&z_xdrs, newentry))

	     || (!xdr_long(&z_xdrs, &ReleaseType))) \{

		z_result = RXGEN_CC_MARSHAL;

		goto fail;

	\}


	z_result = RXGEN_SUCCESS;

fail:

	return z_result;

\}


int \bold{EndVL_ReplaceEntry}(z_call)

	register struct rx_call *z_call;

\{

	int z_result;

	XDR z_xdrs;


	z_result = RXGEN_SUCCESS;

fail:

	return z_result;

\}


int \bold{VL_ListAttributes}(z_conn, attributes, nentries, bulkentries_1)

	register struct rx_connection *z_conn;

	VldbListByAttributes * attributes;

	long * nentries;

	bulkentries * bulkentries_1;

\{

	struct rx_call *z_call = rx_NewCall(z_conn);

	static int z_op = 511;

	int z_result;

	XDR z_xdrs;


	xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);


	\italic{/* Marshal the arguments */}

	if ((!xdr_int(&z_xdrs, &z_op))

	     || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) \{

		z_result = RXGEN_CC_MARSHAL;

		goto fail;

	\}


	\italic{/* Un-marshal the reply arguments */}

	z_xdrs.x_op = XDR_DECODE;

	if ((!xdr_long(&z_xdrs, nentries))

	     || (!xdr_bulkentries(&z_xdrs, bulkentries_1))) \{

		z_result = RXGEN_CC_UNMARSHAL;

		goto fail;

	\}


	z_result = RXGEN_SUCCESS;

fail:

	return rx_EndCall(z_call, z_result);

\}


int \bold{VL_LinkedList}(z_conn, attributes, nentries, linkedentries)

	register struct rx_connection *z_conn;

	VldbListByAttributes * attributes;

	long * nentries;

	vldb_list * linkedentries;

\{

	struct rx_call *z_call = rx_NewCall(z_conn);

	static int z_op = 512;

	int z_result;

	XDR z_xdrs;


	xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);


	\italic{/* Marshal the arguments */}

	if ((!xdr_int(&z_xdrs, &z_op))

	     || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) \{

		z_result = RXGEN_CC_MARSHAL;

		goto fail;

	\}


	\italic{/* Un-marshal the reply arguments */}

	z_xdrs.x_op = XDR_DECODE;

	if ((!xdr_long(&z_xdrs, nentries))

	     || (!xdr_vldb_list(&z_xdrs, linkedentries))) \{

		z_result = RXGEN_CC_UNMARSHAL;

		goto fail;

	\}


	z_result = RXGEN_SUCCESS;

fail:

	return rx_EndCall(z_call, z_result);

\}


\italic{Comments:} Notice the side effect of the "multi" feature (three 
different modules for ReplaceEntry proc).


\italic{\bold{Server-Side stub routines (vldbint.ss.c):}}

\italic{/* Machine generated file -- Do NOT edit */}


#include <rx/xdr.h>

#include <rx/rx.h>

#include <afs/rxgen_consts.h>

#include "vldbint.h"


#include	"vl_opcodes.h"	\italic{/* directly to other places */}

long \bold{_VL_CreateEntry}(z_call, z_xdrs)

	struct rx_call *z_call;

	XDR *z_xdrs;

\{

	long z_result;

	long Volid;

	vldbentry newentry;



	if ((!xdr_long(z_xdrs, &Volid))

	     || (!xdr_vldbentry(z_xdrs, &newentry))) \{

		z_result = RXGEN_SS_UNMARSHAL;

		goto fail;

	\}


	z_result = VL_CreateEntry(z_call, Volid, &newentry);

fail:

	return z_result;

\}



long \bold{_VL_GetEntryByName}(z_call, z_xdrs)

	struct rx_call *z_call;

	XDR *z_xdrs;

\{

	long z_result;

	char *volumename = (char *)0;

	vldbentry entry;



	if ((!xdr_string(z_xdrs, &volumename, 65))) \{

		z_result = RXGEN_SS_UNMARSHAL;

		goto fail;

	\}


	z_result = VL_GetEntryByName(z_call, &volumename, &entry);

	z_xdrs->x_op = XDR_ENCODE;

	if ((!xdr_vldbentry(z_xdrs, &entry)))

		z_result = RXGEN_SS_MARSHAL;

fail:

	z_xdrs->x_op = XDR_FREE;

	if (!xdr_string(z_xdrs, &volumename, 65)) goto fail1;

	return z_result;

fail1:

	return RXGEN_SS_XDRFREE;

\}


long \bold{_VL_GetNewVolumeId}(z_call, z_xdrs)

	struct rx_call *z_call;

	XDR *z_xdrs;

\{

	long z_result;

	long bumpcount;

	long newvolumid;



	if ((!xdr_long(z_xdrs, &bumpcount))) \{

		z_result = RXGEN_SS_UNMARSHAL;

		goto fail;

	\}


	z_result = VL_GetNewVolumeId(z_call, bumpcount, &newvolumid);

	z_xdrs->x_op = XDR_ENCODE;

	if ((!xdr_long(z_xdrs, &newvolumid)))

		z_result = RXGEN_SS_MARSHAL;

fail:

	return z_result;

\}


long \bold{_VL_ReplaceEntry}(z_call, z_xdrs)

	struct rx_call *z_call;

	XDR *z_xdrs;

\{

	long z_result;

	long Volid, voltype, ReleaseType;

	vldbentry newentry;



	if ((!xdr_long(z_xdrs, &Volid))

	     || (!xdr_long(z_xdrs, &voltype))

	     || (!xdr_vldbentry(z_xdrs, &newentry))

	     || (!xdr_long(z_xdrs, &ReleaseType))) \{

		z_result = RXGEN_SS_UNMARSHAL;

		goto fail;

	\}


	z_result = VL_ReplaceEntry(z_call, Volid, voltype, &newentry, ReleaseType);

fail:

	return z_result;

\}


long \bold{_VL_ListAttributes}(z_call, z_xdrs)

	struct rx_call *z_call;

	XDR *z_xdrs;

\{

	long z_result;

	VldbListByAttributes attributes;

	long nentries;

	bulkentries bulkentries_1;



	if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) \{

		z_result = RXGEN_SS_UNMARSHAL;

		goto fail;

	\}


	z_result = VL_ListAttributes(z_call, &attributes, &nentries, &bulkentries_1);

	z_xdrs->x_op = XDR_ENCODE;

	if ((!xdr_long(z_xdrs, &nentries))

	     || (!xdr_bulkentries(z_xdrs, &bulkentries_1)))

		z_result = RXGEN_SS_MARSHAL;

fail:

	z_xdrs->x_op = XDR_FREE;

	if (!xdr_bulkentries(z_xdrs, &bulkentries_1)) goto fail1;

	return z_result;

fail1:

	return RXGEN_SS_XDRFREE;

\}


long \bold{_VL_LinkedList}(z_call, z_xdrs)

	struct rx_call *z_call;

	XDR *z_xdrs;

\{

	long z_result;

	VldbListByAttributes attributes;

	long nentries;

	vldb_list linkedentries;



	if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) \{

		z_result = RXGEN_SS_UNMARSHAL;

		goto fail;

	\}


	z_result = VL_LinkedList(z_call, &attributes, &nentries, &linkedentries);

	z_xdrs->x_op = XDR_ENCODE;

	if ((!xdr_long(z_xdrs, &nentries))

	     || (!xdr_vldb_list(z_xdrs, &linkedentries)))

		z_result = RXGEN_SS_MARSHAL;

fail:

	return z_result;

\}



long _VL_CreateEntry();

long _VL_GetEntryByName();

long _VL_GetNewVolumeId();

long _VL_ReplaceEntry();

long _VL_ListAttributes();

long _VL_LinkedList();


static long (*StubProcsArray0[])() = \{_VL_CreateEntry, _VL_GetEntryByName, 
_VL_GetNewVolumeId, _VL_ReplaceEntry, _VL_ListAttributes, _VL_LinkedList\};


\bold{VL_ExecuteRequest}(z_call)

	register struct rx_call *z_call;

\{

	int op;

	XDR z_xdrs;

	long z_result;


	xdrrx_create(&z_xdrs, z_call, XDR_DECODE);

	if (!xdr_int(&z_xdrs, &op))

		z_result = RXGEN_DECODE;

	else if (op < VL_LOWEST_OPCODE || op > VL_HIGHEST_OPCODE)

		z_result = RXGEN_OPCODE;

	else

		z_result = (*StubProcsArray0[op - VL_LOWEST_OPCODE])(z_call, &z_xdrs);

	return z_result;

\}


\italic{Comments:} If there were gaps in the procedures' opcode sequence the 
code for VL_ExecuteRequest() routine would be have been drastically different 
(it would have been a case statement for each procedure).


\heading{See Also}

\description{
\italic{Rxgen Syntax Summary}:  Summary description of rxgen's grammar.

\italic{Rpcgen Programming Guide}: Sun's RPC protocol compiler.  \italic{Rxgen} 
was implemented as an extension to that compiler.

\italic{External Data Representation: Sun Technical Notes}: Detailed examples 
in using XDR.

\italic{RPCL Syntax Summary}:  Summary of Sun's Remote Procedure Call 
Language.

\italic{Rx}: An extended Remote Procedure Call Protocol.

\italic{Rgen}: An earlier version of a similar stub generator used for the 
\italic{R} RPC protocol.

}



\heading{Notes/Bugs}


\italic{Rxgen} is implemented from Sun's \italic{rpcgen} utility.  All of the 
standard \italic{rpcgen}'s functionality is fully maintained.  Note that some 
active \italic{rpcgen} options that don't apply to \italic{rxgen}'s purpose 
aren't referenced here (i.e., \italic{-s}, \italic{-l}, \italic{-m} options) 
and the interested reader should refer to \italic{rpcgen}'s man page for 
details.


When the "\italic{%#include <include file>}" feature is used make sure that 
you don't have any \italic{rxgen} language features (i.e. %#defines) since 
you'll get syntax errors during compilations..


Since this is an ongoing project many of the above may change/disappear 
without a major warning.

\enddata{text,1222184}
