[comp.sys.amiga.tech] feof does not work: HELP!

ptavoly@cs.ruu.nl (Peter Tavoly) (11/30/90)

I've got a weird problem, it'll probably again be nothing, but still,
I thought I could bother you with it.

Here is my tiny weeny little program (I suggest you read the text below first
                                      it's a bit longish but manageable):

    1  #include "stdlib.h"
    2  #include "stdio.h"
    3  
    4  void load (void);
    5  void save (void);
    6  void menu (void);
    7  
    8  FILE *in, *out;
    9  int y, choice;
   10  char ch, line[20][74];  /* max. 20 lines of each max. 74 chars */
   11  
   12  void main (int argc, char *argv[])
   13  {
   14  
   15  if (argc!=3) { printf ("\n) 1990 by Thomas Tavoly\n\n");
   16   printf ("USAGE: %s input-file output-file\n\n",argv[0]);
   17   exit (0); }
   18  
   19  if ((in=fopen (argv[1],"r"))==NULL) {
   20   printf ("\nCould not open input-file\n\n");
   21   exit (1); }
   22  
   23  y=0;
   24  load(); /* open specified input-file and read stuff */
   25  fclose (in);
   26  menu(); /* choose from input supplied by specified input-file */
   27  
   28  if ((out=fopen (argv[2],"w"))==NULL) {
   29   printf ("\nCould not open output-file\n\n");
   30   exit (1); }
   31  
   32  save(); /* output selected item to target-file */
   33  fclose (out);
   34  
   35  } /* main */
   36  
   37  void load (void)
   38  {
   39  
   40  while (!feof(in))        /* <- this is where the trouble starts :( */
   41   {
   42    printf ("%2d. ",y+1);        /* print line number */
   43    while ((ch=fgetc (in))!='@') /* read until separator encountered */
   44     putchar (ch);               /* and output characters one by one */
   45    printf ("\n");               /* next line (if any) */
   46    fgets (line [y],74,in);      /* read rest of line for later use */
   47   if (feof(in)) return;
   48   y++;
   49   } /* while */
   50  } /* load */
   51  
   52  void save (void)
   53  {
   54  
   55  fputs (line [y],out);
   56  
   57  } /* save */
   58  
   59  void menu (void)
   60  {
   61  
   62  do {
   63   printf ("\nYour choice: ");
   64   scanf ("%d", &choice);
   65   } while ((choice < 0) || (choice > y+1));
   66  if (choice == 0) exit (0);
   67  
   68  } /* menu */

Usage: program input_file output_file
for example: program s:choice.txt ram:temp.script

The program is supposed to read a textfile, formatted in the following
way (this is just an arbitrary example):

Pack it with PowerPacker 2.3b@SYS:ppacker2.3b
Install C compiler in RAM:@execute s:C-startup
Start up Moria@execute WB1.3:s/Moria.startup
Load the Workbench@loadwb

Where all lines are apart on a single line terminated only by one newline
as you would get when you typed this in ed.

The first part of the line (up to the @) is output to the screen with
a line number in front of it, starting with 1.

The second part of the line (the separating @ is discarded) is put into a
predefined array, for later use.

Thus you would see on screen when the program is started up:

 1. Pack it with PowerPacker 2.3b
 2. Install C compiler in RAM:
 3. Start up Moria
 4. Load the Workbench

The temporary array contains the following:

line[0][] = "ppacker2.3b"
line[1][] = "execute s:C-startup"
line[2][] = "execute WB1.3:s/Moria.startup"
line[3][] = "loadwb"

Then the following line is displayed:

Your choice:

Now you can choose from either one of the four above or type a zero (all
followed by return) to end the program. According to your choice one of the
elements of the array is selected and output to the destination file.
E.g. type 3 and the file specified on the command line as the destination
file will contain this line:

execute WB1.3:s/Moria.startup

The program then ends and you can execute the destination file as you
would do with a script. (Yes, I heard of more 'stylish' ways of doing this,
but I'm not an ace in C yet :)

Purpose of this all: to put this program in the startup-sequence and let
the user choose one of several programs that can then be run, easily
configured through a text file that can be changed by any user without
programming knowledge (Later enhancements could include an Intuition
interface, as soon as I can get my hands on a good book about Intuition.
Can anyone suggest a good one? I know of other (PD?) programs that already
do this, does anyone know where I can find them (Fish xxx)?


Now the problem is that AztecC 5.0a somehow doesn't recognize the 'feof'
in lines 40 and 47. The result of this is that the loop in lines 43-44
will continue forever because the '@' will never be found, since there is
none on a new line, however the program keeps printing the character 255
(an y with an umlaut on top) endlessly.

I could try to look for a character 255 but this is not a nice way, and
suppose that this character appears in your text, (as in Queensryche..:).
In case of binaries it is even more likely to appear.

What am I forgetting? Is this a 5.0a bug or is there some #include or
#define missing? Note, that I did not yet buy the compiler, are later
versions any better (5.Xx?) ? How about Lattice? Come on owners, this is
your chance to convince a potential buyer :)


On a different note: there are now three different views on which compiler
is better:

1. Lattice, since a lot of known developers work with it.
2. Manx Aztec, since it is (according to some) more professional (?).
3. It seems Lattice is seen better in the US, but Aztec is used more widely
in Europe.

What's your view?

Please respond by mail, this has been posted through my brother's account
as well. I have not much possibility to read mail regularly either..

 Thomas Tavoly@connected to an ANCIENT Prime terminal on 1200 bps...:(

peter@sugar.hackercorp.com (Peter da Silva) (12/01/90)

In article <4413@ruuinf.cs.ruu.nl> ptavoly@cs.ruu.nl (Peter Tavoly) writes:
>    40  while (!feof(in))        /* <- this is where the trouble starts :( */
>    41   {
>    42    printf ("%2d. ",y+1);        /* print line number */
>    43    while ((ch=fgetc (in))!='@') /* read until separator encountered */
                      ^^^^^
What happens if you hit EOF here?

After reading the final line you're going to sit in an infinite loop comparing
EOF with '@'. The simplest fix is to insert "!feof(in) && " before "(ch=fgetc",
but I'd read the whole line into memory and manipulate it there. Not quite as
efficient, maybe, but I/O time is likely to dominate in this application.
-- 
Peter da Silva.   `-_-'
<peter@sugar.hackercorp.com>.

andrew@teslab.lab.OZ (Andrew Phillips) (12/10/90)

In article <4413@ruuinf.cs.ruu.nl> ptavoly@cs.ruu.nl (Peter Tavoly) writes:
>   40  while (!feof(in))        /* <- this is where the trouble starts :( */
>   41   {

>   43    while ((ch=fgetc (in))!='@') /* read until separator encountered */
>   44     putchar (ch);               /* and output characters one by one */

>   46    fgets (line [y],74,in);      /* read rest of line for later use */
>   47   if (feof(in)) return;

>   49   } /* while */

>Now the problem is that AztecC 5.0a somehow doesn't recognize the 'feof' ...

Your trouble is that feof() does not return 1 until after you try
reading PAST the end of file.  So feof(in) is not true until after
you read the first character of the next line (assuming you have a
line-feed at the end of the last line of your file).

>... however the program keeps printing the character 255
>(an y with an umlaut on top) endlessly.

>I could try to look for a character 255 but this is not a nice way, and
>suppose that this character appears in your text, (as in Queensryche..:).
>In case of binaries it is even more likely to appear.

The character 255 comes from fgetc() returning -1 (fgetc returns an
INT) to indicate eof (or error) and this being converted to a char
when assigned to ch.  It would be safer to make ch an int and check
for ch being -1 after each call to fgetc().

So I would say that Aztec C feof() is OK, although I haven't bothered
to test it.

Andrew.
-- 
Andrew Phillips (andrew@teslab.lab.oz.au) Phone +61 (Aust) 2 (Sydney) 289 8712