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); 32b480faa3 2008-10-24 drh: int i, c; dbda8d6ce9 2007-07-21 drh: char *z; 32b480faa3 2008-10-24 drh: for(i=0; (c = zIn[i])!=0; i++){ 32b480faa3 2008-10-24 drh: if( isspace(c) || c=='"' || (c=='\\' && zIn[i+1]!=0) ){ 32b480faa3 2008-10-24 drh: blob_appendf(pBlob, "\"%s\"", zIn); 32b480faa3 2008-10-24 drh: z = blob_buffer(pBlob); 32b480faa3 2008-10-24 drh: for(i=n+1; i<=n+k; i++){ 32b480faa3 2008-10-24 drh: if( z[i]=='"' ) z[i] = '_'; 32b480faa3 2008-10-24 drh: } 32b480faa3 2008-10-24 drh: return; 32b480faa3 2008-10-24 drh: } dbda8d6ce9 2007-07-21 drh: } 32b480faa3 2008-10-24 drh: blob_append(pBlob, zIn, -1); 32b480faa3 2008-10-24 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* 32b480faa3 2008-10-24 drh: ** Run the fossil diff command separately for every file in the current 32b480faa3 2008-10-24 drh: ** checkout that has changed. dbda8d6ce9 2007-07-21 drh: */ 32b480faa3 2008-10-24 drh: static void diff_all(int internalDiff, const char *zRevision){ 32b480faa3 2008-10-24 drh: Stmt q; dbda8d6ce9 2007-07-21 drh: Blob cmd; 32b480faa3 2008-10-24 drh: int nCmdBase; 32b480faa3 2008-10-24 drh: int vid; dbda8d6ce9 2007-07-21 drh: 32b480faa3 2008-10-24 drh: vid = db_lget_int("checkout", 0); 32b480faa3 2008-10-24 drh: vfile_check_signature(vid); dbda8d6ce9 2007-07-21 drh: blob_zero(&cmd); 32b480faa3 2008-10-24 drh: shell_escape(&cmd, g.argv[0]); 32b480faa3 2008-10-24 drh: blob_append(&cmd, " diff ", -1); 32b480faa3 2008-10-24 drh: if( internalDiff ){ 32b480faa3 2008-10-24 drh: blob_append(&cmd, "-i ", -1); 32b480faa3 2008-10-24 drh: } 32b480faa3 2008-10-24 drh: if( zRevision ){ 32b480faa3 2008-10-24 drh: blob_append(&cmd, "-r ", -1); 32b480faa3 2008-10-24 drh: shell_escape(&cmd, zRevision); 32b480faa3 2008-10-24 drh: blob_append(&cmd, " ", 1); 32b480faa3 2008-10-24 drh: } 32b480faa3 2008-10-24 drh: nCmdBase = blob_size(&cmd); 32b480faa3 2008-10-24 drh: db_prepare(&q, 32b480faa3 2008-10-24 drh: "SELECT pathname, deleted, chnged, rid FROM vfile " 32b480faa3 2008-10-24 drh: "WHERE chnged OR deleted OR rid=0 ORDER BY 1" 32b480faa3 2008-10-24 drh: ); 32b480faa3 2008-10-24 drh: 32b480faa3 2008-10-24 drh: while( db_step(&q)==SQLITE_ROW ){ 32b480faa3 2008-10-24 drh: const char *zPathname = db_column_text(&q,0); 32b480faa3 2008-10-24 drh: int isDeleted = db_column_int(&q, 1); 32b480faa3 2008-10-24 drh: int isChnged = db_column_int(&q,2); 32b480faa3 2008-10-24 drh: int isNew = db_column_int(&q,3)==0; 32b480faa3 2008-10-24 drh: char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); 32b480faa3 2008-10-24 drh: cmd.nUsed = nCmdBase; 32b480faa3 2008-10-24 drh: if( isDeleted ){ 32b480faa3 2008-10-24 drh: printf("DELETED %s\n", zPathname); 32b480faa3 2008-10-24 drh: }else if( access(zFullName, 0) ){ 32b480faa3 2008-10-24 drh: printf("MISSING %s\n", zPathname); 32b480faa3 2008-10-24 drh: }else if( isNew ){ 32b480faa3 2008-10-24 drh: printf("ADDED %s\n", zPathname); 32b480faa3 2008-10-24 drh: }else if( isDeleted ){ 32b480faa3 2008-10-24 drh: printf("DELETED %s\n", zPathname); 32b480faa3 2008-10-24 drh: }else if( isChnged==3 ){ 32b480faa3 2008-10-24 drh: printf("ADDED_BY_MERGE %s\n", zPathname); 32b480faa3 2008-10-24 drh: }else{ 32b480faa3 2008-10-24 drh: shell_escape(&cmd, zFullName); 32b480faa3 2008-10-24 drh: printf("%s\n", blob_str(&cmd)); 32b480faa3 2008-10-24 drh: fflush(stdout); 32b480faa3 2008-10-24 drh: system(blob_str(&cmd)); 32b480faa3 2008-10-24 drh: } 32b480faa3 2008-10-24 drh: free(zFullName); c82fb61775 2007-09-24 jnc: } 32b480faa3 2008-10-24 drh: db_finalize(&q); c82fb61775 2007-09-24 jnc: } c82fb61775 2007-09-24 jnc: c82fb61775 2007-09-24 jnc: /* c82fb61775 2007-09-24 jnc: ** COMMAND: diff 01ce2cf3dc 2007-09-24 jnc: ** COMMAND: gdiff c82fb61775 2007-09-24 jnc: ** 371dd6574c 2007-12-04 drh: ** Usage: %fossil diff|gdiff ?-i? ?-r REVISION? FILE... c82fb61775 2007-09-24 jnc: ** c82fb61775 2007-09-24 jnc: ** Show the difference between the current version of a file (as it c82fb61775 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. c82fb61775 2007-09-24 jnc: ** c82fb61775 2007-09-24 jnc: ** Here are a few external diff command settings, for example: c82fb61775 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 c82fb61775 2007-09-24 jnc: */ c82fb61775 2007-09-24 jnc: void diff_cmd(void){ 32b480faa3 2008-10-24 drh: int isGDiff = g.argv[1][0]=='g'; 574763bab9 2007-09-26 jnc: const char *zFile, *zRevision; c82fb61775 2007-09-24 jnc: Blob cmd; c82fb61775 2007-09-24 jnc: Blob fname; 574763bab9 2007-09-26 jnc: Blob vname; 574763bab9 2007-09-26 jnc: Blob record; 574763bab9 2007-09-26 jnc: int cnt=0,internalDiff; 01ce2cf3dc 2007-09-24 jnc: 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(); 32b480faa3 2008-10-24 drh: db_must_be_within_tree(); c82fb61775 2007-09-24 jnc: 32b480faa3 2008-10-24 drh: if( !isGDiff && g.argc==2 ){ 32b480faa3 2008-10-24 drh: diff_all(internalDiff, zRevision); 32b480faa3 2008-10-24 drh: return; 32b480faa3 2008-10-24 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; 32b480faa3 2008-10-24 drh: if( !isGDiff ){ 134e2aeccc 2007-09-28 drh: zExternalCommand = db_get("diff-command", 0); dbda8d6ce9 2007-07-21 drh: }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: } 01ce2cf3dc 2007-09-24 jnc: blob_zero(&cmd); 01ce2cf3dc 2007-09-24 jnc: blob_appendf(&cmd, "%s ", zExternalCommand); 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 ){ dbda8d6ce9 2007-07-21 drh: fossil_panic("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{ 32b480faa3 2008-10-24 drh: historical_version_of_file(zRevision, blob_str(&fname), &record); 574763bab9 2007-09-26 jnc: } 32b480faa3 2008-10-24 drh: if( internalDiff ){ 574763bab9 2007-09-26 jnc: Blob out; 574763bab9 2007-09-26 jnc: Blob current; 574763bab9 2007-09-26 jnc: blob_zero(¤t); 574763bab9 2007-09-26 jnc: blob_read_from_file(¤t, zFile); 574763bab9 2007-09-26 jnc: blob_zero(&out); 57b2735ebd 2007-11-15 drh: text_diff(&record, ¤t, &out, 5); 574763bab9 2007-09-26 jnc: printf("%s\n", blob_str(&out)); 574763bab9 2007-09-26 jnc: blob_reset(¤t); 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); dbda8d6ce9 2007-07-21 drh: 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); dbda8d6ce9 2007-07-21 drh: }