LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-02-2017, 05:53 PM   #1
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,638

Rep: Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857
how to set flags for non valid arguments getopt?


Oh Kay I'm back, now I am trying to set a flag to indicate missing needed "non valid" argument.

with out this check it works as long as you add this needed argument that getopt only provides for after everything else.

so I am going to just post everything - instead of guessing and reading someone saying got a see it.

Code:
//#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include </usr/include/Imlib2.h>


#include "mhsetroot.h"
#include "getinfo.h"
#include "options.h"

	int w = 0;
	int h = 0;

typedef struct
{
	int r, g, b, a;
}	Color, *PColor;


int getHex (char c)
{
	//printf("in gethex\n");
	switch (c)
	{
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			return c - '0';
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
			return c - 'A' + 10;
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
			return c - 'a' + 10;
	default:
return 0;
	}// end switch
} // end function


int parse_color (char *optarg, PColor co, int a)
{
	if (optarg[0] != '#')
		return 1;

	if ((strlen (optarg) != 7) && (strlen (optarg) != 9))
		return 1;

	co->r = getHex (optarg[1]) * 16 + getHex (optarg[2]);
	co->g = getHex (optarg[3]) * 16 + getHex (optarg[4]);
	co->b = getHex (optarg[5]) * 16 + getHex (optarg[6]);
	co->a = a;

	if (strlen (optarg) == 9)
		co->a = getHex (optarg[7]) * 16 + getHex (optarg[8]);

	return 0;
}

void init_parse_options(int argc, char **argv){

	mh_parse_options_array(argc, argv, 0);

	}

static void mh_parse_options_array(int argc, char **argv, int finalrun){


	static char string_options [] = "fFCT:hvdce:t:g:n:s:a:";
//  no_argument  0
// required_argument 1
// optional_argument 2
static struct option long_options[] = {
 // a b c d e f g h i j k l m n o p q r s t u v w x y z
		{"fullscreen", 0,  0,  'F'},
	    {"fill",  0 ,  0, 'f'},
	    {"center", 0 ,0,'C'},
	    {"tile",1 , 0, 'T'}, // arg n=normal v = vertical etc..
	    {"flip-image-horz", 0 ,0, 'h'},
	    {"flip-image-vert", 0 , 0 , 'v'},
	    {"flip-image-dia", 0, 0, 'd'},
	    {"resize-center", 0, 0, 'c'},
	    {"resize-flip",1 , 0, 'e'},
	    {"resize-tile", 1, 0, 't'}, // no arg for normal tile
	   {"geometry", 1, 0, 'g'},
	//    {"filename", 1, 0, 'n'},
	    {"gradient", 1, 0, 'a'},
	    // add colors
	    {"solid", 1 , 0 , 's'},

	      {"add", 1,0, 200},
	      {"addd", 1, 0 , 201},
		{0,0,0,0}
	}; // end options

	int c;
 	int opterr;
	int option_index = 0;
	int distance, distanceflag = 3;

	extern char *optarg;
	extern int optind;

	while (( c = getopt_long_only(argc, argv, string_options, long_options,&option_index) ) != -1) {

		Color co;
		switch (c) {
			case 'F':
			    mode = FULLSCREEN;
				break;
			case 'f':
				mode = FILL;
				break;
			case 'C':
				mode = CENTER;
				break;
			case 'T':
				if (strcmp(optarg, "v")== 0)
				{
					mode = TILEV;
				}
				else if (strcmp(optarg,  "h") == 0)
				{
					mode = TILEH;
				}
				else if (strcmp(optarg, "hv") == 0 )
				{
					mode = TILEHV;
				}
				else if(strcmp(optarg, "n") == 0)
				{
					mode = TILE;
				}
				break;
			case 'h':
				mode = FLIPIMGH;
				break;
			case 'v':
				mode = FLIPIMGV;
				break;
			case 'd':
				mode = FLIPIMGD;
				break;
			case 'c':
				mode = DCENTER;
				break;
			case 'e':
				if (strcmp(optarg, "v") == 0)
				{
					mode = DFLIPIMGV;
				}
				else if(strcmp(optarg, "d") == 0 )
				{
					mode =DFLIPIMGD;
				}
				else if(strcmp(optarg, "h") == 0 )
				{
					mode = DFLIPIMGH;
				}
				break;
			case 't': // resize tile
				if (strcmp(optarg, "v")== 0)
				{
					mode = DTILEV;
				}
				else if (strcmp(optarg,  "h") == 0)
				{
					mode = DTILEH;
				}
				else if (strcmp(optarg, "hv") == 0 )
				{
					mode = DTILEHV;
				}
				else if(strcmp(optarg, "n") == 0 )
				{
					mode = DTILE;
				}
				break;
			case 'g':
				strcpy (str1, optarg);
				if (findX(str1, &w, &h) == 0 )
				{
					newW = w;
					newH = h;
				}
				break;
				/**
			case 'n':
				printf("in case file %s\n", optarg);
				filename = optarg;
				break;
				* **/

			case 's':

				getScreenDimentions(&w, &h);
						screenwidth = w;
						screenheight = h;
				parse_color (optarg, &co, 255); // alpha = 255
				imlib_context_set_color (co.r, co.g, co.b, co.a);
				imlib_image_fill_rectangle (0, 0, screenwidth, screenheight);

				break;
			case 'a':
				getScreenDimentions(&w, &h);
						screenwidth = w;
						screenheight = h;
				imlib_image_fill_color_range_rectangle (0, 0, screenwidth, screenheight, atoi(optarg)); // optarg = int
				break;

			case 200:
				// -add "#FFFFFF" -add "#FFFFFF"
				// I'm sure their is a better - busy right now.
				if (parse_color (optarg, &co, 255) == 1 ) // alpha = 255
				{
					printf("Bad Color <%s>\n", optarg);
				}
				imlib_context_set_color (co.r, co.g, co.b, co.a);
				imlib_add_color_to_color_range (1);

				break;
		case 201:
				printf("addd color\n");
				printf("optind %d argc %d\n", optind, argc);
				printf("argv[optind] is %s\n", argv[optind]);



				if (!isdigit(atoi(argv[optind])))
				{
					distanceflag = 0;
				}
				else
				{
					distanceflag = 1;
				}



				parse_color (optarg, &co, 255); // alpha = 255
				imlib_context_set_color (co.r, co.g, co.b, co.a);
				imlib_add_color_to_color_range (distance);

				break;


			 case '?':
                printf("Unknown option\n");
                break;


		default:
			break;

		} // end switch
		if (distanceflag == 0)
		{
			 /* distance  is mandatory */
			fprintf(stderr, "%s: missing  distance\n", argv[0]);
			exit(1);
		 }
	} // end while
	printf("optind before if (optind %d < argv %d )\n",optind, argc);

	  if (optind < argc) /* these are the arguments after the command-line options */
		for (; optind < argc; optind++)
		{
			printf("argument: \"%s\"\n", argv[optind]);

				if(isdigit(atoi(argv[optind])) )
					{
					printf("got number %d\n", atoi(argv[optind]));

					sscanf (argv[optind], "%i", &distance);
				}
				else
				filename = argv[optind];
		}
		else
		{
			printf("no arguments left to process\n");
		}

printf("filename is %s\n", filename );

    optind = 0;

} //end function
optind goes plus one to get next on line. I am assuming that one that is programming this needs to use some kind of logic applied to how the arguments need to be else through an error.


I have an option that requires two (2) arguments added to it for it to work.

RGBA red green blue alpha (int)

so I am trying to get it to work - which it does when I do not put in error checking (the way I am doing it, which cannot be right) as long as one enters all of the information correctly. it will work.

my error checking logic is off.


when I comment out the error checking I get this:
Code:
//    0     1  2    3         4      5       6      7      8      9   10 11  12
> ./tryme2 -c -g 1200x400  --addd "#FF0000" 32   --addd "#eef442" 4  -a 43  /home/userx/slackware_14.jpg
addd color
optind 6 argc 13
argv[optind] is 32
addd color
optind 9 argc 13
argv[optind] is 4
optind before if (optind 10 < argv 13 )
argument: "32"
argument: "4"
argument: "/home/userx/slackware_14.jpg"
filename is /home/userx/slackware_14.jpg
in setImage loadimage.c
where optind is at in --addd where it takes the required arg then the next one with is option current count when it is inside of --addd

so when a number is missing the next char is optind. if I take that same value that is indicated by optind then check it for isdigit if no flag it - check flag at end of switch

in my mind regardless of passes it is either going to be spot on if the number is there and if not the isdigit will say no and it gets flaged as not there.

when I comment out the error checking and put in all of the correct information it fails.

but does not fail without the check.

this is with error checking
Code:
  //   0    1  2  3           4      5      6       7     8       9   10 11        12  
> ./tryme2 -c -g 1200x400  --addd "#FF0000" 32   --addd "#eef442" 4  -a 43  /home/userx/slackware_14.jpg
addd color
optind 6 argc 13
argv[optind] is 32
./tryme2: missing  distance
saying that optind 9 which is the value of 4 is not an int because it is flagged 1
Code:
if (!isdigit(atoi(argv[optind])))
{
    distanceflag = 0;
}
else
{
   distanceflag = 1;
}

// the check here at the end of the switch checks for zero if flagged not int


if (distanceflag == 0)
		{
			 /* distance  is mandatory */
			fprintf(stderr, "%s: missing  distance\n", argv[0]);
			exit(1);
		 }
it is the same count where both optind should be the same information in it
where on the first instance is this
Code:
optind 6 argc 13
argv[optind] is 32
optind is 6 which = 32 an int
[/code]

and the second one down the line still stays the same.
Code:
optind 9 argc 13
argv[optind] is 4
optind is 9 which = 4

nothing has changed but it gets a is not a digit


when adding this line to where the flag is being set:
Code:
	if (!isdigit(atoi(argv[optind])))
					printf("\n\nIsDigit - atoi(argv[optind] %d\n\n", atoi(argv[optind]));
we see that both times it is checked and comes back valid.

Code:
// 0        1  2  3          4       5      6      7      8       9   10 11        12
> ./tryme2 -c -g 1200x400  --addd "#FF0000" 32   --addd "#eef442" 4  -a 43  /home/userx/slackware_14.jpg
addd color
optind 6 argc 13
argv[optind] is 32


IsDigit - atoi(argv[optind] 32

addd color
optind 9 argc 13
argv[optind] is 4


IsDigit - atoi(argv[optind] 4

optind before if (optind 10 < argv 13 )
argument: "32"
argument: "4"
argument: "/home/userx/slackware_14.jpg"
filename is /home/userx/slackware_14.jpg
in setImage loadimage.c
AND if I leave one or the other out without error checking optind shows an option being the on the count of optind.
Code:

                                                    // missing    ^ shows next 
> ./tryme2 -c -g 1200x400  --addd "#FF0000" 32   --addd "#eef442"   -a 43  /home/userx/slackware_14.jpg
addd color
optind 6 argc 12
argv[optind] is 32


IsDigit - atoi(argv[optind] 32

addd color
optind 9 argc 12
argv[optind] is -a


IsDigit - atoi(argv[optind] 0

optind before if (optind 10 < argv 12 )
argument: "32"
argument: "/home/userx/slackware_14.jpg"
filename is /home/userx/slackware_14.jpg
in setImage loadimage.c


-------------------------------------------------------------------------------------------------
                              //missing     ^ shows next
> ./tryme2 -c -g 1200x400  --addd "#FF0000"    --addd "#eef442" 55  -a 43  /home/userx/slackware_14.jpg
addd color
optind 6 argc 12
argv[optind] is --addd


IsDigit - atoi(argv[optind] 0

addd color
optind 8 argc 12
argv[optind] is 55
optind before if (optind 10 < argv 12 )
argument: "55"
got number 55
argument: "/home/userx/slackware_14.jpg"
filename is /home/userx/slackware_14.jpg
in setImage loadimage.c
they should then show isdigit as a non zero and then get flagged. with error checking on, because they are now missing,


as stated when they are both there it then still gets flagged as not a number (digit).
with the last one a file name that I grab because that is all that can be left.


so where am I failing again in my logic?

Last edited by BW-userx; 08-02-2017 at 06:08 PM.
 
Old 08-02-2017, 06:14 PM   #2
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,638

Original Poster
Rep: Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857
I just added this to the error output to show what it is talking about.

Code:
if (!isdigit(atoi(argv[optind])))
{
printf("in Flag: 0 atoi(argv[optind] %d\n", atoi(argv[optind]));
distanceflag = 0;
}
else
{
printf("in Flag 1 atoi(argv[optind] %d\n", atoi(argv[optind]));
distanceflag = 1;
}

Code:
if (distanceflag == 0)
{
 /* distance  is mandatory */
fprintf(stderr, " distanceflag  %d, %s: missing  distance: %d\n", distanceflag ,argv[0], atoi(argv[optind]));
exit(1);
}
}
error check I even atoi(argv[optind]) and gets an int.
this is what I ran :
Code:
> ./tryme2 -c -g 1200x400  --addd "#FF0000"  44 --addd "#eef442" 55  -a 43  /home/userx/slackware_14.jpg
addd color

optind 6 argc 13

argv[optind] is 44

in Flag: 0 atoi(argv[optind] 44

 distanceflag  0, ./tryme2: missing  distance: 44
Both values are there. and isdigit is saying it is not when I apply it to error checking?

Last edited by BW-userx; 08-02-2017 at 06:27 PM.
 
Old 08-02-2017, 11:00 PM   #3
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_10{.0|.1|.2}
Posts: 4,417
Blog Entries: 6

Rep: Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374
Quote:
Originally Posted by BW-userx View Post
Oh Kay I'm back, now I am trying to set a flag to indicate missing needed "non valid" argument.

with out this check it works as long as you add this needed argument that getopt only provides for after everything else.

so I am going to just post everything - instead of guessing and reading someone saying got a see it.
But we still can't "see" it - it disappears into a wall of text which most will either skim or skip completely. The real object should be to reduce your code to some simplest example which illustrates the precise problem, then post your question and the example. Very often, in fact almost always that exercise will lead you to a solution, or at least a much better understanding of how it should work.

I know I have asked before, and no one likes a nag, but I will ask you again to please put more effort into how you present your questions, in a way more respectful of other people's time. It benefits you, and other members and every future visitor who lands on this page after their own search.

If you need to post whole sections of your application's code, then I strongly recommend that you use your LQ blog space to do so. That will allow you to maintain updated code in a format which you can easily reference and share in forum posts, but without the constraints that normally apply to forum posts and questions.

OK, that out of the way, here is the core of the problem as I see it (without trying to debug the whole thing)...

Quote:
Originally Posted by BW-userx View Post
I have an option that requires two (2) arguments added to it for it to work.

RGBA red green blue alpha (int)

so I am trying to get it to work - which it does when I do not put in error checking (the way I am doing it, which cannot be right) as long as one enters all of the information correctly. it will work.
getopt() only supports zero or one argument per option. If you require two arguments then you have to handle that yourself. You think that you are doing that with the look-ahead, but you are being too clever.

What is happening here is two-fold: getopt knows nothing of your look-ahead peek at the second argument, and what your look-ahead code sees in argv[optind] depends on how it got there (i.e. everything that went before it)! This is because getopt() permutes non-option arguments as they are encountered - that is, inside your loop.

When you pass this string of arguments into your application...

Code:
//    0     1  2    3         4      5       6      7      8      9   10 11  12
> ./tryme2 -c -g 1200x400  --addd "#FF0000" 32   --addd "#eef442" 4  -a 43  /home/userx/slackware_14.jpg
...When argument #4 is found its val is returned (201), optarg is pointed to "#FF0000" and optind is incremented twice, making it point to "32".

If your look-ahead now peeks at argv[optind] it will see "32" at that instant.

Then we go around the loop again and oops - getopt sees "32" too, a non-option argument, so it permutes the argv array moving that arg to the position beyond #7 and it's arg, #8, moving #7->#6 and #8->#7, and "32"->#8!

Now, you receive another --addd (201), peek ahead and what do you see? "32" - an integer, so you pass the test again, but the real second agrument to this instance of --addd should have been "4"!

Once more around the loop, getopt permutes "32" and "4" then finds -a and its argument, "43", leaving arguments #10,#11 and #12 with values of "32", "4" and /home/userx/slackware_14.jpg still to be processed by your code!

When you turn your error checking on and off you change how you got there (i.e. you are looking at it at a different point in time, and in a different sequence of operations). If argv has been permuted in the mean time, you see something different...

The above is a conceptual example of what is happening, the actual mechanics may differ. But the difficulty arises from trying to use getopt in a way it was not intended by requiring two arguments for one option. You can cheat that mechanism by incrementing optind yourself (which you are not doing as far as I have seen), but that leads to additional consequences, exploration of which I leave to you!

One additional complication is that you are using those argument values inside the getopt reading loop. As such, they are used before they are all parsed. That is sometimes a good way to do it, sometimes not. As a general practice I always process "consumable" args first, then non-option args (after permutation), then apply error checking, only then put them to use.

If you truly must use options which accept more than one argument, then getopt may not be the right tool to use. I would suggest that you consider redefining your options, or how multiple arguments may be passed to them (hint: -g 1200x400), and choose a best strategy instead of trying to force it to work with getopt by juggling indexes in ways other than as intended.

Hope this helps!

Last edited by astrogeek; 08-03-2017 at 01:31 AM. Reason: more typos, added final comment
 
Old 08-03-2017, 01:16 AM   #4
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_10{.0|.1|.2}
Posts: 4,417
Blog Entries: 6

Rep: Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374
Picking up where we left off...

Quote:
Originally Posted by BW-userx View Post
I just added this to the error output to show what it is talking about.

Code:
if (!isdigit(atoi(argv[optind])))
That is not right, isdigit() takes a character argument, but this passes it an integer.
 
Old 08-03-2017, 03:19 AM   #5
pan64
LQ Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 9,462

Rep: Reputation: 2778Reputation: 2778Reputation: 2778Reputation: 2778Reputation: 2778Reputation: 2778Reputation: 2778Reputation: 2778Reputation: 2778Reputation: 2778Reputation: 2778
I still think you make things overcomplicated, please construct simple functions with simple functionality. Do not try to solve everything in one line. Remember nowadays the built-in optimization of gcc is much better than (the human beings) it was, so the compact code will not be better just makes the code unreadable.

regarding the comment of astrogeek:
1. I think you need to compile using -Wall and also fix all the warnings you got.
2. (as far as I see) you wrote atoi(argv[optind])) at least 3 times in your code, which is probably compact, but not efficient.
 
Old 08-03-2017, 08:14 AM   #6
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,638

Original Poster
Rep: Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857
Quote:
Originally Posted by astrogeek View Post
But we still can't "see" it - it disappears into a wall of text which most will either skim or skip completely. The real object should be to reduce your code to some simplest example which illustrates the precise problem, then post your question and the example. Very often, in fact almost always that exercise will lead you to a solution, or at least a much better understanding of how it should work.
Quote:
I know I have asked before, and no one likes a nag, but I will ask you again to please put more effort into how you present your questions, in a way more respectful of other people's time. It benefits you, and other members and every future visitor who lands on this page after their own search.

If you need to post whole sections of your application's code, then I strongly recommend that you use your LQ blog space to do so. That will allow you to maintain updated code in a format which you can easily reference and share in forum posts, but without the constraints that normally apply to forum posts and questions.

OK, that out of the way, here is the core of the problem as I see it (without trying to debug the whole thing)...
WELL:
the time before when I tried to keep it as simple as possible I was then told I needed to post my code. or "they'd" not understand what I was talking about, so I did, this time, I just forwent that and posed my code, and tried to explain every which way I already tried, and the results of each try.

As per what is said in here, show one what they have first tried to do - show examples of what they tried to do and what failed, and what they are doing, show the work or else one may think they are not even trying to figure it out so they will know. and in some cases it is easier to just tell them this is how to do it. without then having to try to figure it out. then they will know for the next time, but that is of another issue.

and yes even I do not like reading everything word for word. but skim the post for quick information, like the first paragraph is only read, even in news papers, they know the head line has to get ones attention and then if that first paragraph is not interesting, the article gets left behind.

But as I said I was trying to forgo that we need more information post.

Damné si vous le faites et damné si vous ne le faites pas - c'est la vie

(i'm going to post this now and read the rest of what you and the others have said. )
Quote:
getopt() only supports zero or one argument per option. If you require two arguments then you have to handle that yourself. You think that you are doing that with the look-ahead, but you are being too clever.

What is happening here is two-fold: getopt knows nothing of your look-ahead peek at the second argument, and what your look-ahead code sees in argv[optind] depends on how it got there (i.e. everything that went before it)! This is because getopt() permutes non-option arguments as they are encountered - that is, inside your loop.

When you pass this string of arguments into your application...

Code:
//    0     1  2    3         4      5       6      7      8      9   10 11  12
> ./tryme2 -c -g 1200x400  --addd "#FF0000" 32   --addd "#eef442" 4  -a 43  /home/userx/slackware_14.jpg
...When argument #4 is found its val is returned (201), optarg is pointed to "#FF0000" and optind is incremented twice, making it point to "32".

If your look-ahead now peeks at argv[optind] it will see "32" at that instant.

Then we go around the loop again and oops - getopt sees "32" too, a non-option argument, so it permutes the argv array moving that arg to the position beyond #7 and it's arg, #8, moving #7->#6 and #8->#7, and "32"->#8!

Now, you receive another --addd (201), peek ahead and what do you see? "32" - an integer, so you pass the test again, but the real second agrument to this instance of --addd should have been "4"!

Once more around the loop, getopt permutes "32" and "4" then finds -a and its argument, "43", leaving arguments #10,#11 and #12 with values of "32", "4" and /home/userx/slackware_14.jpg still to be processed by your code!

When you turn your error checking on and off you change how you got there (i.e. you are looking at it at a different point in time, and in a different sequence of operations). If argv has been permuted in the mean time, you see something different...

The above is a conceptual example of what is happening, the actual mechanics may differ. But the difficulty arises from trying to use getopt in a way it was not intended by requiring two arguments for one option. You can cheat that mechanism by incrementing optind yourself (which you are not doing as far as I have seen), but that leads to additional consequences, exploration of which I leave to you!

One additional complication is that you are using those argument values inside the getopt reading loop. As such, they are used before they are all parsed. That is sometimes a good way to do it, sometimes not. As a general practice I always process "consumable" args first, then non-option args (after permutation), then apply error checking, only then put them to use.

If you truly must use options which accept more than one argument, then getopt may not be the right tool to use. I would suggest that you consider redefining your options, or how multiple arguments may be passed to them (hint: -g 1200x400), and choose a best strategy instead of trying to force it to work with getopt by juggling indexes in ways other than as intended.

Hope this helps!
<reply starts here>

so starting with the after the switch code,
Code:
  if (optind < argc) /* these are the arguments after the command-line options */
for (; optind < argc; optind++)
{
printf("argument: \"%s\"\n", argv[optind]);
  if(isdigit(atoi(argv[optind])) )
  {
    printf("got number %d\n", atoi(argv[optind]));
    // it gets picked up here for use.
     sscanf (argv[optind], "%i", &distance);
   }
else
    // char or string gets picked up here. 
    filename = argv[optind];
}
else
{
printf("no arguments left to process\n");
}

printf("filename is %s\n", filename );

optind = 0;
where if I modified that it'd only show the remaining "stuff" that was inserted that was not part of the options requirements.

if you look closely you'll see this is where I was picking it up at.
and that only the code within the switch was for trying to catch it when the user forgot to add that needed required information, if not there throw an error message exit.

therefore if user enters:
Code:
--addd "#FFF000" <here a int has to be else fails>
so with optind looking ahead by one to match thier option listings, if it does then it will show up within it by checking it for isdigit.

because it cannot be it has to be
Code:
//short -g
//or
//long --long
first that getopt sees else it will skip it.

still the optind indicates what it is that getopt is looking at. I too am just looking at the same thing to use it to check for isdigit -

because regardless of what the user puts on the line, it is always going to be in this format. if using rgba colors. Indicated by the long -- option only.

Code:
--addd <color> <int>
anything after that

if it is not just like that above then it going to end up to be this instead.
Code:
--add <color> -b <or> --long
which getopt is set up to see and get only this.
Code:
-add <color>
then go to the next option long or short. Nevertheless it is always going to have the one more to look ahead to see what that next one is, if it is not an option it skips it by using optind. resets to zero and runs the loop again.(?)


in my test it is always showing one ahead. I am trying to use use that to my advantage to just show me what it is seeing and using to tell it to stop reset to zero run again.


just before it does, because I'll see it first then throw an error message exit before it resets to zero, I reset it to zero, but that does not matter and more because I already called to exit the program.


I do hope you're understanding that line of thought.

it is to catch the error user made send message to user then shut it down to prevent further errors.

now that I've said all of that, I'm going to process it and yours and putting them together and see what I get.

because I think I know by what you've said, I just got to find it and fix it.

or figure out a different way to throw error messages and exit.

Last edited by BW-userx; 08-03-2017 at 08:40 AM.
 
Old 08-03-2017, 08:55 AM   #7
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,638

Original Poster
Rep: Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857
Quote:
Originally Posted by pan64 View Post
I still think you make things overcomplicated, please construct simple functions with simple functionality. Do not try to solve everything in one line. Remember nowadays the built-in optimization of gcc is much better than (the human beings) it was, so the compact code will not be better just makes the code unreadable.

regarding the comment of astrogeek:
1. I think you need to compile using -Wall and also fix all the warnings you got.
2. (as far as I see) you wrote atoi(argv[optind])) at least 3 times in your code, which is probably compact, but not efficient.
thanks let me toss that into my copy paste and up arrow line of compiling. and fictionalize everything. but I usually try to get it to work first then see how I can then put it into a function next. unless I already know how to make it a function that works. well I do not do this on a daily basis. I have not touch C in over 4 years. and even then I only had a slim basic idea of what I was doing.

thanks for your advice.
 
Old 08-03-2017, 09:33 AM   #8
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,638

Original Poster
Rep: Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857
Quote:
Originally Posted by astrogeek View Post
Picking up where we left off...



That is not right, isdigit() takes a character argument, but this passes it an integer.
Yeah but look at what I am getting, checking for return zero if it is a digit, so != 0 should be a valid way for checking character is not a digit.
Code:
 printf("right before check - isdigit(argv[optind]) %s\n",argv[optind]);

if (isdigit(argv[optind]) != 0)

//if (!isdigit(argv[optind]))

printf("\n\nIsDigit - isdigit(argv[optind]) %s\n\n",argv[optind]);
digit is 20
Code:
right before check - isdigit(argv[optind]) 20
Segmentation fault
use the other way of doing this,
Code:
 printf("right before check - isdigit(argv[optind]) %s\n",argv[optind]);

//if (isdigit(argv[optind]) != 0)

if (!isdigit(argv[optind]))

printf("\n\nIsDigit - atoi(argv[optind] %s\n\n",argv[optind]);
digit is 20
Code:
> ./checkforColor --addd  "#f44242" 20  --add "#4286f4" 30  -a 30
addd color
optind 3 argc 9
next optind 3 argv[optind] is 20

right before check - isdigit(argv[optind]) 20
Segmentation fault
regardless whatever or however it is getting passed to isdigit is is not suppose to seg fault.

atoi stopped that from happening. which atoi(char) will give an integer so yeah that's bad logic.

still does not explain the seg fault

Last edited by BW-userx; 08-03-2017 at 09:41 AM.
 
Old 08-03-2017, 11:30 AM   #9
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,638

Original Poster
Rep: Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857
Quote:
Originally Posted by astrogeek View Post
What is happening here is two-fold: getopt knows nothing of your look-ahead peek at the second argument, and what your look-ahead code sees in argv[optind] depends on how it got there (i.e. everything that went before it)! This is because getopt() permutes non-option arguments as they are encountered - that is, inside your loop.

When you pass this string of arguments into your application...

Code:
//    0     1  2    3         4      5       6      7      8      9   10 11  12
> ./tryme2 -c -g 1200x400  --addd "#FF0000" 32   --addd "#eef442" 4  -a 43  /home/userx/slackware_14.jpg
...When argument #4 is found its val is returned (201), optarg is pointed to "#FF0000" and optind is incremented twice, making it point to "32".

If your look-ahead now peeks at argv[optind] it will see "32" at that instant.

Then we go around the loop again and oops - getopt sees "32" too, a non-option argument, so it permutes the argv array moving that arg to the position beyond #7 and it's arg, #8, moving #7->#6 and #8->#7, and "32"->#8!

Now, you receive another --addd (201), peek ahead and what do you see? "32" - an integer, so you pass the test again, but the real second agrument to this instance of --addd should have been "4"!

Once more around the loop, getopt permutes "32" and "4" then finds -a and its argument, "43", leaving arguments #10,#11 and #12 with values of "32", "4" and /home/userx/slackware_14.jpg still to be processed by your code!

When you turn your error checking on and off you change how you got there (i.e. you are looking at it at a different point in time, and in a different sequence of operations). If argv has been permuted in the mean time, you see something different...

The above is a conceptual example of what is happening, the actual mechanics may differ. But the difficulty arises from trying to use getopt in a way it was not intended by requiring two arguments for one option. You can cheat that mechanism by incrementing optind yourself (which you are not doing as far as I have seen), but that leads to additional consequences, exploration of which I leave to you!

One additional complication is that you are using those argument values inside the getopt reading loop. As such, they are used before they are all parsed. That is sometimes a good way to do it, sometimes not. As a general practice I always process "consumable" args first, then non-option args (after permutation), then apply error checking, only then put them to use.

If you truly must use options which accept more than one argument, then getopt may not be the right tool to use. I would suggest that you consider redefining your options, or how multiple arguments may be passed to them (hint: -g 1200x400), and choose a best strategy instead of trying to force it to work with getopt by juggling indexes in ways other than as intended.

Hope this helps!
so getopt runs the line hits an option (--option) optind+1 -> gets optarg . jumps out of switch, begins again, where it left off ?

Code:
 first run
./appname --option1 optarg --option2 optarg

(option1 optarg)
var1 = optarg;
second run it starts where it left off and it sees this?
Code:
--option2 optarg
var2 = optarg
then it is now at end of line so it gets set to -1 , kicks out of loop. var1 and var2 two have their needed values,

but, when option1 is used more than once within the same line, then does not option1 being used more than one will then need something like an array to keep values?

Code:
./appname --(d)option1 var1=3 --(w)option2 var=303 --(d)option1 val2=8
runs down picks up --d twice because that is how it is needed to be done instead of making another option that holds the same twice needed data to keep it separate ,


if var1 is not an array it gets over written on second pass?
Code:
--(d)option val1 = 3
chops of --(w)option var = 303 var is saved
--(d)option var2=8
where var1 and var2 are actually the same thing. so it get over written. confusing I am sure but write it out to where it needs to be used twice in the same line and both can be different.
Code:
color  
color  
gradient <int>
two colors on the screen at a given angle.

imlib_add_color_to_color_range (int distance_away) over lays colors over another color, two colors asked for then the distance . no big deal,

rgba
Code:
color <value>
color  <value>
gradient <int>
<value> twice can be two different values same var used in --option then should be an
Code:
int array[2] = {value first time, value second time}; // same --option
?


ran the same way to vary the effect need <a> anyways the beforehand, before I get too carried away in explaining everything. as if you really want to know or need to know that part of it.

This part:

the way optget works is - it runs down the line (string) until it gets one, resets, then starts over again where it left off in the line (string) - goes through that looking for one again, if it finds one, it just keeps repeating this mode of operation until it gets to the end of line then sets itself -1.

one being an -- or -

anything it encounters that is not designated for an argument right after -- or - while it is looking gets saved too but set aside, then it hands it back to you at the end to do with it what you will, if anything. no errors thrown by getopt if the left overs are not used.

then their is the order of the left over are in when given back to deal with as well(?) which someone went over in "here" as well.

is that a correct assessment?

Last edited by BW-userx; 08-03-2017 at 11:53 AM.
 
Old 08-03-2017, 06:14 PM   #10
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_10{.0|.1|.2}
Posts: 4,417
Blog Entries: 6

Rep: Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374
Quote:
Originally Posted by BW-userx View Post
the time before when I tried to keep it as simple as possible I was then told I needed to post my code. or "they'd" not understand what I was talking about, so I did, this time, I just forwent that and posed my code, and tried to explain every which way I already tried, and the results of each try.
What we include in any post should be the simplest description or example required to communicate the question in that post, on its merits alone (difficult enough!). There is no need to feel pressured to include more because of a request in some previous post. Conversely, when a member consistently posts too much or too little information, it frustrates others who may then overreact with their own comments... the object is for us all to find the right balance.

Reducing a problem to a minimal code example which demonstrates the single difficulty clearly is a necessary programmer's troubleshootng skill, as well as being a most effective communication method. Less is more in this context! Or as Albert Einstein is often quoted as saying,

Quote:
“Everything should be as simple as it can be, but not simpler”.
In the programming forum especially, keeping questions (and replies) well focused and easy to follow is a major factor in keeping the information accessible to others over the long term. Thanks for your help!

By the way, I will once again encourage you to make use of your LQ blog space for larger code segments and free discussion of your own projects, without the constraints required by a question oriented forum. There you can post as many iterations of your own code as you want and discuss your own design choices in ways that do not fit the forum format. It is a much under-used resource!

Last edited by astrogeek; 08-03-2017 at 06:30 PM. Reason: tpoys, typos
 
Old 08-03-2017, 06:19 PM   #11
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_10{.0|.1|.2}
Posts: 4,417
Blog Entries: 6

Rep: Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374
Quote:
Originally Posted by BW-userx View Post
regardless whatever or however it is getting passed to isdigit is is not suppose to seg fault.

atoi stopped that from happening. which atoi(char) will give an integer so yeah that's bad logic.

still does not explain the seg fault
Ah! I suspect this would have been one of those simple, specific questions which should have been asked earlier, and would have avoided much of the time taken to get to this point!

The reason for the segfault is this...

First, from man isdigit:

Code:
These functions check whether c, which must have the value of an unsigned char or EOF, falls into a cer‐
tain character class according to the current locale.
Now, argv is an array of pointers to characters, NOT an array of characters!

When you call it like this...

Code:
isdigit(argv[optind])
...you are passing it a pointer, not a character!

But when you call it this way...
Code:
isdigit(atoi(argv[optind]))
... you are passing it an integer, not the character representation of an integer, so your test fails!

Try it like this to get the desired result without segfault:
Code:
isdigit(*argv[optind])
BUT! What happens in this case, where the user provides no second argument or following arguments...

Code:
./trythis -addd "#ffffff"
...optind has been incremented, but points to... what, exactly...?

I leave that for your consideration, but this is another case that results from working outside what getopt() provides, and one you must handle on your own if you continue this path. (See my next comments to come shortly...).
 
Old 08-03-2017, 06:24 PM   #12
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_10{.0|.1|.2}
Posts: 4,417
Blog Entries: 6

Rep: Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374
Quote:
Originally Posted by BW-userx View Post
...
is that a correct assessment?
Hmmm... probably not (I have not tried to follow in detail), but mostly because my own example became too detailed and did not really communicate the central point I had in mind.

In fact, I added, "The above is a conceptual example of what is happening, the actual mechanics may differ", part specifically to avoid us falling into the trap of discussing just how getopt performs its permutations and loosing sight of the problem at hand!

So, let's step out of that trap and allow me to restate the point I was trying to make, which was this...

Imposing option rules or processing arguments out of the order provided by getopt() while in a getopt() driven input loop can lead to several unintended consequences as a result of argument permutations, including bad pointers as mentioned in my previous comment.

If you are going to use getopt(...) to parse your arguments, then you should work within its constraints and not engage in juggling indexes, peeking into arguments not yet processed and trying to impose constraints which are ultimately in conflict with the way getopt works, such as multiple arguments per option.

When you do that, you open yourself to all manner of unforeseen consequences!

If your requirements are in fundamental conflict with getopt operation, it is best, and easier in the long run, to simply write your own processing loop for your args.

So let's not begin to dissect exactly how some unspecified version of getopt() works internally, take a step back and consider the points on offer here.

Hope that is a bit more clear.
 
Old 08-03-2017, 07:14 PM   #13
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,638

Original Poster
Rep: Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857
Quote:
Originally Posted by astrogeek View Post
Ah! I suspect this would have been one of those simple, specific questions which should have been asked earlier, and would have avoided much of the time taken to get to this point!

The reason for the segfault is this...

First, from man isdigit:

Code:
These functions check whether c, which must have the value of an unsigned char or EOF, falls into a cer‐
tain character class according to the current locale.
Now, argv is an array of pointers to characters, NOT an array of characters!

When you call it like this...

Code:
isdigit(argv[optind])
...you are passing it a pointer, not a character!

But when you call it this way...
Code:
isdigit(atoi(argv[optind]))
... you are passing it an integer, not the character representation of an integer, so your test fails!

Try it like this to get the desired result without segfault:
Code:
isdigit(*argv[optind])
BUT! What happens in this case, where the user provides no second argument or following arguments...

Code:
./trythis -addd "#ffffff"
...optind has been incremented, but points to... what, exactly...?

I leave that for your consideration, but this is another case that results from working outside what getopt() provides, and one you must handle on your own if you continue this path. (See my next comments to come shortly...).
unsigned char and just char what I read is the same thing I googled it.
Code:
there is no difference. Actually on many platforms unqualified char is signed.
 The same way -- e.g. if you have an 8-bit char, 7 bits can be used for magnitude
 and 1 for sign. So an unsigned char might range from 0 to 255, 
whilst a signed char might range from -128 to 127 (for example)
neither one is a digit so isdigit should return a non zero

I too was checking for it
Code:
if(optarg)
but when I am changing code to try and figure it out yeah it is hard to keep track of so yeah...

so now i am playing catch up with post...
 
Old 08-03-2017, 07:23 PM   #14
BW-userx
Senior Member
 
Registered: Sep 2013
Location: MID-SOUTH USA
Distribution: Void Linux / Slackware 14.2
Posts: 4,638

Original Poster
Rep: Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857Reputation: 857
Quote:
Originally Posted by astrogeek View Post
Hmmm... probably not (I have not tried to follow in detail), but mostly because my own example became too detailed and did not really communicate the central point I had in mind.

In fact, I added, "The above is a conceptual example of what is happening, the actual mechanics may differ", part specifically to avoid us falling into the trap of discussing just how getopt performs its permutations and loosing sight of the problem at hand!

So, let's step out of that trap and allow me to restate the point I was trying to make, which was this...

Imposing option rules or processing arguments out of the order provided by getopt() while in a getopt() driven input loop can lead to several unintended consequences as a result of argument permutations, including bad pointers as mentioned in my previous comment.

If you are going to use getopt(...) to parse your arguments, then you should work within its constraints and not engage in juggling indexes, peeking into arguments not yet processed and trying to impose constraints which are ultimately in conflict with the way getopt works, such as multiple arguments per option.

When you do that, you open yourself to all manner of unforeseen consequences!

If your requirements are in fundamental conflict with getopt operation, it is best, and easier in the long run, to simply write your own processing loop for your args.

So let's not begin to dissect exactly how some unspecified version of getopt() works internally, take a step back and consider the points on offer here.

Hope that is a bit more clear.
I'll just try to refrain from asking questions in here because

“You can please some of the people all of the time, you can please all of the people some of the time, but you can’t please all of the people all of the time”.”

John Lydgate
 
Old 08-04-2017, 03:47 AM   #15
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=14, FreeBSD_10{.0|.1|.2}
Posts: 4,417
Blog Entries: 6

Rep: Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374Reputation: 2374
Quote:
Originally Posted by BW-userx View Post
I'll just try to refrain from asking questions in here because

“You can please some of the people all of the time, you can please all of the people some of the time, but you can’t please all of the people all of the time”.”

John Lydgate
I am not sure I understand why you have responded this way, please explain.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Is there a standard way to differentiate command line arguments and flags in C Alpha90 Programming 11 03-10-2016 09:27 PM
BASH script using getopt to parse optional arguments nano2 General 6 04-28-2011 08:09 AM
how is zero flags set telnet_ping Programming 5 09-14-2007 08:06 PM
How do you set compiler flags in SuSE? Thaidog SUSE / openSUSE 0 12-26-2006 10:04 PM
flags vs normal arguments merchtemeagle Programming 7 12-14-2005 10:20 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 05:58 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration