/*************************************************************************\ * Copyright (C) Michael Kerrisk, 2018. * * * * This program is free software. You may use, modify, and redistribute it * * under the terms of the GNU Lesser General Public License as published * * by the Free Software Foundation, either version 3 or (at your option) * * any later version. This program is distributed without any warranty. * * See the files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. * \*************************************************************************/ /* Listing 3-6 */ /* get_num.c Functions to process numeric command-line arguments. */ #include #include #include #include #include #include "get_num.h" /* Print a diagnostic message that contains a function name ('fname'), the value of a command-line argument ('arg'), the name of that command-line argument ('name'), and a diagnostic error message ('msg'). */ static void gnFail(const char *fname, const char *msg, const char *arg, const char *name) { fprintf(stderr, "%s error", fname); if (name != NULL) fprintf(stderr, " (in %s)", name); fprintf(stderr, ": %s\n", msg); if (arg != NULL && *arg != '\0') fprintf(stderr, " offending text: %s\n", arg); exit(EXIT_FAILURE); } /* Convert a numeric command-line argument ('arg') into a long integer, returned as the function result. 'flags' is a bit mask of flags controlling how the conversion is done and what diagnostic checks are performed on the numeric result; see get_num.h for details. 'fname' is the name of our caller, and 'name' is the name associated with the command-line argument 'arg'. 'fname' and 'name' are used to print a diagnostic message in case an error is detected when processing 'arg'. */ static long getNum(const char *fname, const char *arg, int flags, const char *name) { long res; char *endptr; int base; if (arg == NULL || *arg == '\0') gnFail(fname, "null or empty string", arg, name); base = (flags & GN_ANY_BASE) ? 0 : (flags & GN_BASE_8) ? 8 : (flags & GN_BASE_16) ? 16 : 10; errno = 0; res = strtol(arg, &endptr, base); if (errno != 0) gnFail(fname, "strtol() failed", arg, name); if (*endptr != '\0') gnFail(fname, "nonnumeric characters", arg, name); if ((flags & GN_NONNEG) && res < 0) gnFail(fname, "negative value not allowed", arg, name); if ((flags & GN_GT_0) && res <= 0) gnFail(fname, "value must be > 0", arg, name); return res; } /* Convert a numeric command-line argument string to a long integer. See the comments for getNum() for a description of the arguments to this function. */ long getLong(const char *arg, int flags, const char *name) { return getNum("getLong", arg, flags, name); } /* Convert a numeric command-line argument string to an integer. See the comments for getNum() for a description of the arguments to this function. */ int getInt(const char *arg, int flags, const char *name) { long res; res = getNum("getInt", arg, flags, name); if (res > INT_MAX || res < INT_MIN) gnFail("getInt", "integer out of range", arg, name); return (int) res; }