URI: 
       diffio.c - 9base - revived minimalist port of Plan 9 userland to Unix
  HTML git clone git://git.suckless.org/9base
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       diffio.c (6620B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <ctype.h>
            5 #include "diff.h"
            6 
            7 struct line {
            8         int        serial;
            9         int        value;
           10 };
           11 extern struct line *file[2];
           12 extern int len[2];
           13 extern long *ixold, *ixnew;
           14 extern int *J;
           15 
           16 static Biobuf *input[2];
           17 static char *file1, *file2;
           18 static int firstchange;
           19 
           20 #define MAXLINELEN        4096
           21 #define MIN(x, y)        ((x) < (y) ? (x): (y))
           22 
           23 static int
           24 readline(Biobuf *bp, char *buf)
           25 {
           26         int c;
           27         char *p, *e;
           28 
           29         p = buf;
           30         e = p + MAXLINELEN-1;
           31         do {
           32                 c = Bgetc(bp);
           33                 if (c < 0) {
           34                         if (p == buf)
           35                                 return -1;
           36                         break;
           37                 }
           38                 if (c == '\n')
           39                         break;
           40                 *p++ = c;
           41         } while (p < e);
           42         *p = 0;
           43         if (c != '\n' && c >= 0) {
           44                 do c = Bgetc(bp);
           45                 while (c >= 0 && c != '\n');
           46         }
           47         return p - buf;
           48 }
           49 
           50 #define HALFLONG 16
           51 #define low(x)        (x&((1L<<HALFLONG)-1))
           52 #define high(x)        (x>>HALFLONG)
           53 
           54 /*
           55  * hashing has the effect of
           56  * arranging line in 7-bit bytes and then
           57  * summing 1-s complement in 16-bit hunks 
           58  */
           59 static int
           60 readhash(Biobuf *bp, char *buf)
           61 {
           62         long sum;
           63         unsigned shift;
           64         char *p;
           65         int len, space;
           66 
           67         sum = 1;
           68         shift = 0;
           69         if ((len = readline(bp, buf)) == -1)
           70                 return 0;
           71         p = buf;
           72         switch(bflag)        /* various types of white space handling */
           73         {
           74         case 0:
           75                 while (len--) {
           76                         sum += (long)*p++ << (shift &= (HALFLONG-1));
           77                         shift += 7;
           78                 }
           79                 break;
           80         case 1:
           81                 /*
           82                  * coalesce multiple white-space
           83                  */
           84                 for (space = 0; len--; p++) {
           85                         if (isspace((uchar)*p)) {
           86                                 space++;
           87                                 continue;
           88                         }
           89                         if (space) {
           90                                 shift += 7;
           91                                 space = 0;
           92                         }
           93                         sum += (long)*p << (shift &= (HALFLONG-1));
           94                         shift += 7;
           95                 }
           96                 break;
           97         default:
           98                 /*
           99                  * strip all white-space
          100                  */
          101                 while (len--) {
          102                         if (isspace((uchar)*p)) {
          103                                 p++;
          104                                 continue;
          105                         }
          106                         sum += (long)*p++ << (shift &= (HALFLONG-1));
          107                         shift += 7;
          108                 }
          109                 break;
          110         }
          111         sum = low(sum) + high(sum);
          112         return ((short)low(sum) + (short)high(sum));
          113 }
          114 
          115 Biobuf *
          116 prepare(int i, char *arg)
          117 {
          118         struct line *p;
          119         int j, h;
          120         Biobuf *bp;
          121         char *cp, buf[MAXLINELEN];
          122         int nbytes;
          123         Rune r;
          124 
          125         bp = Bopen(arg, OREAD);
          126         if (!bp) {
          127                 panic(mflag ? 0: 2, "cannot open %s: %r\n", arg);
          128                 return 0;
          129         }
          130         if (binary)
          131                 return bp;
          132         nbytes = Bread(bp, buf, MIN(1024, MAXLINELEN));
          133         if (nbytes > 0) {
          134                 cp = buf;
          135                 while (cp < buf+nbytes-UTFmax) {
          136                         /*
          137                          * heuristic for a binary file in the
          138                          * brave new UNICODE world
          139                          */
          140                         cp += chartorune(&r, cp);
          141                         if (r == 0 || (r > 0x7f && r <= 0xa0)) {
          142                                 binary++;
          143                                 return bp;
          144                         }
          145                 }
          146                 Bseek(bp, 0, 0);
          147         }
          148         p = MALLOC(struct line, 3);
          149         for (j = 0; h = readhash(bp, buf); p[j].value = h)
          150                 p = REALLOC(p, struct line, (++j+3));
          151         len[i] = j;
          152         file[i] = p;
          153         input[i] = bp;                        /*fix*/
          154         if (i == 0) {                        /*fix*/
          155                 file1 = arg;
          156                 firstchange = 0;
          157         }
          158         else
          159                 file2 = arg;
          160         return bp;
          161 }
          162 
          163 static int
          164 squishspace(char *buf)
          165 {
          166         char *p, *q;
          167         int space;
          168 
          169         for (space = 0, q = p = buf; *q; q++) {
          170                 if (isspace((uchar)*q)) {
          171                         space++;
          172                         continue;
          173                 }
          174                 if (space && bflag == 1) {
          175                         *p++ = ' ';
          176                         space = 0;
          177                 }
          178                 *p++ = *q;
          179         }
          180         *p = 0;
          181         return p - buf;
          182 }
          183 
          184 /*
          185  * need to fix up for unexpected EOF's
          186  */
          187 void
          188 check(Biobuf *bf, Biobuf *bt)
          189 {
          190         int f, t, flen, tlen;
          191         char fbuf[MAXLINELEN], tbuf[MAXLINELEN];
          192 
          193         ixold[0] = ixnew[0] = 0;
          194         for (f = t = 1; f < len[0]; f++) {
          195                 flen = readline(bf, fbuf);
          196                 ixold[f] = ixold[f-1] + flen + 1;                /* ftell(bf) */
          197                 if (J[f] == 0)
          198                         continue;
          199                 do {
          200                         tlen = readline(bt, tbuf);
          201                         ixnew[t] = ixnew[t-1] + tlen + 1;        /* ftell(bt) */
          202                 } while (t++ < J[f]);
          203                 if (bflag) {
          204                         flen = squishspace(fbuf);
          205                         tlen = squishspace(tbuf);
          206                 }
          207                 if (flen != tlen || strcmp(fbuf, tbuf))
          208                         J[f] = 0;
          209         }
          210         while (t < len[1]) {
          211                 tlen = readline(bt, tbuf);
          212                 ixnew[t] = ixnew[t-1] + tlen + 1;        /* fseek(bt) */
          213                 t++;
          214         }
          215 }
          216 
          217 static void
          218 range(int a, int b, char *separator)
          219 {
          220         Bprint(&stdout, "%d", a > b ? b: a);
          221         if (a < b)
          222                 Bprint(&stdout, "%s%d", separator, b);
          223 }
          224 
          225 static void
          226 fetch(long *f, int a, int b, Biobuf *bp, char *s)
          227 {
          228         char buf[MAXLINELEN];
          229         int maxb;
          230 
          231         if(a <= 1)
          232                 a = 1;
          233         if(bp == input[0])
          234                 maxb = len[0];
          235         else
          236                 maxb = len[1];
          237         if(b > maxb)
          238                 b = maxb;
          239         if(a > maxb)
          240                 return;
          241         Bseek(bp, f[a-1], 0);
          242         while (a++ <= b) {
          243                 readline(bp, buf);
          244                 Bprint(&stdout, "%s%s\n", s, buf);
          245         }
          246 }
          247 
          248 typedef struct Change Change;
          249 struct Change
          250 {
          251         int a;
          252         int b;
          253         int c;
          254         int d;
          255 };
          256 
          257 Change *changes;
          258 int nchanges;
          259 
          260 void
          261 change(int a, int b, int c, int d)
          262 {
          263         char verb;
          264         char buf[4];
          265         Change *ch;
          266 
          267         if (a > b && c > d)
          268                 return;
          269         anychange = 1;
          270         if (mflag && firstchange == 0) {
          271                 if(mode) {
          272                         buf[0] = '-';
          273                         buf[1] = mode;
          274                         buf[2] = ' ';
          275                         buf[3] = '\0';
          276                 } else {
          277                         buf[0] = '\0';
          278                 }
          279                 Bprint(&stdout, "diff %s%s %s\n", buf, file1, file2);
          280                 firstchange = 1;
          281         }
          282         verb = a > b ? 'a': c > d ? 'd': 'c';
          283         switch(mode) {
          284         case 'e':
          285                 range(a, b, ",");
          286                 Bputc(&stdout, verb);
          287                 break;
          288         case 0:
          289                 range(a, b, ",");
          290                 Bputc(&stdout, verb);
          291                 range(c, d, ",");
          292                 break;
          293         case 'n':
          294                 Bprint(&stdout, "%s:", file1);
          295                 range(a, b, ",");
          296                 Bprint(&stdout, " %c ", verb);
          297                 Bprint(&stdout, "%s:", file2);
          298                 range(c, d, ",");
          299                 break;
          300         case 'f':
          301                 Bputc(&stdout, verb);
          302                 range(a, b, " ");
          303                 break;
          304         case 'c':
          305         case 'a':
          306                 if(nchanges%1024 == 0)
          307                         changes = erealloc(changes, (nchanges+1024)*sizeof(changes[0]));
          308                 ch = &changes[nchanges++];
          309                 ch->a = a;
          310                 ch->b = b;
          311                 ch->c = c;
          312                 ch->d = d;
          313                 return;
          314         }
          315         Bputc(&stdout, '\n');
          316         if (mode == 0 || mode == 'n') {
          317                 fetch(ixold, a, b, input[0], "< ");
          318                 if (a <= b && c <= d)
          319                         Bprint(&stdout, "---\n");
          320         }
          321         fetch(ixnew, c, d, input[1], mode == 0 || mode == 'n' ? "> ": "");
          322         if (mode != 0 && mode != 'n' && c <= d)
          323                 Bprint(&stdout, ".\n");
          324 }
          325 
          326 enum
          327 {
          328         Lines = 3                /* number of lines of context shown */
          329 };
          330 
          331 int
          332 changeset(int i)
          333 {
          334         while(i<nchanges && changes[i].b+1+2*Lines > changes[i+1].a)
          335                 i++;
          336         if(i<nchanges)
          337                 return i+1;
          338         return nchanges;
          339 }
          340 
          341 void
          342 flushchanges(void)
          343 {
          344         int a, b, c, d, at;
          345         int i, j;
          346 
          347         if(nchanges == 0)
          348                 return;
          349         
          350         for(i=0; i<nchanges; ){
          351                 j = changeset(i);
          352                 a = changes[i].a-Lines;
          353                 b = changes[j-1].b+Lines;
          354                 c = changes[i].c-Lines;
          355                 d = changes[j-1].d+Lines;
          356                 if(a < 1)
          357                         a = 1;
          358                 if(c < 1)
          359                         c = 1;
          360                 if(b > len[0])
          361                         b = len[0];
          362                 if(d > len[1])
          363                         d = len[1];
          364                 if(mode == 'a'){
          365                         a = 1;
          366                         b = len[0];
          367                         c = 1;
          368                         d = len[1];
          369                         j = nchanges;
          370                 }
          371                 Bprint(&stdout, "%s:", file1);
          372                 range(a, b, ",");
          373                 Bprint(&stdout, " - ");
          374                 Bprint(&stdout, "%s:", file2);
          375                 range(c, d, ",");
          376                 Bputc(&stdout, '\n');
          377                 at = a;
          378                 for(; i<j; i++){
          379                         fetch(ixold, at, changes[i].a-1, input[0], "  ");
          380                         fetch(ixold, changes[i].a, changes[i].b, input[0], "- ");
          381                         fetch(ixnew, changes[i].c, changes[i].d, input[1], "+ ");
          382                         at = changes[i].b+1;
          383                 }
          384                 fetch(ixold, at, b, input[0], "  ");
          385         }
          386         nchanges = 0;
          387 }