// 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 <getopt.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#define EX_OK 0
#define EX_USAGE (-1)
#define EX_SOFTWARE (-2)
#else
#include <sysexits.h>
#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;
}