home *** CD-ROM | disk | FTP | other *** search
- ; /* "execute undiff.c"
- lc -j73 -cfist -L undiff.c
- delete undiff.o undiff.lnk
- quit
- */
-
- /*===========================================================================
- * UNDIFF.C -- Apply output from Lattice DIFF
- * Copyright ⌐ 1991 by Robert L. Pyron. All Rights Reserved.
- *
- * You may use this program for any purpose at all. If you use any
- * source code from this program, I ask that you give me credit in your
- * documentation. I would be very pleased if somebody were to make
- * improvements to this program and pass them on to the Amiga
- * community.
- *
- * Lattice DIFF outputs a sequence of commands for converting one text file
- * to another. Unfortunately, there is no program available which will apply
- * these diffs to the original file and yield the modified file. (Or maybe
- * there is, and I just didn't RTFM carefully enough!)
- *
- * Anyway, this is something I hacked together in about six hours --
- * don't expect production-quality code here.
- *
- * Usage is:
- *
- * UNDIFF < diff_file
- *
- * There are very few bells and whistles here. The only one I can think of
- * offhand is that you may concatenate all of your diff files into one big
- * file, and feed that into UNDIFF.
- *
- * If the diff file says "TRANSFORM foo/bar.c TO sna/fu.c", then that is
- * what you get -- no redirection of input or output files to somewhere
- * else.
- *
- * The destination directory must already exist.
- *
- * If the program terminates due to an error, you will be left with a
- * malformed target file.
- *
- * Error output is rather cryptic.
- *===========================================================================
- */
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- typedef unsigned long ULONG;
-
- typedef enum _ParseState
- {
- IDLE = 0,
- PARSE_TRANSFORM = 10,PARSE_COMMAND,
- DO_APPEND = 20,APPENDING_1,
- DO_CHANGE = 30,CHANGING_1,CHANGING_2,CHANGING_3,CHANGING_4,CHANGING_5,
- DO_DELETE = 40,DELETING_1,DELETING_2,
- DO_NODIFF = 50,
- ERROR = -1,IO_ERROR = -2,
- DONE = 99,QUIT = 100
- } ParseState;
-
- #define BADIO -2
- #define ENDFILE -1
- #define EMPTY 0
- #define BLANK ' '
- #define TAB '\t'
- #define ASTER '*'
- #define NODIFF 'N'
- #define DASH '-'
- #define SRCLINE '<'
- #define DSTLINE '>'
-
- char srcname[256]; /* name of current source file */
- char dstname[256]; /* name of current destination file */
-
- char srctemp[256]; /* temp; src file specified in this command */
- char dsttemp[256]; /* temp; dst file specified in this command */
-
- char srcrange[32]; /* temp for decoding range specification */
- char dstrange[32]; /* temp for decoding range specification */
-
- char cmdbuf[256]; /* input buffer for dif file */
- char linebuf[256]; /* buffer for moving lines from file A to file B */
-
- ULONG src1, src2; /* source line range specified by command */
- ULONG dst1, dst2; /* dest line range specified by command */
-
- ULONG cmdline; /* current line number in dif file */
- ULONG srcline; /* current line number in source file */
- ULONG dstline; /* current line number in destination file */
-
- FILE *cmdfp;
- FILE *srcfp;
- FILE *dstfp;
-
- void main (int argc, char **argv);
- int parse_transform (char *cmdbuf);
- int parse_nodiff (char *cmdbuf);
- int parse_append (char *cmdbuf);
- int parse_change (char *cmdbuf);
- int parse_delete (char *cmdbuf);
- int parse_range (char *range, unsigned long *lo, unsigned long *hi);
- int getdif (char *cmdbuf);
- int getsrc (char *linebuf);
- int putdst (char *linebuf);
-
- /*-------------------------------------------------------------------------
- *-------------------------------------------------------------------------
- */
-
- void main (int argc, char **argv)
- {
- ParseState state = IDLE, laststate;
- char *error = "";
- int cmd, rc;
-
- cmdfp = stdin; /****** LAZY LAZY LAZY ******/
-
- loop:
- switch (state)
- {
- case IDLE:
- laststate = state;
-
- /*
- * We're just waiting around for something to happen.
- */
- error = "unknown command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case ENDFILE: state = DONE; break;
- case EMPTY: state = IDLE; break;
- case BLANK: state = PARSE_TRANSFORM; break;
- case TAB: state = PARSE_TRANSFORM; break;
- case ASTER: state = PARSE_COMMAND; break;
- case NODIFF: state = PARSE_COMMAND; break;
- default: state = ERROR; break;
- }
- break;
-
- case PARSE_TRANSFORM:
- laststate = state;
-
- /*
- * Copy remainder of current file.
- */
- if (srcfp && dstfp)
- {
- do
- {
- if ((rc = getsrc(linebuf)) == 0)
- rc = putdst(linebuf);
- }
- while (rc == 0);
- if (ferror(srcfp) || ferror(dstfp))
- { state = IO_ERROR; break; }
- }
-
- /*
- * Confirm that cmdbuf contains a "TO TRANSFORM" command.
- * Close current src and dst files, and open new files.
- */
- error = "bad command";
- if (parse_transform(cmdbuf))
- { state = ERROR; break; }
-
- printf ("TRANSFORMING %s TO %s ...\n",
- srcname, dstname);
-
- if (srcfp) { fclose (srcfp); srcfp = NULL; }
- if (dstfp) { fclose (dstfp); dstfp = NULL; }
-
- srcfp = fopen (srcname,"r");
- dstfp = fopen (dstname,"w");
- srcline = dstline = 0;
-
- state = (srcfp && dstfp) ? IDLE : IO_ERROR;
- break;
-
- case PARSE_COMMAND:
- laststate = state;
-
- /*
- * cmdbuf should contain an APPEND, CHANGE, or DELETE command.
- */
- error = "bad command";
- if (parse_append(cmdbuf) == 0)
- state = DO_APPEND;
- else if (parse_change(cmdbuf) == 0)
- state = DO_CHANGE;
- else if (parse_delete(cmdbuf) == 0)
- state = DO_DELETE;
- else if (parse_nodiff(cmdbuf) == 0)
- state = DO_NODIFF;
- else
- state = ERROR;
- break;
-
- case DO_NODIFF:
- laststate = state;
-
- error = "inconsistent file name";
- if (stricmp(srcname,srctemp) || stricmp(dstname,dsttemp))
- { state = ERROR; break; }
-
- /*
- * Copy remainder of file.
- */
- if (srcfp && dstfp)
- {
- do
- {
- if ((rc = getsrc(linebuf)) == 0)
- rc = putdst(linebuf);
- }
- while (rc == 0);
- if (ferror(srcfp) || ferror(dstfp))
- { state = IO_ERROR; break; }
- }
-
- state = IDLE;
- break;
-
- case DO_APPEND:
- laststate = state;
-
- /*
- * cmdbuf contains an APPEND command.
- * Make sure file name agrees.
- */
- error = "inconsistent file name";
- if (stricmp(srcname,srctemp))
- { state = ERROR; break; }
-
- /*
- * Copy unaffected lines.
- */
- while (srcline < src1)
- {
- if (getsrc(linebuf) != 0)
- { state = IO_ERROR; break; }
- if (putdst(linebuf) != 0)
- { state = IO_ERROR; break; }
- }
- error = "inconsistent line count";
- if (srcline != src1)
- { state = ERROR; break; }
-
- /*
- * Get next dif line. Should begin with '>'.
- */
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case DSTLINE: state = APPENDING_1; break;
- default: state = ERROR; break;
- }
- break;
-
- case APPENDING_1:
- laststate = state;
-
- /*
- * cmdbuf contains a line that should be output.
- * Do so, then get next dif line.
- */
- if (putdst(cmdbuf+1) != 0)
- { state = IO_ERROR; break; }
-
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case ENDFILE: state = DONE; break;
- case EMPTY: state = IDLE; break;
- case DSTLINE: state = APPENDING_1; break;
- default: state = ERROR; break;
- }
- break;
-
- case DO_CHANGE:
- laststate = state;
-
- /*
- * cmdbuf contains a CHANGE command.
- * Make sure file names agree.
- */
- error = "inconsistent file name";
- if (stricmp(srcname,srctemp) || stricmp(dstname,dsttemp))
- { state = ERROR; break; }
-
- /*
- * Copy unaffected lines.
- */
- while (srcline < src1-1 && dstline < dst1-1)
- {
- if (getsrc(linebuf) != 0)
- { state = IO_ERROR; break; }
- if (putdst(linebuf) != 0)
- { state = IO_ERROR; break; }
- }
- error = "inconsistent line count";
- if (srcline != src1-1 || dstline != dst1-1)
- { state = ERROR; break; }
-
- /*
- * Get next dif line. Should begin with '<'.
- */
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case SRCLINE: state = CHANGING_1; break;
- default: state = ERROR; break;
- }
- break;
-
- case CHANGING_1:
- laststate = state;
-
- /*
- * cmdbuf contains a line that should be "deleted".
- * Make sure it matches current line in src file.
- */
- if (getsrc(linebuf) != 0)
- { state = IO_ERROR; break; }
- error = "line does not match";
- if (strcmp(linebuf,cmdbuf+1))
- { state = ERROR; break; }
-
- /*
- * Get next dif line.
- */
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case SRCLINE: state = CHANGING_1; break;
- case EMPTY: state = CHANGING_2; break;
- default: state = ERROR; break;
- }
- break;
-
- case CHANGING_2:
- laststate = state;
-
- /*
- * We've finished the "delete" component of the change.
- * Look for separator line between "delete" and "append"
- * lines.
- */
- error = "inconsistent line count";
- if (srcline != src2)
- { state = ERROR; break; }
-
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case EMPTY: state = CHANGING_2; break;
- case DASH: state = CHANGING_3; break;
- default: state = ERROR; break;
- }
- break;
-
- case CHANGING_3:
- laststate = state;
-
- /*
- * cmdbuf holds separator between "delete and "append" lines.
- * Next line should begin with '>'.
- */
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case DSTLINE: state = CHANGING_4; break;
- default: state = ERROR; break;
- }
- break;
-
- case CHANGING_4:
- laststate = state;
-
- /*
- * cmdbuf contains a line that should be output.
- * Do so, then get next dif line.
- */
-
- if (putdst(cmdbuf+1) != 0)
- { state = IO_ERROR; break; }
-
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case DSTLINE: state = CHANGING_4; break;
- case EMPTY: state = IDLE; break;
- default: state = ERROR; break;
- }
- break;
-
- case CHANGING_5:
- laststate = state;
-
- /*
- * Check to see that we inserted the proper number of lines.
- */
- error = "inconsistent line count";
- state = (dstline == dst2) ? IDLE : ERROR;
- break;
-
-
- case DO_DELETE:
- laststate = state;
-
- /*
- * cmdbuf contains an APPEND command.
- * Make sure file name agrees.
- */
- error = "inconsistent file name";
- if (stricmp(srcname,srctemp))
- { state = ERROR; break; }
-
- /*
- * Copy unaffected lines.
- */
- while (srcline < src1-1)
- {
- if (getsrc(linebuf) != 0)
- { state = IO_ERROR; break; }
- if (putdst(linebuf) != 0)
- { state = IO_ERROR; break; }
- }
- error = "inconsistent line count";
- if (srcline != src1-1)
- { state = ERROR; break; }
-
- /*
- * Get next dif line. Should begin with '<'.
- */
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case SRCLINE: state = DELETING_1; break;
- default: state = ERROR; break;
- }
- break;
-
- case DELETING_1:
- laststate = state;
-
- /*
- * cmdbuf contains a line that should be "deleted".
- * Make sure it matches current line in src file.
- */
- if (getsrc(linebuf) != 0)
- { state = IO_ERROR; break; }
- error = "line does not match";
- if (strcmp(linebuf,cmdbuf+1))
- { state = ERROR; break; }
-
- /*
- * Get next dif line.
- */
- error = "bad command";
- switch (cmd = getdif (cmdbuf))
- {
- case BADIO: state = IO_ERROR; break;
- case SRCLINE: state = DELETING_1; break;
- case EMPTY: state = DELETING_2; break;
- default: state = ERROR; break;
- }
- break;
-
- case DELETING_2:
- laststate = state;
-
- /*
- * Check to see that we deleted the proper number of lines.
- */
- error = "inconsistent line count";
- state = (srcline == src2) ? IDLE : ERROR;
- break;
-
- case ERROR:
- printf ("*** ERROR: %s\n", error);
- printf ("state = %d cmdline = %d srcline = %d dstline = %d\n",
- (int) laststate, cmdline, srcline, dstline);
- printf ("src1 = %d src2 = %d dst1 = %d dst2 = %d\n",
- src1, src2, dst1, dst2);
- printf ("cmdbuf = %s\n", cmdbuf);
- printf ("linebuf = %s\n", linebuf);
- printf ("srcrange = %s\n", srcrange);
- printf ("dstrange = %s\n", dstrange);
-
- rc = 100;
- state = QUIT;
- break;
-
- case IO_ERROR:
- printf ("*** I/O error\n");
- rc = 200;
- state = QUIT;
- break;
-
- case DONE:
- /*
- * Copy remainder of file.
- */
- if (srcfp && dstfp)
- {
- do
- {
- if ((rc = getsrc(linebuf)) == 0)
- rc = putdst(linebuf);
- }
- while (rc == 0);
- if (ferror(srcfp) || ferror(dstfp))
- { state = IO_ERROR; break; }
- }
-
- rc = 0;
- state = QUIT;
- break;
-
- case QUIT:
- if (srcfp) { fclose (srcfp); srcfp = NULL; }
- if (dstfp) { fclose (dstfp); dstfp = NULL; }
- exit(rc);
- break;
-
- default:
- error = "unknown state!";
- state = ERROR;
- break;
- }
- goto loop;
- }
-
-
- /*-------------------------------------------------------------------------
- * Extract srcname and dstname from TRANSFORM command.
- * "TO TRANSFORM <srcname> INTO <dstname> ..."
- *
- * Sets global variables "srcname" and "dstname".
- * Returns 0 on success.
- *-------------------------------------------------------------------------
- */
-
- int parse_transform (char *cmdbuf)
- {
- int nc = sscanf (cmdbuf, " TO TRANSFORM %s INTO %s ...",
- srcname, dstname);
- return (nc != 2);
- }
-
- /*-------------------------------------------------------------------------
- * Extract srcname and dstname from NODIFF command.
- * "NO DIFFERENCE BETWEEN <dst> AND <src>"
- *
- * Sets global variables "srctemp" and "dsttemp".
- * Returns 0 on success.
- *-------------------------------------------------------------------------
- */
-
- int parse_nodiff (char *cmdbuf)
- {
- int nc = sscanf (cmdbuf, "NO DIFFERENCE BETWEEN %s AND %s",
- dsttemp, srctemp);
- return (nc != 2);
- }
-
- /*-------------------------------------------------------------------------
- * Extract line number and file name from APPEND command.
- * "*** APPEND AFTER <n> IN <dst> ***"
- *
- * Returns 0 on success.
- *-------------------------------------------------------------------------
- */
-
- int parse_append (char *cmdbuf)
- {
- int nc = sscanf (cmdbuf, "*** APPEND AFTER %s IN %s ***",
- srcrange, srctemp);
-
- return (nc == 2) ? parse_range(srcrange,&src1,&src2) : -1;
- }
-
- /*-------------------------------------------------------------------------
- * Extract info from CHANGE command.
- * "*** CHANGE <range> IN <src> TO <range> IN <dst> ***",
- *
- * Returns 0 on success.
- *-------------------------------------------------------------------------
- */
-
- int parse_change (char *cmdbuf)
- {
- int nc = sscanf (cmdbuf, "*** CHANGE %s IN %s TO %s IN %s ***",
- srcrange, srctemp, dstrange, dsttemp);
- if (nc != 4)
- return -1;
- else if (parse_range(srcrange,&src1,&src2) != 0)
- return -1;
- else if (parse_range(dstrange,&dst1,&dst2) != 0)
- return -1;
- return 0;
- }
-
- /*-------------------------------------------------------------------------
- * Extract line number and file name from DELETE command.
- * "*** DELETE <range> FROM <src> ***",
- *
- * Returns 0 on success.
- *-------------------------------------------------------------------------
- */
-
- int parse_delete (char *cmdbuf)
- {
- int nc = sscanf (cmdbuf, "*** DELETE %s FROM %s ***",
- srcrange, srctemp);
-
- return (nc == 2) ? parse_range(srcrange,&src1,&src2) : -1;
- }
-
- /*-------------------------------------------------------------------------
- * Parse a range specifier in the form "n" or "[n,n]".
- * Returns 0 on success.
- *-------------------------------------------------------------------------
- */
-
- int parse_range (char *range, ULONG *lo, ULONG *hi)
- {
- *lo = *hi = -1;
- if (sscanf (range,"[%lu,%lu]", lo, hi) == 2)
- return 0;
- else if (sscanf (range,"%lu", lo) == 1)
- {
- *hi = *lo;
- return 0;
- }
- else
- {
- printf ("****** cannot scan range %s ******\n", range);
- return -1;
- }
- }
-
- /*-------------------------------------------------------------------------
- * Read line from dif file. Strip trailing newline.
- * Return first character (or negative value for error or eof).
- *-------------------------------------------------------------------------
- */
-
- int getdif (char *cmdbuf)
- {
- int len;
-
- if (fgets(cmdbuf,255,cmdfp))
- {
- cmdbuf[255] = '\0';
- len = strlen(cmdbuf);
- if (len && cmdbuf[--len] == '\n')
- cmdbuf[len] = '\0';
- cmdline++;
- return (int) cmdbuf[0];
- }
- else if (feof(cmdfp))
- return ENDFILE;
- else
- return BADIO;
- }
-
- /*-------------------------------------------------------------------------
- * Read line from source file; increment counter.
- *-------------------------------------------------------------------------
- */
-
- int getsrc (char *linebuf)
- {
- char *p;
- int len;
- p = fgets(linebuf,255,srcfp);
- if (p && (len = strlen(p)) && (p[--len] == '\n'))
- p[len] = '\0';
-
- linebuf[255] = '\0';
- srcline++;
- return (p == NULL);
- }
-
- /*-------------------------------------------------------------------------
- * Write line to destination file; increment counter.
- *-------------------------------------------------------------------------
- */
-
- int putdst (char *linebuf)
- {
- int rc = fputs (linebuf,dstfp);
- fputc ('\n',dstfp);
- dstline++;
- return rc;
- }
-
-