|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 5970 (0x1752) Types: TextFile Notes: UNIX file Names: »diffh.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─ ⟦this⟧ »cmd/diff/diffh.c«
/* * Half-hearted version of diff (doesn't * use the complicated algorithm). * This algorithm works on arbitrary files * but is only intended where changes are * minimal and well-spaced. There is another * algorithm which also takes space but is at * least guaranteed to be linear in time and space (unlike * Least Common Subsequence) and sometimes produces * more realistic results (and sometimes it doesn't) * Consult: "A Technique for Isolating Diffeences between * Files", Paul Heckel, CACM, November 1978. * This shares code with the normal * diff though. */ #include "diff.h" #define NPEND 200 /* Default # pending lines */ #define NMATCH 2 /* Minimum lines in a row to have a match */ /* * Structure for each line * This is referenced by the * structure for each file * below. */ typedef struct LINE { unsigned l_num; /* Line number */ struct LINE *l_next; /* Pointer for ungetting lines */ char l_text[]; /* Data of line */ } LINE; /* * Structure of pending lines * and ungot lines stored for * each of the input files. */ typedef struct PENDING { FILE *p_fp; /* I/O stream for input */ int p_eof; /* Reached EOF on this input */ char *p_fn; /* File name */ LINE *p_master; /* Master input buffer */ LINE *p_work; /* Current working line */ LINE *p_ungot; /* Ungot lines */ LINE *p_lines[NPEND]; /* Pending lines */ } PENDING; PENDING p1, p2; LINE *lcopy(); /* * A NOP routine so that diff() * gets invoked. */ /* ARGSUSED */ diffh(args) char **args; { } /* * The actual code to produce list * of differences by a stupider * (but cheaper) algorithm. */ diff(fp1, fp2) FILE *fp1; FILE *fp2; { register int top, bot; register int i; p1.p_master = p1.p_work = (LINE *)alloc(sizeof(LINE) + LSIZE); p2.p_master = p2.p_work = (LINE *)alloc(sizeof(LINE) + LSIZE); p1.p_fp = fp1; p2.p_fp = fp2; p1.p_fn = fn1; p2.p_fn = fn2; while (lget(&p1) | lget(&p2)) { register char *s1, *s2; s1 = p1.p_work->l_text; s2 = p2.p_work->l_text; if (*s1=='\0' && *s2=='\0') continue; if ((*equal)(s1, s2)) { text(s1); continue; } top = 0; lpend(&p1, top); lpend(&p2, top++); do { if (top >= NPEND) cerr("Out of memory, lines %d and %d", p1.p_lines[0]->l_num, p2.p_lines[0]->l_num); /* * Not checked, lget has * to stop going over EOF * by itself. */ lget(&p1); lget(&p2); lpend(&p1, top); lpend(&p2, top++); bot = top-NMATCH; for (i=0; i<bot; i++) { if (lsearch(i, bot)) { lunget(&p1, i+NMATCH, top); break; } if (lsearch(bot, i)) { lunget(&p2, i+NMATCH, top); break; } } } while (i>bot || i==bot && !lsearch(i, i)); } } /* * Get a line and put it into the current * working position. * Return 0 at EOF. */ lget(pp) register PENDING *pp; { if (pp->p_master != pp->p_work) free(pp->p_work); if (pp->p_ungot != NULL) { pp->p_work = pp->p_ungot; pp->p_ungot = pp->p_ungot->l_next; return (1); } pp->p_work = pp->p_master; return (lgets(pp)); } /* * Unget pending lines between * `beg' and `end' that are * not already dealt with. */ lunget(pp, beg, end) register PENDING *pp; register int beg, end; { while (--end >= beg) { pp->p_lines[end]->l_next = pp->p_ungot; pp->p_ungot = pp->p_lines[end]; pp->p_lines[end] = NULL; } } /* * Copy a line to a new (allocated) * line space. */ LINE * lcopy(lp) register LINE *lp; { register LINE *rlp; register char *cp; for (cp = lp->l_text; *cp != '\0'; cp++) ; rlp = (LINE *)alloc(cp-lp->l_text+1 + sizeof(LINE)); rlp->l_num = lp->l_num; rlp->l_next = NULL; strcpy(rlp->l_text, lp->l_text); return (rlp); } /* * Save line away in a pending line * position, specified by `pos'. */ lpend(pp, pos) register PENDING *pp; register int pos; { if (pp->p_lines[pos] != NULL) free(pp->p_lines[pos]); if (pp->p_master != pp->p_work) { pp->p_lines[pos] = pp->p_work; pp->p_work = pp->p_master; } else pp->p_lines[pos] = lcopy(pp->p_work); } /* * Read a string from input (specified * by the PENDING pointer) and throw away * partial lines. */ lgets(pp) register PENDING *pp; { register int c; register char *s; register unsigned lim = LSIZE; s = pp->p_master->l_text; if (pp->p_eof) { *s = '\0'; return (0); } while (--lim > 0 && (c = getc(pp->p_fp)) != EOF) if ((*s++ = c) == '\n') break; *s = '\0'; if (c == EOF) { if (s != pp->p_master->l_text) fprintf(stderr, "diff: partial line omitted from %s\n", pp->p_fn); pp->p_eof++; return (0); } pp->p_master->l_num++; return (1); } /* * Search for a match in the pending lines. * The two parameters are `pos1' and `pos2' * for the position to start searching in * file1 and file2, respectively. The * search looks for at least NMATCH lines. */ lsearch(pos1, pos2) int pos1; int pos2; { register LINE **lpp1, **lpp2; register int i; register char *s1, *s2; register int ln11, ln12, ln21, ln22; lpp1 = &p1.p_lines[pos1]; lpp2 = &p2.p_lines[pos2]; /* * Empty strings are actually * dummies for after EOF. */ for (i=0; i<NMATCH; i++) { s1 = lpp1[i]->l_text; s2 = lpp2[i]->l_text; if (*s1!='\0' || *s2!='\0') if (!(*equal)(s1, s2)) break; } if (i < NMATCH) return (0); lpp1 = p1.p_lines; lpp2 = p2.p_lines; ln11 = lpp1[0]->l_num; ln12 = lpp1[pos1-1]->l_num; ln21 = lpp2[0]->l_num; ln22 = lpp2[pos2-1]->l_num; if (pos1 == 0) append(ln11, ln21, ln22); else if (pos2 == 0) delete(ln11, ln12, ln21); else change(ln11, ln12, ln21, ln22); for (i = 0; i < pos1; i++) text1(lpp1[i]->l_text); prsep(); for (i = 0; i < pos2; i++) text2(lpp2[i]->l_text); prend(); for (i=0; i<NMATCH; i++) if (*(s1 = lpp1[i+pos1]->l_text) != '\0') text(s1); return (1); } /* * Allocator that also checks for * an prints a message if out of space. */ char * alloc(nb) unsigned nb; { register char *rp; if ((rp = calloc(nb, 1)) == NULL) cerr("out of memory"); return (rp); }