"Fossies" - the Fresh Open Source Software Archive

Member "dirdiff-2.1/filecmp.c" (19 Apr 2005, 7406 Bytes) of package /linux/privat/old/dirdiff-2.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "filecmp.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Tcl command procedure to compare two files and report whether
    3  * they are identical.
    4  *
    5  * P. Mackerras 17/7/96.
    6  *
    7  * $Id: filecmp.c,v 1.3 2001/08/15 11:12:44 paulus Exp $
    8  */
    9 #include <stdio.h>
   10 #include <string.h>
   11 #include <ctype.h>
   12 #include <tcl.h>
   13 #include <sys/fcntl.h>
   14 
   15 #define BSIZE       32768
   16 #define MAXTAGLEN   512 /* max tag length for sanity, < BSIZE */
   17 
   18 #ifdef NO_MEMMOVE
   19 #define memmove(t, f, n)    bcopy(f, t, n)
   20 #endif
   21 
   22 char *rcs_ignores[] = {
   23     "Log",          /* must be at index 0! */
   24     "Id",
   25     "Revision",
   26     "Source",
   27     "Author",
   28     "Date",
   29     "State",
   30     "Header",
   31     NULL
   32 };
   33 
   34 char *comment_leaders[] = {
   35     " *",
   36     "#",
   37     NULL
   38 };
   39 
   40 /*
   41  * See if the text starting at p, for n chars, looks like an RCS tag.
   42  * We already know p[0] == '$' and n >= 4.
   43  * Return 0 if it isn't a tag, -1 if it looks like a tag but is incomplete,
   44  * or the length of the tag.
   45  */
   46 int
   47 tag_length(p, n)
   48     char *p;
   49     int n;
   50 {
   51     int i, j, k, l;
   52     int maybe;
   53     char *t, *cl;
   54 
   55     /* check through list of tags */
   56     for (i = 0; (t = rcs_ignores[i]) != NULL; ++i) {
   57     for (j = 1; *t != 0; ++j, ++t) {
   58         if (j >= n)
   59         return -1;
   60         if (p[j] != *t)
   61         break;
   62     }
   63     if (*t == 0)
   64         break;
   65     }
   66     if (t == NULL)      /* if tag wasn't in list */
   67     return 0;
   68     if (j >= n)         /* if we got to the end of the buffer */
   69     return -1;
   70     if (p[j] == '$')        /* for the \dollar Id\dollar case */
   71     return j + 1;
   72     if (p[j] != ':')        /* tag word must be followed by $ or : */
   73     return 0;
   74     while (++j < n) {       /* if by :, matching $ must appear before \n */
   75     if (p[j] == '\n')
   76         return 0;       /* got \n without $: not a tag */
   77     if (p[j] == '$') {
   78         if (i != 0)     /* got $: if the tag wasn't \dollar Log, */
   79         return j + 1;   /* that's the end of the tag */
   80         /* here we skip lines that start with ' * ' or '# '. */
   81         for (;;) {
   82         /* skip to \n */
   83         while (++j < n && p[j] != '\n')
   84             ;
   85         if (++j >= n)
   86             break;
   87         maybe = 0;
   88         l = n - j;
   89         if (l >= 3 && p[j] == ' ' && p[j+1] == '*' && p[j+2] != '/')
   90             continue;   /* C-style comment leader */
   91         if (p[j] == '#')
   92             continue;   /* Script comment leader */
   93         if (l < 3 && p[j] == ' ' && (l < 2 || p[j] == '*'))
   94             maybe = 1;  /* may be C-style comment leader */
   95         if (maybe)
   96             break;
   97         return j;   /* we've found the end of the tag */
   98         }
   99         /* Incomplete tag following \dollar Log;
  100            the complete tag could be quite long. */
  101         if (n >= BSIZE)
  102         return 0;
  103         return -1;
  104     }
  105     }
  106     if (n > MAXTAGLEN)      /* incomplete tag too long: not a tag */
  107     return 0;
  108     return -1;          /* incomplete tag */
  109 }
  110 
  111 int rcscmp(char *p1, int *k1p, char *p2, int *k2p, int e1, int e2)
  112 {
  113     int k1 = *k1p, k2 = *k2p;
  114     int i, t1, t2;
  115 
  116     for (;;) {
  117     for (i = 0; i < k1 && i < k2; ++i) {
  118         if (p1[i] != p2[i])
  119         return 0;
  120         if (p1[i] == '$')
  121         break;
  122     }
  123     p1 += i;
  124     k1 -= i;
  125     p2 += i;
  126     k2 -= i;
  127     /* 4 == strlen("<dollar>Id<dollar>") */
  128     if (k1 < 4 && !e1 || k2 < 4 && !e2)
  129         break;
  130     if (k1 < 4 || k2 < 4) {
  131         /* near the end of one or both files */
  132         if (k1 != k2 || memcmp(p1, p2, k1) != 0)
  133         return 0;
  134         k1 = k2 = 0;
  135         break;
  136     }
  137     /* check that the tags look the same (1st 2 chars at least) */
  138     if (p1[1] != p2[1] || p1[2] != p2[2])
  139         return 0;
  140     t1 = tag_length(p1, k1);
  141     if (t1 < 0 && e1)
  142         t1 = 0;
  143     if (t1 != 0) {
  144         t2 = tag_length(p2, k2);
  145         if (t2 < 0 && e2)
  146         t2 = 0;
  147     }
  148     if (t1 == 0 || t2 == 0) {
  149         /* one or other string isn't a tag */
  150         p1 += 3;
  151         k1 -= 3;
  152         p2 += 3;
  153         k2 -= 3;
  154         continue;
  155     }
  156     if (t1 < 0 || t2 < 0)
  157         break;      /* one or other tag is incomplete */
  158     p1 += t1;
  159     k1 -= t1;
  160     p2 += t2;
  161     k2 -= t2;
  162     if (k1 == 0 || k2 == 0)
  163         break;
  164     }
  165     *k1p = k1;
  166     *k2p = k2;
  167     return 1;
  168 }
  169 
  170 static char bktag[] = "BK Id: ";
  171 #define BKTAGLEN    7
  172 
  173 int bkcmp(char *p1, int *k1p, char *p2, int *k2p, int e1, int e2)
  174 {
  175     int k1 = *k1p, k2 = *k2p;
  176     int i, match, t1, t2;
  177 
  178     for (;;) {
  179         match = 0;
  180         for (i = 0; i < k1 && i < k2; ++i) {
  181             if (p1[i] != p2[i])
  182                 return 0;
  183             if (p1[i] == bktag[match]) {
  184                 if (++match == BKTAGLEN) {
  185                     ++i;
  186                     break;
  187                 }
  188             } else {
  189                 match = (p1[i] == bktag[0]);
  190             }
  191         }
  192         p1 += i;
  193         k1 -= i;
  194         p2 += i;
  195         k2 -= i;
  196         if (match < BKTAGLEN) {
  197             /* we have run out of one or other buffer */
  198             if (k1 == 0 && e1 || k2 == 0 && e2) {
  199                 if (k1 == k2)
  200                     break;
  201                 return 0;
  202             }
  203             k1 += match;
  204             k2 += match;
  205             break;
  206         }
  207         /* found a tag, skip to eol on both files */
  208         for (t1 = 0; t1 < k1; ++t1)
  209             if (p1[t1] == '\n')
  210                 break;
  211         for (t2 = 0; t2 < k2; ++t2)
  212             if (p2[t2] == '\n')
  213                 break;
  214         if (t1 < k1 && t2 < k2) {
  215             p1 += t1;
  216             k1 -= t1;
  217             p2 += t2;
  218             k2 -= t2;
  219             continue;
  220         }
  221         /* ran out before eol on one or both files */
  222         if (t1 == k1 && e1 || t2 == k2 && e2) {
  223             k1 -= t1;
  224             k2 -= t2;
  225             if (k1 == k2)
  226                 break;
  227             return 0;
  228         }
  229         /* not at eof on either file */
  230         k1 += BKTAGLEN;
  231         k2 += BKTAGLEN;
  232         break;
  233     }
  234     *k1p = k1;
  235     *k2p = k2;
  236     return 1;
  237 }
  238 
  239 int
  240 FileCmpCmd(clientData, interp, argc, argv)
  241     ClientData clientData;
  242     Tcl_Interp *interp;
  243     int argc;
  244     char **argv;
  245 {
  246     int i, fi;
  247     int f1, f2;
  248     char *b1, *b2;
  249     int n1, n2, same;
  250     int k1, k2, t1, t2;
  251     int rcsflag, bkflag;
  252     int e1, e2;
  253 
  254     fi = 1;
  255     rcsflag = 0;
  256     bkflag = 0;
  257     if (argc > 1 && strcmp(argv[1], "-rcs") == 0) {
  258     ++fi;
  259     rcsflag = 1;
  260     } else if (argc > 1 && strcmp(argv[1], "-bk") == 0) {
  261     ++fi;
  262     bkflag = 1;
  263     }
  264     if (argc != fi + 2) {
  265     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  266              " ?-rcs? file1 file2\"", (char *) NULL);
  267     return TCL_ERROR;
  268     }
  269 
  270     if ((f1 = open(argv[fi], O_RDONLY)) == -1) {
  271     Tcl_AppendResult(interp, "can't open \"", argv[fi], "\": ",
  272              Tcl_PosixError(interp), (char *) NULL);
  273     return TCL_ERROR;
  274     }
  275     if ((f2 = open(argv[fi+1], O_RDONLY)) == -1) {
  276     Tcl_AppendResult(interp, "can't open \"", argv[fi+1], "\": ",
  277              Tcl_PosixError(interp), (char *) NULL);
  278     close(f1);
  279     return TCL_ERROR;
  280     }
  281 
  282     b1 = (char *) ckalloc(BSIZE);
  283     b2 = (char *) ckalloc(BSIZE);
  284 
  285     same = 1;
  286 
  287     k1 = k2 = 0;
  288     e1 = e2 = 0;
  289 
  290     for (;;) {
  291     /* Here we already have k1 chars in b1 and k2 chars in b2. */
  292     if (!e1 && k1 < BSIZE) {
  293         n1 = read(f1, b1 + k1, BSIZE - k1);
  294         if (n1 < 0) {
  295         Tcl_AppendResult(interp, "error reading \"", argv[fi],
  296                  "\": ", Tcl_PosixError(interp),
  297                  (char *) NULL);
  298         break;
  299         }
  300         k1 += n1;
  301         if (k1 < BSIZE)
  302         e1 = 1;
  303     }
  304     if (!e2 && k2 < BSIZE) {
  305         n2 = read(f2, b2 + k2, BSIZE - k2);
  306         if (n2 < 0) {
  307         Tcl_AppendResult(interp, "error reading \"", argv[fi+1],
  308                  "\": ", Tcl_PosixError(interp),
  309                  (char *) NULL);
  310         break;
  311         }
  312         k2 += n2;
  313         if (k2 < BSIZE)
  314         e2 = 1;
  315     }
  316     if (k1 == 0 && k2 == 0)
  317         break;
  318     t1 = k1;
  319     t2 = k2;
  320     if (rcsflag)
  321         same = rcscmp(b1, &k1, b2, &k2, e1, e2);
  322     else if (bkflag)
  323         same = bkcmp(b1, &k1, b2, &k2, e1, e2);
  324     else {
  325         if (k1 != k2 || memcmp(b1, b2, k1) != 0)
  326         same = 0;
  327         k1 = k2 = 0;
  328     }
  329     if (!same || (e1 && e2))
  330         break;
  331     if (k1 > 0)
  332         memmove(b1, b1 + t1 - k1, k1);
  333     if (k2 > 0)
  334         memmove(b2, b2 + t2 - k2, k2);
  335     }
  336 
  337     close(f1);
  338     close(f2);
  339     ckfree(b1);
  340     ckfree(b2);
  341     if (n1 < 0 || n2 < 0)
  342     return TCL_ERROR;
  343 
  344     sprintf(interp->result, "%d", same);
  345     return TCL_OK;
  346 }
  347 
  348 int
  349 Filecmp_Init(interp)
  350     Tcl_Interp *interp;
  351 {
  352     Tcl_CreateCommand(interp, "filecmp", FileCmpCmd, NULL, NULL);
  353     return TCL_OK;
  354 }