.. _program_listing_file_server_server_args_parser.c: Program Listing for File server_args_parser.c ============================================= |exhale_lsh| :ref:`Return to documentation for file ` (``server/server_args_parser.c``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include #include #include #include #include #include #include "bits/getopt_core.h" #include "client/client.h" #include "utils/debug.h" #include "server_args_parser.h" // Helper message to avoid long strings in the code static constexpr const char INVALID_ARG[] = { "Invalid option or missing argument\n%s\n" }; // Structure to hold the command line parameters, to be used by getopt_long static const struct option long_options[] = { {"help", no_argument, nullptr, 'h'}, {"port", required_argument, nullptr, 'p'}, {"width", required_argument, nullptr, 'x'}, {"height", required_argument, nullptr, 'y'}, {"names", required_argument, nullptr, 'n'}, {"client-number", required_argument, nullptr, 'c'}, {"freq", required_argument, nullptr, 'f'}, {nullptr, 0, nullptr, 0} }; static size_t get_team_slot(char **teams, const char *team_name, size_t count) { size_t i = 0; for (; i < count; i++) if (strcmp(teams[i], team_name) == 0) return i; return count; } static bool parse_teams(params_t *params, char *argv[], int *idx) { size_t i = 0; size_t slot; if (argv[*idx] == nullptr) return false; for (; argv[*idx + i] != nullptr && *argv[*idx + i] != '-'; i++); for (size_t j = 0; j < i; j++) { slot = get_team_slot( params->teams, argv[*idx + j], params->registered_team_count); if (slot != params->registered_team_count) return fprintf(stderr, (slot > TEAM_ID_GRAPHIC) ? "Team '%s' is already registered.\n" : "Cannot create reserved team name '%s'\n" , argv[*idx + j]), false; params->teams[params->registered_team_count] = argv[*idx + j]; params->registered_team_count++; } *idx += i; params->teams[params->registered_team_count] = nullptr; return true; } static uint16_t parse_number_arg( const char *arg, const char *name, uint16_t min, uint16_t max) { char *endptr; long value = strtol(arg, &endptr, 10); if (*endptr != '\0' || value < min || value > max) { fprintf(stderr, "Invalid value for %s: %s (must be between %u and %u)\n", name, arg, min, max ); return 0; } return value; } static bool number_arg_dispatcher(params_t *params, const char *arg, char opt) { switch (opt) { case 'f': params->frequency = parse_number_arg(arg, "f", 1, 10000); break; case 'x': params->map_width = parse_number_arg(arg, "x", 10, 42); break; case 'y': params->map_height = parse_number_arg(arg, "y", 10, 42); break; case 'p': params->port = parse_number_arg(arg, "p", 1024, 65535); break; case 'c': params->team_capacity = parse_number_arg(arg, "c", 1, 200); break; default: return fprintf(stderr, INVALID_ARG, SERVER_USAGE), false; } return true; } static bool arg_dispatcher(params_t *params, char *argv[], char opt) { switch (opt) { case 'h': params->help = true; return true; case 'n': optind--; if (!parse_teams(params, argv, &optind)) { fprintf(stderr, "Failed to parse team names.\n"); return false; } return true; case '?': default: return number_arg_dispatcher(params, optarg, opt); } } DEBUG_USED static void print_params(const params_t *params) { DEBUG_MSG("===================Zappy Server==================="); DEBUG("port = %d", params->port); DEBUG("width = %d", params->map_width); DEBUG("heigth = %d", params->map_height); DEBUG("clients_nb = %d", params->team_capacity); DEBUG("freq = %d", params->frequency); DEBUG_MSG("Teams:"); for (size_t i = 0; params->teams[i] != nullptr; i++) DEBUG(" - %s: id = [%03zu]", params->teams[i], i); DEBUG_MSG("=================================================="); } bool parse_args(params_t *params, int argc, char *argv[]) { for (int opt;;) { opt = getopt_long(argc, argv, "hp:x:y:n:c:f:", long_options, nullptr); if (opt < 0) break; if (!arg_dispatcher(params, argv, opt)) return false; } if (params->frequency == 0) params->frequency = 100; if (params->port == 0 || params->map_width == 0 || params->map_height == 0 || params->team_capacity == 0 || params->teams == nullptr ) return fprintf(stderr, "%s", SERVER_USAGE), false; DEBUG_CALL(print_params, params); return true; }