|
1
|
/* |
|
2
|
** Copyright (c) 2007 D. Richard Hipp |
|
3
|
** |
|
4
|
** This program is free software; you can redistribute it and/or |
|
5
|
** modify it under the terms of the Simplified BSD License (also |
|
6
|
** known as the "2-Clause License" or "FreeBSD License".) |
|
7
|
|
|
8
|
** This program is distributed in the hope that it will be useful, |
|
9
|
** but without any warranty; without even the implied warranty of |
|
10
|
** merchantability or fitness for a particular purpose. |
|
11
|
** |
|
12
|
** Author contact information: |
|
13
|
** [email protected] |
|
14
|
** http://www.hwaci.com/drh/ |
|
15
|
** |
|
16
|
******************************************************************************* |
|
17
|
** |
|
18
|
** This file contains code used to implement the "diff" command |
|
19
|
*/ |
|
20
|
#include "config.h" |
|
21
|
#include "diffcmd.h" |
|
22
|
#include <assert.h> |
|
23
|
|
|
24
|
/* includes needed to catch interrupts */ |
|
25
|
#ifdef _WIN32 |
|
26
|
# include <windows.h> |
|
27
|
#else |
|
28
|
# include <signal.h> |
|
29
|
#endif |
|
30
|
|
|
31
|
/* |
|
32
|
** Use the right null device for the platform. |
|
33
|
*/ |
|
34
|
#if defined(_WIN32) |
|
35
|
# define NULL_DEVICE "NUL" |
|
36
|
#else |
|
37
|
# define NULL_DEVICE "/dev/null" |
|
38
|
#endif |
|
39
|
|
|
40
|
/* |
|
41
|
** Used when the name for the diff is unknown. |
|
42
|
*/ |
|
43
|
#define DIFF_NO_NAME "(unknown)" |
|
44
|
|
|
45
|
/* |
|
46
|
** Use the "exec-rel-paths" setting and the --exec-abs-paths and |
|
47
|
** --exec-rel-paths command line options to determine whether |
|
48
|
** certain external commands are executed using relative paths. |
|
49
|
*/ |
|
50
|
static int determine_exec_relative_option(int force){ |
|
51
|
static int relativePaths = -1; |
|
52
|
if( force || relativePaths==-1 ){ |
|
53
|
int relPathOption = find_option("exec-rel-paths", 0, 0)!=0; |
|
54
|
int absPathOption = find_option("exec-abs-paths", 0, 0)!=0; |
|
55
|
#if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) |
|
56
|
relativePaths = db_get_boolean("exec-rel-paths", 1); |
|
57
|
#else |
|
58
|
relativePaths = db_get_boolean("exec-rel-paths", 0); |
|
59
|
#endif |
|
60
|
if( relPathOption ){ relativePaths = 1; } |
|
61
|
if( absPathOption ){ relativePaths = 0; } |
|
62
|
} |
|
63
|
return relativePaths; |
|
64
|
} |
|
65
|
|
|
66
|
#if INTERFACE |
|
67
|
/* |
|
68
|
** An array of FileDirList objects describe the files and directories listed |
|
69
|
** on the command line of a "diff" command. Only those objects listed are |
|
70
|
** actually diffed. |
|
71
|
*/ |
|
72
|
struct FileDirList { |
|
73
|
int nUsed; /* Number of times each entry is used */ |
|
74
|
int nName; /* Length of the entry */ |
|
75
|
char *zName; /* Text of the entry */ |
|
76
|
}; |
|
77
|
#endif |
|
78
|
|
|
79
|
/* |
|
80
|
** Return true if zFile is a file named on the azInclude[] list or is |
|
81
|
** a file in a directory named on the azInclude[] list. |
|
82
|
** |
|
83
|
** if azInclude is NULL, then always include zFile. |
|
84
|
*/ |
|
85
|
static int file_dir_match(FileDirList *p, const char *zFile){ |
|
86
|
if( p==0 || strcmp(p->zName,".")==0 ) return 1; |
|
87
|
if( filenames_are_case_sensitive() ){ |
|
88
|
while( p->zName ){ |
|
89
|
if( strcmp(zFile, p->zName)==0 |
|
90
|
|| (strncmp(zFile, p->zName, p->nName)==0 |
|
91
|
&& zFile[p->nName]=='/') |
|
92
|
){ |
|
93
|
break; |
|
94
|
} |
|
95
|
p++; |
|
96
|
} |
|
97
|
}else{ |
|
98
|
while( p->zName ){ |
|
99
|
if( fossil_stricmp(zFile, p->zName)==0 |
|
100
|
|| (fossil_strnicmp(zFile, p->zName, p->nName)==0 |
|
101
|
&& zFile[p->nName]=='/') |
|
102
|
){ |
|
103
|
break; |
|
104
|
} |
|
105
|
p++; |
|
106
|
} |
|
107
|
} |
|
108
|
if( p->zName ){ |
|
109
|
p->nUsed++; |
|
110
|
return 1; |
|
111
|
} |
|
112
|
return 0; |
|
113
|
} |
|
114
|
|
|
115
|
/* |
|
116
|
** Print details about the compared versions - possibly the working directory |
|
117
|
** or the undo buffer. For check-ins, show hash and commit time. |
|
118
|
** |
|
119
|
** This is intended primarily to go into the "header garbage" that is ignored |
|
120
|
** by patch(1). |
|
121
|
** |
|
122
|
** zFrom and zTo are interpreted as symbolic version names, unless they |
|
123
|
** start with '(', in which case they are printed directly. |
|
124
|
*/ |
|
125
|
void diff_print_versions(const char *zFrom, const char *zTo, DiffConfig *pCfg){ |
|
126
|
if( (pCfg->diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT| |
|
127
|
DIFF_HTML|DIFF_WEBPAGE|DIFF_BROWSER|DIFF_JSON|DIFF_TCL))==0 ){ |
|
128
|
fossil_print("Fossil-Diff-From: %s\n", |
|
129
|
zFrom[0]=='(' ? zFrom : mprintf("%S %s", |
|
130
|
rid_to_uuid(symbolic_name_to_rid(zFrom, "ci")), |
|
131
|
db_text("","SELECT datetime(%f)||' UTC'", |
|
132
|
symbolic_name_to_mtime(zFrom, 0, 0)))); |
|
133
|
fossil_print("Fossil-Diff-To: %s\n", |
|
134
|
zTo[0]=='(' ? zTo : mprintf("%S %s", |
|
135
|
rid_to_uuid(symbolic_name_to_rid(zTo, "ci")), |
|
136
|
db_text("","SELECT datetime(%f)||' UTC'", |
|
137
|
symbolic_name_to_mtime(zTo, 0, 1)))); |
|
138
|
fossil_print("%.66c\n", '-'); |
|
139
|
} |
|
140
|
} |
|
141
|
|
|
142
|
/* |
|
143
|
** Print the "Index:" message that patches wants to see at the top of a diff. |
|
144
|
*/ |
|
145
|
void diff_print_index(const char *zFile, DiffConfig *pCfg, Blob *pOut){ |
|
146
|
if( (pCfg->diffFlags & |
|
147
|
(DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON| |
|
148
|
DIFF_WEBPAGE|DIFF_TCL))==0 |
|
149
|
){ |
|
150
|
blob_appendf(pOut, "Index: %s\n%.66c\n", zFile, '='); |
|
151
|
} |
|
152
|
} |
|
153
|
|
|
154
|
/* |
|
155
|
** Print the +++/--- filename lines or whatever filename information |
|
156
|
** is appropriate for the output format. |
|
157
|
** |
|
158
|
*/ |
|
159
|
void diff_print_filenames( |
|
160
|
const char *zLeft, /* Name of the left file */ |
|
161
|
const char *zRight, /* Name of the right file */ |
|
162
|
DiffConfig *pCfg, /* Diff configuration */ |
|
163
|
Blob *pOut /* Write to this blob, or stdout of this is NULL */ |
|
164
|
){ |
|
165
|
u64 diffFlags = pCfg->diffFlags; |
|
166
|
/* Standardize on /dev/null, regardless of platform. */ |
|
167
|
if( pCfg->diffFlags & DIFF_FILE_ADDED ) zLeft = "/dev/null"; |
|
168
|
if( pCfg->diffFlags & DIFF_FILE_DELETED ) zRight = "/dev/null"; |
|
169
|
if( pCfg->azLabel[0] ) zLeft = pCfg->azLabel[0]; |
|
170
|
if( pCfg->azLabel[1] ) zRight = pCfg->azLabel[1]; |
|
171
|
if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){ |
|
172
|
/* no-op */ |
|
173
|
}else if( diffFlags & DIFF_DEBUG ){ |
|
174
|
blob_appendf(pOut, "FILE-LEFT %s\nFILE-RIGHT %s\n", zLeft, zRight); |
|
175
|
}else if( diffFlags & DIFF_WEBPAGE ){ |
|
176
|
if( fossil_strcmp(zLeft,zRight)==0 ){ |
|
177
|
blob_appendf(pOut,"<h1>%h</h1>\n", zLeft); |
|
178
|
}else{ |
|
179
|
blob_appendf(pOut,"<h1>%h ⇆ %h</h1>\n", zLeft, zRi { |
|
180
|
@ font-size: 150%; |
|
181
|
@ } |
|
182
|
@ table.diff { |
|
183
|
@ width: 100%; |
|
184
|
@ bo ){ |
|
185
|
blob_append line-height: inhe |