1#
2# $Id: gen_rpc.awk,v 12.14 2007/11/18 14:15:41 bostic Exp $
3# Awk script for generating client/server RPC code.
4#
5# This awk script generates most of the RPC routines for DB client/server
6# use. It also generates a template for server and client procedures.  These
7# functions must still be edited, but are highly stylized and the initial
8# template gets you a fair way along the path).
9#
10# This awk script requires that these variables be set when it is called:
11#
12#	major		-- Major version number
13#	minor		-- Minor version number
14#	xidsize		-- size of GIDs
15#	client_file	-- the C source file being created for client code
16#	ctmpl_file	-- the C template file being created for client code
17#	server_file	-- the C source file being created for server code
18#	stmpl_file	-- the C template file being created for server code
19#	xdr_file	-- the XDR message file created
20#
21# And stdin must be the input file that defines the RPC setup.
22BEGIN {
23	if (major == "" || minor == "" || xidsize == "" ||
24	    client_file == "" || ctmpl_file == "" ||
25	    server_file == "" || stmpl_file == "" || xdr_file == "") {
26		print "Usage: gen_rpc.awk requires these variables be set:"
27		print "\tmajor\t-- Major version number"
28		print "\tminor\t-- Minor version number"
29		print "\txidsize\t-- GID size"
30		print "\tclient_file\t-- the client C source file being created"
31		print "\tctmpl_file\t-- the client template file being created"
32		print "\tserver_file\t-- the server C source file being created"
33		print "\tstmpl_file\t-- the server template file being created"
34		print "\txdr_file\t-- the XDR message file being created"
35		error = 1; exit
36	}
37
38	FS="\t\t*"
39	CFILE=client_file
40	printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \
41	    > CFILE
42
43	TFILE = ctmpl_file
44	printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \
45	    > TFILE
46
47	SFILE = server_file
48	printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \
49	    > SFILE
50
51	# Server procedure template.
52	PFILE = stmpl_file
53	XFILE = xdr_file
54	printf("/* Do not edit: automatically built by gen_rpc.awk. */\n") \
55	    > XFILE
56	nendlist = 1;
57
58	# Output headers
59	general_headers()
60
61	# Put out the actual illegal and no-server functions.
62	illegal_functions(CFILE)
63}
64END {
65	if (error == 0) {
66		printf("program DB_RPC_SERVERPROG {\n") >> XFILE
67		printf("\tversion DB_RPC_SERVERVERS {\n") >> XFILE
68
69		for (i = 1; i < nendlist; ++i)
70			printf("\t\t%s;\n", endlist[i]) >> XFILE
71
72		printf("\t} = %d%03d;\n", major, minor) >> XFILE
73		printf("} = 351457;\n") >> XFILE
74
75		obj_init("DB", "dbp", obj_db, CFILE)
76		obj_init("DBC", "dbc", obj_dbc, CFILE)
77		obj_init("DB_ENV", "dbenv", obj_dbenv, CFILE)
78		obj_init("DB_TXN", "txn", obj_txn, CFILE)
79	}
80}
81
82/^[	 ]*LOCAL/ {
83	# LOCAL methods are ones where we don't override the handle
84	# method for RPC, nor is it illegal -- it's just satisfied
85	# locally.
86	next;
87}
88/^[	 ]*NOFUNC/ {
89	++obj_indx;
90
91	# NOFUNC methods are illegal on the RPC client.
92	if ($2 ~ "^db_")
93		obj_illegal(obj_db, "dbp", $2, $3)
94	else if ($2 ~ "^dbc_")
95		obj_illegal(obj_dbc, "dbc", $2, $3)
96	else if ($2 ~ "^env_")
97		obj_illegal(obj_dbenv, "dbenv", $2, $3)
98	else if ($2 ~ "^txn_")
99		obj_illegal(obj_txn, "txn", $2, $3)
100	else {
101		print "unexpected handle prefix: " $2
102		error = 1; exit
103	}
104	next;
105}
106/^[	 ]*BEGIN/ {
107	++obj_indx;
108
109	name = $2;
110	link_only = ret_code = 0
111	if ($3 == "LINKONLY")
112		link_only = 1
113	else if ($3 == "RETCODE")
114		ret_code = 1
115
116	funcvars = 0;
117	newvars = 0;
118	nvars = 0;
119	rvars = 0;
120	xdr_free = 0;
121
122	db_handle = 0;
123	dbc_handle = 0;
124	dbt_handle = 0;
125	env_handle = 0;
126	mp_handle = 0;
127	txn_handle = 0;
128}
129/^[	 ]*ARG/ {
130	rpc_type[nvars] = $2;
131	c_type[nvars] = $3;
132	pr_type[nvars] = $3;
133	args[nvars] = $4;
134	func_arg[nvars] = 0;
135	if (rpc_type[nvars] == "LIST") {
136		list_type[nvars] = $5;
137	} else
138		list_type[nvars] = 0;
139
140	if (c_type[nvars] == "DBT *")
141		dbt_handle = 1;
142	else if (c_type[nvars] == "DB_ENV *") {
143		ctp_type[nvars] = "CT_ENV";
144		env_handle = 1;
145		env_idx = nvars;
146
147		if (nvars == 0)
148			obj_func("dbenv", obj_dbenv);
149	} else if (c_type[nvars] == "DB *") {
150		ctp_type[nvars] = "CT_DB";
151		if (db_handle != 1) {
152			db_handle = 1;
153			db_idx = nvars;
154		}
155
156		if (nvars == 0)
157			obj_func("dbp", obj_db);
158	} else if (c_type[nvars] == "DBC *") {
159		ctp_type[nvars] = "CT_CURSOR";
160		dbc_handle = 1;
161		dbc_idx = nvars;
162
163		if (nvars == 0)
164			obj_func("dbc", obj_dbc);
165	} else if (c_type[nvars] == "DB_TXN *") {
166		ctp_type[nvars] = "CT_TXN";
167		txn_handle = 1;
168		txn_idx = nvars;
169
170		if (nvars == 0)
171			obj_func("txn", obj_txn);
172	}
173
174	++nvars;
175}
176/^[	 ]*FUNCPROT/ {
177	pr_type[nvars] = $2;
178}
179/^[	 ]*FUNCARG/ {
180	rpc_type[nvars] = "IGNORE";
181	c_type[nvars] = $2;
182	args[nvars] = sprintf("func%d", funcvars);
183	func_arg[nvars] = 1;
184	++funcvars;
185	++nvars;
186}
187/^[	 ]*RET/ {
188	ret_type[rvars] = $2;
189	retc_type[rvars] = $3;
190	retargs[rvars] = $4;
191	if (ret_type[rvars] == "LIST" || ret_type[rvars] == "DBT") {
192		xdr_free = 1;
193	}
194	if (ret_type[rvars] == "LIST") {
195		retlist_type[rvars] = $5;
196	} else
197		retlist_type[rvars] = 0;
198	ret_isarg[rvars] = 0;
199
200	++rvars;
201}
202/^[	 ]*ARET/ {
203	ret_type[rvars] = $2;
204	rpc_type[nvars] = "IGNORE";
205	retc_type[rvars] = $3;
206	c_type[nvars] = sprintf("%s *", $3);
207	pr_type[nvars] = c_type[nvars];
208	retargs[rvars] = $4;
209	args[nvars] = sprintf("%sp", $4);
210	if (ret_type[rvars] == "LIST" || ret_type[rvars] == "DBT") {
211		xdr_free = 1;
212	}
213	func_arg[nvars] = 0;
214	if (ret_type[nvars] == "LIST") {
215		retlist_type[rvars] =  $5;
216		list_type[nvars] = $5;
217	} else {
218		retlist_type[rvars] = 0;
219		list_type[nvars] = 0;
220	}
221	ret_isarg[rvars] = 1;
222
223	++nvars;
224	++rvars;
225}
226/^[	 ]*END/ {
227	#
228	# =====================================================
229	# LINKONLY -- just reference the function, that's all.
230	#
231	if (link_only)
232		next;
233
234	#
235	# =====================================================
236	# XDR messages.
237	#
238	printf("\n") >> XFILE
239	printf("struct __%s_msg {\n", name) >> XFILE
240	for (i = 0; i < nvars; ++i) {
241		if (rpc_type[i] == "LIST") {
242			if (list_type[i] == "GID") {
243				printf("\topaque %s<>;\n", args[i]) >> XFILE
244			} else {
245				printf("\tunsigned int %s<>;\n", args[i]) >> XFILE
246			}
247		}
248		if (rpc_type[i] == "ID") {
249			printf("\tunsigned int %scl_id;\n", args[i]) >> XFILE
250		}
251		if (rpc_type[i] == "STRING") {
252			printf("\tstring %s<>;\n", args[i]) >> XFILE
253		}
254		if (rpc_type[i] == "GID") {
255			printf("\topaque %s[%d];\n", args[i], xidsize) >> XFILE
256		}
257		if (rpc_type[i] == "INT") {
258			printf("\tunsigned int %s;\n", args[i]) >> XFILE
259		}
260		if (rpc_type[i] == "DBT") {
261			printf("\tunsigned int %sdlen;\n", args[i]) >> XFILE
262			printf("\tunsigned int %sdoff;\n", args[i]) >> XFILE
263			printf("\tunsigned int %sulen;\n", args[i]) >> XFILE
264			printf("\tunsigned int %sflags;\n", args[i]) >> XFILE
265			printf("\topaque %sdata<>;\n", args[i]) >> XFILE
266		}
267	}
268	printf("};\n") >> XFILE
269
270	printf("\n") >> XFILE
271	#
272	# Generate the reply message
273	#
274	printf("struct __%s_reply {\n", name) >> XFILE
275	printf("\t/* num return vars: %d */\n", rvars) >> XFILE
276	printf("\tint status;\n") >> XFILE
277	for (i = 0; i < rvars; ++i) {
278		if (ret_type[i] == "ID") {
279			printf("\tunsigned int %scl_id;\n", retargs[i]) >> XFILE
280		}
281		if (ret_type[i] == "STRING") {
282			printf("\tstring %s<>;\n", retargs[i]) >> XFILE
283		}
284		if (ret_type[i] == "INT") {
285			printf("\tunsigned int %s;\n", retargs[i]) >> XFILE
286		}
287		if (ret_type[i] == "DBL") {
288			printf("\tdouble %s;\n", retargs[i]) >> XFILE
289		}
290		if (ret_type[i] == "DBT") {
291			printf("\topaque %sdata<>;\n", retargs[i]) >> XFILE
292		}
293		if (ret_type[i] == "LIST") {
294			if (retlist_type[i] == "GID") {
295				printf("\topaque %s<>;\n", retargs[i]) >> XFILE
296			} else {
297				printf("\tunsigned int %s<>;\n", retargs[i]) >> XFILE
298			}
299		}
300	}
301	printf("};\n") >> XFILE
302
303	endlist[nendlist] = \
304	    sprintf("__%s_reply __DB_%s(__%s_msg) = %d", \
305		name, name, name, nendlist);
306	nendlist++;
307	#
308	# =====================================================
309	# Server functions.
310	#
311	# First spit out PUBLIC prototypes for server functions.
312	#
313	printf("__%s_reply *\n", name) >> SFILE
314	printf("__db_%s_%d%03d__SVCSUFFIX__(msg, req)\n", \
315	    name, major, minor) >> SFILE
316	printf("\t__%s_msg *msg;\n", name) >> SFILE;
317	printf("\tstruct svc_req *req;\n", name) >> SFILE;
318	printf("{\n") >> SFILE
319	printf("\tstatic __%s_reply reply; /* must be static */\n", \
320	    name) >> SFILE
321	if (xdr_free) {
322		printf("\tstatic int __%s_free = 0; /* must be static */\n\n", \
323		    name) >> SFILE
324	}
325	printf("\tCOMPQUIET(req, NULL);\n", name) >> SFILE
326	if (xdr_free) {
327		printf("\tif (__%s_free)\n", name) >> SFILE
328		printf("\t\txdr_free((xdrproc_t)xdr___%s_reply, (void *)&reply);\n", \
329		    name) >> SFILE
330		printf("\t__%s_free = 0;\n", name) >> SFILE
331		printf("\n\t/* Reinitialize allocated fields */\n") >> SFILE
332		for (i = 0; i < rvars; ++i) {
333			if (ret_type[i] == "LIST") {
334				printf("\treply.%s.%s_val = NULL;\n", \
335				    retargs[i], retargs[i]) >> SFILE
336			}
337			if (ret_type[i] == "DBT") {
338				printf("\treply.%sdata.%sdata_val = NULL;\n", \
339				    retargs[i], retargs[i]) >> SFILE
340			}
341		}
342	}
343
344	need_out = 0;
345	#
346	# Compose server proc to call.  Decompose message components as args.
347	#
348	printf("\n\t__%s_proc(", name) >> SFILE
349	sep = "";
350	for (i = 0; i < nvars; ++i) {
351		if (rpc_type[i] == "IGNORE") {
352			continue;
353		}
354		if (rpc_type[i] == "ID") {
355			printf("%smsg->%scl_id", sep, args[i]) >> SFILE
356		}
357		if (rpc_type[i] == "STRING") {
358			printf("%s(*msg->%s == '\\0') ? NULL : msg->%s", \
359			    sep, args[i], args[i]) >> SFILE
360		}
361		if (rpc_type[i] == "GID") {
362			printf("%s(u_int8_t *)msg->%s", sep, args[i]) >> SFILE
363		}
364		if (rpc_type[i] == "INT") {
365			printf("%smsg->%s", sep, args[i]) >> SFILE
366		}
367		if (rpc_type[i] == "LIST") {
368			printf("%smsg->%s.%s_val", \
369			    sep, args[i], args[i]) >> SFILE
370			printf("%smsg->%s.%s_len", \
371			    sep, args[i], args[i]) >> SFILE
372		}
373		if (rpc_type[i] == "DBT") {
374			printf("%smsg->%sdlen", sep, args[i]) >> SFILE
375			sep = ",\n\t    ";
376			printf("%smsg->%sdoff", sep, args[i]) >> SFILE
377			printf("%smsg->%sulen", sep, args[i]) >> SFILE
378			printf("%smsg->%sflags", sep, args[i]) >> SFILE
379			printf("%smsg->%sdata.%sdata_val", \
380			    sep, args[i], args[i]) >> SFILE
381			printf("%smsg->%sdata.%sdata_len", \
382			    sep, args[i], args[i]) >> SFILE
383		}
384		sep = ",\n\t    ";
385	}
386	printf("%s&reply", sep) >> SFILE
387	if (xdr_free)
388		printf("%s&__%s_free);\n", sep, name) >> SFILE
389	else
390		printf(");\n\n") >> SFILE
391	if (need_out) {
392		printf("\nout:\n") >> SFILE
393	}
394	printf("\treturn (&reply);\n") >> SFILE
395	printf("}\n\n") >> SFILE
396
397	#
398	# =====================================================
399	# Generate Procedure Template Server code
400	#
401	# Spit out comment, prototype, function name and arg list.
402	printf("/* BEGIN __%s_proc */\n", name) >> PFILE
403	delete p;
404	pi = 1;
405	p[pi++] = sprintf("void __%s_proc __P((", name);
406	p[pi++] = "";
407	for (i = 0; i < nvars; ++i) {
408		if (rpc_type[i] == "IGNORE")
409			continue;
410		if (rpc_type[i] == "ID") {
411			p[pi++] = "long";
412			p[pi++] = ", ";
413		}
414		if (rpc_type[i] == "STRING") {
415			p[pi++] = "char *";
416			p[pi++] = ", ";
417		}
418		if (rpc_type[i] == "GID") {
419			p[pi++] = "u_int8_t *";
420			p[pi++] = ", ";
421		}
422		if (rpc_type[i] == "INT") {
423			p[pi++] = "u_int32_t";
424			p[pi++] = ", ";
425		}
426		if (rpc_type[i] == "INTRET") {
427			p[pi++] = "u_int32_t *";
428			p[pi++] = ", ";
429		}
430		if (rpc_type[i] == "LIST" && list_type[i] == "GID") {
431			p[pi++] = "u_int8_t *";
432			p[pi++] = ", ";
433			p[pi++] = "u_int32_t";
434			p[pi++] = ", ";
435		}
436		if (rpc_type[i] == "LIST" && list_type[i] == "INT") {
437			p[pi++] = "u_int32_t *";
438			p[pi++] = ", ";
439			p[pi++] = "u_int32_t";
440			p[pi++] = ", ";
441		}
442		if (rpc_type[i] == "LIST" && list_type[i] == "ID") {
443			p[pi++] = "u_int32_t *";
444			p[pi++] = ", ";
445			p[pi++] = "u_int32_t";
446			p[pi++] = ", ";
447		}
448		if (rpc_type[i] == "DBT") {
449			p[pi++] = "u_int32_t";
450			p[pi++] = ", ";
451			p[pi++] = "u_int32_t";
452			p[pi++] = ", ";
453			p[pi++] = "u_int32_t";
454			p[pi++] = ", ";
455			p[pi++] = "u_int32_t";
456			p[pi++] = ", ";
457			p[pi++] = "void *";
458			p[pi++] = ", ";
459			p[pi++] = "u_int32_t";
460			p[pi++] = ", ";
461		}
462	}
463	p[pi++] = sprintf("__%s_reply *", name);
464	if (xdr_free) {
465		p[pi++] = ", ";
466		p[pi++] = "int *));";
467	} else {
468		p[pi++] = "";
469		p[pi++] = "));";
470	}
471	p[pi++] = "";
472
473	printf("void\n") >> PFILE
474	printf("__%s_proc(", name) >> PFILE
475	sep = "";
476	argcount = 0;
477	for (i = 0; i < nvars; ++i) {
478		argcount++;
479		split_lines();
480		if (argcount == 0) {
481			sep = "";
482		}
483		if (rpc_type[i] == "IGNORE")
484			continue;
485		if (rpc_type[i] == "ID") {
486			printf("%s%scl_id", sep, args[i]) >> PFILE
487		}
488		if (rpc_type[i] == "STRING") {
489			printf("%s%s", sep, args[i]) >> PFILE
490		}
491		if (rpc_type[i] == "GID") {
492			printf("%s%s", sep, args[i]) >> PFILE
493		}
494		if (rpc_type[i] == "INT") {
495			printf("%s%s", sep, args[i]) >> PFILE
496		}
497		if (rpc_type[i] == "INTRET") {
498			printf("%s%s", sep, args[i]) >> PFILE
499		}
500		if (rpc_type[i] == "LIST") {
501			printf("%s%s", sep, args[i]) >> PFILE
502			argcount++;
503			split_lines();
504			if (argcount == 0) {
505				sep = "";
506			} else {
507				sep = ", ";
508			}
509			printf("%s%slen", sep, args[i]) >> PFILE
510		}
511		if (rpc_type[i] == "DBT") {
512			printf("%s%sdlen", sep, args[i]) >> PFILE
513			sep = ", ";
514			argcount++;
515			split_lines();
516			if (argcount == 0) {
517				sep = "";
518			} else {
519				sep = ", ";
520			}
521			printf("%s%sdoff", sep, args[i]) >> PFILE
522			argcount++;
523			split_lines();
524			if (argcount == 0) {
525				sep = "";
526			} else {
527				sep = ", ";
528			}
529			printf("%s%sulen", sep, args[i]) >> PFILE
530			argcount++;
531			split_lines();
532			if (argcount == 0) {
533				sep = "";
534			} else {
535				sep = ", ";
536			}
537			printf("%s%sflags", sep, args[i]) >> PFILE
538			argcount++;
539			split_lines();
540			if (argcount == 0) {
541				sep = "";
542			} else {
543				sep = ", ";
544			}
545			printf("%s%sdata", sep, args[i]) >> PFILE
546			argcount++;
547			split_lines();
548			if (argcount == 0) {
549				sep = "";
550			} else {
551				sep = ", ";
552			}
553			printf("%s%ssize", sep, args[i]) >> PFILE
554		}
555		sep = ", ";
556	}
557	printf("%sreplyp",sep) >> PFILE
558	if (xdr_free) {
559		printf("%sfreep)\n",sep) >> PFILE
560	} else {
561		printf(")\n") >> PFILE
562	}
563	#
564	# Spit out arg types/names;
565	#
566	for (i = 0; i < nvars; ++i) {
567		if (rpc_type[i] == "ID") {
568			printf("\tunsigned int %scl_id;\n", args[i]) >> PFILE
569		}
570		if (rpc_type[i] == "STRING") {
571			printf("\tchar *%s;\n", args[i]) >> PFILE
572		}
573		if (rpc_type[i] == "GID") {
574			printf("\tu_int8_t *%s;\n", args[i]) >> PFILE
575		}
576		if (rpc_type[i] == "INT") {
577			printf("\tu_int32_t %s;\n", args[i]) >> PFILE
578		}
579		if (rpc_type[i] == "LIST" && list_type[i] == "GID") {
580			printf("\tu_int8_t * %s;\n", args[i]) >> PFILE
581		}
582		if (rpc_type[i] == "LIST" && list_type[i] == "INT") {
583			printf("\tu_int32_t * %s;\n", args[i]) >> PFILE
584			printf("\tu_int32_t %ssize;\n", args[i]) >> PFILE
585		}
586		if (rpc_type[i] == "LIST" && list_type[i] == "ID") {
587			printf("\tu_int32_t * %s;\n", args[i]) >> PFILE
588		}
589		if (rpc_type[i] == "LIST") {
590			printf("\tu_int32_t %slen;\n", args[i]) >> PFILE
591		}
592		if (rpc_type[i] == "DBT") {
593			printf("\tu_int32_t %sdlen;\n", args[i]) >> PFILE
594			printf("\tu_int32_t %sdoff;\n", args[i]) >> PFILE
595			printf("\tu_int32_t %sulen;\n", args[i]) >> PFILE
596			printf("\tu_int32_t %sflags;\n", args[i]) >> PFILE
597			printf("\tvoid *%sdata;\n", args[i]) >> PFILE
598			printf("\tu_int32_t %ssize;\n", args[i]) >> PFILE
599		}
600	}
601	printf("\t__%s_reply *replyp;\n",name) >> PFILE
602	if (xdr_free) {
603		printf("\tint * freep;\n") >> PFILE
604	}
605
606	printf("/* END __%s_proc */\n", name) >> PFILE
607
608	#
609	# Function body
610	#
611	printf("{\n") >> PFILE
612	printf("\tint ret;\n") >> PFILE
613	for (i = 0; i < nvars; ++i) {
614		if (rpc_type[i] == "ID") {
615			printf("\t%s %s;\n", c_type[i], args[i]) >> PFILE
616			printf("\tct_entry *%s_ctp;\n", args[i]) >> PFILE
617		}
618	}
619	printf("\n") >> PFILE
620	for (i = 0; i < nvars; ++i) {
621		if (rpc_type[i] == "ID") {
622			printf("\tACTIVATE_CTP(%s_ctp, %scl_id, %s);\n", \
623			    args[i], args[i], ctp_type[i]) >> PFILE
624			printf("\t%s = (%s)%s_ctp->ct_anyp;\n", \
625			    args[i], c_type[i], args[i]) >> PFILE
626		}
627	}
628	printf("\n\t/*\n\t * XXX Code goes here\n\t */\n\n") >> PFILE
629	printf("\treplyp->status = ret;\n") >> PFILE
630	printf("\treturn;\n") >> PFILE
631	printf("}\n\n") >> PFILE
632
633	#
634	# =====================================================
635	# Generate Client code
636	#
637	# Spit out PUBLIC prototypes.
638	#
639	delete p;
640	pi = 1;
641	p[pi++] = sprintf("int __dbcl_%s __P((", name);
642	p[pi++] = "";
643	for (i = 0; i < nvars; ++i) {
644		p[pi++] = pr_type[i];
645		p[pi++] = ", ";
646	}
647	p[pi - 1] = "";
648	p[pi] = "));";
649	proto_format(p, CFILE);
650
651	#
652	# Spit out function name/args.
653	#
654	printf("int\n") >> CFILE
655	printf("__dbcl_%s(", name) >> CFILE
656	sep = "";
657	for (i = 0; i < nvars; ++i) {
658		printf("%s%s", sep, args[i]) >> CFILE
659		sep = ", ";
660	}
661	printf(")\n") >> CFILE
662
663	for (i = 0; i < nvars; ++i)
664		if (func_arg[i] == 0)
665			printf("\t%s %s;\n", c_type[i], args[i]) >> CFILE
666		else
667			printf("\t%s;\n", c_type[i]) >> CFILE
668
669	printf("{\n") >> CFILE
670	printf("\tCLIENT *cl;\n") >> CFILE
671	printf("\t__%s_msg msg;\n", name) >> CFILE
672	printf("\t__%s_reply *replyp = NULL;\n", name) >> CFILE;
673	printf("\tint ret;\n") >> CFILE
674	if (!env_handle)
675		printf("\tDB_ENV *dbenv;\n") >> CFILE
676	#
677	# If we are managing a list, we need a few more vars.
678	#
679	for (i = 0; i < nvars; ++i) {
680		if (rpc_type[i] == "LIST") {
681			printf("\t%s %sp;\n", c_type[i], args[i]) >> CFILE
682			printf("\tint %si;\n", args[i]) >> CFILE
683			if (list_type[i] == "GID")
684				printf("\tu_int8_t ** %sq;\n", args[i]) >> CFILE
685			else
686				printf("\tu_int32_t * %sq;\n", args[i]) >> CFILE
687		}
688	}
689
690	printf("\n") >> CFILE
691	printf("\tret = 0;\n") >> CFILE
692	if (!env_handle) {
693		if (db_handle)
694			printf("\tdbenv = %s->dbenv;\n", args[db_idx]) >> CFILE
695		else if (dbc_handle)
696			printf("\tdbenv = %s->dbenv;\n", \
697			    args[dbc_idx]) >> CFILE
698		else if (txn_handle)
699			printf("\tdbenv = %s->mgrp->env->dbenv;\n", \
700			    args[txn_idx]) >> CFILE
701		else
702			printf("\tdbenv = NULL;\n") >> CFILE
703		printf("\tif (dbenv == NULL || !RPC_ON(dbenv))\n") >> CFILE
704		printf("\t\treturn (__dbcl_noserver(NULL));\n") >> CFILE
705	} else {
706		printf("\tif (%s == NULL || !RPC_ON(%s))\n", \
707		    args[env_idx], args[env_idx]) >> CFILE
708		printf("\t\treturn (__dbcl_noserver(%s));\n", \
709		    args[env_idx]) >> CFILE
710	}
711	printf("\n") >> CFILE
712
713	printf("\tcl = (CLIENT *)%s->cl_handle;\n\n", \
714	    env_handle ? args[env_idx] : "dbenv") >> CFILE
715
716	#
717	# If there is a function arg, check that it is NULL
718	#
719	for (i = 0; i < nvars; ++i) {
720		if (func_arg[i] != 1)
721			continue;
722		printf("\tif (%s != NULL) {\n", args[i]) >> CFILE
723		if (!env_handle) {
724			printf("\t\t__db_errx(dbenv->env, ") >> CFILE
725		} else {
726			printf(\
727			    "\t\t__db_errx(%s->env, ", args[env_idx]) >> CFILE
728		}
729		printf("\"User functions not supported in RPC\");\n") >> CFILE
730		printf("\t\treturn (EINVAL);\n\t}\n") >> CFILE
731	}
732
733	#
734	# Compose message components
735	#
736	for (i = 0; i < nvars; ++i) {
737		if (rpc_type[i] == "ID") {
738			# We don't need to check for a NULL DB_ENV *, because
739			# we already checked for it.  I frankly couldn't care
740			# less, but lint gets all upset at the wasted cycles.
741			if (c_type[i] != "DB_ENV *") {
742				printf("\tif (%s == NULL)\n", args[i]) >> CFILE
743				printf("\t\tmsg.%scl_id = 0;\n\telse\n", \
744				    args[i]) >> CFILE
745				indent = "\t\t";
746			} else
747				indent = "\t";
748			if (c_type[i] == "DB_TXN *") {
749				printf("%smsg.%scl_id = %s->txnid;\n", \
750				    indent, args[i], args[i]) >> CFILE
751			} else {
752				printf("%smsg.%scl_id = %s->cl_id;\n", \
753				    indent, args[i], args[i]) >> CFILE
754			}
755		}
756		if (rpc_type[i] == "GID") {
757			printf("\tmemcpy(msg.%s, %s, %d);\n", \
758			    args[i], args[i], xidsize) >> CFILE
759		}
760		if (rpc_type[i] == "INT") {
761			printf("\tmsg.%s = (u_int)%s;\n",
762			    args[i], args[i]) >> CFILE
763		}
764		if (rpc_type[i] == "STRING") {
765			printf("\tif (%s == NULL)\n", args[i]) >> CFILE
766			printf("\t\tmsg.%s = \"\";\n", args[i]) >> CFILE
767			printf("\telse\n") >> CFILE
768			printf("\t\tmsg.%s = (char *)%s;\n", \
769			    args[i], args[i]) >> CFILE
770		}
771		if (rpc_type[i] == "DBT") {
772			printf("\tmsg.%sdlen = %s->dlen;\n", \
773			    args[i], args[i]) >> CFILE
774			printf("\tmsg.%sdoff = %s->doff;\n", \
775			    args[i], args[i]) >> CFILE
776			printf("\tmsg.%sulen = %s->ulen;\n", \
777			    args[i], args[i]) >> CFILE
778			printf("\tmsg.%sflags = %s->flags;\n", \
779			    args[i], args[i]) >> CFILE
780			printf("\tmsg.%sdata.%sdata_val = %s->data;\n", \
781			    args[i], args[i], args[i]) >> CFILE
782			printf("\tmsg.%sdata.%sdata_len = %s->size;\n", \
783			    args[i], args[i], args[i]) >> CFILE
784		}
785		if (rpc_type[i] == "LIST") {
786			printf("\tfor (%si = 0, %sp = %s; *%sp != 0; ", \
787			    args[i], args[i], args[i], args[i]) >> CFILE
788			printf(" %si++, %sp++)\n\t\t;\n", args[i], args[i]) \
789			    >> CFILE
790
791			#
792			# If we are an array of ints, *_len is how many
793			# elements.  If we are a GID, *_len is total bytes.
794			#
795			printf("\tmsg.%s.%s_len = (u_int)%si",
796			    args[i], args[i], args[i]) >> CFILE
797			if (list_type[i] == "GID")
798				printf(" * %d;\n", xidsize) >> CFILE
799			else
800				printf(";\n") >> CFILE
801			printf("\tif ((ret = __os_calloc(") >> CFILE
802			if (!env_handle)
803				printf("dbenv->env,\n") >> CFILE
804			else
805				printf("%s->env,\n", args[env_idx]) >> CFILE
806			printf("\t    msg.%s.%s_len,", \
807			    args[i], args[i]) >> CFILE
808			if (list_type[i] == "GID")
809				printf(" 1,") >> CFILE
810			else
811				printf(" sizeof(u_int32_t),") >> CFILE
812			printf(" &msg.%s.%s_val)) != 0)\n",\
813			    args[i], args[i], args[i], args[i]) >> CFILE
814			printf("\t\treturn (ret);\n") >> CFILE
815			printf("\tfor (%sq = msg.%s.%s_val, %sp = %s; ", \
816			    args[i], args[i], args[i], \
817			    args[i], args[i]) >> CFILE
818			printf("%si--; %sq++, %sp++)\n", \
819			    args[i], args[i], args[i]) >> CFILE
820			printf("\t\t*%sq = ", args[i]) >> CFILE
821			if (list_type[i] == "GID")
822				printf("*%sp;\n", args[i]) >> CFILE
823			if (list_type[i] == "ID")
824				printf("(*%sp)->cl_id;\n", args[i]) >> CFILE
825			if (list_type[i] == "INT")
826				printf("*%sp;\n", args[i]) >> CFILE
827		}
828	}
829
830	printf("\n") >> CFILE
831	printf("\treplyp = __db_%s_%d%03d(&msg, cl);\n", name, major, minor) \
832	    >> CFILE
833	for (i = 0; i < nvars; ++i)
834		if (rpc_type[i] == "LIST")
835			printf("\t__os_free(%s->env, msg.%s.%s_val);\n",
836			    env_handle ? args[env_idx] : "dbenv",
837			    args[i], args[i]) >> CFILE
838
839	printf("\tif (replyp == NULL) {\n") >> CFILE
840	printf("\t\t__db_errx(%s->env, clnt_sperror(cl, \"Berkeley DB\"));\n",
841	    env_handle ? args[env_idx] : "dbenv") >> CFILE
842
843	printf("\t\tret = DB_NOSERVER;\n") >> CFILE
844	printf("\t\tgoto out;\n") >> CFILE
845	printf("\t}\n") >> CFILE
846
847	if (ret_code == 0) {
848		printf("\tret = replyp->status;\n") >> CFILE
849
850		#
851		# Set any arguments that are returned
852		#
853		for (i = 0; i < rvars; ++i) {
854			if (ret_isarg[i]) {
855				printf("\tif (%sp != NULL)\n",
856				    retargs[i]) >> CFILE;
857				printf("\t\t*%sp = (%s)replyp->%s;\n",
858				    retargs[i],
859				    retc_type[i], retargs[i]) >> CFILE;
860			}
861		}
862	} else {
863		printf("\tret = __dbcl_%s_ret(", name) >> CFILE
864		sep = "";
865		for (i = 0; i < nvars; ++i) {
866			printf("%s%s", sep, args[i]) >> CFILE
867			sep = ", ";
868		}
869		printf("%sreplyp);\n", sep) >> CFILE
870	}
871	printf("out:\n") >> CFILE
872	#
873	# Free reply if there was one.
874	#
875	printf("\tif (replyp != NULL)\n") >> CFILE
876	printf("\t\txdr_free((xdrproc_t)xdr___%s_reply,",name) >> CFILE
877	printf(" (void *)replyp);\n") >> CFILE
878	printf("\treturn (ret);\n") >> CFILE
879	printf("}\n\n") >> CFILE
880
881	#
882	# Generate Client Template code
883	#
884	if (ret_code) {
885		#
886		# If we are doing a list, write prototypes
887		#
888		delete p;
889		pi = 1;
890		p[pi++] = sprintf("int __dbcl_%s_ret __P((", name);
891		p[pi++] = "";
892		for (i = 0; i < nvars; ++i) {
893			p[pi++] = pr_type[i];
894			p[pi++] = ", ";
895		}
896		p[pi] = sprintf("__%s_reply *));", name);
897		proto_format(p, TFILE);
898
899		printf("int\n") >> TFILE
900		printf("__dbcl_%s_ret(", name) >> TFILE
901		sep = "";
902		for (i = 0; i < nvars; ++i) {
903			printf("%s%s", sep, args[i]) >> TFILE
904			sep = ", ";
905		}
906		printf("%sreplyp)\n",sep) >> TFILE
907
908		for (i = 0; i < nvars; ++i)
909			if (func_arg[i] == 0)
910				printf("\t%s %s;\n", c_type[i], args[i]) \
911				    >> TFILE
912			else
913				printf("\t%s;\n", c_type[i]) >> TFILE
914		printf("\t__%s_reply *replyp;\n", name) >> TFILE;
915		printf("{\n") >> TFILE
916		printf("\tint ret;\n") >> TFILE
917		#
918		# Local vars in template
919		#
920		for (i = 0; i < rvars; ++i) {
921			if (ret_type[i] == "ID" || ret_type[i] == "STRING" ||
922			    ret_type[i] == "INT" || ret_type[i] == "DBL") {
923				printf("\t%s %s;\n", \
924				    retc_type[i], retargs[i]) >> TFILE
925			} else if (ret_type[i] == "LIST") {
926				if (retlist_type[i] == "GID")
927					printf("\tu_int8_t *__db_%s;\n", \
928					    retargs[i]) >> TFILE
929				if (retlist_type[i] == "ID" ||
930				    retlist_type[i] == "INT")
931					printf("\tu_int32_t *__db_%s;\n", \
932					    retargs[i]) >> TFILE
933			} else {
934				printf("\t/* %s %s; */\n", \
935				    ret_type[i], retargs[i]) >> TFILE
936			}
937		}
938		#
939		# Client return code
940		#
941		printf("\n") >> TFILE
942		printf("\tif (replyp->status != 0)\n") >> TFILE
943		printf("\t\treturn (replyp->status);\n") >> TFILE
944		for (i = 0; i < rvars; ++i) {
945			varname = "";
946			if (ret_type[i] == "ID") {
947				varname = sprintf("%scl_id", retargs[i]);
948			}
949			if (ret_type[i] == "STRING") {
950				varname =  retargs[i];
951			}
952			if (ret_type[i] == "INT" || ret_type[i] == "DBL") {
953				varname =  retargs[i];
954			}
955			if (ret_type[i] == "DBT") {
956				varname = sprintf("%sdata", retargs[i]);
957			}
958			if (ret_type[i] == "ID" || ret_type[i] == "STRING" ||
959			    ret_type[i] == "INT" || ret_type[i] == "DBL") {
960				printf("\t%s = replyp->%s;\n", \
961				    retargs[i], varname) >> TFILE
962			} else if (ret_type[i] == "LIST") {
963				printf("\n\t/*\n") >> TFILE
964				printf("\t * XXX Handle list\n") >> TFILE
965				printf("\t */\n\n") >> TFILE
966			} else {
967				printf("\t/* Handle replyp->%s; */\n", \
968				    varname) >> TFILE
969			}
970		}
971		printf("\n\t/*\n\t * XXX Code goes here\n\t */\n\n") >> TFILE
972		printf("\treturn (replyp->status);\n") >> TFILE
973		printf("}\n\n") >> TFILE
974	}
975}
976
977function general_headers()
978{
979	printf("#include \"db_config.h\"\n") >> CFILE
980	printf("\n") >> CFILE
981	printf("#include \"db_int.h\"\n") >> CFILE
982	printf("#ifdef HAVE_SYSTEM_INCLUDE_FILES\n") >> CFILE
983	printf("#include <rpc/rpc.h>\n") >> CFILE
984	printf("#endif\n") >> CFILE
985	printf("#include \"db_server.h\"\n") >> CFILE
986	printf("#include \"dbinc/txn.h\"\n") >> CFILE
987	printf("#include \"dbinc_auto/rpc_client_ext.h\"\n") >> CFILE
988	printf("\n") >> CFILE
989
990	printf("#include \"db_config.h\"\n") >> TFILE
991	printf("\n") >> TFILE
992	printf("#include \"db_int.h\"\n") >> TFILE
993	printf("#include \"dbinc/txn.h\"\n") >> TFILE
994	printf("\n") >> TFILE
995
996	printf("#include \"db_config.h\"\n") >> SFILE
997	printf("\n") >> SFILE
998	printf("#include \"db_int.h\"\n") >> SFILE
999	printf("#ifdef HAVE_SYSTEM_INCLUDE_FILES\n") >> SFILE
1000	printf("#include <rpc/rpc.h>\n") >> SFILE
1001	printf("#endif\n") >> SFILE
1002	printf("#include \"db_server.h\"\n") >> SFILE
1003	printf("#include \"dbinc/db_server_int.h\"\n") >> SFILE
1004	printf("#include \"dbinc_auto/rpc_server_ext.h\"\n") >> SFILE
1005	printf("\n") >> SFILE
1006
1007	printf("#include \"db_config.h\"\n") >> PFILE
1008	printf("\n") >> PFILE
1009	printf("#include \"db_int.h\"\n") >> PFILE
1010	printf("#ifdef HAVE_SYSTEM_INCLUDE_FILES\n") >> PFILE
1011	printf("#include <rpc/rpc.h>\n") >> PFILE
1012	printf("#endif\n") >> PFILE
1013	printf("#include \"db_server.h\"\n") >> PFILE
1014	printf("#include \"dbinc/db_server_int.h\"\n") >> PFILE
1015	printf("\n") >> PFILE
1016}
1017
1018#
1019# illegal_functions --
1020#	Output general illegal-call functions
1021function illegal_functions(OUTPUT)
1022{
1023	printf("static int __dbcl_dbp_illegal __P((DB *));\n") >> OUTPUT
1024	printf("static int __dbcl_noserver __P((DB_ENV *));\n") >> OUTPUT
1025	printf("static int __dbcl_txn_illegal __P((DB_TXN *));\n") >> OUTPUT
1026	# If we ever need an "illegal" function for a DBC method.
1027	# printf("static int __dbcl_dbc_illegal __P((DBC *));\n") >> OUTPUT
1028	printf("\n") >> OUTPUT
1029
1030	printf("static int\n") >> OUTPUT
1031	printf("__dbcl_noserver(dbenv)\n") >> OUTPUT
1032	printf("\tDB_ENV *dbenv;\n") >> OUTPUT
1033	printf("{\n\t__db_errx(dbenv == NULL ? NULL : dbenv->env,") >> OUTPUT
1034	printf(\
1035	    "\n\t    \"No Berkeley DB RPC server environment\");\n") >> OUTPUT
1036	printf("\treturn (DB_NOSERVER);\n") >> OUTPUT
1037	printf("}\n\n") >> OUTPUT
1038
1039	printf("/*\n") >> OUTPUT
1040	printf(" * __dbcl_dbenv_illegal --\n") >> OUTPUT
1041	printf(" *	DB_ENV method not supported under RPC.\n") >> OUTPUT
1042	printf(" *\n") >> OUTPUT
1043	printf(" * PUBLIC: int __dbcl_dbenv_illegal __P((DB_ENV *));\n")\
1044	    >> OUTPUT
1045	printf(" */\n") >> OUTPUT
1046	printf("int\n") >> OUTPUT
1047	printf("__dbcl_dbenv_illegal(dbenv)\n") >> OUTPUT
1048	printf("\tDB_ENV *dbenv;\n") >> OUTPUT
1049	printf("{\n\t__db_errx(dbenv == NULL ? NULL : dbenv->env,") >> OUTPUT
1050	printf("\n\t    \"Interface not supported by ") >> OUTPUT
1051	printf("Berkeley DB RPC client environments\");\n") >> OUTPUT
1052	printf("\treturn (DB_OPNOTSUP);\n") >> OUTPUT
1053	printf("}\n\n") >> OUTPUT
1054	printf("/*\n") >> OUTPUT
1055	printf(" * __dbcl_dbp_illegal --\n") >> OUTPUT
1056	printf(" *	DB method not supported under RPC.\n") >> OUTPUT
1057	printf(" */\n") >> OUTPUT
1058	printf("static int\n") >> OUTPUT
1059	printf("__dbcl_dbp_illegal(dbp)\n") >> OUTPUT
1060	printf("\tDB *dbp;\n") >> OUTPUT
1061	printf("{\n\treturn (__dbcl_dbenv_illegal(dbp->dbenv));\n") >> OUTPUT
1062	printf("}\n\n") >> OUTPUT
1063	printf("/*\n") >> OUTPUT
1064	printf(" * __dbcl_txn_illegal --\n") >> OUTPUT
1065	printf(" *	DB_TXN method not supported under RPC.\n") >> OUTPUT
1066	printf(" */\n") >> OUTPUT
1067	printf("static int\n__dbcl_txn_illegal(txn)\n") >> OUTPUT
1068	printf("\tDB_TXN *txn;\n") >> OUTPUT
1069	printf("{\n\treturn (__dbcl_dbenv_illegal(txn->mgrp->env->dbenv));\n")\
1070	    >> OUTPUT
1071	printf("}\n\n") >> OUTPUT
1072	# If we ever need an "illegal" function for a DBC method.
1073	# printf("static int\n") >> OUTPUT
1074	# printf("__dbcl_dbc_illegal(dbc)\n") >> OUTPUT
1075	# printf("\tDBC *dbc;\n") >> OUTPUT
1076	# printf("{\n\treturn (__dbcl_dbenv_illegal(dbc->dbenv));\n") \
1077	#    >> OUTPUT
1078	# printf("}\n\n") >> OUTPUT
1079}
1080
1081function obj_func(v, l)
1082{
1083	# Ignore db_create and env_create -- there's got to be something
1084	# cleaner, but I don't want to rewrite rpc.src right now.
1085	if (name == "db_create")
1086		return;
1087	if (name == "env_create")
1088		return;
1089
1090	# Strip off the leading prefix for the method name.
1091	#
1092	# There are two method names for cursors, the old and the new.
1093	#
1094	# There just has to be something cleaner, but yadda, yadda, yadda.
1095	len = length(name);
1096	i = index(name, "_");
1097	s = substr(name, i + 1, len - i)
1098
1099	if (v != "dbc" || s == "get_priority" || s == "set_priority")
1100		o = ""
1101	else
1102		o = sprintf(" = %s->c_%s", v, s)
1103	l[obj_indx] = sprintf("\t%s->%s%s = __dbcl_%s;", v, s, o, name)
1104}
1105
1106function obj_illegal(l, handle, method, proto)
1107{
1108	# All of the functions return an int, with one exception.  Hack
1109	# to make that work.
1110	type = method == "db_get_mpf" ? "DB_MPOOLFILE *" : "int"
1111
1112	# Strip off the leading prefix for the method name -- there's got to
1113	# be something cleaner, but I don't want to rewrite rpc.src right now.
1114	len = length(method);
1115	i = index(method, "_");
1116
1117	l[obj_indx] =\
1118	    sprintf("\t%s->%s =\n\t    (%s (*)(",\
1119	    handle, substr(method, i + 1, len - i), type)\
1120	    proto\
1121	    sprintf("))\n\t    __dbcl_%s_illegal;", handle);
1122}
1123
1124function obj_init(obj, v, list, OUTPUT) {
1125	printf("/*\n") >> OUTPUT
1126	printf(" * __dbcl_%s_init --\n", v) >> OUTPUT
1127	printf(" *\tInitialize %s handle methods.\n", obj) >> OUTPUT
1128	printf(" *\n") >> OUTPUT
1129	printf(\
1130	    " * PUBLIC: void __dbcl_%s_init __P((%s *));\n", v, obj) >> OUTPUT
1131	printf(" */\n") >> OUTPUT
1132	printf("void\n") >> OUTPUT
1133	printf("__dbcl_%s_init(%s)\n", v, v) >> OUTPUT
1134	printf("\t%s *%s;\n", obj, v) >> OUTPUT
1135	printf("{\n") >> OUTPUT
1136	for (i = 1; i < obj_indx; ++i) {
1137		if (i in list)
1138			print list[i] >> OUTPUT
1139	}
1140	printf("\treturn;\n}\n\n") >> OUTPUT
1141}
1142
1143#
1144# split_lines --
1145#	Add line separators to pretty-print the output.
1146function split_lines() {
1147	if (argcount > 3) {
1148		# Reset the counter, remove any trailing whitespace from
1149		# the separator.
1150		argcount = 0;
1151		sub("[ 	]$", "", sep)
1152
1153		printf("%s\n\t\t", sep) >> PFILE
1154	}
1155}
1156
1157# proto_format --
1158#	Pretty-print a function prototype.
1159function proto_format(p, OUTPUT)
1160{
1161	printf("/*\n") >> OUTPUT;
1162
1163	s = "";
1164	for (i = 1; i in p; ++i)
1165		s = s p[i];
1166
1167	t = " * PUBLIC: "
1168	if (length(s) + length(t) < 80)
1169		printf("%s%s", t, s) >> OUTPUT;
1170	else {
1171		split(s, p, "__P");
1172		len = length(t) + length(p[1]);
1173		printf("%s%s", t, p[1]) >> OUTPUT
1174
1175		n = split(p[2], comma, ",");
1176		comma[1] = "__P" comma[1];
1177		for (i = 1; i <= n; i++) {
1178			if (len + length(comma[i]) > 75) {
1179				printf("\n * PUBLIC:     ") >> OUTPUT;
1180				len = 0;
1181			}
1182			printf("%s%s", comma[i], i == n ? "" : ",") >> OUTPUT;
1183			len += length(comma[i]);
1184		}
1185	}
1186	printf("\n */\n") >> OUTPUT;
1187}
1188