1 /* 2 * Client code generation. 3 * 4 * Copyright (C) 2019, 2020, 2021 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 /* Generate expected output item requirements. */ 93 94 if (output_items) 95 fprintf(fp, " err = ipc_message_expect(&msg, %d);\n" 96 " if (err)\n" 97 " return err;\n", output_items); 98 99 /* Populate input parameters in the message. Dereference function parameters 100 acting as "inout" parameters. */ 101 102 if (input_words) 103 { 104 /* Reserve space for the words before any items, obtaining a pointer to the 105 words. */ 106 107 write_accessor_initialisation(IN_PARAMETER, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, 108 opname, fp); 109 110 if (protocol != NULL) 111 fprintf(fp, " in_words->_op = opcode_%s;\n", opname); 112 113 write_message_access(param, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER, 114 WORD_CLASS, fp); 115 } 116 117 /* Do the same for items. */ 118 119 if (input_items) 120 { 121 fputs("\n", fp); 122 write_message_access(param, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER, 123 ITEM_CLASS, fp); 124 } 125 126 /* Send the request. */ 127 128 fprintf(fp, client_function_body_call, opcode, "_endp"); 129 130 /* Retrieve output parameters from the message. */ 131 132 if (output_words) 133 { 134 write_accessor_initialisation(OUT_PARAMETER, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, 135 opname, fp); 136 write_message_access(param, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, OUT_PARAMETER, 137 WORD_CLASS, fp); 138 } 139 140 /* Do the same for items. */ 141 142 if (output_items) 143 { 144 fputs("\n", fp); 145 write_message_access(param, CLIENT_ROLE, GENERAL_FUNCTION_ROLE, OUT_PARAMETER, 146 ITEM_CLASS, fp); 147 } 148 149 /* Generate the epilogue. */ 150 151 fputs(client_function_body_epilogue, fp); 152 153 /* Free allocated strings. */ 154 155 free(opname); 156 157 if (protocol == NULL) 158 free(opcode); 159 } 160 161 /* Populate an interface structure with client functions. */ 162 163 void write_client_interface(struct interface *iface, FILE *fp) 164 { 165 struct signature *sig; 166 char *opname; 167 168 if (iface->signatures == NULL) 169 fprintf(fp, client_interface_prologue_empty_c, iface->name, iface->name); 170 else 171 { 172 fprintf(fp, client_interface_prologue_c, iface->name, iface->name); 173 174 for (sig = iface->signatures; sig != NULL; sig = sig->tail) 175 { 176 opname = get_operation_name(iface, sig); 177 178 fprintf(fp, client_interface_member_c, sig->operation, opname); 179 180 free(opname); 181 } 182 183 fputs(client_interface_epilogue_c, fp); 184 } 185 }