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_types_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_interfaces_fp = get_output_file(compound_interfaces_filename, 142 compound_dirname, conf.compound); 143 if (compound_interfaces_fp == NULL) 144 return 0; 145 146 compound_interface_types_fp = get_output_file(compound_interface_types_filename, 147 compound_dirname, conf.compound); 148 if (compound_interface_types_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_interfaces_fp != NULL) 201 fputs(compound_interfaces_prologue, compound_interfaces_fp); 202 203 if (compound_interface_types_fp != NULL) 204 { 205 fputs(compound_interface_types_prologue, compound_interface_types_fp); 206 207 /* Include reference types. */ 208 209 fprintf(compound_interface_types_fp, ref_type_definition_prologue_c); 210 fprintf(compound_interface_types_fp, ref_type_definition_epilogue_c, L4_CAP_TYPE, 211 conf.compound_name); 212 } 213 214 return 1; 215 } 216 217 void write_compound_output(struct interface *iface) 218 { 219 char *protocol, *ref; 220 int input_items; 221 222 if (compound_dispatch_fp != NULL) 223 { 224 protocol = get_protocol(iface->attributes); 225 226 /* Populate a function dispatching to each interface-level function where 227 the same protocol applies to an entire interface. */ 228 229 if (protocol != NULL) 230 { 231 ref = get_object_conversion(iface, 1); 232 233 fprintf(compound_dispatch_fp, dispatch_function_interface_case, 234 protocol, iface->name, ref); 235 236 free(ref); 237 } 238 239 /* Or dispatch to each operation defined at this level. */ 240 241 else 242 write_dispatcher_cases(iface->signatures, compound_dispatch_fp, iface, 1); 243 } 244 245 if (compound_dispatch_header_fp != NULL) 246 { 247 /* Compute the maximum number of items expected by each interface. */ 248 249 input_items = get_max_input_items(iface->signatures); 250 251 if (input_items > max_input_items) 252 max_input_items = input_items; 253 } 254 255 /* Add this interface to the compound interface. */ 256 257 if (compound_interface_fp != NULL) 258 write_compound_interface(iface); 259 260 /* Add this interface's header to the compound interface includes. */ 261 262 if (compound_interfaces_fp != NULL) 263 write_include(output_basename, "_interface.h", compound_interfaces_fp); 264 265 processed_interfaces++; 266 } 267 268 /* Generate includes for the server and common declarations from each input 269 file. */ 270 271 void write_compound_dispatch_include(void) 272 { 273 if (compound_dispatch_header_fp != NULL) 274 write_include(output_basename, "_server.h", compound_dispatch_header_fp); 275 } 276 277 /* Augment a compound interface class declaration. */ 278 279 void write_compound_interface(struct interface *iface) 280 { 281 char *sep; 282 283 if (conf.language == CPP_LANGUAGE) 284 { 285 sep = processed_interfaces ? ", " : " "; 286 fprintf(compound_interface_fp, "%spublic %s", sep, iface->name); 287 } 288 else 289 fprintf(compound_interface_fp, " iface_%s *to_%s;\n", iface->name, iface->name); 290 } 291 292 void end_compound_output(void) 293 { 294 /* Close the files. */ 295 296 if (compound_dispatch_fp != NULL) 297 { 298 fputs(compound_dispatch_epilogue, compound_dispatch_fp); 299 fputs(END_FUNCTION, compound_dispatch_fp); 300 fclose(compound_dispatch_fp); 301 } 302 303 if (compound_dispatch_header_fp != NULL) 304 { 305 fprintf(compound_dispatch_header_fp, expected_items_definition, 306 conf.compound_name, max_input_items); 307 fclose(compound_dispatch_header_fp); 308 } 309 310 if (compound_interface_fp != NULL) 311 { 312 if (conf.language == CPP_LANGUAGE) 313 fputs(compound_interface_epilogue_cpp, compound_interface_fp); 314 else 315 { 316 fprintf(compound_interface_fp, compound_interface_epilogue_c, 317 conf.compound_name); 318 319 /* Include object types. */ 320 321 fprintf(compound_interface_fp, object_type_definition_c, 322 conf.compound_name, conf.compound_name, conf.compound_name); 323 } 324 325 fclose(compound_interface_fp); 326 } 327 328 if (compound_interfaces_fp != NULL) 329 fclose(compound_interfaces_fp); 330 331 if (compound_interface_types_fp != NULL) 332 fclose(compound_interface_types_fp); 333 } 334 335 336 337 /* Generate files containing interface details. */ 338 339 void write_files(struct interface *iface) 340 { 341 char *filename; 342 343 /* NOTE: Should exit with an error. */ 344 345 if (!set_output_location(iface)) 346 return; 347 348 /* Include server details for a compound interface dispatch function. */ 349 350 write_compound_dispatch_include(); 351 352 /* Open the separate files and write the details of each interface. */ 353 354 if (conf.headers) 355 { 356 if (conf.client) 357 { 358 client_header_fp = get_output_file(client_header_filename, output_dirname, output_basename); 359 if (client_header_fp == NULL) 360 goto finalisation; 361 } 362 363 if (conf.server) 364 { 365 server_header_fp = get_output_file(server_header_filename, output_dirname, output_basename); 366 if (server_header_fp == NULL) 367 goto finalisation; 368 } 369 } 370 371 if (conf.interfaces) 372 { 373 interface_fp = get_output_file(interface_filename, output_dirname, output_basename); 374 if (interface_fp == NULL) 375 goto finalisation; 376 } 377 378 if (conf.routines) 379 { 380 if (conf.client) 381 { 382 filename = (conf.language == CPP_LANGUAGE) ? client_filename_cpp : client_filename_c; 383 client_fp = get_output_file(filename, output_dirname, output_basename); 384 if (client_fp == NULL) 385 goto finalisation; 386 } 387 388 if (conf.server) 389 { 390 filename = (conf.language == CPP_LANGUAGE) ? server_filename_cpp : server_filename_c; 391 server_fp = get_output_file(filename, output_dirname, output_basename); 392 if (server_fp == NULL) 393 goto finalisation; 394 } 395 } 396 397 /* Emit prologues. */ 398 399 if (client_fp != NULL) 400 fprintf(client_fp, client_prologue, output_basename, output_basename); 401 402 if (client_header_fp != NULL) 403 fputs(header_prologue, client_header_fp); 404 405 if (server_fp != NULL) 406 fprintf(server_fp, server_prologue, output_basename, output_basename); 407 408 if (server_header_fp != NULL) 409 fputs(server_header_prologue, server_header_fp); 410 411 if (interface_fp != NULL) 412 fputs(header_prologue, interface_fp); 413 414 /* Write the interface details. */ 415 416 write_interfaces(iface); 417 418 finalisation: 419 420 /* Close the files. */ 421 422 if (client_fp != NULL) 423 fclose(client_fp); 424 425 if (client_header_fp != NULL) 426 fclose(client_header_fp); 427 428 if (server_fp != NULL) 429 fclose(server_fp); 430 431 if (server_header_fp != NULL) 432 fclose(server_header_fp); 433 434 if (interface_fp != NULL) 435 fclose(interface_fp); 436 437 /* Free the names. */ 438 439 if (conf.output_dir == NULL) 440 free(output_dirname); 441 442 free(output_basename); 443 } 444 445 /* Generate the source file corresponding to the interface. */ 446 447 void write_interfaces(struct interface *iface) 448 { 449 int input_items; 450 451 if (iface == NULL) 452 return; 453 454 /* The list is reversed. */ 455 456 write_interfaces(iface->tail); 457 458 /* Write this particular interface after all referenced ones. */ 459 460 if (conf.verbose) 461 show_interface(iface); 462 463 /* Record details of this interface in the compound output. */ 464 465 write_compound_output(iface); 466 467 /* Emit function definitions. */ 468 469 if (client_fp != NULL) 470 { 471 write_functions(iface->signatures, client_fp, iface, 472 write_client_function); 473 474 if (conf.language == C_LANGUAGE) 475 write_client_interface(iface, client_fp); 476 } 477 478 if (server_fp != NULL) 479 { 480 write_functions(iface->signatures, server_fp, iface, 481 write_server_function); 482 483 /* Emit handle and dispatch functions. */ 484 485 write_handler_signature(iface->name, DEFINITION_ROLE, server_fp); 486 fprintf(server_fp, handle_function, iface->name); 487 fputs(END_FUNCTION, server_fp); 488 489 write_dispatcher(iface->signatures, server_fp, iface); 490 } 491 492 /* Emit the headers. */ 493 494 if (client_header_fp != NULL) 495 { 496 /* Emit interface include to obtain the type employed by the client 497 interface. */ 498 499 write_include(output_basename, "_interface.h", client_header_fp); 500 501 write_interface_definition(iface, CLIENT_ROLE, client_header_fp); 502 } 503 504 if (server_header_fp != NULL) 505 { 506 /* Emit interface include to obtain the interface type. */ 507 508 write_include(output_basename, "_interface.h", server_header_fp); 509 510 /* Emit signatures. */ 511 512 write_signatures(iface->signatures, DECLARATION_ROLE, server_header_fp, 513 iface, write_server_signature); 514 515 /* Emit dispatch and handle function signatures. */ 516 517 write_dispatcher_signature(iface->name, DECLARATION_ROLE, server_header_fp); 518 write_handler_signature(iface->name, DECLARATION_ROLE, server_header_fp); 519 } 520 521 /* The server interface is used by client and server code. */ 522 523 if (interface_fp != NULL) 524 write_interface_definition(iface, SERVER_ROLE, interface_fp); 525 } 526 527 /* Generate functions corresponding to the signatures. */ 528 529 void write_functions(struct signature *sig, FILE *fp, struct interface *iface, 530 void (*write_function)(struct signature *, FILE *, struct interface *)) 531 { 532 if (sig == NULL) 533 return; 534 535 write_function(sig, fp, iface); 536 write_functions(sig->tail, fp, iface, write_function); 537 }