home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / rcs567s.zip / rcs / src / rcsfcmp.c < prev    next >
C/C++ Source or Header  |  1994-03-17  |  9KB  |  349 lines

  1. /* Compare working files, ignoring RCS keyword strings.  */
  2.  
  3. /*****************************************************************************
  4.  *                       rcsfcmp()
  5.  *                       Testprogram: define FCMPTEST
  6.  *****************************************************************************
  7.  */
  8.  
  9. /* Copyright 1982, 1988, 1989 Walter Tichy
  10.    Copyright 1990, 1991, 1992, 1993, 1994 Paul Eggert
  11.    Distributed under license by the Free Software Foundation, Inc.
  12.  
  13. This file is part of RCS.
  14.  
  15. RCS is free software; you can redistribute it and/or modify
  16. it under the terms of the GNU General Public License as published by
  17. the Free Software Foundation; either version 2, or (at your option)
  18. any later version.
  19.  
  20. RCS is distributed in the hope that it will be useful,
  21. but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23. GNU General Public License for more details.
  24.  
  25. You should have received a copy of the GNU General Public License
  26. along with RCS; see the file COPYING.  If not, write to
  27. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  28.  
  29. Report problems and direct all questions to:
  30.  
  31.     rcs-bugs@cs.purdue.edu
  32.  
  33. */
  34.  
  35.  
  36.  
  37.  
  38.  
  39. /*
  40.  * $Log: rcsfcmp.c,v $
  41.  * Revision 5.12  1994/03/17 14:05:48  eggert
  42.  * Normally calculate the $Log prefix from context, not from RCS file.
  43.  * Calculate line numbers correctly even if the $Log prefix contains newlines.
  44.  * Remove lint.
  45.  *
  46.  * Revision 5.11  1993/11/03 17:42:27  eggert
  47.  * Fix yet another off-by-one error when comparing Log string expansions.
  48.  *
  49.  * Revision 5.10  1992/07/28 16:12:44  eggert
  50.  * Statement macro names now end in _.
  51.  *
  52.  * Revision 5.9  1991/10/07  17:32:46  eggert
  53.  * Count log lines correctly.
  54.  *
  55.  * Revision 5.8  1991/08/19  03:13:55  eggert
  56.  * Tune.
  57.  *
  58.  * Revision 5.7  1991/04/21  11:58:22  eggert
  59.  * Fix errno bug.  Add MS-DOS support.
  60.  *
  61.  * Revision 5.6  1991/02/28  19:18:47  eggert
  62.  * Open work file at most once.
  63.  *
  64.  * Revision 5.5  1990/11/27  09:26:05  eggert
  65.  * Fix comment leader bug.
  66.  *
  67.  * Revision 5.4  1990/11/01  05:03:42  eggert
  68.  * Permit arbitrary data in logs and comment leaders.
  69.  *
  70.  * Revision 5.3  1990/09/11  02:41:15  eggert
  71.  * Don't ignore differences inside keyword strings if -ko is set.
  72.  *
  73.  * Revision 5.1  1990/08/29  07:13:58  eggert
  74.  * Clean old log messages too.
  75.  *
  76.  * Revision 5.0  1990/08/22  08:12:49  eggert
  77.  * Don't append "checked in with -k by " log to logs,
  78.  * so that checking in a program with -k doesn't change it.
  79.  * Ansify and Posixate.  Remove lint.
  80.  *
  81.  * Revision 4.5  89/05/01  15:12:42  narten
  82.  * changed copyright header to reflect current distribution rules
  83.  * 
  84.  * Revision 4.4  88/08/09  19:12:50  eggert
  85.  * Shrink stdio code size.
  86.  * 
  87.  * Revision 4.3  87/12/18  11:40:02  narten
  88.  * lint cleanups (Guy Harris)
  89.  * 
  90.  * Revision 4.2  87/10/18  10:33:06  narten
  91.  * updting version number. Changes relative to 1.1 actually relative to 
  92.  * 4.1
  93.  * 
  94.  * Revision 1.2  87/03/27  14:22:19  jenkins
  95.  * Port to suns
  96.  * 
  97.  * Revision 4.1  83/05/10  16:24:04  wft
  98.  * Marker matching now uses trymatch(). Marker pattern is now
  99.  * checked precisely.
  100.  * 
  101.  * Revision 3.1  82/12/04  13:21:40  wft
  102.  * Initial revision.
  103.  *
  104.  */
  105.  
  106. /*
  107. #define FCMPTEST
  108. */
  109. /* Testprogram; prints out whether two files are identical,
  110.  * except for keywords
  111.  */
  112.  
  113. #include  "rcsbase.h"
  114.  
  115. libId(fcmpId, "$Id: rcsfcmp.c,v 5.12 1994/03/17 14:05:48 eggert Exp $")
  116.  
  117.     static int discardkeyval P((int,RILE*));
  118.     static int
  119. discardkeyval(c, f)
  120.     register int c;
  121.     register RILE *f;
  122. {
  123.     for (;;)
  124.         switch (c) {
  125.             case KDELIM:
  126.             case '\n':
  127.                 return c;
  128.             default:
  129.                 Igeteof_(f, c, return EOF;)
  130.                 break;
  131.         }
  132. }
  133.  
  134.     int
  135. rcsfcmp(xfp, xstatp, uname, delta)
  136.     register RILE *xfp;
  137.     struct stat const *xstatp;
  138.     char const *uname;
  139.     struct hshentry const *delta;
  140. /* Compare the files xfp and uname.  Return zero
  141.  * if xfp has the same contents as uname and neither has keywords,
  142.  * otherwise -1 if they are the same ignoring keyword values,
  143.  * and 1 if they differ even ignoring
  144.  * keyword values. For the LOG-keyword, rcsfcmp skips the log message
  145.  * given by the parameter delta in xfp.  Thus, rcsfcmp returns nonpositive
  146.  * if xfp contains the same as uname, with the keywords expanded.
  147.  * Implementation: character-by-character comparison until $ is found.
  148.  * If a $ is found, read in the marker keywords; if they are real keywords
  149.  * and identical, read in keyword value. If value is terminated properly,
  150.  * disregard it and optionally skip log message; otherwise, compare value.
  151.  */
  152. {
  153.     register int xc, uc;
  154.     char xkeyword[keylength+2];
  155.     int eqkeyvals;
  156.     register RILE *ufp;
  157.     register int xeof, ueof;
  158.     register char * tp;
  159.     register char const *sp;
  160.     register size_t leaderlen;
  161.     int result;
  162.     enum markers match1;
  163.     struct stat ustat;
  164.  
  165.     if (!(ufp = Iopen(uname, FOPEN_R_WORK, &ustat))) {
  166.        efaterror(uname);
  167.     }
  168.     xeof = ueof = false;
  169.     if (Expand==OLD_EXPAND) {
  170.     if (!(result = xstatp->st_size!=ustat.st_size)) {
  171. #        if has_mmap && large_memory
  172.         result = !!memcmp(xfp->base,ufp->base,(size_t)xstatp->st_size);
  173. #        else
  174.         for (;;) {
  175.             /* get the next characters */
  176.             Igeteof_(xfp, xc, xeof=true;)
  177.             Igeteof_(ufp, uc, ueof=true;)
  178.             if (xeof | ueof)
  179.             goto eof;
  180.             if (xc != uc)
  181.             goto return1;
  182.         }
  183. #        endif
  184.     }
  185.     } else {
  186.     xc = 0;
  187.     uc = 0; /* Keep lint happy.  */
  188.     leaderlen = 0;
  189.     result = 0;
  190.  
  191.     for (;;) {
  192.       if (xc != KDELIM) {
  193.         /* get the next characters */
  194.         Igeteof_(xfp, xc, xeof=true;)
  195.         Igeteof_(ufp, uc, ueof=true;)
  196.         if (xeof | ueof)
  197.         goto eof;
  198.       } else {
  199.         /* try to get both keywords */
  200.         tp = xkeyword;
  201.         for (;;) {
  202.         Igeteof_(xfp, xc, xeof=true;)
  203.         Igeteof_(ufp, uc, ueof=true;)
  204.         if (xeof | ueof)
  205.             goto eof;
  206.         if (xc != uc)
  207.             break;
  208.         switch (xc) {
  209.             default:
  210.             if (xkeyword+keylength <= tp)
  211.                 break;
  212.             *tp++ = xc;
  213.             continue;
  214.             case '\n': case KDELIM: case VDELIM:
  215.             break;
  216.         }
  217.         break;
  218.         }
  219.         if (
  220.         (xc==KDELIM || xc==VDELIM)  &&  (uc==KDELIM || uc==VDELIM)  &&
  221.         (*tp = xc,  (match1 = trymatch(xkeyword)) != Nomatch)
  222.         ) {
  223. #ifdef FCMPTEST
  224.           VOID printf("found common keyword %s\n",xkeyword);
  225. #endif
  226.           result = -1;
  227.           for (;;) {
  228.           if (xc != uc) {
  229.               xc = discardkeyval(xc, xfp);
  230.               uc = discardkeyval(uc, ufp);
  231.               if ((xeof = xc==EOF)  |  (ueof = uc==EOF))
  232.               goto eof;
  233.               eqkeyvals = false;
  234.               break;
  235.           }
  236.           switch (xc) {
  237.               default:
  238.               Igeteof_(xfp, xc, xeof=true;)
  239.               Igeteof_(ufp, uc, ueof=true;)
  240.               if (xeof | ueof)
  241.                   goto eof;
  242.               continue;
  243.  
  244.               case '\n': case KDELIM:
  245.               eqkeyvals = true;
  246.               break;
  247.           }
  248.           break;
  249.           }
  250.           if (xc != uc)
  251.           goto return1;
  252.           if (xc==KDELIM) {
  253.           /* Skip closing KDELIM.  */
  254.           Igeteof_(xfp, xc, xeof=true;)
  255.           Igeteof_(ufp, uc, ueof=true;)
  256.           if (xeof | ueof)
  257.               goto eof;
  258.           /* if the keyword is LOG, also skip the log message in xfp*/
  259.           if (match1==Log) {
  260.               /* first, compute the number of line feeds in log msg */
  261.               int lncnt;
  262.               size_t ls, ccnt;
  263.               sp = delta->log.string;
  264.               ls = delta->log.size;
  265.               if (ls<sizeof(ciklog)-1 || memcmp(sp,ciklog,sizeof(ciklog)-1)) {
  266.             /*
  267.             * This log message was inserted.  Skip its header.
  268.             * The number of newlines to skip is
  269.             * 1 + (C+1)*(1+L+1), where C is the number of newlines
  270.             * in the comment leader, and L is the number of
  271.             * newlines in the log string.
  272.             */
  273.             int c1 = 1;
  274.             for (ccnt=Comment.size; ccnt--; )
  275.                 c1 += Comment.string[ccnt] == '\n';
  276.             lncnt = 2*c1 + 1;
  277.             while (ls--) if (*sp++=='\n') lncnt += c1;
  278.             for (;;) {
  279.                 if (xc=='\n')
  280.                 if(--lncnt==0) break;
  281.                 Igeteof_(xfp, xc, goto returnresult;)
  282.             }
  283.             /* skip last comment leader */
  284.             /* Can't just skip another line here, because there may be */
  285.             /* additional characters on the line (after the Log....$)  */
  286.             ccnt = RCSversion<VERSION(5) ? Comment.size : leaderlen;
  287.             do {
  288.                 Igeteof_(xfp, xc, goto returnresult;)
  289.                 /*
  290.                  * Read to the end of the comment leader or '\n',
  291.                  * whatever comes first, because the leader's
  292.                  * trailing white space was probably stripped.
  293.                  */
  294.             } while (ccnt-- && (xc!='\n' || --c1));
  295.               }
  296.           }
  297.           } else {
  298.           /* both end in the same character, but not a KDELIM */
  299.           /* must compare string values.*/
  300. #ifdef FCMPTEST
  301.           VOID printf("non-terminated keywords %s, potentially different values\n",xkeyword);
  302. #endif
  303.           if (!eqkeyvals)
  304.               goto return1;
  305.           }
  306.         }
  307.       }
  308.       if (xc != uc)
  309.           goto return1;
  310.       if (xc == '\n')
  311.           leaderlen = 0;
  312.       else
  313.           leaderlen++;
  314.     }
  315.     }
  316.  
  317.   eof:
  318.     if (xeof==ueof)
  319.     goto returnresult;
  320.   return1:
  321.     result = 1;
  322.   returnresult:
  323.     Ifclose(ufp);
  324.     return result;
  325. }
  326.  
  327.  
  328.  
  329. #ifdef FCMPTEST
  330.  
  331. char const cmdid[] = "rcsfcmp";
  332.  
  333. main(argc, argv)
  334. int  argc; char  *argv[];
  335. /* first argument: comment leader; 2nd: log message, 3rd: expanded file,
  336.  * 4th: unexpanded file
  337.  */
  338. {       struct hshentry delta;
  339.  
  340.     Comment.string = argv[1];
  341.     Comment.size = strlen(argv[1]);
  342.     delta.log.string = argv[2];
  343.     delta.log.size = strlen(argv[2]);
  344.     if (rcsfcmp(Iopen(argv[3], FOPEN_R_WORK, (struct stat*)0), argv[4], &delta))
  345.                 VOID printf("files are the same\n");
  346.         else    VOID printf("files are different\n");
  347. }
  348. #endif
  349.