1#
2# See the file LICENSE for redistribution information.
3#
4# Copyright (c) 1996, 2013 Oracle and/or its affiliates.  All rights reserved.
5#
6# $Id$
7#
8
9BEGIN {
10	if (source_file == "" || header_file == "") {
11	    print "Usage: gen_msg.awk requires these variables to be set:";
12	    print "\theader_file\t-- the message #include file being created";
13	    print "\tsource_file\t-- the message source file being created";
14	    exit;
15	}
16	CFILE=source_file;
17	HFILE=header_file;
18	maxmsg = 0;
19}
20/^[	]*PREFIX/ {
21	prefix = $2;
22
23	# Start .c files.
24	printf("/* Do not edit: automatically built by gen_msg.awk. */\n\n") \
25	    > CFILE
26	printf("#include \"db_config.h\"\n\n") >> CFILE
27
28	# Start .h file, make the entire file conditional.
29	printf("/* Do not edit: automatically built by gen_msg.awk. */\n\n") \
30	    > HFILE
31	printf("#ifndef\t%s_AUTOMSG_H\n#define\t%s_AUTOMSG_H\n\n", prefix, prefix) \
32	    >> HFILE;
33	printf("/*\n") >> HFILE;
34	printf(" * Message sizes are simply the sum of field sizes (not\n") \
35	    >> HFILE;
36	printf(" * counting variable size parts, when DBTs are present),\n") \
37	    >> HFILE;
38	printf(" * and may be different from struct sizes due to padding.\n") \
39	    >> HFILE;
40	printf(" */\n") >> HFILE;
41}
42/^[	]*INCLUDE/ {
43	for (i = 2; i < NF; i++)
44		printf("%s ", $i) >> CFILE;
45	printf("%s\n", $i) >> CFILE;
46}
47/^[	]*BEGIN_MSG/ {
48	if (in_begin) {
49		print "Invalid format: missing END statement";
50		exit;
51	}
52	in_begin = 1;
53	nvars = 0;
54	thismsg = $2;
55	for (i = 2; i<= NF; i++) {
56		if ($i == "alloc")
57			alloc = 1;
58		else if ($i == "check_length")
59			check_length = 1;
60		else if ($i == "version")
61			version = 1;
62	}
63
64	base_name = sprintf("%s_%s", prefix, thismsg);
65	typedef_name = sprintf("%s_args", base_name);
66	msg_size_name = toupper(sprintf("%s_SIZE", base_name));
67	max_name = toupper(sprintf("%s_MAXMSG_SIZE", prefix));
68}
69/^[	]*ARG/ {
70	vars[nvars] = $2;
71	types[nvars] = $3;
72	if (types[nvars] == "DBT")
73		has_dbt = 1;
74	nvars++;
75}
76/^[	]*END/ {
77	if (!in_begin) {
78		print "Invalid format: missing BEGIN statement";
79		exit;
80	}
81	if (nvars == 0) {
82		printf("%s needs at least one field\n", thismsg);
83		exit;
84	}
85
86	sum = 0;
87	for (i = 0; i < nvars; i++)
88		sum += type_length(types[i]);
89	printf("#define\t%s\t%d\n", msg_size_name, sum) >> HFILE;
90	if (sum > maxmsg)
91		maxmsg = sum;
92
93	printf("typedef struct _%s {\n", typedef_name) >> HFILE;
94	for (i = 0; i < nvars; i++) {
95		if (types[i] == "DB_LSN" || types[i] == "DBT")
96			printf("\t%s\t\t%s;\n", types[i], vars[i]) >> HFILE;
97		else
98			printf("\t%s\t%s;\n", types[i], vars[i]) >> HFILE;
99	}
100	printf("} %s;\n\n", typedef_name) >> HFILE;
101
102	emit_marshal();
103	emit_unmarshal();
104
105	# Reinitialize variables for next time.
106	in_begin = 0;
107	alloc = 0;
108	check_length = 0;
109	version = 0;
110	has_dbt = 0;
111}
112END {
113	# End the conditional for the HFILE
114	printf("#define\t%s\t%d\n", max_name, maxmsg) >> HFILE;
115	printf("#endif\n") >> HFILE;
116}
117
118# Length of fixed part of message.  Does not count variable-length data portion
119# of DBT.
120#
121function type_length(type)
122{
123	if (type == "DB_LSN")
124		return (8);
125	if (type == "DBT" || type == "u_int32_t" || type == "db_pgno_t")
126		return (4);
127	if (type == "u_int16_t")
128		return (2);
129	if (type == "u_int8_t")
130		return (1);
131	printf("unknown field type: %s", type);
132	exit(1);
133}
134
135function emit_marshal()
136{
137	pi = 1;
138	if (check_length)
139		p[pi++] = "int ";
140	else
141		p[pi++] = "void ";
142	function_name = sprintf("%s_marshal", base_name);
143	p[pi++] = function_name;
144	p[pi++] = " __P((ENV *, ";
145	if (version)
146		p[pi++] = "u_int32_t, ";
147	p[pi++] = sprintf("%s *, u_int8_t *", typedef_name);
148	if (check_length)
149		p[pi++] = ", size_t, size_t *";
150	p[pi++] = "));";
151	proto_format(p, CFILE);
152
153	if (check_length)
154		printf("int\n") >> CFILE;
155	else
156		printf("void\n") >> CFILE;
157	printf("%s(env", function_name) >> CFILE;
158	if (version)
159		printf(", version") >> CFILE;
160	printf(", argp, bp") >> CFILE;
161	if (check_length)
162		printf(", max, lenp") >> CFILE;
163	printf(")\n") >> CFILE;
164
165	printf("\tENV *env;\n") >> CFILE;
166	if (version)
167		printf("\tu_int32_t version;\n") >> CFILE;
168	printf("\t%s *argp;\n", typedef_name) >> CFILE;
169	printf("\tu_int8_t *bp;\n") >> CFILE;
170	if (check_length)
171		printf("\tsize_t *lenp, max;\n") >> CFILE;
172	printf("{\n") >> CFILE;
173
174	if (version)
175		printf("\tint copy_only;\n") >> CFILE;
176	if (check_length) {
177		printf("\tu_int8_t *start;\n\n") >> CFILE;
178		printf("\tif (max < %s", msg_size_name) >> CFILE;
179		for (i = 0; i < nvars; i++)
180			if (types[i] == "DBT")
181				printf("\n\t    + (size_t)argp->%s.size", \
182                                    vars[i]) >> CFILE;
183		# add in dbt sizes
184		printf(")\n") >> CFILE;
185		printf("\t\treturn (ENOMEM);\n") >> CFILE;
186		printf("\tstart = bp;\n\n") >> CFILE;
187	}
188
189	if (version) {
190		printf("\tcopy_only = 0;\n") >> CFILE;
191		printf("\tif (version < DB_REPVERSION_47)\n") >> CFILE;
192		printf("\t\tcopy_only = 1;\n") >> CFILE;
193	}
194	for (i = 0; i < nvars; i++) {
195		if (types[i] == "u_int32_t" || types[i] == "db_pgno_t") {
196			if (version) {
197				printf("\tif (copy_only) {\n") >> CFILE;
198				printf(\
199    "\t\tmemcpy(bp, &argp->%s, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
200				printf(\
201    "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
202				printf("\t} else\n\t") >> CFILE;
203			}
204			printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s);\n", \
205                            vars[i]) >> CFILE;
206		} else if (types[i] == "u_int16_t") {
207			if (version) {
208				printf("\tif (copy_only) {\n") >> CFILE;
209				printf(\
210    "\t\tmemcpy(bp, &argp->%s, sizeof(u_int16_t));\n", vars[i]) >> CFILE;
211				printf(\
212    "\t\tbp += sizeof(u_int16_t);\n") >> CFILE;
213				printf("\t} else\n\t") >> CFILE;
214			}
215			printf("\tDB_HTONS_COPYOUT(env, bp, argp->%s);\n", \
216                            vars[i]) >> CFILE;
217		} else if (types[i] == "u_int8_t") {
218				printf(\
219    "\t*bp++ = argp->%s;\n", vars[i]) >> CFILE;
220		} else if (types[i] == "DB_LSN") {
221			if (version) {
222				printf("\tif (copy_only) {\n") >> CFILE;
223				printf(\
224    "\t\tmemcpy(bp, &argp->%s.file, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
225				printf(\
226    "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
227				printf(\
228    "\t\tmemcpy(bp, &argp->%s.offset, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
229				printf(\
230    "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
231				printf("\t} else {\n\t") >> CFILE;
232			}
233			printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s.file);\n",\
234                            vars[i]) >> CFILE;
235			if (version)
236				printf("\t") >> CFILE;
237			printf( \
238                            "\tDB_HTONL_COPYOUT(env, bp, argp->%s.offset);\n", \
239                            vars[i]) >> CFILE;
240			if (version)
241				printf("\t}\n") >> CFILE;
242		} else if (types[i] == "DBT") {
243			if (version) {
244				printf("\tif (copy_only) {\n") >> CFILE;
245				printf(\
246    "\t\tmemcpy(bp, &argp->%s.size, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
247				printf(\
248    "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
249				printf("\t} else\n\t") >> CFILE;
250			}
251			printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s.size);\n",\
252                            vars[i]) >> CFILE;
253			printf("\tif (argp->%s.size > 0) {\n", vars[i]) \
254                            >> CFILE;
255			printf( \
256                            "\t\tmemcpy(bp, argp->%s.data, argp->%s.size);\n", \
257                            vars[i], vars[i]) >> CFILE;
258			printf("\t\tbp += argp->%s.size;\n", vars[i]) >> CFILE;
259			printf("\t}\n") >> CFILE;
260		} else {
261			printf("unknown field type: %s", types[i]);
262			exit(1);
263		}
264	}
265
266	if (check_length) {
267		printf("\n\t*lenp = (size_t)(bp - start);\n") >> CFILE;
268		printf("\treturn (0);\n") >> CFILE;
269	}
270	printf("}\n\n") >> CFILE;
271}
272
273function emit_unmarshal()
274{
275	pi = 1;
276	p[pi++] = "int ";
277	function_name = sprintf("%s_unmarshal", base_name);
278	p[pi++] = function_name;
279	p[pi++] = " __P((ENV *, ";
280	if (version)
281		p[pi++] = sprintf("u_int32_t, ");
282	if (alloc)
283		p[pi++] = sprintf("%s **, u_int8_t *, ", typedef_name);
284	else
285		p[pi++] = sprintf("%s *, u_int8_t *, ", typedef_name);
286	p[pi++] = sprintf("size_t, u_int8_t **));");
287	proto_format(p, CFILE);
288
289	printf("int\n") >> CFILE;
290	if (alloc)
291		arg_name = "argpp";
292	else
293		arg_name = "argp";
294	printf("%s(env, ", function_name) >> CFILE;
295	if (version)
296		printf("version, ") >> CFILE;
297	printf("%s, bp, ", arg_name) >> CFILE;
298	printf("max, nextp)\n") >> CFILE;
299	printf("\tENV *env;\n") >> CFILE;
300	if (version)
301		printf("\tu_int32_t version;\n") >> CFILE;
302	if (alloc)
303		printf("\t%s **argpp;\n", typedef_name) >> CFILE;
304	else
305		printf("\t%s *argp;\n", typedef_name) >> CFILE;
306	printf("\tu_int8_t *bp;\n") >> CFILE;
307	printf("\tsize_t max;\n") >> CFILE;
308	printf("\tu_int8_t **nextp;\n") >> CFILE;
309	printf("{\n") >> CFILE;
310	has_locals = 0;
311	if (has_dbt) {
312		printf("\tsize_t needed;\n") >> CFILE;
313		has_locals = 1;
314	}
315	if (alloc) {
316		printf("\t%s *argp;\n", typedef_name) >> CFILE;
317		printf("\tint ret;\n") >> CFILE;
318		has_locals = 1;
319	}
320	if (version) {
321		printf("\tint copy_only;\n") >> CFILE;
322		has_locals = 1;
323	}
324	if (has_locals)
325		printf("\n") >> CFILE;
326
327	# Check that input byte buffer is long enough.
328	#
329	if (has_dbt) {
330		printf("\tneeded = %s;\n", msg_size_name) >> CFILE;
331		printf("\tif (max < needed)\n") >> CFILE;
332	} else
333		printf("\tif (max < %s)\n", msg_size_name) >> CFILE;
334	printf("\t\tgoto too_few;\n") >> CFILE;
335
336	if (alloc) {
337		printf( \
338              "\tif ((ret = __os_malloc(env, sizeof(*argp), &argp)) != 0)\n") \
339		    >> CFILE;
340		printf("\t\treturn (ret);\n\n") >> CFILE;
341	}
342	if (version) {
343		printf("\tcopy_only = 0;\n") >> CFILE;
344		printf("\tif (version < DB_REPVERSION_47)\n") >> CFILE;
345		printf("\t\tcopy_only = 1;\n") >> CFILE;
346	}
347
348	for (i = 0; i < nvars; i++) {
349		if (types[i] == "u_int32_t" || types[i] == "db_pgno_t") {
350			if (version) {
351				printf("\tif (copy_only) {\n") >> CFILE;
352				printf(\
353    "\t\tmemcpy(&argp->%s, bp, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
354				printf(\
355    "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
356				printf("\t} else\n\t") >> CFILE;
357			}
358			printf("\tDB_NTOHL_COPYIN(env, argp->%s, bp);\n", \
359                            vars[i]) >> CFILE;
360		} else if (types[i] == "u_int16_t") {
361			if (version) {
362				printf("\tif (copy_only) {\n") >> CFILE;
363				printf(\
364    "\t\tmemcpy(&argp->%s, bp, sizeof(u_int16_t));\n", vars[i]) >> CFILE;
365				printf(\
366    "\t\tbp += sizeof(u_int16_t);\n") >> CFILE;
367				printf("\t} else\n\t") >> CFILE;
368			}
369			printf("\tDB_NTOHS_COPYIN(env, argp->%s, bp);\n", \
370                            vars[i]) >> CFILE;
371		} else if (types[i] == "u_int8_t") {
372				printf(\
373    "\targp->%s = *bp++;\n", vars[i]) >> CFILE;
374		} else if (types[i] == "DB_LSN") {
375			if (version) {
376				printf("\tif (copy_only) {\n") >> CFILE;
377				printf(\
378    "\t\tmemcpy(&argp->%s.file, bp, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
379				printf(\
380    "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
381				printf(\
382    "\t\tmemcpy(&argp->%s.offset, bp, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
383				printf(\
384    "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
385				printf("\t} else {\n\t") >> CFILE;
386			}
387			printf("\tDB_NTOHL_COPYIN(env, argp->%s.file, bp);\n", \
388                            vars[i]) >> CFILE;
389			if (version)
390				printf("\t") >> CFILE;
391			printf( \
392                            "\tDB_NTOHL_COPYIN(env, argp->%s.offset, bp);\n", \
393                            vars[i]) >> CFILE;
394			if (version)
395				printf("\t}\n") >> CFILE;
396		} else if (types[i] == "DBT") {
397			if (version) {
398				printf("\tif (copy_only) {\n") >> CFILE;
399				printf(\
400    "\t\tmemcpy(&argp->%s.size, bp, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
401				printf(\
402    "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
403				printf("\t} else\n\t") >> CFILE;
404			}
405			printf("\tDB_NTOHL_COPYIN(env, argp->%s.size, bp);\n", \
406                            vars[i]) >> CFILE;
407			printf("\tif (argp->%s.size == 0)\n", vars[i]) >> CFILE;
408			printf("\t\targp->%s.data = NULL;\n", vars[i]) >> CFILE;
409			printf("\telse\n") >> CFILE;
410			printf("\t\targp->%s.data = bp;\n", vars[i]) >> CFILE;
411			printf("\tneeded += (size_t)argp->%s.size;\n", \
412                            vars[i]) >> CFILE;
413			printf("\tif (max < needed)\n") >> CFILE;
414			printf("\t\tgoto too_few;\n") >> CFILE;
415			printf("\tbp += argp->%s.size;\n", vars[i]) >> CFILE;
416		} else {
417			printf("unknown field type: %s", types[i]);
418			exit(1);
419		}
420	}
421
422	printf("\n\tif (nextp != NULL)\n") >> CFILE;
423	printf("\t\t*nextp = bp;\n") >> CFILE;
424	if (alloc) {
425		printf("\t*argpp = argp;\n") >> CFILE;
426	}
427	printf("\treturn (0);\n\n") >> CFILE;
428
429	printf("too_few:\n") >> CFILE;
430	printf("\t__db_errx(env, DB_STR(\"3675\",\n") >> CFILE;
431	printf("\t    \"Not enough input bytes to fill a %s message\"));\n", \
432	    base_name) >> CFILE;
433	printf("\treturn (EINVAL);\n") >> CFILE;
434	printf("}\n\n") >> CFILE;
435}
436
437# proto_format --
438#	Pretty-print a function prototype.
439function proto_format(p, fp)
440{
441	printf("/*\n") >> fp;
442
443	s = "";
444	for (i = 1; i in p; ++i)
445		s = s p[i];
446
447	t = " * PUBLIC: "
448	if (length(s) + length(t) < 80)
449		printf("%s%s", t, s) >> fp;
450	else {
451		split(s, p, "__P");
452		len = length(t) + length(p[1]);
453		printf("%s%s", t, p[1]) >> fp
454
455		n = split(p[2], comma, ",");
456		comma[1] = "__P" comma[1];
457		for (i = 1; i <= n; i++) {
458			if (len + length(comma[i]) > 70) {
459				printf("\n * PUBLIC:	") >> fp;
460				len = 0;
461			}
462			printf("%s%s", comma[i], i == n ? "" : ",") >> fp;
463			len += length(comma[i]) + 2;
464		}
465	}
466	printf("\n */\n") >> fp;
467	delete p;
468}
469