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