Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | merge trunk |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | win32-longpath |
| Files: | files | file ages | folders |
| SHA1: |
02a0e8890e34d6f88ed3aad8419e2d84 |
| User & Date: | jan.nijtmans 2013-12-30 20:57:28.268 |
Context
|
2014-01-23
| ||
| 21:18 | merge branch-1.28, a few other cherry-picks from trunk check-in: 303e7af7c3 user: jan.nijtmans tags: win32-longpath | |
|
2013-12-30
| ||
| 20:57 | merge trunk check-in: 02a0e8890e user: jan.nijtmans tags: win32-longpath | |
|
2013-12-29
| ||
| 00:53 | Fix floating-point divide by zero issue in TH1 reported on the mailing list and add tests. check-in: 479b3de1d2 user: mistachkin tags: trunk | |
|
2013-12-20
| ||
| 12:12 | The same, but then with modified SQLite (minimal patch to function winFullPathname this time). This way, applications wanting to use the "win32-longpath" VFS don't have to do tricky extended-path modifications any more. check-in: 8e8e3a11bc user: jan.nijtmans tags: win32-longpath | |
Changes
Changes to src/attach.c.
| ︙ | ︙ | |||
212 213 214 215 216 217 218 |
rid, attachRid
);
}else{
rid = content_put(pAttach);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
| | | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
rid, attachRid
);
}else{
rid = content_put(pAttach);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
manifest_crosslink(rid, pAttach, MC_NONE);
}
/*
** WEBPAGE: attachadd
**
** tkt=TICKETUUID
|
| ︙ | ︙ | |||
429 430 431 432 433 434 435 |
blob_appendf(&manifest, "A %F %F\n", zFile, zTarget);
zDate = date_in_standard_format("now");
blob_appendf(&manifest, "D %s\n", zDate);
blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
md5sum_blob(&manifest, &cksum);
blob_appendf(&manifest, "Z %b\n", &cksum);
rid = content_put(&manifest);
| | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
blob_appendf(&manifest, "A %F %F\n", zFile, zTarget);
zDate = date_in_standard_format("now");
blob_appendf(&manifest, "D %s\n", zDate);
blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
md5sum_blob(&manifest, &cksum);
blob_appendf(&manifest, "Z %b\n", &cksum);
rid = content_put(&manifest);
manifest_crosslink(rid, &manifest, MC_NONE);
db_end_transaction(0);
@ <p>The attachment below has been deleted.</p>
}
if( P("del")
&& ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
){
|
| ︙ | ︙ |
Changes to src/branch.c.
| ︙ | ︙ | |||
151 152 153 154 155 156 157 |
}
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
if( brid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
| | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
}
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
if( brid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&branch) );
content_deltify(rootid, brid, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid);
fossil_print("New branch: %s\n", zUuid);
if( g.argc==3 ){
fossil_print(
|
| ︙ | ︙ |
Changes to src/cgi.c.
| ︙ | ︙ | |||
268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
if(zTok) return 1;
}
}
return 0;
}
#endif
/*
** Do a normal HTTP reply
*/
void cgi_reply(void){
int total_size;
if( iReplyStatus<=0 ){
| > > > > > > > > > > | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
if(zTok) return 1;
}
}
return 0;
}
#endif
/*
** Return true if the response should be sent with Content-Encoding: gzip.
*/
static int is_gzippable(void){
if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
return strncmp(zContentType, "text/", 5)==0
|| strglob("application/*xml", zContentType)
|| strglob("application/*javascript", zContentType);
}
/*
** Do a normal HTTP reply
*/
void cgi_reply(void){
int total_size;
if( iReplyStatus<=0 ){
|
| ︙ | ︙ | |||
346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
cgi_combine_header_and_body();
blob_compress(&cgiContent[0], &cgiContent[0]);
}
if( iReplyStatus != 304 ) {
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
}else{
total_size = 0;
}
fprintf(g.httpOut, "\r\n");
if( total_size>0 && iReplyStatus != 304 ){
| > > > > > > > > > > > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
cgi_combine_header_and_body();
blob_compress(&cgiContent[0], &cgiContent[0]);
}
if( iReplyStatus != 304 ) {
if( is_gzippable() ){
int i;
gzip_begin(0);
for( i=0; i<2; i++ ){
int size = blob_size(&cgiContent[i]);
if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
blob_reset(&cgiContent[i]);
}
gzip_finish(&cgiContent[0]);
fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
}
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
}else{
total_size = 0;
}
fprintf(g.httpOut, "\r\n");
if( total_size>0 && iReplyStatus != 304 ){
|
| ︙ | ︙ | |||
1300 1301 1302 1303 1304 1305 1306 |
while( fossil_isspace(*zVal) ){ zVal++; }
i = strlen(zVal);
while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
zVal[i] = 0;
for(i=0; zFieldName[i]; i++){
zFieldName[i] = fossil_tolower(zFieldName[i]);
}
| > > | | 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 |
while( fossil_isspace(*zVal) ){ zVal++; }
i = strlen(zVal);
while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
zVal[i] = 0;
for(i=0; zFieldName[i]; i++){
zFieldName[i] = fossil_tolower(zFieldName[i]);
}
if( fossil_strcmp(zFieldName,"accept-encoding:")==0 ){
cgi_setenv("HTTP_ACCEPT_ENCODING", zVal);
}else if( fossil_strcmp(zFieldName,"content-length:")==0 ){
cgi_setenv("CONTENT_LENGTH", zVal);
}else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
cgi_setenv("CONTENT_TYPE", zVal);
}else if( fossil_strcmp(zFieldName,"cookie:")==0 ){
cgi_setenv("HTTP_COOKIE", zVal);
}else if( fossil_strcmp(zFieldName,"https:")==0 ){
cgi_setenv("HTTPS", zVal);
|
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 | ** interactive user or these warnings should be skipped for some other ** reason, the --no-warnings option may be used. A check-in is not ** allowed against a closed leaf. ** ** The --private option creates a private check-in that is never synced. ** Children of private check-ins are automatically private. ** | | > > > > > > | 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 |
** interactive user or these warnings should be skipped for some other
** reason, the --no-warnings option may be used. A check-in is not
** allowed against a closed leaf.
**
** The --private option creates a private check-in that is never synced.
** Children of private check-ins are automatically private.
**
** The --tag option applies the symbolic tag name to the check-in.
**
** The --sha1sum option detects edited files by computing each file's
** SHA1 hash rather than just checking for changes to its size or mtime.
**
** Options:
** --allow-conflict allow unresolved merge conflicts
** --allow-empty allow a commit with no changes
** --allow-fork allow the commit to fork
** --allow-older allow a commit older than its ancestor
** --baseline use a baseline manifest in the commit process
** --bgcolor COLOR apply COLOR to this one check-in only
** --branch NEW-BRANCH-NAME check in to this new branch
** --branchcolor COLOR apply given COLOR to the branch
** --close close the branch being committed
** --delta use a delta manifest in the commit process
** -m|--comment COMMENT-TEXT use COMMENT-TEXT as commit comment
** -M|--message-file FILE read the commit comment from given file
** --mimetype MIMETYPE mimetype of check-in comment
** -n|--dry-run If given, display instead of run actions
** --no-warnings omit all warnings about file contents
** --nosign do not attempt to sign this commit with gpg
** --private do not sync changes and their descendants
** --sha1sum verify file status using SHA1 hashing rather
** than relying on file mtimes
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
**
** See also: branch, changes, checkout, extra, sync
*/
void commit_cmd(void){
int hasChanges; /* True if unsaved changes exist */
int vid; /* blob-id of parent version */
int nrid; /* blob-id of a modified file */
int nvid; /* Blob-id of the new check-in */
Blob comment; /* Check-in comment */
const char *zComment; /* Check-in comment */
Stmt q; /* Various queries */
char *zUuid; /* UUID of the new check-in */
int useSha1sum = 0; /* True to verify file status using SHA1 hashing */
int noSign = 0; /* True to omit signing the manifest using GPG */
int isAMerge = 0; /* True if checking in a merge */
int noWarningFlag = 0; /* True if skipping all warnings */
int forceFlag = 0; /* Undocumented: Disables all checks */
int forceDelta = 0; /* Force a delta-manifest */
int forceBaseline = 0; /* Force a baseline-manifest */
int allowConflict = 0; /* Allow unresolve merge conflicts */
|
| ︙ | ︙ | |||
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 |
int nConflict = 0; /* Number of unresolved merge conflicts */
int abortCommit = 0;
Blob ans;
char cReply;
memset(&sCiInfo, 0, sizeof(sCiInfo));
url_proxy_options();
noSign = find_option("nosign",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
if( forceDelta && forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
dryRunFlag = find_option("dry-run","n",0)!=0;
| > | 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 |
int nConflict = 0; /* Number of unresolved merge conflicts */
int abortCommit = 0;
Blob ans;
char cReply;
memset(&sCiInfo, 0, sizeof(sCiInfo));
url_proxy_options();
useSha1sum = find_option("sha1sum", 0, 0)!=0;
noSign = find_option("nosign",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
if( forceDelta && forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
dryRunFlag = find_option("dry-run","n",0)!=0;
|
| ︙ | ︙ | |||
1584 1585 1586 1587 1588 1589 1590 |
/*
** Check that the user exists.
*/
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
fossil_fatal("no such user: %s", g.zLogin);
}
| | | 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 |
/*
** Check that the user exists.
*/
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
fossil_fatal("no such user: %s", g.zLogin);
}
hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0);
db_begin_transaction();
db_record_repository_filename(0);
if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
fossil_fatal("nothing has changed; use --allow-empty to override");
}
/* If none of the files that were named on the command line have
|
| ︙ | ︙ | |||
1814 1815 1816 1817 1818 1819 1820 |
}
nvid = content_put(&manifest);
if( nvid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
| | > > > | 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 |
}
nvid = content_put(&manifest);
if( nvid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
if( manifest_crosslink(nvid, &manifest,
dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&manifest) );
content_deltify(vid, nvid, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
" WHERE id=-4");
while( db_step(&q)==SQLITE_ROW ){
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 | ** Check to see if there is an existing checkout that has been ** modified. Return values: ** ** 0: There is an existing checkout but it is unmodified ** 1: There is a modified checkout - there are unsaved changes ** 2: There is no existing checkout */ | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
** Check to see if there is an existing checkout that has been
** modified. Return values:
**
** 0: There is an existing checkout but it is unmodified
** 1: There is a modified checkout - there are unsaved changes
** 2: There is no existing checkout
*/
int unsaved_changes(unsigned int cksigFlags){
int vid;
db_must_be_within_tree();
vid = db_lget_int("checkout",0);
if( vid==0 ) return 2;
vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE);
return db_exists("SELECT 1 FROM vfile WHERE chnged"
" OR coalesce(origname!=pathname,0)");
}
/*
** Undo the current check-out. Unlink all files from the disk.
** Clear the VFILE table.
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
forceFlag = find_option("force","f",0)!=0;
keepFlag = find_option("keep",0,0)!=0;
latestFlag = find_option("latest",0,0)!=0;
promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0;
if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
usage("VERSION|--latest ?--force? ?--keep?");
}
| | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
forceFlag = find_option("force","f",0)!=0;
keepFlag = find_option("keep",0,0)!=0;
latestFlag = find_option("latest",0,0)!=0;
promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0;
if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
usage("VERSION|--latest ?--force? ?--keep?");
}
if( !forceFlag && unsaved_changes(0)==1 ){
fossil_fatal("there are unsaved changes in the current checkout");
}
if( forceFlag ){
db_multi_exec("DELETE FROM vfile");
prior = 0;
}else{
prior = db_lget_int("checkout",0);
|
| ︙ | ︙ | |||
286 287 288 289 290 291 292 |
** --force|-f necessary to close a check out with uncommitted changes
**
** See also: open
*/
void close_cmd(void){
int forceFlag = find_option("force","f",0)!=0;
db_must_be_within_tree();
| | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
** --force|-f necessary to close a check out with uncommitted changes
**
** See also: open
*/
void close_cmd(void){
int forceFlag = find_option("force","f",0)!=0;
db_must_be_within_tree();
if( !forceFlag && unsaved_changes(0)==1 ){
fossil_fatal("there are unsaved changes in the current checkout");
}
if( !forceFlag
&& db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'",
db_name("localdb"))
&& db_exists("SELECT 1 FROM %s.stash", db_name("localdb"))
){
|
| ︙ | ︙ |
Changes to src/configure.c.
| ︙ | ︙ | |||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "adunit", CONFIGSET_SKIN },
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
{ "adunit-omit-if-user", CONFIGSET_SKIN },
{ "th1-setup", CONFIGSET_TH1 },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", CONFIGSET_TH1 },
{ "tcl-setup", CONFIGSET_TH1 },
#endif
{ "project-name", CONFIGSET_PROJ },
| > | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "adunit", CONFIGSET_SKIN },
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
{ "adunit-omit-if-user", CONFIGSET_SKIN },
{ "th1-setup", CONFIGSET_TH1 },
{ "th1-uri-regexp", CONFIGSET_TH1 },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", CONFIGSET_TH1 },
{ "tcl-setup", CONFIGSET_TH1 },
#endif
{ "project-name", CONFIGSET_PROJ },
|
| ︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
{ "@concealed", CONFIGSET_ADDR },
{ "@shun", CONFIGSET_SHUN },
{ "xfer-common-script", CONFIGSET_XFER },
{ "xfer-push-script", CONFIGSET_XFER },
};
static int iConfig = 0;
/*
** Return name of first configuration property matching the given mask.
*/
| > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
{ "@concealed", CONFIGSET_ADDR },
{ "@shun", CONFIGSET_SHUN },
{ "xfer-common-script", CONFIGSET_XFER },
{ "xfer-push-script", CONFIGSET_XFER },
{ "xfer-commit-script", CONFIGSET_XFER },
{ "xfer-ticket-script", CONFIGSET_XFER },
};
static int iConfig = 0;
/*
** Return name of first configuration property matching the given mask.
*/
|
| ︙ | ︙ |
Changes to src/content.c.
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
while( rid ){
int nChildUsed = 0;
int i;
/* Parse the object rid itself */
if( linkFlag ){
content_get(rid, &content);
| | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
while( rid ){
int nChildUsed = 0;
int i;
/* Parse the object rid itself */
if( linkFlag ){
content_get(rid, &content);
manifest_crosslink(rid, &content, MC_NONE);
assert( blob_is_reset(&content) );
}
/* Parse all delta-manifests that depend on baseline-manifest rid */
db_prepare(&q, "SELECT rid FROM orphan WHERE baseline=%d", rid);
while( db_step(&q)==SQLITE_ROW ){
int child = db_column_int(&q, 0);
if( nChildUsed>=nChildAlloc ){
nChildAlloc = nChildAlloc*2 + 10;
aChild = fossil_realloc(aChild, nChildAlloc*sizeof(aChild));
}
aChild[nChildUsed++] = child;
}
db_finalize(&q);
for(i=0; i<nChildUsed; i++){
content_get(aChild[i], &content);
manifest_crosslink(aChild[i], &content, MC_NONE);
assert( blob_is_reset(&content) );
}
if( nChildUsed ){
db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid);
}
/* Recursively dephantomize all artifacts that are derived by
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
1416 1417 1418 1419 1420 1421 1422 |
blob_appendf(&manifest, "T *branch * trunk\n");
blob_appendf(&manifest, "T *sym-trunk *\n");
blob_appendf(&manifest, "U %F\n", g.zLogin);
md5sum_blob(&manifest, &hash);
blob_appendf(&manifest, "Z %b\n", &hash);
blob_reset(&hash);
rid = content_put(&manifest);
| | | 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 |
blob_appendf(&manifest, "T *branch * trunk\n");
blob_appendf(&manifest, "T *sym-trunk *\n");
blob_appendf(&manifest, "U %F\n", g.zLogin);
md5sum_blob(&manifest, &hash);
blob_appendf(&manifest, "Z %b\n", &hash);
blob_reset(&hash);
rid = content_put(&manifest);
manifest_crosslink(rid, &manifest, MC_NONE);
}
}
/*
** COMMAND: new*
** COMMAND: init
**
|
| ︙ | ︙ | |||
2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 |
{ "ssl-ca-location",0, 40, 0, "" },
{ "ssl-identity", 0, 40, 0, "" },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", 0, 0, 0, "off" },
{ "tcl-setup", 0, 40, 0, "" },
#endif
{ "th1-setup", 0, 40, 0, "" },
{ "web-browser", 0, 32, 0, "" },
{ "white-foreground", 0, 0, 0, "off" },
{ 0,0,0,0,0 }
};
/*
** COMMAND: settings
| > | 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 |
{ "ssl-ca-location",0, 40, 0, "" },
{ "ssl-identity", 0, 40, 0, "" },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", 0, 0, 0, "off" },
{ "tcl-setup", 0, 40, 0, "" },
#endif
{ "th1-setup", 0, 40, 0, "" },
{ "th1-uri-regexp",0, 40, 0, "" },
{ "web-browser", 0, 32, 0, "" },
{ "white-foreground", 0, 0, 0, "off" },
{ 0,0,0,0,0 }
};
/*
** COMMAND: settings
|
| ︙ | ︙ | |||
2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 | ** tcl-setup This is the setup script to be evaluated after creating ** and initializing the Tcl interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-setup This is the setup script to be evaluated after creating ** and initializing the TH1 interpreter. By default, this ** is empty and no extra setup is performed. ** ** web-browser A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. ** ** Options: | > > > > | 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 | ** tcl-setup This is the setup script to be evaluated after creating ** and initializing the Tcl interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-setup This is the setup script to be evaluated after creating ** and initializing the TH1 interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-uri-regexp Specify which URI's are allowed in HTTP requests from ** TH1 scripts. If empty, no HTTP requests are allowed ** whatsoever. The default is an empty string. ** ** web-browser A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. ** ** Options: |
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
2177 2178 2179 2180 2181 2182 2183 |
url_add_parameter(&url, "filename", zFilename);
if( iLimit!=20 ){
url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
}
url_add_parameter(&url, "log", showLog ? "1" : "0");
if( showLog ){
style_submenu_element("Hide Log", "Hide Log",
| | | | | | | 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 |
url_add_parameter(&url, "filename", zFilename);
if( iLimit!=20 ){
url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
}
url_add_parameter(&url, "log", showLog ? "1" : "0");
if( showLog ){
style_submenu_element("Hide Log", "Hide Log",
"%s", url_render(&url, "log", "0", 0, 0));
}else{
style_submenu_element("Show Log", "Show Log",
"%s", url_render(&url, "log", "1", 0, 0));
}
if( ann.bLimit ){
char *z1, *z2;
style_submenu_element("All Ancestors", "All Ancestors",
"%s", url_render(&url, "limit", "-1", 0, 0));
z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
z2 = sqlite3_mprintf("%d", iLimit+20);
style_submenu_element(z1, z1, "%s", url_render(&url, "limit", z2, 0, 0));
}
if( iLimit>20 ){
style_submenu_element("20 Ancestors", "20 Ancestors",
"%s", url_render(&url, "limit", "20", 0, 0));
}
if( db_get_boolean("white-foreground", 0) ){
clr1 = 0xa04040;
clr2 = 0x4059a0;
}else{
clr1 = 0xffb5b5; /* Recent changes: red (hot) */
clr2 = 0xb5e0ff; /* Older changes: blue (cold) */
|
| ︙ | ︙ |
Changes to src/event.c.
| ︙ | ︙ | |||
349 350 351 352 353 354 355 |
}
blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
md5sum_blob(&event, &cksum);
blob_appendf(&event, "Z %b\n", &cksum);
blob_reset(&cksum);
nrid = content_put(&event);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
| | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
}
blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
md5sum_blob(&event, &cksum);
blob_appendf(&event, "Z %b\n", &cksum);
blob_reset(&cksum);
nrid = content_put(&event);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
manifest_crosslink(nrid, &event, MC_NONE);
assert( blob_is_reset(&event) );
content_deltify(rid, nrid, 0);
db_end_transaction(0);
cgi_redirectf("event?name=%T", zEventId);
}
if( P("cancel")!=0 ){
cgi_redirectf("event?name=%T", zEventId);
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
292 293 294 295 296 297 298 |
style_header("File History");
login_anonymous_available();
url_initialize(&url, "finfo");
if( brBg ) url_add_parameter(&url, "brbg", 0);
if( uBg ) url_add_parameter(&url, "ubg", 0);
baseCheckin = name_to_rid_www("ci");
if( baseCheckin ) firstChngOnly = 1;
| | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
style_header("File History");
login_anonymous_available();
url_initialize(&url, "finfo");
if( brBg ) url_add_parameter(&url, "brbg", 0);
if( uBg ) url_add_parameter(&url, "ubg", 0);
baseCheckin = name_to_rid_www("ci");
if( baseCheckin ) firstChngOnly = 1;
if( !firstChngOnly ) url_add_parameter(&url, "fco", "0");
zPrevDate[0] = 0;
zFilename = PD("name","");
url_add_parameter(&url, "name", zFilename);
blob_zero(&sql);
blob_appendf(&sql,
"SELECT"
|
| ︙ | ︙ | |||
360 361 362 363 364 365 366 |
if( baseCheckin==0 ){
if( firstChngOnly ){
style_submenu_element("Full", "Show all changes","%s",
url_render(&url, "fco", "0", 0, 0));
}else{
style_submenu_element("Simplified",
"Show only first use of a change","%s",
| | | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
if( baseCheckin==0 ){
if( firstChngOnly ){
style_submenu_element("Full", "Show all changes","%s",
url_render(&url, "fco", "0", 0, 0));
}else{
style_submenu_element("Simplified",
"Show only first use of a change","%s",
url_render(&url, "fco", 0, 0, 0));
}
}
db_prepare(&q, blob_str(&sql));
if( P("showsql")!=0 ){
@ <p>SQL: %h(blob_str(&sql))</p>
}
blob_reset(&sql);
|
| ︙ | ︙ |
Changes to src/gzip.c.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 | char aHdr[10]; assert( gzip.eState==0 ); blob_zero(&gzip.out); aHdr[0] = 0x1f; aHdr[1] = 0x8b; aHdr[2] = 8; aHdr[3] = 0; | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
char aHdr[10];
assert( gzip.eState==0 );
blob_zero(&gzip.out);
aHdr[0] = 0x1f;
aHdr[1] = 0x8b;
aHdr[2] = 8;
aHdr[3] = 0;
if( now==-1 ){
now = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0");
}
put32(&aHdr[4], now&0xffffffff);
aHdr[8] = 2;
aHdr[9] = 255;
blob_append(&gzip.out, aHdr, 10);
gzip.iCRC = 0;
|
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
** Compress a file using gzip.
*/
void test_gzip_cmd(void){
Blob b;
char *zOut;
if( g.argc!=3 ) usage("FILENAME");
sqlite3_open(":memory:", &g.db);
| | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
** Compress a file using gzip.
*/
void test_gzip_cmd(void){
Blob b;
char *zOut;
if( g.argc!=3 ) usage("FILENAME");
sqlite3_open(":memory:", &g.db);
gzip_begin(-1);
blob_read_from_file(&b, g.argv[2]);
zOut = mprintf("%s.gz", g.argv[2]);
gzip_step(blob_buffer(&b), blob_size(&b));
blob_reset(&b);
gzip_finish(&b);
blob_write_to_file(&b, zOut);
blob_reset(&b);
fossil_free(zOut);
}
|
Changes to src/http.c.
| ︙ | ︙ | |||
108 109 110 111 112 113 114 |
char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]);
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
fossil_free(zCredentials);
}
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
| | < | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]);
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
fossil_free(zCredentials);
}
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
if( g.fHttpTrace ){
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
}else{
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
}
blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 | int rc = 0; /* Result code */ int iHttpVersion; /* Which version of HTTP protocol server uses */ char *zLine; /* A single line of the reply header */ int i; /* Loop counter */ int isError = 0; /* True if the reply is an error message */ int isCompressed = 1; /* True if the reply is compressed */ | | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
int rc = 0; /* Result code */
int iHttpVersion; /* Which version of HTTP protocol server uses */
char *zLine; /* A single line of the reply header */
int i; /* Loop counter */
int isError = 0; /* True if the reply is an error message */
int isCompressed = 1; /* True if the reply is compressed */
if( transport_open(GLOBAL_URL()) ){
fossil_warning(transport_errmsg(GLOBAL_URL()));
return 1;
}
/* Construct the login card and prepare the complete payload */
blob_zero(&login);
if( useLogin ) http_build_login_card(pSend, &login);
if( g.fHttpTrace ){
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
transport_log(out);
free(zOutFile);
}
/*
** Send the request to the server.
*/
| | | | | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
transport_log(out);
free(zOutFile);
}
/*
** Send the request to the server.
*/
transport_send(GLOBAL_URL(), &hdr);
transport_send(GLOBAL_URL(), &payload);
blob_reset(&hdr);
blob_reset(&payload);
transport_flip(GLOBAL_URL());
/*
** Read and interpret the server reply
*/
closeConnection = 1;
iLength = -1;
while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
/* printf("[%s]\n", zLine); fflush(stdout); */
if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
if( rc!=200 && rc!=302 ){
int ii;
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
while( zLine[ii]==' ' ) ii++;
|
| ︙ | ︙ | |||
253 254 255 256 257 258 259 |
j = strlen(zLine) - 1;
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
j -= 4;
zLine[j] = 0;
}
fossil_print("redirect to %s\n", &zLine[i]);
url_parse(&zLine[i], 0);
| | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
j = strlen(zLine) - 1;
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
j -= 4;
zLine[j] = 0;
}
fossil_print("redirect to %s\n", &zLine[i]);
url_parse(&zLine[i], 0);
transport_close(GLOBAL_URL());
return http_exchange(pSend, pReply, useLogin, maxRedirect);
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
isCompressed = 0;
}else if( fossil_strnicmp(&zLine[14],
"application/x-fossil-uncompressed", -1)==0 ){
isCompressed = 0;
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 | } /* ** Extract the reply payload that follows the header */ blob_zero(pReply); blob_resize(pReply, iLength); | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
}
/*
** Extract the reply payload that follows the header
*/
blob_zero(pReply);
blob_resize(pReply, iLength);
iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength);
blob_resize(pReply, iLength);
if( isError ){
char *z;
int i, j;
z = blob_str(pReply);
for(i=j=0; z[i]; i++, j++){
if( z[i]=='<' ){
|
| ︙ | ︙ | |||
309 310 311 312 313 314 315 |
** connection from remaining open. The easiest fix for now is to
** simply close and restart the connection for each round-trip.
**
** For SSH we will leave the connection open.
*/
if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
if( closeConnection ){
| | | | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
** connection from remaining open. The easiest fix for now is to
** simply close and restart the connection for each round-trip.
**
** For SSH we will leave the connection open.
*/
if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
if( closeConnection ){
transport_close(GLOBAL_URL());
}else{
transport_rewind(GLOBAL_URL());
}
return 0;
/*
** Jump to here if an error is seen.
*/
write_err:
transport_close(GLOBAL_URL());
return 1;
}
|
Changes to src/http_socket.c.
| ︙ | ︙ | |||
129 130 131 132 133 134 135 | ** by global variables that are set using url_parse(): ** ** g.urlName Name of the server. Ex: www.fossil-scm.org ** g.urlPort TCP/IP port to use. Ex: 80 ** ** Return the number of errors. */ | | | | | | | > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
** by global variables that are set using url_parse():
**
** g.urlName Name of the server. Ex: www.fossil-scm.org
** g.urlPort TCP/IP port to use. Ex: 80
**
** Return the number of errors.
*/
int socket_open(UrlData *pUrlData){
static struct sockaddr_in addr; /* The server address */
static int addrIsInit = 0; /* True once addr is initialized */
socket_global_init();
if( !addrIsInit ){
addr.sin_family = AF_INET;
addr.sin_port = htons(pUrlData->port);
*(int*)&addr.sin_addr = inet_addr(pUrlData->name);
if( -1 == *(int*)&addr.sin_addr ){
#ifndef FOSSIL_STATIC_LINK
struct hostent *pHost;
pHost = gethostbyname(pUrlData->name);
if( pHost!=0 ){
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
}else
#endif
{
socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
return 1;
}
}
addrIsInit = 1;
/* Set the Global.zIpAddr variable to the server we are talking to.
** This is used to populate the ipaddr column of the rcvfrom table,
** if any files are received from the server.
*/
g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
}
iSocket = socket(AF_INET,SOCK_STREAM,0);
if( iSocket<0 ){
socket_set_errmsg("cannot create a socket");
return 1;
}
if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
pUrlData->port);
socket_close();
return 1;
}
#if !defined(_WIN32)
signal(SIGPIPE, SIG_IGN);
#endif
return 0;
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 | } /* ** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets ** populated. For hostnames with more than one IP (or if overridden in ** ~/.ssh/config) the rcvfrom may not match the host to which we connect. */ | | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
}
/*
** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
** populated. For hostnames with more than one IP (or if overridden in
** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
*/
void socket_ssh_resolve_addr(UrlData *pUrlData){
struct hostent *pHost; /* Used to make best effort for rcvfrom */
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
pHost = gethostbyname(pUrlData->name);
if( pHost!=0 ){
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
}
}
|
Changes to src/http_ssl.c.
| ︙ | ︙ | |||
181 182 183 184 185 186 187 | ** by global variables that are set using url_parse(): ** ** g.urlName Name of the server. Ex: www.fossil-scm.org ** g.urlPort TCP/IP port to use. Ex: 80 ** ** Return the number of errors. */ | | | | | | > | > | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
** by global variables that are set using url_parse():
**
** g.urlName Name of the server. Ex: www.fossil-scm.org
** g.urlPort TCP/IP port to use. Ex: 80
**
** Return the number of errors.
*/
int ssl_open(UrlData *pUrlData){
X509 *cert;
int hasSavedCertificate = 0;
int trusted = 0;
unsigned long e;
ssl_global_init();
/* Get certificate for current server from global config and
* (if we have it in config) add it to certificate store.
*/
cert = ssl_get_certificate(pUrlData, &trusted);
if ( cert!=NULL ){
X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
X509_free(cert);
hasSavedCertificate = 1;
}
iBio = BIO_new_ssl_connect(sslCtx);
BIO_get_ssl(iBio, &ssl);
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
if( !SSL_set_tlsext_host_name(ssl, pUrlData->name) ){
fossil_warning("WARNING: failed to set server name indication (SNI), "
"continuing without it.\n");
}
#endif
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
if( iBio==NULL ) {
ssl_set_errmsg("SSL: cannot open SSL (%s)",
ERR_reason_error_string(ERR_get_error()));
return 1;
}
BIO_set_conn_hostname(iBio, pUrlData->name);
BIO_set_conn_int_port(iBio, &pUrlData->port);
if( BIO_do_connect(iBio)<=0 ){
ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
pUrlData->name, pUrlData->port,
ERR_reason_error_string(ERR_get_error()));
ssl_close();
return 1;
}
if( BIO_do_handshake(iBio)<=0 ) {
ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
pUrlData->name, pUrlData->port,
ERR_reason_error_string(ERR_get_error()));
ssl_close();
return 1;
}
/* Check if certificate is valid */
cert = SSL_get_peer_certificate(ssl);
if ( cert==NULL ){
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
"SHA1 fingerprint above\n"
" * use the global ssl-ca-location setting to specify your CA root\n"
" certificates list\n\n"
"If you are not expecting this message, answer no and "
"contact your server\nadministrator.\n\n"
"Accept certificate for host %s (a=always/y/N)? ",
X509_verify_cert_error_string(e), desc, warning,
| | | | | | | | | | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
"SHA1 fingerprint above\n"
" * use the global ssl-ca-location setting to specify your CA root\n"
" certificates list\n\n"
"If you are not expecting this message, answer no and "
"contact your server\nadministrator.\n\n"
"Accept certificate for host %s (a=always/y/N)? ",
X509_verify_cert_error_string(e), desc, warning,
pUrlData->name);
BIO_free(mem);
prompt_user(prompt, &ans);
free(prompt);
cReply = blob_str(&ans)[0];
blob_reset(&ans);
if( cReply!='y' && cReply!='Y' && cReply!='a' && cReply!='A') {
X509_free(cert);
ssl_set_errmsg("SSL certificate declined");
ssl_close();
return 1;
}
if( cReply=='a' || cReply=='A') {
if ( trusted==0 ){
prompt_user("\nSave this certificate as fully trusted (a=always/N)? ",
&ans);
cReply = blob_str(&ans)[0];
trusted = ( cReply=='a' || cReply=='A' );
blob_reset(&ans);
}
ssl_save_certificate(pUrlData, cert, trusted);
}
}
/* Set the Global.zIpAddr variable to the server we are talking to.
** This is used to populate the ipaddr column of the rcvfrom table,
** if any files are received from the server.
*/
{
/* IPv4 only code */
const unsigned char *ip = (const unsigned char *) BIO_get_conn_ip(iBio);
g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
}
X509_free(cert);
return 0;
}
/*
** Save certificate to global config.
*/
void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
BIO *mem;
char *zCert, *zHost;
mem = BIO_new(BIO_s_mem());
PEM_write_bio_X509(mem, cert);
BIO_write(mem, "", 1); /* nul-terminate mem buffer */
BIO_get_mem_data(mem, &zCert);
zHost = mprintf("cert:%s", pUrlData->name);
db_set(zHost, zCert, 1);
free(zHost);
zHost = mprintf("trusted:%s", pUrlData->name);
db_set_int(zHost, trusted, 1);
free(zHost);
BIO_free(mem);
}
/*
** Get certificate for g.urlName from global config.
** Return NULL if no certificate found.
*/
X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
char *zHost, *zCert;
BIO *mem;
X509 *cert;
zHost = mprintf("cert:%s", pUrlData->name);
zCert = db_get(zHost, NULL);
free(zHost);
if ( zCert==NULL )
return NULL;
if ( pTrusted!=0 ){
zHost = mprintf("trusted:%s", pUrlData->name);
*pTrusted = db_get_int(zHost, 0);
free(zHost);
}
mem = BIO_new(BIO_s_mem());
BIO_puts(mem, zCert);
cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
|
| ︙ | ︙ |
Changes to src/http_transport.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | static int sshIn; /* From ssh subprocess to this process */ static FILE *sshOut; /* From this to ssh subprocess */ /* ** Return the current transport error message. */ | | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
static int sshIn; /* From ssh subprocess to this process */
static FILE *sshOut; /* From this to ssh subprocess */
/*
** Return the current transport error message.
*/
const char *transport_errmsg(UrlData *pUrlData){
#ifdef FOSSIL_ENABLE_SSL
if( pUrlData->isHttps ){
return ssl_errmsg();
}
#endif
return socket_errmsg();
}
/*
|
| ︙ | ︙ | |||
84 85 86 87 88 89 90 | #else static char zDefaultSshCmd[] = "ssh -e none -T"; #endif /* ** SSH initialization of the transport layer */ | | | | | | | | | | | | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
#else
static char zDefaultSshCmd[] = "ssh -e none -T";
#endif
/*
** SSH initialization of the transport layer
*/
int transport_ssh_open(UrlData *pUrlData){
/* For SSH we need to create and run SSH fossil http
** to talk to the remote machine.
*/
const char *zSsh; /* The base SSH command */
Blob zCmd; /* The SSH command */
char *zHost; /* The host name to contact */
int n; /* Size of prefix string */
socket_ssh_resolve_addr(pUrlData);
zSsh = db_get("ssh-command", zDefaultSshCmd);
blob_init(&zCmd, zSsh, -1);
if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
#ifdef __MINGW32__
blob_appendf(&zCmd, " -P %d", pUrlData->port);
#else
blob_appendf(&zCmd, " -p %d", pUrlData->port);
#endif
}
if( g.fSshTrace ){
fossil_force_newline();
fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
}
if( pUrlData->user && pUrlData->user[0] ){
zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
}else{
zHost = mprintf("%s", pUrlData->name);
}
n = blob_size(&zCmd);
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, zHost);
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, mprintf("%s", pUrlData->fossil));
blob_append(&zCmd, " test-http", 10);
if( pUrlData->path && pUrlData->path[0] ){
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, mprintf("%s", pUrlData->path));
}
if( g.fSshTrace ){
fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
}
free(zHost);
popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
if( sshPid==0 ){
|
| ︙ | ︙ | |||
144 145 146 147 148 149 150 | ** ** g.urlName Name of the server. Ex: www.fossil-scm.org ** g.urlPort TCP/IP port. Ex: 80 ** g.urlIsHttps Use TLS for the connection ** ** Return the number of errors. */ | | | | | | | | | | | | | | | | | | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
**
** g.urlName Name of the server. Ex: www.fossil-scm.org
** g.urlPort TCP/IP port. Ex: 80
** g.urlIsHttps Use TLS for the connection
**
** Return the number of errors.
*/
int transport_open(UrlData *pUrlData){
int rc = 0;
if( transport.isOpen==0 ){
if( pUrlData->isSsh ){
rc = transport_ssh_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
rc = ssl_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
#else
socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
rc = 1;
#endif
}else if( pUrlData->isFile ){
sqlite3_uint64 iRandId;
sqlite3_randomness(sizeof(iRandId), &iRandId);
transport.zOutFile = mprintf("%s-%llu-out.http",
g.zRepositoryName, iRandId);
transport.zInFile = mprintf("%s-%llu-in.http",
g.zRepositoryName, iRandId);
transport.pFile = fossil_fopen(transport.zOutFile, "wb");
if( transport.pFile==0 ){
fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
}
transport.isOpen = 1;
}else{
rc = socket_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
}
}
return rc;
}
/*
** Close the current connection
*/
void transport_close(UrlData *pUrlData){
if( transport.isOpen ){
free(transport.pBuf);
transport.pBuf = 0;
transport.nAlloc = 0;
transport.nUsed = 0;
transport.iCursor = 0;
if( transport.pLog ){
fclose(transport.pLog);
transport.pLog = 0;
}
if( pUrlData->isSsh ){
transport_ssh_close();
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
ssl_close();
#endif
}else if( pUrlData->isFile ){
if( transport.pFile ){
fclose(transport.pFile);
transport.pFile = 0;
}
file_delete(transport.zInFile);
file_delete(transport.zOutFile);
free(transport.zInFile);
free(transport.zOutFile);
}else{
socket_close();
}
transport.isOpen = 0;
}
}
/*
** Send content over the wire.
*/
void transport_send(UrlData *pUrlData, Blob *toSend){
char *z = blob_buffer(toSend);
int n = blob_size(toSend);
transport.nSent += n;
if( pUrlData->isSsh ){
fwrite(z, 1, n, sshOut);
fflush(sshOut);
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
int sent;
while( n>0 ){
sent = ssl_send(0, z, n);
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
if( sent<=0 ) break;
n -= sent;
}
#endif
}else if( pUrlData->isFile ){
fwrite(z, 1, n, transport.pFile);
}else{
int sent;
while( n>0 ){
sent = socket_send(0, z, n);
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
if( sent<=0 ) break;
n -= sent;
}
}
}
/*
** This routine is called when the outbound message is complete and
** it is time to being receiving a reply.
*/
void transport_flip(UrlData *pUrlData){
if( pUrlData->isFile ){
char *zCmd;
fclose(transport.pFile);
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
g.nameOfExe, pUrlData->name, transport.zOutFile, transport.zInFile
);
fossil_system(zCmd);
free(zCmd);
transport.pFile = fossil_fopen(transport.zInFile, "rb");
}
}
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 | transport.pLog = pLog; } /* ** This routine is called when the inbound message has been received ** and it is time to start sending again. */ | | | | | | | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
transport.pLog = pLog;
}
/*
** This routine is called when the inbound message has been received
** and it is time to start sending again.
*/
void transport_rewind(UrlData *pUrlData){
if( pUrlData->isFile ){
transport_close(pUrlData);
}
}
/*
** Read N bytes of content directly from the wire and write into
** the buffer.
*/
static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){
int got;
if( sshIn ){
int x;
int wanted = N;
got = 0;
while( wanted>0 ){
x = read(sshIn, &zBuf[got], wanted);
if( x<=0 ) break;
got += x;
wanted -= x;
}
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
got = ssl_receive(0, zBuf, N);
#else
got = 0;
#endif
}else if( pUrlData->isFile ){
got = fread(zBuf, 1, N, transport.pFile);
}else{
got = socket_receive(0, zBuf, N);
}
/* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
if( transport.pLog ){
fwrite(zBuf, 1, got, transport.pLog);
fflush(transport.pLog);
}
return got;
}
/*
** Read N bytes of content from the wire and store in the supplied buffer.
** Return the number of bytes actually received.
*/
int transport_receive(UrlData *pUrlData, char *zBuf, int N){
int onHand; /* Bytes current held in the transport buffer */
int nByte = 0; /* Bytes of content received */
onHand = transport.nUsed - transport.iCursor;
if( g.fSshTrace){
printf("Reading %d bytes with %d on hand... ", N, onHand);
fflush(stdout);
|
| ︙ | ︙ | |||
349 350 351 352 353 354 355 |
transport.iCursor = 0;
}
N -= toMove;
zBuf += toMove;
nByte += toMove;
}
if( N>0 ){
| | | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
transport.iCursor = 0;
}
N -= toMove;
zBuf += toMove;
nByte += toMove;
}
if( N>0 ){
int got = transport_fetch(pUrlData, zBuf, N);
if( got>0 ){
nByte += got;
transport.nRcvd += got;
}
}
if( g.fSshTrace ) printf("Got %d bytes\n", nByte);
return nByte;
}
/*
** Load up to N new bytes of content into the transport.pBuf buffer.
** The buffer itself might be moved. And the transport.iCursor value
** might be reset to 0.
*/
static void transport_load_buffer(UrlData *pUrlData, int N){
int i, j;
if( transport.nAlloc==0 ){
transport.nAlloc = N;
transport.pBuf = fossil_malloc( N );
transport.iCursor = 0;
transport.nUsed = 0;
}
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
if( transport.nUsed + N > transport.nAlloc ){
char *pNew;
transport.nAlloc = transport.nUsed + N;
pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
transport.pBuf = pNew;
}
if( N>0 ){
| | | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
if( transport.nUsed + N > transport.nAlloc ){
char *pNew;
transport.nAlloc = transport.nUsed + N;
pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
transport.pBuf = pNew;
}
if( N>0 ){
i = transport_fetch(pUrlData, &transport.pBuf[transport.nUsed], N);
if( i>0 ){
transport.nRcvd += i;
transport.nUsed += i;
}
}
}
/*
** Fetch a single line of input where a line is all text up to the next
** \n character or until the end of input. Remove all trailing whitespace
** from the received line and zero-terminate the result. Return a pointer
** to the line.
**
** Each call to this routine potentially overwrites the returned buffer.
*/
char *transport_receive_line(UrlData *pUrlData){
int i;
int iStart;
i = iStart = transport.iCursor;
while(1){
if( i >= transport.nUsed ){
transport_load_buffer(pUrlData, pUrlData->isSsh ? 2 : 1000);
i -= iStart;
iStart = 0;
if( i >= transport.nUsed ){
transport.pBuf[i] = 0;
transport.iCursor = i;
break;
}
|
| ︙ | ︙ | |||
435 436 437 438 439 440 441 |
if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
return &transport.pBuf[iStart];
}
/*
** Global transport shutdown
*/
| | | | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
return &transport.pBuf[iStart];
}
/*
** Global transport shutdown
*/
void transport_global_shutdown(UrlData *pUrlData){
if( pUrlData->isSsh ){
transport_ssh_close();
}
if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
ssl_global_shutdown();
#endif
}else{
socket_global_shutdown();
}
}
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
592 593 594 595 596 597 598 |
zPJ = blob_str(&projName);
for(jj=0; zPJ[jj]; jj++){
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
zPJ[jj] = '_';
}
}
@ <tr><th>Timelines:</th><td>
| | | | | | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
zPJ = blob_str(&projName);
for(jj=0; zPJ[jj]; jj++){
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
zPJ[jj] = '_';
}
}
@ <tr><th>Timelines:</th><td>
@ %z(href("%R/timeline?f=%S&unhide",zUuid))family</a>
if( zParent ){
@ | %z(href("%R/timeline?p=%S&unhide",zUuid))ancestors</a>
}
if( !isLeaf ){
@ | %z(href("%R/timeline?d=%S&unhide",zUuid))descendants</a>
}
if( zParent && !isLeaf ){
@ | %z(href("%R/timeline?dp=%S&unhide",zUuid))both</a>
}
db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
" WHERE rid=%d AND tagtype>0 "
" AND tag.tagid=tagxref.tagid "
" AND +tag.tagname GLOB 'sym-*'", rid);
while( db_step(&q2)==SQLITE_ROW ){
const char *zTagName = db_column_text(&q2, 0);
|
| ︙ | ︙ | |||
1632 1633 1634 1635 1636 1637 1638 |
}
blob_zero(&downloadName);
objType = object_description(rid, 0, &downloadName);
style_submenu_element("Download", "Download",
"%R/raw/%T?name=%s", blob_str(&downloadName), zUuid);
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
style_submenu_element("Checkins Using", "Checkins Using",
| | | 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 |
}
blob_zero(&downloadName);
objType = object_description(rid, 0, &downloadName);
style_submenu_element("Download", "Download",
"%R/raw/%T?name=%s", blob_str(&downloadName), zUuid);
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
style_submenu_element("Checkins Using", "Checkins Using",
"%R/timeline?n=200&uf=%s",zUuid);
}
asText = P("txt")!=0;
zMime = mimetype_from_name(blob_str(&downloadName));
if( zMime ){
if( fossil_strcmp(zMime, "text/html")==0 ){
if( asText ){
style_submenu_element("Html", "Html",
|
| ︙ | ︙ | |||
2193 2194 2195 2196 2197 2198 2199 |
Blob cksum;
blob_appendf(&ctrl, "U %F\n", g.zLogin);
md5sum_blob(&ctrl, &cksum);
blob_appendf(&ctrl, "Z %b\n", &cksum);
db_begin_transaction();
g.markPrivate = content_is_private(rid);
nrid = content_put(&ctrl);
| | | 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 |
Blob cksum;
blob_appendf(&ctrl, "U %F\n", g.zLogin);
md5sum_blob(&ctrl, &cksum);
blob_appendf(&ctrl, "Z %b\n", &cksum);
db_begin_transaction();
g.markPrivate = content_is_private(rid);
nrid = content_put(&ctrl);
manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS);
assert( blob_is_reset(&ctrl) );
db_end_transaction(0);
}
cgi_redirectf("ci?name=%s", zUuid);
}
blob_zero(&comment);
blob_append(&comment, zNewComment, -1);
|
| ︙ | ︙ |
Changes to src/json_branch.c.
| ︙ | ︙ | |||
289 290 291 292 293 294 295 |
blob_appendf(&branch, "Z %b\n", &mcksum);
brid = content_put(&branch);
if( brid==0 ){
fossil_fatal("Problem committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
| | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
blob_appendf(&branch, "Z %b\n", &mcksum);
brid = content_put(&branch);
if( brid==0 ){
fossil_fatal("Problem committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&branch) );
content_deltify(rootid, brid, 0);
if( zNewRid ){
*zNewRid = brid;
}
|
| ︙ | ︙ |
Changes to src/json_config.c.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 |
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
static const struct JsonConfigProperty {
char const * name;
int groupMask;
} JsonConfigProperties[] = {
| | > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
static const struct JsonConfigProperty {
char const * name;
int groupMask;
} JsonConfigProperties[] = {
{ "css", CONFIGSET_CSS },
{ "header", CONFIGSET_SKIN },
{ "footer", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", CONFIGSET_SKIN },
{ "background-mimetype", CONFIGSET_SKIN },
{ "background-image", CONFIGSET_SKIN },
{ "index-page", CONFIGSET_SKIN },
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "project-name", CONFIGSET_PROJ },
{ "project-description", CONFIGSET_PROJ },
{ "manifest", CONFIGSET_PROJ },
{ "binary-glob", CONFIGSET_PROJ },
{ "clean-glob", CONFIGSET_PROJ },
{ "encoding-glob", CONFIGSET_PROJ },
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
zName = json_command_arg(i);
for( ; zName; zName = json_command_arg(++i) ){
if(0==(strcmp("all", zName))){
confMask = CONFIGSET_ALL;
}else if(0==(strcmp("project", zName))){
confMask |= CONFIGSET_PROJ;
}else if(0==(strcmp("skin", zName))){
| | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
zName = json_command_arg(i);
for( ; zName; zName = json_command_arg(++i) ){
if(0==(strcmp("all", zName))){
confMask = CONFIGSET_ALL;
}else if(0==(strcmp("project", zName))){
confMask |= CONFIGSET_PROJ;
}else if(0==(strcmp("skin", zName))){
confMask |= (CONFIGSET_CSS|CONFIGSET_SKIN);
}else if(0==(strcmp("ticket", zName))){
confMask |= CONFIGSET_TKT;
}else if(0==(strcmp("skin-backup", zName))){
optSkinBackups = 1;
}else{
json_set_err( FSL_JSON_E_INVALID_ARGS,
"Unknown config area: %s", zName);
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
/*
** All global variables are in this structure.
*/
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
char *nameOfExe; /* Full path of executable. */
const char *zErrlog; /* Log errors to this file, if not NULL */
int isConst; /* True if the output is unchanging */
const char *zVfsName; /* The VFS to use for database connections */
sqlite3 *db; /* The connection to the databases */
| > > | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
/*
** All global variables are in this structure.
*/
#define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
char *nameOfExe; /* Full path of executable. */
const char *zErrlog; /* Log errors to this file, if not NULL */
int isConst; /* True if the output is unchanging */
const char *zVfsName; /* The VFS to use for database connections */
sqlite3 *db; /* The connection to the databases */
|
| ︙ | ︙ | |||
166 167 168 169 170 171 172 173 174 175 176 177 178 179 | int markPrivate; /* All new artifacts are private if true */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %w and %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ int urlIsFile; /* True if a "file:" url */ int urlIsHttps; /* True if a "https:" url */ int urlIsSsh; /* True if an "ssh:" url */ char *urlName; /* Hostname for http: or filename for file: */ char *urlHostname; /* The HOST: parameter on http headers */ char *urlProtocol; /* "http" or "https" */ int urlPort; /* TCP port number for http: or https: */ | > > > > | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | int markPrivate; /* All new artifacts are private if true */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %w and %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ Blob httpHeader; /* Complete text of the HTTP request header */ /* ** NOTE: These members MUST be kept in sync with those in the "UrlData" ** structure defined in "url.c". */ int urlIsFile; /* True if a "file:" url */ int urlIsHttps; /* True if a "https:" url */ int urlIsSsh; /* True if an "ssh:" url */ char *urlName; /* Hostname for http: or filename for file: */ char *urlHostname; /* The HOST: parameter on http headers */ char *urlProtocol; /* "http" or "https" */ int urlPort; /* TCP port number for http: or https: */ |
| ︙ | ︙ | |||
829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
** This function returns a human readable version string.
*/
const char *get_version(){
static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
MANIFEST_DATE " UTC";
return version;
}
/*
** COMMAND: version
**
** Usage: %fossil version ?-verbose|-v?
**
** Print the source code version number for the fossil executable.
| > > > > > > > > > > | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 |
** This function returns a human readable version string.
*/
const char *get_version(){
static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
MANIFEST_DATE " UTC";
return version;
}
/*
** This function returns the user-agent string for Fossil, for
** use in HTTP(S) requests.
*/
const char *get_user_agent(){
static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
" " MANIFEST_VERSION ")";
return version;
}
/*
** COMMAND: version
**
** Usage: %fossil version ?-verbose|-v?
**
** Print the source code version number for the fossil executable.
|
| ︙ | ︙ |
Changes to src/manifest.c.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
/*
** File permissions used by Fossil internally.
*/
#define PERM_REG 0 /* regular file */
#define PERM_EXE 1 /* executable */
#define PERM_LNK 2 /* symlink */
/*
** A single F-card within a manifest
*/
struct ManifestFile {
char *zName; /* Name of a file */
char *zUuid; /* UUID of the file */
char *zPerm; /* File permissions */
| > > > > > > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
/*
** File permissions used by Fossil internally.
*/
#define PERM_REG 0 /* regular file */
#define PERM_EXE 1 /* executable */
#define PERM_LNK 2 /* symlink */
/*
** Flags for use with manifest_crosslink().
*/
#define MC_NONE 0 /* default handling */
#define MC_PERMIT_HOOKS 1 /* permit hooks to execute */
/*
** A single F-card within a manifest
*/
struct ManifestFile {
char *zName; /* Name of a file */
char *zUuid; /* UUID of the file */
char *zPerm; /* File permissions */
|
| ︙ | ︙ | |||
1648 1649 1650 1651 1652 1653 1654 | ** This routine always resets the pContent blob before returning. ** ** Historical note: This routine original processed manifests only. ** Processing for other control artifacts was added later. The name ** of the routine, "manifest_crosslink", and the name of this source ** file, is a legacy of its original use. */ | | | > > > > > > > | 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 |
** This routine always resets the pContent blob before returning.
**
** Historical note: This routine original processed manifests only.
** Processing for other control artifacts was added later. The name
** of the routine, "manifest_crosslink", and the name of this source
** file, is a legacy of its original use.
*/
int manifest_crosslink(int rid, Blob *pContent, int flags){
int i, result = TH_OK;
Manifest *p;
Stmt q;
int parentid = 0;
const char *zScript = 0;
const char *zUuid = 0;
if( (p = manifest_cache_find(rid))!=0 ){
blob_reset(pContent);
}else if( (p = manifest_parse(pContent, rid, 0))==0 ){
assert( blob_is_reset(pContent) || pContent==0 );
fossil_error(1, "syntax error in manifest");
return 0;
}
if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
manifest_destroy(p);
assert( blob_is_reset(pContent) );
fossil_error(1, "no manifest");
return 0;
}
if( p->type==CFTYPE_MANIFEST && fetch_baseline(p, 0) ){
manifest_destroy(p);
assert( blob_is_reset(pContent) );
fossil_error(1, "cannot fetch baseline manifest");
return 0;
}
db_begin_transaction();
if( p->type==CFTYPE_MANIFEST ){
zScript = xfer_commit_code();
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
char *zCom;
for(i=0; i<p->nParent; i++){
int pid = uuid_to_rid(p->azParent[i], 1);
db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
"VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, p->rDate);
if( i==0 ){
|
| ︙ | ︙ | |||
1766 1767 1768 1769 1770 1771 1772 |
}
if( tid ){
switch( p->aTag[i].zName[0] ){
case '-': type = 0; break; /* Cancel prior occurrences */
case '+': type = 1; break; /* Apply to target only */
case '*': type = 2; break; /* Propagate to descendants */
default:
| | | 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 |
}
if( tid ){
switch( p->aTag[i].zName[0] ){
case '-': type = 0; break; /* Cancel prior occurrences */
case '+': type = 1; break; /* Apply to target only */
case '*': type = 2; break; /* Propagate to descendants */
default:
fossil_error(1, "unknown tag type in manifest: %s", p->aTag);
return 0;
}
tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue,
rid, p->rDate, tid);
}
}
if( parentid ){
|
| ︙ | ︙ | |||
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 |
TAG_BGCOLOR, rid
);
}
}
if( p->type==CFTYPE_TICKET ){
char *zTag;
assert( manifest_crosslink_busy==1 );
zTag = mprintf("tkt-%s", p->zTicketUuid);
tag_insert(zTag, 1, 0, rid, p->rDate, rid);
free(zTag);
db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
p->zTicketUuid);
}
| > > | 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 |
TAG_BGCOLOR, rid
);
}
}
if( p->type==CFTYPE_TICKET ){
char *zTag;
zScript = xfer_ticket_code();
zUuid = p->zTicketUuid;
assert( manifest_crosslink_busy==1 );
zTag = mprintf("tkt-%s", p->zTicketUuid);
tag_insert(zTag, 1, 0, rid, p->rDate, rid);
free(zTag);
db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
p->zTicketUuid);
}
|
| ︙ | ︙ | |||
1932 1933 1934 1935 1936 1937 1938 |
}
}
if( p->type==CFTYPE_CONTROL ){
Blob comment;
int i;
const char *zName;
const char *zValue;
| | | | | | > > > > > > | | | 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 |
}
}
if( p->type==CFTYPE_CONTROL ){
Blob comment;
int i;
const char *zName;
const char *zValue;
const char *zTagUuid;
int branchMove = 0;
blob_zero(&comment);
if( p->zComment ){
blob_appendf(&comment, " %s.", p->zComment);
}
/* Next loop expects tags to be sorted on UUID, so sort it. */
qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
for(i=0; i<p->nTag; i++){
zTagUuid = p->aTag[i].zUuid;
if( !zTagUuid ) continue;
if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){
blob_appendf(&comment,
" Edit [%S]:",
zTagUuid);
branchMove = 0;
if( db_exists("SELECT 1 FROM event, blob"
" WHERE event.type='ci' AND event.objid=blob.rid"
" AND blob.uuid='%s'", zTagUuid) ){
zScript = xfer_commit_code();
zUuid = zTagUuid;
}
}
zName = p->aTag[i].zName;
zValue = p->aTag[i].zValue;
if( strcmp(zName, "*branch")==0 ){
blob_appendf(&comment,
" Move to branch [/timeline?r=%h&nd&dp=%S&unhide | %h].",
zValue, zTagUuid, zValue);
branchMove = 1;
continue;
}else if( strcmp(zName, "*bgcolor")==0 ){
blob_appendf(&comment,
" Change branch background color to \"%h\".", zValue);
continue;
}else if( strcmp(zName, "+bgcolor")==0 ){
|
| ︙ | ︙ | |||
2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 |
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('g',%.17g,%d,%Q,%Q)",
p->rDate, rid, p->zUser, blob_str(&comment)+1
);
blob_reset(&comment);
}
db_end_transaction(0);
if( p->type==CFTYPE_MANIFEST ){
manifest_cache_insert(p);
}else{
manifest_destroy(p);
}
assert( blob_is_reset(pContent) );
| > > > > > > | | | 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 |
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('g',%.17g,%d,%Q,%Q)",
p->rDate, rid, p->zUser, blob_str(&comment)+1
);
blob_reset(&comment);
}
db_end_transaction(0);
if( zScript && (flags & MC_PERMIT_HOOKS) ){
result = xfer_run_common_script();
if( result==TH_OK ){
result = xfer_run_script(zScript, zUuid);
}
}
if( p->type==CFTYPE_MANIFEST ){
manifest_cache_insert(p);
}else{
manifest_destroy(p);
}
assert( blob_is_reset(pContent) );
return ( result!=TH_ERROR );
}
/*
** COMMAND: test-crosslink
**
** Usage: %fossil test-crosslink RECORDID
**
** Run the manifest_crosslink() routine on the artifact with the given
** record ID. This is typically done in the debugger.
*/
void test_crosslink_cmd(void){
int rid;
Blob content;
db_find_and_open_repository(0, 0);
if( g.argc!=3 ) usage("RECORDID");
rid = name_to_rid(g.argv[2]);
content_get(rid, &content);
manifest_crosslink(rid, &content, MC_NONE);
}
|
Changes to src/rebuild.c.
| ︙ | ︙ | |||
248 249 250 251 252 253 254 |
pUse = pBase;
}else{
blob_copy(©, pBase);
pUse = ©
}
if( zFNameFormat==0 ){
/* We are doing "fossil rebuild" */
| | | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
pUse = pBase;
}else{
blob_copy(©, pBase);
pUse = ©
}
if( zFNameFormat==0 ){
/* We are doing "fossil rebuild" */
manifest_crosslink(rid, pUse, MC_NONE);
}else{
/* We are doing "fossil deconstruct" */
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength);
blob_write_to_file(pUse,zFile);
free(zFile);
free(zUuid);
|
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
810 811 812 813 814 815 816 |
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
zVal = zQ;
}
| | | 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 |
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
zVal = zQ;
}
@ <input type="text" id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)"
if( disabled ){
@ disabled="disabled"
}
@ /> <b>%s(zLabel)</b>
}
/*
|
| ︙ | ︙ |
Changes to src/shell.c.
| ︙ | ︙ | |||
3034 3035 3036 3037 3038 3039 3040 |
break;
}
if( seenInterrupt ){
if( in!=0 ) break;
seenInterrupt = 0;
}
lineno++;
| | > > > | 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 |
break;
}
if( seenInterrupt ){
if( in!=0 ) break;
seenInterrupt = 0;
}
lineno++;
if( nSql==0 && _all_whitespace(zLine) ){
if( p->echoOn ) printf("%s\n", zLine);
continue;
}
if( zLine && zLine[0]=='.' && nSql==0 ){
if( p->echoOn ) printf("%s\n", zLine);
rc = do_meta_command(zLine, p);
if( rc==2 ){ /* exit requested */
break;
}else if( rc ){
errCnt++;
|
| ︙ | ︙ | |||
3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 |
}else{
fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
}
errCnt++;
}
nSql = 0;
}else if( nSql && _all_whitespace(zSql) ){
nSql = 0;
}
}
if( nSql ){
if( !_all_whitespace(zSql) ){
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
}
| > | 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 |
}else{
fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
}
errCnt++;
}
nSql = 0;
}else if( nSql && _all_whitespace(zSql) ){
if( p->echoOn ) printf("%s\n", zSql);
nSql = 0;
}
}
if( nSql ){
if( !_all_whitespace(zSql) ){
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
}
|
| ︙ | ︙ |
Changes to src/sqlite3.c.
| ︙ | ︙ | |||
133 134 135 136 137 138 139 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.3" #define SQLITE_VERSION_NUMBER 3008003 | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.3" #define SQLITE_VERSION_NUMBER 3008003 #define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
9096 9097 9098 9099 9100 9101 9102 | #define OP_Integer 23 /* synopsis: r[P2]=P1 */ #define OP_Int64 24 /* synopsis: r[P2]=P4 */ #define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */ #define OP_Null 26 /* synopsis: r[P2..P3]=NULL */ #define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */ #define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */ #define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */ | | | 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 | #define OP_Integer 23 /* synopsis: r[P2]=P1 */ #define OP_Int64 24 /* synopsis: r[P2]=P4 */ #define OP_String 25 /* synopsis: r[P2]='P4' (len=P1) */ #define OP_Null 26 /* synopsis: r[P2..P3]=NULL */ #define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */ #define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */ #define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */ #define OP_Copy 30 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ #define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */ #define OP_ResultRow 32 /* synopsis: output=r[P1@P2] */ #define OP_CollSeq 33 #define OP_AddImm 34 /* synopsis: r[P1]=r[P1]+P2 */ #define OP_MustBeInt 35 #define OP_RealAffinity 36 #define OP_Permutation 37 |
| ︙ | ︙ | |||
9261 9262 9263 9264 9265 9266 9267 | /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ | | | 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 | /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*); SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); |
| ︙ | ︙ | |||
11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 |
u8 directMode; /* Direct rendering mode means take data directly
** from source tables rather than from accumulators */
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
int sortingIdx; /* Cursor number of the sorting index */
int sortingIdxPTab; /* Cursor number of pseudo-table */
int nSortingColumn; /* Number of columns in the sorting index */
ExprList *pGroupBy; /* The group by clause */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
int iTable; /* Cursor number of the source table */
int iColumn; /* Column number within the source table */
int iSorterColumn; /* Column number in the sorting index */
int iMem; /* Memory location that acts as accumulator */
| > | 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 |
u8 directMode; /* Direct rendering mode means take data directly
** from source tables rather than from accumulators */
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
int sortingIdx; /* Cursor number of the sorting index */
int sortingIdxPTab; /* Cursor number of pseudo-table */
int nSortingColumn; /* Number of columns in the sorting index */
int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */
ExprList *pGroupBy; /* The group by clause */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
int iTable; /* Cursor number of the source table */
int iColumn; /* Column number within the source table */
int iSorterColumn; /* Column number in the sorting index */
int iMem; /* Memory location that acts as accumulator */
|
| ︙ | ︙ | |||
12450 12451 12452 12453 12454 12455 12456 | SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); | | < | 12451 12452 12453 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 | SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); SQLITE_PRIVATE u8 sqlite3HexToInt(int h); SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); #if defined(SQLITE_TEST) SQLITE_PRIVATE const char *sqlite3ErrName(int); #endif SQLITE_PRIVATE const char *sqlite3ErrStr(int); SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); |
| ︙ | ︙ | |||
13774 13775 13776 13777 13778 13779 13780 13781 13782 13783 13784 13785 13786 13787 |
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
Op *aOp; /* Space to hold the virtual machine's program */
Mem *aMem; /* The memory locations */
Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */
Mem *pResultSet; /* Pointer to an array of results */
int nMem; /* Number of memory locations currently allocated */
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
int nLabel; /* Number of labels used */
int *aLabel; /* Space to hold the labels */
u16 nResColumn; /* Number of columns in one row of the result set */
int nCursor; /* Number of slots in apCsr[] */
| > > > | 13774 13775 13776 13777 13778 13779 13780 13781 13782 13783 13784 13785 13786 13787 13788 13789 13790 |
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
Op *aOp; /* Space to hold the virtual machine's program */
Mem *aMem; /* The memory locations */
Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */
Mem *pResultSet; /* Pointer to an array of results */
#ifdef SQLITE_DEBUG
Parse *pParse; /* Parsing context used to create this Vdbe */
#endif
int nMem; /* Number of memory locations currently allocated */
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Number of slots allocated for aOp[] */
int nLabel; /* Number of labels used */
int *aLabel; /* Space to hold the labels */
u16 nResColumn; /* Number of columns in one row of the result set */
int nCursor; /* Number of slots in apCsr[] */
|
| ︙ | ︙ | |||
15441 15442 15443 15444 15445 15446 15447 |
** and we need to know about the failures. Use sqlite3OsFileControlHint()
** when simply tossing information over the wall to the VFS and we do not
** really care if the VFS receives and understands the information since it
** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
** routine has no return value since the return value would be meaningless.
*/
SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
| > > > > > > > > > > > > | > > | 15444 15445 15446 15447 15448 15449 15450 15451 15452 15453 15454 15455 15456 15457 15458 15459 15460 15461 15462 15463 15464 15465 15466 15467 15468 15469 15470 15471 15472 |
** and we need to know about the failures. Use sqlite3OsFileControlHint()
** when simply tossing information over the wall to the VFS and we do not
** really care if the VFS receives and understands the information since it
** is only a hint and can be safely ignored. The sqlite3OsFileControlHint()
** routine has no return value since the return value would be meaningless.
*/
SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
#ifdef SQLITE_TEST
if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
** but the transaction is committed anyway.
**
** The core must call OsFileControl() though, not OsFileControlHint(),
** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
** means the commit really has failed and an error should be returned
** to the user. */
DO_OS_MALLOC_TEST(id);
}
#endif
return id->pMethods->xFileControl(id, op, pArg);
}
SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
(void)id->pMethods->xFileControl(id, op, pArg);
}
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
|
| ︙ | ︙ | |||
23096 23097 23098 23099 23100 23101 23102 |
/* 23 */ "Integer" OpHelp("r[P2]=P1"),
/* 24 */ "Int64" OpHelp("r[P2]=P4"),
/* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
/* 26 */ "Null" OpHelp("r[P2..P3]=NULL"),
/* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
/* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
/* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
| | | 23113 23114 23115 23116 23117 23118 23119 23120 23121 23122 23123 23124 23125 23126 23127 |
/* 23 */ "Integer" OpHelp("r[P2]=P1"),
/* 24 */ "Int64" OpHelp("r[P2]=P4"),
/* 25 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
/* 26 */ "Null" OpHelp("r[P2..P3]=NULL"),
/* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
/* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
/* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
/* 30 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
/* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"),
/* 32 */ "ResultRow" OpHelp("output=r[P1@P2]"),
/* 33 */ "CollSeq" OpHelp(""),
/* 34 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
/* 35 */ "MustBeInt" OpHelp(""),
/* 36 */ "RealAffinity" OpHelp(""),
/* 37 */ "Permutation" OpHelp(""),
|
| ︙ | ︙ | |||
61221 61222 61223 61224 61225 61226 61227 | ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. */ /* ** Create a new virtual database engine. */ | | > > > > | 61238 61239 61240 61241 61242 61243 61244 61245 61246 61247 61248 61249 61250 61251 61252 61253 61254 61255 61256 61257 61258 61259 61260 61261 61262 61263 61264 61265 61266 61267 |
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
*/
/*
** Create a new virtual database engine.
*/
SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
sqlite3 *db = pParse->db;
Vdbe *p;
p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
if( p==0 ) return 0;
p->db = db;
if( db->pVdbe ){
db->pVdbe->pPrev = p;
}
p->pNext = db->pVdbe;
p->pPrev = 0;
db->pVdbe = p;
p->magic = VDBE_MAGIC_INIT;
#if SQLITE_DEBUG
p->pParse = pParse;
#endif
return p;
}
/*
** Remember the SQL string for a prepared statement.
*/
SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
|
| ︙ | ︙ | |||
61352 61353 61354 61355 61356 61357 61358 61359 61360 61361 61362 61363 61364 61365 |
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
pOp->zComment = 0;
#endif
#ifdef SQLITE_DEBUG
if( p->db->flags & SQLITE_VdbeAddopTrace ){
sqlite3VdbePrintOp(0, i, &p->aOp[i]);
test_addop_breakpoint();
}
#endif
#ifdef VDBE_PROFILE
pOp->cycles = 0;
pOp->cnt = 0;
| > > > > > > > > > | 61373 61374 61375 61376 61377 61378 61379 61380 61381 61382 61383 61384 61385 61386 61387 61388 61389 61390 61391 61392 61393 61394 61395 |
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
pOp->zComment = 0;
#endif
#ifdef SQLITE_DEBUG
if( p->db->flags & SQLITE_VdbeAddopTrace ){
int jj, kk;
Parse *pParse = p->pParse;
for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){
struct yColCache *x = pParse->aColCache + jj;
if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue;
printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
kk++;
}
if( kk ) printf("\n");
sqlite3VdbePrintOp(0, i, &p->aOp[i]);
test_addop_breakpoint();
}
#endif
#ifdef VDBE_PROFILE
pOp->cycles = 0;
pOp->cnt = 0;
|
| ︙ | ︙ | |||
62073 62074 62075 62076 62077 62078 62079 | if( c=='2' ) return pOp->p2; if( c=='3' ) return pOp->p3; if( c=='4' ) return pOp->p4.i; return pOp->p5; } /* | | > > > > > > > > > > | 62103 62104 62105 62106 62107 62108 62109 62110 62111 62112 62113 62114 62115 62116 62117 62118 62119 62120 62121 62122 62123 62124 62125 62126 62127 |
if( c=='2' ) return pOp->p2;
if( c=='3' ) return pOp->p3;
if( c=='4' ) return pOp->p4.i;
return pOp->p5;
}
/*
** Compute a string for the "comment" field of a VDBE opcode listing.
**
** The Synopsis: field in comments in the vdbe.c source file gets converted
** to an extra string that is appended to the sqlite3OpcodeName(). In the
** absence of other comments, this synopsis becomes the comment on the opcode.
** Some translation occurs:
**
** "PX" -> "r[X]"
** "PX@PY" -> "r[X..X+Y-1]" or "r[x]" if y is 0 or 1
** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
*/
static int displayComment(
const Op *pOp, /* The opcode to be commented */
const char *zP4, /* Previously obtained value for P4 */
char *zTemp, /* Write result here */
int nTemp /* Space available in zTemp[] */
){
|
| ︙ | ︙ | |||
62107 62108 62109 62110 62111 62112 62113 |
int v1 = translateP(c, pOp);
int v2;
sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
ii += 3;
jj += sqlite3Strlen30(zTemp+jj);
v2 = translateP(zSynopsis[ii], pOp);
| > > > > > | > | 62147 62148 62149 62150 62151 62152 62153 62154 62155 62156 62157 62158 62159 62160 62161 62162 62163 62164 62165 62166 62167 |
int v1 = translateP(c, pOp);
int v2;
sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
ii += 3;
jj += sqlite3Strlen30(zTemp+jj);
v2 = translateP(zSynopsis[ii], pOp);
if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
ii += 2;
v2++;
}
if( v2>1 ){
sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
}
}else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
ii += 4;
}
}
jj += sqlite3Strlen30(zTemp+jj);
}else{
zTemp[jj++] = c;
|
| ︙ | ︙ | |||
62339 62340 62341 62342 62343 62344 62345 62346 62347 62348 62349 62350 62351 62352 |
if( pOut==0 ) pOut = stdout;
zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
displayComment(pOp, zP4, zCom, sizeof(zCom));
#else
zCom[0] = 0
#endif
fprintf(pOut, zFormat1, pc,
sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
zCom
);
fflush(pOut);
}
#endif
| > > > | 62385 62386 62387 62388 62389 62390 62391 62392 62393 62394 62395 62396 62397 62398 62399 62400 62401 |
if( pOut==0 ) pOut = stdout;
zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
displayComment(pOp, zP4, zCom, sizeof(zCom));
#else
zCom[0] = 0
#endif
/* NB: The sqlite3OpcodeName() function is implemented by code created
** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
** information from the vdbe.c source text */
fprintf(pOut, zFormat1, pc,
sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
zCom
);
fflush(pOut);
}
#endif
|
| ︙ | ︙ | |||
67399 67400 67401 67402 67403 67404 67405 |
pIn1++;
pOut++;
}while( n-- );
break;
}
/* Opcode: Copy P1 P2 P3 * *
| | | 67448 67449 67450 67451 67452 67453 67454 67455 67456 67457 67458 67459 67460 67461 67462 |
pIn1++;
pOut++;
}while( n-- );
break;
}
/* Opcode: Copy P1 P2 P3 * *
** Synopsis: r[P2@P3+1]=r[P1@P3+1]
**
** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
**
** This instruction makes a deep copy of the value. A duplicate
** is made of any string or blob constant. See also OP_SCopy.
*/
case OP_Copy: {
|
| ︙ | ︙ | |||
68742 68743 68744 68745 68746 68747 68748 |
assert( rc==SQLITE_OK );
if( pC->szRow>=aOffset[p2+1] ){
/* This is the common case where the desired content fits on the original
** page - where the content is not on an overflow page */
VdbeMemRelease(pDest);
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
}else{
| | | 68791 68792 68793 68794 68795 68796 68797 68798 68799 68800 68801 68802 68803 68804 68805 |
assert( rc==SQLITE_OK );
if( pC->szRow>=aOffset[p2+1] ){
/* This is the common case where the desired content fits on the original
** page - where the content is not on an overflow page */
VdbeMemRelease(pDest);
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
}else{
/* This branch happens only when content is on overflow pages */
t = aType[p2];
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
|| (len = sqlite3VdbeSerialTypeLen(t))==0
){
/* Content is irrelevant for the typeof() function and for
** the length(X) function if X is a blob. So we might as well use
|
| ︙ | ︙ | |||
72860 72861 72862 72863 72864 72865 72866 |
zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault);
rc = SQLITE_ERROR;
sqlite3BtreeLeaveAll(db);
goto blob_open_out;
}
}
| | | 72909 72910 72911 72912 72913 72914 72915 72916 72917 72918 72919 72920 72921 72922 72923 |
zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault);
rc = SQLITE_ERROR;
sqlite3BtreeLeaveAll(db);
goto blob_open_out;
}
}
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
assert( pBlob->pStmt || db->mallocFailed );
if( pBlob->pStmt ){
Vdbe *v = (Vdbe *)pBlob->pStmt;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
|
| ︙ | ︙ | |||
78414 78415 78416 78417 78418 78419 78420 78421 78422 78423 78424 78425 78426 78427 78428 78429 78430 78431 78432 78433 78434 78435 78436 78437 78438 78439 78440 |
/*
** Remember the current column cache context. Any new entries added
** added to the column cache after this call are removed when the
** corresponding pop occurs.
*/
SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
pParse->iCacheLevel++;
}
/*
** Remove from the column cache any entries that were added since the
** the previous N Push operations. In other words, restore the cache
** to the state it was in N Pushes ago.
*/
SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse, int N){
int i;
struct yColCache *p;
assert( N>0 );
assert( pParse->iCacheLevel>=N );
pParse->iCacheLevel -= N;
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg && p->iLevel>pParse->iCacheLevel ){
cacheEntryClear(pParse, p);
p->iReg = 0;
}
}
}
| > > > > > > > > > > | 78463 78464 78465 78466 78467 78468 78469 78470 78471 78472 78473 78474 78475 78476 78477 78478 78479 78480 78481 78482 78483 78484 78485 78486 78487 78488 78489 78490 78491 78492 78493 78494 78495 78496 78497 78498 78499 |
/*
** Remember the current column cache context. Any new entries added
** added to the column cache after this call are removed when the
** corresponding pop occurs.
*/
SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
pParse->iCacheLevel++;
#ifdef SQLITE_DEBUG
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
printf("PUSH to %d\n", pParse->iCacheLevel);
}
#endif
}
/*
** Remove from the column cache any entries that were added since the
** the previous N Push operations. In other words, restore the cache
** to the state it was in N Pushes ago.
*/
SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse, int N){
int i;
struct yColCache *p;
assert( N>0 );
assert( pParse->iCacheLevel>=N );
pParse->iCacheLevel -= N;
#ifdef SQLITE_DEBUG
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
printf("POP to %d\n", pParse->iCacheLevel);
}
#endif
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg && p->iLevel>pParse->iCacheLevel ){
cacheEntryClear(pParse, p);
p->iReg = 0;
}
}
}
|
| ︙ | ︙ | |||
78521 78522 78523 78524 78525 78526 78527 78528 78529 78530 78531 78532 78533 78534 |
/*
** Clear all column cache entries.
*/
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
int i;
struct yColCache *p;
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg ){
cacheEntryClear(pParse, p);
p->iReg = 0;
}
}
}
| > > > > > | 78580 78581 78582 78583 78584 78585 78586 78587 78588 78589 78590 78591 78592 78593 78594 78595 78596 78597 78598 |
/*
** Clear all column cache entries.
*/
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
int i;
struct yColCache *p;
#if SQLITE_DEBUG
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
printf("CLEAR\n");
}
#endif
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
if( p->iReg ){
cacheEntryClear(pParse, p);
p->iReg = 0;
}
}
}
|
| ︙ | ︙ | |||
79657 79658 79659 79660 79661 79662 79663 |
for(pItem=pList->a, i=0; i<n; i++, pItem++){
Expr *pExpr = pItem->pExpr;
if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
}else{
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
if( inReg!=target+i ){
| > > > > > > > > > | > | 79721 79722 79723 79724 79725 79726 79727 79728 79729 79730 79731 79732 79733 79734 79735 79736 79737 79738 79739 79740 79741 79742 79743 79744 79745 |
for(pItem=pList->a, i=0; i<n; i++, pItem++){
Expr *pExpr = pItem->pExpr;
if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
}else{
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
if( inReg!=target+i ){
VdbeOp *pOp;
Vdbe *v = pParse->pVdbe;
if( copyOp==OP_Copy
&& (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
&& pOp->p1+pOp->p3+1==inReg
&& pOp->p2+pOp->p3+1==target+i
){
pOp->p3++;
}else{
sqlite3VdbeAddOp2(v, copyOp, inReg, target+i);
}
}
}
}
return n;
}
/*
|
| ︙ | ︙ | |||
83081 83082 83083 83084 83085 83086 83087 |
*/
static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
{
int rc = SQLITE_OK;
if( pExpr ){
if( pExpr->op!=TK_ID ){
rc = sqlite3ResolveExprNames(pName, pExpr);
| < < < < | 83155 83156 83157 83158 83159 83160 83161 83162 83163 83164 83165 83166 83167 83168 |
*/
static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
{
int rc = SQLITE_OK;
if( pExpr ){
if( pExpr->op!=TK_ID ){
rc = sqlite3ResolveExprNames(pName, pExpr);
}else{
pExpr->op = TK_STRING;
}
}
return rc;
}
|
| ︙ | ︙ | |||
89322 89323 89324 89325 89326 89327 89328 |
int *piPartIdxLabel /* OUT: Jump to this label to skip partial index */
){
Vdbe *v = pParse->pVdbe;
int j;
Table *pTab = pIdx->pTable;
int regBase;
int nCol;
| < < | < < | < < < < | 89392 89393 89394 89395 89396 89397 89398 89399 89400 89401 89402 89403 89404 89405 89406 89407 89408 89409 89410 89411 89412 89413 89414 89415 89416 89417 89418 89419 89420 89421 |
int *piPartIdxLabel /* OUT: Jump to this label to skip partial index */
){
Vdbe *v = pParse->pVdbe;
int j;
Table *pTab = pIdx->pTable;
int regBase;
int nCol;
if( piPartIdxLabel ){
if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
pParse->iPartIdxTab = iDataCur;
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL);
}else{
*piPartIdxLabel = 0;
}
}
nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn;
regBase = sqlite3GetTempRange(pParse, nCol);
for(j=0; j<nCol; j++){
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j],
regBase+j);
}
if( regOut ){
const char *zAff;
if( pTab->pSelect
|| OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt)
){
zAff = 0;
|
| ︙ | ︙ | |||
93980 93981 93982 93983 93984 93985 93986 |
/* Check to see if the new index entry will be unique */
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
regIdx, pIdx->nKeyCol);
/* Generate code to handle collisions */
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
| > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 94042 94043 94044 94045 94046 94047 94048 94049 94050 94051 94052 94053 94054 94055 94056 94057 94058 94059 94060 94061 94062 94063 94064 94065 94066 94067 94068 94069 94070 94071 94072 94073 94074 94075 94076 94077 94078 94079 94080 94081 94082 94083 94084 94085 94086 94087 94088 94089 94090 94091 94092 94093 94094 94095 94096 94097 94098 |
/* Check to see if the new index entry will be unique */
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
regIdx, pIdx->nKeyCol);
/* Generate code to handle collisions */
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
if( isUpdate || onError==OE_Replace ){
if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
/* Conflict only if the rowid of the existing index entry
** is different from old-rowid */
if( isUpdate ){
sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldData);
}
}else{
int x;
/* Extract the PRIMARY KEY from the end of the index entry and
** store it in registers regR..regR+nPk-1 */
if( pIdx!=pPk ){
for(i=0; i<pPk->nKeyCol; i++){
x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
VdbeComment((v, "%s.%s", pTab->zName,
pTab->aCol[pPk->aiColumn[i]].zName));
}
}
if( isUpdate ){
/* If currently processing the PRIMARY KEY of a WITHOUT ROWID
** table, only conflict if the new PRIMARY KEY values are actually
** different from the old.
**
** For a UNIQUE index, only conflict if the PRIMARY KEY values
** of the matched index row are different from the original PRIMARY
** KEY values of this row before the update. */
int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
int op = OP_Ne;
int regCmp = (pIdx->autoIndex==2 ? regIdx : regR);
for(i=0; i<pPk->nKeyCol; i++){
char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
x = pPk->aiColumn[i];
if( i==(pPk->nKeyCol-1) ){
addrJump = addrUniqueOk;
op = OP_Eq;
}
sqlite3VdbeAddOp4(v, op,
regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
);
}
}
}
}
/* Generate code that executes if the new index entry is not unique */
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|| onError==OE_Ignore || onError==OE_Replace );
|
| ︙ | ︙ | |||
99720 99721 99722 99723 99724 99725 99726 |
for(i=0; i<nColumn; i++){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
}
}else if( eDest!=SRT_Exists ){
/* If the destination is an EXISTS(...) expression, the actual
** values returned by the SELECT are not required.
*/
| < | 99784 99785 99786 99787 99788 99789 99790 99791 99792 99793 99794 99795 99796 99797 |
for(i=0; i<nColumn; i++){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
}
}else if( eDest!=SRT_Exists ){
/* If the destination is an EXISTS(...) expression, the actual
** values returned by the SELECT are not required.
*/
sqlite3ExprCodeExprList(pParse, pEList, regResult,
(eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
}
nColumn = nResultCol;
/* If the DISTINCT keyword was present on the SELECT statement
** and this row has been seen before, then do not make this row
|
| ︙ | ︙ | |||
100687 100688 100689 100690 100691 100692 100693 |
/*
** Get a VDBE for the given parser context. Create a new one if necessary.
** If an error occurs, return NULL and leave a message in pParse.
*/
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
Vdbe *v = pParse->pVdbe;
if( v==0 ){
| | | 100750 100751 100752 100753 100754 100755 100756 100757 100758 100759 100760 100761 100762 100763 100764 |
/*
** Get a VDBE for the given parser context. Create a new one if necessary.
** If an error occurs, return NULL and leave a message in pParse.
*/
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
Vdbe *v = pParse->pVdbe;
if( v==0 ){
v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
#ifndef SQLITE_OMIT_TRACE
if( v ){
sqlite3VdbeAddOp0(v, OP_Trace);
}
#endif
}
return v;
|
| ︙ | ︙ | |||
102945 102946 102947 102948 102949 102950 102951 |
** routine generates code that stores NULLs in all of those memory
** cells.
*/
static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
Vdbe *v = pParse->pVdbe;
int i;
struct AggInfo_func *pFunc;
| | | > > > > > > > | > | > > < | 103008 103009 103010 103011 103012 103013 103014 103015 103016 103017 103018 103019 103020 103021 103022 103023 103024 103025 103026 103027 103028 103029 103030 103031 103032 103033 103034 103035 103036 103037 103038 |
** routine generates code that stores NULLs in all of those memory
** cells.
*/
static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
Vdbe *v = pParse->pVdbe;
int i;
struct AggInfo_func *pFunc;
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
if( nReg==0 ) return;
#ifdef SQLITE_DEBUG
/* Verify that all AggInfo registers are within the range specified by
** AggInfo.mnReg..AggInfo.mxReg */
assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
for(i=0; i<pAggInfo->nColumn; i++){
assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
&& pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
}
for(i=0; i<pAggInfo->nFunc; i++){
assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
&& pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
}
#endif
sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
if( pFunc->iDistinct>=0 ){
Expr *pE = pFunc->pExpr;
assert( !ExprHasProperty(pE, EP_xIsSelect) );
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
"argument");
pFunc->iDistinct = -1;
|
| ︙ | ︙ | |||
102998 102999 103000 103001 103002 103003 103004 | int i; int regHit = 0; int addrHitTest = 0; struct AggInfo_func *pF; struct AggInfo_col *pC; pAggInfo->directMode = 1; | < | 103070 103071 103072 103073 103074 103075 103076 103077 103078 103079 103080 103081 103082 103083 |
int i;
int regHit = 0;
int addrHitTest = 0;
struct AggInfo_func *pF;
struct AggInfo_col *pC;
pAggInfo->directMode = 1;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
int nArg;
int addrNext = 0;
int regAgg;
ExprList *pList = pF->pExpr->x.pList;
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
if( pList ){
|
| ︙ | ︙ | |||
103531 103532 103533 103534 103535 103536 103537 103538 103539 103540 103541 103542 103543 103544 103545 103546 103547 103548 103549 103550 103551 103552 103553 103554 103555 103556 103557 103558 |
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
** SELECT statement.
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
sNC.pAggInfo = &sAggInfo;
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
sAggInfo.pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
if( pHaving ){
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; i<sAggInfo.nFunc; i++){
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
sNC.ncFlags |= NC_InAggFunc;
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
sNC.ncFlags &= ~NC_InAggFunc;
}
if( db->mallocFailed ) goto select_end;
/* Processing for aggregates with GROUP BY is very different and
** much more complex than aggregates without a GROUP BY.
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
| > > | 103602 103603 103604 103605 103606 103607 103608 103609 103610 103611 103612 103613 103614 103615 103616 103617 103618 103619 103620 103621 103622 103623 103624 103625 103626 103627 103628 103629 103630 103631 |
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
** SELECT statement.
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
sNC.pAggInfo = &sAggInfo;
sAggInfo.mnReg = pParse->nMem+1;
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
sAggInfo.pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, pOrderBy);
if( pHaving ){
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
sAggInfo.nAccumulator = sAggInfo.nColumn;
for(i=0; i<sAggInfo.nFunc; i++){
assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
sNC.ncFlags |= NC_InAggFunc;
sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
sNC.ncFlags &= ~NC_InAggFunc;
}
sAggInfo.mxReg = pParse->nMem;
if( db->mallocFailed ) goto select_end;
/* Processing for aggregates with GROUP BY is very different and
** much more complex than aggregates without a GROUP BY.
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
|
| ︙ | ︙ | |||
105449 105450 105451 105452 105453 105454 105455 |
assert( i<pTab->nCol );
sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc,
pCol->affinity, &pValue);
if( pValue ){
sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
}
#ifndef SQLITE_OMIT_FLOATING_POINT
| | | 105522 105523 105524 105525 105526 105527 105528 105529 105530 105531 105532 105533 105534 105535 105536 |
assert( i<pTab->nCol );
sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc,
pCol->affinity, &pValue);
if( pValue ){
sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
}
#endif
}
}
/*
|
| ︙ | ︙ | |||
105873 105874 105875 105876 105877 105878 105879 |
** the database after the BEFORE triggers are fired anyway (as the trigger
** may have modified them). So not loading those that are not going to
** be used eliminates some redundant opcodes.
*/
newmask = sqlite3TriggerColmask(
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
);
| | | > > | 105946 105947 105948 105949 105950 105951 105952 105953 105954 105955 105956 105957 105958 105959 105960 105961 105962 105963 105964 105965 105966 105967 105968 105969 105970 105971 105972 105973 105974 105975 105976 105977 105978 |
** the database after the BEFORE triggers are fired anyway (as the trigger
** may have modified them). So not loading those that are not going to
** be used eliminates some redundant opcodes.
*/
newmask = sqlite3TriggerColmask(
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
);
/*sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);*/
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
}else{
j = aXRef[i];
if( j>=0 ){
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
/* This branch loads the value of a column that will not be changed
** into a register. This is done if there are no BEFORE triggers, or
** if there are one or more BEFORE triggers that use this value via
** a new.* reference in a trigger program.
*/
testcase( i==31 );
testcase( i==32 );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
}
}
}
/* Fire any BEFORE UPDATE triggers. This happens before constraints are
** verified. One could argue that this is wrong.
*/
|
| ︙ | ︙ | |||
112002 112003 112004 112005 112006 112007 112008 112009 112010 112011 112012 112013 112014 112015 |
** number 18 was found by experimentation to be the payoff point where
** skip-scan become faster than a full-scan.
*/
if( pTerm==0
&& saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
&& pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
){
LogEst nIter;
pNew->u.btree.nEq++;
pNew->u.btree.nSkip++;
pNew->aLTerm[pNew->nLTerm++] = 0;
pNew->wsFlags |= WHERE_SKIPSCAN;
nIter = sqlite3LogEst(pProbe->aiRowEst[0]/pProbe->aiRowEst[saved_nEq+1]);
| > | 112077 112078 112079 112080 112081 112082 112083 112084 112085 112086 112087 112088 112089 112090 112091 |
** number 18 was found by experimentation to be the payoff point where
** skip-scan become faster than a full-scan.
*/
if( pTerm==0
&& saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
&& pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
){
LogEst nIter;
pNew->u.btree.nEq++;
pNew->u.btree.nSkip++;
pNew->aLTerm[pNew->nLTerm++] = 0;
pNew->wsFlags |= WHERE_SKIPSCAN;
nIter = sqlite3LogEst(pProbe->aiRowEst[0]/pProbe->aiRowEst[saved_nEq+1]);
|
| ︙ | ︙ | |||
119720 119721 119722 119723 119724 119725 119726 | } } /* ** Return a static string containing the name corresponding to the error code ** specified in the argument. */ | | < | 119796 119797 119798 119799 119800 119801 119802 119803 119804 119805 119806 119807 119808 119809 119810 |
}
}
/*
** Return a static string containing the name corresponding to the error code
** specified in the argument.
*/
#if defined(SQLITE_TEST)
SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
const char *zName = 0;
int i, origRc = rc;
for(i=0; i<2 && zName==0; i++, rc &= 0xff){
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
|
| ︙ | ︙ | |||
121298 121299 121300 121301 121302 121303 121304 121305 121306 121307 121308 121309 121310 121311 |
** mode. Doing nothing at all also makes NORMAL the default.
*/
#ifdef SQLITE_DEFAULT_LOCKING_MODE
db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
SQLITE_DEFAULT_LOCKING_MODE);
#endif
/* Enable the lookaside-malloc subsystem */
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
sqlite3GlobalConfig.nLookaside);
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
| > > | 121373 121374 121375 121376 121377 121378 121379 121380 121381 121382 121383 121384 121385 121386 121387 121388 |
** mode. Doing nothing at all also makes NORMAL the default.
*/
#ifdef SQLITE_DEFAULT_LOCKING_MODE
db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
SQLITE_DEFAULT_LOCKING_MODE);
#endif
if( rc ) sqlite3Error(db, rc, 0);
/* Enable the lookaside-malloc subsystem */
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
sqlite3GlobalConfig.nLookaside);
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
|
| ︙ | ︙ | |||
131630 131631 131632 131633 131634 131635 131636 |
if( z[0]=='y' && hasVowel(z+1) ){
z[0] = 'i';
}
/* Step 2 */
switch( z[1] ){
case 'a':
| | | > | | > | | | | > | > | | > | > | | | > | > | | > | > | | > | > | | > | 131707 131708 131709 131710 131711 131712 131713 131714 131715 131716 131717 131718 131719 131720 131721 131722 131723 131724 131725 131726 131727 131728 131729 131730 131731 131732 131733 131734 131735 131736 131737 131738 131739 131740 131741 131742 131743 131744 131745 131746 131747 131748 131749 131750 131751 131752 131753 131754 131755 131756 131757 131758 131759 131760 131761 131762 131763 131764 131765 131766 131767 131768 131769 131770 131771 131772 131773 131774 131775 131776 131777 131778 131779 131780 131781 131782 131783 131784 |
if( z[0]=='y' && hasVowel(z+1) ){
z[0] = 'i';
}
/* Step 2 */
switch( z[1] ){
case 'a':
if( !stem(&z, "lanoita", "ate", m_gt_0) ){
stem(&z, "lanoit", "tion", m_gt_0);
}
break;
case 'c':
if( !stem(&z, "icne", "ence", m_gt_0) ){
stem(&z, "icna", "ance", m_gt_0);
}
break;
case 'e':
stem(&z, "rezi", "ize", m_gt_0);
break;
case 'g':
stem(&z, "igol", "log", m_gt_0);
break;
case 'l':
if( !stem(&z, "ilb", "ble", m_gt_0)
&& !stem(&z, "illa", "al", m_gt_0)
&& !stem(&z, "iltne", "ent", m_gt_0)
&& !stem(&z, "ile", "e", m_gt_0)
){
stem(&z, "ilsuo", "ous", m_gt_0);
}
break;
case 'o':
if( !stem(&z, "noitazi", "ize", m_gt_0)
&& !stem(&z, "noita", "ate", m_gt_0)
){
stem(&z, "rota", "ate", m_gt_0);
}
break;
case 's':
if( !stem(&z, "msila", "al", m_gt_0)
&& !stem(&z, "ssenevi", "ive", m_gt_0)
&& !stem(&z, "ssenluf", "ful", m_gt_0)
){
stem(&z, "ssensuo", "ous", m_gt_0);
}
break;
case 't':
if( !stem(&z, "itila", "al", m_gt_0)
&& !stem(&z, "itivi", "ive", m_gt_0)
){
stem(&z, "itilib", "ble", m_gt_0);
}
break;
}
/* Step 3 */
switch( z[0] ){
case 'e':
if( !stem(&z, "etaci", "ic", m_gt_0)
&& !stem(&z, "evita", "", m_gt_0)
){
stem(&z, "ezila", "al", m_gt_0);
}
break;
case 'i':
stem(&z, "itici", "ic", m_gt_0);
break;
case 'l':
if( !stem(&z, "laci", "ic", m_gt_0) ){
stem(&z, "luf", "", m_gt_0);
}
break;
case 's':
stem(&z, "ssen", "", m_gt_0);
break;
}
/* Step 4 */
|
| ︙ | ︙ | |||
131721 131722 131723 131724 131725 131726 131727 |
case 'n':
if( z[0]=='t' ){
if( z[2]=='a' ){
if( m_gt_1(z+3) ){
z += 3;
}
}else if( z[2]=='e' ){
| | | > | > | | > | 131811 131812 131813 131814 131815 131816 131817 131818 131819 131820 131821 131822 131823 131824 131825 131826 131827 131828 131829 131830 131831 131832 131833 131834 131835 131836 131837 131838 131839 131840 131841 131842 131843 131844 131845 131846 131847 131848 131849 131850 |
case 'n':
if( z[0]=='t' ){
if( z[2]=='a' ){
if( m_gt_1(z+3) ){
z += 3;
}
}else if( z[2]=='e' ){
if( !stem(&z, "tneme", "", m_gt_1)
&& !stem(&z, "tnem", "", m_gt_1)
){
stem(&z, "tne", "", m_gt_1);
}
}
}
break;
case 'o':
if( z[0]=='u' ){
if( m_gt_1(z+2) ){
z += 2;
}
}else if( z[3]=='s' || z[3]=='t' ){
stem(&z, "noi", "", m_gt_1);
}
break;
case 's':
if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){
z += 3;
}
break;
case 't':
if( !stem(&z, "eta", "", m_gt_1) ){
stem(&z, "iti", "", m_gt_1);
}
break;
case 'u':
if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){
z += 3;
}
break;
case 'v':
|
| ︙ | ︙ |
Changes to src/sqlite3.h.
| ︙ | ︙ | |||
105 106 107 108 109 110 111 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.3" #define SQLITE_VERSION_NUMBER 3008003 | | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.3" #define SQLITE_VERSION_NUMBER 3008003 #define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ |
Changes to src/tag.c.
| ︙ | ︙ | |||
324 325 326 327 328 329 330 |
}else{
blob_appendf(&ctrl, "\n");
}
blob_appendf(&ctrl, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
md5sum_blob(&ctrl, &cksum);
blob_appendf(&ctrl, "Z %b\n", &cksum);
nrid = content_put(&ctrl);
| | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
}else{
blob_appendf(&ctrl, "\n");
}
blob_appendf(&ctrl, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
md5sum_blob(&ctrl, &cksum);
blob_appendf(&ctrl, "Z %b\n", &cksum);
nrid = content_put(&ctrl);
manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS);
assert( blob_is_reset(&ctrl) );
}
/*
** COMMAND: tag
** Usage: %fossil tag SUBCOMMAND ...
**
|
| ︙ | ︙ |
Changes to src/tar.c.
| ︙ | ︙ | |||
425 426 427 428 429 430 431 |
int i;
Blob zip;
Blob file;
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
sqlite3_open(":memory:", &g.db);
| | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
int i;
Blob zip;
Blob file;
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
sqlite3_open(":memory:", &g.db);
tar_begin(-1);
for(i=3; i<g.argc; i++){
blob_zero(&file);
blob_read_from_file(&file, g.argv[i]);
tar_add_file(g.argv[i], &file,
file_wd_perm(g.argv[i]), file_wd_mtime(g.argv[i]));
blob_reset(&file);
}
|
| ︙ | ︙ |
Changes to src/th.c.
| ︙ | ︙ | |||
1874 1875 1876 1877 1878 1879 1880 |
}
if( rc==TH_OK && eArgType==ARG_INTEGER ){
int iRes = 0;
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: iRes = iLeft*iRight; break;
case OP_DIVIDE:
| | | | 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 |
}
if( rc==TH_OK && eArgType==ARG_INTEGER ){
int iRes = 0;
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: iRes = iLeft*iRight; break;
case OP_DIVIDE:
if( !iRight ){
Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
return TH_ERROR;
}
iRes = iLeft/iRight;
break;
case OP_MODULUS:
if( !iRight ){
Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft);
return TH_ERROR;
}
iRes = iLeft%iRight;
break;
case OP_ADD: iRes = iLeft+iRight; break;
case OP_SUBTRACT: iRes = iLeft-iRight; break;
|
| ︙ | ︙ | |||
1911 1912 1913 1914 1915 1916 1917 |
case OP_LOGICAL_NOT: iRes = !iLeft; break;
default: assert(!"Internal error");
}
Th_SetResultInt(interp, iRes);
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
| > > > > > | > | 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 |
case OP_LOGICAL_NOT: iRes = !iLeft; break;
default: assert(!"Internal error");
}
Th_SetResultInt(interp, iRes);
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
case OP_DIVIDE:
if( fRight==0.0 ){
Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
return TH_ERROR;
}
Th_SetResultDouble(interp, fLeft/fRight);
break;
case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break;
case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break;
case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break;
case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break;
case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break;
case OP_GE: Th_SetResultInt(interp, fLeft>=fRight); break;
case OP_EQ: Th_SetResultInt(interp, fLeft==fRight); break;
|
| ︙ | ︙ |
Changes to src/th_main.c.
| ︙ | ︙ | |||
825 826 827 828 829 830 831 832 833 834 835 836 837 838 |
}else{
Th_SetResult(interp, zErr, -1);
rc = TH_ERROR;
}
re_free(pRe);
return rc;
}
/*
** Make sure the interpreter has been initialized. Initialize it if
** it has not been already.
**
** The interpreter is stored in the g.interp global variable.
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 |
}else{
Th_SetResult(interp, zErr, -1);
rc = TH_ERROR;
}
re_free(pRe);
return rc;
}
/*
** TH command: http ?-asynchronous? ?--? url ?payload?
**
** Perform an HTTP or HTTPS request for the specified URL. If a
** payload is present, it will be interpreted as text/plain and
** the POST method will be used; otherwise, the GET method will
** be used. Upon success, if the -asynchronous option is used, an
** empty string is returned as the result; otherwise, the response
** from the server is returned as the result. Synchronous requests
** are not currently implemented.
*/
#define HTTP_WRONGNUMARGS "http ?-asynchronous? ?--? url ?payload?"
static int httpCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
int nArg = 1;
int fAsynchronous = 0;
const char *zType, *zRegexp;
Blob payload;
ReCompiled *pRe = 0;
UrlData urlData;
if( argc<2 || argc>5 ){
return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS);
}
if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){
fAsynchronous = 1; nArg++;
}
if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++;
if( nArg+1!=argc && nArg+2!=argc ){
return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
}
memset(&urlData, '\0', sizeof(urlData));
url_parse_local(argv[nArg], 0, &urlData);
if( urlData.isSsh || urlData.isFile ){
Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0);
return TH_ERROR;
}
zRegexp = db_get("th1-uri-regexp", 0);
if( zRegexp && zRegexp[0] ){
const char *zErr = re_compile(&pRe, zRegexp, 0);
if( zErr ){
Th_SetResult(interp, zErr, -1);
return TH_ERROR;
}
}
if( !pRe || !re_match(pRe, (const unsigned char *)urlData.canonical, -1) ){
Th_SetResult(interp, "url not allowed", -1);
re_free(pRe);
return TH_ERROR;
}
re_free(pRe);
blob_zero(&payload);
if( nArg+2==argc ){
blob_append(&payload, argv[nArg+1], argl[nArg+1]);
zType = "POST";
}else{
zType = "GET";
}
if( fAsynchronous ){
const char *zSep, *zParams;
Blob hdr;
zParams = strrchr(argv[nArg], '?');
if( strlen(urlData.path)>0 && zParams!=argv[nArg] ){
zSep = "";
}else{
zSep = "/";
}
blob_zero(&hdr);
blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n",
zType, zSep, urlData.path, zParams ? zParams : "");
if( urlData.proxyAuth ){
blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth);
}
if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){
char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]);
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
fossil_free(zCredentials);
}
blob_appendf(&hdr, "Host: %s\r\n"
"User-Agent: %s\r\n", urlData.hostname, get_user_agent());
if( zType[0]=='P' ){
blob_appendf(&hdr, "Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %d\r\n\r\n", blob_size(&payload));
}else{
blob_appendf(&hdr, "\r\n");
}
if( transport_open(&urlData) ){
Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0);
blob_reset(&hdr);
blob_reset(&payload);
return TH_ERROR;
}
transport_send(&urlData, &hdr);
transport_send(&urlData, &payload);
blob_reset(&hdr);
blob_reset(&payload);
transport_close(&urlData);
Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results. */
return TH_OK;
}else{
Th_ErrorMessage(interp,
"synchronous requests are not yet implemented", 0, 0);
blob_reset(&payload);
return TH_ERROR;
}
}
/*
** Make sure the interpreter has been initialized. Initialize it if
** it has not been already.
**
** The interpreter is stored in the g.interp global variable.
*/
|
| ︙ | ︙ | |||
853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
{"date", dateCmd, 0},
{"decorate", wikiCmd, (void*)&aFlags[2]},
{"enable_output", enableOutputCmd, 0},
{"hascap", hascapCmd, 0},
{"hasfeature", hasfeatureCmd, 0},
{"html", putsCmd, (void*)&aFlags[0]},
{"htmlize", htmlizeCmd, 0},
{"linecount", linecntCmd, 0},
{"puts", putsCmd, (void*)&aFlags[1]},
{"query", queryCmd, 0},
{"randhex", randhexCmd, 0},
{"regexp", regexpCmd, 0},
{"repository", repositoryCmd, 0},
{"setting", settingCmd, 0},
| > | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
{"date", dateCmd, 0},
{"decorate", wikiCmd, (void*)&aFlags[2]},
{"enable_output", enableOutputCmd, 0},
{"hascap", hascapCmd, 0},
{"hasfeature", hasfeatureCmd, 0},
{"html", putsCmd, (void*)&aFlags[0]},
{"htmlize", htmlizeCmd, 0},
{"http", httpCmd, 0},
{"linecount", linecntCmd, 0},
{"puts", putsCmd, (void*)&aFlags[1]},
{"query", queryCmd, 0},
{"randhex", randhexCmd, 0},
{"regexp", regexpCmd, 0},
{"repository", repositoryCmd, 0},
{"setting", settingCmd, 0},
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 |
tagid = 0;
}
if( zType[0]=='a' ){
tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
}else{
tmFlags = TIMELINE_GRAPH;
}
if( P("ng")!=0 || zSearch!=0 ){
tmFlags &= ~TIMELINE_GRAPH;
url_add_parameter(&url, "ng", 0);
}
if( P("brbg")!=0 ){
tmFlags |= TIMELINE_BRCOLOR;
url_add_parameter(&url, "brbg", 0);
| > | 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 |
tagid = 0;
}
if( zType[0]=='a' ){
tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
}else{
tmFlags = TIMELINE_GRAPH;
}
url_add_parameter(&url, "n", mprintf("%d", nEntry));
if( P("ng")!=0 || zSearch!=0 ){
tmFlags &= ~TIMELINE_GRAPH;
url_add_parameter(&url, "ng", 0);
}
if( P("brbg")!=0 ){
tmFlags |= TIMELINE_BRCOLOR;
url_add_parameter(&url, "brbg", 0);
|
| ︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 |
blob_appendf(&desc, "%d ancestors", np);
db_multi_exec("%s", blob_str(&sql));
}
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
}
blob_appendf(&desc, " of %z[%.10s]</a>",
href("%R/info/%s", zUuid), zUuid);
}else if( f_rid && g.perm.Read ){
/* If f= is present, ignore all other parameters other than n= */
char *zUuid;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
"INSERT INTO ok VALUES(%d);"
"INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;"
"INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;",
f_rid, f_rid, f_rid
);
blob_appendf(&sql, " AND event.objid IN ok");
db_multi_exec("%s", blob_str(&sql));
if( useDividers ) timeline_add_dividers(0, f_rid);
blob_appendf(&desc, "Parents and children of check-in ");
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
tmFlags |= TIMELINE_DISJOINT;
}else{
/* Otherwise, a timeline based on a span of time */
int n;
const char *zEType = "timeline item";
char *zDate;
| > > > > > > > > > > > > > > > > > < < | 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 |
blob_appendf(&desc, "%d ancestors", np);
db_multi_exec("%s", blob_str(&sql));
}
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
}
blob_appendf(&desc, " of %z[%.10s]</a>",
href("%R/info/%s", zUuid), zUuid);
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
if( p_rid ){
url_add_parameter(&url, "p", zUuid);
}
if( d_rid ){
if( p_rid ){
/* If both p= and d= are set, we don't have the uuid of d yet. */
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
}
url_add_parameter(&url, "d", zUuid);
}
timeline_submenu(&url, "Unhide", "unhide", "", 0);
}
}else if( f_rid && g.perm.Read ){
/* If f= is present, ignore all other parameters other than n= */
char *zUuid;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
"INSERT INTO ok VALUES(%d);"
"INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;"
"INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;",
f_rid, f_rid, f_rid
);
blob_appendf(&sql, " AND event.objid IN ok");
db_multi_exec("%s", blob_str(&sql));
if( useDividers ) timeline_add_dividers(0, f_rid);
blob_appendf(&desc, "Parents and children of check-in ");
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
tmFlags |= TIMELINE_DISJOINT;
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
url_add_parameter(&url, "f", zUuid);
timeline_submenu(&url, "Unhide", "unhide", "", 0);
}
}else{
/* Otherwise, a timeline based on a span of time */
int n;
const char *zEType = "timeline item";
char *zDate;
if( zUses ){
blob_appendf(&sql, " AND event.objid IN usesfile ");
}
if( renameOnly ){
blob_appendf(&sql, " AND event.objid IN rnfile ");
}
if( zYearMonth ){
|
| ︙ | ︙ | |||
1942 1943 1944 1945 1946 1947 1948 |
" FROM plink p, plink c, blob"
" WHERE p.cid=c.pid AND p.mtime>c.mtime"
" AND blob.rid=c.cid"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
@ <li>
| | | 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 |
" FROM plink p, plink c, blob"
" WHERE p.cid=c.pid AND p.mtime>c.mtime"
" AND blob.rid=c.cid"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
@ <li>
@ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&d=%S(zUuid)&unhide">%S(zUuid)</a>
}
db_finalize(&q);
style_footer();
}
/*
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
511 512 513 514 515 516 517 |
aField[idx].zAppend = mprintf("%.*s", argl[2], argv[2]);
return TH_OK;
}
/*
** Write a ticket into the repository.
*/
| | > | > | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 |
aField[idx].zAppend = mprintf("%.*s", argl[2], argv[2]);
return TH_OK;
}
/*
** Write a ticket into the repository.
*/
static int ticket_put(
Blob *pTicket, /* The text of the ticket change record */
const char *zTktId, /* The ticket to which this change is applied */
int needMod /* True if moderation is needed */
){
int result;
int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
if( rid==0 ){
fossil_fatal("trouble committing ticket: %s", g.zErrMsg);
}
if( needMod ){
moderation_table_create();
db_multi_exec(
"INSERT INTO modreq(objid, tktid) VALUES(%d,'%s')",
rid, zTktId
);
}else{
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
manifest_crosslink_begin();
result = (manifest_crosslink(rid, pTicket, MC_PERMIT_HOOKS)==0);
assert( blob_is_reset(pTicket) );
manifest_crosslink_end();
return result;
}
/*
** Subscript command: submit_ticket
**
** Construct and submit a new ticket artifact. The fields of the artifact
** are the names of the columns in the TICKET table. The content is
|
| ︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 |
aField[i].zName, strlen(zValue), zValue);
}
}
blob_appendf(&tktchng, "K %s\n", zTktUuid);
blob_appendf(&tktchng, "U %F\n", zUser);
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
| | > > | > | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 |
aField[i].zName, strlen(zValue), zValue);
}
}
blob_appendf(&tktchng, "K %s\n", zTktUuid);
blob_appendf(&tktchng, "U %F\n", zUser);
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
if( ticket_put(&tktchng, zTktUuid, 0) ){
fossil_fatal("%s\n", g.zErrMsg);
}else{
fossil_print("ticket %s succeeded for %s\n",
(eCmd==set?"set":"add"),zTktUuid);
}
}
}
}
|
Changes to src/url.c.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
*/
#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
#define URL_PROMPTED 0x010 /* Prompted for PW already */
#endif /* INTERFACE */
/*
** Convert a string to lower-case.
*/
static void url_tolower(char *z){
while( *z ){
*z = fossil_tolower(*z);
z++;
}
}
/*
** Parse the given URL, which describes a sync server. Populate variables
** in the global "g" structure as follows:
**
** g.urlIsFile True if FILE:
** g.urlIsHttps True if HTTPS:
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
*/
#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
#define URL_PROMPTED 0x010 /* Prompted for PW already */
/*
** The URL related data used with this subsystem.
*/
struct UrlData {
/*
** NOTE: These members MUST be kept in sync with the related ones in the
** "Global" structure defined in "main.c".
*/
int isFile; /* True if a "file:" url */
int isHttps; /* True if a "https:" url */
int isSsh; /* True if an "ssh:" url */
char *name; /* Hostname for http: or filename for file: */
char *hostname; /* The HOST: parameter on http headers */
char *protocol; /* "http" or "https" */
int port; /* TCP port number for http: or https: */
int dfltPort; /* The default port for the given protocol */
char *path; /* Pathname for http: */
char *user; /* User id for http: */
char *passwd; /* Password for http: */
char *canonical; /* Canonical representation of the URL */
char *proxyAuth; /* Proxy-Authorizer: string */
char *fossil; /* The fossil query parameter on ssh: */
unsigned flags; /* Boolean flags controlling URL processing */
};
#endif /* INTERFACE */
/*
** Convert a string to lower-case.
*/
static void url_tolower(char *z){
while( *z ){
*z = fossil_tolower(*z);
z++;
}
}
/*
** Parse the given URL. Populate members of the provided UrlData structure
** as follows:
**
** isFile True if FILE:
** isHttps True if HTTPS:
** isSsh True if SSH:
** protocol "http" or "https" or "file"
** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
** port TCP port number for HTTP or HTTPS.
** dfltPort Default TCP port number (80 or 443).
** path Path name for HTTP or HTTPS.
** user Userid.
** passwd Password.
** hostname HOST:PORT or just HOST if port is the default.
** canonical The URL in canonical form, omitting the password
**
*/
void url_parse_local(
const char *zUrl,
unsigned int urlFlags,
UrlData *pUrlData
){
int i, j, c;
char *zFile = 0;
if( zUrl==0 ){
zUrl = db_get("last-sync-url", 0);
if( zUrl==0 ) return;
if( pUrlData->passwd==0 ){
pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
}
}
if( strncmp(zUrl, "http://", 7)==0
|| strncmp(zUrl, "https://", 8)==0
|| strncmp(zUrl, "ssh://", 6)==0
){
int iStart;
char *zLogin;
char *zExe;
char cQuerySep = '?';
pUrlData->isFile = 0;
if( zUrl[4]=='s' ){
pUrlData->isHttps = 1;
pUrlData->protocol = "https";
pUrlData->dfltPort = 443;
iStart = 8;
}else if( zUrl[0]=='s' ){
pUrlData->isSsh = 1;
pUrlData->protocol = "ssh";
pUrlData->dfltPort = 22;
pUrlData->fossil = "fossil";
iStart = 6;
}else{
pUrlData->isHttps = 0;
pUrlData->protocol = "http";
pUrlData->dfltPort = 80;
iStart = 7;
}
for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
if( c=='@' ){
/* Parse up the user-id and password */
for(j=iStart; j<i && zUrl[j]!=':'; j++){}
pUrlData->user = mprintf("%.*s", j-iStart, &zUrl[iStart]);
dehttpize(pUrlData->user);
if( j<i ){
if( ( urlFlags & URL_REMEMBER ) && pUrlData->isSsh==0 ){
urlFlags |= URL_ASK_REMEMBER_PW;
}
pUrlData->passwd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
dehttpize(pUrlData->passwd);
}
if( pUrlData->isSsh ){
urlFlags &= ~URL_ASK_REMEMBER_PW;
}
zLogin = mprintf("%t@", pUrlData->user);
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
i = j;
}else{
for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
zLogin = mprintf("");
}
url_tolower(pUrlData->name);
if( c==':' ){
pUrlData->port = 0;
i++;
while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
pUrlData->port = pUrlData->port*10 + c - '0';
i++;
}
pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
}else{
pUrlData->port = pUrlData->dfltPort;
pUrlData->hostname = pUrlData->name;
}
dehttpize(pUrlData->name);
pUrlData->path = mprintf("%s", &zUrl[i]);
for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
if( pUrlData->path[i] ){
pUrlData->path[i] = 0;
i++;
}
zExe = mprintf("");
while( pUrlData->path[i]!=0 ){
char *zName, *zValue;
zName = &pUrlData->path[i];
zValue = zName;
while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
if( pUrlData->path[i]=='=' ){
pUrlData->path[i] = 0;
i++;
zValue = &pUrlData->path[i];
while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; }
}
if( pUrlData->path[i] ){
pUrlData->path[i] = 0;
i++;
}
if( fossil_strcmp(zName,"fossil")==0 ){
pUrlData->fossil = zValue;
dehttpize(pUrlData->fossil);
zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
cQuerySep = '&';
}
}
dehttpize(pUrlData->path);
if( pUrlData->dfltPort==pUrlData->port ){
pUrlData->canonical = mprintf(
"%s://%s%T%T%s",
pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
);
}else{
pUrlData->canonical = mprintf(
"%s://%s%T:%d%T%s",
pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
pUrlData->path, zExe
);
}
if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
free(zLogin);
}else if( strncmp(zUrl, "file:", 5)==0 ){
pUrlData->isFile = 1;
if( zUrl[5]=='/' && zUrl[6]=='/' ){
i = 7;
}else{
i = 5;
}
zFile = mprintf("%s", &zUrl[i]);
}else if( file_isfile(zUrl) ){
pUrlData->isFile = 1;
zFile = mprintf("%s", zUrl);
}else if( file_isdir(zUrl)==1 ){
zFile = mprintf("%s/FOSSIL", zUrl);
if( file_isfile(zFile) ){
pUrlData->isFile = 1;
}else{
free(zFile);
fossil_fatal("unknown repository: %s", zUrl);
}
}else{
fossil_fatal("unknown repository: %s", zUrl);
}
if( urlFlags ) pUrlData->flags = urlFlags;
if( pUrlData->isFile ){
Blob cfile;
dehttpize(zFile);
file_canonical_name(zFile, &cfile, 0);
free(zFile);
pUrlData->protocol = "file";
pUrlData->path = "";
pUrlData->name = mprintf("%b", &cfile);
pUrlData->canonical = mprintf("file://%T", pUrlData->name);
blob_reset(&cfile);
}else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
url_prompt_for_password_local(pUrlData);
}else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
if( isatty(fileno(stdin)) ){
if( save_password_prompt(pUrlData->passwd) ){
pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
}else{
pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
}
}
}
}
/*
** Parse the given URL, which describes a sync server. Populate variables
** in the global "g" structure as follows:
**
** g.urlIsFile True if FILE:
** g.urlIsHttps True if HTTPS:
|
| ︙ | ︙ | |||
77 78 79 80 81 82 83 |
**
** SSH url format is:
**
** ssh://userid@host:port/path?fossil=path/to/fossil.exe
**
*/
void url_parse(const char *zUrl, unsigned int urlFlags){
| < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
**
** SSH url format is:
**
** ssh://userid@host:port/path?fossil=path/to/fossil.exe
**
*/
void url_parse(const char *zUrl, unsigned int urlFlags){
url_parse_local(zUrl, urlFlags, GLOBAL_URL());
}
/*
** COMMAND: test-urlparser
**
** Usage: %fossil test-urlparser URL ?options?
**
|
| ︙ | ︙ | |||
437 438 439 440 441 442 443 |
blob_appendf(&p->url, "%s%s", zSep, zName2);
if( zValue2[0] ) blob_appendf(&p->url, "=%T", zValue2);
}
return blob_str(&p->url);
}
/*
| | > | | | | | | | | | | | | | > > > > > > > > | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
blob_appendf(&p->url, "%s%s", zSep, zName2);
if( zValue2[0] ) blob_appendf(&p->url, "=%T", zValue2);
}
return blob_str(&p->url);
}
/*
** Prompt the user for the password that corresponds to the "user" member of
** the provided UrlData structure. Store the result into the "passwd" member
** of the provided UrlData structure.
*/
void url_prompt_for_password_local(UrlData *pUrlData){
if( pUrlData->isSsh || pUrlData->isFile ) return;
if( isatty(fileno(stdin))
&& (pUrlData->flags & URL_PROMPT_PW)!=0
&& (pUrlData->flags & URL_PROMPTED)==0
){
pUrlData->flags |= URL_PROMPTED;
pUrlData->passwd = prompt_for_user_password(pUrlData->user);
if( pUrlData->passwd[0]
&& (pUrlData->flags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
){
if( save_password_prompt(pUrlData->passwd) ){
pUrlData->flags |= URL_REMEMBER_PW;
}else{
pUrlData->flags &= ~URL_REMEMBER_PW;
}
}
}else{
fossil_fatal("missing or incorrect password for user \"%s\"",
pUrlData->user);
}
}
/*
** Prompt the user for the password for g.urlUser. Store the result
** in g.urlPasswd.
*/
void url_prompt_for_password(void){
url_prompt_for_password_local(GLOBAL_URL());
}
/*
** Remember the URL and password if requested.
*/
void url_remember(void){
if( g.urlFlags & URL_REMEMBER ){
db_set("last-sync-url", g.urlCanonical, 0);
|
| ︙ | ︙ |
Changes to src/user.c.
| ︙ | ︙ | |||
130 131 132 133 134 135 136 | } blob_reset(&secondTry); } /* ** Prompt to save Fossil user password */ | | | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
}
blob_reset(&secondTry);
}
/*
** Prompt to save Fossil user password
*/
int save_password_prompt(const char *passwd){
Blob x;
char c;
const char *old = db_get("last-sync-pw", 0);
if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){
return 0;
}
prompt_user("remember password (Y/n)? ", &x);
c = blob_str(&x)[0];
blob_reset(&x);
return ( c!='n' && c!='N' );
}
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
292 293 294 295 296 297 298 |
}else{
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
moderation_table_create();
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
| | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
}else{
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
moderation_table_create();
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
manifest_crosslink(nrid, pWiki, MC_NONE);
}
/*
** Formal names and common names for the various wiki styles.
*/
static const char *azStyles[] = {
"text/x-fossil-wiki", "Fossil Wiki",
|
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
blob_reset(&hash);
if( rid==0 ){
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
blob_reset(&content);
}else{
if( !isPriv ) content_make_public(rid);
| | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
blob_reset(&hash);
if( rid==0 ){
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
blob_reset(&content);
}else{
if( !isPriv ) content_make_public(rid);
manifest_crosslink(rid, &content, MC_NONE);
}
assert( blob_is_reset(&content) );
remote_has(rid);
}
/*
** The aToken[0..nToken-1] blob array is a parse of a "cfile" line
|
| ︙ | ︙ | |||
818 819 820 821 822 823 824 |
** from a server without authorization.
*/
static void server_private_xfer_not_authorized(void){
@ error not\sauthorized\sto\ssync\sprivate\scontent
}
/*
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | > | < < | > > > > | | | < < < | > > > | | > > > > > > > > | > | | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 |
** from a server without authorization.
*/
static void server_private_xfer_not_authorized(void){
@ error not\sauthorized\sto\ssync\sprivate\scontent
}
/*
** Return the common TH1 code to evaluate prior to evaluating any other
** TH1 transfer notification scripts.
*/
const char *xfer_common_code(void){
return db_get("xfer-common-script", 0);
}
/*
** Return the TH1 code to evaluate when a push is processed.
*/
const char *xfer_push_code(void){
return db_get("xfer-push-script", 0);
}
/*
** Return the TH1 code to evaluate when a commit is processed.
*/
const char *xfer_commit_code(void){
return db_get("xfer-commit-script", 0);
}
/*
** Return the TH1 code to evaluate when a ticket change is processed.
*/
const char *xfer_ticket_code(void){
return db_get("xfer-ticket-script", 0);
}
/*
** Run the specified TH1 script, if any, and returns 1 on error.
*/
int xfer_run_script(const char *zScript, const char *zUuid){
int result;
if( !zScript ) return TH_OK;
Th_FossilInit(TH_INIT_DEFAULT);
if( zUuid ){
result = Th_SetVar(g.interp, "uuid", -1, zUuid, -1);
if( result!=TH_OK ){
fossil_error(1, "%s", Th_GetResult(g.interp, 0));
return result;
}
}
result = Th_Eval(g.interp, 0, zScript, -1);
if( result!=TH_OK ){
fossil_error(1, "%s", Th_GetResult(g.interp, 0));
}
return result;
}
/*
** Runs the pre-transfer TH1 script, if any, and returns its return code.
** This script may be run multiple times. If the script performs actions
** that cannot be redone, it should use an internal [if] guard similar to
** the following:
**
** if {![info exists common_done]} {
** # ... code here
** set common_done 1
** }
*/
int xfer_run_common_script(void){
Th_FossilInit(TH_INIT_DEFAULT);
return xfer_run_script(xfer_common_code(), 0);
}
/*
** If this variable is set, disable login checks. Used for debugging
** only.
*/
static int disableLogin = 0;
|
| ︙ | ︙ | |||
873 874 875 876 877 878 879 880 881 882 883 884 885 886 |
Xfer xfer;
int deltaFlag = 0;
int isClone = 0;
int nGimme = 0;
int size;
int recvConfig = 0;
char *zNow;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
| > | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
Xfer xfer;
int deltaFlag = 0;
int isClone = 0;
int nGimme = 0;
int size;
int recvConfig = 0;
char *zNow;
int result;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
|
| ︙ | ︙ | |||
902 903 904 905 906 907 908 |
g.xferPanic = 1;
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
);
manifest_crosslink_begin();
| | > | | 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 |
g.xferPanic = 1;
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
);
manifest_crosslink_begin();
result = xfer_run_common_script();
if( result==TH_ERROR ){
cgi_reset_content();
@ error common\sscript\sfailed:\s%F(g.zErrMsg)
nErr++;
}
while( blob_line(xfer.pIn, &xfer.line) ){
if( blob_buffer(&xfer.line)[0]=='#' ) continue;
if( blob_size(&xfer.line)==0 ) continue;
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
|
| ︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 |
cgi_reset_content();
@ error bad\scommand:\s%F(blob_str(&xfer.line))
}
blobarray_reset(xfer.aToken, xfer.nToken);
blob_reset(&xfer.line);
}
if( isPush ){
| > > | | | | > | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 |
cgi_reset_content();
@ error bad\scommand:\s%F(blob_str(&xfer.line))
}
blobarray_reset(xfer.aToken, xfer.nToken);
blob_reset(&xfer.line);
}
if( isPush ){
if( result==TH_OK ){
result = xfer_run_script(xfer_push_code(), 0);
if( result==TH_ERROR ){
cgi_reset_content();
@ error push\sscript\sfailed:\s%F(g.zErrMsg)
nErr++;
}
}
request_phantoms(&xfer, 500);
}
if( isClone && nGimme==0 ){
/* The initial "clone" message from client to server contains no
** "gimme" cards. On that initial message, send the client an "igot"
** card for every artifact currently in the repository. This will
|
| ︙ | ︙ | |||
1879 1880 1881 1882 1883 1884 1885 |
g.clockSkewSeen = 1;
}
fossil_force_newline();
fossil_print(
"%s finished with %lld bytes sent, %lld bytes received\n",
zOpType, nSent, nRcvd);
| | | | 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 |
g.clockSkewSeen = 1;
}
fossil_force_newline();
fossil_print(
"%s finished with %lld bytes sent, %lld bytes received\n",
zOpType, nSent, nRcvd);
transport_close(GLOBAL_URL());
transport_global_shutdown(GLOBAL_URL());
db_multi_exec("DROP TABLE onremote");
manifest_crosslink_end();
content_enable_dephantomize(1);
db_end_transaction(0);
return nErr;
}
|
Changes to src/xfersetup.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
void xfersetup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Transfer Setup");
@ <table border="0" cellspacing="20">
setup_menu_entry("Common", "xfersetup_com",
"Common TH1 code run before all transfer request processing.");
setup_menu_entry("Push", "xfersetup_push",
"Specific TH1 code to run after \"push\" transfer requests.");
@ </table>
style_footer();
}
/*
** Common implementation for the transfer setup editor pages.
*/
static void xfersetup_generic(
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
void xfersetup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Transfer Setup");
@ <table border="0" cellspacing="20">
setup_menu_entry("Common", "xfersetup_com",
"Common TH1 code run before all transfer request processing.");
setup_menu_entry("Push", "xfersetup_push",
"Specific TH1 code to run after \"push\" transfer requests.");
setup_menu_entry("Commit", "xfersetup_commit",
"Specific TH1 code to run after processing a commit.");
setup_menu_entry("Ticket", "xfersetup_ticket",
"Specific TH1 code to run after processing a ticket change.");
@ </table>
url_parse(0, 0);
if( g.urlProtocol ){
unsigned syncFlags;
const char *zButton;
char *zWarning;
if( db_get_boolean("dont-push", 0) ){
syncFlags = SYNC_PULL;
zButton = "Pull";
zWarning = 0;
}else{
syncFlags = SYNC_PUSH | SYNC_PULL;
zButton = "Synchronize";
zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
g.urlCanonical);
}
if( P("sync") ){
user_select();
url_enable_proxy(0);
client_sync(syncFlags, 0, 0);
}
@ <p>Press the %h(zButton) button below to synchronize with the
@ "%h(g.urlCanonical)" repository now. This may be useful when
@ testing the various transfer scripts.</p>
@ <p>You can use the "http -async" command in your scripts, but
@ make sure the "th1-uri-regexp" setting is set first.</p>
if( zWarning ){
@
@ <big><b>%h(zWarning)</b></big>
free(zWarning);
}
@
@ <blockquote>
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
login_insert_csrf_secret();
@ <input type="submit" name="sync" value="%h(zButton)" />
@ </div></form>
@ </blockquote>
@
}
style_footer();
}
/*
** Common implementation for the transfer setup editor pages.
*/
static void xfersetup_generic(
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 147 148 |
;
xfersetup_generic(
"Transfer Push Script",
"xfer-push-script",
zDefaultXferPush,
zDesc,
0,
0,
30
);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
;
xfersetup_generic(
"Transfer Push Script",
"xfer-push-script",
zDefaultXferPush,
zDesc,
0,
0,
30
);
}
static const char *zDefaultXferCommit = 0;
/*
** WEBPAGE: xfersetup_commit
*/
void xfersetup_commit_page(void){
static const char zDesc[] =
@ Enter TH1 script that runs when a commit is processed.
;
xfersetup_generic(
"Transfer Commit Script",
"xfer-commit-script",
zDefaultXferCommit,
zDesc,
0,
0,
30
);
}
static const char *zDefaultXferTicket = 0;
/*
** WEBPAGE: xfersetup_ticket
*/
void xfersetup_ticket_page(void){
static const char zDesc[] =
@ Enter TH1 script that runs when a ticket change is processed.
;
xfersetup_generic(
"Transfer Ticket Script",
"xfer-ticket-script",
zDefaultXferTicket,
zDesc,
0,
0,
30
);
}
|
Changes to test/th1.test.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
fossil test-th-eval --th-open-config "setting -- --"
test th1-setting-9 {$RESULT eq {}}
###############################################################################
fossil test-th-eval --th-open-config "setting -strict -- --"
test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
| > > > > > > > > > > > > > > > > > > > > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
fossil test-th-eval --th-open-config "setting -- --"
test th1-setting-9 {$RESULT eq {}}
###############################################################################
fossil test-th-eval --th-open-config "setting -strict -- --"
test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
###############################################################################
fossil test-th-eval "expr 42/0"
test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
###############################################################################
fossil test-th-eval "expr 42/0.0"
test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
###############################################################################
fossil test-th-eval "expr 42.0/0"
test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
###############################################################################
fossil test-th-eval "expr 42.0/0.0"
test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
|
Changes to www/changes.wiki.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
* Fix handling of password embedded in Fossil URL.
* New <tt>--once</tt> option to [/help?cmd=clone | fossil clone] command
which does not store the URL or password when cloning.
* Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open
repository.
* Fossil now hides check-ins that have the "hidden" tag in timeline webpages.
* Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins.
<h2>Changes For Version 1.27 (2013-09-11)</h2>
* Enhance the [/help?cmd=changes | fossil changes],
[/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
[/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
to restrict operation to files and directories named on the command-line.
* New --integrate option to [/help?cmd=merge | fossil merge], which
| > > > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
* Fix handling of password embedded in Fossil URL.
* New <tt>--once</tt> option to [/help?cmd=clone | fossil clone] command
which does not store the URL or password when cloning.
* Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open
repository.
* Fossil now hides check-ins that have the "hidden" tag in timeline webpages.
* Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins.
* Advanced possibilities for commit and ticket change notifications over
http using TH1 scripting.
* Add --sha1sum option to "[/help?cmd=commit | fossil commit]" command.
<h2>Changes For Version 1.27 (2013-09-11)</h2>
* Enhance the [/help?cmd=changes | fossil changes],
[/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
[/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
to restrict operation to files and directories named on the command-line.
* New --integrate option to [/help?cmd=merge | fossil merge], which
|
| ︙ | ︙ |