home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 …ember: Reference Library / Apple Developer Reference Library (December 1999) (Disk 1).iso / pc / technical documentation / develop / develop issue 28 / develop issue 28 code / merge tools / difference.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-08  |  10.8 KB  |  357 lines

  1. /* Difference utility for Eclectus integration utilities.
  2.      Copyright (C) 1992-1996 Eclectus (D. John Anderson, Alan B. Harper).
  3.  
  4. This file is part of the Eclectus integration utilities.
  5.  
  6. Eclectus integration utilities are free software; you can redistribute
  7. it and/or modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 1, or
  9. (at your option) any later version.
  10.  
  11. Eclectus integration utilities is distributed in the hope that it
  12. will be useful, but WITHOUT ANY WARRANTY; without even the implied
  13. warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. See the GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with the Eclectus integration utilities; see the file COPYING.
  18. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge,
  19. MA 02139, USA.    */
  20.  
  21. #include "diff.h"
  22. #include <stdlib.h>
  23. #include <string.h>
  24.  
  25. static int                    diffPathDepth;
  26. static int                    exitStatus = EXIT_SUCCESS;
  27. static int                    ignoreBinaryFiles;
  28. static int                    returnEXIT_SUCCESS;
  29. static unsigned int    hashValue;
  30. static const char     *programNamePtr;
  31.  
  32. void                        CommandLine (int argc,
  33.                                                          const char **argv,
  34.                                                          const char **pathOldNamePtrPtr,
  35.                                                          const char **pathNewNamePtrPtr);
  36. void                        CommandLineError (int errorMessage, const char *theString);
  37. void                        DiffPaths (const char *pathOldNamePtr, const char *pathNewNamePtr);
  38.     void                        PrintPathSuffix (char commandChar, const char *pathPtr);
  39. int __cdecl            main (int argc, const char **argv);
  40.  
  41. void
  42. CommandLine (int argc, const char **argv, const char **pathOldNamePtrPtr, const char **pathNewNamePtrPtr)
  43. /*
  44.  * Parses the command line.
  45.  */
  46. {
  47.     char                                    commandChar;
  48.     register const char  *commandStringPtr;
  49.     int                                     fileCount;
  50.  
  51.     fileCount = 0;
  52.  
  53.     programNamePtr = *argv++;
  54.     argc--;
  55.  
  56. /* Parse the commands and make sure they are legal */
  57.  
  58.     while (argc > 0) {
  59.         commandStringPtr = *argv++;
  60.         argc--;
  61.         if (*commandStringPtr != '-') {
  62.             if (fileCount >= 2)
  63.                 CommandLineError (TWO_FILES_ONLY, NULL);
  64.             if (FileType (commandStringPtr) == BAD_FILE_TYPE)
  65.                 ErrorWithStringArgument (CANT_OPEN_FILE, commandStringPtr);
  66.  
  67.             if (fileCount == 0)
  68.                 *pathOldNamePtrPtr = commandStringPtr;
  69.             else
  70.                 *pathNewNamePtrPtr = commandStringPtr;
  71.  
  72.             fileCount ++;
  73.         } else {
  74.             if (strlen (commandStringPtr) != 2)
  75.                 CommandLineError (UNEXPECTED_OPTION, commandStringPtr);
  76.             commandChar = *(commandStringPtr + 1);
  77.                 switch (commandChar) {
  78.                     case ('i'):
  79.                         ignoreBinaryFiles = TRUE;
  80.                         break;
  81.                     case ('y'):
  82.                         returnEXIT_SUCCESS = TRUE;
  83.                         break;
  84.                 #ifdef DF_DEBUG
  85.                     case ('X'):
  86.                         ECCheckFreedBlocks = 1;
  87.                         break;
  88.                     case ('x'):
  89.                         ECHeapCheckOn = 1;
  90.                         break;
  91.                 #endif
  92.                 default:
  93.                     CommandLineError (UNEXPECTED_OPTION, commandStringPtr);
  94.                     break;
  95.                 }
  96.         }
  97.     }
  98.     if (fileCount != 2)
  99.         CommandLineError (TWO_FILES_ONLY, NULL);
  100. }
  101.  
  102.     void
  103.     CommandLineError (int errorMessage, const char *theString)
  104.     /*
  105.      * Part of CommandLine.
  106.      */
  107.     {
  108.         fprintf (stderr, "# - ");
  109.         if (theString != NULL)
  110.             fprintf (stderr, ECMessagessArray [errorMessage], theString);
  111.         else
  112.             fprintf (stderr, ECMessagessArray [errorMessage], "");
  113.         fprintf (stderr, ".\n\n"
  114.                                          "### Difference version %s\n"
  115.                                          "#usage: %s SourcePath ModifiedPath > DifferenceScriptFile\n"
  116.                                          "#       -y Always return EXIT_SUCCESS\n"
  117.                                          "#       -i ignore binary files\n\n",
  118.                                          VERSION_STRING,
  119.                                           programNamePtr);
  120.         exit (EXIT_FAILURE);
  121.     }
  122.  
  123. void
  124. DiffPaths (const char *pathOldNamePtr, const char *pathNewNamePtr)
  125. {
  126.     register unsigned char *charPtr;
  127.     register int                        count;
  128.     char                                        differenceChar;
  129.     int                                         fileKind;
  130.     fileNameListPType             fileNameListPtr;
  131.     int                                            filesAreIdentical;
  132.     register unsigned char    hexDigit;
  133.     char                                     *nameSuffixPtr;
  134.     struct file_data                newFile;
  135.     int                                            nonASCIIChars;
  136.     struct file_data                oldFile;
  137.     char                                        pathNewName [FILENAME_MAX + 1];
  138.     int                                         pathNewPrefixLength;
  139.     char                                        pathOldName [FILENAME_MAX + 1];
  140.     int                                         pathOldPrefixLength;
  141.     int                                         suffixLengthPlusOne;
  142.     register unsigned char    theChar;
  143.     register int                        totalBytes;
  144.  
  145.     diffPathDepth++;
  146.     fileKind = FileType (pathNewNamePtr);
  147.     switch (fileKind) {
  148.         case (DIRECTORY_TYPE):
  149.             PrintPathSuffix ('d', pathNewNamePtr);
  150.             fileNameListPtr = ReadDirectory (pathNewNamePtr);
  151.             if (fileNameListPtr == NULL)
  152.                 Error (UNEXPECTED_IO_ERROR);
  153.             nameSuffixPtr = fileNameListPtr->names;
  154.  
  155.             pathNewPrefixLength = strlen (pathNewNamePtr);
  156.             (void) memcpy (pathNewName, pathNewNamePtr, pathNewPrefixLength);
  157.             if (pathNewName [pathNewPrefixLength-1] != DIRECTORY_CHAR) {
  158.                 pathNewName [pathNewPrefixLength] = DIRECTORY_CHAR;
  159.                 pathNewPrefixLength ++;
  160.             }
  161.             pathOldPrefixLength = strlen (pathOldNamePtr);
  162.             (void) memcpy (pathOldName, pathOldNamePtr, pathOldPrefixLength);
  163.             if (pathOldName [pathOldPrefixLength-1] != DIRECTORY_CHAR) {
  164.                 pathOldName [pathOldPrefixLength] = DIRECTORY_CHAR;
  165.                 pathOldPrefixLength ++;
  166.             }
  167.  
  168.             while (*nameSuffixPtr != '\0') {
  169.                 suffixLengthPlusOne = strlen (nameSuffixPtr) + 1;
  170.                 if (pathNewPrefixLength + suffixLengthPlusOne > FILENAME_MAX) {
  171.                     fprintf (stderr, "%s%s\n", pathNewNamePtr, nameSuffixPtr);
  172.                     Error (PATH_TOO_LONG);
  173.                 }
  174.                 if (pathOldPrefixLength + suffixLengthPlusOne > FILENAME_MAX) {
  175.                     fprintf (stderr, "%s%s\n", pathOldNamePtr, nameSuffixPtr);
  176.                     Error (PATH_TOO_LONG);
  177.                 }
  178.                 if (!IgnoreFile (nameSuffixPtr)) {
  179.                     (void) memcpy (pathNewName + pathNewPrefixLength, nameSuffixPtr, suffixLengthPlusOne);
  180.                     (void) memcpy (pathOldName + pathOldPrefixLength, nameSuffixPtr, suffixLengthPlusOne);
  181.                     DiffPaths (pathOldName, pathNewName);
  182.                 }
  183.                 nameSuffixPtr += suffixLengthPlusOne;
  184.             }
  185.             free (fileNameListPtr);
  186.             printf ("u\n");
  187.             break;
  188.         case (BINARY_TYPE):
  189.             if (!ignoreBinaryFiles) {
  190.                 PrintPathSuffix ('b', pathNewNamePtr);
  191.                 bzero (&newFile, sizeof (struct file_data));
  192.                 bzero (&oldFile, sizeof (struct file_data));
  193.                 newFile.namePtr = pathNewNamePtr;
  194.                 newFile.desc = fopen (pathNewNamePtr, "rb");
  195.                 if (newFile.desc == NULL)
  196.                     ErrorWithStringArgument (CANT_OPEN_FILE, pathNewNamePtr);
  197.                 oldFile.namePtr = pathOldNamePtr;
  198.                 oldFile.desc = fopen (pathOldNamePtr, "rb");
  199.                 slurp (&newFile);
  200.                 slurp (&oldFile);
  201.                 totalBytes = newFile.buffered_chars;
  202.                 if (newFile.missing_newline)
  203.                     totalBytes --;
  204.                 filesAreIdentical = FALSE;
  205.                 if (newFile.buffered_chars == oldFile.buffered_chars &&
  206.                       newFile.missing_newline == oldFile.missing_newline)
  207.                     filesAreIdentical = memcmp (newFile.buffer, oldFile.buffer, totalBytes) == 0;
  208.                 charPtr = (unsigned char *) newFile.buffer;
  209.                 if (filesAreIdentical) {
  210.                     differenceChar = ' ';
  211.                     count = totalBytes;
  212.                     while (count-- > 0)
  213.                         hashValue = HASH (hashValue, *charPtr++);
  214.                 } else {
  215.                     differenceChar = '*';
  216.                     exitStatus = EXIT_FAILURE;
  217.                     printf ("H%d\n", (totalBytes + (HEX_LINE_LENGTH -1)) / HEX_LINE_LENGTH);
  218.                     count = 0;
  219.                     while (count < totalBytes) {
  220.                         theChar = *charPtr++;
  221.                         hashValue = HASH (hashValue, theChar);
  222.                         hexDigit = (theChar >> 4) & 0X0F;
  223.                         if (hexDigit < 10)
  224.                             hexDigit += '0';
  225.                         else
  226.                             hexDigit += 'A' - 10;
  227.                         putchar (hexDigit);
  228.                         hexDigit = theChar & 0X0F;
  229.                         if (hexDigit <= 9)
  230.                             hexDigit += '0';
  231.                         else
  232.                             hexDigit += 'A' - 10;
  233.                         putchar (hexDigit);
  234.                         count ++;
  235.                         if (count % HEX_LINE_LENGTH == 0)
  236.                             putchar ('\n');
  237.                     }
  238.                     if (count % HEX_LINE_LENGTH != 0)
  239.                         putchar ('\n');
  240.                 }
  241.                 printf ("h%d\n", hashValue);
  242.                 hashValue = 0;
  243.                 fprintf (stderr, "                BINARY FILE %c%s\n", differenceChar, pathNewNamePtr);
  244.                 freeFile (&oldFile);
  245.                 freeFile (&newFile);
  246.             }
  247.             break;
  248.         case (TEXT_TYPE):
  249.             PrintPathSuffix ('f', pathNewNamePtr);
  250.             bzero (&newFile, sizeof (struct file_data));
  251.             bzero (&oldFile, sizeof (struct file_data));
  252.             newFile.namePtr = pathNewNamePtr;
  253.             newFile.desc = fopen (pathNewNamePtr, "r");
  254.             if (newFile.desc == NULL)
  255.                 ErrorWithStringArgument (CANT_OPEN_FILE, pathNewNamePtr);
  256.             oldFile.namePtr = pathOldNamePtr;
  257.             oldFile.desc = fopen (pathOldNamePtr, "r");
  258.  
  259.             diff_2_files (&oldFile, &newFile);
  260.             differenceChar = ' ';
  261.             filesAreIdentical = newFile.scriptPtr == NULL && (oldFile.buffered_lines == newFile.buffered_lines);
  262.             if (!filesAreIdentical) {
  263.                 differenceChar = '*';
  264.                 exitStatus = EXIT_FAILURE;
  265.             }
  266.             print_rcs_script (&oldFile, &newFile);
  267.             /*
  268.              * Print the hash for newFile.  We use a known value for '\n' since it varies between machines.
  269.              */
  270.             charPtr = (unsigned char *) newFile.buffer;
  271.             count = newFile.buffered_chars;
  272.             if (newFile.missing_newline)
  273.                 count --;
  274.             nonASCIIChars = 0;
  275.             while (count > 0) {
  276.                 theChar = *charPtr++;
  277.                 if (theChar == '\n')
  278.                     theChar = 13;
  279.                 hashValue = HASH (hashValue, theChar);
  280.                 if ((unsigned char) theChar > 127)
  281.                     nonASCIIChars++;
  282.                 count --;
  283.             }
  284.             printf ("h%d\n", hashValue);
  285.             hashValue = 0;
  286.             if (nonASCIIChars == 0)
  287.                 fprintf (stderr, "                            ");
  288.             else
  289.                 fprintf (stderr, "%6d NON-ASCII CHARACTERS ", nonASCIIChars);
  290.             fprintf (stderr, "%c%s\n", differenceChar, pathNewNamePtr);
  291.             freeFile (&oldFile);
  292.             freeFile (&newFile);
  293.             break;
  294.     }
  295.     diffPathDepth--;
  296. }
  297.  
  298.     void
  299.     PrintPathSuffix (char commandChar, const char *pathPtr)
  300.     /*
  301.      * Prints the command character appended by the suffix of pathPtr.  
  302.      */
  303.     {
  304.         const char *suffixPtr;
  305.  
  306.         if (diffPathDepth > 1) {
  307.             suffixPtr = strrchr (pathPtr, DIRECTORY_CHAR);
  308.             if (suffixPtr != NULL)
  309.                 suffixPtr ++;
  310.             else
  311.                 suffixPtr = pathPtr;
  312.             printf ("%c%s\n", commandChar, suffixPtr);
  313.         }
  314.     }
  315.  
  316. int
  317. __cdecl main (int argc, const char **argv)
  318. {
  319.     #ifdef DF_DEBUG
  320.         ECUns32        allocatedBytes;
  321.     #endif
  322.     const char *pathOldNamePtr;
  323.     const char *pathNewNamePtr;
  324.  
  325.     hashValue = 0;
  326.     CommandLine (argc, argv, &pathOldNamePtr, &pathNewNamePtr);
  327.     printf ("%s# Version %s\n# Difference %s %s\n",
  328.                     DIFFERENCE_SCRIPT_START_STRING,
  329.                     VERSION_STRING,
  330.                     pathOldNamePtr,
  331.                     pathNewNamePtr);
  332.     DiffPaths (pathOldNamePtr, pathNewNamePtr);
  333.     printf ("h%d\n", hashValue);
  334.     hashValue = 0;
  335.  
  336.     #ifdef DF_DEBUG
  337.         allocatedBytes = ECDebugPrintMemoryUsage (stderr);
  338.         if (allocatedBytes != 0) {
  339.             fprintf (stderr, "\n\n"
  340.                                              "MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!\n"
  341.                                              "MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!\n"
  342.                                              "MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!\n"
  343.                                              "MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!\n"
  344.                                              "MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!  MEMORY LEAK!\n"
  345.                                              "\n\n");
  346.         }
  347.     #endif
  348.     if (exitStatus == EXIT_SUCCESS)
  349.         fprintf (stderr, "No difference between file(s).\n");
  350.     else
  351.         fprintf (stderr, "File(s) marked \"*\" differ.\n");
  352.     if (returnEXIT_SUCCESS)
  353.         exitStatus = EXIT_SUCCESS;
  354.     return (exitStatus);
  355. }
  356.  
  357.