1 | /* |
2 | * rpc_clntout.c, Client-stub outputter for the RPC protocol compiler |
3 | * Copyright (c) 2010, Oracle America, Inc. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are |
7 | * met: |
8 | * |
9 | * * Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * * Redistributions in binary form must reproduce the above |
12 | * copyright notice, this list of conditions and the following |
13 | * disclaimer in the documentation and/or other materials |
14 | * provided with the distribution. |
15 | * * Neither the name of the "Oracle America, Inc." nor the names of its |
16 | * contributors may be used to endorse or promote products derived |
17 | * from this software without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
22 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
23 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
26 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
28 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | #include <stdio.h> |
33 | #include <string.h> |
34 | #include "rpc/types.h" |
35 | #include "rpc_parse.h" |
36 | #include "rpc_util.h" |
37 | #include "proto.h" |
38 | |
39 | #define DEFAULT_TIMEOUT 25 /* in seconds */ |
40 | static const char RESULT[] = "clnt_res" ; |
41 | |
42 | static void write_program (definition * def); |
43 | static void printbody (proc_list * proc); |
44 | static const char *ampr (const char *type); |
45 | static void printbody (proc_list * proc); |
46 | |
47 | |
48 | void |
49 | write_stubs (void) |
50 | { |
51 | list *l; |
52 | definition *def; |
53 | |
54 | fprintf (fout, |
55 | "\n/* Default timeout can be changed using clnt_control() */\n" ); |
56 | fprintf (fout, "static struct timeval TIMEOUT = { %d, 0 };\n" , |
57 | DEFAULT_TIMEOUT); |
58 | for (l = defined; l != NULL; l = l->next) |
59 | { |
60 | def = (definition *) l->val; |
61 | if (def->def_kind == DEF_PROGRAM) |
62 | { |
63 | write_program (def); |
64 | } |
65 | } |
66 | } |
67 | |
68 | static void |
69 | write_program (definition * def) |
70 | { |
71 | version_list *vp; |
72 | proc_list *proc; |
73 | |
74 | for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) |
75 | { |
76 | for (proc = vp->procs; proc != NULL; proc = proc->next) |
77 | { |
78 | fprintf (fout, "\n" ); |
79 | if (mtflag == 0) |
80 | { |
81 | ptype (proc->res_prefix, proc->res_type, 1); |
82 | fprintf (fout, "*\n" ); |
83 | pvname (proc->proc_name, vp->vers_num); |
84 | printarglist (proc, RESULT, "clnt" , "CLIENT *" ); |
85 | } |
86 | else |
87 | { |
88 | fprintf (fout, "enum clnt_stat \n" ); |
89 | pvname (proc->proc_name, vp->vers_num); |
90 | printarglist (proc, RESULT, "clnt" , "CLIENT *" ); |
91 | } |
92 | fprintf (fout, "{\n" ); |
93 | printbody (proc); |
94 | fprintf (fout, "}\n" ); |
95 | } |
96 | } |
97 | } |
98 | |
99 | /* Writes out declarations of procedure's argument list. |
100 | In either ANSI C style, in one of old rpcgen style (pass by reference), |
101 | or new rpcgen style (multiple arguments, pass by value); |
102 | */ |
103 | |
104 | /* sample addargname = "clnt"; sample addargtype = "CLIENT * " */ |
105 | |
106 | void |
107 | printarglist (proc_list * proc, const char *result, |
108 | const char *addargname, const char *addargtype) |
109 | { |
110 | |
111 | decl_list *l; |
112 | |
113 | if (!newstyle) |
114 | { /* old style: always pass argument by reference */ |
115 | if (Cflag) |
116 | { /* C++ style heading */ |
117 | fprintf (fout, "(" ); |
118 | ptype (proc->args.decls->decl.prefix, |
119 | proc->args.decls->decl.type, 1); |
120 | |
121 | if (mtflag) |
122 | {/* Generate result field */ |
123 | fprintf (fout, "*argp, " ); |
124 | ptype(proc->res_prefix, proc->res_type, 1); |
125 | fprintf (fout, "*%s, %s%s)\n" , result, addargtype, addargname); |
126 | } |
127 | else |
128 | fprintf (fout, "*argp, %s%s)\n" , addargtype, addargname); |
129 | } |
130 | else |
131 | { |
132 | if (!mtflag) |
133 | fprintf (fout, "(argp, %s)\n" , addargname); |
134 | else |
135 | fprintf (fout, "(argp, %s, %s)\n" , result, addargname); |
136 | fprintf (fout, "\t" ); |
137 | ptype (proc->args.decls->decl.prefix, |
138 | proc->args.decls->decl.type, 1); |
139 | fprintf (fout, "*argp;\n" ); |
140 | if (mtflag) |
141 | { |
142 | fprintf (fout, "\t" ); |
143 | ptype (proc->res_prefix, proc->res_type, 1); |
144 | fprintf (fout, "*%s;\n" , result); |
145 | } |
146 | } |
147 | } |
148 | else if (streq (proc->args.decls->decl.type, "void" )) |
149 | { |
150 | /* newstyle, 0 argument */ |
151 | if (mtflag) |
152 | { |
153 | fprintf (fout, "(" ); |
154 | if (Cflag) |
155 | { |
156 | ptype(proc->res_prefix, proc->res_type, 1); |
157 | fprintf (fout, "*%s, %s%s)\n" , result, addargtype, addargname); |
158 | } |
159 | else |
160 | fprintf (fout, "(%s)\n" , addargname); |
161 | } |
162 | else if (Cflag) |
163 | fprintf (fout, "(%s%s)\n" , addargtype, addargname); |
164 | else |
165 | fprintf (fout, "(%s)\n" , addargname); |
166 | } |
167 | else |
168 | { |
169 | /* new style, 1 or multiple arguments */ |
170 | if (!Cflag) |
171 | { |
172 | fprintf (fout, "(" ); |
173 | for (l = proc->args.decls; l != NULL; l = l->next) |
174 | fprintf (fout, "%s, " , l->decl.name); |
175 | if (mtflag) |
176 | fprintf (fout, "%s, " , result); |
177 | fprintf (fout, "%s)\n" , addargname); |
178 | for (l = proc->args.decls; l != NULL; l = l->next) |
179 | { |
180 | pdeclaration (proc->args.argname, &l->decl, 1, ";\n" ); |
181 | } |
182 | if (mtflag) |
183 | { |
184 | fprintf (fout, "\t" ); |
185 | ptype (proc->res_prefix, proc->res_type, 1); |
186 | fprintf (fout, "*%s;\n" , result); |
187 | } |
188 | } |
189 | else |
190 | { /* C++ style header */ |
191 | fprintf (fout, "(" ); |
192 | for (l = proc->args.decls; l != NULL; l = l->next) |
193 | { |
194 | pdeclaration (proc->args.argname, &l->decl, 0, ", " ); |
195 | } |
196 | if (mtflag) |
197 | { |
198 | ptype (proc->res_prefix, proc->res_type, 1); |
199 | fprintf (fout, "*%s, " , result); |
200 | } |
201 | fprintf (fout, " %s%s)\n" , addargtype, addargname); |
202 | } |
203 | } |
204 | |
205 | if (!Cflag) |
206 | fprintf (fout, "\t%s%s;\n" , addargtype, addargname); |
207 | } |
208 | |
209 | |
210 | static |
211 | const char * |
212 | ampr (const char *type) |
213 | { |
214 | if (isvectordef (type, REL_ALIAS)) |
215 | { |
216 | return "" ; |
217 | } |
218 | else |
219 | { |
220 | return "&" ; |
221 | } |
222 | } |
223 | |
224 | static void |
225 | printbody (proc_list * proc) |
226 | { |
227 | decl_list *l; |
228 | bool_t args2 = (proc->arg_num > 1); |
229 | /* int i; */ |
230 | |
231 | /* For new style with multiple arguments, need a structure in which |
232 | to stuff the arguments. */ |
233 | if (newstyle && args2) |
234 | { |
235 | fprintf (fout, "\t%s" , proc->args.argname); |
236 | fprintf (fout, " arg;\n" ); |
237 | } |
238 | if (!mtflag) |
239 | { |
240 | fprintf (fout, "\tstatic " ); |
241 | if (streq (proc->res_type, "void" )) |
242 | { |
243 | fprintf (fout, "char " ); |
244 | } |
245 | else |
246 | { |
247 | ptype (proc->res_prefix, proc->res_type, 0); |
248 | } |
249 | fprintf (fout, "%s;\n" , RESULT); |
250 | fprintf (fout, "\n" ); |
251 | fprintf (fout, "\tmemset((char *)%s%s, 0, sizeof(%s));\n" , |
252 | ampr (proc->res_type), RESULT, RESULT); |
253 | } |
254 | if (newstyle && !args2 && (streq (proc->args.decls->decl.type, "void" ))) |
255 | { |
256 | /* newstyle, 0 arguments */ |
257 | if (mtflag) |
258 | fprintf (fout, "\t return " ); |
259 | else |
260 | fprintf (fout, "\t if " ); |
261 | fprintf (fout, |
262 | "(clnt_call (clnt, %s, (xdrproc_t) xdr_void, " , proc->proc_name); |
263 | |
264 | fprintf (fout, |
265 | "(caddr_t) NULL,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s," , |
266 | stringfix(proc->res_type), (mtflag)?"" :ampr(proc->res_type), |
267 | RESULT); |
268 | if (mtflag) |
269 | fprintf (fout, "\n\t\tTIMEOUT));\n\n" ); |
270 | else |
271 | fprintf (fout, "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n" ); |
272 | } |
273 | else if (newstyle && args2) |
274 | { |
275 | /* newstyle, multiple arguments: stuff arguments into structure */ |
276 | for (l = proc->args.decls; l != NULL; l = l->next) |
277 | { |
278 | fprintf (fout, "\targ.%s = %s;\n" , |
279 | l->decl.name, l->decl.name); |
280 | } |
281 | if (mtflag) |
282 | fprintf (fout, "\treturn " ); |
283 | else |
284 | fprintf (fout, "\tif " ); |
285 | |
286 | fprintf (fout, |
287 | "(clnt_call (clnt, %s, (xdrproc_t) xdr_%s" , proc->proc_name, |
288 | proc->args.argname); |
289 | fprintf (fout, |
290 | ", (caddr_t) &arg,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s," , |
291 | stringfix(proc->res_type), (mtflag)?"" :ampr(proc->res_type), |
292 | RESULT); |
293 | if (mtflag) |
294 | fprintf (fout, "\n\t\tTIMEOUT));\n" ); |
295 | else |
296 | fprintf (fout, "\n\t\tTIMEOUT) != RPC_SUCCESS) {\n" ); |
297 | } |
298 | else |
299 | { /* single argument, new or old style */ |
300 | if (!mtflag) |
301 | fprintf (fout, |
302 | "\tif (clnt_call (clnt, %s,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n\t\tTIMEOUT) != RPC_SUCCESS) {\n" , |
303 | proc->proc_name, |
304 | stringfix (proc->args.decls->decl.type), |
305 | (newstyle ? "&" : "" ), |
306 | (newstyle ? proc->args.decls->decl.name : "argp" ), |
307 | stringfix (proc->res_type), ampr (proc->res_type), |
308 | RESULT); |
309 | else |
310 | fprintf(fout, |
311 | "\treturn (clnt_call(clnt, %s,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n\t\t(xdrproc_t) xdr_%s, (caddr_t) %s%s,\n\t\tTIMEOUT));\n" , |
312 | proc->proc_name, |
313 | stringfix (proc->args.decls->decl.type), |
314 | (newstyle ? "&" : "" ), |
315 | (newstyle ? proc->args.decls->decl.name : "argp" ), |
316 | stringfix (proc->res_type), "" , |
317 | RESULT); |
318 | } |
319 | if (!mtflag) |
320 | { |
321 | fprintf (fout, "\t\treturn (NULL);\n" ); |
322 | fprintf (fout, "\t}\n" ); |
323 | if (streq (proc->res_type, "void" )) |
324 | { |
325 | fprintf (fout, "\treturn ((void *)%s%s);\n" , |
326 | ampr (proc->res_type), RESULT); |
327 | } |
328 | else |
329 | { |
330 | fprintf (fout, "\treturn (%s%s);\n" , ampr (proc->res_type), RESULT); |
331 | } |
332 | } |
333 | } |
334 | |