Index: ./Makefile =================================================================== --- ./Makefile +++ ./Makefile @@ -1,10 +1,16 @@ -# $OpenBSD: Makefile,v 1.4 2006/02/20 08:38:18 otto Exp $ +# $FreeBSD$ -PROG=sdiff -SRCS=common.c edit.c sdiff.c -COPTS+=-Wall -W +.include -LDADD+= -lutil -DPADD+= ${LIBUTIL} +PROG= sdiff +SRCS= common.c edit.c sdiff.c +WARNS= 3 -.include +LIBADD= util +MAN1= sdiff.1 + +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + +.include Index: ./common.h =================================================================== --- ./common.h +++ ./common.h @@ -5,4 +5,4 @@ * Public domain. */ -__dead void cleanup(const char *); +void cleanup(const char *) __dead2; Index: ./common.c =================================================================== --- ./common.c +++ ./common.c @@ -5,6 +5,9 @@ * Public domain. */ +#include +__FBSDID("$FreeBSD$"); + #include #include #include @@ -14,7 +17,8 @@ void cleanup(const char *filename) { + if (unlink(filename)) err(2, "could not delete: %s", filename); - exit(2); + exit(1); } Index: ./edit.c =================================================================== --- ./edit.c +++ ./edit.c @@ -1,10 +1,13 @@ -/* $OpenBSD: edit.c,v 1.20 2013/11/26 21:08:12 deraadt Exp $ */ +/* $OpenBSD: edit.c,v 1.19 2009/06/07 13:29:50 ray Exp $ */ /* * Written by Raymond Lai . * Public domain. */ +#include +__FBSDID("$FreeBSD$"); + #include #include @@ -88,7 +91,7 @@ char buf[BUFSIZ], *text; /* Skip whitespace. */ - while (isspace((unsigned char)*cmd)) + while (isspace(*cmd)) ++cmd; text = NULL; @@ -146,7 +149,7 @@ len = strlen(text); if ((nwritten = write(fd, text, len)) == -1 || - nwritten != len) { + (size_t)nwritten != len) { warn("error writing to temp file"); cleanup(filename); } Index: ./sdiff.1 =================================================================== --- ./sdiff.1 +++ ./sdiff.1 @@ -1,9 +1,10 @@ -.\" $OpenBSD: sdiff.1,v 1.18 2015/02/28 21:51:56 bentley Exp $ +.\" $FreeBSD$ +.\" $OpenBSD: sdiff.1,v 1.15 2007/06/29 14:48:07 jmc Exp $ .\" .\" Written by Raymond Lai . .\" Public domain. .\" -.Dd $Mdocdate: February 28 2015 $ +.Dd $Mdocdate: July 5 2012 $ .Dt SDIFF 1 .Os .Sh NAME @@ -22,11 +23,11 @@ displays two files side by side, with any differences between the two highlighted as follows: new lines are marked with -.Sq > ; +.Sq \*(Gt ; deleted lines are marked with -.Sq < ; +.Sq \*(Lt ; and changed lines are marked with -.Sq | . +.Sq \*(Ba . .Pp .Nm can also be used to interactively merge two files, @@ -37,9 +38,9 @@ .Pp The options are: .Bl -tag -width Ds -.It Fl l +.It Fl l -left-column Only print the left column for identical lines. -.It Fl o Ar outfile +.It Fl o -output Ar outfile Interactively merge .Ar file1 and @@ -78,9 +79,9 @@ Quit .Nm . .El -.It Fl s +.It Fl s -suppress-common-lines Skip identical lines. -.It Fl w Ar width +.It Fl w -width Ar width Print a maximum of .Ar width characters on each line. @@ -91,32 +92,44 @@ .Xr diff 1 are: .Bl -tag -width Ds -.It Fl a +.It Fl a -text Treat .Ar file1 and .Ar file2 as text files. -.It Fl b +.It Fl b -ignore-space-change Ignore trailing blank spaces. -.It Fl d +.It Fl d -minimal Minimize diff size. -.It Fl I Ar regexp +.It Fl I -ignore-matching-lines Ar regexp Ignore line changes matching .Ar regexp . All lines in the change must match .Ar regexp for the change to be ignored. -.It Fl i +.It Fl i -ignore-case Do a case-insensitive comparison. -.It Fl t +.It Fl t -expand-tabs Expand tabs to spaces. -.It Fl W -Ignore all spaces -(the -.Fl w -flag is passed to -.Xr diff 1 ) . +.It Fl W -ignore-all-space +Ignore all spaces. +.It Fl B -ignore-blank-lines +Ignore blank lines. +.It Fl E -ignore-tab-expansion +Treat tabs and eight spaces as the same. +.It Fl t -ignore-tabs +Ignore tabs. +.It Fl H -speed-large-files +Assume scattered small changes in a large file. +.It Fl -ignore-file-name-case +Ignore the case of file names. +.It Fl -no-ignore-file-name-case +Do not ignore file name case. +.It Fl -strip-trailing-cr +Skip identical lines. +.It Fl -tabsize Ar NUM +Change the size of tabs (default is 8.) .El .Sh ENVIRONMENT .Bl -tag -width Ds @@ -143,19 +156,6 @@ The default is .Pa /tmp . .El -.Sh EXIT STATUS -The -.Nm -utility exits with one of the following values: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It 0 -No differences were found. -.It 1 -Differences were found. -.It \*(Gt1 -An error occurred. -.El .Sh SEE ALSO .Xr cmp 1 , .Xr diff 1 , @@ -165,16 +165,10 @@ .Sh AUTHORS .Nm was written from scratch for the public domain by -.An Ray Lai Aq Mt ray@cyth.net . +.An Ray Lai Aq ray@cyth.net . .Sh CAVEATS -Although undocumented, -.Nm -supports most long options supported by GNU sdiff, -though some require GNU diff. .Pp Tabs are treated as anywhere from one to eight characters wide, depending on the current column. Terminals that treat tabs as eight characters wide will look best. -.Sh BUGS -.Nm -may not work with binary data. + Index: ./sdiff.c =================================================================== --- ./sdiff.c +++ ./sdiff.c @@ -5,6 +5,10 @@ * Public domain. */ +#include +__FBSDID("$FreeBSD$"); + +#include #include #include #include @@ -17,26 +21,32 @@ #include #include #include -#include #include #include #include #include -#include + +#include +#include #include "common.h" #include "extern.h" -#define WIDTH 130 +#define DIFF_PATH "/usr/bin/diff" + +#define WIDTH 126 /* * Each column must be at least one character wide, plus three * characters between the columns (space, [<|>], space). */ #define WIDTH_MIN 5 +/* 3 kilobytes of chars */ +#define MAX_CHECK 768 + /* A single diff line. */ struct diffline { - SIMPLEQ_ENTRY(diffline) diffentries; + STAILQ_ENTRY(diffline) diffentries; char *left; char div; char *right; @@ -45,6 +55,8 @@ static void astrcat(char **, const char *); static void enqueue(char *, char, char *); static char *mktmpcpy(const char *); +static int istextfile(FILE *); +static void binexec(char *, char *, char *) __dead2; static void freediff(struct diffline *); static void int_usage(void); static int parsecmd(FILE *, FILE *, FILE *); @@ -55,37 +67,105 @@ static void println(const char *, const char, const char *); static void processq(void); static void prompt(const char *, const char *); -__dead static void usage(void); +static void usage(void) __dead2; +static void fail(char*) __dead2; static char *xfgets(FILE *); -SIMPLEQ_HEAD(, diffline) diffhead = SIMPLEQ_HEAD_INITIALIZER(diffhead); -size_t line_width; /* width of a line (two columns and divider) */ -size_t width; /* width of each column */ -size_t file1ln, file2ln; /* line number of file1 and file2 */ -int Iflag = 0; /* ignore sets matching regexp */ -int lflag; /* print only left column for identical lines */ -int sflag; /* skip identical lines */ -FILE *outfp; /* file to save changes to */ +static STAILQ_HEAD(, diffline) diffhead = STAILQ_HEAD_INITIALIZER(diffhead); +static size_t line_width; /* width of a line (two columns and divider) */ +static size_t width; /* width of each column */ +static size_t file1ln, file2ln; /* line number of file1 and file2 */ +static int Iflag = 0; /* ignore sets matching regexp */ +static int lflag; /* print only left column for identical lines */ +static int sflag; /* skip identical lines */ +FILE *outfp; /* file to save changes to */ const char *tmpdir; /* TMPDIR or /tmp */ +enum { + HELP_OPT = CHAR_MAX + 1, + NORMAL_OPT, + FCASE_SENSITIVE_OPT, + FCASE_IGNORE_OPT, + FROMFILE_OPT, + TOFILE_OPT, + UNIDIR_OPT, + STRIPCR_OPT, + HORIZ_OPT, + LEFTC_OPT, + SUPCL_OPT, + LF_OPT, + /* the following groupings must be in sequence */ + OLDGF_OPT, + NEWGF_OPT, + UNCGF_OPT, + CHGF_OPT, + OLDLF_OPT, + NEWLF_OPT, + UNCLF_OPT, + /* end order-sensitive enums */ + TSIZE_OPT, + HLINES_OPT, + LFILES_OPT, + DIFFPROG_OPT, + PIPE_FD, + /* pid from the diff parent (if applicable) */ + DIFF_PID, + + NOOP_OPT, +}; + static struct option longopts[] = { + /* options only processed in sdiff */ + { "left-column", no_argument, NULL, LEFTC_OPT }, + { "suppress-common-lines", no_argument, NULL, 's' }, + { "width", required_argument, NULL, 'w' }, + + { "output", required_argument, NULL, 'o' }, + { "diff-program", required_argument, NULL, DIFFPROG_OPT }, + + { "pipe-fd", required_argument, NULL, PIPE_FD }, + { "diff-pid", required_argument, NULL, DIFF_PID }, + /* Options processed by diff. */ + { "ignore-file-name-case", no_argument, NULL, FCASE_IGNORE_OPT }, + { "no-ignore-file-name-case", no_argument, NULL, FCASE_SENSITIVE_OPT }, + { "strip-trailing-cr", no_argument, NULL, STRIPCR_OPT }, + { "tabsize", required_argument, NULL, TSIZE_OPT }, + { "help", no_argument, NULL, HELP_OPT }, { "text", no_argument, NULL, 'a' }, { "ignore-blank-lines", no_argument, NULL, 'B' }, { "ignore-space-change", no_argument, NULL, 'b' }, { "minimal", no_argument, NULL, 'd' }, { "ignore-tab-expansion", no_argument, NULL, 'E' }, - { "diff-program", required_argument, NULL, 'F' }, - { "speed-large-files", no_argument, NULL, 'H' }, { "ignore-matching-lines", required_argument, NULL, 'I' }, { "ignore-case", no_argument, NULL, 'i' }, - { "left-column", no_argument, NULL, 'l' }, - { "output", required_argument, NULL, 'o' }, - { "strip-trailing-cr", no_argument, NULL, 'S' }, - { "suppress-common-lines", no_argument, NULL, 's' }, { "expand-tabs", no_argument, NULL, 't' }, + { "speed-large-files", no_argument, NULL, 'H' }, { "ignore-all-space", no_argument, NULL, 'W' }, - { "width", required_argument, NULL, 'w' }, - { NULL, 0, NULL, 0 } + + { NULL, 0, NULL, '\0'} +}; + +static const char *help_msg[] = { + "\nusage: sdiff [-abdilstW] [-I regexp] [-o outfile] [-w width] file1 file2\n", + "\t-l, --left-column, Only print the left column for identical lines.", + "\t-o OUTFILE, --output=OUTFILE, nteractively merge file1 and file2 into outfile.", + "\t-s, --suppress-common-lines, Skip identical lines.", + "\t-w WIDTH, --width=WIDTH, Print a maximum of WIDTH characters on each line.", + "\tOptions passed to diff(1) are:", + "\t\t-a, --text, Treat file1 and file2 as text files.", + "\t\t-b, --ignore-trailing-cr, Ignore trailing blank spaces.", + "\t\t-d, --minimal, Minimize diff size.", + "\t\t-I RE, --ignore-matching-lines=RE, Ignore changes whose line matches RE.", + "\t\t-i, --ignore-case, Do a case-insensitive comparison.", + "\t\t-t, --expand-tabs Expand tabs to spaces.", + "\t\t-W, --ignore-all-spaces, Ignore all spaces.", + "\t\t--speed-large-files, Assume large file with scattered changes.", + "\t\t--strip-trailing-cr, Strip trailing carriage return.", + "\t\t--ignore-file-name-case, Ignore case of file names.", + "\t\t--no-ignore-file-name-case, Do not ignore file name case", + "\t\t--tabsize NUM, Change size of tabs (default 8.)", + + NULL, }; /* @@ -150,22 +230,21 @@ FAIL: unlink(target_file); - exit(2); + exit(1); } int main(int argc, char **argv) { - FILE *diffpipe, *file1, *file2; + FILE *diffpipe=NULL, *file1, *file2; size_t diffargc = 0, wflag = WIDTH; - int ch, fd[2], status; - pid_t pid; + int ch, fd[2] = {-1}, status; + pid_t pid=0; pid_t ppid =-1; const char *outfile = NULL; - char **diffargv, *diffprog = "diff", *filename1, *filename2, - *tmp1, *tmp2, *s1, *s2; - - if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1) - err(2, "pledge"); + struct option *popt; + char **diffargv, *diffprog = DIFF_PATH, *filename1, *filename2, + *tmp1, *tmp2, *s1, *s2; + int i; /* * Process diff flags. @@ -184,69 +263,90 @@ /* Add first argument, the program name. */ diffargv[diffargc++] = diffprog; + /* create a dynamic string for merging single-switch options */ + if ( asprintf(&diffargv[diffargc++], "-") < 0 ) + err(2, "main"); + while ((ch = getopt_long(argc, argv, "aBbdEHI:ilo:stWw:", longopts, NULL)) != -1) { const char *errstr; switch (ch) { + /* only compatible --long-name-form with diff */ + case FCASE_IGNORE_OPT: + case FCASE_SENSITIVE_OPT: + case STRIPCR_OPT: + case TSIZE_OPT: + case 'S': + break; + /* combine no-arg single switches */ case 'a': - diffargv[diffargc++] = "-a"; - break; case 'B': - diffargv[diffargc++] = "-B"; - break; case 'b': - diffargv[diffargc++] = "-b"; - break; case 'd': - diffargv[diffargc++] = "-d"; - break; case 'E': - diffargv[diffargc++] = "-E"; + case 'i': + case 't': + case 'H': + case 'W': + for(popt = longopts; ch != popt->val && popt->name != NULL; popt++); + diffargv[1] = realloc(diffargv[1], sizeof(char) * strlen(diffargv[1]) + 2); + /* + * In diff, the 'W' option is 'w' and the 'w' is 'W'. + */ + if (ch == 'W') + sprintf(diffargv[1], "%sw", diffargv[1]); + else + sprintf(diffargv[1], "%s%c", diffargv[1], ch); break; - case 'F': + case DIFFPROG_OPT: diffargv[0] = diffprog = optarg; break; - case 'H': - diffargv[diffargc++] = "-H"; - break; case 'I': Iflag = 1; diffargv[diffargc++] = "-I"; diffargv[diffargc++] = optarg; break; - case 'i': - diffargv[diffargc++] = "-i"; - break; case 'l': lflag = 1; break; case 'o': outfile = optarg; break; - case 'S': - diffargv[diffargc++] = "--strip-trailing-cr"; - break; case 's': sflag = 1; break; - case 't': - diffargv[diffargc++] = "-t"; - break; - case 'W': - diffargv[diffargc++] = "-w"; - break; case 'w': wflag = strtonum(optarg, WIDTH_MIN, INT_MAX, &errstr); if (errstr) errx(2, "width is %s: %s", errstr, optarg); break; + case DIFF_PID: + ppid = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr) + errx(2, "diff pid value is %s: %s", errstr, optarg); + break; + case HELP_OPT: + for (i = 0; help_msg[i] != NULL; i++) + printf("%s\n", help_msg[i]); + exit(0); + break; default: usage(); + break; } + } + /* no single switches were used */ + if (strcmp(diffargv[1], "-") == 0 ) { + for ( i = 1; i < argc-1; i++) { + diffargv[i] = diffargv[i+1]; + } + diffargv[diffargc-1] = NULL; + diffargc--; } + argc -= optind; argv += optind; @@ -256,7 +356,7 @@ if (outfile && (outfp = fopen(outfile, "w")) == NULL) err(2, "could not open: %s", optarg); - if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') + if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') tmpdir = _PATH_TMP; filename1 = argv[0]; @@ -295,37 +395,54 @@ errx(2, "width is too large: %zu", width); line_width = width * 2 + 3; - if (pipe(fd)) - err(2, "pipe"); + if (ppid == -1 ) { + if (pipe(fd)) + err(2, "pipe"); + + switch (pid = fork()) { + case 0: + /* child */ + /* We don't read from the pipe. */ + close(fd[0]); + if (dup2(fd[1], STDOUT_FILENO) == -1) + err(2, "child could not duplicate descriptor"); + /* Free unused descriptor. */ + close(fd[1]); + execvp(diffprog, diffargv); + err(2, "could not execute diff: %s", diffprog); + break; + case -1: + err(2, "could not fork"); + break; + } - switch(pid = fork()) { - case 0: - /* child */ - /* We don't read from the pipe. */ - close(fd[0]); - if (dup2(fd[1], STDOUT_FILENO) == -1) - err(2, "child could not duplicate descriptor"); - /* Free unused descriptor. */ + /* parent */ + /* We don't write to the pipe. */ close(fd[1]); - execvp(diffprog, diffargv); - err(2, "could not execute diff: %s", diffprog); - case -1: - err(2, "could not fork"); + /* Open pipe to diff command. */ + if ((diffpipe = fdopen(fd[0], "r")) == NULL) + err(2, "could not open diff pipe"); } - - /* parent */ - /* We don't write to the pipe. */ - close(fd[1]); - - /* Open pipe to diff command. */ - if ((diffpipe = fdopen(fd[0], "r")) == NULL) - err(2, "could not open diff pipe"); if ((file1 = fopen(filename1, "r")) == NULL) err(2, "could not open %s", filename1); if ((file2 = fopen(filename2, "r")) == NULL) err(2, "could not open %s", filename2); - + if (!istextfile(file1) || !istextfile(file2)) { + /* Close open files and pipe, delete temps */ + fclose(file1); + fclose(file2); + fclose(diffpipe); + if (tmp1) + if (unlink(tmp1)) + warn("Error deleting %s.", tmp1); + if (tmp2) + if (unlink(tmp2)) + warn("Error deleting %s.", tmp2); + free(tmp1); + free(tmp2); + binexec(diffprog, filename1, filename2); + } /* Line numbers start at one. */ file1ln = file2ln = 1; @@ -337,15 +454,15 @@ /* Wait for diff to exit. */ if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) || WEXITSTATUS(status) >= 2) - err(2, "diff exited abnormally"); + err(2, "diff exited abnormally."); /* Delete and free unneeded temporary files. */ if (tmp1) if (unlink(tmp1)) - warn("error deleting %s", tmp1); + warn("Error deleting %s.", tmp1); if (tmp2) if (unlink(tmp2)) - warn("error deleting %s", tmp2); + warn("Error deleting %s.", tmp2); free(tmp1); free(tmp2); filename1 = filename2 = tmp1 = tmp2 = NULL; @@ -373,6 +490,44 @@ } /* + * When sdiff/zsdiff detects a binary file as input, executes them with + * diff/zdiff to maintain the same behavior as GNU sdiff with binary input. + */ +static void +binexec(char *diffprog, char *f1, char *f2) +{ + + char *args[] = {diffprog, f1, f2, (char *) 0}; + execv(diffprog, args); + + /* If execv() fails, sdiff's execution will continue below. */ + errx(1, "Could not execute diff process.\n"); +} + +/* + * Checks whether a file appears to be a text file. + */ +static int +istextfile(FILE *f) +{ + int i; + char ch; + + if (f == NULL) + return (1); + rewind(f); + for (i = 0; i <= MAX_CHECK || ch != EOF; i++) { + ch = fgetc(f); + if (ch == '\0') { + rewind(f); + return (0); + } + } + rewind(f); + return (1); +} + +/* * Prints an individual column (left or right), taking into account * that tabs are variable-width. Takes a string, the current column * the cursor is on the screen, and the maximum value of the column. @@ -381,6 +536,7 @@ static void printcol(const char *s, size_t *col, const size_t col_max) { + for (; *s && *col < col_max; ++s) { size_t new_col; @@ -404,11 +560,9 @@ return; *col = new_col; break; - default: ++(*col); } - putchar(*s); } } @@ -430,47 +584,37 @@ const char *p; /* Skip leading whitespace. */ - for (p = cmd; isspace((unsigned char)*p); ++p) + for (p = cmd; isspace(*p); ++p) ; - switch (*p) { case 'e': /* Skip `e'. */ ++p; - if (eparse(p, s1, s2) == -1) goto USAGE; break; - case 'l': case '1': /* Choose left column as-is. */ if (s1 != NULL) fprintf(outfp, "%s\n", s1); - /* End of command parsing. */ break; - case 'q': goto QUIT; - case 'r': case '2': /* Choose right column as-is. */ if (s2 != NULL) fprintf(outfp, "%s\n", s2); - /* End of command parsing. */ break; - case 's': sflag = 1; goto PROMPT; - case 'v': sflag = 0; /* FALLTHROUGH */ - default: /* Interactive usage help. */ USAGE: @@ -481,7 +625,6 @@ /* Prompt user again. */ continue; } - free(cmd); return; } @@ -517,16 +660,16 @@ } + /* Otherwise, we pad this column up to width. */ + for (; col < width; ++col) + putchar(' '); + /* Only print left column. */ if (div == ' ' && !s2) { - putchar('\n'); + printf(" (\n"); return; } - /* Otherwise, we pad this column up to width. */ - for (; col < width; ++col) - putchar(' '); - /* * Print column divider. If there is no second column, we don't * need to add the space for padding. @@ -588,7 +731,7 @@ p = line; /* Go to character after line number. */ - while (isdigit((unsigned char)*p)) + while (isdigit(*p)) ++p; c = *p; *p++ = 0; @@ -598,10 +741,9 @@ /* A range is specified for file1. */ if (c == ',') { - q = p; /* Go to character after file2end. */ - while (isdigit((unsigned char)*p)) + while (isdigit(*p)) ++p; c = *p; *p++ = 0; @@ -610,7 +752,6 @@ errx(2, "file1 end is %s: %s", errstr, line); if (file1start > file1end) errx(2, "invalid line range in file1: %s", line); - } else file1end = file1start; @@ -621,7 +762,7 @@ q = p; /* Go to character after line number. */ - while (isdigit((unsigned char)*p)) + while (isdigit(*p)) ++p; c = *p; *p++ = 0; @@ -729,17 +870,14 @@ printa(file2, file2end); n = file2end - file2start + 1; break; - case 'c': printc(file1, file1end, file2, file2end); n = file1end - file1start + 1 + 1 + file2end - file2start + 1; break; - case 'd': printd(file1, file1end); n = file1end - file1start + 1; break; - default: errx(2, "invalid diff command: %c: %s", cmd, line); } @@ -768,7 +906,7 @@ diffp->left = left; diffp->div = div; diffp->right = right; - SIMPLEQ_INSERT_TAIL(&diffhead, diffp, diffentries); + STAILQ_INSERT_TAIL(&diffhead, diffp, diffentries); } /* @@ -777,6 +915,7 @@ static void freediff(struct diffline *diffp) { + free(diffp->left); free(diffp->right); free(diffp); @@ -799,7 +938,6 @@ static const char *oldstr = NULL; char *newstr; - /* * First string is NULL, so just copy append. */ @@ -859,11 +997,11 @@ char divc, *left, *right; /* Don't process empty queue. */ - if (SIMPLEQ_EMPTY(&diffhead)) + if (STAILQ_EMPTY(&diffhead)) return; /* Remember the divider. */ - divc = SIMPLEQ_FIRST(&diffhead)->div; + divc = STAILQ_FIRST(&diffhead)->div; left = NULL; right = NULL; @@ -871,7 +1009,7 @@ * Go through set of diffs, concatenating each line in left or * right column into two long strings, `left' and `right'. */ - SIMPLEQ_FOREACH(diffp, &diffhead, diffentries) { + STAILQ_FOREACH(diffp, &diffhead, diffentries) { /* * Print changed lines if -s was given, * print all lines if -s was not given. @@ -888,9 +1026,9 @@ } /* Empty queue and free each diff line and its elements. */ - while (!SIMPLEQ_EMPTY(&diffhead)) { - diffp = SIMPLEQ_FIRST(&diffhead); - SIMPLEQ_REMOVE_HEAD(&diffhead, diffentries); + while (!STAILQ_EMPTY(&diffhead)) { + diffp = STAILQ_FIRST(&diffhead); + STAILQ_REMOVE_HEAD(&diffhead, diffentries); freediff(diffp); } @@ -925,7 +1063,6 @@ errx(2, "append ended early"); enqueue(NULL, '>', line); } - processq(); } @@ -937,10 +1074,10 @@ printc(FILE *file1, size_t file1end, FILE *file2, size_t file2end) { struct fileline { - SIMPLEQ_ENTRY(fileline) fileentries; + STAILQ_ENTRY(fileline) fileentries; char *line; }; - SIMPLEQ_HEAD(, fileline) delqhead = SIMPLEQ_HEAD_INITIALIZER(delqhead); + STAILQ_HEAD(, fileline) delqhead = STAILQ_HEAD_INITIALIZER(delqhead); /* Read lines to be deleted. */ for (; file1ln <= file1end; ++file1ln) { @@ -955,11 +1092,11 @@ if (!(linep = malloc(sizeof(struct fileline)))) err(2, "printc"); linep->line = line1; - SIMPLEQ_INSERT_TAIL(&delqhead, linep, fileentries); + STAILQ_INSERT_TAIL(&delqhead, linep, fileentries); } /* Process changed lines.. */ - for (; !SIMPLEQ_EMPTY(&delqhead) && file2ln <= file2end; + for (; !STAILQ_EMPTY(&delqhead) && file2ln <= file2end; ++file2ln) { struct fileline *del; char *add; @@ -968,9 +1105,9 @@ if (!(add = xfgets(file2))) errx(2, "error reading add in change"); - del = SIMPLEQ_FIRST(&delqhead); + del = STAILQ_FIRST(&delqhead); enqueue(del->line, '|', add); - SIMPLEQ_REMOVE_HEAD(&delqhead, fileentries); + STAILQ_REMOVE_HEAD(&delqhead, fileentries); /* * Free fileline structure but not its elements since * they are queued up. @@ -992,12 +1129,12 @@ processq(); /* Process remaining lines to delete. */ - while (!SIMPLEQ_EMPTY(&delqhead)) { + while (!STAILQ_EMPTY(&delqhead)) { struct fileline *filep; - filep = SIMPLEQ_FIRST(&delqhead); + filep = STAILQ_FIRST(&delqhead); enqueue(filep->line, '<', NULL); - SIMPLEQ_REMOVE_HEAD(&delqhead, fileentries); + STAILQ_REMOVE_HEAD(&delqhead, fileentries); free(filep); } processq(); @@ -1026,6 +1163,7 @@ static void int_usage(void) { + puts("e:\tedit blank diff\n" "eb:\tedit both diffs concatenated\n" "el:\tedit left diff\n" @@ -1040,10 +1178,9 @@ static void usage(void) { - extern char *__progname; fprintf(stderr, - "usage: %s [-abdilstW] [-I regexp] [-o outfile] [-w width] file1 file2\n", - __progname); - exit(2); + "usage: sdiff [-abdilstW] [-I regexp] [-o outfile] [-w width] file1" + " file2\n"); + exit(1); }