1 /* 2 * Generation of server dispatch and handle functions. 3 * 4 * Copyright (C) 2019, 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 "common.h" 24 #include "dispatch.h" 25 #include "templates.h" 26 27 28 29 /* Generate each dispatch possibility within an interface. */ 30 31 static void write_dispatcher_cases(FILE *fp, struct interface *iface, 32 int compound) 33 { 34 struct signature *sig; 35 char *opcode, *opname, *protocol, *prefix, *ref, *s; 36 37 for (sig = iface->signatures; sig != NULL; sig = sig->tail) 38 { 39 opname = get_operation_name(iface, sig); 40 opcode = get_opcode_identifier(NULL, opname); 41 prefix = get_operation_wrapper_prefix(sig->attributes); 42 43 /* Convert to any base interface. */ 44 45 ref = get_object_conversion(iface, compound); 46 47 /* Generate a reply if appropriate. */ 48 49 if (have_attribute(sig->attributes, "completion")) 50 s = dispatch_function_wrapper_case; 51 else if (have_attribute(sig->attributes, "oneway")) 52 s = dispatch_function_oneway_wrapper_case; 53 else 54 s = dispatch_function_reply_wrapper_case; 55 56 /* Generate the case and invocation. */ 57 58 fprintf(fp, s, opcode, prefix, opname, ref); 59 60 /* Free allocated strings. */ 61 62 free(opcode); 63 free(opname); 64 free(ref); 65 } 66 } 67 68 /* Dispatch to each interface-level function where the same protocol applies to 69 an entire interface. Dispatch to each operation where an interface does not 70 specify a protocol. */ 71 72 static void write_dispatcher_interface_cases(FILE *fp, struct interface *iface, 73 int by_protocol) 74 { 75 struct interface_ref *base; 76 char *protocol, *ref; 77 78 for (base = iface->bases; base != NULL; base = base->tail) 79 { 80 protocol = get_protocol(base->iface->attributes); 81 82 /* Write cases for each interface, using the protocol to select between the 83 cases. */ 84 85 if (by_protocol) 86 { 87 if (protocol != NULL) 88 { 89 /* Convert to any base interface. */ 90 91 ref = get_object_conversion(base->iface, 1); 92 fprintf(fp, dispatch_function_interface_case, protocol, base->name, ref); 93 free(ref); 94 } 95 96 /* Look for any base interfaces employing protocols. */ 97 98 else 99 write_dispatcher_interface_cases(fp, base->iface, 1); 100 } 101 102 /* Write cases for each operation provided by the interface so that they can 103 be selected. Note that this requires distinct opcodes to be used, so in 104 practice requiring explicit opcodes to be indicated. */ 105 106 else if (protocol == NULL) 107 write_dispatcher_interface_cases(fp, base->iface, 1); 108 } 109 110 /* Dispatch to each operation defined at this level. */ 111 112 write_dispatcher_cases(fp, iface, is_compound_interface(iface)); 113 } 114 115 /* Return whether any base interface specifies a protocol. */ 116 117 static int have_interfaces_using_protocols(struct interface *iface) 118 { 119 struct interface_ref *base; 120 121 for (base = iface->bases; base != NULL; base = base->tail) 122 if (get_protocol(base->iface->attributes) != NULL) 123 return 1; 124 125 return 0; 126 } 127 128 129 130 /* Generate dispatch function signatures. */ 131 132 void write_dispatcher_signature(const char *name, enum signature_role role, 133 FILE *fp) 134 { 135 fprintf(fp, dispatch_function_signature, name, name); 136 fputs(get_signature_terminator(role), fp); 137 } 138 139 /* Generate handler function signatures. */ 140 141 void write_handler_signature(const char *name, enum signature_role role, 142 FILE *fp) 143 { 144 fprintf(fp, handle_function_signature, name, name); 145 fputs(get_signature_terminator(role), fp); 146 } 147 148 /* Generate a dispatch function for the different operations. */ 149 150 void write_dispatcher(FILE *fp, struct interface *iface) 151 { 152 char *protocol = get_protocol(iface->attributes); 153 154 write_dispatcher_signature(iface->name, DEFINITION_ROLE, fp); 155 156 /* Declare an error variable to support testing for already-sent messages. */ 157 158 fputs(dispatch_function_prologue, fp); 159 160 /* Without a protocol applying to the entire interface, dispatch using the 161 protocol from the message label. */ 162 163 if (protocol == NULL) 164 fputs(dispatch_function_label_dispatcher, fp); 165 166 /* If a protocol applies to the entire interface, test for this protocol and 167 dispatch using an operation indicator in the word data. */ 168 169 else 170 { 171 fprintf(fp, dispatch_function_test_protocol, protocol); 172 fputs(dispatch_function_word_dispatcher, fp); 173 } 174 175 /* Dispatch to operations and any base interfaces. */ 176 177 write_dispatcher_interface_cases(fp, iface, (protocol == NULL)); 178 179 /* Terminate the dispatcher. */ 180 181 fputs(dispatch_function_default_case, fp); 182 fputs(dispatch_function_dispatcher_epilogue, fp); 183 184 fputs(END_FUNCTION, fp); 185 }