#include <fatal.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <wait.h>
#define ONSIG 16
static char Error[128];
static int seglim;
static char diff[] = "/usr/bin/diff";
static char tempskel[] = "/tmp/bdXXXXXX";
static char tempfile[32];
static char otmp[32], ntmp[32];
static int fflags;
static int fatal_num = 1;
static offset_t linenum;
static size_t obufsiz, nbufsiz, dbufsiz;
static char *readline(char **, size_t *, FILE *);
static void addgen(char **, size_t *, FILE *);
static void delgen(char **, size_t *, FILE *);
static void fixnum(char *);
static void fatal(char *);
static void setsig(void);
static void setsig1(int);
static char *satoi(char *, offset_t *);
static FILE *maket(char *);
static char *prognam;
int
main(int argc, char *argv[])
{
FILE *poldfile, *pnewfile;
char *oline, *nline, *diffline;
char *olp, *nlp, *dp;
int otcnt, ntcnt;
pid_t i;
int pfd[2];
FILE *poldtemp, *pnewtemp, *pipeinp;
int status;
prognam = argv[0];
fflags = FTLMSG | FTLCLN | FTLEXIT;
setsig();
if (argc < 3 || argc > 5)
fatal("arg count");
if (strcmp(argv[1], "-") == 0 && strcmp(argv[2], "-") == 0)
fatal("both files standard input");
if (strcmp(argv[1], "-") == 0)
poldfile = stdin;
else
if ((poldfile = fopen(argv[1], "r")) == NULL) {
(void) snprintf(Error, sizeof (Error),
"Can not open '%s'", argv[1]);
fatal(Error);
}
if (strcmp(argv[2], "-") == 0)
pnewfile = stdin;
else
if ((pnewfile = fopen(argv[2], "r")) == NULL) {
(void) snprintf(Error, sizeof (Error),
"Can not open '%s'", argv[2]);
fatal(Error);
}
seglim = 3500;
if (argc > 3) {
if (argv[3][0] == '-' && argv[3][1] == 's')
fflags &= ~FTLMSG;
else {
if ((seglim = atoi(argv[3])) == 0)
fatal("non-numeric limit");
if (argc == 5 && argv[4][0] == '-' &&
argv[4][1] == 's')
fflags &= ~FTLMSG;
}
}
linenum = 0;
obufsiz = BUFSIZ;
nbufsiz = BUFSIZ;
dbufsiz = BUFSIZ;
if ((oline = (char *)malloc(obufsiz)) == NULL ||
(nline = (char *)malloc(nbufsiz)) == NULL ||
(diffline = (char *)malloc(dbufsiz)) == NULL)
fatal("Out of memory");
for (;;) {
olp = readline(&oline, &obufsiz, poldfile);
nlp = readline(&nline, &nbufsiz, pnewfile);
if (!olp && !nlp)
return (0);
if (!olp) {
addgen(&nline, &nbufsiz, pnewfile);
}
if (!nlp) {
delgen(&oline, &obufsiz, poldfile);
}
if (strcmp(olp, nlp) == 0)
linenum++;
else
break;
}
for (;;) {
if (!olp && !nlp)
return (0);
if (!olp) {
addgen(&nline, &nbufsiz, pnewfile);
}
if (!nlp) {
delgen(&oline, &obufsiz, poldfile);
}
poldtemp = maket(otmp);
otcnt = 0;
while (olp && otcnt < seglim) {
(void) fputs(oline, poldtemp);
if (ferror(poldtemp) != 0) {
fflags |= FTLMSG;
fatal("Can not write to temporary file");
}
olp = readline(&oline, &obufsiz, poldfile);
otcnt++;
}
(void) fclose(poldtemp);
pnewtemp = maket(ntmp);
ntcnt = 0;
while (nlp && ntcnt < seglim) {
(void) fputs(nline, pnewtemp);
if (ferror(pnewtemp) != 0) {
fflags |= FTLMSG;
fatal("Can not write to temporary file");
}
nlp = readline(&nline, &nbufsiz, pnewfile);
ntcnt++;
}
(void) fclose(pnewtemp);
if ((pipe(pfd)) == -1)
fatal("Can not create pipe");
if ((i = fork()) < (pid_t)0) {
(void) close(pfd[0]);
(void) close(pfd[1]);
fatal("Can not fork, try again");
} else if (i == (pid_t)0) {
(void) close(pfd[0]);
(void) close(1);
(void) dup(pfd[1]);
(void) close(pfd[1]);
(void) execlp(diff, diff, otmp, ntmp, 0);
(void) close(1);
(void) snprintf(Error, sizeof (Error),
"Can not execute '%s'", diff);
fatal_num = 2;
fatal(Error);
} else {
(void) close(pfd[1]);
pipeinp = fdopen(pfd[0], "r");
while ((dp = readline(&diffline, &dbufsiz, pipeinp))) {
if (isdigit(*dp))
fixnum(diffline);
else
(void) printf("%s", diffline);
}
(void) fclose(pipeinp);
(void) wait(&status);
if (status&~0x100) {
(void) snprintf(Error, sizeof (Error),
"'%s' failed", diff);
fatal(Error);
}
}
linenum += seglim;
(void) unlink(otmp);
(void) unlink(ntmp);
}
}
static void
saverest(char **linep, size_t *bufsizp, FILE *iptr)
{
char *lp;
FILE *temptr;
temptr = maket(tempfile);
lp = *linep;
while (lp) {
(void) fputs(*linep, temptr);
linenum++;
lp = readline(linep, bufsizp, iptr);
}
(void) fclose(temptr);
}
static void
putsave(char **linep, size_t *bufsizp, char type)
{
FILE *temptr;
if ((temptr = fopen(tempfile, "r")) == NULL) {
(void) snprintf(Error, sizeof (Error),
"Can not open tempfile ('%s')", tempfile); fatal(Error);
}
while (readline(linep, bufsizp, temptr))
(void) printf("%c %s", type, *linep);
(void) fclose(temptr);
(void) unlink(tempfile);
}
static void
fixnum(char *lp)
{
offset_t num;
while (*lp) {
switch (*lp) {
case 'a':
case 'c':
case 'd':
case ',':
case '\n':
(void) printf("%c", *lp);
lp++;
break;
default:
lp = satoi(lp, &num);
num += linenum;
(void) printf("%lld", num);
}
}
}
static void
addgen(char **lpp, size_t *bufsizp, FILE *fp)
{
offset_t oldline;
(void) printf("%llda%lld", linenum, linenum+1);
oldline = linenum + 1;
saverest(lpp, bufsizp, fp);
if (oldline < linenum)
(void) printf(",%lld\n", linenum);
else
(void) printf("\n");
putsave(lpp, bufsizp, '>');
exit(0);
}
static void
delgen(char **lpp, size_t *bufsizp, FILE *fp)
{
offset_t savenum;
(void) printf("%lld", linenum+1);
savenum = linenum;
saverest(lpp, bufsizp, fp);
if (savenum +1 != linenum)
(void) printf(",%lldd%lld\n", linenum, savenum);
else
(void) printf("d%lld\n", savenum);
putsave(lpp, bufsizp, '<');
exit(0);
}
static void
clean_up()
{
(void) unlink(tempfile);
(void) unlink(otmp);
(void) unlink(ntmp);
}
static FILE *
maket(char *file)
{
FILE *iop;
int fd;
(void) strcpy(file, tempskel);
if ((fd = mkstemp(file)) == -1 ||
(iop = fdopen(fd, "w+")) == NULL) {
(void) snprintf(Error, sizeof (Error),
"Can not open/create temp file ('%s')", file);
fatal(Error);
}
return (iop);
}
static void
fatal(char *msg)
{
if (fflags & FTLMSG)
(void) fprintf(stderr, "%s: %s\n", prognam, msg);
if (fflags & FTLCLN)
clean_up();
if (fflags & FTLEXIT)
exit(fatal_num);
}
static void
setsig()
{
void (*act)(int);
int j;
for (j = 1; j < ONSIG; j++) {
act = signal(j, setsig1);
if (act == SIG_ERR)
continue;
if (act == SIG_DFL)
continue;
(void) signal(j, act);
}
}
static void
setsig1(int sig)
{
(void) signal(sig, SIG_IGN);
clean_up();
exit(1);
}
static char *
satoi(char *p, offset_t *ip)
{
offset_t sum;
sum = 0;
while (isdigit(*p))
sum = sum * 10 + (*p++ - '0');
*ip = sum;
return (p);
}
static char *
readline(char **bufferp, size_t *bufsizp, FILE *filep)
{
char *bufp;
size_t newsize;
size_t oldsize;
(*bufferp)[*bufsizp - 1] = '\t';
(*bufferp)[*bufsizp - 2] = ' ';
bufp = fgets(*bufferp, *bufsizp, filep);
if (bufp == NULL)
return (bufp);
while ((*bufferp)[*bufsizp -1] == '\0' &&
(*bufferp)[*bufsizp - 2] != '\n' &&
strlen(*bufferp) == *bufsizp - 1) {
newsize = 2 * (*bufsizp);
bufp = (char *)realloc((void *)*bufferp, newsize);
if (bufp == NULL)
fatal("Out of memory");
oldsize = *bufsizp;
*bufsizp = newsize;
*bufferp = bufp;
(*bufferp)[*bufsizp - 1] = '\t';
(*bufferp)[*bufsizp - 2] = ' ';
bufp = fgets(*bufferp + oldsize -1, oldsize + 1, filep);
if (bufp == NULL) {
if (filep->_flag & _IOEOF) {
bufp = *bufferp;
break;
} else
fatal("Read error");
} else
bufp = *bufferp;
}
return (bufp);
}