3184884947be7ee26e2fb38573123ab09634fe8b
[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 static void gen_line (void);
30 static void gen_decl (int indent, const struct decl *);
31 static void gen_type (const struct type *);
32
33 static void
34 spaces (int n)
35 {
36   int i;
37
38   for (i = 0; i < n; ++i)
39     fputc (' ', yyout);
40 }
41
42 /* This generates a #line directive referring back to the
43  * original source file.
44  */
45 static void
46 gen_line (void)
47 {
48   if (input_filename)
49     fprintf (yyout, "#line %d \"%s\"\n", yylineno, input_filename);
50 }
51
52 static void
53 write_header_def (void)
54 {
55   const char *p;
56
57   p = strrchr (output_filename, '/') ? : output_filename;
58
59   fputs ("RPCGEN_HEADER_", yyout);
60
61   while (*p) {
62     if (isalnum (*p))
63       fputc (toupper (*p), yyout);
64     else
65       fputc ('_', yyout);
66     ++p;
67   }
68 }
69
70 void
71 gen_prologue (const char *filename)
72 {
73   char *basename;
74   int len;
75
76   fprintf (yyout,
77            "/* This file was generated by PortableXDR rpcgen %s\n"
78            " * ANY CHANGES YOU MAKE TO THIS FILE MAY BE LOST!\n"
79            " * The input file was %s\n"
80            " */\n"
81            "\n",
82            PACKAGE_VERSION, filename);
83
84   switch (output_mode)
85     {
86     case output_c:
87       len = strlen (filename);
88       basename = malloc (len + 1);
89       strcpy (basename, filename);
90       if (len >= 2 && basename[len-2] == '.')
91         basename[len-2] = '\0';
92       fprintf (yyout, "#include \"%s.h\"\n", basename);
93       free (basename);
94       break;
95
96     case output_h:
97       fprintf (yyout, "#ifndef ");
98       write_header_def ();
99       fprintf (yyout, "\n#define ");
100       write_header_def ();
101       fprintf (yyout,
102                "\n"
103                "\n"
104                "#ifdef __cplusplus\n"
105                "extern \"C\" {\n"
106                "#endif\n"
107                "\n"
108                "#include <stdint.h>\n"
109                "#include <rpc/rpc.h>\n"
110                "\n");
111       break;
112     }
113 }
114
115 void
116 gen_epilogue (void)
117 {
118   gen_line ();
119
120   switch (output_mode)
121     {
122     case output_c:
123       break;
124
125     case output_h:
126       fprintf (yyout,
127                "\n"
128                "#ifdef __cplusplus\n"
129                "}\n"
130                "#endif\n"
131                "\n"
132                "#endif /* ");
133       write_header_def ();
134       fprintf (yyout, " */\n");
135       break;
136     }
137
138   fprintf (yyout, "\n/* EOF */\n");
139 }
140
141 void
142 gen_const (const char *name, const char *value)
143 {
144   if (output_mode == output_h) {
145     gen_line ();
146
147     fprintf (yyout, "#define %s %s\n", name, value);
148   }
149 }
150
151 void
152 gen_enum (const char *name, const struct cons *enum_values)
153 {
154   gen_line ();
155
156   switch (output_mode)
157     {
158     case output_h:
159       fprintf (yyout, "enum %s {\n", name);
160       while (enum_values) {
161         struct enum_value *enum_value = (struct enum_value *) enum_values->ptr;
162         if (enum_value->value)
163           fprintf (yyout, "  %s = %s,\n",
164                    enum_value->ident, enum_value->value);
165         else
166           fprintf (yyout, "  %s,\n", enum_value->ident);
167         enum_values = enum_values->next;
168       }
169       fprintf (yyout,
170                "};\n"
171                "typedef enum %s %s;\n"
172                "extern bool_t xdr_%s (XDR *, %s *);\n"
173                "\n",
174                name, name, name, name);
175       break;
176
177     case output_c:
178       /* XXX */
179       break;
180     }
181 }
182
183 void
184 gen_struct (const char *name, const struct cons *decls)
185 {
186   gen_line ();
187
188   switch (output_mode)
189     {
190     case output_h:
191       fprintf (yyout, "struct %s {\n", name);
192       while (decls) {
193         gen_decl (2, (struct decl *) decls->ptr);
194         decls = decls->next;
195       }
196       fprintf (yyout,
197                "};\n"
198                "typedef struct %s %s;\n"
199                "extern bool_t xdr_%s (XDR *, %s *);\n"
200                "\n",
201                name, name, name, name);
202       break;
203
204     case output_c:
205       /* XXX */
206       break;
207     }
208 }
209
210 void
211 gen_union (const char *name, const struct decl *discrim,
212            const struct cons *union_cases)
213 {
214   gen_line ();
215
216   switch (output_mode)
217     {
218     case output_h:
219       fprintf (yyout, "struct %s {\n", name);
220       gen_decl (2, discrim);
221       fprintf (yyout, "  union {\n");
222
223       while (union_cases) {
224         struct decl *decl = ((struct union_case *) union_cases->ptr)->decl;
225         if (decl) gen_decl (4, decl);
226         union_cases = union_cases->next;
227       }
228       fprintf (yyout,
229                "  } %s_u;\n"
230                "};\n"
231                "typedef struct %s %s;\n"
232                "extern bool_t xdr_%s (XDR *, %s *);\n"
233                "\n",
234                name, name, name, name, name);
235       break;
236
237     case output_c:
238       /* XXX */
239       break;
240     }
241 }
242
243 void
244 gen_typedef (const struct decl *decl)
245 {
246   if (output_mode == output_h) {
247     gen_line ();
248     fputs ("typedef ", yyout);
249     gen_decl (0, decl);
250     fprintf (yyout,
251              "extern bool_t xdr_%s (XDR *, %s *);\n"
252              "\n",
253              decl->ident, decl->ident);
254   }
255 }
256
257 static void
258 gen_decl (int indent, const struct decl *decl)
259 {
260   spaces (indent);
261
262   switch (decl->decl_type)
263     {
264     case decl_type_simple:
265       gen_type (decl->type);
266       fprintf (yyout, " %s;\n", decl->ident);
267       break;
268
269     case decl_type_fixed_array:
270       gen_type (decl->type);
271       fprintf (yyout, " %s[%s];\n", decl->ident, decl->len);
272       break;
273
274     case decl_type_variable_array:
275       fprintf (yyout, "struct {\n");
276       spaces (indent+2);
277       fprintf (yyout, "uint32_t %s_len;\n", decl->ident);
278       spaces (indent+2);
279       gen_type (decl->type);
280       fprintf (yyout, " *%s_val;\n", decl->ident);
281       spaces (indent);
282       fprintf (yyout, "} %s;\n", decl->ident);
283       break;
284
285     case decl_type_pointer:
286       gen_type (decl->type);
287       fprintf (yyout, " *%s;\n", decl->ident);
288       break;
289     }
290 }
291
292 static void
293 gen_type (const struct type *type)
294 {
295   switch (type->type)
296     {
297     case type_char:
298       if (type->sgn) fputs ("int8_t", yyout);
299       else fputs ("uint8_t", yyout);
300       break;
301
302     case type_short:
303       if (type->sgn) fputs ("int16_t", yyout);
304       else fputs ("uint16_t", yyout);
305       break;
306
307     case type_int:
308       if (type->sgn) fputs ("int32_t", yyout);
309       else fputs ("uint32_t", yyout);
310       break;
311
312     case type_hyper:
313       if (type->sgn) fputs ("int64_t", yyout);
314       else fputs ("uint64_t", yyout);
315       break;
316
317     case type_double:
318       fputs ("double", yyout);
319       break;
320
321     case type_string:
322       fputs ("char *", yyout);
323       break;
324
325     case type_opaque:
326       fputs ("char", yyout);
327       break;
328
329     case type_bool:
330       fputs ("bool_t", yyout);
331       break;
332
333     case type_ident:
334       fputs (type->ident, yyout);
335       break;
336     }
337 }