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; }
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; }
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); }
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; } }
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; }
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; }
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; } }
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 {
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)); } } }
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++; } }
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; }
/** * 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); }
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); }
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); }
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; }
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 (); } }