Fossil SCM
Merge from trunk.
Commit
eb5a49f83500c79a5656f551412b2fcc70045ad6
Parent
a30d1f58d165741…
54 files changed
+1
-1
+1
-1
+5
+5
-5
+10
-7
+443
-26
+23
-8
+4
-4
+7
-4
+9
-7
+1
+31
-24
+7
-6
+15
+15
-8
+44
+44
+4
-6
+14
-15
+34
-16
+4
-4
+6
-6
+1
-1
-1
+20
-6
+4
-3
+13
-13
+3
+167
-73
+7
-5
+98
-3
+3
-2
+263
-162
+23
-23
+113
-113
+10
-2
+22
-17
+15
-10
+1
-1
+3
-3
+11
-13
+4
+15
-16
+142
+3
-1
+2
-2
+2
-2
+5
-7
+5
-7
+10
-10
+22
-2
+18
+6
-7
~
auto.def
~
auto.def
~
src/add.c
~
src/attach.c
~
src/blob.c
~
src/browse.c
~
src/checkin.c
~
src/checkout.c
~
src/db.c
~
src/diff.c
~
src/doc.c
~
src/file.c
~
src/finfo.c
~
src/import.c
~
src/info.c
~
src/main.c
~
src/main.c
~
src/main.mk
~
src/makemake.tcl
~
src/manifest.c
~
src/merge.c
~
src/name.c
~
src/rebuild.c
~
src/report.c
~
src/search.c
~
src/setup.c
~
src/skins.c
~
src/sqlcmd.c
~
src/sqlite3.c
~
src/sqlite3.h
~
src/style.c
~
src/tar.c
~
src/th.c
~
src/th.h
~
src/th_lang.c
~
src/th_main.c
~
src/timeline.c
~
src/tkt.c
~
src/update.c
~
src/user.c
~
src/utf8.c
~
src/winfile.c
~
src/xfer.c
~
test/th1.test
~
test/utf16le.txt
~
test/valgrind-www.tcl
~
win/Makefile.PellesCGMake
~
win/Makefile.dmc
~
win/Makefile.mingw
~
win/Makefile.mingw.mistachkin
~
win/Makefile.msc
~
www/build.wiki
~
www/changes.wiki
~
www/makefile.wiki
M
auto.def
+1
-1
| --- auto.def | ||
| +++ auto.def | ||
| @@ -29,11 +29,11 @@ | ||
| 29 | 29 | # Find tclsh for the test suite. Can't yet use jimsh for this. |
| 30 | 30 | cc-check-progs tclsh |
| 31 | 31 | |
| 32 | 32 | define EXTRA_CFLAGS "" |
| 33 | 33 | define EXTRA_LDFLAGS "" |
| 34 | -define USE_SYSTEM_SQLITE "" | |
| 34 | +define USE_SYSTEM_SQLITE 0 | |
| 35 | 35 | |
| 36 | 36 | if {![opt-bool internal-sqlite]} { |
| 37 | 37 | proc find_internal_sqlite {} { |
| 38 | 38 | |
| 39 | 39 | # On some systems (slackware), libsqlite3 requires -ldl to link. So |
| 40 | 40 |
| --- auto.def | |
| +++ auto.def | |
| @@ -29,11 +29,11 @@ | |
| 29 | # Find tclsh for the test suite. Can't yet use jimsh for this. |
| 30 | cc-check-progs tclsh |
| 31 | |
| 32 | define EXTRA_CFLAGS "" |
| 33 | define EXTRA_LDFLAGS "" |
| 34 | define USE_SYSTEM_SQLITE "" |
| 35 | |
| 36 | if {![opt-bool internal-sqlite]} { |
| 37 | proc find_internal_sqlite {} { |
| 38 | |
| 39 | # On some systems (slackware), libsqlite3 requires -ldl to link. So |
| 40 |
| --- auto.def | |
| +++ auto.def | |
| @@ -29,11 +29,11 @@ | |
| 29 | # Find tclsh for the test suite. Can't yet use jimsh for this. |
| 30 | cc-check-progs tclsh |
| 31 | |
| 32 | define EXTRA_CFLAGS "" |
| 33 | define EXTRA_LDFLAGS "" |
| 34 | define USE_SYSTEM_SQLITE 0 |
| 35 | |
| 36 | if {![opt-bool internal-sqlite]} { |
| 37 | proc find_internal_sqlite {} { |
| 38 | |
| 39 | # On some systems (slackware), libsqlite3 requires -ldl to link. So |
| 40 |
M
auto.def
+1
-1
| --- auto.def | ||
| +++ auto.def | ||
| @@ -29,11 +29,11 @@ | ||
| 29 | 29 | # Find tclsh for the test suite. Can't yet use jimsh for this. |
| 30 | 30 | cc-check-progs tclsh |
| 31 | 31 | |
| 32 | 32 | define EXTRA_CFLAGS "" |
| 33 | 33 | define EXTRA_LDFLAGS "" |
| 34 | -define USE_SYSTEM_SQLITE "" | |
| 34 | +define USE_SYSTEM_SQLITE 0 | |
| 35 | 35 | |
| 36 | 36 | if {![opt-bool internal-sqlite]} { |
| 37 | 37 | proc find_internal_sqlite {} { |
| 38 | 38 | |
| 39 | 39 | # On some systems (slackware), libsqlite3 requires -ldl to link. So |
| 40 | 40 |
| --- auto.def | |
| +++ auto.def | |
| @@ -29,11 +29,11 @@ | |
| 29 | # Find tclsh for the test suite. Can't yet use jimsh for this. |
| 30 | cc-check-progs tclsh |
| 31 | |
| 32 | define EXTRA_CFLAGS "" |
| 33 | define EXTRA_LDFLAGS "" |
| 34 | define USE_SYSTEM_SQLITE "" |
| 35 | |
| 36 | if {![opt-bool internal-sqlite]} { |
| 37 | proc find_internal_sqlite {} { |
| 38 | |
| 39 | # On some systems (slackware), libsqlite3 requires -ldl to link. So |
| 40 |
| --- auto.def | |
| +++ auto.def | |
| @@ -29,11 +29,11 @@ | |
| 29 | # Find tclsh for the test suite. Can't yet use jimsh for this. |
| 30 | cc-check-progs tclsh |
| 31 | |
| 32 | define EXTRA_CFLAGS "" |
| 33 | define EXTRA_LDFLAGS "" |
| 34 | define USE_SYSTEM_SQLITE 0 |
| 35 | |
| 36 | if {![opt-bool internal-sqlite]} { |
| 37 | proc find_internal_sqlite {} { |
| 38 | |
| 39 | # On some systems (slackware), libsqlite3 requires -ldl to link. So |
| 40 |
+5
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -270,10 +270,15 @@ | ||
| 270 | 270 | /* Load the names of all files that are to be added into sfile temp table */ |
| 271 | 271 | for(i=2; i<g.argc; i++){ |
| 272 | 272 | char *zName; |
| 273 | 273 | int isDir; |
| 274 | 274 | Blob fullName; |
| 275 | + | |
| 276 | + /* file_tree_name() throws a fatal error if g.argv[i] is outside of the | |
| 277 | + ** checkout. */ | |
| 278 | + file_tree_name(g.argv[i], &fullName, 1); | |
| 279 | + blob_reset(&fullName); | |
| 275 | 280 | |
| 276 | 281 | file_canonical_name(g.argv[i], &fullName, 0); |
| 277 | 282 | zName = blob_str(&fullName); |
| 278 | 283 | isDir = file_wd_isdir(zName); |
| 279 | 284 | if( isDir==1 ){ |
| 280 | 285 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -270,10 +270,15 @@ | |
| 270 | /* Load the names of all files that are to be added into sfile temp table */ |
| 271 | for(i=2; i<g.argc; i++){ |
| 272 | char *zName; |
| 273 | int isDir; |
| 274 | Blob fullName; |
| 275 | |
| 276 | file_canonical_name(g.argv[i], &fullName, 0); |
| 277 | zName = blob_str(&fullName); |
| 278 | isDir = file_wd_isdir(zName); |
| 279 | if( isDir==1 ){ |
| 280 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -270,10 +270,15 @@ | |
| 270 | /* Load the names of all files that are to be added into sfile temp table */ |
| 271 | for(i=2; i<g.argc; i++){ |
| 272 | char *zName; |
| 273 | int isDir; |
| 274 | Blob fullName; |
| 275 | |
| 276 | /* file_tree_name() throws a fatal error if g.argv[i] is outside of the |
| 277 | ** checkout. */ |
| 278 | file_tree_name(g.argv[i], &fullName, 1); |
| 279 | blob_reset(&fullName); |
| 280 | |
| 281 | file_canonical_name(g.argv[i], &fullName, 0); |
| 282 | zName = blob_str(&fullName); |
| 283 | isDir = file_wd_isdir(zName); |
| 284 | if( isDir==1 ){ |
| 285 |
+5
-5
| --- src/attach.c | ||
| +++ src/attach.c | ||
| @@ -40,16 +40,16 @@ | ||
| 40 | 40 | Stmt q; |
| 41 | 41 | |
| 42 | 42 | if( zPage && zTkt ) zTkt = 0; |
| 43 | 43 | login_check_credentials(); |
| 44 | 44 | blob_zero(&sql); |
| 45 | - blob_append(&sql, | |
| 46 | - "SELECT datetime(mtime,'localtime'), src, target, filename," | |
| 45 | + blob_appendf(&sql, | |
| 46 | + "SELECT datetime(mtime%s), src, target, filename," | |
| 47 | 47 | " comment, user," |
| 48 | 48 | " (SELECT uuid FROM blob WHERE rid=attachid), attachid" |
| 49 | 49 | " FROM attachment", |
| 50 | - -1 | |
| 50 | + timeline_utc() | |
| 51 | 51 | ); |
| 52 | 52 | if( zPage ){ |
| 53 | 53 | if( g.perm.RdWiki==0 ) login_needed(); |
| 54 | 54 | style_header("Attachments To %h", zPage); |
| 55 | 55 | blob_appendf(&sql, " WHERE target=%Q", zPage); |
| @@ -553,16 +553,16 @@ | ||
| 553 | 553 | const char *zHeader /* Header to display with attachments */ |
| 554 | 554 | ){ |
| 555 | 555 | int cnt = 0; |
| 556 | 556 | Stmt q; |
| 557 | 557 | db_prepare(&q, |
| 558 | - "SELECT datetime(mtime,'localtime'), filename, user," | |
| 558 | + "SELECT datetime(mtime%s), filename, user," | |
| 559 | 559 | " (SELECT uuid FROM blob WHERE rid=attachid), src" |
| 560 | 560 | " FROM attachment" |
| 561 | 561 | " WHERE isLatest AND src!='' AND target=%Q" |
| 562 | 562 | " ORDER BY mtime DESC", |
| 563 | - zTarget | |
| 563 | + timeline_utc(), zTarget | |
| 564 | 564 | ); |
| 565 | 565 | while( db_step(&q)==SQLITE_ROW ){ |
| 566 | 566 | const char *zDate = db_column_text(&q, 0); |
| 567 | 567 | const char *zFile = db_column_text(&q, 1); |
| 568 | 568 | const char *zUser = db_column_text(&q, 2); |
| 569 | 569 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -40,16 +40,16 @@ | |
| 40 | Stmt q; |
| 41 | |
| 42 | if( zPage && zTkt ) zTkt = 0; |
| 43 | login_check_credentials(); |
| 44 | blob_zero(&sql); |
| 45 | blob_append(&sql, |
| 46 | "SELECT datetime(mtime,'localtime'), src, target, filename," |
| 47 | " comment, user," |
| 48 | " (SELECT uuid FROM blob WHERE rid=attachid), attachid" |
| 49 | " FROM attachment", |
| 50 | -1 |
| 51 | ); |
| 52 | if( zPage ){ |
| 53 | if( g.perm.RdWiki==0 ) login_needed(); |
| 54 | style_header("Attachments To %h", zPage); |
| 55 | blob_appendf(&sql, " WHERE target=%Q", zPage); |
| @@ -553,16 +553,16 @@ | |
| 553 | const char *zHeader /* Header to display with attachments */ |
| 554 | ){ |
| 555 | int cnt = 0; |
| 556 | Stmt q; |
| 557 | db_prepare(&q, |
| 558 | "SELECT datetime(mtime,'localtime'), filename, user," |
| 559 | " (SELECT uuid FROM blob WHERE rid=attachid), src" |
| 560 | " FROM attachment" |
| 561 | " WHERE isLatest AND src!='' AND target=%Q" |
| 562 | " ORDER BY mtime DESC", |
| 563 | zTarget |
| 564 | ); |
| 565 | while( db_step(&q)==SQLITE_ROW ){ |
| 566 | const char *zDate = db_column_text(&q, 0); |
| 567 | const char *zFile = db_column_text(&q, 1); |
| 568 | const char *zUser = db_column_text(&q, 2); |
| 569 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -40,16 +40,16 @@ | |
| 40 | Stmt q; |
| 41 | |
| 42 | if( zPage && zTkt ) zTkt = 0; |
| 43 | login_check_credentials(); |
| 44 | blob_zero(&sql); |
| 45 | blob_appendf(&sql, |
| 46 | "SELECT datetime(mtime%s), src, target, filename," |
| 47 | " comment, user," |
| 48 | " (SELECT uuid FROM blob WHERE rid=attachid), attachid" |
| 49 | " FROM attachment", |
| 50 | timeline_utc() |
| 51 | ); |
| 52 | if( zPage ){ |
| 53 | if( g.perm.RdWiki==0 ) login_needed(); |
| 54 | style_header("Attachments To %h", zPage); |
| 55 | blob_appendf(&sql, " WHERE target=%Q", zPage); |
| @@ -553,16 +553,16 @@ | |
| 553 | const char *zHeader /* Header to display with attachments */ |
| 554 | ){ |
| 555 | int cnt = 0; |
| 556 | Stmt q; |
| 557 | db_prepare(&q, |
| 558 | "SELECT datetime(mtime%s), filename, user," |
| 559 | " (SELECT uuid FROM blob WHERE rid=attachid), src" |
| 560 | " FROM attachment" |
| 561 | " WHERE isLatest AND src!='' AND target=%Q" |
| 562 | " ORDER BY mtime DESC", |
| 563 | timeline_utc(), zTarget |
| 564 | ); |
| 565 | while( db_step(&q)==SQLITE_ROW ){ |
| 566 | const char *zDate = db_column_text(&q, 0); |
| 567 | const char *zFile = db_column_text(&q, 1); |
| 568 | const char *zUser = db_column_text(&q, 2); |
| 569 |
+10
-7
| --- src/blob.c | ||
| +++ src/blob.c | ||
| @@ -223,10 +223,19 @@ | ||
| 223 | 223 | ** Any prior data in the blob is discarded. |
| 224 | 224 | */ |
| 225 | 225 | void blob_set(Blob *pBlob, const char *zStr){ |
| 226 | 226 | blob_init(pBlob, zStr, -1); |
| 227 | 227 | } |
| 228 | + | |
| 229 | +/* | |
| 230 | +** Initialize a blob to a nul-terminated string obtained from fossil_malloc(). | |
| 231 | +** The blob will take responsibility for freeing the string. | |
| 232 | +*/ | |
| 233 | +void blob_set_dynamic(Blob *pBlob, char *zStr){ | |
| 234 | + blob_init(pBlob, zStr, -1); | |
| 235 | + pBlob->xRealloc = blobReallocMalloc; | |
| 236 | +} | |
| 228 | 237 | |
| 229 | 238 | /* |
| 230 | 239 | ** Initialize a blob to an empty string. |
| 231 | 240 | */ |
| 232 | 241 | void blob_zero(Blob *pBlob){ |
| @@ -1095,21 +1104,18 @@ | ||
| 1095 | 1104 | ** to be UTF-8 already, so no conversion is done. |
| 1096 | 1105 | */ |
| 1097 | 1106 | void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){ |
| 1098 | 1107 | char *zUtf8; |
| 1099 | 1108 | int bomSize = 0; |
| 1100 | -#if defined(_WIN32) || defined(__CYGWIN__) | |
| 1101 | 1109 | int bomReverse = 0; |
| 1102 | -#endif | |
| 1103 | 1110 | if( starts_with_utf8_bom(pBlob, &bomSize) ){ |
| 1104 | 1111 | struct Blob temp; |
| 1105 | 1112 | zUtf8 = blob_str(pBlob) + bomSize; |
| 1106 | 1113 | blob_zero(&temp); |
| 1107 | 1114 | blob_append(&temp, zUtf8, -1); |
| 1108 | 1115 | blob_swap(pBlob, &temp); |
| 1109 | 1116 | blob_reset(&temp); |
| 1110 | -#if defined(_WIN32) || defined(__CYGWIN__) | |
| 1111 | 1117 | }else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){ |
| 1112 | 1118 | zUtf8 = blob_buffer(pBlob); |
| 1113 | 1119 | if( bomReverse ){ |
| 1114 | 1120 | /* Found BOM, but with reversed bytes */ |
| 1115 | 1121 | unsigned int i = blob_size(pBlob); |
| @@ -1122,18 +1128,15 @@ | ||
| 1122 | 1128 | } |
| 1123 | 1129 | /* Make sure the blob contains two terminating 0-bytes */ |
| 1124 | 1130 | blob_append(pBlob, "", 1); |
| 1125 | 1131 | zUtf8 = blob_str(pBlob) + bomSize; |
| 1126 | 1132 | zUtf8 = fossil_unicode_to_utf8(zUtf8); |
| 1127 | - blob_zero(pBlob); | |
| 1128 | - blob_append(pBlob, zUtf8, -1); | |
| 1129 | - fossil_unicode_free(zUtf8); | |
| 1130 | -#endif /* _WIN32 || __CYGWIN__ */ | |
| 1133 | + blob_set_dynamic(pBlob, zUtf8); | |
| 1131 | 1134 | #if defined(_WIN32) |
| 1132 | 1135 | }else if( useMbcs ){ |
| 1133 | 1136 | zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob)); |
| 1134 | 1137 | blob_reset(pBlob); |
| 1135 | 1138 | blob_append(pBlob, zUtf8, -1); |
| 1136 | 1139 | fossil_mbcs_free(zUtf8); |
| 1137 | 1140 | #endif /* _WIN32 */ |
| 1138 | 1141 | } |
| 1139 | 1142 | } |
| 1140 | 1143 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -223,10 +223,19 @@ | |
| 223 | ** Any prior data in the blob is discarded. |
| 224 | */ |
| 225 | void blob_set(Blob *pBlob, const char *zStr){ |
| 226 | blob_init(pBlob, zStr, -1); |
| 227 | } |
| 228 | |
| 229 | /* |
| 230 | ** Initialize a blob to an empty string. |
| 231 | */ |
| 232 | void blob_zero(Blob *pBlob){ |
| @@ -1095,21 +1104,18 @@ | |
| 1095 | ** to be UTF-8 already, so no conversion is done. |
| 1096 | */ |
| 1097 | void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){ |
| 1098 | char *zUtf8; |
| 1099 | int bomSize = 0; |
| 1100 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 1101 | int bomReverse = 0; |
| 1102 | #endif |
| 1103 | if( starts_with_utf8_bom(pBlob, &bomSize) ){ |
| 1104 | struct Blob temp; |
| 1105 | zUtf8 = blob_str(pBlob) + bomSize; |
| 1106 | blob_zero(&temp); |
| 1107 | blob_append(&temp, zUtf8, -1); |
| 1108 | blob_swap(pBlob, &temp); |
| 1109 | blob_reset(&temp); |
| 1110 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 1111 | }else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){ |
| 1112 | zUtf8 = blob_buffer(pBlob); |
| 1113 | if( bomReverse ){ |
| 1114 | /* Found BOM, but with reversed bytes */ |
| 1115 | unsigned int i = blob_size(pBlob); |
| @@ -1122,18 +1128,15 @@ | |
| 1122 | } |
| 1123 | /* Make sure the blob contains two terminating 0-bytes */ |
| 1124 | blob_append(pBlob, "", 1); |
| 1125 | zUtf8 = blob_str(pBlob) + bomSize; |
| 1126 | zUtf8 = fossil_unicode_to_utf8(zUtf8); |
| 1127 | blob_zero(pBlob); |
| 1128 | blob_append(pBlob, zUtf8, -1); |
| 1129 | fossil_unicode_free(zUtf8); |
| 1130 | #endif /* _WIN32 || __CYGWIN__ */ |
| 1131 | #if defined(_WIN32) |
| 1132 | }else if( useMbcs ){ |
| 1133 | zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob)); |
| 1134 | blob_reset(pBlob); |
| 1135 | blob_append(pBlob, zUtf8, -1); |
| 1136 | fossil_mbcs_free(zUtf8); |
| 1137 | #endif /* _WIN32 */ |
| 1138 | } |
| 1139 | } |
| 1140 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -223,10 +223,19 @@ | |
| 223 | ** Any prior data in the blob is discarded. |
| 224 | */ |
| 225 | void blob_set(Blob *pBlob, const char *zStr){ |
| 226 | blob_init(pBlob, zStr, -1); |
| 227 | } |
| 228 | |
| 229 | /* |
| 230 | ** Initialize a blob to a nul-terminated string obtained from fossil_malloc(). |
| 231 | ** The blob will take responsibility for freeing the string. |
| 232 | */ |
| 233 | void blob_set_dynamic(Blob *pBlob, char *zStr){ |
| 234 | blob_init(pBlob, zStr, -1); |
| 235 | pBlob->xRealloc = blobReallocMalloc; |
| 236 | } |
| 237 | |
| 238 | /* |
| 239 | ** Initialize a blob to an empty string. |
| 240 | */ |
| 241 | void blob_zero(Blob *pBlob){ |
| @@ -1095,21 +1104,18 @@ | |
| 1104 | ** to be UTF-8 already, so no conversion is done. |
| 1105 | */ |
| 1106 | void blob_to_utf8_no_bom(Blob *pBlob, int useMbcs){ |
| 1107 | char *zUtf8; |
| 1108 | int bomSize = 0; |
| 1109 | int bomReverse = 0; |
| 1110 | if( starts_with_utf8_bom(pBlob, &bomSize) ){ |
| 1111 | struct Blob temp; |
| 1112 | zUtf8 = blob_str(pBlob) + bomSize; |
| 1113 | blob_zero(&temp); |
| 1114 | blob_append(&temp, zUtf8, -1); |
| 1115 | blob_swap(pBlob, &temp); |
| 1116 | blob_reset(&temp); |
| 1117 | }else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){ |
| 1118 | zUtf8 = blob_buffer(pBlob); |
| 1119 | if( bomReverse ){ |
| 1120 | /* Found BOM, but with reversed bytes */ |
| 1121 | unsigned int i = blob_size(pBlob); |
| @@ -1122,18 +1128,15 @@ | |
| 1128 | } |
| 1129 | /* Make sure the blob contains two terminating 0-bytes */ |
| 1130 | blob_append(pBlob, "", 1); |
| 1131 | zUtf8 = blob_str(pBlob) + bomSize; |
| 1132 | zUtf8 = fossil_unicode_to_utf8(zUtf8); |
| 1133 | blob_set_dynamic(pBlob, zUtf8); |
| 1134 | #if defined(_WIN32) |
| 1135 | }else if( useMbcs ){ |
| 1136 | zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob)); |
| 1137 | blob_reset(pBlob); |
| 1138 | blob_append(pBlob, zUtf8, -1); |
| 1139 | fossil_mbcs_free(zUtf8); |
| 1140 | #endif /* _WIN32 */ |
| 1141 | } |
| 1142 | } |
| 1143 |
+443
-26
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -71,23 +71,29 @@ | ||
| 71 | 71 | ** There is no hyperlink on the file element of the path. |
| 72 | 72 | ** |
| 73 | 73 | ** The computed string is appended to the pOut blob. pOut should |
| 74 | 74 | ** have already been initialized. |
| 75 | 75 | */ |
| 76 | -void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){ | |
| 76 | +void hyperlinked_path( | |
| 77 | + const char *zPath, /* Path to render */ | |
| 78 | + Blob *pOut, /* Write into this blob */ | |
| 79 | + const char *zCI, /* check-in name, or NULL */ | |
| 80 | + const char *zURI, /* "dir" or "tree" */ | |
| 81 | + const char *zREx /* Extra query parameters */ | |
| 82 | +){ | |
| 77 | 83 | int i, j; |
| 78 | 84 | char *zSep = ""; |
| 79 | 85 | |
| 80 | 86 | for(i=0; zPath[i]; i=j){ |
| 81 | 87 | for(j=i; zPath[j] && zPath[j]!='/'; j++){} |
| 82 | 88 | if( zPath[j] && g.perm.Hyperlink ){ |
| 83 | 89 | if( zCI ){ |
| 84 | - char *zLink = href("%R/dir?ci=%S&name=%#T", zCI, j, zPath); | |
| 90 | + char *zLink = href("%R/%s?ci=%S&name=%#T%s", zURI, zCI, j, zPath,zREx); | |
| 85 | 91 | blob_appendf(pOut, "%s%z%#h</a>", |
| 86 | 92 | zSep, zLink, j-i, &zPath[i]); |
| 87 | 93 | }else{ |
| 88 | - char *zLink = href("%R/dir?name=%#T", j, zPath); | |
| 94 | + char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx); | |
| 89 | 95 | blob_appendf(pOut, "%s%z%#h</a>", |
| 90 | 96 | zSep, zLink, j-i, &zPath[i]); |
| 91 | 97 | } |
| 92 | 98 | }else{ |
| 93 | 99 | blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); |
| @@ -101,11 +107,11 @@ | ||
| 101 | 107 | /* |
| 102 | 108 | ** WEBPAGE: dir |
| 103 | 109 | ** |
| 104 | 110 | ** Query parameters: |
| 105 | 111 | ** |
| 106 | -** name=PATH Directory to display. Required. | |
| 112 | +** name=PATH Directory to display. Optional. Top-level if missing | |
| 107 | 113 | ** ci=LABEL Show only files in this check-in. Optional. |
| 108 | 114 | */ |
| 109 | 115 | void page_dir(void){ |
| 110 | 116 | char *zD = fossil_strdup(P("name")); |
| 111 | 117 | int nD = zD ? strlen(zD)+1 : 0; |
| @@ -118,18 +124,22 @@ | ||
| 118 | 124 | int rid = 0; |
| 119 | 125 | char *zUuid = 0; |
| 120 | 126 | Blob dirname; |
| 121 | 127 | Manifest *pM = 0; |
| 122 | 128 | const char *zSubdirLink; |
| 123 | - int linkTrunk = 1, linkTip = 1; | |
| 129 | + int linkTrunk = 1; | |
| 130 | + int linkTip = 1; | |
| 131 | + HQuery sURI; | |
| 124 | 132 | |
| 133 | + if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; } | |
| 125 | 134 | login_check_credentials(); |
| 126 | 135 | if( !g.perm.Read ){ login_needed(); return; } |
| 127 | 136 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 128 | 137 | style_header("File List"); |
| 129 | 138 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 130 | 139 | pathelementFunc, 0, 0); |
| 140 | + url_initialize(&sURI, "dir"); | |
| 131 | 141 | |
| 132 | 142 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 133 | 143 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 134 | 144 | |
| 135 | 145 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -141,58 +151,57 @@ | ||
| 141 | 151 | if( pM ){ |
| 142 | 152 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 143 | 153 | linkTrunk = trunkRid && rid != trunkRid; |
| 144 | 154 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 145 | 155 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 156 | + url_add_parameter(&sURI, "ci", zCI); | |
| 146 | 157 | }else{ |
| 147 | 158 | zCI = 0; |
| 148 | 159 | } |
| 149 | 160 | } |
| 150 | 161 | |
| 151 | 162 | /* Compute the title of the page */ |
| 152 | 163 | blob_zero(&dirname); |
| 153 | 164 | if( zD ){ |
| 165 | + url_add_parameter(&sURI, "name", zD); | |
| 154 | 166 | blob_append(&dirname, "in directory ", -1); |
| 155 | - hyperlinked_path(zD, &dirname, zCI); | |
| 167 | + hyperlinked_path(zD, &dirname, zCI, "dir", ""); | |
| 156 | 168 | zPrefix = mprintf("%s/", zD); |
| 157 | - if( linkTrunk ){ | |
| 158 | - style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk", | |
| 159 | - zD); | |
| 160 | - } | |
| 161 | - if ( linkTip ){ | |
| 162 | - style_submenu_element("Tip", "Tip", "%R/dir?name=%t&ci=tip", zD); | |
| 163 | - } | |
| 169 | + style_submenu_element("Top-Level", "Top-Level", "%s", | |
| 170 | + url_render(&sURI, "name", 0, 0, 0)); | |
| 164 | 171 | }else{ |
| 165 | 172 | blob_append(&dirname, "in the top-level directory", -1); |
| 166 | 173 | zPrefix = ""; |
| 167 | - if( linkTrunk ){ | |
| 168 | - style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk"); | |
| 169 | - } | |
| 170 | - if ( linkTip ){ | |
| 171 | - style_submenu_element("Tip", "Tip", "%R/dir?ci=tip"); | |
| 172 | - } | |
| 174 | + } | |
| 175 | + if( linkTrunk ){ | |
| 176 | + style_submenu_element("Trunk", "Trunk", "%s", | |
| 177 | + url_render(&sURI, "ci", "trunk", 0, 0)); | |
| 178 | + } | |
| 179 | + if( linkTip ){ | |
| 180 | + style_submenu_element("Tip", "Tip", "%s", | |
| 181 | + url_render(&sURI, "ci", "tip", 0, 0)); | |
| 173 | 182 | } |
| 174 | 183 | if( zCI ){ |
| 175 | 184 | char zShort[20]; |
| 176 | 185 | memcpy(zShort, zUuid, 10); |
| 177 | 186 | zShort[10] = 0; |
| 178 | 187 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 179 | 188 | @ %s(blob_str(&dirname))</h2> |
| 180 | 189 | zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); |
| 181 | - if( zD ){ | |
| 182 | - style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); | |
| 183 | - style_submenu_element("All", "All", "%R/dir?name=%t", zD); | |
| 184 | - }else{ | |
| 185 | - style_submenu_element("All", "All", "%R/dir"); | |
| 190 | + if( nD==0 ){ | |
| 186 | 191 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", |
| 187 | 192 | zUuid); |
| 188 | 193 | } |
| 189 | 194 | }else{ |
| 190 | 195 | @ <h2>The union of all files from all check-ins |
| 191 | 196 | @ %s(blob_str(&dirname))</h2> |
| 192 | 197 | zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); |
| 193 | 198 | } |
| 199 | + style_submenu_element("All", "All", "%s", | |
| 200 | + url_render(&sURI, "ci", 0, 0, 0)); | |
| 201 | + style_submenu_element("Tree-View", "Tree-View", "%s", | |
| 202 | + url_render(&sURI, "type", "tree", 0, 0)); | |
| 194 | 203 | |
| 195 | 204 | /* Compute the temporary table "localfiles" containing the names |
| 196 | 205 | ** of all files and subdirectories in the zD[] directory. |
| 197 | 206 | ** |
| 198 | 207 | ** Subdirectory names begin with "/". This causes them to sort |
| @@ -287,10 +296,417 @@ | ||
| 287 | 296 | db_finalize(&q); |
| 288 | 297 | manifest_destroy(pM); |
| 289 | 298 | @ </ul></td></tr></table> |
| 290 | 299 | style_footer(); |
| 291 | 300 | } |
| 301 | + | |
| 302 | +/* | |
| 303 | +** Objects used by the "tree" webpage. | |
| 304 | +*/ | |
| 305 | +typedef struct FileTreeNode FileTreeNode; | |
| 306 | +typedef struct FileTree FileTree; | |
| 307 | + | |
| 308 | +/* | |
| 309 | +** A single line of the file hierarchy | |
| 310 | +*/ | |
| 311 | +struct FileTreeNode { | |
| 312 | + FileTreeNode *pNext; /* Next line in sequence */ | |
| 313 | + FileTreeNode *pPrev; /* Previous line */ | |
| 314 | + FileTreeNode *pParent; /* Directory containing this line */ | |
| 315 | + char *zName; /* Name of this entry. The "tail" */ | |
| 316 | + char *zFullName; /* Full pathname of this entry */ | |
| 317 | + char *zUuid; /* SHA1 hash of this file. May be NULL. */ | |
| 318 | + unsigned nFullName; /* Length of zFullName */ | |
| 319 | + unsigned iLevel; /* Levels of parent directories */ | |
| 320 | + u8 isDir; /* True if there are children */ | |
| 321 | + u8 isLast; /* True if this is the last child of its parent */ | |
| 322 | +}; | |
| 323 | + | |
| 324 | +/* | |
| 325 | +** A complete file hierarchy | |
| 326 | +*/ | |
| 327 | +struct FileTree { | |
| 328 | + FileTreeNode *pFirst; /* First line of the list */ | |
| 329 | + FileTreeNode *pLast; /* Last line of the list */ | |
| 330 | +}; | |
| 331 | + | |
| 332 | +/* | |
| 333 | +** Add one or more new FileTreeNodes to the FileTree object so that the | |
| 334 | +** leaf object zPathname is at the end of the node list | |
| 335 | +*/ | |
| 336 | +static void tree_add_node( | |
| 337 | + FileTree *pTree, /* Tree into which nodes are added */ | |
| 338 | + const char *zPath, /* The full pathname of file to add */ | |
| 339 | + const char *zUuid /* UUID of the file. Might be NULL. */ | |
| 340 | +){ | |
| 341 | + int i; | |
| 342 | + FileTreeNode *pParent; | |
| 343 | + FileTreeNode *pChild; | |
| 344 | + | |
| 345 | + pChild = pTree->pLast; | |
| 346 | + pParent = pChild ? pChild->pParent : 0; | |
| 347 | + while( pParent!=0 && | |
| 348 | + ( strncmp(pParent->zFullName, zPath, pParent->nFullName)!=0 | |
| 349 | + || zPath[pParent->nFullName]!='/' ) | |
| 350 | + ){ | |
| 351 | + pChild = pParent; | |
| 352 | + pParent = pChild->pParent; | |
| 353 | + } | |
| 354 | + i = pParent ? pParent->nFullName+1 : 0; | |
| 355 | + if( pChild ) pChild->isLast = 0; | |
| 356 | + while( zPath[i] ){ | |
| 357 | + FileTreeNode *pNew; | |
| 358 | + int iStart = i; | |
| 359 | + int nByte; | |
| 360 | + while( zPath[i] && zPath[i]!='/' ){ i++; } | |
| 361 | + nByte = sizeof(*pNew) + i + 1; | |
| 362 | + if( zUuid!=0 && zPath[i]==0 ) nByte += UUID_SIZE+1; | |
| 363 | + pNew = fossil_malloc( nByte ); | |
| 364 | + pNew->zFullName = (char*)&pNew[1]; | |
| 365 | + memcpy(pNew->zFullName, zPath, i); | |
| 366 | + pNew->zFullName[i] = 0; | |
| 367 | + pNew->nFullName = i; | |
| 368 | + if( zUuid!=0 && zPath[i]==0 ){ | |
| 369 | + pNew->zUuid = pNew->zFullName + i + 1; | |
| 370 | + memcpy(pNew->zUuid, zUuid, UUID_SIZE+1); | |
| 371 | + }else{ | |
| 372 | + pNew->zUuid = 0; | |
| 373 | + } | |
| 374 | + pNew->zName = pNew->zFullName + iStart; | |
| 375 | + if( pTree->pLast ){ | |
| 376 | + pTree->pLast->pNext = pNew; | |
| 377 | + }else{ | |
| 378 | + pTree->pFirst = pNew; | |
| 379 | + } | |
| 380 | + pNew->pPrev = pTree->pLast; | |
| 381 | + pNew->pNext = 0; | |
| 382 | + pNew->pParent = pParent; | |
| 383 | + pTree->pLast = pNew; | |
| 384 | + pNew->iLevel = pParent ? pParent->iLevel+1 : 0; | |
| 385 | + pNew->isDir = zPath[i]=='/'; | |
| 386 | + pNew->isLast = 1; | |
| 387 | + while( zPath[i]=='/' ){ i++; } | |
| 388 | + pParent = pNew; | |
| 389 | + } | |
| 390 | +} | |
| 391 | + | |
| 392 | +/* | |
| 393 | +** WEBPAGE: tree | |
| 394 | +** | |
| 395 | +** Query parameters: | |
| 396 | +** | |
| 397 | +** name=PATH Directory to display. Optional | |
| 398 | +** ci=LABEL Show only files in this check-in. Optional. | |
| 399 | +** re=REGEXP Show only files matching REGEXP. Optional. | |
| 400 | +** expand Begin with the tree fully expanded. | |
| 401 | +** nofiles Show directories (folders) only. Omit files. | |
| 402 | +*/ | |
| 403 | +void page_tree(void){ | |
| 404 | + char *zD = fossil_strdup(P("name")); | |
| 405 | + int nD = zD ? strlen(zD)+1 : 0; | |
| 406 | + const char *zCI = P("ci"); | |
| 407 | + int rid = 0; | |
| 408 | + char *zUuid = 0; | |
| 409 | + Blob dirname; | |
| 410 | + Manifest *pM = 0; | |
| 411 | + int nFile = 0; /* Number of files (or folders with "nofiles") */ | |
| 412 | + int linkTrunk = 1; /* include link to "trunk" */ | |
| 413 | + int linkTip = 1; /* include link to "tip" */ | |
| 414 | + const char *zRE; /* the value for the re=REGEXP query parameter */ | |
| 415 | + const char *zObjType; /* "files" by default or "folders" for "nofiles" */ | |
| 416 | + char *zREx = ""; /* Extra parameters for path hyperlinks */ | |
| 417 | + ReCompiled *pRE = 0; /* Compiled regular expression */ | |
| 418 | + FileTreeNode *p; /* One line of the tree */ | |
| 419 | + FileTree sTree; /* The complete tree of files */ | |
| 420 | + HQuery sURI; /* Hyperlink */ | |
| 421 | + int startExpanded; /* True to start out with the tree expanded */ | |
| 422 | + int showDirOnly; /* Show directories only. Omit files */ | |
| 423 | + int nDir = 0; /* Number of directories. Used for ID attributes */ | |
| 424 | + char *zProjectName = db_get("project-name", 0); | |
| 425 | + | |
| 426 | + if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; } | |
| 427 | + memset(&sTree, 0, sizeof(sTree)); | |
| 428 | + login_check_credentials(); | |
| 429 | + if( !g.perm.Read ){ login_needed(); return; } | |
| 430 | + while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } | |
| 431 | + sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, | |
| 432 | + pathelementFunc, 0, 0); | |
| 433 | + url_initialize(&sURI, "tree"); | |
| 434 | + if( P("nofiles")!=0 ){ | |
| 435 | + showDirOnly = 1; | |
| 436 | + url_add_parameter(&sURI, "nofiles", "1"); | |
| 437 | + style_header("Folder Hierarchy"); | |
| 438 | + }else{ | |
| 439 | + showDirOnly = 0; | |
| 440 | + style_header("File Tree"); | |
| 441 | + } | |
| 442 | + if( P("expand")!=0 ){ | |
| 443 | + startExpanded = 1; | |
| 444 | + url_add_parameter(&sURI, "expand", "1"); | |
| 445 | + }else{ | |
| 446 | + startExpanded = 0; | |
| 447 | + } | |
| 448 | + | |
| 449 | + /* If a regular expression is specified, compile it */ | |
| 450 | + zRE = P("re"); | |
| 451 | + if( zRE ){ | |
| 452 | + re_compile(&pRE, zRE, 0); | |
| 453 | + url_add_parameter(&sURI, "re", zRE); | |
| 454 | + zREx = mprintf("&re=%T", zRE); | |
| 455 | + } | |
| 456 | + | |
| 457 | + /* If the name= parameter is an empty string, make it a NULL pointer */ | |
| 458 | + if( zD && strlen(zD)==0 ){ zD = 0; } | |
| 459 | + | |
| 460 | + /* If a specific check-in is requested, fetch and parse it. If the | |
| 461 | + ** specific check-in does not exist, clear zCI. zCI==0 will cause all | |
| 462 | + ** files from all check-ins to be displayed. | |
| 463 | + */ | |
| 464 | + if( zCI ){ | |
| 465 | + pM = manifest_get_by_name(zCI, &rid); | |
| 466 | + if( pM ){ | |
| 467 | + int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); | |
| 468 | + linkTrunk = trunkRid && rid != trunkRid; | |
| 469 | + linkTip = rid != symbolic_name_to_rid("tip", "ci"); | |
| 470 | + zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 471 | + url_add_parameter(&sURI, "ci", zCI); | |
| 472 | + }else{ | |
| 473 | + zCI = 0; | |
| 474 | + } | |
| 475 | + } | |
| 476 | + | |
| 477 | + /* Compute the title of the page */ | |
| 478 | + blob_zero(&dirname); | |
| 479 | + if( zD ){ | |
| 480 | + url_add_parameter(&sURI, "name", zD); | |
| 481 | + blob_append(&dirname, "within directory ", -1); | |
| 482 | + hyperlinked_path(zD, &dirname, zCI, "tree", zREx); | |
| 483 | + if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE); | |
| 484 | + style_submenu_element("Top-Level", "Top-Level", "%s", | |
| 485 | + url_render(&sURI, "name", 0, 0, 0)); | |
| 486 | + }else{ | |
| 487 | + if( zRE ){ | |
| 488 | + blob_appendf(&dirname, "matching \"%s\"", zRE); | |
| 489 | + } | |
| 490 | + } | |
| 491 | + if( zCI ){ | |
| 492 | + style_submenu_element("All", "All", "%s", | |
| 493 | + url_render(&sURI, "ci", 0, 0, 0)); | |
| 494 | + if( nD==0 && !showDirOnly ){ | |
| 495 | + style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", | |
| 496 | + zUuid); | |
| 497 | + } | |
| 498 | + } | |
| 499 | + if( linkTrunk ){ | |
| 500 | + style_submenu_element("Trunk", "Trunk", "%s", | |
| 501 | + url_render(&sURI, "ci", "trunk", 0, 0)); | |
| 502 | + } | |
| 503 | + if ( linkTip ){ | |
| 504 | + style_submenu_element("Tip", "Tip", "%s", | |
| 505 | + url_render(&sURI, "ci", "tip", 0, 0)); | |
| 506 | + } | |
| 507 | + if( !showDirOnly ){ | |
| 508 | + style_submenu_element("Flat-View", "Flat-View", "%s", | |
| 509 | + url_render(&sURI, "type", "flat", 0, 0)); | |
| 510 | + } | |
| 511 | + | |
| 512 | + /* Compute the file hierarchy. | |
| 513 | + */ | |
| 514 | + if( zCI ){ | |
| 515 | + Stmt ins, q; | |
| 516 | + ManifestFile *pFile; | |
| 517 | + | |
| 518 | + db_multi_exec( | |
| 519 | + "CREATE TEMP TABLE filelist(" | |
| 520 | + " x TEXT PRIMARY KEY COLLATE nocase," | |
| 521 | + " uuid TEXT" | |
| 522 | + ")%s;", | |
| 523 | + /* Can be removed as soon as SQLite 3.8.2 is sufficiently wide-spread */ | |
| 524 | + sqlite3_libversion_number()>=3008002 ? " WITHOUT ROWID" : "" | |
| 525 | + ); | |
| 526 | + db_prepare(&ins, "INSERT OR IGNORE INTO filelist VALUES(:f,:u)"); | |
| 527 | + manifest_file_rewind(pM); | |
| 528 | + while( (pFile = manifest_file_next(pM,0))!=0 ){ | |
| 529 | + if( nD>0 | |
| 530 | + && (fossil_strncmp(pFile->zName, zD, nD-1)!=0 | |
| 531 | + || pFile->zName[nD-1]!='/') | |
| 532 | + ){ | |
| 533 | + continue; | |
| 534 | + } | |
| 535 | + if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue; | |
| 536 | + db_bind_text(&ins, ":f", pFile->zName); | |
| 537 | + db_bind_text(&ins, ":u", pFile->zUuid); | |
| 538 | + db_step(&ins); | |
| 539 | + db_reset(&ins); | |
| 540 | + } | |
| 541 | + db_finalize(&ins); | |
| 542 | + db_prepare(&q, "SELECT x, uuid FROM filelist ORDER BY x"); | |
| 543 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 544 | + tree_add_node(&sTree, db_column_text(&q,0), db_column_text(&q,1)); | |
| 545 | + nFile++; | |
| 546 | + } | |
| 547 | + db_finalize(&q); | |
| 548 | + }else{ | |
| 549 | + Stmt q; | |
| 550 | + db_prepare(&q, "SELECT name FROM filename ORDER BY name COLLATE nocase"); | |
| 551 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 552 | + const char *z = db_column_text(&q, 0); | |
| 553 | + if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){ | |
| 554 | + continue; | |
| 555 | + } | |
| 556 | + if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue; | |
| 557 | + tree_add_node(&sTree, z, 0); | |
| 558 | + nFile++; | |
| 559 | + } | |
| 560 | + db_finalize(&q); | |
| 561 | + } | |
| 562 | + | |
| 563 | + if( showDirOnly ){ | |
| 564 | + for(nFile=0, p=sTree.pFirst; p; p=p->pNext){ | |
| 565 | + if( p->isDir && p->nFullName>nD ) nFile++; | |
| 566 | + } | |
| 567 | + zObjType = "folders"; | |
| 568 | + style_submenu_element("Files","Files","%s", | |
| 569 | + url_render(&sURI,"nofiles",0,0,0)); | |
| 570 | + }else{ | |
| 571 | + zObjType = "files"; | |
| 572 | + style_submenu_element("Folders","Folders","%s", | |
| 573 | + url_render(&sURI,"nofiles","1",0,0)); | |
| 574 | + } | |
| 575 | + | |
| 576 | + if( zCI ){ | |
| 577 | + @ <h2>%d(nFile) %s(zObjType) of check-in | |
| 578 | + if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){ | |
| 579 | + @ "%h(zCI)" | |
| 580 | + } | |
| 581 | + @ [%z(href("vinfo?name=%T",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2> | |
| 582 | + }else{ | |
| 583 | + int n = db_int(0, "SELECT count(*) FROM plink"); | |
| 584 | + @ <h2>%d(nFile) %s(zObjType) from all %d(n) check-ins | |
| 585 | + @ %s(blob_str(&dirname))</h2> | |
| 586 | + } | |
| 587 | + | |
| 588 | + | |
| 589 | + /* Generate tree of lists. | |
| 590 | + ** | |
| 591 | + ** Each file and directory is a list element: <li>. Files have class=file | |
| 592 | + ** and if the filename as the suffix "xyz" the file also has class=file-xyz. | |
| 593 | + ** Directories have class=dir. The directory specfied by the name= query | |
| 594 | + ** parameter (or the top-level directory if there is no name= query parameter) | |
| 595 | + ** adds class=subdir. | |
| 596 | + ** | |
| 597 | + ** The <li> element for directories also contains a sublist <ul> | |
| 598 | + ** for the contents of that directory. | |
| 599 | + */ | |
| 600 | + @ <div class="filetree"><ul> | |
| 601 | + if( nD ){ | |
| 602 | + @ <li class="dir"> | |
| 603 | + }else{ | |
| 604 | + @ <li class="dir subdir"> | |
| 605 | + } | |
| 606 | + @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> | |
| 607 | + @ <ul> | |
| 608 | + for(p=sTree.pFirst, nDir=0; p; p=p->pNext){ | |
| 609 | + if( p->isDir ){ | |
| 610 | + if( p->nFullName==nD-1 ){ | |
| 611 | + @ <li class="dir subdir"> | |
| 612 | + }else{ | |
| 613 | + @ <li class="dir"> | |
| 614 | + } | |
| 615 | + @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> | |
| 616 | + if( startExpanded || p->nFullName<=nD ){ | |
| 617 | + @ <ul id="dir%d(nDir)"> | |
| 618 | + }else{ | |
| 619 | + @ <ul id="dir%d(nDir)" style='display:none;'> | |
| 620 | + } | |
| 621 | + nDir++; | |
| 622 | + }else if( !showDirOnly ){ | |
| 623 | + char *zLink; | |
| 624 | + if( zCI ){ | |
| 625 | + zLink = href("%R/artifact/%S",p->zUuid); | |
| 626 | + }else{ | |
| 627 | + zLink = href("%R/finfo?name=%T",p->zFullName); | |
| 628 | + } | |
| 629 | + @ <li class="%z(fileext_class(p->zName))">%z(zLink)%h(p->zName)</a> | |
| 630 | + } | |
| 631 | + if( p->isLast ){ | |
| 632 | + int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0); | |
| 633 | + while( nClose-- > 0 ){ | |
| 634 | + @ </ul> | |
| 635 | + } | |
| 636 | + } | |
| 637 | + } | |
| 638 | + @ </ul> | |
| 639 | + @ </ul></div> | |
| 640 | + @ <script>(function(){ | |
| 641 | + @ function isExpanded(ul){ | |
| 642 | + @ var display = window.getComputedStyle(ul).getPropertyValue('display'); | |
| 643 | + @ return display!='none'; | |
| 644 | + @ } | |
| 645 | + @ | |
| 646 | + @ function toggleDir(ul, useInitValue){ | |
| 647 | + @ if( !useInitValue ){ | |
| 648 | + @ expandMap[ul.id] = !isExpanded(ul); | |
| 649 | + @ history.replaceState(expandMap, ''); | |
| 650 | + @ } | |
| 651 | + @ ul.style.display = expandMap[ul.id] ? 'block' : 'none'; | |
| 652 | + @ } | |
| 653 | + @ | |
| 654 | + @ function toggleAll(tree, useInitValue){ | |
| 655 | + @ var lists = tree.querySelectorAll('.subdir > ul > li ul'); | |
| 656 | + @ if( !useInitValue ){ | |
| 657 | + @ var expand = true; /* Default action: make all sublists visible */ | |
| 658 | + @ for( var i=0; lists[i]; i++ ){ | |
| 659 | + @ if( isExpanded(lists[i]) ){ | |
| 660 | + @ expand = false; /* Any already visible - make them all hidden */ | |
| 661 | + @ break; | |
| 662 | + @ } | |
| 663 | + @ } | |
| 664 | + @ expandMap = {'*': expand}; | |
| 665 | + @ history.replaceState(expandMap, ''); | |
| 666 | + @ } | |
| 667 | + @ var display = expandMap['*'] ? 'block' : 'none'; | |
| 668 | + @ for( var i=0; lists[i]; i++ ){ | |
| 669 | + @ lists[i].style.display = display; | |
| 670 | + @ } | |
| 671 | + @ } | |
| 672 | + @ | |
| 673 | + @ function checkState(){ | |
| 674 | + @ expandMap = history.state || {}; | |
| 675 | + @ if( expandMap['*'] ) toggleAll(outer_ul, true); | |
| 676 | + @ for( var id in expandMap ){ | |
| 677 | + @ if( id!=='*' ) toggleDir(gebi(id), true); | |
| 678 | + @ } | |
| 679 | + @ } | |
| 680 | + @ | |
| 681 | + @ /* No-op shim for IE9 */ | |
| 682 | + @ if( !history.replaceState ) history.replaceState = function(){}; | |
| 683 | + @ var outer_ul = document.querySelector('.filetree > ul'); | |
| 684 | + @ var subdir = outer_ul.querySelector('.subdir'); | |
| 685 | + @ var expandMap = {}; | |
| 686 | + @ checkState(); | |
| 687 | + @ outer_ul.onclick = function(e){ | |
| 688 | + @ var a = e.target; | |
| 689 | + @ if( a.nodeName!='A' ) return true; | |
| 690 | + @ if( a.parentNode==subdir ){ | |
| 691 | + @ toggleAll(outer_ul); | |
| 692 | + @ return false; | |
| 693 | + @ } | |
| 694 | + @ if( !subdir.contains(a) ) return true; | |
| 695 | + @ var ul = a.nextSibling; | |
| 696 | + @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; | |
| 697 | + @ if( !ul ) return true; /* This is a file link, not a directory */ | |
| 698 | + @ toggleDir(ul); | |
| 699 | + @ return false; | |
| 700 | + @ } | |
| 701 | + @ }())</script> | |
| 702 | + style_footer(); | |
| 703 | + | |
| 704 | + /* We could free memory used by sTree here if we needed to. But | |
| 705 | + ** the process is about to exit, so doing so would not really accomplish | |
| 706 | + ** anything useful. */ | |
| 707 | +} | |
| 292 | 708 | |
| 293 | 709 | /* |
| 294 | 710 | ** Return a CSS class name based on the given filename's extension. |
| 295 | 711 | ** Result must be freed by the caller. |
| 296 | 712 | **/ |
| @@ -299,11 +715,11 @@ | ||
| 299 | 715 | const char *zExt = strrchr(zFilename, '.'); |
| 300 | 716 | int isExt = zExt && zExt!=zFilename && zExt[1]; |
| 301 | 717 | int i; |
| 302 | 718 | for( i=1; isExt && zExt[i]; i++ ) isExt &= fossil_isalnum(zExt[i]); |
| 303 | 719 | if( isExt ){ |
| 304 | - zClass = mprintf("file-%s", zExt+1); | |
| 720 | + zClass = mprintf("file file-%s", zExt+1); | |
| 305 | 721 | for ( i=5; zClass[i]; i++ ) zClass[i] = fossil_tolower(zClass[i]); |
| 306 | 722 | }else{ |
| 307 | 723 | zClass = mprintf("file"); |
| 308 | 724 | } |
| 309 | 725 | return zClass; |
| @@ -404,14 +820,15 @@ | ||
| 404 | 820 | if( zName==0 ) zName = "tip"; |
| 405 | 821 | rid = symbolic_name_to_rid(zName, "ci"); |
| 406 | 822 | if( rid==0 ){ |
| 407 | 823 | fossil_fatal("not a valid check-in: %s", zName); |
| 408 | 824 | } |
| 825 | + style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); | |
| 409 | 826 | style_header("File Ages", zName); |
| 410 | 827 | compute_fileage(rid); |
| 411 | 828 | baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 412 | - zBaseTime = db_text("","SELECT datetime(%.20g,'localtime')", baseTime); | |
| 829 | + zBaseTime = db_text("","SELECT datetime(%.20g%s)", baseTime, timeline_utc()); | |
| 413 | 830 | @ <h2>File Ages For Check-in |
| 414 | 831 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2> |
| 415 | 832 | @ |
| 416 | 833 | @ <p>The times given are relative to |
| 417 | 834 | @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the |
| 418 | 835 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -71,23 +71,29 @@ | |
| 71 | ** There is no hyperlink on the file element of the path. |
| 72 | ** |
| 73 | ** The computed string is appended to the pOut blob. pOut should |
| 74 | ** have already been initialized. |
| 75 | */ |
| 76 | void hyperlinked_path(const char *zPath, Blob *pOut, const char *zCI){ |
| 77 | int i, j; |
| 78 | char *zSep = ""; |
| 79 | |
| 80 | for(i=0; zPath[i]; i=j){ |
| 81 | for(j=i; zPath[j] && zPath[j]!='/'; j++){} |
| 82 | if( zPath[j] && g.perm.Hyperlink ){ |
| 83 | if( zCI ){ |
| 84 | char *zLink = href("%R/dir?ci=%S&name=%#T", zCI, j, zPath); |
| 85 | blob_appendf(pOut, "%s%z%#h</a>", |
| 86 | zSep, zLink, j-i, &zPath[i]); |
| 87 | }else{ |
| 88 | char *zLink = href("%R/dir?name=%#T", j, zPath); |
| 89 | blob_appendf(pOut, "%s%z%#h</a>", |
| 90 | zSep, zLink, j-i, &zPath[i]); |
| 91 | } |
| 92 | }else{ |
| 93 | blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); |
| @@ -101,11 +107,11 @@ | |
| 101 | /* |
| 102 | ** WEBPAGE: dir |
| 103 | ** |
| 104 | ** Query parameters: |
| 105 | ** |
| 106 | ** name=PATH Directory to display. Required. |
| 107 | ** ci=LABEL Show only files in this check-in. Optional. |
| 108 | */ |
| 109 | void page_dir(void){ |
| 110 | char *zD = fossil_strdup(P("name")); |
| 111 | int nD = zD ? strlen(zD)+1 : 0; |
| @@ -118,18 +124,22 @@ | |
| 118 | int rid = 0; |
| 119 | char *zUuid = 0; |
| 120 | Blob dirname; |
| 121 | Manifest *pM = 0; |
| 122 | const char *zSubdirLink; |
| 123 | int linkTrunk = 1, linkTip = 1; |
| 124 | |
| 125 | login_check_credentials(); |
| 126 | if( !g.perm.Read ){ login_needed(); return; } |
| 127 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 128 | style_header("File List"); |
| 129 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 130 | pathelementFunc, 0, 0); |
| 131 | |
| 132 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 133 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 134 | |
| 135 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -141,58 +151,57 @@ | |
| 141 | if( pM ){ |
| 142 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 143 | linkTrunk = trunkRid && rid != trunkRid; |
| 144 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 145 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 146 | }else{ |
| 147 | zCI = 0; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | /* Compute the title of the page */ |
| 152 | blob_zero(&dirname); |
| 153 | if( zD ){ |
| 154 | blob_append(&dirname, "in directory ", -1); |
| 155 | hyperlinked_path(zD, &dirname, zCI); |
| 156 | zPrefix = mprintf("%s/", zD); |
| 157 | if( linkTrunk ){ |
| 158 | style_submenu_element("Trunk", "Trunk", "%R/dir?name=%t&ci=trunk", |
| 159 | zD); |
| 160 | } |
| 161 | if ( linkTip ){ |
| 162 | style_submenu_element("Tip", "Tip", "%R/dir?name=%t&ci=tip", zD); |
| 163 | } |
| 164 | }else{ |
| 165 | blob_append(&dirname, "in the top-level directory", -1); |
| 166 | zPrefix = ""; |
| 167 | if( linkTrunk ){ |
| 168 | style_submenu_element("Trunk", "Trunk", "%R/dir?ci=trunk"); |
| 169 | } |
| 170 | if ( linkTip ){ |
| 171 | style_submenu_element("Tip", "Tip", "%R/dir?ci=tip"); |
| 172 | } |
| 173 | } |
| 174 | if( zCI ){ |
| 175 | char zShort[20]; |
| 176 | memcpy(zShort, zUuid, 10); |
| 177 | zShort[10] = 0; |
| 178 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 179 | @ %s(blob_str(&dirname))</h2> |
| 180 | zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); |
| 181 | if( zD ){ |
| 182 | style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid); |
| 183 | style_submenu_element("All", "All", "%R/dir?name=%t", zD); |
| 184 | }else{ |
| 185 | style_submenu_element("All", "All", "%R/dir"); |
| 186 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", |
| 187 | zUuid); |
| 188 | } |
| 189 | }else{ |
| 190 | @ <h2>The union of all files from all check-ins |
| 191 | @ %s(blob_str(&dirname))</h2> |
| 192 | zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); |
| 193 | } |
| 194 | |
| 195 | /* Compute the temporary table "localfiles" containing the names |
| 196 | ** of all files and subdirectories in the zD[] directory. |
| 197 | ** |
| 198 | ** Subdirectory names begin with "/". This causes them to sort |
| @@ -287,10 +296,417 @@ | |
| 287 | db_finalize(&q); |
| 288 | manifest_destroy(pM); |
| 289 | @ </ul></td></tr></table> |
| 290 | style_footer(); |
| 291 | } |
| 292 | |
| 293 | /* |
| 294 | ** Return a CSS class name based on the given filename's extension. |
| 295 | ** Result must be freed by the caller. |
| 296 | **/ |
| @@ -299,11 +715,11 @@ | |
| 299 | const char *zExt = strrchr(zFilename, '.'); |
| 300 | int isExt = zExt && zExt!=zFilename && zExt[1]; |
| 301 | int i; |
| 302 | for( i=1; isExt && zExt[i]; i++ ) isExt &= fossil_isalnum(zExt[i]); |
| 303 | if( isExt ){ |
| 304 | zClass = mprintf("file-%s", zExt+1); |
| 305 | for ( i=5; zClass[i]; i++ ) zClass[i] = fossil_tolower(zClass[i]); |
| 306 | }else{ |
| 307 | zClass = mprintf("file"); |
| 308 | } |
| 309 | return zClass; |
| @@ -404,14 +820,15 @@ | |
| 404 | if( zName==0 ) zName = "tip"; |
| 405 | rid = symbolic_name_to_rid(zName, "ci"); |
| 406 | if( rid==0 ){ |
| 407 | fossil_fatal("not a valid check-in: %s", zName); |
| 408 | } |
| 409 | style_header("File Ages", zName); |
| 410 | compute_fileage(rid); |
| 411 | baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 412 | zBaseTime = db_text("","SELECT datetime(%.20g,'localtime')", baseTime); |
| 413 | @ <h2>File Ages For Check-in |
| 414 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2> |
| 415 | @ |
| 416 | @ <p>The times given are relative to |
| 417 | @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the |
| 418 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -71,23 +71,29 @@ | |
| 71 | ** There is no hyperlink on the file element of the path. |
| 72 | ** |
| 73 | ** The computed string is appended to the pOut blob. pOut should |
| 74 | ** have already been initialized. |
| 75 | */ |
| 76 | void hyperlinked_path( |
| 77 | const char *zPath, /* Path to render */ |
| 78 | Blob *pOut, /* Write into this blob */ |
| 79 | const char *zCI, /* check-in name, or NULL */ |
| 80 | const char *zURI, /* "dir" or "tree" */ |
| 81 | const char *zREx /* Extra query parameters */ |
| 82 | ){ |
| 83 | int i, j; |
| 84 | char *zSep = ""; |
| 85 | |
| 86 | for(i=0; zPath[i]; i=j){ |
| 87 | for(j=i; zPath[j] && zPath[j]!='/'; j++){} |
| 88 | if( zPath[j] && g.perm.Hyperlink ){ |
| 89 | if( zCI ){ |
| 90 | char *zLink = href("%R/%s?ci=%S&name=%#T%s", zURI, zCI, j, zPath,zREx); |
| 91 | blob_appendf(pOut, "%s%z%#h</a>", |
| 92 | zSep, zLink, j-i, &zPath[i]); |
| 93 | }else{ |
| 94 | char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx); |
| 95 | blob_appendf(pOut, "%s%z%#h</a>", |
| 96 | zSep, zLink, j-i, &zPath[i]); |
| 97 | } |
| 98 | }else{ |
| 99 | blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); |
| @@ -101,11 +107,11 @@ | |
| 107 | /* |
| 108 | ** WEBPAGE: dir |
| 109 | ** |
| 110 | ** Query parameters: |
| 111 | ** |
| 112 | ** name=PATH Directory to display. Optional. Top-level if missing |
| 113 | ** ci=LABEL Show only files in this check-in. Optional. |
| 114 | */ |
| 115 | void page_dir(void){ |
| 116 | char *zD = fossil_strdup(P("name")); |
| 117 | int nD = zD ? strlen(zD)+1 : 0; |
| @@ -118,18 +124,22 @@ | |
| 124 | int rid = 0; |
| 125 | char *zUuid = 0; |
| 126 | Blob dirname; |
| 127 | Manifest *pM = 0; |
| 128 | const char *zSubdirLink; |
| 129 | int linkTrunk = 1; |
| 130 | int linkTip = 1; |
| 131 | HQuery sURI; |
| 132 | |
| 133 | if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; } |
| 134 | login_check_credentials(); |
| 135 | if( !g.perm.Read ){ login_needed(); return; } |
| 136 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 137 | style_header("File List"); |
| 138 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 139 | pathelementFunc, 0, 0); |
| 140 | url_initialize(&sURI, "dir"); |
| 141 | |
| 142 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 143 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 144 | |
| 145 | /* If a specific check-in is requested, fetch and parse it. If the |
| @@ -141,58 +151,57 @@ | |
| 151 | if( pM ){ |
| 152 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 153 | linkTrunk = trunkRid && rid != trunkRid; |
| 154 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 155 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 156 | url_add_parameter(&sURI, "ci", zCI); |
| 157 | }else{ |
| 158 | zCI = 0; |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | /* Compute the title of the page */ |
| 163 | blob_zero(&dirname); |
| 164 | if( zD ){ |
| 165 | url_add_parameter(&sURI, "name", zD); |
| 166 | blob_append(&dirname, "in directory ", -1); |
| 167 | hyperlinked_path(zD, &dirname, zCI, "dir", ""); |
| 168 | zPrefix = mprintf("%s/", zD); |
| 169 | style_submenu_element("Top-Level", "Top-Level", "%s", |
| 170 | url_render(&sURI, "name", 0, 0, 0)); |
| 171 | }else{ |
| 172 | blob_append(&dirname, "in the top-level directory", -1); |
| 173 | zPrefix = ""; |
| 174 | } |
| 175 | if( linkTrunk ){ |
| 176 | style_submenu_element("Trunk", "Trunk", "%s", |
| 177 | url_render(&sURI, "ci", "trunk", 0, 0)); |
| 178 | } |
| 179 | if( linkTip ){ |
| 180 | style_submenu_element("Tip", "Tip", "%s", |
| 181 | url_render(&sURI, "ci", "tip", 0, 0)); |
| 182 | } |
| 183 | if( zCI ){ |
| 184 | char zShort[20]; |
| 185 | memcpy(zShort, zUuid, 10); |
| 186 | zShort[10] = 0; |
| 187 | @ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>] |
| 188 | @ %s(blob_str(&dirname))</h2> |
| 189 | zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix); |
| 190 | if( nD==0 ){ |
| 191 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", |
| 192 | zUuid); |
| 193 | } |
| 194 | }else{ |
| 195 | @ <h2>The union of all files from all check-ins |
| 196 | @ %s(blob_str(&dirname))</h2> |
| 197 | zSubdirLink = mprintf("%R/dir?name=%T", zPrefix); |
| 198 | } |
| 199 | style_submenu_element("All", "All", "%s", |
| 200 | url_render(&sURI, "ci", 0, 0, 0)); |
| 201 | style_submenu_element("Tree-View", "Tree-View", "%s", |
| 202 | url_render(&sURI, "type", "tree", 0, 0)); |
| 203 | |
| 204 | /* Compute the temporary table "localfiles" containing the names |
| 205 | ** of all files and subdirectories in the zD[] directory. |
| 206 | ** |
| 207 | ** Subdirectory names begin with "/". This causes them to sort |
| @@ -287,10 +296,417 @@ | |
| 296 | db_finalize(&q); |
| 297 | manifest_destroy(pM); |
| 298 | @ </ul></td></tr></table> |
| 299 | style_footer(); |
| 300 | } |
| 301 | |
| 302 | /* |
| 303 | ** Objects used by the "tree" webpage. |
| 304 | */ |
| 305 | typedef struct FileTreeNode FileTreeNode; |
| 306 | typedef struct FileTree FileTree; |
| 307 | |
| 308 | /* |
| 309 | ** A single line of the file hierarchy |
| 310 | */ |
| 311 | struct FileTreeNode { |
| 312 | FileTreeNode *pNext; /* Next line in sequence */ |
| 313 | FileTreeNode *pPrev; /* Previous line */ |
| 314 | FileTreeNode *pParent; /* Directory containing this line */ |
| 315 | char *zName; /* Name of this entry. The "tail" */ |
| 316 | char *zFullName; /* Full pathname of this entry */ |
| 317 | char *zUuid; /* SHA1 hash of this file. May be NULL. */ |
| 318 | unsigned nFullName; /* Length of zFullName */ |
| 319 | unsigned iLevel; /* Levels of parent directories */ |
| 320 | u8 isDir; /* True if there are children */ |
| 321 | u8 isLast; /* True if this is the last child of its parent */ |
| 322 | }; |
| 323 | |
| 324 | /* |
| 325 | ** A complete file hierarchy |
| 326 | */ |
| 327 | struct FileTree { |
| 328 | FileTreeNode *pFirst; /* First line of the list */ |
| 329 | FileTreeNode *pLast; /* Last line of the list */ |
| 330 | }; |
| 331 | |
| 332 | /* |
| 333 | ** Add one or more new FileTreeNodes to the FileTree object so that the |
| 334 | ** leaf object zPathname is at the end of the node list |
| 335 | */ |
| 336 | static void tree_add_node( |
| 337 | FileTree *pTree, /* Tree into which nodes are added */ |
| 338 | const char *zPath, /* The full pathname of file to add */ |
| 339 | const char *zUuid /* UUID of the file. Might be NULL. */ |
| 340 | ){ |
| 341 | int i; |
| 342 | FileTreeNode *pParent; |
| 343 | FileTreeNode *pChild; |
| 344 | |
| 345 | pChild = pTree->pLast; |
| 346 | pParent = pChild ? pChild->pParent : 0; |
| 347 | while( pParent!=0 && |
| 348 | ( strncmp(pParent->zFullName, zPath, pParent->nFullName)!=0 |
| 349 | || zPath[pParent->nFullName]!='/' ) |
| 350 | ){ |
| 351 | pChild = pParent; |
| 352 | pParent = pChild->pParent; |
| 353 | } |
| 354 | i = pParent ? pParent->nFullName+1 : 0; |
| 355 | if( pChild ) pChild->isLast = 0; |
| 356 | while( zPath[i] ){ |
| 357 | FileTreeNode *pNew; |
| 358 | int iStart = i; |
| 359 | int nByte; |
| 360 | while( zPath[i] && zPath[i]!='/' ){ i++; } |
| 361 | nByte = sizeof(*pNew) + i + 1; |
| 362 | if( zUuid!=0 && zPath[i]==0 ) nByte += UUID_SIZE+1; |
| 363 | pNew = fossil_malloc( nByte ); |
| 364 | pNew->zFullName = (char*)&pNew[1]; |
| 365 | memcpy(pNew->zFullName, zPath, i); |
| 366 | pNew->zFullName[i] = 0; |
| 367 | pNew->nFullName = i; |
| 368 | if( zUuid!=0 && zPath[i]==0 ){ |
| 369 | pNew->zUuid = pNew->zFullName + i + 1; |
| 370 | memcpy(pNew->zUuid, zUuid, UUID_SIZE+1); |
| 371 | }else{ |
| 372 | pNew->zUuid = 0; |
| 373 | } |
| 374 | pNew->zName = pNew->zFullName + iStart; |
| 375 | if( pTree->pLast ){ |
| 376 | pTree->pLast->pNext = pNew; |
| 377 | }else{ |
| 378 | pTree->pFirst = pNew; |
| 379 | } |
| 380 | pNew->pPrev = pTree->pLast; |
| 381 | pNew->pNext = 0; |
| 382 | pNew->pParent = pParent; |
| 383 | pTree->pLast = pNew; |
| 384 | pNew->iLevel = pParent ? pParent->iLevel+1 : 0; |
| 385 | pNew->isDir = zPath[i]=='/'; |
| 386 | pNew->isLast = 1; |
| 387 | while( zPath[i]=='/' ){ i++; } |
| 388 | pParent = pNew; |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | /* |
| 393 | ** WEBPAGE: tree |
| 394 | ** |
| 395 | ** Query parameters: |
| 396 | ** |
| 397 | ** name=PATH Directory to display. Optional |
| 398 | ** ci=LABEL Show only files in this check-in. Optional. |
| 399 | ** re=REGEXP Show only files matching REGEXP. Optional. |
| 400 | ** expand Begin with the tree fully expanded. |
| 401 | ** nofiles Show directories (folders) only. Omit files. |
| 402 | */ |
| 403 | void page_tree(void){ |
| 404 | char *zD = fossil_strdup(P("name")); |
| 405 | int nD = zD ? strlen(zD)+1 : 0; |
| 406 | const char *zCI = P("ci"); |
| 407 | int rid = 0; |
| 408 | char *zUuid = 0; |
| 409 | Blob dirname; |
| 410 | Manifest *pM = 0; |
| 411 | int nFile = 0; /* Number of files (or folders with "nofiles") */ |
| 412 | int linkTrunk = 1; /* include link to "trunk" */ |
| 413 | int linkTip = 1; /* include link to "tip" */ |
| 414 | const char *zRE; /* the value for the re=REGEXP query parameter */ |
| 415 | const char *zObjType; /* "files" by default or "folders" for "nofiles" */ |
| 416 | char *zREx = ""; /* Extra parameters for path hyperlinks */ |
| 417 | ReCompiled *pRE = 0; /* Compiled regular expression */ |
| 418 | FileTreeNode *p; /* One line of the tree */ |
| 419 | FileTree sTree; /* The complete tree of files */ |
| 420 | HQuery sURI; /* Hyperlink */ |
| 421 | int startExpanded; /* True to start out with the tree expanded */ |
| 422 | int showDirOnly; /* Show directories only. Omit files */ |
| 423 | int nDir = 0; /* Number of directories. Used for ID attributes */ |
| 424 | char *zProjectName = db_get("project-name", 0); |
| 425 | |
| 426 | if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; } |
| 427 | memset(&sTree, 0, sizeof(sTree)); |
| 428 | login_check_credentials(); |
| 429 | if( !g.perm.Read ){ login_needed(); return; } |
| 430 | while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; } |
| 431 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| 432 | pathelementFunc, 0, 0); |
| 433 | url_initialize(&sURI, "tree"); |
| 434 | if( P("nofiles")!=0 ){ |
| 435 | showDirOnly = 1; |
| 436 | url_add_parameter(&sURI, "nofiles", "1"); |
| 437 | style_header("Folder Hierarchy"); |
| 438 | }else{ |
| 439 | showDirOnly = 0; |
| 440 | style_header("File Tree"); |
| 441 | } |
| 442 | if( P("expand")!=0 ){ |
| 443 | startExpanded = 1; |
| 444 | url_add_parameter(&sURI, "expand", "1"); |
| 445 | }else{ |
| 446 | startExpanded = 0; |
| 447 | } |
| 448 | |
| 449 | /* If a regular expression is specified, compile it */ |
| 450 | zRE = P("re"); |
| 451 | if( zRE ){ |
| 452 | re_compile(&pRE, zRE, 0); |
| 453 | url_add_parameter(&sURI, "re", zRE); |
| 454 | zREx = mprintf("&re=%T", zRE); |
| 455 | } |
| 456 | |
| 457 | /* If the name= parameter is an empty string, make it a NULL pointer */ |
| 458 | if( zD && strlen(zD)==0 ){ zD = 0; } |
| 459 | |
| 460 | /* If a specific check-in is requested, fetch and parse it. If the |
| 461 | ** specific check-in does not exist, clear zCI. zCI==0 will cause all |
| 462 | ** files from all check-ins to be displayed. |
| 463 | */ |
| 464 | if( zCI ){ |
| 465 | pM = manifest_get_by_name(zCI, &rid); |
| 466 | if( pM ){ |
| 467 | int trunkRid = symbolic_name_to_rid("tag:trunk", "ci"); |
| 468 | linkTrunk = trunkRid && rid != trunkRid; |
| 469 | linkTip = rid != symbolic_name_to_rid("tip", "ci"); |
| 470 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 471 | url_add_parameter(&sURI, "ci", zCI); |
| 472 | }else{ |
| 473 | zCI = 0; |
| 474 | } |
| 475 | } |
| 476 | |
| 477 | /* Compute the title of the page */ |
| 478 | blob_zero(&dirname); |
| 479 | if( zD ){ |
| 480 | url_add_parameter(&sURI, "name", zD); |
| 481 | blob_append(&dirname, "within directory ", -1); |
| 482 | hyperlinked_path(zD, &dirname, zCI, "tree", zREx); |
| 483 | if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE); |
| 484 | style_submenu_element("Top-Level", "Top-Level", "%s", |
| 485 | url_render(&sURI, "name", 0, 0, 0)); |
| 486 | }else{ |
| 487 | if( zRE ){ |
| 488 | blob_appendf(&dirname, "matching \"%s\"", zRE); |
| 489 | } |
| 490 | } |
| 491 | if( zCI ){ |
| 492 | style_submenu_element("All", "All", "%s", |
| 493 | url_render(&sURI, "ci", 0, 0, 0)); |
| 494 | if( nD==0 && !showDirOnly ){ |
| 495 | style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S", |
| 496 | zUuid); |
| 497 | } |
| 498 | } |
| 499 | if( linkTrunk ){ |
| 500 | style_submenu_element("Trunk", "Trunk", "%s", |
| 501 | url_render(&sURI, "ci", "trunk", 0, 0)); |
| 502 | } |
| 503 | if ( linkTip ){ |
| 504 | style_submenu_element("Tip", "Tip", "%s", |
| 505 | url_render(&sURI, "ci", "tip", 0, 0)); |
| 506 | } |
| 507 | if( !showDirOnly ){ |
| 508 | style_submenu_element("Flat-View", "Flat-View", "%s", |
| 509 | url_render(&sURI, "type", "flat", 0, 0)); |
| 510 | } |
| 511 | |
| 512 | /* Compute the file hierarchy. |
| 513 | */ |
| 514 | if( zCI ){ |
| 515 | Stmt ins, q; |
| 516 | ManifestFile *pFile; |
| 517 | |
| 518 | db_multi_exec( |
| 519 | "CREATE TEMP TABLE filelist(" |
| 520 | " x TEXT PRIMARY KEY COLLATE nocase," |
| 521 | " uuid TEXT" |
| 522 | ")%s;", |
| 523 | /* Can be removed as soon as SQLite 3.8.2 is sufficiently wide-spread */ |
| 524 | sqlite3_libversion_number()>=3008002 ? " WITHOUT ROWID" : "" |
| 525 | ); |
| 526 | db_prepare(&ins, "INSERT OR IGNORE INTO filelist VALUES(:f,:u)"); |
| 527 | manifest_file_rewind(pM); |
| 528 | while( (pFile = manifest_file_next(pM,0))!=0 ){ |
| 529 | if( nD>0 |
| 530 | && (fossil_strncmp(pFile->zName, zD, nD-1)!=0 |
| 531 | || pFile->zName[nD-1]!='/') |
| 532 | ){ |
| 533 | continue; |
| 534 | } |
| 535 | if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue; |
| 536 | db_bind_text(&ins, ":f", pFile->zName); |
| 537 | db_bind_text(&ins, ":u", pFile->zUuid); |
| 538 | db_step(&ins); |
| 539 | db_reset(&ins); |
| 540 | } |
| 541 | db_finalize(&ins); |
| 542 | db_prepare(&q, "SELECT x, uuid FROM filelist ORDER BY x"); |
| 543 | while( db_step(&q)==SQLITE_ROW ){ |
| 544 | tree_add_node(&sTree, db_column_text(&q,0), db_column_text(&q,1)); |
| 545 | nFile++; |
| 546 | } |
| 547 | db_finalize(&q); |
| 548 | }else{ |
| 549 | Stmt q; |
| 550 | db_prepare(&q, "SELECT name FROM filename ORDER BY name COLLATE nocase"); |
| 551 | while( db_step(&q)==SQLITE_ROW ){ |
| 552 | const char *z = db_column_text(&q, 0); |
| 553 | if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){ |
| 554 | continue; |
| 555 | } |
| 556 | if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue; |
| 557 | tree_add_node(&sTree, z, 0); |
| 558 | nFile++; |
| 559 | } |
| 560 | db_finalize(&q); |
| 561 | } |
| 562 | |
| 563 | if( showDirOnly ){ |
| 564 | for(nFile=0, p=sTree.pFirst; p; p=p->pNext){ |
| 565 | if( p->isDir && p->nFullName>nD ) nFile++; |
| 566 | } |
| 567 | zObjType = "folders"; |
| 568 | style_submenu_element("Files","Files","%s", |
| 569 | url_render(&sURI,"nofiles",0,0,0)); |
| 570 | }else{ |
| 571 | zObjType = "files"; |
| 572 | style_submenu_element("Folders","Folders","%s", |
| 573 | url_render(&sURI,"nofiles","1",0,0)); |
| 574 | } |
| 575 | |
| 576 | if( zCI ){ |
| 577 | @ <h2>%d(nFile) %s(zObjType) of check-in |
| 578 | if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){ |
| 579 | @ "%h(zCI)" |
| 580 | } |
| 581 | @ [%z(href("vinfo?name=%T",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2> |
| 582 | }else{ |
| 583 | int n = db_int(0, "SELECT count(*) FROM plink"); |
| 584 | @ <h2>%d(nFile) %s(zObjType) from all %d(n) check-ins |
| 585 | @ %s(blob_str(&dirname))</h2> |
| 586 | } |
| 587 | |
| 588 | |
| 589 | /* Generate tree of lists. |
| 590 | ** |
| 591 | ** Each file and directory is a list element: <li>. Files have class=file |
| 592 | ** and if the filename as the suffix "xyz" the file also has class=file-xyz. |
| 593 | ** Directories have class=dir. The directory specfied by the name= query |
| 594 | ** parameter (or the top-level directory if there is no name= query parameter) |
| 595 | ** adds class=subdir. |
| 596 | ** |
| 597 | ** The <li> element for directories also contains a sublist <ul> |
| 598 | ** for the contents of that directory. |
| 599 | */ |
| 600 | @ <div class="filetree"><ul> |
| 601 | if( nD ){ |
| 602 | @ <li class="dir"> |
| 603 | }else{ |
| 604 | @ <li class="dir subdir"> |
| 605 | } |
| 606 | @ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a> |
| 607 | @ <ul> |
| 608 | for(p=sTree.pFirst, nDir=0; p; p=p->pNext){ |
| 609 | if( p->isDir ){ |
| 610 | if( p->nFullName==nD-1 ){ |
| 611 | @ <li class="dir subdir"> |
| 612 | }else{ |
| 613 | @ <li class="dir"> |
| 614 | } |
| 615 | @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a> |
| 616 | if( startExpanded || p->nFullName<=nD ){ |
| 617 | @ <ul id="dir%d(nDir)"> |
| 618 | }else{ |
| 619 | @ <ul id="dir%d(nDir)" style='display:none;'> |
| 620 | } |
| 621 | nDir++; |
| 622 | }else if( !showDirOnly ){ |
| 623 | char *zLink; |
| 624 | if( zCI ){ |
| 625 | zLink = href("%R/artifact/%S",p->zUuid); |
| 626 | }else{ |
| 627 | zLink = href("%R/finfo?name=%T",p->zFullName); |
| 628 | } |
| 629 | @ <li class="%z(fileext_class(p->zName))">%z(zLink)%h(p->zName)</a> |
| 630 | } |
| 631 | if( p->isLast ){ |
| 632 | int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0); |
| 633 | while( nClose-- > 0 ){ |
| 634 | @ </ul> |
| 635 | } |
| 636 | } |
| 637 | } |
| 638 | @ </ul> |
| 639 | @ </ul></div> |
| 640 | @ <script>(function(){ |
| 641 | @ function isExpanded(ul){ |
| 642 | @ var display = window.getComputedStyle(ul).getPropertyValue('display'); |
| 643 | @ return display!='none'; |
| 644 | @ } |
| 645 | @ |
| 646 | @ function toggleDir(ul, useInitValue){ |
| 647 | @ if( !useInitValue ){ |
| 648 | @ expandMap[ul.id] = !isExpanded(ul); |
| 649 | @ history.replaceState(expandMap, ''); |
| 650 | @ } |
| 651 | @ ul.style.display = expandMap[ul.id] ? 'block' : 'none'; |
| 652 | @ } |
| 653 | @ |
| 654 | @ function toggleAll(tree, useInitValue){ |
| 655 | @ var lists = tree.querySelectorAll('.subdir > ul > li ul'); |
| 656 | @ if( !useInitValue ){ |
| 657 | @ var expand = true; /* Default action: make all sublists visible */ |
| 658 | @ for( var i=0; lists[i]; i++ ){ |
| 659 | @ if( isExpanded(lists[i]) ){ |
| 660 | @ expand = false; /* Any already visible - make them all hidden */ |
| 661 | @ break; |
| 662 | @ } |
| 663 | @ } |
| 664 | @ expandMap = {'*': expand}; |
| 665 | @ history.replaceState(expandMap, ''); |
| 666 | @ } |
| 667 | @ var display = expandMap['*'] ? 'block' : 'none'; |
| 668 | @ for( var i=0; lists[i]; i++ ){ |
| 669 | @ lists[i].style.display = display; |
| 670 | @ } |
| 671 | @ } |
| 672 | @ |
| 673 | @ function checkState(){ |
| 674 | @ expandMap = history.state || {}; |
| 675 | @ if( expandMap['*'] ) toggleAll(outer_ul, true); |
| 676 | @ for( var id in expandMap ){ |
| 677 | @ if( id!=='*' ) toggleDir(gebi(id), true); |
| 678 | @ } |
| 679 | @ } |
| 680 | @ |
| 681 | @ /* No-op shim for IE9 */ |
| 682 | @ if( !history.replaceState ) history.replaceState = function(){}; |
| 683 | @ var outer_ul = document.querySelector('.filetree > ul'); |
| 684 | @ var subdir = outer_ul.querySelector('.subdir'); |
| 685 | @ var expandMap = {}; |
| 686 | @ checkState(); |
| 687 | @ outer_ul.onclick = function(e){ |
| 688 | @ var a = e.target; |
| 689 | @ if( a.nodeName!='A' ) return true; |
| 690 | @ if( a.parentNode==subdir ){ |
| 691 | @ toggleAll(outer_ul); |
| 692 | @ return false; |
| 693 | @ } |
| 694 | @ if( !subdir.contains(a) ) return true; |
| 695 | @ var ul = a.nextSibling; |
| 696 | @ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling; |
| 697 | @ if( !ul ) return true; /* This is a file link, not a directory */ |
| 698 | @ toggleDir(ul); |
| 699 | @ return false; |
| 700 | @ } |
| 701 | @ }())</script> |
| 702 | style_footer(); |
| 703 | |
| 704 | /* We could free memory used by sTree here if we needed to. But |
| 705 | ** the process is about to exit, so doing so would not really accomplish |
| 706 | ** anything useful. */ |
| 707 | } |
| 708 | |
| 709 | /* |
| 710 | ** Return a CSS class name based on the given filename's extension. |
| 711 | ** Result must be freed by the caller. |
| 712 | **/ |
| @@ -299,11 +715,11 @@ | |
| 715 | const char *zExt = strrchr(zFilename, '.'); |
| 716 | int isExt = zExt && zExt!=zFilename && zExt[1]; |
| 717 | int i; |
| 718 | for( i=1; isExt && zExt[i]; i++ ) isExt &= fossil_isalnum(zExt[i]); |
| 719 | if( isExt ){ |
| 720 | zClass = mprintf("file file-%s", zExt+1); |
| 721 | for ( i=5; zClass[i]; i++ ) zClass[i] = fossil_tolower(zClass[i]); |
| 722 | }else{ |
| 723 | zClass = mprintf("file"); |
| 724 | } |
| 725 | return zClass; |
| @@ -404,14 +820,15 @@ | |
| 820 | if( zName==0 ) zName = "tip"; |
| 821 | rid = symbolic_name_to_rid(zName, "ci"); |
| 822 | if( rid==0 ){ |
| 823 | fossil_fatal("not a valid check-in: %s", zName); |
| 824 | } |
| 825 | style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName); |
| 826 | style_header("File Ages", zName); |
| 827 | compute_fileage(rid); |
| 828 | baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 829 | zBaseTime = db_text("","SELECT datetime(%.20g%s)", baseTime, timeline_utc()); |
| 830 | @ <h2>File Ages For Check-in |
| 831 | @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2> |
| 832 | @ |
| 833 | @ <p>The times given are relative to |
| 834 | @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the |
| 835 |
+23
-8
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -301,13 +301,13 @@ | ||
| 301 | 301 | } |
| 302 | 302 | vfile_check_signature(vid, 0); |
| 303 | 303 | if( showAge ){ |
| 304 | 304 | db_prepare(&q, |
| 305 | 305 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," |
| 306 | - " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')" | |
| 306 | + " datetime(checkin_mtime(%d,rid),'unixepoch'%s)" | |
| 307 | 307 | " FROM vfile %s" |
| 308 | - " ORDER BY %s", vid, blob_str(&where), zOrderBy | |
| 308 | + " ORDER BY %s", vid, timeline_utc(), blob_str(&where), zOrderBy | |
| 309 | 309 | ); |
| 310 | 310 | }else{ |
| 311 | 311 | db_prepare(&q, |
| 312 | 312 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 313 | 313 | " FROM vfile %s" |
| @@ -817,10 +817,17 @@ | ||
| 817 | 817 | blob_append(&prompt, |
| 818 | 818 | "# PRIVATE BRANCH: This check-in will be private and will not sync to\n" |
| 819 | 819 | "# repositories.\n" |
| 820 | 820 | "#\n", -1 |
| 821 | 821 | ); |
| 822 | + } | |
| 823 | + if( p->integrateFlag ){ | |
| 824 | + blob_append(&prompt, | |
| 825 | + "#\n" | |
| 826 | + "# All merged-in branches will be closed due to the --integrate flag\n" | |
| 827 | + "#\n", -1 | |
| 828 | + ); | |
| 822 | 829 | } |
| 823 | 830 | prompt_for_user_comment(pComment, &prompt); |
| 824 | 831 | blob_reset(&prompt); |
| 825 | 832 | } |
| 826 | 833 | |
| @@ -955,10 +962,11 @@ | ||
| 955 | 962 | struct CheckinInfo { |
| 956 | 963 | Blob *pComment; /* Check-in comment text */ |
| 957 | 964 | const char *zMimetype; /* Mimetype of check-in command. May be NULL */ |
| 958 | 965 | int verifyDate; /* Verify that child is younger */ |
| 959 | 966 | int closeFlag; /* Close the branch being committed */ |
| 967 | + int integrateFlag; /* Close merged-in branches */ | |
| 960 | 968 | Blob *pCksum; /* Repository checksum. May be 0 */ |
| 961 | 969 | const char *zDateOvrd; /* Date override. If 0 then use 'now' */ |
| 962 | 970 | const char *zUserOvrd; /* User override. If 0 then use g.zLogin */ |
| 963 | 971 | const char *zBranch; /* Branch name. May be 0 */ |
| 964 | 972 | const char *zColor; /* One-time background color. May be 0 */ |
| @@ -1148,11 +1156,12 @@ | ||
| 1148 | 1156 | } |
| 1149 | 1157 | if( p->closeFlag ){ |
| 1150 | 1158 | blob_appendf(pOut, "T +closed *\n"); |
| 1151 | 1159 | } |
| 1152 | 1160 | db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" |
| 1153 | - " WHERE id=-4 ORDER BY 1"); | |
| 1161 | + " WHERE id %s ORDER BY 1", | |
| 1162 | + p->integrateFlag ? "IN(0,-4)" : "=(-4)"); | |
| 1154 | 1163 | while( db_step(&q)==SQLITE_ROW ){ |
| 1155 | 1164 | const char *zIntegrateUuid = db_column_text(&q, 0); |
| 1156 | 1165 | int rid = db_column_int(&q, 1); |
| 1157 | 1166 | if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref " |
| 1158 | 1167 | " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){ |
| @@ -1276,13 +1285,10 @@ | ||
| 1276 | 1285 | }else{ |
| 1277 | 1286 | if( encodingOk ){ |
| 1278 | 1287 | return 0; /* We don't want encoding warnings for this file. */ |
| 1279 | 1288 | } |
| 1280 | 1289 | zWarning = "Unicode"; |
| 1281 | -#if !defined(_WIN32) && !defined(__CYGWIN__) | |
| 1282 | - zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */ | |
| 1283 | -#endif | |
| 1284 | 1290 | zDisable = "\"encoding-glob\" setting"; |
| 1285 | 1291 | } |
| 1286 | 1292 | file_relative_name(zFilename, &fname, 0); |
| 1287 | 1293 | blob_zero(&ans); |
| 1288 | 1294 | zMsg = mprintf( |
| @@ -1377,11 +1383,14 @@ | ||
| 1377 | 1383 | ** allowed against a closed leaf. |
| 1378 | 1384 | ** |
| 1379 | 1385 | ** The --private option creates a private check-in that is never synced. |
| 1380 | 1386 | ** Children of private check-ins are automatically private. |
| 1381 | 1387 | ** |
| 1382 | -** the --tag option applies the symbolic tag name to the check-in. | |
| 1388 | +** The --tag option applies the symbolic tag name to the check-in. | |
| 1389 | +** | |
| 1390 | +** The --sha1sum option detects edited files by computing each file's | |
| 1391 | +** SHA1 hash rather than just checking for changes to its size or mtime. | |
| 1383 | 1392 | ** |
| 1384 | 1393 | ** Options: |
| 1385 | 1394 | ** --allow-conflict allow unresolved merge conflicts |
| 1386 | 1395 | ** --allow-empty allow a commit with no changes |
| 1387 | 1396 | ** --allow-fork allow the commit to fork |
| @@ -1390,17 +1399,20 @@ | ||
| 1390 | 1399 | ** --bgcolor COLOR apply COLOR to this one check-in only |
| 1391 | 1400 | ** --branch NEW-BRANCH-NAME check in to this new branch |
| 1392 | 1401 | ** --branchcolor COLOR apply given COLOR to the branch |
| 1393 | 1402 | ** --close close the branch being committed |
| 1394 | 1403 | ** --delta use a delta manifest in the commit process |
| 1404 | +** --integrate close all merged-in branches | |
| 1395 | 1405 | ** -m|--comment COMMENT-TEXT use COMMENT-TEXT as commit comment |
| 1396 | 1406 | ** -M|--message-file FILE read the commit comment from given file |
| 1397 | 1407 | ** --mimetype MIMETYPE mimetype of check-in comment |
| 1398 | 1408 | ** -n|--dry-run If given, display instead of run actions |
| 1399 | 1409 | ** --no-warnings omit all warnings about file contents |
| 1400 | 1410 | ** --nosign do not attempt to sign this commit with gpg |
| 1401 | 1411 | ** --private do not sync changes and their descendants |
| 1412 | +** --sha1sum verify file status using SHA1 hashing rather | |
| 1413 | +** than relying on file mtimes | |
| 1402 | 1414 | ** --tag TAG-NAME assign given tag TAG-NAME to the checkin |
| 1403 | 1415 | ** |
| 1404 | 1416 | ** See also: branch, changes, checkout, extra, sync |
| 1405 | 1417 | */ |
| 1406 | 1418 | void commit_cmd(void){ |
| @@ -1410,10 +1422,11 @@ | ||
| 1410 | 1422 | int nvid; /* Blob-id of the new check-in */ |
| 1411 | 1423 | Blob comment; /* Check-in comment */ |
| 1412 | 1424 | const char *zComment; /* Check-in comment */ |
| 1413 | 1425 | Stmt q; /* Various queries */ |
| 1414 | 1426 | char *zUuid; /* UUID of the new check-in */ |
| 1427 | + int useSha1sum = 0; /* True to verify file status using SHA1 hashing */ | |
| 1415 | 1428 | int noSign = 0; /* True to omit signing the manifest using GPG */ |
| 1416 | 1429 | int isAMerge = 0; /* True if checking in a merge */ |
| 1417 | 1430 | int noWarningFlag = 0; /* True if skipping all warnings */ |
| 1418 | 1431 | int forceFlag = 0; /* Undocumented: Disables all checks */ |
| 1419 | 1432 | int forceDelta = 0; /* Force a delta-manifest */ |
| @@ -1441,10 +1454,11 @@ | ||
| 1441 | 1454 | Blob ans; |
| 1442 | 1455 | char cReply; |
| 1443 | 1456 | |
| 1444 | 1457 | memset(&sCiInfo, 0, sizeof(sCiInfo)); |
| 1445 | 1458 | url_proxy_options(); |
| 1459 | + useSha1sum = find_option("sha1sum", 0, 0)!=0; | |
| 1446 | 1460 | noSign = find_option("nosign",0,0)!=0; |
| 1447 | 1461 | forceDelta = find_option("delta",0,0)!=0; |
| 1448 | 1462 | forceBaseline = find_option("baseline",0,0)!=0; |
| 1449 | 1463 | if( forceDelta && forceBaseline ){ |
| 1450 | 1464 | fossil_fatal("cannot use --delta and --baseline together"); |
| @@ -1462,10 +1476,11 @@ | ||
| 1462 | 1476 | noWarningFlag = find_option("no-warnings", 0, 0)!=0; |
| 1463 | 1477 | sCiInfo.zBranch = find_option("branch","b",1); |
| 1464 | 1478 | sCiInfo.zColor = find_option("bgcolor",0,1); |
| 1465 | 1479 | sCiInfo.zBrClr = find_option("branchcolor",0,1); |
| 1466 | 1480 | sCiInfo.closeFlag = find_option("close",0,0)!=0; |
| 1481 | + sCiInfo.integrateFlag = find_option("integrate",0,0)!=0; | |
| 1467 | 1482 | sCiInfo.zMimetype = find_option("mimetype",0,1); |
| 1468 | 1483 | while( (zTag = find_option("tag",0,1))!=0 ){ |
| 1469 | 1484 | if( zTag[0]==0 ) continue; |
| 1470 | 1485 | sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2)); |
| 1471 | 1486 | sCiInfo.azTag[nTag++] = zTag; |
| @@ -1586,11 +1601,11 @@ | ||
| 1586 | 1601 | */ |
| 1587 | 1602 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ |
| 1588 | 1603 | fossil_fatal("no such user: %s", g.zLogin); |
| 1589 | 1604 | } |
| 1590 | 1605 | |
| 1591 | - hasChanges = unsaved_changes(); | |
| 1606 | + hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0); | |
| 1592 | 1607 | db_begin_transaction(); |
| 1593 | 1608 | db_record_repository_filename(0); |
| 1594 | 1609 | if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){ |
| 1595 | 1610 | fossil_fatal("nothing has changed; use --allow-empty to override"); |
| 1596 | 1611 | } |
| 1597 | 1612 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -301,13 +301,13 @@ | |
| 301 | } |
| 302 | vfile_check_signature(vid, 0); |
| 303 | if( showAge ){ |
| 304 | db_prepare(&q, |
| 305 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," |
| 306 | " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')" |
| 307 | " FROM vfile %s" |
| 308 | " ORDER BY %s", vid, blob_str(&where), zOrderBy |
| 309 | ); |
| 310 | }else{ |
| 311 | db_prepare(&q, |
| 312 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 313 | " FROM vfile %s" |
| @@ -817,10 +817,17 @@ | |
| 817 | blob_append(&prompt, |
| 818 | "# PRIVATE BRANCH: This check-in will be private and will not sync to\n" |
| 819 | "# repositories.\n" |
| 820 | "#\n", -1 |
| 821 | ); |
| 822 | } |
| 823 | prompt_for_user_comment(pComment, &prompt); |
| 824 | blob_reset(&prompt); |
| 825 | } |
| 826 | |
| @@ -955,10 +962,11 @@ | |
| 955 | struct CheckinInfo { |
| 956 | Blob *pComment; /* Check-in comment text */ |
| 957 | const char *zMimetype; /* Mimetype of check-in command. May be NULL */ |
| 958 | int verifyDate; /* Verify that child is younger */ |
| 959 | int closeFlag; /* Close the branch being committed */ |
| 960 | Blob *pCksum; /* Repository checksum. May be 0 */ |
| 961 | const char *zDateOvrd; /* Date override. If 0 then use 'now' */ |
| 962 | const char *zUserOvrd; /* User override. If 0 then use g.zLogin */ |
| 963 | const char *zBranch; /* Branch name. May be 0 */ |
| 964 | const char *zColor; /* One-time background color. May be 0 */ |
| @@ -1148,11 +1156,12 @@ | |
| 1148 | } |
| 1149 | if( p->closeFlag ){ |
| 1150 | blob_appendf(pOut, "T +closed *\n"); |
| 1151 | } |
| 1152 | db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" |
| 1153 | " WHERE id=-4 ORDER BY 1"); |
| 1154 | while( db_step(&q)==SQLITE_ROW ){ |
| 1155 | const char *zIntegrateUuid = db_column_text(&q, 0); |
| 1156 | int rid = db_column_int(&q, 1); |
| 1157 | if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref " |
| 1158 | " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){ |
| @@ -1276,13 +1285,10 @@ | |
| 1276 | }else{ |
| 1277 | if( encodingOk ){ |
| 1278 | return 0; /* We don't want encoding warnings for this file. */ |
| 1279 | } |
| 1280 | zWarning = "Unicode"; |
| 1281 | #if !defined(_WIN32) && !defined(__CYGWIN__) |
| 1282 | zConvert = ""; /* On Unix, we cannot easily convert Unicode files. */ |
| 1283 | #endif |
| 1284 | zDisable = "\"encoding-glob\" setting"; |
| 1285 | } |
| 1286 | file_relative_name(zFilename, &fname, 0); |
| 1287 | blob_zero(&ans); |
| 1288 | zMsg = mprintf( |
| @@ -1377,11 +1383,14 @@ | |
| 1377 | ** allowed against a closed leaf. |
| 1378 | ** |
| 1379 | ** The --private option creates a private check-in that is never synced. |
| 1380 | ** Children of private check-ins are automatically private. |
| 1381 | ** |
| 1382 | ** the --tag option applies the symbolic tag name to the check-in. |
| 1383 | ** |
| 1384 | ** Options: |
| 1385 | ** --allow-conflict allow unresolved merge conflicts |
| 1386 | ** --allow-empty allow a commit with no changes |
| 1387 | ** --allow-fork allow the commit to fork |
| @@ -1390,17 +1399,20 @@ | |
| 1390 | ** --bgcolor COLOR apply COLOR to this one check-in only |
| 1391 | ** --branch NEW-BRANCH-NAME check in to this new branch |
| 1392 | ** --branchcolor COLOR apply given COLOR to the branch |
| 1393 | ** --close close the branch being committed |
| 1394 | ** --delta use a delta manifest in the commit process |
| 1395 | ** -m|--comment COMMENT-TEXT use COMMENT-TEXT as commit comment |
| 1396 | ** -M|--message-file FILE read the commit comment from given file |
| 1397 | ** --mimetype MIMETYPE mimetype of check-in comment |
| 1398 | ** -n|--dry-run If given, display instead of run actions |
| 1399 | ** --no-warnings omit all warnings about file contents |
| 1400 | ** --nosign do not attempt to sign this commit with gpg |
| 1401 | ** --private do not sync changes and their descendants |
| 1402 | ** --tag TAG-NAME assign given tag TAG-NAME to the checkin |
| 1403 | ** |
| 1404 | ** See also: branch, changes, checkout, extra, sync |
| 1405 | */ |
| 1406 | void commit_cmd(void){ |
| @@ -1410,10 +1422,11 @@ | |
| 1410 | int nvid; /* Blob-id of the new check-in */ |
| 1411 | Blob comment; /* Check-in comment */ |
| 1412 | const char *zComment; /* Check-in comment */ |
| 1413 | Stmt q; /* Various queries */ |
| 1414 | char *zUuid; /* UUID of the new check-in */ |
| 1415 | int noSign = 0; /* True to omit signing the manifest using GPG */ |
| 1416 | int isAMerge = 0; /* True if checking in a merge */ |
| 1417 | int noWarningFlag = 0; /* True if skipping all warnings */ |
| 1418 | int forceFlag = 0; /* Undocumented: Disables all checks */ |
| 1419 | int forceDelta = 0; /* Force a delta-manifest */ |
| @@ -1441,10 +1454,11 @@ | |
| 1441 | Blob ans; |
| 1442 | char cReply; |
| 1443 | |
| 1444 | memset(&sCiInfo, 0, sizeof(sCiInfo)); |
| 1445 | url_proxy_options(); |
| 1446 | noSign = find_option("nosign",0,0)!=0; |
| 1447 | forceDelta = find_option("delta",0,0)!=0; |
| 1448 | forceBaseline = find_option("baseline",0,0)!=0; |
| 1449 | if( forceDelta && forceBaseline ){ |
| 1450 | fossil_fatal("cannot use --delta and --baseline together"); |
| @@ -1462,10 +1476,11 @@ | |
| 1462 | noWarningFlag = find_option("no-warnings", 0, 0)!=0; |
| 1463 | sCiInfo.zBranch = find_option("branch","b",1); |
| 1464 | sCiInfo.zColor = find_option("bgcolor",0,1); |
| 1465 | sCiInfo.zBrClr = find_option("branchcolor",0,1); |
| 1466 | sCiInfo.closeFlag = find_option("close",0,0)!=0; |
| 1467 | sCiInfo.zMimetype = find_option("mimetype",0,1); |
| 1468 | while( (zTag = find_option("tag",0,1))!=0 ){ |
| 1469 | if( zTag[0]==0 ) continue; |
| 1470 | sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2)); |
| 1471 | sCiInfo.azTag[nTag++] = zTag; |
| @@ -1586,11 +1601,11 @@ | |
| 1586 | */ |
| 1587 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ |
| 1588 | fossil_fatal("no such user: %s", g.zLogin); |
| 1589 | } |
| 1590 | |
| 1591 | hasChanges = unsaved_changes(); |
| 1592 | db_begin_transaction(); |
| 1593 | db_record_repository_filename(0); |
| 1594 | if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){ |
| 1595 | fossil_fatal("nothing has changed; use --allow-empty to override"); |
| 1596 | } |
| 1597 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -301,13 +301,13 @@ | |
| 301 | } |
| 302 | vfile_check_signature(vid, 0); |
| 303 | if( showAge ){ |
| 304 | db_prepare(&q, |
| 305 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)," |
| 306 | " datetime(checkin_mtime(%d,rid),'unixepoch'%s)" |
| 307 | " FROM vfile %s" |
| 308 | " ORDER BY %s", vid, timeline_utc(), blob_str(&where), zOrderBy |
| 309 | ); |
| 310 | }else{ |
| 311 | db_prepare(&q, |
| 312 | "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)" |
| 313 | " FROM vfile %s" |
| @@ -817,10 +817,17 @@ | |
| 817 | blob_append(&prompt, |
| 818 | "# PRIVATE BRANCH: This check-in will be private and will not sync to\n" |
| 819 | "# repositories.\n" |
| 820 | "#\n", -1 |
| 821 | ); |
| 822 | } |
| 823 | if( p->integrateFlag ){ |
| 824 | blob_append(&prompt, |
| 825 | "#\n" |
| 826 | "# All merged-in branches will be closed due to the --integrate flag\n" |
| 827 | "#\n", -1 |
| 828 | ); |
| 829 | } |
| 830 | prompt_for_user_comment(pComment, &prompt); |
| 831 | blob_reset(&prompt); |
| 832 | } |
| 833 | |
| @@ -955,10 +962,11 @@ | |
| 962 | struct CheckinInfo { |
| 963 | Blob *pComment; /* Check-in comment text */ |
| 964 | const char *zMimetype; /* Mimetype of check-in command. May be NULL */ |
| 965 | int verifyDate; /* Verify that child is younger */ |
| 966 | int closeFlag; /* Close the branch being committed */ |
| 967 | int integrateFlag; /* Close merged-in branches */ |
| 968 | Blob *pCksum; /* Repository checksum. May be 0 */ |
| 969 | const char *zDateOvrd; /* Date override. If 0 then use 'now' */ |
| 970 | const char *zUserOvrd; /* User override. If 0 then use g.zLogin */ |
| 971 | const char *zBranch; /* Branch name. May be 0 */ |
| 972 | const char *zColor; /* One-time background color. May be 0 */ |
| @@ -1148,11 +1156,12 @@ | |
| 1156 | } |
| 1157 | if( p->closeFlag ){ |
| 1158 | blob_appendf(pOut, "T +closed *\n"); |
| 1159 | } |
| 1160 | db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid" |
| 1161 | " WHERE id %s ORDER BY 1", |
| 1162 | p->integrateFlag ? "IN(0,-4)" : "=(-4)"); |
| 1163 | while( db_step(&q)==SQLITE_ROW ){ |
| 1164 | const char *zIntegrateUuid = db_column_text(&q, 0); |
| 1165 | int rid = db_column_int(&q, 1); |
| 1166 | if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref " |
| 1167 | " WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){ |
| @@ -1276,13 +1285,10 @@ | |
| 1285 | }else{ |
| 1286 | if( encodingOk ){ |
| 1287 | return 0; /* We don't want encoding warnings for this file. */ |
| 1288 | } |
| 1289 | zWarning = "Unicode"; |
| 1290 | zDisable = "\"encoding-glob\" setting"; |
| 1291 | } |
| 1292 | file_relative_name(zFilename, &fname, 0); |
| 1293 | blob_zero(&ans); |
| 1294 | zMsg = mprintf( |
| @@ -1377,11 +1383,14 @@ | |
| 1383 | ** allowed against a closed leaf. |
| 1384 | ** |
| 1385 | ** The --private option creates a private check-in that is never synced. |
| 1386 | ** Children of private check-ins are automatically private. |
| 1387 | ** |
| 1388 | ** The --tag option applies the symbolic tag name to the check-in. |
| 1389 | ** |
| 1390 | ** The --sha1sum option detects edited files by computing each file's |
| 1391 | ** SHA1 hash rather than just checking for changes to its size or mtime. |
| 1392 | ** |
| 1393 | ** Options: |
| 1394 | ** --allow-conflict allow unresolved merge conflicts |
| 1395 | ** --allow-empty allow a commit with no changes |
| 1396 | ** --allow-fork allow the commit to fork |
| @@ -1390,17 +1399,20 @@ | |
| 1399 | ** --bgcolor COLOR apply COLOR to this one check-in only |
| 1400 | ** --branch NEW-BRANCH-NAME check in to this new branch |
| 1401 | ** --branchcolor COLOR apply given COLOR to the branch |
| 1402 | ** --close close the branch being committed |
| 1403 | ** --delta use a delta manifest in the commit process |
| 1404 | ** --integrate close all merged-in branches |
| 1405 | ** -m|--comment COMMENT-TEXT use COMMENT-TEXT as commit comment |
| 1406 | ** -M|--message-file FILE read the commit comment from given file |
| 1407 | ** --mimetype MIMETYPE mimetype of check-in comment |
| 1408 | ** -n|--dry-run If given, display instead of run actions |
| 1409 | ** --no-warnings omit all warnings about file contents |
| 1410 | ** --nosign do not attempt to sign this commit with gpg |
| 1411 | ** --private do not sync changes and their descendants |
| 1412 | ** --sha1sum verify file status using SHA1 hashing rather |
| 1413 | ** than relying on file mtimes |
| 1414 | ** --tag TAG-NAME assign given tag TAG-NAME to the checkin |
| 1415 | ** |
| 1416 | ** See also: branch, changes, checkout, extra, sync |
| 1417 | */ |
| 1418 | void commit_cmd(void){ |
| @@ -1410,10 +1422,11 @@ | |
| 1422 | int nvid; /* Blob-id of the new check-in */ |
| 1423 | Blob comment; /* Check-in comment */ |
| 1424 | const char *zComment; /* Check-in comment */ |
| 1425 | Stmt q; /* Various queries */ |
| 1426 | char *zUuid; /* UUID of the new check-in */ |
| 1427 | int useSha1sum = 0; /* True to verify file status using SHA1 hashing */ |
| 1428 | int noSign = 0; /* True to omit signing the manifest using GPG */ |
| 1429 | int isAMerge = 0; /* True if checking in a merge */ |
| 1430 | int noWarningFlag = 0; /* True if skipping all warnings */ |
| 1431 | int forceFlag = 0; /* Undocumented: Disables all checks */ |
| 1432 | int forceDelta = 0; /* Force a delta-manifest */ |
| @@ -1441,10 +1454,11 @@ | |
| 1454 | Blob ans; |
| 1455 | char cReply; |
| 1456 | |
| 1457 | memset(&sCiInfo, 0, sizeof(sCiInfo)); |
| 1458 | url_proxy_options(); |
| 1459 | useSha1sum = find_option("sha1sum", 0, 0)!=0; |
| 1460 | noSign = find_option("nosign",0,0)!=0; |
| 1461 | forceDelta = find_option("delta",0,0)!=0; |
| 1462 | forceBaseline = find_option("baseline",0,0)!=0; |
| 1463 | if( forceDelta && forceBaseline ){ |
| 1464 | fossil_fatal("cannot use --delta and --baseline together"); |
| @@ -1462,10 +1476,11 @@ | |
| 1476 | noWarningFlag = find_option("no-warnings", 0, 0)!=0; |
| 1477 | sCiInfo.zBranch = find_option("branch","b",1); |
| 1478 | sCiInfo.zColor = find_option("bgcolor",0,1); |
| 1479 | sCiInfo.zBrClr = find_option("branchcolor",0,1); |
| 1480 | sCiInfo.closeFlag = find_option("close",0,0)!=0; |
| 1481 | sCiInfo.integrateFlag = find_option("integrate",0,0)!=0; |
| 1482 | sCiInfo.zMimetype = find_option("mimetype",0,1); |
| 1483 | while( (zTag = find_option("tag",0,1))!=0 ){ |
| 1484 | if( zTag[0]==0 ) continue; |
| 1485 | sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2)); |
| 1486 | sCiInfo.azTag[nTag++] = zTag; |
| @@ -1586,11 +1601,11 @@ | |
| 1601 | */ |
| 1602 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ |
| 1603 | fossil_fatal("no such user: %s", g.zLogin); |
| 1604 | } |
| 1605 | |
| 1606 | hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0); |
| 1607 | db_begin_transaction(); |
| 1608 | db_record_repository_filename(0); |
| 1609 | if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){ |
| 1610 | fossil_fatal("nothing has changed; use --allow-empty to override"); |
| 1611 | } |
| 1612 |
+4
-4
| --- src/checkout.c | ||
| +++ src/checkout.c | ||
| @@ -28,16 +28,16 @@ | ||
| 28 | 28 | ** |
| 29 | 29 | ** 0: There is an existing checkout but it is unmodified |
| 30 | 30 | ** 1: There is a modified checkout - there are unsaved changes |
| 31 | 31 | ** 2: There is no existing checkout |
| 32 | 32 | */ |
| 33 | -int unsaved_changes(void){ | |
| 33 | +int unsaved_changes(unsigned int cksigFlags){ | |
| 34 | 34 | int vid; |
| 35 | 35 | db_must_be_within_tree(); |
| 36 | 36 | vid = db_lget_int("checkout",0); |
| 37 | 37 | if( vid==0 ) return 2; |
| 38 | - vfile_check_signature(vid, CKSIG_ENOTFILE); | |
| 38 | + vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE); | |
| 39 | 39 | return db_exists("SELECT 1 FROM vfile WHERE chnged" |
| 40 | 40 | " OR coalesce(origname!=pathname,0)"); |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | 43 | /* |
| @@ -200,11 +200,11 @@ | ||
| 200 | 200 | latestFlag = find_option("latest",0,0)!=0; |
| 201 | 201 | promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; |
| 202 | 202 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 203 | 203 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 204 | 204 | } |
| 205 | - if( !forceFlag && unsaved_changes()==1 ){ | |
| 205 | + if( !forceFlag && unsaved_changes(0)==1 ){ | |
| 206 | 206 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 207 | 207 | } |
| 208 | 208 | if( forceFlag ){ |
| 209 | 209 | db_multi_exec("DELETE FROM vfile"); |
| 210 | 210 | prior = 0; |
| @@ -288,11 +288,11 @@ | ||
| 288 | 288 | ** See also: open |
| 289 | 289 | */ |
| 290 | 290 | void close_cmd(void){ |
| 291 | 291 | int forceFlag = find_option("force","f",0)!=0; |
| 292 | 292 | db_must_be_within_tree(); |
| 293 | - if( !forceFlag && unsaved_changes()==1 ){ | |
| 293 | + if( !forceFlag && unsaved_changes(0)==1 ){ | |
| 294 | 294 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 295 | 295 | } |
| 296 | 296 | if( !forceFlag |
| 297 | 297 | && db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'", |
| 298 | 298 | db_name("localdb")) |
| 299 | 299 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -28,16 +28,16 @@ | |
| 28 | ** |
| 29 | ** 0: There is an existing checkout but it is unmodified |
| 30 | ** 1: There is a modified checkout - there are unsaved changes |
| 31 | ** 2: There is no existing checkout |
| 32 | */ |
| 33 | int unsaved_changes(void){ |
| 34 | int vid; |
| 35 | db_must_be_within_tree(); |
| 36 | vid = db_lget_int("checkout",0); |
| 37 | if( vid==0 ) return 2; |
| 38 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 39 | return db_exists("SELECT 1 FROM vfile WHERE chnged" |
| 40 | " OR coalesce(origname!=pathname,0)"); |
| 41 | } |
| 42 | |
| 43 | /* |
| @@ -200,11 +200,11 @@ | |
| 200 | latestFlag = find_option("latest",0,0)!=0; |
| 201 | promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; |
| 202 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 203 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 204 | } |
| 205 | if( !forceFlag && unsaved_changes()==1 ){ |
| 206 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 207 | } |
| 208 | if( forceFlag ){ |
| 209 | db_multi_exec("DELETE FROM vfile"); |
| 210 | prior = 0; |
| @@ -288,11 +288,11 @@ | |
| 288 | ** See also: open |
| 289 | */ |
| 290 | void close_cmd(void){ |
| 291 | int forceFlag = find_option("force","f",0)!=0; |
| 292 | db_must_be_within_tree(); |
| 293 | if( !forceFlag && unsaved_changes()==1 ){ |
| 294 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 295 | } |
| 296 | if( !forceFlag |
| 297 | && db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'", |
| 298 | db_name("localdb")) |
| 299 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -28,16 +28,16 @@ | |
| 28 | ** |
| 29 | ** 0: There is an existing checkout but it is unmodified |
| 30 | ** 1: There is a modified checkout - there are unsaved changes |
| 31 | ** 2: There is no existing checkout |
| 32 | */ |
| 33 | int unsaved_changes(unsigned int cksigFlags){ |
| 34 | int vid; |
| 35 | db_must_be_within_tree(); |
| 36 | vid = db_lget_int("checkout",0); |
| 37 | if( vid==0 ) return 2; |
| 38 | vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE); |
| 39 | return db_exists("SELECT 1 FROM vfile WHERE chnged" |
| 40 | " OR coalesce(origname!=pathname,0)"); |
| 41 | } |
| 42 | |
| 43 | /* |
| @@ -200,11 +200,11 @@ | |
| 200 | latestFlag = find_option("latest",0,0)!=0; |
| 201 | promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; |
| 202 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 203 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 204 | } |
| 205 | if( !forceFlag && unsaved_changes(0)==1 ){ |
| 206 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 207 | } |
| 208 | if( forceFlag ){ |
| 209 | db_multi_exec("DELETE FROM vfile"); |
| 210 | prior = 0; |
| @@ -288,11 +288,11 @@ | |
| 288 | ** See also: open |
| 289 | */ |
| 290 | void close_cmd(void){ |
| 291 | int forceFlag = find_option("force","f",0)!=0; |
| 292 | db_must_be_within_tree(); |
| 293 | if( !forceFlag && unsaved_changes(0)==1 ){ |
| 294 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 295 | } |
| 296 | if( !forceFlag |
| 297 | && db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'", |
| 298 | db_name("localdb")) |
| 299 |
M
src/db.c
+7
-4
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -315,10 +315,14 @@ | ||
| 315 | 315 | return sqlite3_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue); |
| 316 | 316 | } |
| 317 | 317 | int db_bind_text(Stmt *pStmt, const char *zParamName, const char *zValue){ |
| 318 | 318 | return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue, |
| 319 | 319 | -1, SQLITE_STATIC); |
| 320 | +} | |
| 321 | +int db_bind_text16(Stmt *pStmt, const char *zParamName, const char *zValue){ | |
| 322 | + return sqlite3_bind_text16(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue, | |
| 323 | + -1, SQLITE_STATIC); | |
| 320 | 324 | } |
| 321 | 325 | int db_bind_null(Stmt *pStmt, const char *zParamName){ |
| 322 | 326 | return sqlite3_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName)); |
| 323 | 327 | } |
| 324 | 328 | int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){ |
| @@ -942,18 +946,17 @@ | ||
| 942 | 946 | static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" }; |
| 943 | 947 | |
| 944 | 948 | if( g.localOpen) return 1; |
| 945 | 949 | file_getcwd(zPwd, sizeof(zPwd)-20); |
| 946 | 950 | n = strlen(zPwd); |
| 947 | - if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.'; | |
| 948 | 951 | while( n>0 ){ |
| 949 | 952 | for(i=0; i<count(aDbName); i++){ |
| 950 | 953 | sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]); |
| 951 | 954 | if( isValidLocalDb(zPwd) ){ |
| 952 | 955 | /* Found a valid checkout database file */ |
| 953 | 956 | zPwd[n] = 0; |
| 954 | - while( n>1 && zPwd[n-1]=='/' ){ | |
| 957 | + while( n>0 && zPwd[n-1]=='/' ){ | |
| 955 | 958 | n--; |
| 956 | 959 | zPwd[n] = 0; |
| 957 | 960 | } |
| 958 | 961 | g.zLocalRoot = mprintf("%s/", zPwd); |
| 959 | 962 | g.localOpen = 1; |
| @@ -961,12 +964,12 @@ | ||
| 961 | 964 | db_open_repository(zDbName); |
| 962 | 965 | return 1; |
| 963 | 966 | } |
| 964 | 967 | } |
| 965 | 968 | n--; |
| 966 | - while( n>0 && zPwd[n]!='/' ){ n--; } | |
| 967 | - while( n>0 && zPwd[n-1]=='/' ){ n--; } | |
| 969 | + while( n>1 && zPwd[n]!='/' ){ n--; } | |
| 970 | + while( n>1 && zPwd[n-1]=='/' ){ n--; } | |
| 968 | 971 | zPwd[n] = 0; |
| 969 | 972 | } |
| 970 | 973 | |
| 971 | 974 | /* A checkout database file could not be found */ |
| 972 | 975 | return 0; |
| 973 | 976 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -315,10 +315,14 @@ | |
| 315 | return sqlite3_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue); |
| 316 | } |
| 317 | int db_bind_text(Stmt *pStmt, const char *zParamName, const char *zValue){ |
| 318 | return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue, |
| 319 | -1, SQLITE_STATIC); |
| 320 | } |
| 321 | int db_bind_null(Stmt *pStmt, const char *zParamName){ |
| 322 | return sqlite3_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName)); |
| 323 | } |
| 324 | int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){ |
| @@ -942,18 +946,17 @@ | |
| 942 | static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" }; |
| 943 | |
| 944 | if( g.localOpen) return 1; |
| 945 | file_getcwd(zPwd, sizeof(zPwd)-20); |
| 946 | n = strlen(zPwd); |
| 947 | if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.'; |
| 948 | while( n>0 ){ |
| 949 | for(i=0; i<count(aDbName); i++){ |
| 950 | sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]); |
| 951 | if( isValidLocalDb(zPwd) ){ |
| 952 | /* Found a valid checkout database file */ |
| 953 | zPwd[n] = 0; |
| 954 | while( n>1 && zPwd[n-1]=='/' ){ |
| 955 | n--; |
| 956 | zPwd[n] = 0; |
| 957 | } |
| 958 | g.zLocalRoot = mprintf("%s/", zPwd); |
| 959 | g.localOpen = 1; |
| @@ -961,12 +964,12 @@ | |
| 961 | db_open_repository(zDbName); |
| 962 | return 1; |
| 963 | } |
| 964 | } |
| 965 | n--; |
| 966 | while( n>0 && zPwd[n]!='/' ){ n--; } |
| 967 | while( n>0 && zPwd[n-1]=='/' ){ n--; } |
| 968 | zPwd[n] = 0; |
| 969 | } |
| 970 | |
| 971 | /* A checkout database file could not be found */ |
| 972 | return 0; |
| 973 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -315,10 +315,14 @@ | |
| 315 | return sqlite3_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue); |
| 316 | } |
| 317 | int db_bind_text(Stmt *pStmt, const char *zParamName, const char *zValue){ |
| 318 | return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue, |
| 319 | -1, SQLITE_STATIC); |
| 320 | } |
| 321 | int db_bind_text16(Stmt *pStmt, const char *zParamName, const char *zValue){ |
| 322 | return sqlite3_bind_text16(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue, |
| 323 | -1, SQLITE_STATIC); |
| 324 | } |
| 325 | int db_bind_null(Stmt *pStmt, const char *zParamName){ |
| 326 | return sqlite3_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName)); |
| 327 | } |
| 328 | int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){ |
| @@ -942,18 +946,17 @@ | |
| 946 | static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" }; |
| 947 | |
| 948 | if( g.localOpen) return 1; |
| 949 | file_getcwd(zPwd, sizeof(zPwd)-20); |
| 950 | n = strlen(zPwd); |
| 951 | while( n>0 ){ |
| 952 | for(i=0; i<count(aDbName); i++){ |
| 953 | sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]); |
| 954 | if( isValidLocalDb(zPwd) ){ |
| 955 | /* Found a valid checkout database file */ |
| 956 | zPwd[n] = 0; |
| 957 | while( n>0 && zPwd[n-1]=='/' ){ |
| 958 | n--; |
| 959 | zPwd[n] = 0; |
| 960 | } |
| 961 | g.zLocalRoot = mprintf("%s/", zPwd); |
| 962 | g.localOpen = 1; |
| @@ -961,12 +964,12 @@ | |
| 964 | db_open_repository(zDbName); |
| 965 | return 1; |
| 966 | } |
| 967 | } |
| 968 | n--; |
| 969 | while( n>1 && zPwd[n]!='/' ){ n--; } |
| 970 | while( n>1 && zPwd[n-1]=='/' ){ n--; } |
| 971 | zPwd[n] = 0; |
| 972 | } |
| 973 | |
| 974 | /* A checkout database file could not be found */ |
| 975 | return 0; |
| 976 |
+9
-7
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -803,11 +803,11 @@ | ||
| 803 | 803 | p->zStart = zClassChng; |
| 804 | 804 | } |
| 805 | 805 | p->iStart2 = nPrefix + aLCS[1]; |
| 806 | 806 | p->iEnd2 = nLeft - nSuffix; |
| 807 | 807 | p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng; |
| 808 | - sbsSimplifyLine(p, zLeft+nPrefix); | |
| 808 | + sbsSimplifyLine(p, zLeft); | |
| 809 | 809 | sbsWriteText(p, pLeft, SBS_TXTA); |
| 810 | 810 | sbsWriteMarker(p, " | ", "|"); |
| 811 | 811 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 812 | 812 | p->iStart = nPrefix; |
| 813 | 813 | p->iEnd = nPrefix + aLCS[2]; |
| @@ -818,11 +818,11 @@ | ||
| 818 | 818 | p->zStart = zClassChng; |
| 819 | 819 | } |
| 820 | 820 | p->iStart2 = nPrefix + aLCS[3]; |
| 821 | 821 | p->iEnd2 = nRight - nSuffix; |
| 822 | 822 | p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng; |
| 823 | - sbsSimplifyLine(p, zRight+nPrefix); | |
| 823 | + sbsSimplifyLine(p, zRight); | |
| 824 | 824 | sbsWriteText(p, pRight, SBS_TXTB); |
| 825 | 825 | return; |
| 826 | 826 | } |
| 827 | 827 | |
| 828 | 828 | /* If all else fails, show a single big change between left and right */ |
| @@ -1762,10 +1762,12 @@ | ||
| 1762 | 1762 | Blob *pTemp = pA_Blob; |
| 1763 | 1763 | pA_Blob = pB_Blob; |
| 1764 | 1764 | pB_Blob = pTemp; |
| 1765 | 1765 | } |
| 1766 | 1766 | ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; |
| 1767 | + blob_to_utf8_no_bom(pA_Blob, 0); | |
| 1768 | + blob_to_utf8_no_bom(pB_Blob, 0); | |
| 1767 | 1769 | |
| 1768 | 1770 | /* Prepare the input files */ |
| 1769 | 1771 | memset(&c, 0, sizeof(c)); |
| 1770 | 1772 | c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), |
| 1771 | 1773 | &c.nFrom, ignoreEolWs); |
| @@ -2179,26 +2181,26 @@ | ||
| 2179 | 2181 | url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit)); |
| 2180 | 2182 | } |
| 2181 | 2183 | url_add_parameter(&url, "log", showLog ? "1" : "0"); |
| 2182 | 2184 | if( showLog ){ |
| 2183 | 2185 | style_submenu_element("Hide Log", "Hide Log", |
| 2184 | - url_render(&url, "log", "0", 0, 0)); | |
| 2186 | + "%s", url_render(&url, "log", "0", 0, 0)); | |
| 2185 | 2187 | }else{ |
| 2186 | 2188 | style_submenu_element("Show Log", "Show Log", |
| 2187 | - url_render(&url, "log", "1", 0, 0)); | |
| 2189 | + "%s", url_render(&url, "log", "1", 0, 0)); | |
| 2188 | 2190 | } |
| 2189 | 2191 | if( ann.bLimit ){ |
| 2190 | 2192 | char *z1, *z2; |
| 2191 | 2193 | style_submenu_element("All Ancestors", "All Ancestors", |
| 2192 | - url_render(&url, "limit", "-1", 0, 0)); | |
| 2194 | + "%s", url_render(&url, "limit", "-1", 0, 0)); | |
| 2193 | 2195 | z1 = sqlite3_mprintf("%d Ancestors", iLimit+20); |
| 2194 | 2196 | z2 = sqlite3_mprintf("%d", iLimit+20); |
| 2195 | - style_submenu_element(z1, z1, url_render(&url, "limit", z2, 0, 0)); | |
| 2197 | + style_submenu_element(z1, z1, "%s", url_render(&url, "limit", z2, 0, 0)); | |
| 2196 | 2198 | } |
| 2197 | 2199 | if( iLimit>20 ){ |
| 2198 | 2200 | style_submenu_element("20 Ancestors", "20 Ancestors", |
| 2199 | - url_render(&url, "limit", "20", 0, 0)); | |
| 2201 | + "%s", url_render(&url, "limit", "20", 0, 0)); | |
| 2200 | 2202 | } |
| 2201 | 2203 | if( db_get_boolean("white-foreground", 0) ){ |
| 2202 | 2204 | clr1 = 0xa04040; |
| 2203 | 2205 | clr2 = 0x4059a0; |
| 2204 | 2206 | }else{ |
| 2205 | 2207 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -803,11 +803,11 @@ | |
| 803 | p->zStart = zClassChng; |
| 804 | } |
| 805 | p->iStart2 = nPrefix + aLCS[1]; |
| 806 | p->iEnd2 = nLeft - nSuffix; |
| 807 | p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng; |
| 808 | sbsSimplifyLine(p, zLeft+nPrefix); |
| 809 | sbsWriteText(p, pLeft, SBS_TXTA); |
| 810 | sbsWriteMarker(p, " | ", "|"); |
| 811 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 812 | p->iStart = nPrefix; |
| 813 | p->iEnd = nPrefix + aLCS[2]; |
| @@ -818,11 +818,11 @@ | |
| 818 | p->zStart = zClassChng; |
| 819 | } |
| 820 | p->iStart2 = nPrefix + aLCS[3]; |
| 821 | p->iEnd2 = nRight - nSuffix; |
| 822 | p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng; |
| 823 | sbsSimplifyLine(p, zRight+nPrefix); |
| 824 | sbsWriteText(p, pRight, SBS_TXTB); |
| 825 | return; |
| 826 | } |
| 827 | |
| 828 | /* If all else fails, show a single big change between left and right */ |
| @@ -1762,10 +1762,12 @@ | |
| 1762 | Blob *pTemp = pA_Blob; |
| 1763 | pA_Blob = pB_Blob; |
| 1764 | pB_Blob = pTemp; |
| 1765 | } |
| 1766 | ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; |
| 1767 | |
| 1768 | /* Prepare the input files */ |
| 1769 | memset(&c, 0, sizeof(c)); |
| 1770 | c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), |
| 1771 | &c.nFrom, ignoreEolWs); |
| @@ -2179,26 +2181,26 @@ | |
| 2179 | url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit)); |
| 2180 | } |
| 2181 | url_add_parameter(&url, "log", showLog ? "1" : "0"); |
| 2182 | if( showLog ){ |
| 2183 | style_submenu_element("Hide Log", "Hide Log", |
| 2184 | url_render(&url, "log", "0", 0, 0)); |
| 2185 | }else{ |
| 2186 | style_submenu_element("Show Log", "Show Log", |
| 2187 | url_render(&url, "log", "1", 0, 0)); |
| 2188 | } |
| 2189 | if( ann.bLimit ){ |
| 2190 | char *z1, *z2; |
| 2191 | style_submenu_element("All Ancestors", "All Ancestors", |
| 2192 | url_render(&url, "limit", "-1", 0, 0)); |
| 2193 | z1 = sqlite3_mprintf("%d Ancestors", iLimit+20); |
| 2194 | z2 = sqlite3_mprintf("%d", iLimit+20); |
| 2195 | style_submenu_element(z1, z1, url_render(&url, "limit", z2, 0, 0)); |
| 2196 | } |
| 2197 | if( iLimit>20 ){ |
| 2198 | style_submenu_element("20 Ancestors", "20 Ancestors", |
| 2199 | url_render(&url, "limit", "20", 0, 0)); |
| 2200 | } |
| 2201 | if( db_get_boolean("white-foreground", 0) ){ |
| 2202 | clr1 = 0xa04040; |
| 2203 | clr2 = 0x4059a0; |
| 2204 | }else{ |
| 2205 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -803,11 +803,11 @@ | |
| 803 | p->zStart = zClassChng; |
| 804 | } |
| 805 | p->iStart2 = nPrefix + aLCS[1]; |
| 806 | p->iEnd2 = nLeft - nSuffix; |
| 807 | p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng; |
| 808 | sbsSimplifyLine(p, zLeft); |
| 809 | sbsWriteText(p, pLeft, SBS_TXTA); |
| 810 | sbsWriteMarker(p, " | ", "|"); |
| 811 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 812 | p->iStart = nPrefix; |
| 813 | p->iEnd = nPrefix + aLCS[2]; |
| @@ -818,11 +818,11 @@ | |
| 818 | p->zStart = zClassChng; |
| 819 | } |
| 820 | p->iStart2 = nPrefix + aLCS[3]; |
| 821 | p->iEnd2 = nRight - nSuffix; |
| 822 | p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng; |
| 823 | sbsSimplifyLine(p, zRight); |
| 824 | sbsWriteText(p, pRight, SBS_TXTB); |
| 825 | return; |
| 826 | } |
| 827 | |
| 828 | /* If all else fails, show a single big change between left and right */ |
| @@ -1762,10 +1762,12 @@ | |
| 1762 | Blob *pTemp = pA_Blob; |
| 1763 | pA_Blob = pB_Blob; |
| 1764 | pB_Blob = pTemp; |
| 1765 | } |
| 1766 | ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; |
| 1767 | blob_to_utf8_no_bom(pA_Blob, 0); |
| 1768 | blob_to_utf8_no_bom(pB_Blob, 0); |
| 1769 | |
| 1770 | /* Prepare the input files */ |
| 1771 | memset(&c, 0, sizeof(c)); |
| 1772 | c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), |
| 1773 | &c.nFrom, ignoreEolWs); |
| @@ -2179,26 +2181,26 @@ | |
| 2181 | url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit)); |
| 2182 | } |
| 2183 | url_add_parameter(&url, "log", showLog ? "1" : "0"); |
| 2184 | if( showLog ){ |
| 2185 | style_submenu_element("Hide Log", "Hide Log", |
| 2186 | "%s", url_render(&url, "log", "0", 0, 0)); |
| 2187 | }else{ |
| 2188 | style_submenu_element("Show Log", "Show Log", |
| 2189 | "%s", url_render(&url, "log", "1", 0, 0)); |
| 2190 | } |
| 2191 | if( ann.bLimit ){ |
| 2192 | char *z1, *z2; |
| 2193 | style_submenu_element("All Ancestors", "All Ancestors", |
| 2194 | "%s", url_render(&url, "limit", "-1", 0, 0)); |
| 2195 | z1 = sqlite3_mprintf("%d Ancestors", iLimit+20); |
| 2196 | z2 = sqlite3_mprintf("%d", iLimit+20); |
| 2197 | style_submenu_element(z1, z1, "%s", url_render(&url, "limit", z2, 0, 0)); |
| 2198 | } |
| 2199 | if( iLimit>20 ){ |
| 2200 | style_submenu_element("20 Ancestors", "20 Ancestors", |
| 2201 | "%s", url_render(&url, "limit", "20", 0, 0)); |
| 2202 | } |
| 2203 | if( db_get_boolean("white-foreground", 0) ){ |
| 2204 | clr1 = 0xa04040; |
| 2205 | clr2 = 0x4059a0; |
| 2206 | }else{ |
| 2207 |
+1
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -483,10 +483,11 @@ | ||
| 483 | 483 | if( content_get(rid, &filebody)==0 ){ |
| 484 | 484 | goto doc_not_found; |
| 485 | 485 | } |
| 486 | 486 | db_end_transaction(0); |
| 487 | 487 | } |
| 488 | + blob_to_utf8_no_bom(&filebody, 0); | |
| 488 | 489 | |
| 489 | 490 | /* The file is now contained in the filebody blob. Deliver the |
| 490 | 491 | ** file to the user |
| 491 | 492 | */ |
| 492 | 493 | zMime = P("mimetype"); |
| 493 | 494 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -483,10 +483,11 @@ | |
| 483 | if( content_get(rid, &filebody)==0 ){ |
| 484 | goto doc_not_found; |
| 485 | } |
| 486 | db_end_transaction(0); |
| 487 | } |
| 488 | |
| 489 | /* The file is now contained in the filebody blob. Deliver the |
| 490 | ** file to the user |
| 491 | */ |
| 492 | zMime = P("mimetype"); |
| 493 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -483,10 +483,11 @@ | |
| 483 | if( content_get(rid, &filebody)==0 ){ |
| 484 | goto doc_not_found; |
| 485 | } |
| 486 | db_end_transaction(0); |
| 487 | } |
| 488 | blob_to_utf8_no_bom(&filebody, 0); |
| 489 | |
| 490 | /* The file is now contained in the filebody blob. Deliver the |
| 491 | ** file to the user |
| 492 | */ |
| 493 | zMime = P("mimetype"); |
| 494 |
+31
-24
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -703,11 +703,11 @@ | ||
| 703 | 703 | } |
| 704 | 704 | } |
| 705 | 705 | if( j>=0 ) z[j] = z[i]; |
| 706 | 706 | j++; |
| 707 | 707 | } |
| 708 | - if( j==0 ) z[j++] = '.'; | |
| 708 | + if( j==0 ) z[j++] = '/'; | |
| 709 | 709 | z[j] = 0; |
| 710 | 710 | return j; |
| 711 | 711 | } |
| 712 | 712 | |
| 713 | 713 | /* |
| @@ -777,39 +777,40 @@ | ||
| 777 | 777 | ** Convert /A/../ to just / |
| 778 | 778 | ** If the slash parameter is non-zero, the trailing slash, if any, |
| 779 | 779 | ** is retained. |
| 780 | 780 | */ |
| 781 | 781 | void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ |
| 782 | + blob_zero(pOut); | |
| 782 | 783 | if( file_is_absolute_path(zOrigName) ){ |
| 783 | -#if defined(_WIN32) || defined(__CYGWIN__) | |
| 784 | - char *zOut; | |
| 785 | -#endif | |
| 786 | - blob_set(pOut, zOrigName); | |
| 787 | - blob_materialize(pOut); | |
| 784 | + blob_appendf(pOut, "%/", zOrigName); | |
| 785 | + }else{ | |
| 786 | + char zPwd[2000]; | |
| 787 | + file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); | |
| 788 | + if( zPwd[0]=='/' && strlen(zPwd)==1 ){ | |
| 789 | + /* when on '/', don't add an extra '/' */ | |
| 790 | + if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){ | |
| 791 | + /* '.' when on '/' mean '/' */ | |
| 792 | + blob_appendf(pOut, "%/", zPwd); | |
| 793 | + }else{ | |
| 794 | + blob_appendf(pOut, "%/%/", zPwd, zOrigName); | |
| 795 | + } | |
| 796 | + }else{ | |
| 797 | + blob_appendf(pOut, "%//%/", zPwd, zOrigName); | |
| 798 | + } | |
| 799 | + } | |
| 788 | 800 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 801 | + { | |
| 802 | + char *zOut; | |
| 789 | 803 | /* |
| 790 | 804 | ** On Windows/cygwin, normalize the drive letter to upper case. |
| 791 | 805 | */ |
| 792 | 806 | zOut = blob_str(pOut); |
| 793 | - if( fossil_islower(zOut[0]) && zOut[1]==':' ){ | |
| 807 | + if( fossil_islower(zOut[0]) && zOut[1]==':' && zOut[2]=='/' ){ | |
| 794 | 808 | zOut[0] = fossil_toupper(zOut[0]); |
| 795 | 809 | } |
| 796 | -#endif | |
| 797 | - }else{ | |
| 798 | - char zPwd[2000]; | |
| 799 | - file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); | |
| 800 | -#if defined(_WIN32) | |
| 801 | - /* | |
| 802 | - ** On Windows, normalize the drive letter to upper case. | |
| 803 | - */ | |
| 804 | - if( fossil_islower(zPwd[0]) && zPwd[1]==':' ){ | |
| 805 | - zPwd[0] = fossil_toupper(zPwd[0]); | |
| 806 | - } | |
| 807 | -#endif | |
| 808 | - blob_zero(pOut); | |
| 809 | - blob_appendf(pOut, "%//%/", zPwd, zOrigName); | |
| 810 | - } | |
| 810 | + } | |
| 811 | +#endif | |
| 811 | 812 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), |
| 812 | 813 | blob_size(pOut), slash)); |
| 813 | 814 | } |
| 814 | 815 | |
| 815 | 816 | /* |
| @@ -928,11 +929,16 @@ | ||
| 928 | 929 | blob_append(pOut, &zPath[i+1], -1); |
| 929 | 930 | blob_reset(&tmp); |
| 930 | 931 | return; |
| 931 | 932 | } |
| 932 | 933 | while( zPath[i-1]!='/' ){ i--; } |
| 933 | - blob_set(&tmp, "../"); | |
| 934 | + if( zPwd[0]=='/' && strlen(zPwd)==1 ){ | |
| 935 | + /* If on '/', don't go to higher level */ | |
| 936 | + blob_zero(&tmp); | |
| 937 | + }else{ | |
| 938 | + blob_set(&tmp, "../"); | |
| 939 | + } | |
| 934 | 940 | for(j=i; zPwd[j]; j++){ |
| 935 | 941 | if( zPwd[j]=='/' ){ |
| 936 | 942 | blob_append(&tmp, "../", 3); |
| 937 | 943 | } |
| 938 | 944 | } |
| @@ -990,11 +996,12 @@ | ||
| 990 | 996 | }else{ |
| 991 | 997 | xCmp = fossil_strnicmp; |
| 992 | 998 | } |
| 993 | 999 | |
| 994 | 1000 | /* Special case. zOrigName refers to g.zLocalRoot directory. */ |
| 995 | - if( nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0 ){ | |
| 1001 | + if( (nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0) | |
| 1002 | + || (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){ | |
| 996 | 1003 | blob_append(pOut, ".", 1); |
| 997 | 1004 | blob_reset(&localRoot); |
| 998 | 1005 | blob_reset(&full); |
| 999 | 1006 | return 1; |
| 1000 | 1007 | } |
| 1001 | 1008 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -703,11 +703,11 @@ | |
| 703 | } |
| 704 | } |
| 705 | if( j>=0 ) z[j] = z[i]; |
| 706 | j++; |
| 707 | } |
| 708 | if( j==0 ) z[j++] = '.'; |
| 709 | z[j] = 0; |
| 710 | return j; |
| 711 | } |
| 712 | |
| 713 | /* |
| @@ -777,39 +777,40 @@ | |
| 777 | ** Convert /A/../ to just / |
| 778 | ** If the slash parameter is non-zero, the trailing slash, if any, |
| 779 | ** is retained. |
| 780 | */ |
| 781 | void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ |
| 782 | if( file_is_absolute_path(zOrigName) ){ |
| 783 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 784 | char *zOut; |
| 785 | #endif |
| 786 | blob_set(pOut, zOrigName); |
| 787 | blob_materialize(pOut); |
| 788 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 789 | /* |
| 790 | ** On Windows/cygwin, normalize the drive letter to upper case. |
| 791 | */ |
| 792 | zOut = blob_str(pOut); |
| 793 | if( fossil_islower(zOut[0]) && zOut[1]==':' ){ |
| 794 | zOut[0] = fossil_toupper(zOut[0]); |
| 795 | } |
| 796 | #endif |
| 797 | }else{ |
| 798 | char zPwd[2000]; |
| 799 | file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); |
| 800 | #if defined(_WIN32) |
| 801 | /* |
| 802 | ** On Windows, normalize the drive letter to upper case. |
| 803 | */ |
| 804 | if( fossil_islower(zPwd[0]) && zPwd[1]==':' ){ |
| 805 | zPwd[0] = fossil_toupper(zPwd[0]); |
| 806 | } |
| 807 | #endif |
| 808 | blob_zero(pOut); |
| 809 | blob_appendf(pOut, "%//%/", zPwd, zOrigName); |
| 810 | } |
| 811 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), |
| 812 | blob_size(pOut), slash)); |
| 813 | } |
| 814 | |
| 815 | /* |
| @@ -928,11 +929,16 @@ | |
| 928 | blob_append(pOut, &zPath[i+1], -1); |
| 929 | blob_reset(&tmp); |
| 930 | return; |
| 931 | } |
| 932 | while( zPath[i-1]!='/' ){ i--; } |
| 933 | blob_set(&tmp, "../"); |
| 934 | for(j=i; zPwd[j]; j++){ |
| 935 | if( zPwd[j]=='/' ){ |
| 936 | blob_append(&tmp, "../", 3); |
| 937 | } |
| 938 | } |
| @@ -990,11 +996,12 @@ | |
| 990 | }else{ |
| 991 | xCmp = fossil_strnicmp; |
| 992 | } |
| 993 | |
| 994 | /* Special case. zOrigName refers to g.zLocalRoot directory. */ |
| 995 | if( nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0 ){ |
| 996 | blob_append(pOut, ".", 1); |
| 997 | blob_reset(&localRoot); |
| 998 | blob_reset(&full); |
| 999 | return 1; |
| 1000 | } |
| 1001 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -703,11 +703,11 @@ | |
| 703 | } |
| 704 | } |
| 705 | if( j>=0 ) z[j] = z[i]; |
| 706 | j++; |
| 707 | } |
| 708 | if( j==0 ) z[j++] = '/'; |
| 709 | z[j] = 0; |
| 710 | return j; |
| 711 | } |
| 712 | |
| 713 | /* |
| @@ -777,39 +777,40 @@ | |
| 777 | ** Convert /A/../ to just / |
| 778 | ** If the slash parameter is non-zero, the trailing slash, if any, |
| 779 | ** is retained. |
| 780 | */ |
| 781 | void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){ |
| 782 | blob_zero(pOut); |
| 783 | if( file_is_absolute_path(zOrigName) ){ |
| 784 | blob_appendf(pOut, "%/", zOrigName); |
| 785 | }else{ |
| 786 | char zPwd[2000]; |
| 787 | file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); |
| 788 | if( zPwd[0]=='/' && strlen(zPwd)==1 ){ |
| 789 | /* when on '/', don't add an extra '/' */ |
| 790 | if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){ |
| 791 | /* '.' when on '/' mean '/' */ |
| 792 | blob_appendf(pOut, "%/", zPwd); |
| 793 | }else{ |
| 794 | blob_appendf(pOut, "%/%/", zPwd, zOrigName); |
| 795 | } |
| 796 | }else{ |
| 797 | blob_appendf(pOut, "%//%/", zPwd, zOrigName); |
| 798 | } |
| 799 | } |
| 800 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 801 | { |
| 802 | char *zOut; |
| 803 | /* |
| 804 | ** On Windows/cygwin, normalize the drive letter to upper case. |
| 805 | */ |
| 806 | zOut = blob_str(pOut); |
| 807 | if( fossil_islower(zOut[0]) && zOut[1]==':' && zOut[2]=='/' ){ |
| 808 | zOut[0] = fossil_toupper(zOut[0]); |
| 809 | } |
| 810 | } |
| 811 | #endif |
| 812 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), |
| 813 | blob_size(pOut), slash)); |
| 814 | } |
| 815 | |
| 816 | /* |
| @@ -928,11 +929,16 @@ | |
| 929 | blob_append(pOut, &zPath[i+1], -1); |
| 930 | blob_reset(&tmp); |
| 931 | return; |
| 932 | } |
| 933 | while( zPath[i-1]!='/' ){ i--; } |
| 934 | if( zPwd[0]=='/' && strlen(zPwd)==1 ){ |
| 935 | /* If on '/', don't go to higher level */ |
| 936 | blob_zero(&tmp); |
| 937 | }else{ |
| 938 | blob_set(&tmp, "../"); |
| 939 | } |
| 940 | for(j=i; zPwd[j]; j++){ |
| 941 | if( zPwd[j]=='/' ){ |
| 942 | blob_append(&tmp, "../", 3); |
| 943 | } |
| 944 | } |
| @@ -990,11 +996,12 @@ | |
| 996 | }else{ |
| 997 | xCmp = fossil_strnicmp; |
| 998 | } |
| 999 | |
| 1000 | /* Special case. zOrigName refers to g.zLocalRoot directory. */ |
| 1001 | if( (nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0) |
| 1002 | || (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){ |
| 1003 | blob_append(pOut, ".", 1); |
| 1004 | blob_reset(&localRoot); |
| 1005 | blob_reset(&full); |
| 1006 | return 1; |
| 1007 | } |
| 1008 |
+7
-6
| --- src/finfo.c | ||
| +++ src/finfo.c | ||
| @@ -164,11 +164,11 @@ | ||
| 164 | 164 | if( rid==0 ){ |
| 165 | 165 | fossil_fatal("no history for file: %b", &fname); |
| 166 | 166 | } |
| 167 | 167 | zFilename = blob_str(&fname); |
| 168 | 168 | db_prepare(&q, |
| 169 | - "SELECT b.uuid, ci.uuid, date(event.mtime,'localtime')," | |
| 169 | + "SELECT b.uuid, ci.uuid, date(event.mtime%s)," | |
| 170 | 170 | " coalesce(event.ecomment, event.comment)," |
| 171 | 171 | " coalesce(event.euser, event.user)," |
| 172 | 172 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 173 | 173 | " AND tagxref.rid=mlink.mid)" /* Tags */ |
| 174 | 174 | " FROM mlink, blob b, event, blob ci, filename" |
| @@ -176,11 +176,12 @@ | ||
| 176 | 176 | " AND mlink.fnid=filename.fnid" |
| 177 | 177 | " AND b.rid=mlink.fid" |
| 178 | 178 | " AND event.objid=mlink.mid" |
| 179 | 179 | " AND event.objid=ci.rid" |
| 180 | 180 | " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", |
| 181 | - TAG_BRANCH, zFilename, filename_collation(), iLimit, iOffset | |
| 181 | + timeline_utc(), TAG_BRANCH, zFilename, filename_collation(), | |
| 182 | + iLimit, iOffset | |
| 182 | 183 | ); |
| 183 | 184 | blob_zero(&line); |
| 184 | 185 | if( iBrief ){ |
| 185 | 186 | fossil_print("History of %s\n", blob_str(&fname)); |
| 186 | 187 | } |
| @@ -302,11 +303,11 @@ | ||
| 302 | 303 | zFilename = PD("name",""); |
| 303 | 304 | url_add_parameter(&url, "name", zFilename); |
| 304 | 305 | blob_zero(&sql); |
| 305 | 306 | blob_appendf(&sql, |
| 306 | 307 | "SELECT" |
| 307 | - " datetime(event.mtime,'localtime')," /* Date of change */ | |
| 308 | + " datetime(event.mtime%s)," /* Date of change */ | |
| 308 | 309 | " coalesce(event.ecomment, event.comment)," /* Check-in comment */ |
| 309 | 310 | " coalesce(event.euser, event.user)," /* User who made chng */ |
| 310 | 311 | " mlink.pid," /* Parent file rid */ |
| 311 | 312 | " mlink.fid," /* File rid */ |
| 312 | 313 | " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ |
| @@ -315,11 +316,11 @@ | ||
| 315 | 316 | " event.bgcolor," /* Background color */ |
| 316 | 317 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 317 | 318 | " AND tagxref.rid=mlink.mid)," /* Tags */ |
| 318 | 319 | " mlink.mid," /* check-in ID */ |
| 319 | 320 | " mlink.pfnid", /* Previous filename */ |
| 320 | - TAG_BRANCH | |
| 321 | + timeline_utc(), TAG_BRANCH | |
| 321 | 322 | ); |
| 322 | 323 | if( firstChngOnly ){ |
| 323 | 324 | #if 0 |
| 324 | 325 | blob_appendf(&sql, ", min(event.mtime)"); |
| 325 | 326 | #else |
| @@ -375,16 +376,16 @@ | ||
| 375 | 376 | blob_zero(&title); |
| 376 | 377 | if( baseCheckin ){ |
| 377 | 378 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); |
| 378 | 379 | char *zLink = href("%R/info/%S", zUuid); |
| 379 | 380 | blob_appendf(&title, "Ancestors of file "); |
| 380 | - hyperlinked_path(zFilename, &title, zUuid); | |
| 381 | + hyperlinked_path(zFilename, &title, zUuid, "tree", ""); | |
| 381 | 382 | blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid); |
| 382 | 383 | fossil_free(zUuid); |
| 383 | 384 | }else{ |
| 384 | 385 | blob_appendf(&title, "History of files named "); |
| 385 | - hyperlinked_path(zFilename, &title, 0); | |
| 386 | + hyperlinked_path(zFilename, &title, 0, "tree", ""); | |
| 386 | 387 | } |
| 387 | 388 | @ <h2>%b(&title)</h2> |
| 388 | 389 | blob_reset(&title); |
| 389 | 390 | pGraph = graph_init(); |
| 390 | 391 | @ <div id="canvas" style="position:relative;width:1px;height:1px;" |
| 391 | 392 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -164,11 +164,11 @@ | |
| 164 | if( rid==0 ){ |
| 165 | fossil_fatal("no history for file: %b", &fname); |
| 166 | } |
| 167 | zFilename = blob_str(&fname); |
| 168 | db_prepare(&q, |
| 169 | "SELECT b.uuid, ci.uuid, date(event.mtime,'localtime')," |
| 170 | " coalesce(event.ecomment, event.comment)," |
| 171 | " coalesce(event.euser, event.user)," |
| 172 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 173 | " AND tagxref.rid=mlink.mid)" /* Tags */ |
| 174 | " FROM mlink, blob b, event, blob ci, filename" |
| @@ -176,11 +176,12 @@ | |
| 176 | " AND mlink.fnid=filename.fnid" |
| 177 | " AND b.rid=mlink.fid" |
| 178 | " AND event.objid=mlink.mid" |
| 179 | " AND event.objid=ci.rid" |
| 180 | " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", |
| 181 | TAG_BRANCH, zFilename, filename_collation(), iLimit, iOffset |
| 182 | ); |
| 183 | blob_zero(&line); |
| 184 | if( iBrief ){ |
| 185 | fossil_print("History of %s\n", blob_str(&fname)); |
| 186 | } |
| @@ -302,11 +303,11 @@ | |
| 302 | zFilename = PD("name",""); |
| 303 | url_add_parameter(&url, "name", zFilename); |
| 304 | blob_zero(&sql); |
| 305 | blob_appendf(&sql, |
| 306 | "SELECT" |
| 307 | " datetime(event.mtime,'localtime')," /* Date of change */ |
| 308 | " coalesce(event.ecomment, event.comment)," /* Check-in comment */ |
| 309 | " coalesce(event.euser, event.user)," /* User who made chng */ |
| 310 | " mlink.pid," /* Parent file rid */ |
| 311 | " mlink.fid," /* File rid */ |
| 312 | " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ |
| @@ -315,11 +316,11 @@ | |
| 315 | " event.bgcolor," /* Background color */ |
| 316 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 317 | " AND tagxref.rid=mlink.mid)," /* Tags */ |
| 318 | " mlink.mid," /* check-in ID */ |
| 319 | " mlink.pfnid", /* Previous filename */ |
| 320 | TAG_BRANCH |
| 321 | ); |
| 322 | if( firstChngOnly ){ |
| 323 | #if 0 |
| 324 | blob_appendf(&sql, ", min(event.mtime)"); |
| 325 | #else |
| @@ -375,16 +376,16 @@ | |
| 375 | blob_zero(&title); |
| 376 | if( baseCheckin ){ |
| 377 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); |
| 378 | char *zLink = href("%R/info/%S", zUuid); |
| 379 | blob_appendf(&title, "Ancestors of file "); |
| 380 | hyperlinked_path(zFilename, &title, zUuid); |
| 381 | blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid); |
| 382 | fossil_free(zUuid); |
| 383 | }else{ |
| 384 | blob_appendf(&title, "History of files named "); |
| 385 | hyperlinked_path(zFilename, &title, 0); |
| 386 | } |
| 387 | @ <h2>%b(&title)</h2> |
| 388 | blob_reset(&title); |
| 389 | pGraph = graph_init(); |
| 390 | @ <div id="canvas" style="position:relative;width:1px;height:1px;" |
| 391 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -164,11 +164,11 @@ | |
| 164 | if( rid==0 ){ |
| 165 | fossil_fatal("no history for file: %b", &fname); |
| 166 | } |
| 167 | zFilename = blob_str(&fname); |
| 168 | db_prepare(&q, |
| 169 | "SELECT b.uuid, ci.uuid, date(event.mtime%s)," |
| 170 | " coalesce(event.ecomment, event.comment)," |
| 171 | " coalesce(event.euser, event.user)," |
| 172 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 173 | " AND tagxref.rid=mlink.mid)" /* Tags */ |
| 174 | " FROM mlink, blob b, event, blob ci, filename" |
| @@ -176,11 +176,12 @@ | |
| 176 | " AND mlink.fnid=filename.fnid" |
| 177 | " AND b.rid=mlink.fid" |
| 178 | " AND event.objid=mlink.mid" |
| 179 | " AND event.objid=ci.rid" |
| 180 | " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", |
| 181 | timeline_utc(), TAG_BRANCH, zFilename, filename_collation(), |
| 182 | iLimit, iOffset |
| 183 | ); |
| 184 | blob_zero(&line); |
| 185 | if( iBrief ){ |
| 186 | fossil_print("History of %s\n", blob_str(&fname)); |
| 187 | } |
| @@ -302,11 +303,11 @@ | |
| 303 | zFilename = PD("name",""); |
| 304 | url_add_parameter(&url, "name", zFilename); |
| 305 | blob_zero(&sql); |
| 306 | blob_appendf(&sql, |
| 307 | "SELECT" |
| 308 | " datetime(event.mtime%s)," /* Date of change */ |
| 309 | " coalesce(event.ecomment, event.comment)," /* Check-in comment */ |
| 310 | " coalesce(event.euser, event.user)," /* User who made chng */ |
| 311 | " mlink.pid," /* Parent file rid */ |
| 312 | " mlink.fid," /* File rid */ |
| 313 | " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ |
| @@ -315,11 +316,11 @@ | |
| 316 | " event.bgcolor," /* Background color */ |
| 317 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 318 | " AND tagxref.rid=mlink.mid)," /* Tags */ |
| 319 | " mlink.mid," /* check-in ID */ |
| 320 | " mlink.pfnid", /* Previous filename */ |
| 321 | timeline_utc(), TAG_BRANCH |
| 322 | ); |
| 323 | if( firstChngOnly ){ |
| 324 | #if 0 |
| 325 | blob_appendf(&sql, ", min(event.mtime)"); |
| 326 | #else |
| @@ -375,16 +376,16 @@ | |
| 376 | blob_zero(&title); |
| 377 | if( baseCheckin ){ |
| 378 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin); |
| 379 | char *zLink = href("%R/info/%S", zUuid); |
| 380 | blob_appendf(&title, "Ancestors of file "); |
| 381 | hyperlinked_path(zFilename, &title, zUuid, "tree", ""); |
| 382 | blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid); |
| 383 | fossil_free(zUuid); |
| 384 | }else{ |
| 385 | blob_appendf(&title, "History of files named "); |
| 386 | hyperlinked_path(zFilename, &title, 0, "tree", ""); |
| 387 | } |
| 388 | @ <h2>%b(&title)</h2> |
| 389 | blob_reset(&title); |
| 390 | pGraph = graph_init(); |
| 391 | @ <div id="canvas" style="position:relative;width:1px;height:1px;" |
| 392 |
+15
| --- src/import.c | ||
| +++ src/import.c | ||
| @@ -575,22 +575,37 @@ | ||
| 575 | 575 | fossil_free(gg.zMark); |
| 576 | 576 | gg.zMark = fossil_strdup(&zLine[5]); |
| 577 | 577 | }else |
| 578 | 578 | if( memcmp(zLine, "tagger ", 7)==0 || memcmp(zLine, "committer ",10)==0 ){ |
| 579 | 579 | sqlite3_int64 secSince1970; |
| 580 | + int hastz; | |
| 581 | + char tzdir; | |
| 582 | + int tz; | |
| 580 | 583 | for(i=0; zLine[i] && zLine[i]!='<'; i++){} |
| 581 | 584 | if( zLine[i]==0 ) goto malformed_line; |
| 582 | 585 | z = &zLine[i+1]; |
| 583 | 586 | for(i=i+1; zLine[i] && zLine[i]!='>'; i++){} |
| 584 | 587 | if( zLine[i]==0 ) goto malformed_line; |
| 585 | 588 | zLine[i] = 0; |
| 586 | 589 | fossil_free(gg.zUser); |
| 587 | 590 | gg.zUser = fossil_strdup(z); |
| 588 | 591 | secSince1970 = 0; |
| 592 | + | |
| 593 | + /* We don't use sscanf here because of int64 portability issues. */ | |
| 589 | 594 | for(i=i+2; fossil_isdigit(zLine[i]); i++){ |
| 590 | 595 | secSince1970 = secSince1970*10 + zLine[i] - '0'; |
| 591 | 596 | } |
| 597 | + | |
| 598 | + /* Read in optional timezone modifier (we don't know if it's strictly | |
| 599 | + * optional, but better to be sure). */ | |
| 600 | + tzdir = '+'; | |
| 601 | + tz = 0; | |
| 602 | + hastz = sscanf(&zLine[i], " %c%d", &tzdir, &tz); | |
| 603 | + if ((hastz == 1) || (hastz > 2)) goto malformed_line; | |
| 604 | + secSince1970 += ((tzdir == '-') ? -1 : 1) * | |
| 605 | + ((tz/100)*3600 + (tz%100)*60); | |
| 606 | + | |
| 592 | 607 | fossil_free(gg.zDate); |
| 593 | 608 | gg.zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", secSince1970); |
| 594 | 609 | gg.zDate[10] = 'T'; |
| 595 | 610 | }else |
| 596 | 611 | if( memcmp(zLine, "from ", 5)==0 ){ |
| 597 | 612 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -575,22 +575,37 @@ | |
| 575 | fossil_free(gg.zMark); |
| 576 | gg.zMark = fossil_strdup(&zLine[5]); |
| 577 | }else |
| 578 | if( memcmp(zLine, "tagger ", 7)==0 || memcmp(zLine, "committer ",10)==0 ){ |
| 579 | sqlite3_int64 secSince1970; |
| 580 | for(i=0; zLine[i] && zLine[i]!='<'; i++){} |
| 581 | if( zLine[i]==0 ) goto malformed_line; |
| 582 | z = &zLine[i+1]; |
| 583 | for(i=i+1; zLine[i] && zLine[i]!='>'; i++){} |
| 584 | if( zLine[i]==0 ) goto malformed_line; |
| 585 | zLine[i] = 0; |
| 586 | fossil_free(gg.zUser); |
| 587 | gg.zUser = fossil_strdup(z); |
| 588 | secSince1970 = 0; |
| 589 | for(i=i+2; fossil_isdigit(zLine[i]); i++){ |
| 590 | secSince1970 = secSince1970*10 + zLine[i] - '0'; |
| 591 | } |
| 592 | fossil_free(gg.zDate); |
| 593 | gg.zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", secSince1970); |
| 594 | gg.zDate[10] = 'T'; |
| 595 | }else |
| 596 | if( memcmp(zLine, "from ", 5)==0 ){ |
| 597 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -575,22 +575,37 @@ | |
| 575 | fossil_free(gg.zMark); |
| 576 | gg.zMark = fossil_strdup(&zLine[5]); |
| 577 | }else |
| 578 | if( memcmp(zLine, "tagger ", 7)==0 || memcmp(zLine, "committer ",10)==0 ){ |
| 579 | sqlite3_int64 secSince1970; |
| 580 | int hastz; |
| 581 | char tzdir; |
| 582 | int tz; |
| 583 | for(i=0; zLine[i] && zLine[i]!='<'; i++){} |
| 584 | if( zLine[i]==0 ) goto malformed_line; |
| 585 | z = &zLine[i+1]; |
| 586 | for(i=i+1; zLine[i] && zLine[i]!='>'; i++){} |
| 587 | if( zLine[i]==0 ) goto malformed_line; |
| 588 | zLine[i] = 0; |
| 589 | fossil_free(gg.zUser); |
| 590 | gg.zUser = fossil_strdup(z); |
| 591 | secSince1970 = 0; |
| 592 | |
| 593 | /* We don't use sscanf here because of int64 portability issues. */ |
| 594 | for(i=i+2; fossil_isdigit(zLine[i]); i++){ |
| 595 | secSince1970 = secSince1970*10 + zLine[i] - '0'; |
| 596 | } |
| 597 | |
| 598 | /* Read in optional timezone modifier (we don't know if it's strictly |
| 599 | * optional, but better to be sure). */ |
| 600 | tzdir = '+'; |
| 601 | tz = 0; |
| 602 | hastz = sscanf(&zLine[i], " %c%d", &tzdir, &tz); |
| 603 | if ((hastz == 1) || (hastz > 2)) goto malformed_line; |
| 604 | secSince1970 += ((tzdir == '-') ? -1 : 1) * |
| 605 | ((tz/100)*3600 + (tz%100)*60); |
| 606 | |
| 607 | fossil_free(gg.zDate); |
| 608 | gg.zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", secSince1970); |
| 609 | gg.zDate[10] = 'T'; |
| 610 | }else |
| 611 | if( memcmp(zLine, "from ", 5)==0 ){ |
| 612 |
+15
-8
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -230,15 +230,15 @@ | ||
| 230 | 230 | Stmt q; |
| 231 | 231 | int cnt = 0; |
| 232 | 232 | db_prepare(&q, |
| 233 | 233 | "SELECT tag.tagid, tagname, " |
| 234 | 234 | " (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d)," |
| 235 | - " value, datetime(tagxref.mtime,'localtime'), tagtype," | |
| 235 | + " value, datetime(tagxref.mtime%s), tagtype," | |
| 236 | 236 | " (SELECT uuid FROM blob WHERE rid=tagxref.origid AND rid!=%d)" |
| 237 | 237 | " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" |
| 238 | 238 | " WHERE tagxref.rid=%d AND tagname NOT GLOB '%q'" |
| 239 | - " ORDER BY tagname /*sort*/", rid, rid, rid, zNotGlob | |
| 239 | + " ORDER BY tagname /*sort*/", rid, timeline_utc(), rid, rid, zNotGlob | |
| 240 | 240 | ); |
| 241 | 241 | while( db_step(&q)==SQLITE_ROW ){ |
| 242 | 242 | const char *zTagname = db_column_text(&q, 1); |
| 243 | 243 | const char *zSrcUuid = db_column_text(&q, 2); |
| 244 | 244 | const char *zValue = db_column_text(&q, 3); |
| @@ -503,16 +503,16 @@ | ||
| 503 | 503 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 504 | 504 | rid |
| 505 | 505 | ); |
| 506 | 506 | isLeaf = is_a_leaf(rid); |
| 507 | 507 | db_prepare(&q1, |
| 508 | - "SELECT uuid, datetime(mtime, 'localtime'), user, comment," | |
| 509 | - " datetime(omtime, 'localtime'), mtime" | |
| 508 | + "SELECT uuid, datetime(mtime%s), user, comment," | |
| 509 | + " datetime(omtime%s), mtime" | |
| 510 | 510 | " FROM blob, event" |
| 511 | 511 | " WHERE blob.rid=%d" |
| 512 | 512 | " AND event.objid=%d", |
| 513 | - rid, rid | |
| 513 | + timeline_utc(), timeline_utc(), rid, rid | |
| 514 | 514 | ); |
| 515 | 515 | sideBySide = !is_false(PD("sbs","1")); |
| 516 | 516 | if( db_step(&q1)==SQLITE_ROW ){ |
| 517 | 517 | const char *zUuid = db_column_text(&q1, 0); |
| 518 | 518 | char *zTitle = mprintf("Check-in [%.10s]", zUuid); |
| @@ -610,11 +610,11 @@ | ||
| 610 | 610 | " WHERE rid=%d AND tagtype>0 " |
| 611 | 611 | " AND tag.tagid=tagxref.tagid " |
| 612 | 612 | " AND +tag.tagname GLOB 'sym-*'", rid); |
| 613 | 613 | while( db_step(&q2)==SQLITE_ROW ){ |
| 614 | 614 | const char *zTagName = db_column_text(&q2, 0); |
| 615 | - @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a> | |
| 615 | + @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a> | |
| 616 | 616 | } |
| 617 | 617 | db_finalize(&q2); |
| 618 | 618 | |
| 619 | 619 | |
| 620 | 620 | /* The Download: line */ |
| @@ -629,12 +629,13 @@ | ||
| 629 | 629 | fossil_free(zUrl); |
| 630 | 630 | } |
| 631 | 631 | @ </td></tr> |
| 632 | 632 | @ <tr><th>Other Links:</th> |
| 633 | 633 | @ <td> |
| 634 | - @ %z(href("%R/dir?ci=%S",zUuid))files</a> | |
| 634 | + @ %z(href("%R/tree?ci=%S",zUuid))files</a> | |
| 635 | 635 | @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> |
| 636 | + @ | %z(href("%R/tree?ci=%S&nofiles",zUuid))folders</a> | |
| 636 | 637 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 637 | 638 | if( g.perm.Write ){ |
| 638 | 639 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| 639 | 640 | } |
| 640 | 641 | @ </td> |
| @@ -1367,17 +1368,23 @@ | ||
| 1367 | 1368 | ** Return the uninterpreted content of an artifact. Used primarily |
| 1368 | 1369 | ** to view artifacts that are images. |
| 1369 | 1370 | */ |
| 1370 | 1371 | void rawartifact_page(void){ |
| 1371 | 1372 | int rid; |
| 1373 | + char *zUuid; | |
| 1372 | 1374 | const char *zMime; |
| 1373 | 1375 | Blob content; |
| 1374 | 1376 | |
| 1375 | 1377 | rid = name_to_rid_www("name"); |
| 1376 | 1378 | login_check_credentials(); |
| 1377 | 1379 | if( !g.perm.Read ){ login_needed(); return; } |
| 1378 | 1380 | if( rid==0 ) fossil_redirect_home(); |
| 1381 | + zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 1382 | + if( fossil_strcmp(P("name"), zUuid)==0 ){ | |
| 1383 | + g.isConst = 1; | |
| 1384 | + } | |
| 1385 | + free(zUuid); | |
| 1379 | 1386 | zMime = P("m"); |
| 1380 | 1387 | if( zMime==0 ){ |
| 1381 | 1388 | char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename" |
| 1382 | 1389 | " WHERE mlink.fid=%d" |
| 1383 | 1390 | " AND filename.fnid=mlink.fnid", rid); |
| @@ -1674,16 +1681,16 @@ | ||
| 1674 | 1681 | @ sandbox="allow-same-origin" |
| 1675 | 1682 | @ onload="this.height = this.contentDocument.documentElement.scrollHeight;"> |
| 1676 | 1683 | @ </iframe> |
| 1677 | 1684 | }else{ |
| 1678 | 1685 | style_submenu_element("Hex","Hex", "%s/hexdump?name=%s", g.zTop, zUuid); |
| 1686 | + blob_to_utf8_no_bom(&content, 0); | |
| 1679 | 1687 | zMime = mimetype_from_content(&content); |
| 1680 | 1688 | @ <blockquote> |
| 1681 | 1689 | if( zMime==0 ){ |
| 1682 | 1690 | const char *zLn = P("ln"); |
| 1683 | 1691 | const char *z; |
| 1684 | - blob_to_utf8_no_bom(&content, 0); | |
| 1685 | 1692 | z = blob_str(&content); |
| 1686 | 1693 | if( zLn ){ |
| 1687 | 1694 | output_text_with_line_numbers(z, zLn); |
| 1688 | 1695 | }else{ |
| 1689 | 1696 | @ <pre> |
| 1690 | 1697 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -230,15 +230,15 @@ | |
| 230 | Stmt q; |
| 231 | int cnt = 0; |
| 232 | db_prepare(&q, |
| 233 | "SELECT tag.tagid, tagname, " |
| 234 | " (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d)," |
| 235 | " value, datetime(tagxref.mtime,'localtime'), tagtype," |
| 236 | " (SELECT uuid FROM blob WHERE rid=tagxref.origid AND rid!=%d)" |
| 237 | " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" |
| 238 | " WHERE tagxref.rid=%d AND tagname NOT GLOB '%q'" |
| 239 | " ORDER BY tagname /*sort*/", rid, rid, rid, zNotGlob |
| 240 | ); |
| 241 | while( db_step(&q)==SQLITE_ROW ){ |
| 242 | const char *zTagname = db_column_text(&q, 1); |
| 243 | const char *zSrcUuid = db_column_text(&q, 2); |
| 244 | const char *zValue = db_column_text(&q, 3); |
| @@ -503,16 +503,16 @@ | |
| 503 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 504 | rid |
| 505 | ); |
| 506 | isLeaf = is_a_leaf(rid); |
| 507 | db_prepare(&q1, |
| 508 | "SELECT uuid, datetime(mtime, 'localtime'), user, comment," |
| 509 | " datetime(omtime, 'localtime'), mtime" |
| 510 | " FROM blob, event" |
| 511 | " WHERE blob.rid=%d" |
| 512 | " AND event.objid=%d", |
| 513 | rid, rid |
| 514 | ); |
| 515 | sideBySide = !is_false(PD("sbs","1")); |
| 516 | if( db_step(&q1)==SQLITE_ROW ){ |
| 517 | const char *zUuid = db_column_text(&q1, 0); |
| 518 | char *zTitle = mprintf("Check-in [%.10s]", zUuid); |
| @@ -610,11 +610,11 @@ | |
| 610 | " WHERE rid=%d AND tagtype>0 " |
| 611 | " AND tag.tagid=tagxref.tagid " |
| 612 | " AND +tag.tagname GLOB 'sym-*'", rid); |
| 613 | while( db_step(&q2)==SQLITE_ROW ){ |
| 614 | const char *zTagName = db_column_text(&q2, 0); |
| 615 | @ | %z(href("%R/timeline?r=%T",zTagName))%h(zTagName)</a> |
| 616 | } |
| 617 | db_finalize(&q2); |
| 618 | |
| 619 | |
| 620 | /* The Download: line */ |
| @@ -629,12 +629,13 @@ | |
| 629 | fossil_free(zUrl); |
| 630 | } |
| 631 | @ </td></tr> |
| 632 | @ <tr><th>Other Links:</th> |
| 633 | @ <td> |
| 634 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 635 | @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> |
| 636 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 637 | if( g.perm.Write ){ |
| 638 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| 639 | } |
| 640 | @ </td> |
| @@ -1367,17 +1368,23 @@ | |
| 1367 | ** Return the uninterpreted content of an artifact. Used primarily |
| 1368 | ** to view artifacts that are images. |
| 1369 | */ |
| 1370 | void rawartifact_page(void){ |
| 1371 | int rid; |
| 1372 | const char *zMime; |
| 1373 | Blob content; |
| 1374 | |
| 1375 | rid = name_to_rid_www("name"); |
| 1376 | login_check_credentials(); |
| 1377 | if( !g.perm.Read ){ login_needed(); return; } |
| 1378 | if( rid==0 ) fossil_redirect_home(); |
| 1379 | zMime = P("m"); |
| 1380 | if( zMime==0 ){ |
| 1381 | char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename" |
| 1382 | " WHERE mlink.fid=%d" |
| 1383 | " AND filename.fnid=mlink.fnid", rid); |
| @@ -1674,16 +1681,16 @@ | |
| 1674 | @ sandbox="allow-same-origin" |
| 1675 | @ onload="this.height = this.contentDocument.documentElement.scrollHeight;"> |
| 1676 | @ </iframe> |
| 1677 | }else{ |
| 1678 | style_submenu_element("Hex","Hex", "%s/hexdump?name=%s", g.zTop, zUuid); |
| 1679 | zMime = mimetype_from_content(&content); |
| 1680 | @ <blockquote> |
| 1681 | if( zMime==0 ){ |
| 1682 | const char *zLn = P("ln"); |
| 1683 | const char *z; |
| 1684 | blob_to_utf8_no_bom(&content, 0); |
| 1685 | z = blob_str(&content); |
| 1686 | if( zLn ){ |
| 1687 | output_text_with_line_numbers(z, zLn); |
| 1688 | }else{ |
| 1689 | @ <pre> |
| 1690 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -230,15 +230,15 @@ | |
| 230 | Stmt q; |
| 231 | int cnt = 0; |
| 232 | db_prepare(&q, |
| 233 | "SELECT tag.tagid, tagname, " |
| 234 | " (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d)," |
| 235 | " value, datetime(tagxref.mtime%s), tagtype," |
| 236 | " (SELECT uuid FROM blob WHERE rid=tagxref.origid AND rid!=%d)" |
| 237 | " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid" |
| 238 | " WHERE tagxref.rid=%d AND tagname NOT GLOB '%q'" |
| 239 | " ORDER BY tagname /*sort*/", rid, timeline_utc(), rid, rid, zNotGlob |
| 240 | ); |
| 241 | while( db_step(&q)==SQLITE_ROW ){ |
| 242 | const char *zTagname = db_column_text(&q, 1); |
| 243 | const char *zSrcUuid = db_column_text(&q, 2); |
| 244 | const char *zValue = db_column_text(&q, 3); |
| @@ -503,16 +503,16 @@ | |
| 503 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 504 | rid |
| 505 | ); |
| 506 | isLeaf = is_a_leaf(rid); |
| 507 | db_prepare(&q1, |
| 508 | "SELECT uuid, datetime(mtime%s), user, comment," |
| 509 | " datetime(omtime%s), mtime" |
| 510 | " FROM blob, event" |
| 511 | " WHERE blob.rid=%d" |
| 512 | " AND event.objid=%d", |
| 513 | timeline_utc(), timeline_utc(), rid, rid |
| 514 | ); |
| 515 | sideBySide = !is_false(PD("sbs","1")); |
| 516 | if( db_step(&q1)==SQLITE_ROW ){ |
| 517 | const char *zUuid = db_column_text(&q1, 0); |
| 518 | char *zTitle = mprintf("Check-in [%.10s]", zUuid); |
| @@ -610,11 +610,11 @@ | |
| 610 | " WHERE rid=%d AND tagtype>0 " |
| 611 | " AND tag.tagid=tagxref.tagid " |
| 612 | " AND +tag.tagname GLOB 'sym-*'", rid); |
| 613 | while( db_step(&q2)==SQLITE_ROW ){ |
| 614 | const char *zTagName = db_column_text(&q2, 0); |
| 615 | @ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a> |
| 616 | } |
| 617 | db_finalize(&q2); |
| 618 | |
| 619 | |
| 620 | /* The Download: line */ |
| @@ -629,12 +629,13 @@ | |
| 629 | fossil_free(zUrl); |
| 630 | } |
| 631 | @ </td></tr> |
| 632 | @ <tr><th>Other Links:</th> |
| 633 | @ <td> |
| 634 | @ %z(href("%R/tree?ci=%S",zUuid))files</a> |
| 635 | @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> |
| 636 | @ | %z(href("%R/tree?ci=%S&nofiles",zUuid))folders</a> |
| 637 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 638 | if( g.perm.Write ){ |
| 639 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| 640 | } |
| 641 | @ </td> |
| @@ -1367,17 +1368,23 @@ | |
| 1368 | ** Return the uninterpreted content of an artifact. Used primarily |
| 1369 | ** to view artifacts that are images. |
| 1370 | */ |
| 1371 | void rawartifact_page(void){ |
| 1372 | int rid; |
| 1373 | char *zUuid; |
| 1374 | const char *zMime; |
| 1375 | Blob content; |
| 1376 | |
| 1377 | rid = name_to_rid_www("name"); |
| 1378 | login_check_credentials(); |
| 1379 | if( !g.perm.Read ){ login_needed(); return; } |
| 1380 | if( rid==0 ) fossil_redirect_home(); |
| 1381 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1382 | if( fossil_strcmp(P("name"), zUuid)==0 ){ |
| 1383 | g.isConst = 1; |
| 1384 | } |
| 1385 | free(zUuid); |
| 1386 | zMime = P("m"); |
| 1387 | if( zMime==0 ){ |
| 1388 | char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename" |
| 1389 | " WHERE mlink.fid=%d" |
| 1390 | " AND filename.fnid=mlink.fnid", rid); |
| @@ -1674,16 +1681,16 @@ | |
| 1681 | @ sandbox="allow-same-origin" |
| 1682 | @ onload="this.height = this.contentDocument.documentElement.scrollHeight;"> |
| 1683 | @ </iframe> |
| 1684 | }else{ |
| 1685 | style_submenu_element("Hex","Hex", "%s/hexdump?name=%s", g.zTop, zUuid); |
| 1686 | blob_to_utf8_no_bom(&content, 0); |
| 1687 | zMime = mimetype_from_content(&content); |
| 1688 | @ <blockquote> |
| 1689 | if( zMime==0 ){ |
| 1690 | const char *zLn = P("ln"); |
| 1691 | const char *z; |
| 1692 | z = blob_str(&content); |
| 1693 | if( zLn ){ |
| 1694 | output_text_with_line_numbers(z, zLn); |
| 1695 | }else{ |
| 1696 | @ <pre> |
| 1697 |
+44
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -377,10 +377,20 @@ | ||
| 377 | 377 | #endif |
| 378 | 378 | free(g.zErrMsg); |
| 379 | 379 | if(g.db){ |
| 380 | 380 | db_close(0); |
| 381 | 381 | } |
| 382 | + /* | |
| 383 | + ** FIXME: The next two lines cannot always be enabled; however, they | |
| 384 | + ** are very useful for tracking down TH1 memory leaks. | |
| 385 | + */ | |
| 386 | + if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){ | |
| 387 | + if( g.interp ){ | |
| 388 | + Th_DeleteInterp(g.interp); g.interp = 0; | |
| 389 | + } | |
| 390 | + assert( Th_GetOutstandingMalloc()==0 ); | |
| 391 | + } | |
| 382 | 392 | } |
| 383 | 393 | |
| 384 | 394 | /* |
| 385 | 395 | ** Convert all arguments from mbcs (or unicode) to UTF-8. Then |
| 386 | 396 | ** search g.argv for arguments "--args FILENAME". If found, then |
| @@ -559,10 +569,14 @@ | ||
| 559 | 569 | #endif |
| 560 | 570 | { |
| 561 | 571 | const char *zCmdName = "unknown"; |
| 562 | 572 | int idx; |
| 563 | 573 | int rc; |
| 574 | + if( sqlite3_libversion_number()<3008002 ){ | |
| 575 | + fossil_fatal("Unsuitable SQLite version %s, must be at least 3.8.2", | |
| 576 | + sqlite3_libversion()); | |
| 577 | + } | |
| 564 | 578 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 565 | 579 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 566 | 580 | memset(&g, 0, sizeof(g)); |
| 567 | 581 | g.now = time(0); |
| 568 | 582 | g.httpHeader = empty_blob; |
| @@ -1072,10 +1086,40 @@ | ||
| 1072 | 1086 | if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ |
| 1073 | 1087 | @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li> |
| 1074 | 1088 | }else{ |
| 1075 | 1089 | @ <li>%s(z+1)</li> |
| 1076 | 1090 | } |
| 1091 | + j++; | |
| 1092 | + if( j>=n ){ | |
| 1093 | + @ </ul></td> | |
| 1094 | + j = 0; | |
| 1095 | + } | |
| 1096 | + } | |
| 1097 | + if( j>0 ){ | |
| 1098 | + @ </ul></td> | |
| 1099 | + } | |
| 1100 | + @ </tr></table> | |
| 1101 | + | |
| 1102 | + @ <h1>Unsupported commands:</h1> | |
| 1103 | + @ <table border="0"><tr> | |
| 1104 | + for(i=j=0; i<count(aCommand); i++){ | |
| 1105 | + const char *z = aCommand[i].zName; | |
| 1106 | + if( strncmp(z,"test",4)!=0 ) continue; | |
| 1107 | + j++; | |
| 1108 | + } | |
| 1109 | + n = (j+3)/4; | |
| 1110 | + for(i=j=0; i<count(aCommand); i++){ | |
| 1111 | + const char *z = aCommand[i].zName; | |
| 1112 | + if( strncmp(z,"test",4)!=0 ) continue; | |
| 1113 | + if( j==0 ){ | |
| 1114 | + @ <td valign="top"><ul> | |
| 1115 | + } | |
| 1116 | + if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ | |
| 1117 | + @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a></li> | |
| 1118 | + }else{ | |
| 1119 | + @ <li>%s(z)</li> | |
| 1120 | + } | |
| 1077 | 1121 | j++; |
| 1078 | 1122 | if( j>=n ){ |
| 1079 | 1123 | @ </ul></td> |
| 1080 | 1124 | j = 0; |
| 1081 | 1125 | } |
| 1082 | 1126 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -377,10 +377,20 @@ | |
| 377 | #endif |
| 378 | free(g.zErrMsg); |
| 379 | if(g.db){ |
| 380 | db_close(0); |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | /* |
| 385 | ** Convert all arguments from mbcs (or unicode) to UTF-8. Then |
| 386 | ** search g.argv for arguments "--args FILENAME". If found, then |
| @@ -559,10 +569,14 @@ | |
| 559 | #endif |
| 560 | { |
| 561 | const char *zCmdName = "unknown"; |
| 562 | int idx; |
| 563 | int rc; |
| 564 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 565 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 566 | memset(&g, 0, sizeof(g)); |
| 567 | g.now = time(0); |
| 568 | g.httpHeader = empty_blob; |
| @@ -1072,10 +1086,40 @@ | |
| 1072 | if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ |
| 1073 | @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li> |
| 1074 | }else{ |
| 1075 | @ <li>%s(z+1)</li> |
| 1076 | } |
| 1077 | j++; |
| 1078 | if( j>=n ){ |
| 1079 | @ </ul></td> |
| 1080 | j = 0; |
| 1081 | } |
| 1082 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -377,10 +377,20 @@ | |
| 377 | #endif |
| 378 | free(g.zErrMsg); |
| 379 | if(g.db){ |
| 380 | db_close(0); |
| 381 | } |
| 382 | /* |
| 383 | ** FIXME: The next two lines cannot always be enabled; however, they |
| 384 | ** are very useful for tracking down TH1 memory leaks. |
| 385 | */ |
| 386 | if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){ |
| 387 | if( g.interp ){ |
| 388 | Th_DeleteInterp(g.interp); g.interp = 0; |
| 389 | } |
| 390 | assert( Th_GetOutstandingMalloc()==0 ); |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | /* |
| 395 | ** Convert all arguments from mbcs (or unicode) to UTF-8. Then |
| 396 | ** search g.argv for arguments "--args FILENAME". If found, then |
| @@ -559,10 +569,14 @@ | |
| 569 | #endif |
| 570 | { |
| 571 | const char *zCmdName = "unknown"; |
| 572 | int idx; |
| 573 | int rc; |
| 574 | if( sqlite3_libversion_number()<3008002 ){ |
| 575 | fossil_fatal("Unsuitable SQLite version %s, must be at least 3.8.2", |
| 576 | sqlite3_libversion()); |
| 577 | } |
| 578 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 579 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 580 | memset(&g, 0, sizeof(g)); |
| 581 | g.now = time(0); |
| 582 | g.httpHeader = empty_blob; |
| @@ -1072,10 +1086,40 @@ | |
| 1086 | if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ |
| 1087 | @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li> |
| 1088 | }else{ |
| 1089 | @ <li>%s(z+1)</li> |
| 1090 | } |
| 1091 | j++; |
| 1092 | if( j>=n ){ |
| 1093 | @ </ul></td> |
| 1094 | j = 0; |
| 1095 | } |
| 1096 | } |
| 1097 | if( j>0 ){ |
| 1098 | @ </ul></td> |
| 1099 | } |
| 1100 | @ </tr></table> |
| 1101 | |
| 1102 | @ <h1>Unsupported commands:</h1> |
| 1103 | @ <table border="0"><tr> |
| 1104 | for(i=j=0; i<count(aCommand); i++){ |
| 1105 | const char *z = aCommand[i].zName; |
| 1106 | if( strncmp(z,"test",4)!=0 ) continue; |
| 1107 | j++; |
| 1108 | } |
| 1109 | n = (j+3)/4; |
| 1110 | for(i=j=0; i<count(aCommand); i++){ |
| 1111 | const char *z = aCommand[i].zName; |
| 1112 | if( strncmp(z,"test",4)!=0 ) continue; |
| 1113 | if( j==0 ){ |
| 1114 | @ <td valign="top"><ul> |
| 1115 | } |
| 1116 | if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ |
| 1117 | @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a></li> |
| 1118 | }else{ |
| 1119 | @ <li>%s(z)</li> |
| 1120 | } |
| 1121 | j++; |
| 1122 | if( j>=n ){ |
| 1123 | @ </ul></td> |
| 1124 | j = 0; |
| 1125 | } |
| 1126 |
+44
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -377,10 +377,20 @@ | ||
| 377 | 377 | #endif |
| 378 | 378 | free(g.zErrMsg); |
| 379 | 379 | if(g.db){ |
| 380 | 380 | db_close(0); |
| 381 | 381 | } |
| 382 | + /* | |
| 383 | + ** FIXME: The next two lines cannot always be enabled; however, they | |
| 384 | + ** are very useful for tracking down TH1 memory leaks. | |
| 385 | + */ | |
| 386 | + if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){ | |
| 387 | + if( g.interp ){ | |
| 388 | + Th_DeleteInterp(g.interp); g.interp = 0; | |
| 389 | + } | |
| 390 | + assert( Th_GetOutstandingMalloc()==0 ); | |
| 391 | + } | |
| 382 | 392 | } |
| 383 | 393 | |
| 384 | 394 | /* |
| 385 | 395 | ** Convert all arguments from mbcs (or unicode) to UTF-8. Then |
| 386 | 396 | ** search g.argv for arguments "--args FILENAME". If found, then |
| @@ -559,10 +569,14 @@ | ||
| 559 | 569 | #endif |
| 560 | 570 | { |
| 561 | 571 | const char *zCmdName = "unknown"; |
| 562 | 572 | int idx; |
| 563 | 573 | int rc; |
| 574 | + if( sqlite3_libversion_number()<3008002 ){ | |
| 575 | + fossil_fatal("Unsuitable SQLite version %s, must be at least 3.8.2", | |
| 576 | + sqlite3_libversion()); | |
| 577 | + } | |
| 564 | 578 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 565 | 579 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 566 | 580 | memset(&g, 0, sizeof(g)); |
| 567 | 581 | g.now = time(0); |
| 568 | 582 | g.httpHeader = empty_blob; |
| @@ -1072,10 +1086,40 @@ | ||
| 1072 | 1086 | if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ |
| 1073 | 1087 | @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li> |
| 1074 | 1088 | }else{ |
| 1075 | 1089 | @ <li>%s(z+1)</li> |
| 1076 | 1090 | } |
| 1091 | + j++; | |
| 1092 | + if( j>=n ){ | |
| 1093 | + @ </ul></td> | |
| 1094 | + j = 0; | |
| 1095 | + } | |
| 1096 | + } | |
| 1097 | + if( j>0 ){ | |
| 1098 | + @ </ul></td> | |
| 1099 | + } | |
| 1100 | + @ </tr></table> | |
| 1101 | + | |
| 1102 | + @ <h1>Unsupported commands:</h1> | |
| 1103 | + @ <table border="0"><tr> | |
| 1104 | + for(i=j=0; i<count(aCommand); i++){ | |
| 1105 | + const char *z = aCommand[i].zName; | |
| 1106 | + if( strncmp(z,"test",4)!=0 ) continue; | |
| 1107 | + j++; | |
| 1108 | + } | |
| 1109 | + n = (j+3)/4; | |
| 1110 | + for(i=j=0; i<count(aCommand); i++){ | |
| 1111 | + const char *z = aCommand[i].zName; | |
| 1112 | + if( strncmp(z,"test",4)!=0 ) continue; | |
| 1113 | + if( j==0 ){ | |
| 1114 | + @ <td valign="top"><ul> | |
| 1115 | + } | |
| 1116 | + if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ | |
| 1117 | + @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a></li> | |
| 1118 | + }else{ | |
| 1119 | + @ <li>%s(z)</li> | |
| 1120 | + } | |
| 1077 | 1121 | j++; |
| 1078 | 1122 | if( j>=n ){ |
| 1079 | 1123 | @ </ul></td> |
| 1080 | 1124 | j = 0; |
| 1081 | 1125 | } |
| 1082 | 1126 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -377,10 +377,20 @@ | |
| 377 | #endif |
| 378 | free(g.zErrMsg); |
| 379 | if(g.db){ |
| 380 | db_close(0); |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | /* |
| 385 | ** Convert all arguments from mbcs (or unicode) to UTF-8. Then |
| 386 | ** search g.argv for arguments "--args FILENAME". If found, then |
| @@ -559,10 +569,14 @@ | |
| 559 | #endif |
| 560 | { |
| 561 | const char *zCmdName = "unknown"; |
| 562 | int idx; |
| 563 | int rc; |
| 564 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 565 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 566 | memset(&g, 0, sizeof(g)); |
| 567 | g.now = time(0); |
| 568 | g.httpHeader = empty_blob; |
| @@ -1072,10 +1086,40 @@ | |
| 1072 | if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ |
| 1073 | @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li> |
| 1074 | }else{ |
| 1075 | @ <li>%s(z+1)</li> |
| 1076 | } |
| 1077 | j++; |
| 1078 | if( j>=n ){ |
| 1079 | @ </ul></td> |
| 1080 | j = 0; |
| 1081 | } |
| 1082 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -377,10 +377,20 @@ | |
| 377 | #endif |
| 378 | free(g.zErrMsg); |
| 379 | if(g.db){ |
| 380 | db_close(0); |
| 381 | } |
| 382 | /* |
| 383 | ** FIXME: The next two lines cannot always be enabled; however, they |
| 384 | ** are very useful for tracking down TH1 memory leaks. |
| 385 | */ |
| 386 | if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){ |
| 387 | if( g.interp ){ |
| 388 | Th_DeleteInterp(g.interp); g.interp = 0; |
| 389 | } |
| 390 | assert( Th_GetOutstandingMalloc()==0 ); |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | /* |
| 395 | ** Convert all arguments from mbcs (or unicode) to UTF-8. Then |
| 396 | ** search g.argv for arguments "--args FILENAME". If found, then |
| @@ -559,10 +569,14 @@ | |
| 569 | #endif |
| 570 | { |
| 571 | const char *zCmdName = "unknown"; |
| 572 | int idx; |
| 573 | int rc; |
| 574 | if( sqlite3_libversion_number()<3008002 ){ |
| 575 | fossil_fatal("Unsuitable SQLite version %s, must be at least 3.8.2", |
| 576 | sqlite3_libversion()); |
| 577 | } |
| 578 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 579 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 580 | memset(&g, 0, sizeof(g)); |
| 581 | g.now = time(0); |
| 582 | g.httpHeader = empty_blob; |
| @@ -1072,10 +1086,40 @@ | |
| 1086 | if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ |
| 1087 | @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z+1)</a></li> |
| 1088 | }else{ |
| 1089 | @ <li>%s(z+1)</li> |
| 1090 | } |
| 1091 | j++; |
| 1092 | if( j>=n ){ |
| 1093 | @ </ul></td> |
| 1094 | j = 0; |
| 1095 | } |
| 1096 | } |
| 1097 | if( j>0 ){ |
| 1098 | @ </ul></td> |
| 1099 | } |
| 1100 | @ </tr></table> |
| 1101 | |
| 1102 | @ <h1>Unsupported commands:</h1> |
| 1103 | @ <table border="0"><tr> |
| 1104 | for(i=j=0; i<count(aCommand); i++){ |
| 1105 | const char *z = aCommand[i].zName; |
| 1106 | if( strncmp(z,"test",4)!=0 ) continue; |
| 1107 | j++; |
| 1108 | } |
| 1109 | n = (j+3)/4; |
| 1110 | for(i=j=0; i<count(aCommand); i++){ |
| 1111 | const char *z = aCommand[i].zName; |
| 1112 | if( strncmp(z,"test",4)!=0 ) continue; |
| 1113 | if( j==0 ){ |
| 1114 | @ <td valign="top"><ul> |
| 1115 | } |
| 1116 | if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){ |
| 1117 | @ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a></li> |
| 1118 | }else{ |
| 1119 | @ <li>%s(z)</li> |
| 1120 | } |
| 1121 | j++; |
| 1122 | if( j>=n ){ |
| 1123 | @ </ul></td> |
| 1124 | j = 0; |
| 1125 | } |
| 1126 |
+4
-6
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -376,39 +376,37 @@ | ||
| 376 | 376 | |
| 377 | 377 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion |
| 378 | 378 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h |
| 379 | 379 | |
| 380 | 380 | # Setup the options used to compile the included SQLite library. |
| 381 | -SQLITE_OPTIONS = -Dlocaltime=fossil_localtime \ | |
| 382 | - -DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 381 | +SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 383 | 382 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 384 | 383 | -DSQLITE_THREADSAFE=0 \ |
| 385 | 384 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 386 | 385 | -DSQLITE_OMIT_DEPRECATED \ |
| 387 | 386 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 388 | 387 | |
| 389 | 388 | # Setup the options used to compile the included SQLite shell. |
| 390 | 389 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 391 | - -DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 392 | - -Dsqlite3_strglob=strglob | |
| 390 | + -DSQLITE_OMIT_LOAD_EXTENSION=1 | |
| 393 | 391 | |
| 394 | 392 | # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set |
| 395 | 393 | # to 1. If it is set to 1, then there is no need to build or link |
| 396 | 394 | # the sqlite3.o object. Instead, the system sqlite will be linked |
| 397 | 395 | # using -lsqlite3. |
| 398 | 396 | SQLITE3_OBJ.1 = |
| 399 | -SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o | |
| 397 | +SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o | |
| 400 | 398 | SQLITE3_OBJ. = $(SQLITE3_OBJ.0) |
| 401 | 399 | |
| 402 | 400 | # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1. |
| 403 | 401 | # If it is set to 1, then we need to build the Tcl integration code and |
| 404 | 402 | # link to the Tcl library. |
| 405 | 403 | TCL_OBJ.0 = |
| 406 | 404 | TCL_OBJ.1 = $(OBJDIR)/th_tcl.o |
| 407 | 405 | TCL_OBJ. = $(TCL_OBJ.0) |
| 408 | 406 | |
| 409 | -EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) $(OBJDIR)/cson_amalgamation.o | |
| 407 | +EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) $(OBJDIR)/cson_amalgamation.o | |
| 410 | 408 | |
| 411 | 409 | $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) |
| 412 | 410 | $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) |
| 413 | 411 | |
| 414 | 412 | # This rule prevents make from using its default rules to try build |
| 415 | 413 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -376,39 +376,37 @@ | |
| 376 | |
| 377 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion |
| 378 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h |
| 379 | |
| 380 | # Setup the options used to compile the included SQLite library. |
| 381 | SQLITE_OPTIONS = -Dlocaltime=fossil_localtime \ |
| 382 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 383 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 384 | -DSQLITE_THREADSAFE=0 \ |
| 385 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 386 | -DSQLITE_OMIT_DEPRECATED \ |
| 387 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 388 | |
| 389 | # Setup the options used to compile the included SQLite shell. |
| 390 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 391 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 392 | -Dsqlite3_strglob=strglob |
| 393 | |
| 394 | # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set |
| 395 | # to 1. If it is set to 1, then there is no need to build or link |
| 396 | # the sqlite3.o object. Instead, the system sqlite will be linked |
| 397 | # using -lsqlite3. |
| 398 | SQLITE3_OBJ.1 = |
| 399 | SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o |
| 400 | SQLITE3_OBJ. = $(SQLITE3_OBJ.0) |
| 401 | |
| 402 | # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1. |
| 403 | # If it is set to 1, then we need to build the Tcl integration code and |
| 404 | # link to the Tcl library. |
| 405 | TCL_OBJ.0 = |
| 406 | TCL_OBJ.1 = $(OBJDIR)/th_tcl.o |
| 407 | TCL_OBJ. = $(TCL_OBJ.0) |
| 408 | |
| 409 | EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/shell.o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) $(OBJDIR)/cson_amalgamation.o |
| 410 | |
| 411 | $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) |
| 412 | $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) |
| 413 | |
| 414 | # This rule prevents make from using its default rules to try build |
| 415 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -376,39 +376,37 @@ | |
| 376 | |
| 377 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion |
| 378 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h |
| 379 | |
| 380 | # Setup the options used to compile the included SQLite library. |
| 381 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 382 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 383 | -DSQLITE_THREADSAFE=0 \ |
| 384 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 385 | -DSQLITE_OMIT_DEPRECATED \ |
| 386 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 387 | |
| 388 | # Setup the options used to compile the included SQLite shell. |
| 389 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 390 | -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 391 | |
| 392 | # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set |
| 393 | # to 1. If it is set to 1, then there is no need to build or link |
| 394 | # the sqlite3.o object. Instead, the system sqlite will be linked |
| 395 | # using -lsqlite3. |
| 396 | SQLITE3_OBJ.1 = |
| 397 | SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o |
| 398 | SQLITE3_OBJ. = $(SQLITE3_OBJ.0) |
| 399 | |
| 400 | # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1. |
| 401 | # If it is set to 1, then we need to build the Tcl integration code and |
| 402 | # link to the Tcl library. |
| 403 | TCL_OBJ.0 = |
| 404 | TCL_OBJ.1 = $(OBJDIR)/th_tcl.o |
| 405 | TCL_OBJ. = $(TCL_OBJ.0) |
| 406 | |
| 407 | EXTRAOBJ = $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) $(OBJDIR)/th.o $(OBJDIR)/th_lang.o $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) $(OBJDIR)/cson_amalgamation.o |
| 408 | |
| 409 | $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) |
| 410 | $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) |
| 411 | |
| 412 | # This rule prevents make from using its default rules to try build |
| 413 |
+14
-15
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -129,11 +129,10 @@ | ||
| 129 | 129 | } |
| 130 | 130 | |
| 131 | 131 | # Options used to compile the included SQLite library. |
| 132 | 132 | # |
| 133 | 133 | set SQLITE_OPTIONS { |
| 134 | - -Dlocaltime=fossil_localtime | |
| 135 | 134 | -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 136 | 135 | -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 137 | 136 | -DSQLITE_THREADSAFE=0 |
| 138 | 137 | -DSQLITE_DEFAULT_FILE_FORMAT=4 |
| 139 | 138 | -DSQLITE_OMIT_DEPRECATED |
| @@ -147,11 +146,10 @@ | ||
| 147 | 146 | # Options used to compile the included SQLite shell. |
| 148 | 147 | # |
| 149 | 148 | set SHELL_OPTIONS { |
| 150 | 149 | -Dmain=sqlite3_shell |
| 151 | 150 | -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 152 | - -Dsqlite3_strglob=strglob | |
| 153 | 151 | } |
| 154 | 152 | |
| 155 | 153 | # Options used to compile the included SQLite shell on Windows. |
| 156 | 154 | # |
| 157 | 155 | set SHELL_WIN32_OPTIONS $SHELL_OPTIONS |
| @@ -263,11 +261,11 @@ | ||
| 263 | 261 | # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set |
| 264 | 262 | # to 1. If it is set to 1, then there is no need to build or link |
| 265 | 263 | # the sqlite3.o object. Instead, the system sqlite will be linked |
| 266 | 264 | # using -lsqlite3. |
| 267 | 265 | SQLITE3_OBJ.1 = |
| 268 | -SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o | |
| 266 | +SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o | |
| 269 | 267 | SQLITE3_OBJ. = $(SQLITE3_OBJ.0) |
| 270 | 268 | |
| 271 | 269 | # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1. |
| 272 | 270 | # If it is set to 1, then we need to build the Tcl integration code and |
| 273 | 271 | # link to the Tcl library. |
| @@ -275,11 +273,10 @@ | ||
| 275 | 273 | TCL_OBJ.1 = $(OBJDIR)/th_tcl.o |
| 276 | 274 | TCL_OBJ. = $(TCL_OBJ.0) |
| 277 | 275 | |
| 278 | 276 | EXTRAOBJ = \ |
| 279 | 277 | $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ |
| 280 | - $(OBJDIR)/shell.o \ | |
| 281 | 278 | $(OBJDIR)/th.o \ |
| 282 | 279 | $(OBJDIR)/th_lang.o \ |
| 283 | 280 | $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) \ |
| 284 | 281 | $(OBJDIR)/cson_amalgamation.o |
| 285 | 282 | |
| @@ -449,12 +446,12 @@ | ||
| 449 | 446 | #### The directories where the OpenSSL include and library files are located. |
| 450 | 447 | # The recommended usage here is to use the Sysinternals junction tool |
| 451 | 448 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 452 | 449 | # Fossil source code directory and the target OpenSSL source directory. |
| 453 | 450 | # |
| 454 | -OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1e/include | |
| 455 | -OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1e | |
| 451 | +OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include | |
| 452 | +OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f | |
| 456 | 453 | |
| 457 | 454 | #### Either the directory where the Tcl library is installed or the Tcl |
| 458 | 455 | # source code directory resides (depending on the value of the macro |
| 459 | 456 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 460 | 457 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -806,18 +803,18 @@ | ||
| 806 | 803 | set j " \\\n " |
| 807 | 804 | writeln "SQLITE_OPTIONS = [join $MINGW_SQLITE_OPTIONS $j]\n" |
| 808 | 805 | set j " \\\n " |
| 809 | 806 | writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS $j]\n" |
| 810 | 807 | |
| 811 | -writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c" | |
| 808 | +writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c win/Makefile.mingw" | |
| 812 | 809 | writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n" |
| 813 | 810 | |
| 814 | 811 | writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c" |
| 815 | 812 | writeln "\t\$(XTCC) -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n" |
| 816 | 813 | writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_status.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n" |
| 817 | 814 | |
| 818 | -writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h" | |
| 815 | +writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h win/Makefile.mingw" | |
| 819 | 816 | writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n" |
| 820 | 817 | |
| 821 | 818 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 822 | 819 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" |
| 823 | 820 | |
| @@ -1019,12 +1016,12 @@ | ||
| 1019 | 1016 | |
| 1020 | 1017 | # Uncomment to enable SSL support |
| 1021 | 1018 | # FOSSIL_ENABLE_SSL = 1 |
| 1022 | 1019 | |
| 1023 | 1020 | !ifdef FOSSIL_ENABLE_SSL |
| 1024 | -SSLINCDIR = $(B)\compat\openssl-1.0.1e\include | |
| 1025 | -SSLLIBDIR = $(B)\compat\openssl-1.0.1e\out32 | |
| 1021 | +SSLINCDIR = $(B)\compat\openssl-1.0.1f\include | |
| 1022 | +SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32 | |
| 1026 | 1023 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1027 | 1024 | !endif |
| 1028 | 1025 | |
| 1029 | 1026 | # zlib options |
| 1030 | 1027 | ZINCDIR = $(B)\compat\zlib |
| @@ -1035,16 +1032,18 @@ | ||
| 1035 | 1032 | |
| 1036 | 1033 | !ifdef FOSSIL_ENABLE_SSL |
| 1037 | 1034 | INCL = $(INCL) -I$(SSLINCDIR) |
| 1038 | 1035 | !endif |
| 1039 | 1036 | |
| 1040 | -CFLAGS = -nologo -MT -O2 | |
| 1037 | +CFLAGS = -nologo | |
| 1041 | 1038 | LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO |
| 1042 | 1039 | |
| 1043 | 1040 | !ifdef DEBUG |
| 1044 | -CFLAGS = $(CFLAGS) -Zi | |
| 1041 | +CFLAGS = $(CFLAGS) -Zi -MTd -Od | |
| 1045 | 1042 | LDFLAGS = $(LDFLAGS) /DEBUG |
| 1043 | +!else | |
| 1044 | +CFLAGS = $(CFLAGS) -MT -O2 | |
| 1046 | 1045 | !endif |
| 1047 | 1046 | |
| 1048 | 1047 | BCC = $(CC) $(CFLAGS) |
| 1049 | 1048 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL) |
| 1050 | 1049 | RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL) |
| @@ -1130,15 +1129,15 @@ | ||
| 1130 | 1129 | $(BCC) $** |
| 1131 | 1130 | |
| 1132 | 1131 | mkversion$E: $B\src\mkversion.c |
| 1133 | 1132 | $(BCC) $** |
| 1134 | 1133 | |
| 1135 | -$(OX)\shell$O : $(SRCDIR)\shell.c | |
| 1134 | +$(OX)\shell$O : $(SRCDIR)\shell.c $B\win\Makefile.msc | |
| 1136 | 1135 | $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c |
| 1137 | 1136 | |
| 1138 | -$(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c | |
| 1139 | - $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** | |
| 1137 | +$(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c $B\win\Makefile.msc | |
| 1138 | + $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SRCDIR)\sqlite3.c | |
| 1140 | 1139 | |
| 1141 | 1140 | $(OX)\th$O : $(SRCDIR)\th.c |
| 1142 | 1141 | $(TCC) /Fo$@ -c $** |
| 1143 | 1142 | |
| 1144 | 1143 | $(OX)\th_lang$O : $(SRCDIR)\th_lang.c |
| 1145 | 1144 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -129,11 +129,10 @@ | |
| 129 | } |
| 130 | |
| 131 | # Options used to compile the included SQLite library. |
| 132 | # |
| 133 | set SQLITE_OPTIONS { |
| 134 | -Dlocaltime=fossil_localtime |
| 135 | -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 136 | -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 137 | -DSQLITE_THREADSAFE=0 |
| 138 | -DSQLITE_DEFAULT_FILE_FORMAT=4 |
| 139 | -DSQLITE_OMIT_DEPRECATED |
| @@ -147,11 +146,10 @@ | |
| 147 | # Options used to compile the included SQLite shell. |
| 148 | # |
| 149 | set SHELL_OPTIONS { |
| 150 | -Dmain=sqlite3_shell |
| 151 | -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 152 | -Dsqlite3_strglob=strglob |
| 153 | } |
| 154 | |
| 155 | # Options used to compile the included SQLite shell on Windows. |
| 156 | # |
| 157 | set SHELL_WIN32_OPTIONS $SHELL_OPTIONS |
| @@ -263,11 +261,11 @@ | |
| 263 | # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set |
| 264 | # to 1. If it is set to 1, then there is no need to build or link |
| 265 | # the sqlite3.o object. Instead, the system sqlite will be linked |
| 266 | # using -lsqlite3. |
| 267 | SQLITE3_OBJ.1 = |
| 268 | SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o |
| 269 | SQLITE3_OBJ. = $(SQLITE3_OBJ.0) |
| 270 | |
| 271 | # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1. |
| 272 | # If it is set to 1, then we need to build the Tcl integration code and |
| 273 | # link to the Tcl library. |
| @@ -275,11 +273,10 @@ | |
| 275 | TCL_OBJ.1 = $(OBJDIR)/th_tcl.o |
| 276 | TCL_OBJ. = $(TCL_OBJ.0) |
| 277 | |
| 278 | EXTRAOBJ = \ |
| 279 | $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ |
| 280 | $(OBJDIR)/shell.o \ |
| 281 | $(OBJDIR)/th.o \ |
| 282 | $(OBJDIR)/th_lang.o \ |
| 283 | $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) \ |
| 284 | $(OBJDIR)/cson_amalgamation.o |
| 285 | |
| @@ -449,12 +446,12 @@ | |
| 449 | #### The directories where the OpenSSL include and library files are located. |
| 450 | # The recommended usage here is to use the Sysinternals junction tool |
| 451 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 452 | # Fossil source code directory and the target OpenSSL source directory. |
| 453 | # |
| 454 | OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1e/include |
| 455 | OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1e |
| 456 | |
| 457 | #### Either the directory where the Tcl library is installed or the Tcl |
| 458 | # source code directory resides (depending on the value of the macro |
| 459 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 460 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -806,18 +803,18 @@ | |
| 806 | set j " \\\n " |
| 807 | writeln "SQLITE_OPTIONS = [join $MINGW_SQLITE_OPTIONS $j]\n" |
| 808 | set j " \\\n " |
| 809 | writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS $j]\n" |
| 810 | |
| 811 | writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c" |
| 812 | writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n" |
| 813 | |
| 814 | writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c" |
| 815 | writeln "\t\$(XTCC) -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n" |
| 816 | writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_status.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n" |
| 817 | |
| 818 | writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h" |
| 819 | writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n" |
| 820 | |
| 821 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 822 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" |
| 823 | |
| @@ -1019,12 +1016,12 @@ | |
| 1019 | |
| 1020 | # Uncomment to enable SSL support |
| 1021 | # FOSSIL_ENABLE_SSL = 1 |
| 1022 | |
| 1023 | !ifdef FOSSIL_ENABLE_SSL |
| 1024 | SSLINCDIR = $(B)\compat\openssl-1.0.1e\include |
| 1025 | SSLLIBDIR = $(B)\compat\openssl-1.0.1e\out32 |
| 1026 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1027 | !endif |
| 1028 | |
| 1029 | # zlib options |
| 1030 | ZINCDIR = $(B)\compat\zlib |
| @@ -1035,16 +1032,18 @@ | |
| 1035 | |
| 1036 | !ifdef FOSSIL_ENABLE_SSL |
| 1037 | INCL = $(INCL) -I$(SSLINCDIR) |
| 1038 | !endif |
| 1039 | |
| 1040 | CFLAGS = -nologo -MT -O2 |
| 1041 | LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO |
| 1042 | |
| 1043 | !ifdef DEBUG |
| 1044 | CFLAGS = $(CFLAGS) -Zi |
| 1045 | LDFLAGS = $(LDFLAGS) /DEBUG |
| 1046 | !endif |
| 1047 | |
| 1048 | BCC = $(CC) $(CFLAGS) |
| 1049 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL) |
| 1050 | RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL) |
| @@ -1130,15 +1129,15 @@ | |
| 1130 | $(BCC) $** |
| 1131 | |
| 1132 | mkversion$E: $B\src\mkversion.c |
| 1133 | $(BCC) $** |
| 1134 | |
| 1135 | $(OX)\shell$O : $(SRCDIR)\shell.c |
| 1136 | $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c |
| 1137 | |
| 1138 | $(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c |
| 1139 | $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** |
| 1140 | |
| 1141 | $(OX)\th$O : $(SRCDIR)\th.c |
| 1142 | $(TCC) /Fo$@ -c $** |
| 1143 | |
| 1144 | $(OX)\th_lang$O : $(SRCDIR)\th_lang.c |
| 1145 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -129,11 +129,10 @@ | |
| 129 | } |
| 130 | |
| 131 | # Options used to compile the included SQLite library. |
| 132 | # |
| 133 | set SQLITE_OPTIONS { |
| 134 | -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 135 | -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 136 | -DSQLITE_THREADSAFE=0 |
| 137 | -DSQLITE_DEFAULT_FILE_FORMAT=4 |
| 138 | -DSQLITE_OMIT_DEPRECATED |
| @@ -147,11 +146,10 @@ | |
| 146 | # Options used to compile the included SQLite shell. |
| 147 | # |
| 148 | set SHELL_OPTIONS { |
| 149 | -Dmain=sqlite3_shell |
| 150 | -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 151 | } |
| 152 | |
| 153 | # Options used to compile the included SQLite shell on Windows. |
| 154 | # |
| 155 | set SHELL_WIN32_OPTIONS $SHELL_OPTIONS |
| @@ -263,11 +261,11 @@ | |
| 261 | # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set |
| 262 | # to 1. If it is set to 1, then there is no need to build or link |
| 263 | # the sqlite3.o object. Instead, the system sqlite will be linked |
| 264 | # using -lsqlite3. |
| 265 | SQLITE3_OBJ.1 = |
| 266 | SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o |
| 267 | SQLITE3_OBJ. = $(SQLITE3_OBJ.0) |
| 268 | |
| 269 | # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1. |
| 270 | # If it is set to 1, then we need to build the Tcl integration code and |
| 271 | # link to the Tcl library. |
| @@ -275,11 +273,10 @@ | |
| 273 | TCL_OBJ.1 = $(OBJDIR)/th_tcl.o |
| 274 | TCL_OBJ. = $(TCL_OBJ.0) |
| 275 | |
| 276 | EXTRAOBJ = \ |
| 277 | $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \ |
| 278 | $(OBJDIR)/th.o \ |
| 279 | $(OBJDIR)/th_lang.o \ |
| 280 | $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) \ |
| 281 | $(OBJDIR)/cson_amalgamation.o |
| 282 | |
| @@ -449,12 +446,12 @@ | |
| 446 | #### The directories where the OpenSSL include and library files are located. |
| 447 | # The recommended usage here is to use the Sysinternals junction tool |
| 448 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 449 | # Fossil source code directory and the target OpenSSL source directory. |
| 450 | # |
| 451 | OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include |
| 452 | OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f |
| 453 | |
| 454 | #### Either the directory where the Tcl library is installed or the Tcl |
| 455 | # source code directory resides (depending on the value of the macro |
| 456 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 457 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -806,18 +803,18 @@ | |
| 803 | set j " \\\n " |
| 804 | writeln "SQLITE_OPTIONS = [join $MINGW_SQLITE_OPTIONS $j]\n" |
| 805 | set j " \\\n " |
| 806 | writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS $j]\n" |
| 807 | |
| 808 | writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c win/Makefile.mingw" |
| 809 | writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n" |
| 810 | |
| 811 | writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c" |
| 812 | writeln "\t\$(XTCC) -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n" |
| 813 | writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_status.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n" |
| 814 | |
| 815 | writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h win/Makefile.mingw" |
| 816 | writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n" |
| 817 | |
| 818 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 819 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" |
| 820 | |
| @@ -1019,12 +1016,12 @@ | |
| 1016 | |
| 1017 | # Uncomment to enable SSL support |
| 1018 | # FOSSIL_ENABLE_SSL = 1 |
| 1019 | |
| 1020 | !ifdef FOSSIL_ENABLE_SSL |
| 1021 | SSLINCDIR = $(B)\compat\openssl-1.0.1f\include |
| 1022 | SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32 |
| 1023 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 1024 | !endif |
| 1025 | |
| 1026 | # zlib options |
| 1027 | ZINCDIR = $(B)\compat\zlib |
| @@ -1035,16 +1032,18 @@ | |
| 1032 | |
| 1033 | !ifdef FOSSIL_ENABLE_SSL |
| 1034 | INCL = $(INCL) -I$(SSLINCDIR) |
| 1035 | !endif |
| 1036 | |
| 1037 | CFLAGS = -nologo |
| 1038 | LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO |
| 1039 | |
| 1040 | !ifdef DEBUG |
| 1041 | CFLAGS = $(CFLAGS) -Zi -MTd -Od |
| 1042 | LDFLAGS = $(LDFLAGS) /DEBUG |
| 1043 | !else |
| 1044 | CFLAGS = $(CFLAGS) -MT -O2 |
| 1045 | !endif |
| 1046 | |
| 1047 | BCC = $(CC) $(CFLAGS) |
| 1048 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL) |
| 1049 | RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL) |
| @@ -1130,15 +1129,15 @@ | |
| 1129 | $(BCC) $** |
| 1130 | |
| 1131 | mkversion$E: $B\src\mkversion.c |
| 1132 | $(BCC) $** |
| 1133 | |
| 1134 | $(OX)\shell$O : $(SRCDIR)\shell.c $B\win\Makefile.msc |
| 1135 | $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c |
| 1136 | |
| 1137 | $(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c $B\win\Makefile.msc |
| 1138 | $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SRCDIR)\sqlite3.c |
| 1139 | |
| 1140 | $(OX)\th$O : $(SRCDIR)\th.c |
| 1141 | $(TCC) /Fo$@ -c $** |
| 1142 | |
| 1143 | $(OX)\th_lang$O : $(SRCDIR)\th_lang.c |
| 1144 |
+34
-16
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -1494,18 +1494,30 @@ | ||
| 1494 | 1494 | #endif /* LOCAL_INTERFACE */ |
| 1495 | 1495 | |
| 1496 | 1496 | /* |
| 1497 | 1497 | ** Finish up a sequence of manifest_crosslink calls. |
| 1498 | 1498 | */ |
| 1499 | -void manifest_crosslink_end(void){ | |
| 1499 | +int manifest_crosslink_end(int flags){ | |
| 1500 | 1500 | Stmt q, u; |
| 1501 | 1501 | int i; |
| 1502 | + int rc = TH_OK; | |
| 1503 | + int permitHooks = (flags & MC_PERMIT_HOOKS); | |
| 1504 | + const char *zScript = 0; | |
| 1502 | 1505 | assert( manifest_crosslink_busy==1 ); |
| 1506 | + if( permitHooks ){ | |
| 1507 | + rc = xfer_run_common_script(); | |
| 1508 | + if( rc==TH_OK ){ | |
| 1509 | + zScript = xfer_ticket_code(); | |
| 1510 | + } | |
| 1511 | + } | |
| 1503 | 1512 | db_prepare(&q, "SELECT uuid FROM pending_tkt"); |
| 1504 | 1513 | while( db_step(&q)==SQLITE_ROW ){ |
| 1505 | 1514 | const char *zUuid = db_column_text(&q, 0); |
| 1506 | 1515 | ticket_rebuild_entry(zUuid); |
| 1516 | + if( permitHooks && rc==TH_OK ){ | |
| 1517 | + rc = xfer_run_script(zScript, zUuid); | |
| 1518 | + } | |
| 1507 | 1519 | } |
| 1508 | 1520 | db_finalize(&q); |
| 1509 | 1521 | db_multi_exec("DROP TABLE pending_tkt"); |
| 1510 | 1522 | |
| 1511 | 1523 | /* If multiple check-ins happen close together in time, adjust their |
| @@ -1528,18 +1540,21 @@ | ||
| 1528 | 1540 | db_step(&u); |
| 1529 | 1541 | db_reset(&u); |
| 1530 | 1542 | } |
| 1531 | 1543 | db_finalize(&q); |
| 1532 | 1544 | db_finalize(&u); |
| 1533 | - db_multi_exec( | |
| 1534 | - "UPDATE event SET mtime=(SELECT m1 FROM time_fudge WHERE mid=objid)" | |
| 1535 | - " WHERE objid IN (SELECT mid FROM time_fudge);" | |
| 1536 | - "DROP TABLE time_fudge;" | |
| 1537 | - ); | |
| 1545 | + if( db_exists("SELECT 1 FROM time_fudge") ){ | |
| 1546 | + db_multi_exec( | |
| 1547 | + "UPDATE event SET mtime=(SELECT m1 FROM time_fudge WHERE mid=objid)" | |
| 1548 | + " WHERE objid IN (SELECT mid FROM time_fudge);" | |
| 1549 | + ); | |
| 1550 | + } | |
| 1551 | + db_multi_exec("DROP TABLE time_fudge;"); | |
| 1538 | 1552 | |
| 1539 | 1553 | db_end_transaction(0); |
| 1540 | 1554 | manifest_crosslink_busy = 0; |
| 1555 | + return ( rc!=TH_ERROR ); | |
| 1541 | 1556 | } |
| 1542 | 1557 | |
| 1543 | 1558 | /* |
| 1544 | 1559 | ** Make an entry in the event table for a ticket change artifact. |
| 1545 | 1560 | */ |
| @@ -1657,14 +1672,15 @@ | ||
| 1657 | 1672 | ** Processing for other control artifacts was added later. The name |
| 1658 | 1673 | ** of the routine, "manifest_crosslink", and the name of this source |
| 1659 | 1674 | ** file, is a legacy of its original use. |
| 1660 | 1675 | */ |
| 1661 | 1676 | int manifest_crosslink(int rid, Blob *pContent, int flags){ |
| 1662 | - int i, result = TH_OK; | |
| 1677 | + int i, rc = TH_OK; | |
| 1663 | 1678 | Manifest *p; |
| 1664 | 1679 | Stmt q; |
| 1665 | 1680 | int parentid = 0; |
| 1681 | + int permitHooks = (flags & MC_PERMIT_HOOKS); | |
| 1666 | 1682 | const char *zScript = 0; |
| 1667 | 1683 | const char *zUuid = 0; |
| 1668 | 1684 | |
| 1669 | 1685 | if( (p = manifest_cache_find(rid))!=0 ){ |
| 1670 | 1686 | blob_reset(pContent); |
| @@ -1685,11 +1701,13 @@ | ||
| 1685 | 1701 | fossil_error(1, "cannot fetch baseline manifest"); |
| 1686 | 1702 | return 0; |
| 1687 | 1703 | } |
| 1688 | 1704 | db_begin_transaction(); |
| 1689 | 1705 | if( p->type==CFTYPE_MANIFEST ){ |
| 1690 | - zScript = xfer_commit_code(); | |
| 1706 | + if( permitHooks ){ | |
| 1707 | + zScript = xfer_commit_code(); | |
| 1708 | + } | |
| 1691 | 1709 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1692 | 1710 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ |
| 1693 | 1711 | char *zCom; |
| 1694 | 1712 | for(i=0; i<p->nParent; i++){ |
| 1695 | 1713 | int pid = uuid_to_rid(p->azParent[i], 1); |
| @@ -1883,12 +1901,10 @@ | ||
| 1883 | 1901 | } |
| 1884 | 1902 | } |
| 1885 | 1903 | if( p->type==CFTYPE_TICKET ){ |
| 1886 | 1904 | char *zTag; |
| 1887 | 1905 | |
| 1888 | - zScript = xfer_ticket_code(); | |
| 1889 | - zUuid = p->zTicketUuid; | |
| 1890 | 1906 | assert( manifest_crosslink_busy==1 ); |
| 1891 | 1907 | zTag = mprintf("tkt-%s", p->zTicketUuid); |
| 1892 | 1908 | tag_insert(zTag, 1, 0, rid, p->rDate, rid); |
| 1893 | 1909 | free(zTag); |
| 1894 | 1910 | db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)", |
| @@ -1968,11 +1984,13 @@ | ||
| 1968 | 1984 | zTagUuid); |
| 1969 | 1985 | branchMove = 0; |
| 1970 | 1986 | if( db_exists("SELECT 1 FROM event, blob" |
| 1971 | 1987 | " WHERE event.type='ci' AND event.objid=blob.rid" |
| 1972 | 1988 | " AND blob.uuid='%s'", zTagUuid) ){ |
| 1973 | - zScript = xfer_commit_code(); | |
| 1989 | + if( permitHooks ){ | |
| 1990 | + zScript = xfer_commit_code(); | |
| 1991 | + } | |
| 1974 | 1992 | zUuid = zTagUuid; |
| 1975 | 1993 | } |
| 1976 | 1994 | } |
| 1977 | 1995 | zName = p->aTag[i].zName; |
| 1978 | 1996 | zValue = p->aTag[i].zValue; |
| @@ -2042,23 +2060,23 @@ | ||
| 2042 | 2060 | p->rDate, rid, p->zUser, blob_str(&comment)+1 |
| 2043 | 2061 | ); |
| 2044 | 2062 | blob_reset(&comment); |
| 2045 | 2063 | } |
| 2046 | 2064 | db_end_transaction(0); |
| 2047 | - if( zScript && (flags & MC_PERMIT_HOOKS) ){ | |
| 2048 | - result = xfer_run_common_script(); | |
| 2049 | - if( result==TH_OK ){ | |
| 2050 | - result = xfer_run_script(zScript, zUuid); | |
| 2065 | + if( permitHooks ){ | |
| 2066 | + rc = xfer_run_common_script(); | |
| 2067 | + if( rc==TH_OK ){ | |
| 2068 | + rc = xfer_run_script(zScript, zUuid); | |
| 2051 | 2069 | } |
| 2052 | 2070 | } |
| 2053 | 2071 | if( p->type==CFTYPE_MANIFEST ){ |
| 2054 | 2072 | manifest_cache_insert(p); |
| 2055 | 2073 | }else{ |
| 2056 | 2074 | manifest_destroy(p); |
| 2057 | 2075 | } |
| 2058 | 2076 | assert( blob_is_reset(pContent) ); |
| 2059 | - return ( result!=TH_ERROR ); | |
| 2077 | + return ( rc!=TH_ERROR ); | |
| 2060 | 2078 | } |
| 2061 | 2079 | |
| 2062 | 2080 | /* |
| 2063 | 2081 | ** COMMAND: test-crosslink |
| 2064 | 2082 | ** |
| 2065 | 2083 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -1494,18 +1494,30 @@ | |
| 1494 | #endif /* LOCAL_INTERFACE */ |
| 1495 | |
| 1496 | /* |
| 1497 | ** Finish up a sequence of manifest_crosslink calls. |
| 1498 | */ |
| 1499 | void manifest_crosslink_end(void){ |
| 1500 | Stmt q, u; |
| 1501 | int i; |
| 1502 | assert( manifest_crosslink_busy==1 ); |
| 1503 | db_prepare(&q, "SELECT uuid FROM pending_tkt"); |
| 1504 | while( db_step(&q)==SQLITE_ROW ){ |
| 1505 | const char *zUuid = db_column_text(&q, 0); |
| 1506 | ticket_rebuild_entry(zUuid); |
| 1507 | } |
| 1508 | db_finalize(&q); |
| 1509 | db_multi_exec("DROP TABLE pending_tkt"); |
| 1510 | |
| 1511 | /* If multiple check-ins happen close together in time, adjust their |
| @@ -1528,18 +1540,21 @@ | |
| 1528 | db_step(&u); |
| 1529 | db_reset(&u); |
| 1530 | } |
| 1531 | db_finalize(&q); |
| 1532 | db_finalize(&u); |
| 1533 | db_multi_exec( |
| 1534 | "UPDATE event SET mtime=(SELECT m1 FROM time_fudge WHERE mid=objid)" |
| 1535 | " WHERE objid IN (SELECT mid FROM time_fudge);" |
| 1536 | "DROP TABLE time_fudge;" |
| 1537 | ); |
| 1538 | |
| 1539 | db_end_transaction(0); |
| 1540 | manifest_crosslink_busy = 0; |
| 1541 | } |
| 1542 | |
| 1543 | /* |
| 1544 | ** Make an entry in the event table for a ticket change artifact. |
| 1545 | */ |
| @@ -1657,14 +1672,15 @@ | |
| 1657 | ** Processing for other control artifacts was added later. The name |
| 1658 | ** of the routine, "manifest_crosslink", and the name of this source |
| 1659 | ** file, is a legacy of its original use. |
| 1660 | */ |
| 1661 | int manifest_crosslink(int rid, Blob *pContent, int flags){ |
| 1662 | int i, result = TH_OK; |
| 1663 | Manifest *p; |
| 1664 | Stmt q; |
| 1665 | int parentid = 0; |
| 1666 | const char *zScript = 0; |
| 1667 | const char *zUuid = 0; |
| 1668 | |
| 1669 | if( (p = manifest_cache_find(rid))!=0 ){ |
| 1670 | blob_reset(pContent); |
| @@ -1685,11 +1701,13 @@ | |
| 1685 | fossil_error(1, "cannot fetch baseline manifest"); |
| 1686 | return 0; |
| 1687 | } |
| 1688 | db_begin_transaction(); |
| 1689 | if( p->type==CFTYPE_MANIFEST ){ |
| 1690 | zScript = xfer_commit_code(); |
| 1691 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1692 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ |
| 1693 | char *zCom; |
| 1694 | for(i=0; i<p->nParent; i++){ |
| 1695 | int pid = uuid_to_rid(p->azParent[i], 1); |
| @@ -1883,12 +1901,10 @@ | |
| 1883 | } |
| 1884 | } |
| 1885 | if( p->type==CFTYPE_TICKET ){ |
| 1886 | char *zTag; |
| 1887 | |
| 1888 | zScript = xfer_ticket_code(); |
| 1889 | zUuid = p->zTicketUuid; |
| 1890 | assert( manifest_crosslink_busy==1 ); |
| 1891 | zTag = mprintf("tkt-%s", p->zTicketUuid); |
| 1892 | tag_insert(zTag, 1, 0, rid, p->rDate, rid); |
| 1893 | free(zTag); |
| 1894 | db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)", |
| @@ -1968,11 +1984,13 @@ | |
| 1968 | zTagUuid); |
| 1969 | branchMove = 0; |
| 1970 | if( db_exists("SELECT 1 FROM event, blob" |
| 1971 | " WHERE event.type='ci' AND event.objid=blob.rid" |
| 1972 | " AND blob.uuid='%s'", zTagUuid) ){ |
| 1973 | zScript = xfer_commit_code(); |
| 1974 | zUuid = zTagUuid; |
| 1975 | } |
| 1976 | } |
| 1977 | zName = p->aTag[i].zName; |
| 1978 | zValue = p->aTag[i].zValue; |
| @@ -2042,23 +2060,23 @@ | |
| 2042 | p->rDate, rid, p->zUser, blob_str(&comment)+1 |
| 2043 | ); |
| 2044 | blob_reset(&comment); |
| 2045 | } |
| 2046 | db_end_transaction(0); |
| 2047 | if( zScript && (flags & MC_PERMIT_HOOKS) ){ |
| 2048 | result = xfer_run_common_script(); |
| 2049 | if( result==TH_OK ){ |
| 2050 | result = xfer_run_script(zScript, zUuid); |
| 2051 | } |
| 2052 | } |
| 2053 | if( p->type==CFTYPE_MANIFEST ){ |
| 2054 | manifest_cache_insert(p); |
| 2055 | }else{ |
| 2056 | manifest_destroy(p); |
| 2057 | } |
| 2058 | assert( blob_is_reset(pContent) ); |
| 2059 | return ( result!=TH_ERROR ); |
| 2060 | } |
| 2061 | |
| 2062 | /* |
| 2063 | ** COMMAND: test-crosslink |
| 2064 | ** |
| 2065 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -1494,18 +1494,30 @@ | |
| 1494 | #endif /* LOCAL_INTERFACE */ |
| 1495 | |
| 1496 | /* |
| 1497 | ** Finish up a sequence of manifest_crosslink calls. |
| 1498 | */ |
| 1499 | int manifest_crosslink_end(int flags){ |
| 1500 | Stmt q, u; |
| 1501 | int i; |
| 1502 | int rc = TH_OK; |
| 1503 | int permitHooks = (flags & MC_PERMIT_HOOKS); |
| 1504 | const char *zScript = 0; |
| 1505 | assert( manifest_crosslink_busy==1 ); |
| 1506 | if( permitHooks ){ |
| 1507 | rc = xfer_run_common_script(); |
| 1508 | if( rc==TH_OK ){ |
| 1509 | zScript = xfer_ticket_code(); |
| 1510 | } |
| 1511 | } |
| 1512 | db_prepare(&q, "SELECT uuid FROM pending_tkt"); |
| 1513 | while( db_step(&q)==SQLITE_ROW ){ |
| 1514 | const char *zUuid = db_column_text(&q, 0); |
| 1515 | ticket_rebuild_entry(zUuid); |
| 1516 | if( permitHooks && rc==TH_OK ){ |
| 1517 | rc = xfer_run_script(zScript, zUuid); |
| 1518 | } |
| 1519 | } |
| 1520 | db_finalize(&q); |
| 1521 | db_multi_exec("DROP TABLE pending_tkt"); |
| 1522 | |
| 1523 | /* If multiple check-ins happen close together in time, adjust their |
| @@ -1528,18 +1540,21 @@ | |
| 1540 | db_step(&u); |
| 1541 | db_reset(&u); |
| 1542 | } |
| 1543 | db_finalize(&q); |
| 1544 | db_finalize(&u); |
| 1545 | if( db_exists("SELECT 1 FROM time_fudge") ){ |
| 1546 | db_multi_exec( |
| 1547 | "UPDATE event SET mtime=(SELECT m1 FROM time_fudge WHERE mid=objid)" |
| 1548 | " WHERE objid IN (SELECT mid FROM time_fudge);" |
| 1549 | ); |
| 1550 | } |
| 1551 | db_multi_exec("DROP TABLE time_fudge;"); |
| 1552 | |
| 1553 | db_end_transaction(0); |
| 1554 | manifest_crosslink_busy = 0; |
| 1555 | return ( rc!=TH_ERROR ); |
| 1556 | } |
| 1557 | |
| 1558 | /* |
| 1559 | ** Make an entry in the event table for a ticket change artifact. |
| 1560 | */ |
| @@ -1657,14 +1672,15 @@ | |
| 1672 | ** Processing for other control artifacts was added later. The name |
| 1673 | ** of the routine, "manifest_crosslink", and the name of this source |
| 1674 | ** file, is a legacy of its original use. |
| 1675 | */ |
| 1676 | int manifest_crosslink(int rid, Blob *pContent, int flags){ |
| 1677 | int i, rc = TH_OK; |
| 1678 | Manifest *p; |
| 1679 | Stmt q; |
| 1680 | int parentid = 0; |
| 1681 | int permitHooks = (flags & MC_PERMIT_HOOKS); |
| 1682 | const char *zScript = 0; |
| 1683 | const char *zUuid = 0; |
| 1684 | |
| 1685 | if( (p = manifest_cache_find(rid))!=0 ){ |
| 1686 | blob_reset(pContent); |
| @@ -1685,11 +1701,13 @@ | |
| 1701 | fossil_error(1, "cannot fetch baseline manifest"); |
| 1702 | return 0; |
| 1703 | } |
| 1704 | db_begin_transaction(); |
| 1705 | if( p->type==CFTYPE_MANIFEST ){ |
| 1706 | if( permitHooks ){ |
| 1707 | zScript = xfer_commit_code(); |
| 1708 | } |
| 1709 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1710 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){ |
| 1711 | char *zCom; |
| 1712 | for(i=0; i<p->nParent; i++){ |
| 1713 | int pid = uuid_to_rid(p->azParent[i], 1); |
| @@ -1883,12 +1901,10 @@ | |
| 1901 | } |
| 1902 | } |
| 1903 | if( p->type==CFTYPE_TICKET ){ |
| 1904 | char *zTag; |
| 1905 | |
| 1906 | assert( manifest_crosslink_busy==1 ); |
| 1907 | zTag = mprintf("tkt-%s", p->zTicketUuid); |
| 1908 | tag_insert(zTag, 1, 0, rid, p->rDate, rid); |
| 1909 | free(zTag); |
| 1910 | db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)", |
| @@ -1968,11 +1984,13 @@ | |
| 1984 | zTagUuid); |
| 1985 | branchMove = 0; |
| 1986 | if( db_exists("SELECT 1 FROM event, blob" |
| 1987 | " WHERE event.type='ci' AND event.objid=blob.rid" |
| 1988 | " AND blob.uuid='%s'", zTagUuid) ){ |
| 1989 | if( permitHooks ){ |
| 1990 | zScript = xfer_commit_code(); |
| 1991 | } |
| 1992 | zUuid = zTagUuid; |
| 1993 | } |
| 1994 | } |
| 1995 | zName = p->aTag[i].zName; |
| 1996 | zValue = p->aTag[i].zValue; |
| @@ -2042,23 +2060,23 @@ | |
| 2060 | p->rDate, rid, p->zUser, blob_str(&comment)+1 |
| 2061 | ); |
| 2062 | blob_reset(&comment); |
| 2063 | } |
| 2064 | db_end_transaction(0); |
| 2065 | if( permitHooks ){ |
| 2066 | rc = xfer_run_common_script(); |
| 2067 | if( rc==TH_OK ){ |
| 2068 | rc = xfer_run_script(zScript, zUuid); |
| 2069 | } |
| 2070 | } |
| 2071 | if( p->type==CFTYPE_MANIFEST ){ |
| 2072 | manifest_cache_insert(p); |
| 2073 | }else{ |
| 2074 | manifest_destroy(p); |
| 2075 | } |
| 2076 | assert( blob_is_reset(pContent) ); |
| 2077 | return ( rc!=TH_ERROR ); |
| 2078 | } |
| 2079 | |
| 2080 | /* |
| 2081 | ** COMMAND: test-crosslink |
| 2082 | ** |
| 2083 |
+4
-4
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -26,17 +26,17 @@ | ||
| 26 | 26 | ** Print information about a particular check-in. |
| 27 | 27 | */ |
| 28 | 28 | void print_checkin_description(int rid, int indent, const char *zLabel){ |
| 29 | 29 | Stmt q; |
| 30 | 30 | db_prepare(&q, |
| 31 | - "SELECT datetime(mtime,'localtime')," | |
| 31 | + "SELECT datetime(mtime%s)," | |
| 32 | 32 | " coalesce(euser,user), coalesce(ecomment,comment)," |
| 33 | 33 | " (SELECT uuid FROM blob WHERE rid=%d)," |
| 34 | 34 | " (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref" |
| 35 | 35 | " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" |
| 36 | 36 | " AND tagxref.rid=%d AND tagxref.tagtype>0)" |
| 37 | - " FROM event WHERE objid=%d", rid, rid, rid); | |
| 37 | + " FROM event WHERE objid=%d", timeline_utc(), rid, rid, rid); | |
| 38 | 38 | if( db_step(&q)==SQLITE_ROW ){ |
| 39 | 39 | const char *zTagList = db_column_text(&q, 4); |
| 40 | 40 | char *zCom; |
| 41 | 41 | if( zTagList && zTagList[0] ){ |
| 42 | 42 | zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList); |
| @@ -195,16 +195,16 @@ | ||
| 195 | 195 | TAG_BRANCH, vid) |
| 196 | 196 | ); |
| 197 | 197 | } |
| 198 | 198 | db_prepare(&q, |
| 199 | 199 | "SELECT blob.uuid," |
| 200 | - " datetime(event.mtime,'localtime')," | |
| 200 | + " datetime(event.mtime%s)," | |
| 201 | 201 | " coalesce(ecomment, comment)," |
| 202 | 202 | " coalesce(euser, user)" |
| 203 | 203 | " FROM event, blob" |
| 204 | 204 | " WHERE event.objid=%d AND blob.rid=%d", |
| 205 | - mid, mid | |
| 205 | + timeline_utc(), mid, mid | |
| 206 | 206 | ); |
| 207 | 207 | if( db_step(&q)==SQLITE_ROW ){ |
| 208 | 208 | char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", |
| 209 | 209 | db_column_text(&q, 0), db_column_text(&q, 1), |
| 210 | 210 | db_column_text(&q, 3), db_column_text(&q, 2)); |
| 211 | 211 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -26,17 +26,17 @@ | |
| 26 | ** Print information about a particular check-in. |
| 27 | */ |
| 28 | void print_checkin_description(int rid, int indent, const char *zLabel){ |
| 29 | Stmt q; |
| 30 | db_prepare(&q, |
| 31 | "SELECT datetime(mtime,'localtime')," |
| 32 | " coalesce(euser,user), coalesce(ecomment,comment)," |
| 33 | " (SELECT uuid FROM blob WHERE rid=%d)," |
| 34 | " (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref" |
| 35 | " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" |
| 36 | " AND tagxref.rid=%d AND tagxref.tagtype>0)" |
| 37 | " FROM event WHERE objid=%d", rid, rid, rid); |
| 38 | if( db_step(&q)==SQLITE_ROW ){ |
| 39 | const char *zTagList = db_column_text(&q, 4); |
| 40 | char *zCom; |
| 41 | if( zTagList && zTagList[0] ){ |
| 42 | zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList); |
| @@ -195,16 +195,16 @@ | |
| 195 | TAG_BRANCH, vid) |
| 196 | ); |
| 197 | } |
| 198 | db_prepare(&q, |
| 199 | "SELECT blob.uuid," |
| 200 | " datetime(event.mtime,'localtime')," |
| 201 | " coalesce(ecomment, comment)," |
| 202 | " coalesce(euser, user)" |
| 203 | " FROM event, blob" |
| 204 | " WHERE event.objid=%d AND blob.rid=%d", |
| 205 | mid, mid |
| 206 | ); |
| 207 | if( db_step(&q)==SQLITE_ROW ){ |
| 208 | char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", |
| 209 | db_column_text(&q, 0), db_column_text(&q, 1), |
| 210 | db_column_text(&q, 3), db_column_text(&q, 2)); |
| 211 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -26,17 +26,17 @@ | |
| 26 | ** Print information about a particular check-in. |
| 27 | */ |
| 28 | void print_checkin_description(int rid, int indent, const char *zLabel){ |
| 29 | Stmt q; |
| 30 | db_prepare(&q, |
| 31 | "SELECT datetime(mtime%s)," |
| 32 | " coalesce(euser,user), coalesce(ecomment,comment)," |
| 33 | " (SELECT uuid FROM blob WHERE rid=%d)," |
| 34 | " (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref" |
| 35 | " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" |
| 36 | " AND tagxref.rid=%d AND tagxref.tagtype>0)" |
| 37 | " FROM event WHERE objid=%d", timeline_utc(), rid, rid, rid); |
| 38 | if( db_step(&q)==SQLITE_ROW ){ |
| 39 | const char *zTagList = db_column_text(&q, 4); |
| 40 | char *zCom; |
| 41 | if( zTagList && zTagList[0] ){ |
| 42 | zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList); |
| @@ -195,16 +195,16 @@ | |
| 195 | TAG_BRANCH, vid) |
| 196 | ); |
| 197 | } |
| 198 | db_prepare(&q, |
| 199 | "SELECT blob.uuid," |
| 200 | " datetime(event.mtime%s)," |
| 201 | " coalesce(ecomment, comment)," |
| 202 | " coalesce(euser, user)" |
| 203 | " FROM event, blob" |
| 204 | " WHERE event.objid=%d AND blob.rid=%d", |
| 205 | timeline_utc(), mid, mid |
| 206 | ); |
| 207 | if( db_step(&q)==SQLITE_ROW ){ |
| 208 | char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", |
| 209 | db_column_text(&q, 0), db_column_text(&q, 1), |
| 210 | db_column_text(&q, 3), db_column_text(&q, 2)); |
| 211 |
+6
-6
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -458,18 +458,18 @@ | ||
| 458 | 458 | }else if( rid==0 ){ |
| 459 | 459 | fossil_print("Unknown artifact: %s\n", zName); |
| 460 | 460 | }else{ |
| 461 | 461 | Stmt q; |
| 462 | 462 | db_prepare(&q, |
| 463 | - "SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr," | |
| 463 | + "SELECT uuid, size, datetime(mtime%s), ipaddr," | |
| 464 | 464 | " (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref" |
| 465 | 465 | " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" |
| 466 | 466 | " AND tagxref.rid=blob.rid AND tagxref.tagtype>0)" |
| 467 | 467 | " FROM blob, rcvfrom" |
| 468 | 468 | " WHERE rid=%d" |
| 469 | 469 | " AND rcvfrom.rcvid=blob.rcvid", |
| 470 | - rid); | |
| 470 | + timeline_utc(), rid); | |
| 471 | 471 | if( db_step(&q)==SQLITE_ROW ){ |
| 472 | 472 | const char *zTagList = db_column_text(&q, 4); |
| 473 | 473 | if( verboseFlag ){ |
| 474 | 474 | fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid); |
| 475 | 475 | fossil_print("size: %d bytes\n", db_column_int(&q,1)); |
| @@ -484,13 +484,13 @@ | ||
| 484 | 484 | fossil_print("tags: %s\n", zTagList); |
| 485 | 485 | } |
| 486 | 486 | } |
| 487 | 487 | db_finalize(&q); |
| 488 | 488 | db_prepare(&q, |
| 489 | - "SELECT type, datetime(mtime,'localtime')," | |
| 489 | + "SELECT type, datetime(mtime%s)," | |
| 490 | 490 | " coalesce(euser,user), coalesce(ecomment,comment)" |
| 491 | - " FROM event WHERE objid=%d", rid); | |
| 491 | + " FROM event WHERE objid=%d", timeline_utc(), rid); | |
| 492 | 492 | if( db_step(&q)==SQLITE_ROW ){ |
| 493 | 493 | const char *zType; |
| 494 | 494 | switch( db_column_text(&q,0)[0] ){ |
| 495 | 495 | case 'c': zType = "Check-in"; break; |
| 496 | 496 | case 'w': zType = "Wiki-edit"; break; |
| @@ -504,19 +504,19 @@ | ||
| 504 | 504 | fossil_print("comment: "); |
| 505 | 505 | comment_print(db_column_text(&q,3), 10, 78); |
| 506 | 506 | } |
| 507 | 507 | db_finalize(&q); |
| 508 | 508 | db_prepare(&q, |
| 509 | - "SELECT filename.name, blob.uuid, datetime(event.mtime,'localtime')," | |
| 509 | + "SELECT filename.name, blob.uuid, datetime(event.mtime%s)," | |
| 510 | 510 | " coalesce(euser,user), coalesce(ecomment,comment)" |
| 511 | 511 | " FROM mlink, filename, blob, event" |
| 512 | 512 | " WHERE mlink.fid=%d" |
| 513 | 513 | " AND filename.fnid=mlink.fnid" |
| 514 | 514 | " AND event.objid=mlink.mid" |
| 515 | 515 | " AND blob.rid=mlink.mid" |
| 516 | 516 | " ORDER BY event.mtime DESC /*sort*/", |
| 517 | - rid); | |
| 517 | + timeline_utc(), rid); | |
| 518 | 518 | while( db_step(&q)==SQLITE_ROW ){ |
| 519 | 519 | fossil_print("file: %s\n", db_column_text(&q,0)); |
| 520 | 520 | fossil_print(" part of [%.10s] by %s on %s\n", |
| 521 | 521 | db_column_text(&q, 1), |
| 522 | 522 | db_column_text(&q, 3), |
| 523 | 523 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -458,18 +458,18 @@ | |
| 458 | }else if( rid==0 ){ |
| 459 | fossil_print("Unknown artifact: %s\n", zName); |
| 460 | }else{ |
| 461 | Stmt q; |
| 462 | db_prepare(&q, |
| 463 | "SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr," |
| 464 | " (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref" |
| 465 | " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" |
| 466 | " AND tagxref.rid=blob.rid AND tagxref.tagtype>0)" |
| 467 | " FROM blob, rcvfrom" |
| 468 | " WHERE rid=%d" |
| 469 | " AND rcvfrom.rcvid=blob.rcvid", |
| 470 | rid); |
| 471 | if( db_step(&q)==SQLITE_ROW ){ |
| 472 | const char *zTagList = db_column_text(&q, 4); |
| 473 | if( verboseFlag ){ |
| 474 | fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid); |
| 475 | fossil_print("size: %d bytes\n", db_column_int(&q,1)); |
| @@ -484,13 +484,13 @@ | |
| 484 | fossil_print("tags: %s\n", zTagList); |
| 485 | } |
| 486 | } |
| 487 | db_finalize(&q); |
| 488 | db_prepare(&q, |
| 489 | "SELECT type, datetime(mtime,'localtime')," |
| 490 | " coalesce(euser,user), coalesce(ecomment,comment)" |
| 491 | " FROM event WHERE objid=%d", rid); |
| 492 | if( db_step(&q)==SQLITE_ROW ){ |
| 493 | const char *zType; |
| 494 | switch( db_column_text(&q,0)[0] ){ |
| 495 | case 'c': zType = "Check-in"; break; |
| 496 | case 'w': zType = "Wiki-edit"; break; |
| @@ -504,19 +504,19 @@ | |
| 504 | fossil_print("comment: "); |
| 505 | comment_print(db_column_text(&q,3), 10, 78); |
| 506 | } |
| 507 | db_finalize(&q); |
| 508 | db_prepare(&q, |
| 509 | "SELECT filename.name, blob.uuid, datetime(event.mtime,'localtime')," |
| 510 | " coalesce(euser,user), coalesce(ecomment,comment)" |
| 511 | " FROM mlink, filename, blob, event" |
| 512 | " WHERE mlink.fid=%d" |
| 513 | " AND filename.fnid=mlink.fnid" |
| 514 | " AND event.objid=mlink.mid" |
| 515 | " AND blob.rid=mlink.mid" |
| 516 | " ORDER BY event.mtime DESC /*sort*/", |
| 517 | rid); |
| 518 | while( db_step(&q)==SQLITE_ROW ){ |
| 519 | fossil_print("file: %s\n", db_column_text(&q,0)); |
| 520 | fossil_print(" part of [%.10s] by %s on %s\n", |
| 521 | db_column_text(&q, 1), |
| 522 | db_column_text(&q, 3), |
| 523 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -458,18 +458,18 @@ | |
| 458 | }else if( rid==0 ){ |
| 459 | fossil_print("Unknown artifact: %s\n", zName); |
| 460 | }else{ |
| 461 | Stmt q; |
| 462 | db_prepare(&q, |
| 463 | "SELECT uuid, size, datetime(mtime%s), ipaddr," |
| 464 | " (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref" |
| 465 | " WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" |
| 466 | " AND tagxref.rid=blob.rid AND tagxref.tagtype>0)" |
| 467 | " FROM blob, rcvfrom" |
| 468 | " WHERE rid=%d" |
| 469 | " AND rcvfrom.rcvid=blob.rcvid", |
| 470 | timeline_utc(), rid); |
| 471 | if( db_step(&q)==SQLITE_ROW ){ |
| 472 | const char *zTagList = db_column_text(&q, 4); |
| 473 | if( verboseFlag ){ |
| 474 | fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid); |
| 475 | fossil_print("size: %d bytes\n", db_column_int(&q,1)); |
| @@ -484,13 +484,13 @@ | |
| 484 | fossil_print("tags: %s\n", zTagList); |
| 485 | } |
| 486 | } |
| 487 | db_finalize(&q); |
| 488 | db_prepare(&q, |
| 489 | "SELECT type, datetime(mtime%s)," |
| 490 | " coalesce(euser,user), coalesce(ecomment,comment)" |
| 491 | " FROM event WHERE objid=%d", timeline_utc(), rid); |
| 492 | if( db_step(&q)==SQLITE_ROW ){ |
| 493 | const char *zType; |
| 494 | switch( db_column_text(&q,0)[0] ){ |
| 495 | case 'c': zType = "Check-in"; break; |
| 496 | case 'w': zType = "Wiki-edit"; break; |
| @@ -504,19 +504,19 @@ | |
| 504 | fossil_print("comment: "); |
| 505 | comment_print(db_column_text(&q,3), 10, 78); |
| 506 | } |
| 507 | db_finalize(&q); |
| 508 | db_prepare(&q, |
| 509 | "SELECT filename.name, blob.uuid, datetime(event.mtime%s)," |
| 510 | " coalesce(euser,user), coalesce(ecomment,comment)" |
| 511 | " FROM mlink, filename, blob, event" |
| 512 | " WHERE mlink.fid=%d" |
| 513 | " AND filename.fnid=mlink.fnid" |
| 514 | " AND event.objid=mlink.mid" |
| 515 | " AND blob.rid=mlink.mid" |
| 516 | " ORDER BY event.mtime DESC /*sort*/", |
| 517 | timeline_utc(), rid); |
| 518 | while( db_step(&q)==SQLITE_ROW ){ |
| 519 | fossil_print("file: %s\n", db_column_text(&q,0)); |
| 520 | fossil_print(" part of [%.10s] by %s on %s\n", |
| 521 | db_column_text(&q, 1), |
| 522 | db_column_text(&q, 3), |
| 523 |
+1
-1
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -412,11 +412,11 @@ | ||
| 412 | 412 | db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid); |
| 413 | 413 | rebuild_step_done(rid); |
| 414 | 414 | } |
| 415 | 415 | } |
| 416 | 416 | db_finalize(&s); |
| 417 | - manifest_crosslink_end(); | |
| 417 | + manifest_crosslink_end(MC_NONE); | |
| 418 | 418 | rebuild_tag_trunk(); |
| 419 | 419 | if( ttyOutput && !g.fQuiet && totalSize>0 ){ |
| 420 | 420 | processCnt += incrSize; |
| 421 | 421 | percent_complete((processCnt*1000)/totalSize); |
| 422 | 422 | } |
| 423 | 423 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -412,11 +412,11 @@ | |
| 412 | db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid); |
| 413 | rebuild_step_done(rid); |
| 414 | } |
| 415 | } |
| 416 | db_finalize(&s); |
| 417 | manifest_crosslink_end(); |
| 418 | rebuild_tag_trunk(); |
| 419 | if( ttyOutput && !g.fQuiet && totalSize>0 ){ |
| 420 | processCnt += incrSize; |
| 421 | percent_complete((processCnt*1000)/totalSize); |
| 422 | } |
| 423 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -412,11 +412,11 @@ | |
| 412 | db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid); |
| 413 | rebuild_step_done(rid); |
| 414 | } |
| 415 | } |
| 416 | db_finalize(&s); |
| 417 | manifest_crosslink_end(MC_NONE); |
| 418 | rebuild_tag_trunk(); |
| 419 | if( ttyOutput && !g.fQuiet && totalSize>0 ){ |
| 420 | processCnt += incrSize; |
| 421 | percent_complete((processCnt*1000)/totalSize); |
| 422 | } |
| 423 |
-1
| --- src/report.c | ||
| +++ src/report.c | ||
| @@ -210,11 +210,10 @@ | ||
| 210 | 210 | |
| 211 | 211 | /* |
| 212 | 212 | ** Activate the query authorizer |
| 213 | 213 | */ |
| 214 | 214 | static void report_restrict_sql(char **pzErr){ |
| 215 | - (void)fossil_localtime(0); | |
| 216 | 215 | sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr); |
| 217 | 216 | } |
| 218 | 217 | static void report_unrestrict_sql(void){ |
| 219 | 218 | sqlite3_set_authorizer(g.db, 0, 0); |
| 220 | 219 | } |
| 221 | 220 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -210,11 +210,10 @@ | |
| 210 | |
| 211 | /* |
| 212 | ** Activate the query authorizer |
| 213 | */ |
| 214 | static void report_restrict_sql(char **pzErr){ |
| 215 | (void)fossil_localtime(0); |
| 216 | sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr); |
| 217 | } |
| 218 | static void report_unrestrict_sql(void){ |
| 219 | sqlite3_set_authorizer(g.db, 0, 0); |
| 220 | } |
| 221 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -210,11 +210,10 @@ | |
| 210 | |
| 211 | /* |
| 212 | ** Activate the query authorizer |
| 213 | */ |
| 214 | static void report_restrict_sql(char **pzErr){ |
| 215 | sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr); |
| 216 | } |
| 217 | static void report_unrestrict_sql(void){ |
| 218 | sqlite3_set_authorizer(g.db, 0, 0); |
| 219 | } |
| 220 |
+20
-6
| --- src/search.c | ||
| +++ src/search.c | ||
| @@ -106,10 +106,11 @@ | ||
| 106 | 106 | int iBonus = 0; |
| 107 | 107 | int i, j; |
| 108 | 108 | unsigned char seen[8]; |
| 109 | 109 | |
| 110 | 110 | memset(seen, 0, sizeof(seen)); |
| 111 | + if( zDoc==0 ) return score; | |
| 111 | 112 | for(i=0; zDoc[i]; i++){ |
| 112 | 113 | char c = zDoc[i]; |
| 113 | 114 | if( isBoundary[c&0xff] ) continue; |
| 114 | 115 | for(j=0; j<p->nTerm; j++){ |
| 115 | 116 | int n = p->a[j].n; |
| @@ -166,21 +167,23 @@ | ||
| 166 | 167 | |
| 167 | 168 | /* |
| 168 | 169 | ** Testing the search function. |
| 169 | 170 | ** |
| 170 | 171 | ** COMMAND: search* |
| 171 | -** %fossil search [-all|-a] [-limit|-n #] pattern... | |
| 172 | +** %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern... | |
| 172 | 173 | ** |
| 173 | 174 | ** Search for timeline entries matching all words |
| 174 | 175 | ** provided on the command line. Whole-word matches |
| 175 | 176 | ** scope more highly than partial matches. |
| 176 | 177 | ** |
| 177 | 178 | ** Outputs, by default, some top-N fraction of the |
| 178 | 179 | ** results. The -all option can be used to output |
| 179 | 180 | ** all matches, regardless of their search score. |
| 180 | -** -limit can be used to limit the number of entries | |
| 181 | -** returned. | |
| 181 | +** The -limit option can be used to limit the number | |
| 182 | +** of entries returned. The -width option can be | |
| 183 | +** used to set the output width used when printing | |
| 184 | +** matches. | |
| 182 | 185 | */ |
| 183 | 186 | void search_cmd(void){ |
| 184 | 187 | Search *p; |
| 185 | 188 | Blob pattern; |
| 186 | 189 | int i; |
| @@ -189,12 +192,22 @@ | ||
| 189 | 192 | int iBest; |
| 190 | 193 | char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop |
| 191 | 194 | off the end of the |
| 192 | 195 | results. */ |
| 193 | 196 | char const * zLimit = find_option("limit","n",1); |
| 197 | + const char *zWidth = find_option("width","W",1); | |
| 194 | 198 | int nLimit = zLimit ? atoi(zLimit) : -1000; /* Max number of matching |
| 195 | 199 | lines/entries to list */ |
| 200 | + int width; | |
| 201 | + if( zWidth ){ | |
| 202 | + width = atoi(zWidth); | |
| 203 | + if( (width!=0) && (width<=20) ){ | |
| 204 | + fossil_fatal("--width|-W value must be >20 or 0"); | |
| 205 | + } | |
| 206 | + }else{ | |
| 207 | + width = 79; | |
| 208 | + } | |
| 196 | 209 | |
| 197 | 210 | db_must_be_within_tree(); |
| 198 | 211 | if( g.argc<2 ) return; |
| 199 | 212 | blob_init(&pattern, g.argv[2], -1); |
| 200 | 213 | for(i=3; i<g.argc; i++){ |
| @@ -206,15 +219,16 @@ | ||
| 206 | 219 | |
| 207 | 220 | db_multi_exec( |
| 208 | 221 | "CREATE TEMP TABLE srch(rid,uuid,date,comment,x);" |
| 209 | 222 | "CREATE INDEX srch_idx1 ON srch(x);" |
| 210 | 223 | "INSERT INTO srch(rid,uuid,date,comment,x)" |
| 211 | - " SELECT blob.rid, uuid, datetime(event.mtime, 'localtime')," | |
| 224 | + " SELECT blob.rid, uuid, datetime(event.mtime%s)," | |
| 212 | 225 | " coalesce(ecomment,comment)," |
| 213 | 226 | " score(coalesce(ecomment,comment)) AS y" |
| 214 | 227 | " FROM event, blob" |
| 215 | - " WHERE blob.rid=event.objid AND y>0;" | |
| 228 | + " WHERE blob.rid=event.objid AND y>0;", | |
| 229 | + timeline_utc() | |
| 216 | 230 | ); |
| 217 | 231 | iBest = db_int(0, "SELECT max(x) FROM srch"); |
| 218 | 232 | blob_append(&sql, |
| 219 | 233 | "SELECT rid, uuid, date, comment, 0, 0 FROM srch " |
| 220 | 234 | "WHERE 1 ", -1); |
| @@ -222,8 +236,8 @@ | ||
| 222 | 236 | blob_appendf(&sql,"AND x>%d ", iBest/3); |
| 223 | 237 | } |
| 224 | 238 | blob_append(&sql, "ORDER BY x DESC, date DESC ", -1); |
| 225 | 239 | db_prepare(&q, blob_str(&sql)); |
| 226 | 240 | blob_reset(&sql); |
| 227 | - print_timeline(&q, nLimit, 79, 0); | |
| 241 | + print_timeline(&q, nLimit, width, 0); | |
| 228 | 242 | db_finalize(&q); |
| 229 | 243 | } |
| 230 | 244 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -106,10 +106,11 @@ | |
| 106 | int iBonus = 0; |
| 107 | int i, j; |
| 108 | unsigned char seen[8]; |
| 109 | |
| 110 | memset(seen, 0, sizeof(seen)); |
| 111 | for(i=0; zDoc[i]; i++){ |
| 112 | char c = zDoc[i]; |
| 113 | if( isBoundary[c&0xff] ) continue; |
| 114 | for(j=0; j<p->nTerm; j++){ |
| 115 | int n = p->a[j].n; |
| @@ -166,21 +167,23 @@ | |
| 166 | |
| 167 | /* |
| 168 | ** Testing the search function. |
| 169 | ** |
| 170 | ** COMMAND: search* |
| 171 | ** %fossil search [-all|-a] [-limit|-n #] pattern... |
| 172 | ** |
| 173 | ** Search for timeline entries matching all words |
| 174 | ** provided on the command line. Whole-word matches |
| 175 | ** scope more highly than partial matches. |
| 176 | ** |
| 177 | ** Outputs, by default, some top-N fraction of the |
| 178 | ** results. The -all option can be used to output |
| 179 | ** all matches, regardless of their search score. |
| 180 | ** -limit can be used to limit the number of entries |
| 181 | ** returned. |
| 182 | */ |
| 183 | void search_cmd(void){ |
| 184 | Search *p; |
| 185 | Blob pattern; |
| 186 | int i; |
| @@ -189,12 +192,22 @@ | |
| 189 | int iBest; |
| 190 | char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop |
| 191 | off the end of the |
| 192 | results. */ |
| 193 | char const * zLimit = find_option("limit","n",1); |
| 194 | int nLimit = zLimit ? atoi(zLimit) : -1000; /* Max number of matching |
| 195 | lines/entries to list */ |
| 196 | |
| 197 | db_must_be_within_tree(); |
| 198 | if( g.argc<2 ) return; |
| 199 | blob_init(&pattern, g.argv[2], -1); |
| 200 | for(i=3; i<g.argc; i++){ |
| @@ -206,15 +219,16 @@ | |
| 206 | |
| 207 | db_multi_exec( |
| 208 | "CREATE TEMP TABLE srch(rid,uuid,date,comment,x);" |
| 209 | "CREATE INDEX srch_idx1 ON srch(x);" |
| 210 | "INSERT INTO srch(rid,uuid,date,comment,x)" |
| 211 | " SELECT blob.rid, uuid, datetime(event.mtime, 'localtime')," |
| 212 | " coalesce(ecomment,comment)," |
| 213 | " score(coalesce(ecomment,comment)) AS y" |
| 214 | " FROM event, blob" |
| 215 | " WHERE blob.rid=event.objid AND y>0;" |
| 216 | ); |
| 217 | iBest = db_int(0, "SELECT max(x) FROM srch"); |
| 218 | blob_append(&sql, |
| 219 | "SELECT rid, uuid, date, comment, 0, 0 FROM srch " |
| 220 | "WHERE 1 ", -1); |
| @@ -222,8 +236,8 @@ | |
| 222 | blob_appendf(&sql,"AND x>%d ", iBest/3); |
| 223 | } |
| 224 | blob_append(&sql, "ORDER BY x DESC, date DESC ", -1); |
| 225 | db_prepare(&q, blob_str(&sql)); |
| 226 | blob_reset(&sql); |
| 227 | print_timeline(&q, nLimit, 79, 0); |
| 228 | db_finalize(&q); |
| 229 | } |
| 230 |
| --- src/search.c | |
| +++ src/search.c | |
| @@ -106,10 +106,11 @@ | |
| 106 | int iBonus = 0; |
| 107 | int i, j; |
| 108 | unsigned char seen[8]; |
| 109 | |
| 110 | memset(seen, 0, sizeof(seen)); |
| 111 | if( zDoc==0 ) return score; |
| 112 | for(i=0; zDoc[i]; i++){ |
| 113 | char c = zDoc[i]; |
| 114 | if( isBoundary[c&0xff] ) continue; |
| 115 | for(j=0; j<p->nTerm; j++){ |
| 116 | int n = p->a[j].n; |
| @@ -166,21 +167,23 @@ | |
| 167 | |
| 168 | /* |
| 169 | ** Testing the search function. |
| 170 | ** |
| 171 | ** COMMAND: search* |
| 172 | ** %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern... |
| 173 | ** |
| 174 | ** Search for timeline entries matching all words |
| 175 | ** provided on the command line. Whole-word matches |
| 176 | ** scope more highly than partial matches. |
| 177 | ** |
| 178 | ** Outputs, by default, some top-N fraction of the |
| 179 | ** results. The -all option can be used to output |
| 180 | ** all matches, regardless of their search score. |
| 181 | ** The -limit option can be used to limit the number |
| 182 | ** of entries returned. The -width option can be |
| 183 | ** used to set the output width used when printing |
| 184 | ** matches. |
| 185 | */ |
| 186 | void search_cmd(void){ |
| 187 | Search *p; |
| 188 | Blob pattern; |
| 189 | int i; |
| @@ -189,12 +192,22 @@ | |
| 192 | int iBest; |
| 193 | char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop |
| 194 | off the end of the |
| 195 | results. */ |
| 196 | char const * zLimit = find_option("limit","n",1); |
| 197 | const char *zWidth = find_option("width","W",1); |
| 198 | int nLimit = zLimit ? atoi(zLimit) : -1000; /* Max number of matching |
| 199 | lines/entries to list */ |
| 200 | int width; |
| 201 | if( zWidth ){ |
| 202 | width = atoi(zWidth); |
| 203 | if( (width!=0) && (width<=20) ){ |
| 204 | fossil_fatal("--width|-W value must be >20 or 0"); |
| 205 | } |
| 206 | }else{ |
| 207 | width = 79; |
| 208 | } |
| 209 | |
| 210 | db_must_be_within_tree(); |
| 211 | if( g.argc<2 ) return; |
| 212 | blob_init(&pattern, g.argv[2], -1); |
| 213 | for(i=3; i<g.argc; i++){ |
| @@ -206,15 +219,16 @@ | |
| 219 | |
| 220 | db_multi_exec( |
| 221 | "CREATE TEMP TABLE srch(rid,uuid,date,comment,x);" |
| 222 | "CREATE INDEX srch_idx1 ON srch(x);" |
| 223 | "INSERT INTO srch(rid,uuid,date,comment,x)" |
| 224 | " SELECT blob.rid, uuid, datetime(event.mtime%s)," |
| 225 | " coalesce(ecomment,comment)," |
| 226 | " score(coalesce(ecomment,comment)) AS y" |
| 227 | " FROM event, blob" |
| 228 | " WHERE blob.rid=event.objid AND y>0;", |
| 229 | timeline_utc() |
| 230 | ); |
| 231 | iBest = db_int(0, "SELECT max(x) FROM srch"); |
| 232 | blob_append(&sql, |
| 233 | "SELECT rid, uuid, date, comment, 0, 0 FROM srch " |
| 234 | "WHERE 1 ", -1); |
| @@ -222,8 +236,8 @@ | |
| 236 | blob_appendf(&sql,"AND x>%d ", iBest/3); |
| 237 | } |
| 238 | blob_append(&sql, "ORDER BY x DESC, date DESC ", -1); |
| 239 | db_prepare(&q, blob_str(&sql)); |
| 240 | blob_reset(&sql); |
| 241 | print_timeline(&q, nLimit, width, 0); |
| 242 | db_finalize(&q); |
| 243 | } |
| 244 |
+4
-3
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -1184,11 +1184,10 @@ | ||
| 1184 | 1184 | @ <hr /> |
| 1185 | 1185 | onoff_attribute("Use Universal Coordinated Time (UTC)", |
| 1186 | 1186 | "timeline-utc", "utc", 1, 0); |
| 1187 | 1187 | @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or |
| 1188 | 1188 | @ Zulu) instead of in local time. On this server, local time is currently |
| 1189 | - g.fTimeFormat = 2; | |
| 1190 | 1189 | tmDiff = db_double(0.0, "SELECT julianday('now')"); |
| 1191 | 1190 | tmDiff = db_double(0.0, |
| 1192 | 1191 | "SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0", |
| 1193 | 1192 | tmDiff, tmDiff); |
| 1194 | 1193 | sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff); |
| @@ -1598,13 +1597,15 @@ | ||
| 1598 | 1597 | |
| 1599 | 1598 | /* |
| 1600 | 1599 | ** WEBPAGE: setup_logo |
| 1601 | 1600 | */ |
| 1602 | 1601 | void setup_logo(void){ |
| 1602 | + const char *zLogoMtime = db_get_mtime("logo-image", 0, 0); | |
| 1603 | 1603 | const char *zLogoMime = db_get("logo-mimetype","image/gif"); |
| 1604 | 1604 | const char *aLogoImg = P("logoim"); |
| 1605 | 1605 | int szLogoImg = atoi(PD("logoim:bytes","0")); |
| 1606 | + const char *zBgMtime = db_get_mtime("background-image", 0, 0); | |
| 1606 | 1607 | const char *zBgMime = db_get("background-mimetype","image/gif"); |
| 1607 | 1608 | const char *aBgImg = P("bgim"); |
| 1608 | 1609 | int szBgImg = atoi(PD("bgim:bytes","0")); |
| 1609 | 1610 | if( szLogoImg>0 ){ |
| 1610 | 1611 | zLogoMime = PD("logoim:mimetype","image/gif"); |
| @@ -1668,11 +1669,11 @@ | ||
| 1668 | 1669 | cgi_redirect("setup_logo"); |
| 1669 | 1670 | } |
| 1670 | 1671 | style_header("Edit Project Logo And Background"); |
| 1671 | 1672 | @ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b> |
| 1672 | 1673 | @ and looks like this:</p> |
| 1673 | - @ <blockquote><p><img src="%s(g.zTop)/logo" alt="logo" border="1" /> | |
| 1674 | + @ <blockquote><p><img src="%s(g.zTop)/logo/%z(zLogoMtime)" alt="logo" border="1" /> | |
| 1674 | 1675 | @ </p></blockquote> |
| 1675 | 1676 | @ |
| 1676 | 1677 | @ <form action="%s(g.zTop)/setup_logo" method="post" |
| 1677 | 1678 | @ enctype="multipart/form-data"><div> |
| 1678 | 1679 | @ <p>The logo is accessible to all users at this URL: |
| @@ -1690,11 +1691,11 @@ | ||
| 1690 | 1691 | @ </div></form> |
| 1691 | 1692 | @ <hr /> |
| 1692 | 1693 | @ |
| 1693 | 1694 | @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b> |
| 1694 | 1695 | @ and looks like this:</p> |
| 1695 | - @ <blockquote><p><img src="%s(g.zTop)/background" alt="background" border=1 /> | |
| 1696 | + @ <blockquote><p><img src="%s(g.zTop)/background/%z(zBgMtime)" alt="background" border=1 /> | |
| 1696 | 1697 | @ </p></blockquote> |
| 1697 | 1698 | @ |
| 1698 | 1699 | @ <form action="%s(g.zTop)/setup_logo" method="post" |
| 1699 | 1700 | @ enctype="multipart/form-data"><div> |
| 1700 | 1701 | @ <p>The background image is accessible to all users at this URL: |
| 1701 | 1702 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1184,11 +1184,10 @@ | |
| 1184 | @ <hr /> |
| 1185 | onoff_attribute("Use Universal Coordinated Time (UTC)", |
| 1186 | "timeline-utc", "utc", 1, 0); |
| 1187 | @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or |
| 1188 | @ Zulu) instead of in local time. On this server, local time is currently |
| 1189 | g.fTimeFormat = 2; |
| 1190 | tmDiff = db_double(0.0, "SELECT julianday('now')"); |
| 1191 | tmDiff = db_double(0.0, |
| 1192 | "SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0", |
| 1193 | tmDiff, tmDiff); |
| 1194 | sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff); |
| @@ -1598,13 +1597,15 @@ | |
| 1598 | |
| 1599 | /* |
| 1600 | ** WEBPAGE: setup_logo |
| 1601 | */ |
| 1602 | void setup_logo(void){ |
| 1603 | const char *zLogoMime = db_get("logo-mimetype","image/gif"); |
| 1604 | const char *aLogoImg = P("logoim"); |
| 1605 | int szLogoImg = atoi(PD("logoim:bytes","0")); |
| 1606 | const char *zBgMime = db_get("background-mimetype","image/gif"); |
| 1607 | const char *aBgImg = P("bgim"); |
| 1608 | int szBgImg = atoi(PD("bgim:bytes","0")); |
| 1609 | if( szLogoImg>0 ){ |
| 1610 | zLogoMime = PD("logoim:mimetype","image/gif"); |
| @@ -1668,11 +1669,11 @@ | |
| 1668 | cgi_redirect("setup_logo"); |
| 1669 | } |
| 1670 | style_header("Edit Project Logo And Background"); |
| 1671 | @ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b> |
| 1672 | @ and looks like this:</p> |
| 1673 | @ <blockquote><p><img src="%s(g.zTop)/logo" alt="logo" border="1" /> |
| 1674 | @ </p></blockquote> |
| 1675 | @ |
| 1676 | @ <form action="%s(g.zTop)/setup_logo" method="post" |
| 1677 | @ enctype="multipart/form-data"><div> |
| 1678 | @ <p>The logo is accessible to all users at this URL: |
| @@ -1690,11 +1691,11 @@ | |
| 1690 | @ </div></form> |
| 1691 | @ <hr /> |
| 1692 | @ |
| 1693 | @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b> |
| 1694 | @ and looks like this:</p> |
| 1695 | @ <blockquote><p><img src="%s(g.zTop)/background" alt="background" border=1 /> |
| 1696 | @ </p></blockquote> |
| 1697 | @ |
| 1698 | @ <form action="%s(g.zTop)/setup_logo" method="post" |
| 1699 | @ enctype="multipart/form-data"><div> |
| 1700 | @ <p>The background image is accessible to all users at this URL: |
| 1701 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -1184,11 +1184,10 @@ | |
| 1184 | @ <hr /> |
| 1185 | onoff_attribute("Use Universal Coordinated Time (UTC)", |
| 1186 | "timeline-utc", "utc", 1, 0); |
| 1187 | @ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or |
| 1188 | @ Zulu) instead of in local time. On this server, local time is currently |
| 1189 | tmDiff = db_double(0.0, "SELECT julianday('now')"); |
| 1190 | tmDiff = db_double(0.0, |
| 1191 | "SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0", |
| 1192 | tmDiff, tmDiff); |
| 1193 | sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff); |
| @@ -1598,13 +1597,15 @@ | |
| 1597 | |
| 1598 | /* |
| 1599 | ** WEBPAGE: setup_logo |
| 1600 | */ |
| 1601 | void setup_logo(void){ |
| 1602 | const char *zLogoMtime = db_get_mtime("logo-image", 0, 0); |
| 1603 | const char *zLogoMime = db_get("logo-mimetype","image/gif"); |
| 1604 | const char *aLogoImg = P("logoim"); |
| 1605 | int szLogoImg = atoi(PD("logoim:bytes","0")); |
| 1606 | const char *zBgMtime = db_get_mtime("background-image", 0, 0); |
| 1607 | const char *zBgMime = db_get("background-mimetype","image/gif"); |
| 1608 | const char *aBgImg = P("bgim"); |
| 1609 | int szBgImg = atoi(PD("bgim:bytes","0")); |
| 1610 | if( szLogoImg>0 ){ |
| 1611 | zLogoMime = PD("logoim:mimetype","image/gif"); |
| @@ -1668,11 +1669,11 @@ | |
| 1669 | cgi_redirect("setup_logo"); |
| 1670 | } |
| 1671 | style_header("Edit Project Logo And Background"); |
| 1672 | @ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b> |
| 1673 | @ and looks like this:</p> |
| 1674 | @ <blockquote><p><img src="%s(g.zTop)/logo/%z(zLogoMtime)" alt="logo" border="1" /> |
| 1675 | @ </p></blockquote> |
| 1676 | @ |
| 1677 | @ <form action="%s(g.zTop)/setup_logo" method="post" |
| 1678 | @ enctype="multipart/form-data"><div> |
| 1679 | @ <p>The logo is accessible to all users at this URL: |
| @@ -1690,11 +1691,11 @@ | |
| 1691 | @ </div></form> |
| 1692 | @ <hr /> |
| 1693 | @ |
| 1694 | @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b> |
| 1695 | @ and looks like this:</p> |
| 1696 | @ <blockquote><p><img src="%s(g.zTop)/background/%z(zBgMtime)" alt="background" border=1 /> |
| 1697 | @ </p></blockquote> |
| 1698 | @ |
| 1699 | @ <form action="%s(g.zTop)/setup_logo" method="post" |
| 1700 | @ enctype="multipart/form-data"><div> |
| 1701 | @ <p>The background image is accessible to all users at this URL: |
| 1702 |
+13
-13
| --- src/skins.c | ||
| +++ src/skins.c | ||
| @@ -171,11 +171,11 @@ | ||
| 171 | 171 | @ <head> |
| 172 | 172 | @ <base href="$baseurl/$current_page" /> |
| 173 | 173 | @ <title>$<project_name>: $<title></title> |
| 174 | 174 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 175 | 175 | @ href="$home/timeline.rss"> |
| 176 | -@ <link rel="stylesheet" href="$home/style.css?blackwhite" type="text/css" | |
| 176 | +@ <link rel="stylesheet" href="$stylesheet_url" type="text/css" | |
| 177 | 177 | @ media="screen"> |
| 178 | 178 | @ </head> |
| 179 | 179 | @ <body> |
| 180 | 180 | @ <div class="header"> |
| 181 | 181 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| @@ -192,11 +192,11 @@ | ||
| 192 | 192 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 193 | 193 | @ if {[anycap jor]} { |
| 194 | 194 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 195 | 195 | @ } |
| 196 | 196 | @ if {[hascap oh]} { |
| 197 | -@ html "<a href=''$home/dir?ci=tip''>Files</a>\n" | |
| 197 | +@ html "<a href=''$home/tree?ci=tip''>Files</a>\n" | |
| 198 | 198 | @ } |
| 199 | 199 | @ if {[hascap o]} { |
| 200 | 200 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 201 | 201 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 202 | 202 | @ } |
| @@ -379,11 +379,11 @@ | ||
| 379 | 379 | @ <head> |
| 380 | 380 | @ <base href="$baseurl/$current_page" /> |
| 381 | 381 | @ <title>$<project_name>: $<title></title> |
| 382 | 382 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 383 | 383 | @ href="$home/timeline.rss"> |
| 384 | -@ <link rel="stylesheet" href="$home/style.css?tan" type="text/css" | |
| 384 | +@ <link rel="stylesheet" href="$stylesheet_url" type="text/css" | |
| 385 | 385 | @ media="screen"> |
| 386 | 386 | @ </head> |
| 387 | 387 | @ <body> |
| 388 | 388 | @ <div class="header"> |
| 389 | 389 | @ <div class="title">$<title></div> |
| @@ -402,11 +402,11 @@ | ||
| 402 | 402 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 403 | 403 | @ if {[anycap jor]} { |
| 404 | 404 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 405 | 405 | @ } |
| 406 | 406 | @ if {[hascap oh]} { |
| 407 | -@ html "<a href=''$home/dir?ci=tip''>Files</a>\n" | |
| 407 | +@ html "<a href=''$home/tree?ci=tip''>Files</a>\n" | |
| 408 | 408 | @ } |
| 409 | 409 | @ if {[hascap o]} { |
| 410 | 410 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 411 | 411 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 412 | 412 | @ } |
| @@ -620,17 +620,17 @@ | ||
| 620 | 620 | @ <head> |
| 621 | 621 | @ <base href="$baseurl/$current_page" /> |
| 622 | 622 | @ <title>$<project_name>: $<title></title> |
| 623 | 623 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 624 | 624 | @ href="$home/timeline.rss"> |
| 625 | -@ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" | |
| 625 | +@ <link rel="stylesheet" href="$stylesheet_url" type="text/css" | |
| 626 | 626 | @ media="screen"> |
| 627 | 627 | @ </head> |
| 628 | 628 | @ <body> |
| 629 | 629 | @ <div class="header"> |
| 630 | 630 | @ <div class="logo"> |
| 631 | -@ <img src="$home/logo" alt="logo"> | |
| 631 | +@ <img src="$logo_image_url" alt="logo"> | |
| 632 | 632 | @ <br />$<project_name> |
| 633 | 633 | @ </div> |
| 634 | 634 | @ <div class="title">$<title></div> |
| 635 | 635 | @ <div class="status"><th1> |
| 636 | 636 | @ if {[info exists login]} { |
| @@ -645,11 +645,11 @@ | ||
| 645 | 645 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 646 | 646 | @ if {[anycap jor]} { |
| 647 | 647 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 648 | 648 | @ } |
| 649 | 649 | @ if {[hascap oh]} { |
| 650 | -@ html "<a href=''$home/dir?ci=tip''>Files</a>\n" | |
| 650 | +@ html "<a href=''$home/tree?ci=tip''>Files</a>\n" | |
| 651 | 651 | @ } |
| 652 | 652 | @ if {[hascap o]} { |
| 653 | 653 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 654 | 654 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 655 | 655 | @ } |
| @@ -881,17 +881,17 @@ | ||
| 881 | 881 | @ <head> |
| 882 | 882 | @ <base href="$baseurl/$current_page" /> |
| 883 | 883 | @ <title>$<project_name>: $<title></title> |
| 884 | 884 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 885 | 885 | @ href="$home/timeline.rss"> |
| 886 | -@ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" | |
| 886 | +@ <link rel="stylesheet" href="$stylesheet_url" type="text/css" | |
| 887 | 887 | @ media="screen"> |
| 888 | 888 | @ </head> |
| 889 | 889 | @ <body> |
| 890 | 890 | @ <div class="header"> |
| 891 | 891 | @ <div class="logo"> |
| 892 | -@ <img src="$home/logo" alt="logo"> | |
| 892 | +@ <img src="$logo_image_url" alt="logo"> | |
| 893 | 893 | @ <br />$<project_name> |
| 894 | 894 | @ </div> |
| 895 | 895 | @ <div class="title">$<title></div> |
| 896 | 896 | @ <div class="status"><th1> |
| 897 | 897 | @ if {[info exists login]} { |
| @@ -906,11 +906,11 @@ | ||
| 906 | 906 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 907 | 907 | @ if {[anycap jor]} { |
| 908 | 908 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 909 | 909 | @ } |
| 910 | 910 | @ if {[hascap oh]} { |
| 911 | -@ html "<a href=''$home/dir?ci=tip''>Files</a>\n" | |
| 911 | +@ html "<a href=''$home/tree?ci=tip''>Files</a>\n" | |
| 912 | 912 | @ } |
| 913 | 913 | @ if {[hascap o]} { |
| 914 | 914 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 915 | 915 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 916 | 916 | @ } |
| @@ -1109,11 +1109,11 @@ | ||
| 1109 | 1109 | @ <head> |
| 1110 | 1110 | @ <base href="$baseurl/$current_page" /> |
| 1111 | 1111 | @ <title>$<project_name>: $<title></title> |
| 1112 | 1112 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 1113 | 1113 | @ href="$home/timeline.rss" /> |
| 1114 | -@ <link rel="stylesheet" href="$home/style.css?enhanced" type="text/css" | |
| 1114 | +@ <link rel="stylesheet" href="$stylesheet_url" type="text/css" | |
| 1115 | 1115 | @ media="screen" /> |
| 1116 | 1116 | @ </head> |
| 1117 | 1117 | @ <body> |
| 1118 | 1118 | @ <div class="header"> |
| 1119 | 1119 | @ <div class="logo"> |
| @@ -1176,11 +1176,11 @@ | ||
| 1176 | 1176 | @ return $logourl |
| 1177 | 1177 | @ } |
| 1178 | 1178 | @ set logourl [getLogoUrl $baseurl] |
| 1179 | 1179 | @ </th1> |
| 1180 | 1180 | @ <a href="$logourl"> |
| 1181 | -@ <img src="$baseurl/logo" border="0" alt="$project_name"> | |
| 1181 | +@ <img src="$logo_image_url" border="0" alt="$project_name"> | |
| 1182 | 1182 | @ </a> |
| 1183 | 1183 | @ </div> |
| 1184 | 1184 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 1185 | 1185 | @ <div class="status"><th1> |
| 1186 | 1186 | @ if {[info exists login]} { |
| @@ -1195,11 +1195,11 @@ | ||
| 1195 | 1195 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 1196 | 1196 | @ if {[anycap jor]} { |
| 1197 | 1197 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 1198 | 1198 | @ } |
| 1199 | 1199 | @ if {[hascap oh]} { |
| 1200 | -@ html "<a href=''$home/dir?ci=tip''>Files</a>\n" | |
| 1200 | +@ html "<a href=''$home/tree?ci=tip''>Files</a>\n" | |
| 1201 | 1201 | @ } |
| 1202 | 1202 | @ if {[hascap o]} { |
| 1203 | 1203 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 1204 | 1204 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 1205 | 1205 | @ } |
| 1206 | 1206 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -171,11 +171,11 @@ | |
| 171 | @ <head> |
| 172 | @ <base href="$baseurl/$current_page" /> |
| 173 | @ <title>$<project_name>: $<title></title> |
| 174 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 175 | @ href="$home/timeline.rss"> |
| 176 | @ <link rel="stylesheet" href="$home/style.css?blackwhite" type="text/css" |
| 177 | @ media="screen"> |
| 178 | @ </head> |
| 179 | @ <body> |
| 180 | @ <div class="header"> |
| 181 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| @@ -192,11 +192,11 @@ | |
| 192 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 193 | @ if {[anycap jor]} { |
| 194 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 195 | @ } |
| 196 | @ if {[hascap oh]} { |
| 197 | @ html "<a href=''$home/dir?ci=tip''>Files</a>\n" |
| 198 | @ } |
| 199 | @ if {[hascap o]} { |
| 200 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 201 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 202 | @ } |
| @@ -379,11 +379,11 @@ | |
| 379 | @ <head> |
| 380 | @ <base href="$baseurl/$current_page" /> |
| 381 | @ <title>$<project_name>: $<title></title> |
| 382 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 383 | @ href="$home/timeline.rss"> |
| 384 | @ <link rel="stylesheet" href="$home/style.css?tan" type="text/css" |
| 385 | @ media="screen"> |
| 386 | @ </head> |
| 387 | @ <body> |
| 388 | @ <div class="header"> |
| 389 | @ <div class="title">$<title></div> |
| @@ -402,11 +402,11 @@ | |
| 402 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 403 | @ if {[anycap jor]} { |
| 404 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 405 | @ } |
| 406 | @ if {[hascap oh]} { |
| 407 | @ html "<a href=''$home/dir?ci=tip''>Files</a>\n" |
| 408 | @ } |
| 409 | @ if {[hascap o]} { |
| 410 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 411 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 412 | @ } |
| @@ -620,17 +620,17 @@ | |
| 620 | @ <head> |
| 621 | @ <base href="$baseurl/$current_page" /> |
| 622 | @ <title>$<project_name>: $<title></title> |
| 623 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 624 | @ href="$home/timeline.rss"> |
| 625 | @ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" |
| 626 | @ media="screen"> |
| 627 | @ </head> |
| 628 | @ <body> |
| 629 | @ <div class="header"> |
| 630 | @ <div class="logo"> |
| 631 | @ <img src="$home/logo" alt="logo"> |
| 632 | @ <br />$<project_name> |
| 633 | @ </div> |
| 634 | @ <div class="title">$<title></div> |
| 635 | @ <div class="status"><th1> |
| 636 | @ if {[info exists login]} { |
| @@ -645,11 +645,11 @@ | |
| 645 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 646 | @ if {[anycap jor]} { |
| 647 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 648 | @ } |
| 649 | @ if {[hascap oh]} { |
| 650 | @ html "<a href=''$home/dir?ci=tip''>Files</a>\n" |
| 651 | @ } |
| 652 | @ if {[hascap o]} { |
| 653 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 654 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 655 | @ } |
| @@ -881,17 +881,17 @@ | |
| 881 | @ <head> |
| 882 | @ <base href="$baseurl/$current_page" /> |
| 883 | @ <title>$<project_name>: $<title></title> |
| 884 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 885 | @ href="$home/timeline.rss"> |
| 886 | @ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" |
| 887 | @ media="screen"> |
| 888 | @ </head> |
| 889 | @ <body> |
| 890 | @ <div class="header"> |
| 891 | @ <div class="logo"> |
| 892 | @ <img src="$home/logo" alt="logo"> |
| 893 | @ <br />$<project_name> |
| 894 | @ </div> |
| 895 | @ <div class="title">$<title></div> |
| 896 | @ <div class="status"><th1> |
| 897 | @ if {[info exists login]} { |
| @@ -906,11 +906,11 @@ | |
| 906 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 907 | @ if {[anycap jor]} { |
| 908 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 909 | @ } |
| 910 | @ if {[hascap oh]} { |
| 911 | @ html "<a href=''$home/dir?ci=tip''>Files</a>\n" |
| 912 | @ } |
| 913 | @ if {[hascap o]} { |
| 914 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 915 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 916 | @ } |
| @@ -1109,11 +1109,11 @@ | |
| 1109 | @ <head> |
| 1110 | @ <base href="$baseurl/$current_page" /> |
| 1111 | @ <title>$<project_name>: $<title></title> |
| 1112 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 1113 | @ href="$home/timeline.rss" /> |
| 1114 | @ <link rel="stylesheet" href="$home/style.css?enhanced" type="text/css" |
| 1115 | @ media="screen" /> |
| 1116 | @ </head> |
| 1117 | @ <body> |
| 1118 | @ <div class="header"> |
| 1119 | @ <div class="logo"> |
| @@ -1176,11 +1176,11 @@ | |
| 1176 | @ return $logourl |
| 1177 | @ } |
| 1178 | @ set logourl [getLogoUrl $baseurl] |
| 1179 | @ </th1> |
| 1180 | @ <a href="$logourl"> |
| 1181 | @ <img src="$baseurl/logo" border="0" alt="$project_name"> |
| 1182 | @ </a> |
| 1183 | @ </div> |
| 1184 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 1185 | @ <div class="status"><th1> |
| 1186 | @ if {[info exists login]} { |
| @@ -1195,11 +1195,11 @@ | |
| 1195 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 1196 | @ if {[anycap jor]} { |
| 1197 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 1198 | @ } |
| 1199 | @ if {[hascap oh]} { |
| 1200 | @ html "<a href=''$home/dir?ci=tip''>Files</a>\n" |
| 1201 | @ } |
| 1202 | @ if {[hascap o]} { |
| 1203 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 1204 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 1205 | @ } |
| 1206 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -171,11 +171,11 @@ | |
| 171 | @ <head> |
| 172 | @ <base href="$baseurl/$current_page" /> |
| 173 | @ <title>$<project_name>: $<title></title> |
| 174 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 175 | @ href="$home/timeline.rss"> |
| 176 | @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" |
| 177 | @ media="screen"> |
| 178 | @ </head> |
| 179 | @ <body> |
| 180 | @ <div class="header"> |
| 181 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| @@ -192,11 +192,11 @@ | |
| 192 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 193 | @ if {[anycap jor]} { |
| 194 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 195 | @ } |
| 196 | @ if {[hascap oh]} { |
| 197 | @ html "<a href=''$home/tree?ci=tip''>Files</a>\n" |
| 198 | @ } |
| 199 | @ if {[hascap o]} { |
| 200 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 201 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 202 | @ } |
| @@ -379,11 +379,11 @@ | |
| 379 | @ <head> |
| 380 | @ <base href="$baseurl/$current_page" /> |
| 381 | @ <title>$<project_name>: $<title></title> |
| 382 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 383 | @ href="$home/timeline.rss"> |
| 384 | @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" |
| 385 | @ media="screen"> |
| 386 | @ </head> |
| 387 | @ <body> |
| 388 | @ <div class="header"> |
| 389 | @ <div class="title">$<title></div> |
| @@ -402,11 +402,11 @@ | |
| 402 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 403 | @ if {[anycap jor]} { |
| 404 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 405 | @ } |
| 406 | @ if {[hascap oh]} { |
| 407 | @ html "<a href=''$home/tree?ci=tip''>Files</a>\n" |
| 408 | @ } |
| 409 | @ if {[hascap o]} { |
| 410 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 411 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 412 | @ } |
| @@ -620,17 +620,17 @@ | |
| 620 | @ <head> |
| 621 | @ <base href="$baseurl/$current_page" /> |
| 622 | @ <title>$<project_name>: $<title></title> |
| 623 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 624 | @ href="$home/timeline.rss"> |
| 625 | @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" |
| 626 | @ media="screen"> |
| 627 | @ </head> |
| 628 | @ <body> |
| 629 | @ <div class="header"> |
| 630 | @ <div class="logo"> |
| 631 | @ <img src="$logo_image_url" alt="logo"> |
| 632 | @ <br />$<project_name> |
| 633 | @ </div> |
| 634 | @ <div class="title">$<title></div> |
| 635 | @ <div class="status"><th1> |
| 636 | @ if {[info exists login]} { |
| @@ -645,11 +645,11 @@ | |
| 645 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 646 | @ if {[anycap jor]} { |
| 647 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 648 | @ } |
| 649 | @ if {[hascap oh]} { |
| 650 | @ html "<a href=''$home/tree?ci=tip''>Files</a>\n" |
| 651 | @ } |
| 652 | @ if {[hascap o]} { |
| 653 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 654 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 655 | @ } |
| @@ -881,17 +881,17 @@ | |
| 881 | @ <head> |
| 882 | @ <base href="$baseurl/$current_page" /> |
| 883 | @ <title>$<project_name>: $<title></title> |
| 884 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 885 | @ href="$home/timeline.rss"> |
| 886 | @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" |
| 887 | @ media="screen"> |
| 888 | @ </head> |
| 889 | @ <body> |
| 890 | @ <div class="header"> |
| 891 | @ <div class="logo"> |
| 892 | @ <img src="$logo_image_url" alt="logo"> |
| 893 | @ <br />$<project_name> |
| 894 | @ </div> |
| 895 | @ <div class="title">$<title></div> |
| 896 | @ <div class="status"><th1> |
| 897 | @ if {[info exists login]} { |
| @@ -906,11 +906,11 @@ | |
| 906 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 907 | @ if {[anycap jor]} { |
| 908 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 909 | @ } |
| 910 | @ if {[hascap oh]} { |
| 911 | @ html "<a href=''$home/tree?ci=tip''>Files</a>\n" |
| 912 | @ } |
| 913 | @ if {[hascap o]} { |
| 914 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 915 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 916 | @ } |
| @@ -1109,11 +1109,11 @@ | |
| 1109 | @ <head> |
| 1110 | @ <base href="$baseurl/$current_page" /> |
| 1111 | @ <title>$<project_name>: $<title></title> |
| 1112 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 1113 | @ href="$home/timeline.rss" /> |
| 1114 | @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" |
| 1115 | @ media="screen" /> |
| 1116 | @ </head> |
| 1117 | @ <body> |
| 1118 | @ <div class="header"> |
| 1119 | @ <div class="logo"> |
| @@ -1176,11 +1176,11 @@ | |
| 1176 | @ return $logourl |
| 1177 | @ } |
| 1178 | @ set logourl [getLogoUrl $baseurl] |
| 1179 | @ </th1> |
| 1180 | @ <a href="$logourl"> |
| 1181 | @ <img src="$logo_image_url" border="0" alt="$project_name"> |
| 1182 | @ </a> |
| 1183 | @ </div> |
| 1184 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 1185 | @ <div class="status"><th1> |
| 1186 | @ if {[info exists login]} { |
| @@ -1195,11 +1195,11 @@ | |
| 1195 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 1196 | @ if {[anycap jor]} { |
| 1197 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 1198 | @ } |
| 1199 | @ if {[hascap oh]} { |
| 1200 | @ html "<a href=''$home/tree?ci=tip''>Files</a>\n" |
| 1201 | @ } |
| 1202 | @ if {[hascap o]} { |
| 1203 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 1204 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 1205 | @ } |
| 1206 |
+3
| --- src/sqlcmd.c | ||
| +++ src/sqlcmd.c | ||
| @@ -19,10 +19,11 @@ | ||
| 19 | 19 | ** shell against the repository database. The command-line shell itself |
| 20 | 20 | ** is a copy of the "shell.c" code from SQLite. This file contains logic |
| 21 | 21 | ** to initialize the code in shell.c. |
| 22 | 22 | */ |
| 23 | 23 | #include "config.h" |
| 24 | +#if !defined(USE_SYSTEM_SQLITE) || !USE_SYSTEM_SQLITE | |
| 24 | 25 | #include "sqlcmd.h" |
| 25 | 26 | #include <zlib.h> |
| 26 | 27 | |
| 27 | 28 | /* |
| 28 | 29 | ** Implementation of the "content(X)" SQL function. Return the complete |
| @@ -154,5 +155,7 @@ | ||
| 154 | 155 | */ |
| 155 | 156 | void fossil_open(const char **pzRepoName){ |
| 156 | 157 | sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit); |
| 157 | 158 | *pzRepoName = g.zRepositoryName; |
| 158 | 159 | } |
| 160 | + | |
| 161 | +#endif /* !USE_SYSTEM_SQLITE */ | |
| 159 | 162 |
| --- src/sqlcmd.c | |
| +++ src/sqlcmd.c | |
| @@ -19,10 +19,11 @@ | |
| 19 | ** shell against the repository database. The command-line shell itself |
| 20 | ** is a copy of the "shell.c" code from SQLite. This file contains logic |
| 21 | ** to initialize the code in shell.c. |
| 22 | */ |
| 23 | #include "config.h" |
| 24 | #include "sqlcmd.h" |
| 25 | #include <zlib.h> |
| 26 | |
| 27 | /* |
| 28 | ** Implementation of the "content(X)" SQL function. Return the complete |
| @@ -154,5 +155,7 @@ | |
| 154 | */ |
| 155 | void fossil_open(const char **pzRepoName){ |
| 156 | sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit); |
| 157 | *pzRepoName = g.zRepositoryName; |
| 158 | } |
| 159 |
| --- src/sqlcmd.c | |
| +++ src/sqlcmd.c | |
| @@ -19,10 +19,11 @@ | |
| 19 | ** shell against the repository database. The command-line shell itself |
| 20 | ** is a copy of the "shell.c" code from SQLite. This file contains logic |
| 21 | ** to initialize the code in shell.c. |
| 22 | */ |
| 23 | #include "config.h" |
| 24 | #if !defined(USE_SYSTEM_SQLITE) || !USE_SYSTEM_SQLITE |
| 25 | #include "sqlcmd.h" |
| 26 | #include <zlib.h> |
| 27 | |
| 28 | /* |
| 29 | ** Implementation of the "content(X)" SQL function. Return the complete |
| @@ -154,5 +155,7 @@ | |
| 155 | */ |
| 156 | void fossil_open(const char **pzRepoName){ |
| 157 | sqlite3_auto_extension((void(*)(void))sqlcmd_autoinit); |
| 158 | *pzRepoName = g.zRepositoryName; |
| 159 | } |
| 160 | |
| 161 | #endif /* !USE_SYSTEM_SQLITE */ |
| 162 |
+167
-73
| --- src/sqlite3.c | ||
| +++ src/sqlite3.c | ||
| @@ -135,11 +135,11 @@ | ||
| 135 | 135 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 136 | 136 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 137 | 137 | */ |
| 138 | 138 | #define SQLITE_VERSION "3.8.3" |
| 139 | 139 | #define SQLITE_VERSION_NUMBER 3008003 |
| 140 | -#define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d" | |
| 140 | +#define SQLITE_SOURCE_ID "2014-01-04 15:17:04 4e725f53131d3584319c710c8710a068989543c6" | |
| 141 | 141 | |
| 142 | 142 | /* |
| 143 | 143 | ** CAPI3REF: Run-Time Library Version Numbers |
| 144 | 144 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 145 | 145 | ** |
| @@ -2426,15 +2426,17 @@ | ||
| 2426 | 2426 | ** already uses the largest possible [ROWID]. The PRNG is also used for |
| 2427 | 2427 | ** the build-in random() and randomblob() SQL functions. This interface allows |
| 2428 | 2428 | ** applications to access the same PRNG for other purposes. |
| 2429 | 2429 | ** |
| 2430 | 2430 | ** ^A call to this routine stores N bytes of randomness into buffer P. |
| 2431 | +** ^If N is less than one, then P can be a NULL pointer. | |
| 2431 | 2432 | ** |
| 2432 | -** ^The first time this routine is invoked (either internally or by | |
| 2433 | -** the application) the PRNG is seeded using randomness obtained | |
| 2434 | -** from the xRandomness method of the default [sqlite3_vfs] object. | |
| 2435 | -** ^On all subsequent invocations, the pseudo-randomness is generated | |
| 2433 | +** ^If this routine has not been previously called or if the previous | |
| 2434 | +** call had N less than one, then the PRNG is seeded using randomness | |
| 2435 | +** obtained from the xRandomness method of the default [sqlite3_vfs] object. | |
| 2436 | +** ^If the previous call to this routine had an N of 1 or more then | |
| 2437 | +** the pseudo-randomness is generated | |
| 2436 | 2438 | ** internally and without recourse to the [sqlite3_vfs] xRandomness |
| 2437 | 2439 | ** method. |
| 2438 | 2440 | */ |
| 2439 | 2441 | SQLITE_API void sqlite3_randomness(int N, void *P); |
| 2440 | 2442 | |
| @@ -9278,10 +9280,11 @@ | ||
| 9278 | 9280 | SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); |
| 9279 | 9281 | SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); |
| 9280 | 9282 | SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); |
| 9281 | 9283 | SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); |
| 9282 | 9284 | SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr); |
| 9285 | +SQLITE_PRIVATE void sqlite3VdbeDeleteLastOpcode(Vdbe*); | |
| 9283 | 9286 | SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); |
| 9284 | 9287 | SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); |
| 9285 | 9288 | SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); |
| 9286 | 9289 | SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); |
| 9287 | 9290 | SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); |
| @@ -10371,11 +10374,11 @@ | ||
| 10371 | 10374 | */ |
| 10372 | 10375 | #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ |
| 10373 | 10376 | #define SQLITE_ColumnCache 0x0002 /* Column cache */ |
| 10374 | 10377 | #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ |
| 10375 | 10378 | #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ |
| 10376 | -#define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */ | |
| 10379 | +/* not used 0x0010 // Was: SQLITE_IdxRealAsInt */ | |
| 10377 | 10380 | #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ |
| 10378 | 10381 | #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ |
| 10379 | 10382 | #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ |
| 10380 | 10383 | #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ |
| 10381 | 10384 | #define SQLITE_Transitive 0x0200 /* Transitive constraints */ |
| @@ -11605,10 +11608,13 @@ | ||
| 11605 | 11608 | int nErr; /* Number of errors seen */ |
| 11606 | 11609 | int nTab; /* Number of previously allocated VDBE cursors */ |
| 11607 | 11610 | int nMem; /* Number of memory cells used so far */ |
| 11608 | 11611 | int nSet; /* Number of sets used so far */ |
| 11609 | 11612 | int nOnce; /* Number of OP_Once instructions so far */ |
| 11613 | + int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ | |
| 11614 | + int nLabel; /* Number of labels used */ | |
| 11615 | + int *aLabel; /* Space to hold the labels */ | |
| 11610 | 11616 | int ckBase; /* Base register of data during check constraints */ |
| 11611 | 11617 | int iPartIdxTab; /* Table corresponding to a partial index */ |
| 11612 | 11618 | int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ |
| 11613 | 11619 | int iCacheCnt; /* Counter used to generate aColCache[].lru values */ |
| 11614 | 11620 | struct yColCache { |
| @@ -12284,11 +12290,10 @@ | ||
| 12284 | 12290 | SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); |
| 12285 | 12291 | SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); |
| 12286 | 12292 | SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); |
| 12287 | 12293 | SQLITE_PRIVATE void sqlite3PrngSaveState(void); |
| 12288 | 12294 | SQLITE_PRIVATE void sqlite3PrngRestoreState(void); |
| 12289 | -SQLITE_PRIVATE void sqlite3PrngResetState(void); | |
| 12290 | 12295 | SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); |
| 12291 | 12296 | SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); |
| 12292 | 12297 | SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); |
| 12293 | 12298 | SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); |
| 12294 | 12299 | SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); |
| @@ -13776,19 +13781,13 @@ | ||
| 13776 | 13781 | Op *aOp; /* Space to hold the virtual machine's program */ |
| 13777 | 13782 | Mem *aMem; /* The memory locations */ |
| 13778 | 13783 | Mem **apArg; /* Arguments to currently executing user function */ |
| 13779 | 13784 | Mem *aColName; /* Column names to return */ |
| 13780 | 13785 | Mem *pResultSet; /* Pointer to an array of results */ |
| 13781 | -#ifdef SQLITE_DEBUG | |
| 13782 | 13786 | Parse *pParse; /* Parsing context used to create this Vdbe */ |
| 13783 | -#endif | |
| 13784 | 13787 | int nMem; /* Number of memory locations currently allocated */ |
| 13785 | 13788 | int nOp; /* Number of instructions in the program */ |
| 13786 | - int nOpAlloc; /* Number of slots allocated for aOp[] */ | |
| 13787 | - int nLabel; /* Number of labels used */ | |
| 13788 | - int *aLabel; /* Space to hold the labels */ | |
| 13789 | - u16 nResColumn; /* Number of columns in one row of the result set */ | |
| 13790 | 13789 | int nCursor; /* Number of slots in apCsr[] */ |
| 13791 | 13790 | u32 magic; /* Magic number for sanity checking */ |
| 13792 | 13791 | char *zErrMsg; /* Error message written here */ |
| 13793 | 13792 | Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ |
| 13794 | 13793 | VdbeCursor **apCsr; /* One element of this array for each open cursor */ |
| @@ -13797,10 +13796,11 @@ | ||
| 13797 | 13796 | ynVar nVar; /* Number of entries in aVar[] */ |
| 13798 | 13797 | ynVar nzVar; /* Number of entries in azVar[] */ |
| 13799 | 13798 | u32 cacheCtr; /* VdbeCursor row cache generation counter */ |
| 13800 | 13799 | int pc; /* The program counter */ |
| 13801 | 13800 | int rc; /* Value to return */ |
| 13801 | + u16 nResColumn; /* Number of columns in one row of the result set */ | |
| 13802 | 13802 | u8 errorAction; /* Recovery action to do in case of an error */ |
| 13803 | 13803 | u8 minWriteFileFormat; /* Minimum file format for writable database files */ |
| 13804 | 13804 | bft explain:2; /* True if EXPLAIN present on SQL command */ |
| 13805 | 13805 | bft inVtabMethod:2; /* See comments above */ |
| 13806 | 13806 | bft changeCntOn:1; /* True to update the change-counter */ |
| @@ -20901,10 +20901,16 @@ | ||
| 20901 | 20901 | |
| 20902 | 20902 | #if SQLITE_THREADSAFE |
| 20903 | 20903 | sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); |
| 20904 | 20904 | sqlite3_mutex_enter(mutex); |
| 20905 | 20905 | #endif |
| 20906 | + | |
| 20907 | + if( N<=0 ){ | |
| 20908 | + wsdPrng.isInit = 0; | |
| 20909 | + sqlite3_mutex_leave(mutex); | |
| 20910 | + return; | |
| 20911 | + } | |
| 20906 | 20912 | |
| 20907 | 20913 | /* Initialize the state of the random number generator once, |
| 20908 | 20914 | ** the first time this routine is called. The seed value does |
| 20909 | 20915 | ** not need to contain a lot of randomness since we are not |
| 20910 | 20916 | ** trying to do secure encryption or anything like that... |
| @@ -20929,19 +20935,20 @@ | ||
| 20929 | 20935 | wsdPrng.s[i] = t; |
| 20930 | 20936 | } |
| 20931 | 20937 | wsdPrng.isInit = 1; |
| 20932 | 20938 | } |
| 20933 | 20939 | |
| 20934 | - while( N-- ){ | |
| 20940 | + assert( N>0 ); | |
| 20941 | + do{ | |
| 20935 | 20942 | wsdPrng.i++; |
| 20936 | 20943 | t = wsdPrng.s[wsdPrng.i]; |
| 20937 | 20944 | wsdPrng.j += t; |
| 20938 | 20945 | wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j]; |
| 20939 | 20946 | wsdPrng.s[wsdPrng.j] = t; |
| 20940 | 20947 | t += wsdPrng.s[wsdPrng.i]; |
| 20941 | 20948 | *(zBuf++) = wsdPrng.s[t]; |
| 20942 | - } | |
| 20949 | + }while( --N ); | |
| 20943 | 20950 | sqlite3_mutex_leave(mutex); |
| 20944 | 20951 | } |
| 20945 | 20952 | |
| 20946 | 20953 | #ifndef SQLITE_OMIT_BUILTIN_TEST |
| 20947 | 20954 | /* |
| @@ -20966,13 +20973,10 @@ | ||
| 20966 | 20973 | &GLOBAL(struct sqlite3PrngType, sqlite3Prng), |
| 20967 | 20974 | &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), |
| 20968 | 20975 | sizeof(sqlite3Prng) |
| 20969 | 20976 | ); |
| 20970 | 20977 | } |
| 20971 | -SQLITE_PRIVATE void sqlite3PrngResetState(void){ | |
| 20972 | - GLOBAL(struct sqlite3PrngType, sqlite3Prng).isInit = 0; | |
| 20973 | -} | |
| 20974 | 20978 | #endif /* SQLITE_OMIT_BUILTIN_TEST */ |
| 20975 | 20979 | |
| 20976 | 20980 | /************** End of random.c **********************************************/ |
| 20977 | 20981 | /************** Begin file utf.c *********************************************/ |
| 20978 | 20982 | /* |
| @@ -23505,10 +23509,16 @@ | ||
| 23505 | 23509 | ** it is larger than the struct CrashFile defined in test6.c. |
| 23506 | 23510 | */ |
| 23507 | 23511 | char aPadding[32]; |
| 23508 | 23512 | #endif |
| 23509 | 23513 | }; |
| 23514 | + | |
| 23515 | +/* This variable holds the process id (pid) from when the xRandomness() | |
| 23516 | +** method was called. If xOpen() is called from a different process id, | |
| 23517 | +** indicating that a fork() has occurred, the PRNG will be reset. | |
| 23518 | +*/ | |
| 23519 | +static int randomnessPid = 0; | |
| 23510 | 23520 | |
| 23511 | 23521 | /* |
| 23512 | 23522 | ** Allowed values for the unixFile.ctrlFlags bitmask: |
| 23513 | 23523 | */ |
| 23514 | 23524 | #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
| @@ -29104,10 +29114,20 @@ | ||
| 29104 | 29114 | assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB |
| 29105 | 29115 | || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL |
| 29106 | 29116 | || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL |
| 29107 | 29117 | || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
| 29108 | 29118 | ); |
| 29119 | + | |
| 29120 | + /* Detect a pid change and reset the PRNG. There is a race condition | |
| 29121 | + ** here such that two or more threads all trying to open databases at | |
| 29122 | + ** the same instant might all reset the PRNG. But multiple resets | |
| 29123 | + ** are harmless. | |
| 29124 | + */ | |
| 29125 | + if( randomnessPid!=getpid() ){ | |
| 29126 | + randomnessPid = getpid(); | |
| 29127 | + sqlite3_randomness(0,0); | |
| 29128 | + } | |
| 29109 | 29129 | |
| 29110 | 29130 | memset(p, 0, sizeof(unixFile)); |
| 29111 | 29131 | |
| 29112 | 29132 | if( eType==SQLITE_OPEN_MAIN_DB ){ |
| 29113 | 29133 | UnixUnusedFd *pUnused; |
| @@ -29492,22 +29512,22 @@ | ||
| 29492 | 29512 | ** When testing, initializing zBuf[] to zero is all we do. That means |
| 29493 | 29513 | ** that we always use the same random number sequence. This makes the |
| 29494 | 29514 | ** tests repeatable. |
| 29495 | 29515 | */ |
| 29496 | 29516 | memset(zBuf, 0, nBuf); |
| 29517 | + randomnessPid = getpid(); | |
| 29497 | 29518 | #if !defined(SQLITE_TEST) |
| 29498 | 29519 | { |
| 29499 | - int pid, fd, got; | |
| 29520 | + int fd, got; | |
| 29500 | 29521 | fd = robust_open("/dev/urandom", O_RDONLY, 0); |
| 29501 | 29522 | if( fd<0 ){ |
| 29502 | 29523 | time_t t; |
| 29503 | 29524 | time(&t); |
| 29504 | 29525 | memcpy(zBuf, &t, sizeof(t)); |
| 29505 | - pid = getpid(); | |
| 29506 | - memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); | |
| 29507 | - assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf ); | |
| 29508 | - nBuf = sizeof(t) + sizeof(pid); | |
| 29526 | + memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid)); | |
| 29527 | + assert( sizeof(t)+sizeof(randomnessPid)<=(size_t)nBuf ); | |
| 29528 | + nBuf = sizeof(t) + sizeof(randomnessPid); | |
| 29509 | 29529 | }else{ |
| 29510 | 29530 | do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR ); |
| 29511 | 29531 | robust_close(0, fd, __LINE__); |
| 29512 | 29532 | } |
| 29513 | 29533 | } |
| @@ -61200,13 +61220,14 @@ | ||
| 61200 | 61220 | } |
| 61201 | 61221 | p->pNext = db->pVdbe; |
| 61202 | 61222 | p->pPrev = 0; |
| 61203 | 61223 | db->pVdbe = p; |
| 61204 | 61224 | p->magic = VDBE_MAGIC_INIT; |
| 61205 | -#if SQLITE_DEBUG | |
| 61206 | 61225 | p->pParse = pParse; |
| 61207 | -#endif | |
| 61226 | + assert( pParse->aLabel==0 ); | |
| 61227 | + assert( pParse->nLabel==0 ); | |
| 61228 | + assert( pParse->nOpAlloc==0 ); | |
| 61208 | 61229 | return p; |
| 61209 | 61230 | } |
| 61210 | 61231 | |
| 61211 | 61232 | /* |
| 61212 | 61233 | ** Remember the SQL string for a prepared statement. |
| @@ -61258,17 +61279,18 @@ | ||
| 61258 | 61279 | ** If an out-of-memory error occurs while resizing the array, return |
| 61259 | 61280 | ** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain |
| 61260 | 61281 | ** unchanged (this is so that any opcodes already allocated can be |
| 61261 | 61282 | ** correctly deallocated along with the rest of the Vdbe). |
| 61262 | 61283 | */ |
| 61263 | -static int growOpArray(Vdbe *p){ | |
| 61284 | +static int growOpArray(Vdbe *v){ | |
| 61264 | 61285 | VdbeOp *pNew; |
| 61286 | + Parse *p = v->pParse; | |
| 61265 | 61287 | int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op))); |
| 61266 | - pNew = sqlite3DbRealloc(p->db, p->aOp, nNew*sizeof(Op)); | |
| 61288 | + pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); | |
| 61267 | 61289 | if( pNew ){ |
| 61268 | 61290 | p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op); |
| 61269 | - p->aOp = pNew; | |
| 61291 | + v->aOp = pNew; | |
| 61270 | 61292 | } |
| 61271 | 61293 | return (pNew ? SQLITE_OK : SQLITE_NOMEM); |
| 61272 | 61294 | } |
| 61273 | 61295 | |
| 61274 | 61296 | #ifdef SQLITE_DEBUG |
| @@ -61303,11 +61325,11 @@ | ||
| 61303 | 61325 | VdbeOp *pOp; |
| 61304 | 61326 | |
| 61305 | 61327 | i = p->nOp; |
| 61306 | 61328 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 61307 | 61329 | assert( op>0 && op<0xff ); |
| 61308 | - if( p->nOpAlloc<=i ){ | |
| 61330 | + if( p->pParse->nOpAlloc<=i ){ | |
| 61309 | 61331 | if( growOpArray(p) ){ |
| 61310 | 61332 | return 1; |
| 61311 | 61333 | } |
| 61312 | 61334 | } |
| 61313 | 61335 | p->nOp++; |
| @@ -61414,13 +61436,14 @@ | ||
| 61414 | 61436 | ** always negative and P2 values are suppose to be non-negative. |
| 61415 | 61437 | ** Hence, a negative P2 value is a label that has yet to be resolved. |
| 61416 | 61438 | ** |
| 61417 | 61439 | ** Zero is returned if a malloc() fails. |
| 61418 | 61440 | */ |
| 61419 | -SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *p){ | |
| 61441 | +SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){ | |
| 61442 | + Parse *p = v->pParse; | |
| 61420 | 61443 | int i = p->nLabel++; |
| 61421 | - assert( p->magic==VDBE_MAGIC_INIT ); | |
| 61444 | + assert( v->magic==VDBE_MAGIC_INIT ); | |
| 61422 | 61445 | if( (i & (i-1))==0 ){ |
| 61423 | 61446 | p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, |
| 61424 | 61447 | (i*2+1)*sizeof(p->aLabel[0])); |
| 61425 | 61448 | } |
| 61426 | 61449 | if( p->aLabel ){ |
| @@ -61432,16 +61455,17 @@ | ||
| 61432 | 61455 | /* |
| 61433 | 61456 | ** Resolve label "x" to be the address of the next instruction to |
| 61434 | 61457 | ** be inserted. The parameter "x" must have been obtained from |
| 61435 | 61458 | ** a prior call to sqlite3VdbeMakeLabel(). |
| 61436 | 61459 | */ |
| 61437 | -SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *p, int x){ | |
| 61460 | +SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ | |
| 61461 | + Parse *p = v->pParse; | |
| 61438 | 61462 | int j = -1-x; |
| 61439 | - assert( p->magic==VDBE_MAGIC_INIT ); | |
| 61463 | + assert( v->magic==VDBE_MAGIC_INIT ); | |
| 61440 | 61464 | assert( j<p->nLabel ); |
| 61441 | 61465 | if( j>=0 && p->aLabel ){ |
| 61442 | - p->aLabel[j] = p->nOp; | |
| 61466 | + p->aLabel[j] = v->nOp; | |
| 61443 | 61467 | } |
| 61444 | 61468 | } |
| 61445 | 61469 | |
| 61446 | 61470 | /* |
| 61447 | 61471 | ** Mark the VDBE as one that can only be run one time. |
| @@ -61586,11 +61610,12 @@ | ||
| 61586 | 61610 | */ |
| 61587 | 61611 | static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ |
| 61588 | 61612 | int i; |
| 61589 | 61613 | int nMaxArgs = *pMaxFuncArgs; |
| 61590 | 61614 | Op *pOp; |
| 61591 | - int *aLabel = p->aLabel; | |
| 61615 | + Parse *pParse = p->pParse; | |
| 61616 | + int *aLabel = pParse->aLabel; | |
| 61592 | 61617 | p->readOnly = 1; |
| 61593 | 61618 | p->bIsReader = 0; |
| 61594 | 61619 | for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ |
| 61595 | 61620 | u8 opcode = pOp->opcode; |
| 61596 | 61621 | |
| @@ -61649,16 +61674,17 @@ | ||
| 61649 | 61674 | } |
| 61650 | 61675 | } |
| 61651 | 61676 | |
| 61652 | 61677 | pOp->opflags = sqlite3OpcodeProperty[opcode]; |
| 61653 | 61678 | if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ |
| 61654 | - assert( -1-pOp->p2<p->nLabel ); | |
| 61679 | + assert( -1-pOp->p2<pParse->nLabel ); | |
| 61655 | 61680 | pOp->p2 = aLabel[-1-pOp->p2]; |
| 61656 | 61681 | } |
| 61657 | 61682 | } |
| 61658 | - sqlite3DbFree(p->db, p->aLabel); | |
| 61659 | - p->aLabel = 0; | |
| 61683 | + sqlite3DbFree(p->db, pParse->aLabel); | |
| 61684 | + pParse->aLabel = 0; | |
| 61685 | + pParse->nLabel = 0; | |
| 61660 | 61686 | *pMaxFuncArgs = nMaxArgs; |
| 61661 | 61687 | assert( p->bIsReader!=0 || p->btreeMask==0 ); |
| 61662 | 61688 | } |
| 61663 | 61689 | |
| 61664 | 61690 | /* |
| @@ -61698,11 +61724,11 @@ | ||
| 61698 | 61724 | ** address of the first operation added. |
| 61699 | 61725 | */ |
| 61700 | 61726 | SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ |
| 61701 | 61727 | int addr; |
| 61702 | 61728 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 61703 | - if( p->nOp + nOp > p->nOpAlloc && growOpArray(p) ){ | |
| 61729 | + if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p) ){ | |
| 61704 | 61730 | return 0; |
| 61705 | 61731 | } |
| 61706 | 61732 | addr = p->nOp; |
| 61707 | 61733 | if( ALWAYS(nOp>0) ){ |
| 61708 | 61734 | int i; |
| @@ -61886,10 +61912,17 @@ | ||
| 61886 | 61912 | memset(pOp, 0, sizeof(pOp[0])); |
| 61887 | 61913 | pOp->opcode = OP_Noop; |
| 61888 | 61914 | if( addr==p->nOp-1 ) p->nOp--; |
| 61889 | 61915 | } |
| 61890 | 61916 | } |
| 61917 | + | |
| 61918 | +/* | |
| 61919 | +** Remove the last opcode inserted | |
| 61920 | +*/ | |
| 61921 | +SQLITE_PRIVATE void sqlite3VdbeDeleteLastOpcode(Vdbe *p){ | |
| 61922 | + p->nOp--; | |
| 61923 | +} | |
| 61891 | 61924 | |
| 61892 | 61925 | /* |
| 61893 | 61926 | ** Change the value of the P4 operand for a specific instruction. |
| 61894 | 61927 | ** This routine is useful when a large program is loaded from a |
| 61895 | 61928 | ** static array using sqlite3VdbeAddOpList but we want to make a |
| @@ -62768,10 +62801,11 @@ | ||
| 62768 | 62801 | |
| 62769 | 62802 | assert( p!=0 ); |
| 62770 | 62803 | assert( p->nOp>0 ); |
| 62771 | 62804 | assert( pParse!=0 ); |
| 62772 | 62805 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 62806 | + assert( pParse==p->pParse ); | |
| 62773 | 62807 | db = p->db; |
| 62774 | 62808 | assert( db->mallocFailed==0 ); |
| 62775 | 62809 | nVar = pParse->nVar; |
| 62776 | 62810 | nMem = pParse->nMem; |
| 62777 | 62811 | nCursor = pParse->nTab; |
| @@ -62791,12 +62825,12 @@ | ||
| 62791 | 62825 | nMem += nCursor; |
| 62792 | 62826 | |
| 62793 | 62827 | /* Allocate space for memory registers, SQL variables, VDBE cursors and |
| 62794 | 62828 | ** an array to marshal SQL function arguments in. |
| 62795 | 62829 | */ |
| 62796 | - zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */ | |
| 62797 | - zEnd = (u8*)&p->aOp[p->nOpAlloc]; /* First byte past end of zCsr[] */ | |
| 62830 | + zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */ | |
| 62831 | + zEnd = (u8*)&p->aOp[pParse->nOpAlloc]; /* First byte past end of zCsr[] */ | |
| 62798 | 62832 | |
| 62799 | 62833 | resolveP2Values(p, &nArg); |
| 62800 | 62834 | p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); |
| 62801 | 62835 | if( pParse->explain && nMem<10 ){ |
| 62802 | 62836 | nMem = 10; |
| @@ -63795,11 +63829,10 @@ | ||
| 63795 | 63829 | vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); |
| 63796 | 63830 | sqlite3DbFree(db, pSub); |
| 63797 | 63831 | } |
| 63798 | 63832 | for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); |
| 63799 | 63833 | vdbeFreeOpArray(db, p->aOp, p->nOp); |
| 63800 | - sqlite3DbFree(db, p->aLabel); | |
| 63801 | 63834 | sqlite3DbFree(db, p->aColName); |
| 63802 | 63835 | sqlite3DbFree(db, p->zSql); |
| 63803 | 63836 | sqlite3DbFree(db, p->pFree); |
| 63804 | 63837 | #if defined(SQLITE_ENABLE_TREE_EXPLAIN) |
| 63805 | 63838 | sqlite3DbFree(db, p->zExplain); |
| @@ -76765,20 +76798,29 @@ | ||
| 76765 | 76798 | } |
| 76766 | 76799 | return p; |
| 76767 | 76800 | } |
| 76768 | 76801 | |
| 76769 | 76802 | /* |
| 76770 | -** Return 1 if an expression must be FALSE in all cases and 0 if the | |
| 76771 | -** expression might be true. This is an optimization. If is OK to | |
| 76772 | -** return 0 here even if the expression really is always false (a | |
| 76773 | -** false negative). But it is a bug to return 1 if the expression | |
| 76774 | -** might be true in some rare circumstances (a false positive.) | |
| 76803 | +** If the expression is always either TRUE or FALSE (respectively), | |
| 76804 | +** then return 1. If one cannot determine the truth value of the | |
| 76805 | +** expression at compile-time return 0. | |
| 76806 | +** | |
| 76807 | +** This is an optimization. If is OK to return 0 here even if | |
| 76808 | +** the expression really is always false or false (a false negative). | |
| 76809 | +** But it is a bug to return 1 if the expression might have different | |
| 76810 | +** boolean values in different circumstances (a false positive.) | |
| 76775 | 76811 | ** |
| 76776 | 76812 | ** Note that if the expression is part of conditional for a |
| 76777 | 76813 | ** LEFT JOIN, then we cannot determine at compile-time whether or not |
| 76778 | 76814 | ** is it true or false, so always return 0. |
| 76779 | 76815 | */ |
| 76816 | +static int exprAlwaysTrue(Expr *p){ | |
| 76817 | + int v = 0; | |
| 76818 | + if( ExprHasProperty(p, EP_FromJoin) ) return 0; | |
| 76819 | + if( !sqlite3ExprIsInteger(p, &v) ) return 0; | |
| 76820 | + return v!=0; | |
| 76821 | +} | |
| 76780 | 76822 | static int exprAlwaysFalse(Expr *p){ |
| 76781 | 76823 | int v = 0; |
| 76782 | 76824 | if( ExprHasProperty(p, EP_FromJoin) ) return 0; |
| 76783 | 76825 | if( !sqlite3ExprIsInteger(p, &v) ) return 0; |
| 76784 | 76826 | return v==0; |
| @@ -79621,11 +79663,11 @@ | ||
| 79621 | 79663 | sqlite3ExplainPush(pOut); |
| 79622 | 79664 | for(i=0; i<pList->nExpr; i++){ |
| 79623 | 79665 | sqlite3ExplainPrintf(pOut, "item[%d] = ", i); |
| 79624 | 79666 | sqlite3ExplainPush(pOut); |
| 79625 | 79667 | sqlite3ExplainExpr(pOut, pList->a[i].pExpr); |
| 79626 | - sqlite3ExplainPop(pOut); | |
| 79668 | + sqlite3ExplainPop(pOut, 1); | |
| 79627 | 79669 | if( pList->a[i].zName ){ |
| 79628 | 79670 | sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); |
| 79629 | 79671 | } |
| 79630 | 79672 | if( pList->a[i].bSpanIsTab ){ |
| 79631 | 79673 | sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); |
| @@ -79771,21 +79813,23 @@ | ||
| 79771 | 79813 | op = pExpr->op; |
| 79772 | 79814 | switch( op ){ |
| 79773 | 79815 | case TK_AND: { |
| 79774 | 79816 | int d2 = sqlite3VdbeMakeLabel(v); |
| 79775 | 79817 | testcase( jumpIfNull==0 ); |
| 79776 | - sqlite3ExprCachePush(pParse); | |
| 79777 | 79818 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); |
| 79819 | + sqlite3ExprCachePush(pParse); | |
| 79778 | 79820 | sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79779 | 79821 | sqlite3VdbeResolveLabel(v, d2); |
| 79780 | 79822 | sqlite3ExprCachePop(pParse, 1); |
| 79781 | 79823 | break; |
| 79782 | 79824 | } |
| 79783 | 79825 | case TK_OR: { |
| 79784 | 79826 | testcase( jumpIfNull==0 ); |
| 79785 | 79827 | sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); |
| 79828 | + sqlite3ExprCachePush(pParse); | |
| 79786 | 79829 | sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79830 | + sqlite3ExprCachePop(pParse, 1); | |
| 79787 | 79831 | break; |
| 79788 | 79832 | } |
| 79789 | 79833 | case TK_NOT: { |
| 79790 | 79834 | testcase( jumpIfNull==0 ); |
| 79791 | 79835 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); |
| @@ -79856,14 +79900,20 @@ | ||
| 79856 | 79900 | sqlite3VdbeResolveLabel(v, destIfFalse); |
| 79857 | 79901 | break; |
| 79858 | 79902 | } |
| 79859 | 79903 | #endif |
| 79860 | 79904 | default: { |
| 79861 | - r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); | |
| 79862 | - sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); | |
| 79863 | - testcase( regFree1==0 ); | |
| 79864 | - testcase( jumpIfNull==0 ); | |
| 79905 | + if( exprAlwaysTrue(pExpr) ){ | |
| 79906 | + sqlite3VdbeAddOp2(v, OP_Goto, 0, dest); | |
| 79907 | + }else if( exprAlwaysFalse(pExpr) ){ | |
| 79908 | + /* No-op */ | |
| 79909 | + }else{ | |
| 79910 | + r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); | |
| 79911 | + sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); | |
| 79912 | + testcase( regFree1==0 ); | |
| 79913 | + testcase( jumpIfNull==0 ); | |
| 79914 | + } | |
| 79865 | 79915 | break; |
| 79866 | 79916 | } |
| 79867 | 79917 | } |
| 79868 | 79918 | sqlite3ReleaseTempReg(pParse, regFree1); |
| 79869 | 79919 | sqlite3ReleaseTempReg(pParse, regFree2); |
| @@ -79922,18 +79972,20 @@ | ||
| 79922 | 79972 | |
| 79923 | 79973 | switch( pExpr->op ){ |
| 79924 | 79974 | case TK_AND: { |
| 79925 | 79975 | testcase( jumpIfNull==0 ); |
| 79926 | 79976 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); |
| 79977 | + sqlite3ExprCachePush(pParse); | |
| 79927 | 79978 | sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79979 | + sqlite3ExprCachePop(pParse, 1); | |
| 79928 | 79980 | break; |
| 79929 | 79981 | } |
| 79930 | 79982 | case TK_OR: { |
| 79931 | 79983 | int d2 = sqlite3VdbeMakeLabel(v); |
| 79932 | 79984 | testcase( jumpIfNull==0 ); |
| 79933 | - sqlite3ExprCachePush(pParse); | |
| 79934 | 79985 | sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); |
| 79986 | + sqlite3ExprCachePush(pParse); | |
| 79935 | 79987 | sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79936 | 79988 | sqlite3VdbeResolveLabel(v, d2); |
| 79937 | 79989 | sqlite3ExprCachePop(pParse, 1); |
| 79938 | 79990 | break; |
| 79939 | 79991 | } |
| @@ -80001,14 +80053,20 @@ | ||
| 80001 | 80053 | } |
| 80002 | 80054 | break; |
| 80003 | 80055 | } |
| 80004 | 80056 | #endif |
| 80005 | 80057 | default: { |
| 80006 | - r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); | |
| 80007 | - sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); | |
| 80008 | - testcase( regFree1==0 ); | |
| 80009 | - testcase( jumpIfNull==0 ); | |
| 80058 | + if( exprAlwaysFalse(pExpr) ){ | |
| 80059 | + sqlite3VdbeAddOp2(v, OP_Goto, 0, dest); | |
| 80060 | + }else if( exprAlwaysTrue(pExpr) ){ | |
| 80061 | + /* no-op */ | |
| 80062 | + }else{ | |
| 80063 | + r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); | |
| 80064 | + sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); | |
| 80065 | + testcase( regFree1==0 ); | |
| 80066 | + testcase( jumpIfNull==0 ); | |
| 80067 | + } | |
| 80010 | 80068 | break; |
| 80011 | 80069 | } |
| 80012 | 80070 | } |
| 80013 | 80071 | sqlite3ReleaseTempReg(pParse, regFree1); |
| 80014 | 80072 | sqlite3ReleaseTempReg(pParse, regFree2); |
| @@ -89357,22 +89415,22 @@ | ||
| 89357 | 89415 | nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; |
| 89358 | 89416 | regBase = sqlite3GetTempRange(pParse, nCol); |
| 89359 | 89417 | for(j=0; j<nCol; j++){ |
| 89360 | 89418 | sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j], |
| 89361 | 89419 | regBase+j); |
| 89420 | + /* If the column affinity is REAL but the number is an integer, then it | |
| 89421 | + ** might be stored in the table as an integer (using a compact | |
| 89422 | + ** representation) then converted to REAL by an OP_RealAffinity opcode. | |
| 89423 | + ** But we are getting ready to store this value back into an index, where | |
| 89424 | + ** it should be converted by to INTEGER again. So omit the OP_RealAffinity | |
| 89425 | + ** opcode if it is present */ | |
| 89426 | + if( sqlite3VdbeGetOp(v, -1)->opcode==OP_RealAffinity ){ | |
| 89427 | + sqlite3VdbeDeleteLastOpcode(v); | |
| 89428 | + } | |
| 89362 | 89429 | } |
| 89363 | 89430 | if( regOut ){ |
| 89364 | - const char *zAff; | |
| 89365 | - if( pTab->pSelect | |
| 89366 | - || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt) | |
| 89367 | - ){ | |
| 89368 | - zAff = 0; | |
| 89369 | - }else{ | |
| 89370 | - zAff = sqlite3IndexAffinityStr(v, pIdx); | |
| 89371 | - } | |
| 89372 | 89431 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); |
| 89373 | - sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT); | |
| 89374 | 89432 | } |
| 89375 | 89433 | sqlite3ReleaseTempRange(pParse, regBase, nCol); |
| 89376 | 89434 | return regBase; |
| 89377 | 89435 | } |
| 89378 | 89436 | |
| @@ -93721,10 +93779,11 @@ | ||
| 93721 | 93779 | int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ |
| 93722 | 93780 | int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ |
| 93723 | 93781 | int ipkTop = 0; /* Top of the rowid change constraint check */ |
| 93724 | 93782 | int ipkBottom = 0; /* Bottom of the rowid change constraint check */ |
| 93725 | 93783 | u8 isUpdate; /* True if this is an UPDATE operation */ |
| 93784 | + int regRowid = -1; /* Register holding ROWID value */ | |
| 93726 | 93785 | |
| 93727 | 93786 | isUpdate = regOldData!=0; |
| 93728 | 93787 | db = pParse->db; |
| 93729 | 93788 | v = sqlite3GetVdbe(pParse); |
| 93730 | 93789 | assert( v!=0 ); |
| @@ -93951,11 +94010,13 @@ | ||
| 93951 | 94010 | regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); |
| 93952 | 94011 | for(i=0; i<pIdx->nColumn; i++){ |
| 93953 | 94012 | int iField = pIdx->aiColumn[i]; |
| 93954 | 94013 | int x; |
| 93955 | 94014 | if( iField<0 || iField==pTab->iPKey ){ |
| 94015 | + if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ | |
| 93956 | 94016 | x = regNewData; |
| 94017 | + regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; | |
| 93957 | 94018 | }else{ |
| 93958 | 94019 | x = iField + regNewData + 1; |
| 93959 | 94020 | } |
| 93960 | 94021 | sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); |
| 93961 | 94022 | VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); |
| @@ -98780,11 +98841,15 @@ | ||
| 98780 | 98841 | |
| 98781 | 98842 | /* |
| 98782 | 98843 | ** Free all memory allocations in the pParse object |
| 98783 | 98844 | */ |
| 98784 | 98845 | SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){ |
| 98785 | - if( pParse ) sqlite3ExprListDelete(pParse->db, pParse->pConstExpr); | |
| 98846 | + if( pParse ){ | |
| 98847 | + sqlite3 *db = pParse->db; | |
| 98848 | + sqlite3DbFree(db, pParse->aLabel); | |
| 98849 | + sqlite3ExprListDelete(db, pParse->pConstExpr); | |
| 98850 | + } | |
| 98786 | 98851 | } |
| 98787 | 98852 | |
| 98788 | 98853 | /* |
| 98789 | 98854 | ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. |
| 98790 | 98855 | */ |
| @@ -113528,13 +113593,16 @@ | ||
| 113528 | 113593 | sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ |
| 113529 | 113594 | |
| 113530 | 113595 | /* Special case: a WHERE clause that is constant. Evaluate the |
| 113531 | 113596 | ** expression and either jump over all of the code or fall thru. |
| 113532 | 113597 | */ |
| 113533 | - if( pWhere && (nTabList==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){ | |
| 113534 | - sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL); | |
| 113535 | - pWhere = 0; | |
| 113598 | + for(ii=0; ii<sWLB.pWC->nTerm; ii++){ | |
| 113599 | + if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){ | |
| 113600 | + sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak, | |
| 113601 | + SQLITE_JUMPIFNULL); | |
| 113602 | + sWLB.pWC->a[ii].wtFlags |= TERM_CODED; | |
| 113603 | + } | |
| 113536 | 113604 | } |
| 113537 | 113605 | |
| 113538 | 113606 | /* Special case: No FROM clause |
| 113539 | 113607 | */ |
| 113540 | 113608 | if( nTabList==0 ){ |
| @@ -121784,11 +121852,11 @@ | ||
| 121784 | 121852 | ** Reset the PRNG back to its uninitialized state. The next call |
| 121785 | 121853 | ** to sqlite3_randomness() will reseed the PRNG using a single call |
| 121786 | 121854 | ** to the xRandomness method of the default VFS. |
| 121787 | 121855 | */ |
| 121788 | 121856 | case SQLITE_TESTCTRL_PRNG_RESET: { |
| 121789 | - sqlite3PrngResetState(); | |
| 121857 | + sqlite3_randomness(0,0); | |
| 121790 | 121858 | break; |
| 121791 | 121859 | } |
| 121792 | 121860 | |
| 121793 | 121861 | /* |
| 121794 | 121862 | ** sqlite3_test_control(BITVEC_TEST, size, program) |
| @@ -124767,10 +124835,23 @@ | ||
| 124767 | 124835 | sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ |
| 124768 | 124836 | char **pzErr /* OUT: sqlite3_malloc'd error message */ |
| 124769 | 124837 | ){ |
| 124770 | 124838 | return fts3InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); |
| 124771 | 124839 | } |
| 124840 | + | |
| 124841 | +/* | |
| 124842 | +** Set the pIdxInfo->estimatedRows variable to nRow. Unless this | |
| 124843 | +** extension is currently being used by a version of SQLite too old to | |
| 124844 | +** support estimatedRows. In that case this function is a no-op. | |
| 124845 | +*/ | |
| 124846 | +static void setEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ | |
| 124847 | +#if SQLITE_VERSION_NUMBER>=3008002 | |
| 124848 | + if( sqlite3_libversion_number()>=3008002 ){ | |
| 124849 | + pIdxInfo->estimatedRows = nRow; | |
| 124850 | + } | |
| 124851 | +#endif | |
| 124852 | +} | |
| 124772 | 124853 | |
| 124773 | 124854 | /* |
| 124774 | 124855 | ** Implementation of the xBestIndex method for FTS3 tables. There |
| 124775 | 124856 | ** are three possible strategies, in order of preference: |
| 124776 | 124857 | ** |
| @@ -124795,11 +124876,24 @@ | ||
| 124795 | 124876 | pInfo->idxNum = FTS3_FULLSCAN_SEARCH; |
| 124796 | 124877 | pInfo->estimatedCost = 5000000; |
| 124797 | 124878 | for(i=0; i<pInfo->nConstraint; i++){ |
| 124798 | 124879 | int bDocid; /* True if this constraint is on docid */ |
| 124799 | 124880 | struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i]; |
| 124800 | - if( pCons->usable==0 ) continue; | |
| 124881 | + if( pCons->usable==0 ){ | |
| 124882 | + if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ | |
| 124883 | + /* There exists an unusable MATCH constraint. This means that if | |
| 124884 | + ** the planner does elect to use the results of this call as part | |
| 124885 | + ** of the overall query plan the user will see an "unable to use | |
| 124886 | + ** function MATCH in the requested context" error. To discourage | |
| 124887 | + ** this, return a very high cost here. */ | |
| 124888 | + pInfo->idxNum = FTS3_FULLSCAN_SEARCH; | |
| 124889 | + pInfo->estimatedCost = 1e50; | |
| 124890 | + setEstimatedRows(pInfo, ((sqlite3_int64)1) << 50); | |
| 124891 | + return SQLITE_OK; | |
| 124892 | + } | |
| 124893 | + continue; | |
| 124894 | + } | |
| 124801 | 124895 | |
| 124802 | 124896 | bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1); |
| 124803 | 124897 | |
| 124804 | 124898 | /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */ |
| 124805 | 124899 | if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){ |
| 124806 | 124900 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -135,11 +135,11 @@ | |
| 135 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 136 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 137 | */ |
| 138 | #define SQLITE_VERSION "3.8.3" |
| 139 | #define SQLITE_VERSION_NUMBER 3008003 |
| 140 | #define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d" |
| 141 | |
| 142 | /* |
| 143 | ** CAPI3REF: Run-Time Library Version Numbers |
| 144 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 145 | ** |
| @@ -2426,15 +2426,17 @@ | |
| 2426 | ** already uses the largest possible [ROWID]. The PRNG is also used for |
| 2427 | ** the build-in random() and randomblob() SQL functions. This interface allows |
| 2428 | ** applications to access the same PRNG for other purposes. |
| 2429 | ** |
| 2430 | ** ^A call to this routine stores N bytes of randomness into buffer P. |
| 2431 | ** |
| 2432 | ** ^The first time this routine is invoked (either internally or by |
| 2433 | ** the application) the PRNG is seeded using randomness obtained |
| 2434 | ** from the xRandomness method of the default [sqlite3_vfs] object. |
| 2435 | ** ^On all subsequent invocations, the pseudo-randomness is generated |
| 2436 | ** internally and without recourse to the [sqlite3_vfs] xRandomness |
| 2437 | ** method. |
| 2438 | */ |
| 2439 | SQLITE_API void sqlite3_randomness(int N, void *P); |
| 2440 | |
| @@ -9278,10 +9280,11 @@ | |
| 9278 | SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); |
| 9279 | SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); |
| 9280 | SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); |
| 9281 | SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); |
| 9282 | SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr); |
| 9283 | SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); |
| 9284 | SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); |
| 9285 | SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); |
| 9286 | SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); |
| 9287 | SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); |
| @@ -10371,11 +10374,11 @@ | |
| 10371 | */ |
| 10372 | #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ |
| 10373 | #define SQLITE_ColumnCache 0x0002 /* Column cache */ |
| 10374 | #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ |
| 10375 | #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ |
| 10376 | #define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */ |
| 10377 | #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ |
| 10378 | #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ |
| 10379 | #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ |
| 10380 | #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ |
| 10381 | #define SQLITE_Transitive 0x0200 /* Transitive constraints */ |
| @@ -11605,10 +11608,13 @@ | |
| 11605 | int nErr; /* Number of errors seen */ |
| 11606 | int nTab; /* Number of previously allocated VDBE cursors */ |
| 11607 | int nMem; /* Number of memory cells used so far */ |
| 11608 | int nSet; /* Number of sets used so far */ |
| 11609 | int nOnce; /* Number of OP_Once instructions so far */ |
| 11610 | int ckBase; /* Base register of data during check constraints */ |
| 11611 | int iPartIdxTab; /* Table corresponding to a partial index */ |
| 11612 | int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ |
| 11613 | int iCacheCnt; /* Counter used to generate aColCache[].lru values */ |
| 11614 | struct yColCache { |
| @@ -12284,11 +12290,10 @@ | |
| 12284 | SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); |
| 12285 | SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); |
| 12286 | SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); |
| 12287 | SQLITE_PRIVATE void sqlite3PrngSaveState(void); |
| 12288 | SQLITE_PRIVATE void sqlite3PrngRestoreState(void); |
| 12289 | SQLITE_PRIVATE void sqlite3PrngResetState(void); |
| 12290 | SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); |
| 12291 | SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); |
| 12292 | SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); |
| 12293 | SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); |
| 12294 | SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); |
| @@ -13776,19 +13781,13 @@ | |
| 13776 | Op *aOp; /* Space to hold the virtual machine's program */ |
| 13777 | Mem *aMem; /* The memory locations */ |
| 13778 | Mem **apArg; /* Arguments to currently executing user function */ |
| 13779 | Mem *aColName; /* Column names to return */ |
| 13780 | Mem *pResultSet; /* Pointer to an array of results */ |
| 13781 | #ifdef SQLITE_DEBUG |
| 13782 | Parse *pParse; /* Parsing context used to create this Vdbe */ |
| 13783 | #endif |
| 13784 | int nMem; /* Number of memory locations currently allocated */ |
| 13785 | int nOp; /* Number of instructions in the program */ |
| 13786 | int nOpAlloc; /* Number of slots allocated for aOp[] */ |
| 13787 | int nLabel; /* Number of labels used */ |
| 13788 | int *aLabel; /* Space to hold the labels */ |
| 13789 | u16 nResColumn; /* Number of columns in one row of the result set */ |
| 13790 | int nCursor; /* Number of slots in apCsr[] */ |
| 13791 | u32 magic; /* Magic number for sanity checking */ |
| 13792 | char *zErrMsg; /* Error message written here */ |
| 13793 | Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ |
| 13794 | VdbeCursor **apCsr; /* One element of this array for each open cursor */ |
| @@ -13797,10 +13796,11 @@ | |
| 13797 | ynVar nVar; /* Number of entries in aVar[] */ |
| 13798 | ynVar nzVar; /* Number of entries in azVar[] */ |
| 13799 | u32 cacheCtr; /* VdbeCursor row cache generation counter */ |
| 13800 | int pc; /* The program counter */ |
| 13801 | int rc; /* Value to return */ |
| 13802 | u8 errorAction; /* Recovery action to do in case of an error */ |
| 13803 | u8 minWriteFileFormat; /* Minimum file format for writable database files */ |
| 13804 | bft explain:2; /* True if EXPLAIN present on SQL command */ |
| 13805 | bft inVtabMethod:2; /* See comments above */ |
| 13806 | bft changeCntOn:1; /* True to update the change-counter */ |
| @@ -20901,10 +20901,16 @@ | |
| 20901 | |
| 20902 | #if SQLITE_THREADSAFE |
| 20903 | sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); |
| 20904 | sqlite3_mutex_enter(mutex); |
| 20905 | #endif |
| 20906 | |
| 20907 | /* Initialize the state of the random number generator once, |
| 20908 | ** the first time this routine is called. The seed value does |
| 20909 | ** not need to contain a lot of randomness since we are not |
| 20910 | ** trying to do secure encryption or anything like that... |
| @@ -20929,19 +20935,20 @@ | |
| 20929 | wsdPrng.s[i] = t; |
| 20930 | } |
| 20931 | wsdPrng.isInit = 1; |
| 20932 | } |
| 20933 | |
| 20934 | while( N-- ){ |
| 20935 | wsdPrng.i++; |
| 20936 | t = wsdPrng.s[wsdPrng.i]; |
| 20937 | wsdPrng.j += t; |
| 20938 | wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j]; |
| 20939 | wsdPrng.s[wsdPrng.j] = t; |
| 20940 | t += wsdPrng.s[wsdPrng.i]; |
| 20941 | *(zBuf++) = wsdPrng.s[t]; |
| 20942 | } |
| 20943 | sqlite3_mutex_leave(mutex); |
| 20944 | } |
| 20945 | |
| 20946 | #ifndef SQLITE_OMIT_BUILTIN_TEST |
| 20947 | /* |
| @@ -20966,13 +20973,10 @@ | |
| 20966 | &GLOBAL(struct sqlite3PrngType, sqlite3Prng), |
| 20967 | &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), |
| 20968 | sizeof(sqlite3Prng) |
| 20969 | ); |
| 20970 | } |
| 20971 | SQLITE_PRIVATE void sqlite3PrngResetState(void){ |
| 20972 | GLOBAL(struct sqlite3PrngType, sqlite3Prng).isInit = 0; |
| 20973 | } |
| 20974 | #endif /* SQLITE_OMIT_BUILTIN_TEST */ |
| 20975 | |
| 20976 | /************** End of random.c **********************************************/ |
| 20977 | /************** Begin file utf.c *********************************************/ |
| 20978 | /* |
| @@ -23505,10 +23509,16 @@ | |
| 23505 | ** it is larger than the struct CrashFile defined in test6.c. |
| 23506 | */ |
| 23507 | char aPadding[32]; |
| 23508 | #endif |
| 23509 | }; |
| 23510 | |
| 23511 | /* |
| 23512 | ** Allowed values for the unixFile.ctrlFlags bitmask: |
| 23513 | */ |
| 23514 | #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
| @@ -29104,10 +29114,20 @@ | |
| 29104 | assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB |
| 29105 | || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL |
| 29106 | || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL |
| 29107 | || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
| 29108 | ); |
| 29109 | |
| 29110 | memset(p, 0, sizeof(unixFile)); |
| 29111 | |
| 29112 | if( eType==SQLITE_OPEN_MAIN_DB ){ |
| 29113 | UnixUnusedFd *pUnused; |
| @@ -29492,22 +29512,22 @@ | |
| 29492 | ** When testing, initializing zBuf[] to zero is all we do. That means |
| 29493 | ** that we always use the same random number sequence. This makes the |
| 29494 | ** tests repeatable. |
| 29495 | */ |
| 29496 | memset(zBuf, 0, nBuf); |
| 29497 | #if !defined(SQLITE_TEST) |
| 29498 | { |
| 29499 | int pid, fd, got; |
| 29500 | fd = robust_open("/dev/urandom", O_RDONLY, 0); |
| 29501 | if( fd<0 ){ |
| 29502 | time_t t; |
| 29503 | time(&t); |
| 29504 | memcpy(zBuf, &t, sizeof(t)); |
| 29505 | pid = getpid(); |
| 29506 | memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid)); |
| 29507 | assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf ); |
| 29508 | nBuf = sizeof(t) + sizeof(pid); |
| 29509 | }else{ |
| 29510 | do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR ); |
| 29511 | robust_close(0, fd, __LINE__); |
| 29512 | } |
| 29513 | } |
| @@ -61200,13 +61220,14 @@ | |
| 61200 | } |
| 61201 | p->pNext = db->pVdbe; |
| 61202 | p->pPrev = 0; |
| 61203 | db->pVdbe = p; |
| 61204 | p->magic = VDBE_MAGIC_INIT; |
| 61205 | #if SQLITE_DEBUG |
| 61206 | p->pParse = pParse; |
| 61207 | #endif |
| 61208 | return p; |
| 61209 | } |
| 61210 | |
| 61211 | /* |
| 61212 | ** Remember the SQL string for a prepared statement. |
| @@ -61258,17 +61279,18 @@ | |
| 61258 | ** If an out-of-memory error occurs while resizing the array, return |
| 61259 | ** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain |
| 61260 | ** unchanged (this is so that any opcodes already allocated can be |
| 61261 | ** correctly deallocated along with the rest of the Vdbe). |
| 61262 | */ |
| 61263 | static int growOpArray(Vdbe *p){ |
| 61264 | VdbeOp *pNew; |
| 61265 | int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op))); |
| 61266 | pNew = sqlite3DbRealloc(p->db, p->aOp, nNew*sizeof(Op)); |
| 61267 | if( pNew ){ |
| 61268 | p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op); |
| 61269 | p->aOp = pNew; |
| 61270 | } |
| 61271 | return (pNew ? SQLITE_OK : SQLITE_NOMEM); |
| 61272 | } |
| 61273 | |
| 61274 | #ifdef SQLITE_DEBUG |
| @@ -61303,11 +61325,11 @@ | |
| 61303 | VdbeOp *pOp; |
| 61304 | |
| 61305 | i = p->nOp; |
| 61306 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 61307 | assert( op>0 && op<0xff ); |
| 61308 | if( p->nOpAlloc<=i ){ |
| 61309 | if( growOpArray(p) ){ |
| 61310 | return 1; |
| 61311 | } |
| 61312 | } |
| 61313 | p->nOp++; |
| @@ -61414,13 +61436,14 @@ | |
| 61414 | ** always negative and P2 values are suppose to be non-negative. |
| 61415 | ** Hence, a negative P2 value is a label that has yet to be resolved. |
| 61416 | ** |
| 61417 | ** Zero is returned if a malloc() fails. |
| 61418 | */ |
| 61419 | SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *p){ |
| 61420 | int i = p->nLabel++; |
| 61421 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 61422 | if( (i & (i-1))==0 ){ |
| 61423 | p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, |
| 61424 | (i*2+1)*sizeof(p->aLabel[0])); |
| 61425 | } |
| 61426 | if( p->aLabel ){ |
| @@ -61432,16 +61455,17 @@ | |
| 61432 | /* |
| 61433 | ** Resolve label "x" to be the address of the next instruction to |
| 61434 | ** be inserted. The parameter "x" must have been obtained from |
| 61435 | ** a prior call to sqlite3VdbeMakeLabel(). |
| 61436 | */ |
| 61437 | SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *p, int x){ |
| 61438 | int j = -1-x; |
| 61439 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 61440 | assert( j<p->nLabel ); |
| 61441 | if( j>=0 && p->aLabel ){ |
| 61442 | p->aLabel[j] = p->nOp; |
| 61443 | } |
| 61444 | } |
| 61445 | |
| 61446 | /* |
| 61447 | ** Mark the VDBE as one that can only be run one time. |
| @@ -61586,11 +61610,12 @@ | |
| 61586 | */ |
| 61587 | static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ |
| 61588 | int i; |
| 61589 | int nMaxArgs = *pMaxFuncArgs; |
| 61590 | Op *pOp; |
| 61591 | int *aLabel = p->aLabel; |
| 61592 | p->readOnly = 1; |
| 61593 | p->bIsReader = 0; |
| 61594 | for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ |
| 61595 | u8 opcode = pOp->opcode; |
| 61596 | |
| @@ -61649,16 +61674,17 @@ | |
| 61649 | } |
| 61650 | } |
| 61651 | |
| 61652 | pOp->opflags = sqlite3OpcodeProperty[opcode]; |
| 61653 | if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ |
| 61654 | assert( -1-pOp->p2<p->nLabel ); |
| 61655 | pOp->p2 = aLabel[-1-pOp->p2]; |
| 61656 | } |
| 61657 | } |
| 61658 | sqlite3DbFree(p->db, p->aLabel); |
| 61659 | p->aLabel = 0; |
| 61660 | *pMaxFuncArgs = nMaxArgs; |
| 61661 | assert( p->bIsReader!=0 || p->btreeMask==0 ); |
| 61662 | } |
| 61663 | |
| 61664 | /* |
| @@ -61698,11 +61724,11 @@ | |
| 61698 | ** address of the first operation added. |
| 61699 | */ |
| 61700 | SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ |
| 61701 | int addr; |
| 61702 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 61703 | if( p->nOp + nOp > p->nOpAlloc && growOpArray(p) ){ |
| 61704 | return 0; |
| 61705 | } |
| 61706 | addr = p->nOp; |
| 61707 | if( ALWAYS(nOp>0) ){ |
| 61708 | int i; |
| @@ -61886,10 +61912,17 @@ | |
| 61886 | memset(pOp, 0, sizeof(pOp[0])); |
| 61887 | pOp->opcode = OP_Noop; |
| 61888 | if( addr==p->nOp-1 ) p->nOp--; |
| 61889 | } |
| 61890 | } |
| 61891 | |
| 61892 | /* |
| 61893 | ** Change the value of the P4 operand for a specific instruction. |
| 61894 | ** This routine is useful when a large program is loaded from a |
| 61895 | ** static array using sqlite3VdbeAddOpList but we want to make a |
| @@ -62768,10 +62801,11 @@ | |
| 62768 | |
| 62769 | assert( p!=0 ); |
| 62770 | assert( p->nOp>0 ); |
| 62771 | assert( pParse!=0 ); |
| 62772 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 62773 | db = p->db; |
| 62774 | assert( db->mallocFailed==0 ); |
| 62775 | nVar = pParse->nVar; |
| 62776 | nMem = pParse->nMem; |
| 62777 | nCursor = pParse->nTab; |
| @@ -62791,12 +62825,12 @@ | |
| 62791 | nMem += nCursor; |
| 62792 | |
| 62793 | /* Allocate space for memory registers, SQL variables, VDBE cursors and |
| 62794 | ** an array to marshal SQL function arguments in. |
| 62795 | */ |
| 62796 | zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */ |
| 62797 | zEnd = (u8*)&p->aOp[p->nOpAlloc]; /* First byte past end of zCsr[] */ |
| 62798 | |
| 62799 | resolveP2Values(p, &nArg); |
| 62800 | p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); |
| 62801 | if( pParse->explain && nMem<10 ){ |
| 62802 | nMem = 10; |
| @@ -63795,11 +63829,10 @@ | |
| 63795 | vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); |
| 63796 | sqlite3DbFree(db, pSub); |
| 63797 | } |
| 63798 | for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); |
| 63799 | vdbeFreeOpArray(db, p->aOp, p->nOp); |
| 63800 | sqlite3DbFree(db, p->aLabel); |
| 63801 | sqlite3DbFree(db, p->aColName); |
| 63802 | sqlite3DbFree(db, p->zSql); |
| 63803 | sqlite3DbFree(db, p->pFree); |
| 63804 | #if defined(SQLITE_ENABLE_TREE_EXPLAIN) |
| 63805 | sqlite3DbFree(db, p->zExplain); |
| @@ -76765,20 +76798,29 @@ | |
| 76765 | } |
| 76766 | return p; |
| 76767 | } |
| 76768 | |
| 76769 | /* |
| 76770 | ** Return 1 if an expression must be FALSE in all cases and 0 if the |
| 76771 | ** expression might be true. This is an optimization. If is OK to |
| 76772 | ** return 0 here even if the expression really is always false (a |
| 76773 | ** false negative). But it is a bug to return 1 if the expression |
| 76774 | ** might be true in some rare circumstances (a false positive.) |
| 76775 | ** |
| 76776 | ** Note that if the expression is part of conditional for a |
| 76777 | ** LEFT JOIN, then we cannot determine at compile-time whether or not |
| 76778 | ** is it true or false, so always return 0. |
| 76779 | */ |
| 76780 | static int exprAlwaysFalse(Expr *p){ |
| 76781 | int v = 0; |
| 76782 | if( ExprHasProperty(p, EP_FromJoin) ) return 0; |
| 76783 | if( !sqlite3ExprIsInteger(p, &v) ) return 0; |
| 76784 | return v==0; |
| @@ -79621,11 +79663,11 @@ | |
| 79621 | sqlite3ExplainPush(pOut); |
| 79622 | for(i=0; i<pList->nExpr; i++){ |
| 79623 | sqlite3ExplainPrintf(pOut, "item[%d] = ", i); |
| 79624 | sqlite3ExplainPush(pOut); |
| 79625 | sqlite3ExplainExpr(pOut, pList->a[i].pExpr); |
| 79626 | sqlite3ExplainPop(pOut); |
| 79627 | if( pList->a[i].zName ){ |
| 79628 | sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); |
| 79629 | } |
| 79630 | if( pList->a[i].bSpanIsTab ){ |
| 79631 | sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); |
| @@ -79771,21 +79813,23 @@ | |
| 79771 | op = pExpr->op; |
| 79772 | switch( op ){ |
| 79773 | case TK_AND: { |
| 79774 | int d2 = sqlite3VdbeMakeLabel(v); |
| 79775 | testcase( jumpIfNull==0 ); |
| 79776 | sqlite3ExprCachePush(pParse); |
| 79777 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); |
| 79778 | sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79779 | sqlite3VdbeResolveLabel(v, d2); |
| 79780 | sqlite3ExprCachePop(pParse, 1); |
| 79781 | break; |
| 79782 | } |
| 79783 | case TK_OR: { |
| 79784 | testcase( jumpIfNull==0 ); |
| 79785 | sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); |
| 79786 | sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79787 | break; |
| 79788 | } |
| 79789 | case TK_NOT: { |
| 79790 | testcase( jumpIfNull==0 ); |
| 79791 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); |
| @@ -79856,14 +79900,20 @@ | |
| 79856 | sqlite3VdbeResolveLabel(v, destIfFalse); |
| 79857 | break; |
| 79858 | } |
| 79859 | #endif |
| 79860 | default: { |
| 79861 | r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); |
| 79862 | sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); |
| 79863 | testcase( regFree1==0 ); |
| 79864 | testcase( jumpIfNull==0 ); |
| 79865 | break; |
| 79866 | } |
| 79867 | } |
| 79868 | sqlite3ReleaseTempReg(pParse, regFree1); |
| 79869 | sqlite3ReleaseTempReg(pParse, regFree2); |
| @@ -79922,18 +79972,20 @@ | |
| 79922 | |
| 79923 | switch( pExpr->op ){ |
| 79924 | case TK_AND: { |
| 79925 | testcase( jumpIfNull==0 ); |
| 79926 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); |
| 79927 | sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79928 | break; |
| 79929 | } |
| 79930 | case TK_OR: { |
| 79931 | int d2 = sqlite3VdbeMakeLabel(v); |
| 79932 | testcase( jumpIfNull==0 ); |
| 79933 | sqlite3ExprCachePush(pParse); |
| 79934 | sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); |
| 79935 | sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79936 | sqlite3VdbeResolveLabel(v, d2); |
| 79937 | sqlite3ExprCachePop(pParse, 1); |
| 79938 | break; |
| 79939 | } |
| @@ -80001,14 +80053,20 @@ | |
| 80001 | } |
| 80002 | break; |
| 80003 | } |
| 80004 | #endif |
| 80005 | default: { |
| 80006 | r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); |
| 80007 | sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); |
| 80008 | testcase( regFree1==0 ); |
| 80009 | testcase( jumpIfNull==0 ); |
| 80010 | break; |
| 80011 | } |
| 80012 | } |
| 80013 | sqlite3ReleaseTempReg(pParse, regFree1); |
| 80014 | sqlite3ReleaseTempReg(pParse, regFree2); |
| @@ -89357,22 +89415,22 @@ | |
| 89357 | nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; |
| 89358 | regBase = sqlite3GetTempRange(pParse, nCol); |
| 89359 | for(j=0; j<nCol; j++){ |
| 89360 | sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j], |
| 89361 | regBase+j); |
| 89362 | } |
| 89363 | if( regOut ){ |
| 89364 | const char *zAff; |
| 89365 | if( pTab->pSelect |
| 89366 | || OptimizationDisabled(pParse->db, SQLITE_IdxRealAsInt) |
| 89367 | ){ |
| 89368 | zAff = 0; |
| 89369 | }else{ |
| 89370 | zAff = sqlite3IndexAffinityStr(v, pIdx); |
| 89371 | } |
| 89372 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); |
| 89373 | sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT); |
| 89374 | } |
| 89375 | sqlite3ReleaseTempRange(pParse, regBase, nCol); |
| 89376 | return regBase; |
| 89377 | } |
| 89378 | |
| @@ -93721,10 +93779,11 @@ | |
| 93721 | int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ |
| 93722 | int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ |
| 93723 | int ipkTop = 0; /* Top of the rowid change constraint check */ |
| 93724 | int ipkBottom = 0; /* Bottom of the rowid change constraint check */ |
| 93725 | u8 isUpdate; /* True if this is an UPDATE operation */ |
| 93726 | |
| 93727 | isUpdate = regOldData!=0; |
| 93728 | db = pParse->db; |
| 93729 | v = sqlite3GetVdbe(pParse); |
| 93730 | assert( v!=0 ); |
| @@ -93951,11 +94010,13 @@ | |
| 93951 | regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); |
| 93952 | for(i=0; i<pIdx->nColumn; i++){ |
| 93953 | int iField = pIdx->aiColumn[i]; |
| 93954 | int x; |
| 93955 | if( iField<0 || iField==pTab->iPKey ){ |
| 93956 | x = regNewData; |
| 93957 | }else{ |
| 93958 | x = iField + regNewData + 1; |
| 93959 | } |
| 93960 | sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); |
| 93961 | VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); |
| @@ -98780,11 +98841,15 @@ | |
| 98780 | |
| 98781 | /* |
| 98782 | ** Free all memory allocations in the pParse object |
| 98783 | */ |
| 98784 | SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){ |
| 98785 | if( pParse ) sqlite3ExprListDelete(pParse->db, pParse->pConstExpr); |
| 98786 | } |
| 98787 | |
| 98788 | /* |
| 98789 | ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. |
| 98790 | */ |
| @@ -113528,13 +113593,16 @@ | |
| 113528 | sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ |
| 113529 | |
| 113530 | /* Special case: a WHERE clause that is constant. Evaluate the |
| 113531 | ** expression and either jump over all of the code or fall thru. |
| 113532 | */ |
| 113533 | if( pWhere && (nTabList==0 || sqlite3ExprIsConstantNotJoin(pWhere)) ){ |
| 113534 | sqlite3ExprIfFalse(pParse, pWhere, pWInfo->iBreak, SQLITE_JUMPIFNULL); |
| 113535 | pWhere = 0; |
| 113536 | } |
| 113537 | |
| 113538 | /* Special case: No FROM clause |
| 113539 | */ |
| 113540 | if( nTabList==0 ){ |
| @@ -121784,11 +121852,11 @@ | |
| 121784 | ** Reset the PRNG back to its uninitialized state. The next call |
| 121785 | ** to sqlite3_randomness() will reseed the PRNG using a single call |
| 121786 | ** to the xRandomness method of the default VFS. |
| 121787 | */ |
| 121788 | case SQLITE_TESTCTRL_PRNG_RESET: { |
| 121789 | sqlite3PrngResetState(); |
| 121790 | break; |
| 121791 | } |
| 121792 | |
| 121793 | /* |
| 121794 | ** sqlite3_test_control(BITVEC_TEST, size, program) |
| @@ -124767,10 +124835,23 @@ | |
| 124767 | sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ |
| 124768 | char **pzErr /* OUT: sqlite3_malloc'd error message */ |
| 124769 | ){ |
| 124770 | return fts3InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); |
| 124771 | } |
| 124772 | |
| 124773 | /* |
| 124774 | ** Implementation of the xBestIndex method for FTS3 tables. There |
| 124775 | ** are three possible strategies, in order of preference: |
| 124776 | ** |
| @@ -124795,11 +124876,24 @@ | |
| 124795 | pInfo->idxNum = FTS3_FULLSCAN_SEARCH; |
| 124796 | pInfo->estimatedCost = 5000000; |
| 124797 | for(i=0; i<pInfo->nConstraint; i++){ |
| 124798 | int bDocid; /* True if this constraint is on docid */ |
| 124799 | struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i]; |
| 124800 | if( pCons->usable==0 ) continue; |
| 124801 | |
| 124802 | bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1); |
| 124803 | |
| 124804 | /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */ |
| 124805 | if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){ |
| 124806 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -135,11 +135,11 @@ | |
| 135 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 136 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 137 | */ |
| 138 | #define SQLITE_VERSION "3.8.3" |
| 139 | #define SQLITE_VERSION_NUMBER 3008003 |
| 140 | #define SQLITE_SOURCE_ID "2014-01-04 15:17:04 4e725f53131d3584319c710c8710a068989543c6" |
| 141 | |
| 142 | /* |
| 143 | ** CAPI3REF: Run-Time Library Version Numbers |
| 144 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 145 | ** |
| @@ -2426,15 +2426,17 @@ | |
| 2426 | ** already uses the largest possible [ROWID]. The PRNG is also used for |
| 2427 | ** the build-in random() and randomblob() SQL functions. This interface allows |
| 2428 | ** applications to access the same PRNG for other purposes. |
| 2429 | ** |
| 2430 | ** ^A call to this routine stores N bytes of randomness into buffer P. |
| 2431 | ** ^If N is less than one, then P can be a NULL pointer. |
| 2432 | ** |
| 2433 | ** ^If this routine has not been previously called or if the previous |
| 2434 | ** call had N less than one, then the PRNG is seeded using randomness |
| 2435 | ** obtained from the xRandomness method of the default [sqlite3_vfs] object. |
| 2436 | ** ^If the previous call to this routine had an N of 1 or more then |
| 2437 | ** the pseudo-randomness is generated |
| 2438 | ** internally and without recourse to the [sqlite3_vfs] xRandomness |
| 2439 | ** method. |
| 2440 | */ |
| 2441 | SQLITE_API void sqlite3_randomness(int N, void *P); |
| 2442 | |
| @@ -9278,10 +9280,11 @@ | |
| 9280 | SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); |
| 9281 | SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); |
| 9282 | SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); |
| 9283 | SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); |
| 9284 | SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr); |
| 9285 | SQLITE_PRIVATE void sqlite3VdbeDeleteLastOpcode(Vdbe*); |
| 9286 | SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); |
| 9287 | SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); |
| 9288 | SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); |
| 9289 | SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); |
| 9290 | SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); |
| @@ -10371,11 +10374,11 @@ | |
| 10374 | */ |
| 10375 | #define SQLITE_QueryFlattener 0x0001 /* Query flattening */ |
| 10376 | #define SQLITE_ColumnCache 0x0002 /* Column cache */ |
| 10377 | #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ |
| 10378 | #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ |
| 10379 | /* not used 0x0010 // Was: SQLITE_IdxRealAsInt */ |
| 10380 | #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ |
| 10381 | #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ |
| 10382 | #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ |
| 10383 | #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ |
| 10384 | #define SQLITE_Transitive 0x0200 /* Transitive constraints */ |
| @@ -11605,10 +11608,13 @@ | |
| 11608 | int nErr; /* Number of errors seen */ |
| 11609 | int nTab; /* Number of previously allocated VDBE cursors */ |
| 11610 | int nMem; /* Number of memory cells used so far */ |
| 11611 | int nSet; /* Number of sets used so far */ |
| 11612 | int nOnce; /* Number of OP_Once instructions so far */ |
| 11613 | int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ |
| 11614 | int nLabel; /* Number of labels used */ |
| 11615 | int *aLabel; /* Space to hold the labels */ |
| 11616 | int ckBase; /* Base register of data during check constraints */ |
| 11617 | int iPartIdxTab; /* Table corresponding to a partial index */ |
| 11618 | int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ |
| 11619 | int iCacheCnt; /* Counter used to generate aColCache[].lru values */ |
| 11620 | struct yColCache { |
| @@ -12284,11 +12290,10 @@ | |
| 12290 | SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); |
| 12291 | SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); |
| 12292 | SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); |
| 12293 | SQLITE_PRIVATE void sqlite3PrngSaveState(void); |
| 12294 | SQLITE_PRIVATE void sqlite3PrngRestoreState(void); |
| 12295 | SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int); |
| 12296 | SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); |
| 12297 | SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); |
| 12298 | SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); |
| 12299 | SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); |
| @@ -13776,19 +13781,13 @@ | |
| 13781 | Op *aOp; /* Space to hold the virtual machine's program */ |
| 13782 | Mem *aMem; /* The memory locations */ |
| 13783 | Mem **apArg; /* Arguments to currently executing user function */ |
| 13784 | Mem *aColName; /* Column names to return */ |
| 13785 | Mem *pResultSet; /* Pointer to an array of results */ |
| 13786 | Parse *pParse; /* Parsing context used to create this Vdbe */ |
| 13787 | int nMem; /* Number of memory locations currently allocated */ |
| 13788 | int nOp; /* Number of instructions in the program */ |
| 13789 | int nCursor; /* Number of slots in apCsr[] */ |
| 13790 | u32 magic; /* Magic number for sanity checking */ |
| 13791 | char *zErrMsg; /* Error message written here */ |
| 13792 | Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ |
| 13793 | VdbeCursor **apCsr; /* One element of this array for each open cursor */ |
| @@ -13797,10 +13796,11 @@ | |
| 13796 | ynVar nVar; /* Number of entries in aVar[] */ |
| 13797 | ynVar nzVar; /* Number of entries in azVar[] */ |
| 13798 | u32 cacheCtr; /* VdbeCursor row cache generation counter */ |
| 13799 | int pc; /* The program counter */ |
| 13800 | int rc; /* Value to return */ |
| 13801 | u16 nResColumn; /* Number of columns in one row of the result set */ |
| 13802 | u8 errorAction; /* Recovery action to do in case of an error */ |
| 13803 | u8 minWriteFileFormat; /* Minimum file format for writable database files */ |
| 13804 | bft explain:2; /* True if EXPLAIN present on SQL command */ |
| 13805 | bft inVtabMethod:2; /* See comments above */ |
| 13806 | bft changeCntOn:1; /* True to update the change-counter */ |
| @@ -20901,10 +20901,16 @@ | |
| 20901 | |
| 20902 | #if SQLITE_THREADSAFE |
| 20903 | sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); |
| 20904 | sqlite3_mutex_enter(mutex); |
| 20905 | #endif |
| 20906 | |
| 20907 | if( N<=0 ){ |
| 20908 | wsdPrng.isInit = 0; |
| 20909 | sqlite3_mutex_leave(mutex); |
| 20910 | return; |
| 20911 | } |
| 20912 | |
| 20913 | /* Initialize the state of the random number generator once, |
| 20914 | ** the first time this routine is called. The seed value does |
| 20915 | ** not need to contain a lot of randomness since we are not |
| 20916 | ** trying to do secure encryption or anything like that... |
| @@ -20929,19 +20935,20 @@ | |
| 20935 | wsdPrng.s[i] = t; |
| 20936 | } |
| 20937 | wsdPrng.isInit = 1; |
| 20938 | } |
| 20939 | |
| 20940 | assert( N>0 ); |
| 20941 | do{ |
| 20942 | wsdPrng.i++; |
| 20943 | t = wsdPrng.s[wsdPrng.i]; |
| 20944 | wsdPrng.j += t; |
| 20945 | wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j]; |
| 20946 | wsdPrng.s[wsdPrng.j] = t; |
| 20947 | t += wsdPrng.s[wsdPrng.i]; |
| 20948 | *(zBuf++) = wsdPrng.s[t]; |
| 20949 | }while( --N ); |
| 20950 | sqlite3_mutex_leave(mutex); |
| 20951 | } |
| 20952 | |
| 20953 | #ifndef SQLITE_OMIT_BUILTIN_TEST |
| 20954 | /* |
| @@ -20966,13 +20973,10 @@ | |
| 20973 | &GLOBAL(struct sqlite3PrngType, sqlite3Prng), |
| 20974 | &GLOBAL(struct sqlite3PrngType, sqlite3SavedPrng), |
| 20975 | sizeof(sqlite3Prng) |
| 20976 | ); |
| 20977 | } |
| 20978 | #endif /* SQLITE_OMIT_BUILTIN_TEST */ |
| 20979 | |
| 20980 | /************** End of random.c **********************************************/ |
| 20981 | /************** Begin file utf.c *********************************************/ |
| 20982 | /* |
| @@ -23505,10 +23509,16 @@ | |
| 23509 | ** it is larger than the struct CrashFile defined in test6.c. |
| 23510 | */ |
| 23511 | char aPadding[32]; |
| 23512 | #endif |
| 23513 | }; |
| 23514 | |
| 23515 | /* This variable holds the process id (pid) from when the xRandomness() |
| 23516 | ** method was called. If xOpen() is called from a different process id, |
| 23517 | ** indicating that a fork() has occurred, the PRNG will be reset. |
| 23518 | */ |
| 23519 | static int randomnessPid = 0; |
| 23520 | |
| 23521 | /* |
| 23522 | ** Allowed values for the unixFile.ctrlFlags bitmask: |
| 23523 | */ |
| 23524 | #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
| @@ -29104,10 +29114,20 @@ | |
| 29114 | assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB |
| 29115 | || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL |
| 29116 | || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL |
| 29117 | || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
| 29118 | ); |
| 29119 | |
| 29120 | /* Detect a pid change and reset the PRNG. There is a race condition |
| 29121 | ** here such that two or more threads all trying to open databases at |
| 29122 | ** the same instant might all reset the PRNG. But multiple resets |
| 29123 | ** are harmless. |
| 29124 | */ |
| 29125 | if( randomnessPid!=getpid() ){ |
| 29126 | randomnessPid = getpid(); |
| 29127 | sqlite3_randomness(0,0); |
| 29128 | } |
| 29129 | |
| 29130 | memset(p, 0, sizeof(unixFile)); |
| 29131 | |
| 29132 | if( eType==SQLITE_OPEN_MAIN_DB ){ |
| 29133 | UnixUnusedFd *pUnused; |
| @@ -29492,22 +29512,22 @@ | |
| 29512 | ** When testing, initializing zBuf[] to zero is all we do. That means |
| 29513 | ** that we always use the same random number sequence. This makes the |
| 29514 | ** tests repeatable. |
| 29515 | */ |
| 29516 | memset(zBuf, 0, nBuf); |
| 29517 | randomnessPid = getpid(); |
| 29518 | #if !defined(SQLITE_TEST) |
| 29519 | { |
| 29520 | int fd, got; |
| 29521 | fd = robust_open("/dev/urandom", O_RDONLY, 0); |
| 29522 | if( fd<0 ){ |
| 29523 | time_t t; |
| 29524 | time(&t); |
| 29525 | memcpy(zBuf, &t, sizeof(t)); |
| 29526 | memcpy(&zBuf[sizeof(t)], &randomnessPid, sizeof(randomnessPid)); |
| 29527 | assert( sizeof(t)+sizeof(randomnessPid)<=(size_t)nBuf ); |
| 29528 | nBuf = sizeof(t) + sizeof(randomnessPid); |
| 29529 | }else{ |
| 29530 | do{ got = osRead(fd, zBuf, nBuf); }while( got<0 && errno==EINTR ); |
| 29531 | robust_close(0, fd, __LINE__); |
| 29532 | } |
| 29533 | } |
| @@ -61200,13 +61220,14 @@ | |
| 61220 | } |
| 61221 | p->pNext = db->pVdbe; |
| 61222 | p->pPrev = 0; |
| 61223 | db->pVdbe = p; |
| 61224 | p->magic = VDBE_MAGIC_INIT; |
| 61225 | p->pParse = pParse; |
| 61226 | assert( pParse->aLabel==0 ); |
| 61227 | assert( pParse->nLabel==0 ); |
| 61228 | assert( pParse->nOpAlloc==0 ); |
| 61229 | return p; |
| 61230 | } |
| 61231 | |
| 61232 | /* |
| 61233 | ** Remember the SQL string for a prepared statement. |
| @@ -61258,17 +61279,18 @@ | |
| 61279 | ** If an out-of-memory error occurs while resizing the array, return |
| 61280 | ** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain |
| 61281 | ** unchanged (this is so that any opcodes already allocated can be |
| 61282 | ** correctly deallocated along with the rest of the Vdbe). |
| 61283 | */ |
| 61284 | static int growOpArray(Vdbe *v){ |
| 61285 | VdbeOp *pNew; |
| 61286 | Parse *p = v->pParse; |
| 61287 | int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op))); |
| 61288 | pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op)); |
| 61289 | if( pNew ){ |
| 61290 | p->nOpAlloc = sqlite3DbMallocSize(p->db, pNew)/sizeof(Op); |
| 61291 | v->aOp = pNew; |
| 61292 | } |
| 61293 | return (pNew ? SQLITE_OK : SQLITE_NOMEM); |
| 61294 | } |
| 61295 | |
| 61296 | #ifdef SQLITE_DEBUG |
| @@ -61303,11 +61325,11 @@ | |
| 61325 | VdbeOp *pOp; |
| 61326 | |
| 61327 | i = p->nOp; |
| 61328 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 61329 | assert( op>0 && op<0xff ); |
| 61330 | if( p->pParse->nOpAlloc<=i ){ |
| 61331 | if( growOpArray(p) ){ |
| 61332 | return 1; |
| 61333 | } |
| 61334 | } |
| 61335 | p->nOp++; |
| @@ -61414,13 +61436,14 @@ | |
| 61436 | ** always negative and P2 values are suppose to be non-negative. |
| 61437 | ** Hence, a negative P2 value is a label that has yet to be resolved. |
| 61438 | ** |
| 61439 | ** Zero is returned if a malloc() fails. |
| 61440 | */ |
| 61441 | SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){ |
| 61442 | Parse *p = v->pParse; |
| 61443 | int i = p->nLabel++; |
| 61444 | assert( v->magic==VDBE_MAGIC_INIT ); |
| 61445 | if( (i & (i-1))==0 ){ |
| 61446 | p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel, |
| 61447 | (i*2+1)*sizeof(p->aLabel[0])); |
| 61448 | } |
| 61449 | if( p->aLabel ){ |
| @@ -61432,16 +61455,17 @@ | |
| 61455 | /* |
| 61456 | ** Resolve label "x" to be the address of the next instruction to |
| 61457 | ** be inserted. The parameter "x" must have been obtained from |
| 61458 | ** a prior call to sqlite3VdbeMakeLabel(). |
| 61459 | */ |
| 61460 | SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){ |
| 61461 | Parse *p = v->pParse; |
| 61462 | int j = -1-x; |
| 61463 | assert( v->magic==VDBE_MAGIC_INIT ); |
| 61464 | assert( j<p->nLabel ); |
| 61465 | if( j>=0 && p->aLabel ){ |
| 61466 | p->aLabel[j] = v->nOp; |
| 61467 | } |
| 61468 | } |
| 61469 | |
| 61470 | /* |
| 61471 | ** Mark the VDBE as one that can only be run one time. |
| @@ -61586,11 +61610,12 @@ | |
| 61610 | */ |
| 61611 | static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ |
| 61612 | int i; |
| 61613 | int nMaxArgs = *pMaxFuncArgs; |
| 61614 | Op *pOp; |
| 61615 | Parse *pParse = p->pParse; |
| 61616 | int *aLabel = pParse->aLabel; |
| 61617 | p->readOnly = 1; |
| 61618 | p->bIsReader = 0; |
| 61619 | for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ |
| 61620 | u8 opcode = pOp->opcode; |
| 61621 | |
| @@ -61649,16 +61674,17 @@ | |
| 61674 | } |
| 61675 | } |
| 61676 | |
| 61677 | pOp->opflags = sqlite3OpcodeProperty[opcode]; |
| 61678 | if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ |
| 61679 | assert( -1-pOp->p2<pParse->nLabel ); |
| 61680 | pOp->p2 = aLabel[-1-pOp->p2]; |
| 61681 | } |
| 61682 | } |
| 61683 | sqlite3DbFree(p->db, pParse->aLabel); |
| 61684 | pParse->aLabel = 0; |
| 61685 | pParse->nLabel = 0; |
| 61686 | *pMaxFuncArgs = nMaxArgs; |
| 61687 | assert( p->bIsReader!=0 || p->btreeMask==0 ); |
| 61688 | } |
| 61689 | |
| 61690 | /* |
| @@ -61698,11 +61724,11 @@ | |
| 61724 | ** address of the first operation added. |
| 61725 | */ |
| 61726 | SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ |
| 61727 | int addr; |
| 61728 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 61729 | if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p) ){ |
| 61730 | return 0; |
| 61731 | } |
| 61732 | addr = p->nOp; |
| 61733 | if( ALWAYS(nOp>0) ){ |
| 61734 | int i; |
| @@ -61886,10 +61912,17 @@ | |
| 61912 | memset(pOp, 0, sizeof(pOp[0])); |
| 61913 | pOp->opcode = OP_Noop; |
| 61914 | if( addr==p->nOp-1 ) p->nOp--; |
| 61915 | } |
| 61916 | } |
| 61917 | |
| 61918 | /* |
| 61919 | ** Remove the last opcode inserted |
| 61920 | */ |
| 61921 | SQLITE_PRIVATE void sqlite3VdbeDeleteLastOpcode(Vdbe *p){ |
| 61922 | p->nOp--; |
| 61923 | } |
| 61924 | |
| 61925 | /* |
| 61926 | ** Change the value of the P4 operand for a specific instruction. |
| 61927 | ** This routine is useful when a large program is loaded from a |
| 61928 | ** static array using sqlite3VdbeAddOpList but we want to make a |
| @@ -62768,10 +62801,11 @@ | |
| 62801 | |
| 62802 | assert( p!=0 ); |
| 62803 | assert( p->nOp>0 ); |
| 62804 | assert( pParse!=0 ); |
| 62805 | assert( p->magic==VDBE_MAGIC_INIT ); |
| 62806 | assert( pParse==p->pParse ); |
| 62807 | db = p->db; |
| 62808 | assert( db->mallocFailed==0 ); |
| 62809 | nVar = pParse->nVar; |
| 62810 | nMem = pParse->nMem; |
| 62811 | nCursor = pParse->nTab; |
| @@ -62791,12 +62825,12 @@ | |
| 62825 | nMem += nCursor; |
| 62826 | |
| 62827 | /* Allocate space for memory registers, SQL variables, VDBE cursors and |
| 62828 | ** an array to marshal SQL function arguments in. |
| 62829 | */ |
| 62830 | zCsr = (u8*)&p->aOp[p->nOp]; /* Memory avaliable for allocation */ |
| 62831 | zEnd = (u8*)&p->aOp[pParse->nOpAlloc]; /* First byte past end of zCsr[] */ |
| 62832 | |
| 62833 | resolveP2Values(p, &nArg); |
| 62834 | p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort); |
| 62835 | if( pParse->explain && nMem<10 ){ |
| 62836 | nMem = 10; |
| @@ -63795,11 +63829,10 @@ | |
| 63829 | vdbeFreeOpArray(db, pSub->aOp, pSub->nOp); |
| 63830 | sqlite3DbFree(db, pSub); |
| 63831 | } |
| 63832 | for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); |
| 63833 | vdbeFreeOpArray(db, p->aOp, p->nOp); |
| 63834 | sqlite3DbFree(db, p->aColName); |
| 63835 | sqlite3DbFree(db, p->zSql); |
| 63836 | sqlite3DbFree(db, p->pFree); |
| 63837 | #if defined(SQLITE_ENABLE_TREE_EXPLAIN) |
| 63838 | sqlite3DbFree(db, p->zExplain); |
| @@ -76765,20 +76798,29 @@ | |
| 76798 | } |
| 76799 | return p; |
| 76800 | } |
| 76801 | |
| 76802 | /* |
| 76803 | ** If the expression is always either TRUE or FALSE (respectively), |
| 76804 | ** then return 1. If one cannot determine the truth value of the |
| 76805 | ** expression at compile-time return 0. |
| 76806 | ** |
| 76807 | ** This is an optimization. If is OK to return 0 here even if |
| 76808 | ** the expression really is always false or false (a false negative). |
| 76809 | ** But it is a bug to return 1 if the expression might have different |
| 76810 | ** boolean values in different circumstances (a false positive.) |
| 76811 | ** |
| 76812 | ** Note that if the expression is part of conditional for a |
| 76813 | ** LEFT JOIN, then we cannot determine at compile-time whether or not |
| 76814 | ** is it true or false, so always return 0. |
| 76815 | */ |
| 76816 | static int exprAlwaysTrue(Expr *p){ |
| 76817 | int v = 0; |
| 76818 | if( ExprHasProperty(p, EP_FromJoin) ) return 0; |
| 76819 | if( !sqlite3ExprIsInteger(p, &v) ) return 0; |
| 76820 | return v!=0; |
| 76821 | } |
| 76822 | static int exprAlwaysFalse(Expr *p){ |
| 76823 | int v = 0; |
| 76824 | if( ExprHasProperty(p, EP_FromJoin) ) return 0; |
| 76825 | if( !sqlite3ExprIsInteger(p, &v) ) return 0; |
| 76826 | return v==0; |
| @@ -79621,11 +79663,11 @@ | |
| 79663 | sqlite3ExplainPush(pOut); |
| 79664 | for(i=0; i<pList->nExpr; i++){ |
| 79665 | sqlite3ExplainPrintf(pOut, "item[%d] = ", i); |
| 79666 | sqlite3ExplainPush(pOut); |
| 79667 | sqlite3ExplainExpr(pOut, pList->a[i].pExpr); |
| 79668 | sqlite3ExplainPop(pOut, 1); |
| 79669 | if( pList->a[i].zName ){ |
| 79670 | sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); |
| 79671 | } |
| 79672 | if( pList->a[i].bSpanIsTab ){ |
| 79673 | sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); |
| @@ -79771,21 +79813,23 @@ | |
| 79813 | op = pExpr->op; |
| 79814 | switch( op ){ |
| 79815 | case TK_AND: { |
| 79816 | int d2 = sqlite3VdbeMakeLabel(v); |
| 79817 | testcase( jumpIfNull==0 ); |
| 79818 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); |
| 79819 | sqlite3ExprCachePush(pParse); |
| 79820 | sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79821 | sqlite3VdbeResolveLabel(v, d2); |
| 79822 | sqlite3ExprCachePop(pParse, 1); |
| 79823 | break; |
| 79824 | } |
| 79825 | case TK_OR: { |
| 79826 | testcase( jumpIfNull==0 ); |
| 79827 | sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull); |
| 79828 | sqlite3ExprCachePush(pParse); |
| 79829 | sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79830 | sqlite3ExprCachePop(pParse, 1); |
| 79831 | break; |
| 79832 | } |
| 79833 | case TK_NOT: { |
| 79834 | testcase( jumpIfNull==0 ); |
| 79835 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); |
| @@ -79856,14 +79900,20 @@ | |
| 79900 | sqlite3VdbeResolveLabel(v, destIfFalse); |
| 79901 | break; |
| 79902 | } |
| 79903 | #endif |
| 79904 | default: { |
| 79905 | if( exprAlwaysTrue(pExpr) ){ |
| 79906 | sqlite3VdbeAddOp2(v, OP_Goto, 0, dest); |
| 79907 | }else if( exprAlwaysFalse(pExpr) ){ |
| 79908 | /* No-op */ |
| 79909 | }else{ |
| 79910 | r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); |
| 79911 | sqlite3VdbeAddOp3(v, OP_If, r1, dest, jumpIfNull!=0); |
| 79912 | testcase( regFree1==0 ); |
| 79913 | testcase( jumpIfNull==0 ); |
| 79914 | } |
| 79915 | break; |
| 79916 | } |
| 79917 | } |
| 79918 | sqlite3ReleaseTempReg(pParse, regFree1); |
| 79919 | sqlite3ReleaseTempReg(pParse, regFree2); |
| @@ -79922,18 +79972,20 @@ | |
| 79972 | |
| 79973 | switch( pExpr->op ){ |
| 79974 | case TK_AND: { |
| 79975 | testcase( jumpIfNull==0 ); |
| 79976 | sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); |
| 79977 | sqlite3ExprCachePush(pParse); |
| 79978 | sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79979 | sqlite3ExprCachePop(pParse, 1); |
| 79980 | break; |
| 79981 | } |
| 79982 | case TK_OR: { |
| 79983 | int d2 = sqlite3VdbeMakeLabel(v); |
| 79984 | testcase( jumpIfNull==0 ); |
| 79985 | sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL); |
| 79986 | sqlite3ExprCachePush(pParse); |
| 79987 | sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); |
| 79988 | sqlite3VdbeResolveLabel(v, d2); |
| 79989 | sqlite3ExprCachePop(pParse, 1); |
| 79990 | break; |
| 79991 | } |
| @@ -80001,14 +80053,20 @@ | |
| 80053 | } |
| 80054 | break; |
| 80055 | } |
| 80056 | #endif |
| 80057 | default: { |
| 80058 | if( exprAlwaysFalse(pExpr) ){ |
| 80059 | sqlite3VdbeAddOp2(v, OP_Goto, 0, dest); |
| 80060 | }else if( exprAlwaysTrue(pExpr) ){ |
| 80061 | /* no-op */ |
| 80062 | }else{ |
| 80063 | r1 = sqlite3ExprCodeTemp(pParse, pExpr, ®Free1); |
| 80064 | sqlite3VdbeAddOp3(v, OP_IfNot, r1, dest, jumpIfNull!=0); |
| 80065 | testcase( regFree1==0 ); |
| 80066 | testcase( jumpIfNull==0 ); |
| 80067 | } |
| 80068 | break; |
| 80069 | } |
| 80070 | } |
| 80071 | sqlite3ReleaseTempReg(pParse, regFree1); |
| 80072 | sqlite3ReleaseTempReg(pParse, regFree2); |
| @@ -89357,22 +89415,22 @@ | |
| 89415 | nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; |
| 89416 | regBase = sqlite3GetTempRange(pParse, nCol); |
| 89417 | for(j=0; j<nCol; j++){ |
| 89418 | sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j], |
| 89419 | regBase+j); |
| 89420 | /* If the column affinity is REAL but the number is an integer, then it |
| 89421 | ** might be stored in the table as an integer (using a compact |
| 89422 | ** representation) then converted to REAL by an OP_RealAffinity opcode. |
| 89423 | ** But we are getting ready to store this value back into an index, where |
| 89424 | ** it should be converted by to INTEGER again. So omit the OP_RealAffinity |
| 89425 | ** opcode if it is present */ |
| 89426 | if( sqlite3VdbeGetOp(v, -1)->opcode==OP_RealAffinity ){ |
| 89427 | sqlite3VdbeDeleteLastOpcode(v); |
| 89428 | } |
| 89429 | } |
| 89430 | if( regOut ){ |
| 89431 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut); |
| 89432 | } |
| 89433 | sqlite3ReleaseTempRange(pParse, regBase, nCol); |
| 89434 | return regBase; |
| 89435 | } |
| 89436 | |
| @@ -93721,10 +93779,11 @@ | |
| 93779 | int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ |
| 93780 | int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */ |
| 93781 | int ipkTop = 0; /* Top of the rowid change constraint check */ |
| 93782 | int ipkBottom = 0; /* Bottom of the rowid change constraint check */ |
| 93783 | u8 isUpdate; /* True if this is an UPDATE operation */ |
| 93784 | int regRowid = -1; /* Register holding ROWID value */ |
| 93785 | |
| 93786 | isUpdate = regOldData!=0; |
| 93787 | db = pParse->db; |
| 93788 | v = sqlite3GetVdbe(pParse); |
| 93789 | assert( v!=0 ); |
| @@ -93951,11 +94010,13 @@ | |
| 94010 | regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn); |
| 94011 | for(i=0; i<pIdx->nColumn; i++){ |
| 94012 | int iField = pIdx->aiColumn[i]; |
| 94013 | int x; |
| 94014 | if( iField<0 || iField==pTab->iPKey ){ |
| 94015 | if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ |
| 94016 | x = regNewData; |
| 94017 | regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; |
| 94018 | }else{ |
| 94019 | x = iField + regNewData + 1; |
| 94020 | } |
| 94021 | sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); |
| 94022 | VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); |
| @@ -98780,11 +98841,15 @@ | |
| 98841 | |
| 98842 | /* |
| 98843 | ** Free all memory allocations in the pParse object |
| 98844 | */ |
| 98845 | SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){ |
| 98846 | if( pParse ){ |
| 98847 | sqlite3 *db = pParse->db; |
| 98848 | sqlite3DbFree(db, pParse->aLabel); |
| 98849 | sqlite3ExprListDelete(db, pParse->pConstExpr); |
| 98850 | } |
| 98851 | } |
| 98852 | |
| 98853 | /* |
| 98854 | ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. |
| 98855 | */ |
| @@ -113528,13 +113593,16 @@ | |
| 113593 | sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ |
| 113594 | |
| 113595 | /* Special case: a WHERE clause that is constant. Evaluate the |
| 113596 | ** expression and either jump over all of the code or fall thru. |
| 113597 | */ |
| 113598 | for(ii=0; ii<sWLB.pWC->nTerm; ii++){ |
| 113599 | if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){ |
| 113600 | sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak, |
| 113601 | SQLITE_JUMPIFNULL); |
| 113602 | sWLB.pWC->a[ii].wtFlags |= TERM_CODED; |
| 113603 | } |
| 113604 | } |
| 113605 | |
| 113606 | /* Special case: No FROM clause |
| 113607 | */ |
| 113608 | if( nTabList==0 ){ |
| @@ -121784,11 +121852,11 @@ | |
| 121852 | ** Reset the PRNG back to its uninitialized state. The next call |
| 121853 | ** to sqlite3_randomness() will reseed the PRNG using a single call |
| 121854 | ** to the xRandomness method of the default VFS. |
| 121855 | */ |
| 121856 | case SQLITE_TESTCTRL_PRNG_RESET: { |
| 121857 | sqlite3_randomness(0,0); |
| 121858 | break; |
| 121859 | } |
| 121860 | |
| 121861 | /* |
| 121862 | ** sqlite3_test_control(BITVEC_TEST, size, program) |
| @@ -124767,10 +124835,23 @@ | |
| 124835 | sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ |
| 124836 | char **pzErr /* OUT: sqlite3_malloc'd error message */ |
| 124837 | ){ |
| 124838 | return fts3InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr); |
| 124839 | } |
| 124840 | |
| 124841 | /* |
| 124842 | ** Set the pIdxInfo->estimatedRows variable to nRow. Unless this |
| 124843 | ** extension is currently being used by a version of SQLite too old to |
| 124844 | ** support estimatedRows. In that case this function is a no-op. |
| 124845 | */ |
| 124846 | static void setEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ |
| 124847 | #if SQLITE_VERSION_NUMBER>=3008002 |
| 124848 | if( sqlite3_libversion_number()>=3008002 ){ |
| 124849 | pIdxInfo->estimatedRows = nRow; |
| 124850 | } |
| 124851 | #endif |
| 124852 | } |
| 124853 | |
| 124854 | /* |
| 124855 | ** Implementation of the xBestIndex method for FTS3 tables. There |
| 124856 | ** are three possible strategies, in order of preference: |
| 124857 | ** |
| @@ -124795,11 +124876,24 @@ | |
| 124876 | pInfo->idxNum = FTS3_FULLSCAN_SEARCH; |
| 124877 | pInfo->estimatedCost = 5000000; |
| 124878 | for(i=0; i<pInfo->nConstraint; i++){ |
| 124879 | int bDocid; /* True if this constraint is on docid */ |
| 124880 | struct sqlite3_index_constraint *pCons = &pInfo->aConstraint[i]; |
| 124881 | if( pCons->usable==0 ){ |
| 124882 | if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ |
| 124883 | /* There exists an unusable MATCH constraint. This means that if |
| 124884 | ** the planner does elect to use the results of this call as part |
| 124885 | ** of the overall query plan the user will see an "unable to use |
| 124886 | ** function MATCH in the requested context" error. To discourage |
| 124887 | ** this, return a very high cost here. */ |
| 124888 | pInfo->idxNum = FTS3_FULLSCAN_SEARCH; |
| 124889 | pInfo->estimatedCost = 1e50; |
| 124890 | setEstimatedRows(pInfo, ((sqlite3_int64)1) << 50); |
| 124891 | return SQLITE_OK; |
| 124892 | } |
| 124893 | continue; |
| 124894 | } |
| 124895 | |
| 124896 | bDocid = (pCons->iColumn<0 || pCons->iColumn==p->nColumn+1); |
| 124897 | |
| 124898 | /* A direct lookup on the rowid or docid column. Assign a cost of 1.0. */ |
| 124899 | if( iCons<0 && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ && bDocid ){ |
| 124900 |
+7
-5
| --- src/sqlite3.h | ||
| +++ src/sqlite3.h | ||
| @@ -107,11 +107,11 @@ | ||
| 107 | 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | 109 | */ |
| 110 | 110 | #define SQLITE_VERSION "3.8.3" |
| 111 | 111 | #define SQLITE_VERSION_NUMBER 3008003 |
| 112 | -#define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d" | |
| 112 | +#define SQLITE_SOURCE_ID "2014-01-04 15:17:04 4e725f53131d3584319c710c8710a068989543c6" | |
| 113 | 113 | |
| 114 | 114 | /* |
| 115 | 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | 117 | ** |
| @@ -2398,15 +2398,17 @@ | ||
| 2398 | 2398 | ** already uses the largest possible [ROWID]. The PRNG is also used for |
| 2399 | 2399 | ** the build-in random() and randomblob() SQL functions. This interface allows |
| 2400 | 2400 | ** applications to access the same PRNG for other purposes. |
| 2401 | 2401 | ** |
| 2402 | 2402 | ** ^A call to this routine stores N bytes of randomness into buffer P. |
| 2403 | +** ^If N is less than one, then P can be a NULL pointer. | |
| 2403 | 2404 | ** |
| 2404 | -** ^The first time this routine is invoked (either internally or by | |
| 2405 | -** the application) the PRNG is seeded using randomness obtained | |
| 2406 | -** from the xRandomness method of the default [sqlite3_vfs] object. | |
| 2407 | -** ^On all subsequent invocations, the pseudo-randomness is generated | |
| 2405 | +** ^If this routine has not been previously called or if the previous | |
| 2406 | +** call had N less than one, then the PRNG is seeded using randomness | |
| 2407 | +** obtained from the xRandomness method of the default [sqlite3_vfs] object. | |
| 2408 | +** ^If the previous call to this routine had an N of 1 or more then | |
| 2409 | +** the pseudo-randomness is generated | |
| 2408 | 2410 | ** internally and without recourse to the [sqlite3_vfs] xRandomness |
| 2409 | 2411 | ** method. |
| 2410 | 2412 | */ |
| 2411 | 2413 | SQLITE_API void sqlite3_randomness(int N, void *P); |
| 2412 | 2414 | |
| 2413 | 2415 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -107,11 +107,11 @@ | |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.8.3" |
| 111 | #define SQLITE_VERSION_NUMBER 3008003 |
| 112 | #define SQLITE_SOURCE_ID "2013-12-23 11:33:32 25b8a1c9ba77df3b7c78cbce922cb593d661696d" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| @@ -2398,15 +2398,17 @@ | |
| 2398 | ** already uses the largest possible [ROWID]. The PRNG is also used for |
| 2399 | ** the build-in random() and randomblob() SQL functions. This interface allows |
| 2400 | ** applications to access the same PRNG for other purposes. |
| 2401 | ** |
| 2402 | ** ^A call to this routine stores N bytes of randomness into buffer P. |
| 2403 | ** |
| 2404 | ** ^The first time this routine is invoked (either internally or by |
| 2405 | ** the application) the PRNG is seeded using randomness obtained |
| 2406 | ** from the xRandomness method of the default [sqlite3_vfs] object. |
| 2407 | ** ^On all subsequent invocations, the pseudo-randomness is generated |
| 2408 | ** internally and without recourse to the [sqlite3_vfs] xRandomness |
| 2409 | ** method. |
| 2410 | */ |
| 2411 | SQLITE_API void sqlite3_randomness(int N, void *P); |
| 2412 | |
| 2413 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -107,11 +107,11 @@ | |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.8.3" |
| 111 | #define SQLITE_VERSION_NUMBER 3008003 |
| 112 | #define SQLITE_SOURCE_ID "2014-01-04 15:17:04 4e725f53131d3584319c710c8710a068989543c6" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| @@ -2398,15 +2398,17 @@ | |
| 2398 | ** already uses the largest possible [ROWID]. The PRNG is also used for |
| 2399 | ** the build-in random() and randomblob() SQL functions. This interface allows |
| 2400 | ** applications to access the same PRNG for other purposes. |
| 2401 | ** |
| 2402 | ** ^A call to this routine stores N bytes of randomness into buffer P. |
| 2403 | ** ^If N is less than one, then P can be a NULL pointer. |
| 2404 | ** |
| 2405 | ** ^If this routine has not been previously called or if the previous |
| 2406 | ** call had N less than one, then the PRNG is seeded using randomness |
| 2407 | ** obtained from the xRandomness method of the default [sqlite3_vfs] object. |
| 2408 | ** ^If the previous call to this routine had an N of 1 or more then |
| 2409 | ** the pseudo-randomness is generated |
| 2410 | ** internally and without recourse to the [sqlite3_vfs] xRandomness |
| 2411 | ** method. |
| 2412 | */ |
| 2413 | SQLITE_API void sqlite3_randomness(int N, void *P); |
| 2414 | |
| 2415 |
+98
-3
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -243,10 +243,41 @@ | ||
| 243 | 243 | va_start(ap, zFormat); |
| 244 | 244 | local_zCurrentPage = vmprintf(zFormat, ap); |
| 245 | 245 | va_end(ap); |
| 246 | 246 | } |
| 247 | 247 | } |
| 248 | + | |
| 249 | +/* | |
| 250 | +** Create a TH1 variable containing the URL for the specified config resource. | |
| 251 | +** The resulting variable name will be of the form $[zVarPrefix]_url. | |
| 252 | +*/ | |
| 253 | +static void url_var( | |
| 254 | + const char *zVarPrefix, | |
| 255 | + const char *zConfigName, | |
| 256 | + const char *zPageName | |
| 257 | +){ | |
| 258 | + char *zMtime = db_get_mtime(zConfigName, 0, 0); | |
| 259 | + char *zUrl = mprintf("%s/%s/%s%.5s", g.zTop, zPageName, zMtime, | |
| 260 | + MANIFEST_UUID); | |
| 261 | + char *zVarName = mprintf("%s_url", zVarPrefix); | |
| 262 | + Th_Store(zVarName, zUrl); | |
| 263 | + free(zMtime); | |
| 264 | + free(zUrl); | |
| 265 | + free(zVarName); | |
| 266 | +} | |
| 267 | + | |
| 268 | +/* | |
| 269 | +** Create a TH1 variable containing the URL for the specified config image. | |
| 270 | +** The resulting variable name will be of the form $[zImageName]_image_url. | |
| 271 | +*/ | |
| 272 | +static void image_url_var(const char *zImageName){ | |
| 273 | + char *zVarPrefix = mprintf("%s_image", zImageName); | |
| 274 | + char *zConfigName = mprintf("%s-image", zImageName); | |
| 275 | + url_var(zVarPrefix, zConfigName, zImageName); | |
| 276 | + free(zVarPrefix); | |
| 277 | + free(zConfigName); | |
| 278 | +} | |
| 248 | 279 | |
| 249 | 280 | /* |
| 250 | 281 | ** Draw the header. |
| 251 | 282 | */ |
| 252 | 283 | void style_header(const char *zTitleFormat, ...){ |
| @@ -275,10 +306,13 @@ | ||
| 275 | 306 | Th_Store("csrf_token", g.zCsrfToken); |
| 276 | 307 | Th_Store("release_version", RELEASE_VERSION); |
| 277 | 308 | Th_Store("manifest_version", MANIFEST_VERSION); |
| 278 | 309 | Th_Store("manifest_date", MANIFEST_DATE); |
| 279 | 310 | Th_Store("compiler_name", COMPILER_NAME); |
| 311 | + url_var("stylesheet", "css", "style.css"); | |
| 312 | + image_url_var("logo"); | |
| 313 | + image_url_var("background"); | |
| 280 | 314 | if( g.zLogin ){ |
| 281 | 315 | Th_Store("login", g.zLogin); |
| 282 | 316 | } |
| 283 | 317 | if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1); |
| 284 | 318 | Th_Render(zHeader); |
| @@ -406,17 +440,17 @@ | ||
| 406 | 440 | @ <head> |
| 407 | 441 | @ <base href="$baseurl/$current_page" /> |
| 408 | 442 | @ <title>$<project_name>: $<title></title> |
| 409 | 443 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 410 | 444 | @ href="$home/timeline.rss" /> |
| 411 | -@ <link rel="stylesheet" href="$home/style.css?default" type="text/css" | |
| 445 | +@ <link rel="stylesheet" href="$stylesheet_url" type="text/css" | |
| 412 | 446 | @ media="screen" /> |
| 413 | 447 | @ </head> |
| 414 | 448 | @ <body> |
| 415 | 449 | @ <div class="header"> |
| 416 | 450 | @ <div class="logo"> |
| 417 | -@ <img src="$home/logo" alt="logo" /> | |
| 451 | +@ <img src="$logo_image_url" alt="logo" /> | |
| 418 | 452 | @ </div> |
| 419 | 453 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 420 | 454 | @ <div class="status"><th1> |
| 421 | 455 | @ if {[info exists login]} { |
| 422 | 456 | @ puts "Logged in as $login" |
| @@ -430,11 +464,11 @@ | ||
| 430 | 464 | @ html "<a href='$home$index_page'>Home</a>\n" |
| 431 | 465 | @ if {[anycap jor]} { |
| 432 | 466 | @ html "<a href='$home/timeline'>Timeline</a>\n" |
| 433 | 467 | @ } |
| 434 | 468 | @ if {[hascap oh]} { |
| 435 | -@ html "<a href='$home/dir?ci=tip'>Files</a>\n" | |
| 469 | +@ html "<a href='$home/tree?ci=tip'>Files</a>\n" | |
| 436 | 470 | @ } |
| 437 | 471 | @ if {[hascap o]} { |
| 438 | 472 | @ html "<a href='$home/brlist'>Branches</a>\n" |
| 439 | 473 | @ html "<a href='$home/taglist'>Tags</a>\n" |
| 440 | 474 | @ } |
| @@ -737,10 +771,69 @@ | ||
| 737 | 771 | "format for the list in the file browser", |
| 738 | 772 | @ margin-left: 0.5em; |
| 739 | 773 | @ padding-left: 0.5em; |
| 740 | 774 | @ white-space: nowrap; |
| 741 | 775 | }, |
| 776 | + { ".filetree", | |
| 777 | + "tree-view file browser", | |
| 778 | + @ margin: 1em 0; | |
| 779 | + @ line-height: 1.5; | |
| 780 | + }, | |
| 781 | + { ".filetree ul", | |
| 782 | + "tree-view lists", | |
| 783 | + @ margin: 0; | |
| 784 | + @ padding: 0; | |
| 785 | + @ list-style: none; | |
| 786 | + }, | |
| 787 | + { ".filetree ul ul", | |
| 788 | + "tree-view lists below the root", | |
| 789 | + @ position: relative; | |
| 790 | + @ margin: 0 0 0 21px; | |
| 791 | + }, | |
| 792 | + { ".filetree li", | |
| 793 | + "tree-view lists items", | |
| 794 | + @ position: relative; | |
| 795 | + }, | |
| 796 | + { ".filetree li li:before", | |
| 797 | + "tree-view node lines", | |
| 798 | + @ content: ''; | |
| 799 | + @ position: absolute; | |
| 800 | + @ top: -.8em; | |
| 801 | + @ left: -14px; | |
| 802 | + @ width: 14px; | |
| 803 | + @ height: 1.5em; | |
| 804 | + @ border-left: 2px solid #aaa; | |
| 805 | + @ border-bottom: 2px solid #aaa; | |
| 806 | + }, | |
| 807 | + { ".filetree ul ul:before", | |
| 808 | + "tree-view directory lines", | |
| 809 | + @ content: ''; | |
| 810 | + @ position: absolute; | |
| 811 | + @ top: -1.5em; | |
| 812 | + @ bottom: 0; | |
| 813 | + @ left: -35px; | |
| 814 | + @ border-left: 2px solid #aaa; | |
| 815 | + }, | |
| 816 | + { ".filetree li:last-child > ul:before", | |
| 817 | + "hide lines for last-child directories", | |
| 818 | + @ display: none; | |
| 819 | + }, | |
| 820 | + { ".filetree a", | |
| 821 | + "tree-view links", | |
| 822 | + @ position: relative; | |
| 823 | + @ z-index: 1; | |
| 824 | + @ display: inline-block; | |
| 825 | + @ min-height: 16px; | |
| 826 | + @ padding-left: 21px; | |
| 827 | + @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==); | |
| 828 | + @ background-position: center left; | |
| 829 | + @ background-repeat: no-repeat; | |
| 830 | + }, | |
| 831 | + { ".filetree .dir > a", | |
| 832 | + "tree-view directory links", | |
| 833 | + @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=); | |
| 834 | + }, | |
| 742 | 835 | { "table.login_out", |
| 743 | 836 | "table format for login/out label/input table", |
| 744 | 837 | @ text-align: left; |
| 745 | 838 | @ margin-right: 10px; |
| 746 | 839 | @ margin-left: 10px; |
| @@ -1151,10 +1244,12 @@ | ||
| 1151 | 1244 | /* Process through TH1 in order to give an opportunity to substitute |
| 1152 | 1245 | ** variables such as $baseurl. |
| 1153 | 1246 | */ |
| 1154 | 1247 | Th_Store("baseurl", g.zBaseURL); |
| 1155 | 1248 | Th_Store("home", g.zTop); |
| 1249 | + image_url_var("logo"); | |
| 1250 | + image_url_var("background"); | |
| 1156 | 1251 | Th_Render(blob_str(&css)); |
| 1157 | 1252 | |
| 1158 | 1253 | /* Tell CGI that the content returned by this page is considered cacheable */ |
| 1159 | 1254 | g.isConst = 1; |
| 1160 | 1255 | } |
| 1161 | 1256 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -243,10 +243,41 @@ | |
| 243 | va_start(ap, zFormat); |
| 244 | local_zCurrentPage = vmprintf(zFormat, ap); |
| 245 | va_end(ap); |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | /* |
| 250 | ** Draw the header. |
| 251 | */ |
| 252 | void style_header(const char *zTitleFormat, ...){ |
| @@ -275,10 +306,13 @@ | |
| 275 | Th_Store("csrf_token", g.zCsrfToken); |
| 276 | Th_Store("release_version", RELEASE_VERSION); |
| 277 | Th_Store("manifest_version", MANIFEST_VERSION); |
| 278 | Th_Store("manifest_date", MANIFEST_DATE); |
| 279 | Th_Store("compiler_name", COMPILER_NAME); |
| 280 | if( g.zLogin ){ |
| 281 | Th_Store("login", g.zLogin); |
| 282 | } |
| 283 | if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1); |
| 284 | Th_Render(zHeader); |
| @@ -406,17 +440,17 @@ | |
| 406 | @ <head> |
| 407 | @ <base href="$baseurl/$current_page" /> |
| 408 | @ <title>$<project_name>: $<title></title> |
| 409 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 410 | @ href="$home/timeline.rss" /> |
| 411 | @ <link rel="stylesheet" href="$home/style.css?default" type="text/css" |
| 412 | @ media="screen" /> |
| 413 | @ </head> |
| 414 | @ <body> |
| 415 | @ <div class="header"> |
| 416 | @ <div class="logo"> |
| 417 | @ <img src="$home/logo" alt="logo" /> |
| 418 | @ </div> |
| 419 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 420 | @ <div class="status"><th1> |
| 421 | @ if {[info exists login]} { |
| 422 | @ puts "Logged in as $login" |
| @@ -430,11 +464,11 @@ | |
| 430 | @ html "<a href='$home$index_page'>Home</a>\n" |
| 431 | @ if {[anycap jor]} { |
| 432 | @ html "<a href='$home/timeline'>Timeline</a>\n" |
| 433 | @ } |
| 434 | @ if {[hascap oh]} { |
| 435 | @ html "<a href='$home/dir?ci=tip'>Files</a>\n" |
| 436 | @ } |
| 437 | @ if {[hascap o]} { |
| 438 | @ html "<a href='$home/brlist'>Branches</a>\n" |
| 439 | @ html "<a href='$home/taglist'>Tags</a>\n" |
| 440 | @ } |
| @@ -737,10 +771,69 @@ | |
| 737 | "format for the list in the file browser", |
| 738 | @ margin-left: 0.5em; |
| 739 | @ padding-left: 0.5em; |
| 740 | @ white-space: nowrap; |
| 741 | }, |
| 742 | { "table.login_out", |
| 743 | "table format for login/out label/input table", |
| 744 | @ text-align: left; |
| 745 | @ margin-right: 10px; |
| 746 | @ margin-left: 10px; |
| @@ -1151,10 +1244,12 @@ | |
| 1151 | /* Process through TH1 in order to give an opportunity to substitute |
| 1152 | ** variables such as $baseurl. |
| 1153 | */ |
| 1154 | Th_Store("baseurl", g.zBaseURL); |
| 1155 | Th_Store("home", g.zTop); |
| 1156 | Th_Render(blob_str(&css)); |
| 1157 | |
| 1158 | /* Tell CGI that the content returned by this page is considered cacheable */ |
| 1159 | g.isConst = 1; |
| 1160 | } |
| 1161 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -243,10 +243,41 @@ | |
| 243 | va_start(ap, zFormat); |
| 244 | local_zCurrentPage = vmprintf(zFormat, ap); |
| 245 | va_end(ap); |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | /* |
| 250 | ** Create a TH1 variable containing the URL for the specified config resource. |
| 251 | ** The resulting variable name will be of the form $[zVarPrefix]_url. |
| 252 | */ |
| 253 | static void url_var( |
| 254 | const char *zVarPrefix, |
| 255 | const char *zConfigName, |
| 256 | const char *zPageName |
| 257 | ){ |
| 258 | char *zMtime = db_get_mtime(zConfigName, 0, 0); |
| 259 | char *zUrl = mprintf("%s/%s/%s%.5s", g.zTop, zPageName, zMtime, |
| 260 | MANIFEST_UUID); |
| 261 | char *zVarName = mprintf("%s_url", zVarPrefix); |
| 262 | Th_Store(zVarName, zUrl); |
| 263 | free(zMtime); |
| 264 | free(zUrl); |
| 265 | free(zVarName); |
| 266 | } |
| 267 | |
| 268 | /* |
| 269 | ** Create a TH1 variable containing the URL for the specified config image. |
| 270 | ** The resulting variable name will be of the form $[zImageName]_image_url. |
| 271 | */ |
| 272 | static void image_url_var(const char *zImageName){ |
| 273 | char *zVarPrefix = mprintf("%s_image", zImageName); |
| 274 | char *zConfigName = mprintf("%s-image", zImageName); |
| 275 | url_var(zVarPrefix, zConfigName, zImageName); |
| 276 | free(zVarPrefix); |
| 277 | free(zConfigName); |
| 278 | } |
| 279 | |
| 280 | /* |
| 281 | ** Draw the header. |
| 282 | */ |
| 283 | void style_header(const char *zTitleFormat, ...){ |
| @@ -275,10 +306,13 @@ | |
| 306 | Th_Store("csrf_token", g.zCsrfToken); |
| 307 | Th_Store("release_version", RELEASE_VERSION); |
| 308 | Th_Store("manifest_version", MANIFEST_VERSION); |
| 309 | Th_Store("manifest_date", MANIFEST_DATE); |
| 310 | Th_Store("compiler_name", COMPILER_NAME); |
| 311 | url_var("stylesheet", "css", "style.css"); |
| 312 | image_url_var("logo"); |
| 313 | image_url_var("background"); |
| 314 | if( g.zLogin ){ |
| 315 | Th_Store("login", g.zLogin); |
| 316 | } |
| 317 | if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1); |
| 318 | Th_Render(zHeader); |
| @@ -406,17 +440,17 @@ | |
| 440 | @ <head> |
| 441 | @ <base href="$baseurl/$current_page" /> |
| 442 | @ <title>$<project_name>: $<title></title> |
| 443 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 444 | @ href="$home/timeline.rss" /> |
| 445 | @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" |
| 446 | @ media="screen" /> |
| 447 | @ </head> |
| 448 | @ <body> |
| 449 | @ <div class="header"> |
| 450 | @ <div class="logo"> |
| 451 | @ <img src="$logo_image_url" alt="logo" /> |
| 452 | @ </div> |
| 453 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 454 | @ <div class="status"><th1> |
| 455 | @ if {[info exists login]} { |
| 456 | @ puts "Logged in as $login" |
| @@ -430,11 +464,11 @@ | |
| 464 | @ html "<a href='$home$index_page'>Home</a>\n" |
| 465 | @ if {[anycap jor]} { |
| 466 | @ html "<a href='$home/timeline'>Timeline</a>\n" |
| 467 | @ } |
| 468 | @ if {[hascap oh]} { |
| 469 | @ html "<a href='$home/tree?ci=tip'>Files</a>\n" |
| 470 | @ } |
| 471 | @ if {[hascap o]} { |
| 472 | @ html "<a href='$home/brlist'>Branches</a>\n" |
| 473 | @ html "<a href='$home/taglist'>Tags</a>\n" |
| 474 | @ } |
| @@ -737,10 +771,69 @@ | |
| 771 | "format for the list in the file browser", |
| 772 | @ margin-left: 0.5em; |
| 773 | @ padding-left: 0.5em; |
| 774 | @ white-space: nowrap; |
| 775 | }, |
| 776 | { ".filetree", |
| 777 | "tree-view file browser", |
| 778 | @ margin: 1em 0; |
| 779 | @ line-height: 1.5; |
| 780 | }, |
| 781 | { ".filetree ul", |
| 782 | "tree-view lists", |
| 783 | @ margin: 0; |
| 784 | @ padding: 0; |
| 785 | @ list-style: none; |
| 786 | }, |
| 787 | { ".filetree ul ul", |
| 788 | "tree-view lists below the root", |
| 789 | @ position: relative; |
| 790 | @ margin: 0 0 0 21px; |
| 791 | }, |
| 792 | { ".filetree li", |
| 793 | "tree-view lists items", |
| 794 | @ position: relative; |
| 795 | }, |
| 796 | { ".filetree li li:before", |
| 797 | "tree-view node lines", |
| 798 | @ content: ''; |
| 799 | @ position: absolute; |
| 800 | @ top: -.8em; |
| 801 | @ left: -14px; |
| 802 | @ width: 14px; |
| 803 | @ height: 1.5em; |
| 804 | @ border-left: 2px solid #aaa; |
| 805 | @ border-bottom: 2px solid #aaa; |
| 806 | }, |
| 807 | { ".filetree ul ul:before", |
| 808 | "tree-view directory lines", |
| 809 | @ content: ''; |
| 810 | @ position: absolute; |
| 811 | @ top: -1.5em; |
| 812 | @ bottom: 0; |
| 813 | @ left: -35px; |
| 814 | @ border-left: 2px solid #aaa; |
| 815 | }, |
| 816 | { ".filetree li:last-child > ul:before", |
| 817 | "hide lines for last-child directories", |
| 818 | @ display: none; |
| 819 | }, |
| 820 | { ".filetree a", |
| 821 | "tree-view links", |
| 822 | @ position: relative; |
| 823 | @ z-index: 1; |
| 824 | @ display: inline-block; |
| 825 | @ min-height: 16px; |
| 826 | @ padding-left: 21px; |
| 827 | @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==); |
| 828 | @ background-position: center left; |
| 829 | @ background-repeat: no-repeat; |
| 830 | }, |
| 831 | { ".filetree .dir > a", |
| 832 | "tree-view directory links", |
| 833 | @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=); |
| 834 | }, |
| 835 | { "table.login_out", |
| 836 | "table format for login/out label/input table", |
| 837 | @ text-align: left; |
| 838 | @ margin-right: 10px; |
| 839 | @ margin-left: 10px; |
| @@ -1151,10 +1244,12 @@ | |
| 1244 | /* Process through TH1 in order to give an opportunity to substitute |
| 1245 | ** variables such as $baseurl. |
| 1246 | */ |
| 1247 | Th_Store("baseurl", g.zBaseURL); |
| 1248 | Th_Store("home", g.zTop); |
| 1249 | image_url_var("logo"); |
| 1250 | image_url_var("background"); |
| 1251 | Th_Render(blob_str(&css)); |
| 1252 | |
| 1253 | /* Tell CGI that the content returned by this page is considered cacheable */ |
| 1254 | g.isConst = 1; |
| 1255 | } |
| 1256 |
+3
-2
| --- src/tar.c | ||
| +++ src/tar.c | ||
| @@ -336,12 +336,13 @@ | ||
| 336 | 336 | unsigned int mTime /* Modification time */ |
| 337 | 337 | ){ |
| 338 | 338 | int i; |
| 339 | 339 | for(i=nName-1; i>0 && zName[i]!='/'; i--){} |
| 340 | 340 | if( i<=0 ) return; |
| 341 | - if( i < tball.nPrevDirAlloc && tball.zPrevDir[i]==0 && | |
| 342 | - memcmp(tball.zPrevDir, zName, i)==0 ) return; | |
| 341 | + if( i<tball.nPrevDirAlloc | |
| 342 | + && strncmp(tball.zPrevDir, zName, i)==0 | |
| 343 | + && tball.zPrevDir[i]==0 ) return; | |
| 343 | 344 | db_multi_exec("INSERT OR IGNORE INTO dir VALUES('%#q')", i, zName); |
| 344 | 345 | if( sqlite3_changes(g.db)==0 ) return; |
| 345 | 346 | tar_add_directory_of(zName, i-1, mTime); |
| 346 | 347 | tar_add_header(zName, i, 0755, mTime, 0, '5'); |
| 347 | 348 | if( i >= tball.nPrevDirAlloc ){ |
| 348 | 349 |
| --- src/tar.c | |
| +++ src/tar.c | |
| @@ -336,12 +336,13 @@ | |
| 336 | unsigned int mTime /* Modification time */ |
| 337 | ){ |
| 338 | int i; |
| 339 | for(i=nName-1; i>0 && zName[i]!='/'; i--){} |
| 340 | if( i<=0 ) return; |
| 341 | if( i < tball.nPrevDirAlloc && tball.zPrevDir[i]==0 && |
| 342 | memcmp(tball.zPrevDir, zName, i)==0 ) return; |
| 343 | db_multi_exec("INSERT OR IGNORE INTO dir VALUES('%#q')", i, zName); |
| 344 | if( sqlite3_changes(g.db)==0 ) return; |
| 345 | tar_add_directory_of(zName, i-1, mTime); |
| 346 | tar_add_header(zName, i, 0755, mTime, 0, '5'); |
| 347 | if( i >= tball.nPrevDirAlloc ){ |
| 348 |
| --- src/tar.c | |
| +++ src/tar.c | |
| @@ -336,12 +336,13 @@ | |
| 336 | unsigned int mTime /* Modification time */ |
| 337 | ){ |
| 338 | int i; |
| 339 | for(i=nName-1; i>0 && zName[i]!='/'; i--){} |
| 340 | if( i<=0 ) return; |
| 341 | if( i<tball.nPrevDirAlloc |
| 342 | && strncmp(tball.zPrevDir, zName, i)==0 |
| 343 | && tball.zPrevDir[i]==0 ) return; |
| 344 | db_multi_exec("INSERT OR IGNORE INTO dir VALUES('%#q')", i, zName); |
| 345 | if( sqlite3_changes(g.db)==0 ) return; |
| 346 | tar_add_directory_of(zName, i-1, mTime); |
| 347 | tar_add_header(zName, i, 0755, mTime, 0, '5'); |
| 348 | if( i >= tball.nPrevDirAlloc ){ |
| 349 |
M
src/th.c
+263
-162
| --- src/th.c | ||
| +++ src/th.c | ||
| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | |
| 2 | 2 | /* |
| 3 | -** The implementation of the TH core. This file contains the parser, and | |
| 3 | +** The implementation of the TH core. This file contains the parser, and | |
| 4 | 4 | ** the implementation of the interface in th.h. |
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | 7 | #include "config.h" |
| 8 | 8 | #include "th.h" |
| @@ -16,11 +16,11 @@ | ||
| 16 | 16 | /* |
| 17 | 17 | ** Interpreter structure. |
| 18 | 18 | */ |
| 19 | 19 | struct Th_Interp { |
| 20 | 20 | Th_Vtab *pVtab; /* Copy of the argument passed to Th_CreateInterp() */ |
| 21 | - char *zResult; /* Current interpreter result (Th_Malloc()ed) */ | |
| 21 | + char *zResult; /* Current interpreter result (Th_Malloc()ed) */ | |
| 22 | 22 | int nResult; /* number of bytes in zResult */ |
| 23 | 23 | Th_Hash *paCmd; /* Table of registered commands */ |
| 24 | 24 | Th_Frame *pFrame; /* Current execution frame */ |
| 25 | 25 | int isListMode; /* True if thSplitList() should operate in "list" mode */ |
| 26 | 26 | }; |
| @@ -42,25 +42,25 @@ | ||
| 42 | 42 | ** are stored in the Th_Frame.paVar hash table member of the associated |
| 43 | 43 | ** stack frame object. |
| 44 | 44 | ** |
| 45 | 45 | ** When an interpreter is created, a single Th_Frame structure is also |
| 46 | 46 | ** allocated - the global variable scope. Th_Interp.pFrame (the current |
| 47 | -** interpreter frame) is initialised to point to this Th_Frame. It is | |
| 48 | -** not deleted for the lifetime of the interpreter (because the global | |
| 47 | +** interpreter frame) is initialised to point to this Th_Frame. It is | |
| 48 | +** not deleted for the lifetime of the interpreter (because the global | |
| 49 | 49 | ** frame never goes out of scope). |
| 50 | 50 | ** |
| 51 | 51 | ** New stack frames are created by the Th_InFrame() function. Before |
| 52 | 52 | ** invoking its callback function, Th_InFrame() allocates a new Th_Frame |
| 53 | 53 | ** structure with pCaller set to the current frame (Th_Interp.pFrame), |
| 54 | 54 | ** and sets the current frame to the new frame object. After the callback |
| 55 | 55 | ** has been invoked, the allocated Th_Frame is deleted and the value |
| 56 | 56 | ** of the current frame pointer restored. |
| 57 | -** | |
| 58 | -** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions | |
| 59 | -** access variable values in the current frame. If they need to access | |
| 57 | +** | |
| 58 | +** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions | |
| 59 | +** access variable values in the current frame. If they need to access | |
| 60 | 60 | ** the global frame, they do so by traversing the pCaller pointer list. |
| 61 | -** Likewise, the Th_LinkVar() function uses the pCaller pointers to | |
| 61 | +** Likewise, the Th_LinkVar() function uses the pCaller pointers to | |
| 62 | 62 | ** link to variables located in the global or other stack frames. |
| 63 | 63 | */ |
| 64 | 64 | struct Th_Frame { |
| 65 | 65 | Th_Hash *paVar; /* Variables defined in this scope */ |
| 66 | 66 | Th_Frame *pCaller; /* Calling frame */ |
| @@ -84,11 +84,11 @@ | ||
| 84 | 84 | ** value. |
| 85 | 85 | */ |
| 86 | 86 | struct Th_Variable { |
| 87 | 87 | int nRef; /* Number of references to this structure */ |
| 88 | 88 | int nData; /* Number of bytes at Th_Variable.zData */ |
| 89 | - char *zData; /* Data for scalar variables */ | |
| 89 | + char *zData; /* Data for scalar variables */ | |
| 90 | 90 | Th_Hash *pHash; /* Data for array variables */ |
| 91 | 91 | }; |
| 92 | 92 | |
| 93 | 93 | /* |
| 94 | 94 | ** Hash table API: |
| @@ -105,24 +105,24 @@ | ||
| 105 | 105 | static int thEndOfLine(const char *, int); |
| 106 | 106 | |
| 107 | 107 | static int thPushFrame(Th_Interp*, Th_Frame*); |
| 108 | 108 | static void thPopFrame(Th_Interp*); |
| 109 | 109 | |
| 110 | -static void thFreeVariable(Th_HashEntry*, void*); | |
| 111 | -static void thFreeCommand(Th_HashEntry*, void*); | |
| 110 | +static int thFreeVariable(Th_HashEntry*, void*); | |
| 111 | +static int thFreeCommand(Th_HashEntry*, void*); | |
| 112 | 112 | |
| 113 | 113 | /* |
| 114 | 114 | ** The following are used by both the expression and language parsers. |
| 115 | -** Given that the start of the input string (z, n) is a language | |
| 115 | +** Given that the start of the input string (z, n) is a language | |
| 116 | 116 | ** construct of the relevant type (a command enclosed in [], an escape |
| 117 | 117 | ** sequence etc.), these functions determine the number of bytes |
| 118 | 118 | ** of the input consumed by the construct. For example: |
| 119 | 119 | ** |
| 120 | 120 | ** int nByte; |
| 121 | 121 | ** thNextCommand(interp, "[expr $a+1] $nIter", 18, &nByte); |
| 122 | 122 | ** |
| 123 | -** results in variable nByte being set to 11. Or, | |
| 123 | +** results in variable nByte being set to 11. Or, | |
| 124 | 124 | ** |
| 125 | 125 | ** thNextVarname(interp, "$a+1", 4, &nByte); |
| 126 | 126 | ** |
| 127 | 127 | ** results in nByte being set to 2. |
| 128 | 128 | */ |
| @@ -132,24 +132,24 @@ | ||
| 132 | 132 | static int thNextNumber (Th_Interp*, const char *z, int n, int *pN); |
| 133 | 133 | static int thNextSpace (Th_Interp*, const char *z, int n, int *pN); |
| 134 | 134 | |
| 135 | 135 | /* |
| 136 | 136 | ** Given that the input string (z, n) contains a language construct of |
| 137 | -** the relevant type (a command enclosed in [], an escape sequence | |
| 137 | +** the relevant type (a command enclosed in [], an escape sequence | |
| 138 | 138 | ** like "\xFF" or a variable reference like "${varname}", perform |
| 139 | 139 | ** substitution on the string and store the resulting string in |
| 140 | 140 | ** the interpreter result. |
| 141 | 141 | */ |
| 142 | 142 | static int thSubstCommand(Th_Interp*, const char *z, int n); |
| 143 | 143 | static int thSubstEscape (Th_Interp*, const char *z, int n); |
| 144 | 144 | static int thSubstVarname(Th_Interp*, const char *z, int n); |
| 145 | 145 | |
| 146 | 146 | /* |
| 147 | -** Given that there is a th1 word located at the start of the input | |
| 147 | +** Given that there is a th1 word located at the start of the input | |
| 148 | 148 | ** string (z, n), determine the length in bytes of that word. If the |
| 149 | -** isCmd argument is non-zero, then an unescaped ";" byte not | |
| 150 | -** located inside of a block or quoted string is considered to mark | |
| 149 | +** isCmd argument is non-zero, then an unescaped ";" byte not | |
| 150 | +** located inside of a block or quoted string is considered to mark | |
| 151 | 151 | ** the end of the word. |
| 152 | 152 | */ |
| 153 | 153 | static int thNextWord(Th_Interp*, const char *z, int n, int *pN, int isCmd); |
| 154 | 154 | |
| 155 | 155 | /* |
| @@ -176,13 +176,13 @@ | ||
| 176 | 176 | ** Append nAdd bytes of content copied from zAdd to the end of buffer |
| 177 | 177 | ** pBuffer. If there is not enough space currently allocated, resize |
| 178 | 178 | ** the allocation to make space. |
| 179 | 179 | */ |
| 180 | 180 | static int thBufferWrite( |
| 181 | - Th_Interp *interp, | |
| 182 | - Buffer *pBuffer, | |
| 183 | - const char *zAdd, | |
| 181 | + Th_Interp *interp, | |
| 182 | + Buffer *pBuffer, | |
| 183 | + const char *zAdd, | |
| 184 | 184 | int nAdd |
| 185 | 185 | ){ |
| 186 | 186 | int nReq; |
| 187 | 187 | |
| 188 | 188 | if( nAdd<0 ){ |
| @@ -258,12 +258,14 @@ | ||
| 258 | 258 | ** (Th_Frame.paVar). Decrement the reference count of the Th_Variable |
| 259 | 259 | ** structure that the entry points to. Free the Th_Variable if its |
| 260 | 260 | ** reference count reaches 0. |
| 261 | 261 | ** |
| 262 | 262 | ** Argument pContext is a pointer to the interpreter structure. |
| 263 | +** | |
| 264 | +** Returns non-zero if the Th_Variable was actually freed. | |
| 263 | 265 | */ |
| 264 | -static void thFreeVariable(Th_HashEntry *pEntry, void *pContext){ | |
| 266 | +static int thFreeVariable(Th_HashEntry *pEntry, void *pContext){ | |
| 265 | 267 | Th_Variable *pValue = (Th_Variable *)pEntry->pData; |
| 266 | 268 | pValue->nRef--; |
| 267 | 269 | assert( pValue->nRef>=0 ); |
| 268 | 270 | if( pValue->nRef==0 ){ |
| 269 | 271 | Th_Interp *interp = (Th_Interp *)pContext; |
| @@ -271,27 +273,33 @@ | ||
| 271 | 273 | if( pValue->pHash ){ |
| 272 | 274 | Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext); |
| 273 | 275 | Th_HashDelete(interp, pValue->pHash); |
| 274 | 276 | } |
| 275 | 277 | Th_Free(interp, pValue); |
| 278 | + pEntry->pData = 0; | |
| 279 | + return 1; | |
| 276 | 280 | } |
| 281 | + return 0; | |
| 277 | 282 | } |
| 278 | 283 | |
| 279 | 284 | /* |
| 280 | 285 | ** Argument pEntry points to an entry in the command hash table |
| 281 | 286 | ** (Th_Interp.paCmd). Delete the Th_Command structure that the |
| 282 | 287 | ** entry points to. |
| 283 | 288 | ** |
| 284 | 289 | ** Argument pContext is a pointer to the interpreter structure. |
| 290 | +** | |
| 291 | +** Always returns non-zero. | |
| 285 | 292 | */ |
| 286 | -static void thFreeCommand(Th_HashEntry *pEntry, void *pContext){ | |
| 293 | +static int thFreeCommand(Th_HashEntry *pEntry, void *pContext){ | |
| 287 | 294 | Th_Command *pCommand = (Th_Command *)pEntry->pData; |
| 288 | 295 | if( pCommand->xDel ){ |
| 289 | 296 | pCommand->xDel((Th_Interp *)pContext, pCommand->pContext); |
| 290 | 297 | } |
| 291 | 298 | Th_Free((Th_Interp *)pContext, pEntry->pData); |
| 292 | 299 | pEntry->pData = 0; |
| 300 | + return 1; | |
| 293 | 301 | } |
| 294 | 302 | |
| 295 | 303 | /* |
| 296 | 304 | ** Push a new frame onto the stack. |
| 297 | 305 | */ |
| @@ -311,19 +319,19 @@ | ||
| 311 | 319 | Th_HashDelete(interp, pFrame->paVar); |
| 312 | 320 | interp->pFrame = pFrame->pCaller; |
| 313 | 321 | } |
| 314 | 322 | |
| 315 | 323 | /* |
| 316 | -** The first part of the string (zInput,nInput) contains an escape | |
| 324 | +** The first part of the string (zInput,nInput) contains an escape | |
| 317 | 325 | ** sequence. Set *pnEscape to the number of bytes in the escape sequence. |
| 318 | 326 | ** If there is a parse error, return TH_ERROR and set the interpreter |
| 319 | 327 | ** result to an error message. Otherwise return TH_OK. |
| 320 | 328 | */ |
| 321 | 329 | static int thNextEscape( |
| 322 | 330 | Th_Interp *interp, |
| 323 | - const char *zInput, | |
| 324 | - int nInput, | |
| 331 | + const char *zInput, | |
| 332 | + int nInput, | |
| 325 | 333 | int *pnEscape |
| 326 | 334 | ){ |
| 327 | 335 | int i = 2; |
| 328 | 336 | |
| 329 | 337 | assert(nInput>0); |
| @@ -344,18 +352,18 @@ | ||
| 344 | 352 | return TH_OK; |
| 345 | 353 | } |
| 346 | 354 | |
| 347 | 355 | /* |
| 348 | 356 | ** The first part of the string (zInput,nInput) contains a variable |
| 349 | -** reference. Set *pnVarname to the number of bytes in the variable | |
| 350 | -** reference. If there is a parse error, return TH_ERROR and set the | |
| 357 | +** reference. Set *pnVarname to the number of bytes in the variable | |
| 358 | +** reference. If there is a parse error, return TH_ERROR and set the | |
| 351 | 359 | ** interpreter result to an error message. Otherwise return TH_OK. |
| 352 | 360 | */ |
| 353 | 361 | int thNextVarname( |
| 354 | 362 | Th_Interp *interp, |
| 355 | - const char *zInput, | |
| 356 | - int nInput, | |
| 363 | + const char *zInput, | |
| 364 | + int nInput, | |
| 357 | 365 | int *pnVarname |
| 358 | 366 | ){ |
| 359 | 367 | int i; |
| 360 | 368 | |
| 361 | 369 | assert(nInput>0); |
| @@ -401,19 +409,19 @@ | ||
| 401 | 409 | return TH_OK; |
| 402 | 410 | } |
| 403 | 411 | |
| 404 | 412 | /* |
| 405 | 413 | ** The first part of the string (zInput,nInput) contains a command |
| 406 | -** enclosed in a "[]" block. Set *pnCommand to the number of bytes in | |
| 407 | -** the variable reference. If there is a parse error, return TH_ERROR | |
| 408 | -** and set the interpreter result to an error message. Otherwise return | |
| 414 | +** enclosed in a "[]" block. Set *pnCommand to the number of bytes in | |
| 415 | +** the variable reference. If there is a parse error, return TH_ERROR | |
| 416 | +** and set the interpreter result to an error message. Otherwise return | |
| 409 | 417 | ** TH_OK. |
| 410 | 418 | */ |
| 411 | 419 | int thNextCommand( |
| 412 | 420 | Th_Interp *interp, |
| 413 | - const char *zInput, | |
| 414 | - int nInput, | |
| 421 | + const char *zInput, | |
| 422 | + int nInput, | |
| 415 | 423 | int *pnCommand |
| 416 | 424 | ){ |
| 417 | 425 | int nBrace = 0; |
| 418 | 426 | int nSquare = 0; |
| 419 | 427 | int i; |
| @@ -438,17 +446,17 @@ | ||
| 438 | 446 | |
| 439 | 447 | return TH_OK; |
| 440 | 448 | } |
| 441 | 449 | |
| 442 | 450 | /* |
| 443 | -** Set *pnSpace to the number of whitespace bytes at the start of | |
| 451 | +** Set *pnSpace to the number of whitespace bytes at the start of | |
| 444 | 452 | ** input string (zInput, nInput). Always return TH_OK. |
| 445 | 453 | */ |
| 446 | 454 | int thNextSpace( |
| 447 | 455 | Th_Interp *interp, |
| 448 | - const char *zInput, | |
| 449 | - int nInput, | |
| 456 | + const char *zInput, | |
| 457 | + int nInput, | |
| 450 | 458 | int *pnSpace |
| 451 | 459 | ){ |
| 452 | 460 | int i; |
| 453 | 461 | for(i=0; i<nInput && th_isspace(zInput[i]); i++); |
| 454 | 462 | *pnSpace = i; |
| @@ -457,21 +465,21 @@ | ||
| 457 | 465 | |
| 458 | 466 | /* |
| 459 | 467 | ** The first byte of the string (zInput,nInput) is not white-space. |
| 460 | 468 | ** Set *pnWord to the number of bytes in the th1 word that starts |
| 461 | 469 | ** with this byte. If a complete word cannot be parsed or some other |
| 462 | -** error occurs, return TH_ERROR and set the interpreter result to | |
| 470 | +** error occurs, return TH_ERROR and set the interpreter result to | |
| 463 | 471 | ** an error message. Otherwise return TH_OK. |
| 464 | 472 | ** |
| 465 | -** If the isCmd argument is non-zero, then an unescaped ";" byte not | |
| 466 | -** located inside of a block or quoted string is considered to mark | |
| 473 | +** If the isCmd argument is non-zero, then an unescaped ";" byte not | |
| 474 | +** located inside of a block or quoted string is considered to mark | |
| 467 | 475 | ** the end of the word. |
| 468 | 476 | */ |
| 469 | 477 | static int thNextWord( |
| 470 | 478 | Th_Interp *interp, |
| 471 | - const char *zInput, | |
| 472 | - int nInput, | |
| 479 | + const char *zInput, | |
| 480 | + int nInput, | |
| 473 | 481 | int *pnWord, |
| 474 | 482 | int isCmd |
| 475 | 483 | ){ |
| 476 | 484 | int iEnd = 0; |
| 477 | 485 | |
| @@ -531,12 +539,12 @@ | ||
| 531 | 539 | return thEvalLocal(interp, &zWord[1], nWord-2); |
| 532 | 540 | } |
| 533 | 541 | |
| 534 | 542 | /* |
| 535 | 543 | ** The input string (zWord, nWord) contains a th1 variable reference |
| 536 | -** (a '$' byte followed by a variable name). Perform substitution on | |
| 537 | -** the input string and store the resulting string in the interpreter | |
| 544 | +** (a '$' byte followed by a variable name). Perform substitution on | |
| 545 | +** the input string and store the resulting string in the interpreter | |
| 538 | 546 | ** result. |
| 539 | 547 | */ |
| 540 | 548 | static int thSubstVarname( |
| 541 | 549 | Th_Interp *interp, |
| 542 | 550 | const char *zWord, |
| @@ -572,11 +580,11 @@ | ||
| 572 | 580 | return Th_GetVar(interp, &zWord[1], nWord-1); |
| 573 | 581 | } |
| 574 | 582 | |
| 575 | 583 | /* |
| 576 | 584 | ** The input string (zWord, nWord) contains a th1 escape sequence. |
| 577 | -** Perform substitution on the input string and store the resulting | |
| 585 | +** Perform substitution on the input string and store the resulting | |
| 578 | 586 | ** string in the interpreter result. |
| 579 | 587 | */ |
| 580 | 588 | static int thSubstEscape( |
| 581 | 589 | Th_Interp *interp, |
| 582 | 590 | const char *zWord, |
| @@ -608,11 +616,11 @@ | ||
| 608 | 616 | return TH_OK; |
| 609 | 617 | } |
| 610 | 618 | |
| 611 | 619 | /* |
| 612 | 620 | ** The input string (zWord, nWord) contains a th1 word. Perform |
| 613 | -** substitution on the input string and store the resulting | |
| 621 | +** substitution on the input string and store the resulting | |
| 614 | 622 | ** string in the interpreter result. |
| 615 | 623 | */ |
| 616 | 624 | static int thSubstWord( |
| 617 | 625 | Th_Interp *interp, |
| 618 | 626 | const char *zWord, |
| @@ -640,20 +648,20 @@ | ||
| 640 | 648 | int (*xGet)(Th_Interp *, const char*, int, int *) = 0; |
| 641 | 649 | int (*xSubst)(Th_Interp *, const char*, int) = 0; |
| 642 | 650 | |
| 643 | 651 | switch( zWord[i] ){ |
| 644 | 652 | case '\\': |
| 645 | - xGet = thNextEscape; xSubst = thSubstEscape; | |
| 653 | + xGet = thNextEscape; xSubst = thSubstEscape; | |
| 646 | 654 | break; |
| 647 | 655 | case '[': |
| 648 | 656 | if( !interp->isListMode ){ |
| 649 | - xGet = thNextCommand; xSubst = thSubstCommand; | |
| 657 | + xGet = thNextCommand; xSubst = thSubstCommand; | |
| 650 | 658 | break; |
| 651 | 659 | } |
| 652 | 660 | case '$': |
| 653 | 661 | if( !interp->isListMode ){ |
| 654 | - xGet = thNextVarname; xSubst = thSubstVarname; | |
| 662 | + xGet = thNextVarname; xSubst = thSubstVarname; | |
| 655 | 663 | break; |
| 656 | 664 | } |
| 657 | 665 | default: { |
| 658 | 666 | thBufferWrite(interp, &output, &zWord[i], 1); |
| 659 | 667 | continue; /* Go to the next iteration of the for(...) loop */ |
| @@ -685,11 +693,11 @@ | ||
| 685 | 693 | ** Return true if one of the following is true of the buffer pointed |
| 686 | 694 | ** to by zInput, length nInput: |
| 687 | 695 | ** |
| 688 | 696 | ** + It is empty, or |
| 689 | 697 | ** + It contains nothing but white-space, or |
| 690 | -** + It contains no non-white-space characters before the first | |
| 698 | +** + It contains no non-white-space characters before the first | |
| 691 | 699 | ** newline character. |
| 692 | 700 | ** |
| 693 | 701 | ** Otherwise return false. |
| 694 | 702 | */ |
| 695 | 703 | static int thEndOfLine(const char *zInput, int nInput){ |
| @@ -725,16 +733,16 @@ | ||
| 725 | 733 | ** // Free all memory allocated by Th_SplitList(). The arrays pointed |
| 726 | 734 | ** // to by argv and argl are invalidated by this call. |
| 727 | 735 | ** // |
| 728 | 736 | ** Th_Free(interp, argv); |
| 729 | 737 | ** |
| 730 | -*/ | |
| 738 | +*/ | |
| 731 | 739 | static int thSplitList( |
| 732 | 740 | Th_Interp *interp, /* Interpreter context */ |
| 733 | - const char *zList, /* Pointer to buffer containing input list */ | |
| 741 | + const char *zList, /* Pointer to buffer containing input list */ | |
| 734 | 742 | int nList, /* Size of buffer pointed to by zList */ |
| 735 | - char ***pazElem, /* OUT: Array of list elements */ | |
| 743 | + char ***pazElem, /* OUT: Array of list elements */ | |
| 736 | 744 | int **panElem, /* OUT: Lengths of each list element */ |
| 737 | 745 | int *pnCount /* OUT: Number of list elements */ |
| 738 | 746 | ){ |
| 739 | 747 | int rc = TH_OK; |
| 740 | 748 | |
| @@ -774,14 +782,14 @@ | ||
| 774 | 782 | assert((lenbuf.nBuf/sizeof(int))==nCount); |
| 775 | 783 | |
| 776 | 784 | assert((pazElem && panElem) || (!pazElem && !panElem)); |
| 777 | 785 | if( pazElem && rc==TH_OK ){ |
| 778 | 786 | int i; |
| 779 | - char *zElem; | |
| 787 | + char *zElem; | |
| 780 | 788 | int *anElem; |
| 781 | 789 | char **azElem = Th_Malloc(interp, |
| 782 | - sizeof(char*) * nCount + /* azElem */ | |
| 790 | + sizeof(char*) * nCount + /* azElem */ | |
| 783 | 791 | sizeof(int) * nCount + /* anElem */ |
| 784 | 792 | strbuf.nBuf /* space for list element strings */ |
| 785 | 793 | ); |
| 786 | 794 | anElem = (int *)&azElem[nCount]; |
| 787 | 795 | zElem = (char *)&anElem[nCount]; |
| @@ -795,11 +803,11 @@ | ||
| 795 | 803 | *panElem = anElem; |
| 796 | 804 | } |
| 797 | 805 | if( pnCount ){ |
| 798 | 806 | *pnCount = nCount; |
| 799 | 807 | } |
| 800 | - | |
| 808 | + | |
| 801 | 809 | finish: |
| 802 | 810 | thBufferFree(interp, &strbuf); |
| 803 | 811 | thBufferFree(interp, &lenbuf); |
| 804 | 812 | return rc; |
| 805 | 813 | } |
| @@ -876,18 +884,18 @@ | ||
| 876 | 884 | if( rc==TH_OK ){ |
| 877 | 885 | Th_Command *p = (Th_Command *)(pEntry->pData); |
| 878 | 886 | const char **azArg = (const char **)argv; |
| 879 | 887 | rc = p->xProc(interp, p->pContext, argc, azArg, argl); |
| 880 | 888 | } |
| 881 | - | |
| 889 | + | |
| 882 | 890 | /* If an error occurred, add this command to the stack trace report. */ |
| 883 | 891 | if( rc==TH_ERROR ){ |
| 884 | 892 | char *zRes; |
| 885 | 893 | int nRes; |
| 886 | 894 | char *zStack = 0; |
| 887 | 895 | int nStack = 0; |
| 888 | - | |
| 896 | + | |
| 889 | 897 | zRes = Th_TakeResult(interp, &nRes); |
| 890 | 898 | if( TH_OK==Th_GetVar(interp, (char *)"::th_stack_trace", -1) ){ |
| 891 | 899 | zStack = Th_TakeResult(interp, &nStack); |
| 892 | 900 | } |
| 893 | 901 | Th_ListAppend(interp, &zStack, &nStack, zFirst, zInput-zFirst); |
| @@ -912,15 +920,15 @@ | ||
| 912 | 920 | ** |
| 913 | 921 | ** Argument iFrame is interpreted as follows: |
| 914 | 922 | ** |
| 915 | 923 | ** * If iFrame is 0, this means the current frame. |
| 916 | 924 | ** |
| 917 | -** * If iFrame is negative, then the nth frame up the stack, where | |
| 918 | -** n is the absolute value of iFrame. A value of -1 means the | |
| 925 | +** * If iFrame is negative, then the nth frame up the stack, where | |
| 926 | +** n is the absolute value of iFrame. A value of -1 means the | |
| 919 | 927 | ** calling procedure. |
| 920 | 928 | ** |
| 921 | -** * If iFrame is +ve, then the nth frame from the bottom of the | |
| 929 | +** * If iFrame is +ve, then the nth frame from the bottom of the | |
| 922 | 930 | ** stack. An iFrame value of 1 means the toplevel (global) frame. |
| 923 | 931 | */ |
| 924 | 932 | static Th_Frame *getFrame(Th_Interp *interp, int iFrame){ |
| 925 | 933 | Th_Frame *p = interp->pFrame; |
| 926 | 934 | int i; |
| @@ -948,28 +956,28 @@ | ||
| 948 | 956 | |
| 949 | 957 | |
| 950 | 958 | /* |
| 951 | 959 | ** Evaluate th1 script (zProgram, nProgram) in the frame identified by |
| 952 | 960 | ** argument iFrame. Leave either an error message or a result in the |
| 953 | -** interpreter result and return a th1 error code (TH_OK, TH_ERROR, | |
| 961 | +** interpreter result and return a th1 error code (TH_OK, TH_ERROR, | |
| 954 | 962 | ** TH_RETURN, TH_CONTINUE or TH_BREAK). |
| 955 | 963 | */ |
| 956 | 964 | int Th_Eval(Th_Interp *interp, int iFrame, const char *zProgram, int nProgram){ |
| 957 | 965 | int rc = TH_OK; |
| 958 | 966 | Th_Frame *pSavedFrame = interp->pFrame; |
| 959 | 967 | |
| 960 | - /* Set Th_Interp.pFrame to the frame that this script is to be | |
| 968 | + /* Set Th_Interp.pFrame to the frame that this script is to be | |
| 961 | 969 | ** evaluated in. The current frame is saved in pSavedFrame and will |
| 962 | 970 | ** be restored before this function returns. |
| 963 | 971 | */ |
| 964 | 972 | interp->pFrame = getFrame(interp, iFrame); |
| 965 | 973 | |
| 966 | 974 | if( !interp->pFrame ){ |
| 967 | 975 | rc = TH_ERROR; |
| 968 | 976 | }else{ |
| 969 | 977 | int nInput = nProgram; |
| 970 | - | |
| 978 | + | |
| 971 | 979 | if( nInput<0 ){ |
| 972 | 980 | nInput = th_strlen(zProgram); |
| 973 | 981 | } |
| 974 | 982 | rc = thEvalLocal(interp, zProgram, nInput); |
| 975 | 983 | } |
| @@ -995,13 +1003,13 @@ | ||
| 995 | 1003 | ** array key name. |
| 996 | 1004 | */ |
| 997 | 1005 | static int thAnalyseVarname( |
| 998 | 1006 | const char *zVarname, |
| 999 | 1007 | int nVarname, |
| 1000 | - const char **pzOuter, /* OUT: Pointer to scalar/array name */ | |
| 1008 | + const char **pzOuter, /* OUT: Pointer to scalar/array name */ | |
| 1001 | 1009 | int *pnOuter, /* OUT: Number of bytes at *pzOuter */ |
| 1002 | - const char **pzInner, /* OUT: Pointer to array key (or null) */ | |
| 1010 | + const char **pzInner, /* OUT: Pointer to array key (or null) */ | |
| 1003 | 1011 | int *pnInner, /* OUT: Number of bytes at *pzInner */ |
| 1004 | 1012 | int *pisGlobal /* OUT: Set to true if this is a global ref */ |
| 1005 | 1013 | ){ |
| 1006 | 1014 | const char *zOuter = zVarname; |
| 1007 | 1015 | int nOuter; |
| @@ -1042,13 +1050,28 @@ | ||
| 1042 | 1050 | *pnInner = nInner; |
| 1043 | 1051 | *pisGlobal = isGlobal; |
| 1044 | 1052 | return TH_OK; |
| 1045 | 1053 | } |
| 1046 | 1054 | |
| 1055 | +/* | |
| 1056 | +** The Find structure is used to return extra information to callers of the | |
| 1057 | +** thFindValue function. The fields within it are populated by thFindValue | |
| 1058 | +** as soon as the necessary information is available. Callers should check | |
| 1059 | +** each field of interest upon return. | |
| 1060 | +*/ | |
| 1061 | + | |
| 1062 | +struct Find { | |
| 1063 | + Th_HashEntry *pValueEntry; /* Pointer to the scalar or array hash entry */ | |
| 1064 | + Th_HashEntry *pElemEntry; /* Pointer to array element hash entry, if any */ | |
| 1065 | + const char *zElem; /* Name of array element, if applicable */ | |
| 1066 | + int nElem; /* Length of array element name, if applicable */ | |
| 1067 | +}; | |
| 1068 | +typedef struct Find Find; | |
| 1069 | + | |
| 1047 | 1070 | /* |
| 1048 | 1071 | ** Input string (zVar, nVar) contains a variable name. This function locates |
| 1049 | -** the Th_Variable structure associated with the named variable. The | |
| 1072 | +** the Th_Variable structure associated with the named variable. The | |
| 1050 | 1073 | ** variable name may be a global or local scalar or array variable |
| 1051 | 1074 | ** |
| 1052 | 1075 | ** If the create argument is non-zero and the named variable does not exist |
| 1053 | 1076 | ** it is created. Otherwise, an error is left in the interpreter result |
| 1054 | 1077 | ** and NULL returned. |
| @@ -1055,16 +1078,19 @@ | ||
| 1055 | 1078 | ** |
| 1056 | 1079 | ** If the arrayok argument is false and the named variable is an array, |
| 1057 | 1080 | ** an error is left in the interpreter result and NULL returned. If |
| 1058 | 1081 | ** arrayok is true an array name is Ok. |
| 1059 | 1082 | */ |
| 1083 | + | |
| 1060 | 1084 | static Th_Variable *thFindValue( |
| 1061 | 1085 | Th_Interp *interp, |
| 1062 | - const char *zVar, /* Pointer to variable name */ | |
| 1063 | - int nVar, /* Number of bytes at nVar */ | |
| 1064 | - int create, /* If true, create the variable if not found */ | |
| 1065 | - int arrayok /* If true, an array is Ok. Otherwise array==error */ | |
| 1086 | + const char *zVar, /* Pointer to variable name */ | |
| 1087 | + int nVar, /* Number of bytes at nVar */ | |
| 1088 | + int create, /* If true, create the variable if not found */ | |
| 1089 | + int arrayok, /* If true, an array is Ok. Otherwise array==error */ | |
| 1090 | + int noerror, /* If false, set interpreter result to error */ | |
| 1091 | + Find *pFind /* If non-zero, place output here */ | |
| 1066 | 1092 | ){ |
| 1067 | 1093 | const char *zOuter; |
| 1068 | 1094 | int nOuter; |
| 1069 | 1095 | const char *zInner; |
| 1070 | 1096 | int nInner; |
| @@ -1073,16 +1099,24 @@ | ||
| 1073 | 1099 | Th_HashEntry *pEntry; |
| 1074 | 1100 | Th_Frame *pFrame = interp->pFrame; |
| 1075 | 1101 | Th_Variable *pValue; |
| 1076 | 1102 | |
| 1077 | 1103 | thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal); |
| 1104 | + if( pFind ){ | |
| 1105 | + memset(pFind, 0, sizeof(Find)); | |
| 1106 | + pFind->zElem = zInner; | |
| 1107 | + pFind->nElem = nInner; | |
| 1108 | + } | |
| 1078 | 1109 | if( isGlobal ){ |
| 1079 | 1110 | while( pFrame->pCaller ) pFrame = pFrame->pCaller; |
| 1080 | 1111 | } |
| 1081 | 1112 | |
| 1082 | 1113 | pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create); |
| 1083 | - assert(pEntry || !create); | |
| 1114 | + assert(pEntry || create<=0); | |
| 1115 | + if( pFind ){ | |
| 1116 | + pFind->pValueEntry = pEntry; | |
| 1117 | + } | |
| 1084 | 1118 | if( !pEntry ){ |
| 1085 | 1119 | goto no_such_var; |
| 1086 | 1120 | } |
| 1087 | 1121 | |
| 1088 | 1122 | pValue = (Th_Variable *)pEntry->pData; |
| @@ -1093,20 +1127,26 @@ | ||
| 1093 | 1127 | pEntry->pData = (void *)pValue; |
| 1094 | 1128 | } |
| 1095 | 1129 | |
| 1096 | 1130 | if( zInner ){ |
| 1097 | 1131 | if( pValue->zData ){ |
| 1098 | - Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter); | |
| 1132 | + if( !noerror ){ | |
| 1133 | + Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter); | |
| 1134 | + } | |
| 1099 | 1135 | return 0; |
| 1100 | 1136 | } |
| 1101 | 1137 | if( !pValue->pHash ){ |
| 1102 | 1138 | if( !create ){ |
| 1103 | 1139 | goto no_such_var; |
| 1104 | 1140 | } |
| 1105 | 1141 | pValue->pHash = Th_HashNew(interp); |
| 1106 | 1142 | } |
| 1107 | 1143 | pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create); |
| 1144 | + assert(pEntry || create<=0); | |
| 1145 | + if( pFind ){ | |
| 1146 | + pFind->pElemEntry = pEntry; | |
| 1147 | + } | |
| 1108 | 1148 | if( !pEntry ){ |
| 1109 | 1149 | goto no_such_var; |
| 1110 | 1150 | } |
| 1111 | 1151 | pValue = (Th_Variable *)pEntry->pData; |
| 1112 | 1152 | if( !pValue ){ |
| @@ -1115,34 +1155,38 @@ | ||
| 1115 | 1155 | pValue->nRef = 1; |
| 1116 | 1156 | pEntry->pData = (void *)pValue; |
| 1117 | 1157 | } |
| 1118 | 1158 | }else{ |
| 1119 | 1159 | if( pValue->pHash && !arrayok ){ |
| 1120 | - Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter); | |
| 1160 | + if( !noerror ){ | |
| 1161 | + Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter); | |
| 1162 | + } | |
| 1121 | 1163 | return 0; |
| 1122 | 1164 | } |
| 1123 | 1165 | } |
| 1124 | 1166 | |
| 1125 | 1167 | return pValue; |
| 1126 | 1168 | |
| 1127 | 1169 | no_such_var: |
| 1128 | - Th_ErrorMessage(interp, "no such variable:", zVar, nVar); | |
| 1170 | + if( !noerror ){ | |
| 1171 | + Th_ErrorMessage(interp, "no such variable:", zVar, nVar); | |
| 1172 | + } | |
| 1129 | 1173 | return 0; |
| 1130 | 1174 | } |
| 1131 | 1175 | |
| 1132 | 1176 | /* |
| 1133 | -** String (zVar, nVar) must contain the name of a scalar variable or | |
| 1134 | -** array member. Look up the variable, store its current value in | |
| 1177 | +** String (zVar, nVar) must contain the name of a scalar variable or | |
| 1178 | +** array member. Look up the variable, store its current value in | |
| 1135 | 1179 | ** the interpreter result and return TH_OK. |
| 1136 | 1180 | ** |
| 1137 | 1181 | ** If the named variable does not exist, return TH_ERROR and leave |
| 1138 | 1182 | ** an error message in the interpreter result. |
| 1139 | 1183 | */ |
| 1140 | 1184 | int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1141 | 1185 | Th_Variable *pValue; |
| 1142 | 1186 | |
| 1143 | - pValue = thFindValue(interp, zVar, nVar, 0, 0); | |
| 1187 | + pValue = thFindValue(interp, zVar, nVar, 0, 0, 0, 0); | |
| 1144 | 1188 | if( !pValue ){ |
| 1145 | 1189 | return TH_ERROR; |
| 1146 | 1190 | } |
| 1147 | 1191 | if( !pValue->zData ){ |
| 1148 | 1192 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| @@ -1154,11 +1198,12 @@ | ||
| 1154 | 1198 | |
| 1155 | 1199 | /* |
| 1156 | 1200 | ** Return true if variable (zVar, nVar) exists. |
| 1157 | 1201 | */ |
| 1158 | 1202 | int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1159 | - return thFindValue(interp, zVar, nVar, 0, 0)!=0; | |
| 1203 | + Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0); | |
| 1204 | + return pValue && (pValue->zData || pValue->pHash); | |
| 1160 | 1205 | } |
| 1161 | 1206 | |
| 1162 | 1207 | /* |
| 1163 | 1208 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| 1164 | 1209 | ** array member. If the variable does not exist it is created. The |
| @@ -1166,19 +1211,19 @@ | ||
| 1166 | 1211 | ** |
| 1167 | 1212 | ** If (zVar, nVar) refers to an existing array, TH_ERROR is returned |
| 1168 | 1213 | ** and an error message left in the interpreter result. |
| 1169 | 1214 | */ |
| 1170 | 1215 | int Th_SetVar( |
| 1171 | - Th_Interp *interp, | |
| 1172 | - const char *zVar, | |
| 1216 | + Th_Interp *interp, | |
| 1217 | + const char *zVar, | |
| 1173 | 1218 | int nVar, |
| 1174 | 1219 | const char *zValue, |
| 1175 | 1220 | int nValue |
| 1176 | 1221 | ){ |
| 1177 | 1222 | Th_Variable *pValue; |
| 1178 | 1223 | |
| 1179 | - pValue = thFindValue(interp, zVar, nVar, 1, 0); | |
| 1224 | + pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0); | |
| 1180 | 1225 | if( !pValue ){ |
| 1181 | 1226 | return TH_ERROR; |
| 1182 | 1227 | } |
| 1183 | 1228 | |
| 1184 | 1229 | if( nValue<0 ){ |
| @@ -1202,13 +1247,13 @@ | ||
| 1202 | 1247 | ** Create a variable link so that accessing variable (zLocal, nLocal) is |
| 1203 | 1248 | ** the same as accessing variable (zLink, nLink) in stack frame iFrame. |
| 1204 | 1249 | */ |
| 1205 | 1250 | int Th_LinkVar( |
| 1206 | 1251 | Th_Interp *interp, /* Interpreter */ |
| 1207 | - const char *zLocal, int nLocal, /* Local varname */ | |
| 1252 | + const char *zLocal, int nLocal, /* Local varname */ | |
| 1208 | 1253 | int iFrame, /* Stack frame of linked var */ |
| 1209 | - const char *zLink, int nLink /* Linked varname */ | |
| 1254 | + const char *zLink, int nLink /* Linked varname */ | |
| 1210 | 1255 | ){ |
| 1211 | 1256 | Th_Frame *pSavedFrame = interp->pFrame; |
| 1212 | 1257 | Th_Frame *pFrame; |
| 1213 | 1258 | Th_HashEntry *pEntry; |
| 1214 | 1259 | Th_Variable *pValue; |
| @@ -1217,11 +1262,11 @@ | ||
| 1217 | 1262 | if( !pFrame ){ |
| 1218 | 1263 | return TH_ERROR; |
| 1219 | 1264 | } |
| 1220 | 1265 | pSavedFrame = interp->pFrame; |
| 1221 | 1266 | interp->pFrame = pFrame; |
| 1222 | - pValue = thFindValue(interp, zLink, nLink, 1, 1); | |
| 1267 | + pValue = thFindValue(interp, zLink, nLink, 1, 1, 0, 0); | |
| 1223 | 1268 | interp->pFrame = pSavedFrame; |
| 1224 | 1269 | |
| 1225 | 1270 | pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1); |
| 1226 | 1271 | if( pEntry->pData ){ |
| 1227 | 1272 | Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal); |
| @@ -1238,25 +1283,68 @@ | ||
| 1238 | 1283 | ** an array, or an array member. If the identified variable exists, it |
| 1239 | 1284 | ** is deleted and TH_OK returned. Otherwise, an error message is left |
| 1240 | 1285 | ** in the interpreter result and TH_ERROR is returned. |
| 1241 | 1286 | */ |
| 1242 | 1287 | int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1288 | + Find find; | |
| 1243 | 1289 | Th_Variable *pValue; |
| 1290 | + Th_HashEntry *pEntry; | |
| 1291 | + int rc = TH_ERROR; | |
| 1244 | 1292 | |
| 1245 | - pValue = thFindValue(interp, zVar, nVar, 1, 1); | |
| 1293 | + pValue = thFindValue(interp, zVar, nVar, 0, 1, 0, &find); | |
| 1246 | 1294 | if( !pValue ){ |
| 1247 | - return TH_ERROR; | |
| 1248 | - } | |
| 1249 | - | |
| 1250 | - Th_Free(interp, pValue->zData); | |
| 1251 | - pValue->zData = 0; | |
| 1252 | - if( pValue->pHash ){ | |
| 1253 | - Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp); | |
| 1254 | - Th_HashDelete(interp, pValue->pHash); | |
| 1255 | - pValue->pHash = 0; | |
| 1256 | - } | |
| 1257 | - return TH_OK; | |
| 1295 | + return rc; | |
| 1296 | + } | |
| 1297 | + | |
| 1298 | + if( pValue->zData || pValue->pHash ){ | |
| 1299 | + rc = TH_OK; | |
| 1300 | + }else { | |
| 1301 | + Th_ErrorMessage(interp, "no such variable:", zVar, nVar); | |
| 1302 | + } | |
| 1303 | + | |
| 1304 | + /* | |
| 1305 | + ** The variable may be shared by more than one frame; therefore, make sure | |
| 1306 | + ** it is actually freed prior to freeing the parent structure. The values | |
| 1307 | + ** for the variable must be freed now so the variable appears undefined in | |
| 1308 | + ** all frames. The hash entry in the current frame must also be deleted | |
| 1309 | + ** now; otherwise, if the current stack frame is later popped, it will try | |
| 1310 | + ** to delete a variable which has already been freed. | |
| 1311 | + */ | |
| 1312 | + if( find.zElem ){ | |
| 1313 | + pEntry = find.pElemEntry; | |
| 1314 | + }else{ | |
| 1315 | + pEntry = find.pValueEntry; | |
| 1316 | + } | |
| 1317 | + assert( pEntry ); | |
| 1318 | + assert( pValue ); | |
| 1319 | + if( thFreeVariable(pEntry, (void *)interp) ){ | |
| 1320 | + if( find.zElem ){ | |
| 1321 | + Th_Variable *pValue2 = find.pValueEntry->pData; | |
| 1322 | + Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1); | |
| 1323 | + }else if( pEntry->pData ){ | |
| 1324 | + Th_Free(interp, pEntry->pData); | |
| 1325 | + pEntry->pData = 0; | |
| 1326 | + } | |
| 1327 | + }else{ | |
| 1328 | + if( pValue->zData ){ | |
| 1329 | + Th_Free(interp, pValue->zData); | |
| 1330 | + pValue->zData = 0; | |
| 1331 | + } | |
| 1332 | + if( pValue->pHash ){ | |
| 1333 | + Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp); | |
| 1334 | + Th_HashDelete(interp, pValue->pHash); | |
| 1335 | + pValue->pHash = 0; | |
| 1336 | + } | |
| 1337 | + if( find.zElem ){ | |
| 1338 | + Th_Variable *pValue2 = find.pValueEntry->pData; | |
| 1339 | + Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1); | |
| 1340 | + } | |
| 1341 | + } | |
| 1342 | + if( !find.zElem ){ | |
| 1343 | + Th_HashFind(interp, interp->pFrame->paVar, zVar, nVar, -1); | |
| 1344 | + } | |
| 1345 | + return rc; | |
| 1258 | 1346 | } |
| 1259 | 1347 | |
| 1260 | 1348 | /* |
| 1261 | 1349 | ** Return an allocated buffer containing a copy of string (z, n). The |
| 1262 | 1350 | ** caller is responsible for eventually calling Th_Free() to free |
| @@ -1291,11 +1379,11 @@ | ||
| 1291 | 1379 | if( interp ){ |
| 1292 | 1380 | char *zRes = 0; |
| 1293 | 1381 | int nRes = 0; |
| 1294 | 1382 | |
| 1295 | 1383 | Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0); |
| 1296 | - | |
| 1384 | + | |
| 1297 | 1385 | Th_StringAppend(interp, &zRes, &nRes, zPre, -1); |
| 1298 | 1386 | if( zRes[nRes-1]=='"' ){ |
| 1299 | 1387 | Th_StringAppend(interp, &zRes, &nRes, z, n); |
| 1300 | 1388 | Th_StringAppend(interp, &zRes, &nRes, (const char *)"\"", 1); |
| 1301 | 1389 | }else{ |
| @@ -1373,12 +1461,12 @@ | ||
| 1373 | 1461 | return (char *)Th_Malloc(pInterp, 1); |
| 1374 | 1462 | } |
| 1375 | 1463 | } |
| 1376 | 1464 | |
| 1377 | 1465 | |
| 1378 | -/* | |
| 1379 | -** Wrappers around the supplied malloc() and free() | |
| 1466 | +/* | |
| 1467 | +** Wrappers around the supplied malloc() and free() | |
| 1380 | 1468 | */ |
| 1381 | 1469 | void *Th_Malloc(Th_Interp *pInterp, int nByte){ |
| 1382 | 1470 | void *p = pInterp->pVtab->xMalloc(nByte); |
| 1383 | 1471 | if( p ){ |
| 1384 | 1472 | memset(p, 0, nByte); |
| @@ -1390,16 +1478,16 @@ | ||
| 1390 | 1478 | pInterp->pVtab->xFree(z); |
| 1391 | 1479 | } |
| 1392 | 1480 | } |
| 1393 | 1481 | |
| 1394 | 1482 | /* |
| 1395 | -** Install a new th1 command. | |
| 1483 | +** Install a new th1 command. | |
| 1396 | 1484 | ** |
| 1397 | 1485 | ** If a command of the same name already exists, it is deleted automatically. |
| 1398 | 1486 | */ |
| 1399 | 1487 | int Th_CreateCommand( |
| 1400 | - Th_Interp *interp, | |
| 1488 | + Th_Interp *interp, | |
| 1401 | 1489 | const char *zName, /* New command name */ |
| 1402 | 1490 | Th_CommandProc xProc, /* Command callback proc */ |
| 1403 | 1491 | void *pContext, /* Value to pass as second arg to xProc */ |
| 1404 | 1492 | void (*xDel)(Th_Interp *, void *) /* Command destructor callback */ |
| 1405 | 1493 | ){ |
| @@ -1417,27 +1505,27 @@ | ||
| 1417 | 1505 | } |
| 1418 | 1506 | pCommand->xProc = xProc; |
| 1419 | 1507 | pCommand->pContext = pContext; |
| 1420 | 1508 | pCommand->xDel = xDel; |
| 1421 | 1509 | pEntry->pData = (void *)pCommand; |
| 1422 | - | |
| 1510 | + | |
| 1423 | 1511 | return TH_OK; |
| 1424 | 1512 | } |
| 1425 | 1513 | |
| 1426 | 1514 | /* |
| 1427 | -** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0, | |
| 1515 | +** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0, | |
| 1428 | 1516 | ** the command is deleted instead of renamed. |
| 1429 | 1517 | ** |
| 1430 | 1518 | ** If successful, TH_OK is returned. If command zName does not exist, or |
| 1431 | -** if command zNew already exists, an error message is left in the | |
| 1519 | +** if command zNew already exists, an error message is left in the | |
| 1432 | 1520 | ** interpreter result and TH_ERROR is returned. |
| 1433 | 1521 | */ |
| 1434 | 1522 | int Th_RenameCommand( |
| 1435 | - Th_Interp *interp, | |
| 1436 | - const char *zName, /* Existing command name */ | |
| 1523 | + Th_Interp *interp, | |
| 1524 | + const char *zName, /* Existing command name */ | |
| 1437 | 1525 | int nName, /* Number of bytes at zName */ |
| 1438 | - const char *zNew, /* New command name */ | |
| 1526 | + const char *zNew, /* New command name */ | |
| 1439 | 1527 | int nNew /* Number of bytes at zNew */ |
| 1440 | 1528 | ){ |
| 1441 | 1529 | Th_HashEntry *pEntry; |
| 1442 | 1530 | Th_HashEntry *pNewEntry; |
| 1443 | 1531 | |
| @@ -1491,11 +1579,11 @@ | ||
| 1491 | 1579 | ** If an error occurs (if (zList, nList) is not a valid list) an error |
| 1492 | 1580 | ** message is left in the interpreter result and TH_ERROR returned. |
| 1493 | 1581 | ** |
| 1494 | 1582 | ** If successful, *pnCount is set to the number of elements in the list. |
| 1495 | 1583 | ** panElem is set to point at an array of *pnCount integers - the lengths |
| 1496 | -** of the element values. *pazElem is set to point at an array of | |
| 1584 | +** of the element values. *pazElem is set to point at an array of | |
| 1497 | 1585 | ** pointers to buffers containing the array element's data. |
| 1498 | 1586 | ** |
| 1499 | 1587 | ** To free the arrays allocated at *pazElem and *panElem, the caller |
| 1500 | 1588 | ** should call Th_Free() on *pazElem only. Exactly one such call to |
| 1501 | 1589 | ** Th_Free() must be made per call to Th_SplitList(). |
| @@ -1517,13 +1605,13 @@ | ||
| 1517 | 1605 | ** Th_Free(interp, azElem); |
| 1518 | 1606 | ** |
| 1519 | 1607 | */ |
| 1520 | 1608 | int Th_SplitList( |
| 1521 | 1609 | Th_Interp *interp, |
| 1522 | - const char *zList, /* Pointer to buffer containing list */ | |
| 1610 | + const char *zList, /* Pointer to buffer containing list */ | |
| 1523 | 1611 | int nList, /* Number of bytes at zList */ |
| 1524 | - char ***pazElem, /* OUT: Array of pointers to element data */ | |
| 1612 | + char ***pazElem, /* OUT: Array of pointers to element data */ | |
| 1525 | 1613 | int **panElem, /* OUT: Array of element data lengths */ |
| 1526 | 1614 | int *pnCount /* OUT: Number of elements in list */ |
| 1527 | 1615 | ){ |
| 1528 | 1616 | int rc; |
| 1529 | 1617 | interp->isListMode = 1; |
| @@ -1534,16 +1622,16 @@ | ||
| 1534 | 1622 | } |
| 1535 | 1623 | return rc; |
| 1536 | 1624 | } |
| 1537 | 1625 | |
| 1538 | 1626 | /* |
| 1539 | -** Append a new element to an existing th1 list. The element to append | |
| 1627 | +** Append a new element to an existing th1 list. The element to append | |
| 1540 | 1628 | ** to the list is (zElem, nElem). |
| 1541 | 1629 | ** |
| 1542 | 1630 | ** A pointer to the existing list must be stored at *pzList when this |
| 1543 | -** function is called. The length must be stored in *pnList. The value | |
| 1544 | -** of *pzList must either be NULL (in which case *pnList must be 0), or | |
| 1631 | +** function is called. The length must be stored in *pnList. The value | |
| 1632 | +** of *pzList must either be NULL (in which case *pnList must be 0), or | |
| 1545 | 1633 | ** a pointer to memory obtained from Th_Malloc(). |
| 1546 | 1634 | ** |
| 1547 | 1635 | ** This function calls Th_Free() to free the buffer at *pzList and sets |
| 1548 | 1636 | ** *pzList to point to a new buffer containing the new list value. *pnList |
| 1549 | 1637 | ** is similarly updated before returning. The return value is always TH_OK. |
| @@ -1560,13 +1648,13 @@ | ||
| 1560 | 1648 | ** Th_Free(interp, zList); |
| 1561 | 1649 | ** |
| 1562 | 1650 | */ |
| 1563 | 1651 | int Th_ListAppend( |
| 1564 | 1652 | Th_Interp *interp, /* Interpreter context */ |
| 1565 | - char **pzList, /* IN/OUT: Ptr to ptr to list */ | |
| 1653 | + char **pzList, /* IN/OUT: Ptr to ptr to list */ | |
| 1566 | 1654 | int *pnList, /* IN/OUT: Current length of *pzList */ |
| 1567 | - const char *zElem, /* Data to append */ | |
| 1655 | + const char *zElem, /* Data to append */ | |
| 1568 | 1656 | int nElem /* Length of nElem */ |
| 1569 | 1657 | ){ |
| 1570 | 1658 | Buffer output; |
| 1571 | 1659 | int i; |
| 1572 | 1660 | |
| @@ -1615,13 +1703,13 @@ | ||
| 1615 | 1703 | ** Append a new element to an existing th1 string. This function uses |
| 1616 | 1704 | ** the same interface as the Th_ListAppend() function. |
| 1617 | 1705 | */ |
| 1618 | 1706 | int Th_StringAppend( |
| 1619 | 1707 | Th_Interp *interp, /* Interpreter context */ |
| 1620 | - char **pzStr, /* IN/OUT: Ptr to ptr to list */ | |
| 1708 | + char **pzStr, /* IN/OUT: Ptr to ptr to list */ | |
| 1621 | 1709 | int *pnStr, /* IN/OUT: Current length of *pzStr */ |
| 1622 | - const char *zElem, /* Data to append */ | |
| 1710 | + const char *zElem, /* Data to append */ | |
| 1623 | 1711 | int nElem /* Length of nElem */ |
| 1624 | 1712 | ){ |
| 1625 | 1713 | char *zNew; |
| 1626 | 1714 | int nNew; |
| 1627 | 1715 | |
| @@ -1639,11 +1727,11 @@ | ||
| 1639 | 1727 | *pnStr = nNew; |
| 1640 | 1728 | |
| 1641 | 1729 | return TH_OK; |
| 1642 | 1730 | } |
| 1643 | 1731 | |
| 1644 | -/* | |
| 1732 | +/* | |
| 1645 | 1733 | ** Delete an interpreter. |
| 1646 | 1734 | */ |
| 1647 | 1735 | void Th_DeleteInterp(Th_Interp *interp){ |
| 1648 | 1736 | assert(interp->pFrame); |
| 1649 | 1737 | assert(0==interp->pFrame->pCaller); |
| @@ -1660,11 +1748,11 @@ | ||
| 1660 | 1748 | |
| 1661 | 1749 | /* Delete the interpreter structure itself. */ |
| 1662 | 1750 | Th_Free(interp, (void *)interp); |
| 1663 | 1751 | } |
| 1664 | 1752 | |
| 1665 | -/* | |
| 1753 | +/* | |
| 1666 | 1754 | ** Create a new interpreter. |
| 1667 | 1755 | */ |
| 1668 | 1756 | Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){ |
| 1669 | 1757 | Th_Interp *p; |
| 1670 | 1758 | |
| @@ -1694,11 +1782,11 @@ | ||
| 1694 | 1782 | Operator *pOp; |
| 1695 | 1783 | Expr *pParent; |
| 1696 | 1784 | Expr *pLeft; |
| 1697 | 1785 | Expr *pRight; |
| 1698 | 1786 | |
| 1699 | - char *zValue; /* Pointer to literal value */ | |
| 1787 | + char *zValue; /* Pointer to literal value */ | |
| 1700 | 1788 | int nValue; /* Length of literal value buffer */ |
| 1701 | 1789 | }; |
| 1702 | 1790 | |
| 1703 | 1791 | /* Unary operators */ |
| 1704 | 1792 | #define OP_UNARY_MINUS 2 |
| @@ -1750,11 +1838,11 @@ | ||
| 1750 | 1838 | {"+", OP_UNARY_PLUS, 1, ARG_NUMBER}, |
| 1751 | 1839 | {"~", OP_BITWISE_NOT, 1, ARG_INTEGER}, |
| 1752 | 1840 | {"!", OP_LOGICAL_NOT, 1, ARG_INTEGER}, |
| 1753 | 1841 | |
| 1754 | 1842 | /* Binary operators. It is important to the parsing in Th_Expr() that |
| 1755 | - * the two-character symbols ("==") appear before the one-character | |
| 1843 | + * the two-character symbols ("==") appear before the one-character | |
| 1756 | 1844 | * ones ("="). And that the priorities of all binary operators are |
| 1757 | 1845 | * integers between 2 and 12. |
| 1758 | 1846 | */ |
| 1759 | 1847 | {"<<", OP_LEFTSHIFT, 4, ARG_INTEGER}, |
| 1760 | 1848 | {">>", OP_RIGHTSHIFT, 4, ARG_INTEGER}, |
| @@ -1781,16 +1869,16 @@ | ||
| 1781 | 1869 | {0,0,0,0} |
| 1782 | 1870 | }; |
| 1783 | 1871 | |
| 1784 | 1872 | /* |
| 1785 | 1873 | ** The first part of the string (zInput,nInput) contains a number. |
| 1786 | -** Set *pnVarname to the number of bytes in the numeric string. | |
| 1874 | +** Set *pnVarname to the number of bytes in the numeric string. | |
| 1787 | 1875 | */ |
| 1788 | 1876 | static int thNextNumber( |
| 1789 | - Th_Interp *interp, | |
| 1790 | - const char *zInput, | |
| 1791 | - int nInput, | |
| 1877 | + Th_Interp *interp, | |
| 1878 | + const char *zInput, | |
| 1879 | + int nInput, | |
| 1792 | 1880 | int *pnLiteral |
| 1793 | 1881 | ){ |
| 1794 | 1882 | int i; |
| 1795 | 1883 | int seenDot = 0; |
| 1796 | 1884 | for(i=0; i<nInput; i++){ |
| @@ -1856,11 +1944,11 @@ | ||
| 1856 | 1944 | if( eArgType==ARG_NUMBER ){ |
| 1857 | 1945 | if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft)) |
| 1858 | 1946 | && (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight)) |
| 1859 | 1947 | ){ |
| 1860 | 1948 | eArgType = ARG_INTEGER; |
| 1861 | - }else if( | |
| 1949 | + }else if( | |
| 1862 | 1950 | (zLeft && TH_OK!=Th_ToDouble(interp, zLeft, nLeft, &fLeft)) || |
| 1863 | 1951 | (zRight && TH_OK!=Th_ToDouble(interp, zRight, nRight, &fRight)) |
| 1864 | 1952 | ){ |
| 1865 | 1953 | /* A type error. */ |
| 1866 | 1954 | rc = TH_ERROR; |
| @@ -1868,28 +1956,30 @@ | ||
| 1868 | 1956 | }else if( eArgType==ARG_INTEGER ){ |
| 1869 | 1957 | rc = Th_ToInt(interp, zLeft, nLeft, &iLeft); |
| 1870 | 1958 | if( rc==TH_OK && zRight ){ |
| 1871 | 1959 | rc = Th_ToInt(interp, zRight, nRight, &iRight); |
| 1872 | 1960 | } |
| 1873 | - } | |
| 1961 | + } | |
| 1874 | 1962 | } |
| 1875 | 1963 | |
| 1876 | 1964 | if( rc==TH_OK && eArgType==ARG_INTEGER ){ |
| 1877 | 1965 | int iRes = 0; |
| 1878 | 1966 | switch( pExpr->pOp->eOp ) { |
| 1879 | 1967 | case OP_MULTIPLY: iRes = iLeft*iRight; break; |
| 1880 | 1968 | case OP_DIVIDE: |
| 1881 | - if(!iRight){ | |
| 1969 | + if( !iRight ){ | |
| 1882 | 1970 | Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft); |
| 1883 | - return TH_ERROR; | |
| 1971 | + rc = TH_ERROR; | |
| 1972 | + goto finish; | |
| 1884 | 1973 | } |
| 1885 | 1974 | iRes = iLeft/iRight; |
| 1886 | 1975 | break; |
| 1887 | 1976 | case OP_MODULUS: |
| 1888 | - if(!iRight){ | |
| 1977 | + if( !iRight ){ | |
| 1889 | 1978 | Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft); |
| 1890 | - return TH_ERROR; | |
| 1979 | + rc = TH_ERROR; | |
| 1980 | + goto finish; | |
| 1891 | 1981 | } |
| 1892 | 1982 | iRes = iLeft%iRight; |
| 1893 | 1983 | break; |
| 1894 | 1984 | case OP_ADD: iRes = iLeft+iRight; break; |
| 1895 | 1985 | case OP_SUBTRACT: iRes = iLeft-iRight; break; |
| @@ -1913,11 +2003,18 @@ | ||
| 1913 | 2003 | } |
| 1914 | 2004 | Th_SetResultInt(interp, iRes); |
| 1915 | 2005 | }else if( rc==TH_OK && eArgType==ARG_NUMBER ){ |
| 1916 | 2006 | switch( pExpr->pOp->eOp ) { |
| 1917 | 2007 | case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break; |
| 1918 | - case OP_DIVIDE: Th_SetResultDouble(interp, fLeft/fRight); break; | |
| 2008 | + case OP_DIVIDE: | |
| 2009 | + if( fRight==0.0 ){ | |
| 2010 | + Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft); | |
| 2011 | + rc = TH_ERROR; | |
| 2012 | + goto finish; | |
| 2013 | + } | |
| 2014 | + Th_SetResultDouble(interp, fLeft/fRight); | |
| 2015 | + break; | |
| 1919 | 2016 | case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break; |
| 1920 | 2017 | case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break; |
| 1921 | 2018 | case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break; |
| 1922 | 2019 | case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break; |
| 1923 | 2020 | case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break; |
| @@ -1936,10 +2033,12 @@ | ||
| 1936 | 2033 | case OP_SEQ: Th_SetResultInt(interp, iEqual); break; |
| 1937 | 2034 | case OP_SNE: Th_SetResultInt(interp, !iEqual); break; |
| 1938 | 2035 | default: assert(!"Internal error"); |
| 1939 | 2036 | } |
| 1940 | 2037 | } |
| 2038 | + | |
| 2039 | + finish: | |
| 1941 | 2040 | |
| 1942 | 2041 | Th_Free(interp, zLeft); |
| 1943 | 2042 | Th_Free(interp, zRight); |
| 1944 | 2043 | } |
| 1945 | 2044 | |
| @@ -1959,11 +2058,11 @@ | ||
| 1959 | 2058 | #define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft)) |
| 1960 | 2059 | |
| 1961 | 2060 | for(jj=0; jj<nToken; jj++){ |
| 1962 | 2061 | if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){ |
| 1963 | 2062 | int nNest = 1; |
| 1964 | - int iLeft = jj; | |
| 2063 | + int iLeft = jj; | |
| 1965 | 2064 | |
| 1966 | 2065 | for(jj++; jj<nToken; jj++){ |
| 1967 | 2066 | Operator *pOp = apToken[jj]->pOp; |
| 1968 | 2067 | if( pOp && pOp->eOp==OP_OPEN_BRACKET ) nNest++; |
| 1969 | 2068 | if( pOp && pOp->eOp==OP_CLOSE_BRACKET ) nNest--; |
| @@ -2033,11 +2132,11 @@ | ||
| 2033 | 2132 | /* |
| 2034 | 2133 | ** Parse a string containing a TH expression to a list of tokens. |
| 2035 | 2134 | */ |
| 2036 | 2135 | static int exprParse( |
| 2037 | 2136 | Th_Interp *interp, /* Interpreter to leave error message in */ |
| 2038 | - const char *zExpr, /* Pointer to input string */ | |
| 2137 | + const char *zExpr, /* Pointer to input string */ | |
| 2039 | 2138 | int nExpr, /* Number of bytes at zExpr */ |
| 2040 | 2139 | Expr ***papToken, /* OUT: Array of tokens. */ |
| 2041 | 2140 | int *pnToken /* OUT: Size of token array */ |
| 2042 | 2141 | ){ |
| 2043 | 2142 | int i; |
| @@ -2108,11 +2207,11 @@ | ||
| 2108 | 2207 | memcpy(pNew->zValue, z, pNew->nValue); |
| 2109 | 2208 | i += pNew->nValue; |
| 2110 | 2209 | } |
| 2111 | 2210 | if( (nToken%16)==0 ){ |
| 2112 | 2211 | /* Grow the apToken array. */ |
| 2113 | - Expr **apTokenOld = apToken; | |
| 2212 | + Expr **apTokenOld = apToken; | |
| 2114 | 2213 | apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16)); |
| 2115 | 2214 | memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken); |
| 2116 | 2215 | } |
| 2117 | 2216 | |
| 2118 | 2217 | /* Put the new token at the end of the apToken array */ |
| @@ -2133,11 +2232,11 @@ | ||
| 2133 | 2232 | /* |
| 2134 | 2233 | ** Evaluate the string (zExpr, nExpr) as a Th expression. Store |
| 2135 | 2234 | ** the result in the interpreter interp and return TH_OK if |
| 2136 | 2235 | ** successful. If an error occurs, store an error message in |
| 2137 | 2236 | ** the interpreter result and return an error code. |
| 2138 | -*/ | |
| 2237 | +*/ | |
| 2139 | 2238 | int Th_Expr(Th_Interp *interp, const char *zExpr, int nExpr){ |
| 2140 | 2239 | int rc; /* Return Code */ |
| 2141 | 2240 | int i; /* Loop counter */ |
| 2142 | 2241 | |
| 2143 | 2242 | int nToken = 0; |
| @@ -2150,11 +2249,11 @@ | ||
| 2150 | 2249 | /* Parse the expression to a list of tokens. */ |
| 2151 | 2250 | rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken); |
| 2152 | 2251 | |
| 2153 | 2252 | /* If the parsing was successful, create an expression tree from |
| 2154 | 2253 | ** the parsed list of tokens. If successful, apToken[0] is set |
| 2155 | - ** to point to the root of the expression tree. | |
| 2254 | + ** to point to the root of the expression tree. | |
| 2156 | 2255 | */ |
| 2157 | 2256 | if( rc==TH_OK ){ |
| 2158 | 2257 | rc = exprMakeTree(interp, apToken, nToken); |
| 2159 | 2258 | } |
| 2160 | 2259 | |
| @@ -2188,16 +2287,17 @@ | ||
| 2188 | 2287 | |
| 2189 | 2288 | /* |
| 2190 | 2289 | ** Iterate through all values currently stored in the hash table. Invoke |
| 2191 | 2290 | ** the callback function xCallback for each entry. The second argument |
| 2192 | 2291 | ** passed to xCallback is a copy of the fourth argument passed to this |
| 2193 | -** function. | |
| 2292 | +** function. The return value from the callback function xCallback is | |
| 2293 | +** ignored. | |
| 2194 | 2294 | */ |
| 2195 | 2295 | void Th_HashIterate( |
| 2196 | - Th_Interp *interp, | |
| 2296 | + Th_Interp *interp, | |
| 2197 | 2297 | Th_Hash *pHash, |
| 2198 | - void (*xCallback)(Th_HashEntry *pEntry, void *pContext), | |
| 2298 | + int (*xCallback)(Th_HashEntry *pEntry, void *pContext), | |
| 2199 | 2299 | void *pContext |
| 2200 | 2300 | ){ |
| 2201 | 2301 | int i; |
| 2202 | 2302 | for(i=0; i<TH_HASHSIZE; i++){ |
| 2203 | 2303 | Th_HashEntry *pEntry; |
| @@ -2208,14 +2308,15 @@ | ||
| 2208 | 2308 | } |
| 2209 | 2309 | } |
| 2210 | 2310 | } |
| 2211 | 2311 | |
| 2212 | 2312 | /* |
| 2213 | -** Helper function for Th_HashDelete(). | |
| 2313 | +** Helper function for Th_HashDelete(). Always returns non-zero. | |
| 2214 | 2314 | */ |
| 2215 | -static void xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){ | |
| 2315 | +static int xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){ | |
| 2216 | 2316 | Th_Free((Th_Interp *)pContext, (void *)pEntry); |
| 2317 | + return 1; | |
| 2217 | 2318 | } |
| 2218 | 2319 | |
| 2219 | 2320 | /* |
| 2220 | 2321 | ** Free a hash-table previously allocated by Th_HashNew(). |
| 2221 | 2322 | */ |
| @@ -2225,14 +2326,14 @@ | ||
| 2225 | 2326 | Th_Free(interp, pHash); |
| 2226 | 2327 | } |
| 2227 | 2328 | } |
| 2228 | 2329 | |
| 2229 | 2330 | /* |
| 2230 | -** This function is used to insert or delete hash table items, or to | |
| 2331 | +** This function is used to insert or delete hash table items, or to | |
| 2231 | 2332 | ** query a hash table for an existing item. |
| 2232 | 2333 | ** |
| 2233 | -** If parameter op is less than zero, then the hash-table element | |
| 2334 | +** If parameter op is less than zero, then the hash-table element | |
| 2234 | 2335 | ** identified by (zKey, nKey) is removed from the hash-table if it |
| 2235 | 2336 | ** exists. NULL is returned. |
| 2236 | 2337 | ** |
| 2237 | 2338 | ** Otherwise, if the hash-table contains an item with key (zKey, nKey), |
| 2238 | 2339 | ** a pointer to the associated Th_HashEntry is returned. If parameter |
| @@ -2239,11 +2340,11 @@ | ||
| 2239 | 2340 | ** op is greater than zero, then a new entry is added if one cannot |
| 2240 | 2341 | ** be found. If op is zero, then NULL is returned if the item is |
| 2241 | 2342 | ** not already present in the hash-table. |
| 2242 | 2343 | */ |
| 2243 | 2344 | Th_HashEntry *Th_HashFind( |
| 2244 | - Th_Interp *interp, | |
| 2345 | + Th_Interp *interp, | |
| 2245 | 2346 | Th_Hash *pHash, |
| 2246 | 2347 | const char *zKey, |
| 2247 | 2348 | int nKey, |
| 2248 | 2349 | int op /* -ve = delete, 0 = find, +ve = insert */ |
| 2249 | 2350 | ){ |
| @@ -2307,11 +2408,11 @@ | ||
| 2307 | 2408 | ** '\f' 0x0C |
| 2308 | 2409 | ** '\r' 0x0D |
| 2309 | 2410 | ** |
| 2310 | 2411 | ** Whitespace characters have the 0x01 flag set. Decimal digits have the |
| 2311 | 2412 | ** 0x2 flag set. Single byte printable characters have the 0x4 flag set. |
| 2312 | -** Alphabet characters have the 0x8 bit set. | |
| 2413 | +** Alphabet characters have the 0x8 bit set. | |
| 2313 | 2414 | ** |
| 2314 | 2415 | ** The special list characters have the 0x10 flag set |
| 2315 | 2416 | ** |
| 2316 | 2417 | ** { } [ ] \ ; ' " |
| 2317 | 2418 | ** |
| @@ -2458,14 +2559,14 @@ | ||
| 2458 | 2559 | return z - zBegin; |
| 2459 | 2560 | } |
| 2460 | 2561 | |
| 2461 | 2562 | /* |
| 2462 | 2563 | ** Try to convert the string passed as arguments (z, n) to an integer. |
| 2463 | -** If successful, store the result in *piOut and return TH_OK. | |
| 2564 | +** If successful, store the result in *piOut and return TH_OK. | |
| 2464 | 2565 | ** |
| 2465 | -** If the string cannot be converted to an integer, return TH_ERROR. | |
| 2466 | -** If the interp argument is not NULL, leave an error message in the | |
| 2566 | +** If the string cannot be converted to an integer, return TH_ERROR. | |
| 2567 | +** If the interp argument is not NULL, leave an error message in the | |
| 2467 | 2568 | ** interpreter result too. |
| 2468 | 2569 | */ |
| 2469 | 2570 | int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){ |
| 2470 | 2571 | int i = 0; |
| 2471 | 2572 | int iOut = 0; |
| @@ -2493,20 +2594,20 @@ | ||
| 2493 | 2594 | return TH_OK; |
| 2494 | 2595 | } |
| 2495 | 2596 | |
| 2496 | 2597 | /* |
| 2497 | 2598 | ** Try to convert the string passed as arguments (z, n) to a double. |
| 2498 | -** If successful, store the result in *pfOut and return TH_OK. | |
| 2599 | +** If successful, store the result in *pfOut and return TH_OK. | |
| 2499 | 2600 | ** |
| 2500 | -** If the string cannot be converted to a double, return TH_ERROR. | |
| 2501 | -** If the interp argument is not NULL, leave an error message in the | |
| 2601 | +** If the string cannot be converted to a double, return TH_ERROR. | |
| 2602 | +** If the interp argument is not NULL, leave an error message in the | |
| 2502 | 2603 | ** interpreter result too. |
| 2503 | 2604 | */ |
| 2504 | 2605 | int Th_ToDouble( |
| 2505 | - Th_Interp *interp, | |
| 2506 | - const char *z, | |
| 2507 | - int n, | |
| 2606 | + Th_Interp *interp, | |
| 2607 | + const char *z, | |
| 2608 | + int n, | |
| 2508 | 2609 | double *pfOut |
| 2509 | 2610 | ){ |
| 2510 | 2611 | if( !sqlite3IsNumber((const char *)z, 0) ){ |
| 2511 | 2612 | Th_ErrorMessage(interp, "expected number, got: \"", z, n); |
| 2512 | 2613 | return TH_ERROR; |
| @@ -2547,33 +2648,33 @@ | ||
| 2547 | 2648 | ** the double fVal and return TH_OK. |
| 2548 | 2649 | */ |
| 2549 | 2650 | int Th_SetResultDouble(Th_Interp *interp, double fVal){ |
| 2550 | 2651 | int i; /* Iterator variable */ |
| 2551 | 2652 | double v = fVal; /* Input value */ |
| 2552 | - char zBuf[128]; /* Output buffer */ | |
| 2553 | - char *z = zBuf; /* Output cursor */ | |
| 2653 | + char zBuf[128]; /* Output buffer */ | |
| 2654 | + char *z = zBuf; /* Output cursor */ | |
| 2554 | 2655 | int iDot = 0; /* Digit after which to place decimal point */ |
| 2555 | 2656 | int iExp = 0; /* Exponent (NN in eNN) */ |
| 2556 | - const char *zExp; /* String representation of iExp */ | |
| 2657 | + const char *zExp; /* String representation of iExp */ | |
| 2557 | 2658 | |
| 2558 | 2659 | /* Precision: */ |
| 2559 | 2660 | #define INSIGNIFICANT 0.000000000001 |
| 2560 | 2661 | #define ROUNDER 0.0000000000005 |
| 2561 | 2662 | double insignificant = INSIGNIFICANT; |
| 2562 | 2663 | |
| 2563 | 2664 | /* If the real value is negative, write a '-' character to the |
| 2564 | 2665 | * output and transform v to the corresponding positive number. |
| 2565 | - */ | |
| 2666 | + */ | |
| 2566 | 2667 | if( v<0.0 ){ |
| 2567 | 2668 | *z++ = '-'; |
| 2568 | 2669 | v *= -1.0; |
| 2569 | 2670 | } |
| 2570 | 2671 | |
| 2571 | - /* Normalize v to a value between 1.0 and 10.0. Integer | |
| 2672 | + /* Normalize v to a value between 1.0 and 10.0. Integer | |
| 2572 | 2673 | * variable iExp is set to the exponent. i.e the original |
| 2573 | 2674 | * value is (v * 10^iExp) (or the negative thereof). |
| 2574 | - */ | |
| 2675 | + */ | |
| 2575 | 2676 | if( v>0.0 ){ |
| 2576 | 2677 | while( (v+ROUNDER)>=10.0 ) { iExp++; v *= 0.1; } |
| 2577 | 2678 | while( (v+ROUNDER)<1.0 ) { iExp--; v *= 10.0; } |
| 2578 | 2679 | } |
| 2579 | 2680 | v += ROUNDER; |
| 2580 | 2681 |
| --- src/th.c | |
| +++ src/th.c | |
| @@ -1,8 +1,8 @@ | |
| 1 | |
| 2 | /* |
| 3 | ** The implementation of the TH core. This file contains the parser, and |
| 4 | ** the implementation of the interface in th.h. |
| 5 | */ |
| 6 | |
| 7 | #include "config.h" |
| 8 | #include "th.h" |
| @@ -16,11 +16,11 @@ | |
| 16 | /* |
| 17 | ** Interpreter structure. |
| 18 | */ |
| 19 | struct Th_Interp { |
| 20 | Th_Vtab *pVtab; /* Copy of the argument passed to Th_CreateInterp() */ |
| 21 | char *zResult; /* Current interpreter result (Th_Malloc()ed) */ |
| 22 | int nResult; /* number of bytes in zResult */ |
| 23 | Th_Hash *paCmd; /* Table of registered commands */ |
| 24 | Th_Frame *pFrame; /* Current execution frame */ |
| 25 | int isListMode; /* True if thSplitList() should operate in "list" mode */ |
| 26 | }; |
| @@ -42,25 +42,25 @@ | |
| 42 | ** are stored in the Th_Frame.paVar hash table member of the associated |
| 43 | ** stack frame object. |
| 44 | ** |
| 45 | ** When an interpreter is created, a single Th_Frame structure is also |
| 46 | ** allocated - the global variable scope. Th_Interp.pFrame (the current |
| 47 | ** interpreter frame) is initialised to point to this Th_Frame. It is |
| 48 | ** not deleted for the lifetime of the interpreter (because the global |
| 49 | ** frame never goes out of scope). |
| 50 | ** |
| 51 | ** New stack frames are created by the Th_InFrame() function. Before |
| 52 | ** invoking its callback function, Th_InFrame() allocates a new Th_Frame |
| 53 | ** structure with pCaller set to the current frame (Th_Interp.pFrame), |
| 54 | ** and sets the current frame to the new frame object. After the callback |
| 55 | ** has been invoked, the allocated Th_Frame is deleted and the value |
| 56 | ** of the current frame pointer restored. |
| 57 | ** |
| 58 | ** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions |
| 59 | ** access variable values in the current frame. If they need to access |
| 60 | ** the global frame, they do so by traversing the pCaller pointer list. |
| 61 | ** Likewise, the Th_LinkVar() function uses the pCaller pointers to |
| 62 | ** link to variables located in the global or other stack frames. |
| 63 | */ |
| 64 | struct Th_Frame { |
| 65 | Th_Hash *paVar; /* Variables defined in this scope */ |
| 66 | Th_Frame *pCaller; /* Calling frame */ |
| @@ -84,11 +84,11 @@ | |
| 84 | ** value. |
| 85 | */ |
| 86 | struct Th_Variable { |
| 87 | int nRef; /* Number of references to this structure */ |
| 88 | int nData; /* Number of bytes at Th_Variable.zData */ |
| 89 | char *zData; /* Data for scalar variables */ |
| 90 | Th_Hash *pHash; /* Data for array variables */ |
| 91 | }; |
| 92 | |
| 93 | /* |
| 94 | ** Hash table API: |
| @@ -105,24 +105,24 @@ | |
| 105 | static int thEndOfLine(const char *, int); |
| 106 | |
| 107 | static int thPushFrame(Th_Interp*, Th_Frame*); |
| 108 | static void thPopFrame(Th_Interp*); |
| 109 | |
| 110 | static void thFreeVariable(Th_HashEntry*, void*); |
| 111 | static void thFreeCommand(Th_HashEntry*, void*); |
| 112 | |
| 113 | /* |
| 114 | ** The following are used by both the expression and language parsers. |
| 115 | ** Given that the start of the input string (z, n) is a language |
| 116 | ** construct of the relevant type (a command enclosed in [], an escape |
| 117 | ** sequence etc.), these functions determine the number of bytes |
| 118 | ** of the input consumed by the construct. For example: |
| 119 | ** |
| 120 | ** int nByte; |
| 121 | ** thNextCommand(interp, "[expr $a+1] $nIter", 18, &nByte); |
| 122 | ** |
| 123 | ** results in variable nByte being set to 11. Or, |
| 124 | ** |
| 125 | ** thNextVarname(interp, "$a+1", 4, &nByte); |
| 126 | ** |
| 127 | ** results in nByte being set to 2. |
| 128 | */ |
| @@ -132,24 +132,24 @@ | |
| 132 | static int thNextNumber (Th_Interp*, const char *z, int n, int *pN); |
| 133 | static int thNextSpace (Th_Interp*, const char *z, int n, int *pN); |
| 134 | |
| 135 | /* |
| 136 | ** Given that the input string (z, n) contains a language construct of |
| 137 | ** the relevant type (a command enclosed in [], an escape sequence |
| 138 | ** like "\xFF" or a variable reference like "${varname}", perform |
| 139 | ** substitution on the string and store the resulting string in |
| 140 | ** the interpreter result. |
| 141 | */ |
| 142 | static int thSubstCommand(Th_Interp*, const char *z, int n); |
| 143 | static int thSubstEscape (Th_Interp*, const char *z, int n); |
| 144 | static int thSubstVarname(Th_Interp*, const char *z, int n); |
| 145 | |
| 146 | /* |
| 147 | ** Given that there is a th1 word located at the start of the input |
| 148 | ** string (z, n), determine the length in bytes of that word. If the |
| 149 | ** isCmd argument is non-zero, then an unescaped ";" byte not |
| 150 | ** located inside of a block or quoted string is considered to mark |
| 151 | ** the end of the word. |
| 152 | */ |
| 153 | static int thNextWord(Th_Interp*, const char *z, int n, int *pN, int isCmd); |
| 154 | |
| 155 | /* |
| @@ -176,13 +176,13 @@ | |
| 176 | ** Append nAdd bytes of content copied from zAdd to the end of buffer |
| 177 | ** pBuffer. If there is not enough space currently allocated, resize |
| 178 | ** the allocation to make space. |
| 179 | */ |
| 180 | static int thBufferWrite( |
| 181 | Th_Interp *interp, |
| 182 | Buffer *pBuffer, |
| 183 | const char *zAdd, |
| 184 | int nAdd |
| 185 | ){ |
| 186 | int nReq; |
| 187 | |
| 188 | if( nAdd<0 ){ |
| @@ -258,12 +258,14 @@ | |
| 258 | ** (Th_Frame.paVar). Decrement the reference count of the Th_Variable |
| 259 | ** structure that the entry points to. Free the Th_Variable if its |
| 260 | ** reference count reaches 0. |
| 261 | ** |
| 262 | ** Argument pContext is a pointer to the interpreter structure. |
| 263 | */ |
| 264 | static void thFreeVariable(Th_HashEntry *pEntry, void *pContext){ |
| 265 | Th_Variable *pValue = (Th_Variable *)pEntry->pData; |
| 266 | pValue->nRef--; |
| 267 | assert( pValue->nRef>=0 ); |
| 268 | if( pValue->nRef==0 ){ |
| 269 | Th_Interp *interp = (Th_Interp *)pContext; |
| @@ -271,27 +273,33 @@ | |
| 271 | if( pValue->pHash ){ |
| 272 | Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext); |
| 273 | Th_HashDelete(interp, pValue->pHash); |
| 274 | } |
| 275 | Th_Free(interp, pValue); |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | /* |
| 280 | ** Argument pEntry points to an entry in the command hash table |
| 281 | ** (Th_Interp.paCmd). Delete the Th_Command structure that the |
| 282 | ** entry points to. |
| 283 | ** |
| 284 | ** Argument pContext is a pointer to the interpreter structure. |
| 285 | */ |
| 286 | static void thFreeCommand(Th_HashEntry *pEntry, void *pContext){ |
| 287 | Th_Command *pCommand = (Th_Command *)pEntry->pData; |
| 288 | if( pCommand->xDel ){ |
| 289 | pCommand->xDel((Th_Interp *)pContext, pCommand->pContext); |
| 290 | } |
| 291 | Th_Free((Th_Interp *)pContext, pEntry->pData); |
| 292 | pEntry->pData = 0; |
| 293 | } |
| 294 | |
| 295 | /* |
| 296 | ** Push a new frame onto the stack. |
| 297 | */ |
| @@ -311,19 +319,19 @@ | |
| 311 | Th_HashDelete(interp, pFrame->paVar); |
| 312 | interp->pFrame = pFrame->pCaller; |
| 313 | } |
| 314 | |
| 315 | /* |
| 316 | ** The first part of the string (zInput,nInput) contains an escape |
| 317 | ** sequence. Set *pnEscape to the number of bytes in the escape sequence. |
| 318 | ** If there is a parse error, return TH_ERROR and set the interpreter |
| 319 | ** result to an error message. Otherwise return TH_OK. |
| 320 | */ |
| 321 | static int thNextEscape( |
| 322 | Th_Interp *interp, |
| 323 | const char *zInput, |
| 324 | int nInput, |
| 325 | int *pnEscape |
| 326 | ){ |
| 327 | int i = 2; |
| 328 | |
| 329 | assert(nInput>0); |
| @@ -344,18 +352,18 @@ | |
| 344 | return TH_OK; |
| 345 | } |
| 346 | |
| 347 | /* |
| 348 | ** The first part of the string (zInput,nInput) contains a variable |
| 349 | ** reference. Set *pnVarname to the number of bytes in the variable |
| 350 | ** reference. If there is a parse error, return TH_ERROR and set the |
| 351 | ** interpreter result to an error message. Otherwise return TH_OK. |
| 352 | */ |
| 353 | int thNextVarname( |
| 354 | Th_Interp *interp, |
| 355 | const char *zInput, |
| 356 | int nInput, |
| 357 | int *pnVarname |
| 358 | ){ |
| 359 | int i; |
| 360 | |
| 361 | assert(nInput>0); |
| @@ -401,19 +409,19 @@ | |
| 401 | return TH_OK; |
| 402 | } |
| 403 | |
| 404 | /* |
| 405 | ** The first part of the string (zInput,nInput) contains a command |
| 406 | ** enclosed in a "[]" block. Set *pnCommand to the number of bytes in |
| 407 | ** the variable reference. If there is a parse error, return TH_ERROR |
| 408 | ** and set the interpreter result to an error message. Otherwise return |
| 409 | ** TH_OK. |
| 410 | */ |
| 411 | int thNextCommand( |
| 412 | Th_Interp *interp, |
| 413 | const char *zInput, |
| 414 | int nInput, |
| 415 | int *pnCommand |
| 416 | ){ |
| 417 | int nBrace = 0; |
| 418 | int nSquare = 0; |
| 419 | int i; |
| @@ -438,17 +446,17 @@ | |
| 438 | |
| 439 | return TH_OK; |
| 440 | } |
| 441 | |
| 442 | /* |
| 443 | ** Set *pnSpace to the number of whitespace bytes at the start of |
| 444 | ** input string (zInput, nInput). Always return TH_OK. |
| 445 | */ |
| 446 | int thNextSpace( |
| 447 | Th_Interp *interp, |
| 448 | const char *zInput, |
| 449 | int nInput, |
| 450 | int *pnSpace |
| 451 | ){ |
| 452 | int i; |
| 453 | for(i=0; i<nInput && th_isspace(zInput[i]); i++); |
| 454 | *pnSpace = i; |
| @@ -457,21 +465,21 @@ | |
| 457 | |
| 458 | /* |
| 459 | ** The first byte of the string (zInput,nInput) is not white-space. |
| 460 | ** Set *pnWord to the number of bytes in the th1 word that starts |
| 461 | ** with this byte. If a complete word cannot be parsed or some other |
| 462 | ** error occurs, return TH_ERROR and set the interpreter result to |
| 463 | ** an error message. Otherwise return TH_OK. |
| 464 | ** |
| 465 | ** If the isCmd argument is non-zero, then an unescaped ";" byte not |
| 466 | ** located inside of a block or quoted string is considered to mark |
| 467 | ** the end of the word. |
| 468 | */ |
| 469 | static int thNextWord( |
| 470 | Th_Interp *interp, |
| 471 | const char *zInput, |
| 472 | int nInput, |
| 473 | int *pnWord, |
| 474 | int isCmd |
| 475 | ){ |
| 476 | int iEnd = 0; |
| 477 | |
| @@ -531,12 +539,12 @@ | |
| 531 | return thEvalLocal(interp, &zWord[1], nWord-2); |
| 532 | } |
| 533 | |
| 534 | /* |
| 535 | ** The input string (zWord, nWord) contains a th1 variable reference |
| 536 | ** (a '$' byte followed by a variable name). Perform substitution on |
| 537 | ** the input string and store the resulting string in the interpreter |
| 538 | ** result. |
| 539 | */ |
| 540 | static int thSubstVarname( |
| 541 | Th_Interp *interp, |
| 542 | const char *zWord, |
| @@ -572,11 +580,11 @@ | |
| 572 | return Th_GetVar(interp, &zWord[1], nWord-1); |
| 573 | } |
| 574 | |
| 575 | /* |
| 576 | ** The input string (zWord, nWord) contains a th1 escape sequence. |
| 577 | ** Perform substitution on the input string and store the resulting |
| 578 | ** string in the interpreter result. |
| 579 | */ |
| 580 | static int thSubstEscape( |
| 581 | Th_Interp *interp, |
| 582 | const char *zWord, |
| @@ -608,11 +616,11 @@ | |
| 608 | return TH_OK; |
| 609 | } |
| 610 | |
| 611 | /* |
| 612 | ** The input string (zWord, nWord) contains a th1 word. Perform |
| 613 | ** substitution on the input string and store the resulting |
| 614 | ** string in the interpreter result. |
| 615 | */ |
| 616 | static int thSubstWord( |
| 617 | Th_Interp *interp, |
| 618 | const char *zWord, |
| @@ -640,20 +648,20 @@ | |
| 640 | int (*xGet)(Th_Interp *, const char*, int, int *) = 0; |
| 641 | int (*xSubst)(Th_Interp *, const char*, int) = 0; |
| 642 | |
| 643 | switch( zWord[i] ){ |
| 644 | case '\\': |
| 645 | xGet = thNextEscape; xSubst = thSubstEscape; |
| 646 | break; |
| 647 | case '[': |
| 648 | if( !interp->isListMode ){ |
| 649 | xGet = thNextCommand; xSubst = thSubstCommand; |
| 650 | break; |
| 651 | } |
| 652 | case '$': |
| 653 | if( !interp->isListMode ){ |
| 654 | xGet = thNextVarname; xSubst = thSubstVarname; |
| 655 | break; |
| 656 | } |
| 657 | default: { |
| 658 | thBufferWrite(interp, &output, &zWord[i], 1); |
| 659 | continue; /* Go to the next iteration of the for(...) loop */ |
| @@ -685,11 +693,11 @@ | |
| 685 | ** Return true if one of the following is true of the buffer pointed |
| 686 | ** to by zInput, length nInput: |
| 687 | ** |
| 688 | ** + It is empty, or |
| 689 | ** + It contains nothing but white-space, or |
| 690 | ** + It contains no non-white-space characters before the first |
| 691 | ** newline character. |
| 692 | ** |
| 693 | ** Otherwise return false. |
| 694 | */ |
| 695 | static int thEndOfLine(const char *zInput, int nInput){ |
| @@ -725,16 +733,16 @@ | |
| 725 | ** // Free all memory allocated by Th_SplitList(). The arrays pointed |
| 726 | ** // to by argv and argl are invalidated by this call. |
| 727 | ** // |
| 728 | ** Th_Free(interp, argv); |
| 729 | ** |
| 730 | */ |
| 731 | static int thSplitList( |
| 732 | Th_Interp *interp, /* Interpreter context */ |
| 733 | const char *zList, /* Pointer to buffer containing input list */ |
| 734 | int nList, /* Size of buffer pointed to by zList */ |
| 735 | char ***pazElem, /* OUT: Array of list elements */ |
| 736 | int **panElem, /* OUT: Lengths of each list element */ |
| 737 | int *pnCount /* OUT: Number of list elements */ |
| 738 | ){ |
| 739 | int rc = TH_OK; |
| 740 | |
| @@ -774,14 +782,14 @@ | |
| 774 | assert((lenbuf.nBuf/sizeof(int))==nCount); |
| 775 | |
| 776 | assert((pazElem && panElem) || (!pazElem && !panElem)); |
| 777 | if( pazElem && rc==TH_OK ){ |
| 778 | int i; |
| 779 | char *zElem; |
| 780 | int *anElem; |
| 781 | char **azElem = Th_Malloc(interp, |
| 782 | sizeof(char*) * nCount + /* azElem */ |
| 783 | sizeof(int) * nCount + /* anElem */ |
| 784 | strbuf.nBuf /* space for list element strings */ |
| 785 | ); |
| 786 | anElem = (int *)&azElem[nCount]; |
| 787 | zElem = (char *)&anElem[nCount]; |
| @@ -795,11 +803,11 @@ | |
| 795 | *panElem = anElem; |
| 796 | } |
| 797 | if( pnCount ){ |
| 798 | *pnCount = nCount; |
| 799 | } |
| 800 | |
| 801 | finish: |
| 802 | thBufferFree(interp, &strbuf); |
| 803 | thBufferFree(interp, &lenbuf); |
| 804 | return rc; |
| 805 | } |
| @@ -876,18 +884,18 @@ | |
| 876 | if( rc==TH_OK ){ |
| 877 | Th_Command *p = (Th_Command *)(pEntry->pData); |
| 878 | const char **azArg = (const char **)argv; |
| 879 | rc = p->xProc(interp, p->pContext, argc, azArg, argl); |
| 880 | } |
| 881 | |
| 882 | /* If an error occurred, add this command to the stack trace report. */ |
| 883 | if( rc==TH_ERROR ){ |
| 884 | char *zRes; |
| 885 | int nRes; |
| 886 | char *zStack = 0; |
| 887 | int nStack = 0; |
| 888 | |
| 889 | zRes = Th_TakeResult(interp, &nRes); |
| 890 | if( TH_OK==Th_GetVar(interp, (char *)"::th_stack_trace", -1) ){ |
| 891 | zStack = Th_TakeResult(interp, &nStack); |
| 892 | } |
| 893 | Th_ListAppend(interp, &zStack, &nStack, zFirst, zInput-zFirst); |
| @@ -912,15 +920,15 @@ | |
| 912 | ** |
| 913 | ** Argument iFrame is interpreted as follows: |
| 914 | ** |
| 915 | ** * If iFrame is 0, this means the current frame. |
| 916 | ** |
| 917 | ** * If iFrame is negative, then the nth frame up the stack, where |
| 918 | ** n is the absolute value of iFrame. A value of -1 means the |
| 919 | ** calling procedure. |
| 920 | ** |
| 921 | ** * If iFrame is +ve, then the nth frame from the bottom of the |
| 922 | ** stack. An iFrame value of 1 means the toplevel (global) frame. |
| 923 | */ |
| 924 | static Th_Frame *getFrame(Th_Interp *interp, int iFrame){ |
| 925 | Th_Frame *p = interp->pFrame; |
| 926 | int i; |
| @@ -948,28 +956,28 @@ | |
| 948 | |
| 949 | |
| 950 | /* |
| 951 | ** Evaluate th1 script (zProgram, nProgram) in the frame identified by |
| 952 | ** argument iFrame. Leave either an error message or a result in the |
| 953 | ** interpreter result and return a th1 error code (TH_OK, TH_ERROR, |
| 954 | ** TH_RETURN, TH_CONTINUE or TH_BREAK). |
| 955 | */ |
| 956 | int Th_Eval(Th_Interp *interp, int iFrame, const char *zProgram, int nProgram){ |
| 957 | int rc = TH_OK; |
| 958 | Th_Frame *pSavedFrame = interp->pFrame; |
| 959 | |
| 960 | /* Set Th_Interp.pFrame to the frame that this script is to be |
| 961 | ** evaluated in. The current frame is saved in pSavedFrame and will |
| 962 | ** be restored before this function returns. |
| 963 | */ |
| 964 | interp->pFrame = getFrame(interp, iFrame); |
| 965 | |
| 966 | if( !interp->pFrame ){ |
| 967 | rc = TH_ERROR; |
| 968 | }else{ |
| 969 | int nInput = nProgram; |
| 970 | |
| 971 | if( nInput<0 ){ |
| 972 | nInput = th_strlen(zProgram); |
| 973 | } |
| 974 | rc = thEvalLocal(interp, zProgram, nInput); |
| 975 | } |
| @@ -995,13 +1003,13 @@ | |
| 995 | ** array key name. |
| 996 | */ |
| 997 | static int thAnalyseVarname( |
| 998 | const char *zVarname, |
| 999 | int nVarname, |
| 1000 | const char **pzOuter, /* OUT: Pointer to scalar/array name */ |
| 1001 | int *pnOuter, /* OUT: Number of bytes at *pzOuter */ |
| 1002 | const char **pzInner, /* OUT: Pointer to array key (or null) */ |
| 1003 | int *pnInner, /* OUT: Number of bytes at *pzInner */ |
| 1004 | int *pisGlobal /* OUT: Set to true if this is a global ref */ |
| 1005 | ){ |
| 1006 | const char *zOuter = zVarname; |
| 1007 | int nOuter; |
| @@ -1042,13 +1050,28 @@ | |
| 1042 | *pnInner = nInner; |
| 1043 | *pisGlobal = isGlobal; |
| 1044 | return TH_OK; |
| 1045 | } |
| 1046 | |
| 1047 | /* |
| 1048 | ** Input string (zVar, nVar) contains a variable name. This function locates |
| 1049 | ** the Th_Variable structure associated with the named variable. The |
| 1050 | ** variable name may be a global or local scalar or array variable |
| 1051 | ** |
| 1052 | ** If the create argument is non-zero and the named variable does not exist |
| 1053 | ** it is created. Otherwise, an error is left in the interpreter result |
| 1054 | ** and NULL returned. |
| @@ -1055,16 +1078,19 @@ | |
| 1055 | ** |
| 1056 | ** If the arrayok argument is false and the named variable is an array, |
| 1057 | ** an error is left in the interpreter result and NULL returned. If |
| 1058 | ** arrayok is true an array name is Ok. |
| 1059 | */ |
| 1060 | static Th_Variable *thFindValue( |
| 1061 | Th_Interp *interp, |
| 1062 | const char *zVar, /* Pointer to variable name */ |
| 1063 | int nVar, /* Number of bytes at nVar */ |
| 1064 | int create, /* If true, create the variable if not found */ |
| 1065 | int arrayok /* If true, an array is Ok. Otherwise array==error */ |
| 1066 | ){ |
| 1067 | const char *zOuter; |
| 1068 | int nOuter; |
| 1069 | const char *zInner; |
| 1070 | int nInner; |
| @@ -1073,16 +1099,24 @@ | |
| 1073 | Th_HashEntry *pEntry; |
| 1074 | Th_Frame *pFrame = interp->pFrame; |
| 1075 | Th_Variable *pValue; |
| 1076 | |
| 1077 | thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal); |
| 1078 | if( isGlobal ){ |
| 1079 | while( pFrame->pCaller ) pFrame = pFrame->pCaller; |
| 1080 | } |
| 1081 | |
| 1082 | pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create); |
| 1083 | assert(pEntry || !create); |
| 1084 | if( !pEntry ){ |
| 1085 | goto no_such_var; |
| 1086 | } |
| 1087 | |
| 1088 | pValue = (Th_Variable *)pEntry->pData; |
| @@ -1093,20 +1127,26 @@ | |
| 1093 | pEntry->pData = (void *)pValue; |
| 1094 | } |
| 1095 | |
| 1096 | if( zInner ){ |
| 1097 | if( pValue->zData ){ |
| 1098 | Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter); |
| 1099 | return 0; |
| 1100 | } |
| 1101 | if( !pValue->pHash ){ |
| 1102 | if( !create ){ |
| 1103 | goto no_such_var; |
| 1104 | } |
| 1105 | pValue->pHash = Th_HashNew(interp); |
| 1106 | } |
| 1107 | pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create); |
| 1108 | if( !pEntry ){ |
| 1109 | goto no_such_var; |
| 1110 | } |
| 1111 | pValue = (Th_Variable *)pEntry->pData; |
| 1112 | if( !pValue ){ |
| @@ -1115,34 +1155,38 @@ | |
| 1115 | pValue->nRef = 1; |
| 1116 | pEntry->pData = (void *)pValue; |
| 1117 | } |
| 1118 | }else{ |
| 1119 | if( pValue->pHash && !arrayok ){ |
| 1120 | Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter); |
| 1121 | return 0; |
| 1122 | } |
| 1123 | } |
| 1124 | |
| 1125 | return pValue; |
| 1126 | |
| 1127 | no_such_var: |
| 1128 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| 1129 | return 0; |
| 1130 | } |
| 1131 | |
| 1132 | /* |
| 1133 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| 1134 | ** array member. Look up the variable, store its current value in |
| 1135 | ** the interpreter result and return TH_OK. |
| 1136 | ** |
| 1137 | ** If the named variable does not exist, return TH_ERROR and leave |
| 1138 | ** an error message in the interpreter result. |
| 1139 | */ |
| 1140 | int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1141 | Th_Variable *pValue; |
| 1142 | |
| 1143 | pValue = thFindValue(interp, zVar, nVar, 0, 0); |
| 1144 | if( !pValue ){ |
| 1145 | return TH_ERROR; |
| 1146 | } |
| 1147 | if( !pValue->zData ){ |
| 1148 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| @@ -1154,11 +1198,12 @@ | |
| 1154 | |
| 1155 | /* |
| 1156 | ** Return true if variable (zVar, nVar) exists. |
| 1157 | */ |
| 1158 | int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1159 | return thFindValue(interp, zVar, nVar, 0, 0)!=0; |
| 1160 | } |
| 1161 | |
| 1162 | /* |
| 1163 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| 1164 | ** array member. If the variable does not exist it is created. The |
| @@ -1166,19 +1211,19 @@ | |
| 1166 | ** |
| 1167 | ** If (zVar, nVar) refers to an existing array, TH_ERROR is returned |
| 1168 | ** and an error message left in the interpreter result. |
| 1169 | */ |
| 1170 | int Th_SetVar( |
| 1171 | Th_Interp *interp, |
| 1172 | const char *zVar, |
| 1173 | int nVar, |
| 1174 | const char *zValue, |
| 1175 | int nValue |
| 1176 | ){ |
| 1177 | Th_Variable *pValue; |
| 1178 | |
| 1179 | pValue = thFindValue(interp, zVar, nVar, 1, 0); |
| 1180 | if( !pValue ){ |
| 1181 | return TH_ERROR; |
| 1182 | } |
| 1183 | |
| 1184 | if( nValue<0 ){ |
| @@ -1202,13 +1247,13 @@ | |
| 1202 | ** Create a variable link so that accessing variable (zLocal, nLocal) is |
| 1203 | ** the same as accessing variable (zLink, nLink) in stack frame iFrame. |
| 1204 | */ |
| 1205 | int Th_LinkVar( |
| 1206 | Th_Interp *interp, /* Interpreter */ |
| 1207 | const char *zLocal, int nLocal, /* Local varname */ |
| 1208 | int iFrame, /* Stack frame of linked var */ |
| 1209 | const char *zLink, int nLink /* Linked varname */ |
| 1210 | ){ |
| 1211 | Th_Frame *pSavedFrame = interp->pFrame; |
| 1212 | Th_Frame *pFrame; |
| 1213 | Th_HashEntry *pEntry; |
| 1214 | Th_Variable *pValue; |
| @@ -1217,11 +1262,11 @@ | |
| 1217 | if( !pFrame ){ |
| 1218 | return TH_ERROR; |
| 1219 | } |
| 1220 | pSavedFrame = interp->pFrame; |
| 1221 | interp->pFrame = pFrame; |
| 1222 | pValue = thFindValue(interp, zLink, nLink, 1, 1); |
| 1223 | interp->pFrame = pSavedFrame; |
| 1224 | |
| 1225 | pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1); |
| 1226 | if( pEntry->pData ){ |
| 1227 | Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal); |
| @@ -1238,25 +1283,68 @@ | |
| 1238 | ** an array, or an array member. If the identified variable exists, it |
| 1239 | ** is deleted and TH_OK returned. Otherwise, an error message is left |
| 1240 | ** in the interpreter result and TH_ERROR is returned. |
| 1241 | */ |
| 1242 | int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1243 | Th_Variable *pValue; |
| 1244 | |
| 1245 | pValue = thFindValue(interp, zVar, nVar, 1, 1); |
| 1246 | if( !pValue ){ |
| 1247 | return TH_ERROR; |
| 1248 | } |
| 1249 | |
| 1250 | Th_Free(interp, pValue->zData); |
| 1251 | pValue->zData = 0; |
| 1252 | if( pValue->pHash ){ |
| 1253 | Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp); |
| 1254 | Th_HashDelete(interp, pValue->pHash); |
| 1255 | pValue->pHash = 0; |
| 1256 | } |
| 1257 | return TH_OK; |
| 1258 | } |
| 1259 | |
| 1260 | /* |
| 1261 | ** Return an allocated buffer containing a copy of string (z, n). The |
| 1262 | ** caller is responsible for eventually calling Th_Free() to free |
| @@ -1291,11 +1379,11 @@ | |
| 1291 | if( interp ){ |
| 1292 | char *zRes = 0; |
| 1293 | int nRes = 0; |
| 1294 | |
| 1295 | Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0); |
| 1296 | |
| 1297 | Th_StringAppend(interp, &zRes, &nRes, zPre, -1); |
| 1298 | if( zRes[nRes-1]=='"' ){ |
| 1299 | Th_StringAppend(interp, &zRes, &nRes, z, n); |
| 1300 | Th_StringAppend(interp, &zRes, &nRes, (const char *)"\"", 1); |
| 1301 | }else{ |
| @@ -1373,12 +1461,12 @@ | |
| 1373 | return (char *)Th_Malloc(pInterp, 1); |
| 1374 | } |
| 1375 | } |
| 1376 | |
| 1377 | |
| 1378 | /* |
| 1379 | ** Wrappers around the supplied malloc() and free() |
| 1380 | */ |
| 1381 | void *Th_Malloc(Th_Interp *pInterp, int nByte){ |
| 1382 | void *p = pInterp->pVtab->xMalloc(nByte); |
| 1383 | if( p ){ |
| 1384 | memset(p, 0, nByte); |
| @@ -1390,16 +1478,16 @@ | |
| 1390 | pInterp->pVtab->xFree(z); |
| 1391 | } |
| 1392 | } |
| 1393 | |
| 1394 | /* |
| 1395 | ** Install a new th1 command. |
| 1396 | ** |
| 1397 | ** If a command of the same name already exists, it is deleted automatically. |
| 1398 | */ |
| 1399 | int Th_CreateCommand( |
| 1400 | Th_Interp *interp, |
| 1401 | const char *zName, /* New command name */ |
| 1402 | Th_CommandProc xProc, /* Command callback proc */ |
| 1403 | void *pContext, /* Value to pass as second arg to xProc */ |
| 1404 | void (*xDel)(Th_Interp *, void *) /* Command destructor callback */ |
| 1405 | ){ |
| @@ -1417,27 +1505,27 @@ | |
| 1417 | } |
| 1418 | pCommand->xProc = xProc; |
| 1419 | pCommand->pContext = pContext; |
| 1420 | pCommand->xDel = xDel; |
| 1421 | pEntry->pData = (void *)pCommand; |
| 1422 | |
| 1423 | return TH_OK; |
| 1424 | } |
| 1425 | |
| 1426 | /* |
| 1427 | ** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0, |
| 1428 | ** the command is deleted instead of renamed. |
| 1429 | ** |
| 1430 | ** If successful, TH_OK is returned. If command zName does not exist, or |
| 1431 | ** if command zNew already exists, an error message is left in the |
| 1432 | ** interpreter result and TH_ERROR is returned. |
| 1433 | */ |
| 1434 | int Th_RenameCommand( |
| 1435 | Th_Interp *interp, |
| 1436 | const char *zName, /* Existing command name */ |
| 1437 | int nName, /* Number of bytes at zName */ |
| 1438 | const char *zNew, /* New command name */ |
| 1439 | int nNew /* Number of bytes at zNew */ |
| 1440 | ){ |
| 1441 | Th_HashEntry *pEntry; |
| 1442 | Th_HashEntry *pNewEntry; |
| 1443 | |
| @@ -1491,11 +1579,11 @@ | |
| 1491 | ** If an error occurs (if (zList, nList) is not a valid list) an error |
| 1492 | ** message is left in the interpreter result and TH_ERROR returned. |
| 1493 | ** |
| 1494 | ** If successful, *pnCount is set to the number of elements in the list. |
| 1495 | ** panElem is set to point at an array of *pnCount integers - the lengths |
| 1496 | ** of the element values. *pazElem is set to point at an array of |
| 1497 | ** pointers to buffers containing the array element's data. |
| 1498 | ** |
| 1499 | ** To free the arrays allocated at *pazElem and *panElem, the caller |
| 1500 | ** should call Th_Free() on *pazElem only. Exactly one such call to |
| 1501 | ** Th_Free() must be made per call to Th_SplitList(). |
| @@ -1517,13 +1605,13 @@ | |
| 1517 | ** Th_Free(interp, azElem); |
| 1518 | ** |
| 1519 | */ |
| 1520 | int Th_SplitList( |
| 1521 | Th_Interp *interp, |
| 1522 | const char *zList, /* Pointer to buffer containing list */ |
| 1523 | int nList, /* Number of bytes at zList */ |
| 1524 | char ***pazElem, /* OUT: Array of pointers to element data */ |
| 1525 | int **panElem, /* OUT: Array of element data lengths */ |
| 1526 | int *pnCount /* OUT: Number of elements in list */ |
| 1527 | ){ |
| 1528 | int rc; |
| 1529 | interp->isListMode = 1; |
| @@ -1534,16 +1622,16 @@ | |
| 1534 | } |
| 1535 | return rc; |
| 1536 | } |
| 1537 | |
| 1538 | /* |
| 1539 | ** Append a new element to an existing th1 list. The element to append |
| 1540 | ** to the list is (zElem, nElem). |
| 1541 | ** |
| 1542 | ** A pointer to the existing list must be stored at *pzList when this |
| 1543 | ** function is called. The length must be stored in *pnList. The value |
| 1544 | ** of *pzList must either be NULL (in which case *pnList must be 0), or |
| 1545 | ** a pointer to memory obtained from Th_Malloc(). |
| 1546 | ** |
| 1547 | ** This function calls Th_Free() to free the buffer at *pzList and sets |
| 1548 | ** *pzList to point to a new buffer containing the new list value. *pnList |
| 1549 | ** is similarly updated before returning. The return value is always TH_OK. |
| @@ -1560,13 +1648,13 @@ | |
| 1560 | ** Th_Free(interp, zList); |
| 1561 | ** |
| 1562 | */ |
| 1563 | int Th_ListAppend( |
| 1564 | Th_Interp *interp, /* Interpreter context */ |
| 1565 | char **pzList, /* IN/OUT: Ptr to ptr to list */ |
| 1566 | int *pnList, /* IN/OUT: Current length of *pzList */ |
| 1567 | const char *zElem, /* Data to append */ |
| 1568 | int nElem /* Length of nElem */ |
| 1569 | ){ |
| 1570 | Buffer output; |
| 1571 | int i; |
| 1572 | |
| @@ -1615,13 +1703,13 @@ | |
| 1615 | ** Append a new element to an existing th1 string. This function uses |
| 1616 | ** the same interface as the Th_ListAppend() function. |
| 1617 | */ |
| 1618 | int Th_StringAppend( |
| 1619 | Th_Interp *interp, /* Interpreter context */ |
| 1620 | char **pzStr, /* IN/OUT: Ptr to ptr to list */ |
| 1621 | int *pnStr, /* IN/OUT: Current length of *pzStr */ |
| 1622 | const char *zElem, /* Data to append */ |
| 1623 | int nElem /* Length of nElem */ |
| 1624 | ){ |
| 1625 | char *zNew; |
| 1626 | int nNew; |
| 1627 | |
| @@ -1639,11 +1727,11 @@ | |
| 1639 | *pnStr = nNew; |
| 1640 | |
| 1641 | return TH_OK; |
| 1642 | } |
| 1643 | |
| 1644 | /* |
| 1645 | ** Delete an interpreter. |
| 1646 | */ |
| 1647 | void Th_DeleteInterp(Th_Interp *interp){ |
| 1648 | assert(interp->pFrame); |
| 1649 | assert(0==interp->pFrame->pCaller); |
| @@ -1660,11 +1748,11 @@ | |
| 1660 | |
| 1661 | /* Delete the interpreter structure itself. */ |
| 1662 | Th_Free(interp, (void *)interp); |
| 1663 | } |
| 1664 | |
| 1665 | /* |
| 1666 | ** Create a new interpreter. |
| 1667 | */ |
| 1668 | Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){ |
| 1669 | Th_Interp *p; |
| 1670 | |
| @@ -1694,11 +1782,11 @@ | |
| 1694 | Operator *pOp; |
| 1695 | Expr *pParent; |
| 1696 | Expr *pLeft; |
| 1697 | Expr *pRight; |
| 1698 | |
| 1699 | char *zValue; /* Pointer to literal value */ |
| 1700 | int nValue; /* Length of literal value buffer */ |
| 1701 | }; |
| 1702 | |
| 1703 | /* Unary operators */ |
| 1704 | #define OP_UNARY_MINUS 2 |
| @@ -1750,11 +1838,11 @@ | |
| 1750 | {"+", OP_UNARY_PLUS, 1, ARG_NUMBER}, |
| 1751 | {"~", OP_BITWISE_NOT, 1, ARG_INTEGER}, |
| 1752 | {"!", OP_LOGICAL_NOT, 1, ARG_INTEGER}, |
| 1753 | |
| 1754 | /* Binary operators. It is important to the parsing in Th_Expr() that |
| 1755 | * the two-character symbols ("==") appear before the one-character |
| 1756 | * ones ("="). And that the priorities of all binary operators are |
| 1757 | * integers between 2 and 12. |
| 1758 | */ |
| 1759 | {"<<", OP_LEFTSHIFT, 4, ARG_INTEGER}, |
| 1760 | {">>", OP_RIGHTSHIFT, 4, ARG_INTEGER}, |
| @@ -1781,16 +1869,16 @@ | |
| 1781 | {0,0,0,0} |
| 1782 | }; |
| 1783 | |
| 1784 | /* |
| 1785 | ** The first part of the string (zInput,nInput) contains a number. |
| 1786 | ** Set *pnVarname to the number of bytes in the numeric string. |
| 1787 | */ |
| 1788 | static int thNextNumber( |
| 1789 | Th_Interp *interp, |
| 1790 | const char *zInput, |
| 1791 | int nInput, |
| 1792 | int *pnLiteral |
| 1793 | ){ |
| 1794 | int i; |
| 1795 | int seenDot = 0; |
| 1796 | for(i=0; i<nInput; i++){ |
| @@ -1856,11 +1944,11 @@ | |
| 1856 | if( eArgType==ARG_NUMBER ){ |
| 1857 | if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft)) |
| 1858 | && (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight)) |
| 1859 | ){ |
| 1860 | eArgType = ARG_INTEGER; |
| 1861 | }else if( |
| 1862 | (zLeft && TH_OK!=Th_ToDouble(interp, zLeft, nLeft, &fLeft)) || |
| 1863 | (zRight && TH_OK!=Th_ToDouble(interp, zRight, nRight, &fRight)) |
| 1864 | ){ |
| 1865 | /* A type error. */ |
| 1866 | rc = TH_ERROR; |
| @@ -1868,28 +1956,30 @@ | |
| 1868 | }else if( eArgType==ARG_INTEGER ){ |
| 1869 | rc = Th_ToInt(interp, zLeft, nLeft, &iLeft); |
| 1870 | if( rc==TH_OK && zRight ){ |
| 1871 | rc = Th_ToInt(interp, zRight, nRight, &iRight); |
| 1872 | } |
| 1873 | } |
| 1874 | } |
| 1875 | |
| 1876 | if( rc==TH_OK && eArgType==ARG_INTEGER ){ |
| 1877 | int iRes = 0; |
| 1878 | switch( pExpr->pOp->eOp ) { |
| 1879 | case OP_MULTIPLY: iRes = iLeft*iRight; break; |
| 1880 | case OP_DIVIDE: |
| 1881 | if(!iRight){ |
| 1882 | Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft); |
| 1883 | return TH_ERROR; |
| 1884 | } |
| 1885 | iRes = iLeft/iRight; |
| 1886 | break; |
| 1887 | case OP_MODULUS: |
| 1888 | if(!iRight){ |
| 1889 | Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft); |
| 1890 | return TH_ERROR; |
| 1891 | } |
| 1892 | iRes = iLeft%iRight; |
| 1893 | break; |
| 1894 | case OP_ADD: iRes = iLeft+iRight; break; |
| 1895 | case OP_SUBTRACT: iRes = iLeft-iRight; break; |
| @@ -1913,11 +2003,18 @@ | |
| 1913 | } |
| 1914 | Th_SetResultInt(interp, iRes); |
| 1915 | }else if( rc==TH_OK && eArgType==ARG_NUMBER ){ |
| 1916 | switch( pExpr->pOp->eOp ) { |
| 1917 | case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break; |
| 1918 | case OP_DIVIDE: Th_SetResultDouble(interp, fLeft/fRight); break; |
| 1919 | case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break; |
| 1920 | case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break; |
| 1921 | case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break; |
| 1922 | case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break; |
| 1923 | case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break; |
| @@ -1936,10 +2033,12 @@ | |
| 1936 | case OP_SEQ: Th_SetResultInt(interp, iEqual); break; |
| 1937 | case OP_SNE: Th_SetResultInt(interp, !iEqual); break; |
| 1938 | default: assert(!"Internal error"); |
| 1939 | } |
| 1940 | } |
| 1941 | |
| 1942 | Th_Free(interp, zLeft); |
| 1943 | Th_Free(interp, zRight); |
| 1944 | } |
| 1945 | |
| @@ -1959,11 +2058,11 @@ | |
| 1959 | #define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft)) |
| 1960 | |
| 1961 | for(jj=0; jj<nToken; jj++){ |
| 1962 | if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){ |
| 1963 | int nNest = 1; |
| 1964 | int iLeft = jj; |
| 1965 | |
| 1966 | for(jj++; jj<nToken; jj++){ |
| 1967 | Operator *pOp = apToken[jj]->pOp; |
| 1968 | if( pOp && pOp->eOp==OP_OPEN_BRACKET ) nNest++; |
| 1969 | if( pOp && pOp->eOp==OP_CLOSE_BRACKET ) nNest--; |
| @@ -2033,11 +2132,11 @@ | |
| 2033 | /* |
| 2034 | ** Parse a string containing a TH expression to a list of tokens. |
| 2035 | */ |
| 2036 | static int exprParse( |
| 2037 | Th_Interp *interp, /* Interpreter to leave error message in */ |
| 2038 | const char *zExpr, /* Pointer to input string */ |
| 2039 | int nExpr, /* Number of bytes at zExpr */ |
| 2040 | Expr ***papToken, /* OUT: Array of tokens. */ |
| 2041 | int *pnToken /* OUT: Size of token array */ |
| 2042 | ){ |
| 2043 | int i; |
| @@ -2108,11 +2207,11 @@ | |
| 2108 | memcpy(pNew->zValue, z, pNew->nValue); |
| 2109 | i += pNew->nValue; |
| 2110 | } |
| 2111 | if( (nToken%16)==0 ){ |
| 2112 | /* Grow the apToken array. */ |
| 2113 | Expr **apTokenOld = apToken; |
| 2114 | apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16)); |
| 2115 | memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken); |
| 2116 | } |
| 2117 | |
| 2118 | /* Put the new token at the end of the apToken array */ |
| @@ -2133,11 +2232,11 @@ | |
| 2133 | /* |
| 2134 | ** Evaluate the string (zExpr, nExpr) as a Th expression. Store |
| 2135 | ** the result in the interpreter interp and return TH_OK if |
| 2136 | ** successful. If an error occurs, store an error message in |
| 2137 | ** the interpreter result and return an error code. |
| 2138 | */ |
| 2139 | int Th_Expr(Th_Interp *interp, const char *zExpr, int nExpr){ |
| 2140 | int rc; /* Return Code */ |
| 2141 | int i; /* Loop counter */ |
| 2142 | |
| 2143 | int nToken = 0; |
| @@ -2150,11 +2249,11 @@ | |
| 2150 | /* Parse the expression to a list of tokens. */ |
| 2151 | rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken); |
| 2152 | |
| 2153 | /* If the parsing was successful, create an expression tree from |
| 2154 | ** the parsed list of tokens. If successful, apToken[0] is set |
| 2155 | ** to point to the root of the expression tree. |
| 2156 | */ |
| 2157 | if( rc==TH_OK ){ |
| 2158 | rc = exprMakeTree(interp, apToken, nToken); |
| 2159 | } |
| 2160 | |
| @@ -2188,16 +2287,17 @@ | |
| 2188 | |
| 2189 | /* |
| 2190 | ** Iterate through all values currently stored in the hash table. Invoke |
| 2191 | ** the callback function xCallback for each entry. The second argument |
| 2192 | ** passed to xCallback is a copy of the fourth argument passed to this |
| 2193 | ** function. |
| 2194 | */ |
| 2195 | void Th_HashIterate( |
| 2196 | Th_Interp *interp, |
| 2197 | Th_Hash *pHash, |
| 2198 | void (*xCallback)(Th_HashEntry *pEntry, void *pContext), |
| 2199 | void *pContext |
| 2200 | ){ |
| 2201 | int i; |
| 2202 | for(i=0; i<TH_HASHSIZE; i++){ |
| 2203 | Th_HashEntry *pEntry; |
| @@ -2208,14 +2308,15 @@ | |
| 2208 | } |
| 2209 | } |
| 2210 | } |
| 2211 | |
| 2212 | /* |
| 2213 | ** Helper function for Th_HashDelete(). |
| 2214 | */ |
| 2215 | static void xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){ |
| 2216 | Th_Free((Th_Interp *)pContext, (void *)pEntry); |
| 2217 | } |
| 2218 | |
| 2219 | /* |
| 2220 | ** Free a hash-table previously allocated by Th_HashNew(). |
| 2221 | */ |
| @@ -2225,14 +2326,14 @@ | |
| 2225 | Th_Free(interp, pHash); |
| 2226 | } |
| 2227 | } |
| 2228 | |
| 2229 | /* |
| 2230 | ** This function is used to insert or delete hash table items, or to |
| 2231 | ** query a hash table for an existing item. |
| 2232 | ** |
| 2233 | ** If parameter op is less than zero, then the hash-table element |
| 2234 | ** identified by (zKey, nKey) is removed from the hash-table if it |
| 2235 | ** exists. NULL is returned. |
| 2236 | ** |
| 2237 | ** Otherwise, if the hash-table contains an item with key (zKey, nKey), |
| 2238 | ** a pointer to the associated Th_HashEntry is returned. If parameter |
| @@ -2239,11 +2340,11 @@ | |
| 2239 | ** op is greater than zero, then a new entry is added if one cannot |
| 2240 | ** be found. If op is zero, then NULL is returned if the item is |
| 2241 | ** not already present in the hash-table. |
| 2242 | */ |
| 2243 | Th_HashEntry *Th_HashFind( |
| 2244 | Th_Interp *interp, |
| 2245 | Th_Hash *pHash, |
| 2246 | const char *zKey, |
| 2247 | int nKey, |
| 2248 | int op /* -ve = delete, 0 = find, +ve = insert */ |
| 2249 | ){ |
| @@ -2307,11 +2408,11 @@ | |
| 2307 | ** '\f' 0x0C |
| 2308 | ** '\r' 0x0D |
| 2309 | ** |
| 2310 | ** Whitespace characters have the 0x01 flag set. Decimal digits have the |
| 2311 | ** 0x2 flag set. Single byte printable characters have the 0x4 flag set. |
| 2312 | ** Alphabet characters have the 0x8 bit set. |
| 2313 | ** |
| 2314 | ** The special list characters have the 0x10 flag set |
| 2315 | ** |
| 2316 | ** { } [ ] \ ; ' " |
| 2317 | ** |
| @@ -2458,14 +2559,14 @@ | |
| 2458 | return z - zBegin; |
| 2459 | } |
| 2460 | |
| 2461 | /* |
| 2462 | ** Try to convert the string passed as arguments (z, n) to an integer. |
| 2463 | ** If successful, store the result in *piOut and return TH_OK. |
| 2464 | ** |
| 2465 | ** If the string cannot be converted to an integer, return TH_ERROR. |
| 2466 | ** If the interp argument is not NULL, leave an error message in the |
| 2467 | ** interpreter result too. |
| 2468 | */ |
| 2469 | int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){ |
| 2470 | int i = 0; |
| 2471 | int iOut = 0; |
| @@ -2493,20 +2594,20 @@ | |
| 2493 | return TH_OK; |
| 2494 | } |
| 2495 | |
| 2496 | /* |
| 2497 | ** Try to convert the string passed as arguments (z, n) to a double. |
| 2498 | ** If successful, store the result in *pfOut and return TH_OK. |
| 2499 | ** |
| 2500 | ** If the string cannot be converted to a double, return TH_ERROR. |
| 2501 | ** If the interp argument is not NULL, leave an error message in the |
| 2502 | ** interpreter result too. |
| 2503 | */ |
| 2504 | int Th_ToDouble( |
| 2505 | Th_Interp *interp, |
| 2506 | const char *z, |
| 2507 | int n, |
| 2508 | double *pfOut |
| 2509 | ){ |
| 2510 | if( !sqlite3IsNumber((const char *)z, 0) ){ |
| 2511 | Th_ErrorMessage(interp, "expected number, got: \"", z, n); |
| 2512 | return TH_ERROR; |
| @@ -2547,33 +2648,33 @@ | |
| 2547 | ** the double fVal and return TH_OK. |
| 2548 | */ |
| 2549 | int Th_SetResultDouble(Th_Interp *interp, double fVal){ |
| 2550 | int i; /* Iterator variable */ |
| 2551 | double v = fVal; /* Input value */ |
| 2552 | char zBuf[128]; /* Output buffer */ |
| 2553 | char *z = zBuf; /* Output cursor */ |
| 2554 | int iDot = 0; /* Digit after which to place decimal point */ |
| 2555 | int iExp = 0; /* Exponent (NN in eNN) */ |
| 2556 | const char *zExp; /* String representation of iExp */ |
| 2557 | |
| 2558 | /* Precision: */ |
| 2559 | #define INSIGNIFICANT 0.000000000001 |
| 2560 | #define ROUNDER 0.0000000000005 |
| 2561 | double insignificant = INSIGNIFICANT; |
| 2562 | |
| 2563 | /* If the real value is negative, write a '-' character to the |
| 2564 | * output and transform v to the corresponding positive number. |
| 2565 | */ |
| 2566 | if( v<0.0 ){ |
| 2567 | *z++ = '-'; |
| 2568 | v *= -1.0; |
| 2569 | } |
| 2570 | |
| 2571 | /* Normalize v to a value between 1.0 and 10.0. Integer |
| 2572 | * variable iExp is set to the exponent. i.e the original |
| 2573 | * value is (v * 10^iExp) (or the negative thereof). |
| 2574 | */ |
| 2575 | if( v>0.0 ){ |
| 2576 | while( (v+ROUNDER)>=10.0 ) { iExp++; v *= 0.1; } |
| 2577 | while( (v+ROUNDER)<1.0 ) { iExp--; v *= 10.0; } |
| 2578 | } |
| 2579 | v += ROUNDER; |
| 2580 |
| --- src/th.c | |
| +++ src/th.c | |
| @@ -1,8 +1,8 @@ | |
| 1 | |
| 2 | /* |
| 3 | ** The implementation of the TH core. This file contains the parser, and |
| 4 | ** the implementation of the interface in th.h. |
| 5 | */ |
| 6 | |
| 7 | #include "config.h" |
| 8 | #include "th.h" |
| @@ -16,11 +16,11 @@ | |
| 16 | /* |
| 17 | ** Interpreter structure. |
| 18 | */ |
| 19 | struct Th_Interp { |
| 20 | Th_Vtab *pVtab; /* Copy of the argument passed to Th_CreateInterp() */ |
| 21 | char *zResult; /* Current interpreter result (Th_Malloc()ed) */ |
| 22 | int nResult; /* number of bytes in zResult */ |
| 23 | Th_Hash *paCmd; /* Table of registered commands */ |
| 24 | Th_Frame *pFrame; /* Current execution frame */ |
| 25 | int isListMode; /* True if thSplitList() should operate in "list" mode */ |
| 26 | }; |
| @@ -42,25 +42,25 @@ | |
| 42 | ** are stored in the Th_Frame.paVar hash table member of the associated |
| 43 | ** stack frame object. |
| 44 | ** |
| 45 | ** When an interpreter is created, a single Th_Frame structure is also |
| 46 | ** allocated - the global variable scope. Th_Interp.pFrame (the current |
| 47 | ** interpreter frame) is initialised to point to this Th_Frame. It is |
| 48 | ** not deleted for the lifetime of the interpreter (because the global |
| 49 | ** frame never goes out of scope). |
| 50 | ** |
| 51 | ** New stack frames are created by the Th_InFrame() function. Before |
| 52 | ** invoking its callback function, Th_InFrame() allocates a new Th_Frame |
| 53 | ** structure with pCaller set to the current frame (Th_Interp.pFrame), |
| 54 | ** and sets the current frame to the new frame object. After the callback |
| 55 | ** has been invoked, the allocated Th_Frame is deleted and the value |
| 56 | ** of the current frame pointer restored. |
| 57 | ** |
| 58 | ** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions |
| 59 | ** access variable values in the current frame. If they need to access |
| 60 | ** the global frame, they do so by traversing the pCaller pointer list. |
| 61 | ** Likewise, the Th_LinkVar() function uses the pCaller pointers to |
| 62 | ** link to variables located in the global or other stack frames. |
| 63 | */ |
| 64 | struct Th_Frame { |
| 65 | Th_Hash *paVar; /* Variables defined in this scope */ |
| 66 | Th_Frame *pCaller; /* Calling frame */ |
| @@ -84,11 +84,11 @@ | |
| 84 | ** value. |
| 85 | */ |
| 86 | struct Th_Variable { |
| 87 | int nRef; /* Number of references to this structure */ |
| 88 | int nData; /* Number of bytes at Th_Variable.zData */ |
| 89 | char *zData; /* Data for scalar variables */ |
| 90 | Th_Hash *pHash; /* Data for array variables */ |
| 91 | }; |
| 92 | |
| 93 | /* |
| 94 | ** Hash table API: |
| @@ -105,24 +105,24 @@ | |
| 105 | static int thEndOfLine(const char *, int); |
| 106 | |
| 107 | static int thPushFrame(Th_Interp*, Th_Frame*); |
| 108 | static void thPopFrame(Th_Interp*); |
| 109 | |
| 110 | static int thFreeVariable(Th_HashEntry*, void*); |
| 111 | static int thFreeCommand(Th_HashEntry*, void*); |
| 112 | |
| 113 | /* |
| 114 | ** The following are used by both the expression and language parsers. |
| 115 | ** Given that the start of the input string (z, n) is a language |
| 116 | ** construct of the relevant type (a command enclosed in [], an escape |
| 117 | ** sequence etc.), these functions determine the number of bytes |
| 118 | ** of the input consumed by the construct. For example: |
| 119 | ** |
| 120 | ** int nByte; |
| 121 | ** thNextCommand(interp, "[expr $a+1] $nIter", 18, &nByte); |
| 122 | ** |
| 123 | ** results in variable nByte being set to 11. Or, |
| 124 | ** |
| 125 | ** thNextVarname(interp, "$a+1", 4, &nByte); |
| 126 | ** |
| 127 | ** results in nByte being set to 2. |
| 128 | */ |
| @@ -132,24 +132,24 @@ | |
| 132 | static int thNextNumber (Th_Interp*, const char *z, int n, int *pN); |
| 133 | static int thNextSpace (Th_Interp*, const char *z, int n, int *pN); |
| 134 | |
| 135 | /* |
| 136 | ** Given that the input string (z, n) contains a language construct of |
| 137 | ** the relevant type (a command enclosed in [], an escape sequence |
| 138 | ** like "\xFF" or a variable reference like "${varname}", perform |
| 139 | ** substitution on the string and store the resulting string in |
| 140 | ** the interpreter result. |
| 141 | */ |
| 142 | static int thSubstCommand(Th_Interp*, const char *z, int n); |
| 143 | static int thSubstEscape (Th_Interp*, const char *z, int n); |
| 144 | static int thSubstVarname(Th_Interp*, const char *z, int n); |
| 145 | |
| 146 | /* |
| 147 | ** Given that there is a th1 word located at the start of the input |
| 148 | ** string (z, n), determine the length in bytes of that word. If the |
| 149 | ** isCmd argument is non-zero, then an unescaped ";" byte not |
| 150 | ** located inside of a block or quoted string is considered to mark |
| 151 | ** the end of the word. |
| 152 | */ |
| 153 | static int thNextWord(Th_Interp*, const char *z, int n, int *pN, int isCmd); |
| 154 | |
| 155 | /* |
| @@ -176,13 +176,13 @@ | |
| 176 | ** Append nAdd bytes of content copied from zAdd to the end of buffer |
| 177 | ** pBuffer. If there is not enough space currently allocated, resize |
| 178 | ** the allocation to make space. |
| 179 | */ |
| 180 | static int thBufferWrite( |
| 181 | Th_Interp *interp, |
| 182 | Buffer *pBuffer, |
| 183 | const char *zAdd, |
| 184 | int nAdd |
| 185 | ){ |
| 186 | int nReq; |
| 187 | |
| 188 | if( nAdd<0 ){ |
| @@ -258,12 +258,14 @@ | |
| 258 | ** (Th_Frame.paVar). Decrement the reference count of the Th_Variable |
| 259 | ** structure that the entry points to. Free the Th_Variable if its |
| 260 | ** reference count reaches 0. |
| 261 | ** |
| 262 | ** Argument pContext is a pointer to the interpreter structure. |
| 263 | ** |
| 264 | ** Returns non-zero if the Th_Variable was actually freed. |
| 265 | */ |
| 266 | static int thFreeVariable(Th_HashEntry *pEntry, void *pContext){ |
| 267 | Th_Variable *pValue = (Th_Variable *)pEntry->pData; |
| 268 | pValue->nRef--; |
| 269 | assert( pValue->nRef>=0 ); |
| 270 | if( pValue->nRef==0 ){ |
| 271 | Th_Interp *interp = (Th_Interp *)pContext; |
| @@ -271,27 +273,33 @@ | |
| 273 | if( pValue->pHash ){ |
| 274 | Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext); |
| 275 | Th_HashDelete(interp, pValue->pHash); |
| 276 | } |
| 277 | Th_Free(interp, pValue); |
| 278 | pEntry->pData = 0; |
| 279 | return 1; |
| 280 | } |
| 281 | return 0; |
| 282 | } |
| 283 | |
| 284 | /* |
| 285 | ** Argument pEntry points to an entry in the command hash table |
| 286 | ** (Th_Interp.paCmd). Delete the Th_Command structure that the |
| 287 | ** entry points to. |
| 288 | ** |
| 289 | ** Argument pContext is a pointer to the interpreter structure. |
| 290 | ** |
| 291 | ** Always returns non-zero. |
| 292 | */ |
| 293 | static int thFreeCommand(Th_HashEntry *pEntry, void *pContext){ |
| 294 | Th_Command *pCommand = (Th_Command *)pEntry->pData; |
| 295 | if( pCommand->xDel ){ |
| 296 | pCommand->xDel((Th_Interp *)pContext, pCommand->pContext); |
| 297 | } |
| 298 | Th_Free((Th_Interp *)pContext, pEntry->pData); |
| 299 | pEntry->pData = 0; |
| 300 | return 1; |
| 301 | } |
| 302 | |
| 303 | /* |
| 304 | ** Push a new frame onto the stack. |
| 305 | */ |
| @@ -311,19 +319,19 @@ | |
| 319 | Th_HashDelete(interp, pFrame->paVar); |
| 320 | interp->pFrame = pFrame->pCaller; |
| 321 | } |
| 322 | |
| 323 | /* |
| 324 | ** The first part of the string (zInput,nInput) contains an escape |
| 325 | ** sequence. Set *pnEscape to the number of bytes in the escape sequence. |
| 326 | ** If there is a parse error, return TH_ERROR and set the interpreter |
| 327 | ** result to an error message. Otherwise return TH_OK. |
| 328 | */ |
| 329 | static int thNextEscape( |
| 330 | Th_Interp *interp, |
| 331 | const char *zInput, |
| 332 | int nInput, |
| 333 | int *pnEscape |
| 334 | ){ |
| 335 | int i = 2; |
| 336 | |
| 337 | assert(nInput>0); |
| @@ -344,18 +352,18 @@ | |
| 352 | return TH_OK; |
| 353 | } |
| 354 | |
| 355 | /* |
| 356 | ** The first part of the string (zInput,nInput) contains a variable |
| 357 | ** reference. Set *pnVarname to the number of bytes in the variable |
| 358 | ** reference. If there is a parse error, return TH_ERROR and set the |
| 359 | ** interpreter result to an error message. Otherwise return TH_OK. |
| 360 | */ |
| 361 | int thNextVarname( |
| 362 | Th_Interp *interp, |
| 363 | const char *zInput, |
| 364 | int nInput, |
| 365 | int *pnVarname |
| 366 | ){ |
| 367 | int i; |
| 368 | |
| 369 | assert(nInput>0); |
| @@ -401,19 +409,19 @@ | |
| 409 | return TH_OK; |
| 410 | } |
| 411 | |
| 412 | /* |
| 413 | ** The first part of the string (zInput,nInput) contains a command |
| 414 | ** enclosed in a "[]" block. Set *pnCommand to the number of bytes in |
| 415 | ** the variable reference. If there is a parse error, return TH_ERROR |
| 416 | ** and set the interpreter result to an error message. Otherwise return |
| 417 | ** TH_OK. |
| 418 | */ |
| 419 | int thNextCommand( |
| 420 | Th_Interp *interp, |
| 421 | const char *zInput, |
| 422 | int nInput, |
| 423 | int *pnCommand |
| 424 | ){ |
| 425 | int nBrace = 0; |
| 426 | int nSquare = 0; |
| 427 | int i; |
| @@ -438,17 +446,17 @@ | |
| 446 | |
| 447 | return TH_OK; |
| 448 | } |
| 449 | |
| 450 | /* |
| 451 | ** Set *pnSpace to the number of whitespace bytes at the start of |
| 452 | ** input string (zInput, nInput). Always return TH_OK. |
| 453 | */ |
| 454 | int thNextSpace( |
| 455 | Th_Interp *interp, |
| 456 | const char *zInput, |
| 457 | int nInput, |
| 458 | int *pnSpace |
| 459 | ){ |
| 460 | int i; |
| 461 | for(i=0; i<nInput && th_isspace(zInput[i]); i++); |
| 462 | *pnSpace = i; |
| @@ -457,21 +465,21 @@ | |
| 465 | |
| 466 | /* |
| 467 | ** The first byte of the string (zInput,nInput) is not white-space. |
| 468 | ** Set *pnWord to the number of bytes in the th1 word that starts |
| 469 | ** with this byte. If a complete word cannot be parsed or some other |
| 470 | ** error occurs, return TH_ERROR and set the interpreter result to |
| 471 | ** an error message. Otherwise return TH_OK. |
| 472 | ** |
| 473 | ** If the isCmd argument is non-zero, then an unescaped ";" byte not |
| 474 | ** located inside of a block or quoted string is considered to mark |
| 475 | ** the end of the word. |
| 476 | */ |
| 477 | static int thNextWord( |
| 478 | Th_Interp *interp, |
| 479 | const char *zInput, |
| 480 | int nInput, |
| 481 | int *pnWord, |
| 482 | int isCmd |
| 483 | ){ |
| 484 | int iEnd = 0; |
| 485 | |
| @@ -531,12 +539,12 @@ | |
| 539 | return thEvalLocal(interp, &zWord[1], nWord-2); |
| 540 | } |
| 541 | |
| 542 | /* |
| 543 | ** The input string (zWord, nWord) contains a th1 variable reference |
| 544 | ** (a '$' byte followed by a variable name). Perform substitution on |
| 545 | ** the input string and store the resulting string in the interpreter |
| 546 | ** result. |
| 547 | */ |
| 548 | static int thSubstVarname( |
| 549 | Th_Interp *interp, |
| 550 | const char *zWord, |
| @@ -572,11 +580,11 @@ | |
| 580 | return Th_GetVar(interp, &zWord[1], nWord-1); |
| 581 | } |
| 582 | |
| 583 | /* |
| 584 | ** The input string (zWord, nWord) contains a th1 escape sequence. |
| 585 | ** Perform substitution on the input string and store the resulting |
| 586 | ** string in the interpreter result. |
| 587 | */ |
| 588 | static int thSubstEscape( |
| 589 | Th_Interp *interp, |
| 590 | const char *zWord, |
| @@ -608,11 +616,11 @@ | |
| 616 | return TH_OK; |
| 617 | } |
| 618 | |
| 619 | /* |
| 620 | ** The input string (zWord, nWord) contains a th1 word. Perform |
| 621 | ** substitution on the input string and store the resulting |
| 622 | ** string in the interpreter result. |
| 623 | */ |
| 624 | static int thSubstWord( |
| 625 | Th_Interp *interp, |
| 626 | const char *zWord, |
| @@ -640,20 +648,20 @@ | |
| 648 | int (*xGet)(Th_Interp *, const char*, int, int *) = 0; |
| 649 | int (*xSubst)(Th_Interp *, const char*, int) = 0; |
| 650 | |
| 651 | switch( zWord[i] ){ |
| 652 | case '\\': |
| 653 | xGet = thNextEscape; xSubst = thSubstEscape; |
| 654 | break; |
| 655 | case '[': |
| 656 | if( !interp->isListMode ){ |
| 657 | xGet = thNextCommand; xSubst = thSubstCommand; |
| 658 | break; |
| 659 | } |
| 660 | case '$': |
| 661 | if( !interp->isListMode ){ |
| 662 | xGet = thNextVarname; xSubst = thSubstVarname; |
| 663 | break; |
| 664 | } |
| 665 | default: { |
| 666 | thBufferWrite(interp, &output, &zWord[i], 1); |
| 667 | continue; /* Go to the next iteration of the for(...) loop */ |
| @@ -685,11 +693,11 @@ | |
| 693 | ** Return true if one of the following is true of the buffer pointed |
| 694 | ** to by zInput, length nInput: |
| 695 | ** |
| 696 | ** + It is empty, or |
| 697 | ** + It contains nothing but white-space, or |
| 698 | ** + It contains no non-white-space characters before the first |
| 699 | ** newline character. |
| 700 | ** |
| 701 | ** Otherwise return false. |
| 702 | */ |
| 703 | static int thEndOfLine(const char *zInput, int nInput){ |
| @@ -725,16 +733,16 @@ | |
| 733 | ** // Free all memory allocated by Th_SplitList(). The arrays pointed |
| 734 | ** // to by argv and argl are invalidated by this call. |
| 735 | ** // |
| 736 | ** Th_Free(interp, argv); |
| 737 | ** |
| 738 | */ |
| 739 | static int thSplitList( |
| 740 | Th_Interp *interp, /* Interpreter context */ |
| 741 | const char *zList, /* Pointer to buffer containing input list */ |
| 742 | int nList, /* Size of buffer pointed to by zList */ |
| 743 | char ***pazElem, /* OUT: Array of list elements */ |
| 744 | int **panElem, /* OUT: Lengths of each list element */ |
| 745 | int *pnCount /* OUT: Number of list elements */ |
| 746 | ){ |
| 747 | int rc = TH_OK; |
| 748 | |
| @@ -774,14 +782,14 @@ | |
| 782 | assert((lenbuf.nBuf/sizeof(int))==nCount); |
| 783 | |
| 784 | assert((pazElem && panElem) || (!pazElem && !panElem)); |
| 785 | if( pazElem && rc==TH_OK ){ |
| 786 | int i; |
| 787 | char *zElem; |
| 788 | int *anElem; |
| 789 | char **azElem = Th_Malloc(interp, |
| 790 | sizeof(char*) * nCount + /* azElem */ |
| 791 | sizeof(int) * nCount + /* anElem */ |
| 792 | strbuf.nBuf /* space for list element strings */ |
| 793 | ); |
| 794 | anElem = (int *)&azElem[nCount]; |
| 795 | zElem = (char *)&anElem[nCount]; |
| @@ -795,11 +803,11 @@ | |
| 803 | *panElem = anElem; |
| 804 | } |
| 805 | if( pnCount ){ |
| 806 | *pnCount = nCount; |
| 807 | } |
| 808 | |
| 809 | finish: |
| 810 | thBufferFree(interp, &strbuf); |
| 811 | thBufferFree(interp, &lenbuf); |
| 812 | return rc; |
| 813 | } |
| @@ -876,18 +884,18 @@ | |
| 884 | if( rc==TH_OK ){ |
| 885 | Th_Command *p = (Th_Command *)(pEntry->pData); |
| 886 | const char **azArg = (const char **)argv; |
| 887 | rc = p->xProc(interp, p->pContext, argc, azArg, argl); |
| 888 | } |
| 889 | |
| 890 | /* If an error occurred, add this command to the stack trace report. */ |
| 891 | if( rc==TH_ERROR ){ |
| 892 | char *zRes; |
| 893 | int nRes; |
| 894 | char *zStack = 0; |
| 895 | int nStack = 0; |
| 896 | |
| 897 | zRes = Th_TakeResult(interp, &nRes); |
| 898 | if( TH_OK==Th_GetVar(interp, (char *)"::th_stack_trace", -1) ){ |
| 899 | zStack = Th_TakeResult(interp, &nStack); |
| 900 | } |
| 901 | Th_ListAppend(interp, &zStack, &nStack, zFirst, zInput-zFirst); |
| @@ -912,15 +920,15 @@ | |
| 920 | ** |
| 921 | ** Argument iFrame is interpreted as follows: |
| 922 | ** |
| 923 | ** * If iFrame is 0, this means the current frame. |
| 924 | ** |
| 925 | ** * If iFrame is negative, then the nth frame up the stack, where |
| 926 | ** n is the absolute value of iFrame. A value of -1 means the |
| 927 | ** calling procedure. |
| 928 | ** |
| 929 | ** * If iFrame is +ve, then the nth frame from the bottom of the |
| 930 | ** stack. An iFrame value of 1 means the toplevel (global) frame. |
| 931 | */ |
| 932 | static Th_Frame *getFrame(Th_Interp *interp, int iFrame){ |
| 933 | Th_Frame *p = interp->pFrame; |
| 934 | int i; |
| @@ -948,28 +956,28 @@ | |
| 956 | |
| 957 | |
| 958 | /* |
| 959 | ** Evaluate th1 script (zProgram, nProgram) in the frame identified by |
| 960 | ** argument iFrame. Leave either an error message or a result in the |
| 961 | ** interpreter result and return a th1 error code (TH_OK, TH_ERROR, |
| 962 | ** TH_RETURN, TH_CONTINUE or TH_BREAK). |
| 963 | */ |
| 964 | int Th_Eval(Th_Interp *interp, int iFrame, const char *zProgram, int nProgram){ |
| 965 | int rc = TH_OK; |
| 966 | Th_Frame *pSavedFrame = interp->pFrame; |
| 967 | |
| 968 | /* Set Th_Interp.pFrame to the frame that this script is to be |
| 969 | ** evaluated in. The current frame is saved in pSavedFrame and will |
| 970 | ** be restored before this function returns. |
| 971 | */ |
| 972 | interp->pFrame = getFrame(interp, iFrame); |
| 973 | |
| 974 | if( !interp->pFrame ){ |
| 975 | rc = TH_ERROR; |
| 976 | }else{ |
| 977 | int nInput = nProgram; |
| 978 | |
| 979 | if( nInput<0 ){ |
| 980 | nInput = th_strlen(zProgram); |
| 981 | } |
| 982 | rc = thEvalLocal(interp, zProgram, nInput); |
| 983 | } |
| @@ -995,13 +1003,13 @@ | |
| 1003 | ** array key name. |
| 1004 | */ |
| 1005 | static int thAnalyseVarname( |
| 1006 | const char *zVarname, |
| 1007 | int nVarname, |
| 1008 | const char **pzOuter, /* OUT: Pointer to scalar/array name */ |
| 1009 | int *pnOuter, /* OUT: Number of bytes at *pzOuter */ |
| 1010 | const char **pzInner, /* OUT: Pointer to array key (or null) */ |
| 1011 | int *pnInner, /* OUT: Number of bytes at *pzInner */ |
| 1012 | int *pisGlobal /* OUT: Set to true if this is a global ref */ |
| 1013 | ){ |
| 1014 | const char *zOuter = zVarname; |
| 1015 | int nOuter; |
| @@ -1042,13 +1050,28 @@ | |
| 1050 | *pnInner = nInner; |
| 1051 | *pisGlobal = isGlobal; |
| 1052 | return TH_OK; |
| 1053 | } |
| 1054 | |
| 1055 | /* |
| 1056 | ** The Find structure is used to return extra information to callers of the |
| 1057 | ** thFindValue function. The fields within it are populated by thFindValue |
| 1058 | ** as soon as the necessary information is available. Callers should check |
| 1059 | ** each field of interest upon return. |
| 1060 | */ |
| 1061 | |
| 1062 | struct Find { |
| 1063 | Th_HashEntry *pValueEntry; /* Pointer to the scalar or array hash entry */ |
| 1064 | Th_HashEntry *pElemEntry; /* Pointer to array element hash entry, if any */ |
| 1065 | const char *zElem; /* Name of array element, if applicable */ |
| 1066 | int nElem; /* Length of array element name, if applicable */ |
| 1067 | }; |
| 1068 | typedef struct Find Find; |
| 1069 | |
| 1070 | /* |
| 1071 | ** Input string (zVar, nVar) contains a variable name. This function locates |
| 1072 | ** the Th_Variable structure associated with the named variable. The |
| 1073 | ** variable name may be a global or local scalar or array variable |
| 1074 | ** |
| 1075 | ** If the create argument is non-zero and the named variable does not exist |
| 1076 | ** it is created. Otherwise, an error is left in the interpreter result |
| 1077 | ** and NULL returned. |
| @@ -1055,16 +1078,19 @@ | |
| 1078 | ** |
| 1079 | ** If the arrayok argument is false and the named variable is an array, |
| 1080 | ** an error is left in the interpreter result and NULL returned. If |
| 1081 | ** arrayok is true an array name is Ok. |
| 1082 | */ |
| 1083 | |
| 1084 | static Th_Variable *thFindValue( |
| 1085 | Th_Interp *interp, |
| 1086 | const char *zVar, /* Pointer to variable name */ |
| 1087 | int nVar, /* Number of bytes at nVar */ |
| 1088 | int create, /* If true, create the variable if not found */ |
| 1089 | int arrayok, /* If true, an array is Ok. Otherwise array==error */ |
| 1090 | int noerror, /* If false, set interpreter result to error */ |
| 1091 | Find *pFind /* If non-zero, place output here */ |
| 1092 | ){ |
| 1093 | const char *zOuter; |
| 1094 | int nOuter; |
| 1095 | const char *zInner; |
| 1096 | int nInner; |
| @@ -1073,16 +1099,24 @@ | |
| 1099 | Th_HashEntry *pEntry; |
| 1100 | Th_Frame *pFrame = interp->pFrame; |
| 1101 | Th_Variable *pValue; |
| 1102 | |
| 1103 | thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal); |
| 1104 | if( pFind ){ |
| 1105 | memset(pFind, 0, sizeof(Find)); |
| 1106 | pFind->zElem = zInner; |
| 1107 | pFind->nElem = nInner; |
| 1108 | } |
| 1109 | if( isGlobal ){ |
| 1110 | while( pFrame->pCaller ) pFrame = pFrame->pCaller; |
| 1111 | } |
| 1112 | |
| 1113 | pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create); |
| 1114 | assert(pEntry || create<=0); |
| 1115 | if( pFind ){ |
| 1116 | pFind->pValueEntry = pEntry; |
| 1117 | } |
| 1118 | if( !pEntry ){ |
| 1119 | goto no_such_var; |
| 1120 | } |
| 1121 | |
| 1122 | pValue = (Th_Variable *)pEntry->pData; |
| @@ -1093,20 +1127,26 @@ | |
| 1127 | pEntry->pData = (void *)pValue; |
| 1128 | } |
| 1129 | |
| 1130 | if( zInner ){ |
| 1131 | if( pValue->zData ){ |
| 1132 | if( !noerror ){ |
| 1133 | Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter); |
| 1134 | } |
| 1135 | return 0; |
| 1136 | } |
| 1137 | if( !pValue->pHash ){ |
| 1138 | if( !create ){ |
| 1139 | goto no_such_var; |
| 1140 | } |
| 1141 | pValue->pHash = Th_HashNew(interp); |
| 1142 | } |
| 1143 | pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create); |
| 1144 | assert(pEntry || create<=0); |
| 1145 | if( pFind ){ |
| 1146 | pFind->pElemEntry = pEntry; |
| 1147 | } |
| 1148 | if( !pEntry ){ |
| 1149 | goto no_such_var; |
| 1150 | } |
| 1151 | pValue = (Th_Variable *)pEntry->pData; |
| 1152 | if( !pValue ){ |
| @@ -1115,34 +1155,38 @@ | |
| 1155 | pValue->nRef = 1; |
| 1156 | pEntry->pData = (void *)pValue; |
| 1157 | } |
| 1158 | }else{ |
| 1159 | if( pValue->pHash && !arrayok ){ |
| 1160 | if( !noerror ){ |
| 1161 | Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter); |
| 1162 | } |
| 1163 | return 0; |
| 1164 | } |
| 1165 | } |
| 1166 | |
| 1167 | return pValue; |
| 1168 | |
| 1169 | no_such_var: |
| 1170 | if( !noerror ){ |
| 1171 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| 1172 | } |
| 1173 | return 0; |
| 1174 | } |
| 1175 | |
| 1176 | /* |
| 1177 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| 1178 | ** array member. Look up the variable, store its current value in |
| 1179 | ** the interpreter result and return TH_OK. |
| 1180 | ** |
| 1181 | ** If the named variable does not exist, return TH_ERROR and leave |
| 1182 | ** an error message in the interpreter result. |
| 1183 | */ |
| 1184 | int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1185 | Th_Variable *pValue; |
| 1186 | |
| 1187 | pValue = thFindValue(interp, zVar, nVar, 0, 0, 0, 0); |
| 1188 | if( !pValue ){ |
| 1189 | return TH_ERROR; |
| 1190 | } |
| 1191 | if( !pValue->zData ){ |
| 1192 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| @@ -1154,11 +1198,12 @@ | |
| 1198 | |
| 1199 | /* |
| 1200 | ** Return true if variable (zVar, nVar) exists. |
| 1201 | */ |
| 1202 | int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1203 | Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0); |
| 1204 | return pValue && (pValue->zData || pValue->pHash); |
| 1205 | } |
| 1206 | |
| 1207 | /* |
| 1208 | ** String (zVar, nVar) must contain the name of a scalar variable or |
| 1209 | ** array member. If the variable does not exist it is created. The |
| @@ -1166,19 +1211,19 @@ | |
| 1211 | ** |
| 1212 | ** If (zVar, nVar) refers to an existing array, TH_ERROR is returned |
| 1213 | ** and an error message left in the interpreter result. |
| 1214 | */ |
| 1215 | int Th_SetVar( |
| 1216 | Th_Interp *interp, |
| 1217 | const char *zVar, |
| 1218 | int nVar, |
| 1219 | const char *zValue, |
| 1220 | int nValue |
| 1221 | ){ |
| 1222 | Th_Variable *pValue; |
| 1223 | |
| 1224 | pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0); |
| 1225 | if( !pValue ){ |
| 1226 | return TH_ERROR; |
| 1227 | } |
| 1228 | |
| 1229 | if( nValue<0 ){ |
| @@ -1202,13 +1247,13 @@ | |
| 1247 | ** Create a variable link so that accessing variable (zLocal, nLocal) is |
| 1248 | ** the same as accessing variable (zLink, nLink) in stack frame iFrame. |
| 1249 | */ |
| 1250 | int Th_LinkVar( |
| 1251 | Th_Interp *interp, /* Interpreter */ |
| 1252 | const char *zLocal, int nLocal, /* Local varname */ |
| 1253 | int iFrame, /* Stack frame of linked var */ |
| 1254 | const char *zLink, int nLink /* Linked varname */ |
| 1255 | ){ |
| 1256 | Th_Frame *pSavedFrame = interp->pFrame; |
| 1257 | Th_Frame *pFrame; |
| 1258 | Th_HashEntry *pEntry; |
| 1259 | Th_Variable *pValue; |
| @@ -1217,11 +1262,11 @@ | |
| 1262 | if( !pFrame ){ |
| 1263 | return TH_ERROR; |
| 1264 | } |
| 1265 | pSavedFrame = interp->pFrame; |
| 1266 | interp->pFrame = pFrame; |
| 1267 | pValue = thFindValue(interp, zLink, nLink, 1, 1, 0, 0); |
| 1268 | interp->pFrame = pSavedFrame; |
| 1269 | |
| 1270 | pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1); |
| 1271 | if( pEntry->pData ){ |
| 1272 | Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal); |
| @@ -1238,25 +1283,68 @@ | |
| 1283 | ** an array, or an array member. If the identified variable exists, it |
| 1284 | ** is deleted and TH_OK returned. Otherwise, an error message is left |
| 1285 | ** in the interpreter result and TH_ERROR is returned. |
| 1286 | */ |
| 1287 | int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){ |
| 1288 | Find find; |
| 1289 | Th_Variable *pValue; |
| 1290 | Th_HashEntry *pEntry; |
| 1291 | int rc = TH_ERROR; |
| 1292 | |
| 1293 | pValue = thFindValue(interp, zVar, nVar, 0, 1, 0, &find); |
| 1294 | if( !pValue ){ |
| 1295 | return rc; |
| 1296 | } |
| 1297 | |
| 1298 | if( pValue->zData || pValue->pHash ){ |
| 1299 | rc = TH_OK; |
| 1300 | }else { |
| 1301 | Th_ErrorMessage(interp, "no such variable:", zVar, nVar); |
| 1302 | } |
| 1303 | |
| 1304 | /* |
| 1305 | ** The variable may be shared by more than one frame; therefore, make sure |
| 1306 | ** it is actually freed prior to freeing the parent structure. The values |
| 1307 | ** for the variable must be freed now so the variable appears undefined in |
| 1308 | ** all frames. The hash entry in the current frame must also be deleted |
| 1309 | ** now; otherwise, if the current stack frame is later popped, it will try |
| 1310 | ** to delete a variable which has already been freed. |
| 1311 | */ |
| 1312 | if( find.zElem ){ |
| 1313 | pEntry = find.pElemEntry; |
| 1314 | }else{ |
| 1315 | pEntry = find.pValueEntry; |
| 1316 | } |
| 1317 | assert( pEntry ); |
| 1318 | assert( pValue ); |
| 1319 | if( thFreeVariable(pEntry, (void *)interp) ){ |
| 1320 | if( find.zElem ){ |
| 1321 | Th_Variable *pValue2 = find.pValueEntry->pData; |
| 1322 | Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1); |
| 1323 | }else if( pEntry->pData ){ |
| 1324 | Th_Free(interp, pEntry->pData); |
| 1325 | pEntry->pData = 0; |
| 1326 | } |
| 1327 | }else{ |
| 1328 | if( pValue->zData ){ |
| 1329 | Th_Free(interp, pValue->zData); |
| 1330 | pValue->zData = 0; |
| 1331 | } |
| 1332 | if( pValue->pHash ){ |
| 1333 | Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp); |
| 1334 | Th_HashDelete(interp, pValue->pHash); |
| 1335 | pValue->pHash = 0; |
| 1336 | } |
| 1337 | if( find.zElem ){ |
| 1338 | Th_Variable *pValue2 = find.pValueEntry->pData; |
| 1339 | Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1); |
| 1340 | } |
| 1341 | } |
| 1342 | if( !find.zElem ){ |
| 1343 | Th_HashFind(interp, interp->pFrame->paVar, zVar, nVar, -1); |
| 1344 | } |
| 1345 | return rc; |
| 1346 | } |
| 1347 | |
| 1348 | /* |
| 1349 | ** Return an allocated buffer containing a copy of string (z, n). The |
| 1350 | ** caller is responsible for eventually calling Th_Free() to free |
| @@ -1291,11 +1379,11 @@ | |
| 1379 | if( interp ){ |
| 1380 | char *zRes = 0; |
| 1381 | int nRes = 0; |
| 1382 | |
| 1383 | Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0); |
| 1384 | |
| 1385 | Th_StringAppend(interp, &zRes, &nRes, zPre, -1); |
| 1386 | if( zRes[nRes-1]=='"' ){ |
| 1387 | Th_StringAppend(interp, &zRes, &nRes, z, n); |
| 1388 | Th_StringAppend(interp, &zRes, &nRes, (const char *)"\"", 1); |
| 1389 | }else{ |
| @@ -1373,12 +1461,12 @@ | |
| 1461 | return (char *)Th_Malloc(pInterp, 1); |
| 1462 | } |
| 1463 | } |
| 1464 | |
| 1465 | |
| 1466 | /* |
| 1467 | ** Wrappers around the supplied malloc() and free() |
| 1468 | */ |
| 1469 | void *Th_Malloc(Th_Interp *pInterp, int nByte){ |
| 1470 | void *p = pInterp->pVtab->xMalloc(nByte); |
| 1471 | if( p ){ |
| 1472 | memset(p, 0, nByte); |
| @@ -1390,16 +1478,16 @@ | |
| 1478 | pInterp->pVtab->xFree(z); |
| 1479 | } |
| 1480 | } |
| 1481 | |
| 1482 | /* |
| 1483 | ** Install a new th1 command. |
| 1484 | ** |
| 1485 | ** If a command of the same name already exists, it is deleted automatically. |
| 1486 | */ |
| 1487 | int Th_CreateCommand( |
| 1488 | Th_Interp *interp, |
| 1489 | const char *zName, /* New command name */ |
| 1490 | Th_CommandProc xProc, /* Command callback proc */ |
| 1491 | void *pContext, /* Value to pass as second arg to xProc */ |
| 1492 | void (*xDel)(Th_Interp *, void *) /* Command destructor callback */ |
| 1493 | ){ |
| @@ -1417,27 +1505,27 @@ | |
| 1505 | } |
| 1506 | pCommand->xProc = xProc; |
| 1507 | pCommand->pContext = pContext; |
| 1508 | pCommand->xDel = xDel; |
| 1509 | pEntry->pData = (void *)pCommand; |
| 1510 | |
| 1511 | return TH_OK; |
| 1512 | } |
| 1513 | |
| 1514 | /* |
| 1515 | ** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0, |
| 1516 | ** the command is deleted instead of renamed. |
| 1517 | ** |
| 1518 | ** If successful, TH_OK is returned. If command zName does not exist, or |
| 1519 | ** if command zNew already exists, an error message is left in the |
| 1520 | ** interpreter result and TH_ERROR is returned. |
| 1521 | */ |
| 1522 | int Th_RenameCommand( |
| 1523 | Th_Interp *interp, |
| 1524 | const char *zName, /* Existing command name */ |
| 1525 | int nName, /* Number of bytes at zName */ |
| 1526 | const char *zNew, /* New command name */ |
| 1527 | int nNew /* Number of bytes at zNew */ |
| 1528 | ){ |
| 1529 | Th_HashEntry *pEntry; |
| 1530 | Th_HashEntry *pNewEntry; |
| 1531 | |
| @@ -1491,11 +1579,11 @@ | |
| 1579 | ** If an error occurs (if (zList, nList) is not a valid list) an error |
| 1580 | ** message is left in the interpreter result and TH_ERROR returned. |
| 1581 | ** |
| 1582 | ** If successful, *pnCount is set to the number of elements in the list. |
| 1583 | ** panElem is set to point at an array of *pnCount integers - the lengths |
| 1584 | ** of the element values. *pazElem is set to point at an array of |
| 1585 | ** pointers to buffers containing the array element's data. |
| 1586 | ** |
| 1587 | ** To free the arrays allocated at *pazElem and *panElem, the caller |
| 1588 | ** should call Th_Free() on *pazElem only. Exactly one such call to |
| 1589 | ** Th_Free() must be made per call to Th_SplitList(). |
| @@ -1517,13 +1605,13 @@ | |
| 1605 | ** Th_Free(interp, azElem); |
| 1606 | ** |
| 1607 | */ |
| 1608 | int Th_SplitList( |
| 1609 | Th_Interp *interp, |
| 1610 | const char *zList, /* Pointer to buffer containing list */ |
| 1611 | int nList, /* Number of bytes at zList */ |
| 1612 | char ***pazElem, /* OUT: Array of pointers to element data */ |
| 1613 | int **panElem, /* OUT: Array of element data lengths */ |
| 1614 | int *pnCount /* OUT: Number of elements in list */ |
| 1615 | ){ |
| 1616 | int rc; |
| 1617 | interp->isListMode = 1; |
| @@ -1534,16 +1622,16 @@ | |
| 1622 | } |
| 1623 | return rc; |
| 1624 | } |
| 1625 | |
| 1626 | /* |
| 1627 | ** Append a new element to an existing th1 list. The element to append |
| 1628 | ** to the list is (zElem, nElem). |
| 1629 | ** |
| 1630 | ** A pointer to the existing list must be stored at *pzList when this |
| 1631 | ** function is called. The length must be stored in *pnList. The value |
| 1632 | ** of *pzList must either be NULL (in which case *pnList must be 0), or |
| 1633 | ** a pointer to memory obtained from Th_Malloc(). |
| 1634 | ** |
| 1635 | ** This function calls Th_Free() to free the buffer at *pzList and sets |
| 1636 | ** *pzList to point to a new buffer containing the new list value. *pnList |
| 1637 | ** is similarly updated before returning. The return value is always TH_OK. |
| @@ -1560,13 +1648,13 @@ | |
| 1648 | ** Th_Free(interp, zList); |
| 1649 | ** |
| 1650 | */ |
| 1651 | int Th_ListAppend( |
| 1652 | Th_Interp *interp, /* Interpreter context */ |
| 1653 | char **pzList, /* IN/OUT: Ptr to ptr to list */ |
| 1654 | int *pnList, /* IN/OUT: Current length of *pzList */ |
| 1655 | const char *zElem, /* Data to append */ |
| 1656 | int nElem /* Length of nElem */ |
| 1657 | ){ |
| 1658 | Buffer output; |
| 1659 | int i; |
| 1660 | |
| @@ -1615,13 +1703,13 @@ | |
| 1703 | ** Append a new element to an existing th1 string. This function uses |
| 1704 | ** the same interface as the Th_ListAppend() function. |
| 1705 | */ |
| 1706 | int Th_StringAppend( |
| 1707 | Th_Interp *interp, /* Interpreter context */ |
| 1708 | char **pzStr, /* IN/OUT: Ptr to ptr to list */ |
| 1709 | int *pnStr, /* IN/OUT: Current length of *pzStr */ |
| 1710 | const char *zElem, /* Data to append */ |
| 1711 | int nElem /* Length of nElem */ |
| 1712 | ){ |
| 1713 | char *zNew; |
| 1714 | int nNew; |
| 1715 | |
| @@ -1639,11 +1727,11 @@ | |
| 1727 | *pnStr = nNew; |
| 1728 | |
| 1729 | return TH_OK; |
| 1730 | } |
| 1731 | |
| 1732 | /* |
| 1733 | ** Delete an interpreter. |
| 1734 | */ |
| 1735 | void Th_DeleteInterp(Th_Interp *interp){ |
| 1736 | assert(interp->pFrame); |
| 1737 | assert(0==interp->pFrame->pCaller); |
| @@ -1660,11 +1748,11 @@ | |
| 1748 | |
| 1749 | /* Delete the interpreter structure itself. */ |
| 1750 | Th_Free(interp, (void *)interp); |
| 1751 | } |
| 1752 | |
| 1753 | /* |
| 1754 | ** Create a new interpreter. |
| 1755 | */ |
| 1756 | Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){ |
| 1757 | Th_Interp *p; |
| 1758 | |
| @@ -1694,11 +1782,11 @@ | |
| 1782 | Operator *pOp; |
| 1783 | Expr *pParent; |
| 1784 | Expr *pLeft; |
| 1785 | Expr *pRight; |
| 1786 | |
| 1787 | char *zValue; /* Pointer to literal value */ |
| 1788 | int nValue; /* Length of literal value buffer */ |
| 1789 | }; |
| 1790 | |
| 1791 | /* Unary operators */ |
| 1792 | #define OP_UNARY_MINUS 2 |
| @@ -1750,11 +1838,11 @@ | |
| 1838 | {"+", OP_UNARY_PLUS, 1, ARG_NUMBER}, |
| 1839 | {"~", OP_BITWISE_NOT, 1, ARG_INTEGER}, |
| 1840 | {"!", OP_LOGICAL_NOT, 1, ARG_INTEGER}, |
| 1841 | |
| 1842 | /* Binary operators. It is important to the parsing in Th_Expr() that |
| 1843 | * the two-character symbols ("==") appear before the one-character |
| 1844 | * ones ("="). And that the priorities of all binary operators are |
| 1845 | * integers between 2 and 12. |
| 1846 | */ |
| 1847 | {"<<", OP_LEFTSHIFT, 4, ARG_INTEGER}, |
| 1848 | {">>", OP_RIGHTSHIFT, 4, ARG_INTEGER}, |
| @@ -1781,16 +1869,16 @@ | |
| 1869 | {0,0,0,0} |
| 1870 | }; |
| 1871 | |
| 1872 | /* |
| 1873 | ** The first part of the string (zInput,nInput) contains a number. |
| 1874 | ** Set *pnVarname to the number of bytes in the numeric string. |
| 1875 | */ |
| 1876 | static int thNextNumber( |
| 1877 | Th_Interp *interp, |
| 1878 | const char *zInput, |
| 1879 | int nInput, |
| 1880 | int *pnLiteral |
| 1881 | ){ |
| 1882 | int i; |
| 1883 | int seenDot = 0; |
| 1884 | for(i=0; i<nInput; i++){ |
| @@ -1856,11 +1944,11 @@ | |
| 1944 | if( eArgType==ARG_NUMBER ){ |
| 1945 | if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft)) |
| 1946 | && (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight)) |
| 1947 | ){ |
| 1948 | eArgType = ARG_INTEGER; |
| 1949 | }else if( |
| 1950 | (zLeft && TH_OK!=Th_ToDouble(interp, zLeft, nLeft, &fLeft)) || |
| 1951 | (zRight && TH_OK!=Th_ToDouble(interp, zRight, nRight, &fRight)) |
| 1952 | ){ |
| 1953 | /* A type error. */ |
| 1954 | rc = TH_ERROR; |
| @@ -1868,28 +1956,30 @@ | |
| 1956 | }else if( eArgType==ARG_INTEGER ){ |
| 1957 | rc = Th_ToInt(interp, zLeft, nLeft, &iLeft); |
| 1958 | if( rc==TH_OK && zRight ){ |
| 1959 | rc = Th_ToInt(interp, zRight, nRight, &iRight); |
| 1960 | } |
| 1961 | } |
| 1962 | } |
| 1963 | |
| 1964 | if( rc==TH_OK && eArgType==ARG_INTEGER ){ |
| 1965 | int iRes = 0; |
| 1966 | switch( pExpr->pOp->eOp ) { |
| 1967 | case OP_MULTIPLY: iRes = iLeft*iRight; break; |
| 1968 | case OP_DIVIDE: |
| 1969 | if( !iRight ){ |
| 1970 | Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft); |
| 1971 | rc = TH_ERROR; |
| 1972 | goto finish; |
| 1973 | } |
| 1974 | iRes = iLeft/iRight; |
| 1975 | break; |
| 1976 | case OP_MODULUS: |
| 1977 | if( !iRight ){ |
| 1978 | Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft); |
| 1979 | rc = TH_ERROR; |
| 1980 | goto finish; |
| 1981 | } |
| 1982 | iRes = iLeft%iRight; |
| 1983 | break; |
| 1984 | case OP_ADD: iRes = iLeft+iRight; break; |
| 1985 | case OP_SUBTRACT: iRes = iLeft-iRight; break; |
| @@ -1913,11 +2003,18 @@ | |
| 2003 | } |
| 2004 | Th_SetResultInt(interp, iRes); |
| 2005 | }else if( rc==TH_OK && eArgType==ARG_NUMBER ){ |
| 2006 | switch( pExpr->pOp->eOp ) { |
| 2007 | case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break; |
| 2008 | case OP_DIVIDE: |
| 2009 | if( fRight==0.0 ){ |
| 2010 | Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft); |
| 2011 | rc = TH_ERROR; |
| 2012 | goto finish; |
| 2013 | } |
| 2014 | Th_SetResultDouble(interp, fLeft/fRight); |
| 2015 | break; |
| 2016 | case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break; |
| 2017 | case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break; |
| 2018 | case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break; |
| 2019 | case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break; |
| 2020 | case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break; |
| @@ -1936,10 +2033,12 @@ | |
| 2033 | case OP_SEQ: Th_SetResultInt(interp, iEqual); break; |
| 2034 | case OP_SNE: Th_SetResultInt(interp, !iEqual); break; |
| 2035 | default: assert(!"Internal error"); |
| 2036 | } |
| 2037 | } |
| 2038 | |
| 2039 | finish: |
| 2040 | |
| 2041 | Th_Free(interp, zLeft); |
| 2042 | Th_Free(interp, zRight); |
| 2043 | } |
| 2044 | |
| @@ -1959,11 +2058,11 @@ | |
| 2058 | #define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft)) |
| 2059 | |
| 2060 | for(jj=0; jj<nToken; jj++){ |
| 2061 | if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){ |
| 2062 | int nNest = 1; |
| 2063 | int iLeft = jj; |
| 2064 | |
| 2065 | for(jj++; jj<nToken; jj++){ |
| 2066 | Operator *pOp = apToken[jj]->pOp; |
| 2067 | if( pOp && pOp->eOp==OP_OPEN_BRACKET ) nNest++; |
| 2068 | if( pOp && pOp->eOp==OP_CLOSE_BRACKET ) nNest--; |
| @@ -2033,11 +2132,11 @@ | |
| 2132 | /* |
| 2133 | ** Parse a string containing a TH expression to a list of tokens. |
| 2134 | */ |
| 2135 | static int exprParse( |
| 2136 | Th_Interp *interp, /* Interpreter to leave error message in */ |
| 2137 | const char *zExpr, /* Pointer to input string */ |
| 2138 | int nExpr, /* Number of bytes at zExpr */ |
| 2139 | Expr ***papToken, /* OUT: Array of tokens. */ |
| 2140 | int *pnToken /* OUT: Size of token array */ |
| 2141 | ){ |
| 2142 | int i; |
| @@ -2108,11 +2207,11 @@ | |
| 2207 | memcpy(pNew->zValue, z, pNew->nValue); |
| 2208 | i += pNew->nValue; |
| 2209 | } |
| 2210 | if( (nToken%16)==0 ){ |
| 2211 | /* Grow the apToken array. */ |
| 2212 | Expr **apTokenOld = apToken; |
| 2213 | apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16)); |
| 2214 | memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken); |
| 2215 | } |
| 2216 | |
| 2217 | /* Put the new token at the end of the apToken array */ |
| @@ -2133,11 +2232,11 @@ | |
| 2232 | /* |
| 2233 | ** Evaluate the string (zExpr, nExpr) as a Th expression. Store |
| 2234 | ** the result in the interpreter interp and return TH_OK if |
| 2235 | ** successful. If an error occurs, store an error message in |
| 2236 | ** the interpreter result and return an error code. |
| 2237 | */ |
| 2238 | int Th_Expr(Th_Interp *interp, const char *zExpr, int nExpr){ |
| 2239 | int rc; /* Return Code */ |
| 2240 | int i; /* Loop counter */ |
| 2241 | |
| 2242 | int nToken = 0; |
| @@ -2150,11 +2249,11 @@ | |
| 2249 | /* Parse the expression to a list of tokens. */ |
| 2250 | rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken); |
| 2251 | |
| 2252 | /* If the parsing was successful, create an expression tree from |
| 2253 | ** the parsed list of tokens. If successful, apToken[0] is set |
| 2254 | ** to point to the root of the expression tree. |
| 2255 | */ |
| 2256 | if( rc==TH_OK ){ |
| 2257 | rc = exprMakeTree(interp, apToken, nToken); |
| 2258 | } |
| 2259 | |
| @@ -2188,16 +2287,17 @@ | |
| 2287 | |
| 2288 | /* |
| 2289 | ** Iterate through all values currently stored in the hash table. Invoke |
| 2290 | ** the callback function xCallback for each entry. The second argument |
| 2291 | ** passed to xCallback is a copy of the fourth argument passed to this |
| 2292 | ** function. The return value from the callback function xCallback is |
| 2293 | ** ignored. |
| 2294 | */ |
| 2295 | void Th_HashIterate( |
| 2296 | Th_Interp *interp, |
| 2297 | Th_Hash *pHash, |
| 2298 | int (*xCallback)(Th_HashEntry *pEntry, void *pContext), |
| 2299 | void *pContext |
| 2300 | ){ |
| 2301 | int i; |
| 2302 | for(i=0; i<TH_HASHSIZE; i++){ |
| 2303 | Th_HashEntry *pEntry; |
| @@ -2208,14 +2308,15 @@ | |
| 2308 | } |
| 2309 | } |
| 2310 | } |
| 2311 | |
| 2312 | /* |
| 2313 | ** Helper function for Th_HashDelete(). Always returns non-zero. |
| 2314 | */ |
| 2315 | static int xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){ |
| 2316 | Th_Free((Th_Interp *)pContext, (void *)pEntry); |
| 2317 | return 1; |
| 2318 | } |
| 2319 | |
| 2320 | /* |
| 2321 | ** Free a hash-table previously allocated by Th_HashNew(). |
| 2322 | */ |
| @@ -2225,14 +2326,14 @@ | |
| 2326 | Th_Free(interp, pHash); |
| 2327 | } |
| 2328 | } |
| 2329 | |
| 2330 | /* |
| 2331 | ** This function is used to insert or delete hash table items, or to |
| 2332 | ** query a hash table for an existing item. |
| 2333 | ** |
| 2334 | ** If parameter op is less than zero, then the hash-table element |
| 2335 | ** identified by (zKey, nKey) is removed from the hash-table if it |
| 2336 | ** exists. NULL is returned. |
| 2337 | ** |
| 2338 | ** Otherwise, if the hash-table contains an item with key (zKey, nKey), |
| 2339 | ** a pointer to the associated Th_HashEntry is returned. If parameter |
| @@ -2239,11 +2340,11 @@ | |
| 2340 | ** op is greater than zero, then a new entry is added if one cannot |
| 2341 | ** be found. If op is zero, then NULL is returned if the item is |
| 2342 | ** not already present in the hash-table. |
| 2343 | */ |
| 2344 | Th_HashEntry *Th_HashFind( |
| 2345 | Th_Interp *interp, |
| 2346 | Th_Hash *pHash, |
| 2347 | const char *zKey, |
| 2348 | int nKey, |
| 2349 | int op /* -ve = delete, 0 = find, +ve = insert */ |
| 2350 | ){ |
| @@ -2307,11 +2408,11 @@ | |
| 2408 | ** '\f' 0x0C |
| 2409 | ** '\r' 0x0D |
| 2410 | ** |
| 2411 | ** Whitespace characters have the 0x01 flag set. Decimal digits have the |
| 2412 | ** 0x2 flag set. Single byte printable characters have the 0x4 flag set. |
| 2413 | ** Alphabet characters have the 0x8 bit set. |
| 2414 | ** |
| 2415 | ** The special list characters have the 0x10 flag set |
| 2416 | ** |
| 2417 | ** { } [ ] \ ; ' " |
| 2418 | ** |
| @@ -2458,14 +2559,14 @@ | |
| 2559 | return z - zBegin; |
| 2560 | } |
| 2561 | |
| 2562 | /* |
| 2563 | ** Try to convert the string passed as arguments (z, n) to an integer. |
| 2564 | ** If successful, store the result in *piOut and return TH_OK. |
| 2565 | ** |
| 2566 | ** If the string cannot be converted to an integer, return TH_ERROR. |
| 2567 | ** If the interp argument is not NULL, leave an error message in the |
| 2568 | ** interpreter result too. |
| 2569 | */ |
| 2570 | int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){ |
| 2571 | int i = 0; |
| 2572 | int iOut = 0; |
| @@ -2493,20 +2594,20 @@ | |
| 2594 | return TH_OK; |
| 2595 | } |
| 2596 | |
| 2597 | /* |
| 2598 | ** Try to convert the string passed as arguments (z, n) to a double. |
| 2599 | ** If successful, store the result in *pfOut and return TH_OK. |
| 2600 | ** |
| 2601 | ** If the string cannot be converted to a double, return TH_ERROR. |
| 2602 | ** If the interp argument is not NULL, leave an error message in the |
| 2603 | ** interpreter result too. |
| 2604 | */ |
| 2605 | int Th_ToDouble( |
| 2606 | Th_Interp *interp, |
| 2607 | const char *z, |
| 2608 | int n, |
| 2609 | double *pfOut |
| 2610 | ){ |
| 2611 | if( !sqlite3IsNumber((const char *)z, 0) ){ |
| 2612 | Th_ErrorMessage(interp, "expected number, got: \"", z, n); |
| 2613 | return TH_ERROR; |
| @@ -2547,33 +2648,33 @@ | |
| 2648 | ** the double fVal and return TH_OK. |
| 2649 | */ |
| 2650 | int Th_SetResultDouble(Th_Interp *interp, double fVal){ |
| 2651 | int i; /* Iterator variable */ |
| 2652 | double v = fVal; /* Input value */ |
| 2653 | char zBuf[128]; /* Output buffer */ |
| 2654 | char *z = zBuf; /* Output cursor */ |
| 2655 | int iDot = 0; /* Digit after which to place decimal point */ |
| 2656 | int iExp = 0; /* Exponent (NN in eNN) */ |
| 2657 | const char *zExp; /* String representation of iExp */ |
| 2658 | |
| 2659 | /* Precision: */ |
| 2660 | #define INSIGNIFICANT 0.000000000001 |
| 2661 | #define ROUNDER 0.0000000000005 |
| 2662 | double insignificant = INSIGNIFICANT; |
| 2663 | |
| 2664 | /* If the real value is negative, write a '-' character to the |
| 2665 | * output and transform v to the corresponding positive number. |
| 2666 | */ |
| 2667 | if( v<0.0 ){ |
| 2668 | *z++ = '-'; |
| 2669 | v *= -1.0; |
| 2670 | } |
| 2671 | |
| 2672 | /* Normalize v to a value between 1.0 and 10.0. Integer |
| 2673 | * variable iExp is set to the exponent. i.e the original |
| 2674 | * value is (v * 10^iExp) (or the negative thereof). |
| 2675 | */ |
| 2676 | if( v>0.0 ){ |
| 2677 | while( (v+ROUNDER)>=10.0 ) { iExp++; v *= 0.1; } |
| 2678 | while( (v+ROUNDER)<1.0 ) { iExp--; v *= 10.0; } |
| 2679 | } |
| 2680 | v += ROUNDER; |
| 2681 |
M
src/th.h
+23
-23
| --- src/th.h | ||
| +++ src/th.h | ||
| @@ -18,70 +18,70 @@ | ||
| 18 | 18 | /* |
| 19 | 19 | ** Opaque handle for interpeter. |
| 20 | 20 | */ |
| 21 | 21 | typedef struct Th_Interp Th_Interp; |
| 22 | 22 | |
| 23 | -/* | |
| 24 | -** Create and delete interpreters. | |
| 23 | +/* | |
| 24 | +** Create and delete interpreters. | |
| 25 | 25 | */ |
| 26 | 26 | Th_Interp * Th_CreateInterp(Th_Vtab *pVtab); |
| 27 | 27 | void Th_DeleteInterp(Th_Interp *); |
| 28 | 28 | |
| 29 | -/* | |
| 29 | +/* | |
| 30 | 30 | ** Evaluate an TH program in the stack frame identified by parameter |
| 31 | 31 | ** iFrame, according to the following rules: |
| 32 | 32 | ** |
| 33 | 33 | ** * If iFrame is 0, this means the current frame. |
| 34 | 34 | ** |
| 35 | -** * If iFrame is negative, then the nth frame up the stack, where n is | |
| 35 | +** * If iFrame is negative, then the nth frame up the stack, where n is | |
| 36 | 36 | ** the absolute value of iFrame. A value of -1 means the calling |
| 37 | 37 | ** procedure. |
| 38 | 38 | ** |
| 39 | 39 | ** * If iFrame is +ve, then the nth frame from the bottom of the stack. |
| 40 | 40 | ** An iFrame value of 1 means the toplevel (global) frame. |
| 41 | 41 | */ |
| 42 | 42 | int Th_Eval(Th_Interp *interp, int iFrame, const char *zProg, int nProg); |
| 43 | 43 | |
| 44 | 44 | /* |
| 45 | -** Evaluate a TH expression. The result is stored in the | |
| 45 | +** Evaluate a TH expression. The result is stored in the | |
| 46 | 46 | ** interpreter result. |
| 47 | 47 | */ |
| 48 | 48 | int Th_Expr(Th_Interp *interp, const char *, int); |
| 49 | 49 | |
| 50 | -/* | |
| 50 | +/* | |
| 51 | 51 | ** Access TH variables in the current stack frame. If the variable name |
| 52 | -** begins with "::", the lookup is in the top level (global) frame. | |
| 52 | +** begins with "::", the lookup is in the top level (global) frame. | |
| 53 | 53 | */ |
| 54 | 54 | int Th_ExistsVar(Th_Interp *, const char *, int); |
| 55 | 55 | int Th_GetVar(Th_Interp *, const char *, int); |
| 56 | 56 | int Th_SetVar(Th_Interp *, const char *, int, const char *, int); |
| 57 | 57 | int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int); |
| 58 | 58 | int Th_UnsetVar(Th_Interp *, const char *, int); |
| 59 | 59 | |
| 60 | 60 | typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *); |
| 61 | 61 | |
| 62 | -/* | |
| 63 | -** Register new commands. | |
| 62 | +/* | |
| 63 | +** Register new commands. | |
| 64 | 64 | */ |
| 65 | 65 | int Th_CreateCommand( |
| 66 | - Th_Interp *interp, | |
| 67 | - const char *zName, | |
| 66 | + Th_Interp *interp, | |
| 67 | + const char *zName, | |
| 68 | 68 | /* int (*xProc)(Th_Interp *, void *, int, const char **, int *), */ |
| 69 | 69 | Th_CommandProc xProc, |
| 70 | 70 | void *pContext, |
| 71 | 71 | void (*xDel)(Th_Interp *, void *) |
| 72 | 72 | ); |
| 73 | 73 | |
| 74 | -/* | |
| 74 | +/* | |
| 75 | 75 | ** Delete or rename commands. |
| 76 | 76 | */ |
| 77 | 77 | int Th_RenameCommand(Th_Interp *, const char *, int, const char *, int); |
| 78 | 78 | |
| 79 | -/* | |
| 80 | -** Push a new stack frame (local variable context) onto the interpreter | |
| 81 | -** stack, call the function supplied as parameter xCall with the two | |
| 82 | -** context arguments, | |
| 79 | +/* | |
| 80 | +** Push a new stack frame (local variable context) onto the interpreter | |
| 81 | +** stack, call the function supplied as parameter xCall with the two | |
| 82 | +** context arguments, | |
| 83 | 83 | ** |
| 84 | 84 | ** xCall(interp, pContext1, pContext2) |
| 85 | 85 | ** |
| 86 | 86 | ** , then pop the frame off of the interpreter stack. The value returned |
| 87 | 87 | ** by the xCall() function is returned as the result of this function. |
| @@ -93,21 +93,21 @@ | ||
| 93 | 93 | int (*xCall)(Th_Interp *, void *pContext1, void *pContext2), |
| 94 | 94 | void *pContext1, |
| 95 | 95 | void *pContext2 |
| 96 | 96 | ); |
| 97 | 97 | |
| 98 | -/* | |
| 98 | +/* | |
| 99 | 99 | ** Valid return codes for xProc callbacks. |
| 100 | 100 | */ |
| 101 | 101 | #define TH_OK 0 |
| 102 | 102 | #define TH_ERROR 1 |
| 103 | 103 | #define TH_BREAK 2 |
| 104 | 104 | #define TH_RETURN 3 |
| 105 | 105 | #define TH_CONTINUE 4 |
| 106 | 106 | |
| 107 | -/* | |
| 108 | -** Set and get the interpreter result. | |
| 107 | +/* | |
| 108 | +** Set and get the interpreter result. | |
| 109 | 109 | */ |
| 110 | 110 | int Th_SetResult(Th_Interp *, const char *, int); |
| 111 | 111 | const char *Th_GetResult(Th_Interp *, int *); |
| 112 | 112 | char *Th_TakeResult(Th_Interp *, int *); |
| 113 | 113 | |
| @@ -115,26 +115,26 @@ | ||
| 115 | 115 | ** Set an error message as the interpreter result. This also |
| 116 | 116 | ** sets the global stack-trace variable $::th_stack_trace. |
| 117 | 117 | */ |
| 118 | 118 | int Th_ErrorMessage(Th_Interp *, const char *, const char *, int); |
| 119 | 119 | |
| 120 | -/* | |
| 120 | +/* | |
| 121 | 121 | ** Access the memory management functions associated with the specified |
| 122 | 122 | ** interpreter. |
| 123 | 123 | */ |
| 124 | 124 | void *Th_Malloc(Th_Interp *, int); |
| 125 | 125 | void Th_Free(Th_Interp *, void *); |
| 126 | 126 | |
| 127 | -/* | |
| 127 | +/* | |
| 128 | 128 | ** Functions for handling TH lists. |
| 129 | 129 | */ |
| 130 | 130 | int Th_ListAppend(Th_Interp *, char **, int *, const char *, int); |
| 131 | 131 | int Th_SplitList(Th_Interp *, const char *, int, char ***, int **, int *); |
| 132 | 132 | |
| 133 | 133 | int Th_StringAppend(Th_Interp *, char **, int *, const char *, int); |
| 134 | 134 | |
| 135 | -/* | |
| 135 | +/* | |
| 136 | 136 | ** Functions for handling numbers and pointers. |
| 137 | 137 | */ |
| 138 | 138 | int Th_ToInt(Th_Interp *, const char *, int, int *); |
| 139 | 139 | int Th_ToDouble(Th_Interp *, const char *, int, double *); |
| 140 | 140 | int Th_SetResultInt(Th_Interp *, int); |
| @@ -174,15 +174,15 @@ | ||
| 174 | 174 | int nKey; |
| 175 | 175 | Th_HashEntry *pNext; /* Internal use only */ |
| 176 | 176 | }; |
| 177 | 177 | Th_Hash *Th_HashNew(Th_Interp *); |
| 178 | 178 | void Th_HashDelete(Th_Interp *, Th_Hash *); |
| 179 | -void Th_HashIterate(Th_Interp*,Th_Hash*,void (*x)(Th_HashEntry*, void*),void*); | |
| 179 | +void Th_HashIterate(Th_Interp*,Th_Hash*,int (*x)(Th_HashEntry*, void*),void*); | |
| 180 | 180 | Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const char*, int, int); |
| 181 | 181 | |
| 182 | 182 | /* |
| 183 | 183 | ** Useful functions from th_lang.c. |
| 184 | 184 | */ |
| 185 | 185 | int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg); |
| 186 | 186 | |
| 187 | 187 | typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand; |
| 188 | 188 | int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*); |
| 189 | 189 |
| --- src/th.h | |
| +++ src/th.h | |
| @@ -18,70 +18,70 @@ | |
| 18 | /* |
| 19 | ** Opaque handle for interpeter. |
| 20 | */ |
| 21 | typedef struct Th_Interp Th_Interp; |
| 22 | |
| 23 | /* |
| 24 | ** Create and delete interpreters. |
| 25 | */ |
| 26 | Th_Interp * Th_CreateInterp(Th_Vtab *pVtab); |
| 27 | void Th_DeleteInterp(Th_Interp *); |
| 28 | |
| 29 | /* |
| 30 | ** Evaluate an TH program in the stack frame identified by parameter |
| 31 | ** iFrame, according to the following rules: |
| 32 | ** |
| 33 | ** * If iFrame is 0, this means the current frame. |
| 34 | ** |
| 35 | ** * If iFrame is negative, then the nth frame up the stack, where n is |
| 36 | ** the absolute value of iFrame. A value of -1 means the calling |
| 37 | ** procedure. |
| 38 | ** |
| 39 | ** * If iFrame is +ve, then the nth frame from the bottom of the stack. |
| 40 | ** An iFrame value of 1 means the toplevel (global) frame. |
| 41 | */ |
| 42 | int Th_Eval(Th_Interp *interp, int iFrame, const char *zProg, int nProg); |
| 43 | |
| 44 | /* |
| 45 | ** Evaluate a TH expression. The result is stored in the |
| 46 | ** interpreter result. |
| 47 | */ |
| 48 | int Th_Expr(Th_Interp *interp, const char *, int); |
| 49 | |
| 50 | /* |
| 51 | ** Access TH variables in the current stack frame. If the variable name |
| 52 | ** begins with "::", the lookup is in the top level (global) frame. |
| 53 | */ |
| 54 | int Th_ExistsVar(Th_Interp *, const char *, int); |
| 55 | int Th_GetVar(Th_Interp *, const char *, int); |
| 56 | int Th_SetVar(Th_Interp *, const char *, int, const char *, int); |
| 57 | int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int); |
| 58 | int Th_UnsetVar(Th_Interp *, const char *, int); |
| 59 | |
| 60 | typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *); |
| 61 | |
| 62 | /* |
| 63 | ** Register new commands. |
| 64 | */ |
| 65 | int Th_CreateCommand( |
| 66 | Th_Interp *interp, |
| 67 | const char *zName, |
| 68 | /* int (*xProc)(Th_Interp *, void *, int, const char **, int *), */ |
| 69 | Th_CommandProc xProc, |
| 70 | void *pContext, |
| 71 | void (*xDel)(Th_Interp *, void *) |
| 72 | ); |
| 73 | |
| 74 | /* |
| 75 | ** Delete or rename commands. |
| 76 | */ |
| 77 | int Th_RenameCommand(Th_Interp *, const char *, int, const char *, int); |
| 78 | |
| 79 | /* |
| 80 | ** Push a new stack frame (local variable context) onto the interpreter |
| 81 | ** stack, call the function supplied as parameter xCall with the two |
| 82 | ** context arguments, |
| 83 | ** |
| 84 | ** xCall(interp, pContext1, pContext2) |
| 85 | ** |
| 86 | ** , then pop the frame off of the interpreter stack. The value returned |
| 87 | ** by the xCall() function is returned as the result of this function. |
| @@ -93,21 +93,21 @@ | |
| 93 | int (*xCall)(Th_Interp *, void *pContext1, void *pContext2), |
| 94 | void *pContext1, |
| 95 | void *pContext2 |
| 96 | ); |
| 97 | |
| 98 | /* |
| 99 | ** Valid return codes for xProc callbacks. |
| 100 | */ |
| 101 | #define TH_OK 0 |
| 102 | #define TH_ERROR 1 |
| 103 | #define TH_BREAK 2 |
| 104 | #define TH_RETURN 3 |
| 105 | #define TH_CONTINUE 4 |
| 106 | |
| 107 | /* |
| 108 | ** Set and get the interpreter result. |
| 109 | */ |
| 110 | int Th_SetResult(Th_Interp *, const char *, int); |
| 111 | const char *Th_GetResult(Th_Interp *, int *); |
| 112 | char *Th_TakeResult(Th_Interp *, int *); |
| 113 | |
| @@ -115,26 +115,26 @@ | |
| 115 | ** Set an error message as the interpreter result. This also |
| 116 | ** sets the global stack-trace variable $::th_stack_trace. |
| 117 | */ |
| 118 | int Th_ErrorMessage(Th_Interp *, const char *, const char *, int); |
| 119 | |
| 120 | /* |
| 121 | ** Access the memory management functions associated with the specified |
| 122 | ** interpreter. |
| 123 | */ |
| 124 | void *Th_Malloc(Th_Interp *, int); |
| 125 | void Th_Free(Th_Interp *, void *); |
| 126 | |
| 127 | /* |
| 128 | ** Functions for handling TH lists. |
| 129 | */ |
| 130 | int Th_ListAppend(Th_Interp *, char **, int *, const char *, int); |
| 131 | int Th_SplitList(Th_Interp *, const char *, int, char ***, int **, int *); |
| 132 | |
| 133 | int Th_StringAppend(Th_Interp *, char **, int *, const char *, int); |
| 134 | |
| 135 | /* |
| 136 | ** Functions for handling numbers and pointers. |
| 137 | */ |
| 138 | int Th_ToInt(Th_Interp *, const char *, int, int *); |
| 139 | int Th_ToDouble(Th_Interp *, const char *, int, double *); |
| 140 | int Th_SetResultInt(Th_Interp *, int); |
| @@ -174,15 +174,15 @@ | |
| 174 | int nKey; |
| 175 | Th_HashEntry *pNext; /* Internal use only */ |
| 176 | }; |
| 177 | Th_Hash *Th_HashNew(Th_Interp *); |
| 178 | void Th_HashDelete(Th_Interp *, Th_Hash *); |
| 179 | void Th_HashIterate(Th_Interp*,Th_Hash*,void (*x)(Th_HashEntry*, void*),void*); |
| 180 | Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const char*, int, int); |
| 181 | |
| 182 | /* |
| 183 | ** Useful functions from th_lang.c. |
| 184 | */ |
| 185 | int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg); |
| 186 | |
| 187 | typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand; |
| 188 | int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*); |
| 189 |
| --- src/th.h | |
| +++ src/th.h | |
| @@ -18,70 +18,70 @@ | |
| 18 | /* |
| 19 | ** Opaque handle for interpeter. |
| 20 | */ |
| 21 | typedef struct Th_Interp Th_Interp; |
| 22 | |
| 23 | /* |
| 24 | ** Create and delete interpreters. |
| 25 | */ |
| 26 | Th_Interp * Th_CreateInterp(Th_Vtab *pVtab); |
| 27 | void Th_DeleteInterp(Th_Interp *); |
| 28 | |
| 29 | /* |
| 30 | ** Evaluate an TH program in the stack frame identified by parameter |
| 31 | ** iFrame, according to the following rules: |
| 32 | ** |
| 33 | ** * If iFrame is 0, this means the current frame. |
| 34 | ** |
| 35 | ** * If iFrame is negative, then the nth frame up the stack, where n is |
| 36 | ** the absolute value of iFrame. A value of -1 means the calling |
| 37 | ** procedure. |
| 38 | ** |
| 39 | ** * If iFrame is +ve, then the nth frame from the bottom of the stack. |
| 40 | ** An iFrame value of 1 means the toplevel (global) frame. |
| 41 | */ |
| 42 | int Th_Eval(Th_Interp *interp, int iFrame, const char *zProg, int nProg); |
| 43 | |
| 44 | /* |
| 45 | ** Evaluate a TH expression. The result is stored in the |
| 46 | ** interpreter result. |
| 47 | */ |
| 48 | int Th_Expr(Th_Interp *interp, const char *, int); |
| 49 | |
| 50 | /* |
| 51 | ** Access TH variables in the current stack frame. If the variable name |
| 52 | ** begins with "::", the lookup is in the top level (global) frame. |
| 53 | */ |
| 54 | int Th_ExistsVar(Th_Interp *, const char *, int); |
| 55 | int Th_GetVar(Th_Interp *, const char *, int); |
| 56 | int Th_SetVar(Th_Interp *, const char *, int, const char *, int); |
| 57 | int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int); |
| 58 | int Th_UnsetVar(Th_Interp *, const char *, int); |
| 59 | |
| 60 | typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *); |
| 61 | |
| 62 | /* |
| 63 | ** Register new commands. |
| 64 | */ |
| 65 | int Th_CreateCommand( |
| 66 | Th_Interp *interp, |
| 67 | const char *zName, |
| 68 | /* int (*xProc)(Th_Interp *, void *, int, const char **, int *), */ |
| 69 | Th_CommandProc xProc, |
| 70 | void *pContext, |
| 71 | void (*xDel)(Th_Interp *, void *) |
| 72 | ); |
| 73 | |
| 74 | /* |
| 75 | ** Delete or rename commands. |
| 76 | */ |
| 77 | int Th_RenameCommand(Th_Interp *, const char *, int, const char *, int); |
| 78 | |
| 79 | /* |
| 80 | ** Push a new stack frame (local variable context) onto the interpreter |
| 81 | ** stack, call the function supplied as parameter xCall with the two |
| 82 | ** context arguments, |
| 83 | ** |
| 84 | ** xCall(interp, pContext1, pContext2) |
| 85 | ** |
| 86 | ** , then pop the frame off of the interpreter stack. The value returned |
| 87 | ** by the xCall() function is returned as the result of this function. |
| @@ -93,21 +93,21 @@ | |
| 93 | int (*xCall)(Th_Interp *, void *pContext1, void *pContext2), |
| 94 | void *pContext1, |
| 95 | void *pContext2 |
| 96 | ); |
| 97 | |
| 98 | /* |
| 99 | ** Valid return codes for xProc callbacks. |
| 100 | */ |
| 101 | #define TH_OK 0 |
| 102 | #define TH_ERROR 1 |
| 103 | #define TH_BREAK 2 |
| 104 | #define TH_RETURN 3 |
| 105 | #define TH_CONTINUE 4 |
| 106 | |
| 107 | /* |
| 108 | ** Set and get the interpreter result. |
| 109 | */ |
| 110 | int Th_SetResult(Th_Interp *, const char *, int); |
| 111 | const char *Th_GetResult(Th_Interp *, int *); |
| 112 | char *Th_TakeResult(Th_Interp *, int *); |
| 113 | |
| @@ -115,26 +115,26 @@ | |
| 115 | ** Set an error message as the interpreter result. This also |
| 116 | ** sets the global stack-trace variable $::th_stack_trace. |
| 117 | */ |
| 118 | int Th_ErrorMessage(Th_Interp *, const char *, const char *, int); |
| 119 | |
| 120 | /* |
| 121 | ** Access the memory management functions associated with the specified |
| 122 | ** interpreter. |
| 123 | */ |
| 124 | void *Th_Malloc(Th_Interp *, int); |
| 125 | void Th_Free(Th_Interp *, void *); |
| 126 | |
| 127 | /* |
| 128 | ** Functions for handling TH lists. |
| 129 | */ |
| 130 | int Th_ListAppend(Th_Interp *, char **, int *, const char *, int); |
| 131 | int Th_SplitList(Th_Interp *, const char *, int, char ***, int **, int *); |
| 132 | |
| 133 | int Th_StringAppend(Th_Interp *, char **, int *, const char *, int); |
| 134 | |
| 135 | /* |
| 136 | ** Functions for handling numbers and pointers. |
| 137 | */ |
| 138 | int Th_ToInt(Th_Interp *, const char *, int, int *); |
| 139 | int Th_ToDouble(Th_Interp *, const char *, int, double *); |
| 140 | int Th_SetResultInt(Th_Interp *, int); |
| @@ -174,15 +174,15 @@ | |
| 174 | int nKey; |
| 175 | Th_HashEntry *pNext; /* Internal use only */ |
| 176 | }; |
| 177 | Th_Hash *Th_HashNew(Th_Interp *); |
| 178 | void Th_HashDelete(Th_Interp *, Th_Hash *); |
| 179 | void Th_HashIterate(Th_Interp*,Th_Hash*,int (*x)(Th_HashEntry*, void*),void*); |
| 180 | Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const char*, int, int); |
| 181 | |
| 182 | /* |
| 183 | ** Useful functions from th_lang.c. |
| 184 | */ |
| 185 | int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg); |
| 186 | |
| 187 | typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand; |
| 188 | int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*); |
| 189 |
+113
-113
| --- src/th_lang.c | ||
| +++ src/th_lang.c | ||
| @@ -1,12 +1,12 @@ | ||
| 1 | 1 | |
| 2 | 2 | /* |
| 3 | -** This file contains the implementation of all of the TH language | |
| 4 | -** built-in commands. | |
| 3 | +** This file contains the implementation of all of the TH language | |
| 4 | +** built-in commands. | |
| 5 | 5 | ** |
| 6 | -** All built-in commands are implemented using the public interface | |
| 7 | -** declared in th.h, so this file serves as both a part of the language | |
| 6 | +** All built-in commands are implemented using the public interface | |
| 7 | +** declared in th.h, so this file serves as both a part of the language | |
| 8 | 8 | ** implementation and an example of how to extend the language with |
| 9 | 9 | ** new commands. |
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | #include "config.h" |
| @@ -18,19 +18,19 @@ | ||
| 18 | 18 | Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1); |
| 19 | 19 | return TH_ERROR; |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | /* |
| 23 | -** Syntax: | |
| 23 | +** Syntax: | |
| 24 | 24 | ** |
| 25 | 25 | ** catch script ?varname? |
| 26 | 26 | */ |
| 27 | 27 | static int catch_command( |
| 28 | - Th_Interp *interp, | |
| 29 | - void *ctx, | |
| 30 | - int argc, | |
| 31 | - const char **argv, | |
| 28 | + Th_Interp *interp, | |
| 29 | + void *ctx, | |
| 30 | + int argc, | |
| 31 | + const char **argv, | |
| 32 | 32 | int *argl |
| 33 | 33 | ){ |
| 34 | 34 | int rc; |
| 35 | 35 | |
| 36 | 36 | if( argc!=2 && argc!=3 ){ |
| @@ -47,19 +47,19 @@ | ||
| 47 | 47 | Th_SetResultInt(interp, rc); |
| 48 | 48 | return TH_OK; |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | /* |
| 52 | -** TH Syntax: | |
| 52 | +** TH Syntax: | |
| 53 | 53 | ** |
| 54 | 54 | ** if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN? |
| 55 | 55 | */ |
| 56 | 56 | static int if_command( |
| 57 | - Th_Interp *interp, | |
| 58 | - void *ctx, | |
| 59 | - int argc, | |
| 60 | - const char **argv, | |
| 57 | + Th_Interp *interp, | |
| 58 | + void *ctx, | |
| 59 | + int argc, | |
| 60 | + const char **argv, | |
| 61 | 61 | int *argl |
| 62 | 62 | ){ |
| 63 | 63 | int rc = TH_OK; |
| 64 | 64 | |
| 65 | 65 | int iCond; /* Result of evaluating expression */ |
| @@ -94,19 +94,19 @@ | ||
| 94 | 94 | wrong_args: |
| 95 | 95 | return Th_WrongNumArgs(interp, "if ..."); |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | 98 | /* |
| 99 | -** TH Syntax: | |
| 99 | +** TH Syntax: | |
| 100 | 100 | ** |
| 101 | 101 | ** expr expr |
| 102 | 102 | */ |
| 103 | 103 | static int expr_command( |
| 104 | - Th_Interp *interp, | |
| 105 | - void *ctx, | |
| 106 | - int argc, | |
| 107 | - const char **argv, | |
| 104 | + Th_Interp *interp, | |
| 105 | + void *ctx, | |
| 106 | + int argc, | |
| 107 | + const char **argv, | |
| 108 | 108 | int *argl |
| 109 | 109 | ){ |
| 110 | 110 | if( argc!=2 ){ |
| 111 | 111 | return Th_WrongNumArgs(interp, "expr expression"); |
| 112 | 112 | } |
| @@ -113,11 +113,11 @@ | ||
| 113 | 113 | |
| 114 | 114 | return Th_Expr(interp, argv[1], argl[1]); |
| 115 | 115 | } |
| 116 | 116 | |
| 117 | 117 | /* |
| 118 | -** Evaluate the th1 script (zBody, nBody) in the local stack frame. | |
| 118 | +** Evaluate the th1 script (zBody, nBody) in the local stack frame. | |
| 119 | 119 | ** Return the result of the evaluation, except if the result |
| 120 | 120 | ** is TH_CONTINUE, return TH_OK instead. |
| 121 | 121 | */ |
| 122 | 122 | static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){ |
| 123 | 123 | int rc = Th_Eval(interp, 0, zBody, nBody); |
| @@ -126,19 +126,19 @@ | ||
| 126 | 126 | } |
| 127 | 127 | return rc; |
| 128 | 128 | } |
| 129 | 129 | |
| 130 | 130 | /* |
| 131 | -** TH Syntax: | |
| 131 | +** TH Syntax: | |
| 132 | 132 | ** |
| 133 | 133 | ** for init condition incr script |
| 134 | 134 | */ |
| 135 | 135 | static int for_command( |
| 136 | - Th_Interp *interp, | |
| 137 | - void *ctx, | |
| 138 | - int argc, | |
| 139 | - const char **argv, | |
| 136 | + Th_Interp *interp, | |
| 137 | + void *ctx, | |
| 138 | + int argc, | |
| 139 | + const char **argv, | |
| 140 | 140 | int *argl |
| 141 | 141 | ){ |
| 142 | 142 | int rc; |
| 143 | 143 | int iCond; |
| 144 | 144 | |
| @@ -147,11 +147,11 @@ | ||
| 147 | 147 | } |
| 148 | 148 | |
| 149 | 149 | /* Evaluate the 'init' script */ |
| 150 | 150 | rc = Th_Eval(interp, 0, argv[1], -1); |
| 151 | 151 | |
| 152 | - while( rc==TH_OK | |
| 152 | + while( rc==TH_OK | |
| 153 | 153 | && TH_OK==(rc = Th_Expr(interp, argv[2], -1)) |
| 154 | 154 | && TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond)) |
| 155 | 155 | && iCond |
| 156 | 156 | && TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4])) |
| 157 | 157 | ){ |
| @@ -161,45 +161,45 @@ | ||
| 161 | 161 | if( rc==TH_BREAK ) rc = TH_OK; |
| 162 | 162 | return rc; |
| 163 | 163 | } |
| 164 | 164 | |
| 165 | 165 | /* |
| 166 | -** TH Syntax: | |
| 166 | +** TH Syntax: | |
| 167 | 167 | ** |
| 168 | 168 | ** list ?arg1 ?arg2? ...? |
| 169 | 169 | */ |
| 170 | 170 | static int list_command( |
| 171 | - Th_Interp *interp, | |
| 172 | - void *ctx, | |
| 173 | - int argc, | |
| 174 | - const char **argv, | |
| 171 | + Th_Interp *interp, | |
| 172 | + void *ctx, | |
| 173 | + int argc, | |
| 174 | + const char **argv, | |
| 175 | 175 | int *argl |
| 176 | 176 | ){ |
| 177 | 177 | char *zList = 0; |
| 178 | 178 | int nList = 0; |
| 179 | 179 | int i; |
| 180 | 180 | |
| 181 | 181 | for(i=1; i<argc; i++){ |
| 182 | 182 | Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]); |
| 183 | 183 | } |
| 184 | - | |
| 184 | + | |
| 185 | 185 | Th_SetResult(interp, zList, nList); |
| 186 | 186 | Th_Free(interp, zList); |
| 187 | 187 | |
| 188 | 188 | return TH_OK; |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | 191 | /* |
| 192 | -** TH Syntax: | |
| 192 | +** TH Syntax: | |
| 193 | 193 | ** |
| 194 | 194 | ** lindex list index |
| 195 | 195 | */ |
| 196 | 196 | static int lindex_command( |
| 197 | - Th_Interp *interp, | |
| 198 | - void *ctx, | |
| 199 | - int argc, | |
| 200 | - const char **argv, | |
| 197 | + Th_Interp *interp, | |
| 198 | + void *ctx, | |
| 199 | + int argc, | |
| 200 | + const char **argv, | |
| 201 | 201 | int *argl |
| 202 | 202 | ){ |
| 203 | 203 | int iElem; |
| 204 | 204 | int rc; |
| 205 | 205 | |
| @@ -227,19 +227,19 @@ | ||
| 227 | 227 | |
| 228 | 228 | return rc; |
| 229 | 229 | } |
| 230 | 230 | |
| 231 | 231 | /* |
| 232 | -** TH Syntax: | |
| 232 | +** TH Syntax: | |
| 233 | 233 | ** |
| 234 | 234 | ** llength list |
| 235 | 235 | */ |
| 236 | 236 | static int llength_command( |
| 237 | - Th_Interp *interp, | |
| 238 | - void *ctx, | |
| 239 | - int argc, | |
| 240 | - const char **argv, | |
| 237 | + Th_Interp *interp, | |
| 238 | + void *ctx, | |
| 239 | + int argc, | |
| 240 | + const char **argv, | |
| 241 | 241 | int *argl |
| 242 | 242 | ){ |
| 243 | 243 | int nElem; |
| 244 | 244 | int rc; |
| 245 | 245 | |
| @@ -254,19 +254,19 @@ | ||
| 254 | 254 | |
| 255 | 255 | return rc; |
| 256 | 256 | } |
| 257 | 257 | |
| 258 | 258 | /* |
| 259 | -** TH Syntax: | |
| 259 | +** TH Syntax: | |
| 260 | 260 | ** |
| 261 | 261 | ** set varname ?value? |
| 262 | 262 | */ |
| 263 | 263 | static int set_command( |
| 264 | - Th_Interp *interp, | |
| 265 | - void *ctx, | |
| 266 | - int argc, | |
| 267 | - const char **argv, | |
| 264 | + Th_Interp *interp, | |
| 265 | + void *ctx, | |
| 266 | + int argc, | |
| 267 | + const char **argv, | |
| 268 | 268 | int *argl |
| 269 | 269 | ){ |
| 270 | 270 | if( argc!=2 && argc!=3 ){ |
| 271 | 271 | return Th_WrongNumArgs(interp, "set varname ?value?"); |
| 272 | 272 | } |
| @@ -277,30 +277,30 @@ | ||
| 277 | 277 | return Th_GetVar(interp, argv[1], argl[1]); |
| 278 | 278 | } |
| 279 | 279 | |
| 280 | 280 | /* |
| 281 | 281 | ** When a new command is created using the built-in [proc] command, an |
| 282 | -** instance of the following structure is allocated and populated. A | |
| 283 | -** pointer to the structure is passed as the context (second) argument | |
| 282 | +** instance of the following structure is allocated and populated. A | |
| 283 | +** pointer to the structure is passed as the context (second) argument | |
| 284 | 284 | ** to function proc_call1() when the new command is executed. |
| 285 | 285 | */ |
| 286 | 286 | typedef struct ProcDefn ProcDefn; |
| 287 | 287 | struct ProcDefn { |
| 288 | 288 | int nParam; /* Number of formal (non "args") parameters */ |
| 289 | - char **azParam; /* Parameter names */ | |
| 289 | + char **azParam; /* Parameter names */ | |
| 290 | 290 | int *anParam; /* Lengths of parameter names */ |
| 291 | - char **azDefault; /* Default values */ | |
| 291 | + char **azDefault; /* Default values */ | |
| 292 | 292 | int *anDefault; /* Lengths of default values */ |
| 293 | 293 | int hasArgs; /* True if there is an "args" parameter */ |
| 294 | - char *zProgram; /* Body of proc */ | |
| 294 | + char *zProgram; /* Body of proc */ | |
| 295 | 295 | int nProgram; /* Number of bytes at zProgram */ |
| 296 | - char *zUsage; /* Usage message */ | |
| 296 | + char *zUsage; /* Usage message */ | |
| 297 | 297 | int nUsage; /* Number of bytes at zUsage */ |
| 298 | 298 | }; |
| 299 | 299 | |
| 300 | -/* This structure is used to temporarily store arguments passed to an | |
| 301 | -** invocation of a command created using [proc]. A pointer to an | |
| 300 | +/* This structure is used to temporarily store arguments passed to an | |
| 301 | +** invocation of a command created using [proc]. A pointer to an | |
| 302 | 302 | ** instance is passed as the second argument to the proc_call2() function. |
| 303 | 303 | */ |
| 304 | 304 | typedef struct ProcArgs ProcArgs; |
| 305 | 305 | struct ProcArgs { |
| 306 | 306 | int argc; |
| @@ -323,11 +323,11 @@ | ||
| 323 | 323 | ProcArgs *pArgs = (ProcArgs *)pContext2; |
| 324 | 324 | |
| 325 | 325 | /* Check if there are the right number of arguments. If there are |
| 326 | 326 | ** not, generate a usage message for the command. |
| 327 | 327 | */ |
| 328 | - if( (pArgs->argc>(p->nParam+1) && !p->hasArgs) | |
| 328 | + if( (pArgs->argc>(p->nParam+1) && !p->hasArgs) | |
| 329 | 329 | || (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1]) |
| 330 | 330 | ){ |
| 331 | 331 | char *zUsage = 0; |
| 332 | 332 | int nUsage = 0; |
| 333 | 333 | Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]); |
| @@ -374,12 +374,12 @@ | ||
| 374 | 374 | ** created using the [proc] command. The second argument, pContext, |
| 375 | 375 | ** is a pointer to the associated ProcDefn structure. |
| 376 | 376 | */ |
| 377 | 377 | static int proc_call1( |
| 378 | 378 | Th_Interp *interp, |
| 379 | - void *pContext, | |
| 380 | - int argc, | |
| 379 | + void *pContext, | |
| 380 | + int argc, | |
| 381 | 381 | const char **argv, |
| 382 | 382 | int *argl |
| 383 | 383 | ){ |
| 384 | 384 | int rc; |
| 385 | 385 | |
| @@ -400,32 +400,32 @@ | ||
| 400 | 400 | } |
| 401 | 401 | return rc; |
| 402 | 402 | } |
| 403 | 403 | |
| 404 | 404 | /* |
| 405 | -** This function is registered as the delete callback for all commands | |
| 406 | -** created using the built-in [proc] command. It is called automatically | |
| 407 | -** when a command created using [proc] is deleted. | |
| 405 | +** This function is registered as the delete callback for all commands | |
| 406 | +** created using the built-in [proc] command. It is called automatically | |
| 407 | +** when a command created using [proc] is deleted. | |
| 408 | 408 | ** |
| 409 | 409 | ** It frees the ProcDefn structure allocated when the command was created. |
| 410 | -*/ | |
| 410 | +*/ | |
| 411 | 411 | static void proc_del(Th_Interp *interp, void *pContext){ |
| 412 | 412 | ProcDefn *p = (ProcDefn *)pContext; |
| 413 | 413 | Th_Free(interp, (void *)p->zUsage); |
| 414 | 414 | Th_Free(interp, (void *)p); |
| 415 | 415 | } |
| 416 | 416 | |
| 417 | 417 | /* |
| 418 | -** TH Syntax: | |
| 418 | +** TH Syntax: | |
| 419 | 419 | ** |
| 420 | 420 | ** proc name arglist code |
| 421 | 421 | */ |
| 422 | 422 | static int proc_command( |
| 423 | - Th_Interp *interp, | |
| 424 | - void *ctx, | |
| 423 | + Th_Interp *interp, | |
| 424 | + void *ctx, | |
| 425 | 425 | int argc, |
| 426 | - const char **argv, | |
| 426 | + const char **argv, | |
| 427 | 427 | int *argl |
| 428 | 428 | ){ |
| 429 | 429 | int rc; |
| 430 | 430 | char *zName; |
| 431 | 431 | |
| @@ -436,11 +436,11 @@ | ||
| 436 | 436 | |
| 437 | 437 | char **azParam; |
| 438 | 438 | int *anParam; |
| 439 | 439 | int nParam; |
| 440 | 440 | |
| 441 | - char *zUsage = 0; /* Build up a usage message here */ | |
| 441 | + char *zUsage = 0; /* Build up a usage message here */ | |
| 442 | 442 | int nUsage = 0; /* Number of bytes at zUsage */ |
| 443 | 443 | |
| 444 | 444 | if( argc!=4 ){ |
| 445 | 445 | return Th_WrongNumArgs(interp, "proc name arglist code"); |
| 446 | 446 | } |
| @@ -448,14 +448,14 @@ | ||
| 448 | 448 | return TH_ERROR; |
| 449 | 449 | } |
| 450 | 450 | |
| 451 | 451 | /* Allocate the new ProcDefn structure. */ |
| 452 | 452 | nByte = sizeof(ProcDefn) + /* ProcDefn structure */ |
| 453 | - (sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */ | |
| 454 | - (sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */ | |
| 453 | + (sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */ | |
| 454 | + (sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */ | |
| 455 | 455 | argl[3] + /* zProgram */ |
| 456 | - argl[2]; /* Space for copies of parameter names and default values */ | |
| 456 | + argl[2]; /* Space for copies of parameter names and default values */ | |
| 457 | 457 | p = (ProcDefn *)Th_Malloc(interp, nByte); |
| 458 | 458 | |
| 459 | 459 | /* If the last parameter in the parameter list is "args", then set the |
| 460 | 460 | ** ProcDefn.hasArgs flag. The "args" parameter does not require an |
| 461 | 461 | ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays. |
| @@ -472,11 +472,11 @@ | ||
| 472 | 472 | p->anDefault = (int *)&p->azDefault[nParam]; |
| 473 | 473 | p->zProgram = (char *)&p->anDefault[nParam]; |
| 474 | 474 | memcpy(p->zProgram, argv[3], argl[3]); |
| 475 | 475 | p->nProgram = argl[3]; |
| 476 | 476 | zSpace = &p->zProgram[p->nProgram]; |
| 477 | - | |
| 477 | + | |
| 478 | 478 | for(i=0; i<nParam; i++){ |
| 479 | 479 | char **az; |
| 480 | 480 | int *an; |
| 481 | 481 | int n; |
| 482 | 482 | if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){ |
| @@ -537,40 +537,40 @@ | ||
| 537 | 537 | Th_Free(interp, zUsage); |
| 538 | 538 | return TH_ERROR; |
| 539 | 539 | } |
| 540 | 540 | |
| 541 | 541 | /* |
| 542 | -** TH Syntax: | |
| 542 | +** TH Syntax: | |
| 543 | 543 | ** |
| 544 | 544 | ** rename oldcmd newcmd |
| 545 | 545 | */ |
| 546 | 546 | static int rename_command( |
| 547 | - Th_Interp *interp, | |
| 548 | - void *ctx, | |
| 547 | + Th_Interp *interp, | |
| 548 | + void *ctx, | |
| 549 | 549 | int argc, |
| 550 | - const char **argv, | |
| 550 | + const char **argv, | |
| 551 | 551 | int *argl |
| 552 | 552 | ){ |
| 553 | 553 | if( argc!=3 ){ |
| 554 | 554 | return Th_WrongNumArgs(interp, "rename oldcmd newcmd"); |
| 555 | 555 | } |
| 556 | 556 | return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]); |
| 557 | 557 | } |
| 558 | 558 | |
| 559 | 559 | /* |
| 560 | -** TH Syntax: | |
| 560 | +** TH Syntax: | |
| 561 | 561 | ** |
| 562 | 562 | ** break ?value...? |
| 563 | 563 | ** continue ?value...? |
| 564 | 564 | ** ok ?value...? |
| 565 | 565 | ** error ?value...? |
| 566 | 566 | */ |
| 567 | 567 | static int simple_command( |
| 568 | - Th_Interp *interp, | |
| 569 | - void *ctx, | |
| 570 | - int argc, | |
| 571 | - const char **argv, | |
| 568 | + Th_Interp *interp, | |
| 569 | + void *ctx, | |
| 570 | + int argc, | |
| 571 | + const char **argv, | |
| 572 | 572 | int *argl |
| 573 | 573 | ){ |
| 574 | 574 | if( argc!=1 && argc!=2 ){ |
| 575 | 575 | return Th_WrongNumArgs(interp, "return ?value?"); |
| 576 | 576 | } |
| @@ -579,19 +579,19 @@ | ||
| 579 | 579 | } |
| 580 | 580 | return FOSSIL_PTR_TO_INT(ctx); |
| 581 | 581 | } |
| 582 | 582 | |
| 583 | 583 | /* |
| 584 | -** TH Syntax: | |
| 584 | +** TH Syntax: | |
| 585 | 585 | ** |
| 586 | 586 | ** return ?-code code? ?value? |
| 587 | 587 | */ |
| 588 | 588 | static int return_command( |
| 589 | - Th_Interp *interp, | |
| 590 | - void *ctx, | |
| 591 | - int argc, | |
| 592 | - const char **argv, | |
| 589 | + Th_Interp *interp, | |
| 590 | + void *ctx, | |
| 591 | + int argc, | |
| 592 | + const char **argv, | |
| 593 | 593 | int *argl |
| 594 | 594 | ){ |
| 595 | 595 | int iCode = TH_RETURN; |
| 596 | 596 | if( argc<1 || argc>4 ){ |
| 597 | 597 | return Th_WrongNumArgs(interp, "return ?-code code? ?value?"); |
| @@ -638,11 +638,11 @@ | ||
| 638 | 638 | iRes = nLeft-nRight; |
| 639 | 639 | } |
| 640 | 640 | |
| 641 | 641 | if( iRes<0 ) iRes = -1; |
| 642 | 642 | if( iRes>0 ) iRes = 1; |
| 643 | - | |
| 643 | + | |
| 644 | 644 | return Th_SetResultInt(interp, iRes); |
| 645 | 645 | } |
| 646 | 646 | |
| 647 | 647 | /* |
| 648 | 648 | ** TH Syntax: |
| @@ -672,11 +672,11 @@ | ||
| 672 | 672 | if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){ |
| 673 | 673 | iRes = i; |
| 674 | 674 | break; |
| 675 | 675 | } |
| 676 | 676 | } |
| 677 | - | |
| 677 | + | |
| 678 | 678 | return Th_SetResultInt(interp, iRes); |
| 679 | 679 | } |
| 680 | 680 | |
| 681 | 681 | /* |
| 682 | 682 | ** TH Syntax: |
| @@ -733,11 +733,11 @@ | ||
| 733 | 733 | if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){ |
| 734 | 734 | iRes = i; |
| 735 | 735 | break; |
| 736 | 736 | } |
| 737 | 737 | } |
| 738 | - | |
| 738 | + | |
| 739 | 739 | return Th_SetResultInt(interp, iRes); |
| 740 | 740 | } |
| 741 | 741 | |
| 742 | 742 | /* |
| 743 | 743 | ** TH Syntax: |
| @@ -867,11 +867,11 @@ | ||
| 867 | 867 | ** TH Syntax: |
| 868 | 868 | ** |
| 869 | 869 | ** unset VAR |
| 870 | 870 | */ |
| 871 | 871 | static int unset_command( |
| 872 | - Th_Interp *interp, | |
| 872 | + Th_Interp *interp, | |
| 873 | 873 | void *ctx, |
| 874 | 874 | int argc, |
| 875 | 875 | const char **argv, |
| 876 | 876 | int *argl |
| 877 | 877 | ){ |
| @@ -880,11 +880,11 @@ | ||
| 880 | 880 | } |
| 881 | 881 | return Th_UnsetVar(interp, argv[1], argl[1]); |
| 882 | 882 | } |
| 883 | 883 | |
| 884 | 884 | int Th_CallSubCommand( |
| 885 | - Th_Interp *interp, | |
| 885 | + Th_Interp *interp, | |
| 886 | 886 | void *ctx, |
| 887 | 887 | int argc, |
| 888 | 888 | const char **argv, |
| 889 | 889 | int *argl, |
| 890 | 890 | Th_SubCommand *aSub |
| @@ -916,11 +916,11 @@ | ||
| 916 | 916 | ** string length STRING |
| 917 | 917 | ** string range STRING FIRST LAST |
| 918 | 918 | ** string repeat STRING COUNT |
| 919 | 919 | */ |
| 920 | 920 | static int string_command( |
| 921 | - Th_Interp *interp, | |
| 921 | + Th_Interp *interp, | |
| 922 | 922 | void *ctx, |
| 923 | 923 | int argc, |
| 924 | 924 | const char **argv, |
| 925 | 925 | int *argl |
| 926 | 926 | ){ |
| @@ -944,11 +944,11 @@ | ||
| 944 | 944 | ** TH Syntax: |
| 945 | 945 | ** |
| 946 | 946 | ** info exists VARNAME |
| 947 | 947 | */ |
| 948 | 948 | static int info_command( |
| 949 | - Th_Interp *interp, | |
| 949 | + Th_Interp *interp, | |
| 950 | 950 | void *ctx, |
| 951 | 951 | int argc, |
| 952 | 952 | const char **argv, |
| 953 | 953 | int *argl |
| 954 | 954 | ){ |
| @@ -958,20 +958,20 @@ | ||
| 958 | 958 | }; |
| 959 | 959 | return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub); |
| 960 | 960 | } |
| 961 | 961 | |
| 962 | 962 | /* |
| 963 | -** Convert the script level frame specification (used by the commands | |
| 964 | -** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as | |
| 963 | +** Convert the script level frame specification (used by the commands | |
| 964 | +** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as | |
| 965 | 965 | ** used by Th_LinkVar() and Th_Eval(). If successful, write the integer |
| 966 | 966 | ** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR |
| 967 | 967 | ** and leave an error message in the interpreter result. |
| 968 | 968 | */ |
| 969 | 969 | static int thToFrame( |
| 970 | - Th_Interp *interp, | |
| 971 | - const char *zFrame, | |
| 972 | - int nFrame, | |
| 970 | + Th_Interp *interp, | |
| 971 | + const char *zFrame, | |
| 972 | + int nFrame, | |
| 973 | 973 | int *piFrame |
| 974 | 974 | ){ |
| 975 | 975 | int iFrame; |
| 976 | 976 | if( th_isdigit(zFrame[0]) ){ |
| 977 | 977 | int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame); |
| @@ -992,11 +992,11 @@ | ||
| 992 | 992 | ** TH Syntax: |
| 993 | 993 | ** |
| 994 | 994 | ** uplevel ?LEVEL? SCRIPT |
| 995 | 995 | */ |
| 996 | 996 | static int uplevel_command( |
| 997 | - Th_Interp *interp, | |
| 997 | + Th_Interp *interp, | |
| 998 | 998 | void *ctx, |
| 999 | 999 | int argc, |
| 1000 | 1000 | const char **argv, |
| 1001 | 1001 | int *argl |
| 1002 | 1002 | ){ |
| @@ -1010,19 +1010,19 @@ | ||
| 1010 | 1010 | } |
| 1011 | 1011 | return Th_Eval(interp, iFrame, argv[argc-1], -1); |
| 1012 | 1012 | } |
| 1013 | 1013 | |
| 1014 | 1014 | /* |
| 1015 | -** TH Syntax: | |
| 1015 | +** TH Syntax: | |
| 1016 | 1016 | ** |
| 1017 | 1017 | ** upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...? |
| 1018 | 1018 | */ |
| 1019 | 1019 | static int upvar_command( |
| 1020 | - Th_Interp *interp, | |
| 1021 | - void *ctx, | |
| 1022 | - int argc, | |
| 1023 | - const char **argv, | |
| 1020 | + Th_Interp *interp, | |
| 1021 | + void *ctx, | |
| 1022 | + int argc, | |
| 1023 | + const char **argv, | |
| 1024 | 1024 | int *argl |
| 1025 | 1025 | ){ |
| 1026 | 1026 | int iVar = 1; |
| 1027 | 1027 | int iFrame = -1; |
| 1028 | 1028 | int rc = TH_OK; |
| @@ -1030,32 +1030,32 @@ | ||
| 1030 | 1030 | |
| 1031 | 1031 | if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){ |
| 1032 | 1032 | iVar++; |
| 1033 | 1033 | } |
| 1034 | 1034 | if( argc==iVar || (argc-iVar)%2 ){ |
| 1035 | - return Th_WrongNumArgs(interp, | |
| 1035 | + return Th_WrongNumArgs(interp, | |
| 1036 | 1036 | "upvar frame othervar myvar ?othervar myvar...?"); |
| 1037 | 1037 | } |
| 1038 | 1038 | for(i=iVar; rc==TH_OK && i<argc; i=i+2){ |
| 1039 | 1039 | rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]); |
| 1040 | 1040 | } |
| 1041 | 1041 | return rc; |
| 1042 | 1042 | } |
| 1043 | 1043 | |
| 1044 | 1044 | /* |
| 1045 | -** TH Syntax: | |
| 1045 | +** TH Syntax: | |
| 1046 | 1046 | ** |
| 1047 | 1047 | ** breakpoint ARGS |
| 1048 | 1048 | ** |
| 1049 | 1049 | ** This command does nothing at all. Its purpose in life is to serve |
| 1050 | 1050 | ** as a point for setting breakpoints in a debugger. |
| 1051 | 1051 | */ |
| 1052 | 1052 | static int breakpoint_command( |
| 1053 | - Th_Interp *interp, | |
| 1054 | - void *ctx, | |
| 1055 | - int argc, | |
| 1056 | - const char **argv, | |
| 1053 | + Th_Interp *interp, | |
| 1054 | + void *ctx, | |
| 1055 | + int argc, | |
| 1056 | + const char **argv, | |
| 1057 | 1057 | int *argl |
| 1058 | 1058 | ){ |
| 1059 | 1059 | int cnt = 0; |
| 1060 | 1060 | cnt++; |
| 1061 | 1061 | return TH_OK; |
| @@ -1078,11 +1078,11 @@ | ||
| 1078 | 1078 | {"if", if_command, 0}, |
| 1079 | 1079 | {"info", info_command, 0}, |
| 1080 | 1080 | {"lindex", lindex_command, 0}, |
| 1081 | 1081 | {"list", list_command, 0}, |
| 1082 | 1082 | {"llength", llength_command, 0}, |
| 1083 | - {"proc", proc_command, 0}, | |
| 1083 | + {"proc", proc_command, 0}, | |
| 1084 | 1084 | {"rename", rename_command, 0}, |
| 1085 | 1085 | {"set", set_command, 0}, |
| 1086 | 1086 | {"string", string_command, 0}, |
| 1087 | 1087 | {"unset", unset_command, 0}, |
| 1088 | 1088 | {"uplevel", uplevel_command, 0}, |
| @@ -1089,13 +1089,13 @@ | ||
| 1089 | 1089 | {"upvar", upvar_command, 0}, |
| 1090 | 1090 | |
| 1091 | 1091 | {"breakpoint", breakpoint_command, 0}, |
| 1092 | 1092 | |
| 1093 | 1093 | {"return", return_command, 0}, |
| 1094 | - {"break", simple_command, (void *)TH_BREAK}, | |
| 1095 | - {"continue", simple_command, (void *)TH_CONTINUE}, | |
| 1096 | - {"error", simple_command, (void *)TH_ERROR}, | |
| 1094 | + {"break", simple_command, (void *)TH_BREAK}, | |
| 1095 | + {"continue", simple_command, (void *)TH_CONTINUE}, | |
| 1096 | + {"error", simple_command, (void *)TH_ERROR}, | |
| 1097 | 1097 | |
| 1098 | 1098 | {0, 0, 0} |
| 1099 | 1099 | }; |
| 1100 | 1100 | int i; |
| 1101 | 1101 | |
| 1102 | 1102 |
| --- src/th_lang.c | |
| +++ src/th_lang.c | |
| @@ -1,12 +1,12 @@ | |
| 1 | |
| 2 | /* |
| 3 | ** This file contains the implementation of all of the TH language |
| 4 | ** built-in commands. |
| 5 | ** |
| 6 | ** All built-in commands are implemented using the public interface |
| 7 | ** declared in th.h, so this file serves as both a part of the language |
| 8 | ** implementation and an example of how to extend the language with |
| 9 | ** new commands. |
| 10 | */ |
| 11 | |
| 12 | #include "config.h" |
| @@ -18,19 +18,19 @@ | |
| 18 | Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1); |
| 19 | return TH_ERROR; |
| 20 | } |
| 21 | |
| 22 | /* |
| 23 | ** Syntax: |
| 24 | ** |
| 25 | ** catch script ?varname? |
| 26 | */ |
| 27 | static int catch_command( |
| 28 | Th_Interp *interp, |
| 29 | void *ctx, |
| 30 | int argc, |
| 31 | const char **argv, |
| 32 | int *argl |
| 33 | ){ |
| 34 | int rc; |
| 35 | |
| 36 | if( argc!=2 && argc!=3 ){ |
| @@ -47,19 +47,19 @@ | |
| 47 | Th_SetResultInt(interp, rc); |
| 48 | return TH_OK; |
| 49 | } |
| 50 | |
| 51 | /* |
| 52 | ** TH Syntax: |
| 53 | ** |
| 54 | ** if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN? |
| 55 | */ |
| 56 | static int if_command( |
| 57 | Th_Interp *interp, |
| 58 | void *ctx, |
| 59 | int argc, |
| 60 | const char **argv, |
| 61 | int *argl |
| 62 | ){ |
| 63 | int rc = TH_OK; |
| 64 | |
| 65 | int iCond; /* Result of evaluating expression */ |
| @@ -94,19 +94,19 @@ | |
| 94 | wrong_args: |
| 95 | return Th_WrongNumArgs(interp, "if ..."); |
| 96 | } |
| 97 | |
| 98 | /* |
| 99 | ** TH Syntax: |
| 100 | ** |
| 101 | ** expr expr |
| 102 | */ |
| 103 | static int expr_command( |
| 104 | Th_Interp *interp, |
| 105 | void *ctx, |
| 106 | int argc, |
| 107 | const char **argv, |
| 108 | int *argl |
| 109 | ){ |
| 110 | if( argc!=2 ){ |
| 111 | return Th_WrongNumArgs(interp, "expr expression"); |
| 112 | } |
| @@ -113,11 +113,11 @@ | |
| 113 | |
| 114 | return Th_Expr(interp, argv[1], argl[1]); |
| 115 | } |
| 116 | |
| 117 | /* |
| 118 | ** Evaluate the th1 script (zBody, nBody) in the local stack frame. |
| 119 | ** Return the result of the evaluation, except if the result |
| 120 | ** is TH_CONTINUE, return TH_OK instead. |
| 121 | */ |
| 122 | static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){ |
| 123 | int rc = Th_Eval(interp, 0, zBody, nBody); |
| @@ -126,19 +126,19 @@ | |
| 126 | } |
| 127 | return rc; |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | ** TH Syntax: |
| 132 | ** |
| 133 | ** for init condition incr script |
| 134 | */ |
| 135 | static int for_command( |
| 136 | Th_Interp *interp, |
| 137 | void *ctx, |
| 138 | int argc, |
| 139 | const char **argv, |
| 140 | int *argl |
| 141 | ){ |
| 142 | int rc; |
| 143 | int iCond; |
| 144 | |
| @@ -147,11 +147,11 @@ | |
| 147 | } |
| 148 | |
| 149 | /* Evaluate the 'init' script */ |
| 150 | rc = Th_Eval(interp, 0, argv[1], -1); |
| 151 | |
| 152 | while( rc==TH_OK |
| 153 | && TH_OK==(rc = Th_Expr(interp, argv[2], -1)) |
| 154 | && TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond)) |
| 155 | && iCond |
| 156 | && TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4])) |
| 157 | ){ |
| @@ -161,45 +161,45 @@ | |
| 161 | if( rc==TH_BREAK ) rc = TH_OK; |
| 162 | return rc; |
| 163 | } |
| 164 | |
| 165 | /* |
| 166 | ** TH Syntax: |
| 167 | ** |
| 168 | ** list ?arg1 ?arg2? ...? |
| 169 | */ |
| 170 | static int list_command( |
| 171 | Th_Interp *interp, |
| 172 | void *ctx, |
| 173 | int argc, |
| 174 | const char **argv, |
| 175 | int *argl |
| 176 | ){ |
| 177 | char *zList = 0; |
| 178 | int nList = 0; |
| 179 | int i; |
| 180 | |
| 181 | for(i=1; i<argc; i++){ |
| 182 | Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]); |
| 183 | } |
| 184 | |
| 185 | Th_SetResult(interp, zList, nList); |
| 186 | Th_Free(interp, zList); |
| 187 | |
| 188 | return TH_OK; |
| 189 | } |
| 190 | |
| 191 | /* |
| 192 | ** TH Syntax: |
| 193 | ** |
| 194 | ** lindex list index |
| 195 | */ |
| 196 | static int lindex_command( |
| 197 | Th_Interp *interp, |
| 198 | void *ctx, |
| 199 | int argc, |
| 200 | const char **argv, |
| 201 | int *argl |
| 202 | ){ |
| 203 | int iElem; |
| 204 | int rc; |
| 205 | |
| @@ -227,19 +227,19 @@ | |
| 227 | |
| 228 | return rc; |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | ** TH Syntax: |
| 233 | ** |
| 234 | ** llength list |
| 235 | */ |
| 236 | static int llength_command( |
| 237 | Th_Interp *interp, |
| 238 | void *ctx, |
| 239 | int argc, |
| 240 | const char **argv, |
| 241 | int *argl |
| 242 | ){ |
| 243 | int nElem; |
| 244 | int rc; |
| 245 | |
| @@ -254,19 +254,19 @@ | |
| 254 | |
| 255 | return rc; |
| 256 | } |
| 257 | |
| 258 | /* |
| 259 | ** TH Syntax: |
| 260 | ** |
| 261 | ** set varname ?value? |
| 262 | */ |
| 263 | static int set_command( |
| 264 | Th_Interp *interp, |
| 265 | void *ctx, |
| 266 | int argc, |
| 267 | const char **argv, |
| 268 | int *argl |
| 269 | ){ |
| 270 | if( argc!=2 && argc!=3 ){ |
| 271 | return Th_WrongNumArgs(interp, "set varname ?value?"); |
| 272 | } |
| @@ -277,30 +277,30 @@ | |
| 277 | return Th_GetVar(interp, argv[1], argl[1]); |
| 278 | } |
| 279 | |
| 280 | /* |
| 281 | ** When a new command is created using the built-in [proc] command, an |
| 282 | ** instance of the following structure is allocated and populated. A |
| 283 | ** pointer to the structure is passed as the context (second) argument |
| 284 | ** to function proc_call1() when the new command is executed. |
| 285 | */ |
| 286 | typedef struct ProcDefn ProcDefn; |
| 287 | struct ProcDefn { |
| 288 | int nParam; /* Number of formal (non "args") parameters */ |
| 289 | char **azParam; /* Parameter names */ |
| 290 | int *anParam; /* Lengths of parameter names */ |
| 291 | char **azDefault; /* Default values */ |
| 292 | int *anDefault; /* Lengths of default values */ |
| 293 | int hasArgs; /* True if there is an "args" parameter */ |
| 294 | char *zProgram; /* Body of proc */ |
| 295 | int nProgram; /* Number of bytes at zProgram */ |
| 296 | char *zUsage; /* Usage message */ |
| 297 | int nUsage; /* Number of bytes at zUsage */ |
| 298 | }; |
| 299 | |
| 300 | /* This structure is used to temporarily store arguments passed to an |
| 301 | ** invocation of a command created using [proc]. A pointer to an |
| 302 | ** instance is passed as the second argument to the proc_call2() function. |
| 303 | */ |
| 304 | typedef struct ProcArgs ProcArgs; |
| 305 | struct ProcArgs { |
| 306 | int argc; |
| @@ -323,11 +323,11 @@ | |
| 323 | ProcArgs *pArgs = (ProcArgs *)pContext2; |
| 324 | |
| 325 | /* Check if there are the right number of arguments. If there are |
| 326 | ** not, generate a usage message for the command. |
| 327 | */ |
| 328 | if( (pArgs->argc>(p->nParam+1) && !p->hasArgs) |
| 329 | || (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1]) |
| 330 | ){ |
| 331 | char *zUsage = 0; |
| 332 | int nUsage = 0; |
| 333 | Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]); |
| @@ -374,12 +374,12 @@ | |
| 374 | ** created using the [proc] command. The second argument, pContext, |
| 375 | ** is a pointer to the associated ProcDefn structure. |
| 376 | */ |
| 377 | static int proc_call1( |
| 378 | Th_Interp *interp, |
| 379 | void *pContext, |
| 380 | int argc, |
| 381 | const char **argv, |
| 382 | int *argl |
| 383 | ){ |
| 384 | int rc; |
| 385 | |
| @@ -400,32 +400,32 @@ | |
| 400 | } |
| 401 | return rc; |
| 402 | } |
| 403 | |
| 404 | /* |
| 405 | ** This function is registered as the delete callback for all commands |
| 406 | ** created using the built-in [proc] command. It is called automatically |
| 407 | ** when a command created using [proc] is deleted. |
| 408 | ** |
| 409 | ** It frees the ProcDefn structure allocated when the command was created. |
| 410 | */ |
| 411 | static void proc_del(Th_Interp *interp, void *pContext){ |
| 412 | ProcDefn *p = (ProcDefn *)pContext; |
| 413 | Th_Free(interp, (void *)p->zUsage); |
| 414 | Th_Free(interp, (void *)p); |
| 415 | } |
| 416 | |
| 417 | /* |
| 418 | ** TH Syntax: |
| 419 | ** |
| 420 | ** proc name arglist code |
| 421 | */ |
| 422 | static int proc_command( |
| 423 | Th_Interp *interp, |
| 424 | void *ctx, |
| 425 | int argc, |
| 426 | const char **argv, |
| 427 | int *argl |
| 428 | ){ |
| 429 | int rc; |
| 430 | char *zName; |
| 431 | |
| @@ -436,11 +436,11 @@ | |
| 436 | |
| 437 | char **azParam; |
| 438 | int *anParam; |
| 439 | int nParam; |
| 440 | |
| 441 | char *zUsage = 0; /* Build up a usage message here */ |
| 442 | int nUsage = 0; /* Number of bytes at zUsage */ |
| 443 | |
| 444 | if( argc!=4 ){ |
| 445 | return Th_WrongNumArgs(interp, "proc name arglist code"); |
| 446 | } |
| @@ -448,14 +448,14 @@ | |
| 448 | return TH_ERROR; |
| 449 | } |
| 450 | |
| 451 | /* Allocate the new ProcDefn structure. */ |
| 452 | nByte = sizeof(ProcDefn) + /* ProcDefn structure */ |
| 453 | (sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */ |
| 454 | (sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */ |
| 455 | argl[3] + /* zProgram */ |
| 456 | argl[2]; /* Space for copies of parameter names and default values */ |
| 457 | p = (ProcDefn *)Th_Malloc(interp, nByte); |
| 458 | |
| 459 | /* If the last parameter in the parameter list is "args", then set the |
| 460 | ** ProcDefn.hasArgs flag. The "args" parameter does not require an |
| 461 | ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays. |
| @@ -472,11 +472,11 @@ | |
| 472 | p->anDefault = (int *)&p->azDefault[nParam]; |
| 473 | p->zProgram = (char *)&p->anDefault[nParam]; |
| 474 | memcpy(p->zProgram, argv[3], argl[3]); |
| 475 | p->nProgram = argl[3]; |
| 476 | zSpace = &p->zProgram[p->nProgram]; |
| 477 | |
| 478 | for(i=0; i<nParam; i++){ |
| 479 | char **az; |
| 480 | int *an; |
| 481 | int n; |
| 482 | if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){ |
| @@ -537,40 +537,40 @@ | |
| 537 | Th_Free(interp, zUsage); |
| 538 | return TH_ERROR; |
| 539 | } |
| 540 | |
| 541 | /* |
| 542 | ** TH Syntax: |
| 543 | ** |
| 544 | ** rename oldcmd newcmd |
| 545 | */ |
| 546 | static int rename_command( |
| 547 | Th_Interp *interp, |
| 548 | void *ctx, |
| 549 | int argc, |
| 550 | const char **argv, |
| 551 | int *argl |
| 552 | ){ |
| 553 | if( argc!=3 ){ |
| 554 | return Th_WrongNumArgs(interp, "rename oldcmd newcmd"); |
| 555 | } |
| 556 | return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]); |
| 557 | } |
| 558 | |
| 559 | /* |
| 560 | ** TH Syntax: |
| 561 | ** |
| 562 | ** break ?value...? |
| 563 | ** continue ?value...? |
| 564 | ** ok ?value...? |
| 565 | ** error ?value...? |
| 566 | */ |
| 567 | static int simple_command( |
| 568 | Th_Interp *interp, |
| 569 | void *ctx, |
| 570 | int argc, |
| 571 | const char **argv, |
| 572 | int *argl |
| 573 | ){ |
| 574 | if( argc!=1 && argc!=2 ){ |
| 575 | return Th_WrongNumArgs(interp, "return ?value?"); |
| 576 | } |
| @@ -579,19 +579,19 @@ | |
| 579 | } |
| 580 | return FOSSIL_PTR_TO_INT(ctx); |
| 581 | } |
| 582 | |
| 583 | /* |
| 584 | ** TH Syntax: |
| 585 | ** |
| 586 | ** return ?-code code? ?value? |
| 587 | */ |
| 588 | static int return_command( |
| 589 | Th_Interp *interp, |
| 590 | void *ctx, |
| 591 | int argc, |
| 592 | const char **argv, |
| 593 | int *argl |
| 594 | ){ |
| 595 | int iCode = TH_RETURN; |
| 596 | if( argc<1 || argc>4 ){ |
| 597 | return Th_WrongNumArgs(interp, "return ?-code code? ?value?"); |
| @@ -638,11 +638,11 @@ | |
| 638 | iRes = nLeft-nRight; |
| 639 | } |
| 640 | |
| 641 | if( iRes<0 ) iRes = -1; |
| 642 | if( iRes>0 ) iRes = 1; |
| 643 | |
| 644 | return Th_SetResultInt(interp, iRes); |
| 645 | } |
| 646 | |
| 647 | /* |
| 648 | ** TH Syntax: |
| @@ -672,11 +672,11 @@ | |
| 672 | if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){ |
| 673 | iRes = i; |
| 674 | break; |
| 675 | } |
| 676 | } |
| 677 | |
| 678 | return Th_SetResultInt(interp, iRes); |
| 679 | } |
| 680 | |
| 681 | /* |
| 682 | ** TH Syntax: |
| @@ -733,11 +733,11 @@ | |
| 733 | if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){ |
| 734 | iRes = i; |
| 735 | break; |
| 736 | } |
| 737 | } |
| 738 | |
| 739 | return Th_SetResultInt(interp, iRes); |
| 740 | } |
| 741 | |
| 742 | /* |
| 743 | ** TH Syntax: |
| @@ -867,11 +867,11 @@ | |
| 867 | ** TH Syntax: |
| 868 | ** |
| 869 | ** unset VAR |
| 870 | */ |
| 871 | static int unset_command( |
| 872 | Th_Interp *interp, |
| 873 | void *ctx, |
| 874 | int argc, |
| 875 | const char **argv, |
| 876 | int *argl |
| 877 | ){ |
| @@ -880,11 +880,11 @@ | |
| 880 | } |
| 881 | return Th_UnsetVar(interp, argv[1], argl[1]); |
| 882 | } |
| 883 | |
| 884 | int Th_CallSubCommand( |
| 885 | Th_Interp *interp, |
| 886 | void *ctx, |
| 887 | int argc, |
| 888 | const char **argv, |
| 889 | int *argl, |
| 890 | Th_SubCommand *aSub |
| @@ -916,11 +916,11 @@ | |
| 916 | ** string length STRING |
| 917 | ** string range STRING FIRST LAST |
| 918 | ** string repeat STRING COUNT |
| 919 | */ |
| 920 | static int string_command( |
| 921 | Th_Interp *interp, |
| 922 | void *ctx, |
| 923 | int argc, |
| 924 | const char **argv, |
| 925 | int *argl |
| 926 | ){ |
| @@ -944,11 +944,11 @@ | |
| 944 | ** TH Syntax: |
| 945 | ** |
| 946 | ** info exists VARNAME |
| 947 | */ |
| 948 | static int info_command( |
| 949 | Th_Interp *interp, |
| 950 | void *ctx, |
| 951 | int argc, |
| 952 | const char **argv, |
| 953 | int *argl |
| 954 | ){ |
| @@ -958,20 +958,20 @@ | |
| 958 | }; |
| 959 | return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub); |
| 960 | } |
| 961 | |
| 962 | /* |
| 963 | ** Convert the script level frame specification (used by the commands |
| 964 | ** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as |
| 965 | ** used by Th_LinkVar() and Th_Eval(). If successful, write the integer |
| 966 | ** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR |
| 967 | ** and leave an error message in the interpreter result. |
| 968 | */ |
| 969 | static int thToFrame( |
| 970 | Th_Interp *interp, |
| 971 | const char *zFrame, |
| 972 | int nFrame, |
| 973 | int *piFrame |
| 974 | ){ |
| 975 | int iFrame; |
| 976 | if( th_isdigit(zFrame[0]) ){ |
| 977 | int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame); |
| @@ -992,11 +992,11 @@ | |
| 992 | ** TH Syntax: |
| 993 | ** |
| 994 | ** uplevel ?LEVEL? SCRIPT |
| 995 | */ |
| 996 | static int uplevel_command( |
| 997 | Th_Interp *interp, |
| 998 | void *ctx, |
| 999 | int argc, |
| 1000 | const char **argv, |
| 1001 | int *argl |
| 1002 | ){ |
| @@ -1010,19 +1010,19 @@ | |
| 1010 | } |
| 1011 | return Th_Eval(interp, iFrame, argv[argc-1], -1); |
| 1012 | } |
| 1013 | |
| 1014 | /* |
| 1015 | ** TH Syntax: |
| 1016 | ** |
| 1017 | ** upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...? |
| 1018 | */ |
| 1019 | static int upvar_command( |
| 1020 | Th_Interp *interp, |
| 1021 | void *ctx, |
| 1022 | int argc, |
| 1023 | const char **argv, |
| 1024 | int *argl |
| 1025 | ){ |
| 1026 | int iVar = 1; |
| 1027 | int iFrame = -1; |
| 1028 | int rc = TH_OK; |
| @@ -1030,32 +1030,32 @@ | |
| 1030 | |
| 1031 | if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){ |
| 1032 | iVar++; |
| 1033 | } |
| 1034 | if( argc==iVar || (argc-iVar)%2 ){ |
| 1035 | return Th_WrongNumArgs(interp, |
| 1036 | "upvar frame othervar myvar ?othervar myvar...?"); |
| 1037 | } |
| 1038 | for(i=iVar; rc==TH_OK && i<argc; i=i+2){ |
| 1039 | rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]); |
| 1040 | } |
| 1041 | return rc; |
| 1042 | } |
| 1043 | |
| 1044 | /* |
| 1045 | ** TH Syntax: |
| 1046 | ** |
| 1047 | ** breakpoint ARGS |
| 1048 | ** |
| 1049 | ** This command does nothing at all. Its purpose in life is to serve |
| 1050 | ** as a point for setting breakpoints in a debugger. |
| 1051 | */ |
| 1052 | static int breakpoint_command( |
| 1053 | Th_Interp *interp, |
| 1054 | void *ctx, |
| 1055 | int argc, |
| 1056 | const char **argv, |
| 1057 | int *argl |
| 1058 | ){ |
| 1059 | int cnt = 0; |
| 1060 | cnt++; |
| 1061 | return TH_OK; |
| @@ -1078,11 +1078,11 @@ | |
| 1078 | {"if", if_command, 0}, |
| 1079 | {"info", info_command, 0}, |
| 1080 | {"lindex", lindex_command, 0}, |
| 1081 | {"list", list_command, 0}, |
| 1082 | {"llength", llength_command, 0}, |
| 1083 | {"proc", proc_command, 0}, |
| 1084 | {"rename", rename_command, 0}, |
| 1085 | {"set", set_command, 0}, |
| 1086 | {"string", string_command, 0}, |
| 1087 | {"unset", unset_command, 0}, |
| 1088 | {"uplevel", uplevel_command, 0}, |
| @@ -1089,13 +1089,13 @@ | |
| 1089 | {"upvar", upvar_command, 0}, |
| 1090 | |
| 1091 | {"breakpoint", breakpoint_command, 0}, |
| 1092 | |
| 1093 | {"return", return_command, 0}, |
| 1094 | {"break", simple_command, (void *)TH_BREAK}, |
| 1095 | {"continue", simple_command, (void *)TH_CONTINUE}, |
| 1096 | {"error", simple_command, (void *)TH_ERROR}, |
| 1097 | |
| 1098 | {0, 0, 0} |
| 1099 | }; |
| 1100 | int i; |
| 1101 | |
| 1102 |
| --- src/th_lang.c | |
| +++ src/th_lang.c | |
| @@ -1,12 +1,12 @@ | |
| 1 | |
| 2 | /* |
| 3 | ** This file contains the implementation of all of the TH language |
| 4 | ** built-in commands. |
| 5 | ** |
| 6 | ** All built-in commands are implemented using the public interface |
| 7 | ** declared in th.h, so this file serves as both a part of the language |
| 8 | ** implementation and an example of how to extend the language with |
| 9 | ** new commands. |
| 10 | */ |
| 11 | |
| 12 | #include "config.h" |
| @@ -18,19 +18,19 @@ | |
| 18 | Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1); |
| 19 | return TH_ERROR; |
| 20 | } |
| 21 | |
| 22 | /* |
| 23 | ** Syntax: |
| 24 | ** |
| 25 | ** catch script ?varname? |
| 26 | */ |
| 27 | static int catch_command( |
| 28 | Th_Interp *interp, |
| 29 | void *ctx, |
| 30 | int argc, |
| 31 | const char **argv, |
| 32 | int *argl |
| 33 | ){ |
| 34 | int rc; |
| 35 | |
| 36 | if( argc!=2 && argc!=3 ){ |
| @@ -47,19 +47,19 @@ | |
| 47 | Th_SetResultInt(interp, rc); |
| 48 | return TH_OK; |
| 49 | } |
| 50 | |
| 51 | /* |
| 52 | ** TH Syntax: |
| 53 | ** |
| 54 | ** if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN? |
| 55 | */ |
| 56 | static int if_command( |
| 57 | Th_Interp *interp, |
| 58 | void *ctx, |
| 59 | int argc, |
| 60 | const char **argv, |
| 61 | int *argl |
| 62 | ){ |
| 63 | int rc = TH_OK; |
| 64 | |
| 65 | int iCond; /* Result of evaluating expression */ |
| @@ -94,19 +94,19 @@ | |
| 94 | wrong_args: |
| 95 | return Th_WrongNumArgs(interp, "if ..."); |
| 96 | } |
| 97 | |
| 98 | /* |
| 99 | ** TH Syntax: |
| 100 | ** |
| 101 | ** expr expr |
| 102 | */ |
| 103 | static int expr_command( |
| 104 | Th_Interp *interp, |
| 105 | void *ctx, |
| 106 | int argc, |
| 107 | const char **argv, |
| 108 | int *argl |
| 109 | ){ |
| 110 | if( argc!=2 ){ |
| 111 | return Th_WrongNumArgs(interp, "expr expression"); |
| 112 | } |
| @@ -113,11 +113,11 @@ | |
| 113 | |
| 114 | return Th_Expr(interp, argv[1], argl[1]); |
| 115 | } |
| 116 | |
| 117 | /* |
| 118 | ** Evaluate the th1 script (zBody, nBody) in the local stack frame. |
| 119 | ** Return the result of the evaluation, except if the result |
| 120 | ** is TH_CONTINUE, return TH_OK instead. |
| 121 | */ |
| 122 | static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){ |
| 123 | int rc = Th_Eval(interp, 0, zBody, nBody); |
| @@ -126,19 +126,19 @@ | |
| 126 | } |
| 127 | return rc; |
| 128 | } |
| 129 | |
| 130 | /* |
| 131 | ** TH Syntax: |
| 132 | ** |
| 133 | ** for init condition incr script |
| 134 | */ |
| 135 | static int for_command( |
| 136 | Th_Interp *interp, |
| 137 | void *ctx, |
| 138 | int argc, |
| 139 | const char **argv, |
| 140 | int *argl |
| 141 | ){ |
| 142 | int rc; |
| 143 | int iCond; |
| 144 | |
| @@ -147,11 +147,11 @@ | |
| 147 | } |
| 148 | |
| 149 | /* Evaluate the 'init' script */ |
| 150 | rc = Th_Eval(interp, 0, argv[1], -1); |
| 151 | |
| 152 | while( rc==TH_OK |
| 153 | && TH_OK==(rc = Th_Expr(interp, argv[2], -1)) |
| 154 | && TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond)) |
| 155 | && iCond |
| 156 | && TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4])) |
| 157 | ){ |
| @@ -161,45 +161,45 @@ | |
| 161 | if( rc==TH_BREAK ) rc = TH_OK; |
| 162 | return rc; |
| 163 | } |
| 164 | |
| 165 | /* |
| 166 | ** TH Syntax: |
| 167 | ** |
| 168 | ** list ?arg1 ?arg2? ...? |
| 169 | */ |
| 170 | static int list_command( |
| 171 | Th_Interp *interp, |
| 172 | void *ctx, |
| 173 | int argc, |
| 174 | const char **argv, |
| 175 | int *argl |
| 176 | ){ |
| 177 | char *zList = 0; |
| 178 | int nList = 0; |
| 179 | int i; |
| 180 | |
| 181 | for(i=1; i<argc; i++){ |
| 182 | Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]); |
| 183 | } |
| 184 | |
| 185 | Th_SetResult(interp, zList, nList); |
| 186 | Th_Free(interp, zList); |
| 187 | |
| 188 | return TH_OK; |
| 189 | } |
| 190 | |
| 191 | /* |
| 192 | ** TH Syntax: |
| 193 | ** |
| 194 | ** lindex list index |
| 195 | */ |
| 196 | static int lindex_command( |
| 197 | Th_Interp *interp, |
| 198 | void *ctx, |
| 199 | int argc, |
| 200 | const char **argv, |
| 201 | int *argl |
| 202 | ){ |
| 203 | int iElem; |
| 204 | int rc; |
| 205 | |
| @@ -227,19 +227,19 @@ | |
| 227 | |
| 228 | return rc; |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | ** TH Syntax: |
| 233 | ** |
| 234 | ** llength list |
| 235 | */ |
| 236 | static int llength_command( |
| 237 | Th_Interp *interp, |
| 238 | void *ctx, |
| 239 | int argc, |
| 240 | const char **argv, |
| 241 | int *argl |
| 242 | ){ |
| 243 | int nElem; |
| 244 | int rc; |
| 245 | |
| @@ -254,19 +254,19 @@ | |
| 254 | |
| 255 | return rc; |
| 256 | } |
| 257 | |
| 258 | /* |
| 259 | ** TH Syntax: |
| 260 | ** |
| 261 | ** set varname ?value? |
| 262 | */ |
| 263 | static int set_command( |
| 264 | Th_Interp *interp, |
| 265 | void *ctx, |
| 266 | int argc, |
| 267 | const char **argv, |
| 268 | int *argl |
| 269 | ){ |
| 270 | if( argc!=2 && argc!=3 ){ |
| 271 | return Th_WrongNumArgs(interp, "set varname ?value?"); |
| 272 | } |
| @@ -277,30 +277,30 @@ | |
| 277 | return Th_GetVar(interp, argv[1], argl[1]); |
| 278 | } |
| 279 | |
| 280 | /* |
| 281 | ** When a new command is created using the built-in [proc] command, an |
| 282 | ** instance of the following structure is allocated and populated. A |
| 283 | ** pointer to the structure is passed as the context (second) argument |
| 284 | ** to function proc_call1() when the new command is executed. |
| 285 | */ |
| 286 | typedef struct ProcDefn ProcDefn; |
| 287 | struct ProcDefn { |
| 288 | int nParam; /* Number of formal (non "args") parameters */ |
| 289 | char **azParam; /* Parameter names */ |
| 290 | int *anParam; /* Lengths of parameter names */ |
| 291 | char **azDefault; /* Default values */ |
| 292 | int *anDefault; /* Lengths of default values */ |
| 293 | int hasArgs; /* True if there is an "args" parameter */ |
| 294 | char *zProgram; /* Body of proc */ |
| 295 | int nProgram; /* Number of bytes at zProgram */ |
| 296 | char *zUsage; /* Usage message */ |
| 297 | int nUsage; /* Number of bytes at zUsage */ |
| 298 | }; |
| 299 | |
| 300 | /* This structure is used to temporarily store arguments passed to an |
| 301 | ** invocation of a command created using [proc]. A pointer to an |
| 302 | ** instance is passed as the second argument to the proc_call2() function. |
| 303 | */ |
| 304 | typedef struct ProcArgs ProcArgs; |
| 305 | struct ProcArgs { |
| 306 | int argc; |
| @@ -323,11 +323,11 @@ | |
| 323 | ProcArgs *pArgs = (ProcArgs *)pContext2; |
| 324 | |
| 325 | /* Check if there are the right number of arguments. If there are |
| 326 | ** not, generate a usage message for the command. |
| 327 | */ |
| 328 | if( (pArgs->argc>(p->nParam+1) && !p->hasArgs) |
| 329 | || (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1]) |
| 330 | ){ |
| 331 | char *zUsage = 0; |
| 332 | int nUsage = 0; |
| 333 | Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]); |
| @@ -374,12 +374,12 @@ | |
| 374 | ** created using the [proc] command. The second argument, pContext, |
| 375 | ** is a pointer to the associated ProcDefn structure. |
| 376 | */ |
| 377 | static int proc_call1( |
| 378 | Th_Interp *interp, |
| 379 | void *pContext, |
| 380 | int argc, |
| 381 | const char **argv, |
| 382 | int *argl |
| 383 | ){ |
| 384 | int rc; |
| 385 | |
| @@ -400,32 +400,32 @@ | |
| 400 | } |
| 401 | return rc; |
| 402 | } |
| 403 | |
| 404 | /* |
| 405 | ** This function is registered as the delete callback for all commands |
| 406 | ** created using the built-in [proc] command. It is called automatically |
| 407 | ** when a command created using [proc] is deleted. |
| 408 | ** |
| 409 | ** It frees the ProcDefn structure allocated when the command was created. |
| 410 | */ |
| 411 | static void proc_del(Th_Interp *interp, void *pContext){ |
| 412 | ProcDefn *p = (ProcDefn *)pContext; |
| 413 | Th_Free(interp, (void *)p->zUsage); |
| 414 | Th_Free(interp, (void *)p); |
| 415 | } |
| 416 | |
| 417 | /* |
| 418 | ** TH Syntax: |
| 419 | ** |
| 420 | ** proc name arglist code |
| 421 | */ |
| 422 | static int proc_command( |
| 423 | Th_Interp *interp, |
| 424 | void *ctx, |
| 425 | int argc, |
| 426 | const char **argv, |
| 427 | int *argl |
| 428 | ){ |
| 429 | int rc; |
| 430 | char *zName; |
| 431 | |
| @@ -436,11 +436,11 @@ | |
| 436 | |
| 437 | char **azParam; |
| 438 | int *anParam; |
| 439 | int nParam; |
| 440 | |
| 441 | char *zUsage = 0; /* Build up a usage message here */ |
| 442 | int nUsage = 0; /* Number of bytes at zUsage */ |
| 443 | |
| 444 | if( argc!=4 ){ |
| 445 | return Th_WrongNumArgs(interp, "proc name arglist code"); |
| 446 | } |
| @@ -448,14 +448,14 @@ | |
| 448 | return TH_ERROR; |
| 449 | } |
| 450 | |
| 451 | /* Allocate the new ProcDefn structure. */ |
| 452 | nByte = sizeof(ProcDefn) + /* ProcDefn structure */ |
| 453 | (sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */ |
| 454 | (sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */ |
| 455 | argl[3] + /* zProgram */ |
| 456 | argl[2]; /* Space for copies of parameter names and default values */ |
| 457 | p = (ProcDefn *)Th_Malloc(interp, nByte); |
| 458 | |
| 459 | /* If the last parameter in the parameter list is "args", then set the |
| 460 | ** ProcDefn.hasArgs flag. The "args" parameter does not require an |
| 461 | ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays. |
| @@ -472,11 +472,11 @@ | |
| 472 | p->anDefault = (int *)&p->azDefault[nParam]; |
| 473 | p->zProgram = (char *)&p->anDefault[nParam]; |
| 474 | memcpy(p->zProgram, argv[3], argl[3]); |
| 475 | p->nProgram = argl[3]; |
| 476 | zSpace = &p->zProgram[p->nProgram]; |
| 477 | |
| 478 | for(i=0; i<nParam; i++){ |
| 479 | char **az; |
| 480 | int *an; |
| 481 | int n; |
| 482 | if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){ |
| @@ -537,40 +537,40 @@ | |
| 537 | Th_Free(interp, zUsage); |
| 538 | return TH_ERROR; |
| 539 | } |
| 540 | |
| 541 | /* |
| 542 | ** TH Syntax: |
| 543 | ** |
| 544 | ** rename oldcmd newcmd |
| 545 | */ |
| 546 | static int rename_command( |
| 547 | Th_Interp *interp, |
| 548 | void *ctx, |
| 549 | int argc, |
| 550 | const char **argv, |
| 551 | int *argl |
| 552 | ){ |
| 553 | if( argc!=3 ){ |
| 554 | return Th_WrongNumArgs(interp, "rename oldcmd newcmd"); |
| 555 | } |
| 556 | return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]); |
| 557 | } |
| 558 | |
| 559 | /* |
| 560 | ** TH Syntax: |
| 561 | ** |
| 562 | ** break ?value...? |
| 563 | ** continue ?value...? |
| 564 | ** ok ?value...? |
| 565 | ** error ?value...? |
| 566 | */ |
| 567 | static int simple_command( |
| 568 | Th_Interp *interp, |
| 569 | void *ctx, |
| 570 | int argc, |
| 571 | const char **argv, |
| 572 | int *argl |
| 573 | ){ |
| 574 | if( argc!=1 && argc!=2 ){ |
| 575 | return Th_WrongNumArgs(interp, "return ?value?"); |
| 576 | } |
| @@ -579,19 +579,19 @@ | |
| 579 | } |
| 580 | return FOSSIL_PTR_TO_INT(ctx); |
| 581 | } |
| 582 | |
| 583 | /* |
| 584 | ** TH Syntax: |
| 585 | ** |
| 586 | ** return ?-code code? ?value? |
| 587 | */ |
| 588 | static int return_command( |
| 589 | Th_Interp *interp, |
| 590 | void *ctx, |
| 591 | int argc, |
| 592 | const char **argv, |
| 593 | int *argl |
| 594 | ){ |
| 595 | int iCode = TH_RETURN; |
| 596 | if( argc<1 || argc>4 ){ |
| 597 | return Th_WrongNumArgs(interp, "return ?-code code? ?value?"); |
| @@ -638,11 +638,11 @@ | |
| 638 | iRes = nLeft-nRight; |
| 639 | } |
| 640 | |
| 641 | if( iRes<0 ) iRes = -1; |
| 642 | if( iRes>0 ) iRes = 1; |
| 643 | |
| 644 | return Th_SetResultInt(interp, iRes); |
| 645 | } |
| 646 | |
| 647 | /* |
| 648 | ** TH Syntax: |
| @@ -672,11 +672,11 @@ | |
| 672 | if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){ |
| 673 | iRes = i; |
| 674 | break; |
| 675 | } |
| 676 | } |
| 677 | |
| 678 | return Th_SetResultInt(interp, iRes); |
| 679 | } |
| 680 | |
| 681 | /* |
| 682 | ** TH Syntax: |
| @@ -733,11 +733,11 @@ | |
| 733 | if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){ |
| 734 | iRes = i; |
| 735 | break; |
| 736 | } |
| 737 | } |
| 738 | |
| 739 | return Th_SetResultInt(interp, iRes); |
| 740 | } |
| 741 | |
| 742 | /* |
| 743 | ** TH Syntax: |
| @@ -867,11 +867,11 @@ | |
| 867 | ** TH Syntax: |
| 868 | ** |
| 869 | ** unset VAR |
| 870 | */ |
| 871 | static int unset_command( |
| 872 | Th_Interp *interp, |
| 873 | void *ctx, |
| 874 | int argc, |
| 875 | const char **argv, |
| 876 | int *argl |
| 877 | ){ |
| @@ -880,11 +880,11 @@ | |
| 880 | } |
| 881 | return Th_UnsetVar(interp, argv[1], argl[1]); |
| 882 | } |
| 883 | |
| 884 | int Th_CallSubCommand( |
| 885 | Th_Interp *interp, |
| 886 | void *ctx, |
| 887 | int argc, |
| 888 | const char **argv, |
| 889 | int *argl, |
| 890 | Th_SubCommand *aSub |
| @@ -916,11 +916,11 @@ | |
| 916 | ** string length STRING |
| 917 | ** string range STRING FIRST LAST |
| 918 | ** string repeat STRING COUNT |
| 919 | */ |
| 920 | static int string_command( |
| 921 | Th_Interp *interp, |
| 922 | void *ctx, |
| 923 | int argc, |
| 924 | const char **argv, |
| 925 | int *argl |
| 926 | ){ |
| @@ -944,11 +944,11 @@ | |
| 944 | ** TH Syntax: |
| 945 | ** |
| 946 | ** info exists VARNAME |
| 947 | */ |
| 948 | static int info_command( |
| 949 | Th_Interp *interp, |
| 950 | void *ctx, |
| 951 | int argc, |
| 952 | const char **argv, |
| 953 | int *argl |
| 954 | ){ |
| @@ -958,20 +958,20 @@ | |
| 958 | }; |
| 959 | return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub); |
| 960 | } |
| 961 | |
| 962 | /* |
| 963 | ** Convert the script level frame specification (used by the commands |
| 964 | ** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as |
| 965 | ** used by Th_LinkVar() and Th_Eval(). If successful, write the integer |
| 966 | ** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR |
| 967 | ** and leave an error message in the interpreter result. |
| 968 | */ |
| 969 | static int thToFrame( |
| 970 | Th_Interp *interp, |
| 971 | const char *zFrame, |
| 972 | int nFrame, |
| 973 | int *piFrame |
| 974 | ){ |
| 975 | int iFrame; |
| 976 | if( th_isdigit(zFrame[0]) ){ |
| 977 | int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame); |
| @@ -992,11 +992,11 @@ | |
| 992 | ** TH Syntax: |
| 993 | ** |
| 994 | ** uplevel ?LEVEL? SCRIPT |
| 995 | */ |
| 996 | static int uplevel_command( |
| 997 | Th_Interp *interp, |
| 998 | void *ctx, |
| 999 | int argc, |
| 1000 | const char **argv, |
| 1001 | int *argl |
| 1002 | ){ |
| @@ -1010,19 +1010,19 @@ | |
| 1010 | } |
| 1011 | return Th_Eval(interp, iFrame, argv[argc-1], -1); |
| 1012 | } |
| 1013 | |
| 1014 | /* |
| 1015 | ** TH Syntax: |
| 1016 | ** |
| 1017 | ** upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...? |
| 1018 | */ |
| 1019 | static int upvar_command( |
| 1020 | Th_Interp *interp, |
| 1021 | void *ctx, |
| 1022 | int argc, |
| 1023 | const char **argv, |
| 1024 | int *argl |
| 1025 | ){ |
| 1026 | int iVar = 1; |
| 1027 | int iFrame = -1; |
| 1028 | int rc = TH_OK; |
| @@ -1030,32 +1030,32 @@ | |
| 1030 | |
| 1031 | if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){ |
| 1032 | iVar++; |
| 1033 | } |
| 1034 | if( argc==iVar || (argc-iVar)%2 ){ |
| 1035 | return Th_WrongNumArgs(interp, |
| 1036 | "upvar frame othervar myvar ?othervar myvar...?"); |
| 1037 | } |
| 1038 | for(i=iVar; rc==TH_OK && i<argc; i=i+2){ |
| 1039 | rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]); |
| 1040 | } |
| 1041 | return rc; |
| 1042 | } |
| 1043 | |
| 1044 | /* |
| 1045 | ** TH Syntax: |
| 1046 | ** |
| 1047 | ** breakpoint ARGS |
| 1048 | ** |
| 1049 | ** This command does nothing at all. Its purpose in life is to serve |
| 1050 | ** as a point for setting breakpoints in a debugger. |
| 1051 | */ |
| 1052 | static int breakpoint_command( |
| 1053 | Th_Interp *interp, |
| 1054 | void *ctx, |
| 1055 | int argc, |
| 1056 | const char **argv, |
| 1057 | int *argl |
| 1058 | ){ |
| 1059 | int cnt = 0; |
| 1060 | cnt++; |
| 1061 | return TH_OK; |
| @@ -1078,11 +1078,11 @@ | |
| 1078 | {"if", if_command, 0}, |
| 1079 | {"info", info_command, 0}, |
| 1080 | {"lindex", lindex_command, 0}, |
| 1081 | {"list", list_command, 0}, |
| 1082 | {"llength", llength_command, 0}, |
| 1083 | {"proc", proc_command, 0}, |
| 1084 | {"rename", rename_command, 0}, |
| 1085 | {"set", set_command, 0}, |
| 1086 | {"string", string_command, 0}, |
| 1087 | {"unset", unset_command, 0}, |
| 1088 | {"uplevel", uplevel_command, 0}, |
| @@ -1089,13 +1089,13 @@ | |
| 1089 | {"upvar", upvar_command, 0}, |
| 1090 | |
| 1091 | {"breakpoint", breakpoint_command, 0}, |
| 1092 | |
| 1093 | {"return", return_command, 0}, |
| 1094 | {"break", simple_command, (void *)TH_BREAK}, |
| 1095 | {"continue", simple_command, (void *)TH_CONTINUE}, |
| 1096 | {"error", simple_command, (void *)TH_ERROR}, |
| 1097 | |
| 1098 | {0, 0, 0} |
| 1099 | }; |
| 1100 | int i; |
| 1101 | |
| 1102 |
+10
-2
| --- src/th_main.c | ||
| +++ src/th_main.c | ||
| @@ -57,10 +57,17 @@ | ||
| 57 | 57 | nOutstandingMalloc--; |
| 58 | 58 | } |
| 59 | 59 | free(p); |
| 60 | 60 | } |
| 61 | 61 | static Th_Vtab vtab = { xMalloc, xFree }; |
| 62 | + | |
| 63 | +/* | |
| 64 | +** Returns the number of outstanding TH1 memory allocations. | |
| 65 | +*/ | |
| 66 | +int Th_GetOutstandingMalloc(){ | |
| 67 | + return nOutstandingMalloc; | |
| 68 | +} | |
| 62 | 69 | |
| 63 | 70 | /* |
| 64 | 71 | ** Generate a TH1 trace message if debugging is enabled. |
| 65 | 72 | */ |
| 66 | 73 | void Th_Trace(const char *zFormat, ...){ |
| @@ -255,11 +262,11 @@ | ||
| 255 | 262 | const char **argv, |
| 256 | 263 | int *argl |
| 257 | 264 | ){ |
| 258 | 265 | char *zOut; |
| 259 | 266 | if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){ |
| 260 | - zOut = db_text("??", "SELECT datetime('now','localtime')"); | |
| 267 | + zOut = db_text("??", "SELECT datetime('now'%s)", timeline_utc()); | |
| 261 | 268 | }else{ |
| 262 | 269 | zOut = db_text("??", "SELECT datetime('now')"); |
| 263 | 270 | } |
| 264 | 271 | Th_SetResult(interp, zOut, -1); |
| 265 | 272 | free(zOut); |
| @@ -1004,11 +1011,12 @@ | ||
| 1004 | 1011 | } |
| 1005 | 1012 | if( forceReset || created ){ |
| 1006 | 1013 | th_register_language(g.interp); /* Basic scripting commands. */ |
| 1007 | 1014 | } |
| 1008 | 1015 | #ifdef FOSSIL_ENABLE_TCL |
| 1009 | - if( forceTcl || getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){ | |
| 1016 | + if( forceTcl || fossil_getenv("TH1_ENABLE_TCL")!=0 || | |
| 1017 | + db_get_boolean("tcl", 0) ){ | |
| 1010 | 1018 | if( !g.tcl.setup ){ |
| 1011 | 1019 | g.tcl.setup = db_get("tcl-setup", 0); /* Grab Tcl setup script. */ |
| 1012 | 1020 | } |
| 1013 | 1021 | th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */ |
| 1014 | 1022 | } |
| 1015 | 1023 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -57,10 +57,17 @@ | |
| 57 | nOutstandingMalloc--; |
| 58 | } |
| 59 | free(p); |
| 60 | } |
| 61 | static Th_Vtab vtab = { xMalloc, xFree }; |
| 62 | |
| 63 | /* |
| 64 | ** Generate a TH1 trace message if debugging is enabled. |
| 65 | */ |
| 66 | void Th_Trace(const char *zFormat, ...){ |
| @@ -255,11 +262,11 @@ | |
| 255 | const char **argv, |
| 256 | int *argl |
| 257 | ){ |
| 258 | char *zOut; |
| 259 | if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){ |
| 260 | zOut = db_text("??", "SELECT datetime('now','localtime')"); |
| 261 | }else{ |
| 262 | zOut = db_text("??", "SELECT datetime('now')"); |
| 263 | } |
| 264 | Th_SetResult(interp, zOut, -1); |
| 265 | free(zOut); |
| @@ -1004,11 +1011,12 @@ | |
| 1004 | } |
| 1005 | if( forceReset || created ){ |
| 1006 | th_register_language(g.interp); /* Basic scripting commands. */ |
| 1007 | } |
| 1008 | #ifdef FOSSIL_ENABLE_TCL |
| 1009 | if( forceTcl || getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){ |
| 1010 | if( !g.tcl.setup ){ |
| 1011 | g.tcl.setup = db_get("tcl-setup", 0); /* Grab Tcl setup script. */ |
| 1012 | } |
| 1013 | th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */ |
| 1014 | } |
| 1015 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -57,10 +57,17 @@ | |
| 57 | nOutstandingMalloc--; |
| 58 | } |
| 59 | free(p); |
| 60 | } |
| 61 | static Th_Vtab vtab = { xMalloc, xFree }; |
| 62 | |
| 63 | /* |
| 64 | ** Returns the number of outstanding TH1 memory allocations. |
| 65 | */ |
| 66 | int Th_GetOutstandingMalloc(){ |
| 67 | return nOutstandingMalloc; |
| 68 | } |
| 69 | |
| 70 | /* |
| 71 | ** Generate a TH1 trace message if debugging is enabled. |
| 72 | */ |
| 73 | void Th_Trace(const char *zFormat, ...){ |
| @@ -255,11 +262,11 @@ | |
| 262 | const char **argv, |
| 263 | int *argl |
| 264 | ){ |
| 265 | char *zOut; |
| 266 | if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){ |
| 267 | zOut = db_text("??", "SELECT datetime('now'%s)", timeline_utc()); |
| 268 | }else{ |
| 269 | zOut = db_text("??", "SELECT datetime('now')"); |
| 270 | } |
| 271 | Th_SetResult(interp, zOut, -1); |
| 272 | free(zOut); |
| @@ -1004,11 +1011,12 @@ | |
| 1011 | } |
| 1012 | if( forceReset || created ){ |
| 1013 | th_register_language(g.interp); /* Basic scripting commands. */ |
| 1014 | } |
| 1015 | #ifdef FOSSIL_ENABLE_TCL |
| 1016 | if( forceTcl || fossil_getenv("TH1_ENABLE_TCL")!=0 || |
| 1017 | db_get_boolean("tcl", 0) ){ |
| 1018 | if( !g.tcl.setup ){ |
| 1019 | g.tcl.setup = db_get("tcl-setup", 0); /* Grab Tcl setup script. */ |
| 1020 | } |
| 1021 | th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */ |
| 1022 | } |
| 1023 |
+22
-17
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -289,10 +289,11 @@ | ||
| 289 | 289 | const char *zBr = 0; /* Branch */ |
| 290 | 290 | int commentColumn = 3; /* Column containing comment text */ |
| 291 | 291 | int modPending; /* Pending moderation */ |
| 292 | 292 | char zTime[20]; |
| 293 | 293 | |
| 294 | + if( zDate==0 ) zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */ | |
| 294 | 295 | modPending = moderation_pending(rid); |
| 295 | 296 | if( tagid ){ |
| 296 | 297 | if( modPending ) tagid = -tagid; |
| 297 | 298 | if( tagid==prevTagid ){ |
| 298 | 299 | if( tmFlags & TIMELINE_BRIEF ){ |
| @@ -320,11 +321,11 @@ | ||
| 320 | 321 | prevWasDivider = 1; |
| 321 | 322 | continue; |
| 322 | 323 | } |
| 323 | 324 | prevWasDivider = 0; |
| 324 | 325 | if( dateFormat<2 ){ |
| 325 | - if( memcmp(zDate, zPrevDate, 10) ){ | |
| 326 | + if( fossil_strnicmp(zDate, zPrevDate, 10) ){ | |
| 326 | 327 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 327 | 328 | @ <tr><td> |
| 328 | 329 | @ <div class="divider timelineDate">%s(zPrevDate)</div> |
| 329 | 330 | @ </td><td></td><td></td></tr> |
| 330 | 331 | } |
| @@ -904,15 +905,16 @@ | ||
| 904 | 905 | /* |
| 905 | 906 | ** Return a pointer to a constant string that forms the basis |
| 906 | 907 | ** for a timeline query for the WWW interface. |
| 907 | 908 | */ |
| 908 | 909 | const char *timeline_query_for_www(void){ |
| 910 | + static const char *zBase = 0; | |
| 909 | 911 | static const char zBaseSql[] = |
| 910 | 912 | @ SELECT |
| 911 | 913 | @ blob.rid AS blobRid, |
| 912 | 914 | @ uuid AS uuid, |
| 913 | - @ datetime(event.mtime,'localtime') AS timestamp, | |
| 915 | + @ datetime(event.mtime%s) AS timestamp, | |
| 914 | 916 | @ coalesce(ecomment, comment) AS comment, |
| 915 | 917 | @ coalesce(euser, user) AS user, |
| 916 | 918 | @ blob.rid IN leaf AS leaf, |
| 917 | 919 | @ bgcolor AS bgColor, |
| 918 | 920 | @ event.type AS eventType, |
| @@ -923,11 +925,14 @@ | ||
| 923 | 925 | @ brief AS brief, |
| 924 | 926 | @ event.mtime AS mtime |
| 925 | 927 | @ FROM event CROSS JOIN blob |
| 926 | 928 | @ WHERE blob.rid=event.objid |
| 927 | 929 | ; |
| 928 | - return zBaseSql; | |
| 930 | + if( zBase==0 ){ | |
| 931 | + zBase = mprintf(zBaseSql, timeline_utc()); | |
| 932 | + } | |
| 933 | + return zBase; | |
| 929 | 934 | } |
| 930 | 935 | |
| 931 | 936 | /* |
| 932 | 937 | ** Generate a submenu element with a single parameter change. |
| 933 | 938 | */ |
| @@ -1593,11 +1598,11 @@ | ||
| 1593 | 1598 | fossil_print("--- entry limit (%d) reached ---\n", nAbsLimit); |
| 1594 | 1599 | break; /* entry count limit hit, stop. */ |
| 1595 | 1600 | } |
| 1596 | 1601 | } |
| 1597 | 1602 | sqlite3_snprintf(sizeof(zUuid), zUuid, "%.10s", zId); |
| 1598 | - if( memcmp(zDate, zPrevDate, 10) ){ | |
| 1603 | + if( fossil_strnicmp(zDate, zPrevDate, 10) ){ | |
| 1599 | 1604 | fossil_print("=== %.10s ===\n", zDate); |
| 1600 | 1605 | memcpy(zPrevDate, zDate, 10); |
| 1601 | 1606 | nLine++; /* record another line */ |
| 1602 | 1607 | } |
| 1603 | 1608 | if( zCom==0 ) zCom = ""; |
| @@ -1671,15 +1676,16 @@ | ||
| 1671 | 1676 | /* |
| 1672 | 1677 | ** Return a pointer to a static string that forms the basis for |
| 1673 | 1678 | ** a timeline query for display on a TTY. |
| 1674 | 1679 | */ |
| 1675 | 1680 | const char *timeline_query_for_tty(void){ |
| 1681 | + static const char *zBase = 0; | |
| 1676 | 1682 | static const char zBaseSql[] = |
| 1677 | 1683 | @ SELECT |
| 1678 | 1684 | @ blob.rid AS rid, |
| 1679 | 1685 | @ uuid, |
| 1680 | - @ datetime(event.mtime,'localtime') AS mDateTime, | |
| 1686 | + @ datetime(event.mtime%s) AS mDateTime, | |
| 1681 | 1687 | @ coalesce(ecomment,comment) |
| 1682 | 1688 | @ || ' (user: ' || coalesce(euser,user,'?') |
| 1683 | 1689 | @ || (SELECT case when length(x)>0 then ' tags: ' || x else '' end |
| 1684 | 1690 | @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x |
| 1685 | 1691 | @ FROM tag, tagxref |
| @@ -1696,11 +1702,14 @@ | ||
| 1696 | 1702 | @ AND tagxref.tagtype>0 |
| 1697 | 1703 | @ AND tagxref.rid=blob.rid |
| 1698 | 1704 | @ WHERE blob.rid=event.objid |
| 1699 | 1705 | @ AND tag.tagname='branch' |
| 1700 | 1706 | ; |
| 1701 | - return zBaseSql; | |
| 1707 | + if( zBase==0 ){ | |
| 1708 | + zBase = mprintf(zBaseSql, timeline_utc()); | |
| 1709 | + } | |
| 1710 | + return zBase; | |
| 1702 | 1711 | } |
| 1703 | 1712 | |
| 1704 | 1713 | /* |
| 1705 | 1714 | ** Return true if the input string is a date in the ISO 8601 format: |
| 1706 | 1715 | ** YYYY-MM-DD. |
| @@ -1876,32 +1885,28 @@ | ||
| 1876 | 1885 | print_timeline(&q, n, width, verboseFlag); |
| 1877 | 1886 | db_finalize(&q); |
| 1878 | 1887 | } |
| 1879 | 1888 | |
| 1880 | 1889 | /* |
| 1881 | -** This is a version of the "localtime()" function from the standard | |
| 1882 | -** C library. It converts a unix timestamp (seconds since 1970) into | |
| 1883 | -** a broken-out local time structure. | |
| 1890 | +** Return one of two things: | |
| 1891 | +** | |
| 1892 | +** ",'localtime'" if the timeline-utc property is set to 0. | |
| 1884 | 1893 | ** |
| 1885 | -** This modified version of localtime() works like the library localtime() | |
| 1886 | -** by default. Except if the timeline-utc property is set, this routine | |
| 1887 | -** uses gmttime() instead. Thus by setting the timeline-utc property, we | |
| 1888 | -** can get all localtimes to be displayed at UTC time. | |
| 1894 | +** "" (empty string) otherwise. | |
| 1889 | 1895 | */ |
| 1890 | -struct tm *fossil_localtime(const time_t *clock){ | |
| 1896 | +const char *timeline_utc(){ | |
| 1891 | 1897 | if( g.fTimeFormat==0 ){ |
| 1892 | 1898 | if( db_get_int("timeline-utc", 1) ){ |
| 1893 | 1899 | g.fTimeFormat = 1; |
| 1894 | 1900 | }else{ |
| 1895 | 1901 | g.fTimeFormat = 2; |
| 1896 | 1902 | } |
| 1897 | 1903 | } |
| 1898 | - if( clock==0 ) return 0; | |
| 1899 | 1904 | if( g.fTimeFormat==1 ){ |
| 1900 | - return gmtime(clock); | |
| 1905 | + return ""; | |
| 1901 | 1906 | }else{ |
| 1902 | - return localtime(clock); | |
| 1907 | + return ",'localtime'"; | |
| 1903 | 1908 | } |
| 1904 | 1909 | } |
| 1905 | 1910 | |
| 1906 | 1911 | |
| 1907 | 1912 | /* |
| 1908 | 1913 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -289,10 +289,11 @@ | |
| 289 | const char *zBr = 0; /* Branch */ |
| 290 | int commentColumn = 3; /* Column containing comment text */ |
| 291 | int modPending; /* Pending moderation */ |
| 292 | char zTime[20]; |
| 293 | |
| 294 | modPending = moderation_pending(rid); |
| 295 | if( tagid ){ |
| 296 | if( modPending ) tagid = -tagid; |
| 297 | if( tagid==prevTagid ){ |
| 298 | if( tmFlags & TIMELINE_BRIEF ){ |
| @@ -320,11 +321,11 @@ | |
| 320 | prevWasDivider = 1; |
| 321 | continue; |
| 322 | } |
| 323 | prevWasDivider = 0; |
| 324 | if( dateFormat<2 ){ |
| 325 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 326 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 327 | @ <tr><td> |
| 328 | @ <div class="divider timelineDate">%s(zPrevDate)</div> |
| 329 | @ </td><td></td><td></td></tr> |
| 330 | } |
| @@ -904,15 +905,16 @@ | |
| 904 | /* |
| 905 | ** Return a pointer to a constant string that forms the basis |
| 906 | ** for a timeline query for the WWW interface. |
| 907 | */ |
| 908 | const char *timeline_query_for_www(void){ |
| 909 | static const char zBaseSql[] = |
| 910 | @ SELECT |
| 911 | @ blob.rid AS blobRid, |
| 912 | @ uuid AS uuid, |
| 913 | @ datetime(event.mtime,'localtime') AS timestamp, |
| 914 | @ coalesce(ecomment, comment) AS comment, |
| 915 | @ coalesce(euser, user) AS user, |
| 916 | @ blob.rid IN leaf AS leaf, |
| 917 | @ bgcolor AS bgColor, |
| 918 | @ event.type AS eventType, |
| @@ -923,11 +925,14 @@ | |
| 923 | @ brief AS brief, |
| 924 | @ event.mtime AS mtime |
| 925 | @ FROM event CROSS JOIN blob |
| 926 | @ WHERE blob.rid=event.objid |
| 927 | ; |
| 928 | return zBaseSql; |
| 929 | } |
| 930 | |
| 931 | /* |
| 932 | ** Generate a submenu element with a single parameter change. |
| 933 | */ |
| @@ -1593,11 +1598,11 @@ | |
| 1593 | fossil_print("--- entry limit (%d) reached ---\n", nAbsLimit); |
| 1594 | break; /* entry count limit hit, stop. */ |
| 1595 | } |
| 1596 | } |
| 1597 | sqlite3_snprintf(sizeof(zUuid), zUuid, "%.10s", zId); |
| 1598 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 1599 | fossil_print("=== %.10s ===\n", zDate); |
| 1600 | memcpy(zPrevDate, zDate, 10); |
| 1601 | nLine++; /* record another line */ |
| 1602 | } |
| 1603 | if( zCom==0 ) zCom = ""; |
| @@ -1671,15 +1676,16 @@ | |
| 1671 | /* |
| 1672 | ** Return a pointer to a static string that forms the basis for |
| 1673 | ** a timeline query for display on a TTY. |
| 1674 | */ |
| 1675 | const char *timeline_query_for_tty(void){ |
| 1676 | static const char zBaseSql[] = |
| 1677 | @ SELECT |
| 1678 | @ blob.rid AS rid, |
| 1679 | @ uuid, |
| 1680 | @ datetime(event.mtime,'localtime') AS mDateTime, |
| 1681 | @ coalesce(ecomment,comment) |
| 1682 | @ || ' (user: ' || coalesce(euser,user,'?') |
| 1683 | @ || (SELECT case when length(x)>0 then ' tags: ' || x else '' end |
| 1684 | @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x |
| 1685 | @ FROM tag, tagxref |
| @@ -1696,11 +1702,14 @@ | |
| 1696 | @ AND tagxref.tagtype>0 |
| 1697 | @ AND tagxref.rid=blob.rid |
| 1698 | @ WHERE blob.rid=event.objid |
| 1699 | @ AND tag.tagname='branch' |
| 1700 | ; |
| 1701 | return zBaseSql; |
| 1702 | } |
| 1703 | |
| 1704 | /* |
| 1705 | ** Return true if the input string is a date in the ISO 8601 format: |
| 1706 | ** YYYY-MM-DD. |
| @@ -1876,32 +1885,28 @@ | |
| 1876 | print_timeline(&q, n, width, verboseFlag); |
| 1877 | db_finalize(&q); |
| 1878 | } |
| 1879 | |
| 1880 | /* |
| 1881 | ** This is a version of the "localtime()" function from the standard |
| 1882 | ** C library. It converts a unix timestamp (seconds since 1970) into |
| 1883 | ** a broken-out local time structure. |
| 1884 | ** |
| 1885 | ** This modified version of localtime() works like the library localtime() |
| 1886 | ** by default. Except if the timeline-utc property is set, this routine |
| 1887 | ** uses gmttime() instead. Thus by setting the timeline-utc property, we |
| 1888 | ** can get all localtimes to be displayed at UTC time. |
| 1889 | */ |
| 1890 | struct tm *fossil_localtime(const time_t *clock){ |
| 1891 | if( g.fTimeFormat==0 ){ |
| 1892 | if( db_get_int("timeline-utc", 1) ){ |
| 1893 | g.fTimeFormat = 1; |
| 1894 | }else{ |
| 1895 | g.fTimeFormat = 2; |
| 1896 | } |
| 1897 | } |
| 1898 | if( clock==0 ) return 0; |
| 1899 | if( g.fTimeFormat==1 ){ |
| 1900 | return gmtime(clock); |
| 1901 | }else{ |
| 1902 | return localtime(clock); |
| 1903 | } |
| 1904 | } |
| 1905 | |
| 1906 | |
| 1907 | /* |
| 1908 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -289,10 +289,11 @@ | |
| 289 | const char *zBr = 0; /* Branch */ |
| 290 | int commentColumn = 3; /* Column containing comment text */ |
| 291 | int modPending; /* Pending moderation */ |
| 292 | char zTime[20]; |
| 293 | |
| 294 | if( zDate==0 ) zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */ |
| 295 | modPending = moderation_pending(rid); |
| 296 | if( tagid ){ |
| 297 | if( modPending ) tagid = -tagid; |
| 298 | if( tagid==prevTagid ){ |
| 299 | if( tmFlags & TIMELINE_BRIEF ){ |
| @@ -320,11 +321,11 @@ | |
| 321 | prevWasDivider = 1; |
| 322 | continue; |
| 323 | } |
| 324 | prevWasDivider = 0; |
| 325 | if( dateFormat<2 ){ |
| 326 | if( fossil_strnicmp(zDate, zPrevDate, 10) ){ |
| 327 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 328 | @ <tr><td> |
| 329 | @ <div class="divider timelineDate">%s(zPrevDate)</div> |
| 330 | @ </td><td></td><td></td></tr> |
| 331 | } |
| @@ -904,15 +905,16 @@ | |
| 905 | /* |
| 906 | ** Return a pointer to a constant string that forms the basis |
| 907 | ** for a timeline query for the WWW interface. |
| 908 | */ |
| 909 | const char *timeline_query_for_www(void){ |
| 910 | static const char *zBase = 0; |
| 911 | static const char zBaseSql[] = |
| 912 | @ SELECT |
| 913 | @ blob.rid AS blobRid, |
| 914 | @ uuid AS uuid, |
| 915 | @ datetime(event.mtime%s) AS timestamp, |
| 916 | @ coalesce(ecomment, comment) AS comment, |
| 917 | @ coalesce(euser, user) AS user, |
| 918 | @ blob.rid IN leaf AS leaf, |
| 919 | @ bgcolor AS bgColor, |
| 920 | @ event.type AS eventType, |
| @@ -923,11 +925,14 @@ | |
| 925 | @ brief AS brief, |
| 926 | @ event.mtime AS mtime |
| 927 | @ FROM event CROSS JOIN blob |
| 928 | @ WHERE blob.rid=event.objid |
| 929 | ; |
| 930 | if( zBase==0 ){ |
| 931 | zBase = mprintf(zBaseSql, timeline_utc()); |
| 932 | } |
| 933 | return zBase; |
| 934 | } |
| 935 | |
| 936 | /* |
| 937 | ** Generate a submenu element with a single parameter change. |
| 938 | */ |
| @@ -1593,11 +1598,11 @@ | |
| 1598 | fossil_print("--- entry limit (%d) reached ---\n", nAbsLimit); |
| 1599 | break; /* entry count limit hit, stop. */ |
| 1600 | } |
| 1601 | } |
| 1602 | sqlite3_snprintf(sizeof(zUuid), zUuid, "%.10s", zId); |
| 1603 | if( fossil_strnicmp(zDate, zPrevDate, 10) ){ |
| 1604 | fossil_print("=== %.10s ===\n", zDate); |
| 1605 | memcpy(zPrevDate, zDate, 10); |
| 1606 | nLine++; /* record another line */ |
| 1607 | } |
| 1608 | if( zCom==0 ) zCom = ""; |
| @@ -1671,15 +1676,16 @@ | |
| 1676 | /* |
| 1677 | ** Return a pointer to a static string that forms the basis for |
| 1678 | ** a timeline query for display on a TTY. |
| 1679 | */ |
| 1680 | const char *timeline_query_for_tty(void){ |
| 1681 | static const char *zBase = 0; |
| 1682 | static const char zBaseSql[] = |
| 1683 | @ SELECT |
| 1684 | @ blob.rid AS rid, |
| 1685 | @ uuid, |
| 1686 | @ datetime(event.mtime%s) AS mDateTime, |
| 1687 | @ coalesce(ecomment,comment) |
| 1688 | @ || ' (user: ' || coalesce(euser,user,'?') |
| 1689 | @ || (SELECT case when length(x)>0 then ' tags: ' || x else '' end |
| 1690 | @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x |
| 1691 | @ FROM tag, tagxref |
| @@ -1696,11 +1702,14 @@ | |
| 1702 | @ AND tagxref.tagtype>0 |
| 1703 | @ AND tagxref.rid=blob.rid |
| 1704 | @ WHERE blob.rid=event.objid |
| 1705 | @ AND tag.tagname='branch' |
| 1706 | ; |
| 1707 | if( zBase==0 ){ |
| 1708 | zBase = mprintf(zBaseSql, timeline_utc()); |
| 1709 | } |
| 1710 | return zBase; |
| 1711 | } |
| 1712 | |
| 1713 | /* |
| 1714 | ** Return true if the input string is a date in the ISO 8601 format: |
| 1715 | ** YYYY-MM-DD. |
| @@ -1876,32 +1885,28 @@ | |
| 1885 | print_timeline(&q, n, width, verboseFlag); |
| 1886 | db_finalize(&q); |
| 1887 | } |
| 1888 | |
| 1889 | /* |
| 1890 | ** Return one of two things: |
| 1891 | ** |
| 1892 | ** ",'localtime'" if the timeline-utc property is set to 0. |
| 1893 | ** |
| 1894 | ** "" (empty string) otherwise. |
| 1895 | */ |
| 1896 | const char *timeline_utc(){ |
| 1897 | if( g.fTimeFormat==0 ){ |
| 1898 | if( db_get_int("timeline-utc", 1) ){ |
| 1899 | g.fTimeFormat = 1; |
| 1900 | }else{ |
| 1901 | g.fTimeFormat = 2; |
| 1902 | } |
| 1903 | } |
| 1904 | if( g.fTimeFormat==1 ){ |
| 1905 | return ""; |
| 1906 | }else{ |
| 1907 | return ",'localtime'"; |
| 1908 | } |
| 1909 | } |
| 1910 | |
| 1911 | |
| 1912 | /* |
| 1913 |
+15
-10
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -137,12 +137,13 @@ | ||
| 137 | 137 | const char *zName; |
| 138 | 138 | Stmt q; |
| 139 | 139 | int i, n, size, j; |
| 140 | 140 | |
| 141 | 141 | zName = PD("name","-none-"); |
| 142 | - db_prepare(&q, "SELECT datetime(tkt_mtime,'localtime') AS tkt_datetime, *" | |
| 143 | - " FROM ticket WHERE tkt_uuid GLOB '%q*'", zName); | |
| 142 | + db_prepare(&q, "SELECT datetime(tkt_mtime%s) AS tkt_datetime, *" | |
| 143 | + " FROM ticket WHERE tkt_uuid GLOB '%q*'", | |
| 144 | + timeline_utc(), zName); | |
| 144 | 145 | if( db_step(&q)==SQLITE_ROW ){ |
| 145 | 146 | n = db_column_count(&q); |
| 146 | 147 | for(i=0; i<n; i++){ |
| 147 | 148 | const char *zVal = db_column_text(&q, i); |
| 148 | 149 | const char *zName = db_column_name(&q, i); |
| @@ -534,13 +535,17 @@ | ||
| 534 | 535 | }else{ |
| 535 | 536 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid); |
| 536 | 537 | db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid); |
| 537 | 538 | } |
| 538 | 539 | manifest_crosslink_begin(); |
| 539 | - result = (manifest_crosslink(rid, pTicket, MC_PERMIT_HOOKS)==0); | |
| 540 | + result = (manifest_crosslink(rid, pTicket, MC_NONE)==0); | |
| 540 | 541 | assert( blob_is_reset(pTicket) ); |
| 541 | - manifest_crosslink_end(); | |
| 542 | + if( !result ){ | |
| 543 | + result = manifest_crosslink_end(MC_PERMIT_HOOKS); | |
| 544 | + }else{ | |
| 545 | + manifest_crosslink_end(MC_NONE); | |
| 546 | + } | |
| 542 | 547 | return result; |
| 543 | 548 | } |
| 544 | 549 | |
| 545 | 550 | /* |
| 546 | 551 | ** Subscript command: submit_ticket |
| @@ -905,21 +910,21 @@ | ||
| 905 | 910 | @ No such ticket: %h(zUuid) |
| 906 | 911 | style_footer(); |
| 907 | 912 | return; |
| 908 | 913 | } |
| 909 | 914 | db_prepare(&q, |
| 910 | - "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" | |
| 915 | + "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL" | |
| 911 | 916 | " FROM event, blob" |
| 912 | 917 | " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" |
| 913 | 918 | " AND blob.rid=event.objid" |
| 914 | 919 | " UNION " |
| 915 | - "SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user" | |
| 920 | + "SELECT datetime(mtime%s), attachid, uuid, src, filename, user" | |
| 916 | 921 | " FROM attachment, blob" |
| 917 | 922 | " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" |
| 918 | 923 | " AND blob.rid=attachid" |
| 919 | 924 | " ORDER BY 1", |
| 920 | - tagid, tagid | |
| 925 | + timeline_utc(), tagid, timeline_utc(), tagid | |
| 921 | 926 | ); |
| 922 | 927 | while( db_step(&q)==SQLITE_ROW ){ |
| 923 | 928 | Manifest *pTicket; |
| 924 | 929 | char zShort[12]; |
| 925 | 930 | const char *zDate = db_column_text(&q, 0); |
| @@ -1214,22 +1219,22 @@ | ||
| 1214 | 1219 | zTktUuid); |
| 1215 | 1220 | if( tagid==0 ){ |
| 1216 | 1221 | fossil_fatal("no such ticket %h", zTktUuid); |
| 1217 | 1222 | } |
| 1218 | 1223 | db_prepare(&q, |
| 1219 | - "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" | |
| 1224 | + "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL" | |
| 1220 | 1225 | " FROM event, blob" |
| 1221 | 1226 | " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" |
| 1222 | 1227 | " AND blob.rid=event.objid" |
| 1223 | 1228 | " UNION " |
| 1224 | - "SELECT datetime(mtime,'localtime'), attachid, uuid, src, " | |
| 1229 | + "SELECT datetime(mtime%s), attachid, uuid, src, " | |
| 1225 | 1230 | " filename, user" |
| 1226 | 1231 | " FROM attachment, blob" |
| 1227 | 1232 | " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" |
| 1228 | 1233 | " AND blob.rid=attachid" |
| 1229 | 1234 | " ORDER BY 1 DESC", |
| 1230 | - tagid, tagid | |
| 1235 | + timeline_utc(), tagid, timeline_utc(), tagid | |
| 1231 | 1236 | ); |
| 1232 | 1237 | while( db_step(&q)==SQLITE_ROW ){ |
| 1233 | 1238 | Manifest *pTicket; |
| 1234 | 1239 | char zShort[12]; |
| 1235 | 1240 | const char *zDate = db_column_text(&q, 0); |
| 1236 | 1241 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -137,12 +137,13 @@ | |
| 137 | const char *zName; |
| 138 | Stmt q; |
| 139 | int i, n, size, j; |
| 140 | |
| 141 | zName = PD("name","-none-"); |
| 142 | db_prepare(&q, "SELECT datetime(tkt_mtime,'localtime') AS tkt_datetime, *" |
| 143 | " FROM ticket WHERE tkt_uuid GLOB '%q*'", zName); |
| 144 | if( db_step(&q)==SQLITE_ROW ){ |
| 145 | n = db_column_count(&q); |
| 146 | for(i=0; i<n; i++){ |
| 147 | const char *zVal = db_column_text(&q, i); |
| 148 | const char *zName = db_column_name(&q, i); |
| @@ -534,13 +535,17 @@ | |
| 534 | }else{ |
| 535 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid); |
| 536 | db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid); |
| 537 | } |
| 538 | manifest_crosslink_begin(); |
| 539 | result = (manifest_crosslink(rid, pTicket, MC_PERMIT_HOOKS)==0); |
| 540 | assert( blob_is_reset(pTicket) ); |
| 541 | manifest_crosslink_end(); |
| 542 | return result; |
| 543 | } |
| 544 | |
| 545 | /* |
| 546 | ** Subscript command: submit_ticket |
| @@ -905,21 +910,21 @@ | |
| 905 | @ No such ticket: %h(zUuid) |
| 906 | style_footer(); |
| 907 | return; |
| 908 | } |
| 909 | db_prepare(&q, |
| 910 | "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" |
| 911 | " FROM event, blob" |
| 912 | " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" |
| 913 | " AND blob.rid=event.objid" |
| 914 | " UNION " |
| 915 | "SELECT datetime(mtime,'localtime'), attachid, uuid, src, filename, user" |
| 916 | " FROM attachment, blob" |
| 917 | " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" |
| 918 | " AND blob.rid=attachid" |
| 919 | " ORDER BY 1", |
| 920 | tagid, tagid |
| 921 | ); |
| 922 | while( db_step(&q)==SQLITE_ROW ){ |
| 923 | Manifest *pTicket; |
| 924 | char zShort[12]; |
| 925 | const char *zDate = db_column_text(&q, 0); |
| @@ -1214,22 +1219,22 @@ | |
| 1214 | zTktUuid); |
| 1215 | if( tagid==0 ){ |
| 1216 | fossil_fatal("no such ticket %h", zTktUuid); |
| 1217 | } |
| 1218 | db_prepare(&q, |
| 1219 | "SELECT datetime(mtime,'localtime'), objid, uuid, NULL, NULL, NULL" |
| 1220 | " FROM event, blob" |
| 1221 | " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" |
| 1222 | " AND blob.rid=event.objid" |
| 1223 | " UNION " |
| 1224 | "SELECT datetime(mtime,'localtime'), attachid, uuid, src, " |
| 1225 | " filename, user" |
| 1226 | " FROM attachment, blob" |
| 1227 | " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" |
| 1228 | " AND blob.rid=attachid" |
| 1229 | " ORDER BY 1 DESC", |
| 1230 | tagid, tagid |
| 1231 | ); |
| 1232 | while( db_step(&q)==SQLITE_ROW ){ |
| 1233 | Manifest *pTicket; |
| 1234 | char zShort[12]; |
| 1235 | const char *zDate = db_column_text(&q, 0); |
| 1236 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -137,12 +137,13 @@ | |
| 137 | const char *zName; |
| 138 | Stmt q; |
| 139 | int i, n, size, j; |
| 140 | |
| 141 | zName = PD("name","-none-"); |
| 142 | db_prepare(&q, "SELECT datetime(tkt_mtime%s) AS tkt_datetime, *" |
| 143 | " FROM ticket WHERE tkt_uuid GLOB '%q*'", |
| 144 | timeline_utc(), zName); |
| 145 | if( db_step(&q)==SQLITE_ROW ){ |
| 146 | n = db_column_count(&q); |
| 147 | for(i=0; i<n; i++){ |
| 148 | const char *zVal = db_column_text(&q, i); |
| 149 | const char *zName = db_column_name(&q, i); |
| @@ -534,13 +535,17 @@ | |
| 535 | }else{ |
| 536 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid); |
| 537 | db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid); |
| 538 | } |
| 539 | manifest_crosslink_begin(); |
| 540 | result = (manifest_crosslink(rid, pTicket, MC_NONE)==0); |
| 541 | assert( blob_is_reset(pTicket) ); |
| 542 | if( !result ){ |
| 543 | result = manifest_crosslink_end(MC_PERMIT_HOOKS); |
| 544 | }else{ |
| 545 | manifest_crosslink_end(MC_NONE); |
| 546 | } |
| 547 | return result; |
| 548 | } |
| 549 | |
| 550 | /* |
| 551 | ** Subscript command: submit_ticket |
| @@ -905,21 +910,21 @@ | |
| 910 | @ No such ticket: %h(zUuid) |
| 911 | style_footer(); |
| 912 | return; |
| 913 | } |
| 914 | db_prepare(&q, |
| 915 | "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL" |
| 916 | " FROM event, blob" |
| 917 | " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" |
| 918 | " AND blob.rid=event.objid" |
| 919 | " UNION " |
| 920 | "SELECT datetime(mtime%s), attachid, uuid, src, filename, user" |
| 921 | " FROM attachment, blob" |
| 922 | " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" |
| 923 | " AND blob.rid=attachid" |
| 924 | " ORDER BY 1", |
| 925 | timeline_utc(), tagid, timeline_utc(), tagid |
| 926 | ); |
| 927 | while( db_step(&q)==SQLITE_ROW ){ |
| 928 | Manifest *pTicket; |
| 929 | char zShort[12]; |
| 930 | const char *zDate = db_column_text(&q, 0); |
| @@ -1214,22 +1219,22 @@ | |
| 1219 | zTktUuid); |
| 1220 | if( tagid==0 ){ |
| 1221 | fossil_fatal("no such ticket %h", zTktUuid); |
| 1222 | } |
| 1223 | db_prepare(&q, |
| 1224 | "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL" |
| 1225 | " FROM event, blob" |
| 1226 | " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)" |
| 1227 | " AND blob.rid=event.objid" |
| 1228 | " UNION " |
| 1229 | "SELECT datetime(mtime%s), attachid, uuid, src, " |
| 1230 | " filename, user" |
| 1231 | " FROM attachment, blob" |
| 1232 | " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)" |
| 1233 | " AND blob.rid=attachid" |
| 1234 | " ORDER BY 1 DESC", |
| 1235 | timeline_utc(), tagid, timeline_utc(), tagid |
| 1236 | ); |
| 1237 | while( db_step(&q)==SQLITE_ROW ){ |
| 1238 | Manifest *pTicket; |
| 1239 | char zShort[12]; |
| 1240 | const char *zDate = db_column_text(&q, 0); |
| 1241 |
+1
-1
| --- src/update.c | ||
| +++ src/update.c | ||
| @@ -353,11 +353,11 @@ | ||
| 353 | 353 | db_prepare(&mtimeXfer, |
| 354 | 354 | "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)" |
| 355 | 355 | " WHERE id=:idt" |
| 356 | 356 | ); |
| 357 | 357 | assert( g.zLocalRoot!=0 ); |
| 358 | - assert( strlen(g.zLocalRoot)>1 ); | |
| 358 | + assert( strlen(g.zLocalRoot)>0 ); | |
| 359 | 359 | assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' ); |
| 360 | 360 | while( db_step(&q)==SQLITE_ROW ){ |
| 361 | 361 | const char *zName = db_column_text(&q, 0); /* The filename from root */ |
| 362 | 362 | int idv = db_column_int(&q, 1); /* VFILE entry for current */ |
| 363 | 363 | int ridv = db_column_int(&q, 2); /* RecordID for current */ |
| 364 | 364 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -353,11 +353,11 @@ | |
| 353 | db_prepare(&mtimeXfer, |
| 354 | "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)" |
| 355 | " WHERE id=:idt" |
| 356 | ); |
| 357 | assert( g.zLocalRoot!=0 ); |
| 358 | assert( strlen(g.zLocalRoot)>1 ); |
| 359 | assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' ); |
| 360 | while( db_step(&q)==SQLITE_ROW ){ |
| 361 | const char *zName = db_column_text(&q, 0); /* The filename from root */ |
| 362 | int idv = db_column_int(&q, 1); /* VFILE entry for current */ |
| 363 | int ridv = db_column_int(&q, 2); /* RecordID for current */ |
| 364 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -353,11 +353,11 @@ | |
| 353 | db_prepare(&mtimeXfer, |
| 354 | "UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)" |
| 355 | " WHERE id=:idt" |
| 356 | ); |
| 357 | assert( g.zLocalRoot!=0 ); |
| 358 | assert( strlen(g.zLocalRoot)>0 ); |
| 359 | assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' ); |
| 360 | while( db_step(&q)==SQLITE_ROW ){ |
| 361 | const char *zName = db_column_text(&q, 0); /* The filename from root */ |
| 362 | int idv = db_column_int(&q, 1); /* VFILE entry for current */ |
| 363 | int ridv = db_column_int(&q, 2); /* RecordID for current */ |
| 364 |
+3
-3
| --- src/user.c | ||
| +++ src/user.c | ||
| @@ -450,13 +450,13 @@ | ||
| 450 | 450 | cgi_redirectf("%s/access_log?y=%d&n=%d", g.zTop, y, n); |
| 451 | 451 | return; |
| 452 | 452 | } |
| 453 | 453 | style_header("Access Log"); |
| 454 | 454 | blob_zero(&sql); |
| 455 | - blob_append(&sql, | |
| 456 | - "SELECT uname, ipaddr, datetime(mtime, 'localtime'), success" | |
| 457 | - " FROM accesslog", -1 | |
| 455 | + blob_appendf(&sql, | |
| 456 | + "SELECT uname, ipaddr, datetime(mtime%s), success" | |
| 457 | + " FROM accesslog", timeline_utc() | |
| 458 | 458 | ); |
| 459 | 459 | if( y==1 ){ |
| 460 | 460 | blob_append(&sql, " WHERE success", -1); |
| 461 | 461 | }else if( y==2 ){ |
| 462 | 462 | blob_append(&sql, " WHERE NOT success", -1); |
| 463 | 463 |
| --- src/user.c | |
| +++ src/user.c | |
| @@ -450,13 +450,13 @@ | |
| 450 | cgi_redirectf("%s/access_log?y=%d&n=%d", g.zTop, y, n); |
| 451 | return; |
| 452 | } |
| 453 | style_header("Access Log"); |
| 454 | blob_zero(&sql); |
| 455 | blob_append(&sql, |
| 456 | "SELECT uname, ipaddr, datetime(mtime, 'localtime'), success" |
| 457 | " FROM accesslog", -1 |
| 458 | ); |
| 459 | if( y==1 ){ |
| 460 | blob_append(&sql, " WHERE success", -1); |
| 461 | }else if( y==2 ){ |
| 462 | blob_append(&sql, " WHERE NOT success", -1); |
| 463 |
| --- src/user.c | |
| +++ src/user.c | |
| @@ -450,13 +450,13 @@ | |
| 450 | cgi_redirectf("%s/access_log?y=%d&n=%d", g.zTop, y, n); |
| 451 | return; |
| 452 | } |
| 453 | style_header("Access Log"); |
| 454 | blob_zero(&sql); |
| 455 | blob_appendf(&sql, |
| 456 | "SELECT uname, ipaddr, datetime(mtime%s), success" |
| 457 | " FROM accesslog", timeline_utc() |
| 458 | ); |
| 459 | if( y==1 ){ |
| 460 | blob_append(&sql, " WHERE success", -1); |
| 461 | }else if( y==2 ){ |
| 462 | blob_append(&sql, " WHERE NOT success", -1); |
| 463 |
+11
-13
| --- src/utf8.c | ||
| +++ src/utf8.c | ||
| @@ -54,18 +54,22 @@ | ||
| 54 | 54 | ** returned pointer when done. |
| 55 | 55 | */ |
| 56 | 56 | char *fossil_unicode_to_utf8(const void *zUnicode){ |
| 57 | 57 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 58 | 58 | int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0); |
| 59 | - char *zUtf = sqlite3_malloc( nByte ); | |
| 60 | - if( zUtf==0 ){ | |
| 61 | - return 0; | |
| 62 | - } | |
| 59 | + char *zUtf = fossil_malloc( nByte ); | |
| 63 | 60 | WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0); |
| 64 | 61 | return zUtf; |
| 65 | 62 | #else |
| 66 | - return fossil_strdup(zUnicode); /* TODO: implement for unix */ | |
| 63 | + static Stmt q; | |
| 64 | + char *zUtf8; | |
| 65 | + db_static_prepare(&q, "SELECT :utf8"); | |
| 66 | + db_bind_text16(&q, ":utf8", zUnicode); | |
| 67 | + db_step(&q); | |
| 68 | + zUtf8 = fossil_strdup(db_column_text(&q, 0)); | |
| 69 | + db_reset(&q); | |
| 70 | + return zUtf8; | |
| 67 | 71 | #endif |
| 68 | 72 | } |
| 69 | 73 | |
| 70 | 74 | /* |
| 71 | 75 | ** Translate UTF-8 to unicode for use in system calls. Return a pointer to the |
| @@ -73,31 +77,25 @@ | ||
| 73 | 77 | ** used to store the returned pointer when done. |
| 74 | 78 | */ |
| 75 | 79 | void *fossil_utf8_to_unicode(const char *zUtf8){ |
| 76 | 80 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 77 | 81 | int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); |
| 78 | - wchar_t *zUnicode = sqlite3_malloc( nByte * 2 ); | |
| 79 | - if( zUnicode==0 ){ | |
| 80 | - return 0; | |
| 81 | - } | |
| 82 | + wchar_t *zUnicode = fossil_malloc( nByte * 2 ); | |
| 82 | 83 | MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte); |
| 83 | 84 | return zUnicode; |
| 84 | 85 | #else |
| 86 | + assert( 0 ); /* Never used in unix */ | |
| 85 | 87 | return fossil_strdup(zUtf8); /* TODO: implement for unix */ |
| 86 | 88 | #endif |
| 87 | 89 | } |
| 88 | 90 | |
| 89 | 91 | /* |
| 90 | 92 | ** Deallocate any memory that was previously allocated by |
| 91 | 93 | ** fossil_unicode_to_utf8(). |
| 92 | 94 | */ |
| 93 | 95 | void fossil_unicode_free(void *pOld){ |
| 94 | -#if defined(_WIN32) || defined(__CYGWIN__) | |
| 95 | - sqlite3_free(pOld); | |
| 96 | -#else | |
| 97 | 96 | fossil_free(pOld); |
| 98 | -#endif | |
| 99 | 97 | } |
| 100 | 98 | |
| 101 | 99 | #if defined(__APPLE__) && !defined(WITHOUT_ICONV) |
| 102 | 100 | # include <iconv.h> |
| 103 | 101 | #endif |
| 104 | 102 |
| --- src/utf8.c | |
| +++ src/utf8.c | |
| @@ -54,18 +54,22 @@ | |
| 54 | ** returned pointer when done. |
| 55 | */ |
| 56 | char *fossil_unicode_to_utf8(const void *zUnicode){ |
| 57 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 58 | int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0); |
| 59 | char *zUtf = sqlite3_malloc( nByte ); |
| 60 | if( zUtf==0 ){ |
| 61 | return 0; |
| 62 | } |
| 63 | WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0); |
| 64 | return zUtf; |
| 65 | #else |
| 66 | return fossil_strdup(zUnicode); /* TODO: implement for unix */ |
| 67 | #endif |
| 68 | } |
| 69 | |
| 70 | /* |
| 71 | ** Translate UTF-8 to unicode for use in system calls. Return a pointer to the |
| @@ -73,31 +77,25 @@ | |
| 73 | ** used to store the returned pointer when done. |
| 74 | */ |
| 75 | void *fossil_utf8_to_unicode(const char *zUtf8){ |
| 76 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 77 | int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); |
| 78 | wchar_t *zUnicode = sqlite3_malloc( nByte * 2 ); |
| 79 | if( zUnicode==0 ){ |
| 80 | return 0; |
| 81 | } |
| 82 | MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte); |
| 83 | return zUnicode; |
| 84 | #else |
| 85 | return fossil_strdup(zUtf8); /* TODO: implement for unix */ |
| 86 | #endif |
| 87 | } |
| 88 | |
| 89 | /* |
| 90 | ** Deallocate any memory that was previously allocated by |
| 91 | ** fossil_unicode_to_utf8(). |
| 92 | */ |
| 93 | void fossil_unicode_free(void *pOld){ |
| 94 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 95 | sqlite3_free(pOld); |
| 96 | #else |
| 97 | fossil_free(pOld); |
| 98 | #endif |
| 99 | } |
| 100 | |
| 101 | #if defined(__APPLE__) && !defined(WITHOUT_ICONV) |
| 102 | # include <iconv.h> |
| 103 | #endif |
| 104 |
| --- src/utf8.c | |
| +++ src/utf8.c | |
| @@ -54,18 +54,22 @@ | |
| 54 | ** returned pointer when done. |
| 55 | */ |
| 56 | char *fossil_unicode_to_utf8(const void *zUnicode){ |
| 57 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 58 | int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0); |
| 59 | char *zUtf = fossil_malloc( nByte ); |
| 60 | WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0); |
| 61 | return zUtf; |
| 62 | #else |
| 63 | static Stmt q; |
| 64 | char *zUtf8; |
| 65 | db_static_prepare(&q, "SELECT :utf8"); |
| 66 | db_bind_text16(&q, ":utf8", zUnicode); |
| 67 | db_step(&q); |
| 68 | zUtf8 = fossil_strdup(db_column_text(&q, 0)); |
| 69 | db_reset(&q); |
| 70 | return zUtf8; |
| 71 | #endif |
| 72 | } |
| 73 | |
| 74 | /* |
| 75 | ** Translate UTF-8 to unicode for use in system calls. Return a pointer to the |
| @@ -73,31 +77,25 @@ | |
| 77 | ** used to store the returned pointer when done. |
| 78 | */ |
| 79 | void *fossil_utf8_to_unicode(const char *zUtf8){ |
| 80 | #if defined(_WIN32) || defined(__CYGWIN__) |
| 81 | int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0); |
| 82 | wchar_t *zUnicode = fossil_malloc( nByte * 2 ); |
| 83 | MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte); |
| 84 | return zUnicode; |
| 85 | #else |
| 86 | assert( 0 ); /* Never used in unix */ |
| 87 | return fossil_strdup(zUtf8); /* TODO: implement for unix */ |
| 88 | #endif |
| 89 | } |
| 90 | |
| 91 | /* |
| 92 | ** Deallocate any memory that was previously allocated by |
| 93 | ** fossil_unicode_to_utf8(). |
| 94 | */ |
| 95 | void fossil_unicode_free(void *pOld){ |
| 96 | fossil_free(pOld); |
| 97 | } |
| 98 | |
| 99 | #if defined(__APPLE__) && !defined(WITHOUT_ICONV) |
| 100 | # include <iconv.h> |
| 101 | #endif |
| 102 |
+4
| --- src/winfile.c | ||
| +++ src/winfile.c | ||
| @@ -22,10 +22,14 @@ | ||
| 22 | 22 | #ifdef _WIN32 |
| 23 | 23 | /* This code is for win32 only */ |
| 24 | 24 | #include <sys/stat.h> |
| 25 | 25 | #include <windows.h> |
| 26 | 26 | #include "winfile.h" |
| 27 | + | |
| 28 | +#ifndef LABEL_SECURITY_INFORMATION | |
| 29 | +# define LABEL_SECURITY_INFORMATION (0x00000010L) | |
| 30 | +#endif | |
| 27 | 31 | |
| 28 | 32 | /* |
| 29 | 33 | ** Fill stat buf with information received from stat() or lstat(). |
| 30 | 34 | ** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on. |
| 31 | 35 | ** |
| 32 | 36 |
| --- src/winfile.c | |
| +++ src/winfile.c | |
| @@ -22,10 +22,14 @@ | |
| 22 | #ifdef _WIN32 |
| 23 | /* This code is for win32 only */ |
| 24 | #include <sys/stat.h> |
| 25 | #include <windows.h> |
| 26 | #include "winfile.h" |
| 27 | |
| 28 | /* |
| 29 | ** Fill stat buf with information received from stat() or lstat(). |
| 30 | ** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on. |
| 31 | ** |
| 32 |
| --- src/winfile.c | |
| +++ src/winfile.c | |
| @@ -22,10 +22,14 @@ | |
| 22 | #ifdef _WIN32 |
| 23 | /* This code is for win32 only */ |
| 24 | #include <sys/stat.h> |
| 25 | #include <windows.h> |
| 26 | #include "winfile.h" |
| 27 | |
| 28 | #ifndef LABEL_SECURITY_INFORMATION |
| 29 | # define LABEL_SECURITY_INFORMATION (0x00000010L) |
| 30 | #endif |
| 31 | |
| 32 | /* |
| 33 | ** Fill stat buf with information received from stat() or lstat(). |
| 34 | ** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on. |
| 35 | ** |
| 36 |
+15
-16
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -852,25 +852,25 @@ | ||
| 852 | 852 | |
| 853 | 853 | /* |
| 854 | 854 | ** Run the specified TH1 script, if any, and returns 1 on error. |
| 855 | 855 | */ |
| 856 | 856 | int xfer_run_script(const char *zScript, const char *zUuid){ |
| 857 | - int result; | |
| 857 | + int rc; | |
| 858 | 858 | if( !zScript ) return TH_OK; |
| 859 | 859 | Th_FossilInit(TH_INIT_DEFAULT); |
| 860 | 860 | if( zUuid ){ |
| 861 | - result = Th_SetVar(g.interp, "uuid", -1, zUuid, -1); | |
| 862 | - if( result!=TH_OK ){ | |
| 861 | + rc = Th_SetVar(g.interp, "uuid", -1, zUuid, -1); | |
| 862 | + if( rc!=TH_OK ){ | |
| 863 | 863 | fossil_error(1, "%s", Th_GetResult(g.interp, 0)); |
| 864 | - return result; | |
| 864 | + return rc; | |
| 865 | 865 | } |
| 866 | 866 | } |
| 867 | - result = Th_Eval(g.interp, 0, zScript, -1); | |
| 868 | - if( result!=TH_OK ){ | |
| 867 | + rc = Th_Eval(g.interp, 0, zScript, -1); | |
| 868 | + if( rc!=TH_OK ){ | |
| 869 | 869 | fossil_error(1, "%s", Th_GetResult(g.interp, 0)); |
| 870 | 870 | } |
| 871 | - return result; | |
| 871 | + return rc; | |
| 872 | 872 | } |
| 873 | 873 | |
| 874 | 874 | /* |
| 875 | 875 | ** Runs the pre-transfer TH1 script, if any, and returns its return code. |
| 876 | 876 | ** This script may be run multiple times. If the script performs actions |
| @@ -881,11 +881,10 @@ | ||
| 881 | 881 | ** # ... code here |
| 882 | 882 | ** set common_done 1 |
| 883 | 883 | ** } |
| 884 | 884 | */ |
| 885 | 885 | int xfer_run_common_script(void){ |
| 886 | - Th_FossilInit(TH_INIT_DEFAULT); | |
| 887 | 886 | return xfer_run_script(xfer_common_code(), 0); |
| 888 | 887 | } |
| 889 | 888 | |
| 890 | 889 | /* |
| 891 | 890 | ** If this variable is set, disable login checks. Used for debugging |
| @@ -915,11 +914,11 @@ | ||
| 915 | 914 | int isClone = 0; |
| 916 | 915 | int nGimme = 0; |
| 917 | 916 | int size; |
| 918 | 917 | int recvConfig = 0; |
| 919 | 918 | char *zNow; |
| 920 | - int result; | |
| 919 | + int rc; | |
| 921 | 920 | |
| 922 | 921 | if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ |
| 923 | 922 | fossil_redirect_home(); |
| 924 | 923 | } |
| 925 | 924 | g.zLogin = "anonymous"; |
| @@ -945,12 +944,12 @@ | ||
| 945 | 944 | db_begin_transaction(); |
| 946 | 945 | db_multi_exec( |
| 947 | 946 | "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" |
| 948 | 947 | ); |
| 949 | 948 | manifest_crosslink_begin(); |
| 950 | - result = xfer_run_common_script(); | |
| 951 | - if( result==TH_ERROR ){ | |
| 949 | + rc = xfer_run_common_script(); | |
| 950 | + if( rc==TH_ERROR ){ | |
| 952 | 951 | cgi_reset_content(); |
| 953 | 952 | @ error common\sscript\sfailed:\s%F(g.zErrMsg) |
| 954 | 953 | nErr++; |
| 955 | 954 | } |
| 956 | 955 | while( blob_line(xfer.pIn, &xfer.line) ){ |
| @@ -1273,13 +1272,13 @@ | ||
| 1273 | 1272 | } |
| 1274 | 1273 | blobarray_reset(xfer.aToken, xfer.nToken); |
| 1275 | 1274 | blob_reset(&xfer.line); |
| 1276 | 1275 | } |
| 1277 | 1276 | if( isPush ){ |
| 1278 | - if( result==TH_OK ){ | |
| 1279 | - result = xfer_run_script(xfer_push_code(), 0); | |
| 1280 | - if( result==TH_ERROR ){ | |
| 1277 | + if( rc==TH_OK ){ | |
| 1278 | + rc = xfer_run_script(xfer_push_code(), 0); | |
| 1279 | + if( rc==TH_ERROR ){ | |
| 1281 | 1280 | cgi_reset_content(); |
| 1282 | 1281 | @ error push\sscript\sfailed:\s%F(g.zErrMsg) |
| 1283 | 1282 | nErr++; |
| 1284 | 1283 | } |
| 1285 | 1284 | } |
| @@ -1302,11 +1301,11 @@ | ||
| 1302 | 1301 | } |
| 1303 | 1302 | if( recvConfig ){ |
| 1304 | 1303 | configure_finalize_receive(); |
| 1305 | 1304 | } |
| 1306 | 1305 | db_multi_exec("DROP TABLE onremote"); |
| 1307 | - manifest_crosslink_end(); | |
| 1306 | + manifest_crosslink_end(MC_PERMIT_HOOKS); | |
| 1308 | 1307 | |
| 1309 | 1308 | /* Send the server timestamp last, in case prior processing happened |
| 1310 | 1309 | ** to use up a significant fraction of our time window. |
| 1311 | 1310 | */ |
| 1312 | 1311 | zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')"); |
| @@ -1929,10 +1928,10 @@ | ||
| 1929 | 1928 | "%s finished with %lld bytes sent, %lld bytes received\n", |
| 1930 | 1929 | zOpType, nSent, nRcvd); |
| 1931 | 1930 | transport_close(GLOBAL_URL()); |
| 1932 | 1931 | transport_global_shutdown(GLOBAL_URL()); |
| 1933 | 1932 | db_multi_exec("DROP TABLE onremote"); |
| 1934 | - manifest_crosslink_end(); | |
| 1933 | + manifest_crosslink_end(MC_PERMIT_HOOKS); | |
| 1935 | 1934 | content_enable_dephantomize(1); |
| 1936 | 1935 | db_end_transaction(0); |
| 1937 | 1936 | return nErr; |
| 1938 | 1937 | } |
| 1939 | 1938 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -852,25 +852,25 @@ | |
| 852 | |
| 853 | /* |
| 854 | ** Run the specified TH1 script, if any, and returns 1 on error. |
| 855 | */ |
| 856 | int xfer_run_script(const char *zScript, const char *zUuid){ |
| 857 | int result; |
| 858 | if( !zScript ) return TH_OK; |
| 859 | Th_FossilInit(TH_INIT_DEFAULT); |
| 860 | if( zUuid ){ |
| 861 | result = Th_SetVar(g.interp, "uuid", -1, zUuid, -1); |
| 862 | if( result!=TH_OK ){ |
| 863 | fossil_error(1, "%s", Th_GetResult(g.interp, 0)); |
| 864 | return result; |
| 865 | } |
| 866 | } |
| 867 | result = Th_Eval(g.interp, 0, zScript, -1); |
| 868 | if( result!=TH_OK ){ |
| 869 | fossil_error(1, "%s", Th_GetResult(g.interp, 0)); |
| 870 | } |
| 871 | return result; |
| 872 | } |
| 873 | |
| 874 | /* |
| 875 | ** Runs the pre-transfer TH1 script, if any, and returns its return code. |
| 876 | ** This script may be run multiple times. If the script performs actions |
| @@ -881,11 +881,10 @@ | |
| 881 | ** # ... code here |
| 882 | ** set common_done 1 |
| 883 | ** } |
| 884 | */ |
| 885 | int xfer_run_common_script(void){ |
| 886 | Th_FossilInit(TH_INIT_DEFAULT); |
| 887 | return xfer_run_script(xfer_common_code(), 0); |
| 888 | } |
| 889 | |
| 890 | /* |
| 891 | ** If this variable is set, disable login checks. Used for debugging |
| @@ -915,11 +914,11 @@ | |
| 915 | int isClone = 0; |
| 916 | int nGimme = 0; |
| 917 | int size; |
| 918 | int recvConfig = 0; |
| 919 | char *zNow; |
| 920 | int result; |
| 921 | |
| 922 | if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ |
| 923 | fossil_redirect_home(); |
| 924 | } |
| 925 | g.zLogin = "anonymous"; |
| @@ -945,12 +944,12 @@ | |
| 945 | db_begin_transaction(); |
| 946 | db_multi_exec( |
| 947 | "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" |
| 948 | ); |
| 949 | manifest_crosslink_begin(); |
| 950 | result = xfer_run_common_script(); |
| 951 | if( result==TH_ERROR ){ |
| 952 | cgi_reset_content(); |
| 953 | @ error common\sscript\sfailed:\s%F(g.zErrMsg) |
| 954 | nErr++; |
| 955 | } |
| 956 | while( blob_line(xfer.pIn, &xfer.line) ){ |
| @@ -1273,13 +1272,13 @@ | |
| 1273 | } |
| 1274 | blobarray_reset(xfer.aToken, xfer.nToken); |
| 1275 | blob_reset(&xfer.line); |
| 1276 | } |
| 1277 | if( isPush ){ |
| 1278 | if( result==TH_OK ){ |
| 1279 | result = xfer_run_script(xfer_push_code(), 0); |
| 1280 | if( result==TH_ERROR ){ |
| 1281 | cgi_reset_content(); |
| 1282 | @ error push\sscript\sfailed:\s%F(g.zErrMsg) |
| 1283 | nErr++; |
| 1284 | } |
| 1285 | } |
| @@ -1302,11 +1301,11 @@ | |
| 1302 | } |
| 1303 | if( recvConfig ){ |
| 1304 | configure_finalize_receive(); |
| 1305 | } |
| 1306 | db_multi_exec("DROP TABLE onremote"); |
| 1307 | manifest_crosslink_end(); |
| 1308 | |
| 1309 | /* Send the server timestamp last, in case prior processing happened |
| 1310 | ** to use up a significant fraction of our time window. |
| 1311 | */ |
| 1312 | zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')"); |
| @@ -1929,10 +1928,10 @@ | |
| 1929 | "%s finished with %lld bytes sent, %lld bytes received\n", |
| 1930 | zOpType, nSent, nRcvd); |
| 1931 | transport_close(GLOBAL_URL()); |
| 1932 | transport_global_shutdown(GLOBAL_URL()); |
| 1933 | db_multi_exec("DROP TABLE onremote"); |
| 1934 | manifest_crosslink_end(); |
| 1935 | content_enable_dephantomize(1); |
| 1936 | db_end_transaction(0); |
| 1937 | return nErr; |
| 1938 | } |
| 1939 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -852,25 +852,25 @@ | |
| 852 | |
| 853 | /* |
| 854 | ** Run the specified TH1 script, if any, and returns 1 on error. |
| 855 | */ |
| 856 | int xfer_run_script(const char *zScript, const char *zUuid){ |
| 857 | int rc; |
| 858 | if( !zScript ) return TH_OK; |
| 859 | Th_FossilInit(TH_INIT_DEFAULT); |
| 860 | if( zUuid ){ |
| 861 | rc = Th_SetVar(g.interp, "uuid", -1, zUuid, -1); |
| 862 | if( rc!=TH_OK ){ |
| 863 | fossil_error(1, "%s", Th_GetResult(g.interp, 0)); |
| 864 | return rc; |
| 865 | } |
| 866 | } |
| 867 | rc = Th_Eval(g.interp, 0, zScript, -1); |
| 868 | if( rc!=TH_OK ){ |
| 869 | fossil_error(1, "%s", Th_GetResult(g.interp, 0)); |
| 870 | } |
| 871 | return rc; |
| 872 | } |
| 873 | |
| 874 | /* |
| 875 | ** Runs the pre-transfer TH1 script, if any, and returns its return code. |
| 876 | ** This script may be run multiple times. If the script performs actions |
| @@ -881,11 +881,10 @@ | |
| 881 | ** # ... code here |
| 882 | ** set common_done 1 |
| 883 | ** } |
| 884 | */ |
| 885 | int xfer_run_common_script(void){ |
| 886 | return xfer_run_script(xfer_common_code(), 0); |
| 887 | } |
| 888 | |
| 889 | /* |
| 890 | ** If this variable is set, disable login checks. Used for debugging |
| @@ -915,11 +914,11 @@ | |
| 914 | int isClone = 0; |
| 915 | int nGimme = 0; |
| 916 | int size; |
| 917 | int recvConfig = 0; |
| 918 | char *zNow; |
| 919 | int rc; |
| 920 | |
| 921 | if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ |
| 922 | fossil_redirect_home(); |
| 923 | } |
| 924 | g.zLogin = "anonymous"; |
| @@ -945,12 +944,12 @@ | |
| 944 | db_begin_transaction(); |
| 945 | db_multi_exec( |
| 946 | "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);" |
| 947 | ); |
| 948 | manifest_crosslink_begin(); |
| 949 | rc = xfer_run_common_script(); |
| 950 | if( rc==TH_ERROR ){ |
| 951 | cgi_reset_content(); |
| 952 | @ error common\sscript\sfailed:\s%F(g.zErrMsg) |
| 953 | nErr++; |
| 954 | } |
| 955 | while( blob_line(xfer.pIn, &xfer.line) ){ |
| @@ -1273,13 +1272,13 @@ | |
| 1272 | } |
| 1273 | blobarray_reset(xfer.aToken, xfer.nToken); |
| 1274 | blob_reset(&xfer.line); |
| 1275 | } |
| 1276 | if( isPush ){ |
| 1277 | if( rc==TH_OK ){ |
| 1278 | rc = xfer_run_script(xfer_push_code(), 0); |
| 1279 | if( rc==TH_ERROR ){ |
| 1280 | cgi_reset_content(); |
| 1281 | @ error push\sscript\sfailed:\s%F(g.zErrMsg) |
| 1282 | nErr++; |
| 1283 | } |
| 1284 | } |
| @@ -1302,11 +1301,11 @@ | |
| 1301 | } |
| 1302 | if( recvConfig ){ |
| 1303 | configure_finalize_receive(); |
| 1304 | } |
| 1305 | db_multi_exec("DROP TABLE onremote"); |
| 1306 | manifest_crosslink_end(MC_PERMIT_HOOKS); |
| 1307 | |
| 1308 | /* Send the server timestamp last, in case prior processing happened |
| 1309 | ** to use up a significant fraction of our time window. |
| 1310 | */ |
| 1311 | zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')"); |
| @@ -1929,10 +1928,10 @@ | |
| 1928 | "%s finished with %lld bytes sent, %lld bytes received\n", |
| 1929 | zOpType, nSent, nRcvd); |
| 1930 | transport_close(GLOBAL_URL()); |
| 1931 | transport_global_shutdown(GLOBAL_URL()); |
| 1932 | db_multi_exec("DROP TABLE onremote"); |
| 1933 | manifest_crosslink_end(MC_PERMIT_HOOKS); |
| 1934 | content_enable_dephantomize(1); |
| 1935 | db_end_transaction(0); |
| 1936 | return nErr; |
| 1937 | } |
| 1938 |
+142
| --- test/th1.test | ||
| +++ test/th1.test | ||
| @@ -65,5 +65,147 @@ | ||
| 65 | 65 | |
| 66 | 66 | ############################################################################### |
| 67 | 67 | |
| 68 | 68 | fossil test-th-eval --th-open-config "setting -strict -- --" |
| 69 | 69 | test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}} |
| 70 | + | |
| 71 | +############################################################################### | |
| 72 | + | |
| 73 | +fossil test-th-eval "expr 42/0" | |
| 74 | +test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}} | |
| 75 | + | |
| 76 | +############################################################################### | |
| 77 | + | |
| 78 | +fossil test-th-eval "expr 42/0.0" | |
| 79 | +test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}} | |
| 80 | + | |
| 81 | +############################################################################### | |
| 82 | + | |
| 83 | +fossil test-th-eval "expr 42.0/0" | |
| 84 | +test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}} | |
| 85 | + | |
| 86 | +############################################################################### | |
| 87 | + | |
| 88 | +fossil test-th-eval "expr 42.0/0.0" | |
| 89 | +test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}} | |
| 90 | + | |
| 91 | +############################################################################### | |
| 92 | + | |
| 93 | +fossil test-th-eval "expr 42%0" | |
| 94 | +test th1-modulus-by-zero-1 {$RESULT eq {TH_ERROR: Modulo by 0: 42}} | |
| 95 | + | |
| 96 | +############################################################################### | |
| 97 | + | |
| 98 | +fossil test-th-eval "expr 42%0.0" | |
| 99 | +test th1-modulus-by-zero-2 {$RESULT eq {TH_ERROR: expected integer, got: "0.0"}} | |
| 100 | + | |
| 101 | +############################################################################### | |
| 102 | + | |
| 103 | +fossil test-th-eval "expr 42.0%0" | |
| 104 | +test th1-modulus-by-zero-3 {$RESULT eq \ | |
| 105 | +{TH_ERROR: expected integer, got: "42.0"}} | |
| 106 | + | |
| 107 | +############################################################################### | |
| 108 | + | |
| 109 | +fossil test-th-eval "expr 42.0%0.0" | |
| 110 | +test th1-modulus-by-zero-4 {$RESULT eq \ | |
| 111 | +{TH_ERROR: expected integer, got: "42.0"}} | |
| 112 | + | |
| 113 | +############################################################################### | |
| 114 | + | |
| 115 | +fossil test-th-eval "set var 1; info exists var" | |
| 116 | +test th1-info-exists-1 {$RESULT eq {1}} | |
| 117 | + | |
| 118 | +############################################################################### | |
| 119 | + | |
| 120 | +fossil test-th-eval "set var 1; unset var; info exists var" | |
| 121 | +test th1-info-exists-2 {$RESULT eq {0}} | |
| 122 | + | |
| 123 | +############################################################################### | |
| 124 | + | |
| 125 | +fossil test-th-eval "set var 1; unset var; set var 2; info exists var" | |
| 126 | +test th1-info-exists-3 {$RESULT eq {1}} | |
| 127 | + | |
| 128 | +############################################################################### | |
| 129 | + | |
| 130 | +fossil test-th-eval "set var 1; expr {\$var+0}" | |
| 131 | +test th1-info-exists-4 {$RESULT eq {1}} | |
| 132 | + | |
| 133 | +############################################################################### | |
| 134 | + | |
| 135 | +fossil test-th-eval "set var 1; unset var; expr {\$var+0}" | |
| 136 | +test th1-info-exists-5 {$RESULT eq {TH_ERROR: no such variable: var}} | |
| 137 | + | |
| 138 | +############################################################################### | |
| 139 | + | |
| 140 | +fossil test-th-eval "catch {bad}; info exists var; set th_stack_trace" | |
| 141 | +test th1-info-exists-6 {$RESULT eq {bad}} | |
| 142 | + | |
| 143 | +############################################################################### | |
| 144 | + | |
| 145 | +fossil test-th-eval "set var(1) 1; info exists var" | |
| 146 | +test th1-info-exists-7 {$RESULT eq {1}} | |
| 147 | + | |
| 148 | +############################################################################### | |
| 149 | + | |
| 150 | +fossil test-th-eval "set var(1) 1; unset var(1); info exists var" | |
| 151 | +test th1-info-exists-8 {$RESULT eq {1}} | |
| 152 | + | |
| 153 | +############################################################################### | |
| 154 | + | |
| 155 | +fossil test-th-eval "set var(1) 1; unset var; info exists var" | |
| 156 | +test th1-info-exists-9 {$RESULT eq {0}} | |
| 157 | + | |
| 158 | +############################################################################### | |
| 159 | + | |
| 160 | +fossil test-th-eval "set var(1) 1; info exists var(1)" | |
| 161 | +test th1-info-exists-10 {$RESULT eq {1}} | |
| 162 | + | |
| 163 | +############################################################################### | |
| 164 | + | |
| 165 | +fossil test-th-eval "set var(1) 1; unset var(1); info exists var(1)" | |
| 166 | +test th1-info-exists-11 {$RESULT eq {0}} | |
| 167 | + | |
| 168 | +############################################################################### | |
| 169 | + | |
| 170 | +fossil test-th-eval "set var(1) 1; unset var; info exists var(1)" | |
| 171 | +test th1-info-exists-12 {$RESULT eq {0}} | |
| 172 | + | |
| 173 | +############################################################################### | |
| 174 | + | |
| 175 | +fossil test-th-eval "set var 1; unset var" | |
| 176 | +test th1-unset-1 {$RESULT eq {var}} | |
| 177 | + | |
| 178 | +############################################################################### | |
| 179 | + | |
| 180 | +fossil test-th-eval "unset var" | |
| 181 | +test th1-unset-2 {$RESULT eq {TH_ERROR: no such variable: var}} | |
| 182 | + | |
| 183 | +############################################################################### | |
| 184 | + | |
| 185 | +fossil test-th-eval "set var 1; unset var; unset var" | |
| 186 | +test th1-unset-3 {$RESULT eq {TH_ERROR: no such variable: var}} | |
| 187 | + | |
| 188 | +############################################################################### | |
| 189 | + | |
| 190 | +fossil test-th-eval "set gv 1; proc p {} {upvar 1 gv lv; unset lv}; p; unset gv" | |
| 191 | +test th1-unset-4 {$RESULT eq {TH_ERROR: no such variable: gv}} | |
| 192 | + | |
| 193 | +############################################################################### | |
| 194 | + | |
| 195 | +fossil test-th-eval "set gv 1; upvar 0 gv gv2; info exists gv2" | |
| 196 | +test th1-unset-5 {$RESULT eq {1}} | |
| 197 | + | |
| 198 | +############################################################################### | |
| 199 | + | |
| 200 | +fossil test-th-eval "set gv 1; upvar 0 gv gv2; unset gv; unset gv2" | |
| 201 | +test th1-unset-6 {$RESULT eq {TH_ERROR: no such variable: gv2}} | |
| 202 | + | |
| 203 | +############################################################################### | |
| 204 | + | |
| 205 | +fossil test-th-eval "set gv 1; upvar 0 gv gv2(1); unset gv; unset gv2(1)" | |
| 206 | +test th1-unset-7 {$RESULT eq {TH_ERROR: no such variable: gv2(1)}} | |
| 207 | + | |
| 208 | +############################################################################### | |
| 209 | + | |
| 210 | +fossil test-th-eval "set gv(1) 1; upvar 0 gv(1) gv2; unset gv(1); unset gv2" | |
| 211 | +test th1-unset-8 {$RESULT eq {TH_ERROR: no such variable: gv2}} | |
| 70 | 212 | |
| 71 | 213 | ADDED test/utf16le.txt |
| --- test/th1.test | |
| +++ test/th1.test | |
| @@ -65,5 +65,147 @@ | |
| 65 | |
| 66 | ############################################################################### |
| 67 | |
| 68 | fossil test-th-eval --th-open-config "setting -strict -- --" |
| 69 | test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}} |
| 70 | |
| 71 | DDED test/utf16le.txt |
| --- test/th1.test | |
| +++ test/th1.test | |
| @@ -65,5 +65,147 @@ | |
| 65 | |
| 66 | ############################################################################### |
| 67 | |
| 68 | fossil test-th-eval --th-open-config "setting -strict -- --" |
| 69 | test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}} |
| 70 | |
| 71 | ############################################################################### |
| 72 | |
| 73 | fossil test-th-eval "expr 42/0" |
| 74 | test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}} |
| 75 | |
| 76 | ############################################################################### |
| 77 | |
| 78 | fossil test-th-eval "expr 42/0.0" |
| 79 | test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}} |
| 80 | |
| 81 | ############################################################################### |
| 82 | |
| 83 | fossil test-th-eval "expr 42.0/0" |
| 84 | test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}} |
| 85 | |
| 86 | ############################################################################### |
| 87 | |
| 88 | fossil test-th-eval "expr 42.0/0.0" |
| 89 | test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}} |
| 90 | |
| 91 | ############################################################################### |
| 92 | |
| 93 | fossil test-th-eval "expr 42%0" |
| 94 | test th1-modulus-by-zero-1 {$RESULT eq {TH_ERROR: Modulo by 0: 42}} |
| 95 | |
| 96 | ############################################################################### |
| 97 | |
| 98 | fossil test-th-eval "expr 42%0.0" |
| 99 | test th1-modulus-by-zero-2 {$RESULT eq {TH_ERROR: expected integer, got: "0.0"}} |
| 100 | |
| 101 | ############################################################################### |
| 102 | |
| 103 | fossil test-th-eval "expr 42.0%0" |
| 104 | test th1-modulus-by-zero-3 {$RESULT eq \ |
| 105 | {TH_ERROR: expected integer, got: "42.0"}} |
| 106 | |
| 107 | ############################################################################### |
| 108 | |
| 109 | fossil test-th-eval "expr 42.0%0.0" |
| 110 | test th1-modulus-by-zero-4 {$RESULT eq \ |
| 111 | {TH_ERROR: expected integer, got: "42.0"}} |
| 112 | |
| 113 | ############################################################################### |
| 114 | |
| 115 | fossil test-th-eval "set var 1; info exists var" |
| 116 | test th1-info-exists-1 {$RESULT eq {1}} |
| 117 | |
| 118 | ############################################################################### |
| 119 | |
| 120 | fossil test-th-eval "set var 1; unset var; info exists var" |
| 121 | test th1-info-exists-2 {$RESULT eq {0}} |
| 122 | |
| 123 | ############################################################################### |
| 124 | |
| 125 | fossil test-th-eval "set var 1; unset var; set var 2; info exists var" |
| 126 | test th1-info-exists-3 {$RESULT eq {1}} |
| 127 | |
| 128 | ############################################################################### |
| 129 | |
| 130 | fossil test-th-eval "set var 1; expr {\$var+0}" |
| 131 | test th1-info-exists-4 {$RESULT eq {1}} |
| 132 | |
| 133 | ############################################################################### |
| 134 | |
| 135 | fossil test-th-eval "set var 1; unset var; expr {\$var+0}" |
| 136 | test th1-info-exists-5 {$RESULT eq {TH_ERROR: no such variable: var}} |
| 137 | |
| 138 | ############################################################################### |
| 139 | |
| 140 | fossil test-th-eval "catch {bad}; info exists var; set th_stack_trace" |
| 141 | test th1-info-exists-6 {$RESULT eq {bad}} |
| 142 | |
| 143 | ############################################################################### |
| 144 | |
| 145 | fossil test-th-eval "set var(1) 1; info exists var" |
| 146 | test th1-info-exists-7 {$RESULT eq {1}} |
| 147 | |
| 148 | ############################################################################### |
| 149 | |
| 150 | fossil test-th-eval "set var(1) 1; unset var(1); info exists var" |
| 151 | test th1-info-exists-8 {$RESULT eq {1}} |
| 152 | |
| 153 | ############################################################################### |
| 154 | |
| 155 | fossil test-th-eval "set var(1) 1; unset var; info exists var" |
| 156 | test th1-info-exists-9 {$RESULT eq {0}} |
| 157 | |
| 158 | ############################################################################### |
| 159 | |
| 160 | fossil test-th-eval "set var(1) 1; info exists var(1)" |
| 161 | test th1-info-exists-10 {$RESULT eq {1}} |
| 162 | |
| 163 | ############################################################################### |
| 164 | |
| 165 | fossil test-th-eval "set var(1) 1; unset var(1); info exists var(1)" |
| 166 | test th1-info-exists-11 {$RESULT eq {0}} |
| 167 | |
| 168 | ############################################################################### |
| 169 | |
| 170 | fossil test-th-eval "set var(1) 1; unset var; info exists var(1)" |
| 171 | test th1-info-exists-12 {$RESULT eq {0}} |
| 172 | |
| 173 | ############################################################################### |
| 174 | |
| 175 | fossil test-th-eval "set var 1; unset var" |
| 176 | test th1-unset-1 {$RESULT eq {var}} |
| 177 | |
| 178 | ############################################################################### |
| 179 | |
| 180 | fossil test-th-eval "unset var" |
| 181 | test th1-unset-2 {$RESULT eq {TH_ERROR: no such variable: var}} |
| 182 | |
| 183 | ############################################################################### |
| 184 | |
| 185 | fossil test-th-eval "set var 1; unset var; unset var" |
| 186 | test th1-unset-3 {$RESULT eq {TH_ERROR: no such variable: var}} |
| 187 | |
| 188 | ############################################################################### |
| 189 | |
| 190 | fossil test-th-eval "set gv 1; proc p {} {upvar 1 gv lv; unset lv}; p; unset gv" |
| 191 | test th1-unset-4 {$RESULT eq {TH_ERROR: no such variable: gv}} |
| 192 | |
| 193 | ############################################################################### |
| 194 | |
| 195 | fossil test-th-eval "set gv 1; upvar 0 gv gv2; info exists gv2" |
| 196 | test th1-unset-5 {$RESULT eq {1}} |
| 197 | |
| 198 | ############################################################################### |
| 199 | |
| 200 | fossil test-th-eval "set gv 1; upvar 0 gv gv2; unset gv; unset gv2" |
| 201 | test th1-unset-6 {$RESULT eq {TH_ERROR: no such variable: gv2}} |
| 202 | |
| 203 | ############################################################################### |
| 204 | |
| 205 | fossil test-th-eval "set gv 1; upvar 0 gv gv2(1); unset gv; unset gv2(1)" |
| 206 | test th1-unset-7 {$RESULT eq {TH_ERROR: no such variable: gv2(1)}} |
| 207 | |
| 208 | ############################################################################### |
| 209 | |
| 210 | fossil test-th-eval "set gv(1) 1; upvar 0 gv(1) gv2; unset gv(1); unset gv2" |
| 211 | test th1-unset-8 {$RESULT eq {TH_ERROR: no such variable: gv2}} |
| 212 | |
| 213 | DDED test/utf16le.txt |
Binary file
+3
-1
| --- test/valgrind-www.tcl | ||
| +++ test/valgrind-www.tcl | ||
| @@ -12,11 +12,13 @@ | ||
| 12 | 12 | # |
| 13 | 13 | proc run_query {url} { |
| 14 | 14 | set fd [open q.txt w] |
| 15 | 15 | puts $fd "GET $url HTTP/1.0\r\n\r" |
| 16 | 16 | close $fd |
| 17 | - return [exec valgrind ./fossil test-http <q.txt 2>@ stderr] | |
| 17 | + set msg {} | |
| 18 | + catch {exec valgrind ./fossil test-http <q.txt 2>@ stderr} msg | |
| 19 | + return $msg | |
| 18 | 20 | } |
| 19 | 21 | set todo {} |
| 20 | 22 | foreach url { |
| 21 | 23 | /home |
| 22 | 24 | /timeline |
| 23 | 25 |
| --- test/valgrind-www.tcl | |
| +++ test/valgrind-www.tcl | |
| @@ -12,11 +12,13 @@ | |
| 12 | # |
| 13 | proc run_query {url} { |
| 14 | set fd [open q.txt w] |
| 15 | puts $fd "GET $url HTTP/1.0\r\n\r" |
| 16 | close $fd |
| 17 | return [exec valgrind ./fossil test-http <q.txt 2>@ stderr] |
| 18 | } |
| 19 | set todo {} |
| 20 | foreach url { |
| 21 | /home |
| 22 | /timeline |
| 23 |
| --- test/valgrind-www.tcl | |
| +++ test/valgrind-www.tcl | |
| @@ -12,11 +12,13 @@ | |
| 12 | # |
| 13 | proc run_query {url} { |
| 14 | set fd [open q.txt w] |
| 15 | puts $fd "GET $url HTTP/1.0\r\n\r" |
| 16 | close $fd |
| 17 | set msg {} |
| 18 | catch {exec valgrind ./fossil test-http <q.txt 2>@ stderr} msg |
| 19 | return $msg |
| 20 | } |
| 21 | set todo {} |
| 22 | foreach url { |
| 23 | /home |
| 24 | /timeline |
| 25 |
+2
-2
| --- win/Makefile.PellesCGMake | ||
| +++ win/Makefile.PellesCGMake | ||
| @@ -83,17 +83,17 @@ | ||
| 83 | 83 | |
| 84 | 84 | # define the sqlite files, which need special flags on compile |
| 85 | 85 | SQLITESRC=sqlite3.c |
| 86 | 86 | ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) |
| 87 | 87 | SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) |
| 88 | -SQLITEDEFINES=-Dlocaltime=fossil_localtime -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS | |
| 88 | +SQLITEDEFINES=-DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS | |
| 89 | 89 | |
| 90 | 90 | # define the sqlite shell files, which need special flags on compile |
| 91 | 91 | SQLITESHELLSRC=shell.c |
| 92 | 92 | ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) |
| 93 | 93 | SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) |
| 94 | -SQLITESHELLDEFINES=-Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dsqlite3_strglob=strglob -Dgetenv=fossil_getenv -Dfopen=fossil_fopen | |
| 94 | +SQLITESHELLDEFINES=-Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dgetenv=fossil_getenv -Dfopen=fossil_fopen | |
| 95 | 95 | |
| 96 | 96 | # define the th scripting files, which need special flags on compile |
| 97 | 97 | THSRC=th.c th_lang.c |
| 98 | 98 | ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) |
| 99 | 99 | THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) |
| 100 | 100 |
| --- win/Makefile.PellesCGMake | |
| +++ win/Makefile.PellesCGMake | |
| @@ -83,17 +83,17 @@ | |
| 83 | |
| 84 | # define the sqlite files, which need special flags on compile |
| 85 | SQLITESRC=sqlite3.c |
| 86 | ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) |
| 87 | SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) |
| 88 | SQLITEDEFINES=-Dlocaltime=fossil_localtime -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 89 | |
| 90 | # define the sqlite shell files, which need special flags on compile |
| 91 | SQLITESHELLSRC=shell.c |
| 92 | ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) |
| 93 | SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) |
| 94 | SQLITESHELLDEFINES=-Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dsqlite3_strglob=strglob -Dgetenv=fossil_getenv -Dfopen=fossil_fopen |
| 95 | |
| 96 | # define the th scripting files, which need special flags on compile |
| 97 | THSRC=th.c th_lang.c |
| 98 | ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) |
| 99 | THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) |
| 100 |
| --- win/Makefile.PellesCGMake | |
| +++ win/Makefile.PellesCGMake | |
| @@ -83,17 +83,17 @@ | |
| 83 | |
| 84 | # define the sqlite files, which need special flags on compile |
| 85 | SQLITESRC=sqlite3.c |
| 86 | ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) |
| 87 | SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) |
| 88 | SQLITEDEFINES=-DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 89 | |
| 90 | # define the sqlite shell files, which need special flags on compile |
| 91 | SQLITESHELLSRC=shell.c |
| 92 | ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) |
| 93 | SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) |
| 94 | SQLITESHELLDEFINES=-Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dgetenv=fossil_getenv -Dfopen=fossil_fopen |
| 95 | |
| 96 | # define the th scripting files, which need special flags on compile |
| 97 | THSRC=th.c th_lang.c |
| 98 | ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) |
| 99 | THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) |
| 100 |
+2
-2
| --- win/Makefile.dmc | ||
| +++ win/Makefile.dmc | ||
| @@ -24,13 +24,13 @@ | ||
| 24 | 24 | CFLAGS = -o |
| 25 | 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 27 | 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 |
| 28 | 28 | |
| 29 | -SQLITE_OPTIONS = -Dlocaltime=fossil_localtime -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS | |
| 29 | +SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS | |
| 30 | 30 | |
| 31 | -SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dsqlite3_strglob=strglob -Dgetenv=fossil_getenv -Dfopen=fossil_fopen | |
| 31 | +SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dgetenv=fossil_getenv -Dfopen=fossil_fopen | |
| 32 | 32 | |
| 33 | 33 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c |
| 34 | 34 | |
| 35 | 35 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 36 | 36 | |
| 37 | 37 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -24,13 +24,13 @@ | |
| 24 | CFLAGS = -o |
| 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 |
| 28 | |
| 29 | SQLITE_OPTIONS = -Dlocaltime=fossil_localtime -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 30 | |
| 31 | SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dsqlite3_strglob=strglob -Dgetenv=fossil_getenv -Dfopen=fossil_fopen |
| 32 | |
| 33 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c |
| 34 | |
| 35 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 36 | |
| 37 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -24,13 +24,13 @@ | |
| 24 | CFLAGS = -o |
| 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 |
| 28 | |
| 29 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 30 | |
| 31 | SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dgetenv=fossil_getenv -Dfopen=fossil_fopen |
| 32 | |
| 33 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c |
| 34 | |
| 35 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 36 | |
| 37 |
+5
-7
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -84,12 +84,12 @@ | ||
| 84 | 84 | #### The directories where the OpenSSL include and library files are located. |
| 85 | 85 | # The recommended usage here is to use the Sysinternals junction tool |
| 86 | 86 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 87 | 87 | # Fossil source code directory and the target OpenSSL source directory. |
| 88 | 88 | # |
| 89 | -OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1e/include | |
| 90 | -OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1e | |
| 89 | +OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include | |
| 90 | +OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f | |
| 91 | 91 | |
| 92 | 92 | #### Either the directory where the Tcl library is installed or the Tcl |
| 93 | 93 | # source code directory resides (depending on the value of the macro |
| 94 | 94 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 95 | 95 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -1698,12 +1698,11 @@ | ||
| 1698 | 1698 | $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h |
| 1699 | 1699 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c |
| 1700 | 1700 | |
| 1701 | 1701 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 1702 | 1702 | |
| 1703 | -SQLITE_OPTIONS = -Dlocaltime=fossil_localtime \ | |
| 1704 | - -DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 1703 | +SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 1705 | 1704 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 1706 | 1705 | -DSQLITE_THREADSAFE=0 \ |
| 1707 | 1706 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 1708 | 1707 | -DSQLITE_OMIT_DEPRECATED \ |
| 1709 | 1708 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ |
| @@ -1711,23 +1710,22 @@ | ||
| 1711 | 1710 | -DSQLITE_USE_MALLOC_H \ |
| 1712 | 1711 | -DSQLITE_USE_MSIZE |
| 1713 | 1712 | |
| 1714 | 1713 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 1715 | 1714 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1716 | - -Dsqlite3_strglob=strglob \ | |
| 1717 | 1715 | -Dgetenv=fossil_getenv \ |
| 1718 | 1716 | -Dfopen=fossil_fopen |
| 1719 | 1717 | |
| 1720 | -$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c | |
| 1718 | +$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c win/Makefile.mingw | |
| 1721 | 1719 | $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 1722 | 1720 | |
| 1723 | 1721 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1724 | 1722 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o |
| 1725 | 1723 | |
| 1726 | 1724 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 1727 | 1725 | |
| 1728 | -$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h | |
| 1726 | +$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h win/Makefile.mingw | |
| 1729 | 1727 | $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 1730 | 1728 | |
| 1731 | 1729 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 1732 | 1730 | $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 1733 | 1731 | |
| 1734 | 1732 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -84,12 +84,12 @@ | |
| 84 | #### The directories where the OpenSSL include and library files are located. |
| 85 | # The recommended usage here is to use the Sysinternals junction tool |
| 86 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 87 | # Fossil source code directory and the target OpenSSL source directory. |
| 88 | # |
| 89 | OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1e/include |
| 90 | OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1e |
| 91 | |
| 92 | #### Either the directory where the Tcl library is installed or the Tcl |
| 93 | # source code directory resides (depending on the value of the macro |
| 94 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 95 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -1698,12 +1698,11 @@ | |
| 1698 | $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h |
| 1699 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c |
| 1700 | |
| 1701 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 1702 | |
| 1703 | SQLITE_OPTIONS = -Dlocaltime=fossil_localtime \ |
| 1704 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1705 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 1706 | -DSQLITE_THREADSAFE=0 \ |
| 1707 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 1708 | -DSQLITE_OMIT_DEPRECATED \ |
| 1709 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ |
| @@ -1711,23 +1710,22 @@ | |
| 1711 | -DSQLITE_USE_MALLOC_H \ |
| 1712 | -DSQLITE_USE_MSIZE |
| 1713 | |
| 1714 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 1715 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1716 | -Dsqlite3_strglob=strglob \ |
| 1717 | -Dgetenv=fossil_getenv \ |
| 1718 | -Dfopen=fossil_fopen |
| 1719 | |
| 1720 | $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c |
| 1721 | $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 1722 | |
| 1723 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1724 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o |
| 1725 | |
| 1726 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 1727 | |
| 1728 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h |
| 1729 | $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 1730 | |
| 1731 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 1732 | $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 1733 | |
| 1734 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -84,12 +84,12 @@ | |
| 84 | #### The directories where the OpenSSL include and library files are located. |
| 85 | # The recommended usage here is to use the Sysinternals junction tool |
| 86 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 87 | # Fossil source code directory and the target OpenSSL source directory. |
| 88 | # |
| 89 | OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include |
| 90 | OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f |
| 91 | |
| 92 | #### Either the directory where the Tcl library is installed or the Tcl |
| 93 | # source code directory resides (depending on the value of the macro |
| 94 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 95 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -1698,12 +1698,11 @@ | |
| 1698 | $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h |
| 1699 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c |
| 1700 | |
| 1701 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 1702 | |
| 1703 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1704 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 1705 | -DSQLITE_THREADSAFE=0 \ |
| 1706 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 1707 | -DSQLITE_OMIT_DEPRECATED \ |
| 1708 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ |
| @@ -1711,23 +1710,22 @@ | |
| 1710 | -DSQLITE_USE_MALLOC_H \ |
| 1711 | -DSQLITE_USE_MSIZE |
| 1712 | |
| 1713 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 1714 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1715 | -Dgetenv=fossil_getenv \ |
| 1716 | -Dfopen=fossil_fopen |
| 1717 | |
| 1718 | $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c win/Makefile.mingw |
| 1719 | $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 1720 | |
| 1721 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1722 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o |
| 1723 | |
| 1724 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 1725 | |
| 1726 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h win/Makefile.mingw |
| 1727 | $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 1728 | |
| 1729 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 1730 | $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 1731 | |
| 1732 |
+5
-7
| --- win/Makefile.mingw.mistachkin | ||
| +++ win/Makefile.mingw.mistachkin | ||
| @@ -84,12 +84,12 @@ | ||
| 84 | 84 | #### The directories where the OpenSSL include and library files are located. |
| 85 | 85 | # The recommended usage here is to use the Sysinternals junction tool |
| 86 | 86 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 87 | 87 | # Fossil source code directory and the target OpenSSL source directory. |
| 88 | 88 | # |
| 89 | -OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1e/include | |
| 90 | -OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1e | |
| 89 | +OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include | |
| 90 | +OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f | |
| 91 | 91 | |
| 92 | 92 | #### Either the directory where the Tcl library is installed or the Tcl |
| 93 | 93 | # source code directory resides (depending on the value of the macro |
| 94 | 94 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 95 | 95 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -1698,12 +1698,11 @@ | ||
| 1698 | 1698 | $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h |
| 1699 | 1699 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c |
| 1700 | 1700 | |
| 1701 | 1701 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 1702 | 1702 | |
| 1703 | -SQLITE_OPTIONS = -Dlocaltime=fossil_localtime \ | |
| 1704 | - -DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 1703 | +SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 1705 | 1704 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 1706 | 1705 | -DSQLITE_THREADSAFE=0 \ |
| 1707 | 1706 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 1708 | 1707 | -DSQLITE_OMIT_DEPRECATED \ |
| 1709 | 1708 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ |
| @@ -1711,23 +1710,22 @@ | ||
| 1711 | 1710 | -DSQLITE_USE_MALLOC_H \ |
| 1712 | 1711 | -DSQLITE_USE_MSIZE |
| 1713 | 1712 | |
| 1714 | 1713 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 1715 | 1714 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1716 | - -Dsqlite3_strglob=strglob \ | |
| 1717 | 1715 | -Dgetenv=fossil_getenv \ |
| 1718 | 1716 | -Dfopen=fossil_fopen |
| 1719 | 1717 | |
| 1720 | -$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c | |
| 1718 | +$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c win/Makefile.mingw.mistachkin | |
| 1721 | 1719 | $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 1722 | 1720 | |
| 1723 | 1721 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1724 | 1722 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o |
| 1725 | 1723 | |
| 1726 | 1724 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 1727 | 1725 | |
| 1728 | -$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h | |
| 1726 | +$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h win/Makefile.mingw.mistachkin | |
| 1729 | 1727 | $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 1730 | 1728 | |
| 1731 | 1729 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 1732 | 1730 | $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 1733 | 1731 | |
| 1734 | 1732 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -84,12 +84,12 @@ | |
| 84 | #### The directories where the OpenSSL include and library files are located. |
| 85 | # The recommended usage here is to use the Sysinternals junction tool |
| 86 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 87 | # Fossil source code directory and the target OpenSSL source directory. |
| 88 | # |
| 89 | OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1e/include |
| 90 | OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1e |
| 91 | |
| 92 | #### Either the directory where the Tcl library is installed or the Tcl |
| 93 | # source code directory resides (depending on the value of the macro |
| 94 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 95 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -1698,12 +1698,11 @@ | |
| 1698 | $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h |
| 1699 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c |
| 1700 | |
| 1701 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 1702 | |
| 1703 | SQLITE_OPTIONS = -Dlocaltime=fossil_localtime \ |
| 1704 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1705 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 1706 | -DSQLITE_THREADSAFE=0 \ |
| 1707 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 1708 | -DSQLITE_OMIT_DEPRECATED \ |
| 1709 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ |
| @@ -1711,23 +1710,22 @@ | |
| 1711 | -DSQLITE_USE_MALLOC_H \ |
| 1712 | -DSQLITE_USE_MSIZE |
| 1713 | |
| 1714 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 1715 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1716 | -Dsqlite3_strglob=strglob \ |
| 1717 | -Dgetenv=fossil_getenv \ |
| 1718 | -Dfopen=fossil_fopen |
| 1719 | |
| 1720 | $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c |
| 1721 | $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 1722 | |
| 1723 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1724 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o |
| 1725 | |
| 1726 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 1727 | |
| 1728 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h |
| 1729 | $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 1730 | |
| 1731 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 1732 | $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 1733 | |
| 1734 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -84,12 +84,12 @@ | |
| 84 | #### The directories where the OpenSSL include and library files are located. |
| 85 | # The recommended usage here is to use the Sysinternals junction tool |
| 86 | # to create a hard link between an "openssl-1.x" sub-directory of the |
| 87 | # Fossil source code directory and the target OpenSSL source directory. |
| 88 | # |
| 89 | OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include |
| 90 | OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f |
| 91 | |
| 92 | #### Either the directory where the Tcl library is installed or the Tcl |
| 93 | # source code directory resides (depending on the value of the macro |
| 94 | # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, |
| 95 | # this directory must have "include" and "lib" sub-directories. If |
| @@ -1698,12 +1698,11 @@ | |
| 1698 | $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h |
| 1699 | $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c |
| 1700 | |
| 1701 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 1702 | |
| 1703 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1704 | -DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 1705 | -DSQLITE_THREADSAFE=0 \ |
| 1706 | -DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 1707 | -DSQLITE_OMIT_DEPRECATED \ |
| 1708 | -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ |
| @@ -1711,23 +1710,22 @@ | |
| 1710 | -DSQLITE_USE_MALLOC_H \ |
| 1711 | -DSQLITE_USE_MSIZE |
| 1712 | |
| 1713 | SHELL_OPTIONS = -Dmain=sqlite3_shell \ |
| 1714 | -DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 1715 | -Dgetenv=fossil_getenv \ |
| 1716 | -Dfopen=fossil_fopen |
| 1717 | |
| 1718 | $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c win/Makefile.mingw.mistachkin |
| 1719 | $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 1720 | |
| 1721 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c |
| 1722 | $(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o |
| 1723 | |
| 1724 | $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h |
| 1725 | |
| 1726 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h win/Makefile.mingw.mistachkin |
| 1727 | $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 1728 | |
| 1729 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 1730 | $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 1731 | |
| 1732 |
+10
-10
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -23,12 +23,12 @@ | ||
| 23 | 23 | |
| 24 | 24 | # Uncomment to enable SSL support |
| 25 | 25 | # FOSSIL_ENABLE_SSL = 1 |
| 26 | 26 | |
| 27 | 27 | !ifdef FOSSIL_ENABLE_SSL |
| 28 | -SSLINCDIR = $(B)\compat\openssl-1.0.1e\include | |
| 29 | -SSLLIBDIR = $(B)\compat\openssl-1.0.1e\out32 | |
| 28 | +SSLINCDIR = $(B)\compat\openssl-1.0.1f\include | |
| 29 | +SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32 | |
| 30 | 30 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 31 | 31 | !endif |
| 32 | 32 | |
| 33 | 33 | # zlib options |
| 34 | 34 | ZINCDIR = $(B)\compat\zlib |
| @@ -39,16 +39,18 @@ | ||
| 39 | 39 | |
| 40 | 40 | !ifdef FOSSIL_ENABLE_SSL |
| 41 | 41 | INCL = $(INCL) -I$(SSLINCDIR) |
| 42 | 42 | !endif |
| 43 | 43 | |
| 44 | -CFLAGS = -nologo -MT -O2 | |
| 44 | +CFLAGS = -nologo | |
| 45 | 45 | LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO |
| 46 | 46 | |
| 47 | 47 | !ifdef DEBUG |
| 48 | -CFLAGS = $(CFLAGS) -Zi | |
| 48 | +CFLAGS = $(CFLAGS) -Zi -MTd -Od | |
| 49 | 49 | LDFLAGS = $(LDFLAGS) /DEBUG |
| 50 | +!else | |
| 51 | +CFLAGS = $(CFLAGS) -MT -O2 | |
| 50 | 52 | !endif |
| 51 | 53 | |
| 52 | 54 | BCC = $(CC) $(CFLAGS) |
| 53 | 55 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL) |
| 54 | 56 | RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL) |
| @@ -65,21 +67,19 @@ | ||
| 65 | 67 | RCC = $(RCC) -DFOSSIL_ENABLE_SSL=1 |
| 66 | 68 | LIBS = $(LIBS) $(SSLLIB) |
| 67 | 69 | LIBDIR = $(LIBDIR) -LIBPATH:$(SSLLIBDIR) |
| 68 | 70 | !endif |
| 69 | 71 | |
| 70 | -SQLITE_OPTIONS = /Dlocaltime=fossil_localtime \ | |
| 71 | - /DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 72 | +SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \ | |
| 72 | 73 | /DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 73 | 74 | /DSQLITE_THREADSAFE=0 \ |
| 74 | 75 | /DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 75 | 76 | /DSQLITE_OMIT_DEPRECATED \ |
| 76 | 77 | /DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 77 | 78 | |
| 78 | 79 | SHELL_OPTIONS = /Dmain=sqlite3_shell \ |
| 79 | 80 | /DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 80 | - /Dsqlite3_strglob=strglob \ | |
| 81 | 81 | /Dgetenv=fossil_getenv \ |
| 82 | 82 | /Dfopen=fossil_fopen |
| 83 | 83 | |
| 84 | 84 | SRC = add_.c \ |
| 85 | 85 | allrepo_.c \ |
| @@ -450,15 +450,15 @@ | ||
| 450 | 450 | $(BCC) $** |
| 451 | 451 | |
| 452 | 452 | mkversion$E: $B\src\mkversion.c |
| 453 | 453 | $(BCC) $** |
| 454 | 454 | |
| 455 | -$(OX)\shell$O : $(SRCDIR)\shell.c | |
| 455 | +$(OX)\shell$O : $(SRCDIR)\shell.c $B\win\Makefile.msc | |
| 456 | 456 | $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c |
| 457 | 457 | |
| 458 | -$(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c | |
| 459 | - $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** | |
| 458 | +$(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c $B\win\Makefile.msc | |
| 459 | + $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SRCDIR)\sqlite3.c | |
| 460 | 460 | |
| 461 | 461 | $(OX)\th$O : $(SRCDIR)\th.c |
| 462 | 462 | $(TCC) /Fo$@ -c $** |
| 463 | 463 | |
| 464 | 464 | $(OX)\th_lang$O : $(SRCDIR)\th_lang.c |
| 465 | 465 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -23,12 +23,12 @@ | |
| 23 | |
| 24 | # Uncomment to enable SSL support |
| 25 | # FOSSIL_ENABLE_SSL = 1 |
| 26 | |
| 27 | !ifdef FOSSIL_ENABLE_SSL |
| 28 | SSLINCDIR = $(B)\compat\openssl-1.0.1e\include |
| 29 | SSLLIBDIR = $(B)\compat\openssl-1.0.1e\out32 |
| 30 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 31 | !endif |
| 32 | |
| 33 | # zlib options |
| 34 | ZINCDIR = $(B)\compat\zlib |
| @@ -39,16 +39,18 @@ | |
| 39 | |
| 40 | !ifdef FOSSIL_ENABLE_SSL |
| 41 | INCL = $(INCL) -I$(SSLINCDIR) |
| 42 | !endif |
| 43 | |
| 44 | CFLAGS = -nologo -MT -O2 |
| 45 | LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO |
| 46 | |
| 47 | !ifdef DEBUG |
| 48 | CFLAGS = $(CFLAGS) -Zi |
| 49 | LDFLAGS = $(LDFLAGS) /DEBUG |
| 50 | !endif |
| 51 | |
| 52 | BCC = $(CC) $(CFLAGS) |
| 53 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL) |
| 54 | RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL) |
| @@ -65,21 +67,19 @@ | |
| 65 | RCC = $(RCC) -DFOSSIL_ENABLE_SSL=1 |
| 66 | LIBS = $(LIBS) $(SSLLIB) |
| 67 | LIBDIR = $(LIBDIR) -LIBPATH:$(SSLLIBDIR) |
| 68 | !endif |
| 69 | |
| 70 | SQLITE_OPTIONS = /Dlocaltime=fossil_localtime \ |
| 71 | /DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 72 | /DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 73 | /DSQLITE_THREADSAFE=0 \ |
| 74 | /DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 75 | /DSQLITE_OMIT_DEPRECATED \ |
| 76 | /DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 77 | |
| 78 | SHELL_OPTIONS = /Dmain=sqlite3_shell \ |
| 79 | /DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 80 | /Dsqlite3_strglob=strglob \ |
| 81 | /Dgetenv=fossil_getenv \ |
| 82 | /Dfopen=fossil_fopen |
| 83 | |
| 84 | SRC = add_.c \ |
| 85 | allrepo_.c \ |
| @@ -450,15 +450,15 @@ | |
| 450 | $(BCC) $** |
| 451 | |
| 452 | mkversion$E: $B\src\mkversion.c |
| 453 | $(BCC) $** |
| 454 | |
| 455 | $(OX)\shell$O : $(SRCDIR)\shell.c |
| 456 | $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c |
| 457 | |
| 458 | $(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c |
| 459 | $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** |
| 460 | |
| 461 | $(OX)\th$O : $(SRCDIR)\th.c |
| 462 | $(TCC) /Fo$@ -c $** |
| 463 | |
| 464 | $(OX)\th_lang$O : $(SRCDIR)\th_lang.c |
| 465 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -23,12 +23,12 @@ | |
| 23 | |
| 24 | # Uncomment to enable SSL support |
| 25 | # FOSSIL_ENABLE_SSL = 1 |
| 26 | |
| 27 | !ifdef FOSSIL_ENABLE_SSL |
| 28 | SSLINCDIR = $(B)\compat\openssl-1.0.1f\include |
| 29 | SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32 |
| 30 | SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib |
| 31 | !endif |
| 32 | |
| 33 | # zlib options |
| 34 | ZINCDIR = $(B)\compat\zlib |
| @@ -39,16 +39,18 @@ | |
| 39 | |
| 40 | !ifdef FOSSIL_ENABLE_SSL |
| 41 | INCL = $(INCL) -I$(SSLINCDIR) |
| 42 | !endif |
| 43 | |
| 44 | CFLAGS = -nologo |
| 45 | LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO |
| 46 | |
| 47 | !ifdef DEBUG |
| 48 | CFLAGS = $(CFLAGS) -Zi -MTd -Od |
| 49 | LDFLAGS = $(LDFLAGS) /DEBUG |
| 50 | !else |
| 51 | CFLAGS = $(CFLAGS) -MT -O2 |
| 52 | !endif |
| 53 | |
| 54 | BCC = $(CC) $(CFLAGS) |
| 55 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL) |
| 56 | RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL) |
| @@ -65,21 +67,19 @@ | |
| 67 | RCC = $(RCC) -DFOSSIL_ENABLE_SSL=1 |
| 68 | LIBS = $(LIBS) $(SSLLIB) |
| 69 | LIBDIR = $(LIBDIR) -LIBPATH:$(SSLLIBDIR) |
| 70 | !endif |
| 71 | |
| 72 | SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 73 | /DSQLITE_ENABLE_LOCKING_STYLE=0 \ |
| 74 | /DSQLITE_THREADSAFE=0 \ |
| 75 | /DSQLITE_DEFAULT_FILE_FORMAT=4 \ |
| 76 | /DSQLITE_OMIT_DEPRECATED \ |
| 77 | /DSQLITE_ENABLE_EXPLAIN_COMMENTS |
| 78 | |
| 79 | SHELL_OPTIONS = /Dmain=sqlite3_shell \ |
| 80 | /DSQLITE_OMIT_LOAD_EXTENSION=1 \ |
| 81 | /Dgetenv=fossil_getenv \ |
| 82 | /Dfopen=fossil_fopen |
| 83 | |
| 84 | SRC = add_.c \ |
| 85 | allrepo_.c \ |
| @@ -450,15 +450,15 @@ | |
| 450 | $(BCC) $** |
| 451 | |
| 452 | mkversion$E: $B\src\mkversion.c |
| 453 | $(BCC) $** |
| 454 | |
| 455 | $(OX)\shell$O : $(SRCDIR)\shell.c $B\win\Makefile.msc |
| 456 | $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c |
| 457 | |
| 458 | $(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c $B\win\Makefile.msc |
| 459 | $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SRCDIR)\sqlite3.c |
| 460 | |
| 461 | $(OX)\th$O : $(SRCDIR)\th.c |
| 462 | $(TCC) /Fo$@ -c $** |
| 463 | |
| 464 | $(OX)\th_lang$O : $(SRCDIR)\th_lang.c |
| 465 |
+22
-2
| --- www/build.wiki | ||
| +++ www/build.wiki | ||
| @@ -17,12 +17,12 @@ | ||
| 17 | 17 | <p>Building and installing is very simple. Three steps:</p> |
| 18 | 18 | |
| 19 | 19 | <ol> |
| 20 | 20 | <li> Download and unpack a source tarball or ZIP. |
| 21 | 21 | <li> <b>./configure; make</b> |
| 22 | -<li> Move or copy the resulting "fossil" executable to someplace | |
| 23 | - on your $PATH. | |
| 22 | +<li> Move the resulting "fossil" or "fossil.exe" executable to someplace on | |
| 23 | +your $PATH. | |
| 24 | 24 | </ol> |
| 25 | 25 | |
| 26 | 26 | <p><hr> |
| 27 | 27 | |
| 28 | 28 | <h2>1.0 Obtaining The Source Code</h2> |
| @@ -50,10 +50,30 @@ | ||
| 50 | 50 | <li><p>Finally, click on one of the |
| 51 | 51 | "Zip Archive" or "Tarball" links, according to your preference. |
| 52 | 52 | These link will build a ZIP archive or a gzip-compressed tarball of the |
| 53 | 53 | complete source code and download it to your browser. |
| 54 | 54 | </ol> |
| 55 | + | |
| 56 | +<h2>Aside: Is it really safe to use an unreleased development version of | |
| 57 | +the Fossil source code?</h2> | |
| 58 | + | |
| 59 | +Yes! Any check-in on the | |
| 60 | +[/timeline?t=trunk | trunk branch] of the Fossil | |
| 61 | +[http://fossil-scm.org/fossil/timeline | Fossil self-hosting repository] | |
| 62 | +will work fine. (Dodgy code is always on a branch.) In the unlikely | |
| 63 | +event that you pick a version with a serious bug, it still won't | |
| 64 | +clobber your files. Fossil uses several | |
| 65 | +[./selfcheck.wiki | self-checks] prior to committing any | |
| 66 | +repository change that prevent loss-of-work due to bugs. | |
| 67 | + | |
| 68 | +The Fossil [./selfhost.wiki | self-hosting repositories], especially | |
| 69 | +the one at [http://www.fossil-scm.org/fossil], usually run a version | |
| 70 | +of trunk that is less than a week or two old. Look at the bottom | |
| 71 | +right-hand corner of this screen (to the right of "This page was | |
| 72 | +generated in...") to see exactly which version of Fossil is | |
| 73 | +rendering this page. It is always safe to use whatever version | |
| 74 | +of the Fossil code you find running on the main Fossil website. | |
| 55 | 75 | |
| 56 | 76 | <h2>2.0 Compiling</h2> |
| 57 | 77 | |
| 58 | 78 | <ol> |
| 59 | 79 | <li value="5"> |
| 60 | 80 |
| --- www/build.wiki | |
| +++ www/build.wiki | |
| @@ -17,12 +17,12 @@ | |
| 17 | <p>Building and installing is very simple. Three steps:</p> |
| 18 | |
| 19 | <ol> |
| 20 | <li> Download and unpack a source tarball or ZIP. |
| 21 | <li> <b>./configure; make</b> |
| 22 | <li> Move or copy the resulting "fossil" executable to someplace |
| 23 | on your $PATH. |
| 24 | </ol> |
| 25 | |
| 26 | <p><hr> |
| 27 | |
| 28 | <h2>1.0 Obtaining The Source Code</h2> |
| @@ -50,10 +50,30 @@ | |
| 50 | <li><p>Finally, click on one of the |
| 51 | "Zip Archive" or "Tarball" links, according to your preference. |
| 52 | These link will build a ZIP archive or a gzip-compressed tarball of the |
| 53 | complete source code and download it to your browser. |
| 54 | </ol> |
| 55 | |
| 56 | <h2>2.0 Compiling</h2> |
| 57 | |
| 58 | <ol> |
| 59 | <li value="5"> |
| 60 |
| --- www/build.wiki | |
| +++ www/build.wiki | |
| @@ -17,12 +17,12 @@ | |
| 17 | <p>Building and installing is very simple. Three steps:</p> |
| 18 | |
| 19 | <ol> |
| 20 | <li> Download and unpack a source tarball or ZIP. |
| 21 | <li> <b>./configure; make</b> |
| 22 | <li> Move the resulting "fossil" or "fossil.exe" executable to someplace on |
| 23 | your $PATH. |
| 24 | </ol> |
| 25 | |
| 26 | <p><hr> |
| 27 | |
| 28 | <h2>1.0 Obtaining The Source Code</h2> |
| @@ -50,10 +50,30 @@ | |
| 50 | <li><p>Finally, click on one of the |
| 51 | "Zip Archive" or "Tarball" links, according to your preference. |
| 52 | These link will build a ZIP archive or a gzip-compressed tarball of the |
| 53 | complete source code and download it to your browser. |
| 54 | </ol> |
| 55 | |
| 56 | <h2>Aside: Is it really safe to use an unreleased development version of |
| 57 | the Fossil source code?</h2> |
| 58 | |
| 59 | Yes! Any check-in on the |
| 60 | [/timeline?t=trunk | trunk branch] of the Fossil |
| 61 | [http://fossil-scm.org/fossil/timeline | Fossil self-hosting repository] |
| 62 | will work fine. (Dodgy code is always on a branch.) In the unlikely |
| 63 | event that you pick a version with a serious bug, it still won't |
| 64 | clobber your files. Fossil uses several |
| 65 | [./selfcheck.wiki | self-checks] prior to committing any |
| 66 | repository change that prevent loss-of-work due to bugs. |
| 67 | |
| 68 | The Fossil [./selfhost.wiki | self-hosting repositories], especially |
| 69 | the one at [http://www.fossil-scm.org/fossil], usually run a version |
| 70 | of trunk that is less than a week or two old. Look at the bottom |
| 71 | right-hand corner of this screen (to the right of "This page was |
| 72 | generated in...") to see exactly which version of Fossil is |
| 73 | rendering this page. It is always safe to use whatever version |
| 74 | of the Fossil code you find running on the main Fossil website. |
| 75 | |
| 76 | <h2>2.0 Compiling</h2> |
| 77 | |
| 78 | <ol> |
| 79 | <li value="5"> |
| 80 |
+18
| --- www/changes.wiki | ||
| +++ www/changes.wiki | ||
| @@ -32,10 +32,28 @@ | ||
| 32 | 32 | which does not store the URL or password when cloning. |
| 33 | 33 | * Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open |
| 34 | 34 | repository. |
| 35 | 35 | * Fossil now hides check-ins that have the "hidden" tag in timeline webpages. |
| 36 | 36 | * Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins. |
| 37 | + * Advanced possibilities for commit and ticket change notifications over | |
| 38 | + http using TH1 scripting. | |
| 39 | + * Add --sha1sum and --integrate options | |
| 40 | + to the "[/help?cmd=commit | fossil commit]" command. | |
| 41 | + * Add the "clean" and "extra" subcommands to the | |
| 42 | + "[/help?cmd=all | fossil all]" command | |
| 43 | + * Add the --whatif option to "[/help?cmd=clean|fossil clean]" that works the | |
| 44 | + same as "--dry-run", | |
| 45 | + so that the name does not collide with the --dry-run option of "fossil all". | |
| 46 | + * Provide a configuration option to show dates on the web timeline | |
| 47 | + as "YYMMMDD HH:MM" | |
| 48 | + * Add an option to the "stats" webpage that allows an administrator to see | |
| 49 | + the current repository schema. | |
| 50 | + * Enhancements to the "[/help?cmd=/vdiff|/vdiff]" webpage for more difference | |
| 51 | + display options. | |
| 52 | + * Added the "[/tree?ci=trunk&expand | /tree]" webpage as an alternative | |
| 53 | + to "/dir" and make it the default way of showing file lists. | |
| 54 | + * Send gzipped HTTP responses to clients that support it. | |
| 37 | 55 | |
| 38 | 56 | <h2>Changes For Version 1.27 (2013-09-11)</h2> |
| 39 | 57 | * Enhance the [/help?cmd=changes | fossil changes], |
| 40 | 58 | [/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras], |
| 41 | 59 | [/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands |
| 42 | 60 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -32,10 +32,28 @@ | |
| 32 | which does not store the URL or password when cloning. |
| 33 | * Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open |
| 34 | repository. |
| 35 | * Fossil now hides check-ins that have the "hidden" tag in timeline webpages. |
| 36 | * Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins. |
| 37 | |
| 38 | <h2>Changes For Version 1.27 (2013-09-11)</h2> |
| 39 | * Enhance the [/help?cmd=changes | fossil changes], |
| 40 | [/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras], |
| 41 | [/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands |
| 42 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -32,10 +32,28 @@ | |
| 32 | which does not store the URL or password when cloning. |
| 33 | * Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open |
| 34 | repository. |
| 35 | * Fossil now hides check-ins that have the "hidden" tag in timeline webpages. |
| 36 | * Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins. |
| 37 | * Advanced possibilities for commit and ticket change notifications over |
| 38 | http using TH1 scripting. |
| 39 | * Add --sha1sum and --integrate options |
| 40 | to the "[/help?cmd=commit | fossil commit]" command. |
| 41 | * Add the "clean" and "extra" subcommands to the |
| 42 | "[/help?cmd=all | fossil all]" command |
| 43 | * Add the --whatif option to "[/help?cmd=clean|fossil clean]" that works the |
| 44 | same as "--dry-run", |
| 45 | so that the name does not collide with the --dry-run option of "fossil all". |
| 46 | * Provide a configuration option to show dates on the web timeline |
| 47 | as "YYMMMDD HH:MM" |
| 48 | * Add an option to the "stats" webpage that allows an administrator to see |
| 49 | the current repository schema. |
| 50 | * Enhancements to the "[/help?cmd=/vdiff|/vdiff]" webpage for more difference |
| 51 | display options. |
| 52 | * Added the "[/tree?ci=trunk&expand | /tree]" webpage as an alternative |
| 53 | to "/dir" and make it the default way of showing file lists. |
| 54 | * Send gzipped HTTP responses to clients that support it. |
| 55 | |
| 56 | <h2>Changes For Version 1.27 (2013-09-11)</h2> |
| 57 | * Enhance the [/help?cmd=changes | fossil changes], |
| 58 | [/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras], |
| 59 | [/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands |
| 60 |
+6
-7
| --- www/makefile.wiki | ||
| +++ www/makefile.wiki | ||
| @@ -203,23 +203,22 @@ | ||
| 203 | 203 | together in a final step. |
| 204 | 204 | |
| 205 | 205 | Some files require special C-preprocessor macro definitions. |
| 206 | 206 | When compiling sqlite.c, the following macros are recommended: |
| 207 | 207 | |
| 208 | - * -Dlocaltime=fossil_localtime | |
| 209 | 208 | * -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 210 | 209 | * -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 211 | 210 | * -DSQLITE_THREADSAFE=0 |
| 212 | 211 | * -DSQLITE_DEFAULT_FILE_FORMAT=4 |
| 212 | + * -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 | |
| 213 | 213 | |
| 214 | -The first and second symbol definitions above are required; the others | |
| 215 | -are merely recommended. The "localtime()" library function in SQLite must | |
| 216 | -be redefined to invoke fossil_localtime() instead. The fossil_localtime() | |
| 217 | -routine will invoke either gmtime() or localtime() depending on the | |
| 218 | -"Use UTC" setting for the fossil repository. Extension loading is omitted | |
| 214 | +The first symbol definition above is required; the others | |
| 215 | +are merely recommended. Extension loading is omitted | |
| 219 | 216 | as a security measure. Fossil is single-threaded so mutexing is disabled |
| 220 | -in SQLite as a performance enhancement. | |
| 217 | +in SQLite as a performance enhancement. The SQLITE_ENABLE_EXPLAIN_COMMENTS | |
| 218 | +option makes the output of "EXPLAIN" queries in the | |
| 219 | +"[/help?cmd=sqlite3|fossil sql]" command much more readable. | |
| 221 | 220 | |
| 222 | 221 | When compiling the shell.c source file, these macros are required: |
| 223 | 222 | |
| 224 | 223 | * -Dmain=sqlite3_main |
| 225 | 224 | * -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 226 | 225 |
| --- www/makefile.wiki | |
| +++ www/makefile.wiki | |
| @@ -203,23 +203,22 @@ | |
| 203 | together in a final step. |
| 204 | |
| 205 | Some files require special C-preprocessor macro definitions. |
| 206 | When compiling sqlite.c, the following macros are recommended: |
| 207 | |
| 208 | * -Dlocaltime=fossil_localtime |
| 209 | * -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 210 | * -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 211 | * -DSQLITE_THREADSAFE=0 |
| 212 | * -DSQLITE_DEFAULT_FILE_FORMAT=4 |
| 213 | |
| 214 | The first and second symbol definitions above are required; the others |
| 215 | are merely recommended. The "localtime()" library function in SQLite must |
| 216 | be redefined to invoke fossil_localtime() instead. The fossil_localtime() |
| 217 | routine will invoke either gmtime() or localtime() depending on the |
| 218 | "Use UTC" setting for the fossil repository. Extension loading is omitted |
| 219 | as a security measure. Fossil is single-threaded so mutexing is disabled |
| 220 | in SQLite as a performance enhancement. |
| 221 | |
| 222 | When compiling the shell.c source file, these macros are required: |
| 223 | |
| 224 | * -Dmain=sqlite3_main |
| 225 | * -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 226 |
| --- www/makefile.wiki | |
| +++ www/makefile.wiki | |
| @@ -203,23 +203,22 @@ | |
| 203 | together in a final step. |
| 204 | |
| 205 | Some files require special C-preprocessor macro definitions. |
| 206 | When compiling sqlite.c, the following macros are recommended: |
| 207 | |
| 208 | * -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 209 | * -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 210 | * -DSQLITE_THREADSAFE=0 |
| 211 | * -DSQLITE_DEFAULT_FILE_FORMAT=4 |
| 212 | * -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 |
| 213 | |
| 214 | The first symbol definition above is required; the others |
| 215 | are merely recommended. Extension loading is omitted |
| 216 | as a security measure. Fossil is single-threaded so mutexing is disabled |
| 217 | in SQLite as a performance enhancement. The SQLITE_ENABLE_EXPLAIN_COMMENTS |
| 218 | option makes the output of "EXPLAIN" queries in the |
| 219 | "[/help?cmd=sqlite3|fossil sql]" command much more readable. |
| 220 | |
| 221 | When compiling the shell.c source file, these macros are required: |
| 222 | |
| 223 | * -Dmain=sqlite3_main |
| 224 | * -DSQLITE_OMIT_LOAD_EXTENSION=1 |
| 225 |