From 6a1d661036f1774f4fd7f964357c8739c38a9092 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sat, 16 Dec 2006 22:18:44 +0000 Subject: [PATCH] diff: fix -q exit code last_char_is: sacrifice 9 bytes but avoid double-scan --- coreutils/diff.c | 142 ++++++++++++++++++++++--------------------- libbb/last_char_is.c | 12 ++-- 2 files changed, 78 insertions(+), 76 deletions(-) diff --git a/coreutils/diff.c b/coreutils/diff.c index 2ed26babe..0df9989b7 100644 --- a/coreutils/diff.c +++ b/coreutils/diff.c @@ -50,8 +50,6 @@ #define D_SKIPPED2 (1<<8) /* Command line options */ -static unsigned long cmd_flags; - #define FLAG_a (1<<0) #define FLAG_b (1<<1) #define FLAG_d (1<<2) @@ -68,12 +66,12 @@ static unsigned long cmd_flags; #define FLAG_w (1<<13) /* XXX: FIXME: the following variables should be static, but gcc currently - * creates a much bigger object if we do this. */ + * creates a much bigger object if we do this. [which version of gcc? --vda] */ int context, status; char *start, *label[2]; struct stat stb1, stb2; char **dl; -static int dl_count = 0; +static int dl_count; struct cand { int x; @@ -116,6 +114,7 @@ static struct context_vec *context_vec_start; static struct context_vec *context_vec_end; static struct context_vec *context_vec_ptr; + static void print_only(const char *path, size_t dirlen, const char *entry) { if (dirlen > 1) @@ -123,6 +122,7 @@ static void print_only(const char *path, size_t dirlen, const char *entry) printf("Only in %.*s: %s\n", (int) dirlen, path, entry); } + static void print_status(int val, char *path1, char *path2, char *entry) { const char *const _entry = entry ? entry : ""; @@ -140,20 +140,20 @@ static void print_status(int val, char *path1, char *path2, char *entry) printf("Binary files %s and %s differ\n", _path1, _path2); break; case D_DIFFER: - if (cmd_flags & FLAG_q) + if (option_mask32 & FLAG_q) printf("Files %s and %s differ\n", _path1, _path2); break; case D_SAME: - if (cmd_flags & FLAG_s) + if (option_mask32 & FLAG_s) printf("Files %s and %s are identical\n", _path1, _path2); break; case D_MISMATCH1: - printf("File %s is a directory while file %s is a regular file\n", - _path1, _path2); + printf("File %s is a %s while file %s is a %s\n", + _path1, "directory", _path2, "regular file"); break; case D_MISMATCH2: - printf("File %s is a regular file while file %s is a directory\n", - _path1, _path2); + printf("File %s is a %s while file %s is a %s\n", + _path1, "regular file", _path2, "directory"); break; case D_SKIPPED1: printf("File %s is not a regular file or directory and was skipped\n", @@ -170,6 +170,7 @@ static void print_status(int val, char *path1, char *path2, char *entry) } } + /* * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. */ @@ -180,7 +181,7 @@ static int readhash(FILE * f) sum = 1; space = 0; - if (!(cmd_flags & FLAG_b) && !(cmd_flags & FLAG_w)) { + if (!(option_mask32 & FLAG_b) && !(option_mask32 & FLAG_w)) { if (FLAG_i) for (i = 0; (t = getc(f)) != '\n'; i++) { if (t == EOF) { @@ -209,7 +210,7 @@ static int readhash(FILE * f) space++; continue; default: - if (space && !(cmd_flags & FLAG_w)) { + if (space && !(option_mask32 & FLAG_w)) { i++; space = 0; } @@ -234,22 +235,20 @@ static int readhash(FILE * f) } - /* * Check to see if the given files differ. * Returns 0 if they are the same, 1 if different, and -1 on error. */ static int files_differ(FILE * f1, FILE * f2, int flags) { - char buf1[BUFSIZ], buf2[BUFSIZ]; size_t i, j; if ((flags & (D_EMPTY1 | D_EMPTY2)) || stb1.st_size != stb2.st_size || (stb1.st_mode & S_IFMT) != (stb2.st_mode & S_IFMT)) return 1; while (1) { - i = fread(buf1, 1, sizeof(buf1), f1); - j = fread(buf2, 1, sizeof(buf2), f2); + i = fread(bb_common_bufsiz1, 1, BUFSIZ/2, f1); + j = fread(bb_common_bufsiz1 + BUFSIZ/2, 1, BUFSIZ/2, f2); if (i != j) return 1; if (i == 0 && j == 0) { @@ -257,11 +256,13 @@ static int files_differ(FILE * f1, FILE * f2, int flags) return 1; return 0; } - if (memcmp(buf1, buf2, i) != 0) + if (memcmp(bb_common_bufsiz1, + bb_common_bufsiz1 + BUFSIZ/2, i) != 0) return 1; } } + static void prepare(int i, FILE * fd, off_t filesize) { struct line *p; @@ -286,6 +287,7 @@ static void prepare(int i, FILE * fd, off_t filesize) file[i] = p; } + static void prune(void) { int i, j; @@ -303,6 +305,7 @@ static void prune(void) } } + static void equiv(struct line *a, int n, struct line *b, int m, int *c) { int i, j; @@ -330,6 +333,7 @@ static void equiv(struct line *a, int n, struct line *b, int m, int *c) c[j] = -1; } + static int isqrt(int n) { int y, x = 1; @@ -347,6 +351,7 @@ static int isqrt(int n) return x; } + static int newcand(int x, int y, int pred) { struct cand *q; @@ -395,7 +400,7 @@ static int stone(int *a, int n, int *b, int *c) #if ENABLE_FEATURE_DIFF_MINIMAL const unsigned int bound = - (cmd_flags & FLAG_d) ? UINT_MAX : MAX(256, isqrt(n)); + (option_mask32 & FLAG_d) ? UINT_MAX : MAX(256, isqrt(n)); #else const unsigned int bound = MAX(256, isqrt(n)); #endif @@ -433,6 +438,7 @@ static int stone(int *a, int n, int *b, int *c) return k; } + static void unravel(int p) { struct cand *q; @@ -457,6 +463,7 @@ static void unsort(struct line *f, int l, int *b) free(a); } + static int skipline(FILE * f) { int i, c; @@ -493,8 +500,8 @@ static void check(FILE * f1, FILE * f2) ixnew[j] = ctnew += skipline(f2); j++; } - if ((cmd_flags & FLAG_b) || (cmd_flags & FLAG_w) - || (cmd_flags & FLAG_i)) { + if ((option_mask32 & FLAG_b) || (option_mask32 & FLAG_w) + || (option_mask32 & FLAG_i)) { while (1) { c = getc(f1); d = getc(f2); @@ -502,13 +509,13 @@ static void check(FILE * f1, FILE * f2) * GNU diff ignores a missing newline * in one file if bflag || wflag. */ - if (((cmd_flags & FLAG_b) || (cmd_flags & FLAG_w)) && + if (((option_mask32 & FLAG_b) || (option_mask32 & FLAG_w)) && ((c == EOF && d == '\n') || (c == '\n' && d == EOF))) { break; } ctold++; ctnew++; - if ((cmd_flags & FLAG_b) && isspace(c) && isspace(d)) { + if ((option_mask32 & FLAG_b) && isspace(c) && isspace(d)) { do { if (c == '\n') break; @@ -519,7 +526,7 @@ static void check(FILE * f1, FILE * f2) break; ctnew++; } while (isspace(d = getc(f2))); - } else if (cmd_flags & FLAG_w) { + } else if (option_mask32 & FLAG_w) { while (isspace(c) && c != '\n') { c = getc(f1); ctold++; @@ -565,6 +572,7 @@ static void check(FILE * f1, FILE * f2) ixnew[j] = ctnew += skipline(f2); } + /* shellsort CACM #201 */ static void sort(struct line *a, int n) { @@ -607,6 +615,7 @@ static void uni_range(int a, int b) printf("%d,0", b); } + static int fetch(long *f, int a, int b, FILE * lb, int ch) { int i, j, c, lastc, col, nc; @@ -618,7 +627,7 @@ static int fetch(long *f, int a, int b, FILE * lb, int ch) nc = f[i] - f[i - 1]; if (ch != '\0') { putchar(ch); - if (cmd_flags & FLAG_T) + if (option_mask32 & FLAG_T) putchar('\t'); } col = 0; @@ -627,7 +636,7 @@ static int fetch(long *f, int a, int b, FILE * lb, int ch) puts("\n\\ No newline at end of file"); return 0; } - if (c == '\t' && (cmd_flags & FLAG_t)) { + if (c == '\t' && (option_mask32 & FLAG_t)) { do { putchar(' '); } while (++col & 7); @@ -640,21 +649,22 @@ static int fetch(long *f, int a, int b, FILE * lb, int ch) return 0; } + static int asciifile(FILE * f) { #if ENABLE_FEATURE_DIFF_BINARY - unsigned char buf[BUFSIZ]; int i, cnt; #endif - if ((cmd_flags & FLAG_a) || f == NULL) + if ((option_mask32 & FLAG_a) || f == NULL) return 1; #if ENABLE_FEATURE_DIFF_BINARY rewind(f); - cnt = fread(buf, 1, sizeof(buf), f); + cnt = fread(bb_common_bufsiz1, 1, BUFSIZ, f); for (i = 0; i < cnt; i++) { - if (!isprint(buf[i]) && !isspace(buf[i])) { + if (!isprint(bb_common_bufsiz1[i]) + && !isspace(bb_common_bufsiz1[i])) { return 0; } } @@ -662,6 +672,7 @@ static int asciifile(FILE * f) return 1; } + /* dump accumulated "unified" diff changes */ static void dump_unified_vec(FILE * f1, FILE * f2) { @@ -735,10 +746,9 @@ static void print_header(const char *file1, const char *file2) } - /* * Indicate that there is a difference between lines a and b of the from file - * to get to lines c to d of the to file. If a is greater then b then there + * to get to lines c to d of the to file. If a is greater than b then there * are no lines in the from file involved and this means that there were * lines appended (beginning at b). If c is greater than d then there are * lines missing from the to file. @@ -748,10 +758,10 @@ static void change(char *file1, FILE * f1, char *file2, FILE * f2, int a, { static size_t max_context = 64; - if (a > b && c > d) - return; - if (cmd_flags & FLAG_q) + if ((a > b && c > d) || (option_mask32 & FLAG_q)) { + anychange = 1; return; + } /* * Allocate change records as needed. @@ -771,7 +781,6 @@ static void change(char *file1, FILE * f1, char *file2, FILE * f2, int a, * Print the context/unidiff header first time through. */ print_header(file1, file2); - anychange = 1; } else if (a > context_vec_ptr->b + (2 * context) + 1 && c > context_vec_ptr->d + (2 * context) + 1) { /* @@ -785,14 +794,12 @@ static void change(char *file1, FILE * f1, char *file2, FILE * f2, int a, context_vec_ptr->b = b; context_vec_ptr->c = c; context_vec_ptr->d = d; - return; - + anychange = 1; } static void output(char *file1, FILE * f1, char *file2, FILE * f2) { - /* Note that j0 and j1 can't be used as they are defined in math.h. * This also allows the rather amusing variable 'j00'... */ int m, i0, i1, j00, j01; @@ -816,7 +823,7 @@ static void output(char *file1, FILE * f1, char *file2, FILE * f2) if (m == 0) { change(file1, f1, file2, f2, 1, 0, 1, len[1]); } - if (anychange != 0) { + if (anychange != 0 && !(option_mask32 & FLAG_q)) { dump_unified_vec(f1, f2); } } @@ -883,7 +890,6 @@ static void output(char *file1, FILE * f1, char *file2, FILE * f2) * 3*(number of k-candidates installed), typically about * 6n words for files of length n. */ - static int diffreg(char *ofile1, char *ofile2, int flags) { char *file1 = ofile1; @@ -901,25 +907,20 @@ static int diffreg(char *ofile1, char *ofile2, int flags) if (strcmp(file1, "-") == 0 && strcmp(file2, "-") == 0) goto closem; + f1 = stdin; if (flags & D_EMPTY1) f1 = xfopen(bb_dev_null, "r"); - else { - if (strcmp(file1, "-") == 0) - f1 = stdin; - else - f1 = xfopen(file1, "r"); - } + else if (file1[0] != '-' || file1[1]) /* not "-" */ + f1 = xfopen(file1, "r"); + f2 = stdin; if (flags & D_EMPTY2) f2 = xfopen(bb_dev_null, "r"); - else { - if (strcmp(file2, "-") == 0) - f2 = stdin; - else - f2 = xfopen(file2, "r"); - } + else if (file2[0] != '-' || file2[1]) /* not "-" */ + f2 = xfopen(file2, "r"); - if ((i = files_differ(f1, f2, flags)) == 0) + i = files_differ(f1, f2, flags); + if (i == 0) goto closem; else if (i != 1) { /* 1 == ok */ /* error */ @@ -965,7 +966,7 @@ static int diffreg(char *ofile1, char *ofile2, int flags) check(f1, f2); output(file1, f1, file2, f2); - closem: + closem: if (anychange) { status |= 1; if (rval == D_SAME) @@ -982,10 +983,10 @@ static int diffreg(char *ofile1, char *ofile2, int flags) return rval; } + #if ENABLE_FEATURE_DIFF_DIR static void do_diff(char *dir1, char *path1, char *dir2, char *path2) { - int flags = D_HEADER; int val; @@ -1023,14 +1024,15 @@ static void do_diff(char *dir1, char *path1, char *dir2, char *path2) } #endif + #if ENABLE_FEATURE_DIFF_DIR static int dir_strcmp(const void *p1, const void *p2) { return strcmp(*(char *const *) p1, *(char *const *) p2); } -/* This function adds a filename to dl, the directory listing. */ +/* This function adds a filename to dl, the directory listing. */ static int add_to_dirlist(const char *filename, struct stat ATTRIBUTE_UNUSED * sb, void *userdata, int depth ATTRIBUTE_UNUSED) @@ -1038,7 +1040,7 @@ static int add_to_dirlist(const char *filename, dl_count++; dl = xrealloc(dl, dl_count * sizeof(char *)); dl[dl_count - 1] = xstrdup(filename); - if (cmd_flags & FLAG_r) { + if (option_mask32 & FLAG_r) { int *pp = (int *) userdata; int path_len = *pp + 1; @@ -1047,10 +1049,10 @@ static int add_to_dirlist(const char *filename, return TRUE; } + /* This returns a sorted directory listing. */ static char **get_dir(char *path) { - int i; char **retval; @@ -1068,7 +1070,7 @@ static char **get_dir(char *path) dl_count = 0; /* Now fill dl with a listing. */ - if (cmd_flags & FLAG_r) + if (option_mask32 & FLAG_r) recursive_action(path, TRUE, TRUE, FALSE, add_to_dirlist, NULL, userdata, 0); else { @@ -1095,9 +1097,9 @@ static char **get_dir(char *path) return retval; } + static void diffdir(char *p1, char *p2) { - char **dirlist1, **dirlist2; char *dp1, *dp2; int dirlist1_count, dirlist2_count; @@ -1144,13 +1146,13 @@ static void diffdir(char *p1, char *p2) dirlist1++; dirlist2++; } else if (pos < 0) { - if (cmd_flags & FLAG_N) + if (option_mask32 & FLAG_N) do_diff(p1, dp1, p2, NULL); else print_only(p1, strlen(p1) + 1, dp1); dirlist1++; } else { - if (cmd_flags & FLAG_N) + if (option_mask32 & FLAG_N) do_diff(p1, NULL, p2, dp2); else print_only(p2, strlen(p2) + 1, dp2); @@ -1161,7 +1163,6 @@ static void diffdir(char *p1, char *p2) #endif - int diff_main(int argc, char **argv) { int gotstdin = 0; @@ -1170,10 +1171,11 @@ int diff_main(int argc, char **argv) llist_t *L_arg = NULL; opt_complementary = "L::"; - cmd_flags = getopt32(argc, argv, "abdiL:NqrsS:tTU:wu", + getopt32(argc, argv, "abdiL:NqrsS:tTU:wu" + "p" /* ignored (for compatibility) */, &L_arg, &start, &U_opt); - if (cmd_flags & FLAG_L) { + if (option_mask32 & FLAG_L) { while (L_arg) { if (label[0] == NULL) label[0] = L_arg->data; @@ -1196,8 +1198,8 @@ int diff_main(int argc, char **argv) } context = 3; /* This is the default number of lines of context. */ - if (cmd_flags & FLAG_U) { - context = xatoul_range(U_opt, 1, INT_MAX); + if (option_mask32 & FLAG_U) { + context = xatou_range(U_opt, 1, INT_MAX); } argc -= optind; argv += optind; @@ -1210,12 +1212,12 @@ int diff_main(int argc, char **argv) bb_error_msg("missing filename"); bb_show_usage(); } - if (strcmp(argv[0], "-") == 0) { + if (argv[0][0] == '-' && !argv[0][1]) { /* "-" */ fstat(STDIN_FILENO, &stb1); gotstdin = 1; } else xstat(argv[0], &stb1); - if (strcmp(argv[1], "-") == 0) { + if (argv[1][0] == '-' && !argv[1][1]) { /* "-" */ fstat(STDIN_FILENO, &stb2); gotstdin = 1; } else @@ -1239,5 +1241,5 @@ int diff_main(int argc, char **argv) } print_status(diffreg(argv[0], argv[1], 0), argv[0], argv[1], NULL); } - exit(status); + return status; } diff --git a/libbb/last_char_is.c b/libbb/last_char_is.c index 3616d5916..aaa85ddd9 100644 --- a/libbb/last_char_is.c +++ b/libbb/last_char_is.c @@ -9,15 +9,15 @@ #include "libbb.h" -/* Find out if the last character of a string matches the one given Don't - * underrun the buffer if the string length is 0. Also avoids a possible - * space-hogging inline of strlen() per usage. +/* Find out if the last character of a string matches the one given. + * Don't underrun the buffer if the string length is 0. */ char* last_char_is(const char *s, int c) { - if (s) { - s = strrchr(s, c); - if (s && !s[1]) + if (s && *s) { + size_t sz = strlen(s) - 1; + s += sz; + if ( (unsigned char)*s == c) return (char*)s; } return NULL;