Thread: getopts - prioritizing flags

  1. #1
    Registered User
    Join Date
    Jan 2010
    Posts
    69

    getopts - prioritizing flags

    I'm writing a Cat program and my program is pretty much coming together but I'm having trouble with the order of flags in command line. Like for example when I
    ./cat -Es test.txt my program puts the dollar sign at the end of each line but then my line squeeze doesn't work and it's because my squeeze was written to detect '\n' at the front of my line buf. When i ./cat -sE test.txt it supresses repeated lines and prints '$' at the end of each line. So my question is, is there a way i can make certain flags Priority over other flags so when i type ./cat -Es test.txt in the command line my program with in essence switch the -Es around to -sE? If you need me to clear up anything in here please ask.

    P.S. I have tried checking for '$' in my squeeze method and it didn't work out

    here is where my getopts is
    Code:
     while( fgets(buf, 1500, fptr) != NULL)
            {
                    while((choice = getopt ( argc, argv, "AbeEnstTuv")) != -1)
                    {
                            switch(choice)
                            {
                                    case 'A': /*Shows all equivalent to -vET*/
                                    case_A( buf );
                                    break;
    
                                    case 'b': /*number non-blank output lines*/
                                    case_b(buf, &counter_b, tmp);
                                    break;
    
                                    case 'e':
                                    printf("equivalent to -vE\n");
                                    break;
    
                                    case 'E': /*adds '$' to the end of every line*/
                                    case_E( buf );
                                    printf("\n");
                                    break;
    
                                    case 'n': /*numbers all output lines*/
                                    case_n( buf, &counter_n, tmp );
                                    break;
    
                                    case 's': /*suppress repeated empty output lines */
                                    case_s( buf , &counter_s, fptr);
                                    break;
    
                                    case 't':
                                    printf("equivalent to -vT\n");
                                    break;
    
                                    case 'T': /*display TAB character as ^I*/
                                    case_T( buf );
                                    break;
    
                                    case 'u': /*ignored*/
                                    break;
    
                                    case 'v':
                                    case_v( buf, fptr );
                                    break;
    
                            }
                    }
                    optind = 1;
                    printf("%s", buf);
            }
    ./cat -Es test.txt
    Code:
    [cat]$ ./cat -Es test.txt
    
    This is a test of how cat works.$
    Some characters like tab                        need to be replaced.$
    $
    Others don't, and line numbering can be trickier than you think.$
    Even more so when you have the -s flag on.$
    $
    Test 1$
    $
    Test 2$
    $
    $
    Test 3$
    $
    $
    $
    Test 4$
    $
    $
    $
    $
    $
    ./cat -sE test.txt << this is what i want it to do >>
    Code:
    [cat]$ ./cat -sE test.txt
    
    This is a test of how cat works.$
    Some characters like tab                        need to be replaced.$
    $
    Others don't, and line numbering can be trickier than you think.$
    Even more so when you have the -s flag on.$
    $
    Test 1$
    $
    Test 2$
    $
    Test 3$
    $
    Test 4$
    $

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I would just set a global* var to indicate E is set, then in the s function make it check E, and treat lines that are "$\n" the same as "\n".

    * it may not have to be global, you could set it in main and pass to the s function. I hope you are not giving functions completely descriptive names like "case_E" and "case_s" BTW.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Jan 2010
    Posts
    69
    I am giving them those names...... is that bad? I haven't had any problems with it yet?

    Also in my case_E im not appending the '$' to the front of the buf im replacing the '\n' with it.

    Another thing is I was wondering if I could just put all the choices into a character array and then sort them????
    Last edited by Dr Saucie; 03-24-2010 at 11:02 AM.

  4. #4
    Registered User jeffcobb's Avatar
    Join Date
    Dec 2009
    Location
    Henderson, NV
    Posts
    875
    While I don't know if I would go the global route, MK is right, just check your opts once and set a flag/variable for each just once, not on every read of the file/line...if you only have a few opts its no big deal but if you have a lot of opts I tend to create a structure to hold them all and then pass a pointer to that structure around to the methods that need them...no global vars, you keep all of your opts in one place and this makes it easy to default them to something useful. Then as you parse your opts via getopts() you just set the right struct member...can post an example of this if you like..
    C/C++ Environment: GNU CC/Emacs
    Make system: CMake
    Debuggers: Valgrind/GDB

  5. #5
    Registered User
    Join Date
    Jan 2010
    Posts
    69
    could you please?

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Jeff's idea looks like a good one.

    Quote Originally Posted by Dr Saucie View Post
    I am giving them those names...... is that bad? I haven't had any problems with it yet?
    No it won't create any technical problems. Just a style issue. No worries.

    Code:
    Also in my case_E im not appending the '$' to the front of the buf im replacing the '\n' with it.
    In any case, the point is that you know what the (empty) line will look like to case_s if case_s is called when E is set, so you should be able to deal with it there.

    Another thing is I was wondering if I could just put all the choices into a character array and then sort them????
    Probably. Actually that's a pretty neat idea too. You could make a sorted copy of argv and spoof getopt:
    Code:
                   while((choice = getopt ( argc, argv_sortedcopy, "AbeEnstTuv")) != -1)
    Or, if you are allowed, just sort argv before you call getopt.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User jeffcobb's Avatar
    Join Date
    Dec 2009
    Location
    Henderson, NV
    Posts
    875
    Quote Originally Posted by Dr Saucie View Post
    could you please?
    OK will do. I am on my way out the door ATM to get fingerprinted for a job but will do it when I get back...note I am not going to write cat for you, just the opts part and an example of using it this way...
    C/C++ Environment: GNU CC/Emacs
    Make system: CMake
    Debuggers: Valgrind/GDB

  8. #8
    Registered User
    Join Date
    Jan 2010
    Posts
    69
    Quote Originally Posted by jeffcobb View Post
    OK will do. I am on my way out the door ATM to get fingerprinted for a job but will do it when I get back...note I am not going to write cat for you, just the opts part and an example of using it this way...
    Alright well I have class here in like 30 mins anyways but yeah I wouldn't expect you to write my program. Most of its done anyways im just trying to test all my flags.

    Thanks to both of you I have a bunch of fresh new ideas to try =)

  9. #9
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I think Jeff meant something like:
    Code:
    typedef struct {
         int case_E;
         int case_s;
         [etc]
    } argflags;
    
    int main() {
          argflags myflags = {0};  // all unset;
                    while((choice = getopt ( argc, argv, "AbeEnstTuv")) != -1)
                    {
                            switch(choice)
                            {
                                    case 'E': /*adds '$' to the end of every line*/
                                    case_E( buf, myargs);
                                    myargs.case_E = 1;
                                    printf("\n");
                                    break;
    Then you can check relevant flags inside each function. You could actually do this easily using bitflags too; one int will cover 32 args.

    I notice you seem to be calling getopt repeatedly in a loop while reading lines from the file. I don't think that is a very good idea; you should just run getopts once and set some flags. So to combine the ideas:
    Code:
    #define case_a 1;
    #define case_b 1<<1;
    #define case_c 1<<2;
    #define case_d 1<<3;
    #define case_e 1<<4;
    
    int main() {
    	char options[]="abcde";
    	int argflags = 0; // none set;
    
    	while ((opt=getopt(argc, argv, options))>0) {
    		switch (case) {
    			case ('a'):
    				argflags ^= case_a;
    				break;
    			case ('b'):
    				argflags ^= case_b;
    				break;
    			case ('c'):
    			        argflags ^= case_c;
    				break;
    			case ('d'):
    				argflags ^= case_d;
    				break;
    			case ('e'):
    				argflags ^= case_e;
    				break;
    		}
    	}
    Then in your fgets loop:
    Code:
    if (argflags&case_a) a_func(buf, argflags);
    I changed the name of the function, but you get the point. This will give you more control in the fgets loop: for example, you can arrange the "if" statements so that the s function always executes before the E function. It didn't really hit me before that the real cause of the issue is your (somewhat bizarre) use of nesting the getopt loop in the fgets loop.
    Last edited by MK27; 03-24-2010 at 12:16 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #10
    Registered User jeffcobb's Avatar
    Join Date
    Dec 2009
    Location
    Henderson, NV
    Posts
    875
    MK beat me to it. Tks mate!
    C/C++ Environment: GNU CC/Emacs
    Make system: CMake
    Debuggers: Valgrind/GDB

  11. #11
    Registered User
    Join Date
    Jan 2010
    Posts
    69
    YAY!!! So i ended up putting my flags into a temp char array and sending to a sort method and sorting it by priority, then putting the flags back into argv and returning it. That definitely did the trick. If there was rep on here you guys would get a boat load lol.

  12. #12
    Registered User
    Join Date
    Jan 2010
    Posts
    69
    One last question to complete the program. I'm trying to replace all /t's in the program with a ^I, but I'm not sure exactly how to fit a string into a char spot, or even how to put two chars in without overriding.

    Code:
    for ( i = 0; i < filelength; ++i )
        {
            if ( buf[i] == '\t' )
            {
                buf[i] = "^I";
            }
        }
    Obviously doesn't work, but something along those lines is what I was thinking.

  13. #13
    Registered User
    Join Date
    Jan 2010
    Location
    Ca, US
    Posts
    29
    You can not just drop an extra char in that char array.
    You need to have a new array that will hold the extra chars and just loop through building the second one.
    Something like this

    Code:
    for ( i = 0,j = 0; i < filelength; ++i,++j )
       {
            if ( buf[i] == '\t' )
            {
                newbuf[j] = '^';
                newbuf[++j] = 'I'
            } else {
                newbuf[j] = buf[i];
            }        
        }

  14. #14
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    I usually set up my options as follows:
    Code:
    #define OPT_A 2
    #define OPT_B 4
    #define OPT_C 8
    ...
    Then you set your flags (which could be global or a passed around variable) (this could also be simplified using a lookup table of options -> flags):
    Code:
    while ((c = getopt(argc, argv, "abc")) != -1) {
        switch(c) {
            case 'a':
                flags |= OPT_A;
                break;
            case 'b':
                flags |= OPT_B;
                break;
            case 'c':
                flags |= OPT_C;
                break;
        }
    }
    Now you can process the options without regard to the order they were fed in, as previously shown by MK...I believe this method is a little simpler when checking for options as now you simply have to do:
    Code:
    if (flags & OPT_X == OPT_X) do_Something; /* OPT_X is set */
    It's useful to make this into a quick macro:
    Code:
    #define CHKOPT(f,o) ((f) & (o) == (o))
    My 2 cents, just add on to what MK and others above already stated.

  15. #15
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by nonpuz View Post
    Now you can process the options without regard to the order they were fed in, as previously shown by MK...I believe this method is a little simpler when checking for options as now you simply have to do:
    Probably better to use |= (OR) as you did rather than XOR as I did, altho in this case it will amount to the same thing.

    This:
    Code:
    if (flags & OPT_X == OPT_X) do_Something;
    Can be reduced to:
    Code:
    if (flags & OPT_X) do_Something;
    since it will be either zero or else the value of OPT_X. So to the inverse (if an option is not set):
    Code:
    if (!(flags & OPT_X)) do_Something;
    I dunno if there's much point making these into macros
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. obtaining which combination of flags are being set
    By stanlvw in forum C++ Programming
    Replies: 4
    Last Post: 07-16-2008, 02:43 AM
  2. Cannot get interface flags: Invalid argument
    By nasim751 in forum C Programming
    Replies: 1
    Last Post: 04-15-2008, 02:27 AM
  3. Cannot get interface flags: Invalid argument
    By nasim751 in forum C Programming
    Replies: 3
    Last Post: 04-14-2008, 02:29 AM
  4. Bit Flags
    By Padawan in forum C Programming
    Replies: 15
    Last Post: 03-30-2004, 10:38 PM
  5. Flags, the ambiguity of
    By Jeremy G in forum C++ Programming
    Replies: 1
    Last Post: 01-25-2003, 11:41 PM