Fossil SCM

Merge trunk. Split same_dline() in 3 different functions. Ongoing.

jan.nijtmans 2014-03-13 14:32 strip-trailing-cr merge
Commit a915aa03b3c66f481843e01afd49b89b7d4f6b6a
+51
--- src/clone.c
+++ src/clone.c
@@ -109,22 +109,25 @@
109109
** --admin-user|-A USERNAME Make USERNAME the administrator
110110
** --once Don't save url.
111111
** --private Also clone private branches
112112
** --ssl-identity=filename Use the SSL identity if requested by the server
113113
** --ssh-command|-c 'command' Use this SSH command
114
+** --httpauth|-B 'user:pass' Add HTTP Basic Authorization to requests
114115
**
115116
** See also: init
116117
*/
117118
void clone_cmd(void){
118119
char *zPassword;
119120
const char *zDefaultUser; /* Optional name of the default user */
121
+ const char *zHttpAuth; /* HTTP Authorization user:pass information */
120122
int nErr = 0;
121123
int bPrivate = 0; /* Also clone private branches */
122124
int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
123125
124126
if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
125127
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
128
+ zHttpAuth = find_option("httpauth","B",1);
126129
zDefaultUser = find_option("admin-user","A",1);
127130
clone_ssh_find_options();
128131
url_proxy_options();
129132
if( g.argc < 4 ){
130133
usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
@@ -159,10 +162,11 @@
159162
db_initial_setup(0, 0, zDefaultUser, 0);
160163
user_select();
161164
db_set("content-schema", CONTENT_SCHEMA, 0);
162165
db_set("aux-schema", AUX_SCHEMA, 0);
163166
db_set("rebuilt", get_version(), 0);
167
+ remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, g.argv[2]);
164168
url_remember();
165169
if( g.zSSLIdentity!=0 ){
166170
/* If the --ssl-identity option was specified, store it as a setting */
167171
Blob fn;
168172
blob_zero(&fn);
@@ -195,10 +199,57 @@
195199
fossil_print("project-id: %s\n", db_get("project-code", 0));
196200
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
197201
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
198202
db_end_transaction(0);
199203
}
204
+
205
+/*
206
+** If user chooses to use HTTP Authentication over unencrypted HTTP,
207
+** remember decision. Otherwise, if the URL is being changed and no
208
+** preference has been indicated, err on the safe side and revert the
209
+** decision. Set the global preference if the URL is not being changed.
210
+*/
211
+void remember_or_get_http_auth(
212
+ const char *zHttpAuth, /* Credentials in the form "user:password" */
213
+ int fRemember, /* True to remember credentials for later reuse */
214
+ const char *zUrl /* URL for which these credentials apply */
215
+){
216
+ char *zKey = mprintf("http-auth:%s", g.urlCanonical);
217
+ if( zHttpAuth && zHttpAuth[0] ){
218
+ g.zHttpAuth = mprintf("%s", zHttpAuth);
219
+ }
220
+ if( fRemember ){
221
+ if( g.zHttpAuth && g.zHttpAuth[0] ){
222
+ set_httpauth(g.zHttpAuth);
223
+ }else if( zUrl && zUrl[0] ){
224
+ db_unset(zKey, 0);
225
+ }else{
226
+ g.zHttpAuth = get_httpauth();
227
+ }
228
+ }else if( g.zHttpAuth==0 && zUrl==0 ){
229
+ g.zHttpAuth = get_httpauth();
230
+ }
231
+ free(zKey);
232
+}
233
+
234
+/*
235
+** Get the HTTP Authorization preference from db.
236
+*/
237
+char *get_httpauth(void){
238
+ char *zKey = mprintf("http-auth:%s", g.urlCanonical);
239
+ return unobscure(db_get(zKey, 0));
240
+ free(zKey);
241
+}
242
+
243
+/*
244
+** Set the HTTP Authorization preference in db.
245
+*/
246
+void set_httpauth(const char *zHttpAuth){
247
+ char *zKey = mprintf("http-auth:%s", g.urlCanonical);
248
+ db_set(zKey, obscure(zHttpAuth), 0);
249
+ free(zKey);
250
+}
200251
201252
/*
202253
** Look for SSH clone command line options and setup in globals.
203254
*/
204255
void clone_ssh_find_options(void){
205256
--- src/clone.c
+++ src/clone.c
@@ -109,22 +109,25 @@
109 ** --admin-user|-A USERNAME Make USERNAME the administrator
110 ** --once Don't save url.
111 ** --private Also clone private branches
112 ** --ssl-identity=filename Use the SSL identity if requested by the server
113 ** --ssh-command|-c 'command' Use this SSH command
 
114 **
115 ** See also: init
116 */
117 void clone_cmd(void){
118 char *zPassword;
119 const char *zDefaultUser; /* Optional name of the default user */
 
120 int nErr = 0;
121 int bPrivate = 0; /* Also clone private branches */
122 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
123
124 if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
125 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
 
126 zDefaultUser = find_option("admin-user","A",1);
127 clone_ssh_find_options();
128 url_proxy_options();
129 if( g.argc < 4 ){
130 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
@@ -159,10 +162,11 @@
159 db_initial_setup(0, 0, zDefaultUser, 0);
160 user_select();
161 db_set("content-schema", CONTENT_SCHEMA, 0);
162 db_set("aux-schema", AUX_SCHEMA, 0);
163 db_set("rebuilt", get_version(), 0);
 
164 url_remember();
165 if( g.zSSLIdentity!=0 ){
166 /* If the --ssl-identity option was specified, store it as a setting */
167 Blob fn;
168 blob_zero(&fn);
@@ -195,10 +199,57 @@
195 fossil_print("project-id: %s\n", db_get("project-code", 0));
196 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
197 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
198 db_end_transaction(0);
199 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
201 /*
202 ** Look for SSH clone command line options and setup in globals.
203 */
204 void clone_ssh_find_options(void){
205
--- src/clone.c
+++ src/clone.c
@@ -109,22 +109,25 @@
109 ** --admin-user|-A USERNAME Make USERNAME the administrator
110 ** --once Don't save url.
111 ** --private Also clone private branches
112 ** --ssl-identity=filename Use the SSL identity if requested by the server
113 ** --ssh-command|-c 'command' Use this SSH command
114 ** --httpauth|-B 'user:pass' Add HTTP Basic Authorization to requests
115 **
116 ** See also: init
117 */
118 void clone_cmd(void){
119 char *zPassword;
120 const char *zDefaultUser; /* Optional name of the default user */
121 const char *zHttpAuth; /* HTTP Authorization user:pass information */
122 int nErr = 0;
123 int bPrivate = 0; /* Also clone private branches */
124 int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
125
126 if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
127 if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
128 zHttpAuth = find_option("httpauth","B",1);
129 zDefaultUser = find_option("admin-user","A",1);
130 clone_ssh_find_options();
131 url_proxy_options();
132 if( g.argc < 4 ){
133 usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
@@ -159,10 +162,11 @@
162 db_initial_setup(0, 0, zDefaultUser, 0);
163 user_select();
164 db_set("content-schema", CONTENT_SCHEMA, 0);
165 db_set("aux-schema", AUX_SCHEMA, 0);
166 db_set("rebuilt", get_version(), 0);
167 remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, g.argv[2]);
168 url_remember();
169 if( g.zSSLIdentity!=0 ){
170 /* If the --ssl-identity option was specified, store it as a setting */
171 Blob fn;
172 blob_zero(&fn);
@@ -195,10 +199,57 @@
199 fossil_print("project-id: %s\n", db_get("project-code", 0));
200 zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
201 fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
202 db_end_transaction(0);
203 }
204
205 /*
206 ** If user chooses to use HTTP Authentication over unencrypted HTTP,
207 ** remember decision. Otherwise, if the URL is being changed and no
208 ** preference has been indicated, err on the safe side and revert the
209 ** decision. Set the global preference if the URL is not being changed.
210 */
211 void remember_or_get_http_auth(
212 const char *zHttpAuth, /* Credentials in the form "user:password" */
213 int fRemember, /* True to remember credentials for later reuse */
214 const char *zUrl /* URL for which these credentials apply */
215 ){
216 char *zKey = mprintf("http-auth:%s", g.urlCanonical);
217 if( zHttpAuth && zHttpAuth[0] ){
218 g.zHttpAuth = mprintf("%s", zHttpAuth);
219 }
220 if( fRemember ){
221 if( g.zHttpAuth && g.zHttpAuth[0] ){
222 set_httpauth(g.zHttpAuth);
223 }else if( zUrl && zUrl[0] ){
224 db_unset(zKey, 0);
225 }else{
226 g.zHttpAuth = get_httpauth();
227 }
228 }else if( g.zHttpAuth==0 && zUrl==0 ){
229 g.zHttpAuth = get_httpauth();
230 }
231 free(zKey);
232 }
233
234 /*
235 ** Get the HTTP Authorization preference from db.
236 */
237 char *get_httpauth(void){
238 char *zKey = mprintf("http-auth:%s", g.urlCanonical);
239 return unobscure(db_get(zKey, 0));
240 free(zKey);
241 }
242
243 /*
244 ** Set the HTTP Authorization preference in db.
245 */
246 void set_httpauth(const char *zHttpAuth){
247 char *zKey = mprintf("http-auth:%s", g.urlCanonical);
248 db_set(zKey, obscure(zHttpAuth), 0);
249 free(zKey);
250 }
251
252 /*
253 ** Look for SSH clone command line options and setup in globals.
254 */
255 void clone_ssh_find_options(void){
256
+42 -14
--- src/diff.c
+++ src/diff.c
@@ -115,10 +115,11 @@
115115
int nEditAlloc; /* Space allocated for aEdit[] */
116116
DLine *aFrom; /* File on left side of the diff */
117117
int nFrom; /* Number of lines in aFrom[] */
118118
DLine *aTo; /* File on right side of the diff */
119119
int nTo; /* Number of lines in aTo[] */
120
+ int (*same_fn)(DLine *, DLine *); /* Function to be used for comparing */
120121
};
121122
122123
/*
123124
** Return an array of DLine objects containing a pointer to the
124125
** start of each line and a hash of that line. The lower
@@ -198,12 +199,21 @@
198199
199200
/*
200201
** Return true if two DLine elements are identical.
201202
*/
202203
static int same_dline(DLine *pA, DLine *pB){
203
- return pA->h==pB->h; // TODO: not quite right, need better hash function.
204
- //return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
204
+ return pA->h==pB->h && memcmp(pA->z,pB->z, pA->n)==0;
205
+}
206
+
207
+static int same_dline_ignore_wschg(DLine *pA, DLine *pB){
208
+ return pA->h==pB->h && memcmp(pA->z+pA->indent,pB->z+pB->indent,
209
+ pA->h & LENGTH_MASK)==0;
210
+}
211
+
212
+static int same_dline_ignore_allws(DLine *pA, DLine *pB){
213
+ return pA->h==pB->h && memcmp(pA->z+pA->indent,pB->z+pB->indent,
214
+ pA->h & LENGTH_MASK)==0;
205215
}
206216
207217
/*
208218
** Return true if the regular expression *pRe matches any of the
209219
** N dlines
@@ -1355,16 +1365,16 @@
13551365
int iSXb = iS1; /* Best match so far */
13561366
int iSYb = iS2; /* Best match so far */
13571367
13581368
for(i=iS1; i<iE1-mxLength; i++){
13591369
for(j=iS2; j<iE2-mxLength; j++){
1360
- if( !same_dline(&p->aFrom[i], &p->aTo[j]) ) continue;
1361
- if( mxLength && !same_dline(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
1370
+ if( !p->same_fn(&p->aFrom[i], &p->aTo[j]) ) continue;
1371
+ if( mxLength && !p->same_fn(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
13621372
continue;
13631373
}
13641374
k = 1;
1365
- while( i+k<iE1 && j+k<iE2 && same_dline(&p->aFrom[i+k],&p->aTo[j+k]) ){
1375
+ while( i+k<iE1 && j+k<iE2 && p->same_fn(&p->aFrom[i+k],&p->aTo[j+k]) ){
13661376
k++;
13671377
}
13681378
if( k>mxLength ){
13691379
iSXb = i;
13701380
iSYb = j;
@@ -1426,11 +1436,11 @@
14261436
mid = (iE1 + iS1)/2;
14271437
for(i=iS1; i<iE1; i++){
14281438
int limit = 0;
14291439
j = p->aTo[p->aFrom[i].h % p->nTo].iHash;
14301440
while( j>0
1431
- && (j-1<iS2 || j>=iE2 || !same_dline(&p->aFrom[i], &p->aTo[j-1]))
1441
+ && (j-1<iS2 || j>=iE2 || !p->same_fn(&p->aFrom[i], &p->aTo[j-1]))
14321442
){
14331443
if( limit++ > 10 ){
14341444
j = 0;
14351445
break;
14361446
}
@@ -1443,19 +1453,19 @@
14431453
iSX = i;
14441454
iSY = j-1;
14451455
pA = &p->aFrom[iSX-1];
14461456
pB = &p->aTo[iSY-1];
14471457
n = minInt(iSX-iS1, iSY-iS2);
1448
- for(k=0; k<n && same_dline(pA,pB); k++, pA--, pB--){}
1458
+ for(k=0; k<n && p->same_fn(pA,pB); k++, pA--, pB--){}
14491459
iSX -= k;
14501460
iSY -= k;
14511461
iEX = i+1;
14521462
iEY = j;
14531463
pA = &p->aFrom[iEX];
14541464
pB = &p->aTo[iEY];
14551465
n = minInt(iE1-iEX, iE2-iEY);
1456
- for(k=0; k<n && same_dline(pA,pB); k++, pA++, pB++){}
1466
+ for(k=0; k<n && p->same_fn(pA,pB); k++, pA++, pB++){}
14571467
iEX += k;
14581468
iEY += k;
14591469
skew = (iSX-iS1) - (iSY-iS2);
14601470
if( skew<0 ) skew = -skew;
14611471
dist = (iSX+iEX)/2 - mid;
@@ -1592,16 +1602,16 @@
15921602
int mnE, iS, iE1, iE2;
15931603
15941604
/* Carve off the common header and footer */
15951605
iE1 = p->nFrom;
15961606
iE2 = p->nTo;
1597
- while( iE1>0 && iE2>0 && same_dline(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
1607
+ while( iE1>0 && iE2>0 && p->same_fn(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
15981608
iE1--;
15991609
iE2--;
16001610
}
16011611
mnE = iE1<iE2 ? iE1 : iE2;
1602
- for(iS=0; iS<mnE && same_dline(&p->aFrom[iS],&p->aTo[iS]); iS++){}
1612
+ for(iS=0; iS<mnE && p->same_fn(&p->aFrom[iS],&p->aTo[iS]); iS++){}
16031613
16041614
/* do the difference */
16051615
if( iS>0 ){
16061616
appendTriple(p, iS, 0, 0);
16071617
}
@@ -1666,11 +1676,11 @@
16661676
16671677
/* Shift insertions toward the beginning of the file */
16681678
while( cpy>0 && del==0 && ins>0 ){
16691679
DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */
16701680
DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */
1671
- if( same_dline(pTop, pBtm)==0 ) break;
1681
+ if( p->same_fn(pTop, pBtm)==0 ) break;
16721682
if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
16731683
lnFrom--;
16741684
lnTo--;
16751685
p->aEdit[r]--;
16761686
p->aEdit[r+3]++;
@@ -1679,11 +1689,11 @@
16791689
16801690
/* Shift insertions toward the end of the file */
16811691
while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
16821692
DLine *pTop = &p->aTo[lnTo]; /* First line inserted */
16831693
DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */
1684
- if( same_dline(pTop, pBtm)==0 ) break;
1694
+ if( p->same_fn(pTop, pBtm)==0 ) break;
16851695
if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
16861696
lnFrom++;
16871697
lnTo++;
16881698
p->aEdit[r]++;
16891699
p->aEdit[r+3]--;
@@ -1692,11 +1702,11 @@
16921702
16931703
/* Shift deletions toward the beginning of the file */
16941704
while( cpy>0 && del>0 && ins==0 ){
16951705
DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */
16961706
DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
1697
- if( same_dline(pTop, pBtm)==0 ) break;
1707
+ if( p->same_fn(pTop, pBtm)==0 ) break;
16981708
if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
16991709
lnFrom--;
17001710
lnTo--;
17011711
p->aEdit[r]--;
17021712
p->aEdit[r+3]++;
@@ -1705,11 +1715,11 @@
17051715
17061716
/* Shift deletions toward the end of the file */
17071717
while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
17081718
DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */
17091719
DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
1710
- if( same_dline(pTop, pBtm)==0 ) break;
1720
+ if( p->same_fn(pTop, pBtm)==0 ) break;
17111721
if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
17121722
lnFrom++;
17131723
lnTo++;
17141724
p->aEdit[r]++;
17151725
p->aEdit[r+3]--;
@@ -1785,10 +1795,19 @@
17851795
blob_to_utf8_no_bom(pA_Blob, 0);
17861796
blob_to_utf8_no_bom(pB_Blob, 0);
17871797
17881798
/* Prepare the input files */
17891799
memset(&c, 0, sizeof(c));
1800
+ if( diffFlags & DIFF_IGNORE_WSCHG ){
1801
+ if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
1802
+ c.same_fn = same_dline_ignore_allws;
1803
+ }else{
1804
+ c.same_fn = same_dline_ignore_wschg;
1805
+ }
1806
+ }else{
1807
+ c.same_fn = same_dline;
1808
+ }
17901809
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
17911810
&c.nFrom, diffFlags);
17921811
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
17931812
&c.nTo, diffFlags);
17941813
if( c.aFrom==0 || c.aTo==0 ){
@@ -1997,10 +2016,19 @@
19972016
*/
19982017
static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
19992018
int i;
20002019
20012020
memset(p, 0, sizeof(*p));
2021
+ if( diffFlags & DIFF_IGNORE_WSCHG ){
2022
+ if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
2023
+ p->c.same_fn = same_dline_ignore_allws;
2024
+ }else{
2025
+ p->c.same_fn = same_dline_ignore_wschg;
2026
+ }
2027
+ }else{
2028
+ p->c.same_fn = same_dline;
2029
+ }
20022030
p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
20032031
diffFlags);
20042032
if( p->c.aTo==0 ){
20052033
return 1;
20062034
}
20072035
--- src/diff.c
+++ src/diff.c
@@ -115,10 +115,11 @@
115 int nEditAlloc; /* Space allocated for aEdit[] */
116 DLine *aFrom; /* File on left side of the diff */
117 int nFrom; /* Number of lines in aFrom[] */
118 DLine *aTo; /* File on right side of the diff */
119 int nTo; /* Number of lines in aTo[] */
 
120 };
121
122 /*
123 ** Return an array of DLine objects containing a pointer to the
124 ** start of each line and a hash of that line. The lower
@@ -198,12 +199,21 @@
198
199 /*
200 ** Return true if two DLine elements are identical.
201 */
202 static int same_dline(DLine *pA, DLine *pB){
203 return pA->h==pB->h; // TODO: not quite right, need better hash function.
204 //return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
 
 
 
 
 
 
 
 
 
205 }
206
207 /*
208 ** Return true if the regular expression *pRe matches any of the
209 ** N dlines
@@ -1355,16 +1365,16 @@
1355 int iSXb = iS1; /* Best match so far */
1356 int iSYb = iS2; /* Best match so far */
1357
1358 for(i=iS1; i<iE1-mxLength; i++){
1359 for(j=iS2; j<iE2-mxLength; j++){
1360 if( !same_dline(&p->aFrom[i], &p->aTo[j]) ) continue;
1361 if( mxLength && !same_dline(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
1362 continue;
1363 }
1364 k = 1;
1365 while( i+k<iE1 && j+k<iE2 && same_dline(&p->aFrom[i+k],&p->aTo[j+k]) ){
1366 k++;
1367 }
1368 if( k>mxLength ){
1369 iSXb = i;
1370 iSYb = j;
@@ -1426,11 +1436,11 @@
1426 mid = (iE1 + iS1)/2;
1427 for(i=iS1; i<iE1; i++){
1428 int limit = 0;
1429 j = p->aTo[p->aFrom[i].h % p->nTo].iHash;
1430 while( j>0
1431 && (j-1<iS2 || j>=iE2 || !same_dline(&p->aFrom[i], &p->aTo[j-1]))
1432 ){
1433 if( limit++ > 10 ){
1434 j = 0;
1435 break;
1436 }
@@ -1443,19 +1453,19 @@
1443 iSX = i;
1444 iSY = j-1;
1445 pA = &p->aFrom[iSX-1];
1446 pB = &p->aTo[iSY-1];
1447 n = minInt(iSX-iS1, iSY-iS2);
1448 for(k=0; k<n && same_dline(pA,pB); k++, pA--, pB--){}
1449 iSX -= k;
1450 iSY -= k;
1451 iEX = i+1;
1452 iEY = j;
1453 pA = &p->aFrom[iEX];
1454 pB = &p->aTo[iEY];
1455 n = minInt(iE1-iEX, iE2-iEY);
1456 for(k=0; k<n && same_dline(pA,pB); k++, pA++, pB++){}
1457 iEX += k;
1458 iEY += k;
1459 skew = (iSX-iS1) - (iSY-iS2);
1460 if( skew<0 ) skew = -skew;
1461 dist = (iSX+iEX)/2 - mid;
@@ -1592,16 +1602,16 @@
1592 int mnE, iS, iE1, iE2;
1593
1594 /* Carve off the common header and footer */
1595 iE1 = p->nFrom;
1596 iE2 = p->nTo;
1597 while( iE1>0 && iE2>0 && same_dline(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
1598 iE1--;
1599 iE2--;
1600 }
1601 mnE = iE1<iE2 ? iE1 : iE2;
1602 for(iS=0; iS<mnE && same_dline(&p->aFrom[iS],&p->aTo[iS]); iS++){}
1603
1604 /* do the difference */
1605 if( iS>0 ){
1606 appendTriple(p, iS, 0, 0);
1607 }
@@ -1666,11 +1676,11 @@
1666
1667 /* Shift insertions toward the beginning of the file */
1668 while( cpy>0 && del==0 && ins>0 ){
1669 DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */
1670 DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */
1671 if( same_dline(pTop, pBtm)==0 ) break;
1672 if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
1673 lnFrom--;
1674 lnTo--;
1675 p->aEdit[r]--;
1676 p->aEdit[r+3]++;
@@ -1679,11 +1689,11 @@
1679
1680 /* Shift insertions toward the end of the file */
1681 while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
1682 DLine *pTop = &p->aTo[lnTo]; /* First line inserted */
1683 DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */
1684 if( same_dline(pTop, pBtm)==0 ) break;
1685 if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
1686 lnFrom++;
1687 lnTo++;
1688 p->aEdit[r]++;
1689 p->aEdit[r+3]--;
@@ -1692,11 +1702,11 @@
1692
1693 /* Shift deletions toward the beginning of the file */
1694 while( cpy>0 && del>0 && ins==0 ){
1695 DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */
1696 DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
1697 if( same_dline(pTop, pBtm)==0 ) break;
1698 if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
1699 lnFrom--;
1700 lnTo--;
1701 p->aEdit[r]--;
1702 p->aEdit[r+3]++;
@@ -1705,11 +1715,11 @@
1705
1706 /* Shift deletions toward the end of the file */
1707 while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
1708 DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */
1709 DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
1710 if( same_dline(pTop, pBtm)==0 ) break;
1711 if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
1712 lnFrom++;
1713 lnTo++;
1714 p->aEdit[r]++;
1715 p->aEdit[r+3]--;
@@ -1785,10 +1795,19 @@
1785 blob_to_utf8_no_bom(pA_Blob, 0);
1786 blob_to_utf8_no_bom(pB_Blob, 0);
1787
1788 /* Prepare the input files */
1789 memset(&c, 0, sizeof(c));
 
 
 
 
 
 
 
 
 
1790 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
1791 &c.nFrom, diffFlags);
1792 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
1793 &c.nTo, diffFlags);
1794 if( c.aFrom==0 || c.aTo==0 ){
@@ -1997,10 +2016,19 @@
1997 */
1998 static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
1999 int i;
2000
2001 memset(p, 0, sizeof(*p));
 
 
 
 
 
 
 
 
 
2002 p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
2003 diffFlags);
2004 if( p->c.aTo==0 ){
2005 return 1;
2006 }
2007
--- src/diff.c
+++ src/diff.c
@@ -115,10 +115,11 @@
115 int nEditAlloc; /* Space allocated for aEdit[] */
116 DLine *aFrom; /* File on left side of the diff */
117 int nFrom; /* Number of lines in aFrom[] */
118 DLine *aTo; /* File on right side of the diff */
119 int nTo; /* Number of lines in aTo[] */
120 int (*same_fn)(DLine *, DLine *); /* Function to be used for comparing */
121 };
122
123 /*
124 ** Return an array of DLine objects containing a pointer to the
125 ** start of each line and a hash of that line. The lower
@@ -198,12 +199,21 @@
199
200 /*
201 ** Return true if two DLine elements are identical.
202 */
203 static int same_dline(DLine *pA, DLine *pB){
204 return pA->h==pB->h && memcmp(pA->z,pB->z, pA->n)==0;
205 }
206
207 static int same_dline_ignore_wschg(DLine *pA, DLine *pB){
208 return pA->h==pB->h && memcmp(pA->z+pA->indent,pB->z+pB->indent,
209 pA->h & LENGTH_MASK)==0;
210 }
211
212 static int same_dline_ignore_allws(DLine *pA, DLine *pB){
213 return pA->h==pB->h && memcmp(pA->z+pA->indent,pB->z+pB->indent,
214 pA->h & LENGTH_MASK)==0;
215 }
216
217 /*
218 ** Return true if the regular expression *pRe matches any of the
219 ** N dlines
@@ -1355,16 +1365,16 @@
1365 int iSXb = iS1; /* Best match so far */
1366 int iSYb = iS2; /* Best match so far */
1367
1368 for(i=iS1; i<iE1-mxLength; i++){
1369 for(j=iS2; j<iE2-mxLength; j++){
1370 if( !p->same_fn(&p->aFrom[i], &p->aTo[j]) ) continue;
1371 if( mxLength && !p->same_fn(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
1372 continue;
1373 }
1374 k = 1;
1375 while( i+k<iE1 && j+k<iE2 && p->same_fn(&p->aFrom[i+k],&p->aTo[j+k]) ){
1376 k++;
1377 }
1378 if( k>mxLength ){
1379 iSXb = i;
1380 iSYb = j;
@@ -1426,11 +1436,11 @@
1436 mid = (iE1 + iS1)/2;
1437 for(i=iS1; i<iE1; i++){
1438 int limit = 0;
1439 j = p->aTo[p->aFrom[i].h % p->nTo].iHash;
1440 while( j>0
1441 && (j-1<iS2 || j>=iE2 || !p->same_fn(&p->aFrom[i], &p->aTo[j-1]))
1442 ){
1443 if( limit++ > 10 ){
1444 j = 0;
1445 break;
1446 }
@@ -1443,19 +1453,19 @@
1453 iSX = i;
1454 iSY = j-1;
1455 pA = &p->aFrom[iSX-1];
1456 pB = &p->aTo[iSY-1];
1457 n = minInt(iSX-iS1, iSY-iS2);
1458 for(k=0; k<n && p->same_fn(pA,pB); k++, pA--, pB--){}
1459 iSX -= k;
1460 iSY -= k;
1461 iEX = i+1;
1462 iEY = j;
1463 pA = &p->aFrom[iEX];
1464 pB = &p->aTo[iEY];
1465 n = minInt(iE1-iEX, iE2-iEY);
1466 for(k=0; k<n && p->same_fn(pA,pB); k++, pA++, pB++){}
1467 iEX += k;
1468 iEY += k;
1469 skew = (iSX-iS1) - (iSY-iS2);
1470 if( skew<0 ) skew = -skew;
1471 dist = (iSX+iEX)/2 - mid;
@@ -1592,16 +1602,16 @@
1602 int mnE, iS, iE1, iE2;
1603
1604 /* Carve off the common header and footer */
1605 iE1 = p->nFrom;
1606 iE2 = p->nTo;
1607 while( iE1>0 && iE2>0 && p->same_fn(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
1608 iE1--;
1609 iE2--;
1610 }
1611 mnE = iE1<iE2 ? iE1 : iE2;
1612 for(iS=0; iS<mnE && p->same_fn(&p->aFrom[iS],&p->aTo[iS]); iS++){}
1613
1614 /* do the difference */
1615 if( iS>0 ){
1616 appendTriple(p, iS, 0, 0);
1617 }
@@ -1666,11 +1676,11 @@
1676
1677 /* Shift insertions toward the beginning of the file */
1678 while( cpy>0 && del==0 && ins>0 ){
1679 DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */
1680 DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */
1681 if( p->same_fn(pTop, pBtm)==0 ) break;
1682 if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
1683 lnFrom--;
1684 lnTo--;
1685 p->aEdit[r]--;
1686 p->aEdit[r+3]++;
@@ -1679,11 +1689,11 @@
1689
1690 /* Shift insertions toward the end of the file */
1691 while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
1692 DLine *pTop = &p->aTo[lnTo]; /* First line inserted */
1693 DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */
1694 if( p->same_fn(pTop, pBtm)==0 ) break;
1695 if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
1696 lnFrom++;
1697 lnTo++;
1698 p->aEdit[r]++;
1699 p->aEdit[r+3]--;
@@ -1692,11 +1702,11 @@
1702
1703 /* Shift deletions toward the beginning of the file */
1704 while( cpy>0 && del>0 && ins==0 ){
1705 DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */
1706 DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
1707 if( p->same_fn(pTop, pBtm)==0 ) break;
1708 if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
1709 lnFrom--;
1710 lnTo--;
1711 p->aEdit[r]--;
1712 p->aEdit[r+3]++;
@@ -1705,11 +1715,11 @@
1715
1716 /* Shift deletions toward the end of the file */
1717 while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
1718 DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */
1719 DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
1720 if( p->same_fn(pTop, pBtm)==0 ) break;
1721 if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
1722 lnFrom++;
1723 lnTo++;
1724 p->aEdit[r]++;
1725 p->aEdit[r+3]--;
@@ -1785,10 +1795,19 @@
1795 blob_to_utf8_no_bom(pA_Blob, 0);
1796 blob_to_utf8_no_bom(pB_Blob, 0);
1797
1798 /* Prepare the input files */
1799 memset(&c, 0, sizeof(c));
1800 if( diffFlags & DIFF_IGNORE_WSCHG ){
1801 if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
1802 c.same_fn = same_dline_ignore_allws;
1803 }else{
1804 c.same_fn = same_dline_ignore_wschg;
1805 }
1806 }else{
1807 c.same_fn = same_dline;
1808 }
1809 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
1810 &c.nFrom, diffFlags);
1811 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
1812 &c.nTo, diffFlags);
1813 if( c.aFrom==0 || c.aTo==0 ){
@@ -1997,10 +2016,19 @@
2016 */
2017 static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
2018 int i;
2019
2020 memset(p, 0, sizeof(*p));
2021 if( diffFlags & DIFF_IGNORE_WSCHG ){
2022 if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
2023 p->c.same_fn = same_dline_ignore_allws;
2024 }else{
2025 p->c.same_fn = same_dline_ignore_wschg;
2026 }
2027 }else{
2028 p->c.same_fn = same_dline;
2029 }
2030 p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
2031 diffFlags);
2032 if( p->c.aTo==0 ){
2033 return 1;
2034 }
2035
+42 -14
--- src/diff.c
+++ src/diff.c
@@ -115,10 +115,11 @@
115115
int nEditAlloc; /* Space allocated for aEdit[] */
116116
DLine *aFrom; /* File on left side of the diff */
117117
int nFrom; /* Number of lines in aFrom[] */
118118
DLine *aTo; /* File on right side of the diff */
119119
int nTo; /* Number of lines in aTo[] */
120
+ int (*same_fn)(DLine *, DLine *); /* Function to be used for comparing */
120121
};
121122
122123
/*
123124
** Return an array of DLine objects containing a pointer to the
124125
** start of each line and a hash of that line. The lower
@@ -198,12 +199,21 @@
198199
199200
/*
200201
** Return true if two DLine elements are identical.
201202
*/
202203
static int same_dline(DLine *pA, DLine *pB){
203
- return pA->h==pB->h; // TODO: not quite right, need better hash function.
204
- //return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
204
+ return pA->h==pB->h && memcmp(pA->z,pB->z, pA->n)==0;
205
+}
206
+
207
+static int same_dline_ignore_wschg(DLine *pA, DLine *pB){
208
+ return pA->h==pB->h && memcmp(pA->z+pA->indent,pB->z+pB->indent,
209
+ pA->h & LENGTH_MASK)==0;
210
+}
211
+
212
+static int same_dline_ignore_allws(DLine *pA, DLine *pB){
213
+ return pA->h==pB->h && memcmp(pA->z+pA->indent,pB->z+pB->indent,
214
+ pA->h & LENGTH_MASK)==0;
205215
}
206216
207217
/*
208218
** Return true if the regular expression *pRe matches any of the
209219
** N dlines
@@ -1355,16 +1365,16 @@
13551365
int iSXb = iS1; /* Best match so far */
13561366
int iSYb = iS2; /* Best match so far */
13571367
13581368
for(i=iS1; i<iE1-mxLength; i++){
13591369
for(j=iS2; j<iE2-mxLength; j++){
1360
- if( !same_dline(&p->aFrom[i], &p->aTo[j]) ) continue;
1361
- if( mxLength && !same_dline(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
1370
+ if( !p->same_fn(&p->aFrom[i], &p->aTo[j]) ) continue;
1371
+ if( mxLength && !p->same_fn(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
13621372
continue;
13631373
}
13641374
k = 1;
1365
- while( i+k<iE1 && j+k<iE2 && same_dline(&p->aFrom[i+k],&p->aTo[j+k]) ){
1375
+ while( i+k<iE1 && j+k<iE2 && p->same_fn(&p->aFrom[i+k],&p->aTo[j+k]) ){
13661376
k++;
13671377
}
13681378
if( k>mxLength ){
13691379
iSXb = i;
13701380
iSYb = j;
@@ -1426,11 +1436,11 @@
14261436
mid = (iE1 + iS1)/2;
14271437
for(i=iS1; i<iE1; i++){
14281438
int limit = 0;
14291439
j = p->aTo[p->aFrom[i].h % p->nTo].iHash;
14301440
while( j>0
1431
- && (j-1<iS2 || j>=iE2 || !same_dline(&p->aFrom[i], &p->aTo[j-1]))
1441
+ && (j-1<iS2 || j>=iE2 || !p->same_fn(&p->aFrom[i], &p->aTo[j-1]))
14321442
){
14331443
if( limit++ > 10 ){
14341444
j = 0;
14351445
break;
14361446
}
@@ -1443,19 +1453,19 @@
14431453
iSX = i;
14441454
iSY = j-1;
14451455
pA = &p->aFrom[iSX-1];
14461456
pB = &p->aTo[iSY-1];
14471457
n = minInt(iSX-iS1, iSY-iS2);
1448
- for(k=0; k<n && same_dline(pA,pB); k++, pA--, pB--){}
1458
+ for(k=0; k<n && p->same_fn(pA,pB); k++, pA--, pB--){}
14491459
iSX -= k;
14501460
iSY -= k;
14511461
iEX = i+1;
14521462
iEY = j;
14531463
pA = &p->aFrom[iEX];
14541464
pB = &p->aTo[iEY];
14551465
n = minInt(iE1-iEX, iE2-iEY);
1456
- for(k=0; k<n && same_dline(pA,pB); k++, pA++, pB++){}
1466
+ for(k=0; k<n && p->same_fn(pA,pB); k++, pA++, pB++){}
14571467
iEX += k;
14581468
iEY += k;
14591469
skew = (iSX-iS1) - (iSY-iS2);
14601470
if( skew<0 ) skew = -skew;
14611471
dist = (iSX+iEX)/2 - mid;
@@ -1592,16 +1602,16 @@
15921602
int mnE, iS, iE1, iE2;
15931603
15941604
/* Carve off the common header and footer */
15951605
iE1 = p->nFrom;
15961606
iE2 = p->nTo;
1597
- while( iE1>0 && iE2>0 && same_dline(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
1607
+ while( iE1>0 && iE2>0 && p->same_fn(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
15981608
iE1--;
15991609
iE2--;
16001610
}
16011611
mnE = iE1<iE2 ? iE1 : iE2;
1602
- for(iS=0; iS<mnE && same_dline(&p->aFrom[iS],&p->aTo[iS]); iS++){}
1612
+ for(iS=0; iS<mnE && p->same_fn(&p->aFrom[iS],&p->aTo[iS]); iS++){}
16031613
16041614
/* do the difference */
16051615
if( iS>0 ){
16061616
appendTriple(p, iS, 0, 0);
16071617
}
@@ -1666,11 +1676,11 @@
16661676
16671677
/* Shift insertions toward the beginning of the file */
16681678
while( cpy>0 && del==0 && ins>0 ){
16691679
DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */
16701680
DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */
1671
- if( same_dline(pTop, pBtm)==0 ) break;
1681
+ if( p->same_fn(pTop, pBtm)==0 ) break;
16721682
if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
16731683
lnFrom--;
16741684
lnTo--;
16751685
p->aEdit[r]--;
16761686
p->aEdit[r+3]++;
@@ -1679,11 +1689,11 @@
16791689
16801690
/* Shift insertions toward the end of the file */
16811691
while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
16821692
DLine *pTop = &p->aTo[lnTo]; /* First line inserted */
16831693
DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */
1684
- if( same_dline(pTop, pBtm)==0 ) break;
1694
+ if( p->same_fn(pTop, pBtm)==0 ) break;
16851695
if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
16861696
lnFrom++;
16871697
lnTo++;
16881698
p->aEdit[r]++;
16891699
p->aEdit[r+3]--;
@@ -1692,11 +1702,11 @@
16921702
16931703
/* Shift deletions toward the beginning of the file */
16941704
while( cpy>0 && del>0 && ins==0 ){
16951705
DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */
16961706
DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
1697
- if( same_dline(pTop, pBtm)==0 ) break;
1707
+ if( p->same_fn(pTop, pBtm)==0 ) break;
16981708
if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
16991709
lnFrom--;
17001710
lnTo--;
17011711
p->aEdit[r]--;
17021712
p->aEdit[r+3]++;
@@ -1705,11 +1715,11 @@
17051715
17061716
/* Shift deletions toward the end of the file */
17071717
while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
17081718
DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */
17091719
DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
1710
- if( same_dline(pTop, pBtm)==0 ) break;
1720
+ if( p->same_fn(pTop, pBtm)==0 ) break;
17111721
if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
17121722
lnFrom++;
17131723
lnTo++;
17141724
p->aEdit[r]++;
17151725
p->aEdit[r+3]--;
@@ -1785,10 +1795,19 @@
17851795
blob_to_utf8_no_bom(pA_Blob, 0);
17861796
blob_to_utf8_no_bom(pB_Blob, 0);
17871797
17881798
/* Prepare the input files */
17891799
memset(&c, 0, sizeof(c));
1800
+ if( diffFlags & DIFF_IGNORE_WSCHG ){
1801
+ if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
1802
+ c.same_fn = same_dline_ignore_allws;
1803
+ }else{
1804
+ c.same_fn = same_dline_ignore_wschg;
1805
+ }
1806
+ }else{
1807
+ c.same_fn = same_dline;
1808
+ }
17901809
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
17911810
&c.nFrom, diffFlags);
17921811
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
17931812
&c.nTo, diffFlags);
17941813
if( c.aFrom==0 || c.aTo==0 ){
@@ -1997,10 +2016,19 @@
19972016
*/
19982017
static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
19992018
int i;
20002019
20012020
memset(p, 0, sizeof(*p));
2021
+ if( diffFlags & DIFF_IGNORE_WSCHG ){
2022
+ if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
2023
+ p->c.same_fn = same_dline_ignore_allws;
2024
+ }else{
2025
+ p->c.same_fn = same_dline_ignore_wschg;
2026
+ }
2027
+ }else{
2028
+ p->c.same_fn = same_dline;
2029
+ }
20022030
p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
20032031
diffFlags);
20042032
if( p->c.aTo==0 ){
20052033
return 1;
20062034
}
20072035
--- src/diff.c
+++ src/diff.c
@@ -115,10 +115,11 @@
115 int nEditAlloc; /* Space allocated for aEdit[] */
116 DLine *aFrom; /* File on left side of the diff */
117 int nFrom; /* Number of lines in aFrom[] */
118 DLine *aTo; /* File on right side of the diff */
119 int nTo; /* Number of lines in aTo[] */
 
120 };
121
122 /*
123 ** Return an array of DLine objects containing a pointer to the
124 ** start of each line and a hash of that line. The lower
@@ -198,12 +199,21 @@
198
199 /*
200 ** Return true if two DLine elements are identical.
201 */
202 static int same_dline(DLine *pA, DLine *pB){
203 return pA->h==pB->h; // TODO: not quite right, need better hash function.
204 //return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
 
 
 
 
 
 
 
 
 
205 }
206
207 /*
208 ** Return true if the regular expression *pRe matches any of the
209 ** N dlines
@@ -1355,16 +1365,16 @@
1355 int iSXb = iS1; /* Best match so far */
1356 int iSYb = iS2; /* Best match so far */
1357
1358 for(i=iS1; i<iE1-mxLength; i++){
1359 for(j=iS2; j<iE2-mxLength; j++){
1360 if( !same_dline(&p->aFrom[i], &p->aTo[j]) ) continue;
1361 if( mxLength && !same_dline(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
1362 continue;
1363 }
1364 k = 1;
1365 while( i+k<iE1 && j+k<iE2 && same_dline(&p->aFrom[i+k],&p->aTo[j+k]) ){
1366 k++;
1367 }
1368 if( k>mxLength ){
1369 iSXb = i;
1370 iSYb = j;
@@ -1426,11 +1436,11 @@
1426 mid = (iE1 + iS1)/2;
1427 for(i=iS1; i<iE1; i++){
1428 int limit = 0;
1429 j = p->aTo[p->aFrom[i].h % p->nTo].iHash;
1430 while( j>0
1431 && (j-1<iS2 || j>=iE2 || !same_dline(&p->aFrom[i], &p->aTo[j-1]))
1432 ){
1433 if( limit++ > 10 ){
1434 j = 0;
1435 break;
1436 }
@@ -1443,19 +1453,19 @@
1443 iSX = i;
1444 iSY = j-1;
1445 pA = &p->aFrom[iSX-1];
1446 pB = &p->aTo[iSY-1];
1447 n = minInt(iSX-iS1, iSY-iS2);
1448 for(k=0; k<n && same_dline(pA,pB); k++, pA--, pB--){}
1449 iSX -= k;
1450 iSY -= k;
1451 iEX = i+1;
1452 iEY = j;
1453 pA = &p->aFrom[iEX];
1454 pB = &p->aTo[iEY];
1455 n = minInt(iE1-iEX, iE2-iEY);
1456 for(k=0; k<n && same_dline(pA,pB); k++, pA++, pB++){}
1457 iEX += k;
1458 iEY += k;
1459 skew = (iSX-iS1) - (iSY-iS2);
1460 if( skew<0 ) skew = -skew;
1461 dist = (iSX+iEX)/2 - mid;
@@ -1592,16 +1602,16 @@
1592 int mnE, iS, iE1, iE2;
1593
1594 /* Carve off the common header and footer */
1595 iE1 = p->nFrom;
1596 iE2 = p->nTo;
1597 while( iE1>0 && iE2>0 && same_dline(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
1598 iE1--;
1599 iE2--;
1600 }
1601 mnE = iE1<iE2 ? iE1 : iE2;
1602 for(iS=0; iS<mnE && same_dline(&p->aFrom[iS],&p->aTo[iS]); iS++){}
1603
1604 /* do the difference */
1605 if( iS>0 ){
1606 appendTriple(p, iS, 0, 0);
1607 }
@@ -1666,11 +1676,11 @@
1666
1667 /* Shift insertions toward the beginning of the file */
1668 while( cpy>0 && del==0 && ins>0 ){
1669 DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */
1670 DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */
1671 if( same_dline(pTop, pBtm)==0 ) break;
1672 if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
1673 lnFrom--;
1674 lnTo--;
1675 p->aEdit[r]--;
1676 p->aEdit[r+3]++;
@@ -1679,11 +1689,11 @@
1679
1680 /* Shift insertions toward the end of the file */
1681 while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
1682 DLine *pTop = &p->aTo[lnTo]; /* First line inserted */
1683 DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */
1684 if( same_dline(pTop, pBtm)==0 ) break;
1685 if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
1686 lnFrom++;
1687 lnTo++;
1688 p->aEdit[r]++;
1689 p->aEdit[r+3]--;
@@ -1692,11 +1702,11 @@
1692
1693 /* Shift deletions toward the beginning of the file */
1694 while( cpy>0 && del>0 && ins==0 ){
1695 DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */
1696 DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
1697 if( same_dline(pTop, pBtm)==0 ) break;
1698 if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
1699 lnFrom--;
1700 lnTo--;
1701 p->aEdit[r]--;
1702 p->aEdit[r+3]++;
@@ -1705,11 +1715,11 @@
1705
1706 /* Shift deletions toward the end of the file */
1707 while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
1708 DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */
1709 DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
1710 if( same_dline(pTop, pBtm)==0 ) break;
1711 if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
1712 lnFrom++;
1713 lnTo++;
1714 p->aEdit[r]++;
1715 p->aEdit[r+3]--;
@@ -1785,10 +1795,19 @@
1785 blob_to_utf8_no_bom(pA_Blob, 0);
1786 blob_to_utf8_no_bom(pB_Blob, 0);
1787
1788 /* Prepare the input files */
1789 memset(&c, 0, sizeof(c));
 
 
 
 
 
 
 
 
 
1790 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
1791 &c.nFrom, diffFlags);
1792 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
1793 &c.nTo, diffFlags);
1794 if( c.aFrom==0 || c.aTo==0 ){
@@ -1997,10 +2016,19 @@
1997 */
1998 static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
1999 int i;
2000
2001 memset(p, 0, sizeof(*p));
 
 
 
 
 
 
 
 
 
2002 p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
2003 diffFlags);
2004 if( p->c.aTo==0 ){
2005 return 1;
2006 }
2007
--- src/diff.c
+++ src/diff.c
@@ -115,10 +115,11 @@
115 int nEditAlloc; /* Space allocated for aEdit[] */
116 DLine *aFrom; /* File on left side of the diff */
117 int nFrom; /* Number of lines in aFrom[] */
118 DLine *aTo; /* File on right side of the diff */
119 int nTo; /* Number of lines in aTo[] */
120 int (*same_fn)(DLine *, DLine *); /* Function to be used for comparing */
121 };
122
123 /*
124 ** Return an array of DLine objects containing a pointer to the
125 ** start of each line and a hash of that line. The lower
@@ -198,12 +199,21 @@
199
200 /*
201 ** Return true if two DLine elements are identical.
202 */
203 static int same_dline(DLine *pA, DLine *pB){
204 return pA->h==pB->h && memcmp(pA->z,pB->z, pA->n)==0;
205 }
206
207 static int same_dline_ignore_wschg(DLine *pA, DLine *pB){
208 return pA->h==pB->h && memcmp(pA->z+pA->indent,pB->z+pB->indent,
209 pA->h & LENGTH_MASK)==0;
210 }
211
212 static int same_dline_ignore_allws(DLine *pA, DLine *pB){
213 return pA->h==pB->h && memcmp(pA->z+pA->indent,pB->z+pB->indent,
214 pA->h & LENGTH_MASK)==0;
215 }
216
217 /*
218 ** Return true if the regular expression *pRe matches any of the
219 ** N dlines
@@ -1355,16 +1365,16 @@
1365 int iSXb = iS1; /* Best match so far */
1366 int iSYb = iS2; /* Best match so far */
1367
1368 for(i=iS1; i<iE1-mxLength; i++){
1369 for(j=iS2; j<iE2-mxLength; j++){
1370 if( !p->same_fn(&p->aFrom[i], &p->aTo[j]) ) continue;
1371 if( mxLength && !p->same_fn(&p->aFrom[i+mxLength], &p->aTo[j+mxLength]) ){
1372 continue;
1373 }
1374 k = 1;
1375 while( i+k<iE1 && j+k<iE2 && p->same_fn(&p->aFrom[i+k],&p->aTo[j+k]) ){
1376 k++;
1377 }
1378 if( k>mxLength ){
1379 iSXb = i;
1380 iSYb = j;
@@ -1426,11 +1436,11 @@
1436 mid = (iE1 + iS1)/2;
1437 for(i=iS1; i<iE1; i++){
1438 int limit = 0;
1439 j = p->aTo[p->aFrom[i].h % p->nTo].iHash;
1440 while( j>0
1441 && (j-1<iS2 || j>=iE2 || !p->same_fn(&p->aFrom[i], &p->aTo[j-1]))
1442 ){
1443 if( limit++ > 10 ){
1444 j = 0;
1445 break;
1446 }
@@ -1443,19 +1453,19 @@
1453 iSX = i;
1454 iSY = j-1;
1455 pA = &p->aFrom[iSX-1];
1456 pB = &p->aTo[iSY-1];
1457 n = minInt(iSX-iS1, iSY-iS2);
1458 for(k=0; k<n && p->same_fn(pA,pB); k++, pA--, pB--){}
1459 iSX -= k;
1460 iSY -= k;
1461 iEX = i+1;
1462 iEY = j;
1463 pA = &p->aFrom[iEX];
1464 pB = &p->aTo[iEY];
1465 n = minInt(iE1-iEX, iE2-iEY);
1466 for(k=0; k<n && p->same_fn(pA,pB); k++, pA++, pB++){}
1467 iEX += k;
1468 iEY += k;
1469 skew = (iSX-iS1) - (iSY-iS2);
1470 if( skew<0 ) skew = -skew;
1471 dist = (iSX+iEX)/2 - mid;
@@ -1592,16 +1602,16 @@
1602 int mnE, iS, iE1, iE2;
1603
1604 /* Carve off the common header and footer */
1605 iE1 = p->nFrom;
1606 iE2 = p->nTo;
1607 while( iE1>0 && iE2>0 && p->same_fn(&p->aFrom[iE1-1], &p->aTo[iE2-1]) ){
1608 iE1--;
1609 iE2--;
1610 }
1611 mnE = iE1<iE2 ? iE1 : iE2;
1612 for(iS=0; iS<mnE && p->same_fn(&p->aFrom[iS],&p->aTo[iS]); iS++){}
1613
1614 /* do the difference */
1615 if( iS>0 ){
1616 appendTriple(p, iS, 0, 0);
1617 }
@@ -1666,11 +1676,11 @@
1676
1677 /* Shift insertions toward the beginning of the file */
1678 while( cpy>0 && del==0 && ins>0 ){
1679 DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of insert */
1680 DLine *pBtm = &p->aTo[lnTo+ins-1]; /* Last line inserted */
1681 if( p->same_fn(pTop, pBtm)==0 ) break;
1682 if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
1683 lnFrom--;
1684 lnTo--;
1685 p->aEdit[r]--;
1686 p->aEdit[r+3]++;
@@ -1679,11 +1689,11 @@
1689
1690 /* Shift insertions toward the end of the file */
1691 while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
1692 DLine *pTop = &p->aTo[lnTo]; /* First line inserted */
1693 DLine *pBtm = &p->aTo[lnTo+ins]; /* First line past end of insert */
1694 if( p->same_fn(pTop, pBtm)==0 ) break;
1695 if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
1696 lnFrom++;
1697 lnTo++;
1698 p->aEdit[r]++;
1699 p->aEdit[r+3]--;
@@ -1692,11 +1702,11 @@
1702
1703 /* Shift deletions toward the beginning of the file */
1704 while( cpy>0 && del>0 && ins==0 ){
1705 DLine *pTop = &p->aFrom[lnFrom-1]; /* Line before start of delete */
1706 DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
1707 if( p->same_fn(pTop, pBtm)==0 ) break;
1708 if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
1709 lnFrom--;
1710 lnTo--;
1711 p->aEdit[r]--;
1712 p->aEdit[r+3]++;
@@ -1705,11 +1715,11 @@
1715
1716 /* Shift deletions toward the end of the file */
1717 while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
1718 DLine *pTop = &p->aFrom[lnFrom]; /* First line deleted */
1719 DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
1720 if( p->same_fn(pTop, pBtm)==0 ) break;
1721 if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
1722 lnFrom++;
1723 lnTo++;
1724 p->aEdit[r]++;
1725 p->aEdit[r+3]--;
@@ -1785,10 +1795,19 @@
1795 blob_to_utf8_no_bom(pA_Blob, 0);
1796 blob_to_utf8_no_bom(pB_Blob, 0);
1797
1798 /* Prepare the input files */
1799 memset(&c, 0, sizeof(c));
1800 if( diffFlags & DIFF_IGNORE_WSCHG ){
1801 if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
1802 c.same_fn = same_dline_ignore_allws;
1803 }else{
1804 c.same_fn = same_dline_ignore_wschg;
1805 }
1806 }else{
1807 c.same_fn = same_dline;
1808 }
1809 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
1810 &c.nFrom, diffFlags);
1811 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
1812 &c.nTo, diffFlags);
1813 if( c.aFrom==0 || c.aTo==0 ){
@@ -1997,10 +2016,19 @@
2016 */
2017 static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
2018 int i;
2019
2020 memset(p, 0, sizeof(*p));
2021 if( diffFlags & DIFF_IGNORE_WSCHG ){
2022 if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
2023 p->c.same_fn = same_dline_ignore_allws;
2024 }else{
2025 p->c.same_fn = same_dline_ignore_wschg;
2026 }
2027 }else{
2028 p->c.same_fn = same_dline;
2029 }
2030 p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
2031 diffFlags);
2032 if( p->c.aTo==0 ){
2033 return 1;
2034 }
2035
+92 -9
--- src/http.c
+++ src/http.c
@@ -19,10 +19,26 @@
1919
*/
2020
#include "config.h"
2121
#include "http.h"
2222
#include <assert.h>
2323
24
+#ifdef _WIN32
25
+#include <io.h>
26
+#ifndef isatty
27
+#define isatty(d) _isatty(d)
28
+#endif
29
+#ifndef fileno
30
+#define fileno(s) _fileno(s)
31
+#endif
32
+#endif
33
+
34
+/* Maximum number of HTTP Authorization attempts */
35
+#define MAX_HTTP_AUTH 2
36
+
37
+/* Keep track of HTTP Basic Authorization failures */
38
+static int fSeenHttpAuth = 0;
39
+
2440
/*
2541
** Construct the "login" card with the client credentials.
2642
**
2743
** login LOGIN NONCE SIGNATURE
2844
**
@@ -62,16 +78,10 @@
6278
/* Password failure while doing a sync from the command-line interface */
6379
url_prompt_for_password();
6480
zPw = g.urlPasswd;
6581
}
6682
67
- /* If the first character of the password is "#", then that character is
68
- ** not really part of the password - it is an indicator that we should
69
- ** use Basic Authentication. So skip that character.
70
- */
71
- if( zPw && zPw[0]=='#' ) zPw++;
72
-
7383
/* The login card wants the SHA1 hash of the password, so convert the
7484
** password to its SHA1 hash it it isn't already a SHA1 hash.
7585
*/
7686
/* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */
7787
if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0);
@@ -102,16 +112,15 @@
102112
}
103113
blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep);
104114
if( g.urlProxyAuth ){
105115
blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.urlProxyAuth);
106116
}
107
- if( g.urlPasswd && g.urlUser && g.urlPasswd[0]=='#' ){
108
- char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]);
117
+ if( g.zHttpAuth && g.zHttpAuth[0] ){
118
+ const char *zCredentials = g.zHttpAuth;
109119
char *zEncoded = encode64(zCredentials, -1);
110120
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
111121
fossil_free(zEncoded);
112
- fossil_free(zCredentials);
113122
}
114123
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
115124
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
116125
if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
117126
if( g.fHttpTrace ){
@@ -119,10 +128,71 @@
119128
}else{
120129
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
121130
}
122131
blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
123132
}
133
+
134
+/*
135
+** Use Fossil credentials for HTTP Basic Authorization prompt
136
+*/
137
+static int use_fossil_creds_for_httpauth_prompt(void){
138
+ Blob x;
139
+ char c;
140
+ prompt_user("Use Fossil username and password (y/N)? ", &x);
141
+ c = blob_str(&x)[0];
142
+ blob_reset(&x);
143
+ return ( c=='y' || c=='Y' );
144
+}
145
+
146
+/*
147
+** Prompt to save HTTP Basic Authorization information
148
+*/
149
+static int save_httpauth_prompt(void){
150
+ Blob x;
151
+ char c;
152
+ if( (g.urlFlags & URL_REMEMBER)==0 ) return;
153
+ prompt_user("Remember Basic Authorization credentials (Y/n)? ", &x);
154
+ c = blob_str(&x)[0];
155
+ blob_reset(&x);
156
+ return ( c!='n' && c!='N' );
157
+}
158
+
159
+/*
160
+** Get the HTTP Basic Authorization credentials from the user
161
+** when 401 is received.
162
+*/
163
+char *prompt_for_httpauth_creds(void){
164
+ Blob x;
165
+ char *zUser;
166
+ char *zPw;
167
+ char *zPrompt;
168
+ char *zHttpAuth = 0;
169
+ if( !isatty(fileno(stdin)) ) return 0;
170
+ zPrompt = mprintf("\n%s authorization required by\n%s\n",
171
+ g.urlIsHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.urlCanonical);
172
+ fossil_print(zPrompt);
173
+ free(zPrompt);
174
+ if ( g.urlUser && g.urlPasswd && use_fossil_creds_for_httpauth_prompt() ){
175
+ zHttpAuth = mprintf("%s:%s", g.urlUser, g.urlPasswd);
176
+ }else{
177
+ prompt_user("Basic Authorization user: ", &x);
178
+ zUser = mprintf("%b", &x);
179
+ zPrompt = mprintf("HTTP password for %b: ", &x);
180
+ blob_reset(&x);
181
+ prompt_for_password(zPrompt, &x, 1);
182
+ zPw = mprintf("%b", &x);
183
+ zHttpAuth = mprintf("%s:%s", zUser, zPw);
184
+ free(zUser);
185
+ free(zPw);
186
+ free(zPrompt);
187
+ blob_reset(&x);
188
+ }
189
+ if( save_httpauth_prompt() ){
190
+ set_httpauth(zHttpAuth);
191
+ }
192
+ return zHttpAuth;
193
+}
124194
125195
/*
126196
** Sign the content in pSend, compress it, and send it to the server
127197
** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
128198
** in pRecv. pRecv is assumed to be uninitialized when
@@ -205,10 +275,20 @@
205275
iLength = -1;
206276
while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
207277
/* printf("[%s]\n", zLine); fflush(stdout); */
208278
if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
209279
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
280
+ if( rc==401 ){
281
+ if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
282
+ if( g.zHttpAuth ){
283
+ if( g.zHttpAuth ) free(g.zHttpAuth);
284
+ }
285
+ g.zHttpAuth = prompt_for_httpauth_creds();
286
+ transport_close(GLOBAL_URL());
287
+ return http_exchange(pSend, pReply, useLogin, maxRedirect);
288
+ }
289
+ }
210290
if( rc!=200 && rc!=302 ){
211291
int ii;
212292
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
213293
while( zLine[ii]==' ' ) ii++;
214294
fossil_warning("server says: %s", &zLine[ii]);
@@ -254,10 +334,13 @@
254334
j -= 4;
255335
zLine[j] = 0;
256336
}
257337
fossil_print("redirect to %s\n", &zLine[i]);
258338
url_parse(&zLine[i], 0);
339
+ fSeenHttpAuth = 0;
340
+ if( g.zHttpAuth ) free(g.zHttpAuth);
341
+ g.zHttpAuth = get_httpauth();
259342
transport_close(GLOBAL_URL());
260343
return http_exchange(pSend, pReply, useLogin, maxRedirect);
261344
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
262345
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
263346
isCompressed = 0;
264347
--- src/http.c
+++ src/http.c
@@ -19,10 +19,26 @@
19 */
20 #include "config.h"
21 #include "http.h"
22 #include <assert.h>
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24 /*
25 ** Construct the "login" card with the client credentials.
26 **
27 ** login LOGIN NONCE SIGNATURE
28 **
@@ -62,16 +78,10 @@
62 /* Password failure while doing a sync from the command-line interface */
63 url_prompt_for_password();
64 zPw = g.urlPasswd;
65 }
66
67 /* If the first character of the password is "#", then that character is
68 ** not really part of the password - it is an indicator that we should
69 ** use Basic Authentication. So skip that character.
70 */
71 if( zPw && zPw[0]=='#' ) zPw++;
72
73 /* The login card wants the SHA1 hash of the password, so convert the
74 ** password to its SHA1 hash it it isn't already a SHA1 hash.
75 */
76 /* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */
77 if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0);
@@ -102,16 +112,15 @@
102 }
103 blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep);
104 if( g.urlProxyAuth ){
105 blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.urlProxyAuth);
106 }
107 if( g.urlPasswd && g.urlUser && g.urlPasswd[0]=='#' ){
108 char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]);
109 char *zEncoded = encode64(zCredentials, -1);
110 blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
111 fossil_free(zEncoded);
112 fossil_free(zCredentials);
113 }
114 blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
115 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
116 if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
117 if( g.fHttpTrace ){
@@ -119,10 +128,71 @@
119 }else{
120 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
121 }
122 blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
123 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
125 /*
126 ** Sign the content in pSend, compress it, and send it to the server
127 ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
128 ** in pRecv. pRecv is assumed to be uninitialized when
@@ -205,10 +275,20 @@
205 iLength = -1;
206 while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
207 /* printf("[%s]\n", zLine); fflush(stdout); */
208 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
209 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
 
 
 
 
 
 
 
 
 
 
210 if( rc!=200 && rc!=302 ){
211 int ii;
212 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
213 while( zLine[ii]==' ' ) ii++;
214 fossil_warning("server says: %s", &zLine[ii]);
@@ -254,10 +334,13 @@
254 j -= 4;
255 zLine[j] = 0;
256 }
257 fossil_print("redirect to %s\n", &zLine[i]);
258 url_parse(&zLine[i], 0);
 
 
 
259 transport_close(GLOBAL_URL());
260 return http_exchange(pSend, pReply, useLogin, maxRedirect);
261 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
262 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
263 isCompressed = 0;
264
--- src/http.c
+++ src/http.c
@@ -19,10 +19,26 @@
19 */
20 #include "config.h"
21 #include "http.h"
22 #include <assert.h>
23
24 #ifdef _WIN32
25 #include <io.h>
26 #ifndef isatty
27 #define isatty(d) _isatty(d)
28 #endif
29 #ifndef fileno
30 #define fileno(s) _fileno(s)
31 #endif
32 #endif
33
34 /* Maximum number of HTTP Authorization attempts */
35 #define MAX_HTTP_AUTH 2
36
37 /* Keep track of HTTP Basic Authorization failures */
38 static int fSeenHttpAuth = 0;
39
40 /*
41 ** Construct the "login" card with the client credentials.
42 **
43 ** login LOGIN NONCE SIGNATURE
44 **
@@ -62,16 +78,10 @@
78 /* Password failure while doing a sync from the command-line interface */
79 url_prompt_for_password();
80 zPw = g.urlPasswd;
81 }
82
 
 
 
 
 
 
83 /* The login card wants the SHA1 hash of the password, so convert the
84 ** password to its SHA1 hash it it isn't already a SHA1 hash.
85 */
86 /* fossil_print("\nzPw=[%s]\n", zPw); // TESTING ONLY */
87 if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0);
@@ -102,16 +112,15 @@
112 }
113 blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep);
114 if( g.urlProxyAuth ){
115 blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.urlProxyAuth);
116 }
117 if( g.zHttpAuth && g.zHttpAuth[0] ){
118 const char *zCredentials = g.zHttpAuth;
119 char *zEncoded = encode64(zCredentials, -1);
120 blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
121 fossil_free(zEncoded);
 
122 }
123 blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
124 blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
125 if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
126 if( g.fHttpTrace ){
@@ -119,10 +128,71 @@
128 }else{
129 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
130 }
131 blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
132 }
133
134 /*
135 ** Use Fossil credentials for HTTP Basic Authorization prompt
136 */
137 static int use_fossil_creds_for_httpauth_prompt(void){
138 Blob x;
139 char c;
140 prompt_user("Use Fossil username and password (y/N)? ", &x);
141 c = blob_str(&x)[0];
142 blob_reset(&x);
143 return ( c=='y' || c=='Y' );
144 }
145
146 /*
147 ** Prompt to save HTTP Basic Authorization information
148 */
149 static int save_httpauth_prompt(void){
150 Blob x;
151 char c;
152 if( (g.urlFlags & URL_REMEMBER)==0 ) return;
153 prompt_user("Remember Basic Authorization credentials (Y/n)? ", &x);
154 c = blob_str(&x)[0];
155 blob_reset(&x);
156 return ( c!='n' && c!='N' );
157 }
158
159 /*
160 ** Get the HTTP Basic Authorization credentials from the user
161 ** when 401 is received.
162 */
163 char *prompt_for_httpauth_creds(void){
164 Blob x;
165 char *zUser;
166 char *zPw;
167 char *zPrompt;
168 char *zHttpAuth = 0;
169 if( !isatty(fileno(stdin)) ) return 0;
170 zPrompt = mprintf("\n%s authorization required by\n%s\n",
171 g.urlIsHttps==1 ? "Encrypted HTTPS" : "Unencrypted HTTP", g.urlCanonical);
172 fossil_print(zPrompt);
173 free(zPrompt);
174 if ( g.urlUser && g.urlPasswd && use_fossil_creds_for_httpauth_prompt() ){
175 zHttpAuth = mprintf("%s:%s", g.urlUser, g.urlPasswd);
176 }else{
177 prompt_user("Basic Authorization user: ", &x);
178 zUser = mprintf("%b", &x);
179 zPrompt = mprintf("HTTP password for %b: ", &x);
180 blob_reset(&x);
181 prompt_for_password(zPrompt, &x, 1);
182 zPw = mprintf("%b", &x);
183 zHttpAuth = mprintf("%s:%s", zUser, zPw);
184 free(zUser);
185 free(zPw);
186 free(zPrompt);
187 blob_reset(&x);
188 }
189 if( save_httpauth_prompt() ){
190 set_httpauth(zHttpAuth);
191 }
192 return zHttpAuth;
193 }
194
195 /*
196 ** Sign the content in pSend, compress it, and send it to the server
197 ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
198 ** in pRecv. pRecv is assumed to be uninitialized when
@@ -205,10 +275,20 @@
275 iLength = -1;
276 while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
277 /* printf("[%s]\n", zLine); fflush(stdout); */
278 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
279 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
280 if( rc==401 ){
281 if( fSeenHttpAuth++ < MAX_HTTP_AUTH ){
282 if( g.zHttpAuth ){
283 if( g.zHttpAuth ) free(g.zHttpAuth);
284 }
285 g.zHttpAuth = prompt_for_httpauth_creds();
286 transport_close(GLOBAL_URL());
287 return http_exchange(pSend, pReply, useLogin, maxRedirect);
288 }
289 }
290 if( rc!=200 && rc!=302 ){
291 int ii;
292 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
293 while( zLine[ii]==' ' ) ii++;
294 fossil_warning("server says: %s", &zLine[ii]);
@@ -254,10 +334,13 @@
334 j -= 4;
335 zLine[j] = 0;
336 }
337 fossil_print("redirect to %s\n", &zLine[i]);
338 url_parse(&zLine[i], 0);
339 fSeenHttpAuth = 0;
340 if( g.zHttpAuth ) free(g.zHttpAuth);
341 g.zHttpAuth = get_httpauth();
342 transport_close(GLOBAL_URL());
343 return http_exchange(pSend, pReply, useLogin, maxRedirect);
344 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
345 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
346 isCompressed = 0;
347
+2
--- src/main.c
+++ src/main.c
@@ -140,10 +140,11 @@
140140
int fSqlTrace; /* True if --sqltrace flag is present */
141141
int fSqlStats; /* True if --sqltrace or --sqlstats are present */
142142
int fSqlPrint; /* True if -sqlprint flag is present */
143143
int fQuiet; /* True if -quiet flag is present */
144144
int fHttpTrace; /* Trace outbound HTTP requests */
145
+ char *zHttpAuth; /* HTTP Authorization user:pass information */
145146
int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
146147
int fSshTrace; /* Trace the SSH setup traffic */
147148
int fSshClient; /* HTTP client flags for SSH client */
148149
char *zSshCmd; /* SSH command string */
149150
int fNoSync; /* Do not do an autosync ever. --nosync */
@@ -651,10 +652,11 @@
651652
g.fSshClient = 0;
652653
g.zSshCmd = 0;
653654
if( g.fSqlTrace ) g.fSqlStats = 1;
654655
g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
655656
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
657
+ g.zHttpAuth = 0;
656658
g.zLogin = find_option("user", "U", 1);
657659
g.zSSLIdentity = find_option("ssl-identity", 0, 1);
658660
g.zErrlog = find_option("errorlog", 0, 1);
659661
if( find_option("utc",0,0) ) g.fTimeFormat = 1;
660662
if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
661663
--- src/main.c
+++ src/main.c
@@ -140,10 +140,11 @@
140 int fSqlTrace; /* True if --sqltrace flag is present */
141 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
142 int fSqlPrint; /* True if -sqlprint flag is present */
143 int fQuiet; /* True if -quiet flag is present */
144 int fHttpTrace; /* Trace outbound HTTP requests */
 
145 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
146 int fSshTrace; /* Trace the SSH setup traffic */
147 int fSshClient; /* HTTP client flags for SSH client */
148 char *zSshCmd; /* SSH command string */
149 int fNoSync; /* Do not do an autosync ever. --nosync */
@@ -651,10 +652,11 @@
651 g.fSshClient = 0;
652 g.zSshCmd = 0;
653 if( g.fSqlTrace ) g.fSqlStats = 1;
654 g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
655 g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
 
656 g.zLogin = find_option("user", "U", 1);
657 g.zSSLIdentity = find_option("ssl-identity", 0, 1);
658 g.zErrlog = find_option("errorlog", 0, 1);
659 if( find_option("utc",0,0) ) g.fTimeFormat = 1;
660 if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
661
--- src/main.c
+++ src/main.c
@@ -140,10 +140,11 @@
140 int fSqlTrace; /* True if --sqltrace flag is present */
141 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
142 int fSqlPrint; /* True if -sqlprint flag is present */
143 int fQuiet; /* True if -quiet flag is present */
144 int fHttpTrace; /* Trace outbound HTTP requests */
145 char *zHttpAuth; /* HTTP Authorization user:pass information */
146 int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
147 int fSshTrace; /* Trace the SSH setup traffic */
148 int fSshClient; /* HTTP client flags for SSH client */
149 char *zSshCmd; /* SSH command string */
150 int fNoSync; /* Do not do an autosync ever. --nosync */
@@ -651,10 +652,11 @@
652 g.fSshClient = 0;
653 g.zSshCmd = 0;
654 if( g.fSqlTrace ) g.fSqlStats = 1;
655 g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
656 g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
657 g.zHttpAuth = 0;
658 g.zLogin = find_option("user", "U", 1);
659 g.zSSLIdentity = find_option("ssl-identity", 0, 1);
660 g.zErrlog = find_option("errorlog", 0, 1);
661 if( find_option("utc",0,0) ) g.fTimeFormat = 1;
662 if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
663
+5
--- src/sync.c
+++ src/sync.c
@@ -54,10 +54,11 @@
5454
if( g.urlUser!=0 && g.urlPasswd==0 ){
5555
g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
5656
g.urlFlags |= URL_PROMPT_PW;
5757
url_prompt_for_password();
5858
}
59
+ g.zHttpAuth = get_httpauth();
5960
url_remember();
6061
#if 0 /* Disabled for now */
6162
if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
6263
/* When doing an automatic pull, also automatically pull shuns from
6364
** the server if pull_shuns is enabled.
@@ -83,17 +84,19 @@
8384
** of a server to sync against. If no argument is given, use the
8485
** most recently synced URL. Remember the current URL for next time.
8586
*/
8687
static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
8788
const char *zUrl = 0;
89
+ const char *zHttpAuth = 0;
8890
unsigned configSync = 0;
8991
unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
9092
int urlOptional = 0;
9193
if( find_option("autourl",0,0)!=0 ){
9294
urlOptional = 1;
9395
urlFlags = 0;
9496
}
97
+ zHttpAuth = find_option("httpauth","B",1);
9598
if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
9699
if( find_option("private",0,0)!=0 ){
97100
*pSyncFlags |= SYNC_PRIVATE;
98101
}
99102
if( find_option("verbose","v",0)!=0 ){
@@ -116,10 +119,11 @@
116119
}
117120
if( urlFlags & URL_REMEMBER ){
118121
clone_ssh_db_set_options();
119122
}
120123
url_parse(zUrl, urlFlags);
124
+ remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
121125
url_remember();
122126
if( g.urlProtocol==0 ){
123127
if( urlOptional ) fossil_exit(0);
124128
usage("URL");
125129
}
@@ -263,10 +267,11 @@
263267
usage("remote-url ?URL|off?");
264268
}
265269
if( g.argc==3 ){
266270
db_unset("last-sync-url", 0);
267271
db_unset("last-sync-pw", 0);
272
+ db_unset("http-auth", 0);
268273
if( is_false(g.argv[2]) ) return;
269274
url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
270275
}
271276
url_remember();
272277
zUrl = db_get("last-sync-url", 0);
273278
--- src/sync.c
+++ src/sync.c
@@ -54,10 +54,11 @@
54 if( g.urlUser!=0 && g.urlPasswd==0 ){
55 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
56 g.urlFlags |= URL_PROMPT_PW;
57 url_prompt_for_password();
58 }
 
59 url_remember();
60 #if 0 /* Disabled for now */
61 if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
62 /* When doing an automatic pull, also automatically pull shuns from
63 ** the server if pull_shuns is enabled.
@@ -83,17 +84,19 @@
83 ** of a server to sync against. If no argument is given, use the
84 ** most recently synced URL. Remember the current URL for next time.
85 */
86 static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
87 const char *zUrl = 0;
 
88 unsigned configSync = 0;
89 unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
90 int urlOptional = 0;
91 if( find_option("autourl",0,0)!=0 ){
92 urlOptional = 1;
93 urlFlags = 0;
94 }
 
95 if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
96 if( find_option("private",0,0)!=0 ){
97 *pSyncFlags |= SYNC_PRIVATE;
98 }
99 if( find_option("verbose","v",0)!=0 ){
@@ -116,10 +119,11 @@
116 }
117 if( urlFlags & URL_REMEMBER ){
118 clone_ssh_db_set_options();
119 }
120 url_parse(zUrl, urlFlags);
 
121 url_remember();
122 if( g.urlProtocol==0 ){
123 if( urlOptional ) fossil_exit(0);
124 usage("URL");
125 }
@@ -263,10 +267,11 @@
263 usage("remote-url ?URL|off?");
264 }
265 if( g.argc==3 ){
266 db_unset("last-sync-url", 0);
267 db_unset("last-sync-pw", 0);
 
268 if( is_false(g.argv[2]) ) return;
269 url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
270 }
271 url_remember();
272 zUrl = db_get("last-sync-url", 0);
273
--- src/sync.c
+++ src/sync.c
@@ -54,10 +54,11 @@
54 if( g.urlUser!=0 && g.urlPasswd==0 ){
55 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
56 g.urlFlags |= URL_PROMPT_PW;
57 url_prompt_for_password();
58 }
59 g.zHttpAuth = get_httpauth();
60 url_remember();
61 #if 0 /* Disabled for now */
62 if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
63 /* When doing an automatic pull, also automatically pull shuns from
64 ** the server if pull_shuns is enabled.
@@ -83,17 +84,19 @@
84 ** of a server to sync against. If no argument is given, use the
85 ** most recently synced URL. Remember the current URL for next time.
86 */
87 static void process_sync_args(unsigned *pConfigFlags, unsigned *pSyncFlags){
88 const char *zUrl = 0;
89 const char *zHttpAuth = 0;
90 unsigned configSync = 0;
91 unsigned urlFlags = URL_REMEMBER | URL_PROMPT_PW;
92 int urlOptional = 0;
93 if( find_option("autourl",0,0)!=0 ){
94 urlOptional = 1;
95 urlFlags = 0;
96 }
97 zHttpAuth = find_option("httpauth","B",1);
98 if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
99 if( find_option("private",0,0)!=0 ){
100 *pSyncFlags |= SYNC_PRIVATE;
101 }
102 if( find_option("verbose","v",0)!=0 ){
@@ -116,10 +119,11 @@
119 }
120 if( urlFlags & URL_REMEMBER ){
121 clone_ssh_db_set_options();
122 }
123 url_parse(zUrl, urlFlags);
124 remember_or_get_http_auth(zHttpAuth, urlFlags & URL_REMEMBER, zUrl);
125 url_remember();
126 if( g.urlProtocol==0 ){
127 if( urlOptional ) fossil_exit(0);
128 usage("URL");
129 }
@@ -263,10 +267,11 @@
267 usage("remote-url ?URL|off?");
268 }
269 if( g.argc==3 ){
270 db_unset("last-sync-url", 0);
271 db_unset("last-sync-pw", 0);
272 db_unset("http-auth", 0);
273 if( is_false(g.argv[2]) ) return;
274 url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
275 }
276 url_remember();
277 zUrl = db_get("last-sync-url", 0);
278
+3 -3
--- src/timeline.c
+++ src/timeline.c
@@ -592,11 +592,11 @@
592592
if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
593593
GraphRow *pRow;
594594
int i;
595595
char cSep;
596596
597
- @ <script type='text/javascript'>(function(){
597
+ @ <script>
598598
@ var railPitch=%d(pGraph->iRailPitch);
599599
600600
/* the rowinfo[] array contains all the information needed to generate
601601
** the graph. Each entry contains information for a single row:
602602
**
@@ -868,14 +868,14 @@
868868
@ var h = absoluteY(lastId);
869869
@ if( h!=lastY ){
870870
@ renderGraph();
871871
@ lastY = h;
872872
@ }
873
- @ setTimeout(arguments.callee, 1000);
873
+ @ setTimeout("checkHeight();", 1000);
874874
@ }
875875
@ checkHeight();
876
- @ })()</script>
876
+ @ </script>
877877
}
878878
}
879879
880880
/*
881881
** Create a temporary table suitable for storing timeline data.
882882
--- src/timeline.c
+++ src/timeline.c
@@ -592,11 +592,11 @@
592 if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
593 GraphRow *pRow;
594 int i;
595 char cSep;
596
597 @ <script type='text/javascript'>(function(){
598 @ var railPitch=%d(pGraph->iRailPitch);
599
600 /* the rowinfo[] array contains all the information needed to generate
601 ** the graph. Each entry contains information for a single row:
602 **
@@ -868,14 +868,14 @@
868 @ var h = absoluteY(lastId);
869 @ if( h!=lastY ){
870 @ renderGraph();
871 @ lastY = h;
872 @ }
873 @ setTimeout(arguments.callee, 1000);
874 @ }
875 @ checkHeight();
876 @ })()</script>
877 }
878 }
879
880 /*
881 ** Create a temporary table suitable for storing timeline data.
882
--- src/timeline.c
+++ src/timeline.c
@@ -592,11 +592,11 @@
592 if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
593 GraphRow *pRow;
594 int i;
595 char cSep;
596
597 @ <script>
598 @ var railPitch=%d(pGraph->iRailPitch);
599
600 /* the rowinfo[] array contains all the information needed to generate
601 ** the graph. Each entry contains information for a single row:
602 **
@@ -868,14 +868,14 @@
868 @ var h = absoluteY(lastId);
869 @ if( h!=lastY ){
870 @ renderGraph();
871 @ lastY = h;
872 @ }
873 @ setTimeout("checkHeight();", 1000);
874 @ }
875 @ checkHeight();
876 @ </script>
877 }
878 }
879
880 /*
881 ** Create a temporary table suitable for storing timeline data.
882
+2 -1
--- src/xfer.c
+++ src/xfer.c
@@ -578,11 +578,12 @@
578578
defossilize(zLogin);
579579
580580
if( fossil_strcmp(zLogin, "nobody")==0 || fossil_strcmp(zLogin,"anonymous")==0 ){
581581
return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
582582
}
583
- if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0 ){
583
+ if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
584
+ && db_get_boolean("remote_user_ok",0) ){
584585
return 0; /* Accept Basic Authorization */
585586
}
586587
db_prepare(&q,
587588
"SELECT pw, cap, uid FROM user"
588589
" WHERE login=%Q"
589590
--- src/xfer.c
+++ src/xfer.c
@@ -578,11 +578,12 @@
578 defossilize(zLogin);
579
580 if( fossil_strcmp(zLogin, "nobody")==0 || fossil_strcmp(zLogin,"anonymous")==0 ){
581 return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
582 }
583 if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0 ){
 
584 return 0; /* Accept Basic Authorization */
585 }
586 db_prepare(&q,
587 "SELECT pw, cap, uid FROM user"
588 " WHERE login=%Q"
589
--- src/xfer.c
+++ src/xfer.c
@@ -578,11 +578,12 @@
578 defossilize(zLogin);
579
580 if( fossil_strcmp(zLogin, "nobody")==0 || fossil_strcmp(zLogin,"anonymous")==0 ){
581 return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
582 }
583 if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
584 && db_get_boolean("remote_user_ok",0) ){
585 return 0; /* Accept Basic Authorization */
586 }
587 db_prepare(&q,
588 "SELECT pw, cap, uid FROM user"
589 " WHERE login=%Q"
590
--- test/utf16be.txt
+++ test/utf16be.txt
--- test/utf16be.txt
+++ test/utf16be.txt
0
--- test/utf16be.txt
+++ test/utf16be.txt
0
--- test/utf16le.txt
+++ test/utf16le.txt
--- test/utf16le.txt
+++ test/utf16le.txt
0
--- test/utf16le.txt
+++ test/utf16le.txt
0

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button