Seems to create a reasonable .c and .h file now.
[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/rpc.h>\n"
123                "\n"
124                "/* Use the following symbol in your code to detect whether\n"
125                " * PortableXDR's rpcgen was used to compile the source file.\n"
126                " */\n"
127                "#define PORTABLE_RPCGEN_");
128       write_basename_caps ();
129       fprintf (yyout,
130                " 1\n"
131                "\n");
132       break;
133     }
134 }
135
136 void
137 gen_epilogue (void)
138 {
139   gen_line ();
140
141   switch (output_mode)
142     {
143     case output_c:
144       break;
145
146     case output_h:
147       fprintf (yyout,
148                "\n"
149                "#ifdef __cplusplus\n"
150                "}\n"
151                "#endif\n"
152                "\n"
153                "#endif /* RPCGEN_HEADER_");
154       write_basename_caps ();
155       fprintf (yyout, "_H */\n");
156       break;
157     }
158
159   fprintf (yyout, "\n/* EOF */\n");
160 }
161
162 void
163 gen_const (const char *name, const char *value)
164 {
165   if (output_mode == output_h) {
166     gen_line ();
167
168     fprintf (yyout, "#define %s %s\n", name, value);
169   }
170 }
171
172 void
173 gen_enum (const char *name, const struct cons *enum_values)
174 {
175   gen_line ();
176
177   switch (output_mode)
178     {
179     case output_h:
180       fprintf (yyout, "enum %s {\n", name);
181       while (enum_values) {
182         struct enum_value *enum_value = (struct enum_value *) enum_values->ptr;
183         if (enum_value->value)
184           fprintf (yyout, "  %s = %s,\n",
185                    enum_value->ident, enum_value->value);
186         else
187           fprintf (yyout, "  %s,\n", enum_value->ident);
188         enum_values = enum_values->next;
189       }
190       fprintf (yyout,
191                "};\n"
192                "typedef enum %s %s;\n"
193                "extern bool_t xdr_%s (XDR *, %s *);\n"
194                "\n",
195                name, name, name, name);
196       break;
197
198     case output_c:
199       fprintf (yyout,
200                "bool_t\n"
201                "xdr_%s (XDR *xdrs, %s *objp)\n"
202                "{\n"
203                "  if (!xdr_enum (xdrs, (enum_t *) objp))\n"
204                "    return FALSE;\n"
205                "  return TRUE;\n"
206                "}\n"
207                "\n",
208                name, name);
209       break;
210     }
211 }
212
213 /* The Sun rpcgen seems to do some sort of inlining optimization based
214  * on {size of struct|number of elements}(?)  We don't do any such
215  * optimization.  Instead we rely on gcc doing the correct level of
216  * optimization based on inlined functions found in the header files.
217  */
218 void
219 gen_struct (const char *name, const struct cons *decls)
220 {
221   gen_line ();
222
223   switch (output_mode)
224     {
225     case output_h:
226       fprintf (yyout, "struct %s {\n", name);
227       while (decls) {
228         gen_decl (2, (struct decl *) decls->ptr);
229         decls = decls->next;
230       }
231       fprintf (yyout,
232                "};\n"
233                "typedef struct %s %s;\n"
234                "extern bool_t xdr_%s (XDR *, %s *);\n"
235                "\n",
236                name, name, name, name);
237       break;
238
239     case output_c:
240       fprintf (yyout,
241                "bool_t\n"
242                "xdr_%s (XDR *xdrs, %s *objp)\n"
243                "{\n",
244                name, name);
245       while (decls) {
246         gen_decl_xdr_call (2, (struct decl *) decls->ptr, "&objp->");
247         decls = decls->next;
248       }
249       fprintf (yyout,
250                "  return TRUE;\n"
251                "}\n"
252                "\n");
253       break;
254     }
255 }
256
257 void
258 gen_union (const char *name, const struct decl *discrim,
259            const struct cons *union_cases)
260 {
261   char *str;
262   int len;
263
264   gen_line ();
265
266   switch (output_mode)
267     {
268     case output_h:
269       fprintf (yyout, "struct %s {\n", name);
270       gen_decl (2, discrim);
271       fprintf (yyout, "  union {\n");
272
273       while (union_cases) {
274         struct union_case *uc = (struct union_case *) union_cases->ptr;
275         if (uc->decl) gen_decl (4, uc->decl);
276         union_cases = union_cases->next;
277       }
278       fprintf (yyout,
279                "  } %s_u;\n"
280                "};\n"
281                "typedef struct %s %s;\n"
282                "extern bool_t xdr_%s (XDR *, %s *);\n"
283                "\n",
284                name, name, name, name, name);
285       break;
286
287     case output_c:
288       fprintf (yyout,
289                "bool_t\n"
290                "xdr_%s (XDR *xdrs, %s *objp)\n"
291                "{\n",
292                name, name);
293       gen_decl_xdr_call (2, discrim, "&objp->");
294       fprintf (yyout,
295                "  switch (objp->%s) {\n",
296                discrim->ident);
297
298       len = strlen (name) + 11;
299       str = malloc (len);
300       snprintf (str, len, "&objp->%s_u.", name);
301
302       while (union_cases) {
303         struct union_case *uc = (struct union_case *) union_cases->ptr;
304         fprintf (yyout,
305                  "  case %s:\n",
306                  uc->const_);
307         gen_decl_xdr_call (4, uc->decl, str);
308         fprintf (yyout,
309                  "    break;\n");
310         union_cases = union_cases->next;
311       }
312       fprintf (yyout,
313                "  }\n"
314                "  return TRUE;\n"
315                "}\n"
316                "\n");
317       free (str);
318       break;
319     }
320 }
321
322 void
323 gen_typedef (const struct decl *decl)
324 {
325   gen_line ();
326
327   switch (output_mode)
328     {
329     case output_h:
330       fputs ("typedef ", yyout);
331       gen_decl (0, decl);
332
333       fprintf (yyout,
334                "extern bool_t xdr_%s (XDR *, %s *);\n"
335                "\n",
336                decl->ident, decl->ident);
337       break;
338
339     case output_c:
340       fprintf (yyout,
341                "bool_t\n");
342       fprintf (yyout, "xdr_%s (XDR *xdrs, %s *objp)\n",
343                decl->ident, decl->ident);
344       fprintf (yyout, "{\n");
345       gen_decl_xdr_call (2, decl, "&objp->");
346       fprintf (yyout,
347                "  return TRUE;\n"
348                "}\n"
349                "\n");
350       break;
351     }
352 }
353
354 static void
355 gen_decl (int indent, const struct decl *decl)
356 {
357   spaces (indent);
358
359   switch (decl->decl_type)
360     {
361     case decl_type_string:
362       fprintf (yyout, "char *%s;\n", decl->ident);
363       break;
364
365     case decl_type_opaque_fixed:
366       fprintf (yyout, "char %s[%s];\n", decl->ident, decl->len);
367       break;
368
369     case decl_type_opaque_variable:
370       fprintf (yyout, "struct {\n");
371       spaces (indent+2);
372       fprintf (yyout, "uint32_t %s_len;\n", decl->ident);
373       spaces (indent+2);
374       fprintf (yyout, "char *%s_val;\n", decl->ident);
375       spaces (indent);
376       fprintf (yyout, "} %s;\n", decl->ident);
377       break;
378
379     case decl_type_simple:
380       gen_type (decl->type);
381       fprintf (yyout, " %s;\n", decl->ident);
382       break;
383
384     case decl_type_fixed_array:
385       gen_type (decl->type);
386       fprintf (yyout, " %s[%s];\n", decl->ident, decl->len);
387       break;
388
389     case decl_type_variable_array:
390       fprintf (yyout, "struct {\n");
391       spaces (indent+2);
392       fprintf (yyout, "uint32_t %s_len;\n", decl->ident);
393       spaces (indent+2);
394       gen_type (decl->type);
395       fprintf (yyout, " *%s_val;\n", decl->ident);
396       spaces (indent);
397       fprintf (yyout, "} %s;\n", decl->ident);
398       break;
399
400     case decl_type_pointer:
401       gen_type (decl->type);
402       fprintf (yyout, " *%s;\n", decl->ident);
403       break;
404     }
405 }
406
407 static const char *
408 xdr_func_of_simple_type (const struct type *type)
409 {
410   const char *r;
411
412   /* The caller supplies the "xdr_" prefix. */
413   switch (type->type) {
414   case type_char:
415     if (type->sgn) r = "char"; else r = "u_char";
416     break;
417   case type_short:
418     if (type->sgn) r = "short"; else r = "u_short";
419     break;
420   case type_int:
421     if (type->sgn) r = "int"; else r = "u_int";
422     break;
423   case type_hyper:
424     if (type->sgn) r = "quad_t"; else r = "u_quad_t";
425     break;
426   case type_double:
427     r = "double";
428     break;
429   case type_bool:
430     r = "bool";
431     break;
432   case type_ident:
433     r = type->ident;
434     break;
435   default: abort ();            /* Avoid GCC warning. */
436   }
437   return r;
438 }
439
440 /* Caller must free the result. */
441 static char *
442 sizeof_simple_type (const struct type *type)
443 {
444   int len;
445   char *str, *r;
446
447   switch (type->type) {
448   case type_char:
449     r = strdup ("1");           /* Note: fixed by the XDR RFC. */
450     break;
451   case type_short:
452     r = strdup ("2");
453     break;
454   case type_int:
455     r = strdup ("4");
456     break;
457   case type_hyper:
458     r = strdup ("8");
459     break;
460   case type_double:
461     r = strdup ("8");
462     break;
463   case type_bool:
464     r = strdup ("4");
465     break;
466   case type_ident:
467     len = strlen (type->ident) + 10;
468     str = malloc (len);
469     snprintf (str, len, "sizeof (%s)", type->ident);
470     r = str;
471     break;
472   default: abort ();            /* Avoid GCC warning. */
473   }
474
475   return r;
476 }
477
478 static void
479 gen_decl_xdr_call (int indent, const struct decl *decl, const char *struct_name)
480 {
481   char *str;
482   char *len_str;
483
484   spaces (indent);
485
486   switch (decl->decl_type)
487     {
488     case decl_type_string:
489       if (decl->len)
490         fprintf (yyout, "if (!xdr_string (xdrs, objp, %s))\n", decl->len);
491       else
492         fprintf (yyout, "if (!xdr_string (xdrs, objp, ~0))\n");
493       break;
494
495     case decl_type_opaque_fixed:
496       fprintf (yyout, "if (!xdr_opaque (xdrs, &objp, %s))\n", decl->len);
497       break;
498
499     case decl_type_opaque_variable:
500       len_str = decl->len ? : "~0";
501       fprintf (yyout,
502                "if (!xdr_bytes (xdrs, %s%s.%s_val, %s%s.%s_len, %s))\n",
503                struct_name, decl->ident, decl->ident,
504                struct_name, decl->ident, decl->ident, len_str);
505       break;
506
507     case decl_type_simple:
508       fprintf (yyout, "if (!xdr_%s (xdrs, %s%s))\n",
509                xdr_func_of_simple_type (decl->type), struct_name, decl->ident);
510       break;
511
512     case decl_type_fixed_array:
513       str = sizeof_simple_type (decl->type);
514       fprintf (yyout,
515                "if (!xdr_vector (xdrs, %s%s, %s, %s, (xdrproc_t) xdr_%s))\n",
516                struct_name, decl->ident, decl->len,
517                str, xdr_func_of_simple_type (decl->type));
518       free (str);
519       break;
520
521     case decl_type_variable_array:
522       str = sizeof_simple_type (decl->type);
523       len_str = decl->len ? : "~0";
524       fprintf (yyout,
525                "if (!xdr_array (xdrs, %s%s.%s_val, %s%s.%s_len, %s, %s, (xdrproc_t) xdr_%s))\n",
526                struct_name, decl->ident, decl->ident,
527                struct_name, decl->ident, decl->ident,
528                len_str,
529                str, xdr_func_of_simple_type (decl->type));
530       free (str);
531       break;
532
533     case decl_type_pointer:
534       str = sizeof_simple_type (decl->type);
535       fprintf (yyout, "if (!xdr_pointer (xdrs, objp, %s, (xdrproc_t) xdr_%s))\n",
536                str, xdr_func_of_simple_type (decl->type));
537       free (str);
538       break;
539     }
540
541   spaces (indent+2);
542   fprintf (yyout, "return FALSE;\n");
543 }
544
545 static void
546 gen_type (const struct type *type)
547 {
548   switch (type->type)
549     {
550     case type_char:
551       if (type->sgn) fputs ("int8_t", yyout);
552       else fputs ("uint8_t", yyout);
553       break;
554
555     case type_short:
556       if (type->sgn) fputs ("int16_t", yyout);
557       else fputs ("uint16_t", yyout);
558       break;
559
560     case type_int:
561       if (type->sgn) fputs ("int32_t", yyout);
562       else fputs ("uint32_t", yyout);
563       break;
564
565     case type_hyper:
566       if (type->sgn) fputs ("int64_t", yyout);
567       else fputs ("uint64_t", yyout);
568       break;
569
570     case type_double:
571       fputs ("double", yyout);
572       break;
573
574     case type_bool:
575       fputs ("bool_t", yyout);
576       break;
577
578     case type_ident:
579       fputs (type->ident, yyout);
580       break;
581     }
582 }