-
Notifications
You must be signed in to change notification settings - Fork 55
Error on negative number when non-negative required #200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error on negative number when non-negative required #200
Conversation
Instead of silently pretending the user passed zero, let's issue an error message and bail out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like that it doesn't notify the user about which option needs a non negative number but it's better than the current situation.
Can (and IMO should) be done by removing the function entirely and checking for it at call site. For example: case 'd':
- opt.delay = nonNegativeNumber(optionsParseRequiredNumber(optarg));
+ if ((opt.delay = optionsParseRequiredNumber(optarg)) < 0)
+ errx(EXIT_FAILURE, "delay needs to be non-negative");
break; Or maybe the function could accept a name: ```diff
case 'd':
- opt.delay = nonNegativeNumber(optionsParseRequiredNumber(optarg));
+ opt.delay = nonNegativeNumber("delay", optionsParseRequiredNumber(optarg)); And inside the function you'd do |
Yeah, after @guijan's comment I came to the same conclusion -- I'll admit that the main reason I haven't already changed it to do that instead is that it would introduce a conflict with another (slightly larger) PR that I've currently got open awaiting review (#199). If that one gets merged first I'll change this one to also replace the new callsite that patch adds. |
optionsParseRequiredNumber(), optionsParseRequireRange(), and nonNegativeNumber() should all be replaced by strtonum(). That would make it really easy to print much more informative error messages and we would shed some lines of code. The one catch is that I already know upfront Cygwin is missing this function, this would introduce a dependency on my libbsd-compatible library on that system which is something @daltomi was against in a previous PR. |
The
Bad idea :-) , please note how you come to that conclusion (
I agree with this 👍 |
As someone reading this snippet for the first time, the function actually obfuscated the intent compared to an immediate check such as opt.delay = nonNegativeNumber(optionsParseRequiredNumber(optarg)); Here I can assume what
All of these are valid action that a function named 'nonNegativeNumber' might take. And in this case it does 2, but no where in the function name does it say that. So in order to actually figure out what's happening I need to go jump to the function definition. Compare that with the following; the intent is very clear and doesn't require having to look up a function definition somewhere else. if ((opt.delay = optionsParseRequiredNumber(optarg)) < 0)
errx(EXIT_FAILURE, "delay must be non-negative"); It's immediately obvious that the intention is that the number cannot be negative and if it is negative then exit the process. For things that are so simple as a check against 0, I don't think a function adds any value. If anything shallow functions harms readability more than it helps. |
In other function names I used the word |
Hi @zevweiss We are in the process of launching a new release, I would like your PR to be included. |
I'm working on this. I wrote my own /* options_parsenum: "string to number" function.
*
* Parses the string representation of an integer in str, and simultaneously
* ensures that it is >= min and <= max.
*
* Returns the integer and sets *errmsg to NULL on success.
* Returns 0 and sets *errmsg to a pointer to a string containing the
* reason why the number can't be parsed on error.
*
* usage:
* char *errmsg;
* unsigned int nonnegative;
* if ((nonnegative = options_parsenum(optarg, 0, UINT_MAX, &errmsg)) == NULL)
* errx(1, "-n: '%s' is %s", optarg, errmsg);
*/
long long options_parsenum(const char *str, long long min, long long max,
const char *errmsg[static 1])
{
char *end = NULL;
long long rval;
int saved_errno = errno;
*errmsg = NULL;
errno = 0;
rval = strtoll(str, &end, 10);
if (errno == ERANGE)
*errmsg = "not representable";
else if (rval < min)
*errmsg = min == 0 ? "negative" : "too small";
else if (rval > max)
*errmsg = "too large";
else if (*str == '\0' || *end != '\0')
*errmsg = "not a number";
errno = saved_errno;
return (*errmsg ? 0 : rval);
} |
Seems unnecessarily complicated just to test for negative number, also Unless you're talking about replacing |
Yes, it's for replacing |
Instead of silently pretending the user passed zero, let's issue an error message and bail out.