1 /* 2 * Code generation from interface descriptions. 3 * 4 * Copyright (C) 2019, 2020, 2022 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 fputs(header_prologue, client_header_fp); 136 137 if (server_fp != NULL) 138 fprintf(server_fp, server_prologue, iface->output_basename, 139 iface->output_basename); 140 141 if (server_header_fp != NULL) 142 fputs(server_header_prologue, server_header_fp); 143 144 if (interface_fp != NULL) 145 fputs(header_prologue, interface_fp); 146 147 /* Write the interface details. */ 148 149 write_interfaces(iface); 150 151 finalisation: 152 153 /* Close the files. */ 154 155 if (client_fp != NULL) 156 fclose(client_fp); 157 158 if (client_header_fp != NULL) 159 fclose(client_header_fp); 160 161 if (server_fp != NULL) 162 fclose(server_fp); 163 164 if (server_header_fp != NULL) 165 fclose(server_header_fp); 166 167 if (interface_fp != NULL) 168 fclose(interface_fp); 169 } 170 171 /* Generate source file content corresponding to each interface in turn. */ 172 173 void write_interfaces(struct interface *iface) 174 { 175 if (iface == NULL) 176 return; 177 178 /* The list is reversed by recursing to subsequent interfaces and thus 179 processing them first. */ 180 181 write_interfaces(iface->tail); 182 183 /* Emit function definitions. */ 184 185 if (client_fp != NULL) 186 { 187 /* Do not write client definitions for compound interfaces. */ 188 189 if (!is_compound_interface(iface)) 190 { 191 write_functions(iface->signatures, client_fp, iface, 192 write_client_function); 193 194 if (conf.language == C_LANGUAGE) 195 write_client_interface(iface, client_fp); 196 } 197 } 198 199 if (server_fp != NULL) 200 { 201 /* Write the dispatcher and handler functions. */ 202 203 write_functions(iface->signatures, server_fp, iface, 204 write_server_function); 205 206 /* Emit handle and dispatch functions. */ 207 208 write_handler_signature(iface->name, DEFINITION_ROLE, server_fp); 209 fprintf(server_fp, handle_function, iface->name); 210 fputs(END_FUNCTION, server_fp); 211 212 write_dispatcher(server_fp, iface); 213 214 /* Emit default configuration instance definition. */ 215 216 fprintf(server_fp, server_config_instance, 217 iface->name, iface->name, iface->name); 218 } 219 220 /* Emit the headers. */ 221 222 if (client_header_fp != NULL) 223 { 224 /* Emit interface include to obtain the type employed by the client 225 interface, doing this once per file. */ 226 227 if (iface->tail == NULL) 228 write_include(iface->output_basename, "_interface.h", client_header_fp); 229 230 /* Do not write client definitions for compound interfaces. */ 231 232 if (!is_compound_interface(iface)) 233 write_interface_definition(iface, CLIENT_ROLE, client_header_fp); 234 } 235 236 if (server_header_fp != NULL) 237 { 238 /* Emit interface include to obtain the interface type, doing this once per 239 file. */ 240 241 if (iface->tail == NULL) 242 write_include(iface->output_basename, "_interface.h", server_header_fp); 243 244 /* Write any includes for base interfaces. */ 245 246 write_server_includes(iface, server_header_fp); 247 248 /* Emit signatures. */ 249 250 write_signatures(iface->signatures, DECLARATION_ROLE, server_header_fp, 251 iface, write_server_signature); 252 253 /* Emit dispatch and handle function signatures. */ 254 255 write_dispatcher_signature(iface->name, DECLARATION_ROLE, server_header_fp); 256 write_handler_signature(iface->name, DECLARATION_ROLE, server_header_fp); 257 258 /* Emit default configuration instance declaration. */ 259 260 fprintf(server_header_fp, server_config_instance_declaration, iface->name); 261 } 262 263 /* The server interface is used by client and server code. */ 264 265 if (interface_fp != NULL) 266 write_interface_definition(iface, SERVER_ROLE, interface_fp); 267 }