starting into H&S

F

Frank

I'm very pleased with my recent purchase of H&S V. Now that I'm not
eating the money spent, I seem to be able not to starve with a house
full of food.

I was glad to read that H&S has an on-line presence. Does anyone have
an opinion of it? Code examples? Errata? Other goodies?

I always have trouble with control structures when I switch syntaxes.
I'm looking for H&S solns to the following problem. I want this
program to spit back to the command line when argv[1] == 0 . I
believe there exists a solution in standard C.


F:\gfortran\dan>gcc j4.c -Wall -o j.exe

F:\gfortran\dan>j 0 ot3.txt
argv1 is 0
stderr has the following error 0
errno is 0
endp is 003D2445
the pointer char endp, points to [ ]:[0]
all ok

F:\gfortran\dan>type j4.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

int exptab(int n, const char *path)
{FILE *fin, *fout;
char *path_exp,
*exp_suffix = ".exp";
int c, nc;

if(n<0||n>999||path==0||*path==0) return -1;
nc=strlen(path); if(nc<=0||nc>999) return -1;
c =strlen(exp_suffix); if(c <=0||c >999) return -1;
nc+=c;
path_exp = malloc(nc + 1);
if(!path_exp)
{fprintf(stderr, "%s: %s\n", "exptab", "malloc error");
return -1;
}
strcat(strcpy(path_exp, path), exp_suffix);
fout = fopen(path_exp, "w");
free(path_exp);
if(!fout){fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__,
"fopen");
return -1;
}
fin = fopen(path, "r");
if(!fin){fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__,
"fopen");
fclose(fout);
return -1;
}
while( (c=fgetc(fin)) != EOF )
{if(c == '\t')
{nc=n;
while(nc--)
fputc(' ', fout);
}
else fputc(c, fout);
}
c=0;
if( fclose(fin) !=0 ) c=1;
if( fclose(fout)!=0 ) c=1;
return c==1?(fprintf(stderr, "%s(%d): %s\n",
__FILE__, __LINE__,"exptab"),-1):0;

}

/*test*/
#include <errno.h>
int main(int argc, char *argv[])
{long n;
char *endp;
int errnoStrtol;

if(argc != 3){fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return -1;
}
errno=0; endp=argv[1];
n=strtol(argv[1], &endp, 10);
errnoStrtol=errno;

// print some values
printf("argv1 is %ld\n" , n);
fprintf(stderr, "stderr has the following error %d\n ", errnoStrtol);
printf("errno is %d\n" , errnoStrtol);
printf("endp is %p\n" , (void*) endp);
// printf(" endp points to %p\n" , (void*)*endp);
// have no meaning:
// long strtol(char* s, char** whereIn_s, int base);
// strtol has need to change the value in the
// char pointer "endp" for doing that
// i have to pass to strtol the &endp (that is "char**" )
// so it(strtol()function) can change endp with the right value

if(endp!=0)
printf(" the pointer char endp, points to [%c]:[%d]\n" ,
endp[0], (int)endp[0]);
if (endp==argv[1] || // this mens that no number is get
errnoStrtol!=0 || // this means there were error of overflow
n>9999 // number n too big
){//perror("main");
printf("Errore nell'inserimento dell'input\n");
return EXIT_FAILURE;
}
return exptab( atoi(argv[1]), argv[2])==0?
(printf("all ok\n"), 0): EXIT_FAILURE;
}

// gcc j4.c -Wall -o j.exe

F:\gfortran\dan>

So, with the above input:

F:\gfortran\dan>j 0 ot3.txt

I'd like the program control to go through stderr, then ffprintf to
stderr "do you really want to erase the tabs completely (Y/N)?", then
pop me back to command line.

What I can't see here I think I can express through 2 questions:

q1) If I want the comman line back, do I send a system command with
nothing in it?

q2) How does a c program remember previous data on argv?

For the sake of topicality I'd like to keep the notation consistent
with H&S V. Thanks for your comment,
 
F

Flash Gordon

Frank wrote:

I always have trouble with control structures when I switch syntaxes.
I'm looking for H&S solns to the following problem. I want this
program to spit back to the command line when argv[1] == 0 . I
believe there exists a solution in standard C.

What do you meant by, spit back the command line? If you meant print the
command as entered by the user, that is not, in general, possible. If
you mean print out the arguments provided to the program, that is easy,
just print them out!

int exptab(int n, const char *path)
{FILE *fin, *fout;
char *path_exp,
*exp_suffix = ".exp";
int c, nc;

if(n<0||n>999||path==0||*path==0) return -1;
nc=strlen(path); if(nc<=0||nc>999) return -1;
c =strlen(exp_suffix); if(c <=0||c >999) return -1;

The above formatting is horrible. You can, of course, format your source
however you want, but I'm not going to bother reading it when the
formatting is that nasty.
nc+=c;
path_exp = malloc(nc + 1);
if(!path_exp)
{fprintf(stderr, "%s: %s\n", "exptab", "malloc error");

Why on earth go to the trouble of using %s and passing string literals?
Far clearer to just use a simple string literal with no format specifiers.

I'd like the program control to go through stderr, then ffprintf to
stderr "do you really want to erase the tabs completely (Y/N)?", then
pop me back to command line.

To return to the command line exit the program.
What I can't see here I think I can express through 2 questions:

q1) If I want the comman line back, do I send a system command with
nothing in it?

What? I seriously cannot see what you are trying to get at. Simply exit
the program in one of the ways you already know.
q2) How does a c program remember previous data on argv?

The same as any other variable or pointer. It stays the same until the
program changes it, and if the program needs the old value then the
programmer has to make sure it will still be available (by copying it,
reversing the change, or simply not changing it).
For the sake of topicality I'd like to keep the notation consistent
with H&S V. Thanks for your comment,

Buy me a copy of H&S V and I'll consider it, until then you will have to
live with me not knowing what terminology they use.
 
B

Barry Schwarz

I'm very pleased with my recent purchase of H&S V. Now that I'm not
eating the money spent, I seem to be able not to starve with a house
full of food.

I was glad to read that H&S has an on-line presence. Does anyone have
an opinion of it? Code examples? Errata? Other goodies?

I always have trouble with control structures when I switch syntaxes.
I'm looking for H&S solns to the following problem. I want this
program to spit back to the command line when argv[1] == 0 . I
believe there exists a solution in standard C.

If argv[1] == 0, then argc must be 1. In that case, there are no
command line arguments (or at least none were passed to your program)
and argv[0] is the only string you have access to. It contains some
implementation specific text that represents the program name but
1 - argv[0][0] will be '\0' if the program name is not available.
2 - it need not be the full path name the user entered.

What exactly do you think standard C can do for you with these
restrictions?
F:\gfortran\dan>gcc j4.c -Wall -o j.exe

F:\gfortran\dan>j 0 ot3.txt
argv1 is 0
stderr has the following error 0
errno is 0
endp is 003D2445
the pointer char endp, points to [ ]:[0]
all ok

F:\gfortran\dan>type j4.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

int exptab(int n, const char *path)
{FILE *fin, *fout;
char *path_exp,
*exp_suffix = ".exp";
int c, nc;

if(n<0||n>999||path==0||*path==0) return -1;
nc=strlen(path); if(nc<=0||nc>999) return -1;
c =strlen(exp_suffix); if(c <=0||c >999) return -1;
nc+=c;
path_exp = malloc(nc + 1);
if(!path_exp)
{fprintf(stderr, "%s: %s\n", "exptab", "malloc error");
return -1;
}

Here you indent the expressions after the if and make things line up
nicely.
strcat(strcpy(path_exp, path), exp_suffix);
fout = fopen(path_exp, "w");
free(path_exp);
if(!fout){fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__,
"fopen");
return -1;
}

Here your formatting for what amounts to the exact same test sucks.


snip what must be the 136th incarnation of this program containing the
same non-portable code as repeatedly commented on.
So, with the above input:

F:\gfortran\dan>j 0 ot3.txt

Do you realize that with this line of invocation, argv[1] != 0? How
does this relate to your question at the beginning?
I'd like the program control to go through stderr, then ffprintf to
stderr "do you really want to erase the tabs completely (Y/N)?", then
pop me back to command line.

By command line do you mean shell? If your program asks a question,
why would you return to the shell without waiting for the answer?
What I can't see here I think I can express through 2 questions:

q1) If I want the comman line back, do I send a system command with
nothing in it?

What do you mean "want the command line back"? Whether the system
function (C doesn't have commands) will accept a null string is system
dependent. If it does accept it, what it does with it is also system
specific. It would be a lot simpler for you test the following code
on your system and see what happens than wait for an irrelevant
response here.
#include <stdlib.h>
#include <stdio.h>
int main(void){
system("");
puts("What happened?");
return 0;
}
q2) How does a c program remember previous data on argv?

If you mean from a previous execution from the program, it doesn't.
You would need to store it someplace that survives after the program
terminates (such as in a file) and then restore it from that place.
For the sake of topicality I'd like to keep the notation consistent
with H&S V. Thanks for your comment,

What is H&S V? Is the notation there any different than the standard?

Speaking of notation you probably meant to ask how to handle
strcmp(argv[1], "0") == 0

Why would you need to get back to the command line to ask the user to
confirm he really meant it? You already coded how to present the
question. You can use one of a number of standard functions to read
the user's response and then take appropriate action.
 
K

Keith Thompson

Flash Gordon said:
Frank wrote: [...]
int exptab(int n, const char *path)
{FILE *fin, *fout;
char *path_exp,
*exp_suffix = ".exp";
int c, nc;

if(n<0||n>999||path==0||*path==0) return -1;
nc=strlen(path); if(nc<=0||nc>999) return -1;
c =strlen(exp_suffix); if(c <=0||c >999) return -1;

The above formatting is horrible. You can, of course, format your
source however you want, but I'm not going to bother reading it when
the formatting is that nasty.
[...]

Agreed.

Frank, if your system has the "indent" command, consider running your
code through something like "indent -kr". Or pick a set of options
that you like. (Read the documentation for "indent" first; by
default, it modifies your source file in place, unlike most Unix
commands which filter input to output.)
 
N

Nick Keighley

Frank wrote:



The above formatting is horrible. You can, of course, format your source
however you want, but I'm not going to bother reading it when the
formatting is that nasty.

I'd format the above something like this

int exptab (int n, const char *path)
{
FILE *fin;
FILE *fout;
char *path_exp;
char *exp_suffix = ".exp";
int c, nc;

if (n < 0 || n > 999 || path == 0 || *path == 0)
return -1;

nc = strlen (path);
if (nc <= 0 || nc > 999)
return -1;

c = strlen (exp_suffix);
if (c <= 0 || c > 999)
return -1;

I'd submit that is a more "idiomatic" and readable layout
 
F

Frank

It shows the lack of command I have over the source if I post like
that. Many times I'll run others' code to figure out aspects of what
I want to be doing. I think you'll find the formatting below more to
your liking.
I'd format the above something like this

int exptab (int n, const char *path)
{
    FILE *fin;
    FILE *fout;
    char *path_exp;
    char *exp_suffix = ".exp";
    int   c, nc;

    if (n < 0 || n > 999 || path == 0 || *path == 0)
        return -1;

    nc = strlen (path);
    if (nc <= 0 || nc > 999)
        return -1;

    c = strlen (exp_suffix);
    if (c <= 0 || c > 999)
        return -1;

I'd submit that is a more "idiomatic" and readable layout

Ok, nick, I just added this to my latest version. I struggled with
Keith's question for a couple hours. My elusary (is that a word?)
goal was to get an indent command in my mingw/gcc install. I'll split
that off into another thread.

The program I have is adaptable to a homecooked version of an indent.
Now that I've been doing it for half a day (while holding up the earth
with my other hand), I realize that it is a logical progression from a
detab program. Here's what I have now:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int main(int argc, char *argv[])
{
int n;
char *endp;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;

path=argv[2];
if (n < 0 || n > 999 || path == 0 || *path == 0)
{
fprintf(stderr, "%s: path failed\n", argv[0]);
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
nc = strlen (path);
if (nc <= 0 || nc > 999)
return EXIT_FAILURE;
c = strlen (exp_suffix);
if (c <= 0 || c > 999)
return EXIT_FAILURE;



if (argc != 3)
{
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0;
n = strtol(argv[1], &endp, 10);
path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp)
{
fprintf(stderr, "%s: %s\n", __func__, "malloc error");
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);
fout = fopen(path_exp, "w");
free(path_exp);

if (!fout)
{
fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__, "fopen");
return EXIT_FAILURE;
}
fin = fopen(path, "r");
if (!fin)
{
fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__, "fopen");
fclose(fout);
return EXIT_FAILURE;
}

// print some values
printf(" argv1 is %d\n" , n);
//fprintf(stderr, " stderr has the following error %d\n ", errno);
//printf(" errno is %d\n" , errno);
printf(" argv2 is %s\n" , path);

fclose(fin);
fclose(fout);
return EXIT_SUCCESS;
}

// gcc bb4.c -Wall -o indent.exe

A couple questions here.
q1) You have a line that is ultimately terminated by a newline. This
line begins with n * m spaces, where m is a natural number and
supplied to this program by argv1. It is the "tab distance." N, in
this case, is how many times you to have to pop out because of curly
braces. For example,

if (n < 0 || n > 999 || path == 0 || *path == 0)
{
fprintf(stderr, "%s: path failed\n", argv[0]);
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}

m=2 for all this code, and n goes from 1 to 2 to 3 then back to 2.

So n*m is the number of spaces that begin the current line. My
question is what to do when I encounter a backslash. I guess I'd be
inclined to treat it like they do with fixed-form fortran. There, the
source begins on the seventh column, and a continuation character at
the end of the previous line and in the 6th column give you a
guaranteed continuation.

So, specifically, would this be a good way to go:

if (n < 0 || n > 999 || path == 0 || *path == 0)
{
fprintf(stderr, "%s: path fai\
\led\n", argv[0]);
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
 
B

Ben Bacarisse

Frank said:
The program I have is adaptable to a homecooked version of an indent.
My
question is what to do when I encounter a backslash. I guess I'd be
inclined to treat it like they do with fixed-form fortran. There, the
source begins on the seventh column, and a continuation character at
the end of the previous line and in the 6th column give you a
guaranteed continuation.

You don't get to choose. To implement an indent program you first
have to study the syntax of C, and a \ at the end of a source line is
treated as if neither it nor the newline were there (the details are
in the standard, but this is the gist of it).
So, specifically, would this be a good way to go:

if (n < 0 || n > 999 || path == 0 || *path == 0)
{
fprintf(stderr, "%s: path fai\
\led\n", argv[0]);
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}

This is wrong if it the output from some form of indent program. The
string has spaces in it along with an invalid escape sequence: \l.
 
F

Frank

The program I have is adaptable to a homecooked version of an indent.
 My
question is what to do when I encounter a backslash.  I guess I'd be
inclined to treat it like they do with fixed-form fortran.  There, the
source begins on the seventh column, and a continuation character at
the end of the previous line and in the 6th column give you a
guaranteed continuation.

You don't get to choose.  To implement an indent program you first
have to study the syntax of C, and a \ at the end of a source line is
treated as if neither it nor the newline were there (the details are
in the standard, but this is the gist of it).
So, specifically, would this be a good way to go:
  if (n < 0 || n > 999 || path == 0 || *path == 0)
    {
      fprintf(stderr, "%s: path fai\
      \led\n", argv[0]);
      fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
      return EXIT_FAILURE;
    }

This is wrong if it the output from some form of indent program.  The
string has spaces in it along with an invalid escape sequence: \l.

I thought C's continuation was like fortran. (??) Alright, so is
this better:

if (!fin)
{
fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__, "fopen");
fclose(f\
out);
return EXIT_FAILURE;
}
 
B

Barry Schwarz

On Mon, 24 Aug 2009 19:30:05 -0700 (PDT), Frank

snip
The program I have is adaptable to a homecooked version of an indent.
Now that I've been doing it for half a day (while holding up the earth
with my other hand), I realize that it is a logical progression from a
detab program. Here's what I have now:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int main(int argc, char *argv[])
{
int n;
char *endp;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;

path=argv[2];
if (n < 0 || n > 999 || path == 0 || *path == 0)

This invokes undefined behavior.
{
fprintf(stderr, "%s: path failed\n", argv[0]);

Since you haven't tried to do anything with any path, this is
obviously out of place. Isn't it about time you started testing your
code before posting it?
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
nc = strlen (path);
if (nc <= 0 || nc > 999)
return EXIT_FAILURE;
c = strlen (exp_suffix);
if (c <= 0 || c > 999)
return EXIT_FAILURE;



if (argc != 3)
{
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);

Doesn't this look a little bit redundant.
return EXIT_FAILURE;
}
errno = 0;
n = strtol(argv[1], &endp, 10);

You don't use endp so including here seems like a waste.
path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp)
{
fprintf(stderr, "%s: %s\n", __func__, "malloc error");
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);
fout = fopen(path_exp, "w");
free(path_exp);

if (!fout)
{
fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__, "fopen");

Wouldn't it be a good idea to indicate which file failed to open?
return EXIT_FAILURE;
}
fin = fopen(path, "r");

As mentioned earlier, you really want to process fin before fout.
if (!fin)
{
fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__, "fopen");
fclose(fout);
return EXIT_FAILURE;
}

// print some values
printf(" argv1 is %d\n" , n);
//fprintf(stderr, " stderr has the following error %d\n ", errno);
//printf(" errno is %d\n" , errno);
printf(" argv2 is %s\n" , path);

fclose(fin);
fclose(fout);
return EXIT_SUCCESS;
}

A text book example of doing something right (cutting and pasting
lines of code from different functions) as opposed to doing the right
thing (writing a function to perform a specific task or even
identifying the task).
 
F

Frank

On Mon, 24 Aug 2009 19:30:05 -0700 (PDT), Frank


snip


The program I have is adaptable to a homecooked version of an indent.
Now that I've been doing it for half a day (while holding up the earth
with my other hand), I realize that it is a logical progression from a
detab program.  Here's what I have now:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
int main(int argc, char *argv[])
{
 int n;
 char *endp;
 FILE *fin, *fout;
 char *path_exp, *exp_suffix = ".exp";
 const char *path;
 int   c, nc;
 path=argv[2];
 if (n < 0 || n > 999 || path == 0 || *path == 0)

This invokes undefined behavior.

Think I got this.
   {
     fprintf(stderr, "%s: path failed\n", argv[0]);

Since you haven't tried to do anything with any path, this is
obviously out of place.  Isn't it about time you started testing your
code before posting it?  

Some of it I don't know how to test for.
     fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
     return EXIT_FAILURE;
   }
 nc = strlen (path);
 if (nc <= 0 || nc > 999)
   return EXIT_FAILURE;
 c = strlen (exp_suffix);
 if (c <= 0 || c > 999)
   return EXIT_FAILURE;
 if (argc != 3)
 {
   fprintf(stderr, "%s: <num> <filename>\n", argv[0]);

Doesn't this look a little bit redundant.
   return EXIT_FAILURE;
 }
 errno = 0;
 n = strtol(argv[1], &endp, 10);

You don't use endp so including here seems like a waste.

Got this, I think.
Wouldn't it be a good idea to indicate  which file failed to open?

Got this.
As mentioned earlier, you really want to process fin before fout.

That seemed really strange to me too.
A text book example of doing something right (cutting and pasting
lines of code from different functions) as opposed to doing the right
thing (writing a function to perform a specific task or even
identifying the task).

I don't know that I agree with this last paragraph in particular, but
I thank you for your comments. I think it's looking pretty good:


F:\gfortran\dan>gcc bb7.c -Wall -o indent.exe

F:\gfortran\dan>indent 5 ot3.txt
argv1 is 5
argv2 is ot3.txt

F:\gfortran\dan>indent 55555555555 ot3.txt
indent: give me a natural number less than 1000

F:\gfortran\dan>indent 5555 ot3.txt
indent: give me a natural number less than 1000

F:\gfortran\dan>indent -7 ot3.txt
indent: give me a natural number less than 1000

F:\gfortran\dan>indent 5 zax
fopen failed to open zax

F:\gfortran\dan>indent 5 5
fopen failed to open 5

F:\gfortran\dan>indent 5 5 5
indent: <num> <filename>

F:\gfortran\dan>type bb7.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int main(int argc, char *argv[])
{
int n;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;

path=argv[2];
if (argc != 3)
{
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0;
n = strtol(argv[1], NULL, 10);
if (n < 0 || n > 999 )
{
fprintf(stderr, "%s: give me a natural number\
less than 1000\n", argv[0]);
return EXIT_FAILURE;
}
nc = strlen (path);
if (nc <= 0 || nc > 999)
{
fprintf(stderr, "%s: nc screwed up\n", argv[0]);
return EXIT_FAILURE;
}
c = strlen (exp_suffix);
path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp)
{
fprintf(stderr, "%s: %s\n", __func__, "malloc error");
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);
fout = fopen(path_exp, "w");
free(path_exp);

fin = fopen(path, "r");
if (!fin)
{
fprintf(stderr, "%s %s\n", "fopen failed to open", argv[2] );
fclose(fout);
return EXIT_FAILURE;
}

if (!fout)
{
fprintf(stderr, "%s \n", "fout failed");
return EXIT_FAILURE;
}


// print some values
printf(" argv1 is %d\n" , n);
printf(" argv2 is %s\n" , path);

fclose(fin);
fclose(fout);
return EXIT_SUCCESS;
}

// gcc bb7.c -Wall -o indent.exe

F:\gfortran\dan>
 
F

Frank

"Frank" <[email protected]> ha scritto nel messaggionews:947edab9-47d0-48eb-8e84-b24a4b59ca5f@t11g2000prh.googlegroups.com...

if you need of questions and answer with the program: the only way is
use stdin and stdout(or stderr)

Right. I'm gonna plead insanity on whatever I was thinking when I
wrote the question. Can you see what I'm doing wrong here?


F:\gfortran\dan>gcc bb8.c -Wall -o indent.exe
bb8.c: In function `main':
bb8.c:88: error: syntax error at end of input

F:\gfortran\dan>type bb8.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int main(int argc, char *argv[])
{
int n, g;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;

path=argv[2];
if (argc != 3)
{
fprintf(stderr, "usage: \n");
fprintf(stderr, "%s <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0;
n = strtod(argv[1], NULL);
if (n < 0 || n > 999 )
{
fprintf(stderr, "%s: give me a natural number\
less than 1000\n", argv[0]);
return EXIT_FAILURE;
}
// if detab
if (n == 0)
{
fprintf(stderr, "this will detab your file");
fprintf(stderr, "If that's what you want, enter zero again");
fprintf(stderr, "To abort, enter anything else");
g = getchar();
if (g == 0)
fprintf(stderr, "detabbing %s \n", argv[2]);
else
{
fprintf(stderr, "Aborting");
return EXIT_FAILURE;
}





nc = strlen (path);
if (nc <= 0 || nc > 999)
{
fprintf(stderr, "%s: nc screwed up\n", argv[0]);
return EXIT_FAILURE;
}
c = strlen (exp_suffix);
path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp)
{
fprintf(stderr, "%s: %s\n", __func__, "malloc error");
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);



fin = fopen(path, "r");
if (!fin)
{
fprintf(stderr, "%s %s\n", "fopen failed to open", argv[2] );
fclose(fout);
return EXIT_FAILURE;
}
fout = fopen(path_exp, "w");
if (!fout)
{
fprintf(stderr, "%s \n", "fout failed");
return EXIT_FAILURE;
}


// print some values and exit
printf(" argv1 is %d\n" , n);
printf(" argv2 is %s\n" , path);
fclose(fin);
fclose(fout);
free(path_exp);
return EXIT_SUCCESS;
}

// gcc bb8.c -Wall -o indent.exe

F:\gfortran\dan>
 
F

Frank

"Frank" <[email protected]> ha scritto nel messaggionews:947edab9-47d0-48eb-8e84-b24a4b59ca5f@t11g2000prh.googlegroups.com...

if you need of questions and answer with the program: the only way is
use stdin and stdout(or stderr)

Right. I'm gonna plead insanity on whatever I was thinking when I
wrote the question. Can you see what I'm doing wrong here?


F:\gfortran\dan>gcc bb8.c -Wall -o indent.exe
bb8.c: In function `main':
bb8.c:88: error: syntax error at end of input

F:\gfortran\dan>type bb8.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int main(int argc, char *argv[])
{
int n, g;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;

path=argv[2];
if (argc != 3)
{
fprintf(stderr, "usage: \n");
fprintf(stderr, "%s <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0;
n = strtod(argv[1], NULL);
if (n < 0 || n > 999 )
{
fprintf(stderr, "%s: give me a natural number\
less than 1000\n", argv[0]);
return EXIT_FAILURE;
}
// if detab
if (n == 0)
{
fprintf(stderr, "this will detab your file");
fprintf(stderr, "If that's what you want, enter zero again");
fprintf(stderr, "To abort, enter anything else");
g = getchar();
if (g == 0)
fprintf(stderr, "detabbing %s \n", argv[2]);
else
{
fprintf(stderr, "Aborting");
return EXIT_FAILURE;
}





nc = strlen (path);
if (nc <= 0 || nc > 999)
{
fprintf(stderr, "%s: nc screwed up\n", argv[0]);
return EXIT_FAILURE;
}
c = strlen (exp_suffix);
path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp)
{
fprintf(stderr, "%s: %s\n", __func__, "malloc error");
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);



fin = fopen(path, "r");
if (!fin)
{
fprintf(stderr, "%s %s\n", "fopen failed to open", argv[2] );
fclose(fout);
return EXIT_FAILURE;
}
fout = fopen(path_exp, "w");
if (!fout)
{
fprintf(stderr, "%s \n", "fout failed");
return EXIT_FAILURE;
}


// print some values and exit
printf(" argv1 is %d\n" , n);
printf(" argv2 is %s\n" , path);
fclose(fin);
fclose(fout);
free(path_exp);
return EXIT_SUCCESS;
}

// gcc bb8.c -Wall -o indent.exe

F:\gfortran\dan>
 
I

Ike Naar

Right. I'm gonna plead insanity on whatever I was thinking when I
wrote the question. Can you see what I'm doing wrong here?

F:\gfortran\dan>gcc bb8.c -Wall -o indent.exe
bb8.c: In function `main':
bb8.c:88: error: syntax error at end of input

F:\gfortran\dan>type bb8.c
[...]
// if detab
if (n == 0)
{

^
This opening brace has no matching closing brace.
fprintf(stderr, "this will detab your file");
fprintf(stderr, "If that's what you want, enter zero again");
fprintf(stderr, "To abort, enter anything else");
g = getchar();
if (g == 0)
fprintf(stderr, "detabbing %s \n", argv[2]);
else
{
fprintf(stderr, "Aborting");
return EXIT_FAILURE;
}
 
B

Ben Bacarisse

Frank said:
I thought C's continuation was like fortran. (??)

I don't know modern Fortran, but C has always permitted free-form
layout, so \ at the end of a line plays a very limited role. About
the place you are likely to see it used is in multi-line macros.
Alright, so is this better:

if (!fin)
{
fprintf(stderr, "%s(%d): %s\n", __FILE__, __LINE__, "fopen");
fclose(f\
out);
return EXIT_FAILURE;
}

That's syntactically correct, though why one would ever write it is
not clear.
 
I

Ike Naar


In my experience, when a compiler diagnoses a syntax error at end-of-input,
it's often because of an unmatched parenthesis/bracket/brace,
an unclosed comment, a missing end-quote in a string literal, or
something similar.
You sometimes have to scan the entire program text to find the culprit :-(
Gosh, you'd think gcc.exe could say "you're missing a right curly brace."

It could; or it could say "syntax error at end of input" because it
detected end-of-input where it did not expect it ;-)

When a program has a syntax error, it is easy to detect that *something*
is wrong, but hard to guess correctly *what* is the underlying cause.

Take, for instance, the malformed expression:

(x+)

Scanning the expression from left to right, when you reach the ')' you
know something is wrong, and you can print a diagnostic: "syntax error at ')'".
But is it wrong because:
- the '+' should not have been there?
(author intended to write "(x)" but accidently added the '+')
- an operand is missing between the '+' and the ')'?
(author intended "(x+y)" but forgot the 'y').
- the operator is misspelled?
(author intended "(x++)").
- the ')' is misspelled?
(author wanted "(x+(whatever" but mis-typed the second '(' as ')').
In each case, a better diagnostic could be given than the neutral
"syntax error at ')'", but you would have to know more about
the author's intentions in order to make the best choice. And if you
guess wrong, the "improved" diagnostic will be more confusing than helpful.
So, to play safe, it's sometimes better to stick to the neutral diagnostic.
 
B

Barry Schwarz

Frank said:
I'd like the program control to go through stderr, then ffprintf to
stderr "do you really want to erase the tabs completely (Y/N)?", then
pop me back to command line.

it is possible to write a function that gets from stdin the answer
of question of kind (Yes/No or Si/No)

// 1==si 0==no (oppure qualunque altra cosa diversa da " s " o " S ")
int ChiediSiNo(void)
{char tmp[256], *p;

if( getStdI(tmp, 128) == -1 )

Why not follow an existing convention and check for EOF instead of -1?
return 0;

Is "no" the correct response when an I/O error occurs or the response
is missing?
p=tmp;
while(Isspace_m((unsigned char)*p)) ++p;
if( (*p=='s'||*p=='S') &&
(p[1]==0||Isspace_m((unsigned char)p[1])

So "no" is the desired response when the user enters "Si"?
 
B

Barry Schwarz

On Mon, 24 Aug 2009 22:28:26 -0700 (PDT), Frank

snip
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int main(int argc, char *argv[])
{
int n;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;

path=argv[2];
if (argc != 3)
{
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0;
n = strtol(argv[1], NULL, 10);
if (n < 0 || n > 999 )
{
fprintf(stderr, "%s: give me a natural number\
less than 1000\n", argv[0]);

As a matter of style, you may want to take advantage of the C
automatic string literal concatenation in source code with
fprintf(stderr, "%s: give me a natural number"
" less than 1000\n", argv[0]);
Note the absence of the \ and the fact that each line contains a
complete literal. The quantity and type of white space between the
closing quote on the first literal and the opening quote of the second
literal is irrelevant.

It can eliminate a lot of problems when pasting code into a Usenet
message and also provides greater flexibility (such as comments at the
end of the first line).
return EXIT_FAILURE;
}
nc = strlen (path);
if (nc <= 0 || nc > 999)

While the < does not introduce an error, it does indicate you are
unfamiliar (or at least uncomfortable) with the fact that size_t is
unsigned.

Why do you care if nc > 999?
{
fprintf(stderr, "%s: nc screwed up\n", argv[0]);

Wouldn't it be nice to tell the user what path pointed to so he could
see his mistake?
return EXIT_FAILURE;
}
c = strlen (exp_suffix);

Why did you calculate c if you don't use it.
path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);

Both calls to strlen are redundant. Since you saved the values from
the previous calls in nc and c ...
if (!path_exp)
{
fprintf(stderr, "%s: %s\n", __func__, "malloc error");

You continue to use %s for string literals when it would be easier and
more efficient to simply include the literal in the format string
directly.
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);

Have you considered using sprintf?
fout = fopen(path_exp, "w");
free(path_exp);

fin = fopen(path, "r");
if (!fin)
{
fprintf(stderr, "%s %s\n", "fopen failed to open", argv[2] );
fclose(fout);

This leaves an empty output file on your system. You should not open
fout until you know fin is good.
return EXIT_FAILURE;
}

if (!fout)
{
fprintf(stderr, "%s \n", "fout failed");

And if you follow that advice, you would fclose fin here.
 
B

Barry Schwarz

"Frank" <[email protected]> ha scritto nel messaggionews:947edab9-47d0-48eb-8e84-b24a4b59ca5f@t11g2000prh.googlegroups.com...

if you need of questions and answer with the program: the only way is
use stdin and stdout(or stderr)

Right. I'm gonna plead insanity on whatever I was thinking when I
wrote the question. Can you see what I'm doing wrong here?


F:\gfortran\dan>gcc bb8.c -Wall -o indent.exe
bb8.c: In function `main':
bb8.c:88: error: syntax error at end of input

F:\gfortran\dan>type bb8.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

int main(int argc, char *argv[])
{
int n, g;
FILE *fin, *fout;
char *path_exp, *exp_suffix = ".exp";
const char *path;
int c, nc;

path=argv[2];
if (argc != 3)
{
fprintf(stderr, "usage: \n");
fprintf(stderr, "%s <num> <filename>\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0;
n = strtod(argv[1], NULL);

You are just posting code at random. Why did you change strtol to
strtod when you are expecting an integer value?
if (n < 0 || n > 999 )
{
fprintf(stderr, "%s: give me a natural number\
less than 1000\n", argv[0]);
return EXIT_FAILURE;
}
// if detab
if (n == 0)
{
fprintf(stderr, "this will detab your file");
fprintf(stderr, "If that's what you want, enter zero again");
fprintf(stderr, "To abort, enter anything else");
g = getchar();
if (g == 0)

If the user types the number 0, this test will fail. Try to remember
that 0 is not the same as '0'.
fprintf(stderr, "detabbing %s \n", argv[2]);
else
{
fprintf(stderr, "Aborting");
return EXIT_FAILURE;
}





nc = strlen (path);
if (nc <= 0 || nc > 999)
{
fprintf(stderr, "%s: nc screwed up\n", argv[0]);
return EXIT_FAILURE;
}
c = strlen (exp_suffix);
path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp)
{
fprintf(stderr, "%s: %s\n", __func__, "malloc error");
return EXIT_FAILURE;
}
strcat(strcpy(path_exp, path), exp_suffix);



fin = fopen(path, "r");
if (!fin)
{
fprintf(stderr, "%s %s\n", "fopen failed to open", argv[2] );
fclose(fout);

This invokes undefined behavior.
return EXIT_FAILURE;
}
fout = fopen(path_exp, "w");
if (!fout)
{
fprintf(stderr, "%s \n", "fout failed");

You forgot to fclose fin.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top