|
dbda8d6…
|
drh
|
1 |
/* |
|
c19f34c…
|
drh
|
2 |
** Copyright (c) 2007 D. Richard Hipp |
|
dbda8d6…
|
drh
|
3 |
** |
|
dbda8d6…
|
drh
|
4 |
** This program is free software; you can redistribute it and/or |
|
c06edd2…
|
drh
|
5 |
** modify it under the terms of the Simplified BSD License (also |
|
c06edd2…
|
drh
|
6 |
** known as the "2-Clause License" or "FreeBSD License".) |
|
c06edd2…
|
drh
|
7 |
|
|
dbda8d6…
|
drh
|
8 |
** This program is distributed in the hope that it will be useful, |
|
c06edd2…
|
drh
|
9 |
** but without any warranty; without even the implied warranty of |
|
c06edd2…
|
drh
|
10 |
** merchantability or fitness for a particular purpose. |
|
dbda8d6…
|
drh
|
11 |
** |
|
dbda8d6…
|
drh
|
12 |
** Author contact information: |
|
dbda8d6…
|
drh
|
13 |
** [email protected] |
|
dbda8d6…
|
drh
|
14 |
** http://www.hwaci.com/drh/ |
|
dbda8d6…
|
drh
|
15 |
** |
|
dbda8d6…
|
drh
|
16 |
******************************************************************************* |
|
dbda8d6…
|
drh
|
17 |
** |
|
dbda8d6…
|
drh
|
18 |
** This file contains code used to implement the "diff" command |
|
dbda8d6…
|
drh
|
19 |
*/ |
|
dbda8d6…
|
drh
|
20 |
#include "config.h" |
|
dbda8d6…
|
drh
|
21 |
#include "diffcmd.h" |
|
dbda8d6…
|
drh
|
22 |
#include <assert.h> |
|
dbda8d6…
|
drh
|
23 |
|
|
00c8622…
|
drh
|
24 |
/* includes needed to catch interrupts */ |
|
00c8622…
|
drh
|
25 |
#ifdef _WIN32 |
|
00c8622…
|
drh
|
26 |
# include <windows.h> |
|
00c8622…
|
drh
|
27 |
#else |
|
f3961f4…
|
drh
|
28 |
# include <signal.h> |
|
f3961f4…
|
drh
|
29 |
#endif |
|
f3961f4…
|
drh
|
30 |
|
|
135ed93…
|
drh
|
31 |
/* |
|
135ed93…
|
drh
|
32 |
** Use the right null device for the platform. |
|
135ed93…
|
drh
|
33 |
*/ |
|
135ed93…
|
drh
|
34 |
#if defined(_WIN32) |
|
135ed93…
|
drh
|
35 |
# define NULL_DEVICE "NUL" |
|
135ed93…
|
drh
|
36 |
#else |
|
135ed93…
|
drh
|
37 |
# define NULL_DEVICE "/dev/null" |
|
135ed93…
|
drh
|
38 |
#endif |
|
135ed93…
|
drh
|
39 |
|
|
135ed93…
|
drh
|
40 |
/* |
|
7807ec4…
|
mistachkin
|
41 |
** Used when the name for the diff is unknown. |
|
7807ec4…
|
mistachkin
|
42 |
*/ |
|
7807ec4…
|
mistachkin
|
43 |
#define DIFF_NO_NAME "(unknown)" |
|
7807ec4…
|
mistachkin
|
44 |
|
|
7807ec4…
|
mistachkin
|
45 |
/* |
|
825d78b…
|
mistachkin
|
46 |
** Use the "exec-rel-paths" setting and the --exec-abs-paths and |
|
825d78b…
|
mistachkin
|
47 |
** --exec-rel-paths command line options to determine whether |
|
825d78b…
|
mistachkin
|
48 |
** certain external commands are executed using relative paths. |
|
825d78b…
|
mistachkin
|
49 |
*/ |
|
c46f980…
|
drh
|
50 |
static int determine_exec_relative_option(int force){ |
|
825d78b…
|
mistachkin
|
51 |
static int relativePaths = -1; |
|
825d78b…
|
mistachkin
|
52 |
if( force || relativePaths==-1 ){ |
|
825d78b…
|
mistachkin
|
53 |
int relPathOption = find_option("exec-rel-paths", 0, 0)!=0; |
|
825d78b…
|
mistachkin
|
54 |
int absPathOption = find_option("exec-abs-paths", 0, 0)!=0; |
|
825d78b…
|
mistachkin
|
55 |
#if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) |
|
825d78b…
|
mistachkin
|
56 |
relativePaths = db_get_boolean("exec-rel-paths", 1); |
|
825d78b…
|
mistachkin
|
57 |
#else |
|
825d78b…
|
mistachkin
|
58 |
relativePaths = db_get_boolean("exec-rel-paths", 0); |
|
825d78b…
|
mistachkin
|
59 |
#endif |
|
825d78b…
|
mistachkin
|
60 |
if( relPathOption ){ relativePaths = 1; } |
|
825d78b…
|
mistachkin
|
61 |
if( absPathOption ){ relativePaths = 0; } |
|
825d78b…
|
mistachkin
|
62 |
} |
|
825d78b…
|
mistachkin
|
63 |
return relativePaths; |
|
825d78b…
|
mistachkin
|
64 |
} |
|
825d78b…
|
mistachkin
|
65 |
|
|
c46f980…
|
drh
|
66 |
#if INTERFACE |
|
c46f980…
|
drh
|
67 |
/* |
|
c46f980…
|
drh
|
68 |
** An array of FileDirList objects describe the files and directories listed |
|
c46f980…
|
drh
|
69 |
** on the command line of a "diff" command. Only those objects listed are |
|
c46f980…
|
drh
|
70 |
** actually diffed. |
|
c46f980…
|
drh
|
71 |
*/ |
|
c46f980…
|
drh
|
72 |
struct FileDirList { |
|
c46f980…
|
drh
|
73 |
int nUsed; /* Number of times each entry is used */ |
|
c46f980…
|
drh
|
74 |
int nName; /* Length of the entry */ |
|
c46f980…
|
drh
|
75 |
char *zName; /* Text of the entry */ |
|
c46f980…
|
drh
|
76 |
}; |
|
c46f980…
|
drh
|
77 |
#endif |
|
c46f980…
|
drh
|
78 |
|
|
c46f980…
|
drh
|
79 |
/* |
|
c46f980…
|
drh
|
80 |
** Return true if zFile is a file named on the azInclude[] list or is |
|
c46f980…
|
drh
|
81 |
** a file in a directory named on the azInclude[] list. |
|
c46f980…
|
drh
|
82 |
** |
|
c46f980…
|
drh
|
83 |
** if azInclude is NULL, then always include zFile. |
|
c46f980…
|
drh
|
84 |
*/ |
|
c46f980…
|
drh
|
85 |
static int file_dir_match(FileDirList *p, const char *zFile){ |
|
c46f980…
|
drh
|
86 |
if( p==0 || strcmp(p->zName,".")==0 ) return 1; |
|
c46f980…
|
drh
|
87 |
if( filenames_are_case_sensitive() ){ |
|
c46f980…
|
drh
|
88 |
while( p->zName ){ |
|
c46f980…
|
drh
|
89 |
if( strcmp(zFile, p->zName)==0 |
|
c46f980…
|
drh
|
90 |
|| (strncmp(zFile, p->zName, p->nName)==0 |
|
c46f980…
|
drh
|
91 |
&& zFile[p->nName]=='/') |
|
c46f980…
|
drh
|
92 |
){ |
|
c46f980…
|
drh
|
93 |
break; |
|
c46f980…
|
drh
|
94 |
} |
|
c46f980…
|
drh
|
95 |
p++; |
|
c46f980…
|
drh
|
96 |
} |
|
c46f980…
|
drh
|
97 |
}else{ |
|
c46f980…
|
drh
|
98 |
while( p->zName ){ |
|
c46f980…
|
drh
|
99 |
if( fossil_stricmp(zFile, p->zName)==0 |
|
c46f980…
|
drh
|
100 |
|| (fossil_strnicmp(zFile, p->zName, p->nName)==0 |
|
c46f980…
|
drh
|
101 |
&& zFile[p->nName]=='/') |
|
c46f980…
|
drh
|
102 |
){ |
|
c46f980…
|
drh
|
103 |
break; |
|
c46f980…
|
drh
|
104 |
} |
|
c46f980…
|
drh
|
105 |
p++; |
|
c46f980…
|
drh
|
106 |
} |
|
c46f980…
|
drh
|
107 |
} |
|
c46f980…
|
drh
|
108 |
if( p->zName ){ |
|
c46f980…
|
drh
|
109 |
p->nUsed++; |
|
c46f980…
|
drh
|
110 |
return 1; |
|
c46f980…
|
drh
|
111 |
} |
|
c46f980…
|
drh
|
112 |
return 0; |
|
c46f980…
|
drh
|
113 |
} |
|
c46f980…
|
drh
|
114 |
|
|
c46f980…
|
drh
|
115 |
/* |
|
41f6a45…
|
danield
|
116 |
** Print details about the compared versions - possibly the working directory |
|
41f6a45…
|
danield
|
117 |
** or the undo buffer. For check-ins, show hash and commit time. |
|
275da70…
|
danield
|
118 |
** |
|
41f6a45…
|
danield
|
119 |
** This is intended primarily to go into the "header garbage" that is ignored |
|
41f6a45…
|
danield
|
120 |
** by patch(1). |
|
41f6a45…
|
danield
|
121 |
** |
|
41f6a45…
|
danield
|
122 |
** zFrom and zTo are interpreted as symbolic version names, unless they |
|
41f6a45…
|
danield
|
123 |
** start with '(', in which case they are printed directly. |
|
41f6a45…
|
danield
|
124 |
*/ |
|
41f6a45…
|
danield
|
125 |
void diff_print_versions(const char *zFrom, const char *zTo, DiffConfig *pCfg){ |
|
41f6a45…
|
danield
|
126 |
if( (pCfg->diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT| |
|
41f6a45…
|
danield
|
127 |
DIFF_HTML|DIFF_WEBPAGE|DIFF_BROWSER|DIFF_JSON|DIFF_TCL))==0 ){ |
|
41f6a45…
|
danield
|
128 |
fossil_print("Fossil-Diff-From: %s\n", |
|
41f6a45…
|
danield
|
129 |
zFrom[0]=='(' ? zFrom : mprintf("%S %s", |
|
41f6a45…
|
danield
|
130 |
rid_to_uuid(symbolic_name_to_rid(zFrom, "ci")), |
|
41f6a45…
|
danield
|
131 |
db_text("","SELECT datetime(%f)||' UTC'", |
|
633ea73…
|
drh
|
132 |
symbolic_name_to_mtime(zFrom, 0, 0)))); |
|
41f6a45…
|
danield
|
133 |
fossil_print("Fossil-Diff-To: %s\n", |
|
41f6a45…
|
danield
|
134 |
zTo[0]=='(' ? zTo : mprintf("%S %s", |
|
41f6a45…
|
danield
|
135 |
rid_to_uuid(symbolic_name_to_rid(zTo, "ci")), |
|
41f6a45…
|
danield
|
136 |
db_text("","SELECT datetime(%f)||' UTC'", |
|
633ea73…
|
drh
|
137 |
symbolic_name_to_mtime(zTo, 0, 1)))); |
|
41f6a45…
|
danield
|
138 |
fossil_print("%.66c\n", '-'); |
|
41f6a45…
|
danield
|
139 |
} |
|
41f6a45…
|
danield
|
140 |
} |
|
41f6a45…
|
danield
|
141 |
|
|
41f6a45…
|
danield
|
142 |
/* |
|
ab47cc7…
|
drh
|
143 |
** Print the "Index:" message that patches wants to see at the top of a diff. |
|
ab47cc7…
|
drh
|
144 |
*/ |
|
590e01d…
|
drh
|
145 |
void diff_print_index(const char *zFile, DiffConfig *pCfg, Blob *pOut){ |
|
1347a1d…
|
drh
|
146 |
if( (pCfg->diffFlags & |
|
1347a1d…
|
drh
|
147 |
(DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON| |
|
1347a1d…
|
drh
|
148 |
DIFF_WEBPAGE|DIFF_TCL))==0 |
|
1347a1d…
|
drh
|
149 |
){ |
|
590e01d…
|
drh
|
150 |
blob_appendf(pOut, "Index: %s\n%.66c\n", zFile, '='); |
|
ab47cc7…
|
drh
|
151 |
} |
|
ab47cc7…
|
drh
|
152 |
} |
|
ab47cc7…
|
drh
|
153 |
|
|
ab47cc7…
|
drh
|
154 |
/* |
|
1347a1d…
|
drh
|
155 |
** Print the +++/--- filename lines or whatever filename information |
|
1347a1d…
|
drh
|
156 |
** is appropriate for the output format. |
|
41f6a45…
|
danield
|
157 |
** |
|
ab47cc7…
|
drh
|
158 |
*/ |
|
9e33074…
|
drh
|
159 |
void diff_print_filenames( |
|
1347a1d…
|
drh
|
160 |
const char *zLeft, /* Name of the left file */ |
|
1347a1d…
|
drh
|
161 |
const char *zRight, /* Name of the right file */ |
|
1347a1d…
|
drh
|
162 |
DiffConfig *pCfg, /* Diff configuration */ |
|
590e01d…
|
drh
|
163 |
Blob *pOut /* Write to this blob, or stdout of this is NULL */ |
|
9e33074…
|
drh
|
164 |
){ |
|
1347a1d…
|
drh
|
165 |
u64 diffFlags = pCfg->diffFlags; |
|
caa6ad3…
|
drh
|
166 |
/* Standardize on /dev/null, regardless of platform. */ |
|
caa6ad3…
|
drh
|
167 |
if( pCfg->diffFlags & DIFF_FILE_ADDED ) zLeft = "/dev/null"; |
|
caa6ad3…
|
drh
|
168 |
if( pCfg->diffFlags & DIFF_FILE_DELETED ) zRight = "/dev/null"; |
|
f5cb12d…
|
drh
|
169 |
if( pCfg->azLabel[0] ) zLeft = pCfg->azLabel[0]; |
|
f5cb12d…
|
drh
|
170 |
if( pCfg->azLabel[1] ) zRight = pCfg->azLabel[1]; |
|
1347a1d…
|
drh
|
171 |
if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){ |
|
e0565d4…
|
drh
|
172 |
/* no-op */ |
|
9e33074…
|
drh
|
173 |
}else if( diffFlags & DIFF_DEBUG ){ |
|
590e01d…
|
drh
|
174 |
blob_appendf(pOut, "FILE-LEFT %s\nFILE-RIGHT %s\n", zLeft, zRight); |
|
ea52b7d…
|
drh
|
175 |
}else if( diffFlags & DIFF_WEBPAGE ){ |
|
ea52b7d…
|
drh
|
176 |
if( fossil_strcmp(zLeft,zRight)==0 ){ |
|
590e01d…
|
drh
|
177 |
blob_appendf(pOut,"<h1>%h</h1>\n", zLeft); |
|
590e01d…
|
drh
|
178 |
}else{ |
|
590e01d…
|
drh
|
179 |
blob_appendf(pOut,"<h1>%h ⇆ %h</h1>\n", zLeft, zRight); |
|
590e01d…
|
drh
|
180 |
} |
|
590e01d…
|
drh
|
181 |
}else if( diffFlags & (DIFF_TCL|DIFF_JSON) ){ |
|
1347a1d…
|
drh
|
182 |
if( diffFlags & DIFF_TCL ){ |
|
1347a1d…
|
drh
|
183 |
blob_append(pOut, "FILE ", 5); |
|
1347a1d…
|
drh
|
184 |
blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft)); |
|
1347a1d…
|
drh
|
185 |
blob_append_char(pOut, ' '); |
|
1347a1d…
|
drh
|
186 |
blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight)); |
|
1347a1d…
|
drh
|
187 |
blob_append_char(pOut, '\n'); |
|
1347a1d…
|
drh
|
188 |
}else{ |
|
590e01d…
|
drh
|
189 |
if( pOut ) blob_trim(pOut); |
|
1347a1d…
|
drh
|
190 |
blob_append(pOut, (pCfg->nFile==0 ? "[{" : ",\n{"), -1); |
|
1347a1d…
|
drh
|
191 |
pCfg->nFile++; |
|
1347a1d…
|
drh
|
192 |
blob_append(pOut, "\n \"leftname\":", -1); |
|
1347a1d…
|
drh
|
193 |
blob_append_json_literal(pOut, zLeft, (int)strlen(zLeft)); |
|
1347a1d…
|
drh
|
194 |
blob_append(pOut, ",\n \"rightname\":", -1); |
|
1347a1d…
|
drh
|
195 |
blob_append_json_literal(pOut, zRight, (int)strlen(zRight)); |
|
1347a1d…
|
drh
|
196 |
blob_append(pOut, ",\n \"diff\":\n", -1); |
|
1347a1d…
|
drh
|
197 |
} |
|
e0565d4…
|
drh
|
198 |
}else if( diffFlags & DIFF_SIDEBYSIDE ){ |
|
1347a1d…
|
drh
|
199 |
int w = diff_width(pCfg); |
|
ab47cc7…
|
drh
|
200 |
int n1 = strlen(zLeft); |
|
1e0e075…
|
drh
|
201 |
int n2 = strlen(zRight); |
|
fade055…
|
mistachkin
|
202 |
int x; |
|
1e0e075…
|
drh
|
203 |
if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){ |
|
1e0e075…
|
drh
|
204 |
if( n1>w*2 ) n1 = w*2; |
|
1e0e075…
|
drh
|
205 |
x = w*2+17 - (n1+2); |
|
590e01d…
|
drh
|
206 |
blob_appendf(pOut, "%.*c %.*s %.*c\n", |
|
590e01d…
|
drh
|
207 |
x/2, '=', n1, zLeft, (x+1)/2, '='); |
|
1e0e075…
|
drh
|
208 |
}else{ |
|
1e0e075…
|
drh
|
209 |
if( w<20 ) w = 20; |
|
1e0e075…
|
drh
|
210 |
if( n1>w-10 ) n1 = w - 10; |
|
1e0e075…
|
drh
|
211 |
if( n2>w-10 ) n2 = w - 10; |
|
590e01d…
|
drh
|
212 |
blob_appendf(pOut, "%.*c %.*s %.*c versus %.*c %.*s %.*c\n", |
|
590e01d…
|
drh
|
213 |
(w-n1+10)/2, '=', n1, zLeft, (w-n1+1)/2, '=', |
|
590e01d…
|
drh
|
214 |
(w-n2)/2, '=', n2, zRight, (w-n2+1)/2, '='); |
|
590e01d…
|
drh
|
215 |
} |
|
590e01d…
|
drh
|
216 |
}else{ |
|
c6715ca…
|
andybradford
|
217 |
blob_appendf(pOut, "--- %s\t\n+++ %s\t\n", zLeft, zRight); |
|
590e01d…
|
drh
|
218 |
} |
|
590e01d…
|
drh
|
219 |
} |
|
590e01d…
|
drh
|
220 |
|
|
590e01d…
|
drh
|
221 |
|
|
590e01d…
|
drh
|
222 |
/* |
|
5a8516d…
|
drh
|
223 |
** Default header texts for diff with --webpage |
|
590e01d…
|
drh
|
224 |
*/ |
|
275da70…
|
danield
|
225 |
static const char zWebpageHdr[] = |
|
9e33074…
|
drh
|
226 |
@ <!DOCTYPE html> |
|
9e33074…
|
drh
|
227 |
@ <html> |
|
9e33074…
|
drh
|
228 |
@ <head> |
|
9e33074…
|
drh
|
229 |
@ <meta charset="UTF-8"> |
|
9e33074…
|
drh
|
230 |
@ <style> |
|
432ff8d…
|
stephan
|
231 |
@ body { |
|
432ff8d…
|
stephan
|
232 |
@ background-color: white; |
|
432ff8d…
|
stephan
|
233 |
@ } |
|
9e33074…
|
drh
|
234 |
@ h1 { |
|
9e33074…
|
drh
|
235 |
@ font-size: 150%; |
|
9e33074…
|
drh
|
236 |
@ } |
|
9e33074…
|
drh
|
237 |
@ |
|
9e33074…
|
drh
|
238 |
@ table.diff { |
|
51c1efd…
|
stephan
|
239 |
@ width: 100%; |
|
eb6611c…
|
drh
|
240 |
@ border-spacing: 0; |
|
9e33074…
|
drh
|
241 |
@ border: 1px solid black; |
|
432ff8d…
|
stephan
|
242 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
243 |
@ font-size: inherit; |
|
eb6611c…
|
drh
|
244 |
@ } |
|
9e33074…
|
drh
|
245 |
@ table.diff td { |
|
eb6611c…
|
drh
|
246 |
@ vertical-align: top; |
|
432ff8d…
|
stephan
|
247 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
248 |
@ font-size: inherit; |
|
9e33074…
|
drh
|
249 |
@ } |
|
9e33074…
|
drh
|
250 |
@ table.diff pre { |
|
9e33074…
|
drh
|
251 |
@ margin: 0 0 0 0; |
|
432ff8d…
|
stephan
|
252 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
253 |
@ font-size: inherit; |
|
9e33074…
|
drh
|
254 |
@ } |
|
9e33074…
|
drh
|
255 |
@ td.diffln { |
|
8c6dddc…
|
stephan
|
256 |
@ width: fit-content; |
|
eb6611c…
|
drh
|
257 |
@ text-align: right; |
|
9e33074…
|
drh
|
258 |
@ padding: 0 1em 0 0; |
|
9e33074…
|
drh
|
259 |
@ } |
|
9e33074…
|
drh
|
260 |
@ td.difflne { |
|
9e33074…
|
drh
|
261 |
@ padding-bottom: 0.4em; |
|
9e33074…
|
drh
|
262 |
@ } |
|
9e33074…
|
drh
|
263 |
@ td.diffsep { |
|
8c6dddc…
|
stephan
|
264 |
@ width: fit-content; |
|
9e33074…
|
drh
|
265 |
@ padding: 0 0.3em 0 1em; |
|
432ff8d…
|
stephan
|
266 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
267 |
@ font-size: inherit; |
|
432ff8d…
|
stephan
|
268 |
@ } |
|
432ff8d…
|
stephan
|
269 |
@ td.diffsep pre { |
|
432ff8d…
|
stephan
|
270 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
271 |
@ font-size: inherit; |
|
eb6611c…
|
drh
|
272 |
@ } |
|
9e33074…
|
drh
|
273 |
@ td.difftxt pre { |
|
eb6611c…
|
drh
|
274 |
@ overflow-x: auto; |
|
eb6611c…
|
drh
|
275 |
@ } |
|
9e33074…
|
drh
|
276 |
@ td.diffln ins { |
|
9e33074…
|
drh
|
277 |
@ background-color: #a0e4b2; |
|
9e33074…
|
drh
|
278 |
@ text-decoration: none; |
|
432ff8d…
|
stephan
|
279 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
280 |
@ font-size: inherit; |
|
9e33074…
|
drh
|
281 |
@ } |
|
9e33074…
|
drh
|
282 |
@ td.diffln del { |
|
9e33074…
|
drh
|
283 |
@ background-color: #ffc0c0; |
|
9e33074…
|
drh
|
284 |
@ text-decoration: none; |
|
432ff8d…
|
stephan
|
285 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
286 |
@ font-size: inherit; |
|
9e33074…
|
drh
|
287 |
@ } |
|
9e33074…
|
drh
|
288 |
@ td.difftxt del { |
|
9e33074…
|
drh
|
289 |
@ background-color: #ffe8e8; |
|
9e33074…
|
drh
|
290 |
@ text-decoration: none; |
|
432ff8d…
|
stephan
|
291 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
292 |
@ font-size: inherit; |
|
9e33074…
|
drh
|
293 |
@ } |
|
9e33074…
|
drh
|
294 |
@ td.difftxt del > del { |
|
9e33074…
|
drh
|
295 |
@ background-color: #ffc0c0; |
|
9e33074…
|
drh
|
296 |
@ text-decoration: none; |
|
9e33074…
|
drh
|
297 |
@ font-weight: bold; |
|
9e33074…
|
drh
|
298 |
@ } |
|
9e33074…
|
drh
|
299 |
@ td.difftxt del > del.edit { |
|
9e33074…
|
drh
|
300 |
@ background-color: #c0c0ff; |
|
9e33074…
|
drh
|
301 |
@ text-decoration: none; |
|
9e33074…
|
drh
|
302 |
@ font-weight: bold; |
|
9e33074…
|
drh
|
303 |
@ } |
|
9e33074…
|
drh
|
304 |
@ td.difftxt ins { |
|
9e33074…
|
drh
|
305 |
@ background-color: #dafbe1; |
|
9e33074…
|
drh
|
306 |
@ text-decoration: none; |
|
432ff8d…
|
stephan
|
307 |
@ line-height: inherit; |
|
432ff8d…
|
stephan
|
308 |
@ font-size: inherit; |
|
9e33074…
|
drh
|
309 |
@ } |
|
9e33074…
|
drh
|
310 |
@ td.difftxt ins > ins { |
|
9e33074…
|
drh
|
311 |
@ background-color: #a0e4b2; |
|
9e33074…
|
drh
|
312 |
@ text-decoration: none; |
|
9e33074…
|
drh
|
313 |
@ font-weight: bold; |
|
9e33074…
|
drh
|
314 |
@ } |
|
9e33074…
|
drh
|
315 |
@ td.difftxt ins > ins.edit { |
|
9e33074…
|
drh
|
316 |
@ background-color: #c0c0ff; |
|
9e33074…
|
drh
|
317 |
@ text-decoration: none; |
|
9e33074…
|
drh
|
318 |
@ font-weight: bold; |
|
9e33074…
|
drh
|
319 |
@ } |
|
a2e6b31…
|
danield
|
320 |
@ @media (prefers-color-scheme: dark) { |
|
a2e6b31…
|
danield
|
321 |
@ body { |
|
a2e6b31…
|
danield
|
322 |
@ background-color: #353535; |
|
a2e6b31…
|
danield
|
323 |
@ color: #ffffff; |
|
a2e6b31…
|
danield
|
324 |
@ } |
|
a2e6b31…
|
danield
|
325 |
@ td.diffln ins { |
|
a2e6b31…
|
danield
|
326 |
@ background-color: #559855; |
|
a2e6b31…
|
danield
|
327 |
@ color: #000000; |
|
a2e6b31…
|
danield
|
328 |
@ } |
|
a2e6b31…
|
danield
|
329 |
@ td.diffln del { |
|
a2e6b31…
|
danield
|
330 |
@ background-color: #cc5555; |
|
a2e6b31…
|
danield
|
331 |
@ color: #000000; |
|
a2e6b31…
|
danield
|
332 |
@ } |
|
a2e6b31…
|
danield
|
333 |
@ td.difftxt del { |
|
a2e6b31…
|
danield
|
334 |
@ background-color: #f9cfcf; |
|
a2e6b31…
|
danield
|
335 |
@ color: #000000; |
|
a2e6b31…
|
danield
|
336 |
@ } |
|
a2e6b31…
|
danield
|
337 |
@ td.difftxt del > del { |
|
a2e6b31…
|
danield
|
338 |
@ background-color: #cc5555; |
|
a2e6b31…
|
danield
|
339 |
@ color: #000000; |
|
a2e6b31…
|
danield
|
340 |
@ } |
|
a2e6b31…
|
danield
|
341 |
@ td.difftxt ins { |
|
a2e6b31…
|
danield
|
342 |
@ background-color: #a2dbb2; |
|
a2e6b31…
|
danield
|
343 |
@ color: #000000; |
|
a2e6b31…
|
danield
|
344 |
@ } |
|
a2e6b31…
|
danield
|
345 |
@ td.difftxt ins > ins { |
|
a2e6b31…
|
danield
|
346 |
@ background-color: #559855; |
|
a2e6b31…
|
danield
|
347 |
@ } |
|
a2e6b31…
|
danield
|
348 |
@ } |
|
275da70…
|
danield
|
349 |
@ |
|
5a8516d…
|
drh
|
350 |
@ </style> |
|
5a8516d…
|
drh
|
351 |
@ </head> |
|
5a8516d…
|
drh
|
352 |
@ <body> |
|
5a8516d…
|
drh
|
353 |
; |
|
275da70…
|
danield
|
354 |
static const char zWebpageHdrDark[] = |
|
5a8516d…
|
drh
|
355 |
@ <!DOCTYPE html> |
|
5a8516d…
|
drh
|
356 |
@ <html> |
|
5a8516d…
|
drh
|
357 |
@ <head> |
|
5a8516d…
|
drh
|
358 |
@ <meta charset="UTF-8"> |
|
5a8516d…
|
drh
|
359 |
@ <style> |
|
5a8516d…
|
drh
|
360 |
@ body { |
|
5a8516d…
|
drh
|
361 |
@ background-color: #353535; |
|
5a8516d…
|
drh
|
362 |
@ color: #ffffff; |
|
5a8516d…
|
drh
|
363 |
@ } |
|
5a8516d…
|
drh
|
364 |
@ h1 { |
|
5a8516d…
|
drh
|
365 |
@ font-size: 150%; |
|
5a8516d…
|
drh
|
366 |
@ } |
|
275da70…
|
danield
|
367 |
@ |
|
5a8516d…
|
drh
|
368 |
@ table.diff { |
|
5a8516d…
|
drh
|
369 |
@ width: 100%; |
|
5a8516d…
|
drh
|
370 |
@ border-spacing: 0; |
|
5a8516d…
|
drh
|
371 |
@ border: 1px solid black; |
|
5a8516d…
|
drh
|
372 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
373 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
374 |
@ } |
|
5a8516d…
|
drh
|
375 |
@ table.diff td { |
|
5a8516d…
|
drh
|
376 |
@ vertical-align: top; |
|
5a8516d…
|
drh
|
377 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
378 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
379 |
@ } |
|
5a8516d…
|
drh
|
380 |
@ table.diff pre { |
|
5a8516d…
|
drh
|
381 |
@ margin: 0 0 0 0; |
|
5a8516d…
|
drh
|
382 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
383 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
384 |
@ } |
|
5a8516d…
|
drh
|
385 |
@ td.diffln { |
|
8c6dddc…
|
stephan
|
386 |
@ width: fit-content; |
|
5a8516d…
|
drh
|
387 |
@ text-align: right; |
|
5a8516d…
|
drh
|
388 |
@ padding: 0 1em 0 0; |
|
5a8516d…
|
drh
|
389 |
@ } |
|
5a8516d…
|
drh
|
390 |
@ td.difflne { |
|
5a8516d…
|
drh
|
391 |
@ padding-bottom: 0.4em; |
|
5a8516d…
|
drh
|
392 |
@ } |
|
5a8516d…
|
drh
|
393 |
@ td.diffsep { |
|
8c6dddc…
|
stephan
|
394 |
@ width: fit-content; |
|
5a8516d…
|
drh
|
395 |
@ padding: 0 0.3em 0 1em; |
|
5a8516d…
|
drh
|
396 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
397 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
398 |
@ } |
|
5a8516d…
|
drh
|
399 |
@ td.diffsep pre { |
|
5a8516d…
|
drh
|
400 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
401 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
402 |
@ } |
|
5a8516d…
|
drh
|
403 |
@ td.difftxt pre { |
|
5a8516d…
|
drh
|
404 |
@ overflow-x: auto; |
|
5a8516d…
|
drh
|
405 |
@ } |
|
5a8516d…
|
drh
|
406 |
@ td.diffln ins { |
|
5a8516d…
|
drh
|
407 |
@ background-color: #559855; |
|
5a8516d…
|
drh
|
408 |
@ color: #000000; |
|
5a8516d…
|
drh
|
409 |
@ text-decoration: none; |
|
5a8516d…
|
drh
|
410 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
411 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
412 |
@ } |
|
5a8516d…
|
drh
|
413 |
@ td.diffln del { |
|
5a8516d…
|
drh
|
414 |
@ background-color: #cc5555; |
|
5a8516d…
|
drh
|
415 |
@ color: #000000; |
|
5a8516d…
|
drh
|
416 |
@ text-decoration: none; |
|
5a8516d…
|
drh
|
417 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
418 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
419 |
@ } |
|
5a8516d…
|
drh
|
420 |
@ td.difftxt del { |
|
5a8516d…
|
drh
|
421 |
@ background-color: #f9cfcf; |
|
5a8516d…
|
drh
|
422 |
@ color: #000000; |
|
5a8516d…
|
drh
|
423 |
@ text-decoration: none; |
|
5a8516d…
|
drh
|
424 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
425 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
426 |
@ } |
|
5a8516d…
|
drh
|
427 |
@ td.difftxt del > del { |
|
5a8516d…
|
drh
|
428 |
@ background-color: #cc5555; |
|
5a8516d…
|
drh
|
429 |
@ color: #000000; |
|
5a8516d…
|
drh
|
430 |
@ text-decoration: none; |
|
5a8516d…
|
drh
|
431 |
@ font-weight: bold; |
|
5a8516d…
|
drh
|
432 |
@ } |
|
5a8516d…
|
drh
|
433 |
@ td.difftxt del > del.edit { |
|
5a8516d…
|
drh
|
434 |
@ background-color: #c0c0ff; |
|
5a8516d…
|
drh
|
435 |
@ text-decoration: none; |
|
5a8516d…
|
drh
|
436 |
@ font-weight: bold; |
|
5a8516d…
|
drh
|
437 |
@ } |
|
5a8516d…
|
drh
|
438 |
@ td.difftxt ins { |
|
5a8516d…
|
drh
|
439 |
@ background-color: #a2dbb2; |
|
5a8516d…
|
drh
|
440 |
@ color: #000000; |
|
5a8516d…
|
drh
|
441 |
@ text-decoration: none; |
|
5a8516d…
|
drh
|
442 |
@ line-height: inherit; |
|
5a8516d…
|
drh
|
443 |
@ font-size: inherit; |
|
5a8516d…
|
drh
|
444 |
@ } |
|
5a8516d…
|
drh
|
445 |
@ td.difftxt ins > ins { |
|
5a8516d…
|
drh
|
446 |
@ background-color: #559855; |
|
5a8516d…
|
drh
|
447 |
@ text-decoration: none; |
|
5a8516d…
|
drh
|
448 |
@ font-weight: bold; |
|
5a8516d…
|
drh
|
449 |
@ } |
|
5a8516d…
|
drh
|
450 |
@ td.difftxt ins > ins.edit { |
|
5a8516d…
|
drh
|
451 |
@ background-color: #c0c0ff; |
|
5a8516d…
|
drh
|
452 |
@ text-decoration: none; |
|
5a8516d…
|
drh
|
453 |
@ font-weight: bold; |
|
5a8516d…
|
drh
|
454 |
@ } |
|
275da70…
|
danield
|
455 |
@ |
|
ea52b7d…
|
drh
|
456 |
@ </style> |
|
ea52b7d…
|
drh
|
457 |
@ </head> |
|
ea52b7d…
|
drh
|
458 |
@ <body> |
|
ea52b7d…
|
drh
|
459 |
; |
|
275da70…
|
danield
|
460 |
const char zWebpageEnd[] = |
|
7e37ae9…
|
drh
|
461 |
@ </body> |
|
7e37ae9…
|
drh
|
462 |
@ </html> |
|
7e37ae9…
|
drh
|
463 |
; |
|
7e37ae9…
|
drh
|
464 |
|
|
7e37ae9…
|
drh
|
465 |
/* |
|
1347a1d…
|
drh
|
466 |
** State variables used by the --browser option for diff. These must |
|
1347a1d…
|
drh
|
467 |
** be static variables, not elements of DiffConfig, since they are |
|
1347a1d…
|
drh
|
468 |
** used by the interrupt handler. |
|
f3961f4…
|
drh
|
469 |
*/ |
|
f3961f4…
|
drh
|
470 |
static char *tempDiffFilename; /* File holding the diff HTML */ |
|
f3961f4…
|
drh
|
471 |
static FILE *diffOut; /* Open to write into tempDiffFilename */ |
|
f3961f4…
|
drh
|
472 |
|
|
f3961f4…
|
drh
|
473 |
/* Amount of delay (in milliseconds) between launching the |
|
9a3372e…
|
drh
|
474 |
** web browser and deleting the temporary file used by --browser |
|
f3961f4…
|
drh
|
475 |
*/ |
|
9a3372e…
|
drh
|
476 |
#ifndef FOSSIL_BROWSER_DIFF_DELAY |
|
9a3372e…
|
drh
|
477 |
# define FOSSIL_BROWSER_DIFF_DELAY 5000 /* 5 seconds by default */ |
|
f3961f4…
|
drh
|
478 |
#endif |
|
f3961f4…
|
drh
|
479 |
|
|
f3961f4…
|
drh
|
480 |
/* |
|
9a3372e…
|
drh
|
481 |
** If we catch a single while writing the temporary file for the --browser |
|
f3961f4…
|
drh
|
482 |
** diff output, then delete the temporary file and exit. |
|
f3961f4…
|
drh
|
483 |
*/ |
|
f3961f4…
|
drh
|
484 |
static void diff_www_interrupt(int NotUsed){ |
|
f3961f4…
|
drh
|
485 |
(void)NotUsed; |
|
f3961f4…
|
drh
|
486 |
if( diffOut ) fclose(diffOut); |
|
f3961f4…
|
drh
|
487 |
if( tempDiffFilename ) file_delete(tempDiffFilename); |
|
f3961f4…
|
drh
|
488 |
exit(1); |
|
f3961f4…
|
drh
|
489 |
} |
|
f3961f4…
|
drh
|
490 |
#ifdef _WIN32 |
|
f3961f4…
|
drh
|
491 |
static BOOL WINAPI diff_console_ctrl_handler(DWORD dwCtrlType){ |
|
f3961f4…
|
drh
|
492 |
if( dwCtrlType==CTRL_C_EVENT ) diff_www_interrupt(0); |
|
f3961f4…
|
drh
|
493 |
return FALSE; |
|
f3961f4…
|
drh
|
494 |
} |
|
f3961f4…
|
drh
|
495 |
#endif |
|
f3961f4…
|
drh
|
496 |
|
|
f3961f4…
|
drh
|
497 |
|
|
f3961f4…
|
drh
|
498 |
/* |
|
f3961f4…
|
drh
|
499 |
** Do preliminary setup and output before computing a diff. |
|
f3961f4…
|
drh
|
500 |
** |
|
9a3372e…
|
drh
|
501 |
** For --browser, redirect stdout to a temporary file that will |
|
f3961f4…
|
drh
|
502 |
** hold the result. Make arrangements to delete that temporary |
|
f3961f4…
|
drh
|
503 |
** file if the diff is interrupted. |
|
f3961f4…
|
drh
|
504 |
** |
|
9a3372e…
|
drh
|
505 |
** For --browser and --webpage, output the HTML header. |
|
eb6611c…
|
drh
|
506 |
*/ |
|
1347a1d…
|
drh
|
507 |
void diff_begin(DiffConfig *pCfg){ |
|
1347a1d…
|
drh
|
508 |
if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){ |
|
f3961f4…
|
drh
|
509 |
tempDiffFilename = fossil_temp_filename(); |
|
f3961f4…
|
drh
|
510 |
tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename); |
|
f48e48f…
|
drh
|
511 |
diffOut = fossil_freopen(tempDiffFilename,"wb",stdout); |
|
f3961f4…
|
drh
|
512 |
if( diffOut==0 ){ |
|
16d3d8b…
|
stephan
|
513 |
fossil_fatal("unable to create temporary file \"%s\"", |
|
f3961f4…
|
drh
|
514 |
tempDiffFilename); |
|
f3961f4…
|
drh
|
515 |
} |
|
f3961f4…
|
drh
|
516 |
#ifndef _WIN32 |
|
f3961f4…
|
drh
|
517 |
signal(SIGINT, diff_www_interrupt); |
|
f3961f4…
|
drh
|
518 |
#else |
|
f3961f4…
|
drh
|
519 |
SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE); |
|
f3961f4…
|
drh
|
520 |
#endif |
|
f3961f4…
|
drh
|
521 |
} |
|
1347a1d…
|
drh
|
522 |
if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){ |
|
275da70…
|
danield
|
523 |
fossil_print("%s",(pCfg->diffFlags & DIFF_DARKMODE)!=0 ? zWebpageHdrDark : |
|
5a8516d…
|
drh
|
524 |
zWebpageHdr); |
|
83feccc…
|
drh
|
525 |
fflush(stdout); |
|
eb6611c…
|
drh
|
526 |
} |
|
eb6611c…
|
drh
|
527 |
} |
|
eb6611c…
|
drh
|
528 |
|
|
eb6611c…
|
drh
|
529 |
/* Do any final output required by a diff and complete the diff |
|
eb6611c…
|
drh
|
530 |
** process. |
|
f3961f4…
|
drh
|
531 |
** |
|
275da70…
|
danield
|
532 |
** For --browser and --webpage, output any javascript required by |
|
f3961f4…
|
drh
|
533 |
** the diff. (Currently JS is only needed for side-by-side diffs). |
|
f3961f4…
|
drh
|
534 |
** |
|
9a3372e…
|
drh
|
535 |
** For --browser, close the connection to the temporary file, then |
|
f3961f4…
|
drh
|
536 |
** launch a web browser to view the file. After a delay |
|
9a3372e…
|
drh
|
537 |
** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file. |
|
eb6611c…
|
drh
|
538 |
*/ |
|
1347a1d…
|
drh
|
539 |
void diff_end(DiffConfig *pCfg, int nErr){ |
|
1347a1d…
|
drh
|
540 |
if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){ |
|
1347a1d…
|
drh
|
541 |
if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){ |
|
9e33074…
|
drh
|
542 |
const unsigned char *zJs = builtin_file("diff.js", 0); |
|
eb6611c…
|
drh
|
543 |
fossil_print("<script>\n%s</script>\n", zJs); |
|
eb6611c…
|
drh
|
544 |
} |
|
eb6611c…
|
drh
|
545 |
fossil_print("%s", zWebpageEnd); |
|
f3961f4…
|
drh
|
546 |
} |
|
1347a1d…
|
drh
|
547 |
if( (pCfg->diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){ |
|
c72c6df…
|
drh
|
548 |
char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename); |
|
f3961f4…
|
drh
|
549 |
fclose(diffOut); |
|
f48e48f…
|
drh
|
550 |
diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout); |
|
f3961f4…
|
drh
|
551 |
fossil_system(zCmd); |
|
f3961f4…
|
drh
|
552 |
fossil_free(zCmd); |
|
4291b9c…
|
drh
|
553 |
diffOut = 0; |
|
9a3372e…
|
drh
|
554 |
sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY); |
|
f3961f4…
|
drh
|
555 |
file_delete(tempDiffFilename); |
|
f3961f4…
|
drh
|
556 |
sqlite3_free(tempDiffFilename); |
|
f3961f4…
|
drh
|
557 |
tempDiffFilename = 0; |
|
f48e48f…
|
drh
|
558 |
} |
|
1347a1d…
|
drh
|
559 |
if( (pCfg->diffFlags & DIFF_JSON)!=0 && pCfg->nFile>0 ){ |
|
1347a1d…
|
drh
|
560 |
fossil_print("]\n"); |
|
1347a1d…
|
drh
|
561 |
} |
|
12a2a5e…
|
drh
|
562 |
} |
|
a51808c…
|
drh
|
563 |
|
|
a51808c…
|
drh
|
564 |
/* |
|
a51808c…
|
drh
|
565 |
** Show the difference between two files, one in memory and one on disk. |
|
a51808c…
|
drh
|
566 |
** |
|
a51808c…
|
drh
|
567 |
** The difference is the set of edits needed to transform pFile1 into |
|
a51808c…
|
drh
|
568 |
** zFile2. The content of pFile1 is in memory. zFile2 exists on disk. |
|
a51808c…
|
drh
|
569 |
*/ |
|
12a2a5e…
|
drh
|
570 |
void diff_file( |
|
a51808c…
|
drh
|
571 |
Blob *pFile1, /* In memory content to compare from */ |
|
a51808c…
|
drh
|
572 |
const char *zFile2, /* On disk content to compare to */ |
|
a51808c…
|
drh
|
573 |
const char *zName, /* Display name of the file */ |
|
1347a1d…
|
drh
|
574 |
DiffConfig *pCfg, /* Flags to control the diff */ |
|
590e01d…
|
drh
|
575 |
Blob *pOut /* Blob to store diff output */ |
|
a51808c…
|
drh
|
576 |
){ |
|
346de5d…
|
drh
|
577 |
if( pCfg->zDiffCmd==0 ){ |
|
585360b…
|
drh
|
578 |
Blob out; /* Diff output text */ |
|
585360b…
|
drh
|
579 |
Blob file2; /* Content of zFile2 */ |
|
585360b…
|
drh
|
580 |
const char *zName2; /* Name of zFile2 for display */ |
|
a51808c…
|
drh
|
581 |
|
|
a51808c…
|
drh
|
582 |
/* Read content of zFile2 into memory */ |
|
a51808c…
|
drh
|
583 |
blob_zero(&file2); |
|
caa6ad3…
|
drh
|
584 |
if( pCfg->diffFlags & DIFF_FILE_DELETED || file_size(zFile2, ExtFILE)<0 ){ |
|
135ed93…
|
drh
|
585 |
zName2 = NULL_DEVICE; |
|
135ed93…
|
drh
|
586 |
}else{ |
|
1772357…
|
drh
|
587 |
blob_read_from_file(&file2, zFile2, ExtFILE); |
|
585360b…
|
drh
|
588 |
zName2 = zName; |
|
585360b…
|
drh
|
589 |
} |
|
a51808c…
|
drh
|
590 |
|
|
a51808c…
|
drh
|
591 |
/* Compute and output the differences */ |
|
3732790…
|
danield
|
592 |
if( (pCfg->diffFlags & DIFF_BRIEF) && !(pCfg->diffFlags & DIFF_NUMSTAT) ){ |
|
fbaa7ca…
|
drh
|
593 |
if( blob_compare(pFile1, &file2) ){ |
|
fbaa7ca…
|
drh
|
594 |
fossil_print("CHANGED %s\n", zName); |
|
fbaa7ca…
|
drh
|
595 |
} |
|
fbaa7ca…
|
drh
|
596 |
}else{ |
|
fbaa7ca…
|
drh
|
597 |
blob_zero(&out); |
|
db034a5…
|
drh
|
598 |
text_diff(pFile1, &file2, &out, pCfg); |
|
1347a1d…
|
drh
|
599 |
if( blob_size(&out) ){ |
|
1347a1d…
|
drh
|
600 |
if( pCfg->diffFlags & DIFF_NUMSTAT ){ |
|
7bcd662…
|
drh
|
601 |
if( !(pCfg->diffFlags & DIFF_BRIEF) ){ |
|
3732790…
|
danield
|
602 |
blob_appendf(pOut, "%s %s\n", blob_str(&out), zName); |
|
7bcd662…
|
drh
|
603 |
} |
|
1347a1d…
|
drh
|
604 |
}else{ |
|
590e01d…
|
drh
|
605 |
diff_print_filenames(zName, zName2, pCfg, pOut); |
|
590e01d…
|
drh
|
606 |
blob_appendf(pOut, "%s\n", blob_str(&out)); |
|
3d6cf6a…
|
drh
|
607 |
} |
|
fbaa7ca…
|
drh
|
608 |
} |
|
fbaa7ca…
|
drh
|
609 |
blob_reset(&out); |
|
d5729c3…
|
drh
|
610 |
} |
|
a51808c…
|
drh
|
611 |
|
|
a51808c…
|
drh
|
612 |
/* Release memory resources */ |
|
a51808c…
|
drh
|
613 |
blob_reset(&file2); |
|
a51808c…
|
drh
|
614 |
}else{ |
|
a51808c…
|
drh
|
615 |
Blob nameFile1; /* Name of temporary file to old pFile1 content */ |
|
a51808c…
|
drh
|
616 |
Blob cmd; /* Text of command to run */ |
|
caa6ad3…
|
drh
|
617 |
int useTempfile = 1; |
|
f8339c2…
|
drh
|
618 |
|
|
346de5d…
|
drh
|
619 |
if( (pCfg->diffFlags & DIFF_INCBINARY)==0 ){ |
|
f8339c2…
|
drh
|
620 |
Blob file2; |
|
346de5d…
|
drh
|
621 |
if( looks_like_binary(pFile1) ){ |
|
49b0ff1…
|
drh
|
622 |
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); |
|
f8339c2…
|
drh
|
623 |
return; |
|
f8339c2…
|
drh
|
624 |
} |
|
346de5d…
|
drh
|
625 |
if( pCfg->zBinGlob ){ |
|
346de5d…
|
drh
|
626 |
Glob *pBinary = glob_create(pCfg->zBinGlob); |
|
f8339c2…
|
drh
|
627 |
if( glob_match(pBinary, zName) ){ |
|
49b0ff1…
|
drh
|
628 |
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); |
|
f8339c2…
|
drh
|
629 |
glob_free(pBinary); |
|
f8339c2…
|
drh
|
630 |
return; |
|
f8339c2…
|
drh
|
631 |
} |
|
f8339c2…
|
drh
|
632 |
glob_free(pBinary); |
|
f8339c2…
|
drh
|
633 |
} |
|
f8339c2…
|
drh
|
634 |
blob_zero(&file2); |
|
1772357…
|
drh
|
635 |
if( file_size(zFile2, ExtFILE)>=0 ){ |
|
1772357…
|
drh
|
636 |
blob_read_from_file(&file2, zFile2, ExtFILE); |
|
4e0e69f…
|
drh
|
637 |
} |
|
4e0e69f…
|
drh
|
638 |
if( looks_like_binary(&file2) ){ |
|
49b0ff1…
|
drh
|
639 |
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); |
|
f8339c2…
|
drh
|
640 |
blob_reset(&file2); |
|
f8339c2…
|
drh
|
641 |
return; |
|
f8339c2…
|
drh
|
642 |
} |
|
f8339c2…
|
drh
|
643 |
blob_reset(&file2); |
|
f8339c2…
|
drh
|
644 |
} |
|
a51808c…
|
drh
|
645 |
|
|
a51808c…
|
drh
|
646 |
/* Construct a temporary file to hold pFile1 based on the name of |
|
a51808c…
|
drh
|
647 |
** zFile2 */ |
|
1dd2527…
|
drh
|
648 |
file_tempname(&nameFile1, zFile2, "orig"); |
|
caa6ad3…
|
drh
|
649 |
#if !defined(_WIN32) |
|
caa6ad3…
|
drh
|
650 |
/* On Unix, use /dev/null for added or deleted files. */ |
|
caa6ad3…
|
drh
|
651 |
if( pCfg->diffFlags & DIFF_FILE_ADDED ){ |
|
caa6ad3…
|
drh
|
652 |
blob_init(&nameFile1, NULL_DEVICE, -1); |
|
caa6ad3…
|
drh
|
653 |
useTempfile = 0; |
|
caa6ad3…
|
drh
|
654 |
}else if( pCfg->diffFlags & DIFF_FILE_DELETED ){ |
|
caa6ad3…
|
drh
|
655 |
zFile2 = NULL_DEVICE; |
|
caa6ad3…
|
drh
|
656 |
} |
|
caa6ad3…
|
drh
|
657 |
#endif |
|
caa6ad3…
|
drh
|
658 |
if( useTempfile ) blob_write_to_file(pFile1, blob_str(&nameFile1)); |
|
a51808c…
|
drh
|
659 |
|
|
a51808c…
|
drh
|
660 |
/* Construct the external diff command */ |
|
a51808c…
|
drh
|
661 |
blob_zero(&cmd); |
|
346de5d…
|
drh
|
662 |
blob_append(&cmd, pCfg->zDiffCmd, -1); |
|
db034a5…
|
drh
|
663 |
if( pCfg->diffFlags & DIFF_INVERT ){ |
|
4f83d06…
|
drh
|
664 |
blob_append_escaped_arg(&cmd, zFile2, 1); |
|
4f83d06…
|
drh
|
665 |
blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1); |
|
2a47673…
|
mgagnon
|
666 |
}else{ |
|
4f83d06…
|
drh
|
667 |
blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1); |
|
4f83d06…
|
drh
|
668 |
blob_append_escaped_arg(&cmd, zFile2, 1); |
|
2a47673…
|
mgagnon
|
669 |
} |
|
a51808c…
|
drh
|
670 |
|
|
a51808c…
|
drh
|
671 |
/* Run the external diff command */ |
|
9b04150…
|
mgagnon
|
672 |
fossil_system(blob_str(&cmd)); |
|
a51808c…
|
drh
|
673 |
|
|
a51808c…
|
drh
|
674 |
/* Delete the temporary file and clean up memory used */ |
|
caa6ad3…
|
drh
|
675 |
if( useTempfile ) file_delete(blob_str(&nameFile1)); |
|
a51808c…
|
drh
|
676 |
blob_reset(&nameFile1); |
|
a51808c…
|
drh
|
677 |
blob_reset(&cmd); |
|
a51808c…
|
drh
|
678 |
} |
|
a51808c…
|
drh
|
679 |
} |
|
a51808c…
|
drh
|
680 |
|
|
a51808c…
|
drh
|
681 |
/* |
|
fe8bb01…
|
drh
|
682 |
** Show the difference between two files, both in memory. |
|
fe8bb01…
|
drh
|
683 |
** |
|
fe8bb01…
|
drh
|
684 |
** The difference is the set of edits needed to transform pFile1 into |
|
fe8bb01…
|
drh
|
685 |
** pFile2. |
|
fe8bb01…
|
drh
|
686 |
** |
|
fe8bb01…
|
drh
|
687 |
** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
|
fe8bb01…
|
drh
|
688 |
** command zDiffCmd to do the diffing. |
|
f8339c2…
|
drh
|
689 |
** |
|
f8339c2…
|
drh
|
690 |
** When using an external diff program, zBinGlob contains the GLOB patterns |
|
f8339c2…
|
drh
|
691 |
** for file names to treat as binary. If fIncludeBinary is zero, these files |
|
f8339c2…
|
drh
|
692 |
** will be skipped in addition to files that may contain binary content. |
|
fe8bb01…
|
drh
|
693 |
*/ |
|
12a2a5e…
|
drh
|
694 |
void diff_file_mem( |
|
fe8bb01…
|
drh
|
695 |
Blob *pFile1, /* In memory content to compare from */ |
|
fe8bb01…
|
drh
|
696 |
Blob *pFile2, /* In memory content to compare to */ |
|
fe8bb01…
|
drh
|
697 |
const char *zName, /* Display name of the file */ |
|
1347a1d…
|
drh
|
698 |
DiffConfig *pCfg /* Diff flags */ |
|
fe8bb01…
|
drh
|
699 |
){ |
|
3732790…
|
danield
|
700 |
if( (pCfg->diffFlags & DIFF_BRIEF) && !(pCfg->diffFlags & DIFF_NUMSTAT) ){ |
|
3732790…
|
danield
|
701 |
return; |
|
3732790…
|
danield
|
702 |
} |
|
346de5d…
|
drh
|
703 |
if( pCfg->zDiffCmd==0 ){ |
|
fe8bb01…
|
drh
|
704 |
Blob out; /* Diff output text */ |
|
fe8bb01…
|
drh
|
705 |
|
|
fe8bb01…
|
drh
|
706 |
blob_zero(&out); |
|
1347a1d…
|
drh
|
707 |
text_diff(pFile1, pFile2, &out, pCfg); |
|
1347a1d…
|
drh
|
708 |
if( pCfg->diffFlags & DIFF_NUMSTAT ){ |
|
7bcd662…
|
drh
|
709 |
if( !(pCfg->diffFlags & DIFF_BRIEF) ){ |
|
3732790…
|
danield
|
710 |
fossil_print("%s %s\n", blob_str(&out), zName); |
|
7bcd662…
|
drh
|
711 |
} |
|
3d6cf6a…
|
drh
|
712 |
}else{ |
|
1347a1d…
|
drh
|
713 |
diff_print_filenames(zName, zName, pCfg, 0); |
|
3d6cf6a…
|
drh
|
714 |
fossil_print("%s\n", blob_str(&out)); |
|
3d6cf6a…
|
drh
|
715 |
} |
|
86d4754…
|
jan.nijtmans
|
716 |
|
|
fe8bb01…
|
drh
|
717 |
/* Release memory resources */ |
|
fe8bb01…
|
drh
|
718 |
blob_reset(&out); |
|
fe8bb01…
|
drh
|
719 |
}else{ |
|
fe8bb01…
|
drh
|
720 |
Blob cmd; |
|
051d0ab…
|
drh
|
721 |
Blob temp1; |
|
051d0ab…
|
drh
|
722 |
Blob temp2; |
|
caa6ad3…
|
drh
|
723 |
int useTempfile1 = 1; |
|
caa6ad3…
|
drh
|
724 |
int useTempfile2 = 1; |
|
f8339c2…
|
drh
|
725 |
|
|
346de5d…
|
drh
|
726 |
if( (pCfg->diffFlags & DIFF_INCBINARY)==0 ){ |
|
346de5d…
|
drh
|
727 |
if( looks_like_binary(pFile1) || looks_like_binary(pFile2) ){ |
|
49b0ff1…
|
drh
|
728 |
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); |
|
f8339c2…
|
drh
|
729 |
return; |
|
f8339c2…
|
drh
|
730 |
} |
|
346de5d…
|
drh
|
731 |
if( pCfg->zBinGlob ){ |
|
346de5d…
|
drh
|
732 |
Glob *pBinary = glob_create(pCfg->zBinGlob); |
|
f8339c2…
|
drh
|
733 |
if( glob_match(pBinary, zName) ){ |
|
49b0ff1…
|
drh
|
734 |
fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY); |
|
f8339c2…
|
drh
|
735 |
glob_free(pBinary); |
|
f8339c2…
|
drh
|
736 |
return; |
|
f8339c2…
|
drh
|
737 |
} |
|
f8339c2…
|
drh
|
738 |
glob_free(pBinary); |
|
f8339c2…
|
drh
|
739 |
} |
|
f8339c2…
|
drh
|
740 |
} |
|
b66b99c…
|
jan.nijtmans
|
741 |
|
|
caa6ad3…
|
drh
|
742 |
/* Construct temporary file names */ |
|
1dd2527…
|
drh
|
743 |
file_tempname(&temp1, zName, "before"); |
|
1dd2527…
|
drh
|
744 |
file_tempname(&temp2, zName, "after"); |
|
caa6ad3…
|
drh
|
745 |
#if !defined(_WIN32) |
|
caa6ad3…
|
drh
|
746 |
/* On Unix, use /dev/null for added or deleted files. */ |
|
caa6ad3…
|
drh
|
747 |
if( pCfg->diffFlags & DIFF_FILE_ADDED ){ |
|
caa6ad3…
|
drh
|
748 |
useTempfile1 = 0; |
|
caa6ad3…
|
drh
|
749 |
blob_init(&temp1, NULL_DEVICE, -1); |
|
caa6ad3…
|
drh
|
750 |
}else if( pCfg->diffFlags & DIFF_FILE_DELETED ){ |
|
caa6ad3…
|
drh
|
751 |
useTempfile2 = 0; |
|
caa6ad3…
|
drh
|
752 |
blob_init(&temp2, NULL_DEVICE, -1); |
|
caa6ad3…
|
drh
|
753 |
} |
|
caa6ad3…
|
drh
|
754 |
#endif |
|
caa6ad3…
|
drh
|
755 |
if( useTempfile1 ) blob_write_to_file(pFile1, blob_str(&temp1)); |
|
caa6ad3…
|
drh
|
756 |
if( useTempfile2 ) blob_write_to_file(pFile2, blob_str(&temp2)); |
|
fe8bb01…
|
drh
|
757 |
|
|
fe8bb01…
|
drh
|
758 |
/* Construct the external diff command */ |
|
fe8bb01…
|
drh
|
759 |
blob_zero(&cmd); |
|
346de5d…
|
drh
|
760 |
blob_append(&cmd, pCfg->zDiffCmd, -1); |
|
4f83d06…
|
drh
|
761 |
blob_append_escaped_arg(&cmd, blob_str(&temp1), 1); |
|
4f83d06…
|
drh
|
762 |
blob_append_escaped_arg(&cmd, blob_str(&temp2), 1); |
|
fe8bb01…
|
drh
|
763 |
|
|
fe8bb01…
|
drh
|
764 |
/* Run the external diff command */ |
|
d9880a8…
|
drh
|
765 |
fossil_system(blob_str(&cmd)); |
|
fe8bb01…
|
drh
|
766 |
|
|
fe8bb01…
|
drh
|
767 |
/* Delete the temporary file and clean up memory used */ |
|
caa6ad3…
|
drh
|
768 |
if( useTempfile1 ) file_delete(blob_str(&temp1)); |
|
caa6ad3…
|
drh
|
769 |
if( useTempfile2 ) file_delete(blob_str(&temp2)); |
|
051d0ab…
|
drh
|
770 |
|
|
051d0ab…
|
drh
|
771 |
blob_reset(&temp1); |
|
051d0ab…
|
drh
|
772 |
blob_reset(&temp2); |
|
fe8bb01…
|
drh
|
773 |
blob_reset(&cmd); |
|
fe8bb01…
|
drh
|
774 |
} |
|
fe8bb01…
|
drh
|
775 |
} |
|
fe8bb01…
|
drh
|
776 |
|
|
fe8bb01…
|
drh
|
777 |
/* |
|
fb2d637…
|
js
|
778 |
** Return true if the disk file is identical to the Blob. Return zero |
|
960c9e8…
|
drh
|
779 |
** if the files differ in any way. |
|
960c9e8…
|
drh
|
780 |
*/ |
|
960c9e8…
|
drh
|
781 |
static int file_same_as_blob(Blob *blob, const char *zDiskFile){ |
|
960c9e8…
|
drh
|
782 |
Blob file; |
|
960c9e8…
|
drh
|
783 |
int rc = 0; |
|
960c9e8…
|
drh
|
784 |
if( blob_size(blob)!=file_size(zDiskFile, ExtFILE) ) return 0; |
|
960c9e8…
|
drh
|
785 |
blob_zero(&file); |
|
960c9e8…
|
drh
|
786 |
blob_read_from_file(&file, zDiskFile, ExtFILE); |
|
960c9e8…
|
drh
|
787 |
if( blob_size(&file)!=blob_size(blob) ){ |
|
960c9e8…
|
drh
|
788 |
rc = 0; |
|
960c9e8…
|
drh
|
789 |
}else{ |
|
960c9e8…
|
drh
|
790 |
rc = memcmp(blob_buffer(&file), blob_buffer(blob), blob_size(&file))==0; |
|
960c9e8…
|
drh
|
791 |
} |
|
960c9e8…
|
drh
|
792 |
blob_reset(&file); |
|
960c9e8…
|
drh
|
793 |
return rc; |
|
960c9e8…
|
drh
|
794 |
} |
|
960c9e8…
|
drh
|
795 |
|
|
960c9e8…
|
drh
|
796 |
/* |
|
99d0baa…
|
drh
|
797 |
** Run a diff between the version zFrom and files on disk in the current |
|
99d0baa…
|
drh
|
798 |
** working checkout. zFrom might be NULL which means to simply show the |
|
99d0baa…
|
drh
|
799 |
** difference between the edited files on disk and the check-out on which |
|
99d0baa…
|
drh
|
800 |
** they are based. |
|
f8339c2…
|
drh
|
801 |
** |
|
f8339c2…
|
drh
|
802 |
** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
|
f8339c2…
|
drh
|
803 |
** command zDiffCmd to do the diffing. |
|
f8339c2…
|
drh
|
804 |
** |
|
f8339c2…
|
drh
|
805 |
** When using an external diff program, zBinGlob contains the GLOB patterns |
|
f8339c2…
|
drh
|
806 |
** for file names to treat as binary. If fIncludeBinary is zero, these files |
|
f8339c2…
|
drh
|
807 |
** will be skipped in addition to files that may contain binary content. |
|
a51808c…
|
drh
|
808 |
*/ |
|
99d0baa…
|
drh
|
809 |
void diff_version_to_checkout( |
|
5ef7435…
|
drh
|
810 |
const char *zFrom, /* Version to difference from */ |
|
1347a1d…
|
drh
|
811 |
DiffConfig *pCfg, /* Flags controlling diff output */ |
|
7ee98fe…
|
drh
|
812 |
FileDirList *pFileDir, /* Which files to diff */ |
|
99d0baa…
|
drh
|
813 |
Blob *pOut /* Blob to output diff instead of stdout */ |
|
5ef7435…
|
drh
|
814 |
){ |
|
c863ec1…
|
drh
|
815 |
int vid; |
|
a51808c…
|
drh
|
816 |
Blob sql; |
|
a51808c…
|
drh
|
817 |
Stmt q; |
|
e2bdc10…
|
danield
|
818 |
int asNewFile; /* Treat non-existent files as empty files */ |
|
3d6cf6a…
|
drh
|
819 |
int isNumStat; /* True for --numstat */ |
|
a51808c…
|
drh
|
820 |
|
|
1347a1d…
|
drh
|
821 |
asNewFile = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0; |
|
1347a1d…
|
drh
|
822 |
isNumStat = (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0; |
|
c863ec1…
|
drh
|
823 |
vid = db_lget_int("checkout", 0); |
|
ae092ec…
|
drh
|
824 |
vfile_check_signature(vid, CKSIG_ENOTFILE); |
|
a51808c…
|
drh
|
825 |
blob_zero(&sql); |
|
a51808c…
|
drh
|
826 |
db_begin_transaction(); |
|
a51808c…
|
drh
|
827 |
if( zFrom ){ |
|
2a013f0…
|
drh
|
828 |
int rid = name_to_typed_rid(zFrom, "ci"); |
|
a51808c…
|
drh
|
829 |
if( !is_a_version(rid) ){ |
|
a51808c…
|
drh
|
830 |
fossil_fatal("no such check-in: %s", zFrom); |
|
a51808c…
|
drh
|
831 |
} |
|
a51808c…
|
drh
|
832 |
load_vfile_from_rid(rid); |
|
49b0ff1…
|
drh
|
833 |
blob_append_sql(&sql, |
|
e4f1c1f…
|
drh
|
834 |
"SELECT v2.pathname, v2.deleted, v2.chnged, v2.rid==0, v1.rid, v1.islink" |
|
a51808c…
|
drh
|
835 |
" FROM vfile v1, vfile v2 " |
|
a51808c…
|
drh
|
836 |
" WHERE v1.pathname=v2.pathname AND v1.vid=%d AND v2.vid=%d" |
|
34341a1…
|
drh
|
837 |
" AND (v2.deleted OR v2.chnged OR v1.mrid!=v2.rid)" |
|
a51808c…
|
drh
|
838 |
"UNION " |
|
e4f1c1f…
|
drh
|
839 |
"SELECT pathname, 1, 0, 0, 0, islink" |
|
a51808c…
|
drh
|
840 |
" FROM vfile v1" |
|
a51808c…
|
drh
|
841 |
" WHERE v1.vid=%d" |
|
a51808c…
|
drh
|
842 |
" AND NOT EXISTS(SELECT 1 FROM vfile v2" |
|
a51808c…
|
drh
|
843 |
" WHERE v2.vid=%d AND v2.pathname=v1.pathname)" |
|
a51808c…
|
drh
|
844 |
"UNION " |
|
e4f1c1f…
|
drh
|
845 |
"SELECT pathname, 0, 0, 1, 0, islink" |
|
a51808c…
|
drh
|
846 |
" FROM vfile v2" |
|
a51808c…
|
drh
|
847 |
" WHERE v2.vid=%d" |
|
a51808c…
|
drh
|
848 |
" AND NOT EXISTS(SELECT 1 FROM vfile v1" |
|
a51808c…
|
drh
|
849 |
" WHERE v1.vid=%d AND v1.pathname=v2.pathname)" |
|
421c9ee…
|
drh
|
850 |
" ORDER BY 1 /*scan*/", |
|
a51808c…
|
drh
|
851 |
rid, vid, rid, vid, vid, rid |
|
a51808c…
|
drh
|
852 |
); |
|
a51808c…
|
drh
|
853 |
}else{ |
|
49b0ff1…
|
drh
|
854 |
blob_append_sql(&sql, |
|
e4f1c1f…
|
drh
|
855 |
"SELECT pathname, deleted, chnged , rid==0, rid, islink" |
|
a51808c…
|
drh
|
856 |
" FROM vfile" |
|
a51808c…
|
drh
|
857 |
" WHERE vid=%d" |
|
a51808c…
|
drh
|
858 |
" AND (deleted OR chnged OR rid==0)" |
|
421c9ee…
|
drh
|
859 |
" ORDER BY pathname /*scan*/", |
|
a51808c…
|
drh
|
860 |
vid |
|
a51808c…
|
drh
|
861 |
); |
|
a51808c…
|
drh
|
862 |
} |
|
41f6a45…
|
danield
|
863 |
if( (pCfg->diffFlags & DIFF_SHOW_VERS)!=0 ){ |
|
41f6a45…
|
danield
|
864 |
diff_print_versions(zFrom ? zFrom : db_lget("checkout-hash", 0), |
|
41f6a45…
|
danield
|
865 |
"(workdir)", pCfg); |
|
41f6a45…
|
danield
|
866 |
} |
|
49b0ff1…
|
drh
|
867 |
db_prepare(&q, "%s", blob_sql_text(&sql)); |
|
36babe0…
|
drh
|
868 |
blob_reset(&sql); |
|
c863ec1…
|
drh
|
869 |
while( db_step(&q)==SQLITE_ROW ){ |
|
c863ec1…
|
drh
|
870 |
const char *zPathname = db_column_text(&q,0); |
|
c863ec1…
|
drh
|
871 |
int isDeleted = db_column_int(&q, 1); |
|
c863ec1…
|
drh
|
872 |
int isChnged = db_column_int(&q,2); |
|
a51808c…
|
drh
|
873 |
int isNew = db_column_int(&q,3); |
|
585360b…
|
drh
|
874 |
int srcid = db_column_int(&q, 4); |
|
e4f1c1f…
|
drh
|
875 |
int isLink = db_column_int(&q, 5); |
|
825d78b…
|
mistachkin
|
876 |
const char *zFullName; |
|
585360b…
|
drh
|
877 |
int showDiff = 1; |
|
825d78b…
|
mistachkin
|
878 |
Blob fname; |
|
825d78b…
|
mistachkin
|
879 |
|
|
c46f980…
|
drh
|
880 |
if( !file_dir_match(pFileDir, zPathname) ) continue; |
|
825d78b…
|
mistachkin
|
881 |
if( determine_exec_relative_option(0) ){ |
|
825d78b…
|
mistachkin
|
882 |
blob_zero(&fname); |
|
825d78b…
|
mistachkin
|
883 |
file_relative_name(zPathname, &fname, 1); |
|
825d78b…
|
mistachkin
|
884 |
}else{ |
|
825d78b…
|
mistachkin
|
885 |
blob_set(&fname, g.zLocalRoot); |
|
825d78b…
|
mistachkin
|
886 |
blob_append(&fname, zPathname, -1); |
|
825d78b…
|
mistachkin
|
887 |
} |
|
825d78b…
|
mistachkin
|
888 |
zFullName = blob_str(&fname); |
|
caa6ad3…
|
drh
|
889 |
pCfg->diffFlags &= (~DIFF_FILE_MASK); |
|
585360b…
|
drh
|
890 |
if( isDeleted ){ |
|
3d6cf6a…
|
drh
|
891 |
if( !isNumStat ){ fossil_print("DELETED %s\n", zPathname); } |
|
caa6ad3…
|
drh
|
892 |
pCfg->diffFlags |= DIFF_FILE_DELETED; |
|
135ed93…
|
drh
|
893 |
if( !asNewFile ){ showDiff = 0; zFullName = NULL_DEVICE; } |
|
9df71fe…
|
jan.nijtmans
|
894 |
}else if( file_access(zFullName, F_OK) ){ |
|
3d6cf6a…
|
drh
|
895 |
if( !isNumStat ){ fossil_print("MISSING %s\n", zPathname); } |
|
585360b…
|
drh
|
896 |
if( !asNewFile ){ showDiff = 0; } |
|
585360b…
|
drh
|
897 |
}else if( isNew ){ |
|
3d6cf6a…
|
drh
|
898 |
if( !isNumStat ){ fossil_print("ADDED %s\n", zPathname); } |
|
caa6ad3…
|
drh
|
899 |
pCfg->diffFlags |= DIFF_FILE_ADDED; |
|
585360b…
|
drh
|
900 |
srcid = 0; |
|
585360b…
|
drh
|
901 |
if( !asNewFile ){ showDiff = 0; } |
|
585360b…
|
drh
|
902 |
}else if( isChnged==3 ){ |
|
3d6cf6a…
|
drh
|
903 |
if( !isNumStat ){ fossil_print("ADDED_BY_MERGE %s\n", zPathname); } |
|
caa6ad3…
|
drh
|
904 |
pCfg->diffFlags |= DIFF_FILE_ADDED; |
|
a6b999c…
|
mistachkin
|
905 |
srcid = 0; |
|
a6b999c…
|
mistachkin
|
906 |
if( !asNewFile ){ showDiff = 0; } |
|
a6b999c…
|
mistachkin
|
907 |
}else if( isChnged==5 ){ |
|
3d6cf6a…
|
drh
|
908 |
if( !isNumStat ){ fossil_print("ADDED_BY_INTEGRATE %s\n", zPathname); } |
|
caa6ad3…
|
drh
|
909 |
pCfg->diffFlags |= DIFF_FILE_ADDED; |
|
585360b…
|
drh
|
910 |
srcid = 0; |
|
585360b…
|
drh
|
911 |
if( !asNewFile ){ showDiff = 0; } |
|
585360b…
|
drh
|
912 |
} |
|
fbaa7ca…
|
drh
|
913 |
if( showDiff ){ |
|
a51808c…
|
drh
|
914 |
Blob content; |
|
1772357…
|
drh
|
915 |
if( !isLink != !file_islink(zFullName) ){ |
|
1347a1d…
|
drh
|
916 |
diff_print_index(zPathname, pCfg, 0); |
|
1347a1d…
|
drh
|
917 |
diff_print_filenames(zPathname, zPathname, pCfg, 0); |
|
49b0ff1…
|
drh
|
918 |
fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK); |
|
e4f1c1f…
|
drh
|
919 |
continue; |
|
e4f1c1f…
|
drh
|
920 |
} |
|
585360b…
|
drh
|
921 |
if( srcid>0 ){ |
|
585360b…
|
drh
|
922 |
content_get(srcid, &content); |
|
585360b…
|
drh
|
923 |
}else{ |
|
585360b…
|
drh
|
924 |
blob_zero(&content); |
|
585360b…
|
drh
|
925 |
} |
|
caa6ad3…
|
drh
|
926 |
if( isChnged==0 |
|
caa6ad3…
|
drh
|
927 |
|| pCfg->diffFlags & DIFF_FILE_DELETED |
|
caa6ad3…
|
drh
|
928 |
|| !file_same_as_blob(&content, zFullName) |
|
caa6ad3…
|
drh
|
929 |
){ |
|
960c9e8…
|
drh
|
930 |
diff_print_index(zPathname, pCfg, pOut); |
|
960c9e8…
|
drh
|
931 |
diff_file(&content, zFullName, zPathname, pCfg, pOut); |
|
960c9e8…
|
drh
|
932 |
} |
|
a51808c…
|
drh
|
933 |
blob_reset(&content); |
|
a51808c…
|
drh
|
934 |
} |
|
825d78b…
|
mistachkin
|
935 |
blob_reset(&fname); |
|
296b90a…
|
drh
|
936 |
} |
|
296b90a…
|
drh
|
937 |
db_finalize(&q); |
|
296b90a…
|
drh
|
938 |
db_end_transaction(1); /* ROLLBACK */ |
|
296b90a…
|
drh
|
939 |
} |
|
296b90a…
|
drh
|
940 |
|
|
296b90a…
|
drh
|
941 |
/* |
|
99d0baa…
|
drh
|
942 |
** Run a diff from the undo buffer to files on disk. |
|
f8339c2…
|
drh
|
943 |
** |
|
f8339c2…
|
drh
|
944 |
** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
|
f8339c2…
|
drh
|
945 |
** command zDiffCmd to do the diffing. |
|
f8339c2…
|
drh
|
946 |
** |
|
f8339c2…
|
drh
|
947 |
** When using an external diff program, zBinGlob contains the GLOB patterns |
|
f8339c2…
|
drh
|
948 |
** for file names to treat as binary. If fIncludeBinary is zero, these files |
|
f8339c2…
|
drh
|
949 |
** will be skipped in addition to files that may contain binary content. |
|
7036534…
|
drh
|
950 |
*/ |
|
99d0baa…
|
drh
|
951 |
static void diff_undo_to_checkout( |
|
1347a1d…
|
drh
|
952 |
DiffConfig *pCfg, /* Flags controlling diff output */ |
|
c46f980…
|
drh
|
953 |
FileDirList *pFileDir /* List of files and directories to diff */ |
|
7036534…
|
drh
|
954 |
){ |
|
485aa80…
|
drh
|
955 |
Stmt q; |
|
f6c1363…
|
drh
|
956 |
Blob content; |
|
f6c1363…
|
drh
|
957 |
db_prepare(&q, "SELECT pathname, content FROM undo"); |
|
f6c1363…
|
drh
|
958 |
blob_init(&content, 0, 0); |
|
41f6a45…
|
danield
|
959 |
if( (pCfg->diffFlags & DIFF_SHOW_VERS)!=0 ){ |
|
41f6a45…
|
danield
|
960 |
diff_print_versions("(undo)", "(workdir)", pCfg); |
|
275da70…
|
danield
|
961 |
} |
|
485aa80…
|
drh
|
962 |
while( db_step(&q)==SQLITE_ROW ){ |
|
c46f980…
|
drh
|
963 |
char *zFullName; |
|
f6c1363…
|
drh
|
964 |
const char *zFile = (const char*)db_column_text(&q, 0); |
|
c46f980…
|
drh
|
965 |
if( !file_dir_match(pFileDir, zFile) ) continue; |
|
c46f980…
|
drh
|
966 |
zFullName = mprintf("%s%s", g.zLocalRoot, zFile); |
|
f6c1363…
|
drh
|
967 |
db_column_blob(&q, 1, &content); |
|
db034a5…
|
drh
|
968 |
diff_file(&content, zFullName, zFile, pCfg, 0); |
|
f6c1363…
|
drh
|
969 |
fossil_free(zFullName); |
|
f6c1363…
|
drh
|
970 |
blob_reset(&content); |
|
485aa80…
|
drh
|
971 |
} |
|
485aa80…
|
drh
|
972 |
db_finalize(&q); |
|
7036534…
|
drh
|
973 |
} |
|
7036534…
|
drh
|
974 |
|
|
7036534…
|
drh
|
975 |
/* |
|
7036534…
|
drh
|
976 |
** Show the difference between two files identified by ManifestFile |
|
7036534…
|
drh
|
977 |
** entries. |
|
f8339c2…
|
drh
|
978 |
** |
|
f8339c2…
|
drh
|
979 |
** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
|
f8339c2…
|
drh
|
980 |
** command zDiffCmd to do the diffing. |
|
f8339c2…
|
drh
|
981 |
** |
|
f8339c2…
|
drh
|
982 |
** When using an external diff program, zBinGlob contains the GLOB patterns |
|
f8339c2…
|
drh
|
983 |
** for file names to treat as binary. If fIncludeBinary is zero, these files |
|
f8339c2…
|
drh
|
984 |
** will be skipped in addition to files that may contain binary content. |
|
fe8bb01…
|
drh
|
985 |
*/ |
|
7036534…
|
drh
|
986 |
static void diff_manifest_entry( |
|
7036534…
|
drh
|
987 |
struct ManifestFile *pFrom, |
|
7036534…
|
drh
|
988 |
struct ManifestFile *pTo, |
|
1347a1d…
|
drh
|
989 |
DiffConfig *pCfg |
|
fe8bb01…
|
drh
|
990 |
){ |
|
7036534…
|
drh
|
991 |
Blob f1, f2; |
|
7036534…
|
drh
|
992 |
int rid; |
|
7807ec4…
|
mistachkin
|
993 |
const char *zName; |
|
7807ec4…
|
mistachkin
|
994 |
if( pFrom ){ |
|
7807ec4…
|
mistachkin
|
995 |
zName = pFrom->zName; |
|
7807ec4…
|
mistachkin
|
996 |
}else if( pTo ){ |
|
7807ec4…
|
mistachkin
|
997 |
zName = pTo->zName; |
|
7807ec4…
|
mistachkin
|
998 |
}else{ |
|
7807ec4…
|
mistachkin
|
999 |
zName = DIFF_NO_NAME; |
|
7807ec4…
|
mistachkin
|
1000 |
} |
|
3732790…
|
danield
|
1001 |
if( (pCfg->diffFlags & DIFF_BRIEF) && !(pCfg->diffFlags & DIFF_NUMSTAT) ){ |
|
3732790…
|
danield
|
1002 |
return; |
|
3732790…
|
danield
|
1003 |
} |
|
1347a1d…
|
drh
|
1004 |
diff_print_index(zName, pCfg, 0); |
|
7036534…
|
drh
|
1005 |
if( pFrom ){ |
|
7036534…
|
drh
|
1006 |
rid = uuid_to_rid(pFrom->zUuid, 0); |
|
7036534…
|
drh
|
1007 |
content_get(rid, &f1); |
|
7036534…
|
drh
|
1008 |
}else{ |
|
7036534…
|
drh
|
1009 |
blob_zero(&f1); |
|
7036534…
|
drh
|
1010 |
} |
|
7036534…
|
drh
|
1011 |
if( pTo ){ |
|
7036534…
|
drh
|
1012 |
rid = uuid_to_rid(pTo->zUuid, 0); |
|
7036534…
|
drh
|
1013 |
content_get(rid, &f2); |
|
7036534…
|
drh
|
1014 |
}else{ |
|
7036534…
|
drh
|
1015 |
blob_zero(&f2); |
|
7036534…
|
drh
|
1016 |
} |
|
346de5d…
|
drh
|
1017 |
diff_file_mem(&f1, &f2, zName, pCfg); |
|
7036534…
|
drh
|
1018 |
blob_reset(&f1); |
|
7036534…
|
drh
|
1019 |
blob_reset(&f2); |
|
fe8bb01…
|
drh
|
1020 |
} |
|
fe8bb01…
|
drh
|
1021 |
|
|
fe8bb01…
|
drh
|
1022 |
/* |
|
fe8bb01…
|
drh
|
1023 |
** Output the differences between two check-ins. |
|
f8339c2…
|
drh
|
1024 |
** |
|
f8339c2…
|
drh
|
1025 |
** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
|
f8339c2…
|
drh
|
1026 |
** command zDiffCmd to do the diffing. |
|
f8339c2…
|
drh
|
1027 |
** |
|
f8339c2…
|
drh
|
1028 |
** When using an external diff program, zBinGlob contains the GLOB patterns |
|
f8339c2…
|
drh
|
1029 |
** for file names to treat as binary. If fIncludeBinary is zero, these files |
|
f8339c2…
|
drh
|
1030 |
** will be skipped in addition to files that may contain binary content. |
|
fe8bb01…
|
drh
|
1031 |
*/ |
|
c46f980…
|
drh
|
1032 |
static void diff_two_versions( |
|
fe8bb01…
|
drh
|
1033 |
const char *zFrom, |
|
fe8bb01…
|
drh
|
1034 |
const char *zTo, |
|
1347a1d…
|
drh
|
1035 |
DiffConfig *pCfg, |
|
c46f980…
|
drh
|
1036 |
FileDirList *pFileDir |
|
296b90a…
|
drh
|
1037 |
){ |
|
d13054c…
|
drh
|
1038 |
Manifest *pFrom, *pTo; |
|
d13054c…
|
drh
|
1039 |
ManifestFile *pFromFile, *pToFile; |
|
1347a1d…
|
drh
|
1040 |
int asNewFlag = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0; |
|
d13054c…
|
drh
|
1041 |
|
|
d13054c…
|
drh
|
1042 |
pFrom = manifest_get_by_name(zFrom, 0); |
|
d13054c…
|
drh
|
1043 |
manifest_file_rewind(pFrom); |
|
d13054c…
|
drh
|
1044 |
pFromFile = manifest_file_next(pFrom,0); |
|
d13054c…
|
drh
|
1045 |
pTo = manifest_get_by_name(zTo, 0); |
|
d13054c…
|
drh
|
1046 |
manifest_file_rewind(pTo); |
|
d13054c…
|
drh
|
1047 |
pToFile = manifest_file_next(pTo,0); |
|
41f6a45…
|
danield
|
1048 |
if( (pCfg->diffFlags & DIFF_SHOW_VERS)!=0 ){ |
|
41f6a45…
|
danield
|
1049 |
diff_print_versions(zFrom, zTo, pCfg); |
|
275da70…
|
danield
|
1050 |
} |
|
d13054c…
|
drh
|
1051 |
while( pFromFile || pToFile ){ |
|
296b90a…
|
drh
|
1052 |
int cmp; |
|
d13054c…
|
drh
|
1053 |
if( pFromFile==0 ){ |
|
296b90a…
|
drh
|
1054 |
cmp = +1; |
|
d13054c…
|
drh
|
1055 |
}else if( pToFile==0 ){ |
|
296b90a…
|
drh
|
1056 |
cmp = -1; |
|
296b90a…
|
drh
|
1057 |
}else{ |
|
31c52c7…
|
drh
|
1058 |
cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); |
|
296b90a…
|
drh
|
1059 |
} |
|
caa6ad3…
|
drh
|
1060 |
pCfg->diffFlags &= (~DIFF_FILE_MASK); |
|
296b90a…
|
drh
|
1061 |
if( cmp<0 ){ |
|
c46f980…
|
drh
|
1062 |
if( file_dir_match(pFileDir, pFromFile->zName) ){ |
|
1347a1d…
|
drh
|
1063 |
if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){ |
|
3d6cf6a…
|
drh
|
1064 |
fossil_print("DELETED %s\n", pFromFile->zName); |
|
3d6cf6a…
|
drh
|
1065 |
} |
|
caa6ad3…
|
drh
|
1066 |
pCfg->diffFlags |= DIFF_FILE_DELETED; |
|
c46f980…
|
drh
|
1067 |
if( asNewFlag ){ |
|
346de5d…
|
drh
|
1068 |
diff_manifest_entry(pFromFile, 0, pCfg); |
|
c46f980…
|
drh
|
1069 |
} |
|
7036534…
|
drh
|
1070 |
} |
|
d13054c…
|
drh
|
1071 |
pFromFile = manifest_file_next(pFrom,0); |
|
296b90a…
|
drh
|
1072 |
}else if( cmp>0 ){ |
|
c46f980…
|
drh
|
1073 |
if( file_dir_match(pFileDir, pToFile->zName) ){ |
|
1347a1d…
|
drh
|
1074 |
if( (pCfg->diffFlags & |
|
1347a1d…
|
drh
|
1075 |
(DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){ |
|
3d6cf6a…
|
drh
|
1076 |
fossil_print("ADDED %s\n", pToFile->zName); |
|
3d6cf6a…
|
drh
|
1077 |
} |
|
caa6ad3…
|
drh
|
1078 |
pCfg->diffFlags |= DIFF_FILE_ADDED; |
|
c46f980…
|
drh
|
1079 |
if( asNewFlag ){ |
|
346de5d…
|
drh
|
1080 |
diff_manifest_entry(0, pToFile, pCfg); |
|
c46f980…
|
drh
|
1081 |
} |
|
7036534…
|
drh
|
1082 |
} |
|
d13054c…
|
drh
|
1083 |
pToFile = manifest_file_next(pTo,0); |
|
31c52c7…
|
drh
|
1084 |
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ |
|
296b90a…
|
drh
|
1085 |
/* No changes */ |
|
c46f980…
|
drh
|
1086 |
(void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */ |
|
d13054c…
|
drh
|
1087 |
pFromFile = manifest_file_next(pFrom,0); |
|
d13054c…
|
drh
|
1088 |
pToFile = manifest_file_next(pTo,0); |
|
d13054c…
|
drh
|
1089 |
}else{ |
|
c46f980…
|
drh
|
1090 |
if( file_dir_match(pFileDir, pToFile->zName) ){ |
|
3732790…
|
danield
|
1091 |
if((pCfg->diffFlags & DIFF_BRIEF) && !(pCfg->diffFlags & DIFF_NUMSTAT)){ |
|
c46f980…
|
drh
|
1092 |
fossil_print("CHANGED %s\n", pFromFile->zName); |
|
c46f980…
|
drh
|
1093 |
}else{ |
|
346de5d…
|
drh
|
1094 |
diff_manifest_entry(pFromFile, pToFile, pCfg); |
|
c46f980…
|
drh
|
1095 |
} |
|
e0565d4…
|
drh
|
1096 |
} |
|
d13054c…
|
drh
|
1097 |
pFromFile = manifest_file_next(pFrom,0); |
|
d13054c…
|
drh
|
1098 |
pToFile = manifest_file_next(pTo,0); |
|
d13054c…
|
drh
|
1099 |
} |
|
d13054c…
|
drh
|
1100 |
} |
|
d13054c…
|
drh
|
1101 |
manifest_destroy(pFrom); |
|
d13054c…
|
drh
|
1102 |
manifest_destroy(pTo); |
|
d13054c…
|
drh
|
1103 |
} |
|
d13054c…
|
drh
|
1104 |
|
|
d13054c…
|
drh
|
1105 |
/* |
|
99d0baa…
|
drh
|
1106 |
** Compute the difference from an external tree of files to the current |
|
99d0baa…
|
drh
|
1107 |
** working checkout with its edits. |
|
99d0baa…
|
drh
|
1108 |
** |
|
99d0baa…
|
drh
|
1109 |
** To put it another way: Every managed file in the current working |
|
36f3549…
|
brickviking
|
1110 |
** checkout is compared to the file with same name under zExternBase. The |
|
99d0baa…
|
drh
|
1111 |
** zExternBase files are on the left and the files in the current working |
|
99d0baa…
|
drh
|
1112 |
** directory are on the right. |
|
99d0baa…
|
drh
|
1113 |
*/ |
|
99d0baa…
|
drh
|
1114 |
void diff_externbase_to_checkout( |
|
99d0baa…
|
drh
|
1115 |
const char *zExternBase, /* Remote tree to use as the baseline */ |
|
99d0baa…
|
drh
|
1116 |
DiffConfig *pCfg, /* Diff settings */ |
|
99d0baa…
|
drh
|
1117 |
FileDirList *pFileDir /* Only look at these files */ |
|
99d0baa…
|
drh
|
1118 |
){ |
|
99d0baa…
|
drh
|
1119 |
int vid; |
|
99d0baa…
|
drh
|
1120 |
Stmt q; |
|
99d0baa…
|
drh
|
1121 |
|
|
99d0baa…
|
drh
|
1122 |
vid = db_lget_int("checkout",0); |
|
99d0baa…
|
drh
|
1123 |
if( file_isdir(zExternBase, ExtFILE)!=1 ){ |
|
99d0baa…
|
drh
|
1124 |
fossil_fatal("\"%s\" is not a directory", zExternBase); |
|
99d0baa…
|
drh
|
1125 |
} |
|
99d0baa…
|
drh
|
1126 |
db_prepare(&q, |
|
99d0baa…
|
drh
|
1127 |
"SELECT pathname FROM vfile WHERE vid=%d ORDER BY pathname", |
|
99d0baa…
|
drh
|
1128 |
vid |
|
99d0baa…
|
drh
|
1129 |
); |
|
99d0baa…
|
drh
|
1130 |
while( db_step(&q)==SQLITE_ROW ){ |
|
99d0baa…
|
drh
|
1131 |
const char *zFile; /* Name of file in the repository */ |
|
99d0baa…
|
drh
|
1132 |
char *zLhs; /* Full name of left-hand side file */ |
|
99d0baa…
|
drh
|
1133 |
char *zRhs; /* Full name of right-hand side file */ |
|
99d0baa…
|
drh
|
1134 |
Blob rhs; /* Full text of RHS */ |
|
99d0baa…
|
drh
|
1135 |
Blob lhs; /* Full text of LHS */ |
|
99d0baa…
|
drh
|
1136 |
|
|
99d0baa…
|
drh
|
1137 |
zFile = db_column_text(&q,0); |
|
99d0baa…
|
drh
|
1138 |
if( !file_dir_match(pFileDir, zFile) ) continue; |
|
99d0baa…
|
drh
|
1139 |
zLhs = mprintf("%s/%s", zExternBase, zFile); |
|
99d0baa…
|
drh
|
1140 |
zRhs = mprintf("%s%s", g.zLocalRoot, zFile); |
|
99d0baa…
|
drh
|
1141 |
if( file_size(zLhs, ExtFILE)<0 ){ |
|
99d0baa…
|
drh
|
1142 |
blob_zero(&lhs); |
|
99d0baa…
|
drh
|
1143 |
}else{ |
|
99d0baa…
|
drh
|
1144 |
blob_read_from_file(&lhs, zLhs, ExtFILE); |
|
99d0baa…
|
drh
|
1145 |
} |
|
99d0baa…
|
drh
|
1146 |
blob_read_from_file(&rhs, zRhs, ExtFILE); |
|
99d0baa…
|
drh
|
1147 |
if( blob_size(&lhs)!=blob_size(&rhs) |
|
99d0baa…
|
drh
|
1148 |
|| memcmp(blob_buffer(&lhs), blob_buffer(&rhs), blob_size(&lhs))!=0 |
|
99d0baa…
|
drh
|
1149 |
){ |
|
99d0baa…
|
drh
|
1150 |
diff_print_index(zFile, pCfg, 0); |
|
99d0baa…
|
drh
|
1151 |
diff_file_mem(&lhs, &rhs, zFile, pCfg); |
|
99d0baa…
|
drh
|
1152 |
} |
|
99d0baa…
|
drh
|
1153 |
blob_reset(&lhs); |
|
99d0baa…
|
drh
|
1154 |
blob_reset(&rhs); |
|
99d0baa…
|
drh
|
1155 |
fossil_free(zLhs); |
|
99d0baa…
|
drh
|
1156 |
fossil_free(zRhs); |
|
99d0baa…
|
drh
|
1157 |
} |
|
99d0baa…
|
drh
|
1158 |
db_finalize(&q); |
|
99d0baa…
|
drh
|
1159 |
} |
|
99d0baa…
|
drh
|
1160 |
|
|
99d0baa…
|
drh
|
1161 |
|
|
99d0baa…
|
drh
|
1162 |
/* |
|
cad57bf…
|
drh
|
1163 |
** Return the name of the external diff command, or return NULL if |
|
cad57bf…
|
drh
|
1164 |
** no external diff command is defined. |
|
cad57bf…
|
drh
|
1165 |
*/ |
|
cad57bf…
|
drh
|
1166 |
const char *diff_command_external(int guiDiff){ |
|
cad57bf…
|
drh
|
1167 |
const char *zName; |
|
954fb42…
|
drh
|
1168 |
zName = guiDiff ? "gdiff-command" : "diff-command"; |
|
8c4c93b…
|
drh
|
1169 |
return db_get(zName, 0); |
|
5bec7a6…
|
drh
|
1170 |
} |
|
5bec7a6…
|
drh
|
1171 |
|
|
5bec7a6…
|
drh
|
1172 |
/* |
|
5bec7a6…
|
drh
|
1173 |
** Return true if it reasonable to run "diff -tk" for "gdiff". |
|
5bec7a6…
|
drh
|
1174 |
** |
|
5bec7a6…
|
drh
|
1175 |
** Details: Return true if all of the following are true: |
|
5bec7a6…
|
drh
|
1176 |
** |
|
5bec7a6…
|
drh
|
1177 |
** (1) The isGDiff flags is true |
|
5bec7a6…
|
drh
|
1178 |
** (2) The "gdiff-command" setting is undefined |
|
5bec7a6…
|
drh
|
1179 |
** (3) There is a "tclsh" on PATH |
|
5bec7a6…
|
drh
|
1180 |
** (4) There is a "wish" on PATH |
|
5bec7a6…
|
drh
|
1181 |
*/ |
|
5bec7a6…
|
drh
|
1182 |
int gdiff_using_tk(int isGdiff){ |
|
5bec7a6…
|
drh
|
1183 |
if( isGdiff |
|
5bec7a6…
|
drh
|
1184 |
&& db_get("gdiff-command","")[0]==0 |
|
5bec7a6…
|
drh
|
1185 |
&& fossil_app_on_path("tclsh",0) |
|
5bec7a6…
|
drh
|
1186 |
&& fossil_app_on_path("wish",0) |
|
5bec7a6…
|
drh
|
1187 |
){ |
|
5bec7a6…
|
drh
|
1188 |
return 1; |
|
5bec7a6…
|
drh
|
1189 |
} |
|
5bec7a6…
|
drh
|
1190 |
return 0; |
|
db6a8e8…
|
drh
|
1191 |
} |
|
22e5d71…
|
drh
|
1192 |
|
|
22e5d71…
|
drh
|
1193 |
/* |
|
22e5d71…
|
drh
|
1194 |
** Show diff output in a Tcl/Tk window, in response to the --tk option |
|
22e5d71…
|
drh
|
1195 |
** to the diff command. |
|
45f3516…
|
jan.nijtmans
|
1196 |
** |
|
252aff3…
|
jan.nijtmans
|
1197 |
** If fossil has direct access to a Tcl interpreter (either loaded |
|
252aff3…
|
jan.nijtmans
|
1198 |
** dynamically through stubs or linked in statically), we can use it |
|
252aff3…
|
jan.nijtmans
|
1199 |
** directly. Otherwise: |
|
22e5d71…
|
drh
|
1200 |
** (1) Write the Tcl/Tk script used for rendering into a temp file. |
|
252aff3…
|
jan.nijtmans
|
1201 |
** (2) Invoke "tclsh" on the temp file using fossil_system(). |
|
22e5d71…
|
drh
|
1202 |
** (3) Delete the temp file. |
|
22e5d71…
|
drh
|
1203 |
*/ |
|
2ed8cdc…
|
drh
|
1204 |
void diff_tk(const char *zSubCmd, int firstArg){ |
|
22e5d71…
|
drh
|
1205 |
int i; |
|
22e5d71…
|
drh
|
1206 |
Blob script; |
|
c543079…
|
drh
|
1207 |
const char *zTempFile = 0; |
|
22e5d71…
|
drh
|
1208 |
char *zCmd; |
|
9fc945c…
|
drh
|
1209 |
const char *zTclsh; |
|
f5cb12d…
|
drh
|
1210 |
int bDebug = find_option("tkdebug",0,0)!=0; |
|
5a8516d…
|
drh
|
1211 |
int bDarkMode = find_option("dark",0,0)!=0; |
|
d7cf189…
|
drh
|
1212 |
(void)find_option("debug",0,0); |
|
22e5d71…
|
drh
|
1213 |
blob_zero(&script); |
|
f5cb12d…
|
drh
|
1214 |
/* Caution: When this routine is called from the merge-info command, |
|
f5cb12d…
|
drh
|
1215 |
** the --tcl argument requires an argument. But merge-info does not |
|
f5cb12d…
|
drh
|
1216 |
** use -i, so we can take -i as that argument. This routine needs to |
|
f5cb12d…
|
drh
|
1217 |
** always have -i after --tcl. |
|
f5cb12d…
|
drh
|
1218 |
** CAUTION! |
|
f5cb12d…
|
drh
|
1219 |
** vvvvvvv */ |
|
9e33074…
|
drh
|
1220 |
blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v", |
|
2ed8cdc…
|
drh
|
1221 |
g.nameOfExe, zSubCmd); |
|
9e33074…
|
drh
|
1222 |
find_option("tcl",0,0); |
|
c060947…
|
jan.nijtmans
|
1223 |
find_option("html",0,0); |
|
c060947…
|
jan.nijtmans
|
1224 |
find_option("side-by-side","y",0); |
|
c060947…
|
jan.nijtmans
|
1225 |
find_option("internal","i",0); |
|
c060947…
|
jan.nijtmans
|
1226 |
find_option("verbose","v",0); |
|
9fc945c…
|
drh
|
1227 |
zTclsh = find_option("tclsh",0,1); |
|
9fc945c…
|
drh
|
1228 |
if( zTclsh==0 ){ |
|
eb804dc…
|
drh
|
1229 |
zTclsh = db_get("tclsh",0); |
|
9fc945c…
|
drh
|
1230 |
} |
|
c060947…
|
jan.nijtmans
|
1231 |
/* The undocumented --script FILENAME option causes the Tk script to |
|
c060947…
|
jan.nijtmans
|
1232 |
** be written into the FILENAME instead of being run. This is used |
|
c060947…
|
jan.nijtmans
|
1233 |
** for testing and debugging. */ |
|
c060947…
|
jan.nijtmans
|
1234 |
zTempFile = find_option("script",0,1); |
|
2ed8cdc…
|
drh
|
1235 |
for(i=firstArg; i<g.argc; i++){ |
|
60d5b1f…
|
drh
|
1236 |
const char *z = g.argv[i]; |
|
544d221…
|
drh
|
1237 |
if( sqlite3_strglob("*}*",z) ){ |
|
544d221…
|
drh
|
1238 |
blob_appendf(&script, " {%/}", z); |
|
544d221…
|
drh
|
1239 |
}else{ |
|
544d221…
|
drh
|
1240 |
int j; |
|
544d221…
|
drh
|
1241 |
blob_append(&script, " ", 1); |
|
544d221…
|
drh
|
1242 |
for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]); |
|
544d221…
|
drh
|
1243 |
} |
|
544d221…
|
drh
|
1244 |
} |
|
5a8516d…
|
drh
|
1245 |
blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode); |
|
f5cb12d…
|
drh
|
1246 |
blob_appendf(&script, "set debug %d\n", bDebug); |
|
5a8516d…
|
drh
|
1247 |
blob_appendf(&script, "%s", builtin_file("diff.tcl", 0)); |
|
cee30a3…
|
drh
|
1248 |
if( zTempFile ){ |
|
cee30a3…
|
drh
|
1249 |
blob_write_to_file(&script, zTempFile); |
|
9fc945c…
|
drh
|
1250 |
fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile); |
|
cee30a3…
|
drh
|
1251 |
}else{ |
|
252aff3…
|
jan.nijtmans
|
1252 |
#if defined(FOSSIL_ENABLE_TCL) |
|
fe9990a…
|
mistachkin
|
1253 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
be26772…
|
mistachkin
|
1254 |
if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script), |
|
18fc492…
|
mistachkin
|
1255 |
blob_size(&script), 1, 1, 0)==TCL_OK ){ |
|
252aff3…
|
jan.nijtmans
|
1256 |
blob_reset(&script); |
|
252aff3…
|
jan.nijtmans
|
1257 |
return; |
|
252aff3…
|
jan.nijtmans
|
1258 |
} |
|
be26772…
|
mistachkin
|
1259 |
/* |
|
be26772…
|
mistachkin
|
1260 |
* If evaluation of the Tcl script fails, the reason may be that Tk |
|
be26772…
|
mistachkin
|
1261 |
* could not be found by the loaded Tcl, or that Tcl cannot be loaded |
|
be26772…
|
mistachkin
|
1262 |
* dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback |
|
be26772…
|
mistachkin
|
1263 |
* to using the external "tclsh", if available. |
|
be26772…
|
mistachkin
|
1264 |
*/ |
|
252aff3…
|
jan.nijtmans
|
1265 |
#endif |
|
cee30a3…
|
drh
|
1266 |
zTempFile = write_blob_to_temp_file(&script); |
|
2209f55…
|
drh
|
1267 |
zCmd = mprintf("%$ %$", zTclsh, zTempFile); |
|
cee30a3…
|
drh
|
1268 |
fossil_system(zCmd); |
|
cee30a3…
|
drh
|
1269 |
file_delete(zTempFile); |
|
cee30a3…
|
drh
|
1270 |
fossil_free(zCmd); |
|
cee30a3…
|
drh
|
1271 |
} |
|
cee30a3…
|
drh
|
1272 |
blob_reset(&script); |
|
f8339c2…
|
drh
|
1273 |
} |
|
f8339c2…
|
drh
|
1274 |
|
|
f8339c2…
|
drh
|
1275 |
/* |
|
f8339c2…
|
drh
|
1276 |
** Returns the GLOB pattern for file names that should be treated as binary |
|
f8339c2…
|
drh
|
1277 |
** by the diff subsystem, if any. |
|
f8339c2…
|
drh
|
1278 |
*/ |
|
f8339c2…
|
drh
|
1279 |
const char *diff_get_binary_glob(void){ |
|
f8339c2…
|
drh
|
1280 |
const char *zBinGlob = find_option("binary", 0, 1); |
|
f8339c2…
|
drh
|
1281 |
if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); |
|
f8339c2…
|
drh
|
1282 |
return zBinGlob; |
|
cad57bf…
|
drh
|
1283 |
} |
|
cad57bf…
|
drh
|
1284 |
|
|
cad57bf…
|
drh
|
1285 |
/* |
|
dbda8d6…
|
drh
|
1286 |
** COMMAND: diff |
|
d0305b3…
|
aku
|
1287 |
** COMMAND: gdiff |
|
d0305b3…
|
aku
|
1288 |
** |
|
2210be1…
|
drh
|
1289 |
** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? |
|
83c032d…
|
drh
|
1290 |
** |
|
83c032d…
|
drh
|
1291 |
** Show the difference between the current version of each of the FILEs |
|
bc36fdc…
|
danield
|
1292 |
** specified (as they exist on disk) and that same file as it was checked- |
|
dc757a5…
|
drh
|
1293 |
** out. Or if the FILE arguments are omitted, show all unsaved changes |
|
5bec7a6…
|
drh
|
1294 |
** currently in the working check-out. The "gdiff" variant means to |
|
e879d1e…
|
brickviking
|
1295 |
** use a GUI diff. |
|
dc757a5…
|
drh
|
1296 |
** |
|
dc757a5…
|
drh
|
1297 |
** The default output format is a "unified patch" (the same as the |
|
dc757a5…
|
drh
|
1298 |
** output of "diff -u" on most unix systems). Many alternative formats |
|
dc757a5…
|
drh
|
1299 |
** are available. A few of the more useful alternatives: |
|
dc757a5…
|
drh
|
1300 |
** |
|
b89f4cd…
|
florian
|
1301 |
** --tk Pop up a Tcl/Tk-based GUI to show the diff |
|
dc757a5…
|
drh
|
1302 |
** --by Show a side-by-side diff in the default web browser |
|
dc757a5…
|
drh
|
1303 |
** -b Show a linear diff in the default web browser |
|
dc757a5…
|
drh
|
1304 |
** -y Show a text side-by-side diff |
|
dc757a5…
|
drh
|
1305 |
** --webpage Format output as HTML |
|
dc757a5…
|
drh
|
1306 |
** --webpage -y HTML output in the side-by-side format |
|
dc757a5…
|
drh
|
1307 |
** |
|
e1b5115…
|
danield
|
1308 |
** The "--from VERSION" option is used to specify the source check-in |
|
dc757a5…
|
drh
|
1309 |
** for the diff operation. If not specified, the source check-in is the |
|
dc757a5…
|
drh
|
1310 |
** base check-in for the current check-out. Similarly, the "--to VERSION" |
|
dc757a5…
|
drh
|
1311 |
** option specifies the check-in from which the second version of the file |
|
dc757a5…
|
drh
|
1312 |
** or files is taken. If there is no "--to" option then the (possibly edited) |
|
dc757a5…
|
drh
|
1313 |
** files in the current check-out are used. The "--checkin VERSION" option |
|
dc757a5…
|
drh
|
1314 |
** shows the changes made by check-in VERSION relative to its primary parent. |
|
5839aba…
|
drh
|
1315 |
** The "--branch BRANCHNAME" shows all the changes on the branch BRANCHNAME. |
|
5839aba…
|
drh
|
1316 |
** |
|
763758d…
|
drh
|
1317 |
** With the "--from VERSION" option, if VERSION is actually a directory name |
|
763758d…
|
drh
|
1318 |
** (not a tag or check-in hash) then the files under that directory are used |
|
763758d…
|
drh
|
1319 |
** as the baseline for the diff. |
|
763758d…
|
drh
|
1320 |
** |
|
e1b5115…
|
danield
|
1321 |
** The "-i" command-line option forces the use of Fossil's own internal |
|
dc757a5…
|
drh
|
1322 |
** diff logic rather than any external diff program that might be configured |
|
dc757a5…
|
drh
|
1323 |
** using the "setting" command. If no external diff program is configured, |
|
dc757a5…
|
drh
|
1324 |
** then the "-i" option is a no-op. The "-i" option converts "gdiff" into |
|
dc757a5…
|
drh
|
1325 |
** "diff". |
|
f8339c2…
|
drh
|
1326 |
** |
|
f8339c2…
|
drh
|
1327 |
** The "--diff-binary" option enables or disables the inclusion of binary files |
|
f8339c2…
|
drh
|
1328 |
** when using an external diff program. |
|
f8339c2…
|
drh
|
1329 |
** |
|
f8339c2…
|
drh
|
1330 |
** The "--binary" option causes files matching the glob PATTERN to be treated |
|
e1b5115…
|
danield
|
1331 |
** as binary when considering if they should be used with the external diff |
|
e1b5115…
|
danield
|
1332 |
** program. This option overrides the "binary-glob" setting. |
|
dc757a5…
|
drh
|
1333 |
** |
|
33d3bf3…
|
km
|
1334 |
** These commands show differences between managed files. Use the "fossil xdiff" |
|
dc757a5…
|
drh
|
1335 |
** command to see differences in unmanaged files. |
|
2210be1…
|
drh
|
1336 |
** |
|
2210be1…
|
drh
|
1337 |
** Options: |
|
11384f1…
|
drh
|
1338 |
** --binary PATTERN Treat files that match the glob PATTERN |
|
11384f1…
|
drh
|
1339 |
** as binary |
|
11384f1…
|
drh
|
1340 |
** --branch BRANCH Show diff of all changes on BRANCH |
|
11384f1…
|
drh
|
1341 |
** --brief Show filenames only |
|
9a3372e…
|
drh
|
1342 |
** -b|--browser Show the diff output in a web-browser |
|
9a3372e…
|
drh
|
1343 |
** --by Shorthand for "--browser -y" |
|
c8a7ee7…
|
danield
|
1344 |
** -ci|--checkin VERSION Show diff of all changes in VERSION |
|
11384f1…
|
drh
|
1345 |
** --command PROG External diff program. Overrides "diff-command" |
|
275da70…
|
danield
|
1346 |
** -c|--context N Show N lines of context around each change, |
|
275da70…
|
danield
|
1347 |
** with negative N meaning show all content |
|
b89f4cd…
|
florian
|
1348 |
** --dark Use dark mode for the Tcl/Tk-based GUI and HTML |
|
11384f1…
|
drh
|
1349 |
** --diff-binary BOOL Include binary files with external commands |
|
11384f1…
|
drh
|
1350 |
** --exec-abs-paths Force absolute path names on external commands |
|
11384f1…
|
drh
|
1351 |
** --exec-rel-paths Force relative path names on external commands |
|
763758d…
|
drh
|
1352 |
** -r|--from VERSION Use VERSION as the baseline for the diff, or |
|
763758d…
|
drh
|
1353 |
** if VERSION is a directory name, use files in |
|
763758d…
|
drh
|
1354 |
** that directory as the baseline. |
|
ea52b7d…
|
drh
|
1355 |
** -w|--ignore-all-space Ignore white space when comparing lines |
|
7f3c728…
|
jamsek
|
1356 |
** -i|--internal Use internal diff logic |
|
eb4efc8…
|
danield
|
1357 |
** --invert Invert the diff |
|
dc757a5…
|
drh
|
1358 |
** --json Output formatted as JSON |
|
eb4efc8…
|
danield
|
1359 |
** -n|--linenum Show line numbers |
|
ea52b7d…
|
drh
|
1360 |
** -N|--new-file Alias for --verbose |
|
df119a3…
|
danield
|
1361 |
** -s|--numstat Show the number of added and deleted lines per |
|
7764287…
|
drh
|
1362 |
** file, omitting the diff. When combined |
|
7764287…
|
drh
|
1363 |
** with --brief, show only the total row. |
|
7f3c728…
|
jamsek
|
1364 |
** -y|--side-by-side Side-by-side diff |
|
11384f1…
|
drh
|
1365 |
** --strip-trailing-cr Strip trailing CR |
|
75c45fd…
|
drh
|
1366 |
** --tcl Tcl-formatted output used internally by --tk |
|
b89f4cd…
|
florian
|
1367 |
** --tclsh PATH Tcl/Tk shell used for --tk (default: "tclsh") |
|
11384f1…
|
drh
|
1368 |
** --tk Launch a Tcl/Tk GUI for display |
|
11384f1…
|
drh
|
1369 |
** --to VERSION Select VERSION as target for the diff |
|
99d0baa…
|
drh
|
1370 |
** --undo Use the undo buffer as the baseline |
|
11384f1…
|
drh
|
1371 |
** --unified Unified diff |
|
11384f1…
|
drh
|
1372 |
** -v|--verbose Output complete text of added or deleted files |
|
41f6a45…
|
danield
|
1373 |
** -h|--versions Show compared versions in the diff header |
|
ea52b7d…
|
drh
|
1374 |
** --webpage Format output as a stand-alone HTML webpage |
|
11384f1…
|
drh
|
1375 |
** -W|--width N Width of lines in side-by-side diff |
|
11384f1…
|
drh
|
1376 |
** -Z|--ignore-trailing-space Ignore changes to end-of-line whitespace |
|
dbda8d6…
|
drh
|
1377 |
*/ |
|
dbda8d6…
|
drh
|
1378 |
void diff_cmd(void){ |
|
85670cf…
|
drh
|
1379 |
int isGDiff; /* True for gdiff. False for normal diff */ |
|
a51808c…
|
drh
|
1380 |
const char *zFrom; /* Source version number */ |
|
a51808c…
|
drh
|
1381 |
const char *zTo; /* Target version number */ |
|
e7c2454…
|
drh
|
1382 |
const char *zCheckin; /* Check-in version number */ |
|
4140eb3…
|
drh
|
1383 |
const char *zBranch; /* Branch to diff */ |
|
485aa80…
|
drh
|
1384 |
int againstUndo = 0; /* Diff against files in the undo buffer */ |
|
c46f980…
|
drh
|
1385 |
FileDirList *pFileDir = 0; /* Restrict the diff to these files */ |
|
1347a1d…
|
drh
|
1386 |
DiffConfig DCfg; /* Diff configuration object */ |
|
763758d…
|
drh
|
1387 |
int bFromIsDir = 0; /* True if zFrom is a directory name */ |
|
4140eb3…
|
drh
|
1388 |
|
|
5bec7a6…
|
drh
|
1389 |
isGDiff = g.argv[1][0]=='g'; |
|
5bec7a6…
|
drh
|
1390 |
if( find_option("tk",0,0)!=0|| has_option("tclsh") ){ |
|
2ed8cdc…
|
drh
|
1391 |
diff_tk("diff", 2); |
|
22e5d71…
|
drh
|
1392 |
return; |
|
22e5d71…
|
drh
|
1393 |
} |
|
a51808c…
|
drh
|
1394 |
zFrom = find_option("from", "r", 1); |
|
a51808c…
|
drh
|
1395 |
zTo = find_option("to", 0, 1); |
|
c8a7ee7…
|
danield
|
1396 |
zCheckin = find_option("checkin", "ci", 1); |
|
9f83e03…
|
drh
|
1397 |
zBranch = find_option("branch", 0, 1); |
|
485aa80…
|
drh
|
1398 |
againstUndo = find_option("undo",0,0)!=0; |
|
99d0baa…
|
drh
|
1399 |
if( againstUndo && (zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ |
|
e7c2454…
|
drh
|
1400 |
fossil_fatal("cannot use --undo together with --from, --to, --checkin," |
|
e7c2454…
|
drh
|
1401 |
" or --branch"); |
|
e3f7ba5…
|
jan.nijtmans
|
1402 |
} |
|
9f83e03…
|
drh
|
1403 |
if( zBranch ){ |
|
e7c2454…
|
drh
|
1404 |
if( zTo || zFrom || zCheckin ){ |
|
e7c2454…
|
drh
|
1405 |
fossil_fatal("cannot use --from, --to, or --checkin with --branch"); |
|
9f83e03…
|
drh
|
1406 |
} |
|
9f83e03…
|
drh
|
1407 |
zTo = zBranch; |
|
9f83e03…
|
drh
|
1408 |
zFrom = mprintf("root:%s", zBranch); |
|
5bec7a6…
|
drh
|
1409 |
zBranch = 0; |
|
e7c2454…
|
drh
|
1410 |
} |
|
99d0baa…
|
drh
|
1411 |
if( zCheckin!=0 && (zFrom!=0 || zTo!=0) ){ |
|
e7c2454…
|
drh
|
1412 |
fossil_fatal("cannot use --checkin together with --from or --to"); |
|
485aa80…
|
drh
|
1413 |
} |
|
8e8e026…
|
stephan
|
1414 |
if( 0==zCheckin ){ |
|
8e8e026…
|
stephan
|
1415 |
if( zTo==0 || againstUndo ){ |
|
8e8e026…
|
stephan
|
1416 |
db_must_be_within_tree(); |
|
8e8e026…
|
stephan
|
1417 |
}else if( zFrom==0 ){ |
|
8e8e026…
|
stephan
|
1418 |
fossil_fatal("must use --from if --to is present"); |
|
8e8e026…
|
stephan
|
1419 |
}else{ |
|
8e8e026…
|
stephan
|
1420 |
db_find_and_open_repository(0, 0); |
|
8e8e026…
|
stephan
|
1421 |
} |
|
c0c3d92…
|
drh
|
1422 |
}else{ |
|
c0c3d92…
|
drh
|
1423 |
db_find_and_open_repository(0, 0); |
|
5bec7a6…
|
drh
|
1424 |
} |
|
5bec7a6…
|
drh
|
1425 |
if( gdiff_using_tk(isGDiff) ){ |
|
5bec7a6…
|
drh
|
1426 |
restore_option("--from", zFrom, 1); |
|
5bec7a6…
|
drh
|
1427 |
restore_option("--to", zTo, 1); |
|
5bec7a6…
|
drh
|
1428 |
restore_option("--checkin", zCheckin, 1); |
|
5bec7a6…
|
drh
|
1429 |
restore_option("--branch", zBranch, 1); |
|
5bec7a6…
|
drh
|
1430 |
if( againstUndo ) restore_option("--undo", 0, 0); |
|
5bec7a6…
|
drh
|
1431 |
diff_tk("diff", 2); |
|
5bec7a6…
|
drh
|
1432 |
return; |
|
763758d…
|
drh
|
1433 |
} |
|
763758d…
|
drh
|
1434 |
determine_exec_relative_option(1); |
|
763758d…
|
drh
|
1435 |
if( zFrom!=file_tail(zFrom) |
|
763758d…
|
drh
|
1436 |
&& file_isdir(zFrom, ExtFILE)==1 |
|
763758d…
|
drh
|
1437 |
&& !db_exists("SELECT 1 FROM tag WHERE tagname='sym-%q'", zFrom) |
|
763758d…
|
drh
|
1438 |
){ |
|
763758d…
|
drh
|
1439 |
bFromIsDir = 1; |
|
763758d…
|
drh
|
1440 |
if( zTo ){ |
|
763758d…
|
drh
|
1441 |
fossil_fatal("cannot use --to together with \"--from PATH\""); |
|
763758d…
|
drh
|
1442 |
} |
|
763758d…
|
drh
|
1443 |
} |
|
763758d…
|
drh
|
1444 |
diff_options(&DCfg, isGDiff, 0); |
|
485aa80…
|
drh
|
1445 |
verify_all_options(); |
|
a2a0390…
|
drh
|
1446 |
g.diffCnt[0] = g.diffCnt[1] = g.diffCnt[2] = 0; |
|
c46f980…
|
drh
|
1447 |
if( g.argc>=3 ){ |
|
c46f980…
|
drh
|
1448 |
int i; |
|
c46f980…
|
drh
|
1449 |
Blob fname; |
|
c46f980…
|
drh
|
1450 |
pFileDir = fossil_malloc( sizeof(*pFileDir) * (g.argc-1) ); |
|
c46f980…
|
drh
|
1451 |
memset(pFileDir, 0, sizeof(*pFileDir) * (g.argc-1)); |
|
c46f980…
|
drh
|
1452 |
for(i=2; i<g.argc; i++){ |
|
c46f980…
|
drh
|
1453 |
file_tree_name(g.argv[i], &fname, 0, 1); |
|
c46f980…
|
drh
|
1454 |
pFileDir[i-2].zName = fossil_strdup(blob_str(&fname)); |
|
c46f980…
|
drh
|
1455 |
if( strcmp(pFileDir[i-2].zName,".")==0 ){ |
|
c46f980…
|
drh
|
1456 |
pFileDir[0].zName[0] = '.'; |
|
c46f980…
|
drh
|
1457 |
pFileDir[0].zName[1] = 0; |
|
c46f980…
|
drh
|
1458 |
break; |
|
c46f980…
|
drh
|
1459 |
} |
|
c46f980…
|
drh
|
1460 |
pFileDir[i-2].nName = blob_size(&fname); |
|
c46f980…
|
drh
|
1461 |
pFileDir[i-2].nUsed = 0; |
|
c46f980…
|
drh
|
1462 |
blob_reset(&fname); |
|
c46f980…
|
drh
|
1463 |
} |
|
c46f980…
|
drh
|
1464 |
} |
|
c14f217…
|
danield
|
1465 |
if( (DCfg.diffFlags & DIFF_NUMSTAT) && !(DCfg.diffFlags & DIFF_BRIEF) ){ |
|
7bcd662…
|
drh
|
1466 |
fossil_print("%10s %10s\n", "INSERTED", "DELETED"); |
|
7bcd662…
|
drh
|
1467 |
} |
|
7bcd662…
|
drh
|
1468 |
if( zCheckin!=0 ){ |
|
e7c2454…
|
drh
|
1469 |
int ridTo = name_to_typed_rid(zCheckin, "ci"); |
|
e7c2454…
|
drh
|
1470 |
zTo = zCheckin; |
|
e7c2454…
|
drh
|
1471 |
zFrom = db_text(0, |
|
e7c2454…
|
drh
|
1472 |
"SELECT uuid FROM blob, plink" |
|
e7c2454…
|
drh
|
1473 |
" WHERE plink.cid=%d AND plink.isprim AND plink.pid=blob.rid", |
|
e7c2454…
|
drh
|
1474 |
ridTo); |
|
e7c2454…
|
drh
|
1475 |
if( zFrom==0 ){ |
|
e7c2454…
|
drh
|
1476 |
fossil_fatal("check-in %s has no parent", zTo); |
|
e7c2454…
|
drh
|
1477 |
} |
|
e7c2454…
|
drh
|
1478 |
} |
|
1347a1d…
|
drh
|
1479 |
diff_begin(&DCfg); |
|
763758d…
|
drh
|
1480 |
if( bFromIsDir ){ |
|
763758d…
|
drh
|
1481 |
diff_externbase_to_checkout(zFrom, &DCfg, pFileDir); |
|
99d0baa…
|
drh
|
1482 |
}else if( againstUndo ){ |
|
485aa80…
|
drh
|
1483 |
if( db_lget_int("undo_available",0)==0 ){ |
|
485aa80…
|
drh
|
1484 |
fossil_print("No undo or redo is available\n"); |
|
485aa80…
|
drh
|
1485 |
return; |
|
485aa80…
|
drh
|
1486 |
} |
|
99d0baa…
|
drh
|
1487 |
diff_undo_to_checkout(&DCfg, pFileDir); |
|
c46f980…
|
drh
|
1488 |
}else if( zTo==0 ){ |
|
99d0baa…
|
drh
|
1489 |
diff_version_to_checkout(zFrom, &DCfg, pFileDir, 0); |
|
c46f980…
|
drh
|
1490 |
}else{ |
|
346de5d…
|
drh
|
1491 |
diff_two_versions(zFrom, zTo, &DCfg, pFileDir); |
|
c46f980…
|
drh
|
1492 |
} |
|
c46f980…
|
drh
|
1493 |
if( pFileDir ){ |
|
c46f980…
|
drh
|
1494 |
int i; |
|
c46f980…
|
drh
|
1495 |
for(i=0; pFileDir[i].zName; i++){ |
|
b789df4…
|
drh
|
1496 |
if( pFileDir[i].nUsed==0 |
|
b789df4…
|
drh
|
1497 |
&& strcmp(pFileDir[0].zName,".")!=0 |
|
1772357…
|
drh
|
1498 |
&& !file_isdir(g.argv[i+2], ExtFILE) |
|
b789df4…
|
drh
|
1499 |
){ |
|
c46f980…
|
drh
|
1500 |
fossil_fatal("not found: '%s'", g.argv[i+2]); |
|
c46f980…
|
drh
|
1501 |
} |
|
c46f980…
|
drh
|
1502 |
fossil_free(pFileDir[i].zName); |
|
c46f980…
|
drh
|
1503 |
} |
|
c46f980…
|
drh
|
1504 |
fossil_free(pFileDir); |
|
1772357…
|
drh
|
1505 |
} |
|
1347a1d…
|
drh
|
1506 |
diff_end(&DCfg, 0); |
|
1347a1d…
|
drh
|
1507 |
if ( DCfg.diffFlags & DIFF_NUMSTAT ){ |
|
3732790…
|
danield
|
1508 |
fossil_print("%10d %10d TOTAL over %d changed file%s\n", |
|
3732790…
|
danield
|
1509 |
g.diffCnt[1], g.diffCnt[2], g.diffCnt[0], g.diffCnt[0]!=1 ? "s": ""); |
|
9bb61a4…
|
drh
|
1510 |
} |
|
4bdf71b…
|
drh
|
1511 |
} |
|
4bdf71b…
|
drh
|
1512 |
|
|
4bdf71b…
|
drh
|
1513 |
/* |
|
4bdf71b…
|
drh
|
1514 |
** WEBPAGE: vpatch |
|
7ab0328…
|
drh
|
1515 |
** URL: /vpatch?from=FROM&to=TO |
|
7ab0328…
|
drh
|
1516 |
** |
|
7ab0328…
|
drh
|
1517 |
** Show a patch that goes from check-in FROM to check-in TO. |
|
4bdf71b…
|
drh
|
1518 |
*/ |
|
4bdf71b…
|
drh
|
1519 |
void vpatch_page(void){ |
|
4bdf71b…
|
drh
|
1520 |
const char *zFrom = P("from"); |
|
4bdf71b…
|
drh
|
1521 |
const char *zTo = P("to"); |
|
1347a1d…
|
drh
|
1522 |
DiffConfig DCfg; |
|
57f1e87…
|
drh
|
1523 |
cgi_check_for_malice(); |
|
4bdf71b…
|
drh
|
1524 |
login_check_credentials(); |
|
653dd40…
|
drh
|
1525 |
if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
|
4bdf71b…
|
drh
|
1526 |
if( zFrom==0 || zTo==0 ) fossil_redirect_home(); |
|
16b3309…
|
drh
|
1527 |
if( robot_restrict("diff") ) return; |
|
4bdf71b…
|
drh
|
1528 |
|
|
9413395…
|
drh
|
1529 |
fossil_nice_default(); |
|
4bdf71b…
|
drh
|
1530 |
cgi_set_content_type("text/plain"); |
|
1347a1d…
|
drh
|
1531 |
diff_config_init(&DCfg, DIFF_VERBOSE); |
|
346de5d…
|
drh
|
1532 |
diff_two_versions(zFrom, zTo, &DCfg, 0); |
|
dbda8d6…
|
drh
|
1533 |
} |