fgets reading a configuration file: compiles OK but output wrong 
Author Message
 fgets reading a configuration file: compiles OK but output wrong

int main (int argc, char **argv)
{

  int   i ;
  int   j ;
  int  status;
  FILE *f1 ;
          FILE  *host ;
          FILE  *svcs ;
  char c;
  char hostname[64];
  char svcsar[32][32];

  f1    =               (fopen("/tmp/ath.tmp", "r+")) ;
  host  =       (fopen("/usr/local/etc/anth.host", "r")) ;
  svcs  =       (fopen("/usr/local/etc/anth.svcs", "r")) ;
/* get hostname from default file *
 */
printf ("default hostname:\t");
          while (fgets(hostname, (sizeof(host)), host)) {
                   while (*hostname == '#') {
                        (fgets(hostname, (sizeof(host)), host)) ;  
                   }
          }
printf ("%s\n", hostname);

/* get list of services
 */
printf ("default services:\t");

                  i = (i = (countnl(svcs)) + 1) ;
                  for (j=0; j < i ; j++) {
                        while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {
                                while ( svcsar[j][0] == '#' ) {
                                        printf ("service[j][0]: %s\n", svcsar[j]);

                                        (fgets(svcsar[j], (sizeof(svcs)), host)) ;  
                                }
                        printf ("service: %s\n", svcsar[j]);
                        }
                  }
 /* this section for allowing commndline overrides; unfinished */
  while (--argc)
    {
      switch (StringCase (*++argv, "-h", argv, "-s", argv, NULL))
        {
        case 0:
          printf ("host filename override:\t");
          while (fgets(hostname, BUFSIZ, host)) {
                   while (hostname[0] == '#') {
                        (fgets(hostname, BUFSIZ, host)) ;
                   }
          }
        }
    }

Quote:
}/*end main */

what i want the program to do is read 2 configuration files and print
their contents without the comments

the first char array is the hostname
i want to read it from:

$ cat /usr/local/etc/anth.host
# anth.host
# list hostname here
zvc.co17.mydomain

the second is an array of pointers to character arrays
i want to loop through the index of the array and write the contents
of

# anth.svcs
# list services here
sshd
named
sendmail
smbd
dhcpd
httpd
xinetd
crond

what is happening right now
the program runs to the point where it enters the while loop and then
exits.  i put printfs inside the while loop and they print nothing.
not only this the string "default services: " is where it stops and it
does not continue until i press Ctl d.  this led me to suspect that it
is expecting some kind of input from a file or console.  console input
and ctl d resume the program

here's the output:
--
default hostname:       in

default services:      

--
notice the gap after hostname?
if i change the fgets statement to
fgets(hostname, 32, host)
everything works out.
it discards the lines beginning in '#' and copies the line with the
hostname into the hostname variable.

however i tried this with the services aspect of the program, and this
did not solve the problem at all.

i reason that i should be able to use a for statement based on the
number of newlines in the services configuration file and then read
each newline that does not begin with a '#' char into the char array
pointed to by the index [j] which is incremented in the for loop until
it reaches i (formerly the number of newlines plus 1)

i must have become tired and missed something because the logic must
be wrong, since it compiles without warnings.
--



Mon, 14 Feb 2005 00:01:09 GMT  
 fgets reading a configuration file: compiles OK but output wrong

Quote:

>int main (int argc, char **argv)
>{

>  int       i ;
>  int   j ;
>  int  status;
>  FILE *f1 ;
>      FILE  *host ;
>      FILE  *svcs ;

Your code is hard to read because of the incoherent indenting.

Quote:
>  char c;
>  char hostname[64];
>  char svcsar[32][32];

>  f1        =               (fopen("/tmp/ath.tmp", "r+")) ;

Why the extra set of parenthesis?

Quote:
>  host      =       (fopen("/usr/local/etc/anth.host", "r")) ;
>  svcs      =       (fopen("/usr/local/etc/anth.svcs", "r")) ;
>/* get hostname from default file *
> */
>printf ("default hostname:\t");
>      while (fgets(hostname, (sizeof(host)), host)) {
>               while (*hostname == '#') {
>                    (fgets(hostname, (sizeof(host)), host)) ;  
>               }
>      }
>printf ("%s\n", hostname);

>/* get list of services
> */
>printf ("default services:\t");

>              i = (i = (countnl(svcs)) + 1) ;

What is countnl()???

Quote:
>              for (j=0; j < i ; j++) {
>                    while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {

"sizeof(svcs)" returns the size of a pointer to FILE.  You want the size
of the buffer supplied for fgets, svcsar[j].

Quote:
>                            while ( svcsar[j][0] == '#' ) {
>                                    printf ("service[j][0]: %s\n", svcsar[j]);

>                                    (fgets(svcsar[j], (sizeof(svcs)), host)) ;  

See above.

- Show quoted text -

Quote:
>                            }
>                    printf ("service: %s\n", svcsar[j]);
>                    }
>              }
> /* this section for allowing commndline overrides; unfinished */
>  while (--argc)
>    {
>      switch (StringCase (*++argv, "-h", argv, "-s", argv, NULL))
>    {
>    case 0:
>      printf ("host filename override:\t");
>      while (fgets(hostname, BUFSIZ, host)) {
>               while (hostname[0] == '#') {
>                    (fgets(hostname, BUFSIZ, host)) ;
>               }
>      }
>    }
>    }
>}/*end main */

>what i want the program to do is read 2 configuration files and print
>their contents without the comments

>the first char array is the hostname
>i want to read it from:

>$ cat /usr/local/etc/anth.host
># anth.host
># list hostname here
>zvc.co17.mydomain

>the second is an array of pointers to character arrays
>i want to loop through the index of the array and write the contents
>of

># anth.svcs
># list services here
>sshd
>named
>sendmail
>smbd
>dhcpd
>httpd
>xinetd
>crond

>what is happening right now
>the program runs to the point where it enters the while loop and then
>exits.  i put printfs inside the while loop and they print nothing.
>not only this the string "default services: " is where it stops and it
>does not continue until i press Ctl d.  this led me to suspect that it
>is expecting some kind of input from a file or console.  console input
>and ctl d resume the program

>here's the output:
>--
>default hostname:       in

>default services:      

>--
>notice the gap after hostname?
>if i change the fgets statement to
>fgets(hostname, 32, host)
>everything works out.
>it discards the lines beginning in '#' and copies the line with the
>hostname into the hostname variable.

>however i tried this with the services aspect of the program, and this
>did not solve the problem at all.

>i reason that i should be able to use a for statement based on the
>number of newlines in the services configuration file and then read
>each newline that does not begin with a '#' char into the char array
>pointed to by the index [j] which is incremented in the for loop until
>it reaches i (formerly the number of newlines plus 1)

>i must have become tired and missed something because the logic must
>be wrong, since it compiles without warnings.
>--


--
Floyd L. Davidson         <http://www.ptialaska.net/~floyd>

--



Fri, 18 Feb 2005 11:40:56 GMT  
 fgets reading a configuration file: compiles OK but output wrong

Quote:
> int main (int argc, char **argv)
> {
>   int      i ;
>   int   j ;
>   int  status;
>   FILE *f1 ;
>      FILE  *host ;
>      FILE  *svcs ;
>   char c;
>   char hostname[64];
>   char svcsar[32][32];
>   f1       =               (fopen("/tmp/ath.tmp", "r+")) ;
>   host     =       (fopen("/usr/local/etc/anth.host", "r")) ;
>   svcs     =       (fopen("/usr/local/etc/anth.svcs", "r")) ;
> /* get hostname from default file *
>  */
> printf ("default hostname:\t");
>      while (fgets(hostname, (sizeof(host)), host)) {

This line is very strange. The second argument is the maximum length
of th string fgets() is supposed to read in. But 'host' is a FILE *,
not a char array, You probably meant

          while ( fgets(hostname, sizeof hostname, host )) {

Quote:
>               while (*hostname == '#') {
>                    (fgets(hostname, (sizeof(host)), host)) ;  

Same problem here.

Quote:
>               }
>      }
> printf ("%s\n", hostname);

Don't forget that fgets() also reads the '\n' into the buffer. So here
you actually print out *two* '\n's (unless the buffer you passed to
fgets() was too small).

Quote:
> /* get list of services
>  */
> printf ("default services:\t");
>              i = (i = (countnl(svcs)) + 1) ;

That's a really strange line. Why not

         i = countnl( svcs) + 1;

What's the countnl() function doing? If it counts the number of newlines
in the file svcs points to, does it also rewind the file afterwards?

Quote:
>              for (j=0; j < i ; j++) {
>                    while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {

Same problem as above, use

                while (fgets(svcsar[j], sizeof svcsar[ j ], svcs)) {

Another point: It looks as if your for-loop is supposed to loop
over all lines of the file (asssuming the countnl() returns the
number of lines in the file). Why do you then also have a while-loop
which looks as if you try to read all lines again?

Quote:
>                            while ( svcsar[j][0] == '#' ) {
>                                    printf ("service[j][0]: %s\n", svcsar[j]);
>                                    (fgets(svcsar[j], (sizeof(svcs)), host)) ;  

And again...

Quote:
>                            }
>                    printf ("service: %s\n", svcsar[j]);
>                    }
>              }

What about replacing this by

    for ( j = 0; j < 32 && fgets(svcsar[j], sizeof svcsar[ j ], svcs); j++ )
    {
        while ( svcsar[ j ][ 0 ] == '#' )
             if ( fgets(svcsar[j], sizeof svcsar[ j ], svcs) == NULL )
                 break;
        printf ("service: %s", svcsar[j]);
    }

As far as I can see that's all you need to skip comment lines and
print out the others. It also will stop reading after the svcsar
buffer is full, which you don't even check for... Let's just hope
that none of the lines is longer than 31 characters ;-)

Quote:
>  /* this section for allowing commndline overrides; unfinished */
>   while (--argc)
>     {
>       switch (StringCase (*++argv, "-h", argv, "-s", argv, NULL))

What is the StingCasse() function supposed to do?

Quote:
>    {
>    case 0:
>      printf ("host filename override:\t");
>      while (fgets(hostname, BUFSIZ, host)) {

No BUFSIZ defined anywhere where I could see it. Don't you mean:

          while (fgets(hostname, sizeof hostname, host)) {

Quote:
>               while (hostname[0] == '#') {
>                    (fgets(hostname, BUFSIZ, host)) ;
>               }
>      }
>    }
>     }
> }/*end main */

                                        Regards, Jens
--
      _  _____  _____

  _  | |  | |    | |
 | |_| |  | |    | |          http://www.physik.fu-berlin.de/~toerring
  \___/ens|_|homs|_|oerring
--



Fri, 18 Feb 2005 11:41:05 GMT  
 fgets reading a configuration file: compiles OK but output wrong

Quote:

> int main (int argc, char **argv)
> {

>   int      i ;
>   int   j ;
>   int  status;
>   FILE *f1 ;
>      FILE  *host ;
>      FILE  *svcs ;
>   char c;
>   char hostname[64];
>   char svcsar[32][32];

>   f1       =               (fopen("/tmp/ath.tmp", "r+")) ;
>   host     =       (fopen("/usr/local/etc/anth.host", "r")) ;
>   svcs     =       (fopen("/usr/local/etc/anth.svcs", "r")) ;
> /* get hostname from default file *
>  */
> printf ("default hostname:\t");
>      while (fgets(hostname, (sizeof(host)), host)) {
>               while (*hostname == '#') {
>                    (fgets(hostname, (sizeof(host)), host)) ;  
>               }
>      }
> printf ("%s\n", hostname);

> /* get list of services
>  */
> printf ("default services:\t");

>              i = (i = (countnl(svcs)) + 1) ;
>              for (j=0; j < i ; j++) {
>                    while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {
>                            while ( svcsar[j][0] == '#' ) {
>                                    printf ("service[j][0]: %s\n", svcsar[j]);

>                                    (fgets(svcsar[j], (sizeof(svcs)), host)) ;  
>                            }
>                    printf ("service: %s\n", svcsar[j]);
>                    }
>              }
>  /* this section for allowing commndline overrides; unfinished */
>   while (--argc)
>     {
>       switch (StringCase (*++argv, "-h", argv, "-s", argv, NULL))
>    {
>    case 0:
>      printf ("host filename override:\t");
>      while (fgets(hostname, BUFSIZ, host)) {
>               while (hostname[0] == '#') {
>                    (fgets(hostname, BUFSIZ, host)) ;
>               }
>      }
>    }
>     }
> }/*end main */

> what i want the program to do is read 2 configuration files and print
> their contents without the comments

Your code is not easy to understand as pointed out in another mail it'
too dense. I suggest you step back and restructure it, e.g strip down
things which do not work and assure yourself that you got what you
expect at different stages, a  good idea could be to use assert. You
state there what you expet and if it's not there you will know. Than
you can fix one problem after the other.

Things you might consider.
- Writing function for skipping over comments. you have code doubling
which is an indication that copy+paste is at work. This is not a good
idea.

- The switch looks very stange too. Just one case?

- you do not do any error checking, therefor how will you know wha
acutuall happens

- you can follow you program in a de{*filter*} to see where it goes wrong.

Regards
Friedrich
--



Fri, 18 Feb 2005 11:41:08 GMT  
 fgets reading a configuration file: compiles OK but output wrong

Quote:

>      while (fgets(hostname, (sizeof(host)), host)) {

The second parameter to all your fgets calls is wrong. You are passing
the size of a 'FILE *' (probably 4 bytes). You have to pass the size of
the buffer that you want to read the data into. That would be
sizeof(hostname) in the above line.
Also note that fgets doesn't remove trailing new lines (\n), so you
should take care of that (unless you need them, which I doubt).

Quote:
>               while (*hostname == '#') {

The nested whiles for skipping the comments could be solved in a
nicer way, though that's just my personal opinion :) like that:

while (fgets(...)) {
        if (hostname[0] != '#') {
                /* process the line */
        }

Quote:
}
>              i = (i = (countnl(svcs)) + 1) ;

That i = (i = (countnl()... thing is really ugly, imo. Just loop the
fgets in a while loop until you reach the end of file and increase a
counter (the index into svcsar[...]) every time you loop.
You should make a few checks if the index is still within the upper
bound of the array also (what if there are more then 32?).

Quote:
>              for (j=0; j < i ; j++) {
>                    while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {

Same problem as above, sizeof(svcs) is probably 4, you need the size
of svcsar[j].

Quote:
>                            while ( svcsar[j][0] == '#' ) {
>                                    printf ("service[j][0]: %s\n", svcsar[j]);

>                                    (fgets(svcsar[j], (sizeof(svcs)), host)) ;  

You are reading from the wrong file here. We are at 'svcs', not 'host' :)

hth,
Max
--



Fri, 18 Feb 2005 11:41:12 GMT  
 fgets reading a configuration file: compiles OK but output wrong
Some embedded comments below.

--
                Fletcher Glenn

Quote:

> int main (int argc, char **argv)
> {

>   int   i ;
>   int   j ;
>   int  status;
>   FILE *f1 ;
>           FILE  *host ;
>           FILE  *svcs ;
>   char c;
>   char hostname[64];
>   char svcsar[32][32];

You never check below to see if any of the fopen()s failed.

Quote:
>   f1    =               (fopen("/tmp/ath.tmp", "r+")) ;
>   host  =       (fopen("/usr/local/etc/anth.host", "r")) ;
>   svcs  =       (fopen("/usr/local/etc/anth.svcs", "r")) ;
> /* get hostname from default file *
>  */
> printf ("default hostname:\t");
>           while (fgets(hostname, (sizeof(host)), host)) {

The size used in fgets should be the size of the target
array - in this case 64 or sizeof(hostname).  This applies
everywhere you use fgets().

Quote:
>                    while (*hostname == '#') {
>                         (fgets(hostname, (sizeof(host)), host)) ;
>                    }
>           }
> printf ("%s\n", hostname);

The printf above should be inside the outer while loop if you
want to print each non-commented line.

Quote:

> /* get list of services
>  */
> printf ("default services:\t");

>                   i = (i = (countnl(svcs)) + 1) ;
>                   for (j=0; j < i ; j++) {
>                         while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {
>                                 while ( svcsar[j][0] == '#' ) {
>                                         printf ("service[j][0]: %s\n", svcsar[j]);

>                                         (fgets(svcsar[j], (sizeof(svcs)), host)) ;
>                                 }
>                         printf ("service: %s\n", svcsar[j]);
>                         }
>                   }
>  /* this section for allowing commndline overrides; unfinished */
>   while (--argc)
>     {
>       switch (StringCase (*++argv, "-h", argv, "-s", argv, NULL))
>         {
>         case 0:
>           printf ("host filename override:\t");
>           while (fgets(hostname, BUFSIZ, host)) {
>                    while (hostname[0] == '#') {
>                         (fgets(hostname, BUFSIZ, host)) ;
>                    }
>           }
>         }
>     }
> }/*end main */

> what i want the program to do is read 2 configuration files and print
> their contents without the comments

> the first char array is the hostname
> i want to read it from:

> $ cat /usr/local/etc/anth.host
> # anth.host
> # list hostname here
> zvc.co17.mydomain

> the second is an array of pointers to character arrays
> i want to loop through the index of the array and write the contents
> of

> # anth.svcs
> # list services here
> sshd
> named
> sendmail
> smbd
> dhcpd
> httpd
> xinetd
> crond

> what is happening right now
> the program runs to the point where it enters the while loop and then
> exits.  i put printfs inside the while loop and they print nothing.
> not only this the string "default services: " is where it stops and it
> does not continue until i press Ctl d.  this led me to suspect that it
> is expecting some kind of input from a file or console.  console input
> and ctl d resume the program

> here's the output:
> --
> default hostname:       in

> default services:

> --
> notice the gap after hostname?
> if i change the fgets statement to
> fgets(hostname, 32, host)
> everything works out.
> it discards the lines beginning in '#' and copies the line with the
> hostname into the hostname variable.

> however i tried this with the services aspect of the program, and this
> did not solve the problem at all.

> i reason that i should be able to use a for statement based on the
> number of newlines in the services configuration file and then read
> each newline that does not begin with a '#' char into the char array
> pointed to by the index [j] which is incremented in the for loop until
> it reaches i (formerly the number of newlines plus 1)

> i must have become tired and missed something because the logic must
> be wrong, since it compiles without warnings.
> --


--



Fri, 18 Feb 2005 11:41:18 GMT  
 fgets reading a configuration file: compiles OK but output wrong

Quote:

>if i change the fgets statement to
>fgets(hostname, 32, host)

You have

fgets(hostname, sizeof(host), host)

in your program.  The sizeof should be hostname, not host.  You have this
error throughout the program -- you're specifying the size of the FILE*
pointer, instead of the size of the buffer that's being filled in.

--

Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
--



Fri, 18 Feb 2005 11:41:46 GMT  
 fgets reading a configuration file: compiles OK but output wrong

in comp.lang.c.moderated:

You need:

#include <stdio.h>

....here.

I haven't analyzed your code extensively, but I have found at least
one glaring error...

Quote:
> int main (int argc, char **argv)
> {

>   int      i ;
>   int   j ;
>   int  status;
>   FILE *f1 ;
>      FILE  *host ;
>      FILE  *svcs ;
>   char c;
>   char hostname[64];
>   char svcsar[32][32];

>   f1       =               (fopen("/tmp/ath.tmp", "r+")) ;
>   host     =       (fopen("/usr/local/etc/anth.host", "r")) ;
>   svcs     =       (fopen("/usr/local/etc/anth.svcs", "r")) ;
> /* get hostname from default file *
>  */
> printf ("default hostname:\t");
>      while (fgets(hostname, (sizeof(host)), host)) {

I imagine that you wanted to use "sizeof hostname" rather than "sizeof
host" -- note that none of the silly parentheses are necessary for
either.  sizeof host is the size of a pointer to a FILE structure,
most likely four bytes on common 32 bit platforms these days.

Quote:
>               while (*hostname == '#') {
>                    (fgets(hostname, (sizeof(host)), host)) ;  
>               }
>      }
> printf ("%s\n", hostname);

> /* get list of services
>  */
> printf ("default services:\t");

>              i = (i = (countnl(svcs)) + 1) ;
>              for (j=0; j < i ; j++) {
>                    while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {

Same thing here.  Even if you had left out the silly parentheses, and
just written "sizeof svcs", that is still the size of a pointer to
FILE, not the size of the buffer you are depositing the results in.

- Show quoted text -

Quote:
>                            while ( svcsar[j][0] == '#' ) {
>                                    printf ("service[j][0]: %s\n", svcsar[j]);

>                                    (fgets(svcsar[j], (sizeof(svcs)), host)) ;  
>                            }
>                    printf ("service: %s\n", svcsar[j]);
>                    }
>              }
>  /* this section for allowing commndline overrides; unfinished */
>   while (--argc)
>     {
>       switch (StringCase (*++argv, "-h", argv, "-s", argv, NULL))
>    {
>    case 0:
>      printf ("host filename override:\t");
>      while (fgets(hostname, BUFSIZ, host)) {
>               while (hostname[0] == '#') {
>                    (fgets(hostname, BUFSIZ, host)) ;
>               }
>      }
>    }
>     }
> }/*end main */

> what i want the program to do is read 2 configuration files and print
> their contents without the comments

> the first char array is the hostname
> i want to read it from:

> $ cat /usr/local/etc/anth.host
> # anth.host
> # list hostname here
> zvc.co17.mydomain

> the second is an array of pointers to character arrays
> i want to loop through the index of the array and write the contents
> of

> # anth.svcs
> # list services here
> sshd
> named
> sendmail
> smbd
> dhcpd
> httpd
> xinetd
> crond

> what is happening right now
> the program runs to the point where it enters the while loop and then
> exits.  i put printfs inside the while loop and they print nothing.
> not only this the string "default services: " is where it stops and it
> does not continue until i press Ctl d.  this led me to suspect that it
> is expecting some kind of input from a file or console.  console input
> and ctl d resume the program

> here's the output:
> --
> default hostname:       in

> default services:      

> --
> notice the gap after hostname?
> if i change the fgets statement to
> fgets(hostname, 32, host)
> everything works out.
> it discards the lines beginning in '#' and copies the line with the
> hostname into the hostname variable.

> however i tried this with the services aspect of the program, and this
> did not solve the problem at all.

> i reason that i should be able to use a for statement based on the
> number of newlines in the services configuration file and then read
> each newline that does not begin with a '#' char into the char array
> pointed to by the index [j] which is incremented in the for loop until
> it reaches i (formerly the number of newlines plus 1)

> i must have become tired and missed something because the logic must
> be wrong, since it compiles without warnings.

There might be other problems, but you will get nowhere fast until you
fix those.

And note:  the sizeof operator accepts either the name of a type,
which requires parentheses around the type, or the name of an instance
of a type, in which case no parentheses are required.  In no case is
there ever a reason to put parentheses around the entire expression.

In other words, given:

int i;

You must use parentheses to get sizeof(int).

But the parentheses are optional for either "sizeof i" or "sizeof(i)".

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
--



Fri, 18 Feb 2005 11:41:51 GMT  
 fgets reading a configuration file: compiles OK but output wrong

Quote:

> int main (int argc, char **argv)
> {

>   int      i ;
>   int   j ;
>   int  status;
>   FILE *f1 ;
>      FILE  *host ;
>      FILE  *svcs ;
>   char c;
>   char hostname[64];
>   char svcsar[32][32];

>   f1       =               (fopen("/tmp/ath.tmp", "r+")) ;
>   host     =       (fopen("/usr/local/etc/anth.host", "r")) ;
>   svcs     =       (fopen("/usr/local/etc/anth.svcs", "r")) ;

The extra parentheses around the fopen() call do no harm, but are irrelevant.
You should check that you actually opened the files successfully before using the file
pointers.

Quote:
> /* get hostname from default file *
>  */
> printf ("default hostname:\t");
>      while (fgets(hostname, (sizeof(host)), host)) {

The extra parentheses around sizeof do no harm, but are irrelevant.
You probably intended to write hostname (the array of characters) for the argument to
sizeof -- as it is, you most likely only get 3 (or possibly 7) characters into your buffer.

Quote:
>               while (*hostname == '#') {
>                    (fgets(hostname, (sizeof(host)), host)) ;  
>               }

Your first loop checks for errors and EOF by testing the return value from fgets(); this
inner loop does not and is therefore error prone.  I think you may be better served by
writing "if (*hostname != '#') break;" in place of the loop.  However, you have a problem
with continuations of lines longer than sizeof(host) - 1 (or, once fixed, sizeof(hostname)
- 1) to worry about.  If someone writes an 80-character explanation for something in a
comment, then you will read the first 63 characters, which start with a '#', followed by
the remaining 17 characters of the line plus the newline, which won't start with a '#' but
which aren't the hostname that you're looking for either.   Either increase the size of
hostname to something very large (POSIX 2001 recommends accepting lines up to 2 KB or 4 KB
IIRC - the book's in the office so I can't check here at home), or explicitly deal with
unterminated lines.

What happens if there is more than one hostname entry in the file?  You just ignore the
surplus at the moment.

Quote:
>      }
> printf ("%s\n", hostname);

> /* get list of services
>  */
> printf ("default services:\t");

>              i = (i = (countnl(svcs)) + 1) ;

This is a weird little bit of code, again liberally sprinkled with parentheses that are
not needed.  The double assignment to i is at least redundant; it is arguably invoking
undefined behaviour since assign twice to i between sequence points.

Additionally, what is the specification of countnl()?  It appears to be "read contents of
given file pointer, ignoring lines that start with a '#' and counting those that don't;
then rewind the file so that it can be reused by the main read loop which follows".
That's an ugly mishmash of operations.

Quote:
>              for (j=0; j < i ; j++) {
>                    while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {

Again, you're messing with the size of a FILE * instead of your character arrays.  Just be
careful about what you do use as the argument to sizeof!  The other comments above also
apply.

Quote:
>                            while ( svcsar[j][0] == '#' ) {
>                                    printf ("service[j][0]: %s\n", svcsar[j]);

>                                    (fgets(svcsar[j], (sizeof(svcs)), host)) ;  
>                            }
>                    printf ("service: %s\n", svcsar[j]);
>                    }
>              }
>  /* this section for allowing commndline overrides; unfinished */

Best left out of the example, then...

Quote:
>   while (--argc)
>     {
>       switch (StringCase (*++argv, "-h", argv, "-s", argv, NULL))
>    {
>    case 0:
>      printf ("host filename override:\t");
>      while (fgets(hostname, BUFSIZ, host)) {
>               while (hostname[0] == '#') {
>                    (fgets(hostname, BUFSIZ, host)) ;
>               }
>      }
>    }
>     }
> }/*end main */

It's a good idea, even in trivial programs, to close resources you open.  You opened three
files; close them before you exit.  IIRC, the o/s on the Amiga computers did not release
things for you when a program terminated, so if the program had grabbed a resource such as
memory and did not release it before exiting, that resource was lost until the machine was
rebooted.  Modern o/s are better at cleaning up behind you, but it is still good practice.

- Show quoted text -

Quote:
> what i want the program to do is read 2 configuration files and print
> their contents without the comments

> the first char array is the hostname
> i want to read it from:

> $ cat /usr/local/etc/anth.host
> # anth.host
> # list hostname here
> zvc.co17.mydomain

> the second is an array of pointers to character arrays
> i want to loop through the index of the array and write the contents
> of

> # anth.svcs
> # list services here
> sshd
> named
> sendmail
> smbd
> dhcpd
> httpd
> xinetd
> crond

> what is happening right now
> the program runs to the point where it enters the while loop and then
> exits.  i put printfs inside the while loop and they print nothing.

Which while loop - there are a lot of them.  Presumably, the first...
If you don't terminate output with a newline, there's no guarantee that the information
will be flushed; in fact, even if you do add a newline, there's no guarantee.  Either use
fflush(stdout) or fflush(0) to ensure the output.  Or do your fprintfs() to stderr, which
is usually unbuffered so what you write appears immediately.

- Show quoted text -

Quote:
> not only this the string "default services: " is where it stops and it
> does not continue until i press Ctl d.  this led me to suspect that it
> is expecting some kind of input from a file or console.  console input
> and ctl d resume the program

> here's the output:
> --
> default hostname:       in

> default services:      

> --
> notice the gap after hostname?
> if i change the fgets statement to
> fgets(hostname, 32, host)
> everything works out.

Using sizeof() is good, but use the sizeof the correct object...

Quote:
> it discards the lines beginning in '#' and copies the line with the
> hostname into the hostname variable.

> however i tried this with the services aspect of the program, and this
> did not solve the problem at all.

> i reason that i should be able to use a for statement based on the
> number of newlines in the services configuration file and then read
> each newline that does not begin with a '#' char into the char array
> pointed to by the index [j] which is incremented in the for loop until
> it reaches i (formerly the number of newlines plus 1)

> i must have become tired and missed something because the logic must
> be wrong, since it compiles without warnings.

--
Jonathan Leffler                   #include <disclaimer.h>

Guardian of DBD::Informix 1.00.PC2 -- http://dbi.perl.org/
--



Fri, 18 Feb 2005 11:42:04 GMT  
 fgets reading a configuration file: compiles OK but output wrong
On Wed, 28 Aug 2002 12:26:38 -0700, Dimitar Haralanov

Quote:

>    The fgets(hostname, (sizeof(host)), host) will ready two characters at
>a time. The reason for this is that sizeof(host) returns not the size of
>the file but rather the size of the pointer 'host', which is 8 bytes (2
>characters).

8 bytes is always 8 characters in C.

<<Remove the del for email>>
--



Fri, 18 Feb 2005 11:42:09 GMT  
 fgets reading a configuration file: compiles OK but output wrong


Quote:
>int main (int argc, char **argv)
>{

>  int       i ;
>  int   j ;
>  int  status;
>  FILE *f1 ;
>      FILE  *host ;
>      FILE  *svcs ;
>  char c;
>  char hostname[64];
>  char svcsar[32][32];

>  f1        =               (fopen("/tmp/ath.tmp", "r+")) ;
>  host      =       (fopen("/usr/local/etc/anth.host", "r")) ;
>  svcs      =       (fopen("/usr/local/etc/anth.svcs", "r")) ;
>/* get hostname from default file *
> */
>printf ("default hostname:\t");
>      while (fgets(hostname, (sizeof(host)), host)) {

You want sizeof hostname for the second parameter.

Quote:
>               while (*hostname == '#') {
>                    (fgets(hostname, (sizeof(host)), host)) ;  

Ditto.

Quote:
>               }
>      }
>printf ("%s\n", hostname);

>/* get list of services
> */
>printf ("default services:\t");

>              i = (i = (countnl(svcs)) + 1) ;
>              for (j=0; j < i ; j++) {
>                    while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {

You want sizeof svcsar[j] for the second parameter.

Quote:
>                            while ( svcsar[j][0] == '#' ) {

Why are you printing out only the first lines that start with #?

Quote:
>                                    printf ("service[j][0]: %s\n", svcsar[j]);

I wonder why you title the output service[j][0].  The j is a constant
which is meaningless to the user and [j][0] implies only one character
but you print a string.  Recommend
        printf("service[%d]: %s\n", j, svcsar[j]);

Quote:

>                                    (fgets(svcsar[j], (sizeof(svcs)), host)) ;  

You want sizeof svcsar[j] for the second parameter and svcs for the
third.

Quote:
>                            }
>                    printf ("service: %s\n", svcsar[j]);
>                    }
>              }

snip rest of code and description

<<Remove the del for email>>
--



Fri, 18 Feb 2005 11:42:12 GMT  
 fgets reading a configuration file: compiles OK but output wrong
in comp.lang.c.moderated i read:

Quote:
>  f1        =               (fopen("/tmp/ath.tmp", "r+")) ;
>  host      =       (fopen("/usr/local/etc/anth.host", "r")) ;
>  svcs      =       (fopen("/usr/local/etc/anth.svcs", "r")) ;

you aren't checking to ensure that these opens all succeeded.

(are you coming from a lisp-ish background?  you seem to use a lot of
parenthesis.)

Quote:
>      while (fgets(hostname, (sizeof(host)), host)) {

this can't possibly be the right thing.  the size you provide to fgets is
the number of bytes it's allowed to write into the buffer (1st parameter).
all of your fgets functions except the last have this problem.

also, when you use fgets you need to check whether the entire line was
read, because fgets can stop early (due to the size limitation).  when this
happens the remainder of the line is still waiting for the next read.

the combination of these two things is what is causing your problem.

also i suggest that you eliminate the nested fgets loops, using a single
loop that contains a test for either of your terminating conditions.

Quote:
>               while (*hostname == '#') {

this is an unusual way to reference the first element of the array.

Quote:
>              i = (i = (countnl(svcs)) + 1) ;

i hope that countnl resets the file's position to where it was before it
counted the number of lines.  but this is more work than is necessary --
just read the lines into your array, skipping comment lines, until you
reach end of file, e.g.,

  int count=0, limit=sizeof array / sizeof array[0];
  while (count < limit
      && 0 != fgets(array[count], sizeof array[count], file))
  {
    /* discard remainder of line if fgets didn't read it all */
    if (0 == strchr(array[count], '\n'))
    {
      int ch;
      while (EOF != (ch=fgetc(file)) && '\n' != ch) {}
    }

    /* if the line isn't a comment then display and count it */
    if ('#' != array[count][0])
    {
      printf("service: %s\n", array[count]);
      count++;
    }
  }

actually you should probably use dynamic memory allocation, but if you
aren't ready to learn that stuff (pointers and realloc) then stick with
these fixed size arrays.

--
bringing you boring signatures for 17 years
--



Fri, 18 Feb 2005 11:42:36 GMT  
 fgets reading a configuration file: compiles OK but output wrong

Quote:

>           FILE  *host ;
>           while (fgets(hostname, (sizeof(host)), host)) {

Why sizeof host?
--



Fri, 18 Feb 2005 11:42:38 GMT  
 fgets reading a configuration file: compiles OK but output wrong

Quote:

> int main (int argc, char **argv)
> {

>   int      i ;
>   int   j ;
>   int  status;
>   FILE *f1 ;
>      FILE  *host ;
>      FILE  *svcs ;
>   char c;
>   char hostname[64];
>   char svcsar[32][32];

>   f1       =               (fopen("/tmp/ath.tmp", "r+")) ;
>   host     =       (fopen("/usr/local/etc/anth.host", "r")) ;
>   svcs     =       (fopen("/usr/local/etc/anth.svcs", "r")) ;
> /* get hostname from default file *
>  */
> printf ("default hostname:\t");
>      while (fgets(hostname, (sizeof(host)), host)) {
>               while (*hostname == '#') {
>                    (fgets(hostname, (sizeof(host)), host)) ;  
>               }
>      }
> printf ("%s\n", hostname);

> /* get list of services
>  */
> printf ("default services:\t");

>              i = (i = (countnl(svcs)) + 1) ;
>              for (j=0; j < i ; j++) {
>                    while (fgets(svcsar[j], (sizeof(svcs)), svcs)) {
>                            while ( svcsar[j][0] == '#' ) {
>                                    printf ("service[j][0]: %s\n", svcsar[j]);

>                                    (fgets(svcsar[j], (sizeof(svcs)), host)) ;  
>                            }
>  printf ("service: %s\n", svcsar[j]);
>                    }
>              }
>  /* this section for allowing commndline overrides; unfinished */
>   while (--argc)
>     {
>       switch (StringCase (*++argv, "-h", argv, "-s", argv, NULL))
>    {
>    case 0:
>      printf ("host filename override:\t");
>      while (fgets(hostname, BUFSIZ, host)) {
>               while (hostname[0] == '#') {
>                    (fgets(hostname, BUFSIZ, host)) ;
>               }
>      }
>    }
>     }
> }/*end main */

> what i want the program to do is read 2 configuration files and print
> their contents without the comments

> the first char array is the hostname
> i want to read it from:

> $ cat /usr/local/etc/anth.host
> # anth.host
> # list hostname here
> zvc.co17.mydomain

> the second is an array of pointers to character arrays
> i want to loop through the index of the array and write the contents
> of

> # anth.svcs
> # list services here
> sshd
> named
> sendmail
> smbd
> dhcpd
> httpd
> xinetd
> crond

> what is happening right now
> the program runs to the point where it enters the while loop and then
> exits.  i put printfs inside the while loop and they print nothing.
> not only this the string "default services: " is where it stops and it
> does not continue until i press Ctl d.  this led me to suspect that it
> is expecting some kind of input from a file or console.  console input
> and ctl d resume the program

> here's the output:
> --
> default hostname:       in

> default services:      

> --
> notice the gap after hostname?
> if i change the fgets statement to
> fgets(hostname, 32, host)
> everything works out.
> it discards the lines beginning in '#' and copies the line with the
> hostname into the hostname variable.

> however i tried this with the services aspect of the program, and this
> did not solve the problem at all.

> i reason that i should be able to use a for statement based on the
> number of newlines in the services configuration file and then read
> each newline that does not begin with a '#' char into the char array
> pointed to by the index [j] which is incremented in the for loop until
> it reaches i (formerly the number of newlines plus 1)

> i must have become tired and missed something because the logic must
> be wrong, since it compiles without warnings.

# include <stdio.h>
# include <string.h>

char cHost [80+1] ;   /* global variable used */
void alltrim () ;   /* function to trim trailing and leading spaces */

int main (void)
{

 struct struVal {
    char cHostName [80+1] ;   /* to hold hostname */
    char cServiceName [80+1] ;  /* to hold service name */
 } fileVal [25] ; /* array of 25 elements */

  FILE *fpHost = NULL ;  /* host file pointer ... not generic */

  int cnt  = 0 , times = 0 ;

  fpHost = fopen ( "confs.host" , "r" ) ; /* file contains hostname
entries */

  if ( fpHost == NULL ) {
     perror ( "error opening file" ) ;
  }
  else {
    while (1) {
      fgets ( cHost, sizeof (cHost), fpHost ) ;
        if ( !feof (fpHost) ) {
          alltrim (cHost) ;
          if ( strlen (cHost) > 0 ) {
           if ( strncasecmp ( cHost, "#", 1) != 0 )  {
              strcpy ( fileVal [cnt ++ ].cHostName , cHost ) ;
            }  /* strncasecmp () */
           } /* strlen */
          } /* if */
          else {
           break ;
          } /* else */
        } /* end while */
     } /* else */

  fclose ( fpHost ) ;

  for ( times = 0; times  < cnt ; times ++ )
        printf ( " \n confs.host : HostName : %s \n", fileVal
[times].cHostName ) ;
  return (0) ;

Quote:
} /* end of main () */

void alltrim ()
{
   char *ptrHost ;
   int len ;

        for ( ptrHost = cHost ; isspace(*ptrHost)  ; ptrHost ++   )
                        ;
  if ( ( len = strlen (ptrHost) ) != 0 )
           while ( isspace (ptrHost[len-1]) )  
                     len -- ;

  ptrHost [len] = '\0' ;

  strcpy ( cHost, ptrHost ) ;

Quote:
}

-- confs.host contents

  # confs.host
  # list hostname here
zvc.col17.mydomain

# new one
com.sun.java

# end of comments

Tested in gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-81)

Above program just demonstrates for storing a list of 25 entries from
a file. This could be made generic by passing only the filename to the
function. This program can be optimized and made smaller. That
exercise is given to you.

Thanks,
dev
--



Fri, 18 Feb 2005 11:43:39 GMT  
 
 [ 14 post ] 

 Relevant Pages 

1. fgets reading a configuration file:

2. read a file than produce 2 output files(HELP)

3. Reading a file & output a file

4. read a file than produce 2 output files(HELP)

5. reading a configuration file

6. reading in configuration files

7. Reading a configuration file

8. reading a configuration file

9. output file after compiling

10. App Config File - How to get it to output to the bin dir on compile

11. Read command output file

12. Capturing fgets output to array?

 

 
Powered by phpBB® Forum Software