Added Gnulib intprops module.
[portablexdr.git] / rpcgen_codegen.c
1 /* -*- C -*-
2  * rpcgen - Generate XDR bindings automatically.
3  * Copyright (C) 2008 Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #include "rpcgen_int.h"
28
29 /* If we're debugging the code generator itself, then #line directives
30  * aren't useful - we want to see the error in the generated code
31  * instead.  Setting this disables #line directives in the output.
32  */
33 #define DEBUG_CODEGEN 0
34
35 static void gen_line (void);
36 static void gen_decl (int indent, const struct decl *);
37 static void gen_decl_xdr_call (int indent, const struct decl *, const char *);
38 static void gen_type (const struct type *);
39
40 static void
41 spaces (int n)
42 {
43   int i;
44
45   for (i = 0; i < n; ++i)
46     fputc (' ', yyout);
47 }
48
49 /* This generates a #line directive referring back to the
50  * original source file.
51  */
52 static void
53 gen_line (void)
54 {
55 #if !DEBUG_CODEGEN
56   if (input_filename)
57     fprintf (yyout, "#line %d \"%s\"\n", yylineno, input_filename);
58 #endif
59 }
60
61 static void
62 write_basename (void)
63 {
64   const char *p = strrchr (output_filename, '/') ? : output_filename;
65   const char *q = strrchr (output_filename, '.');
66
67   while (*p && p != q) {
68     fputc (*p, yyout);
69     ++p;
70   }
71 }
72
73 static void
74 write_basename_caps (void)
75 {
76   const char *p = strrchr (output_filename, '/') ? : output_filename;
77   const char *q = strrchr (output_filename, '.');
78
79   while (*p && p != q) {
80     if (isalnum (*p))
81       fputc (toupper (*p), yyout);
82     else
83       fputc ('_', yyout);
84     ++p;
85   }
86 }
87
88 void
89 gen_prologue (const char *filename)
90 {
91   fprintf (yyout,
92            "/* This file was generated by PortableXDR rpcgen %s\n"
93            " * ANY CHANGES YOU MAKE TO THIS FILE MAY BE LOST!\n"
94            " * The input file was %s\n"
95            " */\n"
96            "\n",
97            PACKAGE_VERSION, filename);
98
99   switch (output_mode)
100     {
101     case output_c:
102       fprintf (yyout, "#include \"");
103       write_basename ();
104       fprintf (yyout, ".h\"\n\n");
105       break;
106
107     case output_h:
108       fprintf (yyout, "#ifndef RPCGEN_HEADER_");
109       write_basename_caps ();
110       fprintf (yyout,
111                "_H\n"
112                "#define RPCGEN_HEADER_");
113       write_basename_caps ();
114       fprintf (yyout,
115                "_H\n"
116                "\n"
117                "#ifdef __cplusplus\n"
118                "extern \"C\" {\n"
119                "#endif\n"
120                "\n"
121                "#include <stdint.h>\n"
122                "#include <rpc/types.h>\n"
123                "#include <rpc/xdr.h>\n"
124                "\n"
125                "/* Use the following symbol in your code to detect whether\n"
126                " * PortableXDR's rpcgen was used to compile the source file.\n"
127                " */\n"
128                "#define PORTABLE_RPCGEN_");
129       write_basename_caps ();
130       fprintf (yyout,
131                " 1\n"
132                "\n");
133       break;
134     }
135 }
136
137 void
138 gen_epilogue (void)
139 {
140   gen_line ();
141
142   switch (output_mode)
143     {
144     case output_c:
145       break;
146
147     case output_h:
148       fprintf (yyout,
149                "\n"
150                "#ifdef __cplusplus\n"
151                "}\n"
152                "#endif\n"
153                "\n"
154                "#endif /* RPCGEN_HEADER_");
155       write_basename_caps ();
156       fprintf (yyout, "_H */\n");
157       break;
158     }
159
160   fprintf (yyout, "\n/* EOF */\n");
161 }
162
163 void
164 gen_const (const char *name, const char *value)
165 {
166   if (output_mode == output_h) {
167     gen_line ();
168
169     fprintf (yyout, "#define %s %s\n", name, value);
170   }
171 }
172
173 void
174 gen_enum (const char *name, const struct cons *enum_values)
175 {
176   gen_line ();
177
178   switch (output_mode)
179     {
180     case output_h:
181       fprintf (yyout, "enum %s {\n", name);
182       while (enum_values) {
183         struct enum_value *enum_value = (struct enum_value *) enum_values->ptr;
184         if (enum_value->value)
185           fprintf (yyout, "  %s = %s,\n",
186                    enum_value->ident, enum_value->value);
187         else
188           fprintf (yyout, "  %s,\n", enum_value->ident);
189         enum_values = enum_values->next;
190       }
191       fprintf (yyout,
192                "};\n"
193                "typedef enum %s %s;\n"
194                "extern bool_t xdr_%s (XDR *, %s *);\n"
195                "\n",
196                name, name, name, name);
197       break;
198
199     case output_c:
200       fprintf (yyout,
201                "bool_t\n"
202                "xdr_%s (XDR *xdrs, %s *objp)\n"
203                "{\n"
204                "  if (!xdr_enum (xdrs, (enum_t *) objp))\n"
205                "    return FALSE;\n"
206                "  return TRUE;\n"
207                "}\n"
208                "\n",
209                name, name);
210       break;
211     }
212 }
213
214 /* The Sun rpcgen seems to do some sort of inlining optimization based
215  * on {size of struct|number of elements}(?)  We don't do any such
216  * optimization.  Instead we rely on gcc doing the correct level of
217  * optimization based on inlined functions found in the header files.
218  */
219 void
220 gen_struct (const char *name, const struct cons *decls)
221 {
222   gen_line ();
223
224   switch (output_mode)
225     {
226     case output_h:
227       fprintf (yyout, "struct %s {\n", name);
228       while (decls) {
229         gen_decl (2, (struct decl *) decls->ptr);
230         decls = decls->next;
231       }
232       fprintf (yyout,
233                "};\n"
234                "typedef struct %s %s;\n"
235                "extern bool_t xdr_%s (XDR *, %s *);\n"
236                "\n",
237                name, name, name, name);
238       break;
239
240     case output_c:
241       fprintf (yyout,
242                "bool_t\n"
243                "xdr_%s (XDR *xdrs, %s *objp)\n"
244                "{\n",
245                name, name);
246       while (decls) {
247         gen_decl_xdr_call (2, (struct decl *) decls->ptr, "&objp->");
248         decls = decls->next;
249       }
250       fprintf (yyout,
251                "  return TRUE;\n"
252                "}\n"
253                "\n");
254       break;
255     }
256 }
257
258 void
259 gen_union (const char *name, const struct decl *discrim,
260            const struct cons *union_cases)
261 {
262   char *str;
263   int len;
264
265   gen_line ();
266
267   switch (output_mode)
268     {
269     case output_h:
270       fprintf (yyout, "struct %s {\n", name);
271       gen_decl (2, discrim);
272       fprintf (yyout, "  union {\n");
273
274       while (union_cases) {
275         struct union_case *uc = (struct union_case *) union_cases->ptr;
276         if (uc->decl) gen_decl (4, uc->decl);
277         union_cases = union_cases->next;
278       }
279       fprintf (yyout,
280                "  } %s_u;\n"
281                "};\n"
282                "typedef struct %s %s;\n"
283                "extern bool_t xdr_%s (XDR *, %s *);\n"
284                "\n",
285                name, name, name, name, name);
286       break;
287
288     case output_c:
289       fprintf (yyout,
290                "bool_t\n"
291                "xdr_%s (XDR *xdrs, %s *objp)\n"
292                "{\n",
293                name, name);
294       gen_decl_xdr_call (2, discrim, "&objp->");
295       fprintf (yyout,
296                "  switch (objp->%s) {\n",
297                discrim->ident);
298
299       len = strlen (name) + 11;
300       str = malloc (len);
301       snprintf (str, len, "&objp->%s_u.", name);
302
303       while (union_cases) {
304         struct union_case *uc = (struct union_case *) union_cases->ptr;
305         fprintf (yyout,
306                  "  case %s:\n",
307                  uc->const_);
308         gen_decl_xdr_call (4, uc->decl, str);
309         fprintf (yyout,
310                  "    break;\n");
311         union_cases = union_cases->next;
312       }
313       fprintf (yyout,
314                "  }\n"
315                "  return TRUE;\n"
316                "}\n"
317                "\n");
318       free (str);
319       break;
320     }
321 }
322
323 void
324 gen_typedef (const struct decl *decl)
325 {
326   gen_line ();
327
328   switch (output_mode)
329     {
330     case output_h:
331       fputs ("typedef ", yyout);
332       gen_decl (0, decl);
333
334       fprintf (yyout,
335                "extern bool_t xdr_%s (XDR *, %s *);\n"
336                "\n",
337                decl->ident, decl->ident);
338       break;
339
340     case output_c:
341       fprintf (yyout,
342                "bool_t\n");
343       fprintf (yyout, "xdr_%s (XDR *xdrs, %s *objp)\n",
344                decl->ident, decl->ident);
345       fprintf (yyout, "{\n");
346       gen_decl_xdr_call (2, decl, "&objp->");
347       fprintf (yyout,
348                "  return TRUE;\n"
349                "}\n"
350                "\n");
351       break;
352     }
353 }
354
355 static void
356 gen_decl (int indent, const struct decl *decl)
357 {
358   spaces (indent);
359
360   switch (decl->decl_type)
361     {
362     case decl_type_string:
363       fprintf (yyout, "char *%s;\n", decl->ident);
364       break;
365
366     case decl_type_opaque_fixed:
367       fprintf (yyout, "char %s[%s];\n", decl->ident, decl->len);
368       break;
369
370     case decl_type_opaque_variable:
371       fprintf (yyout, "struct {\n");
372       spaces (indent+2);
373       fprintf (yyout, "uint32_t %s_len;\n", decl->ident);
374       spaces (indent+2);
375       fprintf (yyout, "char *%s_val;\n", decl->ident);
376       spaces (indent);
377       fprintf (yyout, "} %s;\n", decl->ident);
378       break;
379
380     case decl_type_simple:
381       gen_type (decl->type);
382       fprintf (yyout, " %s;\n", decl->ident);
383       break;
384
385     case decl_type_fixed_array:
386       gen_type (decl->type);
387       fprintf (yyout, " %s[%s];\n", decl->ident, decl->len);
388       break;
389
390     case decl_type_variable_array:
391       fprintf (yyout, "struct {\n");
392       spaces (indent+2);
393       fprintf (yyout, "uint32_t %s_len;\n", decl->ident);
394       spaces (indent+2);
395       gen_type (decl->type);
396       fprintf (yyout, " *%s_val;\n", decl->ident);
397       spaces (indent);
398       fprintf (yyout, "} %s;\n", decl->ident);
399       break;
400
401     case decl_type_pointer:
402       gen_type (decl->type);
403       fprintf (yyout, " *%s;\n", decl->ident);
404       break;
405     }
406 }
407
408 static const char *
409 xdr_func_of_simple_type (const struct type *type)
410 {
411   const char *r;
412
413   /* The caller supplies the "xdr_" prefix. */
414   switch (type->type) {
415   case type_char:
416     if (type->sgn) r = "char"; else r = "u_char";
417     break;
418   case type_short:
419     if (type->sgn) r = "short"; else r = "u_short";
420     break;
421   case type_int:
422     if (type->sgn) r = "int"; else r = "u_int";
423     break;
424   case type_hyper:
425     if (type->sgn) r = "quad_t"; else r = "u_quad_t";
426     break;
427   case type_float:
428     r = "float";
429     break;
430   case type_double:
431     r = "double";
432     break;
433   case type_bool:
434     r = "bool";
435     break;
436   case type_ident:
437     r = type->ident;
438     break;
439   default: abort ();            /* Avoid GCC warning. */
440   }
441   return r;
442 }
443
444 /* Caller must free the result. */
445 static char *
446 sizeof_simple_type (const struct type *type)
447 {
448   int len;
449   char *str, *r;
450
451   switch (type->type) {
452   case type_char:
453     r = strdup ("1");           /* Note: fixed by the XDR RFC. */
454     break;
455   case type_short:
456     r = strdup ("2");
457     break;
458   case type_int:
459     r = strdup ("4");
460     break;
461   case type_hyper:
462     r = strdup ("8");
463     break;
464   case type_float:
465     r = strdup ("4");
466     break;
467   case type_double:
468     r = strdup ("8");
469     break;
470   case type_bool:
471     r = strdup ("4");
472     break;
473   case type_ident:
474     len = strlen (type->ident) + 10;
475     str = malloc (len);
476     snprintf (str, len, "sizeof (%s)", type->ident);
477     r = str;
478     break;
479   default: abort ();            /* Avoid GCC warning. */
480   }
481
482   return r;
483 }
484
485 static void
486 gen_decl_xdr_call (int indent, const struct decl *decl, const char *struct_name)
487 {
488   char *str;
489   char *len_str;
490
491   spaces (indent);
492
493   switch (decl->decl_type)
494     {
495     case decl_type_string:
496       if (decl->len)
497         fprintf (yyout, "if (!xdr_string (xdrs, objp, %s))\n", decl->len);
498       else
499         fprintf (yyout, "if (!xdr_string (xdrs, objp, ~0))\n");
500       break;
501
502     case decl_type_opaque_fixed:
503       fprintf (yyout, "if (!xdr_opaque (xdrs, &objp, %s))\n", decl->len);
504       break;
505
506     case decl_type_opaque_variable:
507       len_str = decl->len ? : "~0";
508       fprintf (yyout,
509                "if (!xdr_bytes (xdrs, %s%s.%s_val, %s%s.%s_len, %s))\n",
510                struct_name, decl->ident, decl->ident,
511                struct_name, decl->ident, decl->ident, len_str);
512       break;
513
514     case decl_type_simple:
515       fprintf (yyout, "if (!xdr_%s (xdrs, %s%s))\n",
516                xdr_func_of_simple_type (decl->type), struct_name, decl->ident);
517       break;
518
519     case decl_type_fixed_array:
520       str = sizeof_simple_type (decl->type);
521       fprintf (yyout,
522                "if (!xdr_vector (xdrs, %s%s, %s, %s, (xdrproc_t) xdr_%s))\n",
523                struct_name, decl->ident, decl->len,
524                str, xdr_func_of_simple_type (decl->type));
525       free (str);
526       break;
527
528     case decl_type_variable_array:
529       str = sizeof_simple_type (decl->type);
530       len_str = decl->len ? : "~0";
531       fprintf (yyout,
532                "if (!xdr_array (xdrs, %s%s.%s_val, %s%s.%s_len, %s, %s, (xdrproc_t) xdr_%s))\n",
533                struct_name, decl->ident, decl->ident,
534                struct_name, decl->ident, decl->ident,
535                len_str,
536                str, xdr_func_of_simple_type (decl->type));
537       free (str);
538       break;
539
540     case decl_type_pointer:
541       str = sizeof_simple_type (decl->type);
542       fprintf (yyout, "if (!xdr_pointer (xdrs, objp, %s, (xdrproc_t) xdr_%s))\n",
543                str, xdr_func_of_simple_type (decl->type));
544       free (str);
545       break;
546     }
547
548   spaces (indent+2);
549   fprintf (yyout, "return FALSE;\n");
550 }
551
552 static void
553 gen_type (const struct type *type)
554 {
555   switch (type->type)
556     {
557     case type_char:
558       if (type->sgn) fputs ("int8_t", yyout);
559       else fputs ("uint8_t", yyout);
560       break;
561
562     case type_short:
563       if (type->sgn) fputs ("int16_t", yyout);
564       else fputs ("uint16_t", yyout);
565       break;
566
567     case type_int:
568       if (type->sgn) fputs ("int32_t", yyout);
569       else fputs ("uint32_t", yyout);
570       break;
571
572     case type_hyper:
573       if (type->sgn) fputs ("int64_t", yyout);
574       else fputs ("uint64_t", yyout);
575       break;
576
577     case type_float:
578       fputs ("float", yyout);
579       break;
580
581     case type_double:
582       fputs ("double", yyout);
583       break;
584
585     case type_bool:
586       fputs ("bool_t", yyout);
587       break;
588
589     case type_ident:
590       fputs (type->ident, yyout);
591       break;
592     }
593 }