1 /* 2 * Code generation from interface descriptions. 3 * 4 * Copyright (C) 2019, 2020 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 "config.h" 26 #include "declaration.h" 27 #include "dispatch.h" 28 #include "includes.h" 29 #include "interface.h" 30 #include "message.h" 31 #include "program.h" 32 #include "server.h" 33 #include "summary.h" 34 #include "templates.h" 35 36 37 38 /* Current filename details. */ 39 40 char *output_basename = NULL, *output_dirname = NULL; 41 42 /* Client, server and common files. */ 43 44 FILE *client_fp = NULL, *client_header_fp = NULL, 45 *server_fp = NULL, *server_header_fp = NULL, 46 *interface_fp = NULL; 47 48 /* Compound interface and dispatcher files. */ 49 50 FILE *compound_dispatch_fp = NULL, *compound_dispatch_header_fp = NULL, 51 *compound_interface_fp = NULL, *compound_interfaces_fp = NULL, 52 *compound_interface_type_fp = NULL; 53 54 /* Processed interfaces. */ 55 56 int processed_interfaces; 57 58 /* Maximum number of input items expected by an interface. */ 59 60 int max_input_items = 0; 61 62 63 64 /* Return the first interface name as the output prefix. */ 65 66 static char *get_output_prefix(struct interface *i) 67 { 68 if (conf.output_prefix != NULL) 69 return conf.output_prefix; 70 71 if (i == NULL) 72 return NULL; 73 74 for (; i->tail != NULL; i = i->tail); 75 return i->name; 76 } 77 78 /* Obtain the basename and directory name of generated output. */ 79 80 static int set_output_location(struct interface *iface) 81 { 82 /* Obtain a prefix for the output files. */ 83 84 conf.output_prefix = get_output_prefix(iface); 85 86 if (conf.output_prefix == NULL) 87 return 0; 88 89 /* Obtain the basename of the output prefix. */ 90 91 output_basename = make_basename(conf.output_prefix); 92 93 if (output_basename == NULL) 94 return 0; 95 96 /* Obtain the directory name from the output prefix. */ 97 98 if (conf.output_dir == NULL) 99 output_dirname = make_dirname(conf.output_prefix); 100 else 101 output_dirname = conf.output_dir; 102 103 if (output_dirname == NULL) 104 { 105 free(output_basename); 106 return 0; 107 } 108 109 return 1; 110 } 111 112 113 114 /* Generate compound code output, if requested. */ 115 116 int begin_compound_output(void) 117 { 118 char *compound_dirname = conf.output_dir != NULL ? conf.output_dir : "."; 119 char *s; 120 121 if (conf.compound == NULL) 122 return 1; 123 124 processed_interfaces = 0; 125 126 if (conf.headers) 127 { 128 compound_dispatch_header_fp = get_output_file(server_header_filename, 129 compound_dirname, conf.compound); 130 if (compound_dispatch_header_fp == NULL) 131 return 0; 132 } 133 134 if (conf.interfaces) 135 { 136 compound_interface_fp = get_output_file(interface_filename, 137 compound_dirname, conf.compound); 138 if (compound_interface_fp == NULL) 139 return 0; 140 141 compound_interface_type_fp = get_output_file(compound_interface_type_filename, 142 compound_dirname, conf.compound); 143 if (compound_interface_type_fp == NULL) 144 return 0; 145 146 compound_interfaces_fp = get_output_file(compound_interfaces_filename, 147 compound_dirname, conf.compound); 148 if (compound_interfaces_fp == NULL) 149 return 0; 150 } 151 152 if (conf.routines) 153 { 154 s = (conf.language == CPP_LANGUAGE) ? server_filename_cpp : 155 server_filename_c; 156 compound_dispatch_fp = get_output_file(s, compound_dirname, conf.compound); 157 if (compound_dispatch_fp == NULL) 158 return 0; 159 } 160 161 /* Emit prologues. */ 162 163 if (compound_dispatch_fp != NULL) 164 { 165 fprintf(compound_dispatch_fp, compound_dispatch_prologue, conf.compound); 166 167 /* Write the handle function and dispatch function prologue. */ 168 169 write_handler_signature(conf.compound_name, DEFINITION_ROLE, 170 compound_dispatch_fp); 171 fprintf(compound_dispatch_fp, handle_function, conf.compound_name); 172 fputs(END_FUNCTION, compound_dispatch_fp); 173 174 write_dispatcher_signature(conf.compound_name, DEFINITION_ROLE, 175 compound_dispatch_fp); 176 fputs(compound_dispatch_function_prologue, compound_dispatch_fp); 177 } 178 179 if (compound_dispatch_header_fp != NULL) 180 { 181 fprintf(compound_dispatch_header_fp, compound_dispatch_header_prologue, 182 conf.compound); 183 184 /* Write the handler and dispatch signatures. */ 185 186 write_handler_signature(conf.compound_name, DECLARATION_ROLE, 187 compound_dispatch_header_fp); 188 189 write_dispatcher_signature(conf.compound_name, DECLARATION_ROLE, 190 compound_dispatch_header_fp); 191 fputs("\n", compound_dispatch_header_fp); 192 } 193 194 if (compound_interface_fp != NULL) 195 fprintf(compound_interface_fp, 196 (conf.language == CPP_LANGUAGE) ? compound_interface_prologue_cpp 197 : compound_interface_prologue_c, 198 conf.compound, conf.compound_name); 199 200 if (compound_interface_type_fp != NULL) 201 { 202 /* Begin reference type. */ 203 204 if (conf.language != CPP_LANGUAGE) 205 fprintf(compound_interface_type_fp, compound_ref_type_definition_prologue_c, 206 conf.compound, L4_CAP_TYPE); 207 } 208 209 if (compound_interfaces_fp != NULL) 210 fputs(compound_interfaces_prologue, compound_interfaces_fp); 211 212 return 1; 213 } 214 215 void write_compound_output(struct interface *iface) 216 { 217 char *protocol, *ref; 218 int input_items; 219 220 if (compound_dispatch_fp != NULL) 221 { 222 protocol = get_protocol(iface->attributes); 223 224 /* Populate a function dispatching to each interface-level function where 225 the same protocol applies to an entire interface. */ 226 227 if (protocol != NULL) 228 { 229 ref = get_object_conversion(iface, 1); 230 231 fprintf(compound_dispatch_fp, dispatch_function_interface_case, 232 protocol, iface->name, ref); 233 234 free(ref); 235 } 236 237 /* Or dispatch to each operation defined at this level. */ 238 239 else 240 write_dispatcher_cases(iface->signatures, compound_dispatch_fp, iface, 1); 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 write_include(output_basename, "_interface.h", compound_interfaces_fp); 262 263 processed_interfaces++; 264 } 265 266 /* Generate includes for the server and common declarations from each input 267 file. */ 268 269 void write_compound_dispatch_include(void) 270 { 271 if (compound_dispatch_header_fp != NULL) 272 write_include(output_basename, "_server.h", compound_dispatch_header_fp); 273 } 274 275 /* Augment a compound interface class declaration. */ 276 277 void write_compound_interface(struct interface *iface) 278 { 279 char *sep; 280 281 if (conf.language == CPP_LANGUAGE) 282 { 283 sep = processed_interfaces ? ", " : " "; 284 fprintf(compound_interface_fp, "%spublic %s", sep, iface->name); 285 } 286 else 287 fprintf(compound_interface_fp, " iface_%s *to_%s;\n", iface->name, iface->name); 288 289 /* Include reference type. */ 290 291 if (conf.language != CPP_LANGUAGE) 292 fprintf(compound_interface_type_fp, compound_ref_type_definition_member_c, 293 iface->name, iface->name); 294 } 295 296 void end_compound_output(void) 297 { 298 /* Close the files. */ 299 300 if (compound_dispatch_fp != NULL) 301 { 302 fputs(compound_dispatch_epilogue, compound_dispatch_fp); 303 fputs(END_FUNCTION, compound_dispatch_fp); 304 fclose(compound_dispatch_fp); 305 } 306 307 if (compound_dispatch_header_fp != NULL) 308 { 309 fprintf(compound_dispatch_header_fp, expected_items_definition, 310 conf.compound_name, max_input_items); 311 fclose(compound_dispatch_header_fp); 312 } 313 314 if (compound_interface_fp != NULL) 315 { 316 if (conf.language == CPP_LANGUAGE) 317 fputs(compound_interface_epilogue_cpp, compound_interface_fp); 318 else 319 { 320 fprintf(compound_interface_fp, compound_interface_epilogue_c, 321 conf.compound_name); 322 323 /* Include object type. */ 324 325 fprintf(compound_interface_fp, object_type_definition_c, 326 conf.compound_name, conf.compound_name, conf.compound_name); 327 } 328 329 fclose(compound_interface_fp); 330 } 331 332 if (compound_interface_type_fp != NULL) 333 { 334 /* Complete reference type. */ 335 336 if (conf.language != CPP_LANGUAGE) 337 fprintf(compound_interface_type_fp, compound_ref_type_definition_epilogue_c, 338 conf.compound_name); 339 340 fclose(compound_interface_type_fp); 341 } 342 343 if (compound_interfaces_fp != NULL) 344 fclose(compound_interfaces_fp); 345 } 346 347 348 349 /* Generate files containing interface details. */ 350 351 void write_files(struct interface *iface) 352 { 353 char *filename; 354 355 /* NOTE: Should exit with an error. */ 356 357 if (!set_output_location(iface)) 358 return; 359 360 /* Include server details for a compound interface dispatch function. */ 361 362 write_compound_dispatch_include(); 363 364 /* Open the separate files and write the details of each interface. */ 365 366 if (conf.headers) 367 { 368 if (conf.client) 369 { 370 client_header_fp = get_output_file(client_header_filename, output_dirname, output_basename); 371 if (client_header_fp == NULL) 372 goto finalisation; 373 } 374 375 if (conf.server) 376 { 377 server_header_fp = get_output_file(server_header_filename, output_dirname, output_basename); 378 if (server_header_fp == NULL) 379 goto finalisation; 380 } 381 } 382 383 if (conf.interfaces) 384 { 385 interface_fp = get_output_file(interface_filename, output_dirname, output_basename); 386 if (interface_fp == NULL) 387 goto finalisation; 388 } 389 390 if (conf.routines) 391 { 392 if (conf.client) 393 { 394 filename = (conf.language == CPP_LANGUAGE) ? client_filename_cpp : client_filename_c; 395 client_fp = get_output_file(filename, output_dirname, output_basename); 396 if (client_fp == NULL) 397 goto finalisation; 398 } 399 400 if (conf.server) 401 { 402 filename = (conf.language == CPP_LANGUAGE) ? server_filename_cpp : server_filename_c; 403 server_fp = get_output_file(filename, output_dirname, output_basename); 404 if (server_fp == NULL) 405 goto finalisation; 406 } 407 } 408 409 /* Emit prologues. */ 410 411 if (client_fp != NULL) 412 fprintf(client_fp, client_prologue, output_basename, output_basename); 413 414 if (client_header_fp != NULL) 415 fputs(header_prologue, client_header_fp); 416 417 if (server_fp != NULL) 418 fprintf(server_fp, server_prologue, output_basename, output_basename); 419 420 if (server_header_fp != NULL) 421 fputs(server_header_prologue, server_header_fp); 422 423 if (interface_fp != NULL) 424 fputs(header_prologue, interface_fp); 425 426 /* Write the interface details. */ 427 428 write_interfaces(iface); 429 430 finalisation: 431 432 /* Close the files. */ 433 434 if (client_fp != NULL) 435 fclose(client_fp); 436 437 if (client_header_fp != NULL) 438 fclose(client_header_fp); 439 440 if (server_fp != NULL) 441 fclose(server_fp); 442 443 if (server_header_fp != NULL) 444 fclose(server_header_fp); 445 446 if (interface_fp != NULL) 447 fclose(interface_fp); 448 449 /* Free the names. */ 450 451 if (conf.output_dir == NULL) 452 free(output_dirname); 453 454 free(output_basename); 455 } 456 457 /* Generate the source file corresponding to the interface. */ 458 459 void write_interfaces(struct interface *iface) 460 { 461 int input_items; 462 463 if (iface == NULL) 464 return; 465 466 /* The list is reversed. */ 467 468 write_interfaces(iface->tail); 469 470 /* Write this particular interface after all referenced ones. */ 471 472 if (conf.verbose) 473 show_interface(iface); 474 475 /* Record details of this interface in the compound output. */ 476 477 write_compound_output(iface); 478 479 /* Emit function definitions. */ 480 481 if (client_fp != NULL) 482 { 483 write_functions(iface->signatures, client_fp, iface, 484 write_client_function); 485 486 if (conf.language == C_LANGUAGE) 487 write_client_interface(iface, client_fp); 488 } 489 490 if (server_fp != NULL) 491 { 492 write_functions(iface->signatures, server_fp, iface, 493 write_server_function); 494 495 /* Emit handle and dispatch functions. */ 496 497 write_handler_signature(iface->name, DEFINITION_ROLE, server_fp); 498 fprintf(server_fp, handle_function, iface->name); 499 fputs(END_FUNCTION, server_fp); 500 501 write_dispatcher(iface->signatures, server_fp, iface); 502 } 503 504 /* Emit the headers. */ 505 506 if (client_header_fp != NULL) 507 { 508 /* Emit interface include to obtain the type employed by the client 509 interface. */ 510 511 write_include(output_basename, "_interface.h", client_header_fp); 512 513 write_interface_definition(iface, CLIENT_ROLE, client_header_fp); 514 } 515 516 if (server_header_fp != NULL) 517 { 518 /* Emit interface include to obtain the interface type. */ 519 520 write_include(output_basename, "_interface.h", server_header_fp); 521 522 /* Emit signatures. */ 523 524 write_signatures(iface->signatures, DECLARATION_ROLE, server_header_fp, 525 iface, write_server_signature); 526 527 /* Emit dispatch and handle function signatures. */ 528 529 write_dispatcher_signature(iface->name, DECLARATION_ROLE, server_header_fp); 530 write_handler_signature(iface->name, DECLARATION_ROLE, server_header_fp); 531 } 532 533 /* The server interface is used by client and server code. */ 534 535 if (interface_fp != NULL) 536 write_interface_definition(iface, SERVER_ROLE, interface_fp); 537 } 538 539 /* Generate functions corresponding to the signatures. */ 540 541 void write_functions(struct signature *sig, FILE *fp, struct interface *iface, 542 void (*write_function)(struct signature *, FILE *, struct interface *)) 543 { 544 if (sig == NULL) 545 return; 546 547 write_function(sig, fp, iface); 548 write_functions(sig->tail, fp, iface, write_function); 549 }