Hi Paul, On Wed, Mar 19, 2025 at 05:39:33PM -0700, Paul Eggert wrote: > On 3/19/25 14:23, Alejandro Colomar wrote: > > > I think not reporting errors or warnings on saturation needs > > justification. > > I don't know what "justification" means, but if it means a comment in the > code I'm not sure I agree. Code where saturation is ordinarily what's wanted > shouldn't need a comment on each nontrivial line saying "Saturation is OK > here." Nah, not a source-code comment. I think comments are usually evil. More like you telling me now why you do it that way. Actually, Bruno send detailed responses in his last email, and I think that you'd benefit from range checks, actually. (See my response to his email.) <https://lore.kernel.org/liba2i/6oyljvsenypqnrmgjbcwskqpdsag677h2dzay6hvfoosju4224@3j7iczm4d7nw/T/#m38066e6eec63a8906e3cbfea275c9d7940d8df98> > > Thanks, those changes look good. BTW, what do you think of using > > strspn(3) to simplify the c_isspace loop? > > Not worth the trouble. The loop is easier to read and debug than the strspn > call, I guess I got used to the niceties of strspn(3) that I find it easier to read. It's a matter of taste, so ok. :) > which got some minor details wrong and fixing that would complicate > the strspn code even further. Do you mean that the implementation of strspn(3) was temporarily broken? Or that the specification is bad? I'm curious about it; could you please clarify? > > However, would you mind clarifying why you don't diagnose huge values in > > the two places that you have updated? > > For this particular resource, a limit of ULONG_MAX has the same practical > effect as a limit of ULONG_MAX + 1. Since the user can't tell the difference > in behavior, it's fine to implement the larger limit as the smaller one, > with no diagnostic. According to Bruno, that limit is later clamped at a much lower value, so I think that clamping could be moved up to the strtou(3) call. Of course, that would mean having to implement strtou(3) for now, since it's non-standard, so keeping it as is is simpler. I was just trying to say that if strtou(3) was standard in libc, then you could just use it and simplify code, while making it more robust. > A reasonable amount of GNU code works that way. Ok. > > struct foo { > > long val; > > int err; > > } > > > > struct foo ret; > > > > ret = f(time_t, ...); > > if (ret.err != 0) > > err(1, "f"); > > > > How do I know which variant of struct foo I need? > > I don't understand the question. There's no variant here; "variant" to me > implies something like a union. > > But to fill in the details: C doesn't have a convenient notation for > returning multiple values, you do need a struct. One convention is to use a > struct whose tag is the same as the function. So, something like this in a > header file somewhere: > > struct a2i { intmax_t val; ptrdiff_t len; } > a2i (char const *str, int base); How do you get a uintmax_t? Let's say I'm parsing an unsigned variable. Also, how do I perform range checks in that call? I need to specify min and max limits. > where LEN is negative for errors, and callers look like this: How do you know how much has been parsed on error? That's something useful from strtoi/u(3). > struct a2i r = a2i(stringval, 10); > if (r.len < 0 || stringval[r.len]) > err("a2i", stringval, r.len); > > the "|| stringval[r.len]" is needed only for callers that consider > nonnumeric suffixes to be an error. How do you perform range checks with this API? > This is simpler than the pointers and "restrict"s in the proposed API. Compare to QChar *alt_2(typename T, T *restrict n, QChar *s, int base, T min, T max); which can be called time_t t; char *end; errno = 0; end = alt_2(time_t, &t, s, 0, past, future); if (errno == ERANGE && t == past) goto too_old; if (errno == ERANGE && t == future) goto too_new; if (errno == ENOTSUP) goto trailing_test; if (errno != 0) goto hard_error; // All's good here. Can use 't'. ... return; trailing_text: printf("Trailing text: %s", end); which gives me for free checks that t is between past and future, and of course saturation. It also gives me for free type validation that t is of type time_t. It calls strtoi(3) if time_t is a signed type, and strtou(3) if time_t is an unsigned type. I can perform all the checks to errno that I want, or I can omit them if I want. This is the API I'm working on at the moment, and I don't think a struct has anything more compelling than that. Have a lovely night! Alex -- <https://www.alejandro-colomar.es/>
Attachment:
signature.asc
Description: PGP signature