1 /* $OpenBSD: rpc_cout.c,v 1.21 2010/09/01 14:43:34 millert Exp $ */ 2 /* $NetBSD: rpc_cout.c,v 1.6 1996/10/01 04:13:53 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 2010, Oracle America, Inc. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are 9 * met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials 16 * provided with the distribution. 17 * * Neither the name of the "Oracle America, Inc." nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 28 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * rpc_cout.c, XDR routine outputter for the RPC protocol compiler 37 */ 38 #include <sys/cdefs.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <ctype.h> 43 #include "rpc_parse.h" 44 #include "rpc_util.h" 45 46 static int findtype(definition *, char *); 47 static int undefined(char *); 48 static void print_generic_header(char *, int); 49 static void print_header(definition *); 50 static void print_prog_header(proc_list *); 51 static void print_trailer(void); 52 static void print_ifopen(int, char *); 53 static void print_ifarg(char *); 54 static void print_ifsizeof(char *, char *); 55 static void print_ifclose(int); 56 static void print_ifstat(int, char *, char *, relation, char *, char *, char *); 57 static void emit_program(definition *); 58 static void emit_enum(definition *); 59 static void emit_union(definition *); 60 static void emit_struct(definition *); 61 static void emit_typedef(definition *); 62 static void print_stat(int, declaration *); 63 void emit_inline(declaration *, int); 64 void emit_single_in_line(declaration *, int, relation); 65 66 /* 67 * Emit the C-routine for the given definition 68 */ 69 void 70 emit(def) 71 definition *def; 72 { 73 if (def->def_kind == DEF_CONST) { 74 return; 75 } 76 if (def->def_kind == DEF_PROGRAM) { 77 emit_program(def); 78 return; 79 } 80 if (def->def_kind == DEF_TYPEDEF) { 81 /* now we need to handle declarations like struct typedef foo 82 * foo; since we dont want this to be expanded into 2 calls to 83 * xdr_foo */ 84 85 if (strcmp(def->def.ty.old_type, def->def_name) == 0) 86 return; 87 } 88 89 print_header(def); 90 switch (def->def_kind) { 91 case DEF_UNION: 92 emit_union(def); 93 break; 94 case DEF_ENUM: 95 emit_enum(def); 96 break; 97 case DEF_STRUCT: 98 emit_struct(def); 99 break; 100 case DEF_TYPEDEF: 101 emit_typedef(def); 102 break; 103 } 104 print_trailer(); 105 } 106 107 static int 108 findtype(def, type) 109 definition *def; 110 char *type; 111 { 112 113 if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST) { 114 return (0); 115 } else { 116 return (streq(def->def_name, type)); 117 } 118 } 119 120 static int 121 undefined(type) 122 char *type; 123 { 124 definition *def; 125 126 def = (definition *) FINDVAL(defined, type, findtype); 127 return (def == NULL); 128 } 129 130 static void 131 print_generic_header(procname, pointerp) 132 char *procname; 133 int pointerp; 134 { 135 fprintf(fout, "\n"); 136 fprintf(fout, "bool_t\n"); 137 if (Cflag) { 138 fprintf(fout, "xdr_%s(", procname); 139 fprintf(fout, "XDR *xdrs, "); 140 fprintf(fout, "%s ", procname); 141 if (pointerp) 142 fprintf(fout, "*"); 143 fprintf(fout, "objp)\n{\n"); 144 } else { 145 fprintf(fout, "xdr_%s(xdrs, objp)\n", procname); 146 fprintf(fout, "\tXDR *xdrs;\n"); 147 fprintf(fout, "\t%s ", procname); 148 if (pointerp) 149 fprintf(fout, "*"); 150 fprintf(fout, "objp;\n{\n"); 151 } 152 } 153 154 static void 155 print_header(def) 156 definition *def; 157 { 158 print_generic_header(def->def_name, 159 def->def_kind != DEF_TYPEDEF || 160 !isvectordef(def->def.ty.old_type, def->def.ty.rel)); 161 162 /* Now add Inline support */ 163 164 if (doinline == 0) 165 return; 166 } 167 168 static void 169 print_prog_header(plist) 170 proc_list *plist; 171 { 172 print_generic_header(plist->args.argname, 1); 173 } 174 175 static void 176 print_trailer() 177 { 178 fprintf(fout, "\treturn (TRUE);\n"); 179 fprintf(fout, "}\n"); 180 } 181 182 static void 183 print_ifopen(indent, name) 184 int indent; 185 char *name; 186 { 187 tabify(fout, indent); 188 fprintf(fout, "if (!xdr_%s(xdrs", name); 189 } 190 191 static void 192 print_ifarg(arg) 193 char *arg; 194 { 195 fprintf(fout, ", %s", arg); 196 } 197 198 static void 199 print_ifsizeof(prefix, type) 200 char *prefix; 201 char *type; 202 { 203 if (streq(type, "bool")) { 204 fprintf(fout, ", sizeof(bool_t), (xdrproc_t)xdr_bool"); 205 } else { 206 fprintf(fout, ", sizeof("); 207 if (undefined(type) && prefix) { 208 fprintf(fout, "%s ", prefix); 209 } 210 fprintf(fout, "%s), (xdrproc_t)xdr_%s", type, type); 211 } 212 } 213 214 static void 215 print_ifclose(indent) 216 int indent; 217 { 218 fprintf(fout, "))\n"); 219 tabify(fout, indent); 220 fprintf(fout, "\treturn (FALSE);\n"); 221 } 222 223 static void 224 print_ifstat(indent, prefix, type, rel, amax, objname, name) 225 int indent; 226 char *prefix; 227 char *type; 228 relation rel; 229 char *amax; 230 char *objname; 231 char *name; 232 { 233 char *alt = NULL; 234 235 switch (rel) { 236 case REL_POINTER: 237 print_ifopen(indent, "pointer"); 238 print_ifarg("(char **)"); 239 fprintf(fout, "%s", objname); 240 print_ifsizeof(prefix, type); 241 break; 242 case REL_VECTOR: 243 if (streq(type, "string")) { 244 alt = "string"; 245 } else 246 if (streq(type, "opaque")) { 247 alt = "opaque"; 248 } 249 if (alt) { 250 print_ifopen(indent, alt); 251 print_ifarg(objname); 252 print_ifarg(amax); 253 } else { 254 print_ifopen(indent, "vector"); 255 print_ifarg("(char *)"); 256 fprintf(fout, "%s,\n", objname); 257 tabify(fout, indent); 258 fprintf(fout, " %s", amax); 259 } 260 if (!alt) { 261 print_ifsizeof(prefix, type); 262 } 263 break; 264 case REL_ARRAY: 265 if (streq(type, "string")) { 266 alt = "string"; 267 } else 268 if (streq(type, "opaque")) { 269 alt = "bytes"; 270 } 271 if (streq(type, "string")) { 272 print_ifopen(indent, alt); 273 print_ifarg(objname); 274 print_ifarg(amax); 275 } else { 276 if (alt) { 277 print_ifopen(indent, alt); 278 } else { 279 print_ifopen(indent, "array"); 280 } 281 print_ifarg("(char **)"); 282 if (*objname == '&') { 283 fprintf(fout, "%s.%s_val,\n\t (u_int *)%s.%s_len", 284 objname, name, objname, name); 285 } else { 286 fprintf(fout, "&%s->%s_val,\n\t (u_int *)&%s->%s_len", 287 objname, name, objname, name); 288 } 289 fprintf(fout, ",\n\t %s", amax); 290 } 291 if (!alt) { 292 print_ifsizeof(prefix, type); 293 } 294 break; 295 case REL_ALIAS: 296 print_ifopen(indent, type); 297 print_ifarg(objname); 298 break; 299 } 300 print_ifclose(indent); 301 } 302 303 /* ARGSUSED */ 304 static void 305 emit_enum(def) 306 definition *def; 307 { 308 fprintf(fout, "\n"); 309 310 print_ifopen(1, "enum"); 311 print_ifarg("(enum_t *)objp"); 312 print_ifclose(1); 313 } 314 315 static void 316 emit_program(def) 317 definition *def; 318 { 319 decl_list *dl; 320 version_list *vlist; 321 proc_list *plist; 322 323 for (vlist = def->def.pr.versions; vlist != NULL; vlist = vlist->next) 324 for (plist = vlist->procs; plist != NULL; plist = plist->next) { 325 if (!newstyle || plist->arg_num < 2) 326 continue; /* old style, or single 327 * argument */ 328 print_prog_header(plist); 329 for (dl = plist->args.decls; dl != NULL; 330 dl = dl->next) 331 print_stat(1, &dl->decl); 332 print_trailer(); 333 } 334 } 335 336 static void 337 emit_union(def) 338 definition *def; 339 { 340 declaration *dflt; 341 case_list *cl; 342 declaration *cs; 343 char *object; 344 char *vecformat = "objp->%s_u.%s"; 345 char *format = "&objp->%s_u.%s"; 346 347 fprintf(fout, "\n"); 348 print_stat(1, &def->def.un.enum_decl); 349 fprintf(fout, "\tswitch (objp->%s) {\n", def->def.un.enum_decl.name); 350 for (cl = def->def.un.cases; cl != NULL; cl = cl->next) { 351 fprintf(fout, "\tcase %s:\n", cl->case_name); 352 if (cl->contflag == 1) /* a continued case statement */ 353 continue; 354 cs = &cl->case_decl; 355 if (!streq(cs->type, "void")) { 356 int len = strlen(def->def_name) + strlen(format) + 357 strlen(cs->name) + 1; 358 359 object = alloc(len); 360 if (object == NULL) { 361 fprintf(stderr, "Fatal error: no memory\n"); 362 crash(); 363 } 364 if (isvectordef(cs->type, cs->rel)) { 365 snprintf(object, len, vecformat, def->def_name, 366 cs->name); 367 } else { 368 snprintf(object, len, format, def->def_name, 369 cs->name); 370 } 371 print_ifstat(2, cs->prefix, cs->type, cs->rel, cs->array_max, 372 object, cs->name); 373 free(object); 374 } 375 fprintf(fout, "\t\tbreak;\n"); 376 } 377 dflt = def->def.un.default_decl; 378 if (dflt != NULL) { 379 if (!streq(dflt->type, "void")) { 380 int len = strlen(def->def_name) + strlen(format) + 381 strlen(dflt->name) + 1; 382 383 fprintf(fout, "\tdefault:\n"); 384 object = alloc(len); 385 if (object == NULL) { 386 fprintf(stderr, "Fatal error: no memory\n"); 387 crash(); 388 } 389 if (isvectordef(dflt->type, dflt->rel)) { 390 snprintf(object, len, vecformat, def->def_name, 391 dflt->name); 392 } else { 393 snprintf(object, len, format, def->def_name, 394 dflt->name); 395 } 396 397 print_ifstat(2, dflt->prefix, dflt->type, dflt->rel, 398 dflt->array_max, object, dflt->name); 399 free(object); 400 fprintf(fout, "\t\tbreak;\n"); 401 } 402 } else { 403 fprintf(fout, "\tdefault:\n"); 404 fprintf(fout, "\t\treturn (FALSE);\n"); 405 } 406 407 fprintf(fout, "\t}\n"); 408 } 409 410 static void 411 emit_struct(def) 412 definition *def; 413 { 414 decl_list *dl; 415 int i, j, size, flag; 416 decl_list *cur, *psav; 417 bas_type *ptr; 418 char *sizestr, *plus; 419 char ptemp[256]; 420 int can_inline; 421 422 if (doinline == 0) { 423 for (dl = def->def.st.decls; dl != NULL; dl = dl->next) 424 print_stat(1, &dl->decl); 425 return; 426 } 427 for (dl = def->def.st.decls; dl != NULL; dl = dl->next) 428 if (dl->decl.rel == REL_VECTOR) { 429 fprintf(fout, "\tint i;\n"); 430 break; 431 } 432 fprintf(fout, "\n"); 433 434 size = 0; 435 can_inline = 0; 436 for (dl = def->def.st.decls; dl != NULL; dl = dl->next) 437 if (dl->decl.prefix == NULL && 438 (ptr = find_type(dl->decl.type)) != NULL && 439 (dl->decl.rel == REL_ALIAS || dl->decl.rel == REL_VECTOR)) { 440 if (dl->decl.rel == REL_ALIAS) 441 size += ptr->length; 442 else { 443 can_inline = 1; 444 break; /* can be inlined */ 445 } 446 } else { 447 if (size >= doinline) { 448 can_inline = 1; 449 break; /* can be inlined */ 450 } 451 size = 0; 452 } 453 if (size > doinline) 454 can_inline = 1; 455 456 if (can_inline == 0) { /* can not inline, drop back to old mode */ 457 fprintf(fout, "\n"); 458 for (dl = def->def.st.decls; dl != NULL; dl = dl->next) 459 print_stat(1, &dl->decl); 460 return; 461 } 462 463 /* May cause lint to complain. but ... */ 464 fprintf(fout, "\tint32_t *buf;\n"); 465 466 flag = PUT; 467 for (j = 0; j < 2; j++) { 468 if (flag == PUT) 469 fprintf(fout, "\n\tif (xdrs->x_op == XDR_ENCODE) {\n"); 470 else 471 fprintf(fout, "\t\treturn (TRUE);\n\t} else if (xdrs->x_op == XDR_DECODE) {\n"); 472 473 i = 0; 474 size = 0; 475 sizestr = NULL; 476 for (dl = def->def.st.decls; dl != NULL; dl = dl->next) { /* xxx */ 477 478 /* now walk down the list and check for basic types */ 479 if (dl->decl.prefix == NULL && 480 (ptr = find_type(dl->decl.type)) != NULL && 481 (dl->decl.rel == REL_ALIAS || dl->decl.rel == REL_VECTOR)) { 482 if (i == 0) 483 cur = dl; 484 i++; 485 486 if (dl->decl.rel == REL_ALIAS) 487 size += ptr->length; 488 else { 489 /* this is required to handle arrays */ 490 491 if (sizestr == NULL) 492 plus = ""; 493 else 494 plus = "+"; 495 496 if (ptr->length != 1) 497 snprintf(ptemp, sizeof ptemp, 498 "%s%s* %d", plus, 499 dl->decl.array_max, 500 ptr->length); 501 else 502 snprintf(ptemp, sizeof ptemp, 503 "%s%s", plus, 504 dl->decl.array_max); 505 506 /* now concatenate to sizestr !!!! */ 507 if (sizestr == NULL) { 508 sizestr = strdup(ptemp); 509 if (sizestr == NULL) { 510 fprintf(stderr, 511 "Fatal error: no memory\n"); 512 crash(); 513 } 514 } else { 515 size_t len; 516 517 len = strlen(sizestr) + 518 strlen(ptemp) + 1; 519 sizestr = (char *)realloc(sizestr, len); 520 if (sizestr == NULL) { 521 fprintf(stderr, 522 "Fatal error: no memory\n"); 523 crash(); 524 } 525 /* build up length of array */ 526 strlcat(sizestr, ptemp, len); 527 } 528 } 529 530 } else { 531 if (i > 0) { 532 if (sizestr == NULL && size < doinline) { 533 /* don't expand into inline 534 * code if size < doinline */ 535 while (cur != dl) { 536 print_stat(2, &cur->decl); 537 cur = cur->next; 538 } 539 } else { 540 /* were already looking at a 541 * xdr_inlineable structure */ 542 if (sizestr == NULL) 543 fprintf(fout, 544 "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t %d * BYTES_PER_XDR_UNIT);", size); 545 else if (size == 0) 546 fprintf(fout, 547 "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t %s * BYTES_PER_XDR_UNIT);", 548 sizestr); 549 else 550 fprintf(fout, 551 "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t (%d + %s) * BYTES_PER_XDR_UNIT);", size, sizestr); 552 553 fprintf(fout, 554 "\n\t\tif (buf == NULL) {\n"); 555 556 psav = cur; 557 while (cur != dl) { 558 print_stat(3, &cur->decl); 559 cur = cur->next; 560 } 561 562 fprintf(fout, "\t\t} else {\n"); 563 564 cur = psav; 565 while (cur != dl) { 566 emit_inline(&cur->decl, flag); 567 cur = cur->next; 568 } 569 fprintf(fout, "\t\t}\n"); 570 } 571 } 572 size = 0; 573 i = 0; 574 sizestr = NULL; 575 print_stat(2, &dl->decl); 576 } 577 } 578 if (i > 0) { 579 if (sizestr == NULL && size < doinline) { 580 /* don't expand into inline code if size < 581 * doinline */ 582 while (cur != dl) { 583 print_stat(2, &cur->decl); 584 cur = cur->next; 585 } 586 } else { 587 /* were already looking at a xdr_inlineable 588 * structure */ 589 if (sizestr == NULL) 590 fprintf(fout, "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t %d * BYTES_PER_XDR_UNIT);", 591 size); 592 else 593 if (size == 0) 594 fprintf(fout, 595 "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t %s * BYTES_PER_XDR_UNIT);", 596 sizestr); 597 else 598 fprintf(fout, 599 "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t (%d + %s) * BYTES_PER_XDR_UNIT);", 600 size, sizestr); 601 602 fprintf(fout, "\n\t\tif (buf == NULL) {\n"); 603 604 psav = cur; 605 while (cur != NULL) { 606 print_stat(3, &cur->decl); 607 cur = cur->next; 608 } 609 fprintf(fout, "\t\t} else {\n"); 610 611 cur = psav; 612 while (cur != dl) { 613 emit_inline(&cur->decl, flag); 614 cur = cur->next; 615 } 616 617 fprintf(fout, "\t\t}\n"); 618 619 } 620 } 621 flag = GET; 622 } 623 fprintf(fout, "\t\treturn (TRUE);\n\t}\n\n"); 624 625 /* now take care of XDR_FREE case */ 626 627 for (dl = def->def.st.decls; dl != NULL; dl = dl->next) 628 print_stat(1, &dl->decl); 629 } 630 631 static void 632 emit_typedef(def) 633 definition *def; 634 { 635 char *prefix = def->def.ty.old_prefix; 636 char *type = def->def.ty.old_type; 637 char *amax = def->def.ty.array_max; 638 relation rel = def->def.ty.rel; 639 640 fprintf(fout, "\n"); 641 print_ifstat(1, prefix, type, rel, amax, "objp", def->def_name); 642 } 643 644 static void 645 print_stat(indent, dec) 646 declaration *dec; 647 int indent; 648 { 649 char *prefix = dec->prefix; 650 char *type = dec->type; 651 char *amax = dec->array_max; 652 relation rel = dec->rel; 653 char name[256]; 654 655 if (isvectordef(type, rel)) { 656 snprintf(name, sizeof name, "objp->%s", dec->name); 657 } else { 658 snprintf(name, sizeof name, "&objp->%s", dec->name); 659 } 660 print_ifstat(indent, prefix, type, rel, amax, name, dec->name); 661 } 662 663 char *upcase(char *); 664 665 void 666 emit_inline(decl, flag) 667 declaration *decl; 668 int flag; 669 { 670 /*check whether an array or not */ 671 672 switch (decl->rel) { 673 case REL_ALIAS: 674 fprintf(fout, "\t"); 675 emit_single_in_line(decl, flag, REL_ALIAS); 676 break; 677 case REL_VECTOR: 678 fprintf(fout, "\t\t\t{\n\t\t\t\t%s *genp;\n\n", decl->type); 679 fprintf(fout, "\t\t\t\tfor (i = 0, genp = objp->%s;\n\t\t\t\t i < %s; i++) {\n\t\t\t", 680 decl->name, decl->array_max); 681 emit_single_in_line(decl, flag, REL_VECTOR); 682 fprintf(fout, "\t\t\t\t}\n\t\t\t}\n"); 683 684 } 685 } 686 687 void 688 emit_single_in_line(decl, flag, rel) 689 declaration *decl; 690 int flag; 691 relation rel; 692 { 693 char *upp_case; 694 int freed = 0; 695 696 if (flag == PUT) 697 fprintf(fout, "\t\tIXDR_PUT_"); 698 else 699 if (rel == REL_ALIAS) 700 fprintf(fout, "\t\tobjp->%s = IXDR_GET_", decl->name); 701 else 702 fprintf(fout, "\t\t*genp++ = IXDR_GET_"); 703 704 upp_case = upcase(decl->type); 705 706 /* hack - XX */ 707 if (strcmp(upp_case, "INT") == 0) { 708 free(upp_case); 709 freed = 1; 710 upp_case = "LONG"; 711 } 712 if (strcmp(upp_case, "U_INT") == 0) { 713 free(upp_case); 714 freed = 1; 715 upp_case = "U_LONG"; 716 } 717 if (flag == PUT) 718 if (rel == REL_ALIAS) 719 fprintf(fout, "%s(buf, objp->%s);\n", upp_case, decl->name); 720 else 721 fprintf(fout, "%s(buf, *genp++);\n", upp_case); 722 723 else 724 fprintf(fout, "%s(buf);\n", upp_case); 725 if (!freed) 726 free(upp_case); 727 } 728 729 char * 730 upcase(str) 731 char *str; 732 { 733 char *ptr, *hptr; 734 735 ptr = (char *) malloc(strlen(str)+1); 736 if (ptr == (char *) NULL) { 737 fprintf(stderr, "malloc failed\n"); 738 exit(1); 739 } 740 741 hptr = ptr; 742 while (*str != '\0') 743 *ptr++ = toupper(*str++); 744 745 *ptr = '\0'; 746 return (hptr); 747 } 748