version 1.13, 2006/02/14 08:26:20 |
version 1.14, 2006/02/15 06:58:06 |
|
|
/* A single diff line. */ |
/* A single diff line. */ |
struct diffline { |
struct diffline { |
SIMPLEQ_ENTRY(diffline) diffentries; |
SIMPLEQ_ENTRY(diffline) diffentries; |
const char *left; |
char *left; |
char div; |
char div; |
const char *right; |
char *right; |
}; |
}; |
|
|
static void astrcat(char **, const char *); |
static void astrcat(char **, const char *); |
static void enqueue(const char *, const char, const char *); |
static void enqueue(char *, char, char *); |
static void freediff(const struct diffline *); |
static void freediff(struct diffline *); |
static void int_usage(void); |
static void int_usage(void); |
static int parsecmd(FILE *, FILE *, FILE *); |
static int parsecmd(FILE *, FILE *, FILE *); |
static void printa(FILE *, size_t); |
static void printa(FILE *, size_t); |
|
|
size_t diffargc = 0, wflag = WIDTH; |
size_t diffargc = 0, wflag = WIDTH; |
int ch, fd[2], status; |
int ch, fd[2], status; |
pid_t pid; |
pid_t pid; |
const char **diffargv, *diffprog = "diff", *s1, *s2; |
char **diffargv, *diffprog = "diff", *s1, *s2; |
|
|
/* |
/* |
* Process diff flags. |
* Process diff flags. |
|
|
/* Free unused descriptor. */ |
/* Free unused descriptor. */ |
close(fd[1]); |
close(fd[1]); |
|
|
execvp(diffprog, (char *const *)diffargv); |
execvp(diffprog, diffargv); |
err(2, "could not execute diff: %s", diffprog); |
err(2, "could not execute diff: %s", diffprog); |
case -1: |
case -1: |
err(2, "could not fork"); |
err(2, "could not fork"); |
|
|
static void |
static void |
prompt(const char *s1, const char *s2) |
prompt(const char *s1, const char *s2) |
{ |
{ |
const char *cmd; |
char *cmd; |
|
|
/* Print command prompt. */ |
/* Print command prompt. */ |
putchar('%'); |
putchar('%'); |
|
|
/* Get user input. */ |
/* Get user input. */ |
for (; (cmd = xfgets(stdin)); free((void *)cmd)) { |
for (; (cmd = xfgets(stdin)); free(cmd)) { |
const char *p; |
const char *p; |
|
|
/* Skip leading whitespace. */ |
/* Skip leading whitespace. */ |
|
|
continue; |
continue; |
} |
} |
|
|
free((void *)cmd); |
free(cmd); |
return; |
return; |
} |
} |
|
|
|
|
*/ |
*/ |
for (; file1ln < file1start && file2ln < file2start; |
for (; file1ln < file1start && file2ln < file2start; |
++file1ln, ++file2ln) { |
++file1ln, ++file2ln) { |
const char *s1, *s2; |
char *s1, *s2; |
|
|
if (!(s1 = xfgets(file1))) |
if (!(s1 = xfgets(file1))) |
errx(2, "file1 shorter than expected"); |
errx(2, "file1 shorter than expected"); |
|
|
|
|
/* If the -l flag was specified, print only left column. */ |
/* If the -l flag was specified, print only left column. */ |
if (lflag) { |
if (lflag) { |
free((void *)s2); |
free(s2); |
/* |
/* |
* XXX - If -l and -I are both specified, all |
* XXX - If -l and -I are both specified, all |
* unchanged or ignored lines are shown with a |
* unchanged or ignored lines are shown with a |
|
|
} |
} |
/* Ignore deleted lines. */ |
/* Ignore deleted lines. */ |
for (; file1ln < file1start; ++file1ln) { |
for (; file1ln < file1start; ++file1ln) { |
const char *s; |
char *s; |
|
|
if (!(s = xfgets(file1))) |
if (!(s = xfgets(file1))) |
errx(2, "file1 shorter than expected"); |
errx(2, "file1 shorter than expected"); |
|
|
} |
} |
/* Ignore added lines. */ |
/* Ignore added lines. */ |
for (; file2ln < file2start; ++file2ln) { |
for (; file2ln < file2start; ++file2ln) { |
const char *s; |
char *s; |
|
|
if (!(s = xfgets(file2))) |
if (!(s = xfgets(file2))) |
errx(2, "file2 shorter than expected"); |
errx(2, "file2 shorter than expected"); |
|
|
/* If -l flag was given, don't print right column. */ |
/* If -l flag was given, don't print right column. */ |
if (lflag) |
if (lflag) |
free((void *)s); |
free(s); |
else |
else |
enqueue(NULL, ')', s); |
enqueue(NULL, ')', s); |
} |
} |
|
|
* Queues up a diff line. |
* Queues up a diff line. |
*/ |
*/ |
static void |
static void |
enqueue(const char *left, const char div, const char *right) |
enqueue(char *left, char div, char *right) |
{ |
{ |
struct diffline *diffp; |
struct diffline *diffp; |
|
|
|
|
* Free a diffline structure and its elements. |
* Free a diffline structure and its elements. |
*/ |
*/ |
static void |
static void |
freediff(const struct diffline *diffp) |
freediff(struct diffline *diffp) |
{ |
{ |
if (diffp->left) |
free(diffp->left); |
free((void *)diffp->left); |
free(diffp->right); |
if (diffp->right) |
free(diffp); |
free((void *)diffp->right); |
|
free((void *)diffp); |
|
} |
} |
|
|
/* |
/* |
|
|
{ |
{ |
/* Length of string in previous run. */ |
/* Length of string in previous run. */ |
static size_t offset = 0; |
static size_t offset = 0; |
size_t copied, newlen; |
size_t newlen; |
/* |
/* |
* String from previous run. Compared to *s to see if we are |
* String from previous run. Compared to *s to see if we are |
* dealing with the same string. If so, we can use offset. |
* dealing with the same string. If so, we can use offset. |
*/ |
*/ |
const static char *oldstr = NULL; |
static const char *oldstr = NULL; |
char *newstr; |
char *newstr; |
|
|
|
|
|
|
|
|
/* Concatenate. */ |
/* Concatenate. */ |
strlcpy(*s + offset, "\n", newlen - offset); |
strlcpy(*s + offset, "\n", newlen - offset); |
copied = strlcat(*s + offset, append, newlen - offset); |
|
|
|
/* Store generated string's values. */ |
/* Store generated string's values. */ |
offset = newlen - 1; |
offset = newlen - 1; |
|
|
processq(void) |
processq(void) |
{ |
{ |
struct diffline *diffp; |
struct diffline *diffp; |
char div, *left, *right; |
char divc, *left, *right; |
|
|
/* Don't process empty queue. */ |
/* Don't process empty queue. */ |
if (SIMPLEQ_EMPTY(&diffhead)) |
if (SIMPLEQ_EMPTY(&diffhead)) |
return; |
return; |
|
|
div = '\0'; |
divc = '\0'; |
left = NULL; |
left = NULL; |
right = NULL; |
right = NULL; |
/* |
/* |
|
|
*/ |
*/ |
SIMPLEQ_FOREACH(diffp, &diffhead, diffentries) { |
SIMPLEQ_FOREACH(diffp, &diffhead, diffentries) { |
/* |
/* |
* Make sure that div is consistent throughout set. |
* Make sure that divc is consistent throughout set. |
* If div is set, compare to next entry's div. They |
* If divc is set, compare to next entry's divc. They |
* should be the same. If div is not set, then store |
* should be the same. If divc is not set, then store |
* this as this set's div. |
* this as this set's divc. |
*/ |
*/ |
if (!div) |
if (divc == '\0') |
div = diffp->div; |
divc = diffp->div; |
|
|
/* |
/* |
* Print changed lines if -s was given, |
* Print changed lines if -s was given, |
* print all lines if -s was not given. |
* print all lines if -s was not given. |
*/ |
*/ |
if (!sflag || div == '|' || div == '<' || div == '>') |
if (!sflag || divc == '|' || divc == '<' || divc == '>') |
println(diffp->left, diffp->div, diffp->right); |
println(diffp->left, diffp->div, diffp->right); |
|
|
/* Append new lines to diff set. */ |
/* Append new lines to diff set. */ |
|
|
|
|
/* Write to outfile, prompting user if lines are different. */ |
/* Write to outfile, prompting user if lines are different. */ |
if (outfile) |
if (outfile) |
switch (div) { |
switch (divc) { |
case ' ': case '(': case ')': |
case ' ': case '(': case ')': |
fprintf(outfile, "%s\n", left); |
fprintf(outfile, "%s\n", left); |
break; |
break; |
|
|
prompt(left, right); |
prompt(left, right); |
break; |
break; |
default: |
default: |
errx(2, "invalid divider: %c", div); |
errx(2, "invalid divider: %c", divc); |
} |
} |
|
|
/* Free left and right. */ |
/* Free left and right. */ |
if (left) |
free(left); |
free(left); |
free(right); |
if (right) |
|
free(right); |
|
} |
} |
|
|
/* |
/* |
|
|
printc(FILE *file1, size_t file1end, FILE *file2, size_t file2end) |
printc(FILE *file1, size_t file1end, FILE *file2, size_t file2end) |
{ |
{ |
struct fileline { |
struct fileline { |
SIMPLEQ_ENTRY(fileline) fileentries; |
SIMPLEQ_ENTRY(fileline) fileentries; |
const char *line; |
char *line; |
}; |
}; |
SIMPLEQ_HEAD(, fileline) delqhead = SIMPLEQ_HEAD_INITIALIZER(delqhead); |
SIMPLEQ_HEAD(, fileline) delqhead = SIMPLEQ_HEAD_INITIALIZER(delqhead); |
|
|
/* Read lines to be deleted. */ |
/* Read lines to be deleted. */ |
for (; file1ln <= file1end; ++file1ln) { |
for (; file1ln <= file1end; ++file1ln) { |
struct fileline *linep; |
struct fileline *linep; |
const char *line1; |
char *line1; |
|
|
/* Read lines from both. */ |
/* Read lines from both. */ |
if (!(line1 = xfgets(file1))) |
if (!(line1 = xfgets(file1))) |
|
|
enqueue(NULL, '>', add); |
enqueue(NULL, '>', add); |
} |
} |
processq(); |
processq(); |
#undef getaddln |
|
|
|
/* Process remaining lines to delete. */ |
/* Process remaining lines to delete. */ |
while (!SIMPLEQ_EMPTY(&delqhead)) { |
while (!SIMPLEQ_EMPTY(&delqhead)) { |
|
|
static void |
static void |
printd(FILE *file1, size_t file1end) |
printd(FILE *file1, size_t file1end) |
{ |
{ |
const char *line1; |
char *line1; |
|
|
/* Print out lines file1ln to line2. */ |
/* Print out lines file1ln to line2. */ |
for (; file1ln <= file1end; ++file1ln) { |
for (; file1ln <= file1end; ++file1ln) { |