[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [leafnode-list] fetchnews fails to download bodies



krasel@xxxxxxxxxxxxxxxxxxxxxxxxxxxx (Cornelius Krasel) writes:

> If an fopen() is performed successfully on a file, does this affect
> the atime and mtime of the file? I ask because of this piece of
> code (from postarticles()):

I have no information for fopen(3), however, assuming that fopen(3) calls
open(2), stat(2) applies:

Traditionally, st_atime is changed by mknod(2), utime(2), read(2),
write(2), and truncate(2).

Traditionally, st_mtime is changed by mknod(2), utime(2), and write(2).

Traditionally, st_ctime is changed by writing or by setting inode
information (i.e., owner, group, link count, mode, etc.).

>         if ( ( stat( de->d_name, &st ) == 0 ) && S_ISREG( st.st_mode ) &&
>              ( ( f = fopen( de->d_name, "r" ) ) != NULL ) &&
>              isgrouponserver( fgetheader( f, "Newsgroups:" ) ) &&
>              ( ( haveid = 
>                  ismsgidonserver( fgetheader( f, "Message-ID:" ) ) ) != 1 ) ) {
> 
> a) Wouldn't it be more efficient to open the file first and then doing
>    fstat()? There shouldn't be any non-regular files in out.going anyway,

Hardly. Once you stat()ed the file, all required data is buffered, so
open (fopen) will not infer additional I/O. However, you can fopen
non-regular files as well which may not give the desired results (may
not be visible at once and on all systems).

IMHO, using lstat(2) here on systems that support lstat would be better.

> b) Obviously,
>    in the code above the strings returned by fgetheader() cannot be
>    free()d - or is there a possibility that I may have overlooked?

Yes. Assignments evaluate to the assigned value, thus:

#1:
  2 * 2     /* is 4 */

  2 * (c = 2) /* assigns 2 to c, then calculates 2 * c, is also */


#2:
do_something(strdup(e)); /* leaks memory unless callee-freed */

char *tmp;
do_something(tmp = strdup(e));
free(tmp);              /* caller-freed */                        

or:
 char *c1, *c2;

..
  && isgrouponserver(c1 = fgetheader(f, "Newsgroup:"))
  && ((haveid=ismsgidonserver(c2 = fgetheader(f, "Message-ID:"))) != 1))

BUT BEFORE you consider this, drop that entire junk. Write an fopen
wrapper named fopen_reg that does the lstat()s and opens only regular
files, returning ENOTSUP in case of trouble, is better. That saves three
lines in that code. 

Then, go nest the && into ifs so you can clean up properly. Explicitly
initializing c1 and c2 to 0 and later doing `if (c1) free(c1);' is bad
style and excess caution, much easier solved.

> And another C question (regarding the recent mail by Matthias Andree about
> syntax):
> 
> c) Can this code
> 	return ( havepath && havemsgid && havefrom && haveng );
>    also be written without the brackets, i.e. is it ensured that
>    the logical expression will be evaluated first and the result
>    being returned?

Don't misunderstand my suggestion: It's not about getting rid of
parentheses, but it's about getting rid of the wrong whitespace on their
immediate insides.

I don't care whether you write:

        return havepath && ... haveng;

or

        return (havepath && ... haveng);

I do care when you write:

        return ( 1 );

rather than either of these:

        return (1);

        return 1;



Answering your question:

return is a statement, thus there is no operator precedence (for the
short-circuiting logical and operator "&&" involved. Everything between
return and the terminating semicolon ";" is evaluated.

So yes, you can omit the parentheses. They are, unlike those in for,
while or if, not part of the syntax specification.

Try:
/* try.c
 * to compile: gcc -O -W -Wall -o try try.c 
 */
#include <stdio.h>

double test(void)
{
    return 1 + 5;
}

int main(void)
{
    printf("%f\n", test());
    return 0;
}
/* EOF */

Quoting "Programmieren in C", 2. Auflage: ANSI-C, by "Kernighan &
Ritchie" (I don't have the original to quote from), p. 222, Appendix A
"C-Sprachbeschreibung", Section 9 "Anweisungen", Subsection A.9.6
"Sprunganweisungen":

"jump-statement:
  return /expression_opt/;

(...) 

Eine Funktion kehrt mit der *return*-Anweisung zu ihrem Aufrufer
zurück. Wenn nach *return* ein Ausdruck folgt, wird dieser Wert dem
Aufrufer der Funktion geliefert. Der Ausdruck wird wie bei einer
Zuweisung in den Resulattyp der Funktion umgewandelt, in der er
auftritt.

Erreicht der Programmablauf das Ende einer Funktion, ist das äquivalent
zur Ausführung von *return* ohne einen Ausdruck. In jedem Fall ist dann
der Resultatwert undefiniert."

-- 
Matthias Andree

-- 
leafnode-list@xxxxxxxxxxxxxxxxxxxxxxxxxxxx -- mailing list for leafnode
To unsubscribe, send mail with "unsubscribe" in the subject to the list