0

I currently have a program, myprogram.c, that can be invoked with command line arguments such as myprogram testfile. This will read in text from testfile, assuming it exists, and the function spaces() will alter the text and print it to stdout. However, I want to be able to invoke the program like myprogram testfile -o outputfile so that instead of printing to stdout, the output is written to outputfile. How would I go about doing this?

What follows is the general structure of my main.

  int main (int argc, char *argv[])
    {
        char *a;
        char *prev_line[999];
        size_t len = 0;
        size_t read;

      /* if there is more than one argument */
      if (argc > 1)
        {
          a = malloc (MAX_NAME_SZ * sizeof (char));
          int i = 1;
          FILE *fp;
          while (i < argc)
        {
          fp = fopen (argv[i], "r");
            if (fp == NULL)
              {
                /*Error statement in case file doesn't exist */
              }
            else
             {
               char* line = NULL;
             while ((read = getline(&line, &len, fp)) != -1) {
              /*code to create char array a */        
              }
          }   
            free(line);
            fclose (fp);
            }
          i++;   
        }
        }
      else /* if no command line arguments */
        {
          /* get array a from stdin*/
          spaces (a);
           return 0;
        }
          spaces (a);
          return 0;
    }

Any help or solution is greatly appreciated. Thanks!

jtuntalan
  • 21
  • 4
  • _so that instead of printing to stdout, the output is written to outputfile ?_ Its output redirection and to get it done through program you need to use `pipe()`, `dup2()`,`execlp()` etc system call you need to use. – Achal May 01 '18 at 02:29
  • 1
    Use `getopt` to parse args. Use `freopen` to change `stdout`. But, you can just change how you invoke your program to use `>` instead of `-o`. – jxh May 01 '18 at 02:30

2 Answers2

1

1) Output redirection

If you are on linux, you could just use output redirection like

myprogram testfile > outputfile

2) getopt()

You might want to look into getopt() if you are on a POSIX system (you might be since you are using getline()). There might be equivalent ways in other platforms as well. See this for a discussion on getopt functionality in Windows.

With getopt(), it's easy. Something like

#include<unistd.h>
#include<ctype.h>
int main(int argc, char **argv)
{
    int c;
    while( (c=getopt(argc, argv, "o:"))!=-1 )
    {
        switch(c)
        {
        case 'o':
            
            printf("\nFile name is: %s" , optarg);
            break;
        case '?':
            if(isprint(optopt))
            {
                printf("\nUnknown option %c", optopt);
            }
            else
            {
                printf("\nUnknown option: %x", optopt);
            }
                
        }
    }
    while(optind < argc)
    {
        printf("\nRemaining args: %s", argv[optind++]);
    }
}

Read the man page and this page.


3) Manual way

You have to parse the command line arguments. This way is likely to cause lot of bugs and errors. As noted in the comments, getopt() would be the better choice if you have it.

If o is the only option you have and it will always be specified like -o, you could do something like

int main(int argc, char **argv)
{
    for(int i=1; i<argc; ++i)
    {
        if(argv[i][0]=='-' && argv[i][1]=='o')
        {
            if(argv[i][2]=='\0')
            {
                printf("\nstandalone o found.");
                if(i+1 < argc)
                {
                    printf("\nOutput file: %s", argv[i+1]);
                }
                else
                {
                    printf("\nOutput file name not given.");    
                    return 1;
                }
            }
            else
            {
                printf("\nOutput file name (closer): %s", argv[i]+2);
            }
        }
    }           


    . . . . . . . . . . 
    . . . . . . . . . . 

}

First we check if the argv[i] begins with a "-o". If it does, we see if that's all there is in that argv[i]. If that's all in it, we look at argv[i+1] to find the file name.
If there's something after the "-o" in argv[i], we consider the rest of the argv[i] as the name of the output file.

So both

myprogram testfile -o outputfile

and

myprogram testfile -ooutputfile

will extract the file name as "outputfile".


After getting the file name so obtained in a character array, say filename, you could then use freopen() as in

freopen(filename, "w", stdout);

Now stdout becomes a stream associated with the our output file. From now on, any write operations to stdout will mean writing to this file.

The stream stdout is first closed and then opens filename and associates this file with the file stream stdout.

Or instead of using freopen(), you could just make another stream by opening the file with fopen() as in

FILE *fout = fopen(filename, "w");

and then writing with fout as in

fprintf(fout, "%s", "output......");
Community
  • 1
  • 1
J...S
  • 5,079
  • 1
  • 20
  • 35
  • 1
    Strongly recommend putting the `getopt()` solution at the top. Personally, i'd not even bother with the ad hoc code (your first example); I've seen too many ad hoc bugs in variants of the ad hoc code to want to use such a mechanism. – Jonathan Leffler May 01 '18 at 07:09
0

Parse the argv[i] for -o then when you find it use argv[i+1] to either create or open the FILE that you want to write to, open it with FILE * out_file = fopen(argv[i+1], "w") the use fprintf(out_file , "output format\n"); to write to it.

Basically all your printfs will become fprintf and you pass the file pointer to every call to it, all the format specifiers are the same though. You can still use printf but it wont go to the file, you can also use fprintf(stderr,""); for error logging if your program keeps growing and you need console logging.

before your program exits make sure to close the file, fclose(out_file).

Bwebb
  • 675
  • 4
  • 14
  • Is this done by `if (argv[i] == "-o")`? I tried that but it didn't seem to detect it. – jtuntalan May 01 '18 at 03:30
  • @jtuntalan `strcpy` is used to compare strings. You may want to look at a library such as GNU getopt, for commandline processing. Or require your user to use shell redirection – M.M May 01 '18 at 03:50
  • @M.M you mean strcmp? You should be able to strcmp(argv[i],"-o") and find it that way – Bwebb May 01 '18 at 03:55
  • Yeah I mean `strcmp` sorry :) – M.M May 01 '18 at 03:59