File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Copyright (c) 2007 D. Richard Hipp
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is free software; you can redistribute it and/or
dbda8d6ce9 2007-07-21       drh: ** modify it under the terms of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License version 2 as published by the Free Software Foundation.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is distributed in the hope that it will be useful,
dbda8d6ce9 2007-07-21       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
dbda8d6ce9 2007-07-21       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbda8d6ce9 2007-07-21       drh: ** General Public License for more details.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** You should have received a copy of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License along with this library; if not, write to the
dbda8d6ce9 2007-07-21       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
dbda8d6ce9 2007-07-21       drh: ** Boston, MA  02111-1307, USA.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Author contact information:
dbda8d6ce9 2007-07-21       drh: **   drh@hwaci.com
dbda8d6ce9 2007-07-21       drh: **   http://www.hwaci.com/drh/
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: *******************************************************************************
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This file contains code used to implement the "diff" command
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "diffcmd.h"
dbda8d6ce9 2007-07-21       drh: #include <assert.h>
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Shell-escape the given string.  Append the result to a blob.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void shell_escape(Blob *pBlob, const char *zIn){
dbda8d6ce9 2007-07-21       drh:   int n = blob_size(pBlob);
dbda8d6ce9 2007-07-21       drh:   int k = strlen(zIn);
c863ec1a98 2008-10-21       drh:   int i, c;
dbda8d6ce9 2007-07-21       drh:   char *z;
c863ec1a98 2008-10-21       drh:   for(i=0; (c = zIn[i])!=0; i++){
c863ec1a98 2008-10-21       drh:     if( isspace(c) || c=='"' || (c=='\\' && zIn[i+1]!=0) ){
c863ec1a98 2008-10-21       drh:       blob_appendf(pBlob, "\"%s\"", zIn);
c863ec1a98 2008-10-21       drh:       z = blob_buffer(pBlob);
c863ec1a98 2008-10-21       drh:       for(i=n+1; i<=n+k; i++){
c863ec1a98 2008-10-21       drh:         if( z[i]=='"' ) z[i] = '_';
c863ec1a98 2008-10-21       drh:       }
c863ec1a98 2008-10-21       drh:       return;
c863ec1a98 2008-10-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
c863ec1a98 2008-10-21       drh:   blob_append(pBlob, zIn, -1);
c82fb61775 2007-09-24       jnc: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
c863ec1a98 2008-10-21       drh: ** Run the fossil diff command separately for every file in the current
c863ec1a98 2008-10-21       drh: ** checkout that has changed.
dbda8d6ce9 2007-07-21       drh: */
c863ec1a98 2008-10-21       drh: static void diff_all(int internalDiff,  const char *zRevision){
c863ec1a98 2008-10-21       drh:   Stmt q;
dbda8d6ce9 2007-07-21       drh:   Blob cmd;
c863ec1a98 2008-10-21       drh:   int nCmdBase;
c863ec1a98 2008-10-21       drh:   int vid;
dbda8d6ce9 2007-07-21       drh: 
c863ec1a98 2008-10-21       drh:   vid = db_lget_int("checkout", 0);
c863ec1a98 2008-10-21       drh:   vfile_check_signature(vid);
dbda8d6ce9 2007-07-21       drh:   blob_zero(&cmd);
c863ec1a98 2008-10-21       drh:   shell_escape(&cmd, g.argv[0]);
c863ec1a98 2008-10-21       drh:   blob_append(&cmd, " diff ", -1);
c863ec1a98 2008-10-21       drh:   if( internalDiff ){
c863ec1a98 2008-10-21       drh:     blob_append(&cmd, "-i ", -1);
c863ec1a98 2008-10-21       drh:   }
c863ec1a98 2008-10-21       drh:   if( zRevision ){
c863ec1a98 2008-10-21       drh:     blob_append(&cmd, "-r ", -1);
c863ec1a98 2008-10-21       drh:     shell_escape(&cmd, zRevision);
c863ec1a98 2008-10-21       drh:     blob_append(&cmd, " ", 1);
c863ec1a98 2008-10-21       drh:   }
c863ec1a98 2008-10-21       drh:   nCmdBase = blob_size(&cmd);
c863ec1a98 2008-10-21       drh:   db_prepare(&q,
c863ec1a98 2008-10-21       drh:     "SELECT pathname, deleted, chnged, rid FROM vfile "
c863ec1a98 2008-10-21       drh:     "WHERE chnged OR deleted OR rid=0 ORDER BY 1"
c863ec1a98 2008-10-21       drh:   );
c863ec1a98 2008-10-21       drh: 
c863ec1a98 2008-10-21       drh:   while( db_step(&q)==SQLITE_ROW ){
c863ec1a98 2008-10-21       drh:     const char *zPathname = db_column_text(&q,0);
c863ec1a98 2008-10-21       drh:     int isDeleted = db_column_int(&q, 1);
c863ec1a98 2008-10-21       drh:     int isChnged = db_column_int(&q,2);
c863ec1a98 2008-10-21       drh:     int isNew = db_column_int(&q,3)==0;
c863ec1a98 2008-10-21       drh:     char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
c863ec1a98 2008-10-21       drh:     cmd.nUsed = nCmdBase;
c863ec1a98 2008-10-21       drh:     if( isDeleted ){
c863ec1a98 2008-10-21       drh:       printf("DELETED  %s\n", zPathname);
c863ec1a98 2008-10-21       drh:     }else if( access(zFullName, 0) ){
c863ec1a98 2008-10-21       drh:       printf("MISSING  %s\n", zPathname);
c863ec1a98 2008-10-21       drh:     }else if( isNew ){
c863ec1a98 2008-10-21       drh:       printf("ADDED    %s\n", zPathname);
c863ec1a98 2008-10-21       drh:     }else if( isDeleted ){
c863ec1a98 2008-10-21       drh:       printf("DELETED  %s\n", zPathname);
c863ec1a98 2008-10-21       drh:     }else if( isChnged==3 ){
c863ec1a98 2008-10-21       drh:       printf("ADDED_BY_MERGE %s\n", zPathname);
c863ec1a98 2008-10-21       drh:     }else{
85670cfcc8 2008-10-24       drh:       printf("Index: %s\n======================================="
85670cfcc8 2008-10-24       drh:              "============================\n",
85670cfcc8 2008-10-24       drh:              zPathname
85670cfcc8 2008-10-24       drh:       );
c863ec1a98 2008-10-21       drh:       shell_escape(&cmd, zFullName);
c863ec1a98 2008-10-21       drh:       printf("%s\n", blob_str(&cmd));
c863ec1a98 2008-10-21       drh:       fflush(stdout);
c863ec1a98 2008-10-21       drh:       system(blob_str(&cmd));
c863ec1a98 2008-10-21       drh:     }
c863ec1a98 2008-10-21       drh:     free(zFullName);
01ce2cf3dc 2007-09-24       jnc:   }
c863ec1a98 2008-10-21       drh:   db_finalize(&q);
01ce2cf3dc 2007-09-24       jnc: }
01ce2cf3dc 2007-09-24       jnc: 
01ce2cf3dc 2007-09-24       jnc: /*
01ce2cf3dc 2007-09-24       jnc: ** COMMAND: diff
01ce2cf3dc 2007-09-24       jnc: ** COMMAND: gdiff
01ce2cf3dc 2007-09-24       jnc: **
371dd6574c 2007-12-04       drh: ** Usage: %fossil diff|gdiff ?-i? ?-r REVISION? FILE...
01ce2cf3dc 2007-09-24       jnc: **
01ce2cf3dc 2007-09-24       jnc: ** Show the difference between the current version of a file (as it
01ce2cf3dc 2007-09-24       jnc: ** exists on disk) and that same file as it was checked out.
01ce2cf3dc 2007-09-24       jnc: **
01ce2cf3dc 2007-09-24       jnc: ** diff will show a textual diff while gdiff will attempt to run a
01ce2cf3dc 2007-09-24       jnc: ** graphical diff command that you have setup. If the choosen command
01ce2cf3dc 2007-09-24       jnc: ** is not yet configured, the internal textual diff command will be
01ce2cf3dc 2007-09-24       jnc: ** used.
01ce2cf3dc 2007-09-24       jnc: **
01ce2cf3dc 2007-09-24       jnc: ** If -i is supplied for either diff or gdiff, the internal textual
01ce2cf3dc 2007-09-24       jnc: ** diff command will be executed.
01ce2cf3dc 2007-09-24       jnc: **
01ce2cf3dc 2007-09-24       jnc: ** Here are a few external diff command settings, for example:
01ce2cf3dc 2007-09-24       jnc: **
371dd6574c 2007-12-04       drh: **   %fossil setting diff-command diff
01ce2cf3dc 2007-09-24       jnc: **
371dd6574c 2007-12-04       drh: **   %fossil setting gdiff-command tkdiff
371dd6574c 2007-12-04       drh: **   %fossil setting gdiff-command eskill22
371dd6574c 2007-12-04       drh: **   %fossil setting gdiff-command tortoisemerge
371dd6574c 2007-12-04       drh: **   %fossil setting gdiff-command meld
371dd6574c 2007-12-04       drh: **   %fossil setting gdiff-command xxdiff
371dd6574c 2007-12-04       drh: **   %fossil setting gdiff-command kdiff3
01ce2cf3dc 2007-09-24       jnc: */
01ce2cf3dc 2007-09-24       jnc: void diff_cmd(void){
85670cfcc8 2008-10-24       drh:   int isGDiff;               /* True for gdiff.  False for normal diff */
85670cfcc8 2008-10-24       drh:   const char *zFile;         /* Name of file to diff */
85670cfcc8 2008-10-24       drh:   const char *zRevision;     /* Version of file to diff against current */
85670cfcc8 2008-10-24       drh:   Blob cmd;                  /* The diff command-line for external diff */
85670cfcc8 2008-10-24       drh:   Blob fname;                /* */
574763bab9 2007-09-26       jnc:   Blob vname;
574763bab9 2007-09-26       jnc:   Blob record;
85670cfcc8 2008-10-24       drh:   int cnt=0;
85670cfcc8 2008-10-24       drh:   int internalDiff;          /* True to use the internal diff engine */
01ce2cf3dc 2007-09-24       jnc: 
85670cfcc8 2008-10-24       drh:   isGDiff = g.argv[1][0]=='g';
01ce2cf3dc 2007-09-24       jnc:   internalDiff = find_option("internal","i",0)!=0;
574763bab9 2007-09-26       jnc:   zRevision = find_option("revision", "r", 1);
574763bab9 2007-09-26       jnc:   verify_all_options();
c863ec1a98 2008-10-21       drh:   db_must_be_within_tree();
c82fb61775 2007-09-24       jnc: 
c863ec1a98 2008-10-21       drh:   if( !isGDiff && g.argc==2 ){
c863ec1a98 2008-10-21       drh:     diff_all(internalDiff, zRevision);
c863ec1a98 2008-10-21       drh:     return;
c863ec1a98 2008-10-21       drh:   }
c82fb61775 2007-09-24       jnc:   if( g.argc<3 ){
c82fb61775 2007-09-24       jnc:     usage("?OPTIONS? FILE");
c82fb61775 2007-09-24       jnc:   }
c82fb61775 2007-09-24       jnc: 
c82fb61775 2007-09-24       jnc:   if( internalDiff==0 ){
01ce2cf3dc 2007-09-24       jnc:     const char *zExternalCommand;
c863ec1a98 2008-10-21       drh:     if( !isGDiff ){
134e2aeccc 2007-09-28       drh:       zExternalCommand = db_get("diff-command", 0);
01ce2cf3dc 2007-09-24       jnc:     }else{
134e2aeccc 2007-09-28       drh:       zExternalCommand = db_get("gdiff-command", 0);
01ce2cf3dc 2007-09-24       jnc:     }
c82fb61775 2007-09-24       jnc:     if( zExternalCommand==0 ){
c82fb61775 2007-09-24       jnc:       internalDiff=1;
dbda8d6ce9 2007-07-21       drh:     }else{
129edda98e 2009-09-11       drh:       blob_zero(&cmd);
129edda98e 2009-09-11       drh:       shell_escape(&cmd, zExternalCommand);
129edda98e 2009-09-11       drh:       blob_append(&cmd, " ", 1);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   zFile = g.argv[g.argc-1];
2ecc407d9b 2008-07-23       drh:   file_tree_name(zFile, &fname, 1);
574763bab9 2007-09-26       jnc: 
574763bab9 2007-09-26       jnc:   blob_zero(&vname);
574763bab9 2007-09-26       jnc:   do{
574763bab9 2007-09-26       jnc:     blob_reset(&vname);
574763bab9 2007-09-26       jnc:     blob_appendf(&vname, "%s~%d", zFile, cnt++);
574763bab9 2007-09-26       jnc:   }while( access(blob_str(&vname),0)==0 );
dbda8d6ce9 2007-07-21       drh: 
574763bab9 2007-09-26       jnc:   if( zRevision==0 ){
574763bab9 2007-09-26       jnc:     int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B", &fname);
dbda8d6ce9 2007-07-21       drh:     if( rid==0 ){
85670cfcc8 2008-10-24       drh:       fossil_fatal("no history for file: %b", &fname);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     content_get(rid, &record);
574763bab9 2007-09-26       jnc:   }else{
c863ec1a98 2008-10-21       drh:     historical_version_of_file(zRevision, blob_str(&fname), &record);
574763bab9 2007-09-26       jnc:   }
c863ec1a98 2008-10-21       drh:   if( internalDiff ){
574763bab9 2007-09-26       jnc:     Blob out;
574763bab9 2007-09-26       jnc:     Blob current;
574763bab9 2007-09-26       jnc:     blob_zero(&current);
574763bab9 2007-09-26       jnc:     blob_read_from_file(&current, zFile);
574763bab9 2007-09-26       jnc:     blob_zero(&out);
57b2735ebd 2007-11-15       drh:     text_diff(&record, &current, &out, 5);
85670cfcc8 2008-10-24       drh:     printf("--- %s\n+++ %s\n", blob_str(&fname), blob_str(&fname));
574763bab9 2007-09-26       jnc:     printf("%s\n", blob_str(&out));
574763bab9 2007-09-26       jnc:     blob_reset(&current);
574763bab9 2007-09-26       jnc:     blob_reset(&out);
c82fb61775 2007-09-24       jnc:   }else{
dbda8d6ce9 2007-07-21       drh:     blob_write_to_file(&record, blob_str(&vname));
dbda8d6ce9 2007-07-21       drh:     blob_reset(&record);
dbda8d6ce9 2007-07-21       drh:     shell_escape(&cmd, blob_str(&vname));
dbda8d6ce9 2007-07-21       drh:     blob_appendf(&cmd, " ");
dbda8d6ce9 2007-07-21       drh:     shell_escape(&cmd, zFile);
aeaee1f385 2009-09-10       drh:     portable_system(blob_str(&cmd));
dbda8d6ce9 2007-07-21       drh:     unlink(blob_str(&vname));
dbda8d6ce9 2007-07-21       drh:     blob_reset(&vname);
dbda8d6ce9 2007-07-21       drh:     blob_reset(&cmd);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   blob_reset(&fname);
aeaee1f385 2009-09-10       drh: }
aeaee1f385 2009-09-10       drh: 
aeaee1f385 2009-09-10       drh: /*
aeaee1f385 2009-09-10       drh: ** This function implements a cross-platform "system()" interface.
aeaee1f385 2009-09-10       drh: */
aeaee1f385 2009-09-10       drh: void portable_system(char *zOrigCmd){
aeaee1f385 2009-09-10       drh: #ifdef __MINGW32__
aeaee1f385 2009-09-10       drh:   /* On windows, we have to put double-quotes around the entire command.
aeaee1f385 2009-09-10       drh:   ** Who knows why - this is just the way windows works.
aeaee1f385 2009-09-10       drh:   */
aeaee1f385 2009-09-10       drh:   char *zNewCmd = mprintf("\"%s\"", zOrigCmd);
aeaee1f385 2009-09-10       drh:   system(zNewCmd);
aeaee1f385 2009-09-10       drh:   free(zNewCmd);
aeaee1f385 2009-09-10       drh: #else
aeaee1f385 2009-09-10       drh:   /* On unix, evaluate the command directly.
aeaee1f385 2009-09-10       drh:   */
aeaee1f385 2009-09-10       drh:   system(zOrigCmd);
aeaee1f385 2009-09-10       drh: #endif
dbda8d6ce9 2007-07-21       drh: }