1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27/* All Rights Reserved */
28/*
29 * University Copyright- Copyright (c) 1982, 1986, 1988
30 * The Regents of the University of California
31 * All Rights Reserved
32 *
33 * University Acknowledgment- Portions of this document are derived from
34 * software developed by the University of California, Berkeley, and its
35 * contributors.
36 */
37
38/*
39 * rpc_clntout.c, Client-stub outputter for the RPC protocol compiler
40 */
41#include <stdio.h>
42#include <string.h>
43#include <rpc/types.h>
44#include "rpc_parse.h"
45#include "rpc_util.h"
46
47extern void pdeclaration(char *, declaration *, int, char *);
48extern void printarglist(proc_list *, char *, char *, char *);
49
50static void write_program(definition *);
51static void printbody(proc_list *);
52
53static char RESULT[] = "clnt_res";
54
55#define	DEFAULT_TIMEOUT 25	/* in seconds */
56
57void
58write_stubs(void)
59{
60	list *l;
61	definition *def;
62
63	f_print(fout,
64	    "\n/* Default timeout can be changed using clnt_control() */\n");
65	f_print(fout, "static struct timeval TIMEOUT = { %d, 0 };\n",
66	    DEFAULT_TIMEOUT);
67	for (l = defined; l != NULL; l = l->next) {
68		def = (definition *) l->val;
69		if (def->def_kind == DEF_PROGRAM) {
70			write_program(def);
71		}
72	}
73}
74
75static void
76write_program(definition *def)
77{
78	version_list *vp;
79	proc_list *proc;
80
81	for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
82		for (proc = vp->procs; proc != NULL; proc = proc->next) {
83			f_print(fout, "\n");
84			if (mtflag == 0) {
85				ptype(proc->res_prefix, proc->res_type, 1);
86				f_print(fout, "*\n");
87				pvname(proc->proc_name, vp->vers_num);
88				printarglist(proc, RESULT, "clnt", "CLIENT *");
89			} else {
90				f_print(fout, "enum clnt_stat \n");
91				pvname(proc->proc_name, vp->vers_num);
92				printarglist(proc, RESULT,  "clnt", "CLIENT *");
93
94			}
95			f_print(fout, "{\n");
96			printbody(proc);
97
98			f_print(fout, "}\n");
99		}
100	}
101}
102
103/*
104 * Writes out declarations of procedure's argument list.
105 * In either ANSI C style, in one of old rpcgen style (pass by reference),
106 * or new rpcgen style (multiple arguments, pass by value);
107 */
108
109/* sample addargname = "clnt"; sample addargtype = "CLIENT * " */
110
111void
112printarglist(proc_list *proc, char *result, char *addargname, char *addargtype)
113{
114	bool_t oneway = streq(proc->res_type, "oneway");
115	decl_list *l;
116
117	if (!newstyle) {
118		/* old style: always pass argument by reference */
119		if (Cflag) {	/* C++ style heading */
120			f_print(fout, "(");
121			ptype(proc->args.decls->decl.prefix,
122			    proc->args.decls->decl.type, 1);
123
124			if (mtflag) {	/* Generate result field */
125				f_print(fout, "*argp, ");
126				if (!oneway) {
127					ptype(proc->res_prefix,
128					    proc->res_type, 1);
129					f_print(fout, "*%s, ", result);
130				}
131				f_print(fout, "%s%s)\n",
132				    addargtype, addargname);
133			} else
134				f_print(fout, "*argp, %s%s)\n",
135				    addargtype, addargname);
136		} else {
137			if (!mtflag)
138				f_print(fout, "(argp, %s)\n", addargname);
139			else {
140				f_print(fout, "(argp, ");
141				if (!oneway) {
142					f_print(fout, "%s, ",
143					    result);
144				}
145				f_print(fout, "%s)\n",
146				    addargname);
147			}
148			f_print(fout, "\t");
149			ptype(proc->args.decls->decl.prefix,
150			    proc->args.decls->decl.type, 1);
151			f_print(fout, "*argp;\n");
152			if (mtflag && !oneway) {
153				f_print(fout, "\t");
154				ptype(proc->res_prefix, proc->res_type, 1);
155				f_print(fout, "*%s;\n", result);
156			}
157		}
158	} else if (streq(proc->args.decls->decl.type, "void")) {
159		/* newstyle, 0 argument */
160		if (mtflag) {
161			f_print(fout, "(");
162
163			if (Cflag) {
164				if (!oneway) {
165					ptype(proc->res_prefix,
166					    proc->res_type, 1);
167					f_print(fout, "*%s, ", result);
168				}
169				f_print(fout, "%s%s)\n",
170				    addargtype, addargname);
171			} else
172				f_print(fout, "(%s)\n", addargname);
173
174		} else
175		if (Cflag)
176			f_print(fout, "(%s%s)\n", addargtype, addargname);
177		else
178			f_print(fout, "(%s)\n", addargname);
179	} else {
180		/* new style, 1 or multiple arguments */
181		if (!Cflag) {
182			f_print(fout, "(");
183			for (l = proc->args.decls;  l != NULL; l = l->next)
184				f_print(fout, "%s, ", l->decl.name);
185			if (mtflag && !oneway)
186				f_print(fout, "%s, ", result);
187
188			f_print(fout, "%s)\n", addargname);
189			for (l = proc->args.decls; l != NULL; l = l->next) {
190				pdeclaration(proc->args.argname,
191				    &l->decl, 1, ";\n");
192			}
193			if (mtflag && !oneway) {
194				f_print(fout, "\t");
195				ptype(proc->res_prefix, proc->res_type, 1);
196				f_print(fout, "*%s;\n", result);
197			}
198
199		} else {	/* C++ style header */
200			f_print(fout, "(");
201			for (l = proc->args.decls; l != NULL; l = l->next) {
202				pdeclaration(proc->args.argname, &l->decl, 0,
203				    ", ");
204			}
205			if (mtflag && !oneway) {
206				ptype(proc->res_prefix, proc->res_type, 1);
207				f_print(fout, "*%s, ", result);
208
209			}
210			f_print(fout, "%s%s)\n", addargtype, addargname);
211		}
212	}
213
214	if (!Cflag)
215		f_print(fout, "\t%s%s;\n", addargtype, addargname);
216}
217
218
219
220static char *
221ampr(char *type)
222{
223	if (isvectordef(type, REL_ALIAS)) {
224		return ("");
225	} else {
226		return ("&");
227	}
228}
229
230static void
231printbody(proc_list *proc)
232{
233	decl_list *l;
234	bool_t args2 = (proc->arg_num > 1);
235	bool_t oneway = streq(proc->res_type, "oneway");
236
237	/*
238	 * For new style with multiple arguments, need a structure in which
239	 *  to stuff the arguments.
240	 */
241	if (newstyle && args2) {
242		f_print(fout, "\t%s", proc->args.argname);
243		f_print(fout, " arg;\n");
244	}
245	if (!oneway) {
246		if (!mtflag) {
247			f_print(fout, "\tstatic ");
248			if (streq(proc->res_type, "void")) {
249				f_print(fout, "char ");
250			} else {
251				ptype(proc->res_prefix, proc->res_type, 0);
252			}
253			f_print(fout, "%s;\n", RESULT);
254			f_print(fout, "\n");
255			f_print(fout,
256			    "\t(void) memset(%s%s, 0, sizeof (%s));\n",
257			    ampr(proc->res_type), RESULT, RESULT);
258
259		}
260		if (newstyle && !args2 &&
261		    (streq(proc->args.decls->decl.type, "void"))) {
262			/* newstyle, 0 arguments */
263
264			if (mtflag)
265				f_print(fout, "\t return ");
266			else
267				f_print(fout, "\t if ");
268
269			f_print(fout,
270			    "(clnt_call(clnt, %s,\n\t\t(xdrproc_t)xdr_void, ",
271			    proc->proc_name);
272			f_print(fout,
273			    "NULL,\n\t\t(xdrproc_t)xdr_%s, "
274			    "(caddr_t)%s%s,",
275			    stringfix(proc->res_type),
276			    (mtflag)?"":ampr(proc->res_type),
277			    RESULT);
278
279			if (mtflag)
280				f_print(fout, "\n\t\tTIMEOUT));\n");
281			else
282				f_print(fout,
283				    "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n");
284
285		} else if (newstyle && args2) {
286			/*
287			 * Newstyle, multiple arguments
288			 * stuff arguments into structure
289			 */
290			for (l = proc->args.decls;  l != NULL; l = l->next) {
291				f_print(fout, "\targ.%s = %s;\n",
292				    l->decl.name, l->decl.name);
293			}
294			if (mtflag)
295				f_print(fout, "\treturn ");
296			else
297				f_print(fout, "\tif ");
298			f_print(fout,
299			    "(clnt_call(clnt, %s,\n\t\t(xdrproc_t)xdr_%s",
300			    proc->proc_name, proc->args.argname);
301			f_print(fout,
302			    ", (caddr_t)&arg,\n\t\t(xdrproc_t)xdr_%s, "
303			    "(caddr_t)%s%s,",
304			    stringfix(proc->res_type),
305			    (mtflag)?"":ampr(proc->res_type),
306			    RESULT);
307			if (mtflag)
308				f_print(fout, "\n\t\tTIMEOUT));\n");
309			else
310				f_print(fout,
311				    "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n");
312		} else {		/* single argument, new or old style */
313			if (!mtflag)
314				f_print(fout,
315				    "\tif (clnt_call(clnt, "
316				    "%s,\n\t\t(xdrproc_t)xdr_%s, "
317				    "(caddr_t)%s%s,\n\t\t(xdrproc_t)xdr_%s, "
318				    "(caddr_t)%s%s,\n\t\tTIMEOUT) != "
319				    "RPC_SUCCESS) {\n",
320				    proc->proc_name,
321				    stringfix(proc->args.decls->decl.type),
322				    (newstyle ? "&" : ""),
323				    (newstyle ?
324				    proc->args.decls->decl.name :
325				    "argp"),
326				    stringfix(proc->res_type),
327				    ampr(proc->res_type),
328				    RESULT);
329			else
330				f_print(fout,
331				    "\treturn (clnt_call(clnt, "
332				    "%s,\n\t\t(xdrproc_t)xdr_%s, "
333				    "(caddr_t)%s%s,\n\t\t(xdrproc_t)xdr_%s, "
334				    "(caddr_t)%s%s,\n\t\tTIMEOUT));\n",
335				    proc->proc_name,
336				    stringfix(proc->args.decls->decl.type),
337				    (newstyle ? "&" : ""),
338				    (newstyle ?
339				    proc->args.decls->decl.name :
340				    "argp"),
341				    stringfix(proc->res_type), "",
342				    RESULT);
343		}
344		if (!mtflag) {
345			f_print(fout, "\t\treturn (NULL);\n");
346			f_print(fout, "\t}\n");
347
348			if (streq(proc->res_type, "void")) {
349				f_print(fout, "\treturn ((void *)%s%s);\n",
350				    ampr(proc->res_type), RESULT);
351			} else {
352				f_print(fout, "\treturn (%s%s);\n",
353				    ampr(proc->res_type), RESULT);
354			}
355		}
356	} else {
357		/* oneway call */
358		if (!mtflag) {
359			f_print(fout, "\tstatic enum clnt_stat ");
360			f_print(fout, "%s;\n", RESULT);
361			f_print(fout, "\n");
362			f_print(fout,
363			    "\t(void) memset(&%s, 0, sizeof (%s));\n",
364			    RESULT, RESULT);
365
366		}
367		if (newstyle && !args2 &&
368		    (streq(proc->args.decls->decl.type, "void"))) {
369			/* newstyle, 0 arguments */
370
371			if (mtflag)
372				f_print(fout, "\t return (");
373			else
374				f_print(fout, "\t if ((%s = ", RESULT);
375
376			f_print(fout,
377			    "clnt_send(clnt, %s,\n\t\t(xdrproc_t)xdr_void, ",
378			    proc->proc_name);
379			f_print(fout, "NULL)");
380
381			if (mtflag)
382				f_print(fout, ");\n");
383			else
384				f_print(fout, ") != RPC_SUCCESS) {\n");
385
386		} else if (newstyle && args2) {
387			/*
388			 * Newstyle, multiple arguments
389			 * stuff arguments into structure
390			 */
391			for (l = proc->args.decls;  l != NULL; l = l->next) {
392				f_print(fout, "\targ.%s = %s;\n",
393				    l->decl.name, l->decl.name);
394			}
395			if (mtflag)
396				f_print(fout, "\treturn (");
397			else
398				f_print(fout, "\tif ((%s =", RESULT);
399			f_print(fout,
400			    "clnt_send(clnt, %s,\n\t\t(xdrproc_t)xdr_%s",
401			    proc->proc_name, proc->args.argname);
402			f_print(fout,
403			    ", (caddr_t)&arg)");
404			if (mtflag)
405				f_print(fout, ");\n");
406			else
407				f_print(fout, ") != RPC_SUCCESS) {\n");
408		} else {		/* single argument, new or old style */
409			if (!mtflag)
410				f_print(fout,
411				    "\tif ((%s = clnt_send(clnt, "
412				    "%s,\n\t\t(xdrproc_t)xdr_%s, "
413				    "(caddr_t)%s%s)) != RPC_SUCCESS) {\n",
414				    RESULT,
415				    proc->proc_name,
416				    stringfix(proc->args.decls->decl.type),
417				    (newstyle ? "&" : ""),
418				    (newstyle ?
419				    proc->args.decls->decl.name :
420				    "argp"));
421			else
422
423				f_print(fout,
424				    "\treturn (clnt_send(clnt, "
425				    "%s,\n\t\t(xdrproc_t)xdr_%s, "
426				    "(caddr_t)%s%s));\n",
427				    proc->proc_name,
428				    stringfix(proc->args.decls->decl.type),
429				    (newstyle ? "&" : ""),
430				    (newstyle ?
431				    proc->args.decls->decl.name :
432				    "argp"));
433		}
434		if (!mtflag) {
435			f_print(fout, "\t\treturn (NULL);\n");
436			f_print(fout, "\t}\n");
437
438			f_print(fout, "\treturn ((void *)&%s);\n",
439			    RESULT);
440		}
441	}
442}
443