1 /* 2 * Common routines. 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 <libgen.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include "common.h" 26 #include "templates.h" 27 28 29 30 /* Generate an error message for file opening failure. */ 31 32 void open_error(const char *dir, const char *name) 33 { 34 fprintf(stderr, "Could not open source file for writing in directory %s (name %s).\n", dir, name); 35 } 36 37 /* Obtain a new basename string. */ 38 39 char *make_basename(const char *path) 40 { 41 char s[strlen(path) + 1]; 42 43 strcpy(s, path); 44 return strdup(basename(s)); 45 } 46 47 /* Obtain a new directory name string. */ 48 49 char *make_dirname(const char *path) 50 { 51 char s[strlen(path) + 1]; 52 53 strcpy(s, path); 54 return strdup(dirname(s)); 55 } 56 57 /* Obtain a file pointer using a parameterised filename. */ 58 59 FILE *get_output_file(const char *filename_template, const char *dir, const char *name) 60 { 61 FILE *fp; 62 char *filename; 63 64 if (asprintf(&filename, filename_template, dir, name) == -1) 65 fp = NULL; 66 else 67 { 68 fp = fopen(filename, "w"); 69 free(filename); 70 } 71 72 /* Write an error message upon failure. */ 73 74 if (fp == NULL) 75 open_error(dir, name); 76 77 return fp; 78 } 79 80 /* Find an attribute value. */ 81 82 char *get_attribute_value(struct attribute *attr, const char *name) 83 { 84 if (attr == NULL) 85 return NULL; 86 87 if (!strcmp(attr->attribute, name) && (attr->identifiers != NULL)) 88 return attr->identifiers->identifier; 89 90 return get_attribute_value(attr->tail, name); 91 } 92 93 /* Return any opcode attribute value. */ 94 95 char *get_opcode(struct attribute *attr) 96 { 97 return get_attribute_value(attr, "opcode"); 98 } 99 100 /* Return any protocol attribute value. */ 101 102 char *get_protocol(struct attribute *attr) 103 { 104 return get_attribute_value(attr, "protocol"); 105 } 106 107 /* Generate a qualified operation name for declarations and definitions. */ 108 109 char *get_signature_operation_name(struct interface *iface, 110 struct signature *sig, 111 enum signature_role role, enum language lang) 112 { 113 char *opname; 114 115 switch (lang) 116 { 117 case C_LANGUAGE: 118 return get_operation_name(iface, sig); 119 120 case CPP_LANGUAGE: 121 if (role == DEFINITION_ROLE) 122 { 123 if (asprintf(&opname, "%s::%s", iface->name, sig->operation) == -1) 124 opname = NULL; 125 } 126 else 127 opname = strdup(sig->operation); 128 break; 129 130 default: 131 opname = NULL; 132 break; 133 } 134 135 return opname; 136 } 137 138 /* Generate a qualified operation name for structure naming and possibly opcode 139 naming. */ 140 141 char *get_operation_name(struct interface *iface, struct signature *sig) 142 { 143 char *opname; 144 145 if (asprintf(&opname, "%s_%s", iface->name, sig->operation) == -1) 146 opname = NULL; 147 148 return opname; 149 } 150 151 /* Return the invocation opcode given protocol and operation name details. */ 152 153 char *get_opcode_identifier(char *protocol, char *opname) 154 { 155 char *opcode; 156 157 if (protocol != NULL) 158 return protocol; 159 160 if (asprintf(&opcode, "opcode_%s", opname) == -1) 161 return NULL; 162 163 return opcode; 164 } 165 166 /* Return the parameter name, being the final identifier in a list. */ 167 168 char *get_parameter_name(struct identifier *ident) 169 { 170 if (ident->tail != NULL) 171 return get_parameter_name(ident->tail); 172 else 173 return ident->identifier; 174 } 175 176 /* Get the appropriate terminating text after a signature. */ 177 178 char *get_signature_terminator(enum signature_role role) 179 { 180 switch (role) 181 { 182 case DECLARATION_ROLE: return COMPLETE_SIGNATURE; 183 case DEFINITION_ROLE: return BEGIN_FUNCTION; 184 case DEFINITION_START_ROLE: return END_SIGNATURE; 185 default: return ""; 186 } 187 } 188 189 /* Count the different kinds of parameters in terms of inputs, outputs, words 190 and items. */ 191 192 void count_parameters(struct parameter *param, int *input_words, 193 int *input_items, int *output_words, int *output_items) 194 { 195 for (*input_words = 0, *input_items = 0, *output_words = 0, *output_items = 0; 196 param != NULL; 197 param = param->tail) 198 { 199 if (param->specifier & IN_PARAMETER) 200 { 201 if (param->cls & ITEM_CLASS) (*input_items)++; 202 else (*input_words)++; 203 } 204 else 205 { 206 if (param->cls & ITEM_CLASS) (*output_items)++; 207 else (*output_words)++; 208 } 209 } 210 } 211 212 /* Return the maximum number of input items accepted by any one of the given 213 signatures. */ 214 215 int get_max_input_items(struct signature *sig) 216 { 217 int input_words, input_items, output_words, output_items; 218 int max_input_items = 0; 219 220 for (; sig != NULL; sig = sig->tail) 221 { 222 count_parameters(sig->parameters, &input_words, &input_items, &output_words, &output_items); 223 224 if (input_items > max_input_items) 225 max_input_items = input_items; 226 } 227 228 return max_input_items; 229 } 230 231 /* Return any operator needed to access the given parameter as a local name. */ 232 233 char *access_name(struct parameter *param, enum component_role component) 234 { 235 /* In the client, employ the dereferencing operator for "inout" and "out" 236 word parameters since the parameters will employ pointer types. */ 237 238 if ((component == CLIENT_ROLE) && (param->specifier & OUT_PARAMETER) && 239 (param->cls & WORD_CLASS)) 240 return "*"; 241 242 /* In the server, when importing items from the message, the address of the 243 variable to hold the capability value must be used. */ 244 245 if ((component == SERVER_ROLE) && (param->specifier & IN_PARAMETER) && 246 (param->cls & ITEM_CLASS)) 247 return "&"; 248 249 return ""; 250 } 251 252 /* Return the item type name for the given parameter. */ 253 254 char *item_type_name(struct parameter *param) 255 { 256 return param->cls == FPAGE_ITEM ? "fpage" : "capability"; 257 } 258 259 /* When copying output items from the message (in the client), the message 260 address must be obtained using the appropriate operator. */ 261 262 char *reference_message(enum component_role component) 263 { 264 return (component == CLIENT_ROLE) ? "&" : ""; 265 } 266 267 /* Return the naming prefix for structure access to a message. */ 268 269 char *structure_prefix(enum specifier direction) 270 { 271 return direction == IN_PARAMETER ? "in" : "out"; 272 } 273 274 /* Return whether message access for the given component role and specifier (or 275 direction) involves writing to (or populating) the message. */ 276 277 int writing_to_message(enum component_role component, enum specifier direction) 278 { 279 return (component == CLIENT_ROLE) && (direction & IN_PARAMETER) || 280 (component == SERVER_ROLE) && (direction & OUT_PARAMETER); 281 }