Thread: reading in command line arguments from a file?

  1. #1
    Registered User
    Join Date
    Jun 2006
    Posts
    28

    reading in command line arguments from a file?

    what is the best way to do this?
    I do know how to open the file and read the args into a variable, but how would you pass them to argc and argv?
    something llike:
    Code:
    if(argc==1){ 
    file=fopen("c:\\args.txt","r");
    if(file==NULL){
    return 1;
    }
    else{
    while(fgets(arg,MAX_PATH,file)!=NULL){
    }
    }
    after that I get lost...
    what do I need to do next?

  2. #2
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    argc and argv are both const so you cannot modify them.

    You could call main() again with your own argc and argv buffers. This is generally a bad aproach because 1) it's not common practice, and 2) it duplicates all the variables in main().

    The better aproach is not to read from argc/v, but to store the arguements into your own strings. If no arguements are given, then default to read them from a file.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  3. #3
    Registered User
    Join Date
    Jun 2006
    Posts
    28
    "If no arguements are given, then default to read them from a file."
    This is exactly what I'm tring to do...hence
    the if (argc==1) statement. Am I not getting something?
    and my while(fgets(arg,MAX_PATH,file)!=NULL) stores the arguments from the file into variable char arg[]. Now I dont know where to go from here. Im new to c programming and have had no experience with command line arguments. If im doing something incorrectly are poorly please correct me.

    sorry if my question was not stated clearly..
    Last edited by g1i7ch; 06-21-2006 at 06:19 PM.

  4. #4
    Awesomefaceradcore bivhitscar's Avatar
    Join Date
    Apr 2006
    Location
    Melbourne, Australia
    Posts
    210
    The small amount of code you have posted should work, what are you having trouble with?
    it's ironic considerate rarity patron of love higher knowledge engulfs me...

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by King Mir
    argc and argv are both const so you cannot modify them.
    No they're not. Yes you can.
    C: A Reference Manual; 5th ed.
    Page 303

    When arguments are declared, those arguments are set up by the execution enviorn-
    ment and are not directly under control of the C programmer. The parameter argc is the
    count of the number of "program arguments" or "options" supplied to the program when it
    was invoked by a user or another program. The parameter argv is a vector of pointers to
    strings representing the program arguments. The first string, argv[0], is the name of the
    program; if the name is not available, argv[0][0] must be '\0'. The string argv[i],
    for i=1, ..., argc-1, is the ith program argument. Standard C requires that argv[argc]
    be a null pointer, but not so in some older implementations. The vector argv and the
    strings to which it points must be modifiable, and their values must not be changed by the
    implementation or host system during program execution. If the implementation does not
    support mixed-case strings, then the strings stored in argv must be in lower case.

    Quzah.
    Hope is the first step on the road to disappointment.

  6. #6
    Registered User
    Join Date
    Jun 2006
    Posts
    28
    Ok, after the code Ive posted dont I need to set the argc=sizeof(arg) and argv = arg or something. cuz I am lost after I open and read in the arguments into char arg[]

    my txt file has 1 line and looks like this :
    -b -s 999
    but could have more arguments in it i.e.
    -b -B 999 -s -vv -R

    printf(arg) looks just like the txt file,this is a good thing

    I dont know how to set argc and argv = to my char arg[] that contains the argument list.

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    > printf(arg) looks just like the txt file,this is a good thing
    If Dave were here he would point out this: http://en.wikipedia.org/wiki/Format_string_attack

    If I understand you correctly, you know how to read from files, you just want to store the switches from the file in argv[]. Then:
    1. Parse the file for switches, storing them in a temporary string.
    2. argc equals how many switches there were.
    3. for each switch s to argc, use strncpy to put the switch in argv[s]
    Last edited by whiteflags; 06-21-2006 at 07:42 PM. Reason: completeness

  8. #8
    Registered User
    Join Date
    Jun 2006
    Posts
    28
    I thank you for pointing that vulnerability out...but I am using printf() only to see that the char arg[] has been loaded with the info from the txt file and I am NOT using it in the code ,only for testing purposes.

    and you are correct, that is what I need to do just not to sure on how to do it.

    an example ,if it's ! to lengthy,would be great.
    Last edited by g1i7ch; 06-21-2006 at 08:42 PM.

  9. #9
    Awesomefaceradcore bivhitscar's Avatar
    Join Date
    Apr 2006
    Location
    Melbourne, Australia
    Posts
    210
    This works, but it's as bare as it comes. I have no doubt that I'll be picked up on numerous errors, but it should get you started.

    I'm a bit unsure about the stability of realloc, but it seemed to work fine in my test.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(int argc, char *argv[])
    {
        FILE * file;
        char buf[BUFSIZ];
        char **arg;         
        char *position;
        char ch;
        int i;
    
        if ( argc == 1 )
        { 
             if ( (file = fopen("args.txt", "r")) == NULL )
             {
                  exit(1);
             }
             else
             {
                 if ( fgets( buf, BUFSIZ, file ) != NULL )
                 {
                      position = strtok( buf, " " );
                      
                      arg = malloc( sizeof( arg ) );     
                      *arg = position;                   
                      
                      while ( (position = strtok( NULL, " " )) != NULL )   
                      {
                            argc++;       
                            
                            arg = realloc ( arg, argc );     
                            arg[argc - 1] = malloc( sizeof( arg ) );
                            arg[argc - 1] = position;    
                      }     
                      
                      argv = malloc ( argc );
                      
                      for ( i = 0; i < argc; i++ )
                      {
                          argv[i] = malloc( strlen( arg[i] ) + 1 );
                          strcpy( argv[i], arg[i] );
                      }
                      
                 }
             }
        }
        
        ch = getchar();
        
        return 0;
    }

    The test text file used:

    Code:
    -b -B 999 -s -vv -R

    [EDIT]

    I suppose an explanation is in order. Basically, this reads the first line from a text file into a buffer. From there it copies the location of each string in the buffer (after using strtok) into an array of pointers. Then it copies the strings from the buffer, using the array of pointers, into argv.

    I hope that makes some kind of sense.
    Last edited by bivhitscar; 06-21-2006 at 08:51 PM.
    it's ironic considerate rarity patron of love higher knowledge engulfs me...

  10. #10
    Registered User
    Join Date
    Jun 2006
    Posts
    28

    Talking

    Code:
    for (i=0,i<1000,i++){
    cout<<thank you<<endl;
    }

  11. #11
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    I had a slightly different idea on how to do this, but I haven't tested anything. You might want to try implementing both of ours and see what works for you.
    It's probably not the fastest algorithm in the world, but it uses memory quite efficiently.
    Code:
        int ch;
        int argc = 0;
        int pos;
        char arg[BUFSIZ];
        for ( pos = 0; ( ch = fgetc( fp ) ) != EOF; ++pos) { /* where fp is your file pointer */
            if ( !isspace(ch) ) 
                arg[pos] = ch;
            else {
                ++argc;
                arg[pos] = '\0'; /* we've a whole argument */
                pos = 0;  /* reset pos to zero for the next iteration */
                strncpy(argv[argc], arg, sizeof(arg));
                memset(arg, 0, sizeof(arg)); /* clear arg for reuse */
            }
        }
    Last edited by whiteflags; 06-21-2006 at 09:18 PM.

  12. #12
    Awesomefaceradcore bivhitscar's Avatar
    Join Date
    Apr 2006
    Location
    Melbourne, Australia
    Posts
    210
    citizen, that pretty much ........s all over my idea. Nice one. (seriously, I'm not being sarcastic)

    I think I started with one idea and it didn't work and it ended up snowballing into the code you see above. :P
    it's ironic considerate rarity patron of love higher knowledge engulfs me...

  13. #13
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Quote Originally Posted by citizen
    Code:
    ++argc;
    ...
    strncpy(argv[argc], arg, sizeof(arg));
    I'm not so sure you can just keep indefinitely adding to argv like that. Where do you expect the additional space to come from?

    A better way would be to create a new argv that is dynamically resizable. Something like:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void add_arg(char ***argv, int *argc, char *arg, unsigned long len)
    {
      char *switchstr;
    
      // Make a new string that contains the switch
      switchstr = malloc(len + 1);
      strncpy(switchstr, arg, len);
      switchstr[len] = '\0';
    
      // resize argv and insert the new switch at the end
      *argv = realloc(*argv, sizeof(**argv) * ((*argc) + 2));
      (*argv)[(*argc)++] = switchstr;
      (*argv)[*argc] = NULL; // Don't forget that argv[argc] MUST be NULL
    }
    
    int main(int argc, char **argv)
    {
      char addargs[] = "-b -B 999 -s -vv -R";
      char **newargv;
      char *p = addargs, *q;
      int i;
    
      // Copy original argv into our new one
      newargv = malloc(sizeof(*newargv) * (argc + 1));
      for(i = 0;i < argc;++i)
      {
        newargv[i] = malloc(strlen(argv[i]) + 1);
        strcpy(newargv[i], argv[i]);
      }
      newargv[argc] = NULL; // Standard states that argv[argc] must be NULL
    
      // Add the switches
      while((q = strchr(p, ' ')))
      {
        add_arg(&newargv, &argc, p, q - p);
        p = q + 1;
      }
    
      if(*p)
        add_arg(&newargv, &argc, p, strlen(p));
    
      // Make the original argv point to our new one;
      argv = newargv;
    
      // Print the complete list of arguments and clean up our allocations
      for(i = 0;i < argc;++i)
      {
        printf("argv[%d] = %s\n", i, argv[i]);
        free(argv[i]);
      }
      free(argv);
    
      return 0;
    }
    My output:
    Code:
    itsme@itsme:~/C$ ./addargs one two three
    argv[0] = ./addargs
    argv[1] = one
    argv[2] = two
    argv[3] = three
    argv[4] = -b
    argv[5] = -B
    argv[6] = 999
    argv[7] = -s
    argv[8] = -vv
    argv[9] = -R
    itsme@itsme:~/C$
    Of course, the code could use some error checking, but you get the idea.

    Also, this doesn't do anything that's near as nice as a real shell can handle (e.g. support for quotes, wildcards, substitutions, etc.)
    Last edited by itsme86; 06-21-2006 at 10:18 PM.
    If you understand what you're doing, you're not learning anything.

  14. #14
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    > I'm not so sure you can just keep indefinitely adding to argv like that. Where do you expect the additional space to come from?
    I figured that was one problem.

    Honestly I think the person writing this program is doing it backwards. I just wasn't sure what the program was for. The absolute best way to do this is to supply arguments if you have them in the console. If you don't supply arguments, then you have to prompt the user for the stuff you need, or something like that. Most people cop out and write the help file if they have an error with the arguments cause it's much easier.

  15. #15
    Awesomefaceradcore bivhitscar's Avatar
    Join Date
    Apr 2006
    Location
    Melbourne, Australia
    Posts
    210
    >I just wasn't sure what the program was for.

    My guess is that the txt file is used as a 'default' set of arguments. *shrug*
    it's ironic considerate rarity patron of love higher knowledge engulfs me...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. gcc link external library
    By spank in forum C Programming
    Replies: 6
    Last Post: 08-08-2007, 03:44 PM
  2. archive format
    By Nor in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 08-05-2003, 07:01 PM
  3. System
    By drdroid in forum C++ Programming
    Replies: 3
    Last Post: 06-28-2002, 10:12 PM
  4. what does this mean to you?
    By pkananen in forum C++ Programming
    Replies: 8
    Last Post: 02-04-2002, 03:58 PM