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