The well-known parameters to main, argc and argv can be combined into a structure. An array of these structures can make up a history of commands. The declarations and XDR routines might look like Example A-9.
struct cmd { u_int c_argc; char **c_argv; }; #define ALEN 1000 /* args cannot be > 1000 chars */ #define NARGC 100 /* commands cannot have > 100 args */ struct history { u_int h_len; struct cmd *h_cmds; }; #define NCMDS 75 /* history is no more than 75 commands */ bool_t xdr_wrapstring(xdrs, sp) XDR *xdrs; char **sp; { return(xdr_string(xdrs, sp, ALEN)); } bool_t xdr_cmd(xdrs, cp) XDR *xdrs; struct cmd *cp; { return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC, sizeof (char *), xdr_wrapstring)); } bool_t xdr_history(xdrs, hp) XDR *xdrs; struct history *hp; { return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS, sizeof (struct cmd), xdr_cmd)); }
The most confusing part of this example is that the routine xdr_wrapstring() is needed to package the xdr_string() routine, because the implementation of xdr_array() passes only two parameters to the array element description routine; xdr_wrapstring() supplies the third parameter to xdr_string().
By now the recursive nature of the XDR library should be obvious. Let's continue with more constructed data types.