Logo Search packages:      
Sourcecode: fhist version File versions

diff.c

/*
 *    fhist - file history and comparison tools
 *    Copyright (C) 1991-1994, 1998-2000, 2002 Peter Miller;
 *    All rights reserved.
 *
 *    Derived from a work
 *    Copyright (C) 1990 David I. Bell.
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 *
 * MANIFEST: functions to compare different versions of a file
 */

#include <ac/errno.h>
#include <ac/stdio.h>
#include <ac/stdlib.h>
#include <ac/string.h>
#include <ac/unistd.h>

#include <cmalloc.h>
#include <compare.h>
#include <diff.h>
#include <error.h>
#include <error_intl.h>
#include <extract.h>
#include <fcheck.h>
#include <fhist.h>
#include <fileio.h>
#include <modlin.h>
#include <str.h>
#include <subroutine.h>


/*
 * Compare two different versions of a module.
 * Count specifies how many edit numbers were supplied to the command.
 * If zero, then we compare inputname to the latest edit.  If one, then
 * we compare inputname to the specified edit number.  If two, then we
 * compare the specified edit numbers.  If matchblab is 1, then we
 * output a message even if the files are identical.
 */
void
diffhistory(char *inputname, char *outputname, char *editname1, char *editname2,
      int matchblab)
{
      long        edit1;      /* first edit number */
      long        edit2;      /* second edit number */
      char        *temp1;
      char        *temp2;     /* temporary file names being compared */
      int         pid;  /* process id */
      short       savedforceflag; /* saved force flag */
      string_ty   *namebuf1; /* first temporary name */
      string_ty   *namebuf2; /* second temporary name */
      string_ty   *numbuf; /* buffer for number string */
      FILE        *fp;

      fc.maxchanges = INFINITY;
      fc.fileAmodify = sc.modifylines;
      fc.fileBmodify = sc.modifylines;
      pid = getpid();
      temp1 = getenv("TMPDIR");
      temp2 = PATH_STR;
      if ((temp1 == NULL) || (*temp1 == '\0'))
      {
            temp1 = "";
            temp2 = temp1;
      }
      fp = openhistoryfile(OHF_READ);
      if (editname1 == NULL)
      {
            /* compare with latest version */
            fclose_and_check(fp, sc.historyname);
            if (fc.verbosity > VERBOSE_DEFAULT)
                  error_raw("[Comparing files \"%s\" and \"%s\"]",
                        sc.sourcename, inputname);
            fc.fileAskip = 1;
            fcomp(sc.sourcename, inputname);
            if (fc.whatflag)
                  dumpwhat(outputname);
            else if (matchblab || fc.inserts || fc.deletes)
                  dumpnormal(outputname);
            return;
      }
      namebuf1 = str_format("%s%sT$1_%d", temp1, temp2, pid);
      namebuf2 = str_format("%s%sT$2_%d", temp1, temp2, pid);

      /*
       * Here when we have to retrieve a previous version.
       */
      edit2 = 0;
      temp1 = NULL;
      temp2 = NULL;
      savedforceflag = sc.forcewriteflag;
      sc.forcewriteflag = 1;
      edit1 = findeditnumber(fp, editname1);
      if (edit1 != sc.lastedit)
            temp1 = namebuf1->str_text;
      if (editname2)
      {
            edit2 = findeditnumber(fp, editname2);
            if (edit2 != sc.lastedit)
                  temp2 = namebuf2->str_text;
      }
      fclose_and_check(fp, sc.historyname);
      if (temp1)
      {
            numbuf = str_format("%ld", edit1);
            extracthistory(numbuf->str_text, temp1, VERBOSE_NONE);
            str_free(numbuf);
      }
      else
            fc.fileAskip = 1;

      if (editname2 == NULL)
      {
            sc.forcewriteflag = savedforceflag;
            fcomp(temp1 ? temp1 : sc.sourcename, inputname);
            if (temp1)
            {
                  if (fc.verbosity > VERBOSE_DEFAULT)
                        error_raw("[Deleting temporary file \"%s\"]", temp1);
                  unlink(temp1);
            }
            if (fc.whatflag)
                  dumpwhat(outputname);
            else if (matchblab || fc.inserts || fc.deletes)
                  dumpnormal(outputname);
            str_free(namebuf1);
            str_free(namebuf2);
            return;
      }

      /*
       * Here if we have to compare against another edit
       */
      if (temp2)
      {
            numbuf = str_format("%ld", edit2);
            extracthistory(numbuf->str_text, temp2, VERBOSE_NONE);
            str_free(numbuf);
      }
      else
            fc.fileBskip = 1;

      sc.forcewriteflag = savedforceflag;
      fcomp(temp1 ? temp1 : sc.sourcename, temp2 ? temp2 : sc.sourcename);
      if (fc.verbosity > VERBOSE_DEFAULT)
      {
            if (temp1 && temp2)
                  error_raw("[Deleting temporary files \"%s\" and \"%s\"]", temp1, temp2);
            else if (temp1 || temp2)
                  error_raw("[Deleting temporary file \"%s\"]", temp1 ? temp1 : temp2);
      }
      if (temp1)
            unlink(temp1);
      if (temp2)
            unlink(temp2);
      if (fc.whatflag)
            dumpwhat(outputname);
      else if (matchblab || fc.inserts || fc.deletes)
            dumpnormal(outputname);
      str_free(namebuf1);
      str_free(namebuf2);
}


/*
 * Routine to do a quick comparison of two files.
 * Returns nonzero if the two files are different.
 *
 * The history (.e) file is binary, because we need to seek in it.
 * The source (.s) file is text, because we don't need to seek in it.
 * The input files are text, by definition.
 * The output files are text, by definition.
 */

static int
quickcomp(char *nameA, char *nameB, long skipA)
{
      FILE  *fpA;       /* first file */
      FILE  *fpB;       /* second file */
      char  *cp;        /* current temporary line */
      char  *cpA;       /* current line for file A */
      char  *cpB;       /* current line for file B */
      long  linenumber; /* current line number */
      long  cplen;            /* length of current temporary line */
      long  linelenA;   /* length of first file line */
      long  linelenB;   /* length of second file line */
      int   bin_a, bin_b;

      fpA = fopen_and_check(nameA, "r");
      fpB = fopen_and_check(nameB, "r");
      if (fc.verbosity > VERBOSE_DEFAULT)
            error_raw("[Comparing files \"%s\" and \"%s\"]", nameA, nameB);
      cplen = 132;
      cp = cm_alloc_and_check(cplen + 1);
      if (skipA > 0)
            skipf(fpA, skipA, nameA);
      linenumber = 0;
      bin_a = 0;
      bin_b = 0;
      for (;;)
      {
            cpA = readlinef(fpA, &linelenA, 0, nameA, &bin_a);
            if (cpA == NULL)
            {
                  cpB = readlinef(fpB, &linelenB, 0, nameB, &bin_b);
                  break;
            }
            if (linelenA > cplen)
            {
                  cplen = linelenA;
                  cp = cm_realloc_and_check(cp, cplen + 1);
            }
            strcpy(cp, cpA);
            cpA = cp;
            cpB = readlinef(fpB, &linelenB, 0, nameB, &bin_b);
            if (cpB == NULL)
                  break;
            if (++linenumber <= sc.modifylines)
            {
                  cpA = modifyline(cpA, &linelenA, (INFO *) NULL);
                  cpB = modifyline(cpB, &linelenB, (INFO *) NULL);
            }
            if ((linelenA != linelenB) || strcmp(cpA, cpB))
                  break;
      }
      if (bin_a)
            binary_warning(nameA);
      if (bin_b)
            binary_warning(nameB);
      fclose_and_check(fpA, nameA);
      fclose_and_check(fpB, nameB);
      cm_free(cp);
      return (cpA || cpB);
}


/*
 * See if a file is up to date, and if so, then delete it.
 * This is useful when cleaning up a directory.
 */

void
cleanhistory(char *inputname)
{
      FILE  *fp;

      fp = openhistoryfile(OHF_READ);
      fclose_and_check(fp, sc.historyname);
      if (access(inputname, 0) && (errno = ENOENT))
      {
            if (fc.verbosity > VERBOSE_DEFAULT)
            {
                  sub_context_ty    *scp;

                  scp = sub_context_new();
                  sub_var_set_charstar(scp, "File_Name", inputname);
                  sub_var_set_charstar(scp, "Module", sc.modulename);
                  error_intl
                  (
                        scp,
            i18n("file \"$filename\" does not exist for module \"$module\"")
                  );
                  sub_context_delete(scp);
            }
            return;
      }
      if (quickcomp(sc.sourcename, inputname, 1L))
      {
            if (fc.verbosity > VERBOSE_DEFAULT)
            {
                  sub_context_ty    *scp;

                  scp = sub_context_new();
                  sub_var_set_charstar(scp, "File_Name", inputname);
                  sub_var_set_charstar(scp, "Module", sc.modulename);
                  error_intl
                  (
                        scp,
i18n("file \"$filename\" differs from latest edit of module \"$module\"")
                  );
            }
            return;
      }
      if (unlink(inputname))
      {
            sub_context_ty    *scp;

            scp = sub_context_new();
            sub_errno_set(scp);
            sub_var_set_charstar(scp, "File_Name", inputname);
            fatal_intl(scp, i18n("unlink \"$filename\": $errno"));
            /* NOTREACHED */
            sub_context_delete(scp);
      }
      if (fc.verbosity)
      {
            sub_context_ty    *scp;

            scp = sub_context_new();
            sub_var_set_charstar(scp, "File_Name", inputname);
            error_intl
            (
                  scp,
                  i18n("deleted up to date file \"$filename\"")
            );
      }
}


/*
 * Check to see if a file is up to date, and report it if not.
 */
void
checkhistory(char *inputname)
{
      FILE  *fp;

      fp = openhistoryfile(OHF_READ);
      fclose_and_check(fp, sc.historyname);
      if (access(inputname, 0) && (errno == ENOENT))
      {
            if (fc.verbosity > VERBOSE_DEFAULT)
            {
                  sub_context_ty    *scp;

                  scp = sub_context_new();
                  sub_var_set_charstar(scp, "File_Name", inputname);
                  sub_var_set_charstar(scp, "Module", sc.modulename);
                  error_intl
                  (
                        scp,
            i18n("file \"$filename\" does not exist for module \"$module\"")
                  );
                  sub_context_delete(scp);
            }
            return;
      }
      if (quickcomp(sc.sourcename, inputname, 1L))
      {
            if (fc.quickflag)
                  printf("%s\n", sc.modulename);
            else
            {
                  sub_context_ty    *scp;
                  string_ty   *s;

                  scp = sub_context_new();
                  sub_var_set_charstar(scp, "File_Name", inputname);
                  sub_var_set_charstar(scp, "Module", sc.modulename);
                  s =
                        subst_intl
                        (
                              scp,
       i18n("file \"$filename\" differs from latest edit of module \"$module\"")
                        );
                  sub_context_delete(scp);
                  printf("%s\n", s->str_text);
                  str_free(s);
            }
            return;
      }
      if (fc.verbosity > VERBOSE_DEFAULT)
            error_raw("[File \"%s\" is up to date]", inputname);
}


/*
 * Compare a file to the newest version of a module, but output nothing.
 * Whether or not there are any differences is returned in the variables
 * inserts and deletes.  The edit list is built so that it can be
 * immediately used to perform an update.
 */
void
comphistory(char *inputname)
{
      FILE  *fp;

      fp = openhistoryfile(OHF_READ);
      fclose_and_check(fp, sc.historyname);
      fc.maxchanges = INFINITY;
      fc.fileAmodify = sc.modifylines;
      fc.fileBmodify = sc.modifylines;
      fc.fileAskip = 1;
      if (fc.verbosity > VERBOSE_DEFAULT)
            error_raw("[Comparing files \"%s\" and \"%s\"]",
                  sc.sourcename, inputname);
      fcomp(sc.sourcename, inputname);
}

Generated by  Doxygen 1.6.0   Back to index