[mod.sources] v06i099: Sun RPC Source

sources-request@mirror.UUCP (08/08/86)

Submitted by: cca!SUN.COM!marks (Mark Stein)
Mod.sources: Volume 6, Issue 99
Archive-name: rpc2/Part11

[  I have only verified that this unpacks correctly.  --r$  ]

Sun RPC source (part 11 of 11).  This software package contains code
and documentation for Revision 3.0 of the Sun Remote Procedure Call
library.  In addition, a beta version of the XDR/RPC protocol compiler
is included.  Comments about this latest release may be mailed to
sun!rpc or rpc@sun.com.

Sun RPC is a product of Sun Microsystems, Inc. and is provided for
unrestricted use provided that this legend is included on all tape
media and as a part of the software program in whole or part.  Users
may copy or modify Sun RPC without charge, but are not authorized to
license or distribute it to anyone else except as part of a product or
program developed by the user.

- - - - - - - - - C U T - H E R E - - - - - - - - - - - - - - - - - -
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	rpc/rpcgen/rpc_util.c
#	rpc/rpcgen/rpc_util.h
#	rpc/rpcgen/rpcgen.1
#	rpc/rpcgen/xdr_update.c
#	rpc/rpcgen/test/Makefile
#	rpc/rpcgen/test/demo_clnt.c
#	rpc/rpcgen/test/demo_proc.c
#	rpc/rpcgen/test/demo_xdr.x
# This archive created: Mon Jul 14 16:55:53 1986
export PATH; PATH=/bin:/usr/bin:$PATH
for d in rpc rpc/doc rpc/rpclib rpc/tools rpc/toys rpc/rpclib/profiled rpc/rpcgen rpc/rpcgen/test
do
	if test ! -d $d
	then
		echo "shar: Making directory $d"
		mkdir $d
		chmod 755 $d
	fi
done
echo shar: "extracting 'rpc/rpcgen/rpc_util.c'" '(4145 characters)'
if test -f 'rpc/rpcgen/rpc_util.c'
then
	echo shar: "will not over-write existing file 'rpc/rpcgen/rpc_util.c'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/rpcgen/rpc_util.c'
X#ifndef lint 
Xstatic char sccsid[] = "@(#)rpc_util.c 1.1 86/03/26 (C) 1986 SMI";
X#endif
X 
X/*
X * rpc_util.c, Utility routines for the RPC protocol compiler
X * Copyright (C) 1986, Sun Microsystems, Inc.
X */
X#include <stdio.h>
X#include "rpc_scan.h"
X#include "rpc_util.h"
X
Xchar curline[MAXLINESIZE];		/* current read line */
Xchar *where = curline;			/* current point in line */
Xint linenum = 0;				/* current line number */
X
Xchar *infile;	/* input filename */
Xchar *outfile;  /* output filename */
Xchar *outfile2; /* possible other output filename */
X
XFILE *fout;		/* file pointer of current output */
XFILE *fin;		/* file pointer of current input */
X
Xlist *printed;	/* list of printed routines */
Xlist *defined;  /* list of defined things */
X
X/*
X * Reinitialize the world
X */
Xreinitialize()
X{
X	bzero(curline,MAXLINESIZE);
X	where = curline;
X	linenum = 0;
X	printed = NULL;
X	defined = NULL;
X}
X
X/*
X * string equality
X */
Xstreq(a,b)
X	char *a;
X	char *b;
X{
X	return(strcmp(a,b) == 0);
X}
X
X/*
X * find a value in a list
X */
Xchar *
Xfindval(lst,val,cmp)
X	list *lst;
X	char *val;
X	int (*cmp)();
X{
X	for (; lst != NULL; lst = lst->next) {
X		if ((*cmp)(lst->val,val)) {
X			return(lst->val);
X		}
X	}    
X	return(NULL);
X}
X
X/*
X * store a value in a list
X */
Xvoid
Xstoreval(lstp,val)
X	list **lstp;
X	char *val;
X{
X	list **l;
X	list *lst;
X
X	for (l = lstp; *l != NULL; l = (list **) &(*l)->next) 
X		;
X	lst = ALLOC(list);
X	lst->val = val;
X	lst->next = NULL;
X	*l = lst;
X}
X
X
X/*
X * print a useful (?) error message, and then die
X */
Xvoid
Xerror(msg)
X	char *msg;
X{
X	extern char *outfile;
X
X	printwhere();
X	fprintf(stderr,"%s, line %d: ",infile ? infile : "<stdin>", linenum);
X	fprintf(stderr,"%s\n",msg);
X	crash();
X}
X
X/*
X * Something went wrong, unlink any files
X * that we may have created and then die.
X */
Xcrash()
X{
X	if (outfile) {
X		unlink(outfile);
X	}	
X	if (outfile2) {
X		unlink(outfile2);
X	}
X	exit(1);
X}
X
X
X
Xstatic char expectbuf[100];
Xstatic char *toktostr();
X
X/*
X * error, token encountered was not the expected one
X */
Xvoid
Xexpected1(exp1)
X	tok_kind exp1;
X{
X	sprintf(expectbuf,"expected '%s'",
X		toktostr(exp1));
X	error(expectbuf);
X}
X
X/*
X * error, token encountered was not one of two expected ones
X */
Xvoid
Xexpected2(exp1,exp2)
X	tok_kind exp1,exp2;
X{
X	sprintf(expectbuf,"expected '%s' or '%s'",
X		toktostr(exp1),
X		toktostr(exp2));
X	error(expectbuf);
X}
X
X/*
X * error, token encountered was not one of 3 expected ones
X */
Xvoid
Xexpected3(exp1,exp2,exp3)
X	tok_kind exp1,exp2,exp3;
X{
X	sprintf(expectbuf,"expected '%s', '%s' or '%s'",
X		toktostr(exp1),
X		toktostr(exp2),
X		toktostr(exp3));
X	error(expectbuf);
X}
X
X
X
Xstatic token tokstrings[] = {
X	{ TOK_IDENT, "identifier" },
X	{ TOK_CONST, "constant" },
X	{ TOK_RPAREN, ")" },
X	{ TOK_LPAREN, "(" },
X	{ TOK_RBRACE, "}" },
X	{ TOK_LBRACE, "{" },
X	{ TOK_LBRACKET, "[" },
X	{ TOK_RBRACKET, "]" },
X	{ TOK_STAR, "*" },
X	{ TOK_COMMA, "," },
X	{ TOK_EQUAL, "=" },
X	{ TOK_COLON, ":" },
X	{ TOK_SEMICOLON, ";" },
X	{ TOK_UNION, "union" },
X	{ TOK_STRUCT, "struct" },
X	{ TOK_SWITCH, "switch" },
X	{ TOK_CASE,	"case" },
X	{ TOK_DEFAULT, "default" },
X	{ TOK_ENUM, "enum" },
X	{ TOK_ARRAY, "array" },
X	{ TOK_TYPEDEF, "typedef" },
X	{ TOK_INT, "int" },
X	{ TOK_SHORT, "short" },
X	{ TOK_LONG, "long" },
X	{ TOK_UNSIGNED, "unsigned" },
X	{ TOK_DOUBLE, "double" },
X	{ TOK_FLOAT, "float" },
X	{ TOK_CHAR, "char" },
X	{ TOK_STRING, "string" },
X	{ TOK_OPAQUE, "opaque" },
X	{ TOK_BOOL, "bool" },
X	{ TOK_VOID, "void" },
X	{ TOK_PROGRAM, "program" },
X	{ TOK_VERSION, "version" },
X	{ TOK_EOF, "??????" }
X};
X 
Xstatic char * 
Xtoktostr(kind) 
X	tok_kind kind; 
X{ 
X	token *sp;
X
X	for (sp = tokstrings; sp->kind != TOK_EOF && sp->kind != kind; sp++)
X		; 
X	return(sp->str); 
X}
X
X
Xstatic 
Xprintbuf()
X{
X	char c;
X	int i;
X	int cnt;
X
X#	define TABSIZE 4
X
X	for (i = 0; c = curline[i]; i++) {
X		if (c == '\t') {
X			cnt = 8 - (i % TABSIZE);
X			c = ' ';
X		} else {
X			cnt = 1;
X		}
X		while (cnt--) {	
X			putc(c,stderr);
X		} 
X	}
X}
X
X
Xstatic
Xprintwhere()
X{
X	int i;
X	char c;
X	int cnt;
X
X	printbuf();
X	for (i = 0; i < where - curline; i++) {
X		c = curline[i];
X		if (c == '\t') {
X			cnt = 8 - (i % TABSIZE);
X		} else {
X			cnt = 1;
X		}
X		while (cnt--) {
X			putc('^',stderr);
X		}
X	}
X	putc('\n',stderr);
X}
SHAR_EOF
if test 4145 -ne "`wc -c < 'rpc/rpcgen/rpc_util.c'`"
then
	echo shar: "error transmitting 'rpc/rpcgen/rpc_util.c'" '(should have been 4145 characters)'
fi
chmod 444 'rpc/rpcgen/rpc_util.c'
fi
echo shar: "extracting 'rpc/rpcgen/rpc_util.h'" '(1202 characters)'
if test -f 'rpc/rpcgen/rpc_util.h'
then
	echo shar: "will not over-write existing file 'rpc/rpcgen/rpc_util.h'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/rpcgen/rpc_util.h'
X/* @(#)rpc_util.h 1.1 86/03/26 (C) 1986 SMI */
X
X/*
X * rpc_util.h, Useful definitions for the RPC protocol compiler
X * Copyright (C) 1986, Sun Microsystems, Inc.
X */
X
Xextern char *malloc();
Xextern char *sprintf();
X#define alloc(size)		malloc((unsigned)(size))
X#define ALLOC(object)   (object *) malloc(sizeof(object)) 
X
X#define OFF 0
X#define ON 1
X
Xstruct list {
X	char *val;
X	struct list *next;
X};
Xtypedef struct list list;
X
X/*
X * Global variables
X */
X#define MAXLINESIZE 1024
Xextern char curline[MAXLINESIZE];
Xextern char *where;
Xextern int linenum;
X
Xextern char *outfile;
Xextern char *outfile2;
Xextern char *infile;
Xextern FILE *fout;
Xextern FILE *fin;
X
Xextern list *printed;
Xextern list *defined;
X
X
X/*
X * rpc_util routines
X */
Xvoid storeval();
X#define STOREVAL(list,item)	\
X	storeval(list,(char *)item)
X
Xchar *findval();
X#define FINDVAL(list,item,finder) \
X	findval(list, (char *) item, finder)
X
Xint streq();
Xvoid error();
Xvoid expected1();
Xvoid expected2();
Xvoid expected3();
X
X/*
X * rpc_cout routines
X */
Xvoid cprint();
Xvoid emit();
X
X/*
X * rpc_hout routines
X */
Xvoid print_datadef();
Xvoid print_funcdefs();
X
X/*
X * rpc_svcout routines
X */
Xvoid write_most();
Xvoid write_register();
Xvoid write_rest();
X
SHAR_EOF
if test 1202 -ne "`wc -c < 'rpc/rpcgen/rpc_util.h'`"
then
	echo shar: "error transmitting 'rpc/rpcgen/rpc_util.h'" '(should have been 1202 characters)'
fi
chmod 444 'rpc/rpcgen/rpc_util.h'
fi
echo shar: "extracting 'rpc/rpcgen/rpcgen.1'" '(11239 characters)'
if test -f 'rpc/rpcgen/rpcgen.1'
then
	echo shar: "will not over-write existing file 'rpc/rpcgen/rpcgen.1'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/rpcgen/rpcgen.1'
X.\" @(#)rpcgen.1 1.1 86/04/15 SMI
X.TH RPCGEN 1 "11 March 1986"
X.SH NAME
Xrpcgen \- an RPC protocol compiler
X.SH SYNOPSIS
X\fBrpcgen\fP \fB-h\fP \fB[-o \fIoutfile\fP]\fP \fB[\fIinputfile\fP]\fP
X.br
X\fBrpcgen\fP \fB-c\fP \fB[-o \fIoutfile\fP]\fP \fB[\fIinfile\fP]\fP 
X.br
X\fBrpcgen\fP \fIinfile\fP
X.br
X\fBrpcgen\fP \fB[-s \fItransport\fP]*\fP \fB[-o\fP \fIoutfile\fP]\fP \fB[\fIinfile\fP]\fP 
X.br
X.SH DESCRIPTION
X\fIrpcgen\fP is a tool that generates 
X.B C 
Xcode to implement an 
X.SM RPC
Xprotocol.  The input to \fIrpcgen\fP is a language with striking 
Xsimilarity to 
X.B C 
Xknown as RPCL (Remote Procedure Call Language).
X.I rpcgen 
Xoperates in four modes.  The first mode is used to convert
XRPCL definitions into 
X.B C 
Xdefinitions for use as a header file.
XThe second mode compiles the XDR routines required to serialize the protocol
Xdescribed by RPCL.  The third mode compiles both, leaving the
Xheader file in a file named \fIinfile\fP with a 
X.B .h 
Xextension and the XDR routines in \fIinfile\fP with a 
X.B .c 
Xextension.  The fourth mode is used to compile an RPC server skeleton, so that 
Xall you have to do is write local procedures that know nothing about RPC
Xin order to implement an RPC server.
X.LP
XThe input may contain 
X.BR C -style 
Xcomments and preprocessor directives.  Comments are ignored, while the 
Xdirectives are simply stuffed uninterpreted in the output header file. 
X.LP
XYou can customize some of your XDR routines by leaving those data
Xtypes undefined.  For every data type that is undefined, \fIrpcgen\fP 
Xwill assume that there exists a routine with the name `xdr_' prepended
Xto the name of the undefined type. 
X.SH OPTIONS
X.IP \fB-c\fP
XCompile XDR routines.
X.IP \fB-h\fP
XCompile 
X.B C 
Xdata-definitions (a header file)
X.IP "\fB-o\fP \fIoutfile\fP"
XSpecify the name of the output file.  If none is specified, standard
Xoutput is used (\fB-c\fP, \fB-h\fP and \fB-s\fP modes only).
X.IP "\fB-s\fP \fItransport\fP"
XCompile a server, using the the given transport.  The supported transports
Xare \fBudp\fP and \fBtcp\fP. This option may be invoked more than once
Xso as to compile a server that serves multiple transports.
X.SH USAGE
X.SS "RPCL Syntax Summary"
XThis summary of RPCL syntax, which is used for 
X.I rpcgen 
Xinput, is intended more for aiding 
Xcomprehension than as an exact statement of the language.
X.SS "Primitive Data Types"
X.RS
X.nf
X[ \fBunsigned\fP ] \fBchar\fP
X[ \fBunsigned\fP ] \fBshort\fP
X[ \fBunsigned\fP ] \fBint\fP
X[ \fBunsigned\fP ] \fBlong\fP
X\fBunsigned\fP
X\fBfloat\fP
X\fBdouble\fP
X\fBvoid\fP
X\fBbool\fP
X.fi
X.RE
XExcept for the added boolean data-type \fBbool\fP,
XRPCL is identical to 
X.BR C .
X\fIrpcgen\fP converts \fBbool\fP declarations to \fBint\fP declarations in the 
Xoutput header file (literally it is converted to a \fBbool_t\fP, which has been
X\fB#define\fP'd to be an \fBint\fP). Also, \fBvoid\fP declarations
Xmay appear only inside of 
X.B union 
Xand 
X.B program 
Xdefinitions.  For those averse to typing the prefix 
X\fBunsigned\fP, the abbreviations \fBu_char\fP, \fBu_short\fP, \fBu_int\fP and 
X\fBu_long\fP are available. 
X.SS Declarations
XRPCL allows only three kinds of declarations:
X.LP
X\fIdeclaration:\fP
X.RS
X.nf
X\fIsimple-declaration\fP
X\fIpointer-declaration\fP
X\fIvector-declaration\fP
X.fi
X.RE
X.LP
X\fIsimple-declaration:\fP
X.RS
X\fItype-name\fP \fIobject-ident\fP
X.RE
X.LP	
X\fIpointer-declaration:\fP
X.RS
X\fItype-name\fP \fB*\fP\fIobject-ident\fP
X.RE
X.LP
X\fIvector-declaration:\fP
X.RS
X\fItype-name\fP \fIobject-ident\fP\fB[\fP\fIsize\fP\fB]\fP
X.RE
X.LP 
X(\fIsize\fP can be either an integer or a symbolic constant)
X.RE
X.LP
XRPCL declarations contain both limitations and extensions with
Xrespect to 
X.BR C .  
XThe limitations are that you cannot declare
Xmultidimensional arrays or pointers-to-pointers in-line (You
Xcan still declare them though, using \fBtypedef\fP). There
Xare two extensions:
X.LP
X.RS
XOpaque data is declared as a vector as follows:
X.LP
X.RS
X\fBopaque\fP \fIobject-ident\fP \fB[\fP \fIsize\fP \fB]\fP
X.RE
X.LP
XIn the protocol, this results in an object of \fIsize\fP bytes. Note that
Xthis is \fInot\fP the same as a declaration of \fIsize\fP characters, 
Xsince XDR characters are 32-bits. Opaque declarations are compiled in the
Xoutput header file into character array declarations of \fIsize\fP bytes.
X.LP
XStrings are special and are declared as a vector declaration:
X.LP
X.RS
X\fBstring\fP \fIobject-ident\fP \fB[\fP \fImax-size\fP \fB]\fP
X.RE
X.LP
XIf \fImax-size\fP is unspecified, then there is essentially no limit to
Xthe maximum length of the string. String declarations get compiled into
Xthe following:
X.LP
X.RS
Xchar *\fIobject-ident\fP
X.RE
X.RE
X.RE
X.SS "Type Definitions"
XThe only way to generate an XDR routine is to define a type. For
Xevery type \fIzetype\fP you define, there is a corresponding
XXDR routine named \fIxdr_zetype\fP.  
X.LP
XThere are six ways to define a type:
X.LP
X\fItype-definition:\fP
X.RS
X.nf
X\fItypedef\fP
X\fIenumeration-def\fP
X\fIstructure-def\fP
X\fIvariable-length-array-def\fP
X\fIdiscriminated-union-def\fP
X\fIprogram-def\fP
X.fi
X.RE
X.LP
XThe first three are very similar to their 
X.B C 
Xnamesakes. 
X.B C 
Xdoes not have a formal type mechanism to define variable-length arrays and
XXDR unions are quite different from their 
X.B C 
Xcounterparts. Program definitions are not really type definitions, 
Xbut they are useful nonetheless.
X.LP
XYou may not nest XDR definitions.  For example, the following will 
Xcause \fIrpcgen\fP to choke:
X.RS
X.nf
Xstruct dontdoit {
X	struct ididit {
X		int oops;
X	} sorry;
X	enum ididitagain { OOPS, WHOOPS } iapologize;
X};
X.fi
X.RE
X.SS \fRTypedefs
XAn XDR \fBtypedef\fP looks as follows:
X.LP
X\fItypedef:\fP
X.RS
X\fBtypedef\fP \fIdeclaration\fP \fB;\fP
X.RE
XThe \fIobject-ident\fP part of \fIdeclaration\fP is the name of the new type,
Xwhereas the \fItype-name\fP part is the name of the type from which it is
Xderived.
X.LP
X.SS "\fIEnumeration Types"
XThe syntax is:
X.LP
X\fIenumeration-def:\fP
X.RS
X\fBenum\fP \fIenum-ident\fP \fB{\fP
X.RS
X\fIenum-list\fP
X.RE
X\fB};\fP
X.RE
X.LP
X\fIenum-list:\fP
X.RS
X\fIenum-symbol-ident\fP [ \fB=\fP \fIassignment\fP ]
X.br
X\fIenum-symbol-ident\fP [ \fB=\fP \fIassignment\fP ] \fB,\fP \fIenum-list\fP
X.RE
X.LP
X(\fIassignment\fP may be either an integer or a symbolic constant)
X.LP
XIf there is no explicit assignment, then the implicit assignment is the
Xvalue of the previous enumeration plus 1.  If not explicitly assigned,
Xthe first enumeration receives the value 0.
X.SS \fIStructures
X\fIstructure-def:\fP
X.RS
X\fBstruct\fP \fIstruct-ident\fP \fB{\fP
X.RS
X\fIdeclaration-list\fP
X.RE
X\fB};\fP
X.RE
X.LP
X\fIdeclaration-list:\fP
X.RS
X\fIdeclaration\fP \fB;\fP
X.br
X\fIdeclaration\fP \fB;\fP \fIdeclaration-list\fP
X.RE
X.RE
X.LP
X.SS "\fIVariable-Length Arrays"
X\fIvariable-length-array-def:\fP
X.RS
X\fBarray\fP \fIarray-ident\fP \fB{\fP
X.RS
X\fBunsigned\fP \fIlength-identifer\fP \fB;\fP
X.br
X\fIvector-declaration\fP \fB;\fP
X.RE
X\fB};\fP
X.RE
X.LP	
XA variable length array definition looks much like a structure 
Xdefinition. Here's an example:
X.RS
X.nf
Xarray mp_int {
X	unsigned len;
X	short val[MAX_MP_LENGTH];
X};
X.fi
X.RE
XThis is compiled into:
X.RS
X.nf
Xstruct mp_int {
X	unsigned len;
X	short *val;
X};
Xtypedef struct mp_int mp_int;
X.fi
X.RE
X.SS "\fIDisriminated Unions"
X\fIdiscriminated-union-def:\fP
X.RS
X\fBunion\fP \fIunion-ident\fP \fBswitch\fP \fB(\fP \fIdiscriminant-declaration\fP \fB)\fP \fB{\fP
X.RS
X\fIcase-list\fP
X.br
X[ \fBdefault\fP \fB:\fP \fIdeclaration\fP \fB;\fP ]
X.RE
X\fB};\fP
X.RE
X.LP
X\fIcase-list:\fP
X.RS
X\fBcase\fP \fIcase-ident\fP \fB:\fP \fIdeclaration\fP \fB;\fP
X.br
X\fBcase\fP \fIcase-ident\fP \fB:\fP \fIdeclaration\fP \fB;\fP \fIcase-list\fP
X.RE
X.LP
X\fIdiscriminant-declaration:\fP
X.RS
X\fIdeclaration\fP
X.RE
X.LP
XThe union definition looks like a cross between a C-union and a C-switch.
XAn example:
X.RS
X.nf
Xunion net_object switch (net_kind kind) {
Xcase MACHINE:
X	struct sockaddr_in sin;
Xcase USER:
X	int uid;
Xdefault:
X	string whatisit;
X};
X.fi
X.RE
XCompiles into:
X.RS
X.nf
Xstruct net_object {
X	net_kind kind;
X	union {
X		struct sockaddr_in sin;
X		int uid;
X		char *whatisit;
X	} net_object;
X};
Xtypedef struct net_object net_object;
X.fi
X.RE
XNote that the name of the union component of the output struct is the
Xsame as the name of the type itself.
X.SS "\fIProgram Definitions"
X\fIprogram-def:\fP
X.RS
X\fBprogram\fP \fIprogram-ident\fP \fB{\fP
X.RS
X\fIversion-list\fP
X.RE
X\fB}\fP \fB=\fP \fIprogram-number\fP \fB;\fP
X.RE
X.LP
X\fIversion-list:\fP
X.RS
X\fIversion\fP
X.br
X\fIversion\fP \fIversion-list\fP
X.RE
X\fIversion:\fP
X.RS
X\fBversion\fP \fIversion-ident\fP \fB{\fP
X.RS
X\fIprocedure-list\fP
X.RE
X\fB} =\fP \fIversion-number\fP \fB;\fP
X.RE
X\fIprocedure-list:\fP
X.RS
X\fIprocedure-declaration\fP
X.br
X\fIprocedure-declaration procedure-list\fP
X.RE
X\fIprocedure-declaration:\fP
X.RS
X\fItype-name\fP \fIprocedure-ident\fP \fB(\fP \fItype-name\fP \fB)\fP \fB=\fP \fIprocedure-number\fP \fB;\fP
X.RE
X.LP
XProgram definitions look like nothing you've ever seen before, so we
Xturn to an example to explain them.  Suppose you wanted to create server
Xthat could get or set the date. It's declaration might look like this:
X.RS
X.nf
Xprogram DATE_PROG {
X	version DATE_VERS {
X		date DATE_GET(timezone) = 1;
X		void DATE_SET(date) = 2;	/* Greenwich mean time */
X	} = 1;
X} = 100;
X.fi
X.RE
XIn the header file, this compiles into the following:
X.RS
X.nf
X#define DATE_PROG 100
X#define DATE_VERS 1
X#define DATE_GET 1
X#define DATE_SET 2
X.fi
X.RE
XThese \fBdefine\fP's are intended for use by the client program to 
Xreference the remote procedures. 
X.LP
XIf you are using \fIrpcgen\fP to compile your server, then there are
Xsome important things for you to know. The server interfaces to
Xyour local procedures by expecting a 
X.B C 
Xfunction with the same name as that in the program definition, but in all 
Xlower-case letters and followed by the version number.  Here is the local 
Xprocedure that implements DATE_GET:
X.RS
X.nf
Xdate *	/* always returns a pointer to the results */
Xdate_get_1(tz)	
X	timezone *tz;	/* always takes a a pointer to the arguments */
X{
X	static date d;	/* must be static! */
X	
X	/* 
X	 * figure out the date
X	 * and store it in d
X	 */
X	return(&d);	
X}
X.fi
X.RE
XThe name of the routine is the same as the \fB#define\fP'd name, but in all 
Xlower case letters and followed by the version number. XDR will recursively 
Xfree the argument after getting the 
Xresults from your local procedure, so you should copy from the argument 
Xany data that you will need between calls. However, XDR neither allocates 
Xnor frees your results. You must take care of their storage yourself.
X.LP
X.SS "Make Inference Rules For Compiling XDR Headers"
X.LP
XIt is possible to set up suffix transformation rules in 
X.IR make  (1)
Xfor compiling XDR routines and header files.  The 
Xconvention is that RPCL protocol files have the extension 
X.BR .x .  
XThe \fImake\fP rules to do this are:
X.nf
X	.SUFFIXES: .x
X	.x.c: 
X		rpcgen -c $< -o $@
X
X	.x.h:
X		rpcgen -h $< -o $@
X.fi
X.SH "SEE ALSO"
X\fIRemote Procedure Call: Programming Guide\fP 
Xand \fIExternal Data Representation: Protocol Specification\fP 
Xin\fI Networking on the Sun Workstation\fP
X.SH BUGS
XName clashes can occur when using program definitions, since the apparent
Xscoping does not really apply. Most of these can be avoided by giving 
Xunique names for programs, versions, procedures and types.
SHAR_EOF
if test 11239 -ne "`wc -c < 'rpc/rpcgen/rpcgen.1'`"
then
	echo shar: "error transmitting 'rpc/rpcgen/rpcgen.1'" '(should have been 11239 characters)'
fi
chmod 444 'rpc/rpcgen/rpcgen.1'
fi
echo shar: "extracting 'rpc/rpcgen/xdr_update.c'" '(1993 characters)'
if test -f 'rpc/rpcgen/xdr_update.c'
then
	echo shar: "will not over-write existing file 'rpc/rpcgen/xdr_update.c'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/rpcgen/xdr_update.c'
X/*
X * xdr_update.c: Additions to release 3.0 XDR routines required
X *	for rpcgen.  These routines are from release 3.2BETA and
X *	may be updated before final release.
X *
X * Copyright (C) 1986, Sun Microsystems, Inc.
X *
X */
X
X#include <rpc/rpc.h>
X#define NULL 0
X#define LASTUNSIGNED	((u_int)0-1)
X
X/*
X * xdr_pointer():
X *
X * XDR a pointer to a possibly recursive data structure. This
X * differs with xdr_reference in that it can serialize/deserialiaze
X * trees correctly.
X *
X *  What's sent is actually a union:
X *
X *  union object_pointer switch (boolean b) {
X *  case TRUE: object_data data;
X *  case FALSE: void nothing;
X *  }
X *
X * > objpp: Pointer to the pointer to the object.
X * > obj_size: size of the object.   
X * > xdr_obj: routine to XDR an object.
X *    
X */
Xbool_t                        
Xxdr_pointer(xdrs,objpp,obj_size,xdr_obj)
X        register XDR *xdrs;
X        char **objpp;
X        u_int obj_size;
X        xdrproc_t xdr_obj;
X{                      
X                       
X        bool_t more_data;
X                
X        more_data = (*objpp != NULL);
X        if (! xdr_bool(xdrs,&more_data)) {
X                return(FALSE);
X        }
X        if (! more_data) {
X                *objpp = NULL;
X                return(TRUE);
X        }
X        return(xdr_reference(xdrs,objpp,obj_size,xdr_obj));
X}
X
X/*
X * xdr_vector():
X *
X * XDR a fixed length array. Unlike variable-length arrays,
X * the storage of fixed length arrays is static and unfreeable.
X * > basep: base of the array
X * > size: size of the array
X * > elemsize: size of each element
X * > xdr_elem: routine to XDR each element
X */
Xbool_t
Xxdr_vector(xdrs, basep, nelem, elemsize, xdr_elem)
X	register XDR *xdrs;
X	register char *basep;
X	register u_int nelem;
X	register u_int elemsize;
X	register xdrproc_t xdr_elem;	
X{
X	register u_int i;
X	register char *elptr;
X
X	elptr = basep;
X	for (i = 0; i < nelem; i++) {
X		if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) {
X			return(FALSE);
X		}
X		elptr += elemsize;
X	}
X	return(TRUE);	
X}
SHAR_EOF
if test 1993 -ne "`wc -c < 'rpc/rpcgen/xdr_update.c'`"
then
	echo shar: "error transmitting 'rpc/rpcgen/xdr_update.c'" '(should have been 1993 characters)'
fi
chmod 664 'rpc/rpcgen/xdr_update.c'
fi
echo shar: "extracting 'rpc/rpcgen/test/Makefile'" '(1274 characters)'
if test -f 'rpc/rpcgen/test/Makefile'
then
	echo shar: "will not over-write existing file 'rpc/rpcgen/test/Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/rpcgen/test/Makefile'
X#  Makefile for the demo rpc service for rpcgen
X#
X#  There are three source files used by this makefile:
X#	demo_xdr.x	Demo protocol specification used as input
X#			by rpcgen to generate demo_xdr.h (xdr
X#			defines and data type decarations),
X#			demo_xdr.c (xdr data type routines),
X#			and demo.c (server program shell)
X#	demo_proc.c	The actual procedure handlers for the server.
X#	demo_clnt.c	The client program.
X
X.SUFFIXES: .x .c .h .o
XCC = cc
X
X# REL3_0 should be defined in CFLAGS if using a pre-3.2 rpc library
XCFLAGS = -DREL3_0
X
XRPCGEN = ../rpcgen
XPROTO = udp
X
XSOBJS = demo.o demo_proc.o demo_xdr.o 
XCOBJS = demo_clnt.o demo_xdr.o 
X
X# RPCLIB should be the rpc library, or commented out if included in libc.
X# xdr_update.o should be included if linking with a pre-3.2 rpc library.
X#RPCLIB = -lrpc
XRPCLIB = ../xdr_update.o
X
X.x.c:
X	$(RPCGEN) -c $< -o $@
X.x.h:
X	$(RPCGEN) -h $< -o $@
X
Xall: demo_svr demo_clnt
X
Xdemo_svr: $(SOBJS)
X	$(CC) $(CFLAGS) -o $@ $(SOBJS) $(RPCLIB)
X
Xdemo_clnt: $(COBJS)
X	$(CC) $(CFLAGS) -o $@ $(COBJS) $(RPCLIB)
X
Xdemo.c: demo_xdr.x demo_xdr.h
X	$(RPCGEN) -s $(PROTO) demo_xdr.x -o $@
X
Xdemo_xdr.c: demo_xdr.x
Xdemo_xdr.o: demo_xdr.c demo_xdr.h
Xdemo_proc.o: demo_xdr.h
Xdemo_clnt.o: demo_xdr.h
X
Xclean:
X	-rm -f *.o *.h demo_clnt demo_svr demo_xdr.c demo.c
SHAR_EOF
if test 1274 -ne "`wc -c < 'rpc/rpcgen/test/Makefile'`"
then
	echo shar: "error transmitting 'rpc/rpcgen/test/Makefile'" '(should have been 1274 characters)'
fi
chmod 664 'rpc/rpcgen/test/Makefile'
fi
echo shar: "extracting 'rpc/rpcgen/test/demo_clnt.c'" '(3254 characters)'
if test -f 'rpc/rpcgen/test/demo_clnt.c'
then
	echo shar: "will not over-write existing file 'rpc/rpcgen/test/demo_clnt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/rpcgen/test/demo_clnt.c'
X/*
X *  Client program for rpcgen demo
X */
X
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include "demo_xdr.h"
X
Xchar *Prog, *Host;
X
Xstruct Calls {
X	char	*name;			/* name of call */
X	enum ret_status arg_type;	/* arg type expected */
X	int	procno;			/* proc number */
X} Calls[] = {
X	{ "ctime",	RET_CLOCK,	CTIME		},
X	{ "localtime",	RET_CLOCK,	LOCALTIME	},
X	{ "gmtime",	RET_CLOCK,	GMTIME		},
X	{ "asctime",	RET_TM,		ASCTIME		},
X	{ "timezone",	RET_TZ,		TIMEZONE	},
X	{ "dysize",	RET_YEAR,	DYSIZE		},
X	{ NULL }
X};
X
Xchar	 *Arg;
Xdemo_res Res;
Xxdrproc_t Xargs, Xres;
X
Xmain(argc, argv)
Xchar **argv;
X{
X	struct Calls *callp;
X	int ret;
X
X	Prog = argv[0];
X	if (argc < 3)
X		usage();
X
X	for (callp = Calls; callp->name; callp++)
X		if (!strcmp(callp->name, argv[2]))
X			break;
X	if (callp->name == NULL) {
X		fprintf(stderr, "%s: call \"%s\" not recognized.\n",
X			Prog, argv[2]);
X		exit(1);
X	}
X	Host = argv[1];
X	argc -= 3; argv += 3;
X	getargs(argc, argv, callp);
X	Xres = xdr_demo_res;
X	if (ret = callrpc(Host, DEMOPROG, DEMOVERS, callp->procno,
X		Xargs, Arg, Xres, &Res))
X	{
X		fprintf(stderr, "%s: rpc failed: ", Prog);
X		clnt_perrno(ret);
X		fprintf(stderr, "\n");
X		exit(1);
X	}
X	printres(callp);
X}
X
Xgetargs(argc, argv, callp)
Xint argc;
Xchar **argv;
Xstruct Calls *callp;
X{
X	static long l_arg;
X	static timeval tv;
X	static tzargs tz_arg;
X
X	gettimeofday(&tv, &tz_arg);
X	switch (callp->arg_type) {
X	    case RET_CLOCK:
X		l_arg = (long)(argc > 0? atoi(argv[0]) : tv.tv_sec);
X		Arg = (char *)&l_arg;
X		Xargs = xdr_clock;
X		break;
X	    case RET_TM:
X		l_arg = (long)(argc > 0? atoi(argv[0]) : tv.tv_sec);
X		Arg = (char *)localtime(&l_arg);
X		Xargs = xdr_tm;
X		break;
X	    case RET_TZ:
X		if (argc == 1) {
X			fprintf(stderr, "\
X%s: call \"%s\" takes two arguments.\n", Prog, callp->name);
X			exit(1);
X		} else if (argc > 1) {
X			tz_arg.zone = atoi(argv[0]);
X			tz_arg.dst = atoi(argv[1]);
X		}
X		Arg = (char *)&tz_arg;
X		Xargs = xdr_tzargs;
X		break;
X	    case RET_YEAR:
X		l_arg = (argc > 0? atoi(argv[0]) : 1986);
X		Arg = (char *)&l_arg;
X		Xargs = xdr_int;
X		break;
X	    default:
X		fprintf(stderr, "%s: panic: unknown arg type %d\n",
X			Prog, callp->arg_type);
X		exit(1);
X	}
X}
X
Xprintres(callp)
Xstruct Calls *callp;
X{
X	switch (Res.which) {
X	    case RET_DATE:
X		printf("date from %s: %s\n", Host, Res.demo_res.date);
X		break;
X	    case RET_TM:
X#define TZP(x) Res.demo_res.tmp->tm_/**/x
X		printf("\
Xtime info from %s: sec=%d, min=%d, hour=%d, mday=%d, mon=%d,\n\
X                   year=%d, wday=%d, yday=%d, isdst=%d\n",
X			Host, TZP(sec), TZP(min), TZP(hour), TZP(mday),
X			TZP(mon), TZP(year), TZP(wday), TZP(yday), TZP(isdst));
X		break;
X	    case RET_STR:
X		printf("Return string from %s: %s\n", Host, Res.demo_res.str);
X		break;
X	    case RET_DAYS:
X		printf("Return from %s: %d days\n", Host, Res.demo_res.days);
X		break;
X	    case RET_ERROR:
X		printf("%s returned error %d (%s)\n", Host,
X			Res.demo_res.err.err_number,
X			Res.demo_res.err.err_text);
X		break;
X	    default:
X		printf("%s returned an unknown return type (%d)\n",
X			Host, Res.which);
X		break;
X	}
X}
X
Xusage()
X{
X	struct Calls *callp;
X
X	fprintf(stderr, "usage: %s host call [args]\n", Prog);
X	fprintf(stderr, "valid calls are:\n");
X	for (callp = Calls; callp->name; callp++)
X		fprintf(stderr, "\t%s\n", callp->name);
X	exit(1);
X}
SHAR_EOF
if test 3254 -ne "`wc -c < 'rpc/rpcgen/test/demo_clnt.c'`"
then
	echo shar: "error transmitting 'rpc/rpcgen/test/demo_clnt.c'" '(should have been 3254 characters)'
fi
chmod 664 'rpc/rpcgen/test/demo_clnt.c'
fi
echo shar: "extracting 'rpc/rpcgen/test/demo_proc.c'" '(833 characters)'
if test -f 'rpc/rpcgen/test/demo_proc.c'
then
	echo shar: "will not over-write existing file 'rpc/rpcgen/test/demo_proc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/rpcgen/test/demo_proc.c'
X/*
X *  Demo procedures
X */
X
X#include <stdio.h>
X#include <rpc/rpc.h>
X#include "demo_xdr.h"
Xstatic demo_res res;
X
Xdemo_res *
Xctime_5(arg)
Xclock *arg;
X{
X	res.which = RET_DATE;
X	res.demo_res.date = (date)ctime(arg);
X	return &res;
X}
X
Xdemo_res *
Xlocaltime_5(arg)
Xclock *arg;
X{
X	res.which = RET_TM;
X	res.demo_res.tmp = (tm *)localtime(arg);
X	return &res;
X}
X
Xdemo_res *
Xgmtime_5(arg)
Xclock *arg;
X{
X	res.which = RET_TM;
X	res.demo_res.tmp = (tm *)gmtime(arg);
X	return &res;
X}
X
Xdemo_res *
Xasctime_5(arg)
Xtm *arg;
X{
X	res.which = RET_DATE;
X	res.demo_res.date = (date)asctime(arg);
X	return &res;
X}
X
Xdemo_res *
Xtimezone_5(arg)
Xtzargs *arg;
X{
X	res.which = RET_STR;
X	res.demo_res.str = (str)timezone(arg->zone, arg->dst);
X	return &res;
X}
X
Xdemo_res *
Xdysize_5(val)
Xint *val;
X{
X	res.which = RET_DAYS;
X	res.demo_res.days = dysize(*val);
X	return &res;
X}
SHAR_EOF
if test 833 -ne "`wc -c < 'rpc/rpcgen/test/demo_proc.c'`"
then
	echo shar: "error transmitting 'rpc/rpcgen/test/demo_proc.c'" '(should have been 833 characters)'
fi
chmod 664 'rpc/rpcgen/test/demo_proc.c'
fi
echo shar: "extracting 'rpc/rpcgen/test/demo_xdr.x'" '(1834 characters)'
if test -f 'rpc/rpcgen/test/demo_xdr.x'
then
	echo shar: "will not over-write existing file 'rpc/rpcgen/test/demo_xdr.x'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/rpcgen/test/demo_xdr.x'
X/*
X *  This file defines the protocol to support a demo rpc
X *  service and is designed to be processed by the `rpcgen'
X *  protocol compiler.  The Sun ctime(3) routines are used
X *  as examples.  See the rpcgen manual page for more detailed
X *  information.
X */
X
X#ifdef REL3_0
X#ifndef NULL
X#       define NULL 0
X#endif
X#endif
X
X
X/*
X *  argument / result data types
X */
X
X#define DATELEN 26
Xtypedef string date[DATELEN];
X
X#define STRLEN 80
Xtypedef string str[STRLEN];
X
Xtypedef long clock;
X
Xstruct tm {
X	int tm_sec;
X	int tm_min;
X	int tm_hour;
X	int tm_mday;
X	int tm_mon;
X	int tm_year;
X	int tm_wday;
X	int tm_yday;
X	int tm_isdst;
X};
X
Xstruct timeval {
X	u_long	tv_sec;
X	long	tv_usec;
X};
X
Xstruct timez {
X	int	tz_minuteswest;
X	int	tz_dsttime;
X};
X
Xstruct tzargs {
X	int	zone;
X	int	dst;
X};
X
X
X/*
X *  There is one generic data type for the result.  This is implemented
X *  as a union switch.  The specific union element returned is specified
X *  by ret_status.
X */
X
Xenum ret_status {
X	RET_DATE, RET_TM, RET_STR, RET_DAYS, RET_CLOCK, RET_TZ, RET_YEAR,
X	RET_ERROR
X};
X
Xstruct ret_err {
X	int	err_number;
X	str	err_text;
X};
X
Xunion demo_res switch (ret_status which) {
X	case RET_DATE:
X		date	date;
X	case RET_TM:
X		tm	*tmp;
X	case RET_STR:
X		str	str;
X	case RET_DAYS:
X		int	days;
X	case RET_ERROR:
X		ret_err err;
X};
X
X
X/*
X *  This section declares the individual procedures which are supported
X *  by this protocol.  The program number and version numbers are
X *  arbitrary in this case.  Procedures correspond to the ctime(3)
X *  time routines.
X */
X
Xprogram DEMOPROG {
X    version DEMOVERS {
X	demo_res	/* date */	CTIME(clock)		= 1;
X	demo_res	/* tm   */	LOCALTIME(clock)	= 2;
X	demo_res	/* tm   */	GMTIME(clock)		= 3;
X	demo_res	/* date */	ASCTIME(tm)		= 4;
X	demo_res	/* str  */	TIMEZONE(tzargs)	= 5;
X	demo_res	/* days */	DYSIZE(int)		= 6;
X    } = 5;
X} = 123456;
SHAR_EOF
if test 1834 -ne "`wc -c < 'rpc/rpcgen/test/demo_xdr.x'`"
then
	echo shar: "error transmitting 'rpc/rpcgen/test/demo_xdr.x'" '(should have been 1834 characters)'
fi
chmod 664 'rpc/rpcgen/test/demo_xdr.x'
fi
exit 0
#	End of shell archive