1 /* 2 * Client code generation. 3 * 4 * Copyright (C) 2019-2024 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 "config.h" 25 #include "common.h" 26 #include "declaration.h" 27 #include "message.h" 28 #include "templates.h" 29 30 31 32 /* Generate operation signature details for client use. */ 33 34 void write_client_signature(struct signature *sig, enum signature_role role, 35 FILE *fp, struct interface *iface) 36 { 37 /* Client interface signatures are oblivious to completions. */ 38 39 write_interface_signature(sig, role, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, fp, 40 iface); 41 } 42 43 /* Generate function source code for each operation signature. */ 44 45 void write_client_function(struct signature *sig, FILE *fp, struct interface *iface) 46 { 47 write_client_signature(sig, DEFINITION_ROLE, fp, iface); 48 write_client_function_body(sig->parameters, fp, iface, sig); 49 fputs(END_FUNCTION, fp); 50 } 51 52 /* Generate a function body corresponding to an operation for client use. */ 53 54 void write_client_function_body(struct parameter *param, FILE *fp, 55 struct interface *iface, struct signature *sig) 56 { 57 int input_words, input_items, output_words, output_items; 58 59 /* With a protocol attribute, the opcode is the attribute value. Otherwise, 60 it is the operation code. */ 61 62 char *opname = get_operation_name(iface, sig), 63 *protocol = get_protocol(iface->attributes), 64 *opcode = get_opcode_identifier(protocol, opname); 65 66 /* Generate the prologue. */ 67 68 fputs(client_function_body_prologue, fp); 69 70 /* Obtain a suitable endpoint reference. */ 71 72 if (conf.language == C_LANGUAGE) 73 fprintf(fp, client_function_body_endpoint_conversion_c, L4_CAP_TYPE); 74 75 /* Count the number of input words, items and output words. */ 76 77 count_parameters(param, &input_words, &input_items, &output_words, &output_items); 78 79 /* Adjust the input words where a protocol is used as the opcode. */ 80 81 if (protocol != NULL) 82 input_words++; 83 84 /* Generate types parameterised with the qualified operation name. */ 85 86 write_accessor_declaration(input_words, output_words, opname, fp); 87 88 /* Initialise the message. */ 89 90 fprintf(fp, "\n ipc_message_new(&msg);\n"); 91 92 /* Populate input parameters in the message. Dereference function parameters 93 acting as "inout" parameters. */ 94 95 if (input_words) 96 { 97 /* Reserve space for the words before any items, obtaining a pointer to the 98 words. */ 99 100 write_accessor_initialisation(IN_PARAMETER, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, 101 opname, fp); 102 103 if (protocol != NULL) 104 fprintf(fp, " in_words->_op = opcode_%s;\n", opname); 105 106 write_message_access(param, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER, 107 WORD_CLASS, fp); 108 } 109 110 /* Do the same for items, also preparing to receive output items. */ 111 112 if (input_items | output_items) 113 { 114 fputs("\n", fp); 115 write_message_access(param, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER, 116 ITEM_CLASS, fp); 117 } 118 119 /* Send the request. */ 120 121 fprintf(fp, have_attribute(sig->attributes, "oneway") ? 122 client_function_body_call_oneway : client_function_body_call, 123 opcode, "_endp"); 124 125 /* Retrieve output parameters from the message. */ 126 127 if (output_words) 128 { 129 write_accessor_initialisation(OUT_PARAMETER, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, 130 opname, fp); 131 write_message_access(param, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, OUT_PARAMETER, 132 WORD_CLASS, fp); 133 } 134 135 /* Do the same for items. */ 136 137 if (output_items) 138 { 139 fputs("\n", fp); 140 write_message_access(param, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, OUT_PARAMETER, 141 ITEM_CLASS, fp); 142 } 143 144 /* Generate the epilogue. */ 145 146 fputs(client_function_body_epilogue, fp); 147 148 /* Free allocated strings. */ 149 150 free(opname); 151 152 if (protocol == NULL) 153 free(opcode); 154 } 155 156 /* Populate an interface structure with client functions. */ 157 158 void write_client_interface(struct interface *iface, FILE *fp) 159 { 160 struct signature *sig; 161 char *opname; 162 163 if (iface->signatures == NULL) 164 fprintf(fp, client_interface_prologue_empty_c, iface->name, iface->name); 165 else 166 { 167 fprintf(fp, client_interface_prologue_c, iface->name, iface->name); 168 169 for (sig = iface->signatures; sig != NULL; sig = sig->tail) 170 { 171 opname = get_operation_name(iface, sig); 172 173 fprintf(fp, client_interface_member_c, sig->operation, opname); 174 175 free(opname); 176 } 177 178 fputs(client_interface_epilogue_c, fp); 179 } 180 }