1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  27 /* All Rights Reserved */
  28 /*
  29  * University Copyright- Copyright (c) 1982, 1986, 1988
  30  * The Regents of the University of California
  31  * All Rights Reserved
  32  *
  33  * University Acknowledgment- Portions of this document are derived from
  34  * software developed by the University of California, Berkeley, and its
  35  * contributors.
  36  */
  37 
  38 /*
  39  * rpc_cout.c, XDR routine outputter for the RPC protocol compiler
  40  */
  41 #include <stdio.h>
  42 #include <stdlib.h>
  43 #include <string.h>
  44 #include <ctype.h>
  45 #include "rpc_parse.h"
  46 #include "rpc_util.h"
  47 
  48 extern void crash(void);
  49 
  50 static void print_header(definition *);
  51 static void print_trailer(void);
  52 static void emit_enum(definition *);
  53 static void emit_program(definition *);
  54 static void emit_union(definition *);
  55 static void emit_struct(definition *);
  56 static void emit_typedef(definition *);
  57 static void print_stat(int, declaration *);
  58 static void emit_inline(int, declaration *, int);
  59 static void emit_inline64(int, declaration *, int);
  60 static void emit_single_in_line(int, declaration *, int, relation);
  61 static void emit_single_in_line64(int, declaration *, int, relation);
  62 static char *upcase(char *);
  63 
  64 /*
  65  * Emit the C-routine for the given definition
  66  */
  67 void
  68 emit(definition *def)
  69 {
  70         if (def->def_kind == DEF_CONST)
  71                 return;
  72         if (def->def_kind == DEF_PROGRAM) {
  73                 emit_program(def);
  74                 return;
  75         }
  76         if (def->def_kind == DEF_TYPEDEF) {
  77                 /*
  78                  * now we need to handle declarations like
  79                  * struct typedef foo foo;
  80                  * since we dont want this to be expanded into 2 calls
  81                  * to xdr_foo
  82                  */
  83 
  84                 if (strcmp(def->def.ty.old_type, def->def_name) == 0)
  85                         return;
  86         };
  87         print_header(def);
  88         switch (def->def_kind) {
  89         case DEF_UNION:
  90                 emit_union(def);
  91                 break;
  92         case DEF_ENUM:
  93                 emit_enum(def);
  94                 break;
  95         case DEF_STRUCT:
  96                 emit_struct(def);
  97                 break;
  98         case DEF_TYPEDEF:
  99                 emit_typedef(def);
 100                 break;
 101         }
 102         print_trailer();
 103 }
 104 
 105 static int
 106 findtype(definition *def, char *type)
 107 {
 108 
 109         if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST)
 110                 return (0);
 111         return (streq(def->def_name, type));
 112 }
 113 
 114 static int
 115 undefined(char *type)
 116 {
 117         definition *def;
 118 
 119         def = (definition *)FINDVAL(defined, type, findtype);
 120         return (def == NULL);
 121 }
 122 
 123 
 124 static void
 125 print_generic_header(char *procname, int pointerp)
 126 {
 127         f_print(fout, "\n");
 128         f_print(fout, "bool_t\n");
 129         if (Cflag) {
 130                 f_print(fout, "xdr_%s(", procname);
 131                 f_print(fout, "XDR *xdrs, ");
 132                 f_print(fout, "%s ", procname);
 133                 if (pointerp)
 134                         f_print(fout, "*");
 135                 f_print(fout, "objp)\n{\n\n");
 136         } else {
 137                 f_print(fout, "xdr_%s(xdrs, objp)\n", procname);
 138                 f_print(fout, "\tXDR *xdrs;\n");
 139                 f_print(fout, "\t%s ", procname);
 140                 if (pointerp)
 141                         f_print(fout, "*");
 142                 f_print(fout, "objp;\n{\n\n");
 143         }
 144 }
 145 
 146 static void
 147 print_header(definition *def)
 148 {
 149         print_generic_header(def->def_name,
 150             def->def_kind != DEF_TYPEDEF ||
 151             !isvectordef(def->def.ty.old_type, def->def.ty.rel));
 152         /* Now add Inline support */
 153 
 154         if (inlinelen == 0)
 155                 return;
 156         /* May cause lint to complain. but  ... */
 157         f_print(fout, "\trpc_inline_t *buf;\n\n");
 158 }
 159 
 160 static void
 161 print_prog_header(proc_list *plist)
 162 {
 163         print_generic_header(plist->args.argname, 1);
 164 }
 165 
 166 static void
 167 print_trailer(void)
 168 {
 169         f_print(fout, "\treturn (TRUE);\n");
 170         f_print(fout, "}\n");
 171 }
 172 
 173 
 174 static void
 175 print_ifopen(int indent, char *name)
 176 {
 177         tabify(fout, indent);
 178         if (streq(name, "rpcprog_t") ||
 179             streq(name, "rpcvers_t") ||
 180             streq(name, "rpcproc_t") ||
 181             streq(name, "rpcprot_t") ||
 182             streq(name, "rpcport_t"))
 183                 (void) strtok(name, "_");
 184         f_print(fout, "if (!xdr_%s(xdrs", name);
 185 }
 186 
 187 static void
 188 print_ifarg(char *arg)
 189 {
 190         f_print(fout, ", %s", arg);
 191 }
 192 
 193 static void
 194 print_ifsizeof(int indent, char *prefix, char *type)
 195 {
 196         if (indent) {
 197                 f_print(fout, ",\n");
 198                 tabify(fout, indent);
 199         } else {
 200                 f_print(fout, ", ");
 201         }
 202         if (streq(type, "bool")) {
 203                 f_print(fout, "sizeof (bool_t), (xdrproc_t)xdr_bool");
 204         } else {
 205                 f_print(fout, "sizeof (");
 206                 if (undefined(type) && prefix) {
 207                         f_print(fout, "%s ", prefix);
 208                 }
 209                 f_print(fout, "%s), (xdrproc_t)xdr_%s", type, type);
 210         }
 211 }
 212 
 213 static void
 214 print_ifclose(int indent)
 215 {
 216         f_print(fout, "))\n");
 217         tabify(fout, indent);
 218         f_print(fout, "\treturn (FALSE);\n");
 219 }
 220 
 221 static void
 222 print_ifstat(int indent, char *prefix, char *type, relation rel,
 223                                         char *amax, char *objname, char *name)
 224 {
 225         char *alt = NULL;
 226 
 227         switch (rel) {
 228         case REL_POINTER:
 229                 print_ifopen(indent, "pointer");
 230                 print_ifarg("(char **)");
 231                 f_print(fout, "%s", objname);
 232                 print_ifsizeof(0, prefix, type);
 233                 break;
 234         case REL_VECTOR:
 235                 if (streq(type, "string"))
 236                         alt = "string";
 237                 else if (streq(type, "opaque"))
 238                         alt = "opaque";
 239                 if (alt) {
 240                         print_ifopen(indent, alt);
 241                         print_ifarg(objname);
 242                 } else {
 243                         print_ifopen(indent, "vector");
 244                         print_ifarg("(char *)");
 245                         f_print(fout, "%s", objname);
 246                 }
 247                 print_ifarg(amax);
 248                 if (!alt)
 249                         print_ifsizeof(indent + 1, prefix, type);
 250                 break;
 251         case REL_ARRAY:
 252                 if (streq(type, "string"))
 253                         alt = "string";
 254                 else if (streq(type, "opaque"))
 255                         alt = "bytes";
 256                 if (streq(type, "string")) {
 257                         print_ifopen(indent, alt);
 258                         print_ifarg(objname);
 259                 } else {
 260                         if (alt)
 261                                 print_ifopen(indent, alt);
 262                         else
 263                                 print_ifopen(indent, "array");
 264                         print_ifarg("(char **)");
 265                         if (*objname == '&')
 266                                 f_print(fout, "%s.%s_val, (u_int *) %s.%s_len",
 267                                     objname, name, objname, name);
 268                         else
 269                                 f_print(fout,
 270                                     "&%s->%s_val, (u_int *) &%s->%s_len",
 271                                     objname, name, objname, name);
 272                 }
 273                 print_ifarg(amax);
 274                 if (!alt)
 275                         print_ifsizeof(indent + 1, prefix, type);
 276                 break;
 277         case REL_ALIAS:
 278                 print_ifopen(indent, type);
 279                 print_ifarg(objname);
 280                 break;
 281         }
 282         print_ifclose(indent);
 283 }
 284 
 285 /* ARGSUSED */
 286 static void
 287 emit_enum(definition *def)
 288 {
 289         print_ifopen(1, "enum");
 290         print_ifarg("(enum_t *)objp");
 291         print_ifclose(1);
 292 }
 293 
 294 static void
 295 emit_program(definition *def)
 296 {
 297         decl_list *dl;
 298         version_list *vlist;
 299         proc_list *plist;
 300 
 301         for (vlist = def->def.pr.versions; vlist != NULL; vlist = vlist->next)
 302                 for (plist = vlist->procs; plist != NULL; plist = plist->next) {
 303                         if (!newstyle || plist->arg_num < 2)
 304                                 continue; /* old style, or single argument */
 305                         print_prog_header(plist);
 306                         for (dl = plist->args.decls; dl != NULL;
 307                             dl = dl->next)
 308                                 print_stat(1, &dl->decl);
 309                         print_trailer();
 310                 }
 311 }
 312 
 313 
 314 static void
 315 emit_union(definition *def)
 316 {
 317         declaration *dflt;
 318         case_list *cl;
 319         declaration *cs;
 320         char *object;
 321 
 322         print_stat(1, &def->def.un.enum_decl);
 323         f_print(fout, "\tswitch (objp->%s) {\n", def->def.un.enum_decl.name);
 324         for (cl = def->def.un.cases; cl != NULL; cl = cl->next) {
 325 
 326                 f_print(fout, "\tcase %s:\n", cl->case_name);
 327                 if (cl->contflag == 1) /* a continued case statement */
 328                         continue;
 329                 cs = &cl->case_decl;
 330                 if (!streq(cs->type, "void")) {
 331                         size_t len = strlen(def->def_name) +
 332                             strlen("&objp->%s_u.%s") +
 333                             strlen(cs->name) + 1;
 334                         object = malloc(len);
 335                         if (isvectordef(cs->type, cs->rel))
 336                                 (void) snprintf(object, len, "objp->%s_u.%s",
 337                                     def->def_name, cs->name);
 338                         else
 339                                 (void) snprintf(object, len, "&objp->%s_u.%s",
 340                                     def->def_name, cs->name);
 341                         print_ifstat(2, cs->prefix, cs->type, cs->rel,
 342                             cs->array_max, object, cs->name);
 343                         free(object);
 344                 }
 345                 f_print(fout, "\t\tbreak;\n");
 346         }
 347         dflt = def->def.un.default_decl;
 348         if (dflt != NULL) {
 349                 if (!streq(dflt->type, "void")) {
 350                         size_t len = strlen(def->def_name) +
 351                             strlen("&objp->%s_u.%s") +
 352                             strlen(dflt->name) + 1;
 353                         f_print(fout, "\tdefault:\n");
 354                         object = malloc(len);
 355                         if (isvectordef(dflt->type, dflt->rel))
 356                                 (void) snprintf(object, len, "objp->%s_u.%s",
 357                                     def->def_name, dflt->name);
 358                         else
 359                                 (void) snprintf(object, len, "&objp->%s_u.%s",
 360                                     def->def_name, dflt->name);
 361 
 362                         print_ifstat(2, dflt->prefix, dflt->type, dflt->rel,
 363                             dflt->array_max, object, dflt->name);
 364                         free(object);
 365                         f_print(fout, "\t\tbreak;\n");
 366                 }
 367         } else {
 368                 f_print(fout, "\tdefault:\n");
 369                 f_print(fout, "\t\treturn (FALSE);\n");
 370         }
 371 
 372         f_print(fout, "\t}\n");
 373 }
 374 
 375 static void
 376 expand_inline(int indent, const char *sizestr,
 377     int size, int flag, decl_list *dl, decl_list *cur)
 378 {
 379         decl_list *psav;
 380 
 381         /*
 382          * were already looking at a xdr_inlineable structure
 383          */
 384         tabify(fout, indent + 1);
 385         if (sizestr == NULL)
 386                 f_print(fout,
 387                     "buf = XDR_INLINE(xdrs, %d * BYTES_PER_XDR_UNIT);",
 388                     size);
 389         else if (size == 0)
 390                 f_print(fout,
 391                     "buf = XDR_INLINE(xdrs, (%s) * BYTES_PER_XDR_UNIT);",
 392                     sizestr);
 393         else
 394                 f_print(fout,
 395                     "buf = XDR_INLINE(xdrs, (%d + (%s)) "
 396                     "* BYTES_PER_XDR_UNIT);", size, sizestr);
 397 
 398         f_print(fout, "\n");
 399         tabify(fout, indent + 1);
 400         f_print(fout, "if (buf == NULL) {\n");
 401 
 402         psav = cur;
 403         while (cur != dl) {
 404                 print_stat(indent + 2,
 405                     &cur->decl);
 406                 cur = cur->next;
 407         }
 408 
 409         tabify(fout, indent+1);
 410         f_print(fout, "} else {\n");
 411 
 412         f_print(fout, "#if defined(_LP64) || defined(_KERNEL)\n");
 413         cur = psav;
 414         while (cur != dl) {
 415                 emit_inline64(indent + 2, &cur->decl, flag);
 416                 cur = cur->next;
 417         }
 418         f_print(fout, "#else\n");
 419         cur = psav;
 420         while (cur != dl) {
 421                 emit_inline(indent + 2, &cur->decl, flag);
 422                 cur = cur->next;
 423         }
 424         f_print(fout, "#endif\n");
 425 
 426         tabify(fout, indent + 1);
 427         f_print(fout, "}\n");
 428 }
 429 
 430 /*
 431  * An inline type is a base type (interger type) or a vector of base types.
 432  */
 433 static int
 434 inline_type(declaration *dc, int *size)
 435 {
 436         bas_type *ptr;
 437 
 438         *size = 0;
 439 
 440         if (dc->prefix == NULL &&
 441             (dc->rel == REL_ALIAS || dc->rel == REL_VECTOR)) {
 442                 ptr = find_type(dc->type);
 443                 if (ptr != NULL) {
 444                         *size = ptr->length;
 445                         return (1);
 446                 }
 447         }
 448 
 449         return (0);
 450 }
 451 
 452 static char *
 453 arraysize(char *sz, declaration *dc, int elsize)
 454 {
 455         int len;
 456         int elsz = elsize;
 457         int digits;
 458         int slen = 0;
 459         char *plus = "";
 460         char *tmp;
 461         size_t tlen;
 462 
 463         /*
 464          * Calculate the size of a string to hold the size of all arrays
 465          * to be inlined.
 466          *
 467          * We have the string representation of the total size that has already
 468          * been seen. (Null if this is the first array).
 469          * We have the string representation of array max from the declaration,
 470          * optionally the plus string, " + ", if this is not the first array,
 471          * and the number of digits for the element size for this declaration.
 472          */
 473         if (sz != NULL) {
 474                 plus = " + ";
 475                 slen = strlen(sz);
 476         }
 477 
 478         /* Calculate the number of digits to hold the element size */
 479         for (digits = 1; elsz >= 10; digits++)
 480                 elsz /= 10;
 481 
 482         /*
 483          * If elsize != 1 the allocate 3 extra bytes for the times
 484          * string, " * ", the "()" below,  and the digits. One extra
 485          * for the trailing NULL
 486          */
 487         len = strlen(dc->array_max) +  (elsize == 1 ? 0 : digits + 5) + 1;
 488         tlen = slen + len + strlen(plus);
 489         tmp = realloc(sz, tlen);
 490         if (tmp == NULL) {
 491                 f_print(stderr, "Fatal error : no memory\n");
 492                 crash();
 493         }
 494 
 495         if (elsize == 1)
 496                 (void) snprintf(tmp + slen, tlen - slen, "%s%s",
 497                     plus, dc->array_max);
 498         else
 499                 (void) snprintf(tmp + slen, tlen - slen, "%s(%s) * %d",
 500                     plus, dc->array_max, elsize);
 501 
 502         return (tmp);
 503 }
 504 
 505 static void
 506 inline_struct(decl_list *dl, decl_list *last, int flag, int indent)
 507 {
 508         int size, tsize;
 509         decl_list *cur;
 510         char *sizestr;
 511 
 512         cur = NULL;
 513         tsize = 0;
 514         sizestr = NULL;
 515         for (; dl != last; dl = dl->next) {
 516                 if (inline_type(&dl->decl, &size)) {
 517                         if (cur == NULL)
 518                                 cur = dl;
 519 
 520                         if (dl->decl.rel == REL_ALIAS)
 521                                 tsize += size;
 522                         else {
 523                                 /* this code is required to handle arrays */
 524                                 sizestr = arraysize(sizestr, &dl->decl, size);
 525                         }
 526                 } else {
 527                         if (cur != NULL)
 528                                 if (sizestr == NULL && tsize < inlinelen) {
 529                                         /*
 530                                          * don't expand into inline code
 531                                          * if tsize < inlinelen
 532                                          */
 533                                         while (cur != dl) {
 534                                                 print_stat(indent + 1,
 535                                                     &cur->decl);
 536                                                 cur = cur->next;
 537                                         }
 538                                 } else {
 539                                         expand_inline(indent, sizestr,
 540                                             tsize, flag, dl, cur);
 541                                 }
 542                         tsize = 0;
 543                         cur = NULL;
 544                         sizestr = NULL;
 545                         print_stat(indent + 1, &dl->decl);
 546                 }
 547         }
 548 
 549         if (cur == NULL)
 550                 return;
 551         if (sizestr == NULL && tsize < inlinelen) {
 552                 /* don't expand into inline code if tsize < inlinelen */
 553                 while (cur != dl) {
 554                         print_stat(indent + 1, &cur->decl);
 555                         cur = cur->next;
 556                 }
 557         } else {
 558                 expand_inline(indent, sizestr, tsize, flag, dl, cur);
 559         }
 560 }
 561 
 562 /*
 563  * Check if we can inline this structure. While we are at it check if the
 564  * declaration list has any vectors defined of "basic" types.
 565  */
 566 static int
 567 check_inline(decl_list *dl, int inlinelen, int *have_vector)
 568 {
 569         int tsize = 0;
 570         int size;
 571         int doinline = 0;
 572 
 573         *have_vector = 0;
 574         if (inlinelen == 0)
 575                 return (0);
 576 
 577         for (; dl != NULL; dl = dl->next) {
 578                 if (!inline_type(&dl->decl, &size)) {
 579                         tsize = 0;
 580                         continue;
 581                 }
 582                 if (dl->decl.rel == REL_VECTOR) {
 583                         *have_vector = 1;
 584                         return (1);
 585                 }
 586                 tsize += size;
 587                 if (tsize >= inlinelen)
 588                         doinline = 1;
 589         }
 590 
 591         return (doinline);
 592 }
 593 
 594 
 595 static void
 596 emit_struct_tail_recursion(definition *defp, int can_inline)
 597 {
 598         int indent = 3;
 599         struct_def *sp = &defp->def.st;
 600         decl_list *dl;
 601 
 602 
 603         f_print(fout, "\t%s *tmp_%s;\n",
 604             defp->def_name, defp->def_name);
 605 
 606         f_print(fout, "\tbool_t more_data = TRUE;\n");
 607         f_print(fout, "\tbool_t first_objp = TRUE;\n\n");
 608 
 609         f_print(fout, "\n\tif (xdrs->x_op == XDR_DECODE) {\n");
 610         f_print(fout, "\n\t\twhile (more_data) {\n");
 611         f_print(fout, "\n\t\t\tvoid bzero();\n\n");
 612 
 613         if (can_inline)
 614                 inline_struct(sp->decls, sp->tail, GET, indent);
 615         else
 616                 for (dl = sp->decls; dl != NULL && dl != sp->tail;
 617                     dl = dl->next)
 618                         print_stat(indent, &dl->decl);
 619 
 620         f_print(fout, "\t\t\tif (!xdr_bool(xdrs, "
 621             "&more_data))\n\t\t\t\treturn (FALSE);\n");
 622 
 623         f_print(fout, "\n\t\t\tif (!more_data) {\n");
 624         f_print(fout, "\t\t\t\tobjp->%s = NULL;\n", sp->tail->decl.name);
 625         f_print(fout, "\t\t\t\tbreak;\n");
 626         f_print(fout, "\t\t\t}\n\n");
 627         f_print(fout, "\t\t\tif (objp->%s == NULL) {\n", sp->tail->decl.name);
 628         f_print(fout, "\t\t\t\tobjp->%s = "
 629             "(%s *)\n\t\t\t\t\tmem_alloc(sizeof (%s));\n",
 630             sp->tail->decl.name, defp->def_name, defp->def_name);
 631 
 632         f_print(fout, "\t\t\t\tif (objp->%s == NULL)\n"
 633             "\t\t\t\t\treturn (FALSE);\n", sp->tail->decl.name);
 634         f_print(fout, "\t\t\t\tbzero(objp->%s, sizeof (%s));\n",
 635             sp->tail->decl.name, defp->def_name);
 636         f_print(fout, "\t\t\t}\n");
 637         f_print(fout, "\t\t\tobjp = objp->%s;\n", sp->tail->decl.name);
 638         f_print(fout, "\t\t}\n");
 639 
 640         f_print(fout, "\n\t} else if (xdrs->x_op == XDR_ENCODE) {\n");
 641         f_print(fout, "\n\t\twhile (more_data) {\n");
 642 
 643         if (can_inline)
 644                 inline_struct(sp->decls, sp->tail, PUT, indent);
 645         else
 646                 for (dl = sp->decls; dl != NULL && dl != sp->tail;
 647                     dl = dl->next)
 648                         print_stat(indent, &dl->decl);
 649 
 650         f_print(fout, "\t\t\tobjp = objp->%s;\n", sp->tail->decl.name);
 651         f_print(fout, "\t\t\tif (objp == NULL)\n");
 652         f_print(fout, "\t\t\t\tmore_data = FALSE;\n");
 653 
 654         f_print(fout, "\t\t\tif (!xdr_bool(xdrs, &more_data))\n"
 655             "\t\t\t\treturn (FALSE);\n");
 656 
 657         f_print(fout, "\t\t}\n");
 658 
 659         f_print(fout, "\n\t} else {\n");
 660         f_print(fout, "\n\t\twhile (more_data) {\n");
 661 
 662         for (dl = sp->decls; dl != NULL && dl != sp->tail; dl = dl->next)
 663                 print_stat(indent, &dl->decl);
 664 
 665         f_print(fout, "\t\t\ttmp_%s = objp;\n", defp->def_name);
 666         f_print(fout, "\t\t\tobjp = objp->%s;\n", sp->tail->decl.name);
 667 
 668         f_print(fout, "\t\t\tif (objp == NULL)\n");
 669         f_print(fout, "\t\t\t\tmore_data = FALSE;\n");
 670 
 671         f_print(fout, "\t\t\tif (!first_objp)\n");
 672 
 673         f_print(fout, "\t\t\t\tmem_free(tmp_%s, sizeof (%s));\n",
 674             defp->def_name, defp->def_name);
 675 
 676         f_print(fout, "\t\t\telse\n\t\t\t\tfirst_objp = FALSE;\n\t\t}\n");
 677 
 678         f_print(fout, "\n\t}\n");
 679 }
 680 
 681 static void
 682 emit_struct(definition *def)
 683 {
 684         decl_list *dl = def->def.st.decls;
 685         int can_inline, have_vector;
 686 
 687 
 688         can_inline = check_inline(dl, inlinelen, &have_vector);
 689         if (have_vector)
 690                 f_print(fout, "\tint i;\n");
 691 
 692 
 693         if (rflag && def->def.st.self_pointer) {
 694                 /* Handle tail recursion elimination */
 695                 emit_struct_tail_recursion(def, can_inline);
 696                 return;
 697         }
 698 
 699 
 700         if (can_inline) {
 701                 f_print(fout, "\n\tif (xdrs->x_op == XDR_ENCODE) {\n");
 702                 inline_struct(dl, NULL, PUT, 1);
 703 
 704                 f_print(fout, "\t\treturn (TRUE);\n\t}"
 705                     " else if (xdrs->x_op == XDR_DECODE) {\n");
 706 
 707                 inline_struct(dl, NULL, GET, 1);
 708                 f_print(fout, "\t\treturn (TRUE);\n\t}\n\n");
 709         }
 710 
 711         /* now take care of XDR_FREE inline  case or the non-inline cases */
 712 
 713         for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
 714                 print_stat(1, &dl->decl);
 715 
 716 }
 717 
 718 static void
 719 emit_typedef(definition *def)
 720 {
 721         char *prefix = def->def.ty.old_prefix;
 722         char *type = def->def.ty.old_type;
 723         char *amax = def->def.ty.array_max;
 724         relation rel = def->def.ty.rel;
 725 
 726         print_ifstat(1, prefix, type, rel, amax, "objp", def->def_name);
 727 }
 728 
 729 static void
 730 print_stat(int indent, declaration *dec)
 731 {
 732         char *prefix = dec->prefix;
 733         char *type = dec->type;
 734         char *amax = dec->array_max;
 735         relation rel = dec->rel;
 736         char name[256];
 737 
 738         if (isvectordef(type, rel))
 739                 (void) snprintf(name, sizeof (name), "objp->%s", dec->name);
 740         else
 741                 (void) snprintf(name, sizeof (name), "&objp->%s", dec->name);
 742         print_ifstat(indent, prefix, type, rel, amax, name, dec->name);
 743 }
 744 
 745 
 746 static void
 747 emit_inline(int indent, declaration *decl, int flag)
 748 {
 749         switch (decl->rel) {
 750         case  REL_ALIAS :
 751                 emit_single_in_line(indent, decl, flag, REL_ALIAS);
 752                 break;
 753         case REL_VECTOR :
 754                 tabify(fout, indent);
 755                 f_print(fout, "{\n");
 756                 tabify(fout, indent + 1);
 757                 f_print(fout, "%s *genp;\n\n", decl->type);
 758                 tabify(fout, indent + 1);
 759                 f_print(fout,
 760                     "for (i = 0, genp = objp->%s;\n", decl->name);
 761                 tabify(fout, indent + 2);
 762                 f_print(fout, "i < %s; i++) {\n", decl->array_max);
 763                 emit_single_in_line(indent + 2, decl, flag, REL_VECTOR);
 764                 tabify(fout, indent + 1);
 765                 f_print(fout, "}\n");
 766                 tabify(fout, indent);
 767                 f_print(fout, "}\n");
 768         }
 769 }
 770 
 771 static void
 772 emit_inline64(int indent, declaration *decl, int flag)
 773 {
 774         switch (decl->rel) {
 775         case  REL_ALIAS :
 776                 emit_single_in_line64(indent, decl, flag, REL_ALIAS);
 777                 break;
 778         case REL_VECTOR :
 779                 tabify(fout, indent);
 780                 f_print(fout, "{\n");
 781                 tabify(fout, indent + 1);
 782                 f_print(fout, "%s *genp;\n\n", decl->type);
 783                 tabify(fout, indent + 1);
 784                 f_print(fout,
 785                     "for (i = 0, genp = objp->%s;\n", decl->name);
 786                 tabify(fout, indent + 2);
 787                 f_print(fout, "i < %s; i++) {\n", decl->array_max);
 788                 emit_single_in_line64(indent + 2, decl, flag, REL_VECTOR);
 789                 tabify(fout, indent + 1);
 790                 f_print(fout, "}\n");
 791                 tabify(fout, indent);
 792                 f_print(fout, "}\n");
 793         }
 794 }
 795 
 796 static void
 797 emit_single_in_line(int indent, declaration *decl, int flag, relation rel)
 798 {
 799         char *upp_case;
 800         int freed = 0;
 801 
 802         tabify(fout, indent);
 803         if (flag == PUT)
 804                 f_print(fout, "IXDR_PUT_");
 805         else
 806                 if (rel == REL_ALIAS)
 807                         f_print(fout, "objp->%s = IXDR_GET_", decl->name);
 808                 else
 809                         f_print(fout, "*genp++ = IXDR_GET_");
 810 
 811         upp_case = upcase(decl->type);
 812 
 813         /* hack  - XX */
 814         if (strcmp(upp_case, "INT") == 0) {
 815                 free(upp_case);
 816                 freed = 1;
 817                 upp_case = "LONG";
 818         }
 819         if ((strcmp(upp_case, "U_INT") == 0) ||
 820             (strcmp(upp_case, "RPCPROG") == 0) ||
 821             (strcmp(upp_case, "RPCVERS") == 0) ||
 822             (strcmp(upp_case, "RPCPROC") == 0) ||
 823             (strcmp(upp_case, "RPCPROT") == 0) ||
 824             (strcmp(upp_case, "RPCPORT") == 0)) {
 825                 free(upp_case);
 826                 freed = 1;
 827                 upp_case = "U_LONG";
 828         }
 829 
 830         if (flag == PUT)
 831                 if (rel == REL_ALIAS)
 832                         f_print(fout,
 833                             "%s(buf, objp->%s);\n", upp_case, decl->name);
 834                 else
 835                         f_print(fout, "%s(buf, *genp++);\n", upp_case);
 836 
 837         else
 838                 f_print(fout, "%s(buf);\n", upp_case);
 839         if (!freed)
 840                 free(upp_case);
 841 }
 842 
 843 static void
 844 emit_single_in_line64(int indent, declaration *decl, int flag, relation rel)
 845 {
 846         char *upp_case;
 847         int freed = 0;
 848 
 849         tabify(fout, indent);
 850         if (flag == PUT)
 851                 f_print(fout, "IXDR_PUT_");
 852         else
 853                 if (rel == REL_ALIAS)
 854                         f_print(fout, "objp->%s = IXDR_GET_", decl->name);
 855                 else
 856                         f_print(fout, "*genp++ = IXDR_GET_");
 857 
 858         upp_case = upcase(decl->type);
 859 
 860         /* hack  - XX */
 861         if ((strcmp(upp_case, "INT") == 0)||(strcmp(upp_case, "LONG") == 0)) {
 862                 free(upp_case);
 863                 freed = 1;
 864                 upp_case = "INT32";
 865         }
 866         if ((strcmp(upp_case, "U_INT") == 0) ||
 867             (strcmp(upp_case, "U_LONG") == 0) ||
 868             (strcmp(upp_case, "RPCPROG") == 0) ||
 869             (strcmp(upp_case, "RPCVERS") == 0) ||
 870             (strcmp(upp_case, "RPCPROC") == 0) ||
 871             (strcmp(upp_case, "RPCPROT") == 0) ||
 872             (strcmp(upp_case, "RPCPORT") == 0)) {
 873                 free(upp_case);
 874                 freed = 1;
 875                 upp_case = "U_INT32";
 876         }
 877 
 878         if (flag == PUT)
 879                 if (rel == REL_ALIAS)
 880                         f_print(fout,
 881                             "%s(buf, objp->%s);\n", upp_case, decl->name);
 882                 else
 883                         f_print(fout, "%s(buf, *genp++);\n", upp_case);
 884 
 885         else
 886                 f_print(fout, "%s(buf);\n", upp_case);
 887         if (!freed)
 888                 free(upp_case);
 889 }
 890 
 891 static char *
 892 upcase(char *str)
 893 {
 894         char *ptr, *hptr;
 895 
 896         ptr = malloc(strlen(str)+1);
 897         if (ptr == NULL) {
 898                 f_print(stderr, "malloc failed\n");
 899                 exit(1);
 900         };
 901 
 902         hptr = ptr;
 903         while (*str != '\0')
 904                 *ptr++ = toupper(*str++);
 905 
 906         *ptr = '\0';
 907         return (hptr);
 908 }