1 /* 2 * Code generation from interface descriptions. 3 * 4 * Copyright (C) 2019, 2020, 2022, 2023 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 "templates.h" 34 35 36 37 /* Client, server and common files. */ 38 39 FILE *client_fp = NULL, *client_header_fp = NULL, 40 *server_fp = NULL, *server_header_fp = NULL, 41 *interface_fp = NULL; 42 43 44 45 /* Generate functions corresponding to the signatures. */ 46 47 static void write_functions(struct signature *sig, FILE *fp, 48 struct interface *iface, 49 void (*write_function)(struct signature *, FILE *, struct interface *)) 50 { 51 if (sig == NULL) 52 return; 53 54 write_function(sig, fp, iface); 55 write_functions(sig->tail, fp, iface, write_function); 56 } 57 58 /* Write includes for base interfaces. */ 59 60 static void write_server_includes(struct interface *iface, FILE *fp) 61 { 62 struct interface_ref *base; 63 64 for (base = iface->bases; base != NULL; base = base->tail) 65 write_include(base->iface->output_basename, "_server.h", fp); 66 } 67 68 69 70 /* Generate files containing interface details. */ 71 72 void write_files(struct interface *iface) 73 { 74 char *filename; 75 76 if (conf.headers) 77 { 78 if (conf.client) 79 { 80 client_header_fp = get_output_file(client_header_filename, 81 iface->output_dirname, 82 iface->output_basename); 83 if (client_header_fp == NULL) 84 goto finalisation; 85 } 86 87 if (conf.server) 88 { 89 server_header_fp = get_output_file(server_header_filename, 90 iface->output_dirname, 91 iface->output_basename); 92 if (server_header_fp == NULL) 93 goto finalisation; 94 } 95 } 96 97 if (conf.interfaces) 98 { 99 interface_fp = get_output_file(interface_filename, iface->output_dirname, 100 iface->output_basename); 101 if (interface_fp == NULL) 102 goto finalisation; 103 } 104 105 if (conf.routines) 106 { 107 if (conf.client) 108 { 109 filename = (conf.language == CPP_LANGUAGE) ? client_filename_cpp 110 : client_filename_c; 111 client_fp = get_output_file(filename, iface->output_dirname, 112 iface->output_basename); 113 if (client_fp == NULL) 114 goto finalisation; 115 } 116 117 if (conf.server) 118 { 119 filename = (conf.language == CPP_LANGUAGE) ? server_filename_cpp 120 : server_filename_c; 121 server_fp = get_output_file(filename, iface->output_dirname, 122 iface->output_basename); 123 if (server_fp == NULL) 124 goto finalisation; 125 } 126 } 127 128 /* Emit prologues. */ 129 130 if (client_fp != NULL) 131 fprintf(client_fp, client_prologue, iface->output_basename, 132 iface->output_basename); 133 134 if (client_header_fp != NULL) 135 fprintf(client_header_fp, header_prologue, "CLIENT", iface->name, 136 "CLIENT", iface->name); 137 138 if (server_fp != NULL) 139 fprintf(server_fp, server_prologue, iface->output_basename, 140 iface->output_basename); 141 142 if (server_header_fp != NULL) 143 fprintf(server_header_fp, server_header_prologue, iface->name, iface->name); 144 145 if (interface_fp != NULL) 146 fprintf(interface_fp, header_prologue, "INTERFACE", iface->name, 147 "INTERFACE", iface->name); 148 149 /* Write the interface details. */ 150 151 write_interfaces(iface); 152 153 finalisation: 154 155 /* Close the files. */ 156 157 if (client_fp != NULL) 158 fclose(client_fp); 159 160 if (client_header_fp != NULL) 161 { 162 fprintf(client_header_fp, header_epilogue); 163 fclose(client_header_fp); 164 } 165 166 if (server_fp != NULL) 167 fclose(server_fp); 168 169 if (server_header_fp != NULL) 170 { 171 fprintf(server_header_fp, header_epilogue); 172 fclose(server_header_fp); 173 } 174 175 if (interface_fp != NULL) 176 { 177 fprintf(interface_fp, header_epilogue); 178 fclose(interface_fp); 179 } 180 } 181 182 /* Generate source file content corresponding to each interface in turn. */ 183 184 void write_interfaces(struct interface *iface) 185 { 186 if (iface == NULL) 187 return; 188 189 /* The list is reversed by recursing to subsequent interfaces and thus 190 processing them first. */ 191 192 write_interfaces(iface->tail); 193 194 /* Emit function definitions. */ 195 196 if (client_fp != NULL) 197 { 198 /* Do not write client definitions for compound interfaces. */ 199 200 if (!is_compound_interface(iface)) 201 { 202 write_functions(iface->signatures, client_fp, iface, 203 write_client_function); 204 205 if (conf.language == C_LANGUAGE) 206 write_client_interface(iface, client_fp); 207 } 208 } 209 210 if (server_fp != NULL) 211 { 212 /* Write the dispatcher and handler functions. */ 213 214 write_functions(iface->signatures, server_fp, iface, 215 write_server_function); 216 217 /* Emit handle and dispatch functions. */ 218 219 write_handler_signature(iface->name, DEFINITION_ROLE, server_fp); 220 fprintf(server_fp, handle_function, iface->name); 221 fputs(END_FUNCTION, server_fp); 222 223 write_dispatcher(server_fp, iface); 224 225 /* Emit default configuration instance definition. */ 226 227 fprintf(server_fp, server_config_instance, 228 iface->name, iface->name, iface->name); 229 } 230 231 /* Emit the headers. */ 232 233 if (client_header_fp != NULL) 234 { 235 /* Emit interface include to obtain the type employed by the client 236 interface, doing this once per file. */ 237 238 if (iface->tail == NULL) 239 write_include(iface->output_basename, "_interface.h", client_header_fp); 240 241 /* Do not write client definitions for compound interfaces. */ 242 243 if (!is_compound_interface(iface)) 244 write_interface_definition(iface, CLIENT_ROLE, client_header_fp); 245 } 246 247 if (server_header_fp != NULL) 248 { 249 /* Emit interface include to obtain the interface type, doing this once per 250 file. */ 251 252 if (iface->tail == NULL) 253 write_include(iface->output_basename, "_interface.h", server_header_fp); 254 255 /* Write any includes for base interfaces. */ 256 257 write_server_includes(iface, server_header_fp); 258 259 /* Emit signatures. */ 260 261 write_signatures(iface->signatures, DECLARATION_ROLE, server_header_fp, 262 iface, write_server_signature); 263 264 /* Emit dispatch and handle function signatures. */ 265 266 write_dispatcher_signature(iface->name, DECLARATION_ROLE, server_header_fp); 267 write_handler_signature(iface->name, DECLARATION_ROLE, server_header_fp); 268 269 /* Emit default configuration instance declaration. */ 270 271 fprintf(server_header_fp, server_config_instance_declaration, iface->name); 272 } 273 274 /* The server interface is used by client and server code. */ 275 276 if (interface_fp != NULL) 277 write_interface_definition(iface, SERVER_ROLE, interface_fp); 278 } 279 280 /* vim: tabstop=2 expandtab shiftwidth=2 281 */