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