tags:

views:

125

answers:

3

Now I do have a hw question for everyone...I've been staring at this for a couple of days kind of tinkering and playing around but even with that I end up with a load of errors...

What I'm trying to do is take the program below and change it so that it takes an optional command line argument infile. If infile is given, then copy infile to standard output, otherwise copy standard input to standard output as before.

The trick about this is that the solution must use the original copy loop (lines 9-11) for both cases. One can only insert code, and not change any of the existing code. Any help would be great. Thanks.

/* $begin cpfile */
include "csapp.h"
int main(int argc, char **argv)
{
    int n;
    rio_t rio;
    char buf[MAXLINE];

    Rio_readinitb(&rio, STDIN_FILENO);                  //line 9
    while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) //line 10
        Rio_writen(STDOUT_FILENO, buf, n);              //line 11
        /* $end cpfile */
        exit(0);
        /* $begin cpfile */
    }
/* $end cpfile */
+5  A: 

C programs get command line arguments through the two arguments to main(), traditionally called argc and argv (for argument count and argument vector, respectively).

Arguments are not "named" anything, they're just strings.

A solution for you could look like this:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    int fileno;
    /* ... your definitions should remain here, too */

    if(argc > 1)
    {
       /* Assume first argument is filename, and open it. */
       fileno = open(argv[1], O_RDONLY);
       if(fileno < 0)
       {
         printf("Unable to open file, aborting\n");
         return 1;
       }
    }
    else
      fileno = STDIN_FILENO;

  /* ... your code goes here ... */
}

Then you'd of course need to change the call to Rio_readinitb() to use the fileno variable for the file descriptor.

If you literally can't change that line, for whatever reason ... I guess you can use the preprocessor to make the symbol evaluate to the new variable name:

#undef  STDIN_FILENO
#define STDIN_FILENO fileno

This is of course not exactly pretty, but should work.

Make sure you put those preprocessor macros after the fileno = STDIN_FILENO; line.

unwind
That would require changing the lines that cannot be changed.
qrdl
@qrdl: Right, thanks. I added a preprocessor workaround.
unwind
But if you can't change the `STDIN_FILENO` in the call to `Rio_readinitb(` the you will always read from stdin. Likewise the call `exit(0);` in the loop is spurious.This assignment does not make a lot of sense.
iWerner
@unwind, I clarified to make sure you didn't #define until the right spot. +1 for being sneaky :-)
paxdiablo
@paxdiablo: Heh ... Thanks. I think that you perceived a bit more sneakyness than intended, but it should work that way so I'm happy.
unwind
+1  A: 

If STDIN_FILENO cannot be reassigned, it sounds like a task for freopen():

freopen(argv[1], "r", stdin);
qrdl
+1  A: 

You can insert dup2 before the lines 9 - 11 and it seems that you will not need change code on the lines 9 - 11. This is an example.

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>


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

    int file_handle;
    int dup2_res;
    if (argc == 2) {
        file_handle = open(argv[1], O_RDONLY);
        dup2_res = dup2 (file_handle, STDIN_FILENO);
    }

    char buffer[100];
    ssize_t read_bytes = 1;
    while (read_bytes)
    {
        read_bytes = read(STDIN_FILENO, &buffer, sizeof(buffer) );
        buffer[read_bytes] = 0;
        printf("%s", buffer);
    }
    close(file_handle);

    return 0;
}
skwllsp
in the book it does talk about using Dup2 ...
I'm Jim Caviezel too
I think you need to make it clear that dup2() isn't ANSI C, and OP didn't specify the platform so it is not necessarily kosher.
qrdl
True, but dup2() is POSIX. But sure, it is dependent on the platform.
BobbyShaftoe