Warning: mysqli::__construct(): (HY000/1203): User howardkn already has more than 'max_user_connections' active connections in D:\Inetpub\vhosts\howardknight.net\al.howardknight.net\includes\artfuncs.php on line 21
Failed to connect to MySQL: (1203) User howardkn already has more than 'max_user_connections' active connectionsPath: ...!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!eternal-september.org!.POSTED!not-for-mail From: Michael S Newsgroups: comp.lang.c Subject: Re: Buffer contents well-defined after fgets() reaches EOF ? Date: Fri, 14 Feb 2025 16:51:08 +0200 Organization: A noiseless patient Spider Lines: 99 Message-ID: <20250214165108.00002984@yahoo.com> References: <20250210124911.00006b31@yahoo.com> <86ldu9zxkb.fsf@linuxsc.com> MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Injection-Date: Fri, 14 Feb 2025 15:51:14 +0100 (CET) Injection-Info: dont-email.me; posting-host="826449c6656c9e445743af80f927f4e5"; logging-data="3680351"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18bX6YBKsSx9ikMt9/dilZ0VyRt//K/Igw=" Cancel-Lock: sha1:7yiC8nMxBE7c/AwYlNnRDJGGghM= X-Newsreader: Claws Mail 4.1.1 (GTK 3.24.34; x86_64-w64-mingw32) Bytes: 4625 On Thu, 13 Feb 2025 07:14:28 -0800 Tim Rentsch wrote: > Michael S writes: > > > On Sun, 9 Feb 2025 17:22:43 -0800 > > Andrey Tarasevich wrote: > > > >> On Sun 2/9/2025 5:06 PM, Andrey Tarasevich wrote: > >> > >>> On Sun 2/9/2025 3:52 PM, Lawrence D'Oliveiro wrote: > >>> > >>>> On Sat, 8 Feb 2025 23:12:44 -0800, Andrey Tarasevich wrote: > >>>> > >>>>> If `fgets` reads nothing (instant end-of-file), the entire > >>>>> buffer remains untouched. > >>>> > >>>> You mean, only a single null byte gets written. > >>> > >>> No. The buffer is not changed at all in such case. > >> > >> ... which actually raises an interesting quiz/puzzle/question: > >> > >> Under what circumstances `fgets` is expected to return an empty > >> string? (I.e. set the [0] entry of the buffer to '\0' and return > >> non-null)? > >> > >> The only answer I can see right away is: > >> > >> When one calls it as `fgets(buffer, 1, file)`, i.e. asks it to > >> read 0 characters. > >> > >> This is under assumption that asking `fgets` to read 0 characters > >> is supposed to prevent it from detecting end-of-file condition or > >> I/O error condition. One can probably do some nitpicking at the > >> current wording... but I believe the above is the intent. > > > > fgets() is one of many poorly defined standard library functions > > inherited from early UNIX days. [...] > > What about the fgets() function do you think is poorly defined? > > Second question: by "poorly defined" do you mean "defined > wrongly" or "defined ambiguously" (or both)? For starter, it looks like designers of fgets() did not believe in their own motto about files being just streams of bytes. I don't know the history, so, may be, the function was defined this way for portability with systems where text files have special record-based structure? Then, everything about it feels inelegant. A return value carries just 1 bit of information, success or failure. So why did they encode this information in baroque way instead of something obvious, 0 and 1? Appending zero at the end also feels like a hack, but it is necessary because of the main problem. And the main problem is: how the user is supposed to figure out how many bytes were read? In well-designed API this question should be answered in O(1) time. With fgets(), it can be answered in O(N) time when input is trusted to contain no zeros. When input is arbitrary, finding out the answer is even harder and requires quirks. What is my suggestion for alternative? Without too deep thinking I'd suggest (ignoring issues of restrict for sake of brevity) function that gives the same answer like foo() below, but hopefully does it faster: char* foo(FILE* fp, char* dst, int count, char last_c) { while (count > 0) { int ch = fgetc(fp); if (ch == EOF) { if (ferror(fp)) dst = NULL; break; } *dst++ = ch; if (ch == last_c) break; --count; } return dst; } The function foo() is more generic than fgets(). For use instead of fgets() it should be accompanied by standard constant EOL_CHAR. I am not completely satisfied with proposed solution. The API is still less obvious than it could be. But it is much better than fgets().