2005-01-19 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / sunrpc / rpc_cout.c
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user or with the express written consent of
8  * Sun Microsystems, Inc.
9  *
10  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13  *
14  * Sun RPC is provided with no support and without any obligation on the
15  * part of Sun Microsystems, Inc. to assist in its use, correction,
16  * modification or enhancement.
17  *
18  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20  * OR ANY PART THEREOF.
21  *
22  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23  * or profits or other special, indirect and consequential damages, even if
24  * Sun has been advised of the possibility of such damages.
25  *
26  * Sun Microsystems, Inc.
27  * 2550 Garcia Avenue
28  * Mountain View, California  94043
29  */
30
31 /*
32  * From: @(#)rpc_cout.c 1.13 89/02/22 (C) 1987 SMI
33  */
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static const char cout_rcsid[] =
36 "$Id$";
37 #endif
38
39 /*
40  * rpc_cout.c, XDR routine outputter for the RPC protocol compiler
41  */
42 #include <ctype.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include "rpc_parse.h"
46 #include "rpc_util.h"
47 #include "proto.h"
48
49 static void emit_enum (definition * def);
50 static void emit_program (const definition * def);
51 static void emit_union (const definition * def);
52 static void emit_struct (definition * def);
53 static void emit_typedef (const definition * def);
54 static void emit_inline (int indent, declaration * decl, int flag);
55 static void emit_single_in_line (int indent, declaration *decl, int flag,
56                                  relation rel);
57 static int findtype (const definition * def, const char *type);
58 static int undefined (const char *type);
59 static void print_generic_header (const char *procname, int pointerp);
60 static void print_ifopen (int indent, const char *name);
61 static void print_ifarg (const char *arg);
62 static void print_ifsizeof (int indent, const char *prefix, const char *type);
63 static void print_ifclose (int indent);
64 static void print_ifstat (int indent, const char *prefix, const char *type,
65                           relation rel, const char *amax,
66                           const char *objname, const char *name);
67 static void print_stat (int indent, const declaration * dec);
68 static void print_header (const definition * def);
69 static void print_trailer (void);
70 static char *upcase (const char *str);
71
72 /*
73  * Emit the C-routine for the given definition
74  */
75 void
76 emit (definition * def)
77 {
78   if (def->def_kind == DEF_CONST)
79     {
80       return;
81     }
82   if (def->def_kind == DEF_PROGRAM)
83     {
84       emit_program (def);
85       return;
86     }
87   if (def->def_kind == DEF_TYPEDEF)
88     {
89       /* now we need to handle declarations like
90          struct typedef foo foo;
91          since we don't want this to be expanded
92          into 2 calls to xdr_foo */
93
94       if (strcmp (def->def.ty.old_type, def->def_name) == 0)
95         return;
96     };
97
98   print_header (def);
99   switch (def->def_kind)
100     {
101     case DEF_UNION:
102       emit_union (def);
103       break;
104     case DEF_ENUM:
105       emit_enum (def);
106       break;
107     case DEF_STRUCT:
108       emit_struct (def);
109       break;
110     case DEF_TYPEDEF:
111       emit_typedef (def);
112       break;
113     default:
114       /* can't happen */
115       break;
116     }
117   print_trailer ();
118 }
119
120 static int
121 findtype (const definition * def, const char *type)
122 {
123   if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST)
124     {
125       return 0;
126     }
127   else
128     {
129       return (streq (def->def_name, type));
130     }
131 }
132
133 static int
134 undefined (const char *type)
135 {
136   definition *def;
137   def = (definition *) FINDVAL (defined, type, findtype);
138   return (def == NULL);
139 }
140
141
142 static void
143 print_generic_header (const char *procname, int pointerp)
144 {
145   f_print (fout, "\n");
146   f_print (fout, "bool_t\n");
147   if (Cflag)
148     {
149       f_print (fout, "xdr_%s (", procname);
150       f_print (fout, "XDR *xdrs, ");
151       f_print (fout, "%s ", procname);
152       if (pointerp)
153         f_print (fout, "*");
154       f_print (fout, "objp)\n{\n");
155     }
156   else
157     {
158       f_print (fout, "xdr_%s (xdrs, objp)\n", procname);
159       f_print (fout, "\tXDR *xdrs;\n");
160       f_print (fout, "\t%s ", procname);
161       if (pointerp)
162         f_print (fout, "*");
163       f_print (fout, "objp;\n{\n");
164     }
165 }
166
167 static void
168 print_header (const definition * def)
169 {
170   print_generic_header (def->def_name,
171                         def->def_kind != DEF_TYPEDEF ||
172                         !isvectordef (def->def.ty.old_type,
173                                       def->def.ty.rel));
174
175   /* Now add Inline support */
176
177   if (inlineflag == 0)
178     return;
179   /*May cause lint to complain. but  ... */
180   f_print (fout, "\tregister int32_t *buf;\n\n");
181 }
182
183 static void
184 print_prog_header (const proc_list * plist)
185 {
186   print_generic_header (plist->args.argname, 1);
187 }
188
189 static void
190 print_trailer (void)
191 {
192   f_print (fout, "\treturn TRUE;\n");
193   f_print (fout, "}\n");
194 }
195
196
197 static void
198 print_ifopen (int indent, const char *name)
199 {
200   tabify (fout, indent);
201   f_print (fout, " if (!xdr_%s (xdrs", name);
202 }
203
204 static void
205 print_ifarg (const char *arg)
206 {
207   f_print (fout, ", %s", arg);
208 }
209
210 static void
211 print_ifsizeof (int indent, const char *prefix, const char *type)
212 {
213   if (indent)
214     {
215       fprintf (fout, ",\n");
216       tabify (fout, indent);
217     }
218   else
219     fprintf (fout, ", ");
220
221   if (streq (type, "bool"))
222     fprintf (fout, "sizeof (bool_t), (xdrproc_t) xdr_bool");
223   else
224     {
225       fprintf (fout, "sizeof (");
226       if (undefined (type) && prefix)
227         {
228           f_print (fout, "%s ", prefix);
229         }
230       fprintf (fout, "%s), (xdrproc_t) xdr_%s", type, type);
231     }
232 }
233
234 static void
235 print_ifclose (int indent)
236 {
237   f_print (fout, "))\n");
238   tabify (fout, indent);
239   f_print (fout, "\t return FALSE;\n");
240 }
241
242 static void
243 print_ifstat (int indent, const char *prefix, const char *type, relation rel,
244               const char *amax, const char *objname, const char *name)
245 {
246   const char *alt = NULL;
247
248   switch (rel)
249     {
250     case REL_POINTER:
251       print_ifopen (indent, "pointer");
252       print_ifarg ("(char **)");
253       f_print (fout, "%s", objname);
254       print_ifsizeof (0, prefix, type);
255       break;
256     case REL_VECTOR:
257       if (streq (type, "string"))
258         {
259           alt = "string";
260         }
261       else if (streq (type, "opaque"))
262         {
263           alt = "opaque";
264         }
265       if (alt)
266         {
267           print_ifopen (indent, alt);
268           print_ifarg (objname);
269         }
270       else
271         {
272           print_ifopen (indent, "vector");
273           print_ifarg ("(char *)");
274           f_print (fout, "%s", objname);
275         }
276       print_ifarg (amax);
277       if (!alt)
278         {
279           print_ifsizeof (indent + 1, prefix, type);
280         }
281       break;
282     case REL_ARRAY:
283       if (streq (type, "string"))
284         {
285           alt = "string";
286         }
287       else if (streq (type, "opaque"))
288         {
289           alt = "bytes";
290         }
291       if (streq (type, "string"))
292         {
293           print_ifopen (indent, alt);
294           print_ifarg (objname);
295         }
296       else
297         {
298           if (alt)
299             {
300               print_ifopen (indent, alt);
301             }
302           else
303             {
304               print_ifopen (indent, "array");
305             }
306           print_ifarg ("(char **)");
307           if (*objname == '&')
308             {
309               f_print (fout, "%s.%s_val, (u_int *) %s.%s_len",
310                        objname, name, objname, name);
311             }
312           else
313             {
314               f_print (fout, "&%s->%s_val, (u_int *) &%s->%s_len",
315                        objname, name, objname, name);
316             }
317         }
318       print_ifarg (amax);
319       if (!alt)
320         {
321           print_ifsizeof (indent + 1, prefix, type);
322         }
323       break;
324     case REL_ALIAS:
325       print_ifopen (indent, type);
326       print_ifarg (objname);
327       break;
328     }
329   print_ifclose (indent);
330 }
331
332 static void
333 emit_enum (definition * def)
334 {
335   (void) def;
336
337   print_ifopen (1, "enum");
338   print_ifarg ("(enum_t *) objp");
339   print_ifclose (1);
340 }
341
342 static void
343 emit_program (const definition * def)
344 {
345   decl_list *dl;
346   version_list *vlist;
347   proc_list *plist;
348
349   for (vlist = def->def.pr.versions; vlist != NULL; vlist = vlist->next)
350     for (plist = vlist->procs; plist != NULL; plist = plist->next)
351       {
352         if (!newstyle || plist->arg_num < 2)
353           continue;             /* old style, or single argument */
354         print_prog_header (plist);
355         for (dl = plist->args.decls; dl != NULL;
356              dl = dl->next)
357           print_stat (1, &dl->decl);
358         print_trailer ();
359       }
360 }
361
362 static void
363 emit_union (const definition * def)
364 {
365   declaration *dflt;
366   case_list *cl;
367   declaration *cs;
368   char *object;
369   const char *vecformat = "objp->%s_u.%s";
370   const char *format = "&objp->%s_u.%s";
371
372   print_stat (1, &def->def.un.enum_decl);
373   f_print (fout, "\tswitch (objp->%s) {\n", def->def.un.enum_decl.name);
374   for (cl = def->def.un.cases; cl != NULL; cl = cl->next)
375     {
376
377       f_print (fout, "\tcase %s:\n", cl->case_name);
378       if (cl->contflag == 1)    /* a continued case statement */
379         continue;
380       cs = &cl->case_decl;
381       if (!streq (cs->type, "void"))
382         {
383           object = alloc (strlen (def->def_name) + strlen (format) +
384                           strlen (cs->name) + 1);
385           if (isvectordef (cs->type, cs->rel))
386             {
387               s_print (object, vecformat, def->def_name,
388                        cs->name);
389             }
390           else
391             {
392               s_print (object, format, def->def_name,
393                        cs->name);
394             }
395           print_ifstat (2, cs->prefix, cs->type, cs->rel, cs->array_max,
396                         object, cs->name);
397           free (object);
398         }
399       f_print (fout, "\t\tbreak;\n");
400     }
401   dflt = def->def.un.default_decl;
402   if (dflt != NULL)
403     {
404       if (!streq (dflt->type, "void"))
405         {
406           f_print (fout, "\tdefault:\n");
407           object = alloc (strlen (def->def_name) + strlen (format) +
408                           strlen (dflt->name) + 1);
409           if (isvectordef (dflt->type, dflt->rel))
410             {
411               s_print (object, vecformat, def->def_name,
412                        dflt->name);
413             }
414           else
415             {
416               s_print (object, format, def->def_name,
417                        dflt->name);
418             }
419
420           print_ifstat (2, dflt->prefix, dflt->type, dflt->rel,
421                         dflt->array_max, object, dflt->name);
422           free (object);
423           f_print (fout, "\t\tbreak;\n");
424         }
425 #ifdef __GNU_LIBRARY__
426       else
427         {
428           f_print (fout, "\tdefault:\n");
429           f_print (fout, "\t\tbreak;\n");
430         }
431 #endif
432     }
433   else
434     {
435       f_print (fout, "\tdefault:\n");
436       f_print (fout, "\t\treturn FALSE;\n");
437     }
438
439   f_print (fout, "\t}\n");
440 }
441
442 static void
443 inline_struct (definition *def, int flag)
444 {
445   decl_list *dl;
446   int i, size;
447   decl_list *cur = NULL;
448   decl_list *psav;
449   bas_type *ptr;
450   char *sizestr;
451   const char *plus;
452   char ptemp[256];
453   int indent = 1;
454
455   if (flag == PUT)
456     f_print (fout, "\n\tif (xdrs->x_op == XDR_ENCODE) {\n");
457   else
458     f_print (fout,
459              "\t\treturn TRUE;\n\t} else if (xdrs->x_op == XDR_DECODE) {\n");
460
461   i = 0;
462   size = 0;
463   sizestr = NULL;
464   for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
465     {                   /* xxx */
466       /* now walk down the list and check for basic types */
467       if ((dl->decl.prefix == NULL) &&
468           ((ptr = find_type (dl->decl.type)) != NULL) &&
469           ((dl->decl.rel == REL_ALIAS) || (dl->decl.rel == REL_VECTOR)))
470         {
471           if (i == 0)
472             cur = dl;
473           ++i;
474
475           if (dl->decl.rel == REL_ALIAS)
476             size += ptr->length;
477           else
478             {
479               /* this is required to handle arrays */
480               if (sizestr == NULL)
481                 plus = "";
482               else
483                 plus = "+ ";
484
485               if (ptr->length != 1)
486                 s_print (ptemp, " %s %s * %d", plus, dl->decl.array_max,
487                          ptr->length);
488               else
489                 s_print (ptemp, " %s%s ", plus, dl->decl.array_max);
490
491               /*now concatenate to sizestr !!!! */
492               if (sizestr == NULL)
493                 sizestr = strdup (ptemp);
494               else
495                 {
496                   sizestr = realloc (sizestr, strlen (sizestr) +
497                                      strlen (ptemp) + 1);
498                   if (sizestr == NULL)
499                     {
500                       f_print (stderr, "Fatal error : no memory \n");
501                       crash ();
502                     };
503                   sizestr = strcat (sizestr, ptemp);
504                   /*build up length of array */
505                 }
506             }
507         }
508       else
509         {
510           if (i > 0)
511             {
512               if (sizestr == NULL && size < inlineflag)
513                 {
514                   /* don't expand into inline code if size < inlineflag */
515                   while (cur != dl)
516                     {
517                       print_stat (indent + 1, &cur->decl);
518                       cur = cur->next;
519                     }
520                 }
521               else
522                 {
523                   /* were already looking at a xdr_inlineable structure */
524                   tabify (fout, indent + 1);
525                   if (sizestr == NULL)
526                     f_print (fout, "buf = XDR_INLINE (xdrs, %d * BYTES_PER_XDR_UNIT);", size);
527                   else if (size == 0)
528                     f_print (fout,
529                              "buf = XDR_INLINE (xdrs, (%s) * BYTES_PER_XDR_UNIT);",
530                              sizestr);
531                   else
532                     f_print (fout,
533                              "buf = XDR_INLINE (xdrs, (%d + (%s)) * BYTES_PER_XDR_UNIT);",
534                              size, sizestr);
535                   f_print (fout, "\n");
536                   tabify (fout, indent + 1);
537                   fprintf (fout, "if (buf == NULL) {\n");
538                   psav = cur;
539                   while (cur != dl)
540                     {
541                       print_stat (indent + 2, &cur->decl);
542                       cur = cur->next;
543                     }
544
545                   f_print (fout, "\n\t\t} else {\n");
546                   cur = psav;
547                   while (cur != dl)
548                     {
549                       emit_inline (indent + 1, &cur->decl, flag);
550                       cur = cur->next;
551                     }
552                   tabify (fout, indent + 1);
553                   f_print (fout, "}\n");
554                 }
555             }
556           size = 0;
557           i = 0;
558           sizestr = NULL;
559           print_stat (indent + 1, &dl->decl);
560         }
561     }
562   if (i > 0)
563     {
564       if (sizestr == NULL && size < inlineflag)
565         {
566           /* don't expand into inline code if size < inlineflag */
567           while (cur != dl)
568             {
569               print_stat (indent + 1, &cur->decl);
570               cur = cur->next;
571             }
572         }
573       else
574         {
575           /* were already looking at a xdr_inlineable structure */
576           if (sizestr == NULL)
577             f_print (fout,
578                      "\t\tbuf = XDR_INLINE (xdrs, %d * BYTES_PER_XDR_UNIT);",
579                      size);
580           else if (size == 0)
581             f_print (fout,
582                      "\t\tbuf = XDR_INLINE (xdrs, (%s) * BYTES_PER_XDR_UNIT);",
583                      sizestr);
584           else
585             f_print (fout,
586                      "\t\tbuf = XDR_INLINE (xdrs, (%d + %s)* BYTES_PER_XDR_UNIT);",
587                      size, sizestr);
588           f_print (fout, "\n\t\tif (buf == NULL) {\n");
589           psav = cur;
590           while (cur != NULL)
591             {
592               print_stat (indent + 2, &cur->decl);
593               cur = cur->next;
594             }
595           f_print (fout, "\t\t} else {\n");
596
597           cur = psav;
598           while (cur != dl)
599             {
600               emit_inline (indent + 2, &cur->decl, flag);
601               cur = cur->next;
602             }
603           f_print (fout, "\t\t}\n");
604         }
605     }
606 }
607
608 /* this may be const.  i haven't traced this one through yet. */
609
610 static void
611 emit_struct (definition * def)
612 {
613   decl_list *dl;
614   int j, size, flag;
615   bas_type *ptr;
616   int can_inline;
617
618
619   if (inlineflag == 0)
620     {
621       /* No xdr_inlining at all */
622       for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
623         print_stat (1, &dl->decl);
624       return;
625     }
626
627   for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
628     if (dl->decl.rel == REL_VECTOR)
629       {
630         f_print (fout, "\tint i;\n");
631         break;
632       }
633
634   size = 0;
635   can_inline = 0;
636   /*
637    * Make a first pass and see if inling is possible.
638    */
639   for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
640     if ((dl->decl.prefix == NULL) &&
641         ((ptr = find_type (dl->decl.type)) != NULL) &&
642         ((dl->decl.rel == REL_ALIAS) || (dl->decl.rel == REL_VECTOR)))
643       {
644         if (dl->decl.rel == REL_ALIAS)
645           size += ptr->length;
646         else
647           {
648             can_inline = 1;
649             break;              /* can be inlined */
650           }
651       }
652     else
653       {
654         if (size >= inlineflag)
655           {
656             can_inline = 1;
657             break;              /* can be inlined */
658           }
659         size = 0;
660       }
661   if (size > inlineflag)
662     can_inline = 1;
663
664   if (can_inline == 0)
665     {                   /* can not inline, drop back to old mode */
666       for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
667         print_stat (1, &dl->decl);
668       return;
669     };
670
671   flag = PUT;
672   for (j = 0; j < 2; j++)
673     {
674       inline_struct (def, flag);
675       if (flag == PUT)
676         flag = GET;
677     }
678
679   f_print (fout, "\t return TRUE;\n\t}\n\n");
680
681   /* now take care of XDR_FREE case */
682
683   for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
684     print_stat (1, &dl->decl);
685 }
686
687 static void
688 emit_typedef (const definition * def)
689 {
690   const char *prefix = def->def.ty.old_prefix;
691   const char *type = def->def.ty.old_type;
692   const char *amax = def->def.ty.array_max;
693   relation rel = def->def.ty.rel;
694
695   print_ifstat (1, prefix, type, rel, amax, "objp", def->def_name);
696 }
697
698 static void
699 print_stat (int indent, const declaration * dec)
700 {
701   const char *prefix = dec->prefix;
702   const char *type = dec->type;
703   const char *amax = dec->array_max;
704   relation rel = dec->rel;
705   char name[256];
706
707   if (isvectordef (type, rel))
708     {
709       s_print (name, "objp->%s", dec->name);
710     }
711   else
712     {
713       s_print (name, "&objp->%s", dec->name);
714     }
715   print_ifstat (indent, prefix, type, rel, amax, name, dec->name);
716 }
717
718
719 static void
720 emit_inline (int indent, declaration * decl, int flag)
721 {
722   switch (decl->rel)
723     {
724     case REL_ALIAS:
725       emit_single_in_line (indent, decl, flag, REL_ALIAS);
726       break;
727     case REL_VECTOR:
728       tabify (fout, indent);
729       f_print (fout, "{\n");
730       tabify (fout, indent + 1);
731       f_print (fout, "register %s *genp;\n\n", decl->type);
732       tabify (fout, indent + 1);
733       f_print (fout,
734                "for (i = 0, genp = objp->%s;\n", decl->name);
735       tabify (fout, indent + 2);
736       f_print (fout, "i < %s; ++i) {\n", decl->array_max);
737       emit_single_in_line (indent + 2, decl, flag, REL_VECTOR);
738       tabify (fout, indent + 1);
739       f_print (fout, "}\n");
740       tabify (fout, indent);
741       f_print (fout, "}\n");
742       break;
743     default:
744       break;
745       /* ?... do nothing I guess */
746     }
747 }
748
749 static void
750 emit_single_in_line (int indent, declaration *decl, int flag, relation rel)
751 {
752   char *upp_case;
753   int freed = 0;
754
755   tabify (fout, indent);
756   if (flag == PUT)
757     f_print (fout, "IXDR_PUT_");
758   else
759     {
760       if (rel == REL_ALIAS)
761         f_print (fout, "objp->%s = IXDR_GET_", decl->name);
762       else
763         f_print (fout, "*genp++ = IXDR_GET_");
764     }
765
766   upp_case = upcase (decl->type);
767
768   /* hack  - XX */
769   if (!strcmp (upp_case, "INT"))
770     {
771       free (upp_case);
772       freed = 1;
773       /* Casting is safe since the `freed' flag is set.  */
774       upp_case = (char *) "LONG";
775     }
776
777   if (!strcmp (upp_case, "U_INT"))
778     {
779       free (upp_case);
780       freed = 1;
781       /* Casting is safe since the `freed' flag is set.  */
782       upp_case = (char *) "U_LONG";
783     }
784
785   if (flag == PUT)
786     {
787       if (rel == REL_ALIAS)
788         f_print (fout, "%s(buf, objp->%s);\n", upp_case, decl->name);
789       else
790         f_print (fout, "%s(buf, *genp++);\n", upp_case);
791     }
792   else
793     {
794       f_print (fout, "%s(buf);\n", upp_case);
795     }
796
797   if (!freed)
798     free (upp_case);
799 }
800
801
802 static char *
803 upcase (const char *str)
804 {
805   char *ptr, *hptr;
806   ptr = malloc (strlen (str) + 1);
807   if (ptr == NULL)
808     {
809       f_print (stderr, "malloc failed\n");
810       exit (1);
811     }
812   hptr = ptr;
813   while (*str != '\0')
814     *ptr++ = toupper (*str++);
815
816   *ptr = '\0';
817   return hptr;
818 }