1 /* 2 * Common routines. 3 * 4 * Copyright (C) 2019, 2020, 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 <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 conversion to a different object type in a dispatcher. */ 94 95 char *get_object_conversion(struct interface *iface, int compound) 96 { 97 char *conversion; 98 99 if (!compound) 100 return strdup("_self"); 101 102 if (asprintf(&conversion, "convert_to_%s(_self)", iface->name) == -1) 103 conversion = NULL; 104 105 return conversion; 106 } 107 108 /* Return any opcode attribute value. */ 109 110 char *get_opcode(struct attribute *attr) 111 { 112 return get_attribute_value(attr, "opcode"); 113 } 114 115 /* Return any opcode type attribute value. */ 116 117 char *get_opcode_type(struct attribute *attr) 118 { 119 return get_attribute_value(attr, "opcode_type"); 120 } 121 122 /* Return any protocol attribute value. */ 123 124 char *get_protocol(struct attribute *attr) 125 { 126 return get_attribute_value(attr, "protocol"); 127 } 128 129 /* Return the wrapper function prefix. */ 130 131 char *get_operation_wrapper_prefix(struct attribute *attr) 132 { 133 if (have_attribute(attr, "completion")) 134 return "initiate"; 135 else 136 return "wrap"; 137 } 138 139 int have_attribute(struct attribute *attr, const char *name) 140 { 141 if (attr == NULL) 142 return 0; 143 144 if (!strcmp(attr->attribute, name)) 145 return 1; 146 147 return have_attribute(attr->tail, name); 148 } 149 150 int have_attribute_value(struct attribute *attr, const char *name, 151 const char *value) 152 { 153 if (attr == NULL) 154 return 0; 155 156 if (!strcmp(attr->attribute, name) && have_identifier(attr->identifiers, value)) 157 return 1; 158 159 return have_attribute_value(attr->tail, name, value); 160 } 161 162 int have_identifier(struct identifier *ident, const char *value) 163 { 164 if (ident == NULL) 165 return 0; 166 167 if (!strcmp(ident->identifier, value)) 168 return 1; 169 170 return have_identifier(ident->tail, value); 171 } 172 173 /* Return the function role of the given signature for server use. */ 174 175 enum function_role get_server_function_role(struct signature *sig) 176 { 177 return have_attribute(sig->attributes, "completion") ? COMPLETION_ROLE 178 : GENERAL_FUNCTION_ROLE; 179 } 180 181 /* Obtain a suitable interface class name depending on the component role. */ 182 183 char *get_interface_class_name(struct interface *iface, 184 enum component_role component) 185 { 186 char *name; 187 188 switch (component) 189 { 190 case CLIENT_ROLE: 191 if (asprintf(&name, "client_%s", iface->name) == -1) 192 name = NULL; 193 break; 194 195 case SERVER_ROLE: 196 name = strdup(iface->name); 197 break; 198 199 default: 200 name = NULL; 201 break; 202 } 203 204 return name; 205 } 206 207 /* Generate a qualified operation name for declarations and definitions. */ 208 209 char *get_signature_operation_name(struct interface *iface, 210 struct signature *sig, 211 enum component_role component, 212 enum signature_role role, enum language lang) 213 { 214 char *opname, *class_name; 215 216 switch (lang) 217 { 218 /* In C, interface members use the bare names. */ 219 220 case C_LANGUAGE: 221 if ((role == MEMBER_DECLARATION_ROLE) || (role == ACCESS_ROLE)) 222 opname = strdup(sig->operation); 223 else 224 opname = get_operation_name(iface, sig); 225 break; 226 227 /* In C++, method definitions are qualified using class names. */ 228 229 case CPP_LANGUAGE: 230 if (role == DEFINITION_ROLE) 231 { 232 class_name = get_interface_class_name(iface, component); 233 234 if (asprintf(&opname, "%s::%s", class_name, sig->operation) == -1) 235 opname = NULL; 236 237 free(class_name); 238 } 239 else 240 opname = strdup(sig->operation); 241 break; 242 243 default: 244 opname = NULL; 245 break; 246 } 247 248 return opname; 249 } 250 251 /* Generate a qualified operation name for structure and function naming. */ 252 253 char *get_operation_name(struct interface *iface, struct signature *sig) 254 { 255 char *opname; 256 257 if (asprintf(&opname, "%s_%s", iface->name, sig->operation) == -1) 258 opname = NULL; 259 260 return opname; 261 } 262 263 /* Return the invocation opcode given protocol and operation name details. */ 264 265 char *get_opcode_identifier(char *protocol, char *opname) 266 { 267 char *opcode; 268 269 if (protocol != NULL) 270 return protocol; 271 272 if (asprintf(&opcode, "opcode_%s", opname) == -1) 273 return NULL; 274 275 return opcode; 276 } 277 278 /* Return the appropriate parameter decoration. Generally, output parameters 279 involve addresses. However, completion functions accept output parameters as 280 values. */ 281 282 const char *get_parameter_decoration(struct parameter *param, 283 enum parameter_role role, 284 enum function_role function) 285 { 286 if ((param->specifier & OUT_PARAMETER) && (function != COMPLETION_ROLE)) 287 { 288 switch (role) 289 { 290 case SIGNATURE_ROLE: return "*"; 291 case INVOCATION_ROLE: return "&"; 292 default: break; 293 } 294 } 295 296 return ""; 297 } 298 299 /* Return the parameter name, being the final identifier in a list. */ 300 301 char *get_parameter_name(struct identifier *ident) 302 { 303 if (ident->tail != NULL) 304 return get_parameter_name(ident->tail); 305 else 306 return ident->identifier; 307 } 308 309 /* Get the appropriate terminating text after a signature. */ 310 311 char *get_signature_terminator(enum signature_role role) 312 { 313 /* Signatures in declarations or member initialisation. */ 314 315 if (role & DECLARATION_ROLE) 316 return COMPLETE_SIGNATURE; 317 318 /* Signatures at the start of functions. */ 319 320 if (role & DEFINITION_ROLE) 321 return BEGIN_FUNCTION; 322 323 return ""; 324 } 325 326 /* Count the different kinds of parameters in terms of inputs, outputs, words 327 and items. */ 328 329 void count_parameters(struct parameter *param, int *input_words, 330 int *input_items, int *output_words, int *output_items) 331 { 332 for (*input_words = 0, *input_items = 0, *output_words = 0, *output_items = 0; 333 param != NULL; 334 param = param->tail) 335 { 336 /* Special case: "out fpage". */ 337 338 if ((param->specifier & IN_PARAMETER) || (param->cls == FPAGE_ITEM)) 339 { 340 if (param->cls & ITEM_CLASS) (*input_items)++; 341 else (*input_words)++; 342 } 343 344 if (param->specifier & OUT_PARAMETER) 345 { 346 if (param->cls & ITEM_CLASS) (*output_items)++; 347 else (*output_words)++; 348 } 349 } 350 } 351 352 /* Return the maximum number of input items accepted by any one of the given 353 signatures. */ 354 355 int get_max_input_items(struct signature *sig) 356 { 357 int input_words, input_items, output_words, output_items; 358 int max_input_items = 0; 359 360 for (; sig != NULL; sig = sig->tail) 361 { 362 count_parameters(sig->parameters, &input_words, &input_items, &output_words, &output_items); 363 364 if (input_items > max_input_items) 365 max_input_items = input_items; 366 } 367 368 return max_input_items; 369 } 370 371 /* Return any operator needed to access the given parameter as a local name. */ 372 373 char *access_name(struct parameter *param, enum component_role component, 374 int writing) 375 { 376 /* In the client, employ the dereferencing operator for "inout" and "out" 377 word parameters since the parameters will employ pointer types. */ 378 379 if ((component == CLIENT_ROLE) && (param->specifier & OUT_PARAMETER) && 380 (param->cls & WORD_CLASS)) 381 return "*"; 382 383 /* In the client, employ the dereferencing operator for written "inout" 384 item parameters since the parameters will employ pointer types. */ 385 386 if ((component == CLIENT_ROLE) && (param->specifier & OUT_PARAMETER) && 387 (param->cls & ITEM_CLASS) && writing) 388 return "*"; 389 390 /* In the server, when importing items from the message, the address of the 391 variable to hold the item must be used. */ 392 393 if ((component == SERVER_ROLE) && (param->specifier & IN_PARAMETER) && 394 (param->cls & ITEM_CLASS) && !writing) 395 return "&"; 396 397 return ""; 398 } 399 400 /* Return the item type name for the given parameter. */ 401 402 char *item_type_name(struct parameter *param, enum component_role component, 403 int writing) 404 { 405 if (param->cls == FPAGE_ITEM) 406 { 407 /* Permit the specification of receive window flexpage items. */ 408 409 if (specify_receive_fpage(param, component, writing)) 410 return "receive_fpage"; 411 else 412 return "fpage"; 413 } 414 else 415 return "capability"; 416 } 417 418 /* Return whether the parameter involves a receive window flexpage. */ 419 420 int specify_receive_fpage(struct parameter *param, 421 enum component_role component, int writing) 422 { 423 return (param->cls == FPAGE_ITEM) && 424 (component == CLIENT_ROLE) && 425 !(param->specifier & IN_PARAMETER) && 426 (param->specifier & OUT_PARAMETER) && 427 writing; 428 } 429 430 /* When copying output items from the message (in the client) or copying into 431 the message (in the server, but only with a new message), the message address 432 must be obtained using the appropriate operator. */ 433 434 char *reference_message(enum component_role component, 435 enum function_role function) 436 { 437 return (component == CLIENT_ROLE) || (function == COMPLETION_ROLE) ? "&" : ""; 438 } 439 440 /* Return the naming prefix for structure access to a message. */ 441 442 char *structure_prefix(enum specifier direction) 443 { 444 return direction == IN_PARAMETER ? "in" : "out"; 445 } 446 447 /* Return whether message access for the given component role and specifier (or 448 direction) involves writing to (or populating) the message. */ 449 450 int writing_to_message(enum component_role component, enum specifier direction) 451 { 452 return (component == CLIENT_ROLE) && (direction & IN_PARAMETER) || 453 (component == SERVER_ROLE) && (direction & OUT_PARAMETER); 454 }