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