1 /* 2 * Main program. 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 <getopt.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <strings.h> 27 #include "common.h" 28 #include "program.h" 29 30 /* Parser functions and settings. */ 31 32 extern void yyparse(void); 33 extern void yyrestart(FILE *); 34 extern int yydebug; 35 36 /* Specialised parser functions. */ 37 38 extern void reset(void); 39 40 /* Current filename and output options. */ 41 42 char *output_prefix = NULL; 43 char *output_dir = NULL; 44 45 /* Compound interface and dispatcher output. */ 46 47 char *output_compound = NULL; 48 char *output_compound_name = NULL; 49 50 int output_client = 0; 51 int output_server = 0; 52 53 int output_headers = 0; 54 int output_interfaces = 0; 55 int output_routines = 0; 56 57 int output_verbose = 0; 58 59 enum language output_language = C_LANGUAGE; 60 61 62 63 /* Return a copy of the given string without any extension. */ 64 65 static char *make_prefix(const char *s) 66 { 67 char *copy = strdup(s); 68 char *ext; 69 70 if (copy == NULL) 71 return NULL; 72 73 ext = strrchr(copy, '.'); 74 75 if (ext != NULL) 76 *ext = '\0'; 77 78 return copy; 79 } 80 81 static int get_compound_prefix_conflict(int argc, char *argv[]) 82 { 83 char *arg, *prefix, *name; 84 int index, result; 85 86 for (index = optind; index < argc; index++) 87 { 88 arg = argv[index]; 89 prefix = make_prefix(arg); 90 result = 0; 91 92 if (prefix != NULL) 93 { 94 name = make_basename(prefix); 95 96 if (name != NULL) 97 { 98 result = strcasecmp(name, output_compound); 99 free(name); 100 } 101 102 free(prefix); 103 } 104 105 if (!result) 106 return index; 107 } 108 109 return 0; 110 } 111 112 113 /* Option definitions. */ 114 /* NOTE: --help and --version to be added. */ 115 116 static struct option long_options[] = { 117 /* long opt following var pointer short opt */ 118 {"all", no_argument, NULL, 'a' }, 119 {"client", no_argument, NULL, 'c' }, 120 {"comp", required_argument, NULL, 'C' }, 121 {"dir", required_argument, NULL, 'd' }, 122 {"headers", no_argument, NULL, 'h' }, 123 {"interfaces", no_argument, NULL, 'i' }, 124 {"language", required_argument, NULL, 'l' }, 125 {"comp-name", required_argument, NULL, 'N' }, 126 {"routines", no_argument, NULL, 'r' }, 127 {"server", no_argument, NULL, 's' }, 128 {"verbose", no_argument, NULL, 'v' }, 129 {0, 0, 0, 0 }, 130 }; 131 132 133 /* Main program, parsing indicated files or standard input. */ 134 135 int main(int argc, char *argv[]) 136 { 137 FILE *fp; 138 char *arg; 139 int option, index, output_selected_content = 0, output_selected_role = 0; 140 141 #if YYDEBUG == 1 142 yydebug = 0; 143 #endif 144 145 /* Accept various options. */ 146 147 while (1) 148 { 149 option = getopt_long(argc, argv, "acC:d:hil:N:rsv", long_options, NULL); 150 if (option == -1) 151 break; 152 153 switch (option) 154 { 155 /* Generate everything. */ 156 case 'a': 157 output_client = 1; output_server = 1; 158 output_headers = 1; output_interfaces = 1; output_routines = 1; 159 output_selected_content = 1; 160 output_selected_role = 1; 161 break; 162 163 /* Select client output. */ 164 case 'c': 165 output_client = 1; 166 output_selected_role = 1; 167 break; 168 169 /* Select compound interface filename prefix and output. */ 170 case 'C': 171 output_compound = optarg; 172 if (output_compound_name == NULL) 173 output_compound_name = output_compound; 174 output_selected_role = 1; 175 break; 176 177 /* Set output directory. */ 178 case 'd': 179 output_dir = optarg; 180 break; 181 182 /* Generate headers. */ 183 case 'h': 184 output_headers = 1; 185 output_selected_content = 1; 186 break; 187 188 /* Generate interface headers. */ 189 case 'i': 190 output_interfaces = 1; 191 output_selected_content = 1; 192 break; 193 194 /* Select output language. */ 195 case 'l': 196 if (!strcasecmp(optarg, "c")) 197 output_language = C_LANGUAGE; 198 else if (!strcasecmp(optarg, "c++")) 199 output_language = CPP_LANGUAGE; 200 else 201 { 202 fprintf(stderr, "Output language not recognised: %s\n", optarg); 203 return 1; 204 } 205 break; 206 207 /* Select compound interface name and output. */ 208 case 'N': 209 output_compound_name = optarg; 210 if (output_compound == NULL) 211 output_compound = output_compound_name; 212 output_selected_role = 1; 213 break; 214 215 /* Generate routines (definitions). */ 216 case 'r': 217 output_routines = 1; 218 output_selected_content = 1; 219 break; 220 221 /* Select server output. */ 222 case 's': 223 output_server = 1; 224 output_selected_role = 1; 225 break; 226 227 /* Verbose reporting. */ 228 case 'v': 229 output_verbose = 1; 230 break; 231 232 default: 233 return 1; 234 } 235 } 236 237 /* Without any output selection, enable all output of the given kind. */ 238 239 if (!output_selected_content) 240 { 241 output_headers = 1; output_interfaces = 1; output_routines = 1; 242 } 243 244 if (!output_selected_role) 245 { 246 output_client = 1; output_server = 1; 247 } 248 249 /* Check any compound interface prefix against named files. */ 250 251 if (output_compound != NULL) 252 { 253 if ((index = get_compound_prefix_conflict(argc, argv))) 254 { 255 fprintf(stderr, "Compound interface prefix %s conflicts with filename %s.\n", 256 output_compound, argv[index]); 257 return 1; 258 } 259 } 260 261 /* Begin generating any compound interface code. */ 262 263 begin_compound_output(); 264 265 /* Process standard input without any named files. */ 266 267 if (optind >= argc) 268 { 269 yyparse(); 270 reset(); 271 } 272 273 /* Process named files. */ 274 275 for (index = optind; index < argc; index++) 276 { 277 arg = argv[index]; 278 279 /* Handle actual files. */ 280 281 output_prefix = make_prefix(arg); 282 283 if (output_prefix != NULL) 284 { 285 fp = fopen(arg, "r"); 286 287 if (fp != NULL) 288 { 289 yyrestart(fp); 290 yyparse(); 291 fclose(fp); 292 293 /* Reset any specialised parser state. */ 294 295 reset(); 296 } 297 298 free(output_prefix); 299 } 300 } 301 302 /* End generating any compound interface code. */ 303 304 end_compound_output(); 305 306 return 0; 307 }