a263f96b0fb7d4a77ccaafb93bd638162b58fc15 — Drew DeVault 27 days ago 05fed9a
mrsh_getopt: handle repeated short options

This handles cases like cmd -arvx (where optstring is "arvx"). This also
changes the reset to mrsh_optind = 0, matching non-POSIX extensions in
various libcs, so that the user needn't also reset mrsh_optpos (which is
not exported from this file).
M builtin/alias.c => builtin/alias.c +1 -1
@@ 17,7 17,7 @@ }
  
  int builtin_alias(struct mrsh_state *state, int argc, char *argv[]) {
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	if (mrsh_getopt(argc, argv, ":") != -1) {
  		fprintf(stderr, "alias: unknown option -- %c\n", mrsh_optopt);
  		fprintf(stderr, alias_usage);

M builtin/cd.c => builtin/cd.c +1 -1
@@ 37,7 37,7 @@ }
  
  int builtin_cd(struct mrsh_state *state, int argc, char *argv[]) {
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	int opt;
  	while ((opt = mrsh_getopt(argc, argv, ":LP")) != -1) {
  		switch (opt) {

M builtin/getopts.c => builtin/getopts.c +1 -1
@@ 12,7 12,7 @@ static const char getopts_usage[] = "usage: getopts optstring name [arg...]\n";
  
  int builtin_getopts(struct mrsh_state *state, int argc, char *argv[]) {
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	if (mrsh_getopt(argc, argv, ":") != -1) {
  		fprintf(stderr, "getopts: unknown option -- %c\n", mrsh_optopt);
  		fprintf(stderr, getopts_usage);

M builtin/pwd.c => builtin/pwd.c +1 -1
@@ 8,7 8,7 @@ static const char pwd_usage[] = "usage: pwd [-L|-P]\n";
  
  int builtin_pwd(struct mrsh_state *state, int argc, char *argv[]) {
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	int opt;
  	while ((opt = mrsh_getopt(argc, argv, ":LP")) != -1) {
  		switch (opt) {

M builtin/read.c => builtin/read.c +1 -1
@@ 14,7 14,7 @@ int builtin_read(struct mrsh_state *state, int argc, char *argv[]) {
  	bool raw = false;
  
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	int opt;
  	while ((opt = mrsh_getopt(argc, argv, ":r")) != -1) {
  		switch (opt) {

M builtin/type.c => builtin/type.c +1 -1
@@ 9,7 9,7 @@ static const char type_usage[] = "usage: type name...\n";
  
  int builtin_type(struct mrsh_state *state, int argc, char *argv[]) {
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	if (mrsh_getopt(argc, argv, ":") != -1) {
  		fprintf(stderr, "type: unknown option -- %c\n", mrsh_optopt);
  		fprintf(stderr, type_usage);

M builtin/ulimit.c => builtin/ulimit.c +1 -1
@@ 14,7 14,7 @@ static const char ulimit_usage[] = "usage: ulimit [-f] [blocks]\n";
  
  int builtin_ulimit(struct mrsh_state *state, int argc, char *argv[]) {
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	int opt;
  	while ((opt = mrsh_getopt(argc, argv, ":f")) != -1) {
  		if (opt == 'f') {

M builtin/umask.c => builtin/umask.c +1 -1
@@ 162,7 162,7 @@ mode_t mode;
  	bool umask_symbolic = false;
  
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	int opt;
  
  	while ((opt = mrsh_getopt(argc, argv, ":S")) != -1) {

M builtin/unalias.c => builtin/unalias.c +1 -1
@@ 15,7 15,7 @@ int builtin_unalias(struct mrsh_state *state, int argc, char *argv[]) {
  	bool all = false;
  
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	int opt;
  	while ((opt = mrsh_getopt(argc, argv, ":a")) != -1) {
  		switch (opt) {

M builtin/unset.c => builtin/unset.c +1 -1
@@ 11,7 11,7 @@ int builtin_unset(struct mrsh_state *state, int argc, char *argv[]) {
  	bool funcs = false;
  
- 	mrsh_optind = 1;
+ 	mrsh_optind = 0;
  	int opt;
  	while ((opt = mrsh_getopt(argc, argv, ":fv")) != -1) {
  		switch (opt) {

M getopt.c => getopt.c +15 -4
@@ 7,11 7,17 @@ int mrsh_optind = 1;
  int mrsh_opterr = 1;
  int mrsh_optopt = 0;
+ int mrsh_optpos = 1;
  
  int mrsh_getopt(int argc, char *const argv[], const char *optstring) {
  	assert(argv[argc] == NULL);
  	mrsh_optarg = NULL;
  
+ 	if (mrsh_optind == 0) {
+ 		mrsh_optind = 1;
+ 		mrsh_optpos = 1;
+ 	}
+ 
  	if (mrsh_optind >= argc) {
  		return -1;
  	}


@@ 35,19 41,24 @@ }
  
  	mrsh_optopt = 0;
- 	int opt = argv[mrsh_optind][1];
+ 	int opt = argv[mrsh_optind][mrsh_optpos];
  	for (; *c != '\0'; c++) {
  		if (*c != opt) {
  			continue;
  		}
  
  		if (c[1] != ':') {
- 			mrsh_optind++;
+ 			if (argv[mrsh_optind][mrsh_optpos + 1] == '\0') {
+ 				mrsh_optind++;
+ 				mrsh_optpos = 1;
+ 			} else {
+ 				mrsh_optpos++;
+ 			}
  			return opt;
  		}
  
- 		if (argv[mrsh_optind][2] != '\0') {
- 			mrsh_optarg = &argv[mrsh_optind][2]; 
+ 		if (argv[mrsh_optind][mrsh_optpos + 1] != '\0') {
+ 			mrsh_optarg = &argv[mrsh_optind][mrsh_optpos + 1];
  		} else {
  			if (mrsh_optind + 2 > argc) {
  				mrsh_optopt = opt;