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