Add BSD license file
[platform/upstream/db4.git] / dist / gen_msg.awk
1 #
2 # See the file LICENSE for redistribution information.
3 #
4 # Copyright (c) 1996-2009 Oracle.  All rights reserved.
5 #
6 # $Id$
7 #
8
9 BEGIN {
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_AUTO_H\n#define\t%s_AUTO_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 }
112 END {
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 #
121 function 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         printf("unknown field type: %s", type);
130         exit(1);
131 }
132
133 function emit_marshal()
134 {
135         pi = 1;
136         if (check_length)
137                 p[pi++] = "int ";
138         else
139                 p[pi++] = "void ";
140         function_name = sprintf("%s_marshal", base_name);
141         p[pi++] = function_name;
142         p[pi++] = " __P((ENV *, ";
143         if (version)
144                 p[pi++] = "u_int32_t, ";
145         p[pi++] = sprintf("%s *, u_int8_t *", typedef_name);
146         if (check_length)
147                 p[pi++] = ", size_t, size_t *";
148         p[pi++] = "));";
149         proto_format(p, CFILE);
150
151         if (check_length)
152                 printf("int\n") >> CFILE;
153         else
154                 printf("void\n") >> CFILE;
155         printf("%s(env", function_name) >> CFILE;
156         if (version)
157                 printf(", version") >> CFILE;
158         printf(", argp, bp") >> CFILE;
159         if (check_length)
160                 printf(", max, lenp") >> CFILE;
161         printf(")\n") >> CFILE;
162
163         printf("\tENV *env;\n") >> CFILE;
164         if (version)
165                 printf("\tu_int32_t version;\n") >> CFILE;
166         printf("\t%s *argp;\n", typedef_name) >> CFILE;
167         printf("\tu_int8_t *bp;\n") >> CFILE;
168         if (check_length)
169                 printf("\tsize_t *lenp, max;\n") >> CFILE;
170         printf("{\n") >> CFILE;
171
172         if (version)
173                 printf("\tint copy_only;\n") >> CFILE;
174         if (check_length) {
175                 printf("\tu_int8_t *start;\n\n") >> CFILE;
176                 printf("\tif (max < %s", msg_size_name) >> CFILE;
177                 for (i = 0; i < nvars; i++)
178                         if (types[i] == "DBT")
179                                 printf("\n\t    + (size_t)argp->%s.size", \
180                                     vars[i]) >> CFILE;
181                 # add in dbt sizes
182                 printf(")\n") >> CFILE;
183                 printf("\t\treturn (ENOMEM);\n") >> CFILE;
184                 printf("\tstart = bp;\n\n") >> CFILE;
185         }
186
187         if (version) {
188                 printf("\tcopy_only = 0;\n") >> CFILE;
189                 printf("\tif (version < DB_REPVERSION_47)\n") >> CFILE;
190                 printf("\t\tcopy_only = 1;\n") >> CFILE;
191         }
192         for (i = 0; i < nvars; i++) {
193                 if (types[i] == "u_int32_t" || types[i] == "db_pgno_t") {
194                         if (version) {
195                                 printf("\tif (copy_only) {\n") >> CFILE;
196                                 printf(\
197     "\t\tmemcpy(bp, &argp->%s, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
198                                 printf(\
199     "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
200                                 printf("\t} else\n\t") >> CFILE;
201                         }
202                         printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s);\n", \
203                             vars[i]) >> CFILE;
204                 } else if (types[i] == "u_int16_t") {
205                         if (version) {
206                                 printf("\tif (copy_only) {\n") >> CFILE;
207                                 printf(\
208     "\t\tmemcpy(bp, &argp->%s, sizeof(u_int16_t));\n", vars[i]) >> CFILE;
209                                 printf(\
210     "\t\tbp += sizeof(u_int16_t);\n") >> CFILE;
211                                 printf("\t} else\n\t") >> CFILE;
212                         }
213                         printf("\tDB_HTONS_COPYOUT(env, bp, argp->%s);\n", \
214                             vars[i]) >> CFILE;
215                 } else if (types[i] == "DB_LSN") {
216                         if (version) {
217                                 printf("\tif (copy_only) {\n") >> CFILE;
218                                 printf(\
219     "\t\tmemcpy(bp, &argp->%s.file, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
220                                 printf(\
221     "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
222                                 printf(\
223     "\t\tmemcpy(bp, &argp->%s.offset, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
224                                 printf(\
225     "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
226                                 printf("\t} else {\n\t") >> CFILE;
227                         }
228                         printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s.file);\n",\
229                             vars[i]) >> CFILE;
230                         if (version)
231                                 printf("\t") >> CFILE;
232                         printf( \
233                             "\tDB_HTONL_COPYOUT(env, bp, argp->%s.offset);\n", \
234                             vars[i]) >> CFILE;
235                         if (version)
236                                 printf("\t}\n") >> CFILE;
237                 } else if (types[i] == "DBT") {
238                         if (version) {
239                                 printf("\tif (copy_only) {\n") >> CFILE;
240                                 printf(\
241     "\t\tmemcpy(bp, &argp->%s.size, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
242                                 printf(\
243     "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
244                                 printf("\t} else\n\t") >> CFILE;
245                         }
246                         printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s.size);\n",\
247                             vars[i]) >> CFILE;
248                         printf("\tif (argp->%s.size > 0) {\n", vars[i]) \
249                             >> CFILE;
250                         printf( \
251                             "\t\tmemcpy(bp, argp->%s.data, argp->%s.size);\n", \
252                             vars[i], vars[i]) >> CFILE;
253                         printf("\t\tbp += argp->%s.size;\n", vars[i]) >> CFILE;
254                         printf("\t}\n") >> CFILE;
255                 } else {
256                         printf("unknown field type: %s", types[i]);
257                         exit(1);
258                 }
259         }
260
261         if (check_length) {
262                 printf("\n\t*lenp = (size_t)(bp - start);\n") >> CFILE;
263                 printf("\treturn (0);\n") >> CFILE;
264         }
265         printf("}\n\n") >> CFILE;
266 }
267
268 function emit_unmarshal()
269 {
270         pi = 1;
271         p[pi++] = "int ";
272         function_name = sprintf("%s_unmarshal", base_name);
273         p[pi++] = function_name;
274         p[pi++] = " __P((ENV *, ";
275         if (version)
276                 p[pi++] = sprintf("u_int32_t, ");
277         if (alloc)
278                 p[pi++] = sprintf("%s **, u_int8_t *, ", typedef_name);
279         else
280                 p[pi++] = sprintf("%s *, u_int8_t *, ", typedef_name);
281         p[pi++] = sprintf("size_t, u_int8_t **));");
282         proto_format(p, CFILE);
283
284         printf("int\n") >> CFILE;
285         if (alloc)
286                 arg_name = "argpp";
287         else
288                 arg_name = "argp";
289         printf("%s(env, ", function_name) >> CFILE;
290         if (version)
291                 printf("version, ") >> CFILE;
292         printf("%s, bp, ", arg_name) >> CFILE;
293         printf("max, nextp)\n") >> CFILE;
294         printf("\tENV *env;\n") >> CFILE;
295         if (version)
296                 printf("\tu_int32_t version;\n") >> CFILE;
297         if (alloc)
298                 printf("\t%s **argpp;\n", typedef_name) >> CFILE;
299         else
300                 printf("\t%s *argp;\n", typedef_name) >> CFILE;
301         printf("\tu_int8_t *bp;\n") >> CFILE;
302         printf("\tsize_t max;\n") >> CFILE;
303         printf("\tu_int8_t **nextp;\n") >> CFILE;
304         printf("{\n") >> CFILE;
305         has_locals = 0;
306         if (has_dbt) {
307                 printf("\tsize_t needed;\n") >> CFILE;
308                 has_locals = 1;
309         }
310         if (alloc) {
311                 printf("\t%s *argp;\n", typedef_name) >> CFILE;
312                 printf("\tint ret;\n") >> CFILE;
313                 has_locals = 1;
314         }
315         if (version) {
316                 printf("\tint copy_only;\n") >> CFILE;
317                 has_locals = 1;
318         }
319         if (has_locals)
320                 printf("\n") >> CFILE;
321
322         # Check that input byte buffer is long enough.
323         #
324         if (has_dbt) {
325                 printf("\tneeded = %s;\n", msg_size_name) >> CFILE;
326                 printf("\tif (max < needed)\n") >> CFILE;
327         } else 
328                 printf("\tif (max < %s)\n", msg_size_name) >> CFILE;
329         printf("\t\tgoto too_few;\n") >> CFILE;
330
331         if (alloc) {
332                 printf( \
333               "\tif ((ret = __os_malloc(env, sizeof(*argp), &argp)) != 0)\n") \
334                     >> CFILE;
335                 printf("\t\treturn (ret);\n\n") >> CFILE;
336         }
337         if (version) {
338                 printf("\tcopy_only = 0;\n") >> CFILE;
339                 printf("\tif (version < DB_REPVERSION_47)\n") >> CFILE;
340                 printf("\t\tcopy_only = 1;\n") >> CFILE;
341         }
342         
343         for (i = 0; i < nvars; i++) {
344                 if (types[i] == "u_int32_t" || types[i] == "db_pgno_t") {
345                         if (version) {
346                                 printf("\tif (copy_only) {\n") >> CFILE;
347                                 printf(\
348     "\t\tmemcpy(&argp->%s, bp, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
349                                 printf(\
350     "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
351                                 printf("\t} else\n\t") >> CFILE;
352                         }
353                         printf("\tDB_NTOHL_COPYIN(env, argp->%s, bp);\n", \
354                             vars[i]) >> CFILE;
355                 } else if (types[i] == "u_int16_t") {
356                         if (version) {
357                                 printf("\tif (copy_only) {\n") >> CFILE;
358                                 printf(\
359     "\t\tmemcpy(&argp->%s, bp, sizeof(u_int16_t));\n", vars[i]) >> CFILE;
360                                 printf(\
361     "\t\tbp += sizeof(u_int16_t);\n") >> CFILE;
362                                 printf("\t} else\n\t") >> CFILE;
363                         }
364                         printf("\tDB_NTOHS_COPYIN(env, argp->%s, bp);\n", \
365                             vars[i]) >> CFILE;
366                 } else if (types[i] == "DB_LSN") {
367                         if (version) {
368                                 printf("\tif (copy_only) {\n") >> CFILE;
369                                 printf(\
370     "\t\tmemcpy(&argp->%s.file, bp, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
371                                 printf(\
372     "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
373                                 printf(\
374     "\t\tmemcpy(&argp->%s.offset, bp, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
375                                 printf(\
376     "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
377                                 printf("\t} else {\n\t") >> CFILE;
378                         }
379                         printf("\tDB_NTOHL_COPYIN(env, argp->%s.file, bp);\n", \
380                             vars[i]) >> CFILE;
381                         if (version)
382                                 printf("\t") >> CFILE;
383                         printf( \
384                             "\tDB_NTOHL_COPYIN(env, argp->%s.offset, bp);\n", \
385                             vars[i]) >> CFILE;
386                         if (version)
387                                 printf("\t}\n") >> CFILE;
388                 } else if (types[i] == "DBT") {
389                         if (version) {
390                                 printf("\tif (copy_only) {\n") >> CFILE;
391                                 printf(\
392     "\t\tmemcpy(&argp->%s.size, bp, sizeof(u_int32_t));\n", vars[i]) >> CFILE;
393                                 printf(\
394     "\t\tbp += sizeof(u_int32_t);\n") >> CFILE;
395                                 printf("\t} else\n\t") >> CFILE;
396                         }
397                         printf("\tDB_NTOHL_COPYIN(env, argp->%s.size, bp);\n", \
398                             vars[i]) >> CFILE;
399                         printf("\targp->%s.data = bp;\n", vars[i]) >> CFILE;
400                         printf("\tneeded += (size_t)argp->%s.size;\n", \
401                             vars[i]) >> CFILE;
402                         printf("\tif (max < needed)\n") >> CFILE;
403                         printf("\t\tgoto too_few;\n") >> CFILE;
404                         printf("\tbp += argp->%s.size;\n", vars[i]) >> CFILE;
405                 } else {
406                         printf("unknown field type: %s", types[i]);
407                         exit(1);
408                 }
409         }
410
411         printf("\n\tif (nextp != NULL)\n") >> CFILE;
412         printf("\t\t*nextp = bp;\n") >> CFILE;
413         if (alloc) {
414                 printf("\t*argpp = argp;\n") >> CFILE;
415         }
416         printf("\treturn (0);\n\n") >> CFILE;
417
418         printf("too_few:\n") >> CFILE;
419         printf("\t__db_errx(env,\n") >> CFILE;
420         printf("\t    \"Not enough input bytes to fill a %s message\");\n", \
421             base_name) >> CFILE;
422         printf("\treturn (EINVAL);\n") >> CFILE;
423         printf("}\n\n") >> CFILE;
424 }       
425
426 # proto_format --
427 #       Pretty-print a function prototype.
428 function proto_format(p, fp)
429 {
430         printf("/*\n") >> fp;
431
432         s = "";
433         for (i = 1; i in p; ++i)
434                 s = s p[i];
435
436         t = " * PUBLIC: "
437         if (length(s) + length(t) < 80)
438                 printf("%s%s", t, s) >> fp;
439         else {
440                 split(s, p, "__P");
441                 len = length(t) + length(p[1]);
442                 printf("%s%s", t, p[1]) >> fp
443
444                 n = split(p[2], comma, ",");
445                 comma[1] = "__P" comma[1];
446                 for (i = 1; i <= n; i++) {
447                         if (len + length(comma[i]) > 70) {
448                                 printf("\n * PUBLIC:    ") >> fp;
449                                 len = 0;
450                         }
451                         printf("%s%s", comma[i], i == n ? "" : ",") >> fp;
452                         len += length(comma[i]) + 2;
453                 }
454         }
455         printf("\n */\n") >> fp;
456         delete p;
457 }