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