pod-updates-20060227
[openafs.git] / doc / man-pages / pod1 / rxgen.pod
1 =head1 NAME
2
3 rxgen - Stub generator for the Rx remote procedure call package
4
5 =head1 SYNOPSIS
6
7 B<rxgen> [B<-h> | B<-c> | B<-C> | B<-S> | B<-r>] [B<-dkpR>]
8     [B<-I> I<dir>] [B<-P> I<prefix>] [B<-o> I<outfile>] [I<infile>]
9
10 B<rxgen> B<-s> I<transport> [B<-o> I<outfile>] [I<infile>]
11
12 B<rxgen> B<-l> [B<-o> I<outfile>] [I<infile>]
13
14 B<rxgen> B<-m> [B<-o> I<outfile>] [I<infile>]
15
16 =head1 DESCRIPTION
17
18 B<rxgen> is a tool that generates C code to implement the Rx RPC protocol;
19 it takes as input a description of an application interface similar to C
20 and produces a number of server and/or client stub routines to be linked
21 with RPC-based programs.  These stubs allow programs to invoke remote
22 procedures through local procedure calls.  B<rxgen> is an extension of
23 Sun's B<rpcgen> (version 3.9) and retains full B<rpcgen> functionality (at
24 least as of that version).  Please refer to rpcgen(1) for more details on
25 the Sun's RPC specific flags, and to the RPC programming guide regarding
26 the RPC language along with useful examples.
27
28 =head1 OPTIONS
29
30 B<rxgen> operates in several different modes.  The generated output files
31 can be produced individually (using one of B<-h>, B<-c>, B<-C>, or B<-S>)
32 or collectively.  All output files are created when the default is used
33 (i.e., no options), or the output is limited to the server stubs (B<-C>
34 and B<-S>) when the B<-r> flag is used.  The following describes the types
35 of generated output files (for simplicity, I<filename> refers to the main
36 output filename):
37
38 =over 4
39
40 =item B<-h>
41
42 Generate C data definitions (a header file) from standard RPCL definitions
43 (default extension: I<filename>.h).
44
45 =item B<-c>
46
47 Compile the XDR routines required to serialize the protocol described by
48 RPCL.  Generate XDR routines for all declarations (default extension:
49 I<filename>.xdr.c).
50
51 =item B<-C>
52
53 Generate all the client-side stub routines (default extension:
54 I<filename>.cs.c).  Calling a routine in this file will cause the
55 arguments to be packed up and sent via Rx (or R).
56
57 =item B<-S>
58
59 Generate all the server-side stub routines (default extension:
60 I<filename>.ss.c).  Arguments are unpacked, and the corresponding server
61 routine is called.
62
63 =item B<-r>
64
65 Generate the two default extension files produced by the B<-C> and B<-S>
66 options.
67
68 =back
69
70 The following options can be used on any combination of B<rxgen> calls:
71
72 =over 4
73
74 =item B<-R>
75
76 Generate code for the older \R protocol, as opposed to Rx, which is the
77 default.
78
79 =item B<-k>
80
81 Must be specified when the generated code is intended to be used by the
82 kernel; special "includes" and other specifics are produced when the
83 target output is for the kernel.
84
85 =item B<-p>
86
87 Package combination flag: when multiple packages are included within a
88 single specification file, a single Execute Request routine will be used
89 for all of them as a result of this flag.  The default is to generate
90 individual Execute Request stubs for each package.
91
92 =item B<-I> I<dir>
93
94 Similar to the B<-I> flag in the C compiler (B<cc>). This flag is passed
95 to the pre-processor (B<cpp>) so that directory I<dir> is searched before
96 the standard lookup list for #include files.  As expected, multiple B<-I>
97 flags can be used simultaneously.
98
99 =item B<-P> I<prefix>
100
101 The I<prefix> string following this switch is prepended to all generated
102 output files; useful when multiple runs want to produce different versions
103 of the same interface (say, kernel and non-kernel versions).
104
105 =item B<-d>
106
107 Debugging mode; only needed when B<rxgen> is to be debugged (say, via
108 B<dbx>).
109
110 =item B<-o> I<outfile>
111
112 Specify the name of the output file.  If none is specified, the standard
113 output is used (B<-c>, B<-h>, B<-C>, and B<-S> modes only).  Note that if
114 an output file is specified in a multi-output file option (such as the
115 default, or with option B<-r>), then the I<outfile> replaces the name
116 generated by default (which is based on the configuration's main file
117 name).
118
119 =back
120
121 The B<-s>, B<-l>, and B<-m> options are present only for B<rpcgen>
122 support.  See rpcgen(1) for information on their use.
123
124 =head1 B<rxgen> SYNTAX SUMMARY
125
126     Specification file:
127
128         <Package description option> |
129         <Prefix description option> |
130         <StartingOpcode description option> |
131         <SplitPrefix description option> |
132         <Procedure description option> |
133         <RPCL language description option>
134
135     <Package description option>:
136
137         "package" <Package_ident>
138
139     <Prefix description option>:
140
141         "prefix" <Prefix_ident>
142
143     <StartingOpcode description option>:
144
145         "startingopcode" <constant>
146
147     <SplitPrefix description option>:
148
149         "splitprefix" <split options> ";"
150
151     <Split options>:
152
153         "IN =" <Start_prefix_ident> "|"
154         "OUT =" <End_prefix_ident> "|"
155         <Split options>
156
157     <Procedure description option>:
158
159         ["proc"] [<Procedure_ident>] [<ServerStub_ident>]
160             <Argument list> ["split" | "multi"]
161             ["=" <Opcode_ident>] ";"
162
163     <Argument list>:
164
165         "(" <Argument definition> <Comma_joined argument> ")"
166
167     <Argument definition>:
168
169         <Direction option> <Standard RPCL type decl> <Arg_ident>
170             ["<" <Max_size> ">" | "[" <Max_size> "]"] | NULL
171
172     <Comma_joined argument>:
173
174         "," <Argument definition> | NULL
175
176     <Direction option>:
177
178         "IN" | "OUT" | "INOUT" | NULL
179
180     <Max_size>:
181
182         <constant> | NULL
183
184     <Package_ident>:
185     <Prefix_ident>:
186     <String_ident>:
187     <Start_prefix_ident>:
188     <End_prefix_ident>:
189     <Procedure_ident>:
190     <ServerStub_ident>:
191     <Arg_ident>:
192     <Opcode_ident>:
193
194         <identifier>
195
196     <RPCL language description option>:
197     <Standard RPCL type decl>:
198
199         Sun's RPCL language syntax (see rpcgen(1))
200
201 =head1 B<rxgen> COMMANDS
202
203 =head2 Comments and Preprocessing
204
205 The input interface may contain preprocessor directives which are passed
206 through the C preprocessor (i.e. C<cpp>).  Since the preprocessor runs on
207 all input files before they are actually interpreted by B<rxgen>, all
208 B<cpp> directives (#include, #ifdefs, #defines, etc.) are legal and
209 welcomed within an B<rxgen> input file.  Of course, none of these
210 preprocessor directives will be included in any of the generated files.
211 To facilitate distinctions between the different types of output files,
212 B<rxgen> defines certain special B<cpp> symbols for use by the B<rxgen>
213 programmer.  These are RPC_HDR (defined when compiling into header,
214 I<filename>.h, files), RPC_XDR (defined when compiling into xdr,
215 I<filename>.xdr.c, files), RPC_CLIENT (defined when compiling into client
216 stubs, I<filename>.cs.c, files), and RPC_SERVER (defined when compiling
217 into server stubs, I<filename>.ss.c, files).
218
219 In addition, B<rxgen> does a little preprocessing of its own.  Any line
220 beginning with C<%> is passed directly into the output file, uninterpreted
221 by B<rxgen>.  For a more heavy en masse dumping of uninterpreted code, it
222 would be adviced to include all such code in an C<#include> file and pass
223 it in preceded by C<%>.  The input interface may also contain any C-style
224 comments which are, of course, ignored. Interpretation is token-based,
225 thus special line-orientation of separate statements is not necessary.
226 B<rxgen> also provides a quite rich and helpful set of error reports,
227 identifying them by exact line location and error type.  Also, B<rxgen>
228 will automatically generate #include lines for standard include files,
229 such as F<rx/xdr.h> and F<rx/rx.h>, along with the generated header file
230 from this interface.
231
232 =head2 Prefixing stub procedures
233
234 The I<package> statement tells B<rxgen> the name of the interface package.
235 It is used for prefixing the naming of all generated stub routines and the
236 execute request procedure.  For example:
237
238     package AFS_
239
240 causes the execute request procedure to be named AFS_ExecuteRequest
241 (Warning: in the older version an additional C<_> was appended after the
242 package name to the ExecuteRequest name; thus make sure you don't have an
243 ExecuteRequest interface routine) and a given stub routine, say Fetch, to
244 be actually named AFS_Fetch.  Multiple package statements (current maximum
245 size is 10) per configuration are permitted and are useful when multiple
246 sets of interfaces are implemented (see the example at the end).  Note
247 that in such cases, use of the B<-p> flag results in the generation of
248 just one ExecuteRequest procedure which recognizes the multiple interfaces
249 and whose name is prefixed by the first package statement.  In the default
250 case, independent ExecuteRequest procedures will be created for each
251 packaged group of remote procedure calls.
252
253 The I<prefix> statement supplies a name to prepend to all calls to remote
254 procedure names in the ExecuteRequest stub routine.  It is useful when the
255 server makes RPC calls to other servers (say, for debugging purposes).
256 For example:
257
258     prefix S
259
260 causes the name C<S> to be prepended to the name of all routines called
261 from the server stubs.  The server can then call the original name and get
262 the client stubs.
263
264 =head2 B<rxgen> procedure declaration
265
266 The I<proc> statement is the most common (and meaningful) in the B<rxgen>
267 interface.  Its syntax description is:
268
269         [proc] [<proc_name>] [<server_stub>] (<arg>, ..., <arg>)
270             [split | multi] [= <opcode>] ;
271
272 where:
273
274 =over 2
275
276 =item *
277
278 C<proc> is an optional prefix of the procedure statement. This is just a
279 stylistic item and not a required procedure delimiter.
280
281 =item *
282
283 <proc_name> is the name of the procedure.  Note that even the name of the
284 procedure is optional.  This only makes sense when the name of the given
285 procedure is identical to the name of the last I<package> statement (i.e.,
286 C<package RCallBack> and the declaration of the C<RCallBack> procedure).
287
288 =item *
289
290 <server_stub>, if present, causes the ExecuteRequest procedure to call
291 that stub instead of the automatically generated stub when a call with
292 that opcode is decoded.
293
294 =item *
295
296 <opcode> is a constant or symbol that is the opcode for that procedure.
297 One might use the preprocessor features (i.e., #define), the I<const>
298 RPC-language feature, or the old good constants as opcodes. Some further
299 evaluation/processing of opcodes is done.  Particularly, checks for
300 duplicate and non-existent opcodes are performed, along with checks for
301 "holes" (i.e., gaps in consecutive opcodes) in the opcode sequences.  For
302 example, we use the fact that when "holes" in opcodes exist, the
303 ExecuteRequest procedure uses the I<case> statement rather than the faster
304 (and smaller, codewise) indexed array method.
305
306 Also, B<rxgen> defines (i.e., appends to the header file) three valuable
307 macros for each package group: <package-name>LOWEST_OPCODE,
308 <package-name>HIGHEST_OPCODE, and <package-name>NUMBER_OPCODES.  These may
309 be useful to the B<rxgen> programmer.  Also, notice that the I<opcode>
310 statement is an optional feature, and can be omitted.  In such cases,
311 automatic opcode numbers are generated sequentially, starting from 0.
312
313 One can change the initial opcode number by using the I<startingopcode>
314 (for lack of a better name) B<rxgen> command.  Its syntax is:
315
316     startingopcode <constant>
317
318 where <constant> must be reasonable!  Note that one can not mix
319 procedures, some with opcodes and some without, nor allow opcodes after
320 the specification of the I<startingopcode> statement.  B<rxgen> will
321 complain in all such cases.
322
323 =item *
324
325 The I<argument> entry represents a given parameter of the procedure.  Its
326 syntax is:
327
328     [IN | INOUT | OUT | <null>] <type_decl> <arg_name>
329         [<max>|<>|[max]|[]]
330
331 If the type is an indirect type (i.e., is followed by *), it is assumed
332 that the pointer should be followed one level and the data pointed to is
333 to be transmitted. This should normally be used for all structures/arrays
334 and out parameters.  A noticeable exception is when explicit
335 array/structure maximum size is given; since no array-of-pointer
336 declarations are allowed one should use typedefs to achieve the similar
337 effect.  The parameters could be input parameters (preceded by IN), output
338 parameters (preceded by OUT), or input/output parameters (preceded by
339 INOUT).  If not specified, then the direction of the previous parameter in
340 the procedure is used.  (Note: the first parameter must be preceded by the
341 directional primitive!)
342
343 =item *
344
345 C<split> is a hack to handle stub routines that do things such as file
346 transfers or any other operation that has to exchange information (e.g.,
347 length of a file) before the call returns its output parameters.  Because
348 of the particular handshake that is involved when doing remote file
349 transfer, we currently break all such calls into two client-side stub
350 routines.  The first (with the default prefix of C<Begin>) is used to pass
351 all IN and INOUT parameters to the server side.  The second (with the
352 default prefix of C<End>) is used to get back the INOUT and OUT parameters
353 from the server.  Between the two calls, the user is supposed to do the
354 appropriate calls for the file transfer. For example, the following
355 procedure declaration in package AFS_
356
357     Fetch (IN a, b,INOUT c, OUT d) split = FETCHOPCODE;
358
359 will roughly generate the two independent client stub routines:
360
361     BeginAFS_Fetch (IN a, b, c)
362
363 and
364
365     EndAFS_Fetch(OUT c, d)
366
367 The I<splitprefix> statement is used to change the default prefix names
368 used by the two client-side stub generated routines when dealing with file
369 transfer-related procedure calls.  For example:
370
371     splitprefix IN=Before_ OUT=After_
372
373 will cause the naming of the two client stubs for a file transfer-related
374 routine, say Fetch(), to be Before_AFS_Fetch() and After_AFS_Fetch(),
375 respectively.
376
377 =item *
378
379 The C<multi> option is nearly identical to the C<split> feature described
380 above.  The only significant visible difference is that along with the two
381 client stubs, the standard client stub is also generated.  Since the
382 intention is to handle the multi-Rx calls, we need the whole standard
383 procedure stub in the cases where no multi-Rx call of the procedure is
384 performed.  A side effect of the C<multi> option is the generation of a
385 special macro (i.e., C<< multi_<Procedure-name> >> which passes back as
386 arguments the C<Begin> and C<End> stubs in the header output file. This
387 macro is used directly by the Rx code when a multi-Rx call of this
388 procedure is performed.
389
390 =back
391
392 =head2 OBSOLETE B<rxgen> FEATURES
393
394 Although the following rxgen commands are still in effect, they will soon
395 be removed since there are better alternatives. DO NOT USE THEM!
396
397 The I<special> statement is a temporary hack used to handle certain
398 inefficiencies of standard xdr routines to handle some user-customized
399 declarations.  In particular, this applies to a string pointer specified
400 as part of a declaration.  For example,
401
402     special struct BBS SeqBody;
403
404 tells B<rxgen> that the entry C<SeqBody> in the user-defined BBS xdr
405 routine is a string (note that more than one string can be "special" per
406 structure -- multiple ones are separated by commas); it will thus allocate
407 and de-allocate space properly in the server-generated stubs that contain
408 this structure as an IN or INOUT parameter.
409
410 A better alternative to I<special> is the I<customized> statement, which
411 is simply the C<customized> token followed by the regular declaration of a
412 struct based on the RPCL rules. In this case, the declaration will be
413 included in the generated header file (B<-h> option) but no xdr routine
414 will be generated for this structure -- the user will supply this.  All
415 pointer entries in this structure will be remembered so when the structure
416 is used as an IN or INOUT in the server stub, no core leaks will occur.
417 For example, consider
418
419     customized struct CBS {
420         long Seqlen;
421         char *SeqBody;
422     }
423
424 The C<xdr_CBS> routine would be provided by the user where during the
425 DECODE xdr opcode, appropriate space for the C<SeqBody> string is
426 allocated.  Similarly, that space is freed during the FREE xdr opcode.
427
428 Note: Old style "Array parameter specifications" are not supported any
429 more.
430
431 =head1 EXAMPLES
432
433 In case there are some requirements not available by the current RPC
434 language, one can customize some XDR routines by leaving those data types
435 undefined. For every data type that is undefined, it will be assumed that
436 a routine exists with the name C<xdr_> prepended to it.  A selected set of
437 B<rxgen> features is presented below, but for a more comprehensive one
438 (unions, complex examples, etc) please refer to the I<rpcgen Programming
439 Guide> and I<eXternal Data Representation: Sun Technical Notes>.
440
441 =head2 Typedefs
442
443 The RPC typedef statement is identical to the C typedef (i.e. C<< typedef
444 <declaration> >>).  By default, most user declarations (i.e. structs,
445 unions, etc) are automatically typedef'ed by B<rxgen>.  Since it makes
446 parsing simpler, its usage is recommended by B<rxgen> scripts.
447
448 =head2 Strings
449
450 The C C<char *> string convention is kind of ambiguous, since it is
451 usually intended to mean a null-terminated string of characters, but it
452 could also represent a pointer to a single character, a pointer to an
453 array of characters, etc.  In the RPC language, a null-terminated string
454 is unambiguously called a "string".  Examples,
455
456     string bigname<>;
457     string name<MAXNAMELEN>;
458     typedef string volname<MAXVOLNAME>;
459
460 Notice that the maximum size of string can be arbitrary (like C<bigname>
461 above) or, preferably, or specified in angle brackets (i.e. C<name> and
462 C<volname> above).  In practice, one should always use only bounded
463 strings in interfaces.  A sample calling proc using the declarations above
464 would be:
465
466     GetEntryByName (IN volname name, 
467         OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;
468
469 or, of course,
470
471     GetEntryByName (IN string volname<MAXVOLNAME>,
472         OUT struct vldbentry *entry) = VL_GETENTRYBYNAME;
473
474 It is very important for the user to understand when the string parameters
475 should be allocated and/or freed by the his/her client and/or server
476 programs. A short analysis on string parameters handling follows (note
477 that a similar method is used for the handling of variable length arrays
478 as it will be shown later on):
479
480 =over 2
481
482 =item *
483
484 In the client side: IN and INOUT string parameters are the programmer's
485 responsibility and should be allocated (static or via malloc) before
486 calling the rpc and freed (if malloc was used) after the rpc's return in
487 the user's client program; of course, for INOUT parameters, the returned
488 string can't be bigger than the malloced input string.
489
490 OUT string parameters are automatically malloced (based on the length of
491 the returned string and not the maxsize) by the B<rxgen> client stubs (in
492 I<filename>.cs.c) and must be freed by the client program; admittedly,
493 this could be somewhat confusing since the user needs to free something
494 that he/she didn't allocate.}
495
496 =item *
497
498 In the server side: IN and INOUT string parameters are automatically
499 malloced (based on the size of incoming strings) by the rxgen server stubs
500 (in I<filename>.ss.c) before they are passed to the user's server
501 procedure; that space is automatically freed just before the rxgen server
502 stub returns; therefore the user need not do anything special for IN and
503 INOUT string parameters.
504
505 OUT string parameters must be malloced by the user's server procedure
506 (i.e. null pointer is passed to it by the rxgen server stub) and it is
507 automatically freed at the end of the B<rxgen> server stub.  Like in the
508 client side, the OUT parameters are somewhat unorthodox (i.e. the server
509 routine must malloc a string without ever freeing it itself; this is done
510 by the B<rxgen> server stub).
511
512 =back
513
514 Note that for INOUT and OUT string parameters, in both the client and
515 server sides their arguments must be char of pointers (i.e. char **).
516
517 =head2 Pointers
518
519 Pointer declarations in RPC are also exactly as they are in C
520 (i.e. C<struct single_vldbentry *vldblist;>).  Of course, one can't send
521 pointers over the network, but one can use XDR pointers for sending
522 recursive data types such as lists and trees (an example of a linked list
523 will be demonstrated shortly).
524
525 =head2 Arrays
526
527 Fixed arrays are just like standard C array declarations (i.e. C<struct
528 UpdateEntry entries[20]>) without any side effect problems in
529 B<rxgen>. Since variable-length arrays have no explicit syntax in C, the
530 angle-brackets are used for it and the array declarations are actually
531 compiled into "struct"s. For example, declarations such as:
532
533     const   MAXBULKSIZE     = 10000;
534     const   MAXENTRIES      = 100;
535     opaque  bulk<MAXBULKSIZE>;           /* At most 10000 items */
536     int     hosts<>;                     /* any number of items */
537     typedef vldbentry blkentries<100>;   /* Preferable array decl */
538
539 are compiled into the following structs:
540
541     struct {
542         u_int   bulk_len;       /* no of items */
543         char    *bulk_val;      /* pointer to array */
544     } bulk;
545
546 for the C<bulk> array, and similarly for the C<< blkentries<100> >> array,
547
548     struct {
549         u_int      blkentries_len;   /* no of items in array */
550         vldbentry  *blkentries_val;  /* pointer to array */
551     } blkentries;
552
553 Therefore the user should be aware of the "magically" generated structure
554 entries such as the number of items in the array (<array_name>_len) and
555 the pointer to the array (<array_name>_val) since some of the entries will
556 have to be filled in from the client/server programs.  A sample proc would
557 be:
558
559     typedef vldbentry blkentries<MAXENTRIES>;
560     proc GetBlk (OUT blkentries *vlentries) = VL_GETBLK;
561
562 or, more directly,
563
564     GetBlk(OUT vldbentry vlentries<MAXENTRIES>) = VL_GETBLK;
565
566 Note that although the latest method is preferable since one does not have
567 to first use the typedef statement (and admittedly, programmers prefer
568 avoiding typedefs), one should realize that B<rxgen> does the structure
569 expansion and the xdr creation implicitly; therefore the user should be
570 aware of the C<vldbentries_val> and C<vldbentries_len> fields as before
571 (see following examples).
572
573 =head3 Array example I (least desirable)
574
575 Procedure declaration in the interface configuration:
576
577     proc ListAttributes (IN vldblistbyattributes *attributes, 
578                  INOUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
579
580 Sample CLIENT code:
581
582     blkentries entries, *pnt;
583     entries.blkentries_len = 10;   /* max # returned entries */
584     entries.blkentries_val = (vldbentry *)malloc(LEN);
585                                    /* It must be set */
586
587     code = VL_ListAttributes(&attributes, &entries);
588     if (!code) {
589         pnt = entries.blkentries_val;
590         for (i=0; i < entries.blkentries_len; i++, pnt++)
591                 display_vldbentry(pnt);
592         /* Make sure you free the allocated space */
593         free((char *)entries.blkentries_val);   
594     }
595
596 Sample SERVER code:
597
598     VL_ListAttributes(attributes, entries)
599     {
600         vldbentry *singleentry = entries->blkentries_val;
601         entries->blkentries_len = 0;
602
603         while (copy_to_vldbentry(&vlentry, singleentry))
604             singleentry++, vldbentries->entries_len++;
605     }
606
607 Although this method for variable-size arrays works fine, there are some
608 major drawbacks.  The array parameter (i.e. vldbentries above) must be
609 declared as INOUT since we need to pass the max length of the expected
610 returned array; more importantly, a big (depending on the value of
611 C<_len>) chunk of junk code is going to be transferred to the server as
612 result of the IN(out) side-effect of the array.  It's an easy and
613 convenient method if the returned array size can be predicted from the
614 start and when the size is quite high.  This method is included as an
615 example of erroneous use (and abuse) of B<rxgen> and should not be used.
616
617 =head3 Array example II (Desirable method)
618
619 Procedure declaration in the interface configuration (using Example I
620 above):
621
622     proc ListAttributes (IN vldblistbyattributes *attributes, 
623         OUT blkentries *vldbentries) = VL_LISTATTRIBUTES;
624
625 Sample CLIENT code:
626
627     blkentries entries, *pnt;
628
629     code = VL_ListAttributes(&attributes, &entries);
630     if (!code) {
631         pnt = entries.blkentries_val;
632         for (i=0; i < entries.blkentries_len; i++, pnt++)
633                 display_vldbentry(pnt);
634         /* Make sure you free the allocated space (by rxgen) */
635         free((char *)entries.blkentries_val);   
636     }
637
638 Sample SERVER code:
639
640     VL_ListAttributes(attributes, entries)
641     {
642         vldbentry *singleentry;
643         entries->blkentries_len = 0;
644         singleentry = entries->blkentries_val
645             = (vldbentry *)malloc(MAXENTRIES * sizeof(vldbentry));
646
647         while (copy_to_vldbentry(&vlentry, singleentry))
648                 singleentry++, vldbentries->entries_len++;
649     }
650
651 This is the best (and simplest) way of using variable-size arrays as an
652 output parameter.  It is the responsibility of the server-side stub to
653 malloc() the adequate space which is automatically freed by the B<rxgen>
654 stub; the client side should free the space allocated by the
655 B<rxgen>-calling stub.
656
657 =head3 Array example III (Linked Lists)
658
659 Considering the following 3 declarations (could have applied some
660 optimizations) in the configuration file:
661
662     typedef struct single_vldbentry *vldblist;
663     struct single_vldbentry {
664         vldbentry vlentry;
665         vldblist  next_vldb;
666     };
667
668     struct vldb_list {
669         vldblist node;
670     };
671
672 and the rxgen procedure declaration:
673
674     LinkedList (IN vldblistbyattributes *attributes, 
675         OUT vldb_list *linkedentries) = VL_LINKEDLIST;
676
677 Sample CLIENT code:
678
679     vldb_list       linkedvldbs;
680     vldblist        vllist, vllist1;
681
682     bzero(&linkedvldbs, sizeof(vldb_list));
683     code = VL_LinkedList(&attributes, &nentries, &linkedvldbs);
684     if (!code) {
685         printf("We got %d vldb entries\n", nentries);
686         for (vllist = linkedvldbs.node; vllist; vllist = vllist1) {
687             vllist1 = vllist->next_vldb;
688             display_entry(&vllist->vlentry);
689             free((char *)vllist);
690         }
691     }
692
693 Sample SERVER code:
694
695     VL_LinkedList(rxcall, attributes, nentries, linkedvldbs);
696     {
697         vldblist vllist, *vllistptr = &linkedvldbs->node;
698         while (...) {
699             vllist = *vllistptr
700                 = (single_vldbentry *)malloc (sizeof (single_vldbentry));
701             copy_to_vldbentry(&tentry, &vllist->vlentry);
702             nentries++;     
703             vllistptr = &vllist->next_vldb;
704         };
705         *vllistptr = NULL;
706     }
707
708 Using a linked list offers many advantages: Nothing is passed to the
709 server (the parameter is OUT), no additional overhead is involved, and the
710 caller doesn't have to explicitly prepare for an arbitrary return size.  A
711 drawback is that the caller has the responsibility of malloc() (on the
712 server) and free (on the client) of each entry (to avoid unwanted
713 core-leaks).  Another drawback is that since it's a recursive call, the C
714 stack will grow linearly with respect to the number of nodes in the list
715 (so it's wise to increase the Rx LWP stack if huge amounts of data are
716 expected back -- default stack size is 4K).  The advantages should
717 outweight the disadvantages here.
718
719 It's important to pay attention to the comments of the three array
720 examples above particularly when they're references to when the user
721 should allocate/free space for the variable length arrays.  The mechanism
722 is very similar to the handling of strings thus you might need to review
723 the strings section above; note that the linked lists are handled somewhat
724 differently...
725
726 =head2 Miscellaneous examples
727
728 Below is an abbreviated version of a random interface file which shows
729 some of the common cases.
730
731     /* Declaration of all structures used by the R.xg script interface */
732
733     struct AFSFid {
734         unsigned long Volume;
735         unsigned long Vnode;
736         unsigned long Unique;
737     };
738
739     typedef long ViceDataType;
740
741     /* Note that TEST would be equivalent to "HEADER" only during the 
742        processing of the header, *.h, file */
743
744     #ifdef RPC_HDR
745     #define TEST "HEADER"
746     #else
747     #define TEST "REST"
748     #endif
749
750     /* This is the standard *.xg specification file */
751
752     package AFS_
753     splitprefix IN=BEFORE_ OUT=AFTER_;
754     Prefix Test
755
756     proc Remove(IN struct AFSFid *Did, IN string volname<64>,
757         OUT struct AFSStatus *Status) = AFS_REMOVE;
758
759     DisconnectFS AUX_disconnectFS() = AFS_DISCONNECTFS;
760
761     proc GetVolumeInfo(IN string Vid, 
762         OUT struct VolumeInfo *Info) = AFS_GETVOLUMEINFO;
763
764     /* You could have more than an interface per configuration */
765
766     package VOTE_
767
768     /* Using the "multi" feature; thus VOTE_Beacon can be called as an 
769        multi-Rx call or as a regular call */
770
771     Beacon (IN long state, long voteStart, 
772         net_version *version, net_tid *tid) 
773         multi = VOTE_BEACON;
774
775     package DISK_
776
777     /* Using the "split" feature */
778
779     SendFile (IN long file, long offset, 
780         long length, net_version *version) 
781         split = DISK_SENDFILE;
782
783 =head2 Output of an actual interface configuration
784
785 We'll demonstrate some of the actual output generated by B<rxgen> by
786 following an abbreviated actual interface configuration.
787
788 =head3 Configuration file
789
790 Contents of the interface configuration file (F<vldbint.xg>):
791
792     package VL_
793     #include "vl_opcodes.h"   /* The opcodes are included here */
794     %#include "vl_opcodes.h"  /* directly to other places */
795
796     /* Current limitations on parameters that affect other packages
797        (i.e. volume) */
798
799     const   MAXNAMELEN      =       65;
800     const   MAXNSERVERS     =       8;
801     const   MAXTYPES        =       3;
802
803     /* External (visible) representation of an individual vldb entry */
804
805     struct vldbentry {
806         char    name[MAXNAMELEN];       
807         long    volumeType;             
808         long    nServers;               
809         long    serverNumber[MAXNSERVERS];
810         long    serverPartition[MAXNSERVERS];
811         long    serverFlags[MAXNSERVERS];
812         u_long  volumeId[MAXTYPES];     
813         long    flags;                  
814     };
815
816     typedef struct single_vldbentry  *vldblist;
817     struct single_vldbentry {
818         vldbentry VldbEntry;
819         vldblist next_vldb;
820     };
821
822     struct vldb_list {
823         vldblist node;
824     };
825
826     /* vldb interface calls */
827
828     CreateEntry     (IN long Volid, 
829                     vldbentry *newentry) = VLCREATEENTRY;
830
831     GetEntryByName  (IN string volumename<MAXNAMELEN>, 
832                     OUT vldbentry *entry) = VLGETENTRYBYNAME;
833
834     GetNewVolumeId  (IN long bumpcount,
835                     OUT long *newvolumid) = VLGETNEWVOLUMEID;
836
837     ReplaceEntry    (IN long Volid, 
838                     long voltype,
839                     vldbentry *newentry,
840                     long ReleaseType) multi = VLREPLACEENTRY;
841
842     ListAttributes  (IN VldbListByAttributes *attributes, 
843                     OUT long *nentries, 
844                     OUT vldbentry bulkentries<MAXVLDBLEN>) 
845                     = VLLISTATTRIBUTES;
846
847     LinkedList      (IN VldbListByAttributes *attributes, 
848                     OUT long *nentries, 
849                     OUT vldb_list *linkedentries) = VLLINKEDLIST;
850
851 We'll concentrate only on the Rx generated code since the R generated code
852 (B<-R> option) will soon be obsolete.  For a detailed description on the
853 Rx-related calls inside the generated stubs (i.e., rx_NewCall(),
854 rx_EndCall()), along with details on what happens inside certain calls
855 (like xdrrx_create()) please refer to the Rx documentation. Typing C<rxgen
856 vldbint.xg> will result in the creation of four files: F<vldbint.h>,
857 F<vldbint.xdr.c>, F<vldbint.cs.c> and F<vldbint.ss.c>.  A closer look at
858 these files follows.
859
860 =head3 Header file (F<vldbint.h>)
861
862     /* Machine generated file -- Do NOT edit */
863
864     #include "vl_opcodes.h"  /* directly to other places */
865     #define MAXNAMELEN 65
866     #define MAXNSERVERS 8
867     #define MAXTYPES 3
868
869     struct vldbentry {
870         char name[MAXNAMELEN];
871         long volumeType;
872         long nServers;
873         long serverNumber[MAXNSERVERS];
874         long serverPartition[MAXNSERVERS];
875         long serverFlags[MAXNSERVERS];
876         u_long volumeId[MAXTYPES];
877         long flags;
878     };
879     typedef struct vldbentry vldbentry;
880     bool_t xdr_vldbentry();
881
882     typedef struct single_vldbentry *vldblist;
883     bool_t xdr_vldblist();
884
885     struct single_vldbentry {
886         vldbentry VldbEntry;
887         vldblist next_vldb;
888     };
889     typedef struct single_vldbentry single_vldbentry;
890     bool_t xdr_single_vldbentry();
891
892     struct vldb_list {
893         vldblist node;
894     };
895     typedef struct vldb_list vldb_list;
896     bool_t xdr_vldb_list();
897
898     #include <rx/rx_multi.h>
899     #define multi_VL_ReplaceEntry(Volid, voltype, newentry, ReleaseType) \
900         multi_Body(StartVL_ReplaceEntry(multi_call, Volid, voltype,
901                    newentry, ReleaseType), EndVL_ReplaceEntry(multi_call))
902
903     typedef struct bulkentries {
904         u_int bulkentries_len;
905         vldbentry *bulkentries_val;
906     } bulkentries;
907     bool_t xdr_bulkentries();
908
909     /* Opcode-related useful stats for package: VL_ */
910     #define VL_LOWEST_OPCODE        501
911     #define VL_HIGHEST_OPCODE       506
912     #define VL_NUMBER_OPCODES       6
913
914 Notice that all structures are automatically typedef'ed and all C<const>s
915 are converted to C<#define>s. Some data structures, such as bulkentries,
916 are taken from procedure params (from ListAttributes proc). Thus, this
917 should be kept in mind when creating stubs piecemeal with B<rxgen> (i.e.,
918 using the B<-c>, B<-h>, B<-C>, or B<-S> flags).  Also, one of the side
919 effects of the C<multi> option (in C<ReplaceEntry> proc) is the generation
920 of the C<multi_VL_ReplaceEntry> above.
921
922 =head3 XDR routines for structures (vldbint.xdr.c)
923
924     /* Machine generated file -- Do NOT edit */
925
926     #include <rx/xdr.h>
927     #include "vldbint.h"
928
929     #include "vl_opcodes.h"  /* directly to other places */
930
931     bool_t
932     xdr_vldbentry(xdrs, objp)
933         XDR *xdrs;
934         vldbentry *objp;
935     {
936         if (!xdr_vector(xdrs, (char *)objp->name, MAXNAMELEN,
937                         sizeof(char), xdr_char))
938             return (FALSE);
939         if (!xdr_long(xdrs, &objp->volumeType))
940             return (FALSE);
941         if (!xdr_long(xdrs, &objp->nServers))
942             return (FALSE);
943         if (!xdr_vector(xdrs, (char *)objp->serverNumber, MAXNSERVERS,
944                         sizeof(long), xdr_long))
945             return (FALSE);
946         if (!xdr_vector(xdrs, (char *)objp->serverPartition,
947                         MAXNSERVERS, sizeof(long), xdr_long))
948             return (FALSE);
949         if (!xdr_vector(xdrs, (char *)objp->serverFlags, MAXNSERVERS,
950                         sizeof(long), xdr_long))
951             return (FALSE);
952         if (!xdr_vector(xdrs, (char *)objp->volumeId, MAXTYPES,
953                         sizeof(u_long), xdr_u_long))
954             return (FALSE);
955         if (!xdr_long(xdrs, &objp->flags))
956             return (FALSE);
957         return (TRUE);
958     }
959
960     bool_t
961     xdr_vldblist(xdrs, objp)
962         XDR *xdrs;
963         vldblist *objp;
964     {
965         if (!xdr_pointer(xdrs, (char **)objp,
966                          sizeof(struct single_vldbentry), 
967                          xdr_single_vldbentry))
968             return (FALSE);
969         return (TRUE);
970     }
971
972     bool_t
973     xdr_single_vldbentry(xdrs, objp)
974         XDR *xdrs;
975         single_vldbentry *objp;
976     {
977         if (!xdr_vldbentry(xdrs, &objp->VldbEntry))
978             return (FALSE);
979         if (!xdr_vldblist(xdrs, &objp->next_vldb))
980             return (FALSE);
981         return (TRUE);
982     }
983
984     bool_t
985     xdr_vldb_list(xdrs, objp)
986         XDR *xdrs;
987         vldb_list *objp;
988     {
989         if (!xdr_vldblist(xdrs, &objp->node))
990             return (FALSE);
991         return (TRUE);
992     }
993
994     bool_t
995     xdr_bulkentries(xdrs, objp)
996         XDR *xdrs;
997         bulkentries *objp;
998     {
999         if (!xdr_array(xdrs, (char **)&objp->bulkentries_val,
1000                        (u_int *)&objp->bulkentries_len, MAXVLDBLEN,
1001                        sizeof(vldbentry), xdr_vldbentry))
1002             return (FALSE);
1003         return (TRUE);
1004     }
1005
1006 Note that the xdr_bulkentries() is automatically generated as a side
1007 effect of a procedure parameter declaration.  Thus, if identical multiple
1008 type parameter declarations are used, then multiply-defined xdr_* stubs
1009 will be created!  We felt this was a better alternative to having the
1010 B<rxgen> programmer deal with types such as bulkentries_1,
1011 bulkentries_2...
1012
1013 =head3 Client-Side stub routines (vldbint.cs.c)
1014
1015     /* Machine generated file -- Do NOT edit */
1016
1017     #include <rx/xdr.h>
1018     #include <rx/rx.h>
1019     #include <afs/rxgen_consts.h>
1020     #include "vldbint.h"
1021
1022     #include "vl_opcodes.h"  /* directly to other places */
1023
1024     int VL_CreateEntry(z_conn, Volid, newentry)
1025         register struct rx_connection *z_conn;
1026         long Volid;
1027         vldbentry * newentry;
1028     {
1029         struct rx_call *z_call = rx_NewCall(z_conn);
1030         static int z_op = 501;
1031         int z_result;
1032         XDR z_xdrs;
1033
1034         xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1035
1036         /* Marshal the arguments */
1037         if ((!xdr_int(&z_xdrs, &z_op))
1038              || (!xdr_long(&z_xdrs, &Volid))
1039              || (!xdr_vldbentry(&z_xdrs, newentry))) {
1040                 z_result = RXGEN_CC_MARSHAL;
1041                 goto fail;
1042         }
1043
1044         z_result = RXGEN_SUCCESS;
1045     fail:
1046         return rx_EndCall(z_call, z_result);
1047     }
1048
1049     int VL_GetEntryByName(z_conn, volumename, entry)
1050         register struct rx_connection *z_conn;
1051         char * volumename;
1052         vldbentry * entry;
1053     {
1054         struct rx_call *z_call = rx_NewCall(z_conn);
1055         static int z_op = 504;
1056         int z_result;
1057         XDR z_xdrs;
1058
1059         xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1060
1061         /* Marshal the arguments */
1062         if ((!xdr_int(&z_xdrs, &z_op))
1063              || (!xdr_string(&z_xdrs, &volumename, 65))) {
1064                 z_result = RXGEN_CC_MARSHAL;
1065                 goto fail;
1066         }
1067
1068         /* Un-marshal the reply arguments */
1069         z_xdrs.x_op = XDR_DECODE;
1070         if ((!xdr_vldbentry(&z_xdrs, entry))) {
1071                 z_result = RXGEN_CC_UNMARSHAL;
1072                 goto fail;
1073         }
1074
1075         z_result = RXGEN_SUCCESS;
1076     fail:
1077         return rx_EndCall(z_call, z_result);
1078     }
1079
1080     int VL_GetNewVolumeId(z_conn, bumpcount, newvolumid)
1081         register struct rx_connection *z_conn;
1082         long bumpcount;
1083         long * newvolumid;
1084     {
1085         struct rx_call *z_call = rx_NewCall(z_conn);
1086         static int z_op = 505;
1087         int z_result;
1088         XDR z_xdrs;
1089
1090         xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1091
1092         /* Marshal the arguments */
1093         if ((!xdr_int(&z_xdrs, &z_op))
1094              || (!xdr_long(&z_xdrs, &bumpcount))) {
1095                 z_result = RXGEN_CC_MARSHAL;
1096                 goto fail;
1097         }
1098
1099         /* Un-marshal the reply arguments */
1100         z_xdrs.x_op = XDR_DECODE;
1101         if ((!xdr_long(&z_xdrs, newvolumid))) {
1102                 z_result = RXGEN_CC_UNMARSHAL;
1103                 goto fail;
1104         }
1105
1106         z_result = RXGEN_SUCCESS;
1107     fail:
1108         return rx_EndCall(z_call, z_result);
1109     }
1110
1111     int VL_ReplaceEntry(z_conn, Volid, voltype, newentry, ReleaseType)
1112         register struct rx_connection *z_conn;
1113         long Volid, voltype, ReleaseType;
1114         vldbentry * newentry;
1115     {
1116         struct rx_call *z_call = rx_NewCall(z_conn);
1117         static int z_op = 506;
1118         int z_result;
1119         XDR z_xdrs;
1120
1121         xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1122
1123         /* Marshal the arguments */
1124         if ((!xdr_int(&z_xdrs, &z_op))
1125              || (!xdr_long(&z_xdrs, &Volid))
1126              || (!xdr_long(&z_xdrs, &voltype))
1127              || (!xdr_vldbentry(&z_xdrs, newentry))
1128              || (!xdr_long(&z_xdrs, &ReleaseType))) {
1129                 z_result = RXGEN_CC_MARSHAL;
1130                 goto fail;
1131         }
1132
1133         z_result = RXGEN_SUCCESS;
1134     fail:
1135         return rx_EndCall(z_call, z_result);
1136     }
1137
1138     int StartVL_ReplaceEntry(z_call, Volid, voltype, newentry, ReleaseType)
1139         register struct rx_call *z_call;
1140         long Volid, voltype, ReleaseType;
1141         vldbentry * newentry;
1142     {
1143         static int z_op = 506;
1144         int z_result;
1145         XDR z_xdrs;
1146
1147         xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1148
1149         /* Marshal the arguments */
1150         if ((!xdr_int(&z_xdrs, &z_op))
1151              || (!xdr_long(&z_xdrs, &Volid))
1152              || (!xdr_long(&z_xdrs, &voltype))
1153              || (!xdr_vldbentry(&z_xdrs, newentry))
1154              || (!xdr_long(&z_xdrs, &ReleaseType))) {
1155                 z_result = RXGEN_CC_MARSHAL;
1156                 goto fail;
1157         }
1158
1159         z_result = RXGEN_SUCCESS;
1160     fail:
1161         return z_result;
1162     }
1163
1164     int EndVL_ReplaceEntry(z_call)
1165         register struct rx_call *z_call;
1166     {
1167         int z_result;
1168         XDR z_xdrs;
1169
1170         z_result = RXGEN_SUCCESS;
1171     fail:
1172         return z_result;
1173     }
1174
1175     int VL_ListAttributes(z_conn, attributes, nentries, bulkentries_1)
1176         register struct rx_connection *z_conn;
1177         VldbListByAttributes * attributes;
1178         long * nentries;
1179         bulkentries * bulkentries_1;
1180     {
1181         struct rx_call *z_call = rx_NewCall(z_conn);
1182         static int z_op = 511;
1183         int z_result;
1184         XDR z_xdrs;
1185
1186         xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1187
1188         /* Marshal the arguments */
1189         if ((!xdr_int(&z_xdrs, &z_op))
1190              || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
1191                 z_result = RXGEN_CC_MARSHAL;
1192                 goto fail;
1193         }
1194
1195         /* Un-marshal the reply arguments */
1196         z_xdrs.x_op = XDR_DECODE;
1197         if ((!xdr_long(&z_xdrs, nentries))
1198              || (!xdr_bulkentries(&z_xdrs, bulkentries_1))) {
1199                 z_result = RXGEN_CC_UNMARSHAL;
1200                 goto fail;
1201         }
1202
1203         z_result = RXGEN_SUCCESS;
1204     fail:
1205         return rx_EndCall(z_call, z_result);
1206     }
1207
1208     int VL_LinkedList(z_conn, attributes, nentries, linkedentries)
1209         register struct rx_connection *z_conn;
1210         VldbListByAttributes * attributes;
1211         long * nentries;
1212         vldb_list * linkedentries;
1213     {
1214         struct rx_call *z_call = rx_NewCall(z_conn);
1215         static int z_op = 512;
1216         int z_result;
1217         XDR z_xdrs;
1218
1219         xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
1220
1221         /* Marshal the arguments */
1222         if ((!xdr_int(&z_xdrs, &z_op))
1223              || (!xdr_VldbListByAttributes(&z_xdrs, attributes))) {
1224                 z_result = RXGEN_CC_MARSHAL;
1225                 goto fail;
1226         }
1227
1228         /* Un-marshal the reply arguments */
1229         z_xdrs.x_op = XDR_DECODE;
1230         if ((!xdr_long(&z_xdrs, nentries))
1231              || (!xdr_vldb_list(&z_xdrs, linkedentries))) {
1232                 z_result = RXGEN_CC_UNMARSHAL;
1233                 goto fail;
1234         }
1235
1236         z_result = RXGEN_SUCCESS;
1237     fail:
1238         return rx_EndCall(z_call, z_result);
1239     }
1240
1241 Notice the side effect of the C<multi> feature (three different modules
1242 for C<ReplaceEntry> proc).
1243
1244 =head3 Server-Side stub routines (vldbint.ss.c)
1245
1246     /* Machine generated file -- Do NOT edit */
1247
1248     #include <rx/xdr.h>
1249     #include <rx/rx.h>
1250     #include <afs/rxgen_consts.h>
1251     #include "vldbint.h"
1252
1253     #include "vl_opcodes.h"  /* directly to other places */
1254
1255     long _VL_CreateEntry(z_call, z_xdrs)
1256         struct rx_call *z_call;
1257         XDR *z_xdrs;
1258     {
1259         long z_result;
1260         long Volid;
1261         vldbentry newentry;
1262
1263         if ((!xdr_long(z_xdrs, &Volid))
1264              || (!xdr_vldbentry(z_xdrs, &newentry))) {
1265                 z_result = RXGEN_SS_UNMARSHAL;
1266                 goto fail;
1267         }
1268
1269         z_result = VL_CreateEntry(z_call, Volid, &newentry);
1270     fail:
1271         return z_result;
1272     }
1273
1274     long _VL_GetEntryByName(z_call, z_xdrs)
1275         struct rx_call *z_call;
1276         XDR *z_xdrs;
1277     {
1278         long z_result;
1279         char *volumename = (char *)0;
1280         vldbentry entry;
1281
1282         if ((!xdr_string(z_xdrs, &volumename, 65))) {
1283                 z_result = RXGEN_SS_UNMARSHAL;
1284                 goto fail;
1285         }
1286
1287         z_result = VL_GetEntryByName(z_call, &volumename, &entry);
1288         z_xdrs->x_op = XDR_ENCODE;
1289         if ((!xdr_vldbentry(z_xdrs, &entry)))
1290                 z_result = RXGEN_SS_MARSHAL;
1291     fail:
1292         z_xdrs->x_op = XDR_FREE;
1293         if (!xdr_string(z_xdrs, &volumename, 65)) goto fail1;
1294         return z_result;
1295     fail1:
1296         return RXGEN_SS_XDRFREE;
1297     }
1298
1299     long _VL_GetNewVolumeId(z_call, z_xdrs)
1300         struct rx_call *z_call;
1301         XDR *z_xdrs;
1302     {
1303         long z_result;
1304         long bumpcount;
1305         long newvolumid;
1306
1307         if ((!xdr_long(z_xdrs, &bumpcount))) {
1308                 z_result = RXGEN_SS_UNMARSHAL;
1309                 goto fail;
1310         }
1311
1312         z_result = VL_GetNewVolumeId(z_call, bumpcount, &newvolumid);
1313         z_xdrs->x_op = XDR_ENCODE;
1314         if ((!xdr_long(z_xdrs, &newvolumid)))
1315                 z_result = RXGEN_SS_MARSHAL;
1316     fail:
1317         return z_result;
1318     }
1319
1320     long _VL_ReplaceEntry(z_call, z_xdrs)
1321         struct rx_call *z_call;
1322         XDR *z_xdrs;
1323     {
1324         long z_result;
1325         long Volid, voltype, ReleaseType;
1326         vldbentry newentry;
1327
1328         if ((!xdr_long(z_xdrs, &Volid))
1329              || (!xdr_long(z_xdrs, &voltype))
1330              || (!xdr_vldbentry(z_xdrs, &newentry))
1331              || (!xdr_long(z_xdrs, &ReleaseType))) {
1332                 z_result = RXGEN_SS_UNMARSHAL;
1333                 goto fail;
1334         }
1335
1336         z_result = VL_ReplaceEntry(z_call, Volid, voltype, &newentry,
1337                                    ReleaseType);
1338     fail:
1339         return z_result;
1340     }
1341
1342     long _VL_ListAttributes(z_call, z_xdrs)
1343         struct rx_call *z_call;
1344         XDR *z_xdrs;
1345     {
1346         long z_result;
1347         VldbListByAttributes attributes;
1348         long nentries;
1349         bulkentries bulkentries_1;
1350
1351         if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
1352                 z_result = RXGEN_SS_UNMARSHAL;
1353                 goto fail;
1354         }
1355
1356         z_result = VL_ListAttributes(z_call, &attributes, &nentries,
1357                                      &bulkentries_1);
1358         z_xdrs->x_op = XDR_ENCODE;
1359         if ((!xdr_long(z_xdrs, &nentries))
1360              || (!xdr_bulkentries(z_xdrs, &bulkentries_1)))
1361                 z_result = RXGEN_SS_MARSHAL;
1362     fail:
1363         z_xdrs->x_op = XDR_FREE;
1364         if (!xdr_bulkentries(z_xdrs, &bulkentries_1)) goto fail1;
1365         return z_result;
1366     fail1:
1367         return RXGEN_SS_XDRFREE;
1368     }
1369
1370     long _VL_LinkedList(z_call, z_xdrs)
1371         struct rx_call *z_call;
1372         XDR *z_xdrs;
1373     {
1374         long z_result;
1375         VldbListByAttributes attributes;
1376         long nentries;
1377         vldb_list linkedentries;
1378
1379         if ((!xdr_VldbListByAttributes(z_xdrs, &attributes))) {
1380                 z_result = RXGEN_SS_UNMARSHAL;
1381                 goto fail;
1382         }
1383
1384         z_result = VL_LinkedList(z_call, &attributes, &nentries,
1385                                  &linkedentries);
1386         z_xdrs->x_op = XDR_ENCODE;
1387         if ((!xdr_long(z_xdrs, &nentries))
1388              || (!xdr_vldb_list(z_xdrs, &linkedentries)))
1389                 z_result = RXGEN_SS_MARSHAL;
1390     fail:
1391         return z_result;
1392     }
1393
1394     long _VL_CreateEntry();
1395     long _VL_GetEntryByName();
1396     long _VL_GetNewVolumeId();
1397     long _VL_ReplaceEntry();
1398     long _VL_ListAttributes();
1399     long _VL_LinkedList();
1400
1401     static long (*StubProcsArray0[])() = {_VL_CreateEntry,
1402         _VL_GetEntryByName, _VL_GetNewVolumeId, _VL_ReplaceEntry,
1403         _VL_ListAttributes, _VL_LinkedList};
1404
1405     VL_ExecuteRequest(z_call)
1406         register struct rx_call *z_call;
1407     {
1408         int op;
1409         XDR z_xdrs;
1410         long z_result;
1411
1412         xdrrx_create(&z_xdrs, z_call, XDR_DECODE);
1413         if (!xdr_int(&z_xdrs, &op))
1414             z_result = RXGEN_DECODE;
1415         else if (op < VL_LOWEST_OPCODE || op > VL_HIGHEST_OPCODE)
1416             z_result = RXGEN_OPCODE;
1417         else
1418             z_result = (*StubProcsArray0[op - VL_LOWEST_OPCODE])
1419                 (z_call, &z_xdrs);
1420         return z_result;
1421     }
1422
1423 If there were gaps in the procedures' opcode sequence the code for
1424 VL_ExecuteRequest() routine would be have been drastically different (it
1425 would have been a case statement for each procedure).
1426
1427 =head1 NOTES
1428
1429 B<rxgen> is implemented from Sun's B<rpcgen> utility.  All of the standard
1430 B<rpcgen>'s functionality is fully maintained.  Note that some active
1431 B<rpcgen> options that don't apply to B<rxgen>'s purpose aren't referenced
1432 here (i.e., B<-s>, B<-l>, B<-m> options) and the interested reader should
1433 refer to rpcgen(1) for details.
1434
1435 When the C<%#include <include file>> feature is used make sure that you
1436 don't have any B<rxgen> language features (i.e. %#defines) since you'll
1437 get syntax errors during compilations..
1438
1439 Since this is an ongoing project many of the above may change/disappear
1440 without a major warning.
1441
1442 =head1 SEE ALSO
1443
1444 I<Rxgen Syntax Summary>: Summary description of rxgen's grammar.
1445
1446 I<Rpcgen Programming Guide>: Sun's RPC protocol compiler.  B<rxgen> was
1447 implemented as an extension to that compiler.
1448
1449 I<External Data Representation: Sun Technical Notes>: Detailed examples in
1450 using XDR.
1451
1452 I<RPCL Syntax Summary>: Summary of Sun's Remote Procedure Call Language.
1453
1454 I<Rx>: An extended Remote Procedure Call Protocol.
1455
1456 I<rgen>: An earlier version of a similar stub generator used for the R RPC
1457 protocol.
1458
1459 =head1 COPYRIGHT
1460
1461 IBM Corporation 2000. <http://www.ibm.com/> All Rights Reserved.
1462
1463 This documentation is covered by the IBM Public License Version 1.0.  It
1464 was converted from the original TeX B<rxgen> manual to POD by Russ
1465 Allbery.