Example #1
0
int sort_pairs_by_arrival(file_t *f1, file_t *f2)
{
  if (f2->duplicates != 0)
    return !ISFLAG(flags, F_REVERSE) ? 1 : -1;

  return !ISFLAG(flags, F_REVERSE) ? -1 : 1;
}
Example #2
0
int sort_pairs_by_mtime(file_t *f1, file_t *f2)
{
  if (f1->mtime < f2->mtime)
    return !ISFLAG(flags, F_REVERSE) ? -1 : 1;
  else if (f1->mtime > f2->mtime)
    return !ISFLAG(flags, F_REVERSE) ? 1 : -1;

  return 0;
}
Example #3
0
static size_t
print_arg (char *string, size_t len, int mdoc, int longp, struct getargs *arg)
{
    const char *s;

    *string = '\0';

    if (ISFLAG(*arg) || (!longp && arg->type == arg_counter))
	return 0;

    if(mdoc){
	if(longp)
	    strlcat(string, "= Ns", len);
	strlcat(string, " Ar ", len);
    }else
	if (longp)
	    strlcat (string, "=", len);
	else
	    strlcat (string, " ", len);

    if (arg->arg_help)
	s = arg->arg_help;
    else if (arg->type == arg_integer || arg->type == arg_counter)
	s = "integer";
    else if (arg->type == arg_string)
	s = "string";
    else if (arg->type == arg_double)
	s = "float";
    else
	s = "<undefined>";

    strlcat(string, s, len);
    return 1 + strlen(s);
}
Example #4
0
void printmatches(file_t *files)
{
  file_t *tmpfile;

  while (files != NULL) {
    if (files->hasdupes) {
      if (!ISFLAG(flags, F_OMITFIRST)) {
	if (ISFLAG(flags, F_SHOWSIZE)) printf("%lld byte%seach:\n", files->size,
	 (files->size != 1) ? "s " : " ");
	if (ISFLAG(flags, F_DSAMELINE)) escapefilename("\\ ", &files->d_name);
	printf("%s%c", files->d_name, ISFLAG(flags, F_DSAMELINE)?' ':'\n');
      }
      tmpfile = files->duplicates;
      while (tmpfile != NULL) {
	if (ISFLAG(flags, F_DSAMELINE)) escapefilename("\\ ", &tmpfile->d_name);
	printf("%s%c", tmpfile->d_name, ISFLAG(flags, F_DSAMELINE)?' ':'\n');
	tmpfile = tmpfile->duplicates;
      }
      printf("\n");

    }
      
    files = files->next;
  }
}
Example #5
0
static size_t
print_arg (FILE *stream, int mdoc, int longp, struct agetargs *arg,
	   int style)
{
    const char *s = NULL;
    int len;

    if (ISFLAG(arg))
	return 0;

    if(mdoc){
	if(longp)
	    fprintf(stream, "= Ns");
	fprintf(stream, " Ar ");
    }else
	if (longp && !(style & AARG_TRANSLONG))
	    putc ('=', stream);
	else
	    putc (' ', stream);

    if (arg->arg_help)
	s = arg->arg_help;
    else if (arg->type == aarg_integer)
	s = "number";
    else if (arg->type == aarg_string)
	s = "string";
    else
	s = "undefined";

    if (style & AARG_TRANSLONG) {
	fprintf (stream, "<%s>", s);
	len = strlen(s) + 2;
    } else {
	fprintf (stream, "%s", s);
	len = strlen(s);
    }
    return 1 + len;
}
Example #6
0
int grokdir(char *dir, file_t **filelistp)
{
  DIR *cd;
  file_t *newfile;
  struct dirent *dirinfo;
  int lastchar;
  int filecount = 0;
  struct stat info;
  struct stat linfo;
  static int progress = 0;
  static char indicator[] = "-\\|/";

  cd = opendir(dir);

  if (!cd) {
    errormsg("could not chdir to %s\n", dir);
    return 0;
  }

  while ((dirinfo = readdir(cd)) != NULL) {
    if (strcmp(dirinfo->d_name, ".") && strcmp(dirinfo->d_name, "..")) {
      if (!ISFLAG(flags, F_HIDEPROGRESS)) {
	fprintf(stderr, "\rBuilding file list %c ", indicator[progress]);
	progress = (progress + 1) % 4;
      }

      newfile = (file_t*) malloc(sizeof(file_t));

      if (!newfile) {
	errormsg("out of memory!\n");
	closedir(cd);
	exit(1);
      } else newfile->next = *filelistp;

      newfile->device = 0;
      newfile->inode = 0;
      newfile->crcsignature = NULL;
      newfile->crcpartial = NULL;
      newfile->duplicates = NULL;
      newfile->hasdupes = 0;

      newfile->d_name = (char*)malloc(strlen(dir)+strlen(dirinfo->d_name)+2);

      if (!newfile->d_name) {
	errormsg("out of memory!\n");
	free(newfile);
	closedir(cd);
	exit(1);
      }

      strcpy(newfile->d_name, dir);
      lastchar = strlen(dir) - 1;
      if (lastchar >= 0 && dir[lastchar] != '/')
	strcat(newfile->d_name, "/");
      strcat(newfile->d_name, dirinfo->d_name);
      
      if (filesize(newfile->d_name) == 0 && ISFLAG(flags, F_EXCLUDEEMPTY)) {
	free(newfile->d_name);
	free(newfile);
	continue;
      }

      if (stat(newfile->d_name, &info) == -1) {
	free(newfile->d_name);
	free(newfile);
	continue;
      }

      if (lstat(newfile->d_name, &linfo) == -1) {
	free(newfile->d_name);
	free(newfile);
	continue;
      }

      if (S_ISDIR(info.st_mode)) {
	if (ISFLAG(flags, F_RECURSE) && (ISFLAG(flags, F_FOLLOWLINKS) || !S_ISLNK(linfo.st_mode)))
	  filecount += grokdir(newfile->d_name, filelistp);
	free(newfile->d_name);
	free(newfile);
      } else {
	if (S_ISREG(linfo.st_mode) || (S_ISLNK(linfo.st_mode) && ISFLAG(flags, F_FOLLOWLINKS))) {
	  *filelistp = newfile;
	  filecount++;
	} else {
	  free(newfile->d_name);
	  free(newfile);
	}
      }
    }
  }

  closedir(cd);

  return filecount;
}
Example #7
0
static int
arg_match_long(struct getargs *args, size_t num_args,
	       char *argv, int argc, const char **rargv, int *optind)
{
    unsigned int i;
    const char *optarg = NULL;
    int negate = 0;
    int partial_match = 0;
    struct getargs *partial = NULL;
    struct getargs *current = NULL;
    int argv_len;
    char *p;

    argv_len = (int)strlen(argv);
    p = strchr (argv, '=');
    if (p != NULL)
	argv_len = (int)(p - argv);

    for (i = 0; i < num_args; ++i) {
	if(args[i].long_name) {
	    int len = (int)strlen(args[i].long_name);
	    char *p = argv;
	    int p_len = argv_len;
	    negate = 0;

	    for (;;) {
		if (strncmp (args[i].long_name, p, p_len) == 0) {
		    if(p_len == len)
			current = &args[i];
		    else {
			++partial_match;
			partial = &args[i];
		    }
		    optarg  = p + p_len;
		} else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
		    negate = !negate;
		    p += 3;
		    p_len -= 3;
		    continue;
		}
		break;
	    }
	    if (current)
		break;
	}
    }
    if (current == NULL) {
	if (partial_match == 1)
	    current = partial;
	else
	    return ARG_ERR_NO_MATCH;
    }
    
    if(*optarg == '\0'
       && !ISFLAG(*current)
       && current->type != arg_collect
       && current->type != arg_counter)
	return ARG_ERR_NO_MATCH;
    switch(current->type){
    case arg_integer:
    {
	int tmp;
	if(sscanf(optarg + 1, "%d", &tmp) != 1)
	    return ARG_ERR_BAD_ARG;
	*(int*)current->value = tmp;
	return 0;
    }
    case arg_string:
    {
	*(char**)current->value = (char*)optarg + 1;
	return 0;
    }
    case arg_strings:
    {
	add_string((getarg_strings*)current->value, (char*)optarg + 1);
	return 0;
    }
    case arg_flag:
    case arg_negative_flag:
    {
	int *flag = current->value;
	if(*optarg == '\0' ||
	   strcmp(optarg + 1, "yes") == 0 || 
	   strcmp(optarg + 1, "true") == 0){
	    *flag = !negate;
	    return 0;
	} else if (*optarg && strcmp(optarg + 1, "maybe") == 0) {
	    *flag = rand() & 1;
	} else {
	    *flag = negate;
	    return 0;
	}
	return ARG_ERR_BAD_ARG;
    }
    case arg_counter :
    {
	int val;

	if (*optarg == '\0')
	    val = 1;
	else {
	    char *endstr;

	    val = strtol (optarg, &endstr, 0);
	    if (endstr == optarg)
		return ARG_ERR_BAD_ARG;
	}
	*(int *)current->value += val;
	return 0;
    }
    case arg_double:
    {
	double tmp;
	if(sscanf(optarg + 1, "%lf", &tmp) != 1)
	    return ARG_ERR_BAD_ARG;
	*(double*)current->value = tmp;
	return 0;
    }
    case arg_collect:{
	struct getarg_collect_info *c = current->value;
	int o = (int)(argv - rargv[*optind]);
	return (*c->func)(FALSE, argc, rargv, optind, &o, c->data);
    }

    default:
	abort ();
	return ARG_ERR_BAD_ARG;
    }
}
Example #8
0
static void
mandoc_template(struct getargs *args,
		size_t num_args,
		const char *progname,
		const char *extra_string)
{
    size_t i;
    char timestr[64], cmd[64];
    char buf[128];
    const char *p;
    time_t t;

    printf(".\\\" Things to fix:\n");
    printf(".\\\"   * correct section, and operating system\n");
    printf(".\\\"   * remove Op from mandatory flags\n");
    printf(".\\\"   * use better macros for arguments (like .Pa for files)\n");
    printf(".\\\"\n");
    t = time(NULL);
    strftime(timestr, sizeof(timestr), "%B %e, %Y", localtime(&t));
    printf(".Dd %s\n", timestr);
    p = strrchr(progname, '/');
    if(p) p++; else p = progname;
    strlcpy(cmd, p, sizeof(cmd));
    strupr(cmd);
       
    printf(".Dt %s SECTION\n", cmd);
    printf(".Os OPERATING_SYSTEM\n");
    printf(".Sh NAME\n");
    printf(".Nm %s\n", p);
    printf(".Nd\n");
    printf("in search of a description\n");
    printf(".Sh SYNOPSIS\n");
    printf(".Nm\n");
    for(i = 0; i < num_args; i++){
	/* we seem to hit a limit on number of arguments if doing
           short and long flags with arguments -- split on two lines */
	if(ISFLAG(args[i]) || 
	   args[i].short_name == 0 || args[i].long_name == NULL) {
	    printf(".Op ");

	    if(args[i].short_name) {
		print_arg(buf, sizeof(buf), 1, 0, args + i);
		printf("Fl %c%s", args[i].short_name, buf);
		if(args[i].long_name)
		    printf(" | ");
	    }
	    if(args[i].long_name) {
		print_arg(buf, sizeof(buf), 1, 1, args + i);
		printf("Fl -%s%s%s",
		       args[i].type == arg_negative_flag ? "no-" : "",
		       args[i].long_name, buf);
	    }
	    printf("\n");
	} else {
	    print_arg(buf, sizeof(buf), 1, 0, args + i);
	    printf(".Oo Fl %c%s \\*(Ba Xo\n", args[i].short_name, buf);
	    print_arg(buf, sizeof(buf), 1, 1, args + i);
	    printf(".Fl -%s%s Oc\n.Xc\n", args[i].long_name, buf);
	}
    /*
	    if(args[i].type == arg_strings)
		fprintf (stderr, "...");
		*/
    }
    if (extra_string && *extra_string)
	printf (".Ar %s\n", extra_string);
    printf(".Sh DESCRIPTION\n");
    printf("Supported options:\n");
    printf(".Bl -tag -width Ds\n");
    for(i = 0; i < num_args; i++){
	printf(".It Xo\n");
	if(args[i].short_name){
	    printf(".Fl %c", args[i].short_name);
	    print_arg(buf, sizeof(buf), 1, 0, args + i);
	    printf("%s", buf);
	    if(args[i].long_name)
		printf(" Ns ,");
	    printf("\n");
	}
	if(args[i].long_name){
	    printf(".Fl -%s%s",
		   args[i].type == arg_negative_flag ? "no-" : "",
		   args[i].long_name);
	    print_arg(buf, sizeof(buf), 1, 1, args + i);
	    printf("%s\n", buf);
	}
	printf(".Xc\n");
	if(args[i].help)
	    printf("%s\n", args[i].help);
    /*
	    if(args[i].type == arg_strings)
		fprintf (stderr, "...");
		*/
    }
    printf(".El\n");
    printf(".\\\".Sh ENVIRONMENT\n");
    printf(".\\\".Sh FILES\n");
    printf(".\\\".Sh EXAMPLES\n");
    printf(".\\\".Sh DIAGNOSTICS\n");
    printf(".\\\".Sh SEE ALSO\n");
    printf(".\\\".Sh STANDARDS\n");
    printf(".\\\".Sh HISTORY\n");
    printf(".\\\".Sh AUTHORS\n");
    printf(".\\\".Sh BUGS\n");
}
/* We parse the argument list in Unicode */
U_CFUNC int32_t
u_printf_parse(const u_printf_stream_handler *streamHandler,
               const UChar     *fmt,
               void            *context,
               u_localized_print_string *locStringContext,
               ULocaleBundle   *formatBundle,
               int32_t         *written,
               va_list         ap)
{
    uint16_t         handlerNum;
    ufmt_args        args;
    ufmt_type_info   argType;
    u_printf_handler *handler;
    u_printf_spec    spec;
    u_printf_spec_info *info = &(spec.fInfo);

    const UChar *alias = fmt;
    const UChar *backup;
    const UChar *lastAlias;

    /* iterate through the pattern */
    while(!locStringContext || locStringContext->available > 0) {

        /* find the next '%' */
        lastAlias = alias;
        while(*alias != UP_PERCENT && *alias != 0x0000) {
            alias++;
        }

        /* write any characters before the '%' */
        if(alias > lastAlias) {
            *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
        }

        /* break if at end of string */
        if(*alias == 0x0000) {
            break;
        }

        /* initialize spec to default values */
        spec.fWidthPos     = -1;
        spec.fPrecisionPos = -1;
        spec.fArgPos       = -1;

        uprv_memset(info, 0, sizeof(*info));
        info->fPrecision    = -1;
        info->fWidth        = -1;
        info->fPadChar      = 0x0020;

        /* skip over the initial '%' */
        alias++;

        /* Check for positional argument */
        if(ISDIGIT(*alias)) {

            /* Save the current position */
            backup = alias;

            /* handle positional parameters */
            if(ISDIGIT(*alias)) {
                spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);

                while(ISDIGIT(*alias)) {
                    spec.fArgPos *= 10;
                    spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
                }
            }

            /* if there is no '$', don't read anything */
            if(*alias != SPEC_DOLLARSIGN) {
                spec.fArgPos = -1;
                alias = backup;
            }
            /* munge the '$' */
            else
                alias++;
        }

        /* Get any format flags */
        while(ISFLAG(*alias)) {
            switch(*alias++) {

                /* left justify */
            case FLAG_MINUS:
                info->fLeft = TRUE;
                break;

                /* always show sign */
            case FLAG_PLUS:
                info->fShowSign = TRUE;
                break;

                /* use space if no sign present */
            case FLAG_SPACE:
                info->fShowSign = TRUE;
                info->fSpace = TRUE;
                break;

                /* use alternate form */
            case FLAG_POUND:
                info->fAlt = TRUE;
                break;

                /* pad with leading zeroes */
            case FLAG_ZERO:
                info->fZero = TRUE;
                info->fPadChar = 0x0030;
                break;

                /* pad character specified */
            case FLAG_PAREN:

                /* TODO test that all four are numbers */
                /* first four characters are hex values for pad char */
                info->fPadChar = (UChar)ufmt_digitvalue(*alias++);
                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));

                /* final character is ignored */
                alias++;

                break;
            }
        }

        /* Get the width */

        /* width is specified out of line */
        if(*alias == SPEC_ASTERISK) {

            info->fWidth = -2;

            /* Skip the '*' */
            alias++;

            /* Save the current position */
            backup = alias;

            /* handle positional parameters */
            if(ISDIGIT(*alias)) {
                spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);

                while(ISDIGIT(*alias)) {
                    spec.fWidthPos *= 10;
                    spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
                }
            }

            /* if there is no '$', don't read anything */
            if(*alias != SPEC_DOLLARSIGN) {
                spec.fWidthPos = -1;
                alias = backup;
            }
            /* munge the '$' */
            else
                alias++;
        }
        /* read the width, if present */
        else if(ISDIGIT(*alias)){
            info->fWidth = (int) (*alias++ - DIGIT_ZERO);

            while(ISDIGIT(*alias)) {
                info->fWidth *= 10;
                info->fWidth += (int) (*alias++ - DIGIT_ZERO);
            }
        }

        /* Get the precision */

        if(*alias == SPEC_PERIOD) {

            /* eat up the '.' */
            alias++;

            /* precision is specified out of line */
            if(*alias == SPEC_ASTERISK) {

                info->fPrecision = -2;

                /* Skip the '*' */
                alias++;

                /* save the current position */
                backup = alias;

                /* handle positional parameters */
                if(ISDIGIT(*alias)) {
                    spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);

                    while(ISDIGIT(*alias)) {
                        spec.fPrecisionPos *= 10;
                        spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
                    }

                    /* if there is no '$', don't read anything */
                    if(*alias != SPEC_DOLLARSIGN) {
                        spec.fPrecisionPos = -1;
                        alias = backup;
                    }
                    else {
                        /* munge the '$' */
                        alias++;
                    }
                }
            }
            /* read the precision */
            else if(ISDIGIT(*alias)){
                info->fPrecision = (int) (*alias++ - DIGIT_ZERO);

                while(ISDIGIT(*alias)) {
                    info->fPrecision *= 10;
                    info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
                }
            }
        }

        /* Get any modifiers */
        if(ISMOD(*alias)) {
            switch(*alias++) {

                /* short */
            case MOD_H:
                info->fIsShort = TRUE;
                break;

                /* long or long long */
            case MOD_LOWERL:
                if(*alias == MOD_LOWERL) {
                    info->fIsLongLong = TRUE;
                    /* skip over the next 'l' */
                    alias++;
                }
                else
                    info->fIsLong = TRUE;
                break;

                /* long double */
            case MOD_L:
                info->fIsLongDouble = TRUE;
                break;
            }
        }

        /* finally, get the specifier letter */
        info->fSpec = *alias++;
        info->fOrigSpec = info->fSpec;

        /* fill in the precision and width, if specified out of line */

        /* width specified out of line */
        if(spec.fInfo.fWidth == -2) {
            if(spec.fWidthPos == -1) {
                /* read the width from the argument list */
                info->fWidth = va_arg(ap, int32_t);
            }
            /* else handle positional parameter */

            /* if it's negative, take the absolute value and set left alignment */
            if(info->fWidth < 0) {
                info->fWidth *= -1; /* Make positive */
                info->fLeft = TRUE;
            }
        }

        /* precision specified out of line */
        if(info->fPrecision == -2) {
            if(spec.fPrecisionPos == -1) {
                /* read the precision from the argument list */
                info->fPrecision = va_arg(ap, int32_t);
            }
            /* else handle positional parameter */

            /* if it's negative, set it to zero */
            if(info->fPrecision < 0)
                info->fPrecision = 0;
        }

        handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
            /* query the info function for argument information */
            argType = g_u_printf_infos[ handlerNum ].info;
            switch(argType) {
            case ufmt_count:
                /* set the spec's width to the # of chars written */
                info->fWidth = *written;
                /* fall through to set the pointer */
            case ufmt_string:
            case ufmt_ustring:
            case ufmt_pointer:
                args.ptrValue = va_arg(ap, void*);
                break;
            case ufmt_char:
            case ufmt_uchar:
            case ufmt_int:
                if (info->fIsLongLong) {
                    args.int64Value = va_arg(ap, int64_t);
                }
                else {
                    args.int64Value = va_arg(ap, int32_t);
                }
                break;
            case ufmt_float:
                args.floatValue = (float) va_arg(ap, double);
                break;
            case ufmt_double:
                args.doubleValue = va_arg(ap, double);
                break;
            default:
                /* else args is ignored */
                args.ptrValue = NULL;
                break;
            }

            /* call the handler function */
            handler = g_u_printf_infos[ handlerNum ].handler;
            if(handler != 0) {
                *written += (*handler)(streamHandler, context, formatBundle, info, &args);
            }
            else {
                /* just echo unknown tags */
                *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
            }
        }
        else {
Example #10
0
void ROKEN_LIB_FUNCTION
arg_printusage_i18n (struct getargs *args,
		     size_t num_args,
		     const char *usage,
		     const char *progname,
		     const char *extra_string,
		     char *(i18n)(const char *))
{
    int i;
    size_t max_len = 0;
    char buf[128];
    int col = 0, columns;
    struct winsize ws;

    if (progname == NULL)
	progname = getprogname();

    if (i18n == NULL)
	i18n = builtin_i18n;

    if(getenv("GETARGMANDOC")){
	mandoc_template(args, num_args, progname, extra_string, i18n);
	return;
    }
    if(get_window_size(2, &ws) == 0)
	columns = ws.ws_col;
    else
	columns = 80;
    col = 0;
    col += fprintf (stderr, "%s: %s", usage, progname);
    buf[0] = '\0';
    for (i = 0; i < num_args; ++i) {
	if(args[i].short_name && ISFLAG(args[i])) {
	    char s[2];
	    if(buf[0] == '\0')
		strlcpy(buf, "[-", sizeof(buf));
	    s[0] = args[i].short_name;
	    s[1] = '\0';
	    strlcat(buf, s, sizeof(buf));
	}
    }
    if(buf[0] != '\0') {
	strlcat(buf, "]", sizeof(buf));
	col = check_column(stderr, col, strlen(buf) + 1, columns);
	col += fprintf(stderr, " %s", buf);
    }

    for (i = 0; i < num_args; ++i) {
	size_t len = 0;

	if (args[i].long_name) {
	    buf[0] = '\0';
	    strlcat(buf, "[--", sizeof(buf));
	    len += 2;
	    if(args[i].type == arg_negative_flag) {
		strlcat(buf, "no-", sizeof(buf));
		len += 3;
	    }
	    strlcat(buf, args[i].long_name, sizeof(buf));
	    len += strlen(args[i].long_name);
	    len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
			     0, 1, &args[i], i18n);
	    strlcat(buf, "]", sizeof(buf));
	    if(args[i].type == arg_strings)
		strlcat(buf, "...", sizeof(buf));
	    col = check_column(stderr, col, strlen(buf) + 1, columns);
	    col += fprintf(stderr, " %s", buf);
	}
	if (args[i].short_name && !ISFLAG(args[i])) {
	    snprintf(buf, sizeof(buf), "[-%c", args[i].short_name);
	    len += 2;
	    len += print_arg(buf + strlen(buf), sizeof(buf) - strlen(buf),
			     0, 0, &args[i], i18n);
	    strlcat(buf, "]", sizeof(buf));
	    if(args[i].type == arg_strings)
		strlcat(buf, "...", sizeof(buf));
	    col = check_column(stderr, col, strlen(buf) + 1, columns);
	    col += fprintf(stderr, " %s", buf);
	}
	if (args[i].long_name && args[i].short_name)
	    len += 2; /* ", " */
	max_len = max(max_len, len);
    }
    if (extra_string) {
	check_column(stderr, col, strlen(extra_string) + 1, columns);
	fprintf (stderr, " %s\n", extra_string);
    } else
	fprintf (stderr, "\n");
    for (i = 0; i < num_args; ++i) {
	if (args[i].help) {
	    size_t count = 0;

	    if (args[i].short_name) {
		count += fprintf (stderr, "-%c", args[i].short_name);
		print_arg (buf, sizeof(buf), 0, 0, &args[i], i18n);
		count += fprintf(stderr, "%s", buf);
	    }
	    if (args[i].short_name && args[i].long_name)
		count += fprintf (stderr, ", ");
	    if (args[i].long_name) {
		count += fprintf (stderr, "--");
		if (args[i].type == arg_negative_flag)
		    count += fprintf (stderr, "no-");
		count += fprintf (stderr, "%s", args[i].long_name);
		print_arg (buf, sizeof(buf), 0, 1, &args[i], i18n);
		count += fprintf(stderr, "%s", buf);
	    }
	    while(count++ <= max_len)
		putc (' ', stderr);
	    fprintf (stderr, "%s\n", (*i18n)(args[i].help));
	}
    }
}
Example #11
0
int main(int argc, char **argv) {
  int x;
  int opt;
  FILE *file1;
  FILE *file2;
  file_t *files = NULL;
  file_t *curfile;
  file_t *match = NULL;
  filetree_t *checktree = NULL;
  int filecount = 0;
  int progress = 0;
 
  static struct option long_options[] = 
  {
    { "omitfirst", 0, 0, 'f' },
    { "recurse", 0, 0, 'r' },
    { "quiet", 0, 0, 'q' },
    { "sameline", 0, 0, '1' },
    { "size", 0, 0, 'S' },
    { "symlinks", 0, 0, 's' },
    { "hardlinks", 0, 0, 'H' },
    { "noempty", 0, 0, 'n' },
    { "delete", 0, 0, 'd' },
    { "version", 0, 0, 'v' },
    { "help", 0, 0, 'h' },
    { 0, 0, 0, 0 }
  };

  program_name = argv[0];

  while ((opt = getopt_long(argc, argv, "frq1SsHndvh", long_options, NULL)) != EOF) {
    switch (opt) {
    case 'f':
      SETFLAG(flags, F_OMITFIRST);
      break;
    case 'r':
      SETFLAG(flags, F_RECURSE);
      break;
    case 'q':
      SETFLAG(flags, F_HIDEPROGRESS);
      break;
    case '1':
      SETFLAG(flags, F_DSAMELINE);
      break;
    case 'S':
      SETFLAG(flags, F_SHOWSIZE);
      break;
    case 's':
      SETFLAG(flags, F_FOLLOWLINKS);
      break;
    case 'H':
      SETFLAG(flags, F_CONSIDERHARDLINKS);
      break;
    case 'n':
      SETFLAG(flags, F_EXCLUDEEMPTY);
      break;
    case 'd':
      SETFLAG(flags, F_DELETEFILES);
      break;
    case 'v':
      printf("fdupes %s\n", VERSION);
      exit(0);
    case 'h':
      help_text();
      exit(1);
    default:
      fprintf(stderr, "Try `fdupes --help' for more information\n");
      exit(1);
    }
  }

  if (optind >= argc) {
    errormsg("no directories specified\n");
    exit(1);
  }

  for (x = optind; x < argc; x++) filecount += grokdir(argv[x], &files);

  if (!files) exit(0);
  
  curfile = files;

  while (curfile) {
    if (!checktree) 
#ifndef EXPERIMENTAL_RBTREE
      registerfile(&checktree, curfile);
#else
      registerfile(&checktree, NULL, TREE_ROOT, curfile);
#endif
    else 
      match = checkmatch(&checktree, checktree, curfile);

    if (match != NULL) {
      file1 = fopen(curfile->d_name, "rb");
      if (!file1) {
	curfile = curfile->next;
	continue;
      }

      file2 = fopen(match->d_name, "rb");
      if (!file2) {
	fclose(file1);
	curfile = curfile->next;
	continue;
      }
 
      if (confirmmatch(file1, file2)) {
	match->hasdupes = 1;
        curfile->duplicates = match->duplicates;
        match->duplicates = curfile;
      }
      
      fclose(file1);
      fclose(file2);
    }

    curfile = curfile->next;

    if (!ISFLAG(flags, F_HIDEPROGRESS)) {
      fprintf(stderr, "\rProgress [%d/%d] %d%% ", progress, filecount,
       (int)((float) progress / (float) filecount * 100.0));
      progress++;
    }
  }
Example #12
0
file_t *checkmatch(filetree_t **root, filetree_t *checktree, file_t *file)
{
  int cmpresult;
  char *crcsignature;
  off_t fsize;

  /* If inodes are equal one of the files is a hard link, which
     is usually not accidental. We don't want to flag them as 
     duplicates, unless the user specifies otherwise. */

  if (!ISFLAG(flags, F_CONSIDERHARDLINKS) && getinode(file->d_name) == 
   checktree->file->inode) return NULL;

  fsize = filesize(file->d_name);
  
  if (fsize < checktree->file->size) 
    cmpresult = -1;
  else 
    if (fsize > checktree->file->size) cmpresult = 1;
  else {
    if (checktree->file->crcsignature == NULL) {
      crcsignature = getcrcsignature(checktree->file->d_name);
      if (crcsignature == NULL) return NULL;

      checktree->file->crcsignature = (char*) malloc(strlen(crcsignature)+1);
      if (checktree->file->crcsignature == NULL) {
	errormsg("out of memory\n");
	exit(1);
      }
      strcpy(checktree->file->crcsignature, crcsignature);
    }

    if (file->crcsignature == NULL) {
      crcsignature = getcrcsignature(file->d_name);
      if (crcsignature == NULL) return NULL;

      file->crcsignature = (char*) malloc(strlen(crcsignature)+1);
      if (file->crcsignature == NULL) {
	errormsg("out of memory\n");
	exit(1);
      }
      strcpy(file->crcsignature, crcsignature);
    }

    cmpresult = strcmp(file->crcsignature, checktree->file->crcsignature);
  }

  if (cmpresult < 0) {
    if (checktree->left != NULL) {
      return checkmatch(root, checktree->left, file);
    } else {
#ifndef EXPERIMENTAL_RBTREE
      registerfile(&(checktree->left), file);
#else
      registerfile(root, checktree, TREE_LEFT, file);
#endif
      return NULL;
    }
  } else if (cmpresult > 0) {
    if (checktree->right != NULL) {
      return checkmatch(root, checktree->right, file);
    } else {
#ifndef EXPERIMENTAL_RBTREE
      registerfile(&(checktree->right), file);
#else
      registerfile(root, checktree, TREE_RIGHT, file);
#endif
      return NULL;
    }
  } else return checktree->file;
}
Example #13
0
/**
 * Parse a single u_scanf format specifier in Unicode.
 * @param fmt A pointer to a '%' character in a u_scanf format specification.
 * @param spec A pointer to a <TT>u_scanf_spec</TT> to receive the parsed
 * format specifier.
 * @return The number of characters contained in this specifier.
 */
static int32_t
u_scanf_parse_spec (const UChar     *fmt,
            u_scanf_spec    *spec)
{
    const UChar *s = fmt;
    const UChar *backup;
    u_scanf_spec_info *info = &(spec->fInfo);

    /* initialize spec to default values */
    spec->fArgPos             = -1;

    info->fWidth        = -1;
    info->fSpec         = 0x0000;
    info->fPadChar      = 0x0020;
    info->fSkipArg      = FALSE;
    info->fIsLongDouble = FALSE;
    info->fIsShort      = FALSE;
    info->fIsLong       = FALSE;
    info->fIsLongLong   = FALSE;
    info->fIsString     = TRUE;


    /* skip over the initial '%' */
    s++;

    /* Check for positional argument */
    if(ISDIGIT(*s)) {

        /* Save the current position */
        backup = s;

        /* handle positional parameters */
        if(ISDIGIT(*s)) {
            spec->fArgPos = (int) (*s++ - DIGIT_ZERO);

            while(ISDIGIT(*s)) {
                spec->fArgPos *= 10;
                spec->fArgPos += (int) (*s++ - DIGIT_ZERO);
            }
        }

        /* if there is no '$', don't read anything */
        if(*s != SPEC_DOLLARSIGN) {
            spec->fArgPos = -1;
            s = backup;
        }
        /* munge the '$' */
        else
            s++;
    }

    /* Get any format flags */
    while(ISFLAG(*s)) {
        switch(*s++) {

            /* skip argument */
        case FLAG_ASTERISK:
            info->fSkipArg = TRUE;
            break;

            /* pad character specified */
        case FLAG_PAREN:

            /* first four characters are hex values for pad char */
            info->fPadChar = (UChar)ufmt_digitvalue(*s++);
            info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
            info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));
            info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*s++));

            /* final character is ignored */
            s++;

            break;
        }
    }

    /* Get the width */
    if(ISDIGIT(*s)){
        info->fWidth = (int) (*s++ - DIGIT_ZERO);

        while(ISDIGIT(*s)) {
            info->fWidth *= 10;
            info->fWidth += (int) (*s++ - DIGIT_ZERO);
        }
    }

    /* Get any modifiers */
    if(ISMOD(*s)) {
        switch(*s++) {

            /* short */
        case MOD_H:
            info->fIsShort = TRUE;
            break;

            /* long or long long */
        case MOD_LOWERL:
            if(*s == MOD_LOWERL) {
                info->fIsLongLong = TRUE;
                /* skip over the next 'l' */
                s++;
            }
            else
                info->fIsLong = TRUE;
            break;

            /* long double */
        case MOD_L:
            info->fIsLongDouble = TRUE;
            break;
        }
    }

    /* finally, get the specifier letter */
    info->fSpec = *s++;

    /* return # of characters in this specifier */
    return (int32_t)(s - fmt);
}
Example #14
0
void deletefiles(file_t *files, int prompt, FILE *tty)
{
  int counter;
  int groups = 0;
  int curgroup = 0;
  file_t *tmpfile;
  file_t *curfile;
  file_t **dupelist;
  int *preserve;
  char *preservestr;
  char *token;
  char *tstr;
  int number;
  int sum;
  int max = 0;
  int x;
  int i;

  curfile = files;
  
  while (curfile) {
    if (curfile->hasdupes) {
      counter = 1;
      groups++;

      tmpfile = curfile->duplicates;
      while (tmpfile) {
	counter++;
	tmpfile = tmpfile->duplicates;
      }
      
      if (counter > max) max = counter;
    }
    
    curfile = curfile->next;
  }

  max++;

  dupelist = (file_t**) malloc(sizeof(file_t*) * max);
  preserve = (int*) malloc(sizeof(int) * max);
  preservestr = (char*) malloc(INPUT_SIZE);

  if (!dupelist || !preserve || !preservestr) {
    errormsg("out of memory\n");
    exit(1);
  }

  while (files) {
    if (files->hasdupes) {
      curgroup++;
      counter = 1;
      dupelist[counter] = files;

      if (prompt) printf("[%d] %s\n", counter, files->d_name);

      tmpfile = files->duplicates;

      while (tmpfile) {
	dupelist[++counter] = tmpfile;
	if (prompt) printf("[%d] %s\n", counter, tmpfile->d_name);
	tmpfile = tmpfile->duplicates;
      }

      if (prompt) printf("\n");

      if (!prompt) /* preserve only the first file */
      {
         preserve[1] = 1;
	 for (x = 2; x <= counter; x++) preserve[x] = 0;
      }

      else /* prompt for files to preserve */

      do {
	printf("Set %d of %d, preserve files [1 - %d, all]", 
          curgroup, groups, counter);
	if (ISFLAG(flags, F_SHOWSIZE)) printf(" (%lld byte%seach)", files->size,
	  (files->size != 1) ? "s " : " ");
	printf(": ");
	fflush(stdout);

	if (!fgets(preservestr, INPUT_SIZE, tty))
	  preservestr[0] = '\n'; /* treat fgets() failure as if nothing was entered */

	i = strlen(preservestr) - 1;

	while (preservestr[i]!='\n'){ /* tail of buffer must be a newline */
	  tstr = (char*)
	    realloc(preservestr, strlen(preservestr) + 1 + INPUT_SIZE);
	  if (!tstr) { /* couldn't allocate memory, treat as fatal */
	    errormsg("out of memory!\n");
	    exit(1);
	  }

	  preservestr = tstr;
	  if (!fgets(preservestr + i + 1, INPUT_SIZE, tty))
	  {
	    preservestr[0] = '\n'; /* treat fgets() failure as if nothing was entered */
	    break;
	  }
	  i = strlen(preservestr)-1;
	}

	for (x = 1; x <= counter; x++) preserve[x] = 0;
	
	token = strtok(preservestr, " ,\n");
	
	while (token != NULL) {
	  if (strcasecmp(token, "all") == 0)
	    for (x = 0; x <= counter; x++) preserve[x] = 1;
	  
	  number = 0;
	  sscanf(token, "%d", &number);
	  if (number > 0 && number <= counter) preserve[number] = 1;
	  
	  token = strtok(NULL, " ,\n");
	}
      
	for (sum = 0, x = 1; x <= counter; x++) sum += preserve[x];
      } while (sum < 1); /* make sure we've preserved at least one file */

      printf("\n");

      for (x = 1; x <= counter; x++) { 
	if (preserve[x])
	  printf("   [+] %s\n", dupelist[x]->d_name);
	else {
	  if (remove(dupelist[x]->d_name) == 0) {
	    printf("   [-] %s\n", dupelist[x]->d_name);
	  } else {
	    printf("   [!] %s ", dupelist[x]->d_name);
	    printf("-- unable to delete file!\n");
	  }
	}
      }
      printf("\n");
    }
    
    files = files->next;
  }

  free(dupelist);
  free(preserve);
  free(preservestr);
}
Example #15
0
static int
arg_match_long(struct agetargs *args, int argc,
	       char **argv, int style, int *next, int *num_arg)
{
    char *optarg = NULL;
    int negate = 0;
    int numarg = -1;
    int partial_match = 0;
    int do_generic=0;
    struct agetargs *partial = NULL;
    struct agetargs *generic_arg = NULL;
    struct agetargs *current = NULL;
    struct agetargs *arg;
    int argv_len;
    char *p, *q;

    if (style & AARG_LONGARG) {
	q = *argv + 2;
	*next = 0;
    } else if (style & AARG_TRANSLONG) {
	q = *argv + 1;
	*next = 0;
    } else {
	*next = 0;
	q = *argv;
    }

    argv_len = strlen(q);
    p = strchr (q, '=');
    if (p != NULL)
	argv_len = p - q;

    for (arg = args; arg->type ; arg++) {
	/* parse a generic argument if it has not already been filled */
	if (!do_generic && arg->type == aarg_generic_string) {
	    char *hole = (char *)arg->value;

	    if (hole && *hole == '\0')
		do_generic = 1;
	}

	if(do_generic) {
	    generic_arg = arg;
	    optarg = *(argv);
	    *next = 0;
	}

	numarg++;
	if(arg->long_name) {
	    int len = strlen(arg->long_name);
	    char *p = q;
	    int p_len = argv_len;
	    negate = 0;

	    for (;;) {
		if (strncmp (arg->long_name, p, len) == 0) {
		    current = arg;
		    if (style & AARG_TRANSLONG) {
			if (ISFLAG(arg)) {
			    optarg = "";
			    *next = 0;
			} else if (*(argv +1)) {
			    optarg = *(argv + 1);
			    *next = 1;
			} else
			    optarg = "";
		    } else if(p[len] == '\0')
			optarg = p + len;
		    else
			optarg = p + len + 1;
		} else if (strncmp (arg->long_name,
				    p,
				    p_len) == 0) {
		    if (!(style & AARG_USEFIRST) || !partial_match) {
			++partial_match;
			partial = arg;
		    }
		    if (style & AARG_TRANSLONG) {
			if (ISFLAG(arg)) {
			    optarg = "";
			    *next = 0;
			} else if (*(argv + 1)) {
			    optarg = *(argv + 1);
			    *next = 1;
			} else
			    optarg = "";
		    } else
			optarg  = p + p_len +1 ;
		} else if (ISFLAG(arg) && strncmp (p, "no-", 3) == 0) {
		    negate = !negate;
		    p += 3;
		    p_len -= 3;
		    continue;
		}
		break;
	    }
	    if (current)
		break;
	}
    }
    if (current == NULL) {
	/* Match a generic argument preferentially over a partial match */
	if (generic_arg && (!partial_match || (style & AARG_USEFIRST)))
	    current = generic_arg;
	else if (partial_match == 1)
	    current = partial;
	else
	    return AARG_ERR_NO_MATCH;

	numarg = current - args;
    }

    if(*optarg == '\0' && !ISFLAG(current))
	return AARG_ERR_NO_MATCH;

    *num_arg = numarg;
    return parse_option(current, style, optarg, argc, argv, next, negate);
}
Example #16
0
int main(int argc, char **argv) {
  int x;
  int opt;
  FILE *file1;
  FILE *file2;
  file_t *files = NULL;
  file_t *curfile;
  file_t **match = NULL;
  filetree_t *checktree = NULL;
  int filecount = 0;
  int progress = 0;
  char **oldargv;
  int firstrecurse;
  
#ifndef OMIT_GETOPT_LONG
  static struct option long_options[] = 
  {
    { "omitfirst", 0, 0, 'f' },
    { "recurse", 0, 0, 'r' },
    { "recursive", 0, 0, 'r' },
    { "recurse:", 0, 0, 'R' },
    { "recursive:", 0, 0, 'R' },
    { "quiet", 0, 0, 'q' },
    { "sameline", 0, 0, '1' },
    { "size", 0, 0, 'S' },
    { "symlinks", 0, 0, 's' },
    { "hardlinks", 0, 0, 'H' },
    { "relink", 0, 0, 'l' },
    { "noempty", 0, 0, 'n' },
    { "delete", 0, 0, 'd' },
    { "version", 0, 0, 'v' },
    { "help", 0, 0, 'h' },
    { "noprompt", 0, 0, 'N' },
    { "summarize", 0, 0, 'm'},
    { "summary", 0, 0, 'm' },
    { 0, 0, 0, 0 }
  };
#define GETOPT getopt_long
#else
#define GETOPT getopt
#endif

  program_name = argv[0];

  oldargv = cloneargs(argc, argv);

  while ((opt = GETOPT(argc, argv, "frRq1Ss::HlndvhNm"
#ifndef OMIT_GETOPT_LONG
          , long_options, NULL
#endif
          )) != EOF) {
    switch (opt) {
    case 'f':
      SETFLAG(flags, F_OMITFIRST);
      break;
    case 'r':
      SETFLAG(flags, F_RECURSE);
      break;
    case 'R':
      SETFLAG(flags, F_RECURSEAFTER);
      break;
    case 'q':
      SETFLAG(flags, F_HIDEPROGRESS);
      break;
    case '1':
      SETFLAG(flags, F_DSAMELINE);
      break;
    case 'S':
      SETFLAG(flags, F_SHOWSIZE);
      break;
    case 's':
      SETFLAG(flags, F_FOLLOWLINKS);
      break;
    case 'H':
      SETFLAG(flags, F_CONSIDERHARDLINKS);
      break;
    case 'n':
      SETFLAG(flags, F_EXCLUDEEMPTY);
      break;
    case 'd':
      SETFLAG(flags, F_DELETEFILES);
      break;
    case 'v':
      printf("fdupes %s\n", VERSION);
      exit(0);
    case 'h':
      help_text();
      exit(1);
    case 'N':
      SETFLAG(flags, F_NOPROMPT);
      break;
    case 'm':
      SETFLAG(flags, F_SUMMARIZEMATCHES);
      break;

    default:
      fprintf(stderr, "Try `fdupes --help' for more information.\n");
      exit(1);
    }
  }

  if (optind >= argc) {
    errormsg("no directories specified\n");
    exit(1);
  }

  if (ISFLAG(flags, F_RECURSE) && ISFLAG(flags, F_RECURSEAFTER)) {
    errormsg("options --recurse and --recurse: are not compatible\n");
    exit(1);
  }

  if (ISFLAG(flags, F_SUMMARIZEMATCHES) && ISFLAG(flags, F_DELETEFILES)) {
    errormsg("options --summarize and --delete are not compatible\n");
    exit(1);
  }

  if (ISFLAG(flags, F_RECURSEAFTER)) {
    firstrecurse = nonoptafter("--recurse:", argc, oldargv, argv, optind);
    
    if (firstrecurse == argc)
      firstrecurse = nonoptafter("-R", argc, oldargv, argv, optind);

    if (firstrecurse == argc) {
      errormsg("-R option must be isolated from other options\n");
      exit(1);
    }

    /* F_RECURSE is not set for directories before --recurse: */
    for (x = optind; x < firstrecurse; x++)
      filecount += grokdir(argv[x], &files);

    /* Set F_RECURSE for directories after --recurse: */
    SETFLAG(flags, F_RECURSE);

    for (x = firstrecurse; x < argc; x++)
      filecount += grokdir(argv[x], &files);
  } else {
    for (x = optind; x < argc; x++)
      filecount += grokdir(argv[x], &files);
  }

  if (!files) {
    if (!ISFLAG(flags, F_HIDEPROGRESS)) fprintf(stderr, "\r%40s\r", " ");
    exit(0);
  }
  
  curfile = files;

  while (curfile) {
    if (!checktree) 
      registerfile(&checktree, curfile);
    else 
      match = checkmatch(&checktree, checktree, curfile);

    if (match != NULL) {
      file1 = fopen(curfile->d_name, "rb");
      if (!file1) {
	curfile = curfile->next;
	continue;
      }
      
      file2 = fopen((*match)->d_name, "rb");
      if (!file2) {
	fclose(file1);
	curfile = curfile->next;
	continue;
      }

      if (confirmmatch(file1, file2)) {
	registerpair(match, curfile, sort_pairs_by_mtime);
	
	/*match->hasdupes = 1;
        curfile->duplicates = match->duplicates;
        match->duplicates = curfile;*/
      }
      
      fclose(file1);
      fclose(file2);
    }

    curfile = curfile->next;

    if (!ISFLAG(flags, F_HIDEPROGRESS)) {
      fprintf(stderr, "\rProgress [%d/%d] %d%% ", progress, filecount,
       (int)((float) progress / (float) filecount * 100.0));
      progress++;
    }
  }

  if (!ISFLAG(flags, F_HIDEPROGRESS)) fprintf(stderr, "\r%40s\r", " ");

  if (ISFLAG(flags, F_DELETEFILES))
  {
    if (ISFLAG(flags, F_NOPROMPT))
    {
      deletefiles(files, 0, 0);
    }
    else
    {
      stdin = freopen("/dev/tty", "r", stdin);
      deletefiles(files, 1, stdin);
    }
  }

  else 

    if (ISFLAG(flags, F_SUMMARIZEMATCHES))
      summarizematches(files);
      
    else

      printmatches(files);

  while (files) {
    curfile = files->next;
    free(files->d_name);
    free(files->crcsignature);
    free(files->crcpartial);
    free(files);
    files = curfile;
  }

  for (x = 0; x < argc; x++)
    free(oldargv[x]);

  free(oldargv);

  purgetree(checktree);

  return 0;
}
Example #17
0
static int
arg_match_long(struct getargs *args, size_t num_args,
               char *argv)
{
    int i;
    char *optarg = NULL;
    int negate = 0;
    int partial_match = 0;
    struct getargs *partial = NULL;
    struct getargs *current = NULL;
    int argv_len;
    char *p;

    argv_len = strlen(argv);
    p = strchr (argv, '=');
    if (p != NULL)
        argv_len = p - argv;

    for (i = 0; i < num_args; ++i) {
        if(args[i].long_name) {
            int len = strlen(args[i].long_name);
            char *p = argv;
            int p_len = argv_len;
            negate = 0;

            for (;;) {
                if (strncmp (args[i].long_name, p, p_len) == 0) {
                    if(p_len == len)
                        current = &args[i];
                    else {
                        ++partial_match;
                        partial = &args[i];
                    }
                    optarg  = p + p_len;
                } else if (ISFLAG(args[i]) && strncmp (p, "no-", 3) == 0) {
                    negate = !negate;
                    p += 3;
                    p_len -= 3;
                    continue;
                }
                break;
            }
            if (current)
                break;
        }
    }
    if (current == NULL) {
        if (partial_match == 1)
            current = partial;
        else
            return ARG_ERR_NO_MATCH;
    }

    if(*optarg == '\0' && !ISFLAG(*current))
        return ARG_ERR_NO_MATCH;
    switch(current->type) {
    case arg_integer:
    {
        int tmp;
        if(sscanf(optarg + 1, "%d", &tmp) != 1)
            return ARG_ERR_BAD_ARG;
        *(int*)current->value = tmp;
        return 0;
    }
    case arg_string:
    {
        *(char**)current->value = optarg + 1;
        return 0;
    }
    case arg_strings:
    {
        add_string((getarg_strings*)current->value, optarg + 1);
        return 0;
    }
    case arg_flag:
    case arg_negative_flag:
    {
        int *flag = current->value;
        if(*optarg == '\0' ||
                strcmp(optarg + 1, "yes") == 0 ||
                strcmp(optarg + 1, "true") == 0) {
            *flag = !negate;
            return 0;
        } else if (*optarg && strcmp(optarg + 1, "maybe") == 0) {
            *flag = rand() & 1;
        } else {
            *flag = negate;
            return 0;
        }
        return ARG_ERR_BAD_ARG;
    }
    default:
        abort ();
    }
}