1 /* $OpenBSD: rpc_cout.c,v 1.29 2023/03/08 04:43:12 guenther 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 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 static const char vecformat[] = "objp->%s_u.%s"; 345 static const 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 = malloc(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 fprintf(fout, "\tdefault:\n"); 379 if (dflt != NULL) { 380 if (!streq(dflt->type, "void")) { 381 int len = strlen(def->def_name) + strlen(format) + 382 strlen(dflt->name) + 1; 383 384 object = malloc(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 } 401 fprintf(fout, "\t\tbreak;\n"); 402 } else { 403 fprintf(fout, "\t\treturn (FALSE);\n"); 404 } 405 406 fprintf(fout, "\t}\n"); 407 } 408 409 static void 410 emit_struct(def) 411 definition *def; 412 { 413 decl_list *dl; 414 int i, j, size, flag; 415 decl_list *cur, *psav; 416 bas_type *ptr; 417 char *sizestr, *plus; 418 char ptemp[256]; 419 int can_inline; 420 421 if (doinline == 0) { 422 for (dl = def->def.st.decls; dl != NULL; dl = dl->next) 423 print_stat(1, &dl->decl); 424 return; 425 } 426 for (dl = def->def.st.decls; dl != NULL; dl = dl->next) 427 if (dl->decl.rel == REL_VECTOR && 428 strcmp(dl->decl.type, "opaque") != 0) { 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 = 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 break; 684 default: 685 break; 686 687 } 688 } 689 690 void 691 emit_single_in_line(decl, flag, rel) 692 declaration *decl; 693 int flag; 694 relation rel; 695 { 696 char *upp_case; 697 int freed = 0; 698 699 if (flag == PUT) 700 fprintf(fout, "\t\tIXDR_PUT_"); 701 else 702 if (rel == REL_ALIAS) 703 fprintf(fout, "\t\tobjp->%s = IXDR_GET_", decl->name); 704 else 705 fprintf(fout, "\t\t*genp++ = IXDR_GET_"); 706 707 upp_case = upcase(decl->type); 708 709 /* hack - XX */ 710 if (strcmp(upp_case, "INT") == 0) { 711 free(upp_case); 712 freed = 1; 713 upp_case = "LONG"; 714 } 715 if (strcmp(upp_case, "U_INT") == 0) { 716 free(upp_case); 717 freed = 1; 718 upp_case = "U_LONG"; 719 } 720 if (flag == PUT) 721 if (rel == REL_ALIAS) 722 fprintf(fout, "%s(buf, objp->%s);\n", upp_case, decl->name); 723 else 724 fprintf(fout, "%s(buf, *genp++);\n", upp_case); 725 726 else 727 fprintf(fout, "%s(buf);\n", upp_case); 728 if (!freed) 729 free(upp_case); 730 } 731 732 char * 733 upcase(str) 734 char *str; 735 { 736 char *ptr, *hptr; 737 738 ptr = malloc(strlen(str)+1); 739 if (ptr == (char *) NULL) { 740 fprintf(stderr, "malloc failed\n"); 741 exit(1); 742 } 743 744 hptr = ptr; 745 while (*str != '\0') 746 *ptr++ = toupper((unsigned char)*str++); 747 748 *ptr = '\0'; 749 return (hptr); 750 } 751