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