// Copyright(c) 2018, Intel Corporation // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of Intel Corporation nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #include "argsfilter.h" #include #include #include #ifdef _WIN32 #define EX_OK 0 #define EX_USAGE (-1) #define EX_SOFTWARE (-2) #else #include #endif #define RETURN_ON_ERR(res, desc) \ do { \ if ((res) != FPGA_OK) { \ optind = 1; \ opterr = old_opterr; \ fprintf(stderr, "Error %s: %s\n", (desc), \ fpgaErrStr(res)); \ return EX_SOFTWARE; \ } \ } while (0) int set_properties_from_args(fpga_properties filter, fpga_result *result, int *argc, char *argv[]) { // prefix the short options with '-' so that unrecognized options are // ignored const char *short_opts = "-:B:D:F:S:"; struct option longopts[] = { {"bus", required_argument, NULL, 'B'}, {"device", required_argument, NULL, 'D'}, {"function", required_argument, NULL, 'F'}, {"socket-id", required_argument, NULL, 'S'}, {"segment", required_argument, NULL, 0xe}, {0, 0, 0, 0}, }; int supported_options = sizeof(longopts) / sizeof(longopts[0]) - 1; int getopt_ret = -1; int option_index = 0; char *endptr = NULL; int found_opts[] = {0, 0, 0, 0, 0}; int next_found = 0; int old_opterr = opterr; opterr = 0; struct _args_filter_config { int bus; int device; int function; int socket_id; int segment; } args_filter_config = { .bus = -1, .device = -1, .function = -1, .socket_id = -1, .segment = -1 }; while (-1 != (getopt_ret = getopt_long(*argc, argv, short_opts, longopts, &option_index))) { const char *tmp_optarg = optarg; if ((optarg) && ('=' == *tmp_optarg)) ++tmp_optarg; switch (getopt_ret) { case 'B': /* bus */ if (NULL == tmp_optarg) break; endptr = NULL; args_filter_config.bus = (int)strtoul(tmp_optarg, &endptr, 0); if (endptr != tmp_optarg + strlen(tmp_optarg)) { fprintf(stderr, "invalid bus: %s\n", tmp_optarg); return EX_USAGE; } found_opts[next_found++] = optind - 2; break; case 'D': /* device */ if (NULL == tmp_optarg) break; endptr = NULL; args_filter_config.device = (int)strtoul(tmp_optarg, &endptr, 0); if (endptr != tmp_optarg + strlen(tmp_optarg)) { fprintf(stderr, "invalid device: %s\n", tmp_optarg); return EX_USAGE; } found_opts[next_found++] = optind - 2; break; case 'F': /* function */ if (NULL == tmp_optarg) break; endptr = NULL; args_filter_config.function = (int)strtoul(tmp_optarg, &endptr, 0); if (endptr != tmp_optarg + strlen(tmp_optarg)) { fprintf(stderr, "invalid function: %s\n", tmp_optarg); return EX_USAGE; } found_opts[next_found++] = optind - 2; break; case 'S': /* socket */ if (NULL == tmp_optarg) break; endptr = NULL; args_filter_config.socket_id = (int)strtoul(tmp_optarg, &endptr, 0); if (endptr != tmp_optarg + strlen(tmp_optarg)) { fprintf(stderr, "invalid socket: %s\n", tmp_optarg); return EX_USAGE; } found_opts[next_found++] = optind - 2; break; case 0xe: /* segment */ if (NULL == tmp_optarg) break; endptr = NULL; args_filter_config.segment = (int)strtoul(tmp_optarg, &endptr, 0); if (endptr != tmp_optarg + strlen(tmp_optarg)) { fprintf(stderr, "invalid segment: %s\n", tmp_optarg); return EX_USAGE; } found_opts[next_found++] = optind - 2; break; case ':': /* missing option argument */ fprintf(stderr, "Missing option argument\n"); return EX_USAGE; case '?': break; case 1: break; default: /* invalid option */ fprintf(stderr, "Invalid cmdline options\n"); return EX_USAGE; } } if (-1 != args_filter_config.bus) { *result = fpgaPropertiesSetBus(filter, args_filter_config.bus); RETURN_ON_ERR(*result, "setting bus"); } if (-1 != args_filter_config.device) { *result = fpgaPropertiesSetDevice(filter, args_filter_config.device); RETURN_ON_ERR(*result, "setting device"); } if (-1 != args_filter_config.function) { *result = fpgaPropertiesSetFunction( filter, args_filter_config.function); RETURN_ON_ERR(*result, "setting function"); } if (-1 != args_filter_config.socket_id) { *result = fpgaPropertiesSetSocketID( filter, args_filter_config.socket_id); RETURN_ON_ERR(*result, "setting socket id"); } if (-1 != args_filter_config.segment) { *result = fpgaPropertiesSetSegment( filter, args_filter_config.segment); RETURN_ON_ERR(*result, "setting segment"); } // using the list of optind values // shorten the argv vector starting with a decrease // of 2 and incrementing that amount by two for each option found int removed = 0; int i, j; for (i = 0; i < supported_options; ++i) { if (found_opts[i]) { for (j = found_opts[i] - removed; j < *argc - 2; j++) { argv[j] = argv[j + 2]; } removed += 2; } else { break; } } *argc -= removed; // restore getopt variables // setting optind to zero will cause getopt to reinitialize for future // calls within the program optind = 0; opterr = old_opterr; return EX_OK; }