detabbing again

B

Ben Bacarisse

Frank said:
I think this is relevant to LCB's code:

n = strtol(argv[1], &endp, 10);
if (n == LONG_MIN || n == LONG_MAX){
perror(__func__);
return -1;
}

The strtol, strtoll, strtoul, and strtoull functions return the
converted
value, if any. If no conversion could be performed, zero is returned.
If the correct value
is outside the range of representable values, LONG_MIN, LONG_MAX,
LLONG_MIN,
LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the
return type
and sign of the value, if any), and the value of the macro ERANGE is
stored in errno.

It would seem that strtol is within its right to return LLONG_MIN.

strtoll is but not strtol.
I think this code needs > and < where it now has equals.

Why? The code is trying to test for an error which. What it needs is
a better test since LONG_M(IN|AX) are perfectly correct conversion
results. The code should really test errno rather than the return
value.

I'd make 'n' long and use:

errno = 0;
n = strtol(argv[1], &endp, 10);
if (endp == argv[1] || errno)
/* there was an error */

If you want a stricter test, use:

if (*endp || errno)

The first will accept "42 green bottles" but the second won't.

<snip>
 
B

Ben Bacarisse

Richard Heathfield said:
Frank said:

[Keith answered that i the text you quote, BTW]
Pointer to pointer to char.

In conversation, I say "pointer to char pointer", and in my head I
never bother with the "to" -- there are "char pointer pointers".
 
D

Dik T. Winter

> But it's safe to assume that LONG_MIN is either -LONG_MAX or
> -LONG_MAX-1, i.e., the assymetry is at most one extra negative value.
>
> Practically all systems these days use 2's-complement representation
> for signed integers and therefore have these non-symmetric ranges.

No need for the "therefore". I know of at least one system where the
negative largest value is actually a trap representation.
 
F

Frank

I think this is relevant to LCB's code:
    n = strtol(argv[1], &endp, 10);
    if (n == LONG_MIN || n == LONG_MAX){
        perror(__func__);
        return -1;
    }
The strtol, strtoll, strtoul, and strtoull functions return the
converted
value, if any. If no conversion could be performed, zero is returned.
If the correct value
is outside the range of representable values, LONG_MIN, LONG_MAX,
LLONG_MIN,
LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the
return type
and sign of the value, if any), and the value of the macro ERANGE is
stored in errno.
It would seem that strtol is within its right to return LLONG_MIN.

strtoll is but not strtol.

I suppose strtol would have no way to represent LLONG_MIN if n is a
long.
 I think this code needs > and < where it now has equals.

Why?  The code is trying to test for an error which.  What it needs is
a better test since LONG_M(IN|AX) are perfectly correct conversion
results.  The code should really test errno rather than the return
value.

I'd make 'n' long and use:

    errno = 0;
    n = strtol(argv[1], &endp, 10);
    if (endp == argv[1] || errno)
        /* there was an error */

I can't quite get my head around this. Maybe we could talk through
some cases.

case 1) 5 || 223

this is an example of "well-formed" input for argv[1], and 223 is a
typical errno that my implentation throws. Why would endp equal one
in this situation?

case 2) 0 || 0

If endp == zero then the test condition is true. I think we want to
test argv[1] to see if it is zero and spit this case back to the user
and say "Do you really want to take the tabs out altogether?"
If you want a stricter test, use:

   if (*endp || errno)

The first will accept "42 green bottles" but the second won't.

Again, I'm fuzzy about what this means. It compiles, but I'd say it's
still a bit wonky in behavior:

F:\gfortran\dan>gcc k3.c -Wall -o k.exe

F:\gfortran\dan>k 42 ot3.txt

F:\gfortran\dan>k 55555555555555 ot3.txt
main: Result too large

F:\gfortran\dan>k 43r ot3.txt
main: No error

F:\gfortran\dan>k 5 zax.txt
k3.c(27): fopen

F:\gfortran\dan>k 5y zax.txt
main: No error

F:\gfortran\dan>type k3.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;
const int cn = n;

path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp){
fprintf(stderr, "%s: %s\n", __func__, "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");
return -1;
}
while ((c=fgetc(fin)) != EOF){
n = cn;
if (c == '\t') while (n--) fputc(' ', fout);
else fputc(c, fout);
}
fclose(fin);
fclose(fout);
return 0;

}

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

if (argc != 3){
fprintf(stderr, "%s: <num> <filename>\n", argv[0]);
return -1;
}
errno = 0;
n = strtol(argv[1], &endp, 10);
if (*endp || errno){
perror(__func__);
return -1;
}
if (*endp != '\0'){
fprintf(stderr, "%s: %s\n", __func__, "strtol error");
return -1;
}
exptab(atoi(argv[1]), argv[2]);
return 0;
}

// gcc k3.c -Wall -o k.exe

F:\gfortran\dan>
 
B

Ben Bacarisse

Frank said:
I think this is relevant to LCB's code:
    n = strtol(argv[1], &endp, 10);
    if (n == LONG_MIN || n == LONG_MAX){
        perror(__func__);
        return -1;
    }
The strtol, strtoll, strtoul, and strtoull functions return the
converted
value, if any. If no conversion could be performed, zero is returned.
If the correct value
is outside the range of representable values, LONG_MIN, LONG_MAX,
LLONG_MIN,
LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the
return type
and sign of the value, if any), and the value of the macro ERANGE is
stored in errno.
It would seem that strtol is within its right to return LLONG_MIN.

strtoll is but not strtol.

I suppose strtol would have no way to represent LLONG_MIN if n is a
long.

It wouldn't even if n were long long. It could represent it but it
couldn't return it. It is the return type of strtol that is key here.
 I think this code needs > and < where it now has equals.

Why?  The code is trying to test for an error which.  What it needs is
a better test since LONG_M(IN|AX) are perfectly correct conversion
results.  The code should really test errno rather than the return
value.

I'd make 'n' long and use:

    errno = 0;
    n = strtol(argv[1], &endp, 10);
    if (endp == argv[1] || errno)
        /* there was an error */

I can't quite get my head around this. Maybe we could talk through
some cases.

case 1) 5 || 223

this is an example of "well-formed" input for argv[1], and 223 is a
typical errno that my implentation throws. Why would endp equal one
in this situation?

Why indeed? I don't understand any of this. errno is not "thrown"
and the numbers don't matter. What does "5 || 223" mean?
case 2) 0 || 0

If endp == zero then the test condition is true. I think we want to
test argv[1] to see if it is zero and spit this case back to the user
and say "Do you really want to take the tabs out altogether?"

Same here. I have no idea what you are talking about. Why not give
an example call and talk about the effect it has?
Again, I'm fuzzy about what this means. It compiles, but I'd say it's
still a bit wonky in behavior:

F:\gfortran\dan>gcc k3.c -Wall -o k.exe

F:\gfortran\dan>k 42 ot3.txt

F:\gfortran\dan>k 55555555555555 ot3.txt
main: Result too large

I did not use perror in my example; perror only makes sense if errno
is non-zero. My stricter test requires different error handling
because some of the errors are not indicated using errno.

Note the original code is also wrong in that an argument of LONG_MAX
will cause perror to be called when there is no error to explain.

<snip code>
 
F

Frank

Why indeed?  I don't understand any of this.  errno is not "thrown"
and the numbers don't matter.  What does "5 || 223" mean?

I try to illustrate here:

F:\gfortran\dan>gcc k4.c -Wall -o k.exe

F:\gfortran\dan>k 5 ot3.txt
argv1 is 5
errno is 0

F:\gfortran\dan>k 5 zax.txt
argv1 is 5
errno is 0
k4.c(27): fopen

F:\gfortran\dan>k 5555555555 ot3.txt
argv1 is 2147483647
errno is 34
main: Result too large

F:\gfortran\dan>type k4.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;
const int cn = n;

path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp){
fprintf(stderr, "%s: %s\n", __func__, "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");
return -1;
}
while ((c=fgetc(fin)) != EOF){
n = cn;
if (c == '\t') while (n--) fputc(' ', fout);
else fputc(c, fout);
}
fclose(fin);
fclose(fout);
return 0;

}

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

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

// print some values
printf(" argv1 is %ld\n" , n);
printf(" errno is %d\n" , errno);



if (*endp || errno){
perror(__func__);
return -1;
}
if (*endp != '\0'){
fprintf(stderr, "%s: %s\n", __func__, "strtol error");
return -1;
}
exptab(atoi(argv[1]), argv[2]);
return 0;
}

// gcc k4.c -Wall -o k.exe

F:\gfortran\dan>
case 2) 0 || 0
If endp == zero then the test condition is true.  I think we want to
test argv[1] to see if it is zero and spit this case back to the user
and say "Do you really want to take the tabs out altogether?"

Same here.  I have no idea what you are talking about.  Why not give
an example call and talk about the effect it has?

I claim that "well-formed" user responses for argv1 are the natural
numbers. If your logic consists or n || m, where n is in the
naturals, then only zero reverses the outcome, given m. I think we
need to split this case off.
I did not use perror in my example; perror only makes sense if errno
is non-zero.  My stricter test requires different error handling
because some of the errors are not indicated using errno.
ok

Note the original code is also wrong in that an argument of LONG_MAX
will cause perror to be called when there is no error to explain.

right. I understand this. So dealing with the return value of strtol
won't compare it against an integer that exists in its range already.
 
B

Ben Bacarisse

Frank said:
I try to illustrate here:

F:\gfortran\dan>gcc k4.c -Wall -o k.exe

F:\gfortran\dan>k 5 ot3.txt
argv1 is 5
errno is 0

F:\gfortran\dan>k 5 zax.txt
argv1 is 5
errno is 0
k4.c(27): fopen

F:\gfortran\dan>k 5555555555 ot3.txt
argv1 is 2147483647
errno is 34
main: Result too large

There is a technical problem with the code (see below) but so far all
these are as I would expect. Did you have a question about them?

errno = 0;
n = strtol(argv[1], &endp, 10);

// print some values
printf(" argv1 is %ld\n" , n);
printf(" errno is %d\n" , errno);

Calling printf can loose the value of errno. It can be set to non-zero
by printf even if printf succeeds because printf does not document the
use of errno. You have to test immediately, though most systems are
helpful and I don't think anything is going wrong because of this.

case 2) 0 || 0
If endp == zero then the test condition is true.  I think we want to
test argv[1] to see if it is zero and spit this case back to the user
and say "Do you really want to take the tabs out altogether?"

Same here.  I have no idea what you are talking about.  Why not give
an example call and talk about the effect it has?

I claim that "well-formed" user responses for argv1 are the natural
numbers. If your logic consists or n || m, where n is in the
naturals, then only zero reverses the outcome, given m. I think we
need to split this case off.

What are you talking about? My logic tests *endp (or endp == argv[1])
and errno. What has n got to do with it? What is m?
right. I understand this. So dealing with the return value of strtol
won't compare it against an integer that exists in its range
already.

I am glad you understand, but I can't unravel your last sentence. If
it is your wording of what I said then it doesn't matter -- I don't
need to follow it.
 
B

Barry Schwarz

On Tue, 18 Aug 2009 16:38:59 -0700 (PDT), Frank

snip
F:\gfortran\dan>type k4.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;
const int cn = n;

path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp){
fprintf(stderr, "%s: %s\n", __func__, "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");

You need to fclose fout here.
return -1;
}
while ((c=fgetc(fin)) != EOF){
n = cn;
if (c == '\t') while (n--) fputc(' ', fout);
else fputc(c, fout);
}
fclose(fin);
fclose(fout);
return 0;

}

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

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

// print some values
printf(" argv1 is %ld\n" , n);
printf(" errno is %d\n" , errno);



if (*endp || errno){
perror(__func__);
return -1;

-1 is not a portable return value from main.
}
if (*endp != '\0'){

If you reach this code, the if can never evaluate true. You probably
want to remove the test on *endp in the previous if.
fprintf(stderr, "%s: %s\n", __func__, "strtol error");
return -1;
}
exptab(atoi(argv[1]), argv[2]);
return 0;
}
 
F

Frank

If you reach this code, the if can never evaluate true.  You probably
want to remove the test on *endp in the previous if.

Thanks for your response, barry, I think I got the points you
commented on. I took this last part out, as the logic needs to be re-
written from first principles.

F:\gfortran\dan>gcc k5.c -Wall -o k.exe

F:\gfortran\dan>k 555555555555 ot3.txt
argv1 is 2147483647
stderr has the following error 34
errno is 34
endp is 003D3B20
endp points to 0022FF70
main: Result too large

F:\gfortran\dan>type k5.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;
const int cn = n;

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;
}
while ((c=fgetc(fin)) != EOF){
n = cn;
if (c == '\t') while (n--) fputc(' ', fout);
else fputc(c, fout);
}
fclose(fin);
fclose(fout);
return 0;

}

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

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

// print some values
printf(" argv1 is %ld\n" , n);
fprintf(stderr, "stderr has the following error %d\n ", errno);
printf(" errno is %d\n" , errno);
printf(" endp is %p\n" , endp);
printf(" endp points to %p\n" , &endp);
//printf(" the pointer to endp points to %d\n" , ??);

if (*endp || errno){
perror(__func__);
return EXIT_FAILURE;
}

exptab(atoi(argv[1]), argv[2]);
return EXIT_SUCCESS;
}

// gcc k5.c -Wall -o k.exe

F:\gfortran\dan>

How do I print the char that endp ** points to?
 
F

Frank

I try to illustrate here:
F:\gfortran\dan>gcc k4.c -Wall -o k.exe
F:\gfortran\dan>k 5 ot3.txt
 argv1 is 5
 errno is 0
F:\gfortran\dan>k 5 zax.txt
 argv1 is 5
 errno is 0
k4.c(27): fopen
F:\gfortran\dan>k 5555555555 ot3.txt
 argv1 is 2147483647
 errno is 34
main: Result too large

There is a technical problem with the code (see below) but so far all
these are as I would expect.  Did you have a question about them?

    errno = 0;
    n = strtol(argv[1], &endp, 10);
    // print some values
    printf(" argv1 is %ld\n" , n);
    printf(" errno is %d\n" , errno);

Calling printf can loose the value of errno.  It can be set to non-zero
by printf even if printf succeeds because printf does not document the
use of errno.  You have to test immediately, though most systems are
helpful and I don't think anything is going wrong because of this.


Is it better to use fprintf and stderr?
case 2) 0 || 0
If endp == zero then the test condition is true.  I think we want to
test argv[1] to see if it is zero and spit this case back to the user
and say "Do you really want to take the tabs out altogether?"
Same here.  I have no idea what you are talking about.  Why not give
an example call and talk about the effect it has?
I claim that "well-formed" user responses for argv1 are the natural
numbers.  If your logic consists or n || m, where n is in the
naturals, then only zero reverses the outcome, given m.  I think we
need to split this case off.

What are you talking about?  My logic tests *endp (or endp == argv[1])
and errno.  What has n got to do with it?  What is m?

Of all the naturals, only one is false, namely, zero. I don't think a
control that tests for the truth of argv[1] is going to help this
program decide anything, so I think the point is moot.

I don't mean to be glib here. And I haven't figured out how endp
tells me anything about errors yet, but I'm getting closer. Cheers,
I am glad you understand, but I can't unravel your last sentence.  If
it is your wording of what I said then it doesn't matter -- I don't
need to follow it.

Again, I don't think that this is going to help the logic of this, so
it doesn't matter.
 
B

Ben Bacarisse

Frank said:
Frank <[email protected]> writes:
    errno = 0;
    n = strtol(argv[1], &endp, 10);
    // print some values
    printf(" argv1 is %ld\n" , n);
    printf(" errno is %d\n" , errno);

Calling printf can loose the value of errno.  It can be set to non-zero
by printf even if printf succeeds because printf does not document the
use of errno.  You have to test immediately, though most systems are
helpful and I don't think anything is going wrong because of this.


Is it better to use fprintf and stderr?

That all have the same property. In general you should test errno
immediately rather than work out what might or might not happen to it.
case 2) 0 || 0
If endp == zero then the test condition is true.  I think we want to
test argv[1] to see if it is zero and spit this case back to the user
and say "Do you really want to take the tabs out altogether?"
Same here.  I have no idea what you are talking about.  Why not give
an example call and talk about the effect it has?
I claim that "well-formed" user responses for argv1 are the natural
numbers.  If your logic consists or n || m, where n is in the
naturals, then only zero reverses the outcome, given m.  I think we
need to split this case off.

What are you talking about?  My logic tests *endp (or endp == argv[1])
and errno.  What has n got to do with it?  What is m?

Of all the naturals, only one is false, namely, zero. I don't think a
control that tests for the truth of argv[1] is going to help this
program decide anything, so I think the point is moot.

I have never suggested testing the truth of argv[1].
I don't mean to be glib here. And I haven't figured out how endp
tells me anything about errors yet, but I'm getting closer. Cheers,

Have you read the specification of strtol? It tells you what happens
to the pointer whose address you pass to strtol (endp in this case).

<snip>
 
F

Frank

Frank said:



Pointer to pointer to char.


Struggling :(

#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;
const int cn = n;

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;
}
while ((c=fgetc(fin)) != EOF){
n = cn;
if (c == '\t') while (n--) fputc(' ', fout);
else fputc(c, fout);
}
fclose(fin);
fclose(fout);
return 0;

}

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

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

// print some values
printf(" argv1 is %ld\n" , n);
fprintf(stderr, " stderr has the following error %d\n ", errno);
printf(" errno is %d\n" , errno);
printf(" endp is %p\n" , endp);
printf(" endp points to %p\n" , &endp);
printf(" the char that the pointer to a pointer to char\
called endp points to is %d\n" , & (&endp));

if (*endp || errno){
perror(__func__);
return EXIT_FAILURE;
}

exptab(atoi(argv[1]), argv[2]);
return EXIT_SUCCESS;
}

// gcc k6.c -Wall -o k.exe



F:\gfortran\dan>gcc k5.c -Wall -o k.exe

F:\gfortran\dan>k 555555555555 ot3.txt
argv1 is 2147483647
stderr has the following error 34
errno is 34
endp is 003D3B20
endp points to 0022FF70
main: Result too large

F:\gfortran\dan>type k5.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;
const int cn = n;

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;
}
while ((c=fgetc(fin)) != EOF){
n = cn;
if (c == '\t') while (n--) fputc(' ', fout);
else fputc(c, fout);
}
fclose(fin);
fclose(fout);
return 0;

}

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

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

// print some values
printf(" argv1 is %ld\n" , n);
fprintf(stderr, "stderr has the following error %d\n ", errno);
printf(" errno is %d\n" , errno);
printf(" endp is %p\n" , endp);
printf(" endp points to %p\n" , &endp);
//printf(" the pointer to endp points to %d\n" , ??);

if (*endp || errno){
perror(__func__);
return EXIT_FAILURE;
}

exptab(atoi(argv[1]), argv[2]);
return EXIT_SUCCESS;
}

F:\gfortran\dan>gcc k6.c -Wall -o k.exe
k6.c: In function `main':
k6.c:62: error: invalid lvalue in unary `&'

F:\gfortran\dan>

It looked like unary & worked once. Why not twice?
 
L

luserXtrog

    errno = 0;
    n = strtol(argv[1], &endp, 10);
    if (endp == argv[1] || errno)
        /* there was an error */

I do not think that the doublepipe is decideable without knowing the
truth value of argv[1].

== binds tighter than || (ie. it happens first).
== is to || as * is to +.
so the operands of || are (endp == argv[1]) and (errno /*!=0*/).
 
L

luserXtrog

Frank said:
Pointer to pointer to char.
dupal?


Struggling :(
[...]
    printf(" endp is %p\n" , endp);
    printf(" endp points to %p\n" , &endp);

You really don't need to know what &endp is.
It's not what endp points to but the memory location
of the char *endp.
But something like
printf(" *endp == %d\n", (unsigned int)*endp);
would show you the character value that terminated
strtol. and (endp-argv[1]) would give you the offset
from the beginning of the string where it happened.

It's only a char ** so it can return extra information
(if you want it). The information it can return this
way is char * value but since it has to happen indirectly,
the prototype has an extra * and in the call there's
an extra & to balance it out.

[...]
F:\gfortran\dan>gcc k6.c -Wall -o k.exe
k6.c: In function `main':
k6.c:62: error: invalid lvalue in unary `&'

F:\gfortran\dan>

It looked like unary & worked once.  Why not twice?

It works where it works.
 
F

Frank

    errno = 0;
    n = strtol(argv[1], &endp, 10);
    if (endp == argv[1] || errno)
        /* there was an error */
I do not think that the doublepipe is decideable without knowing the
truth value of argv[1].

== binds tighter than || (ie. it happens first).
== is to || as * is to +.
so the operands of || are (endp == argv[1]) and (errno /*!=0*/).

ok well, the logic still looks tortured. With Ben's idiom, I can't
tell whether this is intentional.
 
F

Frank

"Frank" <[email protected]> ha scritto nel messaggioi rewrote the last code in your post with some comment

Looks great, kimosabe:

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

F:\gfortran\dan>j 5 ot3.txt
argv1 is 5
stderr has the following error 0
errno is 0
endp is 003D3B15
the pointer to endp points to [ ]:[0]

F:\gfortran\dan>j 5555555555555 ot3.txt
argv1 is 2147483647
stderr has the following error 34
errno is 34
endp is 003D3B21
the pointer to endp points to [ ]:[0]
main: Result too large

F:\gfortran\dan>type j2.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;

// why not to do some test for input?
if(n<0||n>999||path==0||*path==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;
nc+=c;
path_exp = malloc(nc + 1);
if(!path_exp)
{fprintf(stderr, "%s: %s\n", "exptab", "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;
}
while( (c=fgetc(fin)) != EOF )
{if(c == '\t')
{nc=n;
while(nc--)
fputc(' ', fout);
}
else fputc(c, fout);
}
c=0;
// why not see it there are problem in the files?
if( fclose(fin) ==EOF ) c=1;
if( fclose(fout)==EOF ) c=1;
return c==1?
(fprintf(stderr, "%s(%d): %s\n",
__FILE__, __LINE__,"other"),EXIT_FAILURE):
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 EXIT_FAILURE;
}
errno=0;
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 ", errno);
printf(" errno is %d\n" , errnoStrtol);
printf(" endp is %p\n" , endp);
// printf(" endp points to %p\n" , (void*)*endp);
// have not mening: in strtol what is changed is the endp
// value, for this there is **endp, in the definition of
// strtol because for change char* endp; i have to
// pass to the function char** and so &endp
if(endp!=0)
printf(" the pointer to endp points to [%c]:[%d]\n" ,
endp[0], (int)endp[0]);
if ( // *endp!=0 || in general should be meanigless
errnoStrtol)
{perror("main"); return EXIT_FAILURE;}

return exptab( atoi(argv[1]), argv[2]);
}

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

F:\gfortran\dan>

Time to count sheep. (I ate lamb today, ick) Cheers,
 
B

Ben Bacarisse

Frank said:
    errno = 0;
    n = strtol(argv[1], &endp, 10);
    if (endp == argv[1] || errno)
        /* there was an error */
I do not think that the doublepipe is decideable without knowing the
truth value of argv[1].

== binds tighter than || (ie. it happens first).
== is to || as * is to +.
so the operands of || are (endp == argv[1]) and (errno /*!=0*/).

ok well, the logic still looks tortured. With Ben's idiom, I can't
tell whether this is intentional.

What is tortured about it? strtol sets the pointer (whose address you
pass as its second argument) to the value of its first argument when
it is unable to find a string to convert. Testing if endp == argv[1]
is thus the most explicit and direct way to ask if there was a format
error in the string. The other half is a direct test for the all the
other things that can go wrong, which are indicated by errno having
been set.
 
J

jameskuyper

Frank said:
errno = 0;
n = strtol(argv[1], &endp, 10);
if (endp == argv[1] || errno)
/* there was an error */
I do not think that the doublepipe is decideable without knowing the
truth value of argv[1].

== binds tighter than || (ie. it happens first).
== is to || as * is to +.
so the operands of || are (endp == argv[1]) and (errno /*!=0*/).

ok well, the logic still looks tortured.

Earlier, Ben asked you "Have you read the specification of strtol?".
If you had, you would have found out that there are two ways in which
a call to strtol() can indicate failure.

If the subject sequence (the sequence of characters that it should
interpret as representing an integer) is either empty or incorrectly
formatted, strtol(argv[1], &endp, 0) will set the value of endp to agv
[1] (7.20.1.4p7). It will return a value of zero, but there's no point
in checking that zero, because it could just as easily be the result
of processing a valid string, such as "0".

If the subject sequence represents an integer that is outside of the
range that can be represented as a long, strtol() will set errno to
ERANGE (7.20.1.4p8). Because the standard documents the use of errno
by strtol(), strtol() is not free to set errno to any other number, or
for any other reason (7.5p30). It will also return a value of either
LONG_MIN or LONG_MAX, depending upon the sign of the integer, but
there's no point in checking for that; those values could just as
easily be the result of processing a valid string representing those
integers.

If you were going to check for those two possibilities, what logic
would you use? I can't imagine any logic less tortured than Ben's for
checking them. His code will also signal an error if errno gets set to
a non-zero value other than ERANGE, which is something that's not
supposed to be possible. However, if it does happen, I'm inclined to
agree with Ben and treat it as an error indication.
With Ben's idiom, I can't tell whether this is intentional.

I do believe that his use of the simplest, most obvious logic for
testing those possibilities was intentional.

In your code examples, you treat *endp==0 as if it were an error
indication. if strtol(argv[1], &endp, 0) succeeds, it will set endp
to point at the first character in the string pointed at by argv[1]
after the subject sequence; that character could be the null character
that terminates the string. Therefore, *endp will be '\0' if the
string happens to be, for instance "12345". This means that *endp == 0
does not indicate an error, unless endp==argv[1].

Furthermore, the only way endp can end up null is if argv[1] is null;
and that can't be the case, because your code requires argc to be 3.
Therefore, there's no point in checking whether endp==NULL.
 
B

Barry Schwarz

Thanks for your response, barry, I think I got the points you
commented on. I took this last part out, as the logic needs to be re-
written from first principles.

F:\gfortran\dan>gcc k5.c -Wall -o k.exe

F:\gfortran\dan>k 555555555555 ot3.txt
argv1 is 2147483647
stderr has the following error 34
errno is 34
endp is 003D3B20
endp points to 0022FF70
main: Result too large

F:\gfortran\dan>type k5.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;
const int cn = n;

path_exp = malloc(strlen(path) + strlen(exp_suffix) + 1);
if (!path_exp){
fprintf(stderr, "%s: %s\n", __func__, "malloc error");
return EXIT_FAILURE;

There was nothing wrong with returning -1 from exptab but there is
nothing wrong with returning EXIT_FAILURE either (except of course you
are not exiting)
}
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;
}
while ((c=fgetc(fin)) != EOF){
n = cn;
if (c == '\t') while (n--) fputc(' ', fout);
else fputc(c, fout);
}
fclose(fin);
fclose(fout);
return 0;

}

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

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

// print some values
printf(" argv1 is %ld\n" , n);
fprintf(stderr, "stderr has the following error %d\n ", errno);
printf(" errno is %d\n" , errno);
printf(" endp is %p\n" , endp);
printf(" endp points to %p\n" , &endp);
//printf(" the pointer to endp points to %d\n" , ??);

if (*endp || errno){
perror(__func__);

What will perror do if errno is 0 or for that matter is residue from
one of the other subroutine calls?
return EXIT_FAILURE;
}

exptab(atoi(argv[1]), argv[2]);
return EXIT_SUCCESS;
}

// gcc k5.c -Wall -o k.exe

F:\gfortran\dan>

How do I print the char that endp ** points to?

endp is not a char**; it is a char*. So your question should read
"that endp points to". If endp points to a char, then that char is
expressed as *endp (or if you prefer the equivalent endp[0]).

You already know how to print single characters. You did it in
exptab.

You should confirm the character is not '\0' before attempting to
print it since '\0' usually is not a printable character.
 

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

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top