home *** CD-ROM | disk | FTP | other *** search
/ The UNIX CD Bookshelf / OREILLY_TUCB_UNIX_CD.iso / upt / examples / SOURCES / TWIN / TWIN. / twin.c < prev   
Encoding:
C/C++ Source or Header  |  1998-07-24  |  14.4 KB  |  523 lines

  1. /* twin.c */
  2. /* Twin Aspect Display: compare 2 files */
  3. /* (c) Istvan Mohos, 1988 */
  4.  
  5. #define MAIN
  6. #include "ilib.h"
  7. #include <curses.h>
  8. #include <signal.h>
  9.  
  10. #define NSTRIP       4
  11. #define DIVI         1
  12. #define SO           standout()
  13. #define SE           standend()
  14. #define HIT          1
  15. #define YET          0
  16. #define OVR          -1
  17. #define A            0
  18. #define B            1
  19. #define T            2
  20.  
  21. char *Mesg = "Insufficient terminal capabilities. Sorry...";
  22. int charsA;
  23. int charsB;
  24. int Lcount = 1;
  25. int chindxA = 1;
  26. int chindxB = 1;
  27. int Alines;
  28. int Blines;
  29. int oldLcount = 1;
  30. unsigned char *bigbufA;
  31. unsigned char *bigbufB;
  32. unsigned char *Alist;
  33. unsigned char *Blist;
  34. unsigned char **Ap;
  35. unsigned char **Bp;
  36. unsigned char **Aend;
  37. unsigned char **Bend;
  38. unsigned char **oldAp;
  39. unsigned char **oldBp;
  40. unsigned char *tpA;
  41. unsigned char *tpB;
  42.  
  43. main (argc, argv)
  44. int argc;
  45. char *argv[];
  46. {
  47.     register int ri, rj;
  48.     register unsigned char *pr1, *pr2;
  49.     int startline = 1;
  50.     int endline = 0;
  51.     int x1, x2, ver, llen, redg_x;
  52.     int bugs, realc, is_hope;
  53.     int totchars;
  54.     int ucount = 0;
  55.     int newline = 1;
  56.     unsigned char c, *lstart, *rstart, *bufend;
  57.     unsigned char buf0[512], prcount[60];
  58.     char *cop = "(c)mohos1988";
  59.     int goaway();
  60.  
  61.     if (argc != 3)
  62.         fprintf(stderr, "Usage: %s file1 file2\n", argv[0]), exit(1);
  63.  
  64.     if (imode(argv[1], "40000") == 1)
  65.         fprintf(stderr, "%s is a directory\n", argv[1]), exit(1);
  66.     strcpy(buf0, argv[2]);
  67.     if (imode(buf0, "40000") == 1) {
  68.         pr1 = buf0 + strlen(buf0);
  69.         *pr1++ = '/';
  70.         iego(argv[1], pr1, '/', '/');
  71.     }
  72.  
  73.     if ((charsA = iread(argv[1], &bigbufA)) < 1)
  74.         fprintf(stderr, "%s %s \n",ierbuf, argv[1]), exit(1);
  75.     if ((charsB = iread(buf0, &bigbufB)) < 1)
  76.         fprintf(stderr, "%s %s \n",ierbuf, buf0), exit(1);
  77.  
  78.     if ((Alines = illistn(bigbufA, bigbufA+charsA, &Alist)) < 1)
  79.         fprintf(stderr, "%s %s \n",ierbuf, argv[1]), exit(1);
  80.     if ((Blines = illistn(bigbufB, bigbufB+charsB, &Blist)) < 1)
  81.         fprintf(stderr, "%s %s \n",ierbuf, buf0), exit(1);
  82.  
  83.     initscr();
  84.     crmode();
  85.     noecho();
  86.  
  87.     /* God knows why I had this here originally, maybe SysV needs it:
  88.     nonl();
  89.     */
  90.     signal(SIGINT, goaway);
  91.     if ((COLS < 60) || (LINES < 20))
  92.         goaway();
  93.  
  94.     bufend = buf0 + COLS;
  95.     llen = (COLS - NSTRIP - DIVI -1) / 2;
  96.     redg_x = NSTRIP + llen + DIVI; /* x coordinate for curses */
  97.     lstart = buf0 + NSTRIP;
  98.     rstart = buf0 + NSTRIP + llen + DIVI;
  99.     Mesg = "user interrupt...exiting";
  100.  
  101.     ri = 2;
  102.     mvaddstr(ri++, 1, argv[1]);
  103.     sprintf(prcount, "%4d lines, %5d characters ", Alines, charsA);
  104.     SO, mvaddstr(ri++, 5, prcount), SE;
  105.     ri++;
  106.  
  107.     mvaddstr(ri++, 1, buf0);
  108.     sprintf(prcount, "%4d lines, %5d characters ", Blines, charsB);
  109.     SO, mvaddstr(ri++, 5, prcount), SE;
  110.     ri++;
  111.  
  112.     mvaddstr(1, COLS-15, cop);
  113.  
  114.     mvaddstr(ri++, 1, "[N]f  left text up    N lines");
  115.     mvaddstr(ri++, 1, "[N]d  left text down  N lines");
  116.     mvaddstr(ri++, 1, "[N]k  right text up   N lines");
  117.     mvaddstr(ri++, 1, "[N]j  right text down N lines");
  118.     mvaddstr(ri++, 1, "[N]u  both texts up   N lines");
  119.     mvaddstr(ri++, 1, "[N]v  both texts down N lines");
  120.     mvaddstr(ri++, 1, "   t  back to top of files");
  121.     mvaddstr(ri++, 1, "   n  show next difference");
  122.     mvaddstr(ri++, 1, "<TAB> page backward");
  123.     mvaddstr(ri++, 1, "<any> page forward");
  124.     mvaddstr(ri++, 1, "   q  quit");
  125.     refresh();
  126.  
  127.     Ap = oldAp = (unsigned char **)Alist;
  128.     Bp = oldBp = (unsigned char **)Blist;
  129.     Aend = (unsigned char **)Alist + Alines -1; /* last line */
  130.     Bend = (unsigned char **)Blist + Blines -1;
  131.     tpA = *Ap;
  132.     tpB = *Bp;
  133.  
  134.     totchars = charsA + charsB;
  135.     c = getchar();
  136.  
  137.     for (;; ucount = 0) {
  138. number:
  139.         switch(c) {
  140.  
  141.             default:
  142.                 break;
  143.  
  144.             case '0':
  145.             case '1':
  146.             case '2':
  147.             case '3':
  148.             case '4':
  149.             case '5':
  150.             case '6':
  151.             case '7':
  152.             case '8':
  153.             case '9':
  154.                 ucount *= 10;
  155.                 ucount += (c - 48);
  156.                 c = getchar();
  157.                 goto number;
  158.                 break;
  159.  
  160.             case 'k': /* bring text up on the right */
  161.                 reset();
  162.                 if (!ucount)
  163.                     ucount = 1;
  164.                 mov(B, ucount);
  165.                 break;
  166.  
  167.             case 'j': /* bring text down on the right */
  168.                 reset();
  169.                 if (!ucount)
  170.                     ucount = 1;
  171.                 mov(B, -ucount);
  172.                 break;
  173.  
  174.             case 'f': /* bring text up on the left */
  175.                 reset();
  176.                 if (!ucount)
  177.                     ucount = 1;
  178.                 mov(A, ucount);
  179.                 break;
  180.  
  181.             case 'd': /* bring text down on the left */
  182.                 reset();
  183.                 if (!ucount)
  184.                     ucount = 1;
  185.                 mov(A, -ucount);
  186.                 break;
  187.  
  188.             case 'u': /* both up N lines */
  189.                 reset();
  190.                 if (!ucount)
  191.                     ucount = 1;
  192.                 mov(T, -ucount);
  193.                 break;
  194.  
  195.             case 'v': /* both down N lines */
  196.                 reset();
  197.                 if (!ucount)
  198.                     ucount = 1;
  199.                 mov(T, ucount);
  200.                 break;
  201.  
  202.             case '\t': /* both up one window */
  203.                 reset();
  204.                 ucount = endline - startline +1;
  205.                 mov(T, -ucount);
  206.                 break;
  207.  
  208.             case 't': /* back to top */
  209.                 Ap = (unsigned char **)Alist;
  210.                 Lcount = 1;
  211.                 Bp = (unsigned char **)Blist;
  212.                 tpA = *Ap;
  213.                 chindxA = 1;
  214.                 tpB = *Bp;
  215.                 chindxB = 1;
  216.                 break;
  217.  
  218.             case 'q': /* quit */
  219.                 Mesg = "";
  220.                 goaway();
  221.  
  222.             case 'n': /* proceed to next difference */
  223.                 while (Bp <= Bend && Ap <= Aend) {
  224.                     tpA = *Ap;
  225.                     tpB = *Bp;
  226.  
  227.                     /* quick test for size of next line */
  228.                     if (Ap[1] - tpA != Bp[1] - tpB)
  229.                         goto breakout;
  230.                     pr1 = tpA;
  231.                     pr2 = tpB;
  232.                     for (;*pr1; pr1++, pr2++)
  233.                         if (*pr1 != *pr2)
  234.                            goto breakout;
  235.                     if (++Ap <= Aend)
  236.                         ++Lcount;
  237.                     ++Bp;
  238.                 }
  239.                 reset(); /* no change found */
  240.                 putchar(7);
  241. breakout:
  242.                 chindxA = tpA - bigbufA +1;
  243.                 chindxB = tpB - bigbufB +1;
  244.                 break;
  245.         }
  246.  
  247.         if (chindxA + chindxB >= totchars) {
  248.             Mesg = "";
  249.             goaway();
  250.         }
  251.  
  252.         oldAp = Ap;
  253.         oldBp = Bp;
  254.         oldLcount = Lcount;
  255.         ver = 0;  /* new page starts at line 0 */
  256.  
  257.         /* process one line in each iteration of the loop */
  258.         startline = Lcount;
  259.         while (ver < LINES) {
  260.             iblank(buf0, bufend);
  261.             if (newline && chindxA < charsA) {
  262.  
  263.                 sprintf(buf0, "%3d ", Lcount);
  264.                 /* last 3 digits of linenum only, plus space */
  265.                 pr1 = buf0 + strlen(buf0) - NSTRIP;
  266.                 pr2 = buf0;
  267.                 for (ri = NSTRIP; --ri >= 0; *pr2++ = *pr1++);
  268.                 newline = 0;
  269.             }
  270.             else
  271.                 sprintf(buf0, "    ");
  272.  
  273.             pr1 = lstart;
  274.             pr2 = rstart;
  275.  
  276.             for (ri = 0; ri < llen; ri++) {
  277.                 *pr1 = *tpA;
  278.                 *pr2 = *tpB;
  279.  
  280.                 /* end of both text lines */
  281.                 if((*tpA == '\0') && (*tpB == '\0')) {
  282.                     newline = 1;
  283.                     if ((rj = inc(A)) == YET)
  284.                         ++Lcount, ++Ap, ++tpA;
  285.                     else if (rj == OVR)
  286.                         *pr1 = '~';
  287.                     if ((rj = inc(B)) == YET)
  288.                         ++Bp, ++tpB;
  289.                     else if (rj == OVR)
  290.                         *pr2 = '~';
  291.                     break;
  292.                 }
  293.  
  294.                 /* string ends on left side */
  295.                 else if (*tpA == '\0') {
  296.                     /* right side done already */
  297.                     if (chindxB == charsB) {
  298.                         newline = 1;
  299.                         if ((rj = inc(A)) == YET)
  300.                             ++Lcount, ++Ap, ++tpA;
  301.                         else if (rj == OVR)
  302.                             *pr1 = '~';
  303.                         break;
  304.                     }
  305.                     /* leave tpA on null while incrementing tpB */
  306.                     else {
  307.                         if ((rj = inc(B)) == YET || rj == HIT)
  308.                            ++pr2, ++tpB;
  309.                         if (rj == HIT)
  310.                            --chindxB;
  311.                     }
  312.                 }
  313.  
  314.                 /* string ends on right side */
  315.                 else if (*tpB == '\0') {
  316.                     /* left side is done already */
  317.                     if (chindxA == charsA) {
  318.                         if ((rj = inc(B)) == YET)
  319.                             ++Bp, ++tpB;
  320.                         else if (rj == OVR)
  321.                             *pr2 = '~';
  322.                         break;
  323.                     }
  324.                     /* leave tpB on null while incrementing tpA */
  325.                     else {
  326.                         if ((rj = inc(A)) == YET || rj == HIT)
  327.                            ++pr1, ++tpA;
  328.                         if (rj == HIT)
  329.                            --chindxA;
  330.                     }
  331.                 }
  332.  
  333.                 /* add character from both texts */
  334.                 else {
  335.                     if ((rj = inc(A)) == YET || rj == HIT)
  336.                        ++pr1, ++tpA;
  337.                     if (rj == HIT)
  338.                        --chindxA;
  339.                     if ((rj = inc(B)) == YET || rj == HIT)
  340.                        ++pr2, ++tpB;
  341.                     if (rj == HIT)
  342.                        --chindxB;
  343.                 }
  344.             }
  345.             *(buf0 + COLS) = 0;
  346.             mvaddstr(ver, 0, buf0);
  347.  
  348. /* leave text alone: analyze display line */
  349.             pr1 = lstart;
  350.             pr2 = rstart;
  351.             for (bugs = 0, realc = llen, ri = 0; ri < llen; ++ri) {
  352.                 if (WHITE(*pr1) && WHITE(*pr2))
  353.                     --realc;
  354.                 if (*pr1++ != *pr2++)
  355.                     ++bugs;
  356.             }
  357.  
  358. /* at least half of the printing characters match */
  359.             is_hope = bugs <= (realc >> 1);
  360.             pr1 = lstart;
  361.             pr2 = rstart;
  362.             x1 = NSTRIP;
  363.             x2 = redg_x;
  364.             for (ri = 0; ri < llen; ++ri) {
  365.                 if ((*pr1 == *pr2) && is_hope) {
  366.                     if (WHITE(*pr1))
  367.                         *pr1 = ' ', *pr2 = ' ';
  368.                     mvaddch(ver, x1++, *pr1);
  369.                     mvaddch(ver, x2++, *pr2);
  370.                 }
  371.                 else {
  372.                     if (WHITE(*pr1))
  373.                         *pr1 = ' ';
  374.                     if (WHITE(*pr2))
  375.                         *pr2 = ' ';
  376.  
  377.                     standout();
  378.                     mvaddch(ver, x1++, *pr1);
  379.                     mvaddch(ver, x2++, *pr2);
  380.                     standend();
  381.                 }
  382.                 ++pr1;
  383.                 ++pr2;
  384.             }
  385.             if (chindxA <= charsA)
  386.                 mvaddstr(ver, x1, "|");
  387.             else
  388.                 mvaddstr(ver, x1, " ");
  389.             ++ver;
  390.         }
  391.         endline = Lcount;
  392.         move(LINES -1, COLS -2);
  393.         refresh();
  394.         c = getchar();
  395.     }
  396. }
  397.  
  398. goaway()    /* restore terminal in case of interrupt */
  399. {
  400.     signal(SIGINT, SIG_IGN);     /* ignore 2nd interrupt */
  401.     mvcur(0, COLS-1, LINES-1, 0);
  402.     endwin();
  403.     printf("%s\n", Mesg);
  404.     exit(0);
  405. }
  406.  
  407. reset()
  408. {
  409.     Ap = oldAp;
  410.     Bp = oldBp;
  411.     tpA = *Ap;
  412.     tpB = *Bp;
  413.     chindxA = tpA - bigbufA +1;
  414.     chindxB = tpB - bigbufB +1;
  415.     Lcount = oldLcount;
  416. }
  417.  
  418. mov(side, ucount)
  419. int side;
  420. register int ucount;
  421. {
  422.     switch (side) {
  423.         case A:
  424.             if (ucount > 0) {
  425.                 if ((Ap += ucount) <= Aend)
  426.                     Lcount += ucount;
  427.                 else {
  428.                     Ap = Aend;
  429.                     Lcount = Alines;
  430.                     putchar(7);
  431.                 }
  432.             }
  433.             else {
  434.                 if ((Ap += ucount) >= (unsigned char **)Alist)
  435.                     Lcount += ucount;
  436.                 else {
  437.                     Ap = (unsigned char **)Alist;
  438.                     Lcount = 1;
  439.                     putchar(7);
  440.                 }
  441.             }
  442.             tpA = *Ap;
  443.             chindxA = tpA - bigbufA +1;
  444.             break;
  445.  
  446.         case B:
  447.             if (ucount > 0) {
  448.                 if ((Bp += ucount) > Bend) {
  449.                     Bp = Bend;
  450.                     putchar(7);
  451.                 }
  452.             }
  453.             else {
  454.                 if ((Bp += ucount) < (unsigned char **)Blist) {
  455.                     Bp = (unsigned char **)Blist;
  456.                     putchar(7);
  457.                 }
  458.             }
  459.             tpB = *Bp;
  460.             chindxB = tpB - bigbufB +1;
  461.             break;
  462.  
  463.         case T:
  464.         default:
  465.             if (ucount > 0) {
  466.                 if (Ap + ucount > Aend || Bp + ucount > Bend) {
  467.                     Ap = Aend;
  468.                     Lcount = Alines;
  469.                     Bp = Bend;
  470.                     putchar(7);
  471.                 }
  472.                 else {
  473.                     Ap += ucount;
  474.                     Bp += ucount;
  475.                     Lcount += ucount;
  476.                 }
  477.             }
  478.             else {
  479.                 if (Ap + ucount < (unsigned char **)Alist ||
  480.                     Bp + ucount < (unsigned char **)Blist) {
  481.                     Ap = (unsigned char **)Alist;
  482.                     Lcount = 1;
  483.                     Bp = (unsigned char **)Blist;
  484.                     putchar(7);
  485.                 }
  486.                 else {
  487.                     Ap += ucount;
  488.                     Bp += ucount;
  489.                     Lcount += ucount;
  490.                 }
  491.             }
  492.             tpA = *Ap;
  493.             chindxA = tpA - bigbufA +1;
  494.             tpB = *Bp;
  495.             chindxB = tpB - bigbufB +1;
  496.             break;
  497.     }
  498. }
  499.  
  500. inc(side)
  501. int side;
  502. {
  503.     if (side) {
  504.         if (chindxB < charsB) {
  505.             if (++chindxB == charsB) {
  506.                 return(HIT);
  507.             }
  508.             return(YET);
  509.         }
  510.         return(OVR);
  511.     }
  512.     else {
  513.         if (chindxA < charsA) {
  514.             if (++chindxA == charsA) {
  515.                 return(HIT);
  516.             }
  517.             return(YET);
  518.         }
  519.         return(OVR);
  520.     }
  521. }
  522.  
  523.