1 /* 2 * Code generation from interface descriptions. 3 * 4 * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <stdlib.h> 23 #include "client.h" 24 #include "common.h" 25 #include "declaration.h" 26 #include "dispatch.h" 27 #include "message.h" 28 #include "program.h" 29 #include "server.h" 30 #include "structure.h" 31 #include "summary.h" 32 #include "templates.h" 33 34 /* Program state set in the main program. */ 35 36 extern char *output_prefix, *output_dir, 37 *output_compound, *output_compound_name; 38 39 extern int output_client, output_server, 40 output_headers, output_interfaces, output_routines, 41 output_verbose; 42 43 extern enum language output_language; 44 45 /* Current filename details. */ 46 47 char *output_basename = NULL, *output_dirname = NULL; 48 49 /* Client, server and common files. */ 50 51 FILE *client_fp = NULL, *client_header_fp = NULL, 52 *server_fp = NULL, *server_header_fp = NULL, 53 *server_interface_fp = NULL, 54 *common_fp = NULL; 55 56 /* Compound interface and dispatcher files. */ 57 58 FILE *compound_dispatch_fp = NULL, *compound_dispatch_header_fp = NULL, 59 *compound_interface_fp = NULL, *compound_interfaces_fp = NULL; 60 61 /* Processed interfaces. */ 62 63 int processed_interfaces; 64 65 /* Maximum number of input items expected by an interface. */ 66 67 int max_input_items = 0; 68 69 70 71 /* Return the first interface name as the output prefix. */ 72 73 static char *get_output_prefix(struct interface *i) 74 { 75 if (output_prefix != NULL) 76 return output_prefix; 77 78 if (i == NULL) 79 return NULL; 80 81 for (; i->tail != NULL; i = i->tail); 82 return i->name; 83 } 84 85 /* Obtain the basename and directory name of generated output. */ 86 87 static int set_output_location(struct interface *iface) 88 { 89 /* Obtain a prefix for the output files. */ 90 91 output_prefix = get_output_prefix(iface); 92 93 if (output_prefix == NULL) 94 return 0; 95 96 /* Obtain the basename of the output prefix. */ 97 98 output_basename = make_basename(output_prefix); 99 100 if (output_basename == NULL) 101 return 0; 102 103 /* Obtain the directory name from the output prefix. */ 104 105 if (output_dir == NULL) 106 output_dirname = make_dirname(output_prefix); 107 else 108 output_dirname = output_dir; 109 110 if (output_dirname == NULL) 111 { 112 free(output_basename); 113 return 0; 114 } 115 116 return 1; 117 } 118 119 static void write_includes_separator(struct include *inc, FILE *fp) 120 { 121 if (inc != NULL) 122 fputs("\n", fp); 123 } 124 125 static void write_signature_end(FILE *fp) 126 { 127 fputs(";\n", fp); 128 } 129 130 131 /* Generate compound code output, if requested. */ 132 133 void begin_compound_output(void) 134 { 135 char *compound_dirname = output_dir != NULL ? output_dir : "."; 136 char *s; 137 138 if (output_compound == NULL) 139 return; 140 141 processed_interfaces = 0; 142 143 if (output_headers) 144 { 145 compound_dispatch_header_fp = get_output_file(server_header_filename, 146 compound_dirname, output_compound); 147 if (compound_dispatch_header_fp == NULL) 148 goto fail; 149 } 150 151 if (output_interfaces) 152 { 153 compound_interface_fp = get_output_file(server_interface_filename, 154 compound_dirname, output_compound); 155 if (compound_interface_fp == NULL) 156 goto fail; 157 158 compound_interfaces_fp = get_output_file(compound_interfaces_filename, 159 compound_dirname, output_compound); 160 if (compound_interfaces_fp == NULL) 161 goto fail; 162 } 163 164 if (output_routines) 165 { 166 s = (output_language == CPP_LANGUAGE) ? server_filename_cpp : 167 server_filename_c; 168 compound_dispatch_fp = get_output_file(s, compound_dirname, output_compound); 169 if (compound_dispatch_fp == NULL) 170 goto fail; 171 } 172 173 /* Emit prologues. */ 174 175 if (compound_dispatch_fp != NULL) 176 { 177 fprintf(compound_dispatch_fp, compound_dispatch_prologue, output_compound); 178 179 /* Write the handler function. */ 180 181 write_compound_handler_signature(compound_dispatch_fp); 182 fputs("\n", compound_dispatch_fp); 183 fprintf(compound_dispatch_fp, compound_handle_function, output_compound_name); 184 185 /* Write the dispatch function. */ 186 187 write_compound_dispatch_signature(compound_dispatch_fp); 188 fputs("\n", compound_dispatch_fp); 189 fputs(compound_dispatch_function_prologue, compound_dispatch_fp); 190 } 191 192 if (compound_dispatch_header_fp != NULL) 193 { 194 fprintf(compound_dispatch_header_fp, compound_dispatch_header_prologue, 195 output_compound); 196 197 /* Write the handler signature. */ 198 199 write_compound_handler_signature(compound_dispatch_header_fp); 200 fputs(";\n", compound_dispatch_header_fp); 201 202 /* Write the dispatch signature. */ 203 204 write_compound_dispatch_signature(compound_dispatch_header_fp); 205 fputs(";\n\n", compound_dispatch_header_fp); 206 } 207 208 if (compound_interface_fp != NULL) 209 fprintf(compound_interface_fp, compound_interface_prologue, 210 output_compound, output_compound_name); 211 212 if (compound_interfaces_fp != NULL) 213 fputs(compound_interfaces_prologue, compound_interfaces_fp); 214 215 return; 216 217 fail: 218 end_compound_output(); 219 } 220 221 void write_compound_output(struct interface *iface) 222 { 223 char *protocol; 224 int input_items; 225 226 if (compound_dispatch_fp != NULL) 227 { 228 protocol = get_protocol(iface->attributes); 229 230 /* Populate a function dispatching to each interface-level function where 231 the same protocol applies to an entire interface. */ 232 233 if (protocol != NULL) 234 fprintf(compound_dispatch_fp, dispatch_function_interface_case, 235 protocol, iface->name); 236 237 /* Or dispatch to each operation defined at this level. */ 238 239 else 240 write_dispatcher_cases(iface->signatures, compound_dispatch_fp, iface); 241 } 242 243 if (compound_dispatch_header_fp != NULL) 244 { 245 /* Compute the maximum number of items expected by each interface. */ 246 247 input_items = get_max_input_items(iface->signatures); 248 249 if (input_items > max_input_items) 250 max_input_items = input_items; 251 } 252 253 /* Add this interface to the compound interface. */ 254 255 if (compound_interface_fp != NULL) 256 write_compound_interface(iface); 257 258 /* Add this interface's header to the compound interface includes. */ 259 260 if (compound_interfaces_fp != NULL) 261 fprintf(compound_interfaces_fp, "#include \"%s_interface.h\"\n", 262 output_basename); 263 264 processed_interfaces++; 265 } 266 267 /* Generate includes for the server and common declarations from each input 268 file. */ 269 270 void write_compound_dispatch_include(void) 271 { 272 if (compound_dispatch_header_fp != NULL) 273 { 274 fprintf(compound_dispatch_header_fp, "#include \"%s_server.h\"\n", 275 output_basename); 276 fprintf(compound_dispatch_header_fp, "#include \"%s_common.h\"\n", 277 output_basename); 278 } 279 } 280 281 void write_compound_dispatch_signature(FILE *fp) 282 { 283 char *s = (output_language == CPP_LANGUAGE) ? 284 compound_dispatch_function_signature_cpp : 285 compound_dispatch_function_signature_c; 286 287 fprintf(fp, s, output_compound_name, output_compound_name); 288 } 289 290 void write_compound_handler_signature(FILE *fp) 291 { 292 char *s = (output_language == CPP_LANGUAGE) ? 293 compound_handle_function_signature_cpp : 294 compound_handle_function_signature_c; 295 296 fprintf(fp, s, output_compound_name, output_compound_name); 297 } 298 299 /* Augment a compound interface class declaration. */ 300 301 void write_compound_interface(struct interface *iface) 302 { 303 char *sep = processed_interfaces ? ", " : " "; 304 fprintf(compound_interface_fp, "%spublic %s", sep, iface->name); 305 } 306 307 void end_compound_output(void) 308 { 309 /* Close the files. */ 310 311 if (compound_dispatch_fp != NULL) 312 { 313 fputs(compound_dispatch_epilogue, compound_dispatch_fp); 314 fclose(compound_dispatch_fp); 315 } 316 317 if (compound_dispatch_header_fp != NULL) 318 { 319 fprintf(compound_dispatch_header_fp, compound_dispatch_header_epilogue, 320 output_compound_name, max_input_items); 321 fclose(compound_dispatch_header_fp); 322 } 323 324 if (compound_interface_fp != NULL) 325 { 326 fputs(compound_interface_epilogue, compound_interface_fp); 327 fclose(compound_interface_fp); 328 } 329 330 if (compound_interfaces_fp != NULL) 331 fclose(compound_interfaces_fp); 332 } 333 334 335 336 /* Generate files containing interface details. */ 337 338 void write_files(struct interface *iface) 339 { 340 char *server_filename; 341 342 /* NOTE: Should exit with an error. */ 343 344 if (!set_output_location(iface)) 345 return; 346 347 /* Include server details for a compound interface dispatch function. */ 348 349 write_compound_dispatch_include(); 350 351 /* Open the separate files and write the details of each interface. */ 352 353 if (output_headers) 354 { 355 if (output_client) 356 { 357 client_header_fp = get_output_file(client_header_filename, output_dirname, output_basename); 358 if (client_header_fp == NULL) 359 goto finalisation; 360 } 361 362 if (output_server) 363 { 364 server_header_fp = get_output_file(server_header_filename, output_dirname, output_basename); 365 if (server_header_fp == NULL) 366 goto finalisation; 367 } 368 369 common_fp = get_output_file(common_filename, output_dirname, output_basename); 370 if (common_fp == NULL) 371 goto finalisation; 372 } 373 374 if (output_interfaces) 375 { 376 if (output_server) 377 { 378 server_interface_fp = get_output_file(server_interface_filename, output_dirname, output_basename); 379 if (server_interface_fp == NULL) 380 goto finalisation; 381 } 382 } 383 384 if (output_routines) 385 { 386 if (output_client) 387 { 388 client_fp = get_output_file(client_filename, output_dirname, output_basename); 389 if (client_fp == NULL) 390 goto finalisation; 391 } 392 393 if (output_server) 394 { 395 server_filename = (output_language == CPP_LANGUAGE) ? server_filename_cpp : server_filename_c; 396 server_fp = get_output_file(server_filename, output_dirname, output_basename); 397 if (server_fp == NULL) 398 goto finalisation; 399 } 400 } 401 402 /* Emit prologues. */ 403 404 if (client_fp != NULL) 405 fprintf(client_fp, client_prologue, output_basename, output_basename); 406 407 if (client_header_fp != NULL) 408 fputs(header_prologue, client_header_fp); 409 410 if (server_fp != NULL) 411 fprintf(server_fp, server_prologue, output_basename, output_basename); 412 413 if (server_header_fp != NULL) 414 fputs(server_header_prologue, server_header_fp); 415 416 if (server_interface_fp != NULL) 417 fputs(header_prologue, server_interface_fp); 418 419 if (common_fp != NULL) 420 fputs(header_prologue, common_fp); 421 422 /* Write the interface details. */ 423 424 write_interfaces(iface); 425 426 finalisation: 427 428 /* Close the files. */ 429 430 if (client_fp != NULL) 431 fclose(client_fp); 432 433 if (client_header_fp != NULL) 434 fclose(client_header_fp); 435 436 if (server_fp != NULL) 437 fclose(server_fp); 438 439 if (server_header_fp != NULL) 440 fclose(server_header_fp); 441 442 if (server_interface_fp != NULL) 443 fclose(server_interface_fp); 444 445 if (common_fp != NULL) 446 fclose(common_fp); 447 448 /* Free the names. */ 449 450 if (output_dir == NULL) 451 free(output_dirname); 452 453 free(output_basename); 454 } 455 456 /* Generate the source file corresponding to the interface. */ 457 458 void write_interfaces(struct interface *iface) 459 { 460 if (iface == NULL) 461 return; 462 463 /* The list is reversed. */ 464 465 write_interfaces(iface->tail); 466 467 /* Write this particular interface after all referenced ones. */ 468 469 if (output_verbose) 470 show_interface(iface); 471 472 /* Record details of this interface in the compound output. */ 473 474 write_compound_output(iface); 475 476 /* Emit function definitions. */ 477 478 if (client_fp != NULL) 479 write_functions(iface->signatures, client_fp, iface, 480 write_client_function); 481 482 if (server_fp != NULL) 483 { 484 write_functions(iface->signatures, server_fp, iface, 485 write_server_function); 486 487 write_dispatcher(iface->signatures, server_fp, iface); 488 } 489 490 /* Emit the headers. */ 491 492 if (client_header_fp != NULL) 493 { 494 /* Emit include statements. */ 495 496 write_includes_separator(iface->includes, client_header_fp); 497 write_includes(iface->includes, client_header_fp); 498 499 /* Emit signatures. */ 500 501 write_signatures(iface->signatures, client_header_fp, iface, 502 write_client_signature); 503 } 504 505 if (server_header_fp != NULL) 506 { 507 /* Emit interface include where the type is employed by signatures. */ 508 509 if (output_language == CPP_LANGUAGE) 510 fprintf(server_header_fp, "#include \"%s_interface.h\"\n", output_basename); 511 512 /* Emit signatures. */ 513 514 write_signatures(iface->signatures, server_header_fp, iface, 515 write_server_signature); 516 517 write_dispatcher_signature(server_header_fp, iface); 518 } 519 520 if (server_interface_fp != NULL) 521 { 522 /* Emit include statements. */ 523 524 write_includes_separator(iface->includes, server_interface_fp); 525 write_includes(iface->includes, server_interface_fp); 526 527 /* Begin any namespace. */ 528 529 if (output_language == CPP_LANGUAGE) 530 fprintf(server_interface_fp, server_interface_prologue_cpp, iface->name); 531 532 /* Emit signatures. */ 533 534 write_signatures(iface->signatures, server_interface_fp, iface, 535 write_server_interface_signature); 536 537 /* Terminate any namespace. */ 538 539 if (output_language == CPP_LANGUAGE) 540 fputs(server_interface_epilogue_cpp, server_interface_fp); 541 } 542 543 /* Emit common structures. */ 544 545 if (common_fp != NULL) 546 { 547 /* Emit include statements. */ 548 549 write_includes_separator(iface->includes, common_fp); 550 write_includes(iface->includes, common_fp); 551 552 /* Emit opcodes. */ 553 554 write_opcode_definition(iface, common_fp); 555 556 /* Emit message access structures. */ 557 558 write_structures(iface->signatures, common_fp, iface); 559 } 560 } 561 562 /* Write include statements. */ 563 564 void write_includes(struct include *inc, FILE *fp) 565 { 566 if (inc == NULL) 567 return; 568 569 /* The list is reversed. */ 570 571 write_includes(inc->tail, fp); 572 573 fprintf(fp, "#include %s\n", inc->filename); 574 } 575 576 /* Generate signatures. */ 577 578 void write_signatures(struct signature *sig, FILE *fp, struct interface *iface, 579 void (*write_signature)(struct signature *, FILE *, struct interface *)) 580 { 581 if (sig == NULL) 582 return; 583 584 write_signature(sig, fp, iface); 585 write_signatures(sig->tail, fp, iface, write_signature); 586 } 587 588 /* Generate functions corresponding to the signatures. */ 589 590 void write_functions(struct signature *sig, FILE *fp, struct interface *iface, 591 void (*write_function)(struct signature *, FILE *, struct interface *)) 592 { 593 if (sig == NULL) 594 return; 595 596 write_function(sig, fp, iface); 597 write_functions(sig->tail, fp, iface, write_function); 598 }