version 1.10, 2005/12/27 05:04:27 |
version 1.11, 2005/12/27 05:13:14 |
|
|
static void undiff(char *); |
static void undiff(char *); |
__dead static void usage(void); |
__dead static void usage(void); |
static char *xfgets(FILE *); |
static char *xfgets(FILE *); |
static size_t xstrtonum(const char *); |
|
|
|
SIMPLEQ_HEAD(, diffline) diffhead = SIMPLEQ_HEAD_INITIALIZER(diffhead); |
SIMPLEQ_HEAD(, diffline) diffhead = SIMPLEQ_HEAD_INITIALIZER(diffhead); |
size_t line_width; /* width of a line (two columns and divider) */ |
size_t line_width; /* width of a line (two columns and divider) */ |
|
|
} |
} |
|
|
/* |
/* |
* Takes a string nptr and returns a numeric value. The first character |
|
* must be a digit. Parsing ends when a non-numerical character is |
|
* reached. |
|
*/ |
|
static size_t |
|
xstrtonum(const char *nptr) |
|
{ |
|
size_t n; |
|
const char *errstr; |
|
char *copy, *ptr; |
|
|
|
/* Make copy of numeric string. */ |
|
if ((copy = strdup(nptr)) == NULL) |
|
err(2, "out of memory"); |
|
|
|
/* Look for first non-digit. */ |
|
for (ptr = copy; isdigit(*ptr); ++ptr) |
|
; |
|
|
|
/* End string at first non-digit. */ |
|
if (*ptr != '\0') |
|
*ptr = '\0'; |
|
|
|
/* Parse number. */ |
|
n = strtonum(copy, 0, INT_MAX, &errstr); |
|
if (errstr) |
|
errx(2, "line number in diff is %s: %s", errstr, nptr); |
|
|
|
/* Free copy of numeric string. */ |
|
free(copy); |
|
|
|
return (n); |
|
} |
|
|
|
/* |
|
* Prints an individual column (left or right), taking into account |
* Prints an individual column (left or right), taking into account |
* that tabs are variable-width. Takes a string, the current column |
* that tabs are variable-width. Takes a string, the current column |
* the cursor is on the screen, and the maximum value of the column. |
* the cursor is on the screen, and the maximum value of the column. |
|
|
{ |
{ |
size_t file1start, file1end, file2start, file2end; |
size_t file1start, file1end, file2start, file2end; |
/* ed command line and pointer to characters in line */ |
/* ed command line and pointer to characters in line */ |
const char *line, *p; |
char *line, *p, *q; |
char cmd; |
const char *errstr; |
|
char c, cmd; |
|
|
/* Read ed command. */ |
/* Read ed command. */ |
if (!(line = xfgets(difffile))) |
if (!(line = xfgets(difffile))) |
return (EOF); |
return (EOF); |
|
|
file1start = xstrtonum(line); |
|
p = line; |
p = line; |
/* Go to character after line number. */ |
/* Go to character after line number. */ |
while (isdigit(*p)) |
while (isdigit(*p)) |
++p; |
++p; |
|
c = *p; |
|
*p++ = 0; |
|
file1start = strtonum(line, 0, INT_MAX, &errstr); |
|
if (errstr) |
|
errx(2, "file1 start is %s: %s", errstr, line); |
|
|
/* A range is specified for file1. */ |
/* A range is specified for file1. */ |
if (*p == ',') { |
if (c == ',') { |
/* Go to range end. */ |
|
++p; |
|
|
|
file1end = xstrtonum(p); |
q = p; |
if (file1start > file1end) |
|
errx(2, "invalid line range in file1: %s", line); |
|
|
|
/* Go to character after file2end. */ |
/* Go to character after file2end. */ |
while (isdigit(*p)) |
while (isdigit(*p)) |
++p; |
++p; |
|
c = *p; |
|
*p++ = 0; |
|
file1end = strtonum(q, 0, INT_MAX, &errstr); |
|
if (errstr) |
|
errx(2, "file1 end is %s: %s", errstr, line); |
|
if (file1start > file1end) |
|
errx(2, "invalid line range in file1: %s", line); |
|
|
} else |
} else |
file1end = file1start; |
file1end = file1start; |
|
|
/* This character should be the ed command now. */ |
cmd = c; |
cmd = *p; |
|
|
|
/* Check that cmd is valid. */ |
/* Check that cmd is valid. */ |
if (!(cmd == 'a' || cmd == 'c' || cmd == 'd')) |
if (!(cmd == 'a' || cmd == 'c' || cmd == 'd')) |
errx(2, "ed command not recognized: %c: %s", cmd, line); |
errx(2, "ed command not recognized: %c: %s", cmd, line); |
|
|
/* Go to file2 line range. */ |
q = p; |
++p; |
|
|
|
file2start = xstrtonum(p); |
|
/* Go to character after line number. */ |
/* Go to character after line number. */ |
while (isdigit(*p)) |
while (isdigit(*p)) |
++p; |
++p; |
|
c = *p; |
|
*p++ = 0; |
|
file2start = strtonum(q, 0, INT_MAX, &errstr); |
|
if (errstr) |
|
errx(2, "file2 start is %s: %s", errstr, line); |
|
|
/* |
/* |
* There should either be a comma signifying a second line |
* There should either be a comma signifying a second line |
* number or the line should just end here. |
* number or the line should just end here. |
*/ |
*/ |
if (!(*p == ',' || *p == '\0')) |
if (c != ',' && c != '\0') |
errx(2, "invalid line range in file2: %c: %s", *p, line); |
errx(2, "invalid line range in file2: %c: %s", c, line); |
|
|
if (*p == ',') { |
if (c == ',') { |
++p; |
|
|
|
file2end = xstrtonum(p); |
file2end = strtonum(p, 0, INT_MAX, &errstr); |
|
if (errstr) |
|
errx(2, "file2 end is %s: %s", errstr, line); |
if (file2start >= file2end) |
if (file2start >= file2end) |
errx(2, "invalid line range in file2: %s", line); |
errx(2, "invalid line range in file2: %s", line); |
} else |
} else |