kuskmen
kuskmen

Reputation: 3775

Calling system call read leads to infinite loop

I want to make a very simple console application that replaces the Unix command wc -c. For this, I need simply to count the bytes into the file and output them in the console.

If my application is not provided with arguments, it reads them from the standard input (this part I've already made working). However, if I decide to supply more arguments (valid and existing file names), I should count each one of them their bytes.

So far so good. Here is the code

const int __OPEN_ERROR = 48;

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

    if(argc == 1) {
        char buf[3];
        int count = 0, lines = 0;
        while(read(0, buf, 1) != 0) {
            count++;
            if(buf[0] == '\n')
                lines++;
        }

        printf("Count:%d\n", count);
        printf("Lines:%d\n", lines);
    }
    else {
        int fd, bytes = 0;
        char buf[3];

        for (int arg = 1; arg <= argc; arg++) {
            if ((fd = open(argv[arg], O_RDONLY) < 0)) {
                exit(__OPEN_ERROR);
            }
            while (read(fd, buf, 1) != 0) { // <-- this here leads to infinite loop.
                printf("%s", buf);
                bytes++;
            }

            printf("%d %s", bytes, argv[arg]);
        }
    }

    exit(0);
}

Please don't mind how badly this code is written, this is my first day exploring C, for now everything I want is working solution.

Notice how both reads are same but latter one falls into infinite loop, for a reason I cannot understand. And yes, opening the file succeeds.

Upvotes: 0

Views: 1369

Answers (1)

Jean-Baptiste Yun&#232;s
Jean-Baptiste Yun&#232;s

Reputation: 36391

Your loops are wrong, should be:

char buf;
...
while (read(fd, buf, 1) == 1) {
    printf("%c", buf);
    bytes++;
}

read lets you read bytes from file descriptor. The given number say n is a request, this means that read reads at most n bytes, and the returned value is exactly the number of bytes effectively read. As you want to read 1 byte, then test if it read 1 byte. Second, as you read bytes (or char) one by one, then the result is one char and should be print as. %c tells printf to print the value as a char (%s is to print C-strings).

The other error is the control of arg loop, should be:

for (int arg = 1; arg < argc; arg++) // strict test...arg from 0 to argc-1 (included) or argc (excluded)

You must also reset the byte count to 0 on each arg looping, and close each unused file, thus:

for (int arg = 1; arg < argc; arg++) {
    char buf;
    int bytes = 0;
    int fd;
    if ((fd = open(argv[arg], O_RDONLY) < 0)) {
        exit(__OPEN_ERROR);
    }
    while (read(fd, buf, 1) == 1) {
        printf("%c", buf); // optionnal, counting may not print...
        bytes++;
    }
    close(fd);
    printf("%d %s", bytes, argv[arg]);
}

Upvotes: 1

Related Questions