Fossil SCM
merge current trunk
Commit
8cbcf36be3d7b7c62a2b27542fef4b4eea9bd7e48aa807b8c5cad2a1cdae7688
Parent
a42c48797cf4458…
39 files changed
+1
-1
+208
-192
+204
-142
+6
-5
+1
-1
+1
-1
+4
-2
+1
-1
+7
-1
+2
-1
+6
-2
+15
-7
+15
-7
+2
-2
+2
-2
+89
-182
+1
-22
+1
-22
+1
-1
+3
-51
+8
+47
-11
-4
+3
+34
-19
+2
-2
+3
-2
+1
-1
+12
-7
+2
-3
+37
-18
+1
-1
+37
-1
+1
-1
+1
-1
+4
-4
+16
-18
+21
-24
~
VERSION
~
extsrc/shell.c
~
extsrc/sqlite3.c
~
extsrc/sqlite3.h
~
src/ajax.c
~
src/cgi.c
~
src/clone.c
~
src/db.c
~
src/diff.tcl
~
src/http.c
~
src/info.c
~
src/main.mk
~
src/main.mk
~
src/manifest.c
~
src/markdown_html.c
~
src/pikchrshow.c
~
src/repolist.c
~
src/repolist.c
~
src/tag.c
~
src/th_main.c
~
src/th_tcl.c
~
src/timeline.c
~
src/tkt.c
~
src/tktsetup.c
~
src/winfile.c
~
src/xfer.c
~
src/zip.c
~
test/tester.tcl
~
test/th1.test
~
tools/makemake.tcl
~
www/cgi.wiki
~
www/changes.wiki
~
www/containers.md
~
www/customskin.md
~
www/fossil-v-git.wiki
~
www/gsoc-ideas.md
~
www/index.wiki
~
www/reviews.wiki
~
www/th1.md
M
VERSION
+1
-1
| --- VERSION | ||
| +++ VERSION | ||
| @@ -1,1 +1,1 @@ | ||
| 1 | -2.26 | |
| 1 | +2.27 | |
| 2 | 2 |
| --- VERSION | |
| +++ VERSION | |
| @@ -1,1 +1,1 @@ | |
| 1 | 2.26 |
| 2 |
| --- VERSION | |
| +++ VERSION | |
| @@ -1,1 +1,1 @@ | |
| 1 | 2.27 |
| 2 |
+208
-192
| --- extsrc/shell.c | ||
| +++ extsrc/shell.c | ||
| @@ -1622,34 +1622,10 @@ | ||
| 1622 | 1622 | if( n>350 ) n = 350; |
| 1623 | 1623 | sqlite3_snprintf(sizeof(z), z, "%#+.*e", n, r); |
| 1624 | 1624 | sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); |
| 1625 | 1625 | } |
| 1626 | 1626 | |
| 1627 | - | |
| 1628 | -/* | |
| 1629 | -** SQL function: shell_module_schema(X) | |
| 1630 | -** | |
| 1631 | -** Return a fake schema for the table-valued function or eponymous virtual | |
| 1632 | -** table X. | |
| 1633 | -*/ | |
| 1634 | -static void shellModuleSchema( | |
| 1635 | - sqlite3_context *pCtx, | |
| 1636 | - int nVal, | |
| 1637 | - sqlite3_value **apVal | |
| 1638 | -){ | |
| 1639 | - const char *zName; | |
| 1640 | - char *zFake; | |
| 1641 | - UNUSED_PARAMETER(nVal); | |
| 1642 | - zName = (const char*)sqlite3_value_text(apVal[0]); | |
| 1643 | - zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0; | |
| 1644 | - if( zFake ){ | |
| 1645 | - sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), | |
| 1646 | - -1, sqlite3_free); | |
| 1647 | - free(zFake); | |
| 1648 | - } | |
| 1649 | -} | |
| 1650 | - | |
| 1651 | 1627 | /* |
| 1652 | 1628 | ** SQL function: shell_add_schema(S,X) |
| 1653 | 1629 | ** |
| 1654 | 1630 | ** Add the schema name X to the CREATE statement in S and return the result. |
| 1655 | 1631 | ** Examples: |
| @@ -1820,10 +1796,11 @@ | ||
| 1820 | 1796 | # ifdef FILENAME_MAX |
| 1821 | 1797 | # define NAME_MAX (FILENAME_MAX) |
| 1822 | 1798 | # else |
| 1823 | 1799 | # define NAME_MAX (260) |
| 1824 | 1800 | # endif |
| 1801 | +# define DIRENT_NAME_MAX (NAME_MAX) | |
| 1825 | 1802 | #endif |
| 1826 | 1803 | |
| 1827 | 1804 | /* |
| 1828 | 1805 | ** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T". |
| 1829 | 1806 | */ |
| @@ -1863,12 +1840,11 @@ | ||
| 1863 | 1840 | #endif |
| 1864 | 1841 | |
| 1865 | 1842 | /* |
| 1866 | 1843 | ** Provide a macro, for use by the implementation, to determine if a |
| 1867 | 1844 | ** particular directory entry should be skipped over when searching for |
| 1868 | -** the next directory entry that should be returned by the readdir() or | |
| 1869 | -** readdir_r() functions. | |
| 1845 | +** the next directory entry that should be returned by the readdir(). | |
| 1870 | 1846 | */ |
| 1871 | 1847 | |
| 1872 | 1848 | #ifndef is_filtered |
| 1873 | 1849 | # define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) |
| 1874 | 1850 | #endif |
| @@ -1880,16 +1856,15 @@ | ||
| 1880 | 1856 | |
| 1881 | 1857 | extern const char *windirent_getenv(const char *name); |
| 1882 | 1858 | |
| 1883 | 1859 | /* |
| 1884 | 1860 | ** Finally, we can provide the function prototypes for the opendir(), |
| 1885 | -** readdir(), readdir_r(), and closedir() POSIX functions. | |
| 1861 | +** readdir(), and closedir() POSIX functions. | |
| 1886 | 1862 | */ |
| 1887 | 1863 | |
| 1888 | 1864 | extern LPDIR opendir(const char *dirname); |
| 1889 | 1865 | extern LPDIRENT readdir(LPDIR dirp); |
| 1890 | -extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result); | |
| 1891 | 1866 | extern INT closedir(LPDIR dirp); |
| 1892 | 1867 | |
| 1893 | 1868 | #endif /* defined(WIN32) && defined(_MSC_VER) */ |
| 1894 | 1869 | |
| 1895 | 1870 | /************************* End test_windirent.h ********************/ |
| @@ -1942,27 +1917,45 @@ | ||
| 1942 | 1917 | |
| 1943 | 1918 | /* |
| 1944 | 1919 | ** Implementation of the POSIX opendir() function using the MSVCRT. |
| 1945 | 1920 | */ |
| 1946 | 1921 | LPDIR opendir( |
| 1947 | - const char *dirname | |
| 1922 | + const char *dirname /* Directory name, UTF8 encoding */ | |
| 1948 | 1923 | ){ |
| 1949 | - struct _finddata_t data; | |
| 1924 | + struct _wfinddata_t data; | |
| 1950 | 1925 | LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); |
| 1951 | 1926 | SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); |
| 1927 | + wchar_t *b1; | |
| 1928 | + sqlite3_int64 sz; | |
| 1952 | 1929 | |
| 1953 | 1930 | if( dirp==NULL ) return NULL; |
| 1954 | 1931 | memset(dirp, 0, sizeof(DIR)); |
| 1955 | 1932 | |
| 1956 | 1933 | /* TODO: Remove this if Unix-style root paths are not used. */ |
| 1957 | 1934 | if( sqlite3_stricmp(dirname, "/")==0 ){ |
| 1958 | 1935 | dirname = windirent_getenv("SystemDrive"); |
| 1959 | 1936 | } |
| 1960 | 1937 | |
| 1961 | - memset(&data, 0, sizeof(struct _finddata_t)); | |
| 1962 | - _snprintf(data.name, namesize, "%s\\*", dirname); | |
| 1963 | - dirp->d_handle = _findfirst(data.name, &data); | |
| 1938 | + memset(&data, 0, sizeof(data)); | |
| 1939 | + sz = strlen(dirname); | |
| 1940 | + b1 = sqlite3_malloc64( (sz+3)*sizeof(b1[0]) ); | |
| 1941 | + if( b1==0 ){ | |
| 1942 | + closedir(dirp); | |
| 1943 | + return NULL; | |
| 1944 | + } | |
| 1945 | + sz = MultiByteToWideChar(CP_UTF8, 0, dirname, sz, b1, sz); | |
| 1946 | + b1[sz++] = '\\'; | |
| 1947 | + b1[sz++] = '*'; | |
| 1948 | + b1[sz] = 0; | |
| 1949 | + if( sz+1>(sqlite3_int64)namesize ){ | |
| 1950 | + closedir(dirp); | |
| 1951 | + sqlite3_free(b1); | |
| 1952 | + return NULL; | |
| 1953 | + } | |
| 1954 | + memcpy(data.name, b1, (sz+1)*sizeof(b1[0])); | |
| 1955 | + sqlite3_free(b1); | |
| 1956 | + dirp->d_handle = _wfindfirst(data.name, &data); | |
| 1964 | 1957 | |
| 1965 | 1958 | if( dirp->d_handle==BAD_INTPTR_T ){ |
| 1966 | 1959 | closedir(dirp); |
| 1967 | 1960 | return NULL; |
| 1968 | 1961 | } |
| @@ -1969,34 +1962,33 @@ | ||
| 1969 | 1962 | |
| 1970 | 1963 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 1971 | 1964 | if( is_filtered(data) ){ |
| 1972 | 1965 | next: |
| 1973 | 1966 | |
| 1974 | - memset(&data, 0, sizeof(struct _finddata_t)); | |
| 1975 | - if( _findnext(dirp->d_handle, &data)==-1 ){ | |
| 1967 | + memset(&data, 0, sizeof(data)); | |
| 1968 | + if( _wfindnext(dirp->d_handle, &data)==-1 ){ | |
| 1976 | 1969 | closedir(dirp); |
| 1977 | 1970 | return NULL; |
| 1978 | 1971 | } |
| 1979 | 1972 | |
| 1980 | 1973 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 1981 | 1974 | if( is_filtered(data) ) goto next; |
| 1982 | 1975 | } |
| 1983 | 1976 | |
| 1984 | 1977 | dirp->d_first.d_attributes = data.attrib; |
| 1985 | - strncpy(dirp->d_first.d_name, data.name, NAME_MAX); | |
| 1986 | - dirp->d_first.d_name[NAME_MAX] = '\0'; | |
| 1987 | - | |
| 1978 | + WideCharToMultiByte(CP_UTF8, 0, data.name, -1, | |
| 1979 | + dirp->d_first.d_name, DIRENT_NAME_MAX, 0, 0); | |
| 1988 | 1980 | return dirp; |
| 1989 | 1981 | } |
| 1990 | 1982 | |
| 1991 | 1983 | /* |
| 1992 | 1984 | ** Implementation of the POSIX readdir() function using the MSVCRT. |
| 1993 | 1985 | */ |
| 1994 | 1986 | LPDIRENT readdir( |
| 1995 | 1987 | LPDIR dirp |
| 1996 | 1988 | ){ |
| 1997 | - struct _finddata_t data; | |
| 1989 | + struct _wfinddata_t data; | |
| 1998 | 1990 | |
| 1999 | 1991 | if( dirp==NULL ) return NULL; |
| 2000 | 1992 | |
| 2001 | 1993 | if( dirp->d_first.d_ino==0 ){ |
| 2002 | 1994 | dirp->d_first.d_ino++; |
| @@ -2005,69 +1997,23 @@ | ||
| 2005 | 1997 | return &dirp->d_first; |
| 2006 | 1998 | } |
| 2007 | 1999 | |
| 2008 | 2000 | next: |
| 2009 | 2001 | |
| 2010 | - memset(&data, 0, sizeof(struct _finddata_t)); | |
| 2011 | - if( _findnext(dirp->d_handle, &data)==-1 ) return NULL; | |
| 2002 | + memset(&data, 0, sizeof(data)); | |
| 2003 | + if( _wfindnext(dirp->d_handle, &data)==-1 ) return NULL; | |
| 2012 | 2004 | |
| 2013 | 2005 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 2014 | 2006 | if( is_filtered(data) ) goto next; |
| 2015 | 2007 | |
| 2016 | 2008 | dirp->d_next.d_ino++; |
| 2017 | 2009 | dirp->d_next.d_attributes = data.attrib; |
| 2018 | - strncpy(dirp->d_next.d_name, data.name, NAME_MAX); | |
| 2019 | - dirp->d_next.d_name[NAME_MAX] = '\0'; | |
| 2020 | - | |
| 2010 | + WideCharToMultiByte(CP_UTF8, 0, data.name, -1, | |
| 2011 | + dirp->d_next.d_name, DIRENT_NAME_MAX, 0, 0); | |
| 2021 | 2012 | return &dirp->d_next; |
| 2022 | 2013 | } |
| 2023 | 2014 | |
| 2024 | -/* | |
| 2025 | -** Implementation of the POSIX readdir_r() function using the MSVCRT. | |
| 2026 | -*/ | |
| 2027 | -INT readdir_r( | |
| 2028 | - LPDIR dirp, | |
| 2029 | - LPDIRENT entry, | |
| 2030 | - LPDIRENT *result | |
| 2031 | -){ | |
| 2032 | - struct _finddata_t data; | |
| 2033 | - | |
| 2034 | - if( dirp==NULL ) return EBADF; | |
| 2035 | - | |
| 2036 | - if( dirp->d_first.d_ino==0 ){ | |
| 2037 | - dirp->d_first.d_ino++; | |
| 2038 | - dirp->d_next.d_ino++; | |
| 2039 | - | |
| 2040 | - entry->d_ino = dirp->d_first.d_ino; | |
| 2041 | - entry->d_attributes = dirp->d_first.d_attributes; | |
| 2042 | - strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX); | |
| 2043 | - entry->d_name[NAME_MAX] = '\0'; | |
| 2044 | - | |
| 2045 | - *result = entry; | |
| 2046 | - return 0; | |
| 2047 | - } | |
| 2048 | - | |
| 2049 | -next: | |
| 2050 | - | |
| 2051 | - memset(&data, 0, sizeof(struct _finddata_t)); | |
| 2052 | - if( _findnext(dirp->d_handle, &data)==-1 ){ | |
| 2053 | - *result = NULL; | |
| 2054 | - return ENOENT; | |
| 2055 | - } | |
| 2056 | - | |
| 2057 | - /* TODO: Remove this block to allow hidden and/or system files. */ | |
| 2058 | - if( is_filtered(data) ) goto next; | |
| 2059 | - | |
| 2060 | - entry->d_ino = (ino_t)-1; /* not available */ | |
| 2061 | - entry->d_attributes = data.attrib; | |
| 2062 | - strncpy(entry->d_name, data.name, NAME_MAX); | |
| 2063 | - entry->d_name[NAME_MAX] = '\0'; | |
| 2064 | - | |
| 2065 | - *result = entry; | |
| 2066 | - return 0; | |
| 2067 | -} | |
| 2068 | - | |
| 2069 | 2015 | /* |
| 2070 | 2016 | ** Implementation of the POSIX closedir() function using the MSVCRT. |
| 2071 | 2017 | */ |
| 2072 | 2018 | INT closedir( |
| 2073 | 2019 | LPDIR dirp |
| @@ -8085,18 +8031,13 @@ | ||
| 8085 | 8031 | # include "windows.h" |
| 8086 | 8032 | # include <io.h> |
| 8087 | 8033 | # include <direct.h> |
| 8088 | 8034 | /* # include "test_windirent.h" */ |
| 8089 | 8035 | # define dirent DIRENT |
| 8090 | -# ifndef chmod | |
| 8091 | -# define chmod _chmod | |
| 8092 | -# endif | |
| 8093 | -# ifndef stat | |
| 8094 | -# define stat _stat | |
| 8095 | -# endif | |
| 8096 | -# define mkdir(path,mode) _mkdir(path) | |
| 8097 | -# define lstat(path,buf) stat(path,buf) | |
| 8036 | +# define stat _stat | |
| 8037 | +# define chmod(path,mode) fileio_chmod(path,mode) | |
| 8038 | +# define mkdir(path,mode) fileio_mkdir(path) | |
| 8098 | 8039 | #endif |
| 8099 | 8040 | #include <time.h> |
| 8100 | 8041 | #include <errno.h> |
| 8101 | 8042 | |
| 8102 | 8043 | /* When used as part of the CLI, the sqlite3_stdio.h module will have |
| @@ -8117,10 +8058,44 @@ | ||
| 8117 | 8058 | #define FSDIR_COLUMN_MTIME 2 /* Last modification time */ |
| 8118 | 8059 | #define FSDIR_COLUMN_DATA 3 /* File content */ |
| 8119 | 8060 | #define FSDIR_COLUMN_PATH 4 /* Path to top of search */ |
| 8120 | 8061 | #define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */ |
| 8121 | 8062 | |
| 8063 | +/* | |
| 8064 | +** UTF8 chmod() function for Windows | |
| 8065 | +*/ | |
| 8066 | +#if defined(_WIN32) || defined(WIN32) | |
| 8067 | +static int fileio_chmod(const char *zPath, int pmode){ | |
| 8068 | + sqlite3_int64 sz = strlen(zPath); | |
| 8069 | + wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); | |
| 8070 | + int rc; | |
| 8071 | + if( b1==0 ) return -1; | |
| 8072 | + sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); | |
| 8073 | + b1[sz] = 0; | |
| 8074 | + rc = _wchmod(b1, pmode); | |
| 8075 | + sqlite3_free(b1); | |
| 8076 | + return rc; | |
| 8077 | +} | |
| 8078 | +#endif | |
| 8079 | + | |
| 8080 | +/* | |
| 8081 | +** UTF8 mkdir() function for Windows | |
| 8082 | +*/ | |
| 8083 | +#if defined(_WIN32) || defined(WIN32) | |
| 8084 | +static int fileio_mkdir(const char *zPath){ | |
| 8085 | + sqlite3_int64 sz = strlen(zPath); | |
| 8086 | + wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); | |
| 8087 | + int rc; | |
| 8088 | + if( b1==0 ) return -1; | |
| 8089 | + sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); | |
| 8090 | + b1[sz] = 0; | |
| 8091 | + rc = _wmkdir(b1); | |
| 8092 | + sqlite3_free(b1); | |
| 8093 | + return rc; | |
| 8094 | +} | |
| 8095 | +#endif | |
| 8096 | + | |
| 8122 | 8097 | |
| 8123 | 8098 | /* |
| 8124 | 8099 | ** Set the result stored by context ctx to a blob containing the |
| 8125 | 8100 | ** contents of file zName. Or, leave the result unchanged (NULL) |
| 8126 | 8101 | ** if the file does not exist or is unreadable. |
| @@ -8278,11 +8253,17 @@ | ||
| 8278 | 8253 | static int fileStat( |
| 8279 | 8254 | const char *zPath, |
| 8280 | 8255 | struct stat *pStatBuf |
| 8281 | 8256 | ){ |
| 8282 | 8257 | #if defined(_WIN32) |
| 8283 | - int rc = stat(zPath, pStatBuf); | |
| 8258 | + sqlite3_int64 sz = strlen(zPath); | |
| 8259 | + wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); | |
| 8260 | + int rc; | |
| 8261 | + if( b1==0 ) return 1; | |
| 8262 | + sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); | |
| 8263 | + b1[sz] = 0; | |
| 8264 | + rc = _wstat(b1, pStatBuf); | |
| 8284 | 8265 | if( rc==0 ) statTimesToUtc(zPath, pStatBuf); |
| 8285 | 8266 | return rc; |
| 8286 | 8267 | #else |
| 8287 | 8268 | return stat(zPath, pStatBuf); |
| 8288 | 8269 | #endif |
| @@ -8296,13 +8277,11 @@ | ||
| 8296 | 8277 | static int fileLinkStat( |
| 8297 | 8278 | const char *zPath, |
| 8298 | 8279 | struct stat *pStatBuf |
| 8299 | 8280 | ){ |
| 8300 | 8281 | #if defined(_WIN32) |
| 8301 | - int rc = lstat(zPath, pStatBuf); | |
| 8302 | - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); | |
| 8303 | - return rc; | |
| 8282 | + return fileStat(zPath, pStatBuf); | |
| 8304 | 8283 | #else |
| 8305 | 8284 | return lstat(zPath, pStatBuf); |
| 8306 | 8285 | #endif |
| 8307 | 8286 | } |
| 8308 | 8287 | |
| @@ -16808,11 +16787,11 @@ | ||
| 16808 | 16787 | case SQLITE_FCNTL_POWERSAFE_OVERWRITE: zOp = "POWERSAFE_OVERWRITE"; break; |
| 16809 | 16788 | case SQLITE_FCNTL_PRAGMA: { |
| 16810 | 16789 | const char *const* a = (const char*const*)pArg; |
| 16811 | 16790 | if( a[1] && strcmp(a[1],"vfstrace")==0 && a[2] ){ |
| 16812 | 16791 | const u8 *zArg = (const u8*)a[2]; |
| 16813 | - if( zArg[0]>='0' && zArg[0]<=9 ){ | |
| 16792 | + if( zArg[0]>='0' && zArg[0]<='9' ){ | |
| 16814 | 16793 | pInfo->mTrace = (sqlite3_uint64)strtoll(a[2], 0, 0); |
| 16815 | 16794 | }else{ |
| 16816 | 16795 | static const struct { |
| 16817 | 16796 | const char *z; |
| 16818 | 16797 | unsigned int m; |
| @@ -18709,10 +18688,13 @@ | ||
| 18709 | 18688 | rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1); |
| 18710 | 18689 | } |
| 18711 | 18690 | return rc; |
| 18712 | 18691 | } |
| 18713 | 18692 | |
| 18693 | +#ifdef _WIN32 | |
| 18694 | + | |
| 18695 | +#endif | |
| 18714 | 18696 | int sqlite3_dbdata_init( |
| 18715 | 18697 | sqlite3 *db, |
| 18716 | 18698 | char **pzErrMsg, |
| 18717 | 18699 | const sqlite3_api_routines *pApi |
| 18718 | 18700 | ){ |
| @@ -25592,107 +25574,108 @@ | ||
| 25592 | 25574 | " --plain Show results as text/plain, not as HTML", |
| 25593 | 25575 | #endif |
| 25594 | 25576 | }; |
| 25595 | 25577 | |
| 25596 | 25578 | /* |
| 25597 | -** Output help text. | |
| 25579 | +** Output help text for commands that match zPattern. | |
| 25580 | +** | |
| 25581 | +** * If zPattern is NULL, then show all documented commands, but | |
| 25582 | +** only give a one-line summary of each. | |
| 25583 | +** | |
| 25584 | +** * If zPattern is "-a" or "-all" or "--all" then show all help text | |
| 25585 | +** for all commands except undocumented commands. | |
| 25586 | +** | |
| 25587 | +** * If zPattern is "0" then show all help for undocumented commands. | |
| 25588 | +** Undocumented commands begin with "," instead of "." in the azHelp[] | |
| 25589 | +** array. | |
| 25590 | +** | |
| 25591 | +** * If zPattern is a prefix for one or more documented commands, then | |
| 25592 | +** show help for those commands. If only a single command matches the | |
| 25593 | +** prefix, show the full text of the help. If multiple commands match, | |
| 25594 | +** Only show just the first line of each. | |
| 25598 | 25595 | ** |
| 25599 | -** zPattern describes the set of commands for which help text is provided. | |
| 25600 | -** If zPattern is NULL, then show all commands, but only give a one-line | |
| 25601 | -** description of each. | |
| 25596 | +** * Otherwise, show the complete text of any documented command for which | |
| 25597 | +** zPattern is a LIKE match for any text within that command help | |
| 25598 | +** text. | |
| 25602 | 25599 | ** |
| 25603 | -** Return the number of matches. | |
| 25600 | +** Return the number commands that match zPattern. | |
| 25604 | 25601 | */ |
| 25605 | 25602 | static int showHelp(FILE *out, const char *zPattern){ |
| 25606 | 25603 | int i = 0; |
| 25607 | 25604 | int j = 0; |
| 25608 | 25605 | int n = 0; |
| 25609 | 25606 | char *zPat; |
| 25610 | - if( zPattern==0 | |
| 25611 | - || zPattern[0]=='0' | |
| 25612 | - || cli_strcmp(zPattern,"-a")==0 | |
| 25613 | - || cli_strcmp(zPattern,"-all")==0 | |
| 25614 | - || cli_strcmp(zPattern,"--all")==0 | |
| 25615 | - ){ | |
| 25616 | - enum HelpWanted { HW_NoCull = 0, HW_SummaryOnly = 1, HW_Undoc = 2 }; | |
| 25617 | - enum HelpHave { HH_Undoc = 2, HH_Summary = 1, HH_More = 0 }; | |
| 25618 | - /* Show all or most commands | |
| 25619 | - ** *zPattern==0 => summary of documented commands only | |
| 25620 | - ** *zPattern=='0' => whole help for undocumented commands | |
| 25621 | - ** Otherwise => whole help for documented commands | |
| 25622 | - */ | |
| 25623 | - enum HelpWanted hw = HW_SummaryOnly; | |
| 25624 | - enum HelpHave hh = HH_More; | |
| 25625 | - if( zPattern!=0 ){ | |
| 25626 | - hw = (*zPattern=='0')? HW_NoCull|HW_Undoc : HW_NoCull; | |
| 25627 | - } | |
| 25628 | - for(i=0; i<ArraySize(azHelp); i++){ | |
| 25629 | - switch( azHelp[i][0] ){ | |
| 25630 | - case ',': | |
| 25631 | - hh = HH_Summary|HH_Undoc; | |
| 25632 | - break; | |
| 25633 | - case '.': | |
| 25634 | - hh = HH_Summary; | |
| 25635 | - break; | |
| 25636 | - default: | |
| 25637 | - hh &= ~HH_Summary; | |
| 25638 | - break; | |
| 25639 | - } | |
| 25640 | - if( ((hw^hh)&HH_Undoc)==0 ){ | |
| 25641 | - if( (hh&HH_Summary)!=0 ){ | |
| 25642 | - sqlite3_fprintf(out, ".%s\n", azHelp[i]+1); | |
| 25643 | - ++n; | |
| 25644 | - }else if( (hw&HW_SummaryOnly)==0 ){ | |
| 25645 | - sqlite3_fprintf(out, "%s\n", azHelp[i]); | |
| 25646 | - } | |
| 25647 | - } | |
| 25648 | - } | |
| 25649 | - }else{ | |
| 25650 | - /* Seek documented commands for which zPattern is an exact prefix */ | |
| 25651 | - zPat = sqlite3_mprintf(".%s*", zPattern); | |
| 25652 | - shell_check_oom(zPat); | |
| 25653 | - for(i=0; i<ArraySize(azHelp); i++){ | |
| 25654 | - if( sqlite3_strglob(zPat, azHelp[i])==0 ){ | |
| 25655 | - sqlite3_fprintf(out, "%s\n", azHelp[i]); | |
| 25656 | - j = i+1; | |
| 25657 | - n++; | |
| 25658 | - } | |
| 25659 | - } | |
| 25660 | - sqlite3_free(zPat); | |
| 25661 | - if( n ){ | |
| 25662 | - if( n==1 ){ | |
| 25663 | - /* when zPattern is a prefix of exactly one command, then include | |
| 25664 | - ** the details of that command, which should begin at offset j */ | |
| 25665 | - while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){ | |
| 25666 | - sqlite3_fprintf(out, "%s\n", azHelp[j]); | |
| 25667 | - j++; | |
| 25668 | - } | |
| 25669 | - } | |
| 25670 | - return n; | |
| 25671 | - } | |
| 25672 | - /* Look for documented commands that contain zPattern anywhere. | |
| 25673 | - ** Show complete text of all documented commands that match. */ | |
| 25674 | - zPat = sqlite3_mprintf("%%%s%%", zPattern); | |
| 25675 | - shell_check_oom(zPat); | |
| 25676 | - for(i=0; i<ArraySize(azHelp); i++){ | |
| 25677 | - if( azHelp[i][0]==',' ){ | |
| 25678 | - while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i; | |
| 25679 | - continue; | |
| 25680 | - } | |
| 25681 | - if( azHelp[i][0]=='.' ) j = i; | |
| 25682 | - if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){ | |
| 25683 | - sqlite3_fprintf(out, "%s\n", azHelp[j]); | |
| 25684 | - while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){ | |
| 25685 | - j++; | |
| 25686 | - sqlite3_fprintf(out, "%s\n", azHelp[j]); | |
| 25687 | - } | |
| 25688 | - i = j; | |
| 25689 | - n++; | |
| 25690 | - } | |
| 25691 | - } | |
| 25692 | - sqlite3_free(zPat); | |
| 25693 | - } | |
| 25607 | + if( zPattern==0 ){ | |
| 25608 | + /* Show just the first line for all help topics */ | |
| 25609 | + zPattern = "[a-z]"; | |
| 25610 | + }else if( cli_strcmp(zPattern,"-a")==0 | |
| 25611 | + || cli_strcmp(zPattern,"-all")==0 | |
| 25612 | + || cli_strcmp(zPattern,"--all")==0 | |
| 25613 | + ){ | |
| 25614 | + /* Show everything except undocumented commands */ | |
| 25615 | + zPattern = "."; | |
| 25616 | + }else if( cli_strcmp(zPattern,"0")==0 ){ | |
| 25617 | + /* Show complete help text of undocumented commands */ | |
| 25618 | + int show = 0; | |
| 25619 | + for(i=0; i<ArraySize(azHelp); i++){ | |
| 25620 | + if( azHelp[i][0]=='.' ){ | |
| 25621 | + show = 0; | |
| 25622 | + }else if( azHelp[i][0]==',' ){ | |
| 25623 | + show = 1; | |
| 25624 | + sqlite3_fprintf(out, ".%s\n", &azHelp[i][1]); | |
| 25625 | + n++; | |
| 25626 | + }else if( show ){ | |
| 25627 | + sqlite3_fprintf(out, "%s\n", azHelp[i]); | |
| 25628 | + } | |
| 25629 | + } | |
| 25630 | + return n; | |
| 25631 | + } | |
| 25632 | + | |
| 25633 | + /* Seek documented commands for which zPattern is an exact prefix */ | |
| 25634 | + zPat = sqlite3_mprintf(".%s*", zPattern); | |
| 25635 | + shell_check_oom(zPat); | |
| 25636 | + for(i=0; i<ArraySize(azHelp); i++){ | |
| 25637 | + if( sqlite3_strglob(zPat, azHelp[i])==0 ){ | |
| 25638 | + sqlite3_fprintf(out, "%s\n", azHelp[i]); | |
| 25639 | + j = i+1; | |
| 25640 | + n++; | |
| 25641 | + } | |
| 25642 | + } | |
| 25643 | + sqlite3_free(zPat); | |
| 25644 | + if( n ){ | |
| 25645 | + if( n==1 ){ | |
| 25646 | + /* when zPattern is a prefix of exactly one command, then include | |
| 25647 | + ** the details of that command, which should begin at offset j */ | |
| 25648 | + while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){ | |
| 25649 | + sqlite3_fprintf(out, "%s\n", azHelp[j]); | |
| 25650 | + j++; | |
| 25651 | + } | |
| 25652 | + } | |
| 25653 | + return n; | |
| 25654 | + } | |
| 25655 | + | |
| 25656 | + /* Look for documented commands that contain zPattern anywhere. | |
| 25657 | + ** Show complete text of all documented commands that match. */ | |
| 25658 | + zPat = sqlite3_mprintf("%%%s%%", zPattern); | |
| 25659 | + shell_check_oom(zPat); | |
| 25660 | + for(i=0; i<ArraySize(azHelp); i++){ | |
| 25661 | + if( azHelp[i][0]==',' ){ | |
| 25662 | + while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i; | |
| 25663 | + continue; | |
| 25664 | + } | |
| 25665 | + if( azHelp[i][0]=='.' ) j = i; | |
| 25666 | + if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){ | |
| 25667 | + sqlite3_fprintf(out, "%s\n", azHelp[j]); | |
| 25668 | + while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){ | |
| 25669 | + j++; | |
| 25670 | + sqlite3_fprintf(out, "%s\n", azHelp[j]); | |
| 25671 | + } | |
| 25672 | + i = j; | |
| 25673 | + n++; | |
| 25674 | + } | |
| 25675 | + } | |
| 25676 | + sqlite3_free(zPat); | |
| 25694 | 25677 | return n; |
| 25695 | 25678 | } |
| 25696 | 25679 | |
| 25697 | 25680 | /* Forward reference */ |
| 25698 | 25681 | static int process_input(ShellState *p); |
| @@ -25937,10 +25920,43 @@ | ||
| 25937 | 25920 | int sleep = sqlite3_value_int(argv[0]); |
| 25938 | 25921 | (void)argcUnused; |
| 25939 | 25922 | sqlite3_sleep(sleep/1000); |
| 25940 | 25923 | sqlite3_result_int(context, sleep); |
| 25941 | 25924 | } |
| 25925 | + | |
| 25926 | +/* | |
| 25927 | +** SQL function: shell_module_schema(X) | |
| 25928 | +** | |
| 25929 | +** Return a fake schema for the table-valued function or eponymous virtual | |
| 25930 | +** table X. | |
| 25931 | +*/ | |
| 25932 | +static void shellModuleSchema( | |
| 25933 | + sqlite3_context *pCtx, | |
| 25934 | + int nVal, | |
| 25935 | + sqlite3_value **apVal | |
| 25936 | +){ | |
| 25937 | + const char *zName; | |
| 25938 | + char *zFake; | |
| 25939 | + ShellState *p = (ShellState*)sqlite3_user_data(pCtx); | |
| 25940 | + FILE *pSavedLog = p->pLog; | |
| 25941 | + UNUSED_PARAMETER(nVal); | |
| 25942 | + zName = (const char*)sqlite3_value_text(apVal[0]); | |
| 25943 | + | |
| 25944 | + /* Temporarily disable the ".log" when calling shellFakeSchema() because | |
| 25945 | + ** shellFakeSchema() might generate failures for some ephemeral virtual | |
| 25946 | + ** tables due to missing arguments. Example: fts4aux. | |
| 25947 | + ** https://sqlite.org/forum/forumpost/42fe6520b803be51 */ | |
| 25948 | + p->pLog = 0; | |
| 25949 | + zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0; | |
| 25950 | + p->pLog = pSavedLog; | |
| 25951 | + | |
| 25952 | + if( zFake ){ | |
| 25953 | + sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), | |
| 25954 | + -1, sqlite3_free); | |
| 25955 | + free(zFake); | |
| 25956 | + } | |
| 25957 | +} | |
| 25942 | 25958 | |
| 25943 | 25959 | /* Flags for open_db(). |
| 25944 | 25960 | ** |
| 25945 | 25961 | ** The default behavior of open_db() is to exit(1) if the database fails to |
| 25946 | 25962 | ** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error |
| @@ -26081,11 +26097,11 @@ | ||
| 26081 | 26097 | shellDtostr, 0, 0); |
| 26082 | 26098 | sqlite3_create_function(p->db, "dtostr", 2, SQLITE_UTF8, 0, |
| 26083 | 26099 | shellDtostr, 0, 0); |
| 26084 | 26100 | sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, |
| 26085 | 26101 | shellAddSchemaName, 0, 0); |
| 26086 | - sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, | |
| 26102 | + sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, p, | |
| 26087 | 26103 | shellModuleSchema, 0, 0); |
| 26088 | 26104 | sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, |
| 26089 | 26105 | shellPutsFunc, 0, 0); |
| 26090 | 26106 | sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0, |
| 26091 | 26107 | shellUSleepFunc, 0, 0); |
| 26092 | 26108 |
| --- extsrc/shell.c | |
| +++ extsrc/shell.c | |
| @@ -1622,34 +1622,10 @@ | |
| 1622 | if( n>350 ) n = 350; |
| 1623 | sqlite3_snprintf(sizeof(z), z, "%#+.*e", n, r); |
| 1624 | sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); |
| 1625 | } |
| 1626 | |
| 1627 | |
| 1628 | /* |
| 1629 | ** SQL function: shell_module_schema(X) |
| 1630 | ** |
| 1631 | ** Return a fake schema for the table-valued function or eponymous virtual |
| 1632 | ** table X. |
| 1633 | */ |
| 1634 | static void shellModuleSchema( |
| 1635 | sqlite3_context *pCtx, |
| 1636 | int nVal, |
| 1637 | sqlite3_value **apVal |
| 1638 | ){ |
| 1639 | const char *zName; |
| 1640 | char *zFake; |
| 1641 | UNUSED_PARAMETER(nVal); |
| 1642 | zName = (const char*)sqlite3_value_text(apVal[0]); |
| 1643 | zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0; |
| 1644 | if( zFake ){ |
| 1645 | sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), |
| 1646 | -1, sqlite3_free); |
| 1647 | free(zFake); |
| 1648 | } |
| 1649 | } |
| 1650 | |
| 1651 | /* |
| 1652 | ** SQL function: shell_add_schema(S,X) |
| 1653 | ** |
| 1654 | ** Add the schema name X to the CREATE statement in S and return the result. |
| 1655 | ** Examples: |
| @@ -1820,10 +1796,11 @@ | |
| 1820 | # ifdef FILENAME_MAX |
| 1821 | # define NAME_MAX (FILENAME_MAX) |
| 1822 | # else |
| 1823 | # define NAME_MAX (260) |
| 1824 | # endif |
| 1825 | #endif |
| 1826 | |
| 1827 | /* |
| 1828 | ** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T". |
| 1829 | */ |
| @@ -1863,12 +1840,11 @@ | |
| 1863 | #endif |
| 1864 | |
| 1865 | /* |
| 1866 | ** Provide a macro, for use by the implementation, to determine if a |
| 1867 | ** particular directory entry should be skipped over when searching for |
| 1868 | ** the next directory entry that should be returned by the readdir() or |
| 1869 | ** readdir_r() functions. |
| 1870 | */ |
| 1871 | |
| 1872 | #ifndef is_filtered |
| 1873 | # define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) |
| 1874 | #endif |
| @@ -1880,16 +1856,15 @@ | |
| 1880 | |
| 1881 | extern const char *windirent_getenv(const char *name); |
| 1882 | |
| 1883 | /* |
| 1884 | ** Finally, we can provide the function prototypes for the opendir(), |
| 1885 | ** readdir(), readdir_r(), and closedir() POSIX functions. |
| 1886 | */ |
| 1887 | |
| 1888 | extern LPDIR opendir(const char *dirname); |
| 1889 | extern LPDIRENT readdir(LPDIR dirp); |
| 1890 | extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result); |
| 1891 | extern INT closedir(LPDIR dirp); |
| 1892 | |
| 1893 | #endif /* defined(WIN32) && defined(_MSC_VER) */ |
| 1894 | |
| 1895 | /************************* End test_windirent.h ********************/ |
| @@ -1942,27 +1917,45 @@ | |
| 1942 | |
| 1943 | /* |
| 1944 | ** Implementation of the POSIX opendir() function using the MSVCRT. |
| 1945 | */ |
| 1946 | LPDIR opendir( |
| 1947 | const char *dirname |
| 1948 | ){ |
| 1949 | struct _finddata_t data; |
| 1950 | LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); |
| 1951 | SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); |
| 1952 | |
| 1953 | if( dirp==NULL ) return NULL; |
| 1954 | memset(dirp, 0, sizeof(DIR)); |
| 1955 | |
| 1956 | /* TODO: Remove this if Unix-style root paths are not used. */ |
| 1957 | if( sqlite3_stricmp(dirname, "/")==0 ){ |
| 1958 | dirname = windirent_getenv("SystemDrive"); |
| 1959 | } |
| 1960 | |
| 1961 | memset(&data, 0, sizeof(struct _finddata_t)); |
| 1962 | _snprintf(data.name, namesize, "%s\\*", dirname); |
| 1963 | dirp->d_handle = _findfirst(data.name, &data); |
| 1964 | |
| 1965 | if( dirp->d_handle==BAD_INTPTR_T ){ |
| 1966 | closedir(dirp); |
| 1967 | return NULL; |
| 1968 | } |
| @@ -1969,34 +1962,33 @@ | |
| 1969 | |
| 1970 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 1971 | if( is_filtered(data) ){ |
| 1972 | next: |
| 1973 | |
| 1974 | memset(&data, 0, sizeof(struct _finddata_t)); |
| 1975 | if( _findnext(dirp->d_handle, &data)==-1 ){ |
| 1976 | closedir(dirp); |
| 1977 | return NULL; |
| 1978 | } |
| 1979 | |
| 1980 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 1981 | if( is_filtered(data) ) goto next; |
| 1982 | } |
| 1983 | |
| 1984 | dirp->d_first.d_attributes = data.attrib; |
| 1985 | strncpy(dirp->d_first.d_name, data.name, NAME_MAX); |
| 1986 | dirp->d_first.d_name[NAME_MAX] = '\0'; |
| 1987 | |
| 1988 | return dirp; |
| 1989 | } |
| 1990 | |
| 1991 | /* |
| 1992 | ** Implementation of the POSIX readdir() function using the MSVCRT. |
| 1993 | */ |
| 1994 | LPDIRENT readdir( |
| 1995 | LPDIR dirp |
| 1996 | ){ |
| 1997 | struct _finddata_t data; |
| 1998 | |
| 1999 | if( dirp==NULL ) return NULL; |
| 2000 | |
| 2001 | if( dirp->d_first.d_ino==0 ){ |
| 2002 | dirp->d_first.d_ino++; |
| @@ -2005,69 +1997,23 @@ | |
| 2005 | return &dirp->d_first; |
| 2006 | } |
| 2007 | |
| 2008 | next: |
| 2009 | |
| 2010 | memset(&data, 0, sizeof(struct _finddata_t)); |
| 2011 | if( _findnext(dirp->d_handle, &data)==-1 ) return NULL; |
| 2012 | |
| 2013 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 2014 | if( is_filtered(data) ) goto next; |
| 2015 | |
| 2016 | dirp->d_next.d_ino++; |
| 2017 | dirp->d_next.d_attributes = data.attrib; |
| 2018 | strncpy(dirp->d_next.d_name, data.name, NAME_MAX); |
| 2019 | dirp->d_next.d_name[NAME_MAX] = '\0'; |
| 2020 | |
| 2021 | return &dirp->d_next; |
| 2022 | } |
| 2023 | |
| 2024 | /* |
| 2025 | ** Implementation of the POSIX readdir_r() function using the MSVCRT. |
| 2026 | */ |
| 2027 | INT readdir_r( |
| 2028 | LPDIR dirp, |
| 2029 | LPDIRENT entry, |
| 2030 | LPDIRENT *result |
| 2031 | ){ |
| 2032 | struct _finddata_t data; |
| 2033 | |
| 2034 | if( dirp==NULL ) return EBADF; |
| 2035 | |
| 2036 | if( dirp->d_first.d_ino==0 ){ |
| 2037 | dirp->d_first.d_ino++; |
| 2038 | dirp->d_next.d_ino++; |
| 2039 | |
| 2040 | entry->d_ino = dirp->d_first.d_ino; |
| 2041 | entry->d_attributes = dirp->d_first.d_attributes; |
| 2042 | strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX); |
| 2043 | entry->d_name[NAME_MAX] = '\0'; |
| 2044 | |
| 2045 | *result = entry; |
| 2046 | return 0; |
| 2047 | } |
| 2048 | |
| 2049 | next: |
| 2050 | |
| 2051 | memset(&data, 0, sizeof(struct _finddata_t)); |
| 2052 | if( _findnext(dirp->d_handle, &data)==-1 ){ |
| 2053 | *result = NULL; |
| 2054 | return ENOENT; |
| 2055 | } |
| 2056 | |
| 2057 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 2058 | if( is_filtered(data) ) goto next; |
| 2059 | |
| 2060 | entry->d_ino = (ino_t)-1; /* not available */ |
| 2061 | entry->d_attributes = data.attrib; |
| 2062 | strncpy(entry->d_name, data.name, NAME_MAX); |
| 2063 | entry->d_name[NAME_MAX] = '\0'; |
| 2064 | |
| 2065 | *result = entry; |
| 2066 | return 0; |
| 2067 | } |
| 2068 | |
| 2069 | /* |
| 2070 | ** Implementation of the POSIX closedir() function using the MSVCRT. |
| 2071 | */ |
| 2072 | INT closedir( |
| 2073 | LPDIR dirp |
| @@ -8085,18 +8031,13 @@ | |
| 8085 | # include "windows.h" |
| 8086 | # include <io.h> |
| 8087 | # include <direct.h> |
| 8088 | /* # include "test_windirent.h" */ |
| 8089 | # define dirent DIRENT |
| 8090 | # ifndef chmod |
| 8091 | # define chmod _chmod |
| 8092 | # endif |
| 8093 | # ifndef stat |
| 8094 | # define stat _stat |
| 8095 | # endif |
| 8096 | # define mkdir(path,mode) _mkdir(path) |
| 8097 | # define lstat(path,buf) stat(path,buf) |
| 8098 | #endif |
| 8099 | #include <time.h> |
| 8100 | #include <errno.h> |
| 8101 | |
| 8102 | /* When used as part of the CLI, the sqlite3_stdio.h module will have |
| @@ -8117,10 +8058,44 @@ | |
| 8117 | #define FSDIR_COLUMN_MTIME 2 /* Last modification time */ |
| 8118 | #define FSDIR_COLUMN_DATA 3 /* File content */ |
| 8119 | #define FSDIR_COLUMN_PATH 4 /* Path to top of search */ |
| 8120 | #define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */ |
| 8121 | |
| 8122 | |
| 8123 | /* |
| 8124 | ** Set the result stored by context ctx to a blob containing the |
| 8125 | ** contents of file zName. Or, leave the result unchanged (NULL) |
| 8126 | ** if the file does not exist or is unreadable. |
| @@ -8278,11 +8253,17 @@ | |
| 8278 | static int fileStat( |
| 8279 | const char *zPath, |
| 8280 | struct stat *pStatBuf |
| 8281 | ){ |
| 8282 | #if defined(_WIN32) |
| 8283 | int rc = stat(zPath, pStatBuf); |
| 8284 | if( rc==0 ) statTimesToUtc(zPath, pStatBuf); |
| 8285 | return rc; |
| 8286 | #else |
| 8287 | return stat(zPath, pStatBuf); |
| 8288 | #endif |
| @@ -8296,13 +8277,11 @@ | |
| 8296 | static int fileLinkStat( |
| 8297 | const char *zPath, |
| 8298 | struct stat *pStatBuf |
| 8299 | ){ |
| 8300 | #if defined(_WIN32) |
| 8301 | int rc = lstat(zPath, pStatBuf); |
| 8302 | if( rc==0 ) statTimesToUtc(zPath, pStatBuf); |
| 8303 | return rc; |
| 8304 | #else |
| 8305 | return lstat(zPath, pStatBuf); |
| 8306 | #endif |
| 8307 | } |
| 8308 | |
| @@ -16808,11 +16787,11 @@ | |
| 16808 | case SQLITE_FCNTL_POWERSAFE_OVERWRITE: zOp = "POWERSAFE_OVERWRITE"; break; |
| 16809 | case SQLITE_FCNTL_PRAGMA: { |
| 16810 | const char *const* a = (const char*const*)pArg; |
| 16811 | if( a[1] && strcmp(a[1],"vfstrace")==0 && a[2] ){ |
| 16812 | const u8 *zArg = (const u8*)a[2]; |
| 16813 | if( zArg[0]>='0' && zArg[0]<=9 ){ |
| 16814 | pInfo->mTrace = (sqlite3_uint64)strtoll(a[2], 0, 0); |
| 16815 | }else{ |
| 16816 | static const struct { |
| 16817 | const char *z; |
| 16818 | unsigned int m; |
| @@ -18709,10 +18688,13 @@ | |
| 18709 | rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1); |
| 18710 | } |
| 18711 | return rc; |
| 18712 | } |
| 18713 | |
| 18714 | int sqlite3_dbdata_init( |
| 18715 | sqlite3 *db, |
| 18716 | char **pzErrMsg, |
| 18717 | const sqlite3_api_routines *pApi |
| 18718 | ){ |
| @@ -25592,107 +25574,108 @@ | |
| 25592 | " --plain Show results as text/plain, not as HTML", |
| 25593 | #endif |
| 25594 | }; |
| 25595 | |
| 25596 | /* |
| 25597 | ** Output help text. |
| 25598 | ** |
| 25599 | ** zPattern describes the set of commands for which help text is provided. |
| 25600 | ** If zPattern is NULL, then show all commands, but only give a one-line |
| 25601 | ** description of each. |
| 25602 | ** |
| 25603 | ** Return the number of matches. |
| 25604 | */ |
| 25605 | static int showHelp(FILE *out, const char *zPattern){ |
| 25606 | int i = 0; |
| 25607 | int j = 0; |
| 25608 | int n = 0; |
| 25609 | char *zPat; |
| 25610 | if( zPattern==0 |
| 25611 | || zPattern[0]=='0' |
| 25612 | || cli_strcmp(zPattern,"-a")==0 |
| 25613 | || cli_strcmp(zPattern,"-all")==0 |
| 25614 | || cli_strcmp(zPattern,"--all")==0 |
| 25615 | ){ |
| 25616 | enum HelpWanted { HW_NoCull = 0, HW_SummaryOnly = 1, HW_Undoc = 2 }; |
| 25617 | enum HelpHave { HH_Undoc = 2, HH_Summary = 1, HH_More = 0 }; |
| 25618 | /* Show all or most commands |
| 25619 | ** *zPattern==0 => summary of documented commands only |
| 25620 | ** *zPattern=='0' => whole help for undocumented commands |
| 25621 | ** Otherwise => whole help for documented commands |
| 25622 | */ |
| 25623 | enum HelpWanted hw = HW_SummaryOnly; |
| 25624 | enum HelpHave hh = HH_More; |
| 25625 | if( zPattern!=0 ){ |
| 25626 | hw = (*zPattern=='0')? HW_NoCull|HW_Undoc : HW_NoCull; |
| 25627 | } |
| 25628 | for(i=0; i<ArraySize(azHelp); i++){ |
| 25629 | switch( azHelp[i][0] ){ |
| 25630 | case ',': |
| 25631 | hh = HH_Summary|HH_Undoc; |
| 25632 | break; |
| 25633 | case '.': |
| 25634 | hh = HH_Summary; |
| 25635 | break; |
| 25636 | default: |
| 25637 | hh &= ~HH_Summary; |
| 25638 | break; |
| 25639 | } |
| 25640 | if( ((hw^hh)&HH_Undoc)==0 ){ |
| 25641 | if( (hh&HH_Summary)!=0 ){ |
| 25642 | sqlite3_fprintf(out, ".%s\n", azHelp[i]+1); |
| 25643 | ++n; |
| 25644 | }else if( (hw&HW_SummaryOnly)==0 ){ |
| 25645 | sqlite3_fprintf(out, "%s\n", azHelp[i]); |
| 25646 | } |
| 25647 | } |
| 25648 | } |
| 25649 | }else{ |
| 25650 | /* Seek documented commands for which zPattern is an exact prefix */ |
| 25651 | zPat = sqlite3_mprintf(".%s*", zPattern); |
| 25652 | shell_check_oom(zPat); |
| 25653 | for(i=0; i<ArraySize(azHelp); i++){ |
| 25654 | if( sqlite3_strglob(zPat, azHelp[i])==0 ){ |
| 25655 | sqlite3_fprintf(out, "%s\n", azHelp[i]); |
| 25656 | j = i+1; |
| 25657 | n++; |
| 25658 | } |
| 25659 | } |
| 25660 | sqlite3_free(zPat); |
| 25661 | if( n ){ |
| 25662 | if( n==1 ){ |
| 25663 | /* when zPattern is a prefix of exactly one command, then include |
| 25664 | ** the details of that command, which should begin at offset j */ |
| 25665 | while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){ |
| 25666 | sqlite3_fprintf(out, "%s\n", azHelp[j]); |
| 25667 | j++; |
| 25668 | } |
| 25669 | } |
| 25670 | return n; |
| 25671 | } |
| 25672 | /* Look for documented commands that contain zPattern anywhere. |
| 25673 | ** Show complete text of all documented commands that match. */ |
| 25674 | zPat = sqlite3_mprintf("%%%s%%", zPattern); |
| 25675 | shell_check_oom(zPat); |
| 25676 | for(i=0; i<ArraySize(azHelp); i++){ |
| 25677 | if( azHelp[i][0]==',' ){ |
| 25678 | while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i; |
| 25679 | continue; |
| 25680 | } |
| 25681 | if( azHelp[i][0]=='.' ) j = i; |
| 25682 | if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){ |
| 25683 | sqlite3_fprintf(out, "%s\n", azHelp[j]); |
| 25684 | while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){ |
| 25685 | j++; |
| 25686 | sqlite3_fprintf(out, "%s\n", azHelp[j]); |
| 25687 | } |
| 25688 | i = j; |
| 25689 | n++; |
| 25690 | } |
| 25691 | } |
| 25692 | sqlite3_free(zPat); |
| 25693 | } |
| 25694 | return n; |
| 25695 | } |
| 25696 | |
| 25697 | /* Forward reference */ |
| 25698 | static int process_input(ShellState *p); |
| @@ -25937,10 +25920,43 @@ | |
| 25937 | int sleep = sqlite3_value_int(argv[0]); |
| 25938 | (void)argcUnused; |
| 25939 | sqlite3_sleep(sleep/1000); |
| 25940 | sqlite3_result_int(context, sleep); |
| 25941 | } |
| 25942 | |
| 25943 | /* Flags for open_db(). |
| 25944 | ** |
| 25945 | ** The default behavior of open_db() is to exit(1) if the database fails to |
| 25946 | ** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error |
| @@ -26081,11 +26097,11 @@ | |
| 26081 | shellDtostr, 0, 0); |
| 26082 | sqlite3_create_function(p->db, "dtostr", 2, SQLITE_UTF8, 0, |
| 26083 | shellDtostr, 0, 0); |
| 26084 | sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, |
| 26085 | shellAddSchemaName, 0, 0); |
| 26086 | sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, |
| 26087 | shellModuleSchema, 0, 0); |
| 26088 | sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, |
| 26089 | shellPutsFunc, 0, 0); |
| 26090 | sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0, |
| 26091 | shellUSleepFunc, 0, 0); |
| 26092 |
| --- extsrc/shell.c | |
| +++ extsrc/shell.c | |
| @@ -1622,34 +1622,10 @@ | |
| 1622 | if( n>350 ) n = 350; |
| 1623 | sqlite3_snprintf(sizeof(z), z, "%#+.*e", n, r); |
| 1624 | sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); |
| 1625 | } |
| 1626 | |
| 1627 | /* |
| 1628 | ** SQL function: shell_add_schema(S,X) |
| 1629 | ** |
| 1630 | ** Add the schema name X to the CREATE statement in S and return the result. |
| 1631 | ** Examples: |
| @@ -1820,10 +1796,11 @@ | |
| 1796 | # ifdef FILENAME_MAX |
| 1797 | # define NAME_MAX (FILENAME_MAX) |
| 1798 | # else |
| 1799 | # define NAME_MAX (260) |
| 1800 | # endif |
| 1801 | # define DIRENT_NAME_MAX (NAME_MAX) |
| 1802 | #endif |
| 1803 | |
| 1804 | /* |
| 1805 | ** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T". |
| 1806 | */ |
| @@ -1863,12 +1840,11 @@ | |
| 1840 | #endif |
| 1841 | |
| 1842 | /* |
| 1843 | ** Provide a macro, for use by the implementation, to determine if a |
| 1844 | ** particular directory entry should be skipped over when searching for |
| 1845 | ** the next directory entry that should be returned by the readdir(). |
| 1846 | */ |
| 1847 | |
| 1848 | #ifndef is_filtered |
| 1849 | # define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM)) |
| 1850 | #endif |
| @@ -1880,16 +1856,15 @@ | |
| 1856 | |
| 1857 | extern const char *windirent_getenv(const char *name); |
| 1858 | |
| 1859 | /* |
| 1860 | ** Finally, we can provide the function prototypes for the opendir(), |
| 1861 | ** readdir(), and closedir() POSIX functions. |
| 1862 | */ |
| 1863 | |
| 1864 | extern LPDIR opendir(const char *dirname); |
| 1865 | extern LPDIRENT readdir(LPDIR dirp); |
| 1866 | extern INT closedir(LPDIR dirp); |
| 1867 | |
| 1868 | #endif /* defined(WIN32) && defined(_MSC_VER) */ |
| 1869 | |
| 1870 | /************************* End test_windirent.h ********************/ |
| @@ -1942,27 +1917,45 @@ | |
| 1917 | |
| 1918 | /* |
| 1919 | ** Implementation of the POSIX opendir() function using the MSVCRT. |
| 1920 | */ |
| 1921 | LPDIR opendir( |
| 1922 | const char *dirname /* Directory name, UTF8 encoding */ |
| 1923 | ){ |
| 1924 | struct _wfinddata_t data; |
| 1925 | LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR)); |
| 1926 | SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]); |
| 1927 | wchar_t *b1; |
| 1928 | sqlite3_int64 sz; |
| 1929 | |
| 1930 | if( dirp==NULL ) return NULL; |
| 1931 | memset(dirp, 0, sizeof(DIR)); |
| 1932 | |
| 1933 | /* TODO: Remove this if Unix-style root paths are not used. */ |
| 1934 | if( sqlite3_stricmp(dirname, "/")==0 ){ |
| 1935 | dirname = windirent_getenv("SystemDrive"); |
| 1936 | } |
| 1937 | |
| 1938 | memset(&data, 0, sizeof(data)); |
| 1939 | sz = strlen(dirname); |
| 1940 | b1 = sqlite3_malloc64( (sz+3)*sizeof(b1[0]) ); |
| 1941 | if( b1==0 ){ |
| 1942 | closedir(dirp); |
| 1943 | return NULL; |
| 1944 | } |
| 1945 | sz = MultiByteToWideChar(CP_UTF8, 0, dirname, sz, b1, sz); |
| 1946 | b1[sz++] = '\\'; |
| 1947 | b1[sz++] = '*'; |
| 1948 | b1[sz] = 0; |
| 1949 | if( sz+1>(sqlite3_int64)namesize ){ |
| 1950 | closedir(dirp); |
| 1951 | sqlite3_free(b1); |
| 1952 | return NULL; |
| 1953 | } |
| 1954 | memcpy(data.name, b1, (sz+1)*sizeof(b1[0])); |
| 1955 | sqlite3_free(b1); |
| 1956 | dirp->d_handle = _wfindfirst(data.name, &data); |
| 1957 | |
| 1958 | if( dirp->d_handle==BAD_INTPTR_T ){ |
| 1959 | closedir(dirp); |
| 1960 | return NULL; |
| 1961 | } |
| @@ -1969,34 +1962,33 @@ | |
| 1962 | |
| 1963 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 1964 | if( is_filtered(data) ){ |
| 1965 | next: |
| 1966 | |
| 1967 | memset(&data, 0, sizeof(data)); |
| 1968 | if( _wfindnext(dirp->d_handle, &data)==-1 ){ |
| 1969 | closedir(dirp); |
| 1970 | return NULL; |
| 1971 | } |
| 1972 | |
| 1973 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 1974 | if( is_filtered(data) ) goto next; |
| 1975 | } |
| 1976 | |
| 1977 | dirp->d_first.d_attributes = data.attrib; |
| 1978 | WideCharToMultiByte(CP_UTF8, 0, data.name, -1, |
| 1979 | dirp->d_first.d_name, DIRENT_NAME_MAX, 0, 0); |
| 1980 | return dirp; |
| 1981 | } |
| 1982 | |
| 1983 | /* |
| 1984 | ** Implementation of the POSIX readdir() function using the MSVCRT. |
| 1985 | */ |
| 1986 | LPDIRENT readdir( |
| 1987 | LPDIR dirp |
| 1988 | ){ |
| 1989 | struct _wfinddata_t data; |
| 1990 | |
| 1991 | if( dirp==NULL ) return NULL; |
| 1992 | |
| 1993 | if( dirp->d_first.d_ino==0 ){ |
| 1994 | dirp->d_first.d_ino++; |
| @@ -2005,69 +1997,23 @@ | |
| 1997 | return &dirp->d_first; |
| 1998 | } |
| 1999 | |
| 2000 | next: |
| 2001 | |
| 2002 | memset(&data, 0, sizeof(data)); |
| 2003 | if( _wfindnext(dirp->d_handle, &data)==-1 ) return NULL; |
| 2004 | |
| 2005 | /* TODO: Remove this block to allow hidden and/or system files. */ |
| 2006 | if( is_filtered(data) ) goto next; |
| 2007 | |
| 2008 | dirp->d_next.d_ino++; |
| 2009 | dirp->d_next.d_attributes = data.attrib; |
| 2010 | WideCharToMultiByte(CP_UTF8, 0, data.name, -1, |
| 2011 | dirp->d_next.d_name, DIRENT_NAME_MAX, 0, 0); |
| 2012 | return &dirp->d_next; |
| 2013 | } |
| 2014 | |
| 2015 | /* |
| 2016 | ** Implementation of the POSIX closedir() function using the MSVCRT. |
| 2017 | */ |
| 2018 | INT closedir( |
| 2019 | LPDIR dirp |
| @@ -8085,18 +8031,13 @@ | |
| 8031 | # include "windows.h" |
| 8032 | # include <io.h> |
| 8033 | # include <direct.h> |
| 8034 | /* # include "test_windirent.h" */ |
| 8035 | # define dirent DIRENT |
| 8036 | # define stat _stat |
| 8037 | # define chmod(path,mode) fileio_chmod(path,mode) |
| 8038 | # define mkdir(path,mode) fileio_mkdir(path) |
| 8039 | #endif |
| 8040 | #include <time.h> |
| 8041 | #include <errno.h> |
| 8042 | |
| 8043 | /* When used as part of the CLI, the sqlite3_stdio.h module will have |
| @@ -8117,10 +8058,44 @@ | |
| 8058 | #define FSDIR_COLUMN_MTIME 2 /* Last modification time */ |
| 8059 | #define FSDIR_COLUMN_DATA 3 /* File content */ |
| 8060 | #define FSDIR_COLUMN_PATH 4 /* Path to top of search */ |
| 8061 | #define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */ |
| 8062 | |
| 8063 | /* |
| 8064 | ** UTF8 chmod() function for Windows |
| 8065 | */ |
| 8066 | #if defined(_WIN32) || defined(WIN32) |
| 8067 | static int fileio_chmod(const char *zPath, int pmode){ |
| 8068 | sqlite3_int64 sz = strlen(zPath); |
| 8069 | wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); |
| 8070 | int rc; |
| 8071 | if( b1==0 ) return -1; |
| 8072 | sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); |
| 8073 | b1[sz] = 0; |
| 8074 | rc = _wchmod(b1, pmode); |
| 8075 | sqlite3_free(b1); |
| 8076 | return rc; |
| 8077 | } |
| 8078 | #endif |
| 8079 | |
| 8080 | /* |
| 8081 | ** UTF8 mkdir() function for Windows |
| 8082 | */ |
| 8083 | #if defined(_WIN32) || defined(WIN32) |
| 8084 | static int fileio_mkdir(const char *zPath){ |
| 8085 | sqlite3_int64 sz = strlen(zPath); |
| 8086 | wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); |
| 8087 | int rc; |
| 8088 | if( b1==0 ) return -1; |
| 8089 | sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); |
| 8090 | b1[sz] = 0; |
| 8091 | rc = _wmkdir(b1); |
| 8092 | sqlite3_free(b1); |
| 8093 | return rc; |
| 8094 | } |
| 8095 | #endif |
| 8096 | |
| 8097 | |
| 8098 | /* |
| 8099 | ** Set the result stored by context ctx to a blob containing the |
| 8100 | ** contents of file zName. Or, leave the result unchanged (NULL) |
| 8101 | ** if the file does not exist or is unreadable. |
| @@ -8278,11 +8253,17 @@ | |
| 8253 | static int fileStat( |
| 8254 | const char *zPath, |
| 8255 | struct stat *pStatBuf |
| 8256 | ){ |
| 8257 | #if defined(_WIN32) |
| 8258 | sqlite3_int64 sz = strlen(zPath); |
| 8259 | wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); |
| 8260 | int rc; |
| 8261 | if( b1==0 ) return 1; |
| 8262 | sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); |
| 8263 | b1[sz] = 0; |
| 8264 | rc = _wstat(b1, pStatBuf); |
| 8265 | if( rc==0 ) statTimesToUtc(zPath, pStatBuf); |
| 8266 | return rc; |
| 8267 | #else |
| 8268 | return stat(zPath, pStatBuf); |
| 8269 | #endif |
| @@ -8296,13 +8277,11 @@ | |
| 8277 | static int fileLinkStat( |
| 8278 | const char *zPath, |
| 8279 | struct stat *pStatBuf |
| 8280 | ){ |
| 8281 | #if defined(_WIN32) |
| 8282 | return fileStat(zPath, pStatBuf); |
| 8283 | #else |
| 8284 | return lstat(zPath, pStatBuf); |
| 8285 | #endif |
| 8286 | } |
| 8287 | |
| @@ -16808,11 +16787,11 @@ | |
| 16787 | case SQLITE_FCNTL_POWERSAFE_OVERWRITE: zOp = "POWERSAFE_OVERWRITE"; break; |
| 16788 | case SQLITE_FCNTL_PRAGMA: { |
| 16789 | const char *const* a = (const char*const*)pArg; |
| 16790 | if( a[1] && strcmp(a[1],"vfstrace")==0 && a[2] ){ |
| 16791 | const u8 *zArg = (const u8*)a[2]; |
| 16792 | if( zArg[0]>='0' && zArg[0]<='9' ){ |
| 16793 | pInfo->mTrace = (sqlite3_uint64)strtoll(a[2], 0, 0); |
| 16794 | }else{ |
| 16795 | static const struct { |
| 16796 | const char *z; |
| 16797 | unsigned int m; |
| @@ -18709,10 +18688,13 @@ | |
| 18688 | rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1); |
| 18689 | } |
| 18690 | return rc; |
| 18691 | } |
| 18692 | |
| 18693 | #ifdef _WIN32 |
| 18694 | |
| 18695 | #endif |
| 18696 | int sqlite3_dbdata_init( |
| 18697 | sqlite3 *db, |
| 18698 | char **pzErrMsg, |
| 18699 | const sqlite3_api_routines *pApi |
| 18700 | ){ |
| @@ -25592,107 +25574,108 @@ | |
| 25574 | " --plain Show results as text/plain, not as HTML", |
| 25575 | #endif |
| 25576 | }; |
| 25577 | |
| 25578 | /* |
| 25579 | ** Output help text for commands that match zPattern. |
| 25580 | ** |
| 25581 | ** * If zPattern is NULL, then show all documented commands, but |
| 25582 | ** only give a one-line summary of each. |
| 25583 | ** |
| 25584 | ** * If zPattern is "-a" or "-all" or "--all" then show all help text |
| 25585 | ** for all commands except undocumented commands. |
| 25586 | ** |
| 25587 | ** * If zPattern is "0" then show all help for undocumented commands. |
| 25588 | ** Undocumented commands begin with "," instead of "." in the azHelp[] |
| 25589 | ** array. |
| 25590 | ** |
| 25591 | ** * If zPattern is a prefix for one or more documented commands, then |
| 25592 | ** show help for those commands. If only a single command matches the |
| 25593 | ** prefix, show the full text of the help. If multiple commands match, |
| 25594 | ** Only show just the first line of each. |
| 25595 | ** |
| 25596 | ** * Otherwise, show the complete text of any documented command for which |
| 25597 | ** zPattern is a LIKE match for any text within that command help |
| 25598 | ** text. |
| 25599 | ** |
| 25600 | ** Return the number commands that match zPattern. |
| 25601 | */ |
| 25602 | static int showHelp(FILE *out, const char *zPattern){ |
| 25603 | int i = 0; |
| 25604 | int j = 0; |
| 25605 | int n = 0; |
| 25606 | char *zPat; |
| 25607 | if( zPattern==0 ){ |
| 25608 | /* Show just the first line for all help topics */ |
| 25609 | zPattern = "[a-z]"; |
| 25610 | }else if( cli_strcmp(zPattern,"-a")==0 |
| 25611 | || cli_strcmp(zPattern,"-all")==0 |
| 25612 | || cli_strcmp(zPattern,"--all")==0 |
| 25613 | ){ |
| 25614 | /* Show everything except undocumented commands */ |
| 25615 | zPattern = "."; |
| 25616 | }else if( cli_strcmp(zPattern,"0")==0 ){ |
| 25617 | /* Show complete help text of undocumented commands */ |
| 25618 | int show = 0; |
| 25619 | for(i=0; i<ArraySize(azHelp); i++){ |
| 25620 | if( azHelp[i][0]=='.' ){ |
| 25621 | show = 0; |
| 25622 | }else if( azHelp[i][0]==',' ){ |
| 25623 | show = 1; |
| 25624 | sqlite3_fprintf(out, ".%s\n", &azHelp[i][1]); |
| 25625 | n++; |
| 25626 | }else if( show ){ |
| 25627 | sqlite3_fprintf(out, "%s\n", azHelp[i]); |
| 25628 | } |
| 25629 | } |
| 25630 | return n; |
| 25631 | } |
| 25632 | |
| 25633 | /* Seek documented commands for which zPattern is an exact prefix */ |
| 25634 | zPat = sqlite3_mprintf(".%s*", zPattern); |
| 25635 | shell_check_oom(zPat); |
| 25636 | for(i=0; i<ArraySize(azHelp); i++){ |
| 25637 | if( sqlite3_strglob(zPat, azHelp[i])==0 ){ |
| 25638 | sqlite3_fprintf(out, "%s\n", azHelp[i]); |
| 25639 | j = i+1; |
| 25640 | n++; |
| 25641 | } |
| 25642 | } |
| 25643 | sqlite3_free(zPat); |
| 25644 | if( n ){ |
| 25645 | if( n==1 ){ |
| 25646 | /* when zPattern is a prefix of exactly one command, then include |
| 25647 | ** the details of that command, which should begin at offset j */ |
| 25648 | while( j<ArraySize(azHelp)-1 && azHelp[j][0]==' ' ){ |
| 25649 | sqlite3_fprintf(out, "%s\n", azHelp[j]); |
| 25650 | j++; |
| 25651 | } |
| 25652 | } |
| 25653 | return n; |
| 25654 | } |
| 25655 | |
| 25656 | /* Look for documented commands that contain zPattern anywhere. |
| 25657 | ** Show complete text of all documented commands that match. */ |
| 25658 | zPat = sqlite3_mprintf("%%%s%%", zPattern); |
| 25659 | shell_check_oom(zPat); |
| 25660 | for(i=0; i<ArraySize(azHelp); i++){ |
| 25661 | if( azHelp[i][0]==',' ){ |
| 25662 | while( i<ArraySize(azHelp)-1 && azHelp[i+1][0]==' ' ) ++i; |
| 25663 | continue; |
| 25664 | } |
| 25665 | if( azHelp[i][0]=='.' ) j = i; |
| 25666 | if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){ |
| 25667 | sqlite3_fprintf(out, "%s\n", azHelp[j]); |
| 25668 | while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]==' ' ){ |
| 25669 | j++; |
| 25670 | sqlite3_fprintf(out, "%s\n", azHelp[j]); |
| 25671 | } |
| 25672 | i = j; |
| 25673 | n++; |
| 25674 | } |
| 25675 | } |
| 25676 | sqlite3_free(zPat); |
| 25677 | return n; |
| 25678 | } |
| 25679 | |
| 25680 | /* Forward reference */ |
| 25681 | static int process_input(ShellState *p); |
| @@ -25937,10 +25920,43 @@ | |
| 25920 | int sleep = sqlite3_value_int(argv[0]); |
| 25921 | (void)argcUnused; |
| 25922 | sqlite3_sleep(sleep/1000); |
| 25923 | sqlite3_result_int(context, sleep); |
| 25924 | } |
| 25925 | |
| 25926 | /* |
| 25927 | ** SQL function: shell_module_schema(X) |
| 25928 | ** |
| 25929 | ** Return a fake schema for the table-valued function or eponymous virtual |
| 25930 | ** table X. |
| 25931 | */ |
| 25932 | static void shellModuleSchema( |
| 25933 | sqlite3_context *pCtx, |
| 25934 | int nVal, |
| 25935 | sqlite3_value **apVal |
| 25936 | ){ |
| 25937 | const char *zName; |
| 25938 | char *zFake; |
| 25939 | ShellState *p = (ShellState*)sqlite3_user_data(pCtx); |
| 25940 | FILE *pSavedLog = p->pLog; |
| 25941 | UNUSED_PARAMETER(nVal); |
| 25942 | zName = (const char*)sqlite3_value_text(apVal[0]); |
| 25943 | |
| 25944 | /* Temporarily disable the ".log" when calling shellFakeSchema() because |
| 25945 | ** shellFakeSchema() might generate failures for some ephemeral virtual |
| 25946 | ** tables due to missing arguments. Example: fts4aux. |
| 25947 | ** https://sqlite.org/forum/forumpost/42fe6520b803be51 */ |
| 25948 | p->pLog = 0; |
| 25949 | zFake = zName? shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName) : 0; |
| 25950 | p->pLog = pSavedLog; |
| 25951 | |
| 25952 | if( zFake ){ |
| 25953 | sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), |
| 25954 | -1, sqlite3_free); |
| 25955 | free(zFake); |
| 25956 | } |
| 25957 | } |
| 25958 | |
| 25959 | /* Flags for open_db(). |
| 25960 | ** |
| 25961 | ** The default behavior of open_db() is to exit(1) if the database fails to |
| 25962 | ** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error |
| @@ -26081,11 +26097,11 @@ | |
| 26097 | shellDtostr, 0, 0); |
| 26098 | sqlite3_create_function(p->db, "dtostr", 2, SQLITE_UTF8, 0, |
| 26099 | shellDtostr, 0, 0); |
| 26100 | sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, |
| 26101 | shellAddSchemaName, 0, 0); |
| 26102 | sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, p, |
| 26103 | shellModuleSchema, 0, 0); |
| 26104 | sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, |
| 26105 | shellPutsFunc, 0, 0); |
| 26106 | sqlite3_create_function(p->db, "usleep",1,SQLITE_UTF8,0, |
| 26107 | shellUSleepFunc, 0, 0); |
| 26108 |
+204
-142
| --- extsrc/sqlite3.c | ||
| +++ extsrc/sqlite3.c | ||
| @@ -16,11 +16,11 @@ | ||
| 16 | 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | 19 | ** |
| 20 | 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | -** d22475b81c4e26ccc50f3b5626d43b32f7a2 with changes in files: | |
| 21 | +** 336ceeccc6f85bd78f4a26648af7edf9056d with changes in files: | |
| 22 | 22 | ** |
| 23 | 23 | ** |
| 24 | 24 | */ |
| 25 | 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | 26 | #define SQLITE_CORE 1 |
| @@ -465,11 +465,11 @@ | ||
| 465 | 465 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 466 | 466 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 467 | 467 | */ |
| 468 | 468 | #define SQLITE_VERSION "3.50.0" |
| 469 | 469 | #define SQLITE_VERSION_NUMBER 3050000 |
| 470 | -#define SQLITE_SOURCE_ID "2025-04-15 21:59:38 d22475b81c4e26ccc50f3b5626d43b32f7a2de34e5a764539554665bdda735d5" | |
| 470 | +#define SQLITE_SOURCE_ID "2025-05-15 11:20:54 336ceeccc6f85bd78f4a26648af7edf9056d569a767b4120f125a02b2090a349" | |
| 471 | 471 | |
| 472 | 472 | /* |
| 473 | 473 | ** CAPI3REF: Run-Time Library Version Numbers |
| 474 | 474 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 475 | 475 | ** |
| @@ -11872,13 +11872,14 @@ | ||
| 11872 | 11872 | ** This may appear to have some counter-intuitive effects if a single row |
| 11873 | 11873 | ** is written to more than once during a session. For example, if a row |
| 11874 | 11874 | ** is inserted while a session object is enabled, then later deleted while |
| 11875 | 11875 | ** the same session object is disabled, no INSERT record will appear in the |
| 11876 | 11876 | ** changeset, even though the delete took place while the session was disabled. |
| 11877 | -** Or, if one field of a row is updated while a session is disabled, and | |
| 11878 | -** another field of the same row is updated while the session is enabled, the | |
| 11879 | -** resulting changeset will contain an UPDATE change that updates both fields. | |
| 11877 | +** Or, if one field of a row is updated while a session is enabled, and | |
| 11878 | +** then another field of the same row is updated while the session is disabled, | |
| 11879 | +** the resulting changeset will contain an UPDATE change that updates both | |
| 11880 | +** fields. | |
| 11880 | 11881 | */ |
| 11881 | 11882 | SQLITE_API int sqlite3session_changeset( |
| 11882 | 11883 | sqlite3_session *pSession, /* Session object */ |
| 11883 | 11884 | int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ |
| 11884 | 11885 | void **ppChangeset /* OUT: Buffer containing changeset */ |
| @@ -12083,11 +12084,11 @@ | ||
| 12083 | 12084 | ** CAPI3REF: Flags for sqlite3changeset_start_v2 |
| 12084 | 12085 | ** |
| 12085 | 12086 | ** The following flags may passed via the 4th parameter to |
| 12086 | 12087 | ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: |
| 12087 | 12088 | ** |
| 12088 | -** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd> | |
| 12089 | +** <dt>SQLITE_CHANGESETSTART_INVERT <dd> | |
| 12089 | 12090 | ** Invert the changeset while iterating through it. This is equivalent to |
| 12090 | 12091 | ** inverting a changeset using sqlite3changeset_invert() before applying it. |
| 12091 | 12092 | ** It is an error to specify this flag with a patchset. |
| 12092 | 12093 | */ |
| 12093 | 12094 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 |
| @@ -19160,11 +19161,10 @@ | ||
| 19160 | 19161 | unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ |
| 19161 | 19162 | unsigned isResized:1; /* True if resizeIndexObject() has been called */ |
| 19162 | 19163 | unsigned isCovering:1; /* True if this is a covering index */ |
| 19163 | 19164 | unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ |
| 19164 | 19165 | unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ |
| 19165 | - unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */ | |
| 19166 | 19166 | unsigned bNoQuery:1; /* Do not use this index to optimize queries */ |
| 19167 | 19167 | unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ |
| 19168 | 19168 | unsigned bIdxRowid:1; /* One or more of the index keys is the ROWID */ |
| 19169 | 19169 | unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ |
| 19170 | 19170 | unsigned bHasExpr:1; /* Index contains an expression, either a literal |
| @@ -22424,10 +22424,13 @@ | ||
| 22424 | 22424 | #ifdef SQLITE_BITMASK_TYPE |
| 22425 | 22425 | "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), |
| 22426 | 22426 | #endif |
| 22427 | 22427 | #ifdef SQLITE_BUG_COMPATIBLE_20160819 |
| 22428 | 22428 | "BUG_COMPATIBLE_20160819", |
| 22429 | +#endif | |
| 22430 | +#ifdef SQLITE_BUG_COMPATIBLE_20250510 | |
| 22431 | + "BUG_COMPATIBLE_20250510", | |
| 22429 | 22432 | #endif |
| 22430 | 22433 | #ifdef SQLITE_CASE_SENSITIVE_LIKE |
| 22431 | 22434 | "CASE_SENSITIVE_LIKE", |
| 22432 | 22435 | #endif |
| 22433 | 22436 | #ifdef SQLITE_CHECK_PAGES |
| @@ -32987,10 +32990,19 @@ | ||
| 32987 | 32990 | va_end(ap); |
| 32988 | 32991 | zBuf[acc.nChar] = 0; |
| 32989 | 32992 | return zBuf; |
| 32990 | 32993 | } |
| 32991 | 32994 | |
| 32995 | +/* Maximum size of an sqlite3_log() message. */ | |
| 32996 | +#if defined(SQLITE_MAX_LOG_MESSAGE) | |
| 32997 | + /* Leave the definition as supplied */ | |
| 32998 | +#elif SQLITE_PRINT_BUF_SIZE*10>10000 | |
| 32999 | +# define SQLITE_MAX_LOG_MESSAGE 10000 | |
| 33000 | +#else | |
| 33001 | +# define SQLITE_MAX_LOG_MESSAGE (SQLITE_PRINT_BUF_SIZE*10) | |
| 33002 | +#endif | |
| 33003 | + | |
| 32992 | 33004 | /* |
| 32993 | 33005 | ** This is the routine that actually formats the sqlite3_log() message. |
| 32994 | 33006 | ** We house it in a separate routine from sqlite3_log() to avoid using |
| 32995 | 33007 | ** stack space on small-stack systems when logging is disabled. |
| 32996 | 33008 | ** |
| @@ -33003,11 +33015,11 @@ | ||
| 33003 | 33015 | ** Care must be taken that any sqlite3_log() calls that occur while the |
| 33004 | 33016 | ** memory mutex is held do not use these mechanisms. |
| 33005 | 33017 | */ |
| 33006 | 33018 | static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ |
| 33007 | 33019 | StrAccum acc; /* String accumulator */ |
| 33008 | - char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ | |
| 33020 | + char zMsg[SQLITE_MAX_LOG_MESSAGE]; /* Complete log message */ | |
| 33009 | 33021 | |
| 33010 | 33022 | sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); |
| 33011 | 33023 | sqlite3_str_vappendf(&acc, zFormat, ap); |
| 33012 | 33024 | sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, |
| 33013 | 33025 | sqlite3StrAccumFinish(&acc)); |
| @@ -87262,10 +87274,13 @@ | ||
| 87262 | 87274 | ** into register iDest, then add the OPFLAG_TYPEOFARG flag to that |
| 87263 | 87275 | ** opcode. |
| 87264 | 87276 | */ |
| 87265 | 87277 | SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){ |
| 87266 | 87278 | VdbeOp *pOp = sqlite3VdbeGetLastOp(p); |
| 87279 | +#ifdef SQLITE_DEBUG | |
| 87280 | + while( pOp->opcode==OP_ReleaseReg ) pOp--; | |
| 87281 | +#endif | |
| 87267 | 87282 | if( pOp->p3==iDest && pOp->opcode==OP_Column ){ |
| 87268 | 87283 | pOp->p5 |= OPFLAG_TYPEOFARG; |
| 87269 | 87284 | } |
| 87270 | 87285 | } |
| 87271 | 87286 | |
| @@ -95716,11 +95731,11 @@ | ||
| 95716 | 95731 | } |
| 95717 | 95732 | }else{ |
| 95718 | 95733 | sqlite3VdbeError(p, "%s", pOp->p4.z); |
| 95719 | 95734 | } |
| 95720 | 95735 | pcx = (int)(pOp - aOp); |
| 95721 | - sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); | |
| 95736 | + sqlite3_log(pOp->p1, "abort at %d: %s; [%s]", pcx, p->zErrMsg, p->zSql); | |
| 95722 | 95737 | } |
| 95723 | 95738 | rc = sqlite3VdbeHalt(p); |
| 95724 | 95739 | assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); |
| 95725 | 95740 | if( rc==SQLITE_BUSY ){ |
| 95726 | 95741 | p->rc = SQLITE_BUSY; |
| @@ -97042,11 +97057,11 @@ | ||
| 97042 | 97057 | pOut->u.i = ~sqlite3VdbeIntValue(pIn1); |
| 97043 | 97058 | } |
| 97044 | 97059 | break; |
| 97045 | 97060 | } |
| 97046 | 97061 | |
| 97047 | -/* Opcode: Once P1 P2 * * * | |
| 97062 | +/* Opcode: Once P1 P2 P3 * * | |
| 97048 | 97063 | ** |
| 97049 | 97064 | ** Fall through to the next instruction the first time this opcode is |
| 97050 | 97065 | ** encountered on each invocation of the byte-code program. Jump to P2 |
| 97051 | 97066 | ** on the second and all subsequent encounters during the same invocation. |
| 97052 | 97067 | ** |
| @@ -97058,10 +97073,16 @@ | ||
| 97058 | 97073 | ** |
| 97059 | 97074 | ** For subprograms, there is a bitmask in the VdbeFrame that determines |
| 97060 | 97075 | ** whether or not the jump should be taken. The bitmask is necessary |
| 97061 | 97076 | ** because the self-altering code trick does not work for recursive |
| 97062 | 97077 | ** triggers. |
| 97078 | +** | |
| 97079 | +** The P3 operand is not used directly by this opcode. However P3 is | |
| 97080 | +** used by the code generator as follows: If this opcode is the start | |
| 97081 | +** of a subroutine and that subroutine uses a Bloom filter, then P3 will | |
| 97082 | +** be the register that holds that Bloom filter. See tag-202407032019 | |
| 97083 | +** in the source code for implementation details. | |
| 97063 | 97084 | */ |
| 97064 | 97085 | case OP_Once: { /* jump */ |
| 97065 | 97086 | u32 iAddr; /* Address of this instruction */ |
| 97066 | 97087 | assert( p->aOp[0].opcode==OP_Init ); |
| 97067 | 97088 | if( p->pFrame ){ |
| @@ -98103,10 +98124,11 @@ | ||
| 98103 | 98124 | } |
| 98104 | 98125 | }else{ |
| 98105 | 98126 | zHdr += sqlite3PutVarint(zHdr, serial_type); |
| 98106 | 98127 | if( pRec->n ){ |
| 98107 | 98128 | assert( pRec->z!=0 ); |
| 98129 | + assert( pRec->z!=(const char*)sqlite3CtypeMap ); | |
| 98108 | 98130 | memcpy(zPayload, pRec->z, pRec->n); |
| 98109 | 98131 | zPayload += pRec->n; |
| 98110 | 98132 | } |
| 98111 | 98133 | } |
| 98112 | 98134 | if( pRec==pLast ) break; |
| @@ -103551,12 +103573,12 @@ | ||
| 103551 | 103573 | sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); |
| 103552 | 103574 | } |
| 103553 | 103575 | p->rc = rc; |
| 103554 | 103576 | sqlite3SystemError(db, rc); |
| 103555 | 103577 | testcase( sqlite3GlobalConfig.xLog!=0 ); |
| 103556 | - sqlite3_log(rc, "statement aborts at %d: [%s] %s", | |
| 103557 | - (int)(pOp - aOp), p->zSql, p->zErrMsg); | |
| 103578 | + sqlite3_log(rc, "statement aborts at %d: %s; [%s]", | |
| 103579 | + (int)(pOp - aOp), p->zErrMsg, p->zSql); | |
| 103558 | 103580 | if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p); |
| 103559 | 103581 | if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); |
| 103560 | 103582 | if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ |
| 103561 | 103583 | db->flags |= SQLITE_CorruptRdOnly; |
| 103562 | 103584 | } |
| @@ -109287,17 +109309,16 @@ | ||
| 109287 | 109309 | /* Clearly non-deterministic functions like random(), but also |
| 109288 | 109310 | ** date/time functions that use 'now', and other functions like |
| 109289 | 109311 | ** sqlite_version() that might change over time cannot be used |
| 109290 | 109312 | ** in an index or generated column. Curiously, they can be used |
| 109291 | 109313 | ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all |
| 109292 | - ** all this. */ | |
| 109314 | + ** allow this. */ | |
| 109293 | 109315 | sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", |
| 109294 | 109316 | NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr); |
| 109295 | 109317 | }else{ |
| 109296 | 109318 | assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ |
| 109297 | 109319 | pExpr->op2 = pNC->ncFlags & NC_SelfRef; |
| 109298 | - if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); | |
| 109299 | 109320 | } |
| 109300 | 109321 | if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 |
| 109301 | 109322 | && pParse->nested==0 |
| 109302 | 109323 | && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0 |
| 109303 | 109324 | ){ |
| @@ -109309,10 +109330,11 @@ | ||
| 109309 | 109330 | pDef = 0; |
| 109310 | 109331 | }else |
| 109311 | 109332 | if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 |
| 109312 | 109333 | && !IN_RENAME_OBJECT |
| 109313 | 109334 | ){ |
| 109335 | + if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); | |
| 109314 | 109336 | sqlite3ExprFunctionUsable(pParse, pExpr, pDef); |
| 109315 | 109337 | } |
| 109316 | 109338 | } |
| 109317 | 109339 | |
| 109318 | 109340 | if( 0==IN_RENAME_OBJECT ){ |
| @@ -114022,15 +114044,16 @@ | ||
| 114022 | 114044 | pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); |
| 114023 | 114045 | rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); |
| 114024 | 114046 | sqlite3SelectDelete(pParse->db, pCopy); |
| 114025 | 114047 | sqlite3DbFree(pParse->db, dest.zAffSdst); |
| 114026 | 114048 | if( addrBloom ){ |
| 114049 | + /* Remember that location of the Bloom filter in the P3 operand | |
| 114050 | + ** of the OP_Once that began this subroutine. tag-202407032019 */ | |
| 114027 | 114051 | sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; |
| 114028 | 114052 | if( dest.iSDParm2==0 ){ |
| 114029 | - sqlite3VdbeChangeToNoop(v, addrBloom); | |
| 114030 | - }else{ | |
| 114031 | - sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; | |
| 114053 | + /* If the Bloom filter won't actually be used, keep it small */ | |
| 114054 | + sqlite3VdbeGetOp(v, addrBloom)->p1 = 10; | |
| 114032 | 114055 | } |
| 114033 | 114056 | } |
| 114034 | 114057 | if( rc ){ |
| 114035 | 114058 | sqlite3KeyInfoUnref(pKeyInfo); |
| 114036 | 114059 | return; |
| @@ -114473,11 +114496,11 @@ | ||
| 114473 | 114496 | if( destIfFalse==destIfNull ){ |
| 114474 | 114497 | /* Combine Step 3 and Step 5 into a single opcode */ |
| 114475 | 114498 | if( ExprHasProperty(pExpr, EP_Subrtn) ){ |
| 114476 | 114499 | const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); |
| 114477 | 114500 | assert( pOp->opcode==OP_Once || pParse->nErr ); |
| 114478 | - if( pOp->opcode==OP_Once && pOp->p3>0 ){ | |
| 114501 | + if( pOp->opcode==OP_Once && pOp->p3>0 ){ /* tag-202407032019 */ | |
| 114479 | 114502 | assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); |
| 114480 | 114503 | sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, |
| 114481 | 114504 | rLhs, nVector); VdbeCoverage(v); |
| 114482 | 114505 | } |
| 114483 | 114506 | } |
| @@ -116322,15 +116345,15 @@ | ||
| 116322 | 116345 | case TK_ISNULL: |
| 116323 | 116346 | case TK_NOTNULL: { |
| 116324 | 116347 | assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); |
| 116325 | 116348 | assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); |
| 116326 | 116349 | r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); |
| 116327 | - sqlite3VdbeTypeofColumn(v, r1); | |
| 116350 | + assert( regFree1==0 || regFree1==r1 ); | |
| 116351 | + if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); | |
| 116328 | 116352 | sqlite3VdbeAddOp2(v, op, r1, dest); |
| 116329 | 116353 | VdbeCoverageIf(v, op==TK_ISNULL); |
| 116330 | 116354 | VdbeCoverageIf(v, op==TK_NOTNULL); |
| 116331 | - testcase( regFree1==0 ); | |
| 116332 | 116355 | break; |
| 116333 | 116356 | } |
| 116334 | 116357 | case TK_BETWEEN: { |
| 116335 | 116358 | testcase( jumpIfNull==0 ); |
| 116336 | 116359 | exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull); |
| @@ -116497,15 +116520,15 @@ | ||
| 116497 | 116520 | break; |
| 116498 | 116521 | } |
| 116499 | 116522 | case TK_ISNULL: |
| 116500 | 116523 | case TK_NOTNULL: { |
| 116501 | 116524 | r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); |
| 116502 | - sqlite3VdbeTypeofColumn(v, r1); | |
| 116525 | + assert( regFree1==0 || regFree1==r1 ); | |
| 116526 | + if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); | |
| 116503 | 116527 | sqlite3VdbeAddOp2(v, op, r1, dest); |
| 116504 | 116528 | testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); |
| 116505 | 116529 | testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); |
| 116506 | - testcase( regFree1==0 ); | |
| 116507 | 116530 | break; |
| 116508 | 116531 | } |
| 116509 | 116532 | case TK_BETWEEN: { |
| 116510 | 116533 | testcase( jumpIfNull==0 ); |
| 116511 | 116534 | exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull); |
| @@ -121683,20 +121706,10 @@ | ||
| 121683 | 121706 | } |
| 121684 | 121707 | #endif |
| 121685 | 121708 | while( z[0]!=0 && z[0]!=' ' ) z++; |
| 121686 | 121709 | while( z[0]==' ' ) z++; |
| 121687 | 121710 | } |
| 121688 | - | |
| 121689 | - /* Set the bLowQual flag if the peak number of rows obtained | |
| 121690 | - ** from a full equality match is so large that a full table scan | |
| 121691 | - ** seems likely to be faster than using the index. | |
| 121692 | - */ | |
| 121693 | - if( aLog[0] > 66 /* Index has more than 100 rows */ | |
| 121694 | - && aLog[0] <= aLog[nOut-1] /* And only a single value seen */ | |
| 121695 | - ){ | |
| 121696 | - pIndex->bLowQual = 1; | |
| 121697 | - } | |
| 121698 | 121711 | } |
| 121699 | 121712 | } |
| 121700 | 121713 | |
| 121701 | 121714 | /* |
| 121702 | 121715 | ** This callback is invoked once for each index when reading the |
| @@ -124091,11 +124104,11 @@ | ||
| 124091 | 124104 | */ |
| 124092 | 124105 | SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){ |
| 124093 | 124106 | int i; |
| 124094 | 124107 | i16 iCol16; |
| 124095 | 124108 | assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN ); |
| 124096 | - assert( pIdx->nColumn<=SQLITE_MAX_COLUMN ); | |
| 124109 | + assert( pIdx->nColumn<=SQLITE_MAX_COLUMN+1 ); | |
| 124097 | 124110 | iCol16 = iCol; |
| 124098 | 124111 | for(i=0; i<pIdx->nColumn; i++){ |
| 124099 | 124112 | if( iCol16==pIdx->aiColumn[i] ){ |
| 124100 | 124113 | return i; |
| 124101 | 124114 | } |
| @@ -167620,15 +167633,12 @@ | ||
| 167620 | 167633 | opMask = WO_LT|WO_LE; |
| 167621 | 167634 | }else{ |
| 167622 | 167635 | assert( pNew->u.btree.nBtm==0 ); |
| 167623 | 167636 | opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; |
| 167624 | 167637 | } |
| 167625 | - if( pProbe->bUnordered || pProbe->bLowQual ){ | |
| 167626 | - if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); | |
| 167627 | - if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){ | |
| 167628 | - opMask &= ~(WO_EQ|WO_IN|WO_IS); | |
| 167629 | - } | |
| 167638 | + if( pProbe->bUnordered ){ | |
| 167639 | + opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); | |
| 167630 | 167640 | } |
| 167631 | 167641 | |
| 167632 | 167642 | assert( pNew->u.btree.nEq<pProbe->nColumn ); |
| 167633 | 167643 | assert( pNew->u.btree.nEq<pProbe->nKeyCol |
| 167634 | 167644 | || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); |
| @@ -168561,11 +168571,11 @@ | ||
| 168561 | 168571 | } |
| 168562 | 168572 | }else if( m==0 |
| 168563 | 168573 | && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) |
| 168564 | 168574 | ){ |
| 168565 | 168575 | WHERETRACE(0x200, |
| 168566 | - ("-> %s a covering index according to bitmasks\n", | |
| 168576 | + ("-> %s is a covering index according to bitmasks\n", | |
| 168567 | 168577 | pProbe->zName, m==0 ? "is" : "is not")); |
| 168568 | 168578 | pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; |
| 168569 | 168579 | } |
| 168570 | 168580 | } |
| 168571 | 168581 | |
| @@ -207968,60 +207978,113 @@ | ||
| 207968 | 207978 | ** Growing our own isspace() routine this way is twice as fast as |
| 207969 | 207979 | ** the library isspace() function, resulting in a 7% overall performance |
| 207970 | 207980 | ** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). |
| 207971 | 207981 | */ |
| 207972 | 207982 | static const char jsonIsSpace[] = { |
| 207973 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, | |
| 207974 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207975 | - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207976 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207977 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207978 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207979 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207980 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207981 | - | |
| 207982 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207983 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207984 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207985 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207986 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207987 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207988 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207989 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 207983 | +#ifdef SQLITE_ASCII | |
| 207984 | +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ | |
| 207985 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 */ | |
| 207986 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ | |
| 207987 | + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ | |
| 207988 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ | |
| 207989 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ | |
| 207990 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ | |
| 207991 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ | |
| 207992 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ | |
| 207993 | + | |
| 207994 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ | |
| 207995 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ | |
| 207996 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ | |
| 207997 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ | |
| 207998 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ | |
| 207999 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ | |
| 208000 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ | |
| 208001 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ | |
| 208002 | +#endif | |
| 208003 | +#ifdef SQLITE_EBCDIC | |
| 208004 | +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ | |
| 208005 | + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 0 */ | |
| 208006 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ | |
| 208007 | + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ | |
| 208008 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ | |
| 208009 | + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ | |
| 208010 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ | |
| 208011 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ | |
| 208012 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ | |
| 208013 | + | |
| 208014 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ | |
| 208015 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ | |
| 208016 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ | |
| 208017 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ | |
| 208018 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ | |
| 208019 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ | |
| 208020 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ | |
| 208021 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ | |
| 208022 | +#endif | |
| 208023 | + | |
| 207990 | 208024 | }; |
| 207991 | 208025 | #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) |
| 207992 | 208026 | |
| 207993 | 208027 | /* |
| 207994 | 208028 | ** The set of all space characters recognized by jsonIsspace(). |
| 207995 | 208029 | ** Useful as the second argument to strspn(). |
| 207996 | 208030 | */ |
| 208031 | +#ifdef SQLITE_ASCII | |
| 207997 | 208032 | static const char jsonSpaces[] = "\011\012\015\040"; |
| 208033 | +#endif | |
| 208034 | +#ifdef SQLITE_EBCDIC | |
| 208035 | +static const char jsonSpaces[] = "\005\045\015\100"; | |
| 208036 | +#endif | |
| 208037 | + | |
| 207998 | 208038 | |
| 207999 | 208039 | /* |
| 208000 | 208040 | ** Characters that are special to JSON. Control characters, |
| 208001 | 208041 | ** '"' and '\\' and '\''. Actually, '\'' is not special to |
| 208002 | 208042 | ** canonical JSON, but it is special in JSON-5, so we include |
| 208003 | 208043 | ** it in the set of special characters. |
| 208004 | 208044 | */ |
| 208005 | 208045 | static const char jsonIsOk[256] = { |
| 208006 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 208007 | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 208008 | - 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208009 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208010 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208011 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, | |
| 208012 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208013 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208014 | - | |
| 208015 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208016 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208017 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208018 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208019 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208020 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208021 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 208022 | - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 | |
| 208046 | +#ifdef SQLITE_ASCII | |
| 208047 | +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ | |
| 208048 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ | |
| 208049 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ | |
| 208050 | + 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */ | |
| 208051 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */ | |
| 208052 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ | |
| 208053 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 5 */ | |
| 208054 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ | |
| 208055 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ | |
| 208056 | + | |
| 208057 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ | |
| 208058 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ | |
| 208059 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ | |
| 208060 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ | |
| 208061 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ | |
| 208062 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ | |
| 208063 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ | |
| 208064 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ | |
| 208065 | +#endif | |
| 208066 | +#ifdef SQLITE_EBCDIC | |
| 208067 | +/*0 1 2 3 4 5 6 7 8 9 a b c d e f */ | |
| 208068 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ | |
| 208069 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ | |
| 208070 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ | |
| 208071 | + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 3 */ | |
| 208072 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ | |
| 208073 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5 */ | |
| 208074 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ | |
| 208075 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 7 */ | |
| 208076 | + | |
| 208077 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ | |
| 208078 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ | |
| 208079 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ | |
| 208080 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ | |
| 208081 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ | |
| 208082 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ | |
| 208083 | + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ | |
| 208084 | + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ | |
| 208085 | +#endif | |
| 208023 | 208086 | }; |
| 208024 | 208087 | |
| 208025 | 208088 | /* Objects */ |
| 208026 | 208089 | typedef struct JsonCache JsonCache; |
| 208027 | 208090 | typedef struct JsonString JsonString; |
| @@ -208162,11 +208225,11 @@ | ||
| 208162 | 208225 | |
| 208163 | 208226 | /************************************************************************** |
| 208164 | 208227 | ** Forward references |
| 208165 | 208228 | **************************************************************************/ |
| 208166 | 208229 | static void jsonReturnStringAsBlob(JsonString*); |
| 208167 | -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); | |
| 208230 | +static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p); | |
| 208168 | 208231 | static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); |
| 208169 | 208232 | static void jsonReturnParse(sqlite3_context*,JsonParse*); |
| 208170 | 208233 | static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); |
| 208171 | 208234 | static void jsonParseFree(JsonParse*); |
| 208172 | 208235 | static u32 jsonbPayloadSize(const JsonParse*, u32, u32*); |
| @@ -208580,15 +208643,13 @@ | ||
| 208580 | 208643 | jsonAppendString(p, z, n); |
| 208581 | 208644 | } |
| 208582 | 208645 | break; |
| 208583 | 208646 | } |
| 208584 | 208647 | default: { |
| 208585 | - if( jsonFuncArgMightBeBinary(pValue) ){ | |
| 208586 | - JsonParse px; | |
| 208587 | - memset(&px, 0, sizeof(px)); | |
| 208588 | - px.aBlob = (u8*)sqlite3_value_blob(pValue); | |
| 208589 | - px.nBlob = sqlite3_value_bytes(pValue); | |
| 208648 | + JsonParse px; | |
| 208649 | + memset(&px, 0, sizeof(px)); | |
| 208650 | + if( jsonArgIsJsonb(pValue, &px) ){ | |
| 208590 | 208651 | jsonTranslateBlobToText(&px, 0, p); |
| 208591 | 208652 | }else if( p->eErr==0 ){ |
| 208592 | 208653 | sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); |
| 208593 | 208654 | p->eErr = JSTRING_ERR; |
| 208594 | 208655 | jsonStringReset(p); |
| @@ -209522,11 +209583,16 @@ | ||
| 209522 | 209583 | c = z[++j]; |
| 209523 | 209584 | if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' |
| 209524 | 209585 | || c=='n' || c=='r' || c=='t' |
| 209525 | 209586 | || (c=='u' && jsonIs4Hex(&z[j+1])) ){ |
| 209526 | 209587 | if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; |
| 209527 | - }else if( c=='\'' || c=='0' || c=='v' || c=='\n' | |
| 209588 | + }else if( c=='\'' || c=='v' || c=='\n' | |
| 209589 | +#ifdef SQLITE_BUG_COMPATIBLE_20250510 | |
| 209590 | + || (c=='0') /* Legacy bug compatible */ | |
| 209591 | +#else | |
| 209592 | + || (c=='0' && !sqlite3Isdigit(z[j+1])) /* Correct implementation */ | |
| 209593 | +#endif | |
| 209528 | 209594 | || (0xe2==(u8)c && 0x80==(u8)z[j+1] |
| 209529 | 209595 | && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) |
| 209530 | 209596 | || (c=='x' && jsonIs2Hex(&z[j+1])) ){ |
| 209531 | 209597 | opcode = JSONB_TEXT5; |
| 209532 | 209598 | pParse->hasNonstd = 1; |
| @@ -209909,11 +209975,11 @@ | ||
| 209909 | 209975 | || pParse->aBlob[i+4]!=0 |
| 209910 | 209976 | ){ |
| 209911 | 209977 | *pSz = 0; |
| 209912 | 209978 | return 0; |
| 209913 | 209979 | } |
| 209914 | - sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + | |
| 209980 | + sz = ((u32)pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + | |
| 209915 | 209981 | (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; |
| 209916 | 209982 | n = 9; |
| 209917 | 209983 | } |
| 209918 | 209984 | if( (i64)i+sz+n > pParse->nBlob |
| 209919 | 209985 | && (i64)i+sz+n > pParse->nBlob-pParse->delta |
| @@ -210258,37 +210324,10 @@ | ||
| 210258 | 210324 | } |
| 210259 | 210325 | } |
| 210260 | 210326 | return i; |
| 210261 | 210327 | } |
| 210262 | 210328 | |
| 210263 | - | |
| 210264 | -/* Return true if the input pJson | |
| 210265 | -** | |
| 210266 | -** For performance reasons, this routine does not do a detailed check of the | |
| 210267 | -** input BLOB to ensure that it is well-formed. Hence, false positives are | |
| 210268 | -** possible. False negatives should never occur, however. | |
| 210269 | -*/ | |
| 210270 | -static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){ | |
| 210271 | - u32 sz, n; | |
| 210272 | - const u8 *aBlob; | |
| 210273 | - int nBlob; | |
| 210274 | - JsonParse s; | |
| 210275 | - if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; | |
| 210276 | - aBlob = sqlite3_value_blob(pJson); | |
| 210277 | - nBlob = sqlite3_value_bytes(pJson); | |
| 210278 | - if( nBlob<1 ) return 0; | |
| 210279 | - if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0; | |
| 210280 | - memset(&s, 0, sizeof(s)); | |
| 210281 | - s.aBlob = (u8*)aBlob; | |
| 210282 | - s.nBlob = nBlob; | |
| 210283 | - n = jsonbPayloadSize(&s, 0, &sz); | |
| 210284 | - if( n==0 ) return 0; | |
| 210285 | - if( sz+n!=(u32)nBlob ) return 0; | |
| 210286 | - if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0; | |
| 210287 | - return sz+n==(u32)nBlob; | |
| 210288 | -} | |
| 210289 | - | |
| 210290 | 210329 | /* |
| 210291 | 210330 | ** Given that a JSONB_ARRAY object starts at offset i, return |
| 210292 | 210331 | ** the number of entries in that array. |
| 210293 | 210332 | */ |
| 210294 | 210333 | static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){ |
| @@ -210517,11 +210556,25 @@ | ||
| 210517 | 210556 | case 'f': { *piOut = '\f'; return 2; } |
| 210518 | 210557 | case 'n': { *piOut = '\n'; return 2; } |
| 210519 | 210558 | case 'r': { *piOut = '\r'; return 2; } |
| 210520 | 210559 | case 't': { *piOut = '\t'; return 2; } |
| 210521 | 210560 | case 'v': { *piOut = '\v'; return 2; } |
| 210522 | - case '0': { *piOut = 0; return 2; } | |
| 210561 | + case '0': { | |
| 210562 | + /* JSON5 requires that the \0 escape not be followed by a digit. | |
| 210563 | + ** But SQLite did not enforce this restriction in versions 3.42.0 | |
| 210564 | + ** through 3.49.2. That was a bug. But some applications might have | |
| 210565 | + ** come to depend on that bug. Use the SQLITE_BUG_COMPATIBLE_20250510 | |
| 210566 | + ** option to restore the old buggy behavior. */ | |
| 210567 | +#ifdef SQLITE_BUG_COMPATIBLE_20250510 | |
| 210568 | + /* Legacy bug-compatible behavior */ | |
| 210569 | + *piOut = 0; | |
| 210570 | +#else | |
| 210571 | + /* Correct behavior */ | |
| 210572 | + *piOut = (n>2 && sqlite3Isdigit(z[2])) ? JSON_INVALID_CHAR : 0; | |
| 210573 | +#endif | |
| 210574 | + return 2; | |
| 210575 | + } | |
| 210523 | 210576 | case '\'': |
| 210524 | 210577 | case '"': |
| 210525 | 210578 | case '/': |
| 210526 | 210579 | case '\\':{ *piOut = z[1]; return 2; } |
| 210527 | 210580 | case 'x': { |
| @@ -211112,14 +211165,11 @@ | ||
| 211112 | 211165 | pParse->aBlob = aNull; |
| 211113 | 211166 | pParse->nBlob = 1; |
| 211114 | 211167 | return 0; |
| 211115 | 211168 | } |
| 211116 | 211169 | case SQLITE_BLOB: { |
| 211117 | - if( jsonFuncArgMightBeBinary(pArg) ){ | |
| 211118 | - pParse->aBlob = (u8*)sqlite3_value_blob(pArg); | |
| 211119 | - pParse->nBlob = sqlite3_value_bytes(pArg); | |
| 211120 | - }else{ | |
| 211170 | + if( !jsonArgIsJsonb(pArg, pParse) ){ | |
| 211121 | 211171 | sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); |
| 211122 | 211172 | return 1; |
| 211123 | 211173 | } |
| 211124 | 211174 | break; |
| 211125 | 211175 | } |
| @@ -211266,31 +211316,50 @@ | ||
| 211266 | 211316 | } |
| 211267 | 211317 | |
| 211268 | 211318 | /* |
| 211269 | 211319 | ** If pArg is a blob that seems like a JSONB blob, then initialize |
| 211270 | 211320 | ** p to point to that JSONB and return TRUE. If pArg does not seem like |
| 211271 | -** a JSONB blob, then return FALSE; | |
| 211321 | +** a JSONB blob, then return FALSE. | |
| 211272 | 211322 | ** |
| 211273 | -** This routine is only called if it is already known that pArg is a | |
| 211274 | -** blob. The only open question is whether or not the blob appears | |
| 211275 | -** to be a JSONB blob. | |
| 211323 | +** For small BLOBs (having no more than 7 bytes of payload) a full | |
| 211324 | +** validity check is done. So for small BLOBs this routine only returns | |
| 211325 | +** true if the value is guaranteed to be a valid JSONB. For larger BLOBs | |
| 211326 | +** (8 byte or more of payload) only the size of the outermost element is | |
| 211327 | +** checked to verify that the BLOB is superficially valid JSONB. | |
| 211328 | +** | |
| 211329 | +** A full JSONB validation is done on smaller BLOBs because those BLOBs might | |
| 211330 | +** also be text JSON that has been incorrectly cast into a BLOB. | |
| 211331 | +** (See tag-20240123-a and https://sqlite.org/forum/forumpost/012136abd5) | |
| 211332 | +** If the BLOB is 9 bytes are larger, then it is not possible for the | |
| 211333 | +** superficial size check done here to pass if the input is really text | |
| 211334 | +** JSON so we do not need to look deeper in that case. | |
| 211335 | +** | |
| 211336 | +** Why we only need to do full JSONB validation for smaller BLOBs: | |
| 211337 | +** | |
| 211338 | +** The first byte of valid JSON text must be one of: '{', '[', '"', ' ', '\n', | |
| 211339 | +** '\r', '\t', '-', or a digit '0' through '9'. Of these, only a subset | |
| 211340 | +** can also be the first byte of JSONB: '{', '[', and digits '3' | |
| 211341 | +** through '9'. In every one of those cases, the payload size is 7 bytes | |
| 211342 | +** or less. So if we do full JSONB validation for every BLOB where the | |
| 211343 | +** payload is less than 7 bytes, we will never get a false positive for | |
| 211344 | +** JSONB on an input that is really text JSON. | |
| 211276 | 211345 | */ |
| 211277 | 211346 | static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ |
| 211278 | 211347 | u32 n, sz = 0; |
| 211348 | + u8 c; | |
| 211349 | + if( sqlite3_value_type(pArg)!=SQLITE_BLOB ) return 0; | |
| 211279 | 211350 | p->aBlob = (u8*)sqlite3_value_blob(pArg); |
| 211280 | 211351 | p->nBlob = (u32)sqlite3_value_bytes(pArg); |
| 211281 | - if( p->nBlob==0 ){ | |
| 211282 | - p->aBlob = 0; | |
| 211283 | - return 0; | |
| 211284 | - } | |
| 211285 | - if( NEVER(p->aBlob==0) ){ | |
| 211286 | - return 0; | |
| 211287 | - } | |
| 211288 | - if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT | |
| 211352 | + if( p->nBlob>0 | |
| 211353 | + && ALWAYS(p->aBlob!=0) | |
| 211354 | + && ((c = p->aBlob[0]) & 0x0f)<=JSONB_OBJECT | |
| 211289 | 211355 | && (n = jsonbPayloadSize(p, 0, &sz))>0 |
| 211290 | 211356 | && sz+n==p->nBlob |
| 211291 | - && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0) | |
| 211357 | + && ((c & 0x0f)>JSONB_FALSE || sz==0) | |
| 211358 | + && (sz>7 | |
| 211359 | + || (c!=0x7b && c!=0x5b && !sqlite3Isdigit(c)) | |
| 211360 | + || jsonbValidityCheck(p, 0, p->nBlob, 1)==0) | |
| 211292 | 211361 | ){ |
| 211293 | 211362 | return 1; |
| 211294 | 211363 | } |
| 211295 | 211364 | p->aBlob = 0; |
| 211296 | 211365 | p->nBlob = 0; |
| @@ -212379,25 +212448,21 @@ | ||
| 212379 | 212448 | sqlite3_result_int(ctx, 0); |
| 212380 | 212449 | #endif |
| 212381 | 212450 | return; |
| 212382 | 212451 | } |
| 212383 | 212452 | case SQLITE_BLOB: { |
| 212384 | - if( jsonFuncArgMightBeBinary(argv[0]) ){ | |
| 212453 | + JsonParse py; | |
| 212454 | + memset(&py, 0, sizeof(py)); | |
| 212455 | + if( jsonArgIsJsonb(argv[0], &py) ){ | |
| 212385 | 212456 | if( flags & 0x04 ){ |
| 212386 | 212457 | /* Superficial checking only - accomplished by the |
| 212387 | - ** jsonFuncArgMightBeBinary() call above. */ | |
| 212458 | + ** jsonArgIsJsonb() call above. */ | |
| 212388 | 212459 | res = 1; |
| 212389 | 212460 | }else if( flags & 0x08 ){ |
| 212390 | 212461 | /* Strict checking. Check by translating BLOB->TEXT->BLOB. If |
| 212391 | 212462 | ** no errors occur, call that a "strict check". */ |
| 212392 | - JsonParse px; | |
| 212393 | - u32 iErr; | |
| 212394 | - memset(&px, 0, sizeof(px)); | |
| 212395 | - px.aBlob = (u8*)sqlite3_value_blob(argv[0]); | |
| 212396 | - px.nBlob = sqlite3_value_bytes(argv[0]); | |
| 212397 | - iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1); | |
| 212398 | - res = iErr==0; | |
| 212463 | + res = 0==jsonbValidityCheck(&py, 0, py.nBlob, 1); | |
| 212399 | 212464 | } |
| 212400 | 212465 | break; |
| 212401 | 212466 | } |
| 212402 | 212467 | /* Fall through into interpreting the input as text. See note |
| 212403 | 212468 | ** above at tag-20240123-a. */ |
| @@ -212451,13 +212516,11 @@ | ||
| 212451 | 212516 | |
| 212452 | 212517 | assert( argc==1 ); |
| 212453 | 212518 | UNUSED_PARAMETER(argc); |
| 212454 | 212519 | memset(&s, 0, sizeof(s)); |
| 212455 | 212520 | s.db = sqlite3_context_db_handle(ctx); |
| 212456 | - if( jsonFuncArgMightBeBinary(argv[0]) ){ | |
| 212457 | - s.aBlob = (u8*)sqlite3_value_blob(argv[0]); | |
| 212458 | - s.nBlob = sqlite3_value_bytes(argv[0]); | |
| 212521 | + if( jsonArgIsJsonb(argv[0], &s) ){ | |
| 212459 | 212522 | iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); |
| 212460 | 212523 | }else{ |
| 212461 | 212524 | s.zJson = (char*)sqlite3_value_text(argv[0]); |
| 212462 | 212525 | if( s.zJson==0 ) return; /* NULL input or OOM */ |
| 212463 | 212526 | s.nJson = sqlite3_value_bytes(argv[0]); |
| @@ -213138,13 +213201,12 @@ | ||
| 213138 | 213201 | jsonEachCursorReset(p); |
| 213139 | 213202 | if( idxNum==0 ) return SQLITE_OK; |
| 213140 | 213203 | memset(&p->sParse, 0, sizeof(p->sParse)); |
| 213141 | 213204 | p->sParse.nJPRef = 1; |
| 213142 | 213205 | p->sParse.db = p->db; |
| 213143 | - if( jsonFuncArgMightBeBinary(argv[0]) ){ | |
| 213144 | - p->sParse.nBlob = sqlite3_value_bytes(argv[0]); | |
| 213145 | - p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); | |
| 213206 | + if( jsonArgIsJsonb(argv[0], &p->sParse) ){ | |
| 213207 | + /* We have JSONB */ | |
| 213146 | 213208 | }else{ |
| 213147 | 213209 | p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); |
| 213148 | 213210 | p->sParse.nJson = sqlite3_value_bytes(argv[0]); |
| 213149 | 213211 | if( p->sParse.zJson==0 ){ |
| 213150 | 213212 | p->i = p->iEnd = 0; |
| @@ -257213,11 +257275,11 @@ | ||
| 257213 | 257275 | int nArg, /* Number of args */ |
| 257214 | 257276 | sqlite3_value **apUnused /* Function arguments */ |
| 257215 | 257277 | ){ |
| 257216 | 257278 | assert( nArg==0 ); |
| 257217 | 257279 | UNUSED_PARAM2(nArg, apUnused); |
| 257218 | - sqlite3_result_text(pCtx, "fts5: 2025-04-15 21:59:38 d22475b81c4e26ccc50f3b5626d43b32f7a2de34e5a764539554665bdda735d5", -1, SQLITE_TRANSIENT); | |
| 257280 | + sqlite3_result_text(pCtx, "fts5: 2025-05-15 11:20:54 336ceeccc6f85bd78f4a26648af7edf9056d569a767b4120f125a02b2090a349", -1, SQLITE_TRANSIENT); | |
| 257219 | 257281 | } |
| 257220 | 257282 | |
| 257221 | 257283 | /* |
| 257222 | 257284 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 257223 | 257285 | ** |
| 257224 | 257286 |
| --- extsrc/sqlite3.c | |
| +++ extsrc/sqlite3.c | |
| @@ -16,11 +16,11 @@ | |
| 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | ** |
| 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | ** d22475b81c4e26ccc50f3b5626d43b32f7a2 with changes in files: |
| 22 | ** |
| 23 | ** |
| 24 | */ |
| 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | #define SQLITE_CORE 1 |
| @@ -465,11 +465,11 @@ | |
| 465 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 466 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 467 | */ |
| 468 | #define SQLITE_VERSION "3.50.0" |
| 469 | #define SQLITE_VERSION_NUMBER 3050000 |
| 470 | #define SQLITE_SOURCE_ID "2025-04-15 21:59:38 d22475b81c4e26ccc50f3b5626d43b32f7a2de34e5a764539554665bdda735d5" |
| 471 | |
| 472 | /* |
| 473 | ** CAPI3REF: Run-Time Library Version Numbers |
| 474 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 475 | ** |
| @@ -11872,13 +11872,14 @@ | |
| 11872 | ** This may appear to have some counter-intuitive effects if a single row |
| 11873 | ** is written to more than once during a session. For example, if a row |
| 11874 | ** is inserted while a session object is enabled, then later deleted while |
| 11875 | ** the same session object is disabled, no INSERT record will appear in the |
| 11876 | ** changeset, even though the delete took place while the session was disabled. |
| 11877 | ** Or, if one field of a row is updated while a session is disabled, and |
| 11878 | ** another field of the same row is updated while the session is enabled, the |
| 11879 | ** resulting changeset will contain an UPDATE change that updates both fields. |
| 11880 | */ |
| 11881 | SQLITE_API int sqlite3session_changeset( |
| 11882 | sqlite3_session *pSession, /* Session object */ |
| 11883 | int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ |
| 11884 | void **ppChangeset /* OUT: Buffer containing changeset */ |
| @@ -12083,11 +12084,11 @@ | |
| 12083 | ** CAPI3REF: Flags for sqlite3changeset_start_v2 |
| 12084 | ** |
| 12085 | ** The following flags may passed via the 4th parameter to |
| 12086 | ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: |
| 12087 | ** |
| 12088 | ** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd> |
| 12089 | ** Invert the changeset while iterating through it. This is equivalent to |
| 12090 | ** inverting a changeset using sqlite3changeset_invert() before applying it. |
| 12091 | ** It is an error to specify this flag with a patchset. |
| 12092 | */ |
| 12093 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 |
| @@ -19160,11 +19161,10 @@ | |
| 19160 | unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ |
| 19161 | unsigned isResized:1; /* True if resizeIndexObject() has been called */ |
| 19162 | unsigned isCovering:1; /* True if this is a covering index */ |
| 19163 | unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ |
| 19164 | unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ |
| 19165 | unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */ |
| 19166 | unsigned bNoQuery:1; /* Do not use this index to optimize queries */ |
| 19167 | unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ |
| 19168 | unsigned bIdxRowid:1; /* One or more of the index keys is the ROWID */ |
| 19169 | unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ |
| 19170 | unsigned bHasExpr:1; /* Index contains an expression, either a literal |
| @@ -22424,10 +22424,13 @@ | |
| 22424 | #ifdef SQLITE_BITMASK_TYPE |
| 22425 | "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), |
| 22426 | #endif |
| 22427 | #ifdef SQLITE_BUG_COMPATIBLE_20160819 |
| 22428 | "BUG_COMPATIBLE_20160819", |
| 22429 | #endif |
| 22430 | #ifdef SQLITE_CASE_SENSITIVE_LIKE |
| 22431 | "CASE_SENSITIVE_LIKE", |
| 22432 | #endif |
| 22433 | #ifdef SQLITE_CHECK_PAGES |
| @@ -32987,10 +32990,19 @@ | |
| 32987 | va_end(ap); |
| 32988 | zBuf[acc.nChar] = 0; |
| 32989 | return zBuf; |
| 32990 | } |
| 32991 | |
| 32992 | /* |
| 32993 | ** This is the routine that actually formats the sqlite3_log() message. |
| 32994 | ** We house it in a separate routine from sqlite3_log() to avoid using |
| 32995 | ** stack space on small-stack systems when logging is disabled. |
| 32996 | ** |
| @@ -33003,11 +33015,11 @@ | |
| 33003 | ** Care must be taken that any sqlite3_log() calls that occur while the |
| 33004 | ** memory mutex is held do not use these mechanisms. |
| 33005 | */ |
| 33006 | static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ |
| 33007 | StrAccum acc; /* String accumulator */ |
| 33008 | char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */ |
| 33009 | |
| 33010 | sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); |
| 33011 | sqlite3_str_vappendf(&acc, zFormat, ap); |
| 33012 | sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, |
| 33013 | sqlite3StrAccumFinish(&acc)); |
| @@ -87262,10 +87274,13 @@ | |
| 87262 | ** into register iDest, then add the OPFLAG_TYPEOFARG flag to that |
| 87263 | ** opcode. |
| 87264 | */ |
| 87265 | SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){ |
| 87266 | VdbeOp *pOp = sqlite3VdbeGetLastOp(p); |
| 87267 | if( pOp->p3==iDest && pOp->opcode==OP_Column ){ |
| 87268 | pOp->p5 |= OPFLAG_TYPEOFARG; |
| 87269 | } |
| 87270 | } |
| 87271 | |
| @@ -95716,11 +95731,11 @@ | |
| 95716 | } |
| 95717 | }else{ |
| 95718 | sqlite3VdbeError(p, "%s", pOp->p4.z); |
| 95719 | } |
| 95720 | pcx = (int)(pOp - aOp); |
| 95721 | sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); |
| 95722 | } |
| 95723 | rc = sqlite3VdbeHalt(p); |
| 95724 | assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); |
| 95725 | if( rc==SQLITE_BUSY ){ |
| 95726 | p->rc = SQLITE_BUSY; |
| @@ -97042,11 +97057,11 @@ | |
| 97042 | pOut->u.i = ~sqlite3VdbeIntValue(pIn1); |
| 97043 | } |
| 97044 | break; |
| 97045 | } |
| 97046 | |
| 97047 | /* Opcode: Once P1 P2 * * * |
| 97048 | ** |
| 97049 | ** Fall through to the next instruction the first time this opcode is |
| 97050 | ** encountered on each invocation of the byte-code program. Jump to P2 |
| 97051 | ** on the second and all subsequent encounters during the same invocation. |
| 97052 | ** |
| @@ -97058,10 +97073,16 @@ | |
| 97058 | ** |
| 97059 | ** For subprograms, there is a bitmask in the VdbeFrame that determines |
| 97060 | ** whether or not the jump should be taken. The bitmask is necessary |
| 97061 | ** because the self-altering code trick does not work for recursive |
| 97062 | ** triggers. |
| 97063 | */ |
| 97064 | case OP_Once: { /* jump */ |
| 97065 | u32 iAddr; /* Address of this instruction */ |
| 97066 | assert( p->aOp[0].opcode==OP_Init ); |
| 97067 | if( p->pFrame ){ |
| @@ -98103,10 +98124,11 @@ | |
| 98103 | } |
| 98104 | }else{ |
| 98105 | zHdr += sqlite3PutVarint(zHdr, serial_type); |
| 98106 | if( pRec->n ){ |
| 98107 | assert( pRec->z!=0 ); |
| 98108 | memcpy(zPayload, pRec->z, pRec->n); |
| 98109 | zPayload += pRec->n; |
| 98110 | } |
| 98111 | } |
| 98112 | if( pRec==pLast ) break; |
| @@ -103551,12 +103573,12 @@ | |
| 103551 | sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); |
| 103552 | } |
| 103553 | p->rc = rc; |
| 103554 | sqlite3SystemError(db, rc); |
| 103555 | testcase( sqlite3GlobalConfig.xLog!=0 ); |
| 103556 | sqlite3_log(rc, "statement aborts at %d: [%s] %s", |
| 103557 | (int)(pOp - aOp), p->zSql, p->zErrMsg); |
| 103558 | if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p); |
| 103559 | if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); |
| 103560 | if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ |
| 103561 | db->flags |= SQLITE_CorruptRdOnly; |
| 103562 | } |
| @@ -109287,17 +109309,16 @@ | |
| 109287 | /* Clearly non-deterministic functions like random(), but also |
| 109288 | ** date/time functions that use 'now', and other functions like |
| 109289 | ** sqlite_version() that might change over time cannot be used |
| 109290 | ** in an index or generated column. Curiously, they can be used |
| 109291 | ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all |
| 109292 | ** all this. */ |
| 109293 | sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", |
| 109294 | NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr); |
| 109295 | }else{ |
| 109296 | assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ |
| 109297 | pExpr->op2 = pNC->ncFlags & NC_SelfRef; |
| 109298 | if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); |
| 109299 | } |
| 109300 | if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 |
| 109301 | && pParse->nested==0 |
| 109302 | && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0 |
| 109303 | ){ |
| @@ -109309,10 +109330,11 @@ | |
| 109309 | pDef = 0; |
| 109310 | }else |
| 109311 | if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 |
| 109312 | && !IN_RENAME_OBJECT |
| 109313 | ){ |
| 109314 | sqlite3ExprFunctionUsable(pParse, pExpr, pDef); |
| 109315 | } |
| 109316 | } |
| 109317 | |
| 109318 | if( 0==IN_RENAME_OBJECT ){ |
| @@ -114022,15 +114044,16 @@ | |
| 114022 | pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); |
| 114023 | rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); |
| 114024 | sqlite3SelectDelete(pParse->db, pCopy); |
| 114025 | sqlite3DbFree(pParse->db, dest.zAffSdst); |
| 114026 | if( addrBloom ){ |
| 114027 | sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; |
| 114028 | if( dest.iSDParm2==0 ){ |
| 114029 | sqlite3VdbeChangeToNoop(v, addrBloom); |
| 114030 | }else{ |
| 114031 | sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; |
| 114032 | } |
| 114033 | } |
| 114034 | if( rc ){ |
| 114035 | sqlite3KeyInfoUnref(pKeyInfo); |
| 114036 | return; |
| @@ -114473,11 +114496,11 @@ | |
| 114473 | if( destIfFalse==destIfNull ){ |
| 114474 | /* Combine Step 3 and Step 5 into a single opcode */ |
| 114475 | if( ExprHasProperty(pExpr, EP_Subrtn) ){ |
| 114476 | const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); |
| 114477 | assert( pOp->opcode==OP_Once || pParse->nErr ); |
| 114478 | if( pOp->opcode==OP_Once && pOp->p3>0 ){ |
| 114479 | assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); |
| 114480 | sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, |
| 114481 | rLhs, nVector); VdbeCoverage(v); |
| 114482 | } |
| 114483 | } |
| @@ -116322,15 +116345,15 @@ | |
| 116322 | case TK_ISNULL: |
| 116323 | case TK_NOTNULL: { |
| 116324 | assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); |
| 116325 | assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); |
| 116326 | r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); |
| 116327 | sqlite3VdbeTypeofColumn(v, r1); |
| 116328 | sqlite3VdbeAddOp2(v, op, r1, dest); |
| 116329 | VdbeCoverageIf(v, op==TK_ISNULL); |
| 116330 | VdbeCoverageIf(v, op==TK_NOTNULL); |
| 116331 | testcase( regFree1==0 ); |
| 116332 | break; |
| 116333 | } |
| 116334 | case TK_BETWEEN: { |
| 116335 | testcase( jumpIfNull==0 ); |
| 116336 | exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull); |
| @@ -116497,15 +116520,15 @@ | |
| 116497 | break; |
| 116498 | } |
| 116499 | case TK_ISNULL: |
| 116500 | case TK_NOTNULL: { |
| 116501 | r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); |
| 116502 | sqlite3VdbeTypeofColumn(v, r1); |
| 116503 | sqlite3VdbeAddOp2(v, op, r1, dest); |
| 116504 | testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); |
| 116505 | testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); |
| 116506 | testcase( regFree1==0 ); |
| 116507 | break; |
| 116508 | } |
| 116509 | case TK_BETWEEN: { |
| 116510 | testcase( jumpIfNull==0 ); |
| 116511 | exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull); |
| @@ -121683,20 +121706,10 @@ | |
| 121683 | } |
| 121684 | #endif |
| 121685 | while( z[0]!=0 && z[0]!=' ' ) z++; |
| 121686 | while( z[0]==' ' ) z++; |
| 121687 | } |
| 121688 | |
| 121689 | /* Set the bLowQual flag if the peak number of rows obtained |
| 121690 | ** from a full equality match is so large that a full table scan |
| 121691 | ** seems likely to be faster than using the index. |
| 121692 | */ |
| 121693 | if( aLog[0] > 66 /* Index has more than 100 rows */ |
| 121694 | && aLog[0] <= aLog[nOut-1] /* And only a single value seen */ |
| 121695 | ){ |
| 121696 | pIndex->bLowQual = 1; |
| 121697 | } |
| 121698 | } |
| 121699 | } |
| 121700 | |
| 121701 | /* |
| 121702 | ** This callback is invoked once for each index when reading the |
| @@ -124091,11 +124104,11 @@ | |
| 124091 | */ |
| 124092 | SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){ |
| 124093 | int i; |
| 124094 | i16 iCol16; |
| 124095 | assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN ); |
| 124096 | assert( pIdx->nColumn<=SQLITE_MAX_COLUMN ); |
| 124097 | iCol16 = iCol; |
| 124098 | for(i=0; i<pIdx->nColumn; i++){ |
| 124099 | if( iCol16==pIdx->aiColumn[i] ){ |
| 124100 | return i; |
| 124101 | } |
| @@ -167620,15 +167633,12 @@ | |
| 167620 | opMask = WO_LT|WO_LE; |
| 167621 | }else{ |
| 167622 | assert( pNew->u.btree.nBtm==0 ); |
| 167623 | opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; |
| 167624 | } |
| 167625 | if( pProbe->bUnordered || pProbe->bLowQual ){ |
| 167626 | if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); |
| 167627 | if( pProbe->bLowQual && pSrc->fg.isIndexedBy==0 ){ |
| 167628 | opMask &= ~(WO_EQ|WO_IN|WO_IS); |
| 167629 | } |
| 167630 | } |
| 167631 | |
| 167632 | assert( pNew->u.btree.nEq<pProbe->nColumn ); |
| 167633 | assert( pNew->u.btree.nEq<pProbe->nKeyCol |
| 167634 | || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); |
| @@ -168561,11 +168571,11 @@ | |
| 168561 | } |
| 168562 | }else if( m==0 |
| 168563 | && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) |
| 168564 | ){ |
| 168565 | WHERETRACE(0x200, |
| 168566 | ("-> %s a covering index according to bitmasks\n", |
| 168567 | pProbe->zName, m==0 ? "is" : "is not")); |
| 168568 | pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; |
| 168569 | } |
| 168570 | } |
| 168571 | |
| @@ -207968,60 +207978,113 @@ | |
| 207968 | ** Growing our own isspace() routine this way is twice as fast as |
| 207969 | ** the library isspace() function, resulting in a 7% overall performance |
| 207970 | ** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). |
| 207971 | */ |
| 207972 | static const char jsonIsSpace[] = { |
| 207973 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, |
| 207974 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207975 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207976 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207977 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207978 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207979 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207980 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207981 | |
| 207982 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207983 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207984 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207985 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207986 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207987 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207988 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207989 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 207990 | }; |
| 207991 | #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) |
| 207992 | |
| 207993 | /* |
| 207994 | ** The set of all space characters recognized by jsonIsspace(). |
| 207995 | ** Useful as the second argument to strspn(). |
| 207996 | */ |
| 207997 | static const char jsonSpaces[] = "\011\012\015\040"; |
| 207998 | |
| 207999 | /* |
| 208000 | ** Characters that are special to JSON. Control characters, |
| 208001 | ** '"' and '\\' and '\''. Actually, '\'' is not special to |
| 208002 | ** canonical JSON, but it is special in JSON-5, so we include |
| 208003 | ** it in the set of special characters. |
| 208004 | */ |
| 208005 | static const char jsonIsOk[256] = { |
| 208006 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 208007 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 208008 | 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208009 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208010 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208011 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, |
| 208012 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208013 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208014 | |
| 208015 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208016 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208017 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208018 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208019 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208020 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208021 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
| 208022 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 |
| 208023 | }; |
| 208024 | |
| 208025 | /* Objects */ |
| 208026 | typedef struct JsonCache JsonCache; |
| 208027 | typedef struct JsonString JsonString; |
| @@ -208162,11 +208225,11 @@ | |
| 208162 | |
| 208163 | /************************************************************************** |
| 208164 | ** Forward references |
| 208165 | **************************************************************************/ |
| 208166 | static void jsonReturnStringAsBlob(JsonString*); |
| 208167 | static int jsonFuncArgMightBeBinary(sqlite3_value *pJson); |
| 208168 | static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); |
| 208169 | static void jsonReturnParse(sqlite3_context*,JsonParse*); |
| 208170 | static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); |
| 208171 | static void jsonParseFree(JsonParse*); |
| 208172 | static u32 jsonbPayloadSize(const JsonParse*, u32, u32*); |
| @@ -208580,15 +208643,13 @@ | |
| 208580 | jsonAppendString(p, z, n); |
| 208581 | } |
| 208582 | break; |
| 208583 | } |
| 208584 | default: { |
| 208585 | if( jsonFuncArgMightBeBinary(pValue) ){ |
| 208586 | JsonParse px; |
| 208587 | memset(&px, 0, sizeof(px)); |
| 208588 | px.aBlob = (u8*)sqlite3_value_blob(pValue); |
| 208589 | px.nBlob = sqlite3_value_bytes(pValue); |
| 208590 | jsonTranslateBlobToText(&px, 0, p); |
| 208591 | }else if( p->eErr==0 ){ |
| 208592 | sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); |
| 208593 | p->eErr = JSTRING_ERR; |
| 208594 | jsonStringReset(p); |
| @@ -209522,11 +209583,16 @@ | |
| 209522 | c = z[++j]; |
| 209523 | if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' |
| 209524 | || c=='n' || c=='r' || c=='t' |
| 209525 | || (c=='u' && jsonIs4Hex(&z[j+1])) ){ |
| 209526 | if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; |
| 209527 | }else if( c=='\'' || c=='0' || c=='v' || c=='\n' |
| 209528 | || (0xe2==(u8)c && 0x80==(u8)z[j+1] |
| 209529 | && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) |
| 209530 | || (c=='x' && jsonIs2Hex(&z[j+1])) ){ |
| 209531 | opcode = JSONB_TEXT5; |
| 209532 | pParse->hasNonstd = 1; |
| @@ -209909,11 +209975,11 @@ | |
| 209909 | || pParse->aBlob[i+4]!=0 |
| 209910 | ){ |
| 209911 | *pSz = 0; |
| 209912 | return 0; |
| 209913 | } |
| 209914 | sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + |
| 209915 | (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; |
| 209916 | n = 9; |
| 209917 | } |
| 209918 | if( (i64)i+sz+n > pParse->nBlob |
| 209919 | && (i64)i+sz+n > pParse->nBlob-pParse->delta |
| @@ -210258,37 +210324,10 @@ | |
| 210258 | } |
| 210259 | } |
| 210260 | return i; |
| 210261 | } |
| 210262 | |
| 210263 | |
| 210264 | /* Return true if the input pJson |
| 210265 | ** |
| 210266 | ** For performance reasons, this routine does not do a detailed check of the |
| 210267 | ** input BLOB to ensure that it is well-formed. Hence, false positives are |
| 210268 | ** possible. False negatives should never occur, however. |
| 210269 | */ |
| 210270 | static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){ |
| 210271 | u32 sz, n; |
| 210272 | const u8 *aBlob; |
| 210273 | int nBlob; |
| 210274 | JsonParse s; |
| 210275 | if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0; |
| 210276 | aBlob = sqlite3_value_blob(pJson); |
| 210277 | nBlob = sqlite3_value_bytes(pJson); |
| 210278 | if( nBlob<1 ) return 0; |
| 210279 | if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0; |
| 210280 | memset(&s, 0, sizeof(s)); |
| 210281 | s.aBlob = (u8*)aBlob; |
| 210282 | s.nBlob = nBlob; |
| 210283 | n = jsonbPayloadSize(&s, 0, &sz); |
| 210284 | if( n==0 ) return 0; |
| 210285 | if( sz+n!=(u32)nBlob ) return 0; |
| 210286 | if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0; |
| 210287 | return sz+n==(u32)nBlob; |
| 210288 | } |
| 210289 | |
| 210290 | /* |
| 210291 | ** Given that a JSONB_ARRAY object starts at offset i, return |
| 210292 | ** the number of entries in that array. |
| 210293 | */ |
| 210294 | static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){ |
| @@ -210517,11 +210556,25 @@ | |
| 210517 | case 'f': { *piOut = '\f'; return 2; } |
| 210518 | case 'n': { *piOut = '\n'; return 2; } |
| 210519 | case 'r': { *piOut = '\r'; return 2; } |
| 210520 | case 't': { *piOut = '\t'; return 2; } |
| 210521 | case 'v': { *piOut = '\v'; return 2; } |
| 210522 | case '0': { *piOut = 0; return 2; } |
| 210523 | case '\'': |
| 210524 | case '"': |
| 210525 | case '/': |
| 210526 | case '\\':{ *piOut = z[1]; return 2; } |
| 210527 | case 'x': { |
| @@ -211112,14 +211165,11 @@ | |
| 211112 | pParse->aBlob = aNull; |
| 211113 | pParse->nBlob = 1; |
| 211114 | return 0; |
| 211115 | } |
| 211116 | case SQLITE_BLOB: { |
| 211117 | if( jsonFuncArgMightBeBinary(pArg) ){ |
| 211118 | pParse->aBlob = (u8*)sqlite3_value_blob(pArg); |
| 211119 | pParse->nBlob = sqlite3_value_bytes(pArg); |
| 211120 | }else{ |
| 211121 | sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); |
| 211122 | return 1; |
| 211123 | } |
| 211124 | break; |
| 211125 | } |
| @@ -211266,31 +211316,50 @@ | |
| 211266 | } |
| 211267 | |
| 211268 | /* |
| 211269 | ** If pArg is a blob that seems like a JSONB blob, then initialize |
| 211270 | ** p to point to that JSONB and return TRUE. If pArg does not seem like |
| 211271 | ** a JSONB blob, then return FALSE; |
| 211272 | ** |
| 211273 | ** This routine is only called if it is already known that pArg is a |
| 211274 | ** blob. The only open question is whether or not the blob appears |
| 211275 | ** to be a JSONB blob. |
| 211276 | */ |
| 211277 | static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ |
| 211278 | u32 n, sz = 0; |
| 211279 | p->aBlob = (u8*)sqlite3_value_blob(pArg); |
| 211280 | p->nBlob = (u32)sqlite3_value_bytes(pArg); |
| 211281 | if( p->nBlob==0 ){ |
| 211282 | p->aBlob = 0; |
| 211283 | return 0; |
| 211284 | } |
| 211285 | if( NEVER(p->aBlob==0) ){ |
| 211286 | return 0; |
| 211287 | } |
| 211288 | if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT |
| 211289 | && (n = jsonbPayloadSize(p, 0, &sz))>0 |
| 211290 | && sz+n==p->nBlob |
| 211291 | && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0) |
| 211292 | ){ |
| 211293 | return 1; |
| 211294 | } |
| 211295 | p->aBlob = 0; |
| 211296 | p->nBlob = 0; |
| @@ -212379,25 +212448,21 @@ | |
| 212379 | sqlite3_result_int(ctx, 0); |
| 212380 | #endif |
| 212381 | return; |
| 212382 | } |
| 212383 | case SQLITE_BLOB: { |
| 212384 | if( jsonFuncArgMightBeBinary(argv[0]) ){ |
| 212385 | if( flags & 0x04 ){ |
| 212386 | /* Superficial checking only - accomplished by the |
| 212387 | ** jsonFuncArgMightBeBinary() call above. */ |
| 212388 | res = 1; |
| 212389 | }else if( flags & 0x08 ){ |
| 212390 | /* Strict checking. Check by translating BLOB->TEXT->BLOB. If |
| 212391 | ** no errors occur, call that a "strict check". */ |
| 212392 | JsonParse px; |
| 212393 | u32 iErr; |
| 212394 | memset(&px, 0, sizeof(px)); |
| 212395 | px.aBlob = (u8*)sqlite3_value_blob(argv[0]); |
| 212396 | px.nBlob = sqlite3_value_bytes(argv[0]); |
| 212397 | iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1); |
| 212398 | res = iErr==0; |
| 212399 | } |
| 212400 | break; |
| 212401 | } |
| 212402 | /* Fall through into interpreting the input as text. See note |
| 212403 | ** above at tag-20240123-a. */ |
| @@ -212451,13 +212516,11 @@ | |
| 212451 | |
| 212452 | assert( argc==1 ); |
| 212453 | UNUSED_PARAMETER(argc); |
| 212454 | memset(&s, 0, sizeof(s)); |
| 212455 | s.db = sqlite3_context_db_handle(ctx); |
| 212456 | if( jsonFuncArgMightBeBinary(argv[0]) ){ |
| 212457 | s.aBlob = (u8*)sqlite3_value_blob(argv[0]); |
| 212458 | s.nBlob = sqlite3_value_bytes(argv[0]); |
| 212459 | iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); |
| 212460 | }else{ |
| 212461 | s.zJson = (char*)sqlite3_value_text(argv[0]); |
| 212462 | if( s.zJson==0 ) return; /* NULL input or OOM */ |
| 212463 | s.nJson = sqlite3_value_bytes(argv[0]); |
| @@ -213138,13 +213201,12 @@ | |
| 213138 | jsonEachCursorReset(p); |
| 213139 | if( idxNum==0 ) return SQLITE_OK; |
| 213140 | memset(&p->sParse, 0, sizeof(p->sParse)); |
| 213141 | p->sParse.nJPRef = 1; |
| 213142 | p->sParse.db = p->db; |
| 213143 | if( jsonFuncArgMightBeBinary(argv[0]) ){ |
| 213144 | p->sParse.nBlob = sqlite3_value_bytes(argv[0]); |
| 213145 | p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]); |
| 213146 | }else{ |
| 213147 | p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); |
| 213148 | p->sParse.nJson = sqlite3_value_bytes(argv[0]); |
| 213149 | if( p->sParse.zJson==0 ){ |
| 213150 | p->i = p->iEnd = 0; |
| @@ -257213,11 +257275,11 @@ | |
| 257213 | int nArg, /* Number of args */ |
| 257214 | sqlite3_value **apUnused /* Function arguments */ |
| 257215 | ){ |
| 257216 | assert( nArg==0 ); |
| 257217 | UNUSED_PARAM2(nArg, apUnused); |
| 257218 | sqlite3_result_text(pCtx, "fts5: 2025-04-15 21:59:38 d22475b81c4e26ccc50f3b5626d43b32f7a2de34e5a764539554665bdda735d5", -1, SQLITE_TRANSIENT); |
| 257219 | } |
| 257220 | |
| 257221 | /* |
| 257222 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 257223 | ** |
| 257224 |
| --- extsrc/sqlite3.c | |
| +++ extsrc/sqlite3.c | |
| @@ -16,11 +16,11 @@ | |
| 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | ** |
| 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | ** 336ceeccc6f85bd78f4a26648af7edf9056d with changes in files: |
| 22 | ** |
| 23 | ** |
| 24 | */ |
| 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | #define SQLITE_CORE 1 |
| @@ -465,11 +465,11 @@ | |
| 465 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 466 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 467 | */ |
| 468 | #define SQLITE_VERSION "3.50.0" |
| 469 | #define SQLITE_VERSION_NUMBER 3050000 |
| 470 | #define SQLITE_SOURCE_ID "2025-05-15 11:20:54 336ceeccc6f85bd78f4a26648af7edf9056d569a767b4120f125a02b2090a349" |
| 471 | |
| 472 | /* |
| 473 | ** CAPI3REF: Run-Time Library Version Numbers |
| 474 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 475 | ** |
| @@ -11872,13 +11872,14 @@ | |
| 11872 | ** This may appear to have some counter-intuitive effects if a single row |
| 11873 | ** is written to more than once during a session. For example, if a row |
| 11874 | ** is inserted while a session object is enabled, then later deleted while |
| 11875 | ** the same session object is disabled, no INSERT record will appear in the |
| 11876 | ** changeset, even though the delete took place while the session was disabled. |
| 11877 | ** Or, if one field of a row is updated while a session is enabled, and |
| 11878 | ** then another field of the same row is updated while the session is disabled, |
| 11879 | ** the resulting changeset will contain an UPDATE change that updates both |
| 11880 | ** fields. |
| 11881 | */ |
| 11882 | SQLITE_API int sqlite3session_changeset( |
| 11883 | sqlite3_session *pSession, /* Session object */ |
| 11884 | int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ |
| 11885 | void **ppChangeset /* OUT: Buffer containing changeset */ |
| @@ -12083,11 +12084,11 @@ | |
| 12084 | ** CAPI3REF: Flags for sqlite3changeset_start_v2 |
| 12085 | ** |
| 12086 | ** The following flags may passed via the 4th parameter to |
| 12087 | ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: |
| 12088 | ** |
| 12089 | ** <dt>SQLITE_CHANGESETSTART_INVERT <dd> |
| 12090 | ** Invert the changeset while iterating through it. This is equivalent to |
| 12091 | ** inverting a changeset using sqlite3changeset_invert() before applying it. |
| 12092 | ** It is an error to specify this flag with a patchset. |
| 12093 | */ |
| 12094 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 |
| @@ -19160,11 +19161,10 @@ | |
| 19161 | unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ |
| 19162 | unsigned isResized:1; /* True if resizeIndexObject() has been called */ |
| 19163 | unsigned isCovering:1; /* True if this is a covering index */ |
| 19164 | unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ |
| 19165 | unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */ |
| 19166 | unsigned bNoQuery:1; /* Do not use this index to optimize queries */ |
| 19167 | unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ |
| 19168 | unsigned bIdxRowid:1; /* One or more of the index keys is the ROWID */ |
| 19169 | unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ |
| 19170 | unsigned bHasExpr:1; /* Index contains an expression, either a literal |
| @@ -22424,10 +22424,13 @@ | |
| 22424 | #ifdef SQLITE_BITMASK_TYPE |
| 22425 | "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), |
| 22426 | #endif |
| 22427 | #ifdef SQLITE_BUG_COMPATIBLE_20160819 |
| 22428 | "BUG_COMPATIBLE_20160819", |
| 22429 | #endif |
| 22430 | #ifdef SQLITE_BUG_COMPATIBLE_20250510 |
| 22431 | "BUG_COMPATIBLE_20250510", |
| 22432 | #endif |
| 22433 | #ifdef SQLITE_CASE_SENSITIVE_LIKE |
| 22434 | "CASE_SENSITIVE_LIKE", |
| 22435 | #endif |
| 22436 | #ifdef SQLITE_CHECK_PAGES |
| @@ -32987,10 +32990,19 @@ | |
| 32990 | va_end(ap); |
| 32991 | zBuf[acc.nChar] = 0; |
| 32992 | return zBuf; |
| 32993 | } |
| 32994 | |
| 32995 | /* Maximum size of an sqlite3_log() message. */ |
| 32996 | #if defined(SQLITE_MAX_LOG_MESSAGE) |
| 32997 | /* Leave the definition as supplied */ |
| 32998 | #elif SQLITE_PRINT_BUF_SIZE*10>10000 |
| 32999 | # define SQLITE_MAX_LOG_MESSAGE 10000 |
| 33000 | #else |
| 33001 | # define SQLITE_MAX_LOG_MESSAGE (SQLITE_PRINT_BUF_SIZE*10) |
| 33002 | #endif |
| 33003 | |
| 33004 | /* |
| 33005 | ** This is the routine that actually formats the sqlite3_log() message. |
| 33006 | ** We house it in a separate routine from sqlite3_log() to avoid using |
| 33007 | ** stack space on small-stack systems when logging is disabled. |
| 33008 | ** |
| @@ -33003,11 +33015,11 @@ | |
| 33015 | ** Care must be taken that any sqlite3_log() calls that occur while the |
| 33016 | ** memory mutex is held do not use these mechanisms. |
| 33017 | */ |
| 33018 | static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){ |
| 33019 | StrAccum acc; /* String accumulator */ |
| 33020 | char zMsg[SQLITE_MAX_LOG_MESSAGE]; /* Complete log message */ |
| 33021 | |
| 33022 | sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0); |
| 33023 | sqlite3_str_vappendf(&acc, zFormat, ap); |
| 33024 | sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode, |
| 33025 | sqlite3StrAccumFinish(&acc)); |
| @@ -87262,10 +87274,13 @@ | |
| 87274 | ** into register iDest, then add the OPFLAG_TYPEOFARG flag to that |
| 87275 | ** opcode. |
| 87276 | */ |
| 87277 | SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){ |
| 87278 | VdbeOp *pOp = sqlite3VdbeGetLastOp(p); |
| 87279 | #ifdef SQLITE_DEBUG |
| 87280 | while( pOp->opcode==OP_ReleaseReg ) pOp--; |
| 87281 | #endif |
| 87282 | if( pOp->p3==iDest && pOp->opcode==OP_Column ){ |
| 87283 | pOp->p5 |= OPFLAG_TYPEOFARG; |
| 87284 | } |
| 87285 | } |
| 87286 | |
| @@ -95716,11 +95731,11 @@ | |
| 95731 | } |
| 95732 | }else{ |
| 95733 | sqlite3VdbeError(p, "%s", pOp->p4.z); |
| 95734 | } |
| 95735 | pcx = (int)(pOp - aOp); |
| 95736 | sqlite3_log(pOp->p1, "abort at %d: %s; [%s]", pcx, p->zErrMsg, p->zSql); |
| 95737 | } |
| 95738 | rc = sqlite3VdbeHalt(p); |
| 95739 | assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); |
| 95740 | if( rc==SQLITE_BUSY ){ |
| 95741 | p->rc = SQLITE_BUSY; |
| @@ -97042,11 +97057,11 @@ | |
| 97057 | pOut->u.i = ~sqlite3VdbeIntValue(pIn1); |
| 97058 | } |
| 97059 | break; |
| 97060 | } |
| 97061 | |
| 97062 | /* Opcode: Once P1 P2 P3 * * |
| 97063 | ** |
| 97064 | ** Fall through to the next instruction the first time this opcode is |
| 97065 | ** encountered on each invocation of the byte-code program. Jump to P2 |
| 97066 | ** on the second and all subsequent encounters during the same invocation. |
| 97067 | ** |
| @@ -97058,10 +97073,16 @@ | |
| 97073 | ** |
| 97074 | ** For subprograms, there is a bitmask in the VdbeFrame that determines |
| 97075 | ** whether or not the jump should be taken. The bitmask is necessary |
| 97076 | ** because the self-altering code trick does not work for recursive |
| 97077 | ** triggers. |
| 97078 | ** |
| 97079 | ** The P3 operand is not used directly by this opcode. However P3 is |
| 97080 | ** used by the code generator as follows: If this opcode is the start |
| 97081 | ** of a subroutine and that subroutine uses a Bloom filter, then P3 will |
| 97082 | ** be the register that holds that Bloom filter. See tag-202407032019 |
| 97083 | ** in the source code for implementation details. |
| 97084 | */ |
| 97085 | case OP_Once: { /* jump */ |
| 97086 | u32 iAddr; /* Address of this instruction */ |
| 97087 | assert( p->aOp[0].opcode==OP_Init ); |
| 97088 | if( p->pFrame ){ |
| @@ -98103,10 +98124,11 @@ | |
| 98124 | } |
| 98125 | }else{ |
| 98126 | zHdr += sqlite3PutVarint(zHdr, serial_type); |
| 98127 | if( pRec->n ){ |
| 98128 | assert( pRec->z!=0 ); |
| 98129 | assert( pRec->z!=(const char*)sqlite3CtypeMap ); |
| 98130 | memcpy(zPayload, pRec->z, pRec->n); |
| 98131 | zPayload += pRec->n; |
| 98132 | } |
| 98133 | } |
| 98134 | if( pRec==pLast ) break; |
| @@ -103551,12 +103573,12 @@ | |
| 103573 | sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); |
| 103574 | } |
| 103575 | p->rc = rc; |
| 103576 | sqlite3SystemError(db, rc); |
| 103577 | testcase( sqlite3GlobalConfig.xLog!=0 ); |
| 103578 | sqlite3_log(rc, "statement aborts at %d: %s; [%s]", |
| 103579 | (int)(pOp - aOp), p->zErrMsg, p->zSql); |
| 103580 | if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p); |
| 103581 | if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db); |
| 103582 | if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){ |
| 103583 | db->flags |= SQLITE_CorruptRdOnly; |
| 103584 | } |
| @@ -109287,17 +109309,16 @@ | |
| 109309 | /* Clearly non-deterministic functions like random(), but also |
| 109310 | ** date/time functions that use 'now', and other functions like |
| 109311 | ** sqlite_version() that might change over time cannot be used |
| 109312 | ** in an index or generated column. Curiously, they can be used |
| 109313 | ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all |
| 109314 | ** allow this. */ |
| 109315 | sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions", |
| 109316 | NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr); |
| 109317 | }else{ |
| 109318 | assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */ |
| 109319 | pExpr->op2 = pNC->ncFlags & NC_SelfRef; |
| 109320 | } |
| 109321 | if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 |
| 109322 | && pParse->nested==0 |
| 109323 | && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0 |
| 109324 | ){ |
| @@ -109309,10 +109330,11 @@ | |
| 109330 | pDef = 0; |
| 109331 | }else |
| 109332 | if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 |
| 109333 | && !IN_RENAME_OBJECT |
| 109334 | ){ |
| 109335 | if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL); |
| 109336 | sqlite3ExprFunctionUsable(pParse, pExpr, pDef); |
| 109337 | } |
| 109338 | } |
| 109339 | |
| 109340 | if( 0==IN_RENAME_OBJECT ){ |
| @@ -114022,15 +114044,16 @@ | |
| 114044 | pCopy = sqlite3SelectDup(pParse->db, pSelect, 0); |
| 114045 | rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest); |
| 114046 | sqlite3SelectDelete(pParse->db, pCopy); |
| 114047 | sqlite3DbFree(pParse->db, dest.zAffSdst); |
| 114048 | if( addrBloom ){ |
| 114049 | /* Remember that location of the Bloom filter in the P3 operand |
| 114050 | ** of the OP_Once that began this subroutine. tag-202407032019 */ |
| 114051 | sqlite3VdbeGetOp(v, addrOnce)->p3 = dest.iSDParm2; |
| 114052 | if( dest.iSDParm2==0 ){ |
| 114053 | /* If the Bloom filter won't actually be used, keep it small */ |
| 114054 | sqlite3VdbeGetOp(v, addrBloom)->p1 = 10; |
| 114055 | } |
| 114056 | } |
| 114057 | if( rc ){ |
| 114058 | sqlite3KeyInfoUnref(pKeyInfo); |
| 114059 | return; |
| @@ -114473,11 +114496,11 @@ | |
| 114496 | if( destIfFalse==destIfNull ){ |
| 114497 | /* Combine Step 3 and Step 5 into a single opcode */ |
| 114498 | if( ExprHasProperty(pExpr, EP_Subrtn) ){ |
| 114499 | const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); |
| 114500 | assert( pOp->opcode==OP_Once || pParse->nErr ); |
| 114501 | if( pOp->opcode==OP_Once && pOp->p3>0 ){ /* tag-202407032019 */ |
| 114502 | assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); |
| 114503 | sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, |
| 114504 | rLhs, nVector); VdbeCoverage(v); |
| 114505 | } |
| 114506 | } |
| @@ -116322,15 +116345,15 @@ | |
| 116345 | case TK_ISNULL: |
| 116346 | case TK_NOTNULL: { |
| 116347 | assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); |
| 116348 | assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); |
| 116349 | r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); |
| 116350 | assert( regFree1==0 || regFree1==r1 ); |
| 116351 | if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); |
| 116352 | sqlite3VdbeAddOp2(v, op, r1, dest); |
| 116353 | VdbeCoverageIf(v, op==TK_ISNULL); |
| 116354 | VdbeCoverageIf(v, op==TK_NOTNULL); |
| 116355 | break; |
| 116356 | } |
| 116357 | case TK_BETWEEN: { |
| 116358 | testcase( jumpIfNull==0 ); |
| 116359 | exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull); |
| @@ -116497,15 +116520,15 @@ | |
| 116520 | break; |
| 116521 | } |
| 116522 | case TK_ISNULL: |
| 116523 | case TK_NOTNULL: { |
| 116524 | r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); |
| 116525 | assert( regFree1==0 || regFree1==r1 ); |
| 116526 | if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1); |
| 116527 | sqlite3VdbeAddOp2(v, op, r1, dest); |
| 116528 | testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); |
| 116529 | testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); |
| 116530 | break; |
| 116531 | } |
| 116532 | case TK_BETWEEN: { |
| 116533 | testcase( jumpIfNull==0 ); |
| 116534 | exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull); |
| @@ -121683,20 +121706,10 @@ | |
| 121706 | } |
| 121707 | #endif |
| 121708 | while( z[0]!=0 && z[0]!=' ' ) z++; |
| 121709 | while( z[0]==' ' ) z++; |
| 121710 | } |
| 121711 | } |
| 121712 | } |
| 121713 | |
| 121714 | /* |
| 121715 | ** This callback is invoked once for each index when reading the |
| @@ -124091,11 +124104,11 @@ | |
| 124104 | */ |
| 124105 | SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){ |
| 124106 | int i; |
| 124107 | i16 iCol16; |
| 124108 | assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN ); |
| 124109 | assert( pIdx->nColumn<=SQLITE_MAX_COLUMN+1 ); |
| 124110 | iCol16 = iCol; |
| 124111 | for(i=0; i<pIdx->nColumn; i++){ |
| 124112 | if( iCol16==pIdx->aiColumn[i] ){ |
| 124113 | return i; |
| 124114 | } |
| @@ -167620,15 +167633,12 @@ | |
| 167633 | opMask = WO_LT|WO_LE; |
| 167634 | }else{ |
| 167635 | assert( pNew->u.btree.nBtm==0 ); |
| 167636 | opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; |
| 167637 | } |
| 167638 | if( pProbe->bUnordered ){ |
| 167639 | opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); |
| 167640 | } |
| 167641 | |
| 167642 | assert( pNew->u.btree.nEq<pProbe->nColumn ); |
| 167643 | assert( pNew->u.btree.nEq<pProbe->nKeyCol |
| 167644 | || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY ); |
| @@ -168561,11 +168571,11 @@ | |
| 168571 | } |
| 168572 | }else if( m==0 |
| 168573 | && (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700)) |
| 168574 | ){ |
| 168575 | WHERETRACE(0x200, |
| 168576 | ("-> %s is a covering index according to bitmasks\n", |
| 168577 | pProbe->zName, m==0 ? "is" : "is not")); |
| 168578 | pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED; |
| 168579 | } |
| 168580 | } |
| 168581 | |
| @@ -207968,60 +207978,113 @@ | |
| 207978 | ** Growing our own isspace() routine this way is twice as fast as |
| 207979 | ** the library isspace() function, resulting in a 7% overall performance |
| 207980 | ** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). |
| 207981 | */ |
| 207982 | static const char jsonIsSpace[] = { |
| 207983 | #ifdef SQLITE_ASCII |
| 207984 | /*0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
| 207985 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0 */ |
| 207986 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ |
| 207987 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ |
| 207988 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ |
| 207989 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ |
| 207990 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ |
| 207991 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ |
| 207992 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ |
| 207993 | |
| 207994 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ |
| 207995 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ |
| 207996 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ |
| 207997 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ |
| 207998 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ |
| 207999 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ |
| 208000 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ |
| 208001 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ |
| 208002 | #endif |
| 208003 | #ifdef SQLITE_EBCDIC |
| 208004 | /*0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
| 208005 | 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 0 */ |
| 208006 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ |
| 208007 | 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ |
| 208008 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */ |
| 208009 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */ |
| 208010 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */ |
| 208011 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */ |
| 208012 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */ |
| 208013 | |
| 208014 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ |
| 208015 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ |
| 208016 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a */ |
| 208017 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b */ |
| 208018 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c */ |
| 208019 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ |
| 208020 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e */ |
| 208021 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f */ |
| 208022 | #endif |
| 208023 | |
| 208024 | }; |
| 208025 | #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x]) |
| 208026 | |
| 208027 | /* |
| 208028 | ** The set of all space characters recognized by jsonIsspace(). |
| 208029 | ** Useful as the second argument to strspn(). |
| 208030 | */ |
| 208031 | #ifdef SQLITE_ASCII |
| 208032 | static const char jsonSpaces[] = "\011\012\015\040"; |
| 208033 | #endif |
| 208034 | #ifdef SQLITE_EBCDIC |
| 208035 | static const char jsonSpaces[] = "\005\045\015\100"; |
| 208036 | #endif |
| 208037 | |
| 208038 | |
| 208039 | /* |
| 208040 | ** Characters that are special to JSON. Control characters, |
| 208041 | ** '"' and '\\' and '\''. Actually, '\'' is not special to |
| 208042 | ** canonical JSON, but it is special in JSON-5, so we include |
| 208043 | ** it in the set of special characters. |
| 208044 | */ |
| 208045 | static const char jsonIsOk[256] = { |
| 208046 | #ifdef SQLITE_ASCII |
| 208047 | /*0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
| 208048 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ |
| 208049 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ |
| 208050 | 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */ |
| 208051 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */ |
| 208052 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ |
| 208053 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 5 */ |
| 208054 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ |
| 208055 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ |
| 208056 | |
| 208057 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ |
| 208058 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ |
| 208059 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ |
| 208060 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ |
| 208061 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ |
| 208062 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ |
| 208063 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ |
| 208064 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ |
| 208065 | #endif |
| 208066 | #ifdef SQLITE_EBCDIC |
| 208067 | /*0 1 2 3 4 5 6 7 8 9 a b c d e f */ |
| 208068 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */ |
| 208069 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */ |
| 208070 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ |
| 208071 | 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 3 */ |
| 208072 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ |
| 208073 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5 */ |
| 208074 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ |
| 208075 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 7 */ |
| 208076 | |
| 208077 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ |
| 208078 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9 */ |
| 208079 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a */ |
| 208080 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b */ |
| 208081 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* c */ |
| 208082 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d */ |
| 208083 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ |
| 208084 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* f */ |
| 208085 | #endif |
| 208086 | }; |
| 208087 | |
| 208088 | /* Objects */ |
| 208089 | typedef struct JsonCache JsonCache; |
| 208090 | typedef struct JsonString JsonString; |
| @@ -208162,11 +208225,11 @@ | |
| 208225 | |
| 208226 | /************************************************************************** |
| 208227 | ** Forward references |
| 208228 | **************************************************************************/ |
| 208229 | static void jsonReturnStringAsBlob(JsonString*); |
| 208230 | static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p); |
| 208231 | static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); |
| 208232 | static void jsonReturnParse(sqlite3_context*,JsonParse*); |
| 208233 | static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); |
| 208234 | static void jsonParseFree(JsonParse*); |
| 208235 | static u32 jsonbPayloadSize(const JsonParse*, u32, u32*); |
| @@ -208580,15 +208643,13 @@ | |
| 208643 | jsonAppendString(p, z, n); |
| 208644 | } |
| 208645 | break; |
| 208646 | } |
| 208647 | default: { |
| 208648 | JsonParse px; |
| 208649 | memset(&px, 0, sizeof(px)); |
| 208650 | if( jsonArgIsJsonb(pValue, &px) ){ |
| 208651 | jsonTranslateBlobToText(&px, 0, p); |
| 208652 | }else if( p->eErr==0 ){ |
| 208653 | sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); |
| 208654 | p->eErr = JSTRING_ERR; |
| 208655 | jsonStringReset(p); |
| @@ -209522,11 +209583,16 @@ | |
| 209583 | c = z[++j]; |
| 209584 | if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' |
| 209585 | || c=='n' || c=='r' || c=='t' |
| 209586 | || (c=='u' && jsonIs4Hex(&z[j+1])) ){ |
| 209587 | if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ; |
| 209588 | }else if( c=='\'' || c=='v' || c=='\n' |
| 209589 | #ifdef SQLITE_BUG_COMPATIBLE_20250510 |
| 209590 | || (c=='0') /* Legacy bug compatible */ |
| 209591 | #else |
| 209592 | || (c=='0' && !sqlite3Isdigit(z[j+1])) /* Correct implementation */ |
| 209593 | #endif |
| 209594 | || (0xe2==(u8)c && 0x80==(u8)z[j+1] |
| 209595 | && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])) |
| 209596 | || (c=='x' && jsonIs2Hex(&z[j+1])) ){ |
| 209597 | opcode = JSONB_TEXT5; |
| 209598 | pParse->hasNonstd = 1; |
| @@ -209909,11 +209975,11 @@ | |
| 209975 | || pParse->aBlob[i+4]!=0 |
| 209976 | ){ |
| 209977 | *pSz = 0; |
| 209978 | return 0; |
| 209979 | } |
| 209980 | sz = ((u32)pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) + |
| 209981 | (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8]; |
| 209982 | n = 9; |
| 209983 | } |
| 209984 | if( (i64)i+sz+n > pParse->nBlob |
| 209985 | && (i64)i+sz+n > pParse->nBlob-pParse->delta |
| @@ -210258,37 +210324,10 @@ | |
| 210324 | } |
| 210325 | } |
| 210326 | return i; |
| 210327 | } |
| 210328 | |
| 210329 | /* |
| 210330 | ** Given that a JSONB_ARRAY object starts at offset i, return |
| 210331 | ** the number of entries in that array. |
| 210332 | */ |
| 210333 | static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){ |
| @@ -210517,11 +210556,25 @@ | |
| 210556 | case 'f': { *piOut = '\f'; return 2; } |
| 210557 | case 'n': { *piOut = '\n'; return 2; } |
| 210558 | case 'r': { *piOut = '\r'; return 2; } |
| 210559 | case 't': { *piOut = '\t'; return 2; } |
| 210560 | case 'v': { *piOut = '\v'; return 2; } |
| 210561 | case '0': { |
| 210562 | /* JSON5 requires that the \0 escape not be followed by a digit. |
| 210563 | ** But SQLite did not enforce this restriction in versions 3.42.0 |
| 210564 | ** through 3.49.2. That was a bug. But some applications might have |
| 210565 | ** come to depend on that bug. Use the SQLITE_BUG_COMPATIBLE_20250510 |
| 210566 | ** option to restore the old buggy behavior. */ |
| 210567 | #ifdef SQLITE_BUG_COMPATIBLE_20250510 |
| 210568 | /* Legacy bug-compatible behavior */ |
| 210569 | *piOut = 0; |
| 210570 | #else |
| 210571 | /* Correct behavior */ |
| 210572 | *piOut = (n>2 && sqlite3Isdigit(z[2])) ? JSON_INVALID_CHAR : 0; |
| 210573 | #endif |
| 210574 | return 2; |
| 210575 | } |
| 210576 | case '\'': |
| 210577 | case '"': |
| 210578 | case '/': |
| 210579 | case '\\':{ *piOut = z[1]; return 2; } |
| 210580 | case 'x': { |
| @@ -211112,14 +211165,11 @@ | |
| 211165 | pParse->aBlob = aNull; |
| 211166 | pParse->nBlob = 1; |
| 211167 | return 0; |
| 211168 | } |
| 211169 | case SQLITE_BLOB: { |
| 211170 | if( !jsonArgIsJsonb(pArg, pParse) ){ |
| 211171 | sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1); |
| 211172 | return 1; |
| 211173 | } |
| 211174 | break; |
| 211175 | } |
| @@ -211266,31 +211316,50 @@ | |
| 211316 | } |
| 211317 | |
| 211318 | /* |
| 211319 | ** If pArg is a blob that seems like a JSONB blob, then initialize |
| 211320 | ** p to point to that JSONB and return TRUE. If pArg does not seem like |
| 211321 | ** a JSONB blob, then return FALSE. |
| 211322 | ** |
| 211323 | ** For small BLOBs (having no more than 7 bytes of payload) a full |
| 211324 | ** validity check is done. So for small BLOBs this routine only returns |
| 211325 | ** true if the value is guaranteed to be a valid JSONB. For larger BLOBs |
| 211326 | ** (8 byte or more of payload) only the size of the outermost element is |
| 211327 | ** checked to verify that the BLOB is superficially valid JSONB. |
| 211328 | ** |
| 211329 | ** A full JSONB validation is done on smaller BLOBs because those BLOBs might |
| 211330 | ** also be text JSON that has been incorrectly cast into a BLOB. |
| 211331 | ** (See tag-20240123-a and https://sqlite.org/forum/forumpost/012136abd5) |
| 211332 | ** If the BLOB is 9 bytes are larger, then it is not possible for the |
| 211333 | ** superficial size check done here to pass if the input is really text |
| 211334 | ** JSON so we do not need to look deeper in that case. |
| 211335 | ** |
| 211336 | ** Why we only need to do full JSONB validation for smaller BLOBs: |
| 211337 | ** |
| 211338 | ** The first byte of valid JSON text must be one of: '{', '[', '"', ' ', '\n', |
| 211339 | ** '\r', '\t', '-', or a digit '0' through '9'. Of these, only a subset |
| 211340 | ** can also be the first byte of JSONB: '{', '[', and digits '3' |
| 211341 | ** through '9'. In every one of those cases, the payload size is 7 bytes |
| 211342 | ** or less. So if we do full JSONB validation for every BLOB where the |
| 211343 | ** payload is less than 7 bytes, we will never get a false positive for |
| 211344 | ** JSONB on an input that is really text JSON. |
| 211345 | */ |
| 211346 | static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){ |
| 211347 | u32 n, sz = 0; |
| 211348 | u8 c; |
| 211349 | if( sqlite3_value_type(pArg)!=SQLITE_BLOB ) return 0; |
| 211350 | p->aBlob = (u8*)sqlite3_value_blob(pArg); |
| 211351 | p->nBlob = (u32)sqlite3_value_bytes(pArg); |
| 211352 | if( p->nBlob>0 |
| 211353 | && ALWAYS(p->aBlob!=0) |
| 211354 | && ((c = p->aBlob[0]) & 0x0f)<=JSONB_OBJECT |
| 211355 | && (n = jsonbPayloadSize(p, 0, &sz))>0 |
| 211356 | && sz+n==p->nBlob |
| 211357 | && ((c & 0x0f)>JSONB_FALSE || sz==0) |
| 211358 | && (sz>7 |
| 211359 | || (c!=0x7b && c!=0x5b && !sqlite3Isdigit(c)) |
| 211360 | || jsonbValidityCheck(p, 0, p->nBlob, 1)==0) |
| 211361 | ){ |
| 211362 | return 1; |
| 211363 | } |
| 211364 | p->aBlob = 0; |
| 211365 | p->nBlob = 0; |
| @@ -212379,25 +212448,21 @@ | |
| 212448 | sqlite3_result_int(ctx, 0); |
| 212449 | #endif |
| 212450 | return; |
| 212451 | } |
| 212452 | case SQLITE_BLOB: { |
| 212453 | JsonParse py; |
| 212454 | memset(&py, 0, sizeof(py)); |
| 212455 | if( jsonArgIsJsonb(argv[0], &py) ){ |
| 212456 | if( flags & 0x04 ){ |
| 212457 | /* Superficial checking only - accomplished by the |
| 212458 | ** jsonArgIsJsonb() call above. */ |
| 212459 | res = 1; |
| 212460 | }else if( flags & 0x08 ){ |
| 212461 | /* Strict checking. Check by translating BLOB->TEXT->BLOB. If |
| 212462 | ** no errors occur, call that a "strict check". */ |
| 212463 | res = 0==jsonbValidityCheck(&py, 0, py.nBlob, 1); |
| 212464 | } |
| 212465 | break; |
| 212466 | } |
| 212467 | /* Fall through into interpreting the input as text. See note |
| 212468 | ** above at tag-20240123-a. */ |
| @@ -212451,13 +212516,11 @@ | |
| 212516 | |
| 212517 | assert( argc==1 ); |
| 212518 | UNUSED_PARAMETER(argc); |
| 212519 | memset(&s, 0, sizeof(s)); |
| 212520 | s.db = sqlite3_context_db_handle(ctx); |
| 212521 | if( jsonArgIsJsonb(argv[0], &s) ){ |
| 212522 | iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1); |
| 212523 | }else{ |
| 212524 | s.zJson = (char*)sqlite3_value_text(argv[0]); |
| 212525 | if( s.zJson==0 ) return; /* NULL input or OOM */ |
| 212526 | s.nJson = sqlite3_value_bytes(argv[0]); |
| @@ -213138,13 +213201,12 @@ | |
| 213201 | jsonEachCursorReset(p); |
| 213202 | if( idxNum==0 ) return SQLITE_OK; |
| 213203 | memset(&p->sParse, 0, sizeof(p->sParse)); |
| 213204 | p->sParse.nJPRef = 1; |
| 213205 | p->sParse.db = p->db; |
| 213206 | if( jsonArgIsJsonb(argv[0], &p->sParse) ){ |
| 213207 | /* We have JSONB */ |
| 213208 | }else{ |
| 213209 | p->sParse.zJson = (char*)sqlite3_value_text(argv[0]); |
| 213210 | p->sParse.nJson = sqlite3_value_bytes(argv[0]); |
| 213211 | if( p->sParse.zJson==0 ){ |
| 213212 | p->i = p->iEnd = 0; |
| @@ -257213,11 +257275,11 @@ | |
| 257275 | int nArg, /* Number of args */ |
| 257276 | sqlite3_value **apUnused /* Function arguments */ |
| 257277 | ){ |
| 257278 | assert( nArg==0 ); |
| 257279 | UNUSED_PARAM2(nArg, apUnused); |
| 257280 | sqlite3_result_text(pCtx, "fts5: 2025-05-15 11:20:54 336ceeccc6f85bd78f4a26648af7edf9056d569a767b4120f125a02b2090a349", -1, SQLITE_TRANSIENT); |
| 257281 | } |
| 257282 | |
| 257283 | /* |
| 257284 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 257285 | ** |
| 257286 |
+6
-5
| --- extsrc/sqlite3.h | ||
| +++ extsrc/sqlite3.h | ||
| @@ -146,11 +146,11 @@ | ||
| 146 | 146 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 147 | 147 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 148 | 148 | */ |
| 149 | 149 | #define SQLITE_VERSION "3.50.0" |
| 150 | 150 | #define SQLITE_VERSION_NUMBER 3050000 |
| 151 | -#define SQLITE_SOURCE_ID "2025-04-15 21:59:38 d22475b81c4e26ccc50f3b5626d43b32f7a2de34e5a764539554665bdda735d5" | |
| 151 | +#define SQLITE_SOURCE_ID "2025-05-15 11:20:54 336ceeccc6f85bd78f4a26648af7edf9056d569a767b4120f125a02b2090a349" | |
| 152 | 152 | |
| 153 | 153 | /* |
| 154 | 154 | ** CAPI3REF: Run-Time Library Version Numbers |
| 155 | 155 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 156 | 156 | ** |
| @@ -11553,13 +11553,14 @@ | ||
| 11553 | 11553 | ** This may appear to have some counter-intuitive effects if a single row |
| 11554 | 11554 | ** is written to more than once during a session. For example, if a row |
| 11555 | 11555 | ** is inserted while a session object is enabled, then later deleted while |
| 11556 | 11556 | ** the same session object is disabled, no INSERT record will appear in the |
| 11557 | 11557 | ** changeset, even though the delete took place while the session was disabled. |
| 11558 | -** Or, if one field of a row is updated while a session is disabled, and | |
| 11559 | -** another field of the same row is updated while the session is enabled, the | |
| 11560 | -** resulting changeset will contain an UPDATE change that updates both fields. | |
| 11558 | +** Or, if one field of a row is updated while a session is enabled, and | |
| 11559 | +** then another field of the same row is updated while the session is disabled, | |
| 11560 | +** the resulting changeset will contain an UPDATE change that updates both | |
| 11561 | +** fields. | |
| 11561 | 11562 | */ |
| 11562 | 11563 | SQLITE_API int sqlite3session_changeset( |
| 11563 | 11564 | sqlite3_session *pSession, /* Session object */ |
| 11564 | 11565 | int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ |
| 11565 | 11566 | void **ppChangeset /* OUT: Buffer containing changeset */ |
| @@ -11764,11 +11765,11 @@ | ||
| 11764 | 11765 | ** CAPI3REF: Flags for sqlite3changeset_start_v2 |
| 11765 | 11766 | ** |
| 11766 | 11767 | ** The following flags may passed via the 4th parameter to |
| 11767 | 11768 | ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: |
| 11768 | 11769 | ** |
| 11769 | -** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd> | |
| 11770 | +** <dt>SQLITE_CHANGESETSTART_INVERT <dd> | |
| 11770 | 11771 | ** Invert the changeset while iterating through it. This is equivalent to |
| 11771 | 11772 | ** inverting a changeset using sqlite3changeset_invert() before applying it. |
| 11772 | 11773 | ** It is an error to specify this flag with a patchset. |
| 11773 | 11774 | */ |
| 11774 | 11775 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 |
| 11775 | 11776 |
| --- extsrc/sqlite3.h | |
| +++ extsrc/sqlite3.h | |
| @@ -146,11 +146,11 @@ | |
| 146 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 147 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 148 | */ |
| 149 | #define SQLITE_VERSION "3.50.0" |
| 150 | #define SQLITE_VERSION_NUMBER 3050000 |
| 151 | #define SQLITE_SOURCE_ID "2025-04-15 21:59:38 d22475b81c4e26ccc50f3b5626d43b32f7a2de34e5a764539554665bdda735d5" |
| 152 | |
| 153 | /* |
| 154 | ** CAPI3REF: Run-Time Library Version Numbers |
| 155 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 156 | ** |
| @@ -11553,13 +11553,14 @@ | |
| 11553 | ** This may appear to have some counter-intuitive effects if a single row |
| 11554 | ** is written to more than once during a session. For example, if a row |
| 11555 | ** is inserted while a session object is enabled, then later deleted while |
| 11556 | ** the same session object is disabled, no INSERT record will appear in the |
| 11557 | ** changeset, even though the delete took place while the session was disabled. |
| 11558 | ** Or, if one field of a row is updated while a session is disabled, and |
| 11559 | ** another field of the same row is updated while the session is enabled, the |
| 11560 | ** resulting changeset will contain an UPDATE change that updates both fields. |
| 11561 | */ |
| 11562 | SQLITE_API int sqlite3session_changeset( |
| 11563 | sqlite3_session *pSession, /* Session object */ |
| 11564 | int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ |
| 11565 | void **ppChangeset /* OUT: Buffer containing changeset */ |
| @@ -11764,11 +11765,11 @@ | |
| 11764 | ** CAPI3REF: Flags for sqlite3changeset_start_v2 |
| 11765 | ** |
| 11766 | ** The following flags may passed via the 4th parameter to |
| 11767 | ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: |
| 11768 | ** |
| 11769 | ** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd> |
| 11770 | ** Invert the changeset while iterating through it. This is equivalent to |
| 11771 | ** inverting a changeset using sqlite3changeset_invert() before applying it. |
| 11772 | ** It is an error to specify this flag with a patchset. |
| 11773 | */ |
| 11774 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 |
| 11775 |
| --- extsrc/sqlite3.h | |
| +++ extsrc/sqlite3.h | |
| @@ -146,11 +146,11 @@ | |
| 146 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 147 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 148 | */ |
| 149 | #define SQLITE_VERSION "3.50.0" |
| 150 | #define SQLITE_VERSION_NUMBER 3050000 |
| 151 | #define SQLITE_SOURCE_ID "2025-05-15 11:20:54 336ceeccc6f85bd78f4a26648af7edf9056d569a767b4120f125a02b2090a349" |
| 152 | |
| 153 | /* |
| 154 | ** CAPI3REF: Run-Time Library Version Numbers |
| 155 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 156 | ** |
| @@ -11553,13 +11553,14 @@ | |
| 11553 | ** This may appear to have some counter-intuitive effects if a single row |
| 11554 | ** is written to more than once during a session. For example, if a row |
| 11555 | ** is inserted while a session object is enabled, then later deleted while |
| 11556 | ** the same session object is disabled, no INSERT record will appear in the |
| 11557 | ** changeset, even though the delete took place while the session was disabled. |
| 11558 | ** Or, if one field of a row is updated while a session is enabled, and |
| 11559 | ** then another field of the same row is updated while the session is disabled, |
| 11560 | ** the resulting changeset will contain an UPDATE change that updates both |
| 11561 | ** fields. |
| 11562 | */ |
| 11563 | SQLITE_API int sqlite3session_changeset( |
| 11564 | sqlite3_session *pSession, /* Session object */ |
| 11565 | int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ |
| 11566 | void **ppChangeset /* OUT: Buffer containing changeset */ |
| @@ -11764,11 +11765,11 @@ | |
| 11765 | ** CAPI3REF: Flags for sqlite3changeset_start_v2 |
| 11766 | ** |
| 11767 | ** The following flags may passed via the 4th parameter to |
| 11768 | ** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: |
| 11769 | ** |
| 11770 | ** <dt>SQLITE_CHANGESETSTART_INVERT <dd> |
| 11771 | ** Invert the changeset while iterating through it. This is equivalent to |
| 11772 | ** inverting a changeset using sqlite3changeset_invert() before applying it. |
| 11773 | ** It is an error to specify this flag with a patchset. |
| 11774 | */ |
| 11775 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 |
| 11776 |
+1
-1
| --- src/ajax.c | ||
| +++ src/ajax.c | ||
| @@ -307,11 +307,11 @@ | ||
| 307 | 307 | Blob content = empty_blob; |
| 308 | 308 | const char * zRenderMode = 0; |
| 309 | 309 | |
| 310 | 310 | ajax_get_fnci_args( &zFilename, 0 ); |
| 311 | 311 | |
| 312 | - if(!ajax_route_bootstrap(1,1)){ | |
| 312 | + if(!ajax_route_bootstrap(0,1)){ | |
| 313 | 313 | return; |
| 314 | 314 | } |
| 315 | 315 | if(zFilename==0){ |
| 316 | 316 | /* The filename is only used for mimetype determination, |
| 317 | 317 | ** so we can default it... */ |
| 318 | 318 |
| --- src/ajax.c | |
| +++ src/ajax.c | |
| @@ -307,11 +307,11 @@ | |
| 307 | Blob content = empty_blob; |
| 308 | const char * zRenderMode = 0; |
| 309 | |
| 310 | ajax_get_fnci_args( &zFilename, 0 ); |
| 311 | |
| 312 | if(!ajax_route_bootstrap(1,1)){ |
| 313 | return; |
| 314 | } |
| 315 | if(zFilename==0){ |
| 316 | /* The filename is only used for mimetype determination, |
| 317 | ** so we can default it... */ |
| 318 |
| --- src/ajax.c | |
| +++ src/ajax.c | |
| @@ -307,11 +307,11 @@ | |
| 307 | Blob content = empty_blob; |
| 308 | const char * zRenderMode = 0; |
| 309 | |
| 310 | ajax_get_fnci_args( &zFilename, 0 ); |
| 311 | |
| 312 | if(!ajax_route_bootstrap(0,1)){ |
| 313 | return; |
| 314 | } |
| 315 | if(zFilename==0){ |
| 316 | /* The filename is only used for mimetype determination, |
| 317 | ** so we can default it... */ |
| 318 |
+1
-1
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -2661,11 +2661,11 @@ | ||
| 2661 | 2661 | listen4 = socket(AF_INET, SOCK_STREAM, 0); |
| 2662 | 2662 | if( listen4>0 ){ |
| 2663 | 2663 | setsockopt(listen4, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); |
| 2664 | 2664 | rc = bind(listen4, (struct sockaddr*)&inaddr4, sizeof(inaddr4)); |
| 2665 | 2665 | if( rc<0 ){ |
| 2666 | - close(listen6); | |
| 2666 | + close(listen4); | |
| 2667 | 2667 | listen4 = -1; |
| 2668 | 2668 | } |
| 2669 | 2669 | } |
| 2670 | 2670 | if( listen4<0 ){ |
| 2671 | 2671 | fossil_fatal("cannot open a listening socket on %s:%d", |
| 2672 | 2672 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -2661,11 +2661,11 @@ | |
| 2661 | listen4 = socket(AF_INET, SOCK_STREAM, 0); |
| 2662 | if( listen4>0 ){ |
| 2663 | setsockopt(listen4, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); |
| 2664 | rc = bind(listen4, (struct sockaddr*)&inaddr4, sizeof(inaddr4)); |
| 2665 | if( rc<0 ){ |
| 2666 | close(listen6); |
| 2667 | listen4 = -1; |
| 2668 | } |
| 2669 | } |
| 2670 | if( listen4<0 ){ |
| 2671 | fossil_fatal("cannot open a listening socket on %s:%d", |
| 2672 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -2661,11 +2661,11 @@ | |
| 2661 | listen4 = socket(AF_INET, SOCK_STREAM, 0); |
| 2662 | if( listen4>0 ){ |
| 2663 | setsockopt(listen4, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); |
| 2664 | rc = bind(listen4, (struct sockaddr*)&inaddr4, sizeof(inaddr4)); |
| 2665 | if( rc<0 ){ |
| 2666 | close(listen4); |
| 2667 | listen4 = -1; |
| 2668 | } |
| 2669 | } |
| 2670 | if( listen4<0 ){ |
| 2671 | fossil_fatal("cannot open a listening socket on %s:%d", |
| 2672 |
+4
-2
| --- src/clone.c | ||
| +++ src/clone.c | ||
| @@ -430,12 +430,14 @@ | ||
| 430 | 430 | const char *zNm = db_get("short-project-name","download"); |
| 431 | 431 | char *zUrl = href("%R/zip/%t/%t.zip", zDLTag, zNm); |
| 432 | 432 | @ <p>ZIP Archive: %z(zUrl)%h(zNm).zip</a> |
| 433 | 433 | zUrl = href("%R/tarball/%t/%t.tar.gz", zDLTag, zNm); |
| 434 | 434 | @ <p>Tarball: %z(zUrl)%h(zNm).tar.gz</a> |
| 435 | - zUrl = href("%R/sqlar/%t/%t.sqlar", zDLTag, zNm); | |
| 436 | - @ <p>SQLite Archive: %z(zUrl)%h(zNm).sqlar</a> | |
| 435 | + if( g.zLogin!=0 ){ | |
| 436 | + zUrl = href("%R/sqlar/%t/%t.sqlar", zDLTag, zNm); | |
| 437 | + @ <p>SQLite Archive: %z(zUrl)%h(zNm).sqlar</a> | |
| 438 | + } | |
| 437 | 439 | } |
| 438 | 440 | if( !g.perm.Clone ){ |
| 439 | 441 | @ <p>You are not authorized to clone this repository. |
| 440 | 442 | if( g.zLogin==0 || g.zLogin[0]==0 ){ |
| 441 | 443 | @ Maybe you would be able to clone if you |
| 442 | 444 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -430,12 +430,14 @@ | |
| 430 | const char *zNm = db_get("short-project-name","download"); |
| 431 | char *zUrl = href("%R/zip/%t/%t.zip", zDLTag, zNm); |
| 432 | @ <p>ZIP Archive: %z(zUrl)%h(zNm).zip</a> |
| 433 | zUrl = href("%R/tarball/%t/%t.tar.gz", zDLTag, zNm); |
| 434 | @ <p>Tarball: %z(zUrl)%h(zNm).tar.gz</a> |
| 435 | zUrl = href("%R/sqlar/%t/%t.sqlar", zDLTag, zNm); |
| 436 | @ <p>SQLite Archive: %z(zUrl)%h(zNm).sqlar</a> |
| 437 | } |
| 438 | if( !g.perm.Clone ){ |
| 439 | @ <p>You are not authorized to clone this repository. |
| 440 | if( g.zLogin==0 || g.zLogin[0]==0 ){ |
| 441 | @ Maybe you would be able to clone if you |
| 442 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -430,12 +430,14 @@ | |
| 430 | const char *zNm = db_get("short-project-name","download"); |
| 431 | char *zUrl = href("%R/zip/%t/%t.zip", zDLTag, zNm); |
| 432 | @ <p>ZIP Archive: %z(zUrl)%h(zNm).zip</a> |
| 433 | zUrl = href("%R/tarball/%t/%t.tar.gz", zDLTag, zNm); |
| 434 | @ <p>Tarball: %z(zUrl)%h(zNm).tar.gz</a> |
| 435 | if( g.zLogin!=0 ){ |
| 436 | zUrl = href("%R/sqlar/%t/%t.sqlar", zDLTag, zNm); |
| 437 | @ <p>SQLite Archive: %z(zUrl)%h(zNm).sqlar</a> |
| 438 | } |
| 439 | } |
| 440 | if( !g.perm.Clone ){ |
| 441 | @ <p>You are not authorized to clone this repository. |
| 442 | if( g.zLogin==0 || g.zLogin[0]==0 ){ |
| 443 | @ Maybe you would be able to clone if you |
| 444 |
M
src/db.c
+1
-1
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -4758,11 +4758,11 @@ | ||
| 4758 | 4758 | ** SETTING: comment-format width=16 default=1 |
| 4759 | 4759 | ** Set the algorithm for printing timeline comments to the console. |
| 4760 | 4760 | ** |
| 4761 | 4761 | ** Possible values are: |
| 4762 | 4762 | ** 1 Use the original comment printing algorithm: |
| 4763 | -** * Leading and trialing whitespace is removed | |
| 4763 | +** * Leading and trailing whitespace is removed | |
| 4764 | 4764 | ** * Internal whitespace is converted into a single space (0x20) |
| 4765 | 4765 | ** * Line breaks occurs at whitespace or hyphens if possible |
| 4766 | 4766 | ** This is the recommended value and the default. |
| 4767 | 4767 | ** |
| 4768 | 4768 | ** Or a bitwise combination of the following flags: |
| 4769 | 4769 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -4758,11 +4758,11 @@ | |
| 4758 | ** SETTING: comment-format width=16 default=1 |
| 4759 | ** Set the algorithm for printing timeline comments to the console. |
| 4760 | ** |
| 4761 | ** Possible values are: |
| 4762 | ** 1 Use the original comment printing algorithm: |
| 4763 | ** * Leading and trialing whitespace is removed |
| 4764 | ** * Internal whitespace is converted into a single space (0x20) |
| 4765 | ** * Line breaks occurs at whitespace or hyphens if possible |
| 4766 | ** This is the recommended value and the default. |
| 4767 | ** |
| 4768 | ** Or a bitwise combination of the following flags: |
| 4769 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -4758,11 +4758,11 @@ | |
| 4758 | ** SETTING: comment-format width=16 default=1 |
| 4759 | ** Set the algorithm for printing timeline comments to the console. |
| 4760 | ** |
| 4761 | ** Possible values are: |
| 4762 | ** 1 Use the original comment printing algorithm: |
| 4763 | ** * Leading and trailing whitespace is removed |
| 4764 | ** * Internal whitespace is converted into a single space (0x20) |
| 4765 | ** * Line breaks occurs at whitespace or hyphens if possible |
| 4766 | ** This is the recommended value and the default. |
| 4767 | ** |
| 4768 | ** Or a bitwise combination of the following flags: |
| 4769 |
+7
-1
| --- src/diff.tcl | ||
| +++ src/diff.tcl | ||
| @@ -500,10 +500,12 @@ | ||
| 500 | 500 | if {$fn==""} return |
| 501 | 501 | set out [open $fn wb] |
| 502 | 502 | puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'" |
| 503 | 503 | puts $out "# to see the graphical diff.\n#" |
| 504 | 504 | puts $out "set fossilcmd {}" |
| 505 | + puts $out "set darkmode $::darkmode" | |
| 506 | + puts $out "set debug $::debug" | |
| 505 | 507 | puts $out "set prog [list $::prog]" |
| 506 | 508 | puts $out "set difftxt \173" |
| 507 | 509 | foreach e $::difftxt {puts $out [list $e]} |
| 508 | 510 | puts $out "\175" |
| 509 | 511 | puts $out "eval \$prog" |
| @@ -606,11 +608,15 @@ | ||
| 606 | 608 | ::ttk::button .bb.quit -text {Quit} -command exit |
| 607 | 609 | ::ttk::button .bb.reload -text {Reload} -command reloadDiff |
| 608 | 610 | ::ttk::button .bb.invert -text {Invert} -command invertDiff |
| 609 | 611 | ::ttk::button .bb.save -text {Save As...} -command saveDiff |
| 610 | 612 | ::ttk::button .bb.search -text {Search} -command searchOnOff |
| 611 | -pack .bb.quit .bb.reload .bb.invert -side left | |
| 613 | +pack .bb.quit -side left | |
| 614 | +if {$fossilcmd ne ""} { | |
| 615 | + pack .bb.reload -side left | |
| 616 | +} | |
| 617 | +pack .bb.invert -side left | |
| 612 | 618 | if {$fossilcmd!=""} {pack .bb.save -side left} |
| 613 | 619 | pack .bb.files .bb.search -side left |
| 614 | 620 | grid rowconfigure . 1 -weight 1 |
| 615 | 621 | grid columnconfigure . 1 -weight 1 |
| 616 | 622 | grid columnconfigure . 4 -weight 1 |
| 617 | 623 |
| --- src/diff.tcl | |
| +++ src/diff.tcl | |
| @@ -500,10 +500,12 @@ | |
| 500 | if {$fn==""} return |
| 501 | set out [open $fn wb] |
| 502 | puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'" |
| 503 | puts $out "# to see the graphical diff.\n#" |
| 504 | puts $out "set fossilcmd {}" |
| 505 | puts $out "set prog [list $::prog]" |
| 506 | puts $out "set difftxt \173" |
| 507 | foreach e $::difftxt {puts $out [list $e]} |
| 508 | puts $out "\175" |
| 509 | puts $out "eval \$prog" |
| @@ -606,11 +608,15 @@ | |
| 606 | ::ttk::button .bb.quit -text {Quit} -command exit |
| 607 | ::ttk::button .bb.reload -text {Reload} -command reloadDiff |
| 608 | ::ttk::button .bb.invert -text {Invert} -command invertDiff |
| 609 | ::ttk::button .bb.save -text {Save As...} -command saveDiff |
| 610 | ::ttk::button .bb.search -text {Search} -command searchOnOff |
| 611 | pack .bb.quit .bb.reload .bb.invert -side left |
| 612 | if {$fossilcmd!=""} {pack .bb.save -side left} |
| 613 | pack .bb.files .bb.search -side left |
| 614 | grid rowconfigure . 1 -weight 1 |
| 615 | grid columnconfigure . 1 -weight 1 |
| 616 | grid columnconfigure . 4 -weight 1 |
| 617 |
| --- src/diff.tcl | |
| +++ src/diff.tcl | |
| @@ -500,10 +500,12 @@ | |
| 500 | if {$fn==""} return |
| 501 | set out [open $fn wb] |
| 502 | puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'" |
| 503 | puts $out "# to see the graphical diff.\n#" |
| 504 | puts $out "set fossilcmd {}" |
| 505 | puts $out "set darkmode $::darkmode" |
| 506 | puts $out "set debug $::debug" |
| 507 | puts $out "set prog [list $::prog]" |
| 508 | puts $out "set difftxt \173" |
| 509 | foreach e $::difftxt {puts $out [list $e]} |
| 510 | puts $out "\175" |
| 511 | puts $out "eval \$prog" |
| @@ -606,11 +608,15 @@ | |
| 608 | ::ttk::button .bb.quit -text {Quit} -command exit |
| 609 | ::ttk::button .bb.reload -text {Reload} -command reloadDiff |
| 610 | ::ttk::button .bb.invert -text {Invert} -command invertDiff |
| 611 | ::ttk::button .bb.save -text {Save As...} -command saveDiff |
| 612 | ::ttk::button .bb.search -text {Search} -command searchOnOff |
| 613 | pack .bb.quit -side left |
| 614 | if {$fossilcmd ne ""} { |
| 615 | pack .bb.reload -side left |
| 616 | } |
| 617 | pack .bb.invert -side left |
| 618 | if {$fossilcmd!=""} {pack .bb.save -side left} |
| 619 | pack .bb.files .bb.search -side left |
| 620 | grid rowconfigure . 1 -weight 1 |
| 621 | grid columnconfigure . 1 -weight 1 |
| 622 | grid columnconfigure . 4 -weight 1 |
| 623 |
+2
-1
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -52,11 +52,12 @@ | ||
| 52 | 52 | ** Construct the "login" card with the client credentials. |
| 53 | 53 | ** |
| 54 | 54 | ** login LOGIN NONCE SIGNATURE |
| 55 | 55 | ** |
| 56 | 56 | ** The LOGIN is the user id of the client. NONCE is the sha1 checksum |
| 57 | -** of all payload that follows the login card. SIGNATURE is the sha1 | |
| 57 | +** of all payload that follows the login card. Randomness for the NONCE | |
| 58 | +** must be provided in the payload (in xfer.c). SIGNATURE is the sha1 | |
| 58 | 59 | ** checksum of the nonce followed by the user password. |
| 59 | 60 | ** |
| 60 | 61 | ** Write the constructed login card into pLogin. pLogin is initialized |
| 61 | 62 | ** by this routine. |
| 62 | 63 | */ |
| 63 | 64 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -52,11 +52,12 @@ | |
| 52 | ** Construct the "login" card with the client credentials. |
| 53 | ** |
| 54 | ** login LOGIN NONCE SIGNATURE |
| 55 | ** |
| 56 | ** The LOGIN is the user id of the client. NONCE is the sha1 checksum |
| 57 | ** of all payload that follows the login card. SIGNATURE is the sha1 |
| 58 | ** checksum of the nonce followed by the user password. |
| 59 | ** |
| 60 | ** Write the constructed login card into pLogin. pLogin is initialized |
| 61 | ** by this routine. |
| 62 | */ |
| 63 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -52,11 +52,12 @@ | |
| 52 | ** Construct the "login" card with the client credentials. |
| 53 | ** |
| 54 | ** login LOGIN NONCE SIGNATURE |
| 55 | ** |
| 56 | ** The LOGIN is the user id of the client. NONCE is the sha1 checksum |
| 57 | ** of all payload that follows the login card. Randomness for the NONCE |
| 58 | ** must be provided in the payload (in xfer.c). SIGNATURE is the sha1 |
| 59 | ** checksum of the nonce followed by the user password. |
| 60 | ** |
| 61 | ** Write the constructed login card into pLogin. pLogin is initialized |
| 62 | ** by this routine. |
| 63 | */ |
| 64 |
+6
-2
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -993,12 +993,14 @@ | ||
| 993 | 993 | } |
| 994 | 994 | zUrl = mprintf("%R/tarball/%S/%t-%S.tar.gz", zUuid, zPJ, zUuid); |
| 995 | 995 | @ <tr><th>Downloads:</th><td> |
| 996 | 996 | @ %z(href("%s",zUrl))Tarball</a> |
| 997 | 997 | @ | %z(href("%R/zip/%S/%t-%S.zip",zUuid, zPJ,zUuid))ZIP archive</a> |
| 998 | - @ | %z(href("%R/sqlar/%S/%t-%S.sqlar",zUuid,zPJ,zUuid))\ | |
| 999 | - @ SQL archive</a></td></tr> | |
| 998 | + if( g.zLogin!=0 ){ | |
| 999 | + @ | %z(href("%R/sqlar/%S/%t-%S.sqlar",zUuid,zPJ,zUuid))\ | |
| 1000 | + @ SQL archive</a></td></tr> | |
| 1001 | + } | |
| 1000 | 1002 | fossil_free(zUrl); |
| 1001 | 1003 | blob_reset(&projName); |
| 1002 | 1004 | } |
| 1003 | 1005 | |
| 1004 | 1006 | @ <tr><th>Timelines:</th><td> |
| @@ -3930,10 +3932,11 @@ | ||
| 3930 | 3932 | ** --cancel TAG Cancel TAG from this check-in |
| 3931 | 3933 | ** --close Mark this "leaf" as closed |
| 3932 | 3934 | ** --date DATETIME Make DATETIME the check-in time |
| 3933 | 3935 | ** --date-override DATETIME Set the change time on the control artifact |
| 3934 | 3936 | ** -e|--edit-comment Launch editor to revise comment |
| 3937 | +** --editor NAME Text editor to use for check-in comment | |
| 3935 | 3938 | ** --hide Hide branch starting from this check-in |
| 3936 | 3939 | ** -m|--comment COMMENT Make COMMENT the check-in comment |
| 3937 | 3940 | ** -M|--message-file FILE Read the amended comment from FILE |
| 3938 | 3941 | ** -n|--dry-run Print control artifact, but make no changes |
| 3939 | 3942 | ** --no-verify-comment Do not validate the check-in comment |
| @@ -4003,10 +4006,11 @@ | ||
| 4003 | 4006 | if( zChngTime==0 ) zChngTime = find_option("chngtime",0,1); |
| 4004 | 4007 | zUserOvrd = find_option("user-override",0,1); |
| 4005 | 4008 | noVerifyCom = find_option("no-verify-comment",0,0)!=0; |
| 4006 | 4009 | db_find_and_open_repository(0,0); |
| 4007 | 4010 | user_select(); |
| 4011 | + (void)fossil_text_editor(); | |
| 4008 | 4012 | verify_all_options(); |
| 4009 | 4013 | if( g.argc<3 || g.argc>=4 ) usage(AMEND_USAGE_STMT); |
| 4010 | 4014 | rid = name_to_typed_rid(g.argv[2], "ci"); |
| 4011 | 4015 | if( rid==0 && !is_a_version(rid) ) fossil_fatal("no such check-in"); |
| 4012 | 4016 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 4013 | 4017 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -993,12 +993,14 @@ | |
| 993 | } |
| 994 | zUrl = mprintf("%R/tarball/%S/%t-%S.tar.gz", zUuid, zPJ, zUuid); |
| 995 | @ <tr><th>Downloads:</th><td> |
| 996 | @ %z(href("%s",zUrl))Tarball</a> |
| 997 | @ | %z(href("%R/zip/%S/%t-%S.zip",zUuid, zPJ,zUuid))ZIP archive</a> |
| 998 | @ | %z(href("%R/sqlar/%S/%t-%S.sqlar",zUuid,zPJ,zUuid))\ |
| 999 | @ SQL archive</a></td></tr> |
| 1000 | fossil_free(zUrl); |
| 1001 | blob_reset(&projName); |
| 1002 | } |
| 1003 | |
| 1004 | @ <tr><th>Timelines:</th><td> |
| @@ -3930,10 +3932,11 @@ | |
| 3930 | ** --cancel TAG Cancel TAG from this check-in |
| 3931 | ** --close Mark this "leaf" as closed |
| 3932 | ** --date DATETIME Make DATETIME the check-in time |
| 3933 | ** --date-override DATETIME Set the change time on the control artifact |
| 3934 | ** -e|--edit-comment Launch editor to revise comment |
| 3935 | ** --hide Hide branch starting from this check-in |
| 3936 | ** -m|--comment COMMENT Make COMMENT the check-in comment |
| 3937 | ** -M|--message-file FILE Read the amended comment from FILE |
| 3938 | ** -n|--dry-run Print control artifact, but make no changes |
| 3939 | ** --no-verify-comment Do not validate the check-in comment |
| @@ -4003,10 +4006,11 @@ | |
| 4003 | if( zChngTime==0 ) zChngTime = find_option("chngtime",0,1); |
| 4004 | zUserOvrd = find_option("user-override",0,1); |
| 4005 | noVerifyCom = find_option("no-verify-comment",0,0)!=0; |
| 4006 | db_find_and_open_repository(0,0); |
| 4007 | user_select(); |
| 4008 | verify_all_options(); |
| 4009 | if( g.argc<3 || g.argc>=4 ) usage(AMEND_USAGE_STMT); |
| 4010 | rid = name_to_typed_rid(g.argv[2], "ci"); |
| 4011 | if( rid==0 && !is_a_version(rid) ) fossil_fatal("no such check-in"); |
| 4012 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 4013 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -993,12 +993,14 @@ | |
| 993 | } |
| 994 | zUrl = mprintf("%R/tarball/%S/%t-%S.tar.gz", zUuid, zPJ, zUuid); |
| 995 | @ <tr><th>Downloads:</th><td> |
| 996 | @ %z(href("%s",zUrl))Tarball</a> |
| 997 | @ | %z(href("%R/zip/%S/%t-%S.zip",zUuid, zPJ,zUuid))ZIP archive</a> |
| 998 | if( g.zLogin!=0 ){ |
| 999 | @ | %z(href("%R/sqlar/%S/%t-%S.sqlar",zUuid,zPJ,zUuid))\ |
| 1000 | @ SQL archive</a></td></tr> |
| 1001 | } |
| 1002 | fossil_free(zUrl); |
| 1003 | blob_reset(&projName); |
| 1004 | } |
| 1005 | |
| 1006 | @ <tr><th>Timelines:</th><td> |
| @@ -3930,10 +3932,11 @@ | |
| 3932 | ** --cancel TAG Cancel TAG from this check-in |
| 3933 | ** --close Mark this "leaf" as closed |
| 3934 | ** --date DATETIME Make DATETIME the check-in time |
| 3935 | ** --date-override DATETIME Set the change time on the control artifact |
| 3936 | ** -e|--edit-comment Launch editor to revise comment |
| 3937 | ** --editor NAME Text editor to use for check-in comment |
| 3938 | ** --hide Hide branch starting from this check-in |
| 3939 | ** -m|--comment COMMENT Make COMMENT the check-in comment |
| 3940 | ** -M|--message-file FILE Read the amended comment from FILE |
| 3941 | ** -n|--dry-run Print control artifact, but make no changes |
| 3942 | ** --no-verify-comment Do not validate the check-in comment |
| @@ -4003,10 +4006,11 @@ | |
| 4006 | if( zChngTime==0 ) zChngTime = find_option("chngtime",0,1); |
| 4007 | zUserOvrd = find_option("user-override",0,1); |
| 4008 | noVerifyCom = find_option("no-verify-comment",0,0)!=0; |
| 4009 | db_find_and_open_repository(0,0); |
| 4010 | user_select(); |
| 4011 | (void)fossil_text_editor(); |
| 4012 | verify_all_options(); |
| 4013 | if( g.argc<3 || g.argc>=4 ) usage(AMEND_USAGE_STMT); |
| 4014 | rid = name_to_typed_rid(g.argv[2], "ci"); |
| 4015 | if( rid==0 && !is_a_version(rid) ) fossil_fatal("no such check-in"); |
| 4016 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 4017 |
+15
-7
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -579,39 +579,41 @@ | ||
| 579 | 579 | $(OBJDIR)/winfile.o \ |
| 580 | 580 | $(OBJDIR)/winhttp.o \ |
| 581 | 581 | $(OBJDIR)/xfer.o \ |
| 582 | 582 | $(OBJDIR)/xfersetup.o \ |
| 583 | 583 | $(OBJDIR)/zip.o |
| 584 | -all: $(OBJDIR) $(APPNAME) | |
| 584 | +all: $(APPNAME) | |
| 585 | 585 | |
| 586 | 586 | install: all |
| 587 | 587 | mkdir -p $(INSTALLDIR) |
| 588 | 588 | cp $(APPNAME) $(INSTALLDIR) |
| 589 | 589 | |
| 590 | 590 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 591 | 591 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 592 | 592 | |
| 593 | -$(OBJDIR): | |
| 594 | - -mkdir $(OBJDIR) | |
| 595 | - | |
| 596 | 593 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 597 | 594 | -mkdir -p $(OBJDIR) |
| 598 | 595 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 599 | 596 | |
| 600 | 597 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 598 | + -mkdir -p $(OBJDIR) | |
| 601 | 599 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 602 | 600 | |
| 603 | 601 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 602 | + -mkdir -p $(OBJDIR) | |
| 604 | 603 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 605 | 604 | |
| 606 | 605 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 606 | + -mkdir -p $(OBJDIR) | |
| 607 | 607 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 608 | 608 | |
| 609 | 609 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 610 | + -mkdir -p $(OBJDIR) | |
| 610 | 611 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 611 | 612 | |
| 612 | 613 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 614 | + -mkdir -p $(OBJDIR) | |
| 613 | 615 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 614 | 616 | |
| 615 | 617 | # Run the test suite. |
| 616 | 618 | # Other flags that can be included in TESTFLAGS are: |
| 617 | 619 | # |
| @@ -623,11 +625,11 @@ | ||
| 623 | 625 | # -strict Treat known bugs as failures |
| 624 | 626 | # |
| 625 | 627 | # TESTFLAGS can also include names of specific test files to limit |
| 626 | 628 | # the run to just those test cases. |
| 627 | 629 | # |
| 628 | -test: $(OBJDIR) $(APPNAME) | |
| 630 | +test: $(APPNAME) | |
| 629 | 631 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 630 | 632 | |
| 631 | 633 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 632 | 634 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ |
| 633 | 635 | $(SRCDIR)/../manifest \ |
| @@ -2120,23 +2122,29 @@ | ||
| 2120 | 2122 | |
| 2121 | 2123 | $(OBJDIR)/linenoise.o: $(SRCDIR_extsrc)/linenoise.c $(SRCDIR_extsrc)/linenoise.h |
| 2122 | 2124 | $(XTCC) -c $(SRCDIR_extsrc)/linenoise.c -o $@ |
| 2123 | 2125 | |
| 2124 | 2126 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 2127 | + -mkdir -p $(OBJDIR) | |
| 2128 | + | |
| 2125 | 2129 | $(XTCC) -c $(SRCDIR)/th.c -o $@ |
| 2126 | 2130 | |
| 2127 | 2131 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 2132 | + -mkdir -p $(OBJDIR) | |
| 2133 | + | |
| 2128 | 2134 | $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ |
| 2129 | 2135 | |
| 2130 | 2136 | $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c |
| 2137 | + -mkdir -p $(OBJDIR) | |
| 2138 | + | |
| 2131 | 2139 | $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ |
| 2132 | 2140 | |
| 2133 | 2141 | |
| 2134 | -$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c | |
| 2142 | +$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c $(OBJDIR)/mkversion | |
| 2135 | 2143 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2136 | 2144 | |
| 2137 | -$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c | |
| 2145 | +$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c $(OBJDIR)/mkversion | |
| 2138 | 2146 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2139 | 2147 | |
| 2140 | 2148 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 2141 | 2149 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \ |
| 2142 | 2150 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore \ |
| 2143 | 2151 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -579,39 +579,41 @@ | |
| 579 | $(OBJDIR)/winfile.o \ |
| 580 | $(OBJDIR)/winhttp.o \ |
| 581 | $(OBJDIR)/xfer.o \ |
| 582 | $(OBJDIR)/xfersetup.o \ |
| 583 | $(OBJDIR)/zip.o |
| 584 | all: $(OBJDIR) $(APPNAME) |
| 585 | |
| 586 | install: all |
| 587 | mkdir -p $(INSTALLDIR) |
| 588 | cp $(APPNAME) $(INSTALLDIR) |
| 589 | |
| 590 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 591 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 592 | |
| 593 | $(OBJDIR): |
| 594 | -mkdir $(OBJDIR) |
| 595 | |
| 596 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 597 | -mkdir -p $(OBJDIR) |
| 598 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 599 | |
| 600 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 601 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 602 | |
| 603 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 604 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 605 | |
| 606 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 607 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 608 | |
| 609 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 610 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 611 | |
| 612 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 613 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 614 | |
| 615 | # Run the test suite. |
| 616 | # Other flags that can be included in TESTFLAGS are: |
| 617 | # |
| @@ -623,11 +625,11 @@ | |
| 623 | # -strict Treat known bugs as failures |
| 624 | # |
| 625 | # TESTFLAGS can also include names of specific test files to limit |
| 626 | # the run to just those test cases. |
| 627 | # |
| 628 | test: $(OBJDIR) $(APPNAME) |
| 629 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 630 | |
| 631 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 632 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ |
| 633 | $(SRCDIR)/../manifest \ |
| @@ -2120,23 +2122,29 @@ | |
| 2120 | |
| 2121 | $(OBJDIR)/linenoise.o: $(SRCDIR_extsrc)/linenoise.c $(SRCDIR_extsrc)/linenoise.h |
| 2122 | $(XTCC) -c $(SRCDIR_extsrc)/linenoise.c -o $@ |
| 2123 | |
| 2124 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 2125 | $(XTCC) -c $(SRCDIR)/th.c -o $@ |
| 2126 | |
| 2127 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 2128 | $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ |
| 2129 | |
| 2130 | $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c |
| 2131 | $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ |
| 2132 | |
| 2133 | |
| 2134 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c |
| 2135 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2136 | |
| 2137 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 2138 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2139 | |
| 2140 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 2141 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \ |
| 2142 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore \ |
| 2143 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -579,39 +579,41 @@ | |
| 579 | $(OBJDIR)/winfile.o \ |
| 580 | $(OBJDIR)/winhttp.o \ |
| 581 | $(OBJDIR)/xfer.o \ |
| 582 | $(OBJDIR)/xfersetup.o \ |
| 583 | $(OBJDIR)/zip.o |
| 584 | all: $(APPNAME) |
| 585 | |
| 586 | install: all |
| 587 | mkdir -p $(INSTALLDIR) |
| 588 | cp $(APPNAME) $(INSTALLDIR) |
| 589 | |
| 590 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 591 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 592 | |
| 593 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 594 | -mkdir -p $(OBJDIR) |
| 595 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 596 | |
| 597 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 598 | -mkdir -p $(OBJDIR) |
| 599 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 600 | |
| 601 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 602 | -mkdir -p $(OBJDIR) |
| 603 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 604 | |
| 605 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 606 | -mkdir -p $(OBJDIR) |
| 607 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 608 | |
| 609 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 610 | -mkdir -p $(OBJDIR) |
| 611 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 612 | |
| 613 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 614 | -mkdir -p $(OBJDIR) |
| 615 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 616 | |
| 617 | # Run the test suite. |
| 618 | # Other flags that can be included in TESTFLAGS are: |
| 619 | # |
| @@ -623,11 +625,11 @@ | |
| 625 | # -strict Treat known bugs as failures |
| 626 | # |
| 627 | # TESTFLAGS can also include names of specific test files to limit |
| 628 | # the run to just those test cases. |
| 629 | # |
| 630 | test: $(APPNAME) |
| 631 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 632 | |
| 633 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 634 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ |
| 635 | $(SRCDIR)/../manifest \ |
| @@ -2120,23 +2122,29 @@ | |
| 2122 | |
| 2123 | $(OBJDIR)/linenoise.o: $(SRCDIR_extsrc)/linenoise.c $(SRCDIR_extsrc)/linenoise.h |
| 2124 | $(XTCC) -c $(SRCDIR_extsrc)/linenoise.c -o $@ |
| 2125 | |
| 2126 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 2127 | -mkdir -p $(OBJDIR) |
| 2128 | |
| 2129 | $(XTCC) -c $(SRCDIR)/th.c -o $@ |
| 2130 | |
| 2131 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 2132 | -mkdir -p $(OBJDIR) |
| 2133 | |
| 2134 | $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ |
| 2135 | |
| 2136 | $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c |
| 2137 | -mkdir -p $(OBJDIR) |
| 2138 | |
| 2139 | $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ |
| 2140 | |
| 2141 | |
| 2142 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c $(OBJDIR)/mkversion |
| 2143 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2144 | |
| 2145 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c $(OBJDIR)/mkversion |
| 2146 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2147 | |
| 2148 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 2149 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \ |
| 2150 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore \ |
| 2151 |
+15
-7
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -579,39 +579,41 @@ | ||
| 579 | 579 | $(OBJDIR)/winfile.o \ |
| 580 | 580 | $(OBJDIR)/winhttp.o \ |
| 581 | 581 | $(OBJDIR)/xfer.o \ |
| 582 | 582 | $(OBJDIR)/xfersetup.o \ |
| 583 | 583 | $(OBJDIR)/zip.o |
| 584 | -all: $(OBJDIR) $(APPNAME) | |
| 584 | +all: $(APPNAME) | |
| 585 | 585 | |
| 586 | 586 | install: all |
| 587 | 587 | mkdir -p $(INSTALLDIR) |
| 588 | 588 | cp $(APPNAME) $(INSTALLDIR) |
| 589 | 589 | |
| 590 | 590 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 591 | 591 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 592 | 592 | |
| 593 | -$(OBJDIR): | |
| 594 | - -mkdir $(OBJDIR) | |
| 595 | - | |
| 596 | 593 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 597 | 594 | -mkdir -p $(OBJDIR) |
| 598 | 595 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 599 | 596 | |
| 600 | 597 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 598 | + -mkdir -p $(OBJDIR) | |
| 601 | 599 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 602 | 600 | |
| 603 | 601 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 602 | + -mkdir -p $(OBJDIR) | |
| 604 | 603 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 605 | 604 | |
| 606 | 605 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 606 | + -mkdir -p $(OBJDIR) | |
| 607 | 607 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 608 | 608 | |
| 609 | 609 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 610 | + -mkdir -p $(OBJDIR) | |
| 610 | 611 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 611 | 612 | |
| 612 | 613 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 614 | + -mkdir -p $(OBJDIR) | |
| 613 | 615 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 614 | 616 | |
| 615 | 617 | # Run the test suite. |
| 616 | 618 | # Other flags that can be included in TESTFLAGS are: |
| 617 | 619 | # |
| @@ -623,11 +625,11 @@ | ||
| 623 | 625 | # -strict Treat known bugs as failures |
| 624 | 626 | # |
| 625 | 627 | # TESTFLAGS can also include names of specific test files to limit |
| 626 | 628 | # the run to just those test cases. |
| 627 | 629 | # |
| 628 | -test: $(OBJDIR) $(APPNAME) | |
| 630 | +test: $(APPNAME) | |
| 629 | 631 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 630 | 632 | |
| 631 | 633 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 632 | 634 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ |
| 633 | 635 | $(SRCDIR)/../manifest \ |
| @@ -2120,23 +2122,29 @@ | ||
| 2120 | 2122 | |
| 2121 | 2123 | $(OBJDIR)/linenoise.o: $(SRCDIR_extsrc)/linenoise.c $(SRCDIR_extsrc)/linenoise.h |
| 2122 | 2124 | $(XTCC) -c $(SRCDIR_extsrc)/linenoise.c -o $@ |
| 2123 | 2125 | |
| 2124 | 2126 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 2127 | + -mkdir -p $(OBJDIR) | |
| 2128 | + | |
| 2125 | 2129 | $(XTCC) -c $(SRCDIR)/th.c -o $@ |
| 2126 | 2130 | |
| 2127 | 2131 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 2132 | + -mkdir -p $(OBJDIR) | |
| 2133 | + | |
| 2128 | 2134 | $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ |
| 2129 | 2135 | |
| 2130 | 2136 | $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c |
| 2137 | + -mkdir -p $(OBJDIR) | |
| 2138 | + | |
| 2131 | 2139 | $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ |
| 2132 | 2140 | |
| 2133 | 2141 | |
| 2134 | -$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c | |
| 2142 | +$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c $(OBJDIR)/mkversion | |
| 2135 | 2143 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2136 | 2144 | |
| 2137 | -$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c | |
| 2145 | +$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c $(OBJDIR)/mkversion | |
| 2138 | 2146 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2139 | 2147 | |
| 2140 | 2148 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 2141 | 2149 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \ |
| 2142 | 2150 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore \ |
| 2143 | 2151 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -579,39 +579,41 @@ | |
| 579 | $(OBJDIR)/winfile.o \ |
| 580 | $(OBJDIR)/winhttp.o \ |
| 581 | $(OBJDIR)/xfer.o \ |
| 582 | $(OBJDIR)/xfersetup.o \ |
| 583 | $(OBJDIR)/zip.o |
| 584 | all: $(OBJDIR) $(APPNAME) |
| 585 | |
| 586 | install: all |
| 587 | mkdir -p $(INSTALLDIR) |
| 588 | cp $(APPNAME) $(INSTALLDIR) |
| 589 | |
| 590 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 591 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 592 | |
| 593 | $(OBJDIR): |
| 594 | -mkdir $(OBJDIR) |
| 595 | |
| 596 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 597 | -mkdir -p $(OBJDIR) |
| 598 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 599 | |
| 600 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 601 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 602 | |
| 603 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 604 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 605 | |
| 606 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 607 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 608 | |
| 609 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 610 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 611 | |
| 612 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 613 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 614 | |
| 615 | # Run the test suite. |
| 616 | # Other flags that can be included in TESTFLAGS are: |
| 617 | # |
| @@ -623,11 +625,11 @@ | |
| 623 | # -strict Treat known bugs as failures |
| 624 | # |
| 625 | # TESTFLAGS can also include names of specific test files to limit |
| 626 | # the run to just those test cases. |
| 627 | # |
| 628 | test: $(OBJDIR) $(APPNAME) |
| 629 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 630 | |
| 631 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 632 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ |
| 633 | $(SRCDIR)/../manifest \ |
| @@ -2120,23 +2122,29 @@ | |
| 2120 | |
| 2121 | $(OBJDIR)/linenoise.o: $(SRCDIR_extsrc)/linenoise.c $(SRCDIR_extsrc)/linenoise.h |
| 2122 | $(XTCC) -c $(SRCDIR_extsrc)/linenoise.c -o $@ |
| 2123 | |
| 2124 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 2125 | $(XTCC) -c $(SRCDIR)/th.c -o $@ |
| 2126 | |
| 2127 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 2128 | $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ |
| 2129 | |
| 2130 | $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c |
| 2131 | $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ |
| 2132 | |
| 2133 | |
| 2134 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c |
| 2135 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2136 | |
| 2137 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 2138 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2139 | |
| 2140 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 2141 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \ |
| 2142 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore \ |
| 2143 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -579,39 +579,41 @@ | |
| 579 | $(OBJDIR)/winfile.o \ |
| 580 | $(OBJDIR)/winhttp.o \ |
| 581 | $(OBJDIR)/xfer.o \ |
| 582 | $(OBJDIR)/xfersetup.o \ |
| 583 | $(OBJDIR)/zip.o |
| 584 | all: $(APPNAME) |
| 585 | |
| 586 | install: all |
| 587 | mkdir -p $(INSTALLDIR) |
| 588 | cp $(APPNAME) $(INSTALLDIR) |
| 589 | |
| 590 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 591 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 592 | |
| 593 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 594 | -mkdir -p $(OBJDIR) |
| 595 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 596 | |
| 597 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 598 | -mkdir -p $(OBJDIR) |
| 599 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 600 | |
| 601 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 602 | -mkdir -p $(OBJDIR) |
| 603 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 604 | |
| 605 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 606 | -mkdir -p $(OBJDIR) |
| 607 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 608 | |
| 609 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 610 | -mkdir -p $(OBJDIR) |
| 611 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 612 | |
| 613 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 614 | -mkdir -p $(OBJDIR) |
| 615 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 616 | |
| 617 | # Run the test suite. |
| 618 | # Other flags that can be included in TESTFLAGS are: |
| 619 | # |
| @@ -623,11 +625,11 @@ | |
| 625 | # -strict Treat known bugs as failures |
| 626 | # |
| 627 | # TESTFLAGS can also include names of specific test files to limit |
| 628 | # the run to just those test cases. |
| 629 | # |
| 630 | test: $(APPNAME) |
| 631 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 632 | |
| 633 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 634 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ |
| 635 | $(SRCDIR)/../manifest \ |
| @@ -2120,23 +2122,29 @@ | |
| 2122 | |
| 2123 | $(OBJDIR)/linenoise.o: $(SRCDIR_extsrc)/linenoise.c $(SRCDIR_extsrc)/linenoise.h |
| 2124 | $(XTCC) -c $(SRCDIR_extsrc)/linenoise.c -o $@ |
| 2125 | |
| 2126 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 2127 | -mkdir -p $(OBJDIR) |
| 2128 | |
| 2129 | $(XTCC) -c $(SRCDIR)/th.c -o $@ |
| 2130 | |
| 2131 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 2132 | -mkdir -p $(OBJDIR) |
| 2133 | |
| 2134 | $(XTCC) -c $(SRCDIR)/th_lang.c -o $@ |
| 2135 | |
| 2136 | $(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c |
| 2137 | -mkdir -p $(OBJDIR) |
| 2138 | |
| 2139 | $(XTCC) -c $(SRCDIR)/th_tcl.c -o $@ |
| 2140 | |
| 2141 | |
| 2142 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c $(OBJDIR)/mkversion |
| 2143 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2144 | |
| 2145 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c $(OBJDIR)/mkversion |
| 2146 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2147 | |
| 2148 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 2149 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \ |
| 2150 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore \ |
| 2151 |
+2
-2
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -3024,11 +3024,11 @@ | ||
| 3024 | 3024 | CARD_STR2(K, p->zTicketUuid); |
| 3025 | 3025 | CARD_STR2(L, p->zWikiTitle); |
| 3026 | 3026 | ISA( CFTYPE_CLUSTER ){ |
| 3027 | 3027 | CARD_LETTER(M); |
| 3028 | 3028 | blob_append_char(b, '['); |
| 3029 | - for( int i = 0; i < p->nCChild; ++i ){ | |
| 3029 | + for( i = 0; i < p->nCChild; ++i ){ | |
| 3030 | 3030 | if( i>0 ) blob_append_char(b, ','); |
| 3031 | 3031 | blob_appendf(b, "%!j", p->azCChild[i]); |
| 3032 | 3032 | } |
| 3033 | 3033 | blob_append_char(b, ']'); |
| 3034 | 3034 | } |
| @@ -3059,11 +3059,11 @@ | ||
| 3059 | 3059 | } |
| 3060 | 3060 | CARD_STR2(R, p->zRepoCksum); |
| 3061 | 3061 | if( p->nTag ){ |
| 3062 | 3062 | CARD_LETTER(T); |
| 3063 | 3063 | blob_append_char(b, '['); |
| 3064 | - for( int i = 0; i < p->nTag; ++i ){ | |
| 3064 | + for( i = 0; i < p->nTag; ++i ){ | |
| 3065 | 3065 | const char *zName = p->aTag[i].zName; |
| 3066 | 3066 | if( i>0 ) blob_append_char(b, ','); |
| 3067 | 3067 | blob_append_char(b, '{'); |
| 3068 | 3068 | blob_appendf(b, "\"type\":\"%c\"", *zName); |
| 3069 | 3069 | KVP_STR(1, name, &zName[1]); |
| 3070 | 3070 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -3024,11 +3024,11 @@ | |
| 3024 | CARD_STR2(K, p->zTicketUuid); |
| 3025 | CARD_STR2(L, p->zWikiTitle); |
| 3026 | ISA( CFTYPE_CLUSTER ){ |
| 3027 | CARD_LETTER(M); |
| 3028 | blob_append_char(b, '['); |
| 3029 | for( int i = 0; i < p->nCChild; ++i ){ |
| 3030 | if( i>0 ) blob_append_char(b, ','); |
| 3031 | blob_appendf(b, "%!j", p->azCChild[i]); |
| 3032 | } |
| 3033 | blob_append_char(b, ']'); |
| 3034 | } |
| @@ -3059,11 +3059,11 @@ | |
| 3059 | } |
| 3060 | CARD_STR2(R, p->zRepoCksum); |
| 3061 | if( p->nTag ){ |
| 3062 | CARD_LETTER(T); |
| 3063 | blob_append_char(b, '['); |
| 3064 | for( int i = 0; i < p->nTag; ++i ){ |
| 3065 | const char *zName = p->aTag[i].zName; |
| 3066 | if( i>0 ) blob_append_char(b, ','); |
| 3067 | blob_append_char(b, '{'); |
| 3068 | blob_appendf(b, "\"type\":\"%c\"", *zName); |
| 3069 | KVP_STR(1, name, &zName[1]); |
| 3070 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -3024,11 +3024,11 @@ | |
| 3024 | CARD_STR2(K, p->zTicketUuid); |
| 3025 | CARD_STR2(L, p->zWikiTitle); |
| 3026 | ISA( CFTYPE_CLUSTER ){ |
| 3027 | CARD_LETTER(M); |
| 3028 | blob_append_char(b, '['); |
| 3029 | for( i = 0; i < p->nCChild; ++i ){ |
| 3030 | if( i>0 ) blob_append_char(b, ','); |
| 3031 | blob_appendf(b, "%!j", p->azCChild[i]); |
| 3032 | } |
| 3033 | blob_append_char(b, ']'); |
| 3034 | } |
| @@ -3059,11 +3059,11 @@ | |
| 3059 | } |
| 3060 | CARD_STR2(R, p->zRepoCksum); |
| 3061 | if( p->nTag ){ |
| 3062 | CARD_LETTER(T); |
| 3063 | blob_append_char(b, '['); |
| 3064 | for( i = 0; i < p->nTag; ++i ){ |
| 3065 | const char *zName = p->aTag[i].zName; |
| 3066 | if( i>0 ) blob_append_char(b, ','); |
| 3067 | blob_append_char(b, '{'); |
| 3068 | blob_appendf(b, "\"type\":\"%c\"", *zName); |
| 3069 | KVP_STR(1, name, &zName[1]); |
| 3070 |
+2
-2
| --- src/markdown_html.c | ||
| +++ src/markdown_html.c | ||
| @@ -278,11 +278,11 @@ | ||
| 278 | 278 | struct Blob *head_row, |
| 279 | 279 | struct Blob *rows, |
| 280 | 280 | void *opaque |
| 281 | 281 | ){ |
| 282 | 282 | INTER_BLOCK(ob); |
| 283 | - blob_append_literal(ob, "<table>\n"); | |
| 283 | + blob_append_literal(ob, "<table class='md-table'>\n"); | |
| 284 | 284 | if( head_row && blob_size(head_row)>0 ){ |
| 285 | 285 | blob_append_literal(ob, "<thead>\n"); |
| 286 | 286 | blob_appendb(ob, head_row); |
| 287 | 287 | blob_append_literal(ob, "</thead>\n<tbody>\n"); |
| 288 | 288 | } |
| @@ -696,11 +696,11 @@ | ||
| 696 | 696 | ){ |
| 697 | 697 | blob_appendf(&bSrc, "fontscale = %.13g\n", rPikVar); |
| 698 | 698 | } |
| 699 | 699 | blob_append(&bSrc, zSrc, nSrc) |
| 700 | 700 | /*have to dup input to ensure a NUL-terminated source string */; |
| 701 | - pikchr_process(blob_str(&bSrc), pikFlags, 0, ob); | |
| 701 | + pikchr_process(blob_str(&bSrc), pikFlags, ob); | |
| 702 | 702 | blob_reset(&bSrc); |
| 703 | 703 | } |
| 704 | 704 | |
| 705 | 705 | /* Invoked for `...` blocks where there are nSep grave accents in a |
| 706 | 706 | ** row that serve as the delimiter. According to CommonMark: |
| 707 | 707 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -278,11 +278,11 @@ | |
| 278 | struct Blob *head_row, |
| 279 | struct Blob *rows, |
| 280 | void *opaque |
| 281 | ){ |
| 282 | INTER_BLOCK(ob); |
| 283 | blob_append_literal(ob, "<table>\n"); |
| 284 | if( head_row && blob_size(head_row)>0 ){ |
| 285 | blob_append_literal(ob, "<thead>\n"); |
| 286 | blob_appendb(ob, head_row); |
| 287 | blob_append_literal(ob, "</thead>\n<tbody>\n"); |
| 288 | } |
| @@ -696,11 +696,11 @@ | |
| 696 | ){ |
| 697 | blob_appendf(&bSrc, "fontscale = %.13g\n", rPikVar); |
| 698 | } |
| 699 | blob_append(&bSrc, zSrc, nSrc) |
| 700 | /*have to dup input to ensure a NUL-terminated source string */; |
| 701 | pikchr_process(blob_str(&bSrc), pikFlags, 0, ob); |
| 702 | blob_reset(&bSrc); |
| 703 | } |
| 704 | |
| 705 | /* Invoked for `...` blocks where there are nSep grave accents in a |
| 706 | ** row that serve as the delimiter. According to CommonMark: |
| 707 |
| --- src/markdown_html.c | |
| +++ src/markdown_html.c | |
| @@ -278,11 +278,11 @@ | |
| 278 | struct Blob *head_row, |
| 279 | struct Blob *rows, |
| 280 | void *opaque |
| 281 | ){ |
| 282 | INTER_BLOCK(ob); |
| 283 | blob_append_literal(ob, "<table class='md-table'>\n"); |
| 284 | if( head_row && blob_size(head_row)>0 ){ |
| 285 | blob_append_literal(ob, "<thead>\n"); |
| 286 | blob_appendb(ob, head_row); |
| 287 | blob_append_literal(ob, "</thead>\n<tbody>\n"); |
| 288 | } |
| @@ -696,11 +696,11 @@ | |
| 696 | ){ |
| 697 | blob_appendf(&bSrc, "fontscale = %.13g\n", rPikVar); |
| 698 | } |
| 699 | blob_append(&bSrc, zSrc, nSrc) |
| 700 | /*have to dup input to ensure a NUL-terminated source string */; |
| 701 | pikchr_process(blob_str(&bSrc), pikFlags, ob); |
| 702 | blob_reset(&bSrc); |
| 703 | } |
| 704 | |
| 705 | /* Invoked for `...` blocks where there are nSep grave accents in a |
| 706 | ** row that serve as the delimiter. According to CommonMark: |
| 707 |
+89
-182
| --- src/pikchrshow.c | ||
| +++ src/pikchrshow.c | ||
| @@ -27,12 +27,10 @@ | ||
| 27 | 27 | /* The first two must match the values from pikchr.c */ |
| 28 | 28 | #define PIKCHR_PROCESS_PLAINTEXT_ERRORS 0x0001 |
| 29 | 29 | #define PIKCHR_PROCESS_DARK_MODE 0x0002 |
| 30 | 30 | /* end of flags supported directly by pikchr() */ |
| 31 | 31 | #define PIKCHR_PROCESS_PASSTHROUGH 0x0003 /* Pass through these flags */ |
| 32 | -#define PIKCHR_PROCESS_TH1 0x0004 | |
| 33 | -#define PIKCHR_PROCESS_TH1_NOSVG 0x0008 | |
| 34 | 32 | #define PIKCHR_PROCESS_NONCE 0x0010 |
| 35 | 33 | #define PIKCHR_PROCESS_ERR_PRE 0x0020 |
| 36 | 34 | #define PIKCHR_PROCESS_SRC 0x0040 |
| 37 | 35 | #define PIKCHR_PROCESS_DIV 0x0080 |
| 38 | 36 | #define PIKCHR_PROCESS_DIV_INDENT 0x0100 |
| @@ -43,36 +41,20 @@ | ||
| 43 | 41 | #define PIKCHR_PROCESS_DIV_SOURCE 0x2000 |
| 44 | 42 | #define PIKCHR_PROCESS_DIV_SOURCE_INLINE 0x4000 |
| 45 | 43 | #endif |
| 46 | 44 | |
| 47 | 45 | /* |
| 48 | -** Processes a pikchr script, optionally with embedded TH1, and | |
| 49 | -** produces HTML code for it. zIn is the NUL-terminated input | |
| 46 | +** Processes a pikchr script. zIn is the NUL-terminated input | |
| 50 | 47 | ** script. pikFlags may be a bitmask of any of the PIKCHR_PROCESS_xxx |
| 51 | -** flags documented below. thFlags may be a bitmask of any of the | |
| 52 | -** TH_INIT_xxx and/or TH_R2B_xxx flags. Output is sent to pOut, | |
| 53 | -** appending to it without modifying any prior contents. | |
| 48 | +** flags documented below. Output is sent to pOut, | |
| 54 | 49 | ** |
| 55 | -** Returns 0 on success, 1 if TH1 processing failed, or 2 if pikchr | |
| 56 | -** processing failed. In either case, the error message (if any) from | |
| 57 | -** TH1 or pikchr will be appended to pOut. | |
| 50 | +** Returns 0 on success, or non-zero if pikchr processing failed. | |
| 51 | +** In either case, the error message (if any) from pikchr will be | |
| 52 | +** appended to pOut. | |
| 58 | 53 | ** |
| 59 | 54 | ** pikFlags flag descriptions: |
| 60 | 55 | ** |
| 61 | -** - PIKCHR_PROCESS_TH1 means to run zIn through TH1, using the TH1 | |
| 62 | -** init flags specified in the 3rd argument. If thFlags is non-0 then | |
| 63 | -** this flag is assumed even if it is not specified. | |
| 64 | -** | |
| 65 | -** - PIKCHR_PROCESS_TH1_NOSVG means that processing stops after the | |
| 66 | -** TH1 eval step, thus the output will be (presumably) a | |
| 67 | -** TH1-generated/processed pikchr script (or whatever else the TH1 | |
| 68 | -** outputs). If this flag is set, PIKCHR_PROCESS_TH1 is assumed even | |
| 69 | -** if it is not specified. | |
| 70 | -** | |
| 71 | -** All of the remaining flags listed below are ignored if | |
| 72 | -** PIKCHR_PROCESS_TH1_NOSVG is specified! | |
| 73 | -** | |
| 74 | 56 | ** - PIKCHR_PROCESS_DIV: if set, the SVG result is wrapped in a DIV |
| 75 | 57 | ** element which specifies a max-width style value based on the SVG's |
| 76 | 58 | ** calculated size. This flag has multiple mutually exclusive forms: |
| 77 | 59 | ** |
| 78 | 60 | ** - PIKCHR_PROCESS_DIV uses default element alignment. |
| @@ -116,14 +98,14 @@ | ||
| 116 | 98 | ** |
| 117 | 99 | ** - PIKCHR_PROCESS_ERR_PRE: if set and pikchr() fails, the resulting |
| 118 | 100 | ** error report is wrapped in a PRE element, else it is retained |
| 119 | 101 | ** as-is (intended only for console output). |
| 120 | 102 | */ |
| 121 | -int pikchr_process(const char * zIn, int pikFlags, int thFlags, | |
| 122 | - Blob * pOut){ | |
| 123 | - Blob bIn = empty_blob; | |
| 103 | +int pikchr_process(const char *zIn, int pikFlags, Blob * pOut){ | |
| 124 | 104 | int isErr = 0; |
| 105 | + int w = 0, h = 0; | |
| 106 | + char *zOut; | |
| 125 | 107 | const char *zNonce = (PIKCHR_PROCESS_NONCE & pikFlags) |
| 126 | 108 | ? safe_html_nonce(1) : 0; |
| 127 | 109 | |
| 128 | 110 | if(!(PIKCHR_PROCESS_DIV & pikFlags) |
| 129 | 111 | /* If any DIV_xxx flags are set, set DIV */ |
| @@ -135,115 +117,87 @@ | ||
| 135 | 117 | | PIKCHR_PROCESS_DIV_SOURCE_INLINE |
| 136 | 118 | | PIKCHR_PROCESS_DIV_TOGGLE |
| 137 | 119 | ) & pikFlags){ |
| 138 | 120 | pikFlags |= PIKCHR_PROCESS_DIV; |
| 139 | 121 | } |
| 140 | - if(!(PIKCHR_PROCESS_TH1 & pikFlags) | |
| 141 | - /* If any TH1_xxx flags are set, set TH1 */ | |
| 142 | - && (PIKCHR_PROCESS_TH1_NOSVG & pikFlags || thFlags!=0)){ | |
| 143 | - pikFlags |= PIKCHR_PROCESS_TH1; | |
| 144 | - } | |
| 145 | - if(zNonce){ | |
| 146 | - blob_appendf(pOut, "%s\n", zNonce); | |
| 147 | - } | |
| 148 | - if(PIKCHR_PROCESS_TH1 & pikFlags){ | |
| 149 | - Blob out = empty_blob; | |
| 150 | - isErr = Th_RenderToBlob(zIn, &out, thFlags) | |
| 151 | - ? 1 : 0; | |
| 152 | - if(isErr){ | |
| 153 | - blob_append(pOut, blob_str(&out), blob_size(&out)); | |
| 154 | - blob_reset(&out); | |
| 155 | - }else{ | |
| 156 | - bIn = out; | |
| 157 | - } | |
| 158 | - }else{ | |
| 159 | - blob_init(&bIn, zIn, -1); | |
| 160 | - } | |
| 161 | - if(!isErr){ | |
| 162 | - if(PIKCHR_PROCESS_TH1_NOSVG & pikFlags){ | |
| 163 | - blob_append(pOut, blob_str(&bIn), blob_size(&bIn)); | |
| 164 | - }else{ | |
| 165 | - int w = 0, h = 0; | |
| 166 | - const char * zContent = blob_str(&bIn); | |
| 167 | - char *zOut; | |
| 168 | - zOut = pikchr(zContent, "pikchr", | |
| 169 | - 0x01 | (pikFlags&PIKCHR_PROCESS_PASSTHROUGH), | |
| 170 | - &w, &h); | |
| 171 | - if( w>0 && h>0 ){ | |
| 172 | - const char * zClassToggle = ""; | |
| 173 | - const char * zClassSource = ""; | |
| 174 | - const char * zWrapperClass = ""; | |
| 175 | - if(PIKCHR_PROCESS_DIV & pikFlags){ | |
| 176 | - if(PIKCHR_PROCESS_DIV_CENTER & pikFlags){ | |
| 177 | - zWrapperClass = " center"; | |
| 178 | - }else if(PIKCHR_PROCESS_DIV_INDENT & pikFlags){ | |
| 179 | - zWrapperClass = " indent"; | |
| 180 | - }else if(PIKCHR_PROCESS_DIV_FLOAT_LEFT & pikFlags){ | |
| 181 | - zWrapperClass = " float-left"; | |
| 182 | - }else if(PIKCHR_PROCESS_DIV_FLOAT_RIGHT & pikFlags){ | |
| 183 | - zWrapperClass = " float-right"; | |
| 184 | - } | |
| 185 | - if(PIKCHR_PROCESS_DIV_TOGGLE & pikFlags){ | |
| 186 | - zClassToggle = " toggle"; | |
| 187 | - } | |
| 188 | - if(PIKCHR_PROCESS_DIV_SOURCE_INLINE & pikFlags){ | |
| 189 | - if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ | |
| 190 | - zClassSource = " source source-inline"; | |
| 191 | - }else{ | |
| 192 | - zClassSource = " source-inline"; | |
| 193 | - } | |
| 194 | - pikFlags |= PIKCHR_PROCESS_SRC; | |
| 195 | - }else if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ | |
| 196 | - zClassSource = " source"; | |
| 197 | - pikFlags |= PIKCHR_PROCESS_SRC; | |
| 198 | - } | |
| 199 | - blob_appendf(pOut,"<div class='pikchr-wrapper" | |
| 200 | - "%s%s%s'>" | |
| 201 | - "<div class=\"pikchr-svg\" " | |
| 202 | - "style=\"max-width:%dpx\">\n", | |
| 203 | - zWrapperClass/*safe-for-%s*/, | |
| 204 | - zClassToggle/*safe-for-%s*/, | |
| 205 | - zClassSource/*safe-for-%s*/, w); | |
| 206 | - } | |
| 207 | - blob_append(pOut, zOut, -1); | |
| 208 | - if(PIKCHR_PROCESS_DIV & pikFlags){ | |
| 209 | - blob_append(pOut, "</div>\n", 7); | |
| 210 | - } | |
| 211 | - if(PIKCHR_PROCESS_SRC & pikFlags){ | |
| 212 | - static int counter = 0; | |
| 213 | - ++counter; | |
| 214 | - blob_appendf(pOut, "<div class='pikchr-src'>" | |
| 215 | - "<pre id='pikchr-src-%d'>%h</pre>" | |
| 216 | - "<span class='hidden'>" | |
| 217 | - "<a href='%R/pikchrshow?fromSession' " | |
| 218 | - "class='pikchr-src-pikchrshow' target='_new-%d' " | |
| 219 | - "data-pikchrid='pikchr-src-%d' " | |
| 220 | - "title='Open this pikchr in /pikchrshow'" | |
| 221 | - ">→ /pikchrshow</a></span>" | |
| 222 | - "</div>\n", | |
| 223 | - counter, blob_str(&bIn), counter, counter); | |
| 224 | - } | |
| 225 | - if(PIKCHR_PROCESS_DIV & pikFlags){ | |
| 226 | - blob_append(pOut, "</div>\n", 7); | |
| 227 | - } | |
| 228 | - }else{ | |
| 229 | - isErr = 2; | |
| 230 | - if(PIKCHR_PROCESS_ERR_PRE & pikFlags){ | |
| 231 | - blob_append(pOut, "<pre class='error'>\n", 20); | |
| 232 | - } | |
| 233 | - blob_appendf(pOut, "%h", zOut); | |
| 234 | - if(PIKCHR_PROCESS_ERR_PRE & pikFlags){ | |
| 235 | - blob_append(pOut, "\n</pre>\n", 8); | |
| 236 | - } | |
| 237 | - } | |
| 238 | - fossil_free(zOut); | |
| 239 | - } | |
| 240 | - } | |
| 241 | - if(zNonce){ | |
| 242 | - blob_appendf(pOut, "%s\n", zNonce); | |
| 243 | - } | |
| 244 | - blob_reset(&bIn); | |
| 122 | + if(zNonce){ | |
| 123 | + blob_appendf(pOut, "%s\n", zNonce); | |
| 124 | + } | |
| 125 | + zOut = pikchr(zIn, "pikchr", | |
| 126 | + 0x01 | (pikFlags&PIKCHR_PROCESS_PASSTHROUGH), | |
| 127 | + &w, &h); | |
| 128 | + if( w>0 && h>0 ){ | |
| 129 | + const char * zClassToggle = ""; | |
| 130 | + const char * zClassSource = ""; | |
| 131 | + const char * zWrapperClass = ""; | |
| 132 | + if(PIKCHR_PROCESS_DIV & pikFlags){ | |
| 133 | + if(PIKCHR_PROCESS_DIV_CENTER & pikFlags){ | |
| 134 | + zWrapperClass = " center"; | |
| 135 | + }else if(PIKCHR_PROCESS_DIV_INDENT & pikFlags){ | |
| 136 | + zWrapperClass = " indent"; | |
| 137 | + }else if(PIKCHR_PROCESS_DIV_FLOAT_LEFT & pikFlags){ | |
| 138 | + zWrapperClass = " float-left"; | |
| 139 | + }else if(PIKCHR_PROCESS_DIV_FLOAT_RIGHT & pikFlags){ | |
| 140 | + zWrapperClass = " float-right"; | |
| 141 | + } | |
| 142 | + if(PIKCHR_PROCESS_DIV_TOGGLE & pikFlags){ | |
| 143 | + zClassToggle = " toggle"; | |
| 144 | + } | |
| 145 | + if(PIKCHR_PROCESS_DIV_SOURCE_INLINE & pikFlags){ | |
| 146 | + if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ | |
| 147 | + zClassSource = " source source-inline"; | |
| 148 | + }else{ | |
| 149 | + zClassSource = " source-inline"; | |
| 150 | + } | |
| 151 | + pikFlags |= PIKCHR_PROCESS_SRC; | |
| 152 | + }else if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ | |
| 153 | + zClassSource = " source"; | |
| 154 | + pikFlags |= PIKCHR_PROCESS_SRC; | |
| 155 | + } | |
| 156 | + blob_appendf(pOut,"<div class='pikchr-wrapper" | |
| 157 | + "%s%s%s'>" | |
| 158 | + "<div class=\"pikchr-svg\" " | |
| 159 | + "style=\"max-width:%dpx\">\n", | |
| 160 | + zWrapperClass/*safe-for-%s*/, | |
| 161 | + zClassToggle/*safe-for-%s*/, | |
| 162 | + zClassSource/*safe-for-%s*/, w); | |
| 163 | + } | |
| 164 | + blob_append(pOut, zOut, -1); | |
| 165 | + if(PIKCHR_PROCESS_DIV & pikFlags){ | |
| 166 | + blob_append(pOut, "</div>\n", 7); | |
| 167 | + } | |
| 168 | + if(PIKCHR_PROCESS_SRC & pikFlags){ | |
| 169 | + static int counter = 0; | |
| 170 | + ++counter; | |
| 171 | + blob_appendf(pOut, "<div class='pikchr-src'>" | |
| 172 | + "<pre id='pikchr-src-%d'>%h</pre>" | |
| 173 | + "<span class='hidden'>" | |
| 174 | + "<a href='%R/pikchrshow?fromSession' " | |
| 175 | + "class='pikchr-src-pikchrshow' target='_new-%d' " | |
| 176 | + "data-pikchrid='pikchr-src-%d' " | |
| 177 | + "title='Open this pikchr in /pikchrshow'" | |
| 178 | + ">→ /pikchrshow</a></span>" | |
| 179 | + "</div>\n", | |
| 180 | + counter, zIn, counter, counter); | |
| 181 | + } | |
| 182 | + if(PIKCHR_PROCESS_DIV & pikFlags){ | |
| 183 | + blob_append(pOut, "</div>\n", 7); | |
| 184 | + } | |
| 185 | + }else{ | |
| 186 | + isErr = 2; | |
| 187 | + if(PIKCHR_PROCESS_ERR_PRE & pikFlags){ | |
| 188 | + blob_append(pOut, "<pre class='error'>\n", 20); | |
| 189 | + } | |
| 190 | + blob_appendf(pOut, "%h", zOut); | |
| 191 | + if(PIKCHR_PROCESS_ERR_PRE & pikFlags){ | |
| 192 | + blob_append(pOut, "\n</pre>\n", 8); | |
| 193 | + } | |
| 194 | + } | |
| 195 | + fossil_free(zOut); | |
| 196 | + if(zNonce){ | |
| 197 | + blob_appendf(pOut, "%s\n", zNonce); | |
| 198 | + } | |
| 245 | 199 | return isErr; |
| 246 | 200 | } |
| 247 | 201 | |
| 248 | 202 | /* |
| 249 | 203 | ** Legacy impl of /pikchrshow. pikchrshow_page() will delegate to |
| @@ -279,11 +233,11 @@ | ||
| 279 | 233 | TODO: respond with JSON instead.*/ |
| 280 | 234 | cgi_set_content_type("text/html"); |
| 281 | 235 | if(zContent && *zContent){ |
| 282 | 236 | Blob out = empty_blob; |
| 283 | 237 | const int isErr = |
| 284 | - pikchr_process(zContent, pikFlags, 0, &out); | |
| 238 | + pikchr_process(zContent, pikFlags, &out); | |
| 285 | 239 | if(isErr){ |
| 286 | 240 | cgi_printf_header("x-pikchrshow-is-error: %d\r\n", isErr); |
| 287 | 241 | } |
| 288 | 242 | CX("%b", &out); |
| 289 | 243 | blob_reset(&out); |
| @@ -384,11 +338,11 @@ | ||
| 384 | 338 | /* Reminder: Firefox does not properly flexbox a LEGEND |
| 385 | 339 | element, always flowing it in column mode. */); |
| 386 | 340 | CX("<div id='pikchrshow-output'>"); |
| 387 | 341 | if(*zContent){ |
| 388 | 342 | Blob out = empty_blob; |
| 389 | - pikchr_process(zContent, pikFlags, 0, &out); | |
| 343 | + pikchr_process(zContent, pikFlags, &out); | |
| 390 | 344 | CX("%b", &out); |
| 391 | 345 | blob_reset(&out); |
| 392 | 346 | } CX("</div>"/*#pikchrshow-output*/); |
| 393 | 347 | } CX("</fieldset>"/*#pikchrshow-output-wrapper*/); |
| 394 | 348 | } CX("</div>"/*sbs-wrapper*/); |
| @@ -561,60 +515,23 @@ | ||
| 561 | 515 | ** |
| 562 | 516 | ** -src Store the input pikchr's source code in the output as |
| 563 | 517 | ** a separate element adjacent to the SVG one. Implied |
| 564 | 518 | ** by -div-source. |
| 565 | 519 | ** |
| 566 | -** | |
| 567 | -** -th Process the input using TH1 before passing it to pikchr | |
| 568 | -** | |
| 569 | -** -th-novar Disable $var and $<var> TH1 processing. Use this if the | |
| 570 | -** pikchr script uses '$' for its own purposes and that | |
| 571 | -** causes issues. This only affects parsing of '$' outside | |
| 572 | -** of TH1 script blocks. Code in such blocks is unaffected. | |
| 573 | -** | |
| 574 | -** -th-nosvg When using -th, output the post-TH1'd script | |
| 575 | -** instead of the pikchr-rendered output | |
| 576 | -** | |
| 577 | -** -th-trace Trace TH1 execution (for debugging purposes) | |
| 578 | -** | |
| 579 | 520 | ** -dark Change pikchr colors to assume a dark-mode theme. |
| 580 | 521 | ** |
| 581 | 522 | ** |
| 582 | 523 | ** The -div-indent/center/left/right flags may not be combined. |
| 583 | -** | |
| 584 | -** TH1-related Notes and Caveats: | |
| 585 | -** | |
| 586 | -** If the -th flag is used, this command must open a fossil database | |
| 587 | -** for certain functionality to work (via a check-out or the -R REPO | |
| 588 | -** flag). If opening a db fails, execution will continue but any TH1 | |
| 589 | -** commands which require a db will trigger a fatal error. | |
| 590 | -** | |
| 591 | -** In Fossil skins, TH1 variables in the form $varName are expanded | |
| 592 | -** as-is and those in the form $<varName> are htmlized in the | |
| 593 | -** resulting output. This processor disables the htmlizing step, so $x | |
| 594 | -** and $<x> are equivalent unless the TH1-processed pikchr script | |
| 595 | -** invokes the TH1 command [enable_htmlify 1] to enable it. Normally | |
| 596 | -** that option will interfere with pikchr output, however, e.g. by | |
| 597 | -** HTML-encoding double-quotes. | |
| 598 | -** | |
| 599 | -** Many of the fossil-installed TH1 functions simply do not make any | |
| 600 | -** sense for pikchr scripts. | |
| 601 | 524 | */ |
| 602 | 525 | void pikchr_cmd(void){ |
| 603 | 526 | Blob bIn = empty_blob; |
| 604 | 527 | Blob bOut = empty_blob; |
| 605 | 528 | const char * zInfile = "-"; |
| 606 | 529 | const char * zOutfile = "-"; |
| 607 | - const int fTh1 = find_option("th",0,0)!=0; | |
| 608 | - const int fNosvg = find_option("th-nosvg",0,0)!=0; | |
| 609 | 530 | int isErr = 0; |
| 610 | 531 | int pikFlags = find_option("src",0,0)!=0 |
| 611 | 532 | ? PIKCHR_PROCESS_SRC : 0; |
| 612 | - u32 fThFlags = TH_INIT_NO_ENCODE | |
| 613 | - | (find_option("th-novar",0,0)!=0 ? TH_R2B_NO_VARS : 0); | |
| 614 | - | |
| 615 | - Th_InitTraceLog()/*processes -th-trace flag*/; | |
| 616 | 533 | |
| 617 | 534 | if(find_option("div",0,0)!=0){ |
| 618 | 535 | pikFlags |= PIKCHR_PROCESS_DIV; |
| 619 | 536 | }else if(find_option("div-indent",0,0)!=0){ |
| 620 | 537 | pikFlags |= PIKCHR_PROCESS_DIV_INDENT; |
| @@ -644,24 +561,14 @@ | ||
| 644 | 561 | } |
| 645 | 562 | if(g.argc>3){ |
| 646 | 563 | zOutfile = g.argv[3]; |
| 647 | 564 | } |
| 648 | 565 | blob_read_from_file(&bIn, zInfile, ExtFILE); |
| 649 | - if(fTh1){ | |
| 650 | - db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0) | |
| 651 | - /* ^^^ needed for certain TH1 functions to work */; | |
| 652 | - pikFlags |= PIKCHR_PROCESS_TH1; | |
| 653 | - if(fNosvg) pikFlags |= PIKCHR_PROCESS_TH1_NOSVG; | |
| 654 | - } | |
| 655 | - isErr = pikchr_process(blob_str(&bIn), pikFlags, | |
| 656 | - fTh1 ? fThFlags : 0, &bOut); | |
| 566 | + isErr = pikchr_process(blob_str(&bIn), pikFlags, &bOut); | |
| 657 | 567 | if(isErr){ |
| 658 | - fossil_fatal("%s ERROR:%c%b", 1==isErr ? "TH1" : "pikchr", | |
| 659 | - 1==isErr ? ' ' : '\n', | |
| 660 | - &bOut); | |
| 568 | + fossil_fatal("pikchr ERROR: %b", &bOut); | |
| 661 | 569 | }else{ |
| 662 | 570 | blob_write_to_file(&bOut, zOutfile); |
| 663 | 571 | } |
| 664 | - Th_PrintTraceLog(); | |
| 665 | 572 | blob_reset(&bIn); |
| 666 | 573 | blob_reset(&bOut); |
| 667 | 574 | } |
| 668 | 575 |
| --- src/pikchrshow.c | |
| +++ src/pikchrshow.c | |
| @@ -27,12 +27,10 @@ | |
| 27 | /* The first two must match the values from pikchr.c */ |
| 28 | #define PIKCHR_PROCESS_PLAINTEXT_ERRORS 0x0001 |
| 29 | #define PIKCHR_PROCESS_DARK_MODE 0x0002 |
| 30 | /* end of flags supported directly by pikchr() */ |
| 31 | #define PIKCHR_PROCESS_PASSTHROUGH 0x0003 /* Pass through these flags */ |
| 32 | #define PIKCHR_PROCESS_TH1 0x0004 |
| 33 | #define PIKCHR_PROCESS_TH1_NOSVG 0x0008 |
| 34 | #define PIKCHR_PROCESS_NONCE 0x0010 |
| 35 | #define PIKCHR_PROCESS_ERR_PRE 0x0020 |
| 36 | #define PIKCHR_PROCESS_SRC 0x0040 |
| 37 | #define PIKCHR_PROCESS_DIV 0x0080 |
| 38 | #define PIKCHR_PROCESS_DIV_INDENT 0x0100 |
| @@ -43,36 +41,20 @@ | |
| 43 | #define PIKCHR_PROCESS_DIV_SOURCE 0x2000 |
| 44 | #define PIKCHR_PROCESS_DIV_SOURCE_INLINE 0x4000 |
| 45 | #endif |
| 46 | |
| 47 | /* |
| 48 | ** Processes a pikchr script, optionally with embedded TH1, and |
| 49 | ** produces HTML code for it. zIn is the NUL-terminated input |
| 50 | ** script. pikFlags may be a bitmask of any of the PIKCHR_PROCESS_xxx |
| 51 | ** flags documented below. thFlags may be a bitmask of any of the |
| 52 | ** TH_INIT_xxx and/or TH_R2B_xxx flags. Output is sent to pOut, |
| 53 | ** appending to it without modifying any prior contents. |
| 54 | ** |
| 55 | ** Returns 0 on success, 1 if TH1 processing failed, or 2 if pikchr |
| 56 | ** processing failed. In either case, the error message (if any) from |
| 57 | ** TH1 or pikchr will be appended to pOut. |
| 58 | ** |
| 59 | ** pikFlags flag descriptions: |
| 60 | ** |
| 61 | ** - PIKCHR_PROCESS_TH1 means to run zIn through TH1, using the TH1 |
| 62 | ** init flags specified in the 3rd argument. If thFlags is non-0 then |
| 63 | ** this flag is assumed even if it is not specified. |
| 64 | ** |
| 65 | ** - PIKCHR_PROCESS_TH1_NOSVG means that processing stops after the |
| 66 | ** TH1 eval step, thus the output will be (presumably) a |
| 67 | ** TH1-generated/processed pikchr script (or whatever else the TH1 |
| 68 | ** outputs). If this flag is set, PIKCHR_PROCESS_TH1 is assumed even |
| 69 | ** if it is not specified. |
| 70 | ** |
| 71 | ** All of the remaining flags listed below are ignored if |
| 72 | ** PIKCHR_PROCESS_TH1_NOSVG is specified! |
| 73 | ** |
| 74 | ** - PIKCHR_PROCESS_DIV: if set, the SVG result is wrapped in a DIV |
| 75 | ** element which specifies a max-width style value based on the SVG's |
| 76 | ** calculated size. This flag has multiple mutually exclusive forms: |
| 77 | ** |
| 78 | ** - PIKCHR_PROCESS_DIV uses default element alignment. |
| @@ -116,14 +98,14 @@ | |
| 116 | ** |
| 117 | ** - PIKCHR_PROCESS_ERR_PRE: if set and pikchr() fails, the resulting |
| 118 | ** error report is wrapped in a PRE element, else it is retained |
| 119 | ** as-is (intended only for console output). |
| 120 | */ |
| 121 | int pikchr_process(const char * zIn, int pikFlags, int thFlags, |
| 122 | Blob * pOut){ |
| 123 | Blob bIn = empty_blob; |
| 124 | int isErr = 0; |
| 125 | const char *zNonce = (PIKCHR_PROCESS_NONCE & pikFlags) |
| 126 | ? safe_html_nonce(1) : 0; |
| 127 | |
| 128 | if(!(PIKCHR_PROCESS_DIV & pikFlags) |
| 129 | /* If any DIV_xxx flags are set, set DIV */ |
| @@ -135,115 +117,87 @@ | |
| 135 | | PIKCHR_PROCESS_DIV_SOURCE_INLINE |
| 136 | | PIKCHR_PROCESS_DIV_TOGGLE |
| 137 | ) & pikFlags){ |
| 138 | pikFlags |= PIKCHR_PROCESS_DIV; |
| 139 | } |
| 140 | if(!(PIKCHR_PROCESS_TH1 & pikFlags) |
| 141 | /* If any TH1_xxx flags are set, set TH1 */ |
| 142 | && (PIKCHR_PROCESS_TH1_NOSVG & pikFlags || thFlags!=0)){ |
| 143 | pikFlags |= PIKCHR_PROCESS_TH1; |
| 144 | } |
| 145 | if(zNonce){ |
| 146 | blob_appendf(pOut, "%s\n", zNonce); |
| 147 | } |
| 148 | if(PIKCHR_PROCESS_TH1 & pikFlags){ |
| 149 | Blob out = empty_blob; |
| 150 | isErr = Th_RenderToBlob(zIn, &out, thFlags) |
| 151 | ? 1 : 0; |
| 152 | if(isErr){ |
| 153 | blob_append(pOut, blob_str(&out), blob_size(&out)); |
| 154 | blob_reset(&out); |
| 155 | }else{ |
| 156 | bIn = out; |
| 157 | } |
| 158 | }else{ |
| 159 | blob_init(&bIn, zIn, -1); |
| 160 | } |
| 161 | if(!isErr){ |
| 162 | if(PIKCHR_PROCESS_TH1_NOSVG & pikFlags){ |
| 163 | blob_append(pOut, blob_str(&bIn), blob_size(&bIn)); |
| 164 | }else{ |
| 165 | int w = 0, h = 0; |
| 166 | const char * zContent = blob_str(&bIn); |
| 167 | char *zOut; |
| 168 | zOut = pikchr(zContent, "pikchr", |
| 169 | 0x01 | (pikFlags&PIKCHR_PROCESS_PASSTHROUGH), |
| 170 | &w, &h); |
| 171 | if( w>0 && h>0 ){ |
| 172 | const char * zClassToggle = ""; |
| 173 | const char * zClassSource = ""; |
| 174 | const char * zWrapperClass = ""; |
| 175 | if(PIKCHR_PROCESS_DIV & pikFlags){ |
| 176 | if(PIKCHR_PROCESS_DIV_CENTER & pikFlags){ |
| 177 | zWrapperClass = " center"; |
| 178 | }else if(PIKCHR_PROCESS_DIV_INDENT & pikFlags){ |
| 179 | zWrapperClass = " indent"; |
| 180 | }else if(PIKCHR_PROCESS_DIV_FLOAT_LEFT & pikFlags){ |
| 181 | zWrapperClass = " float-left"; |
| 182 | }else if(PIKCHR_PROCESS_DIV_FLOAT_RIGHT & pikFlags){ |
| 183 | zWrapperClass = " float-right"; |
| 184 | } |
| 185 | if(PIKCHR_PROCESS_DIV_TOGGLE & pikFlags){ |
| 186 | zClassToggle = " toggle"; |
| 187 | } |
| 188 | if(PIKCHR_PROCESS_DIV_SOURCE_INLINE & pikFlags){ |
| 189 | if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ |
| 190 | zClassSource = " source source-inline"; |
| 191 | }else{ |
| 192 | zClassSource = " source-inline"; |
| 193 | } |
| 194 | pikFlags |= PIKCHR_PROCESS_SRC; |
| 195 | }else if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ |
| 196 | zClassSource = " source"; |
| 197 | pikFlags |= PIKCHR_PROCESS_SRC; |
| 198 | } |
| 199 | blob_appendf(pOut,"<div class='pikchr-wrapper" |
| 200 | "%s%s%s'>" |
| 201 | "<div class=\"pikchr-svg\" " |
| 202 | "style=\"max-width:%dpx\">\n", |
| 203 | zWrapperClass/*safe-for-%s*/, |
| 204 | zClassToggle/*safe-for-%s*/, |
| 205 | zClassSource/*safe-for-%s*/, w); |
| 206 | } |
| 207 | blob_append(pOut, zOut, -1); |
| 208 | if(PIKCHR_PROCESS_DIV & pikFlags){ |
| 209 | blob_append(pOut, "</div>\n", 7); |
| 210 | } |
| 211 | if(PIKCHR_PROCESS_SRC & pikFlags){ |
| 212 | static int counter = 0; |
| 213 | ++counter; |
| 214 | blob_appendf(pOut, "<div class='pikchr-src'>" |
| 215 | "<pre id='pikchr-src-%d'>%h</pre>" |
| 216 | "<span class='hidden'>" |
| 217 | "<a href='%R/pikchrshow?fromSession' " |
| 218 | "class='pikchr-src-pikchrshow' target='_new-%d' " |
| 219 | "data-pikchrid='pikchr-src-%d' " |
| 220 | "title='Open this pikchr in /pikchrshow'" |
| 221 | ">→ /pikchrshow</a></span>" |
| 222 | "</div>\n", |
| 223 | counter, blob_str(&bIn), counter, counter); |
| 224 | } |
| 225 | if(PIKCHR_PROCESS_DIV & pikFlags){ |
| 226 | blob_append(pOut, "</div>\n", 7); |
| 227 | } |
| 228 | }else{ |
| 229 | isErr = 2; |
| 230 | if(PIKCHR_PROCESS_ERR_PRE & pikFlags){ |
| 231 | blob_append(pOut, "<pre class='error'>\n", 20); |
| 232 | } |
| 233 | blob_appendf(pOut, "%h", zOut); |
| 234 | if(PIKCHR_PROCESS_ERR_PRE & pikFlags){ |
| 235 | blob_append(pOut, "\n</pre>\n", 8); |
| 236 | } |
| 237 | } |
| 238 | fossil_free(zOut); |
| 239 | } |
| 240 | } |
| 241 | if(zNonce){ |
| 242 | blob_appendf(pOut, "%s\n", zNonce); |
| 243 | } |
| 244 | blob_reset(&bIn); |
| 245 | return isErr; |
| 246 | } |
| 247 | |
| 248 | /* |
| 249 | ** Legacy impl of /pikchrshow. pikchrshow_page() will delegate to |
| @@ -279,11 +233,11 @@ | |
| 279 | TODO: respond with JSON instead.*/ |
| 280 | cgi_set_content_type("text/html"); |
| 281 | if(zContent && *zContent){ |
| 282 | Blob out = empty_blob; |
| 283 | const int isErr = |
| 284 | pikchr_process(zContent, pikFlags, 0, &out); |
| 285 | if(isErr){ |
| 286 | cgi_printf_header("x-pikchrshow-is-error: %d\r\n", isErr); |
| 287 | } |
| 288 | CX("%b", &out); |
| 289 | blob_reset(&out); |
| @@ -384,11 +338,11 @@ | |
| 384 | /* Reminder: Firefox does not properly flexbox a LEGEND |
| 385 | element, always flowing it in column mode. */); |
| 386 | CX("<div id='pikchrshow-output'>"); |
| 387 | if(*zContent){ |
| 388 | Blob out = empty_blob; |
| 389 | pikchr_process(zContent, pikFlags, 0, &out); |
| 390 | CX("%b", &out); |
| 391 | blob_reset(&out); |
| 392 | } CX("</div>"/*#pikchrshow-output*/); |
| 393 | } CX("</fieldset>"/*#pikchrshow-output-wrapper*/); |
| 394 | } CX("</div>"/*sbs-wrapper*/); |
| @@ -561,60 +515,23 @@ | |
| 561 | ** |
| 562 | ** -src Store the input pikchr's source code in the output as |
| 563 | ** a separate element adjacent to the SVG one. Implied |
| 564 | ** by -div-source. |
| 565 | ** |
| 566 | ** |
| 567 | ** -th Process the input using TH1 before passing it to pikchr |
| 568 | ** |
| 569 | ** -th-novar Disable $var and $<var> TH1 processing. Use this if the |
| 570 | ** pikchr script uses '$' for its own purposes and that |
| 571 | ** causes issues. This only affects parsing of '$' outside |
| 572 | ** of TH1 script blocks. Code in such blocks is unaffected. |
| 573 | ** |
| 574 | ** -th-nosvg When using -th, output the post-TH1'd script |
| 575 | ** instead of the pikchr-rendered output |
| 576 | ** |
| 577 | ** -th-trace Trace TH1 execution (for debugging purposes) |
| 578 | ** |
| 579 | ** -dark Change pikchr colors to assume a dark-mode theme. |
| 580 | ** |
| 581 | ** |
| 582 | ** The -div-indent/center/left/right flags may not be combined. |
| 583 | ** |
| 584 | ** TH1-related Notes and Caveats: |
| 585 | ** |
| 586 | ** If the -th flag is used, this command must open a fossil database |
| 587 | ** for certain functionality to work (via a check-out or the -R REPO |
| 588 | ** flag). If opening a db fails, execution will continue but any TH1 |
| 589 | ** commands which require a db will trigger a fatal error. |
| 590 | ** |
| 591 | ** In Fossil skins, TH1 variables in the form $varName are expanded |
| 592 | ** as-is and those in the form $<varName> are htmlized in the |
| 593 | ** resulting output. This processor disables the htmlizing step, so $x |
| 594 | ** and $<x> are equivalent unless the TH1-processed pikchr script |
| 595 | ** invokes the TH1 command [enable_htmlify 1] to enable it. Normally |
| 596 | ** that option will interfere with pikchr output, however, e.g. by |
| 597 | ** HTML-encoding double-quotes. |
| 598 | ** |
| 599 | ** Many of the fossil-installed TH1 functions simply do not make any |
| 600 | ** sense for pikchr scripts. |
| 601 | */ |
| 602 | void pikchr_cmd(void){ |
| 603 | Blob bIn = empty_blob; |
| 604 | Blob bOut = empty_blob; |
| 605 | const char * zInfile = "-"; |
| 606 | const char * zOutfile = "-"; |
| 607 | const int fTh1 = find_option("th",0,0)!=0; |
| 608 | const int fNosvg = find_option("th-nosvg",0,0)!=0; |
| 609 | int isErr = 0; |
| 610 | int pikFlags = find_option("src",0,0)!=0 |
| 611 | ? PIKCHR_PROCESS_SRC : 0; |
| 612 | u32 fThFlags = TH_INIT_NO_ENCODE |
| 613 | | (find_option("th-novar",0,0)!=0 ? TH_R2B_NO_VARS : 0); |
| 614 | |
| 615 | Th_InitTraceLog()/*processes -th-trace flag*/; |
| 616 | |
| 617 | if(find_option("div",0,0)!=0){ |
| 618 | pikFlags |= PIKCHR_PROCESS_DIV; |
| 619 | }else if(find_option("div-indent",0,0)!=0){ |
| 620 | pikFlags |= PIKCHR_PROCESS_DIV_INDENT; |
| @@ -644,24 +561,14 @@ | |
| 644 | } |
| 645 | if(g.argc>3){ |
| 646 | zOutfile = g.argv[3]; |
| 647 | } |
| 648 | blob_read_from_file(&bIn, zInfile, ExtFILE); |
| 649 | if(fTh1){ |
| 650 | db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0) |
| 651 | /* ^^^ needed for certain TH1 functions to work */; |
| 652 | pikFlags |= PIKCHR_PROCESS_TH1; |
| 653 | if(fNosvg) pikFlags |= PIKCHR_PROCESS_TH1_NOSVG; |
| 654 | } |
| 655 | isErr = pikchr_process(blob_str(&bIn), pikFlags, |
| 656 | fTh1 ? fThFlags : 0, &bOut); |
| 657 | if(isErr){ |
| 658 | fossil_fatal("%s ERROR:%c%b", 1==isErr ? "TH1" : "pikchr", |
| 659 | 1==isErr ? ' ' : '\n', |
| 660 | &bOut); |
| 661 | }else{ |
| 662 | blob_write_to_file(&bOut, zOutfile); |
| 663 | } |
| 664 | Th_PrintTraceLog(); |
| 665 | blob_reset(&bIn); |
| 666 | blob_reset(&bOut); |
| 667 | } |
| 668 |
| --- src/pikchrshow.c | |
| +++ src/pikchrshow.c | |
| @@ -27,12 +27,10 @@ | |
| 27 | /* The first two must match the values from pikchr.c */ |
| 28 | #define PIKCHR_PROCESS_PLAINTEXT_ERRORS 0x0001 |
| 29 | #define PIKCHR_PROCESS_DARK_MODE 0x0002 |
| 30 | /* end of flags supported directly by pikchr() */ |
| 31 | #define PIKCHR_PROCESS_PASSTHROUGH 0x0003 /* Pass through these flags */ |
| 32 | #define PIKCHR_PROCESS_NONCE 0x0010 |
| 33 | #define PIKCHR_PROCESS_ERR_PRE 0x0020 |
| 34 | #define PIKCHR_PROCESS_SRC 0x0040 |
| 35 | #define PIKCHR_PROCESS_DIV 0x0080 |
| 36 | #define PIKCHR_PROCESS_DIV_INDENT 0x0100 |
| @@ -43,36 +41,20 @@ | |
| 41 | #define PIKCHR_PROCESS_DIV_SOURCE 0x2000 |
| 42 | #define PIKCHR_PROCESS_DIV_SOURCE_INLINE 0x4000 |
| 43 | #endif |
| 44 | |
| 45 | /* |
| 46 | ** Processes a pikchr script. zIn is the NUL-terminated input |
| 47 | ** script. pikFlags may be a bitmask of any of the PIKCHR_PROCESS_xxx |
| 48 | ** flags documented below. Output is sent to pOut, |
| 49 | ** |
| 50 | ** Returns 0 on success, or non-zero if pikchr processing failed. |
| 51 | ** In either case, the error message (if any) from pikchr will be |
| 52 | ** appended to pOut. |
| 53 | ** |
| 54 | ** pikFlags flag descriptions: |
| 55 | ** |
| 56 | ** - PIKCHR_PROCESS_DIV: if set, the SVG result is wrapped in a DIV |
| 57 | ** element which specifies a max-width style value based on the SVG's |
| 58 | ** calculated size. This flag has multiple mutually exclusive forms: |
| 59 | ** |
| 60 | ** - PIKCHR_PROCESS_DIV uses default element alignment. |
| @@ -116,14 +98,14 @@ | |
| 98 | ** |
| 99 | ** - PIKCHR_PROCESS_ERR_PRE: if set and pikchr() fails, the resulting |
| 100 | ** error report is wrapped in a PRE element, else it is retained |
| 101 | ** as-is (intended only for console output). |
| 102 | */ |
| 103 | int pikchr_process(const char *zIn, int pikFlags, Blob * pOut){ |
| 104 | int isErr = 0; |
| 105 | int w = 0, h = 0; |
| 106 | char *zOut; |
| 107 | const char *zNonce = (PIKCHR_PROCESS_NONCE & pikFlags) |
| 108 | ? safe_html_nonce(1) : 0; |
| 109 | |
| 110 | if(!(PIKCHR_PROCESS_DIV & pikFlags) |
| 111 | /* If any DIV_xxx flags are set, set DIV */ |
| @@ -135,115 +117,87 @@ | |
| 117 | | PIKCHR_PROCESS_DIV_SOURCE_INLINE |
| 118 | | PIKCHR_PROCESS_DIV_TOGGLE |
| 119 | ) & pikFlags){ |
| 120 | pikFlags |= PIKCHR_PROCESS_DIV; |
| 121 | } |
| 122 | if(zNonce){ |
| 123 | blob_appendf(pOut, "%s\n", zNonce); |
| 124 | } |
| 125 | zOut = pikchr(zIn, "pikchr", |
| 126 | 0x01 | (pikFlags&PIKCHR_PROCESS_PASSTHROUGH), |
| 127 | &w, &h); |
| 128 | if( w>0 && h>0 ){ |
| 129 | const char * zClassToggle = ""; |
| 130 | const char * zClassSource = ""; |
| 131 | const char * zWrapperClass = ""; |
| 132 | if(PIKCHR_PROCESS_DIV & pikFlags){ |
| 133 | if(PIKCHR_PROCESS_DIV_CENTER & pikFlags){ |
| 134 | zWrapperClass = " center"; |
| 135 | }else if(PIKCHR_PROCESS_DIV_INDENT & pikFlags){ |
| 136 | zWrapperClass = " indent"; |
| 137 | }else if(PIKCHR_PROCESS_DIV_FLOAT_LEFT & pikFlags){ |
| 138 | zWrapperClass = " float-left"; |
| 139 | }else if(PIKCHR_PROCESS_DIV_FLOAT_RIGHT & pikFlags){ |
| 140 | zWrapperClass = " float-right"; |
| 141 | } |
| 142 | if(PIKCHR_PROCESS_DIV_TOGGLE & pikFlags){ |
| 143 | zClassToggle = " toggle"; |
| 144 | } |
| 145 | if(PIKCHR_PROCESS_DIV_SOURCE_INLINE & pikFlags){ |
| 146 | if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ |
| 147 | zClassSource = " source source-inline"; |
| 148 | }else{ |
| 149 | zClassSource = " source-inline"; |
| 150 | } |
| 151 | pikFlags |= PIKCHR_PROCESS_SRC; |
| 152 | }else if(PIKCHR_PROCESS_DIV_SOURCE & pikFlags){ |
| 153 | zClassSource = " source"; |
| 154 | pikFlags |= PIKCHR_PROCESS_SRC; |
| 155 | } |
| 156 | blob_appendf(pOut,"<div class='pikchr-wrapper" |
| 157 | "%s%s%s'>" |
| 158 | "<div class=\"pikchr-svg\" " |
| 159 | "style=\"max-width:%dpx\">\n", |
| 160 | zWrapperClass/*safe-for-%s*/, |
| 161 | zClassToggle/*safe-for-%s*/, |
| 162 | zClassSource/*safe-for-%s*/, w); |
| 163 | } |
| 164 | blob_append(pOut, zOut, -1); |
| 165 | if(PIKCHR_PROCESS_DIV & pikFlags){ |
| 166 | blob_append(pOut, "</div>\n", 7); |
| 167 | } |
| 168 | if(PIKCHR_PROCESS_SRC & pikFlags){ |
| 169 | static int counter = 0; |
| 170 | ++counter; |
| 171 | blob_appendf(pOut, "<div class='pikchr-src'>" |
| 172 | "<pre id='pikchr-src-%d'>%h</pre>" |
| 173 | "<span class='hidden'>" |
| 174 | "<a href='%R/pikchrshow?fromSession' " |
| 175 | "class='pikchr-src-pikchrshow' target='_new-%d' " |
| 176 | "data-pikchrid='pikchr-src-%d' " |
| 177 | "title='Open this pikchr in /pikchrshow'" |
| 178 | ">→ /pikchrshow</a></span>" |
| 179 | "</div>\n", |
| 180 | counter, zIn, counter, counter); |
| 181 | } |
| 182 | if(PIKCHR_PROCESS_DIV & pikFlags){ |
| 183 | blob_append(pOut, "</div>\n", 7); |
| 184 | } |
| 185 | }else{ |
| 186 | isErr = 2; |
| 187 | if(PIKCHR_PROCESS_ERR_PRE & pikFlags){ |
| 188 | blob_append(pOut, "<pre class='error'>\n", 20); |
| 189 | } |
| 190 | blob_appendf(pOut, "%h", zOut); |
| 191 | if(PIKCHR_PROCESS_ERR_PRE & pikFlags){ |
| 192 | blob_append(pOut, "\n</pre>\n", 8); |
| 193 | } |
| 194 | } |
| 195 | fossil_free(zOut); |
| 196 | if(zNonce){ |
| 197 | blob_appendf(pOut, "%s\n", zNonce); |
| 198 | } |
| 199 | return isErr; |
| 200 | } |
| 201 | |
| 202 | /* |
| 203 | ** Legacy impl of /pikchrshow. pikchrshow_page() will delegate to |
| @@ -279,11 +233,11 @@ | |
| 233 | TODO: respond with JSON instead.*/ |
| 234 | cgi_set_content_type("text/html"); |
| 235 | if(zContent && *zContent){ |
| 236 | Blob out = empty_blob; |
| 237 | const int isErr = |
| 238 | pikchr_process(zContent, pikFlags, &out); |
| 239 | if(isErr){ |
| 240 | cgi_printf_header("x-pikchrshow-is-error: %d\r\n", isErr); |
| 241 | } |
| 242 | CX("%b", &out); |
| 243 | blob_reset(&out); |
| @@ -384,11 +338,11 @@ | |
| 338 | /* Reminder: Firefox does not properly flexbox a LEGEND |
| 339 | element, always flowing it in column mode. */); |
| 340 | CX("<div id='pikchrshow-output'>"); |
| 341 | if(*zContent){ |
| 342 | Blob out = empty_blob; |
| 343 | pikchr_process(zContent, pikFlags, &out); |
| 344 | CX("%b", &out); |
| 345 | blob_reset(&out); |
| 346 | } CX("</div>"/*#pikchrshow-output*/); |
| 347 | } CX("</fieldset>"/*#pikchrshow-output-wrapper*/); |
| 348 | } CX("</div>"/*sbs-wrapper*/); |
| @@ -561,60 +515,23 @@ | |
| 515 | ** |
| 516 | ** -src Store the input pikchr's source code in the output as |
| 517 | ** a separate element adjacent to the SVG one. Implied |
| 518 | ** by -div-source. |
| 519 | ** |
| 520 | ** -dark Change pikchr colors to assume a dark-mode theme. |
| 521 | ** |
| 522 | ** |
| 523 | ** The -div-indent/center/left/right flags may not be combined. |
| 524 | */ |
| 525 | void pikchr_cmd(void){ |
| 526 | Blob bIn = empty_blob; |
| 527 | Blob bOut = empty_blob; |
| 528 | const char * zInfile = "-"; |
| 529 | const char * zOutfile = "-"; |
| 530 | int isErr = 0; |
| 531 | int pikFlags = find_option("src",0,0)!=0 |
| 532 | ? PIKCHR_PROCESS_SRC : 0; |
| 533 | |
| 534 | if(find_option("div",0,0)!=0){ |
| 535 | pikFlags |= PIKCHR_PROCESS_DIV; |
| 536 | }else if(find_option("div-indent",0,0)!=0){ |
| 537 | pikFlags |= PIKCHR_PROCESS_DIV_INDENT; |
| @@ -644,24 +561,14 @@ | |
| 561 | } |
| 562 | if(g.argc>3){ |
| 563 | zOutfile = g.argv[3]; |
| 564 | } |
| 565 | blob_read_from_file(&bIn, zInfile, ExtFILE); |
| 566 | isErr = pikchr_process(blob_str(&bIn), pikFlags, &bOut); |
| 567 | if(isErr){ |
| 568 | fossil_fatal("pikchr ERROR: %b", &bOut); |
| 569 | }else{ |
| 570 | blob_write_to_file(&bOut, zOutfile); |
| 571 | } |
| 572 | blob_reset(&bIn); |
| 573 | blob_reset(&bOut); |
| 574 | } |
| 575 |
+1
-22
| --- src/repolist.c | ||
| +++ src/repolist.c | ||
| @@ -101,25 +101,10 @@ | ||
| 101 | 101 | finish_repo_list: |
| 102 | 102 | g.dbIgnoreErrors--; |
| 103 | 103 | sqlite3_close(db); |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | -/* | |
| 107 | -** SETTING: show-repolist-desc boolean default=off | |
| 108 | -** | |
| 109 | -** If the value of this setting is "1" globally, then the repository-list | |
| 110 | -** page will show the description of each repository. This setting only | |
| 111 | -** has effect when it is in the global setting database. | |
| 112 | -*/ | |
| 113 | -/* | |
| 114 | -** SETTING: show-repolist-lg boolean default=off | |
| 115 | -** | |
| 116 | -** If the value of this setting is "1" globally, then the repository-list | |
| 117 | -** page will show the login-group for each repository. This setting only | |
| 118 | -** has effect when it is in the global setting database. | |
| 119 | -*/ | |
| 120 | - | |
| 121 | 106 | /* |
| 122 | 107 | ** Generate a web-page that lists all repositories located under the |
| 123 | 108 | ** g.zRepositoryName directory and return non-zero. |
| 124 | 109 | ** |
| 125 | 110 | ** For the special case when g.zRepositoryName is a non-chroot-jail "/", |
| @@ -151,17 +136,10 @@ | ||
| 151 | 136 | assert( g.db==0 ); |
| 152 | 137 | zShow = P("FOSSIL_REPOLIST_SHOW"); |
| 153 | 138 | if( zShow ){ |
| 154 | 139 | bShowDesc = strstr(zShow,"description")!=0; |
| 155 | 140 | bShowLg = strstr(zShow,"login-group")!=0; |
| 156 | - }else if( db_open_config(1, 1) | |
| 157 | - && db_table_exists("configdb", "global_config") | |
| 158 | - ){ | |
| 159 | - bShowDesc = db_int(bShowDesc, "SELECT value FROM global_config" | |
| 160 | - " WHERE name='show-repolist-desc'"); | |
| 161 | - bShowLg = db_int(bShowLg, "SELECT value FROM global_config" | |
| 162 | - " WHERE name='show-repolist-lg'"); | |
| 163 | 141 | } |
| 164 | 142 | blob_init(&html, 0, 0); |
| 165 | 143 | if( fossil_strcmp(g.zRepositoryName,"/")==0 && !g.fJail ){ |
| 166 | 144 | /* For the special case of the "repository directory" being "/", |
| 167 | 145 | ** show all of the repositories named in the ~/.fossil database. |
| @@ -169,10 +147,11 @@ | ||
| 169 | 147 | ** On unix systems, then entries are of the form "repo:/home/..." |
| 170 | 148 | ** and on Windows systems they are like on unix, starting with a "/" |
| 171 | 149 | ** or they can begin with a drive letter: "repo:C:/Users/...". In either |
| 172 | 150 | ** case, we want returned path to omit any initial "/". |
| 173 | 151 | */ |
| 152 | + db_open_config(1, 0); | |
| 174 | 153 | db_multi_exec( |
| 175 | 154 | "CREATE TEMP VIEW sfile AS" |
| 176 | 155 | " SELECT ltrim(substr(name,6),'/') AS 'pathname' FROM global_config" |
| 177 | 156 | " WHERE name GLOB 'repo:*'" |
| 178 | 157 | ); |
| 179 | 158 |
| --- src/repolist.c | |
| +++ src/repolist.c | |
| @@ -101,25 +101,10 @@ | |
| 101 | finish_repo_list: |
| 102 | g.dbIgnoreErrors--; |
| 103 | sqlite3_close(db); |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | ** SETTING: show-repolist-desc boolean default=off |
| 108 | ** |
| 109 | ** If the value of this setting is "1" globally, then the repository-list |
| 110 | ** page will show the description of each repository. This setting only |
| 111 | ** has effect when it is in the global setting database. |
| 112 | */ |
| 113 | /* |
| 114 | ** SETTING: show-repolist-lg boolean default=off |
| 115 | ** |
| 116 | ** If the value of this setting is "1" globally, then the repository-list |
| 117 | ** page will show the login-group for each repository. This setting only |
| 118 | ** has effect when it is in the global setting database. |
| 119 | */ |
| 120 | |
| 121 | /* |
| 122 | ** Generate a web-page that lists all repositories located under the |
| 123 | ** g.zRepositoryName directory and return non-zero. |
| 124 | ** |
| 125 | ** For the special case when g.zRepositoryName is a non-chroot-jail "/", |
| @@ -151,17 +136,10 @@ | |
| 151 | assert( g.db==0 ); |
| 152 | zShow = P("FOSSIL_REPOLIST_SHOW"); |
| 153 | if( zShow ){ |
| 154 | bShowDesc = strstr(zShow,"description")!=0; |
| 155 | bShowLg = strstr(zShow,"login-group")!=0; |
| 156 | }else if( db_open_config(1, 1) |
| 157 | && db_table_exists("configdb", "global_config") |
| 158 | ){ |
| 159 | bShowDesc = db_int(bShowDesc, "SELECT value FROM global_config" |
| 160 | " WHERE name='show-repolist-desc'"); |
| 161 | bShowLg = db_int(bShowLg, "SELECT value FROM global_config" |
| 162 | " WHERE name='show-repolist-lg'"); |
| 163 | } |
| 164 | blob_init(&html, 0, 0); |
| 165 | if( fossil_strcmp(g.zRepositoryName,"/")==0 && !g.fJail ){ |
| 166 | /* For the special case of the "repository directory" being "/", |
| 167 | ** show all of the repositories named in the ~/.fossil database. |
| @@ -169,10 +147,11 @@ | |
| 169 | ** On unix systems, then entries are of the form "repo:/home/..." |
| 170 | ** and on Windows systems they are like on unix, starting with a "/" |
| 171 | ** or they can begin with a drive letter: "repo:C:/Users/...". In either |
| 172 | ** case, we want returned path to omit any initial "/". |
| 173 | */ |
| 174 | db_multi_exec( |
| 175 | "CREATE TEMP VIEW sfile AS" |
| 176 | " SELECT ltrim(substr(name,6),'/') AS 'pathname' FROM global_config" |
| 177 | " WHERE name GLOB 'repo:*'" |
| 178 | ); |
| 179 |
| --- src/repolist.c | |
| +++ src/repolist.c | |
| @@ -101,25 +101,10 @@ | |
| 101 | finish_repo_list: |
| 102 | g.dbIgnoreErrors--; |
| 103 | sqlite3_close(db); |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | ** Generate a web-page that lists all repositories located under the |
| 108 | ** g.zRepositoryName directory and return non-zero. |
| 109 | ** |
| 110 | ** For the special case when g.zRepositoryName is a non-chroot-jail "/", |
| @@ -151,17 +136,10 @@ | |
| 136 | assert( g.db==0 ); |
| 137 | zShow = P("FOSSIL_REPOLIST_SHOW"); |
| 138 | if( zShow ){ |
| 139 | bShowDesc = strstr(zShow,"description")!=0; |
| 140 | bShowLg = strstr(zShow,"login-group")!=0; |
| 141 | } |
| 142 | blob_init(&html, 0, 0); |
| 143 | if( fossil_strcmp(g.zRepositoryName,"/")==0 && !g.fJail ){ |
| 144 | /* For the special case of the "repository directory" being "/", |
| 145 | ** show all of the repositories named in the ~/.fossil database. |
| @@ -169,10 +147,11 @@ | |
| 147 | ** On unix systems, then entries are of the form "repo:/home/..." |
| 148 | ** and on Windows systems they are like on unix, starting with a "/" |
| 149 | ** or they can begin with a drive letter: "repo:C:/Users/...". In either |
| 150 | ** case, we want returned path to omit any initial "/". |
| 151 | */ |
| 152 | db_open_config(1, 0); |
| 153 | db_multi_exec( |
| 154 | "CREATE TEMP VIEW sfile AS" |
| 155 | " SELECT ltrim(substr(name,6),'/') AS 'pathname' FROM global_config" |
| 156 | " WHERE name GLOB 'repo:*'" |
| 157 | ); |
| 158 |
+1
-22
| --- src/repolist.c | ||
| +++ src/repolist.c | ||
| @@ -101,25 +101,10 @@ | ||
| 101 | 101 | finish_repo_list: |
| 102 | 102 | g.dbIgnoreErrors--; |
| 103 | 103 | sqlite3_close(db); |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | -/* | |
| 107 | -** SETTING: show-repolist-desc boolean default=off | |
| 108 | -** | |
| 109 | -** If the value of this setting is "1" globally, then the repository-list | |
| 110 | -** page will show the description of each repository. This setting only | |
| 111 | -** has effect when it is in the global setting database. | |
| 112 | -*/ | |
| 113 | -/* | |
| 114 | -** SETTING: show-repolist-lg boolean default=off | |
| 115 | -** | |
| 116 | -** If the value of this setting is "1" globally, then the repository-list | |
| 117 | -** page will show the login-group for each repository. This setting only | |
| 118 | -** has effect when it is in the global setting database. | |
| 119 | -*/ | |
| 120 | - | |
| 121 | 106 | /* |
| 122 | 107 | ** Generate a web-page that lists all repositories located under the |
| 123 | 108 | ** g.zRepositoryName directory and return non-zero. |
| 124 | 109 | ** |
| 125 | 110 | ** For the special case when g.zRepositoryName is a non-chroot-jail "/", |
| @@ -151,17 +136,10 @@ | ||
| 151 | 136 | assert( g.db==0 ); |
| 152 | 137 | zShow = P("FOSSIL_REPOLIST_SHOW"); |
| 153 | 138 | if( zShow ){ |
| 154 | 139 | bShowDesc = strstr(zShow,"description")!=0; |
| 155 | 140 | bShowLg = strstr(zShow,"login-group")!=0; |
| 156 | - }else if( db_open_config(1, 1) | |
| 157 | - && db_table_exists("configdb", "global_config") | |
| 158 | - ){ | |
| 159 | - bShowDesc = db_int(bShowDesc, "SELECT value FROM global_config" | |
| 160 | - " WHERE name='show-repolist-desc'"); | |
| 161 | - bShowLg = db_int(bShowLg, "SELECT value FROM global_config" | |
| 162 | - " WHERE name='show-repolist-lg'"); | |
| 163 | 141 | } |
| 164 | 142 | blob_init(&html, 0, 0); |
| 165 | 143 | if( fossil_strcmp(g.zRepositoryName,"/")==0 && !g.fJail ){ |
| 166 | 144 | /* For the special case of the "repository directory" being "/", |
| 167 | 145 | ** show all of the repositories named in the ~/.fossil database. |
| @@ -169,10 +147,11 @@ | ||
| 169 | 147 | ** On unix systems, then entries are of the form "repo:/home/..." |
| 170 | 148 | ** and on Windows systems they are like on unix, starting with a "/" |
| 171 | 149 | ** or they can begin with a drive letter: "repo:C:/Users/...". In either |
| 172 | 150 | ** case, we want returned path to omit any initial "/". |
| 173 | 151 | */ |
| 152 | + db_open_config(1, 0); | |
| 174 | 153 | db_multi_exec( |
| 175 | 154 | "CREATE TEMP VIEW sfile AS" |
| 176 | 155 | " SELECT ltrim(substr(name,6),'/') AS 'pathname' FROM global_config" |
| 177 | 156 | " WHERE name GLOB 'repo:*'" |
| 178 | 157 | ); |
| 179 | 158 |
| --- src/repolist.c | |
| +++ src/repolist.c | |
| @@ -101,25 +101,10 @@ | |
| 101 | finish_repo_list: |
| 102 | g.dbIgnoreErrors--; |
| 103 | sqlite3_close(db); |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | ** SETTING: show-repolist-desc boolean default=off |
| 108 | ** |
| 109 | ** If the value of this setting is "1" globally, then the repository-list |
| 110 | ** page will show the description of each repository. This setting only |
| 111 | ** has effect when it is in the global setting database. |
| 112 | */ |
| 113 | /* |
| 114 | ** SETTING: show-repolist-lg boolean default=off |
| 115 | ** |
| 116 | ** If the value of this setting is "1" globally, then the repository-list |
| 117 | ** page will show the login-group for each repository. This setting only |
| 118 | ** has effect when it is in the global setting database. |
| 119 | */ |
| 120 | |
| 121 | /* |
| 122 | ** Generate a web-page that lists all repositories located under the |
| 123 | ** g.zRepositoryName directory and return non-zero. |
| 124 | ** |
| 125 | ** For the special case when g.zRepositoryName is a non-chroot-jail "/", |
| @@ -151,17 +136,10 @@ | |
| 151 | assert( g.db==0 ); |
| 152 | zShow = P("FOSSIL_REPOLIST_SHOW"); |
| 153 | if( zShow ){ |
| 154 | bShowDesc = strstr(zShow,"description")!=0; |
| 155 | bShowLg = strstr(zShow,"login-group")!=0; |
| 156 | }else if( db_open_config(1, 1) |
| 157 | && db_table_exists("configdb", "global_config") |
| 158 | ){ |
| 159 | bShowDesc = db_int(bShowDesc, "SELECT value FROM global_config" |
| 160 | " WHERE name='show-repolist-desc'"); |
| 161 | bShowLg = db_int(bShowLg, "SELECT value FROM global_config" |
| 162 | " WHERE name='show-repolist-lg'"); |
| 163 | } |
| 164 | blob_init(&html, 0, 0); |
| 165 | if( fossil_strcmp(g.zRepositoryName,"/")==0 && !g.fJail ){ |
| 166 | /* For the special case of the "repository directory" being "/", |
| 167 | ** show all of the repositories named in the ~/.fossil database. |
| @@ -169,10 +147,11 @@ | |
| 169 | ** On unix systems, then entries are of the form "repo:/home/..." |
| 170 | ** and on Windows systems they are like on unix, starting with a "/" |
| 171 | ** or they can begin with a drive letter: "repo:C:/Users/...". In either |
| 172 | ** case, we want returned path to omit any initial "/". |
| 173 | */ |
| 174 | db_multi_exec( |
| 175 | "CREATE TEMP VIEW sfile AS" |
| 176 | " SELECT ltrim(substr(name,6),'/') AS 'pathname' FROM global_config" |
| 177 | " WHERE name GLOB 'repo:*'" |
| 178 | ); |
| 179 |
| --- src/repolist.c | |
| +++ src/repolist.c | |
| @@ -101,25 +101,10 @@ | |
| 101 | finish_repo_list: |
| 102 | g.dbIgnoreErrors--; |
| 103 | sqlite3_close(db); |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | ** Generate a web-page that lists all repositories located under the |
| 108 | ** g.zRepositoryName directory and return non-zero. |
| 109 | ** |
| 110 | ** For the special case when g.zRepositoryName is a non-chroot-jail "/", |
| @@ -151,17 +136,10 @@ | |
| 136 | assert( g.db==0 ); |
| 137 | zShow = P("FOSSIL_REPOLIST_SHOW"); |
| 138 | if( zShow ){ |
| 139 | bShowDesc = strstr(zShow,"description")!=0; |
| 140 | bShowLg = strstr(zShow,"login-group")!=0; |
| 141 | } |
| 142 | blob_init(&html, 0, 0); |
| 143 | if( fossil_strcmp(g.zRepositoryName,"/")==0 && !g.fJail ){ |
| 144 | /* For the special case of the "repository directory" being "/", |
| 145 | ** show all of the repositories named in the ~/.fossil database. |
| @@ -169,10 +147,11 @@ | |
| 147 | ** On unix systems, then entries are of the form "repo:/home/..." |
| 148 | ** and on Windows systems they are like on unix, starting with a "/" |
| 149 | ** or they can begin with a drive letter: "repo:C:/Users/...". In either |
| 150 | ** case, we want returned path to omit any initial "/". |
| 151 | */ |
| 152 | db_open_config(1, 0); |
| 153 | db_multi_exec( |
| 154 | "CREATE TEMP VIEW sfile AS" |
| 155 | " SELECT ltrim(substr(name,6),'/') AS 'pathname' FROM global_config" |
| 156 | " WHERE name GLOB 'repo:*'" |
| 157 | ); |
| 158 |
+1
-1
| --- src/tag.c | ||
| +++ src/tag.c | ||
| @@ -412,11 +412,11 @@ | ||
| 412 | 412 | ** non-CHECK-IN artifacts. |
| 413 | 413 | ** --user-override USER Name USER when adding the tag |
| 414 | 414 | ** |
| 415 | 415 | ** The --date-override and --user-override options support |
| 416 | 416 | ** importing history from other SCM systems. DATETIME has |
| 417 | -** the form 'YYYY-MMM-DD HH:MM:SS'. | |
| 417 | +** the form 'YYYY-MM-DD HH:MM:SS'. | |
| 418 | 418 | ** |
| 419 | 419 | ** Note that fossil uses some tag prefixes internally and this |
| 420 | 420 | ** command will reject tags with these prefixes to avoid |
| 421 | 421 | ** causing problems or confusion: "wiki-", "tkt-", "event-". |
| 422 | 422 | ** |
| 423 | 423 |
| --- src/tag.c | |
| +++ src/tag.c | |
| @@ -412,11 +412,11 @@ | |
| 412 | ** non-CHECK-IN artifacts. |
| 413 | ** --user-override USER Name USER when adding the tag |
| 414 | ** |
| 415 | ** The --date-override and --user-override options support |
| 416 | ** importing history from other SCM systems. DATETIME has |
| 417 | ** the form 'YYYY-MMM-DD HH:MM:SS'. |
| 418 | ** |
| 419 | ** Note that fossil uses some tag prefixes internally and this |
| 420 | ** command will reject tags with these prefixes to avoid |
| 421 | ** causing problems or confusion: "wiki-", "tkt-", "event-". |
| 422 | ** |
| 423 |
| --- src/tag.c | |
| +++ src/tag.c | |
| @@ -412,11 +412,11 @@ | |
| 412 | ** non-CHECK-IN artifacts. |
| 413 | ** --user-override USER Name USER when adding the tag |
| 414 | ** |
| 415 | ** The --date-override and --user-override options support |
| 416 | ** importing history from other SCM systems. DATETIME has |
| 417 | ** the form 'YYYY-MM-DD HH:MM:SS'. |
| 418 | ** |
| 419 | ** Note that fossil uses some tag prefixes internally and this |
| 420 | ** command will reject tags with these prefixes to avoid |
| 421 | ** causing problems or confusion: "wiki-", "tkt-", "event-". |
| 422 | ** |
| 423 |
+3
-51
| --- src/th_main.c | ||
| +++ src/th_main.c | ||
| @@ -31,13 +31,11 @@ | ||
| 31 | 31 | #define TH_INIT_NEED_CONFIG ((u32)0x00000001) /* Open configuration first? */ |
| 32 | 32 | #define TH_INIT_FORCE_TCL ((u32)0x00000002) /* Force Tcl to be enabled? */ |
| 33 | 33 | #define TH_INIT_FORCE_RESET ((u32)0x00000004) /* Force TH1 commands re-added? */ |
| 34 | 34 | #define TH_INIT_FORCE_SETUP ((u32)0x00000008) /* Force eval of setup script? */ |
| 35 | 35 | #define TH_INIT_NO_REPO ((u32)0x00000010) /* Skip opening repository. */ |
| 36 | -#define TH_INIT_NO_ENCODE ((u32)0x00000020) /* Do not html-encode sendText()*/ | |
| 37 | - /* output. */ | |
| 38 | -#define TH_INIT_MASK ((u32)0x0000003F) /* All possible init flags. */ | |
| 36 | +#define TH_INIT_MASK ((u32)0x0000001F) /* All possible init flags. */ | |
| 39 | 37 | |
| 40 | 38 | /* |
| 41 | 39 | ** Useful and/or "well-known" combinations of flag values. |
| 42 | 40 | */ |
| 43 | 41 | #define TH_INIT_DEFAULT (TH_INIT_NONE) /* Default flags. */ |
| @@ -297,50 +295,10 @@ | ||
| 297 | 295 | TH1_LEN(argl[1]),argv[1],enableOutput); |
| 298 | 296 | } |
| 299 | 297 | return rc; |
| 300 | 298 | } |
| 301 | 299 | |
| 302 | -/* | |
| 303 | -** TH1 command: enable_htmlify ?BOOLEAN? | |
| 304 | -** | |
| 305 | -** Enable or disable the HTML escaping done by all output which | |
| 306 | -** originates from TH1 (via sendText()). | |
| 307 | -** | |
| 308 | -** If passed no arguments it instead returns 0 or 1 to indicate the | |
| 309 | -** current state. | |
| 310 | -*/ | |
| 311 | -static int enableHtmlifyCmd( | |
| 312 | - Th_Interp *interp, | |
| 313 | - void *p, | |
| 314 | - int argc, | |
| 315 | - const char **argv, | |
| 316 | - int *argl | |
| 317 | -){ | |
| 318 | - int rc = 0, buul; | |
| 319 | - if( argc>3 ){ | |
| 320 | - return Th_WrongNumArgs(interp, | |
| 321 | - "enable_htmlify [TRACE_LABEL] ?BOOLEAN?"); | |
| 322 | - } | |
| 323 | - buul = (TH_INIT_NO_ENCODE & g.th1Flags) ? 0 : 1; | |
| 324 | - Th_SetResultInt(g.interp, buul); | |
| 325 | - if(argc>1){ | |
| 326 | - if( g.thTrace ){ | |
| 327 | - Th_Trace("enable_htmlify {%.*s} -> %d<br>\n", | |
| 328 | - TH1_LEN(argl[1]),argv[1],buul); | |
| 329 | - } | |
| 330 | - rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &buul); | |
| 331 | - if(!rc){ | |
| 332 | - if(buul){ | |
| 333 | - g.th1Flags &= ~TH_INIT_NO_ENCODE; | |
| 334 | - }else{ | |
| 335 | - g.th1Flags |= TH_INIT_NO_ENCODE; | |
| 336 | - } | |
| 337 | - } | |
| 338 | - } | |
| 339 | - return rc; | |
| 340 | -} | |
| 341 | - | |
| 342 | 300 | /* |
| 343 | 301 | ** Returns a name for a TH1 return code. |
| 344 | 302 | */ |
| 345 | 303 | const char *Th_ReturnCodeName(int rc, int nullIfOk){ |
| 346 | 304 | static char zRc[32]; |
| @@ -376,23 +334,19 @@ | ||
| 376 | 334 | |
| 377 | 335 | /* |
| 378 | 336 | ** Send text to the appropriate output: If pOut is not NULL, it is |
| 379 | 337 | ** appended there, else to the console or to the CGI reply buffer. |
| 380 | 338 | ** Escape all characters with special meaning to HTML if the encode |
| 381 | -** parameter is true, with the exception that that flag is ignored if | |
| 382 | -** g.th1Flags has the TH_INIT_NO_ENCODE flag. | |
| 339 | +** parameter is true. | |
| 383 | 340 | ** |
| 384 | 341 | ** If pOut is NULL and the global pThOut is not then that blob |
| 385 | 342 | ** is used for output. |
| 386 | 343 | */ |
| 387 | 344 | static void sendText(Blob *pOut, const char *z, int n, int encode){ |
| 388 | 345 | if(0==pOut && pThOut!=0){ |
| 389 | 346 | pOut = pThOut; |
| 390 | 347 | } |
| 391 | - if(TH_INIT_NO_ENCODE & g.th1Flags){ | |
| 392 | - encode = 0; | |
| 393 | - } | |
| 394 | 348 | if( enableOutput && n ){ |
| 395 | 349 | if( n<0 ){ |
| 396 | 350 | n = strlen(z); |
| 397 | 351 | }else{ |
| 398 | 352 | n = TH1_LEN(n); |
| @@ -2429,11 +2383,10 @@ | ||
| 2429 | 2383 | {"copybtn", copybtnCmd, 0}, |
| 2430 | 2384 | {"date", dateCmd, 0}, |
| 2431 | 2385 | {"decorate", wikiCmd, (void*)&aFlags[2]}, |
| 2432 | 2386 | {"defHeader", defHeaderCmd, 0}, |
| 2433 | 2387 | {"dir", dirCmd, 0}, |
| 2434 | - {"enable_htmlify",enableHtmlifyCmd, 0}, | |
| 2435 | 2388 | {"enable_output", enableOutputCmd, 0}, |
| 2436 | 2389 | {"encode64", encode64Cmd, 0}, |
| 2437 | 2390 | {"getParameter", getParameterCmd, 0}, |
| 2438 | 2391 | {"glob_match", globMatchCmd, 0}, |
| 2439 | 2392 | {"globalState", globalStateCmd, 0}, |
| @@ -3047,12 +3000,11 @@ | ||
| 3047 | 3000 | ** e.g. via the "render" script function binding, need to use the |
| 3048 | 3001 | ** pThOut blob in order to avoid out-of-order output if |
| 3049 | 3002 | ** Th_SetOutputBlob() has been called. If it has not been called, |
| 3050 | 3003 | ** pThOut will be 0, which will redirect the output to CGI/stdout, |
| 3051 | 3004 | ** as appropriate. We need to pass on g.th1Flags for the case of |
| 3052 | - ** recursive calls, so that, e.g., TH_INIT_NO_ENCODE does not get | |
| 3053 | - ** inadvertently toggled off by a recursive call. | |
| 3005 | + ** recursive calls. | |
| 3054 | 3006 | */; |
| 3055 | 3007 | } |
| 3056 | 3008 | |
| 3057 | 3009 | /* |
| 3058 | 3010 | ** SETTING: vuln-report width=8 default=log |
| 3059 | 3011 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -31,13 +31,11 @@ | |
| 31 | #define TH_INIT_NEED_CONFIG ((u32)0x00000001) /* Open configuration first? */ |
| 32 | #define TH_INIT_FORCE_TCL ((u32)0x00000002) /* Force Tcl to be enabled? */ |
| 33 | #define TH_INIT_FORCE_RESET ((u32)0x00000004) /* Force TH1 commands re-added? */ |
| 34 | #define TH_INIT_FORCE_SETUP ((u32)0x00000008) /* Force eval of setup script? */ |
| 35 | #define TH_INIT_NO_REPO ((u32)0x00000010) /* Skip opening repository. */ |
| 36 | #define TH_INIT_NO_ENCODE ((u32)0x00000020) /* Do not html-encode sendText()*/ |
| 37 | /* output. */ |
| 38 | #define TH_INIT_MASK ((u32)0x0000003F) /* All possible init flags. */ |
| 39 | |
| 40 | /* |
| 41 | ** Useful and/or "well-known" combinations of flag values. |
| 42 | */ |
| 43 | #define TH_INIT_DEFAULT (TH_INIT_NONE) /* Default flags. */ |
| @@ -297,50 +295,10 @@ | |
| 297 | TH1_LEN(argl[1]),argv[1],enableOutput); |
| 298 | } |
| 299 | return rc; |
| 300 | } |
| 301 | |
| 302 | /* |
| 303 | ** TH1 command: enable_htmlify ?BOOLEAN? |
| 304 | ** |
| 305 | ** Enable or disable the HTML escaping done by all output which |
| 306 | ** originates from TH1 (via sendText()). |
| 307 | ** |
| 308 | ** If passed no arguments it instead returns 0 or 1 to indicate the |
| 309 | ** current state. |
| 310 | */ |
| 311 | static int enableHtmlifyCmd( |
| 312 | Th_Interp *interp, |
| 313 | void *p, |
| 314 | int argc, |
| 315 | const char **argv, |
| 316 | int *argl |
| 317 | ){ |
| 318 | int rc = 0, buul; |
| 319 | if( argc>3 ){ |
| 320 | return Th_WrongNumArgs(interp, |
| 321 | "enable_htmlify [TRACE_LABEL] ?BOOLEAN?"); |
| 322 | } |
| 323 | buul = (TH_INIT_NO_ENCODE & g.th1Flags) ? 0 : 1; |
| 324 | Th_SetResultInt(g.interp, buul); |
| 325 | if(argc>1){ |
| 326 | if( g.thTrace ){ |
| 327 | Th_Trace("enable_htmlify {%.*s} -> %d<br>\n", |
| 328 | TH1_LEN(argl[1]),argv[1],buul); |
| 329 | } |
| 330 | rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &buul); |
| 331 | if(!rc){ |
| 332 | if(buul){ |
| 333 | g.th1Flags &= ~TH_INIT_NO_ENCODE; |
| 334 | }else{ |
| 335 | g.th1Flags |= TH_INIT_NO_ENCODE; |
| 336 | } |
| 337 | } |
| 338 | } |
| 339 | return rc; |
| 340 | } |
| 341 | |
| 342 | /* |
| 343 | ** Returns a name for a TH1 return code. |
| 344 | */ |
| 345 | const char *Th_ReturnCodeName(int rc, int nullIfOk){ |
| 346 | static char zRc[32]; |
| @@ -376,23 +334,19 @@ | |
| 376 | |
| 377 | /* |
| 378 | ** Send text to the appropriate output: If pOut is not NULL, it is |
| 379 | ** appended there, else to the console or to the CGI reply buffer. |
| 380 | ** Escape all characters with special meaning to HTML if the encode |
| 381 | ** parameter is true, with the exception that that flag is ignored if |
| 382 | ** g.th1Flags has the TH_INIT_NO_ENCODE flag. |
| 383 | ** |
| 384 | ** If pOut is NULL and the global pThOut is not then that blob |
| 385 | ** is used for output. |
| 386 | */ |
| 387 | static void sendText(Blob *pOut, const char *z, int n, int encode){ |
| 388 | if(0==pOut && pThOut!=0){ |
| 389 | pOut = pThOut; |
| 390 | } |
| 391 | if(TH_INIT_NO_ENCODE & g.th1Flags){ |
| 392 | encode = 0; |
| 393 | } |
| 394 | if( enableOutput && n ){ |
| 395 | if( n<0 ){ |
| 396 | n = strlen(z); |
| 397 | }else{ |
| 398 | n = TH1_LEN(n); |
| @@ -2429,11 +2383,10 @@ | |
| 2429 | {"copybtn", copybtnCmd, 0}, |
| 2430 | {"date", dateCmd, 0}, |
| 2431 | {"decorate", wikiCmd, (void*)&aFlags[2]}, |
| 2432 | {"defHeader", defHeaderCmd, 0}, |
| 2433 | {"dir", dirCmd, 0}, |
| 2434 | {"enable_htmlify",enableHtmlifyCmd, 0}, |
| 2435 | {"enable_output", enableOutputCmd, 0}, |
| 2436 | {"encode64", encode64Cmd, 0}, |
| 2437 | {"getParameter", getParameterCmd, 0}, |
| 2438 | {"glob_match", globMatchCmd, 0}, |
| 2439 | {"globalState", globalStateCmd, 0}, |
| @@ -3047,12 +3000,11 @@ | |
| 3047 | ** e.g. via the "render" script function binding, need to use the |
| 3048 | ** pThOut blob in order to avoid out-of-order output if |
| 3049 | ** Th_SetOutputBlob() has been called. If it has not been called, |
| 3050 | ** pThOut will be 0, which will redirect the output to CGI/stdout, |
| 3051 | ** as appropriate. We need to pass on g.th1Flags for the case of |
| 3052 | ** recursive calls, so that, e.g., TH_INIT_NO_ENCODE does not get |
| 3053 | ** inadvertently toggled off by a recursive call. |
| 3054 | */; |
| 3055 | } |
| 3056 | |
| 3057 | /* |
| 3058 | ** SETTING: vuln-report width=8 default=log |
| 3059 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -31,13 +31,11 @@ | |
| 31 | #define TH_INIT_NEED_CONFIG ((u32)0x00000001) /* Open configuration first? */ |
| 32 | #define TH_INIT_FORCE_TCL ((u32)0x00000002) /* Force Tcl to be enabled? */ |
| 33 | #define TH_INIT_FORCE_RESET ((u32)0x00000004) /* Force TH1 commands re-added? */ |
| 34 | #define TH_INIT_FORCE_SETUP ((u32)0x00000008) /* Force eval of setup script? */ |
| 35 | #define TH_INIT_NO_REPO ((u32)0x00000010) /* Skip opening repository. */ |
| 36 | #define TH_INIT_MASK ((u32)0x0000001F) /* All possible init flags. */ |
| 37 | |
| 38 | /* |
| 39 | ** Useful and/or "well-known" combinations of flag values. |
| 40 | */ |
| 41 | #define TH_INIT_DEFAULT (TH_INIT_NONE) /* Default flags. */ |
| @@ -297,50 +295,10 @@ | |
| 295 | TH1_LEN(argl[1]),argv[1],enableOutput); |
| 296 | } |
| 297 | return rc; |
| 298 | } |
| 299 | |
| 300 | /* |
| 301 | ** Returns a name for a TH1 return code. |
| 302 | */ |
| 303 | const char *Th_ReturnCodeName(int rc, int nullIfOk){ |
| 304 | static char zRc[32]; |
| @@ -376,23 +334,19 @@ | |
| 334 | |
| 335 | /* |
| 336 | ** Send text to the appropriate output: If pOut is not NULL, it is |
| 337 | ** appended there, else to the console or to the CGI reply buffer. |
| 338 | ** Escape all characters with special meaning to HTML if the encode |
| 339 | ** parameter is true. |
| 340 | ** |
| 341 | ** If pOut is NULL and the global pThOut is not then that blob |
| 342 | ** is used for output. |
| 343 | */ |
| 344 | static void sendText(Blob *pOut, const char *z, int n, int encode){ |
| 345 | if(0==pOut && pThOut!=0){ |
| 346 | pOut = pThOut; |
| 347 | } |
| 348 | if( enableOutput && n ){ |
| 349 | if( n<0 ){ |
| 350 | n = strlen(z); |
| 351 | }else{ |
| 352 | n = TH1_LEN(n); |
| @@ -2429,11 +2383,10 @@ | |
| 2383 | {"copybtn", copybtnCmd, 0}, |
| 2384 | {"date", dateCmd, 0}, |
| 2385 | {"decorate", wikiCmd, (void*)&aFlags[2]}, |
| 2386 | {"defHeader", defHeaderCmd, 0}, |
| 2387 | {"dir", dirCmd, 0}, |
| 2388 | {"enable_output", enableOutputCmd, 0}, |
| 2389 | {"encode64", encode64Cmd, 0}, |
| 2390 | {"getParameter", getParameterCmd, 0}, |
| 2391 | {"glob_match", globMatchCmd, 0}, |
| 2392 | {"globalState", globalStateCmd, 0}, |
| @@ -3047,12 +3000,11 @@ | |
| 3000 | ** e.g. via the "render" script function binding, need to use the |
| 3001 | ** pThOut blob in order to avoid out-of-order output if |
| 3002 | ** Th_SetOutputBlob() has been called. If it has not been called, |
| 3003 | ** pThOut will be 0, which will redirect the output to CGI/stdout, |
| 3004 | ** as appropriate. We need to pass on g.th1Flags for the case of |
| 3005 | ** recursive calls. |
| 3006 | */; |
| 3007 | } |
| 3008 | |
| 3009 | /* |
| 3010 | ** SETTING: vuln-report width=8 default=log |
| 3011 |
+8
| --- src/th_tcl.c | ||
| +++ src/th_tcl.c | ||
| @@ -24,10 +24,14 @@ | ||
| 24 | 24 | |
| 25 | 25 | #include "sqlite3.h" |
| 26 | 26 | #include "th.h" |
| 27 | 27 | #include "tcl.h" |
| 28 | 28 | |
| 29 | +#if TCL_MAJOR_VERSION<9 && !defined(Tcl_Size) | |
| 30 | +# define Tcl_Size int | |
| 31 | +#endif | |
| 32 | + | |
| 29 | 33 | /* |
| 30 | 34 | ** This macro is used to verify that the header version of Tcl meets some |
| 31 | 35 | ** minimum requirement. |
| 32 | 36 | */ |
| 33 | 37 | #define MINIMUM_TCL_VERSION(major, minor) \ |
| @@ -183,11 +187,15 @@ | ||
| 183 | 187 | ** the only Tcl API functions that MUST be called prior to being able to call |
| 184 | 188 | ** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). For complete |
| 185 | 189 | ** cleanup if the Tcl stubs initialization fails somehow, the Tcl_DeleteInterp |
| 186 | 190 | ** and Tcl_Finalize function types are also required. |
| 187 | 191 | */ |
| 192 | +#if TCL_MAJOR_VERSION>=9 | |
| 188 | 193 | typedef const char *(tcl_FindExecutableProc) (const char *); |
| 194 | +#else | |
| 195 | +typedef void (tcl_FindExecutableProc) (const char *); | |
| 196 | +#endif | |
| 189 | 197 | typedef Tcl_Interp *(tcl_CreateInterpProc) (void); |
| 190 | 198 | typedef void (tcl_DeleteInterpProc) (Tcl_Interp *); |
| 191 | 199 | typedef void (tcl_FinalizeProc) (void); |
| 192 | 200 | |
| 193 | 201 | /* |
| 194 | 202 |
| --- src/th_tcl.c | |
| +++ src/th_tcl.c | |
| @@ -24,10 +24,14 @@ | |
| 24 | |
| 25 | #include "sqlite3.h" |
| 26 | #include "th.h" |
| 27 | #include "tcl.h" |
| 28 | |
| 29 | /* |
| 30 | ** This macro is used to verify that the header version of Tcl meets some |
| 31 | ** minimum requirement. |
| 32 | */ |
| 33 | #define MINIMUM_TCL_VERSION(major, minor) \ |
| @@ -183,11 +187,15 @@ | |
| 183 | ** the only Tcl API functions that MUST be called prior to being able to call |
| 184 | ** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). For complete |
| 185 | ** cleanup if the Tcl stubs initialization fails somehow, the Tcl_DeleteInterp |
| 186 | ** and Tcl_Finalize function types are also required. |
| 187 | */ |
| 188 | typedef const char *(tcl_FindExecutableProc) (const char *); |
| 189 | typedef Tcl_Interp *(tcl_CreateInterpProc) (void); |
| 190 | typedef void (tcl_DeleteInterpProc) (Tcl_Interp *); |
| 191 | typedef void (tcl_FinalizeProc) (void); |
| 192 | |
| 193 | /* |
| 194 |
| --- src/th_tcl.c | |
| +++ src/th_tcl.c | |
| @@ -24,10 +24,14 @@ | |
| 24 | |
| 25 | #include "sqlite3.h" |
| 26 | #include "th.h" |
| 27 | #include "tcl.h" |
| 28 | |
| 29 | #if TCL_MAJOR_VERSION<9 && !defined(Tcl_Size) |
| 30 | # define Tcl_Size int |
| 31 | #endif |
| 32 | |
| 33 | /* |
| 34 | ** This macro is used to verify that the header version of Tcl meets some |
| 35 | ** minimum requirement. |
| 36 | */ |
| 37 | #define MINIMUM_TCL_VERSION(major, minor) \ |
| @@ -183,11 +187,15 @@ | |
| 187 | ** the only Tcl API functions that MUST be called prior to being able to call |
| 188 | ** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). For complete |
| 189 | ** cleanup if the Tcl stubs initialization fails somehow, the Tcl_DeleteInterp |
| 190 | ** and Tcl_Finalize function types are also required. |
| 191 | */ |
| 192 | #if TCL_MAJOR_VERSION>=9 |
| 193 | typedef const char *(tcl_FindExecutableProc) (const char *); |
| 194 | #else |
| 195 | typedef void (tcl_FindExecutableProc) (const char *); |
| 196 | #endif |
| 197 | typedef Tcl_Interp *(tcl_CreateInterpProc) (void); |
| 198 | typedef void (tcl_DeleteInterpProc) (Tcl_Interp *); |
| 199 | typedef void (tcl_FinalizeProc) (void); |
| 200 | |
| 201 | /* |
| 202 |
+47
-11
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -1273,11 +1273,11 @@ | ||
| 1273 | 1273 | */ |
| 1274 | 1274 | static void addFileGlobExclusion( |
| 1275 | 1275 | const char *zChng, /* The filename GLOB list */ |
| 1276 | 1276 | Blob *pSql /* The SELECT statement under construction */ |
| 1277 | 1277 | ){ |
| 1278 | - if( zChng==0 || zChng[0]==0 ) return; | |
| 1278 | + if( zChng==0 ) return; | |
| 1279 | 1279 | blob_append_sql(pSql," AND event.objid IN (" |
| 1280 | 1280 | "SELECT mlink.mid FROM mlink, filename\n" |
| 1281 | 1281 | " WHERE mlink.fnid=filename.fnid\n" |
| 1282 | 1282 | " AND %s)", |
| 1283 | 1283 | glob_expr("filename.name", mprintf("\"%s\"", zChng))); |
| @@ -1284,14 +1284,33 @@ | ||
| 1284 | 1284 | } |
| 1285 | 1285 | static void addFileGlobDescription( |
| 1286 | 1286 | const char *zChng, /* The filename GLOB list */ |
| 1287 | 1287 | Blob *pDescription /* Result description */ |
| 1288 | 1288 | ){ |
| 1289 | - if( zChng==0 || zChng[0]==0 ) return; | |
| 1289 | + if( zChng==0 ) return; | |
| 1290 | 1290 | blob_appendf(pDescription, " that include changes to files matching '%h'", |
| 1291 | 1291 | zChng); |
| 1292 | 1292 | } |
| 1293 | + | |
| 1294 | +/* | |
| 1295 | +** If zChng is not NULL, then use it as a comma-separated list of | |
| 1296 | +** glob patterns for filenames, and remove from the "ok" table any | |
| 1297 | +** check-ins that do not modify one or more of the files identified | |
| 1298 | +** by zChng. | |
| 1299 | +*/ | |
| 1300 | +static void removeFileGlobFromOk( | |
| 1301 | + const char *zChng /* The filename GLOB list */ | |
| 1302 | +){ | |
| 1303 | + if( zChng==0 ) return; | |
| 1304 | + db_multi_exec( | |
| 1305 | + "DELETE FROM ok WHERE rid NOT IN (\n" | |
| 1306 | + " SELECT mlink.mid FROM mlink, filename\n" | |
| 1307 | + " WHERE mlink.fnid=filename.fnid\n" | |
| 1308 | + " AND %z);\n", | |
| 1309 | + glob_expr("filename.name", zChng) | |
| 1310 | + ); | |
| 1311 | +} | |
| 1293 | 1312 | |
| 1294 | 1313 | /* |
| 1295 | 1314 | ** Similar to fossil_expand_datetime() |
| 1296 | 1315 | ** |
| 1297 | 1316 | ** Add missing "-" characters into a date/time. Examples: |
| @@ -1777,10 +1796,11 @@ | ||
| 1777 | 1796 | nEntry = 0; |
| 1778 | 1797 | useDividers = 0; |
| 1779 | 1798 | cgi_replace_query_parameter("d",fossil_strdup(z)); |
| 1780 | 1799 | zDPNameD = zDPNameP = z; |
| 1781 | 1800 | } |
| 1801 | + if( zChng && zChng[0]==0 ) zChng = 0; | |
| 1782 | 1802 | |
| 1783 | 1803 | /* Undocumented query parameter to set JS mode */ |
| 1784 | 1804 | builtin_set_js_delivery_mode(P("jsmode"),1); |
| 1785 | 1805 | |
| 1786 | 1806 | secondaryRid = name_to_typed_rid(P("sel2"),"ci"); |
| @@ -2175,11 +2195,11 @@ | ||
| 2175 | 2195 | } |
| 2176 | 2196 | db_multi_exec("INSERT OR IGNORE INTO pathnode SELECT x FROM related"); |
| 2177 | 2197 | } |
| 2178 | 2198 | add_extra_rids("pathnode",P("x")); |
| 2179 | 2199 | blob_append_sql(&sql, " AND event.objid IN pathnode"); |
| 2180 | - if( zChng && zChng[0] ){ | |
| 2200 | + if( zChng ){ | |
| 2181 | 2201 | db_multi_exec( |
| 2182 | 2202 | "DELETE FROM pathnode\n" |
| 2183 | 2203 | " WHERE NOT EXISTS(SELECT 1 FROM mlink, filename\n" |
| 2184 | 2204 | " WHERE mlink.mid=x\n" |
| 2185 | 2205 | " AND mlink.fnid=filename.fnid\n" |
| @@ -2299,14 +2319,16 @@ | ||
| 2299 | 2319 | db_multi_exec( |
| 2300 | 2320 | "INSERT INTO ok_d SELECT rid FROM ok;" |
| 2301 | 2321 | "DELETE FROM ok;" |
| 2302 | 2322 | ); |
| 2303 | 2323 | }else{ |
| 2324 | + removeFileGlobFromOk(zChng); | |
| 2304 | 2325 | nd = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2305 | 2326 | if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql)); |
| 2306 | 2327 | if( nd>0 || p_rid==0 ){ |
| 2307 | - blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); | |
| 2328 | + blob_appendf(&desc, "%d descendant%s", | |
| 2329 | + nd>=0 ? nd : 0,(1==nd)?"":"s"); | |
| 2308 | 2330 | } |
| 2309 | 2331 | if( useDividers && !selectedRid ) selectedRid = d_rid; |
| 2310 | 2332 | db_multi_exec("DELETE FROM ok"); |
| 2311 | 2333 | } |
| 2312 | 2334 | } |
| @@ -2335,30 +2357,34 @@ | ||
| 2335 | 2357 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridBackTo); |
| 2336 | 2358 | bBackAdded = 1; |
| 2337 | 2359 | } |
| 2338 | 2360 | if( bSeparateDandP ){ |
| 2339 | 2361 | db_multi_exec("DELETE FROM ok WHERE rid NOT IN ok_d;"); |
| 2362 | + removeFileGlobFromOk(zChng); | |
| 2340 | 2363 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2341 | 2364 | }else{ |
| 2365 | + removeFileGlobFromOk(zChng); | |
| 2342 | 2366 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2343 | 2367 | if( np>0 || nd==0 ){ |
| 2344 | 2368 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 2345 | - blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s"); | |
| 2369 | + blob_appendf(&desc, "%d ancestor%s", | |
| 2370 | + np>=0 ? np : 0, (1==np)?"":"s"); | |
| 2346 | 2371 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2347 | 2372 | } |
| 2348 | 2373 | if( useDividers && !selectedRid ) selectedRid = p_rid; |
| 2349 | 2374 | } |
| 2350 | 2375 | } |
| 2376 | + | |
| 2351 | 2377 | if( bSeparateDandP ){ |
| 2352 | 2378 | int n = db_int(0, "SELECT count(*) FROM ok"); |
| 2353 | 2379 | blob_reset(&desc); |
| 2354 | 2380 | blob_appendf(&desc, |
| 2355 | - "%d check-ins that are both ancestors of %z%h</a>" | |
| 2356 | - " and descendants of %z%h</a>", | |
| 2381 | + "%d check-ins that are derived from %z%h</a>" | |
| 2382 | + " and contribute to %z%h</a>", | |
| 2357 | 2383 | n, |
| 2358 | - href("%R/info?name=%h",zDPNameP),zDPNameP, | |
| 2359 | - href("%R/info?name=%h",zDPNameD),zDPNameD | |
| 2384 | + href("%R/info?name=%h",zDPNameD),zDPNameD, | |
| 2385 | + href("%R/info?name=%h",zDPNameP),zDPNameP | |
| 2360 | 2386 | ); |
| 2361 | 2387 | ridBackTo = 0; |
| 2362 | 2388 | ridFwdTo = 0; |
| 2363 | 2389 | }else{ |
| 2364 | 2390 | blob_appendf(&desc, " of %z%h</a>", |
| @@ -2392,10 +2418,14 @@ | ||
| 2392 | 2418 | blob_appendf(&desc, " up to %z%h</a>%s", |
| 2393 | 2419 | href("%R/info?name=%h",zFwdTo), zFwdTo, |
| 2394 | 2420 | bFwdAdded ? " (not a direct descendant)":""); |
| 2395 | 2421 | } |
| 2396 | 2422 | } |
| 2423 | + if( zChng ){ | |
| 2424 | + if( strstr(blob_str(&desc)," that ") ) blob_appendf(&desc, " and"); | |
| 2425 | + blob_appendf(&desc, " that make changes to files matching \"%h\"", zChng); | |
| 2426 | + } | |
| 2397 | 2427 | if( advancedMenu ){ |
| 2398 | 2428 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); |
| 2399 | 2429 | } |
| 2400 | 2430 | style_submenu_entry("n","Max:",4,0); |
| 2401 | 2431 | timeline_y_submenu(1); |
| @@ -3816,13 +3846,19 @@ | ||
| 3816 | 3846 | " AND (tagxref.value IS NULL OR tagxref.value='%q')", |
| 3817 | 3847 | zBr, zBr, zBr, TAG_BRANCH, zBr, zBr); |
| 3818 | 3848 | } |
| 3819 | 3849 | |
| 3820 | 3850 | if( mode==TIMELINE_MODE_AFTER ){ |
| 3851 | + int lim = n; | |
| 3852 | + if( n == 0 ){ | |
| 3853 | + lim = -1; /* 0 means no limit */ | |
| 3854 | + }else if( n < 0 ){ | |
| 3855 | + lim = -n; | |
| 3856 | + } | |
| 3821 | 3857 | /* Complete the above outer select. */ |
| 3822 | 3858 | blob_append_sql(&sql, |
| 3823 | - "\nORDER BY event.mtime LIMIT abs(%d)) t ORDER BY t.mDateTime DESC;", n); | |
| 3859 | + "\nORDER BY event.mtime LIMIT %d) t ORDER BY t.mDateTime DESC;", lim); | |
| 3824 | 3860 | }else{ |
| 3825 | 3861 | blob_append_sql(&sql, "\nORDER BY event.mtime DESC"); |
| 3826 | 3862 | } |
| 3827 | 3863 | if( iOffset>0 ){ |
| 3828 | 3864 | /* Don't handle LIMIT here, otherwise print_timeline() |
| @@ -3847,11 +3883,11 @@ | ||
| 3847 | 3883 | ** Query parameters: |
| 3848 | 3884 | ** |
| 3849 | 3885 | ** today=DATE Use DATE as today's date |
| 3850 | 3886 | */ |
| 3851 | 3887 | void thisdayinhistory_page(void){ |
| 3852 | - static int aYearsAgo[] = { 1, 2, 3, 4, 5, 10, 15, 20, 30, 40, 50, 75, 100 }; | |
| 3888 | + static int aYearsAgo[] = { 1,2,3,4,5,10,15,20,25,30,40,50,75,100 }; | |
| 3853 | 3889 | const char *zToday; |
| 3854 | 3890 | char *zStartOfProject; |
| 3855 | 3891 | int i; |
| 3856 | 3892 | Stmt q; |
| 3857 | 3893 | char *z; |
| 3858 | 3894 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1273,11 +1273,11 @@ | |
| 1273 | */ |
| 1274 | static void addFileGlobExclusion( |
| 1275 | const char *zChng, /* The filename GLOB list */ |
| 1276 | Blob *pSql /* The SELECT statement under construction */ |
| 1277 | ){ |
| 1278 | if( zChng==0 || zChng[0]==0 ) return; |
| 1279 | blob_append_sql(pSql," AND event.objid IN (" |
| 1280 | "SELECT mlink.mid FROM mlink, filename\n" |
| 1281 | " WHERE mlink.fnid=filename.fnid\n" |
| 1282 | " AND %s)", |
| 1283 | glob_expr("filename.name", mprintf("\"%s\"", zChng))); |
| @@ -1284,14 +1284,33 @@ | |
| 1284 | } |
| 1285 | static void addFileGlobDescription( |
| 1286 | const char *zChng, /* The filename GLOB list */ |
| 1287 | Blob *pDescription /* Result description */ |
| 1288 | ){ |
| 1289 | if( zChng==0 || zChng[0]==0 ) return; |
| 1290 | blob_appendf(pDescription, " that include changes to files matching '%h'", |
| 1291 | zChng); |
| 1292 | } |
| 1293 | |
| 1294 | /* |
| 1295 | ** Similar to fossil_expand_datetime() |
| 1296 | ** |
| 1297 | ** Add missing "-" characters into a date/time. Examples: |
| @@ -1777,10 +1796,11 @@ | |
| 1777 | nEntry = 0; |
| 1778 | useDividers = 0; |
| 1779 | cgi_replace_query_parameter("d",fossil_strdup(z)); |
| 1780 | zDPNameD = zDPNameP = z; |
| 1781 | } |
| 1782 | |
| 1783 | /* Undocumented query parameter to set JS mode */ |
| 1784 | builtin_set_js_delivery_mode(P("jsmode"),1); |
| 1785 | |
| 1786 | secondaryRid = name_to_typed_rid(P("sel2"),"ci"); |
| @@ -2175,11 +2195,11 @@ | |
| 2175 | } |
| 2176 | db_multi_exec("INSERT OR IGNORE INTO pathnode SELECT x FROM related"); |
| 2177 | } |
| 2178 | add_extra_rids("pathnode",P("x")); |
| 2179 | blob_append_sql(&sql, " AND event.objid IN pathnode"); |
| 2180 | if( zChng && zChng[0] ){ |
| 2181 | db_multi_exec( |
| 2182 | "DELETE FROM pathnode\n" |
| 2183 | " WHERE NOT EXISTS(SELECT 1 FROM mlink, filename\n" |
| 2184 | " WHERE mlink.mid=x\n" |
| 2185 | " AND mlink.fnid=filename.fnid\n" |
| @@ -2299,14 +2319,16 @@ | |
| 2299 | db_multi_exec( |
| 2300 | "INSERT INTO ok_d SELECT rid FROM ok;" |
| 2301 | "DELETE FROM ok;" |
| 2302 | ); |
| 2303 | }else{ |
| 2304 | nd = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2305 | if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql)); |
| 2306 | if( nd>0 || p_rid==0 ){ |
| 2307 | blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); |
| 2308 | } |
| 2309 | if( useDividers && !selectedRid ) selectedRid = d_rid; |
| 2310 | db_multi_exec("DELETE FROM ok"); |
| 2311 | } |
| 2312 | } |
| @@ -2335,30 +2357,34 @@ | |
| 2335 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridBackTo); |
| 2336 | bBackAdded = 1; |
| 2337 | } |
| 2338 | if( bSeparateDandP ){ |
| 2339 | db_multi_exec("DELETE FROM ok WHERE rid NOT IN ok_d;"); |
| 2340 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2341 | }else{ |
| 2342 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2343 | if( np>0 || nd==0 ){ |
| 2344 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 2345 | blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s"); |
| 2346 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2347 | } |
| 2348 | if( useDividers && !selectedRid ) selectedRid = p_rid; |
| 2349 | } |
| 2350 | } |
| 2351 | if( bSeparateDandP ){ |
| 2352 | int n = db_int(0, "SELECT count(*) FROM ok"); |
| 2353 | blob_reset(&desc); |
| 2354 | blob_appendf(&desc, |
| 2355 | "%d check-ins that are both ancestors of %z%h</a>" |
| 2356 | " and descendants of %z%h</a>", |
| 2357 | n, |
| 2358 | href("%R/info?name=%h",zDPNameP),zDPNameP, |
| 2359 | href("%R/info?name=%h",zDPNameD),zDPNameD |
| 2360 | ); |
| 2361 | ridBackTo = 0; |
| 2362 | ridFwdTo = 0; |
| 2363 | }else{ |
| 2364 | blob_appendf(&desc, " of %z%h</a>", |
| @@ -2392,10 +2418,14 @@ | |
| 2392 | blob_appendf(&desc, " up to %z%h</a>%s", |
| 2393 | href("%R/info?name=%h",zFwdTo), zFwdTo, |
| 2394 | bFwdAdded ? " (not a direct descendant)":""); |
| 2395 | } |
| 2396 | } |
| 2397 | if( advancedMenu ){ |
| 2398 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); |
| 2399 | } |
| 2400 | style_submenu_entry("n","Max:",4,0); |
| 2401 | timeline_y_submenu(1); |
| @@ -3816,13 +3846,19 @@ | |
| 3816 | " AND (tagxref.value IS NULL OR tagxref.value='%q')", |
| 3817 | zBr, zBr, zBr, TAG_BRANCH, zBr, zBr); |
| 3818 | } |
| 3819 | |
| 3820 | if( mode==TIMELINE_MODE_AFTER ){ |
| 3821 | /* Complete the above outer select. */ |
| 3822 | blob_append_sql(&sql, |
| 3823 | "\nORDER BY event.mtime LIMIT abs(%d)) t ORDER BY t.mDateTime DESC;", n); |
| 3824 | }else{ |
| 3825 | blob_append_sql(&sql, "\nORDER BY event.mtime DESC"); |
| 3826 | } |
| 3827 | if( iOffset>0 ){ |
| 3828 | /* Don't handle LIMIT here, otherwise print_timeline() |
| @@ -3847,11 +3883,11 @@ | |
| 3847 | ** Query parameters: |
| 3848 | ** |
| 3849 | ** today=DATE Use DATE as today's date |
| 3850 | */ |
| 3851 | void thisdayinhistory_page(void){ |
| 3852 | static int aYearsAgo[] = { 1, 2, 3, 4, 5, 10, 15, 20, 30, 40, 50, 75, 100 }; |
| 3853 | const char *zToday; |
| 3854 | char *zStartOfProject; |
| 3855 | int i; |
| 3856 | Stmt q; |
| 3857 | char *z; |
| 3858 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1273,11 +1273,11 @@ | |
| 1273 | */ |
| 1274 | static void addFileGlobExclusion( |
| 1275 | const char *zChng, /* The filename GLOB list */ |
| 1276 | Blob *pSql /* The SELECT statement under construction */ |
| 1277 | ){ |
| 1278 | if( zChng==0 ) return; |
| 1279 | blob_append_sql(pSql," AND event.objid IN (" |
| 1280 | "SELECT mlink.mid FROM mlink, filename\n" |
| 1281 | " WHERE mlink.fnid=filename.fnid\n" |
| 1282 | " AND %s)", |
| 1283 | glob_expr("filename.name", mprintf("\"%s\"", zChng))); |
| @@ -1284,14 +1284,33 @@ | |
| 1284 | } |
| 1285 | static void addFileGlobDescription( |
| 1286 | const char *zChng, /* The filename GLOB list */ |
| 1287 | Blob *pDescription /* Result description */ |
| 1288 | ){ |
| 1289 | if( zChng==0 ) return; |
| 1290 | blob_appendf(pDescription, " that include changes to files matching '%h'", |
| 1291 | zChng); |
| 1292 | } |
| 1293 | |
| 1294 | /* |
| 1295 | ** If zChng is not NULL, then use it as a comma-separated list of |
| 1296 | ** glob patterns for filenames, and remove from the "ok" table any |
| 1297 | ** check-ins that do not modify one or more of the files identified |
| 1298 | ** by zChng. |
| 1299 | */ |
| 1300 | static void removeFileGlobFromOk( |
| 1301 | const char *zChng /* The filename GLOB list */ |
| 1302 | ){ |
| 1303 | if( zChng==0 ) return; |
| 1304 | db_multi_exec( |
| 1305 | "DELETE FROM ok WHERE rid NOT IN (\n" |
| 1306 | " SELECT mlink.mid FROM mlink, filename\n" |
| 1307 | " WHERE mlink.fnid=filename.fnid\n" |
| 1308 | " AND %z);\n", |
| 1309 | glob_expr("filename.name", zChng) |
| 1310 | ); |
| 1311 | } |
| 1312 | |
| 1313 | /* |
| 1314 | ** Similar to fossil_expand_datetime() |
| 1315 | ** |
| 1316 | ** Add missing "-" characters into a date/time. Examples: |
| @@ -1777,10 +1796,11 @@ | |
| 1796 | nEntry = 0; |
| 1797 | useDividers = 0; |
| 1798 | cgi_replace_query_parameter("d",fossil_strdup(z)); |
| 1799 | zDPNameD = zDPNameP = z; |
| 1800 | } |
| 1801 | if( zChng && zChng[0]==0 ) zChng = 0; |
| 1802 | |
| 1803 | /* Undocumented query parameter to set JS mode */ |
| 1804 | builtin_set_js_delivery_mode(P("jsmode"),1); |
| 1805 | |
| 1806 | secondaryRid = name_to_typed_rid(P("sel2"),"ci"); |
| @@ -2175,11 +2195,11 @@ | |
| 2195 | } |
| 2196 | db_multi_exec("INSERT OR IGNORE INTO pathnode SELECT x FROM related"); |
| 2197 | } |
| 2198 | add_extra_rids("pathnode",P("x")); |
| 2199 | blob_append_sql(&sql, " AND event.objid IN pathnode"); |
| 2200 | if( zChng ){ |
| 2201 | db_multi_exec( |
| 2202 | "DELETE FROM pathnode\n" |
| 2203 | " WHERE NOT EXISTS(SELECT 1 FROM mlink, filename\n" |
| 2204 | " WHERE mlink.mid=x\n" |
| 2205 | " AND mlink.fnid=filename.fnid\n" |
| @@ -2299,14 +2319,16 @@ | |
| 2319 | db_multi_exec( |
| 2320 | "INSERT INTO ok_d SELECT rid FROM ok;" |
| 2321 | "DELETE FROM ok;" |
| 2322 | ); |
| 2323 | }else{ |
| 2324 | removeFileGlobFromOk(zChng); |
| 2325 | nd = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2326 | if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql)); |
| 2327 | if( nd>0 || p_rid==0 ){ |
| 2328 | blob_appendf(&desc, "%d descendant%s", |
| 2329 | nd>=0 ? nd : 0,(1==nd)?"":"s"); |
| 2330 | } |
| 2331 | if( useDividers && !selectedRid ) selectedRid = d_rid; |
| 2332 | db_multi_exec("DELETE FROM ok"); |
| 2333 | } |
| 2334 | } |
| @@ -2335,30 +2357,34 @@ | |
| 2357 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridBackTo); |
| 2358 | bBackAdded = 1; |
| 2359 | } |
| 2360 | if( bSeparateDandP ){ |
| 2361 | db_multi_exec("DELETE FROM ok WHERE rid NOT IN ok_d;"); |
| 2362 | removeFileGlobFromOk(zChng); |
| 2363 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2364 | }else{ |
| 2365 | removeFileGlobFromOk(zChng); |
| 2366 | np = db_int(0, "SELECT count(*)-1 FROM ok"); |
| 2367 | if( np>0 || nd==0 ){ |
| 2368 | if( nd>0 ) blob_appendf(&desc, " and "); |
| 2369 | blob_appendf(&desc, "%d ancestor%s", |
| 2370 | np>=0 ? np : 0, (1==np)?"":"s"); |
| 2371 | db_multi_exec("%s", blob_sql_text(&sql)); |
| 2372 | } |
| 2373 | if( useDividers && !selectedRid ) selectedRid = p_rid; |
| 2374 | } |
| 2375 | } |
| 2376 | |
| 2377 | if( bSeparateDandP ){ |
| 2378 | int n = db_int(0, "SELECT count(*) FROM ok"); |
| 2379 | blob_reset(&desc); |
| 2380 | blob_appendf(&desc, |
| 2381 | "%d check-ins that are derived from %z%h</a>" |
| 2382 | " and contribute to %z%h</a>", |
| 2383 | n, |
| 2384 | href("%R/info?name=%h",zDPNameD),zDPNameD, |
| 2385 | href("%R/info?name=%h",zDPNameP),zDPNameP |
| 2386 | ); |
| 2387 | ridBackTo = 0; |
| 2388 | ridFwdTo = 0; |
| 2389 | }else{ |
| 2390 | blob_appendf(&desc, " of %z%h</a>", |
| @@ -2392,10 +2418,14 @@ | |
| 2418 | blob_appendf(&desc, " up to %z%h</a>%s", |
| 2419 | href("%R/info?name=%h",zFwdTo), zFwdTo, |
| 2420 | bFwdAdded ? " (not a direct descendant)":""); |
| 2421 | } |
| 2422 | } |
| 2423 | if( zChng ){ |
| 2424 | if( strstr(blob_str(&desc)," that ") ) blob_appendf(&desc, " and"); |
| 2425 | blob_appendf(&desc, " that make changes to files matching \"%h\"", zChng); |
| 2426 | } |
| 2427 | if( advancedMenu ){ |
| 2428 | style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0); |
| 2429 | } |
| 2430 | style_submenu_entry("n","Max:",4,0); |
| 2431 | timeline_y_submenu(1); |
| @@ -3816,13 +3846,19 @@ | |
| 3846 | " AND (tagxref.value IS NULL OR tagxref.value='%q')", |
| 3847 | zBr, zBr, zBr, TAG_BRANCH, zBr, zBr); |
| 3848 | } |
| 3849 | |
| 3850 | if( mode==TIMELINE_MODE_AFTER ){ |
| 3851 | int lim = n; |
| 3852 | if( n == 0 ){ |
| 3853 | lim = -1; /* 0 means no limit */ |
| 3854 | }else if( n < 0 ){ |
| 3855 | lim = -n; |
| 3856 | } |
| 3857 | /* Complete the above outer select. */ |
| 3858 | blob_append_sql(&sql, |
| 3859 | "\nORDER BY event.mtime LIMIT %d) t ORDER BY t.mDateTime DESC;", lim); |
| 3860 | }else{ |
| 3861 | blob_append_sql(&sql, "\nORDER BY event.mtime DESC"); |
| 3862 | } |
| 3863 | if( iOffset>0 ){ |
| 3864 | /* Don't handle LIMIT here, otherwise print_timeline() |
| @@ -3847,11 +3883,11 @@ | |
| 3883 | ** Query parameters: |
| 3884 | ** |
| 3885 | ** today=DATE Use DATE as today's date |
| 3886 | */ |
| 3887 | void thisdayinhistory_page(void){ |
| 3888 | static int aYearsAgo[] = { 1,2,3,4,5,10,15,20,25,30,40,50,75,100 }; |
| 3889 | const char *zToday; |
| 3890 | char *zStartOfProject; |
| 3891 | int i; |
| 3892 | Stmt q; |
| 3893 | char *z; |
| 3894 |
-4
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -776,14 +776,10 @@ | ||
| 776 | 776 | style_submenu_element("Timeline", "%R/info/%T", zUuid); |
| 777 | 777 | } |
| 778 | 778 | zFullName = db_text(0, |
| 779 | 779 | "SELECT tkt_uuid FROM ticket" |
| 780 | 780 | " WHERE tkt_uuid GLOB '%q*'", zUuid); |
| 781 | - if( g.perm.WrWiki && g.perm.WrTkt ){ | |
| 782 | - style_submenu_element("Edit Description", | |
| 783 | - "%R/wikiedit?name=ticket/%T", zFullName); | |
| 784 | - } | |
| 785 | 781 | if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br>\n", -1); |
| 786 | 782 | ticket_init(); |
| 787 | 783 | initializeVariablesFromCGI(); |
| 788 | 784 | getAllTicketFields(); |
| 789 | 785 | initializeVariablesFromDb(); |
| 790 | 786 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -776,14 +776,10 @@ | |
| 776 | style_submenu_element("Timeline", "%R/info/%T", zUuid); |
| 777 | } |
| 778 | zFullName = db_text(0, |
| 779 | "SELECT tkt_uuid FROM ticket" |
| 780 | " WHERE tkt_uuid GLOB '%q*'", zUuid); |
| 781 | if( g.perm.WrWiki && g.perm.WrTkt ){ |
| 782 | style_submenu_element("Edit Description", |
| 783 | "%R/wikiedit?name=ticket/%T", zFullName); |
| 784 | } |
| 785 | if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br>\n", -1); |
| 786 | ticket_init(); |
| 787 | initializeVariablesFromCGI(); |
| 788 | getAllTicketFields(); |
| 789 | initializeVariablesFromDb(); |
| 790 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -776,14 +776,10 @@ | |
| 776 | style_submenu_element("Timeline", "%R/info/%T", zUuid); |
| 777 | } |
| 778 | zFullName = db_text(0, |
| 779 | "SELECT tkt_uuid FROM ticket" |
| 780 | " WHERE tkt_uuid GLOB '%q*'", zUuid); |
| 781 | if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br>\n", -1); |
| 782 | ticket_init(); |
| 783 | initializeVariablesFromCGI(); |
| 784 | getAllTicketFields(); |
| 785 | initializeVariablesFromDb(); |
| 786 |
+3
| --- src/tktsetup.c | ||
| +++ src/tktsetup.c | ||
| @@ -496,10 +496,13 @@ | ||
| 496 | 496 | @ } |
| 497 | 497 | @ |
| 498 | 498 | @ if {[capexpr {n}]} { |
| 499 | 499 | @ submenu link "Copy Ticket" /tktnew/$tkt_uuid |
| 500 | 500 | @ } |
| 501 | +@ if {[capexpr {nk}]} { | |
| 502 | +@ submenu link "Edit Wiki" /wikiedit?name=ticket/$tkt_uuid | |
| 503 | +@ } | |
| 501 | 504 | @ </th1> |
| 502 | 505 | @ <tr><td class="tktDspLabel">Title:</td> |
| 503 | 506 | @ <td class="tktDspValue" colspan="3"> |
| 504 | 507 | @ $<title> |
| 505 | 508 | @ </td></tr> |
| 506 | 509 |
| --- src/tktsetup.c | |
| +++ src/tktsetup.c | |
| @@ -496,10 +496,13 @@ | |
| 496 | @ } |
| 497 | @ |
| 498 | @ if {[capexpr {n}]} { |
| 499 | @ submenu link "Copy Ticket" /tktnew/$tkt_uuid |
| 500 | @ } |
| 501 | @ </th1> |
| 502 | @ <tr><td class="tktDspLabel">Title:</td> |
| 503 | @ <td class="tktDspValue" colspan="3"> |
| 504 | @ $<title> |
| 505 | @ </td></tr> |
| 506 |
| --- src/tktsetup.c | |
| +++ src/tktsetup.c | |
| @@ -496,10 +496,13 @@ | |
| 496 | @ } |
| 497 | @ |
| 498 | @ if {[capexpr {n}]} { |
| 499 | @ submenu link "Copy Ticket" /tktnew/$tkt_uuid |
| 500 | @ } |
| 501 | @ if {[capexpr {nk}]} { |
| 502 | @ submenu link "Edit Wiki" /wikiedit?name=ticket/$tkt_uuid |
| 503 | @ } |
| 504 | @ </th1> |
| 505 | @ <tr><td class="tktDspLabel">Title:</td> |
| 506 | @ <td class="tktDspValue" colspan="3"> |
| 507 | @ $<title> |
| 508 | @ </td></tr> |
| 509 |
+34
-19
| --- src/winfile.c | ||
| +++ src/winfile.c | ||
| @@ -304,39 +304,47 @@ | ||
| 304 | 304 | */ |
| 305 | 305 | int win32_filenames_equal_nocase( |
| 306 | 306 | const wchar_t *fn1, |
| 307 | 307 | const wchar_t *fn2 |
| 308 | 308 | ){ |
| 309 | - static FARPROC fnCompareStringOrdinal; | |
| 310 | - static FARPROC fnRtlInitUnicodeString; | |
| 311 | - static FARPROC fnRtlEqualUnicodeString; | |
| 309 | + /* ---- Data types used by dynamically loaded API functions. -------------- */ | |
| 310 | + typedef struct { /* UNICODE_STRING from <ntdef.h> */ | |
| 311 | + USHORT Length; | |
| 312 | + USHORT MaximumLength; | |
| 313 | + PWSTR Buffer; | |
| 314 | + } MY_UNICODE_STRING; | |
| 315 | + /* ---- Prototypes for dynamically loaded API functions. ------------------ */ | |
| 316 | + typedef int (WINAPI *FNCOMPARESTRINGORDINAL)(LPCWCH,int,LPCWCH,int,BOOL); | |
| 317 | + typedef VOID (NTAPI *FNRTLINITUNICODESTRING)(MY_UNICODE_STRING*,PCWSTR); | |
| 318 | + typedef BOOLEAN (NTAPI *FNRTLEQUALUNICODESTRING) | |
| 319 | + (MY_UNICODE_STRING*,MY_UNICODE_STRING*,BOOLEAN); | |
| 320 | + /* ------------------------------------------------------------------------ */ | |
| 321 | + static FNCOMPARESTRINGORDINAL fnCompareStringOrdinal; | |
| 322 | + static FNRTLINITUNICODESTRING fnRtlInitUnicodeString; | |
| 323 | + static FNRTLEQUALUNICODESTRING fnRtlEqualUnicodeString; | |
| 312 | 324 | static int loaded_CompareStringOrdinal; |
| 313 | 325 | static int loaded_RtlUnicodeStringAPIs; |
| 314 | 326 | if( !loaded_CompareStringOrdinal ){ |
| 315 | - fnCompareStringOrdinal = | |
| 327 | + fnCompareStringOrdinal = (FNCOMPARESTRINGORDINAL) | |
| 316 | 328 | GetProcAddress(GetModuleHandleA("kernel32"),"CompareStringOrdinal"); |
| 317 | 329 | loaded_CompareStringOrdinal = 1; |
| 318 | 330 | } |
| 319 | 331 | if( fnCompareStringOrdinal ){ |
| 320 | 332 | return fnCompareStringOrdinal(fn1,-1,fn2,-1,1)-2==0; |
| 321 | 333 | } |
| 322 | 334 | if( !loaded_RtlUnicodeStringAPIs ){ |
| 323 | - fnRtlInitUnicodeString = | |
| 335 | + fnRtlInitUnicodeString = (FNRTLINITUNICODESTRING) | |
| 324 | 336 | GetProcAddress(GetModuleHandleA("ntdll"),"RtlInitUnicodeString"); |
| 325 | - fnRtlEqualUnicodeString = | |
| 337 | + fnRtlEqualUnicodeString = (FNRTLEQUALUNICODESTRING) | |
| 326 | 338 | GetProcAddress(GetModuleHandleA("ntdll"),"RtlEqualUnicodeString"); |
| 327 | 339 | loaded_RtlUnicodeStringAPIs = 1; |
| 328 | 340 | } |
| 329 | 341 | if( fnRtlInitUnicodeString && fnRtlEqualUnicodeString ){ |
| 330 | - struct { /* UNICODE_STRING from <ntdef.h> */ | |
| 331 | - unsigned short Length; | |
| 332 | - unsigned short MaximumLength; | |
| 333 | - wchar_t *Buffer; | |
| 334 | - } u1, u2; | |
| 342 | + MY_UNICODE_STRING u1, u2; | |
| 335 | 343 | fnRtlInitUnicodeString(&u1,fn1); |
| 336 | 344 | fnRtlInitUnicodeString(&u2,fn2); |
| 337 | - return (unsigned char)fnRtlEqualUnicodeString(&u1,&u2,1); | |
| 345 | + return (BOOLEAN/*unsigned char*/)fnRtlEqualUnicodeString(&u1,&u2,1); | |
| 338 | 346 | } |
| 339 | 347 | /* In what kind of strange parallel universe are we? */ |
| 340 | 348 | return lstrcmpiW(fn1,fn2)==0; |
| 341 | 349 | } |
| 342 | 350 | |
| @@ -461,11 +469,20 @@ | ||
| 461 | 469 | ** is allocated by mprintf(), or NULL on failure. |
| 462 | 470 | */ |
| 463 | 471 | char *win32_file_id( |
| 464 | 472 | const char *zFileName |
| 465 | 473 | ){ |
| 466 | - static FARPROC fnGetFileInformationByHandleEx; | |
| 474 | + /* ---- Data types used by dynamically loaded API functions. -------------- */ | |
| 475 | + typedef struct { /* FILE_ID_INFO from <winbase.h> */ | |
| 476 | + ULONGLONG VolumeSerialNumber; | |
| 477 | + BYTE FileId[16]; | |
| 478 | + } MY_FILE_ID_INFO; | |
| 479 | + /* ---- Prototypes for dynamically loaded API functions. ------------------ */ | |
| 480 | + typedef int (WINAPI *FNGETFILEINFORMATIONBYHANDLEEX) | |
| 481 | + (HANDLE,int/*enum*/,MY_FILE_ID_INFO*,DWORD); | |
| 482 | + /* ------------------------------------------------------------------------ */ | |
| 483 | + static FNGETFILEINFORMATIONBYHANDLEEX fnGetFileInformationByHandleEx; | |
| 467 | 484 | static int loaded_fnGetFileInformationByHandleEx; |
| 468 | 485 | wchar_t *wzFileName = fossil_utf8_to_path(zFileName,0); |
| 469 | 486 | HANDLE hFile; |
| 470 | 487 | char *zFileId = 0; |
| 471 | 488 | hFile = CreateFileW( |
| @@ -476,17 +493,15 @@ | ||
| 476 | 493 | OPEN_EXISTING, |
| 477 | 494 | FILE_FLAG_BACKUP_SEMANTICS, |
| 478 | 495 | NULL); |
| 479 | 496 | if( hFile!=INVALID_HANDLE_VALUE ){ |
| 480 | 497 | BY_HANDLE_FILE_INFORMATION fi; |
| 481 | - struct { /* FILE_ID_INFO from <winbase.h> */ | |
| 482 | - u64 VolumeSerialNumber; | |
| 483 | - unsigned char FileId[16]; | |
| 484 | - } fi2; | |
| 498 | + MY_FILE_ID_INFO fi2; | |
| 485 | 499 | if( !loaded_fnGetFileInformationByHandleEx ){ |
| 486 | - fnGetFileInformationByHandleEx = GetProcAddress( | |
| 487 | - GetModuleHandleA("kernel32"),"GetFileInformationByHandleEx"); | |
| 500 | + fnGetFileInformationByHandleEx = (FNGETFILEINFORMATIONBYHANDLEEX) | |
| 501 | + GetProcAddress( | |
| 502 | + GetModuleHandleA("kernel32"),"GetFileInformationByHandleEx"); | |
| 488 | 503 | loaded_fnGetFileInformationByHandleEx = 1; |
| 489 | 504 | } |
| 490 | 505 | if( fnGetFileInformationByHandleEx ){ |
| 491 | 506 | if( fnGetFileInformationByHandleEx( |
| 492 | 507 | hFile,/*FileIdInfo*/0x12,&fi2,sizeof(fi2)) ){ |
| 493 | 508 |
| --- src/winfile.c | |
| +++ src/winfile.c | |
| @@ -304,39 +304,47 @@ | |
| 304 | */ |
| 305 | int win32_filenames_equal_nocase( |
| 306 | const wchar_t *fn1, |
| 307 | const wchar_t *fn2 |
| 308 | ){ |
| 309 | static FARPROC fnCompareStringOrdinal; |
| 310 | static FARPROC fnRtlInitUnicodeString; |
| 311 | static FARPROC fnRtlEqualUnicodeString; |
| 312 | static int loaded_CompareStringOrdinal; |
| 313 | static int loaded_RtlUnicodeStringAPIs; |
| 314 | if( !loaded_CompareStringOrdinal ){ |
| 315 | fnCompareStringOrdinal = |
| 316 | GetProcAddress(GetModuleHandleA("kernel32"),"CompareStringOrdinal"); |
| 317 | loaded_CompareStringOrdinal = 1; |
| 318 | } |
| 319 | if( fnCompareStringOrdinal ){ |
| 320 | return fnCompareStringOrdinal(fn1,-1,fn2,-1,1)-2==0; |
| 321 | } |
| 322 | if( !loaded_RtlUnicodeStringAPIs ){ |
| 323 | fnRtlInitUnicodeString = |
| 324 | GetProcAddress(GetModuleHandleA("ntdll"),"RtlInitUnicodeString"); |
| 325 | fnRtlEqualUnicodeString = |
| 326 | GetProcAddress(GetModuleHandleA("ntdll"),"RtlEqualUnicodeString"); |
| 327 | loaded_RtlUnicodeStringAPIs = 1; |
| 328 | } |
| 329 | if( fnRtlInitUnicodeString && fnRtlEqualUnicodeString ){ |
| 330 | struct { /* UNICODE_STRING from <ntdef.h> */ |
| 331 | unsigned short Length; |
| 332 | unsigned short MaximumLength; |
| 333 | wchar_t *Buffer; |
| 334 | } u1, u2; |
| 335 | fnRtlInitUnicodeString(&u1,fn1); |
| 336 | fnRtlInitUnicodeString(&u2,fn2); |
| 337 | return (unsigned char)fnRtlEqualUnicodeString(&u1,&u2,1); |
| 338 | } |
| 339 | /* In what kind of strange parallel universe are we? */ |
| 340 | return lstrcmpiW(fn1,fn2)==0; |
| 341 | } |
| 342 | |
| @@ -461,11 +469,20 @@ | |
| 461 | ** is allocated by mprintf(), or NULL on failure. |
| 462 | */ |
| 463 | char *win32_file_id( |
| 464 | const char *zFileName |
| 465 | ){ |
| 466 | static FARPROC fnGetFileInformationByHandleEx; |
| 467 | static int loaded_fnGetFileInformationByHandleEx; |
| 468 | wchar_t *wzFileName = fossil_utf8_to_path(zFileName,0); |
| 469 | HANDLE hFile; |
| 470 | char *zFileId = 0; |
| 471 | hFile = CreateFileW( |
| @@ -476,17 +493,15 @@ | |
| 476 | OPEN_EXISTING, |
| 477 | FILE_FLAG_BACKUP_SEMANTICS, |
| 478 | NULL); |
| 479 | if( hFile!=INVALID_HANDLE_VALUE ){ |
| 480 | BY_HANDLE_FILE_INFORMATION fi; |
| 481 | struct { /* FILE_ID_INFO from <winbase.h> */ |
| 482 | u64 VolumeSerialNumber; |
| 483 | unsigned char FileId[16]; |
| 484 | } fi2; |
| 485 | if( !loaded_fnGetFileInformationByHandleEx ){ |
| 486 | fnGetFileInformationByHandleEx = GetProcAddress( |
| 487 | GetModuleHandleA("kernel32"),"GetFileInformationByHandleEx"); |
| 488 | loaded_fnGetFileInformationByHandleEx = 1; |
| 489 | } |
| 490 | if( fnGetFileInformationByHandleEx ){ |
| 491 | if( fnGetFileInformationByHandleEx( |
| 492 | hFile,/*FileIdInfo*/0x12,&fi2,sizeof(fi2)) ){ |
| 493 |
| --- src/winfile.c | |
| +++ src/winfile.c | |
| @@ -304,39 +304,47 @@ | |
| 304 | */ |
| 305 | int win32_filenames_equal_nocase( |
| 306 | const wchar_t *fn1, |
| 307 | const wchar_t *fn2 |
| 308 | ){ |
| 309 | /* ---- Data types used by dynamically loaded API functions. -------------- */ |
| 310 | typedef struct { /* UNICODE_STRING from <ntdef.h> */ |
| 311 | USHORT Length; |
| 312 | USHORT MaximumLength; |
| 313 | PWSTR Buffer; |
| 314 | } MY_UNICODE_STRING; |
| 315 | /* ---- Prototypes for dynamically loaded API functions. ------------------ */ |
| 316 | typedef int (WINAPI *FNCOMPARESTRINGORDINAL)(LPCWCH,int,LPCWCH,int,BOOL); |
| 317 | typedef VOID (NTAPI *FNRTLINITUNICODESTRING)(MY_UNICODE_STRING*,PCWSTR); |
| 318 | typedef BOOLEAN (NTAPI *FNRTLEQUALUNICODESTRING) |
| 319 | (MY_UNICODE_STRING*,MY_UNICODE_STRING*,BOOLEAN); |
| 320 | /* ------------------------------------------------------------------------ */ |
| 321 | static FNCOMPARESTRINGORDINAL fnCompareStringOrdinal; |
| 322 | static FNRTLINITUNICODESTRING fnRtlInitUnicodeString; |
| 323 | static FNRTLEQUALUNICODESTRING fnRtlEqualUnicodeString; |
| 324 | static int loaded_CompareStringOrdinal; |
| 325 | static int loaded_RtlUnicodeStringAPIs; |
| 326 | if( !loaded_CompareStringOrdinal ){ |
| 327 | fnCompareStringOrdinal = (FNCOMPARESTRINGORDINAL) |
| 328 | GetProcAddress(GetModuleHandleA("kernel32"),"CompareStringOrdinal"); |
| 329 | loaded_CompareStringOrdinal = 1; |
| 330 | } |
| 331 | if( fnCompareStringOrdinal ){ |
| 332 | return fnCompareStringOrdinal(fn1,-1,fn2,-1,1)-2==0; |
| 333 | } |
| 334 | if( !loaded_RtlUnicodeStringAPIs ){ |
| 335 | fnRtlInitUnicodeString = (FNRTLINITUNICODESTRING) |
| 336 | GetProcAddress(GetModuleHandleA("ntdll"),"RtlInitUnicodeString"); |
| 337 | fnRtlEqualUnicodeString = (FNRTLEQUALUNICODESTRING) |
| 338 | GetProcAddress(GetModuleHandleA("ntdll"),"RtlEqualUnicodeString"); |
| 339 | loaded_RtlUnicodeStringAPIs = 1; |
| 340 | } |
| 341 | if( fnRtlInitUnicodeString && fnRtlEqualUnicodeString ){ |
| 342 | MY_UNICODE_STRING u1, u2; |
| 343 | fnRtlInitUnicodeString(&u1,fn1); |
| 344 | fnRtlInitUnicodeString(&u2,fn2); |
| 345 | return (BOOLEAN/*unsigned char*/)fnRtlEqualUnicodeString(&u1,&u2,1); |
| 346 | } |
| 347 | /* In what kind of strange parallel universe are we? */ |
| 348 | return lstrcmpiW(fn1,fn2)==0; |
| 349 | } |
| 350 | |
| @@ -461,11 +469,20 @@ | |
| 469 | ** is allocated by mprintf(), or NULL on failure. |
| 470 | */ |
| 471 | char *win32_file_id( |
| 472 | const char *zFileName |
| 473 | ){ |
| 474 | /* ---- Data types used by dynamically loaded API functions. -------------- */ |
| 475 | typedef struct { /* FILE_ID_INFO from <winbase.h> */ |
| 476 | ULONGLONG VolumeSerialNumber; |
| 477 | BYTE FileId[16]; |
| 478 | } MY_FILE_ID_INFO; |
| 479 | /* ---- Prototypes for dynamically loaded API functions. ------------------ */ |
| 480 | typedef int (WINAPI *FNGETFILEINFORMATIONBYHANDLEEX) |
| 481 | (HANDLE,int/*enum*/,MY_FILE_ID_INFO*,DWORD); |
| 482 | /* ------------------------------------------------------------------------ */ |
| 483 | static FNGETFILEINFORMATIONBYHANDLEEX fnGetFileInformationByHandleEx; |
| 484 | static int loaded_fnGetFileInformationByHandleEx; |
| 485 | wchar_t *wzFileName = fossil_utf8_to_path(zFileName,0); |
| 486 | HANDLE hFile; |
| 487 | char *zFileId = 0; |
| 488 | hFile = CreateFileW( |
| @@ -476,17 +493,15 @@ | |
| 493 | OPEN_EXISTING, |
| 494 | FILE_FLAG_BACKUP_SEMANTICS, |
| 495 | NULL); |
| 496 | if( hFile!=INVALID_HANDLE_VALUE ){ |
| 497 | BY_HANDLE_FILE_INFORMATION fi; |
| 498 | MY_FILE_ID_INFO fi2; |
| 499 | if( !loaded_fnGetFileInformationByHandleEx ){ |
| 500 | fnGetFileInformationByHandleEx = (FNGETFILEINFORMATIONBYHANDLEEX) |
| 501 | GetProcAddress( |
| 502 | GetModuleHandleA("kernel32"),"GetFileInformationByHandleEx"); |
| 503 | loaded_fnGetFileInformationByHandleEx = 1; |
| 504 | } |
| 505 | if( fnGetFileInformationByHandleEx ){ |
| 506 | if( fnGetFileInformationByHandleEx( |
| 507 | hFile,/*FileIdInfo*/0x12,&fi2,sizeof(fi2)) ){ |
| 508 |
+2
-2
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -2382,17 +2382,17 @@ | ||
| 2382 | 2382 | if( nCycle==0 && db_is_writeable("repository") ){ |
| 2383 | 2383 | xfer_syncwith(g.url.canonical, 0); |
| 2384 | 2384 | } |
| 2385 | 2385 | |
| 2386 | 2386 | /* Output current stats */ |
| 2387 | + nRoundtrip++; | |
| 2388 | + nArtifactSent += xfer.nFileSent + xfer.nDeltaSent; | |
| 2387 | 2389 | if( syncFlags & SYNC_VERBOSE ){ |
| 2388 | 2390 | fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Sent:", |
| 2389 | 2391 | blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent, |
| 2390 | 2392 | xfer.nFileSent, xfer.nDeltaSent); |
| 2391 | 2393 | }else{ |
| 2392 | - nRoundtrip++; | |
| 2393 | - nArtifactSent += xfer.nFileSent + xfer.nDeltaSent; | |
| 2394 | 2394 | if( bOutIsTty!=0 ){ |
| 2395 | 2395 | fossil_print(zBriefFormat /*works-like:"%d%d%d"*/, |
| 2396 | 2396 | nRoundtrip, nArtifactSent, nArtifactRcvd); |
| 2397 | 2397 | } |
| 2398 | 2398 | } |
| 2399 | 2399 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -2382,17 +2382,17 @@ | |
| 2382 | if( nCycle==0 && db_is_writeable("repository") ){ |
| 2383 | xfer_syncwith(g.url.canonical, 0); |
| 2384 | } |
| 2385 | |
| 2386 | /* Output current stats */ |
| 2387 | if( syncFlags & SYNC_VERBOSE ){ |
| 2388 | fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Sent:", |
| 2389 | blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent, |
| 2390 | xfer.nFileSent, xfer.nDeltaSent); |
| 2391 | }else{ |
| 2392 | nRoundtrip++; |
| 2393 | nArtifactSent += xfer.nFileSent + xfer.nDeltaSent; |
| 2394 | if( bOutIsTty!=0 ){ |
| 2395 | fossil_print(zBriefFormat /*works-like:"%d%d%d"*/, |
| 2396 | nRoundtrip, nArtifactSent, nArtifactRcvd); |
| 2397 | } |
| 2398 | } |
| 2399 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -2382,17 +2382,17 @@ | |
| 2382 | if( nCycle==0 && db_is_writeable("repository") ){ |
| 2383 | xfer_syncwith(g.url.canonical, 0); |
| 2384 | } |
| 2385 | |
| 2386 | /* Output current stats */ |
| 2387 | nRoundtrip++; |
| 2388 | nArtifactSent += xfer.nFileSent + xfer.nDeltaSent; |
| 2389 | if( syncFlags & SYNC_VERBOSE ){ |
| 2390 | fossil_print(zValueFormat /*works-like:"%s%d%d%d%d"*/, "Sent:", |
| 2391 | blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent, |
| 2392 | xfer.nFileSent, xfer.nDeltaSent); |
| 2393 | }else{ |
| 2394 | if( bOutIsTty!=0 ){ |
| 2395 | fossil_print(zBriefFormat /*works-like:"%d%d%d"*/, |
| 2396 | nRoundtrip, nArtifactSent, nArtifactRcvd); |
| 2397 | } |
| 2398 | } |
| 2399 |
+3
| --- src/zip.c | ||
| +++ src/zip.c | ||
| @@ -927,10 +927,13 @@ | ||
| 927 | 927 | login_check_credentials(); |
| 928 | 928 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 929 | 929 | if( fossil_strcmp(g.zPath, "sqlar")==0 ){ |
| 930 | 930 | eType = ARCHIVE_SQLAR; |
| 931 | 931 | zType = "SQL"; |
| 932 | + /* For some reason, SQL-archives are like catnip for robots. So | |
| 933 | + ** don't allow them to be downloaded by user "nobody" */ | |
| 934 | + if( g.zLogin==0 ){ login_needed(g.anon.Zip); return; } | |
| 932 | 935 | }else{ |
| 933 | 936 | eType = ARCHIVE_ZIP; |
| 934 | 937 | zType = "ZIP"; |
| 935 | 938 | } |
| 936 | 939 | fossil_nice_default(); |
| 937 | 940 |
| --- src/zip.c | |
| +++ src/zip.c | |
| @@ -927,10 +927,13 @@ | |
| 927 | login_check_credentials(); |
| 928 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 929 | if( fossil_strcmp(g.zPath, "sqlar")==0 ){ |
| 930 | eType = ARCHIVE_SQLAR; |
| 931 | zType = "SQL"; |
| 932 | }else{ |
| 933 | eType = ARCHIVE_ZIP; |
| 934 | zType = "ZIP"; |
| 935 | } |
| 936 | fossil_nice_default(); |
| 937 |
| --- src/zip.c | |
| +++ src/zip.c | |
| @@ -927,10 +927,13 @@ | |
| 927 | login_check_credentials(); |
| 928 | if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; } |
| 929 | if( fossil_strcmp(g.zPath, "sqlar")==0 ){ |
| 930 | eType = ARCHIVE_SQLAR; |
| 931 | zType = "SQL"; |
| 932 | /* For some reason, SQL-archives are like catnip for robots. So |
| 933 | ** don't allow them to be downloaded by user "nobody" */ |
| 934 | if( g.zLogin==0 ){ login_needed(g.anon.Zip); return; } |
| 935 | }else{ |
| 936 | eType = ARCHIVE_ZIP; |
| 937 | zType = "ZIP"; |
| 938 | } |
| 939 | fossil_nice_default(); |
| 940 |
-2
| --- test/tester.tcl | ||
| +++ test/tester.tcl | ||
| @@ -366,12 +366,10 @@ | ||
| 366 | 366 | robot-restrict \ |
| 367 | 367 | robots-txt \ |
| 368 | 368 | safe-html \ |
| 369 | 369 | self-pw-reset \ |
| 370 | 370 | self-register \ |
| 371 | - show-repolist-desc \ | |
| 372 | - show-repolist-lg \ | |
| 373 | 371 | sitemap-extra \ |
| 374 | 372 | ssh-command \ |
| 375 | 373 | ssl-ca-location \ |
| 376 | 374 | ssl-identity \ |
| 377 | 375 | tclsh \ |
| 378 | 376 |
| --- test/tester.tcl | |
| +++ test/tester.tcl | |
| @@ -366,12 +366,10 @@ | |
| 366 | robot-restrict \ |
| 367 | robots-txt \ |
| 368 | safe-html \ |
| 369 | self-pw-reset \ |
| 370 | self-register \ |
| 371 | show-repolist-desc \ |
| 372 | show-repolist-lg \ |
| 373 | sitemap-extra \ |
| 374 | ssh-command \ |
| 375 | ssl-ca-location \ |
| 376 | ssl-identity \ |
| 377 | tclsh \ |
| 378 |
| --- test/tester.tcl | |
| +++ test/tester.tcl | |
| @@ -366,12 +366,10 @@ | |
| 366 | robot-restrict \ |
| 367 | robots-txt \ |
| 368 | safe-html \ |
| 369 | self-pw-reset \ |
| 370 | self-register \ |
| 371 | sitemap-extra \ |
| 372 | ssh-command \ |
| 373 | ssl-ca-location \ |
| 374 | ssl-identity \ |
| 375 | tclsh \ |
| 376 |
+1
-1
| --- test/th1.test | ||
| +++ test/th1.test | ||
| @@ -1061,11 +1061,11 @@ | ||
| 1061 | 1061 | #fossil test-th-eval "info commands" |
| 1062 | 1062 | #set sorted_result [lsort $RESULT] |
| 1063 | 1063 | #protOut "Sorted: $sorted_result" |
| 1064 | 1064 | #set base_commands {anoncap anycap array artifact break breakpoint \ |
| 1065 | 1065 | # builtin_request_js capexpr captureTh1 catch cgiHeaderLine checkout \ |
| 1066 | -# combobox continue copybtn date decorate defHeader dir enable_htmlify \ | |
| 1066 | +# combobox continue copybtn date decorate defHeader dir \ | |
| 1067 | 1067 | # enable_output encode64 error expr for foreach getParameter glob_match \ |
| 1068 | 1068 | # globalState hascap hasfeature html htmlize http httpize if info \ |
| 1069 | 1069 | # insertCsrf lappend lindex linecount list llength lsearch markdown nonce \ |
| 1070 | 1070 | # proc puts query randhex redirect regexp reinitialize rename render \ |
| 1071 | 1071 | # repository return searchable set setParameter setting stime string \ |
| 1072 | 1072 |
| --- test/th1.test | |
| +++ test/th1.test | |
| @@ -1061,11 +1061,11 @@ | |
| 1061 | #fossil test-th-eval "info commands" |
| 1062 | #set sorted_result [lsort $RESULT] |
| 1063 | #protOut "Sorted: $sorted_result" |
| 1064 | #set base_commands {anoncap anycap array artifact break breakpoint \ |
| 1065 | # builtin_request_js capexpr captureTh1 catch cgiHeaderLine checkout \ |
| 1066 | # combobox continue copybtn date decorate defHeader dir enable_htmlify \ |
| 1067 | # enable_output encode64 error expr for foreach getParameter glob_match \ |
| 1068 | # globalState hascap hasfeature html htmlize http httpize if info \ |
| 1069 | # insertCsrf lappend lindex linecount list llength lsearch markdown nonce \ |
| 1070 | # proc puts query randhex redirect regexp reinitialize rename render \ |
| 1071 | # repository return searchable set setParameter setting stime string \ |
| 1072 |
| --- test/th1.test | |
| +++ test/th1.test | |
| @@ -1061,11 +1061,11 @@ | |
| 1061 | #fossil test-th-eval "info commands" |
| 1062 | #set sorted_result [lsort $RESULT] |
| 1063 | #protOut "Sorted: $sorted_result" |
| 1064 | #set base_commands {anoncap anycap array artifact break breakpoint \ |
| 1065 | # builtin_request_js capexpr captureTh1 catch cgiHeaderLine checkout \ |
| 1066 | # combobox continue copybtn date decorate defHeader dir \ |
| 1067 | # enable_output encode64 error expr for foreach getParameter glob_match \ |
| 1068 | # globalState hascap hasfeature html htmlize http httpize if info \ |
| 1069 | # insertCsrf lappend lindex linecount list llength lsearch markdown nonce \ |
| 1070 | # proc puts query randhex redirect regexp reinitialize rename render \ |
| 1071 | # repository return searchable set setParameter setting stime string \ |
| 1072 |
+12
-7
| --- tools/makemake.tcl | ||
| +++ tools/makemake.tcl | ||
| @@ -368,39 +368,41 @@ | ||
| 368 | 368 | writeln [string map [list \ |
| 369 | 369 | <<<SQLITE_OPTIONS>>> [join $SQLITE_OPTIONS " \\\n "] \ |
| 370 | 370 | <<<SHELL_OPTIONS>>> [join $SHELL_OPTIONS " \\\n "] \ |
| 371 | 371 | <<<PIKCHR_OPTIONS>>> [join $PIKCHR_OPTIONS " \\\n "] \ |
| 372 | 372 | <<<NEXT_LINE>>> \\] { |
| 373 | -all: $(OBJDIR) $(APPNAME) | |
| 373 | +all: $(APPNAME) | |
| 374 | 374 | |
| 375 | 375 | install: all |
| 376 | 376 | mkdir -p $(INSTALLDIR) |
| 377 | 377 | cp $(APPNAME) $(INSTALLDIR) |
| 378 | 378 | |
| 379 | 379 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 380 | 380 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 381 | 381 | |
| 382 | -$(OBJDIR): | |
| 383 | - -mkdir $(OBJDIR) | |
| 384 | - | |
| 385 | 382 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 386 | 383 | -mkdir -p $(OBJDIR) |
| 387 | 384 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 388 | 385 | |
| 389 | 386 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 387 | + -mkdir -p $(OBJDIR) | |
| 390 | 388 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 391 | 389 | |
| 392 | 390 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 391 | + -mkdir -p $(OBJDIR) | |
| 393 | 392 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 394 | 393 | |
| 395 | 394 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 395 | + -mkdir -p $(OBJDIR) | |
| 396 | 396 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 397 | 397 | |
| 398 | 398 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 399 | + -mkdir -p $(OBJDIR) | |
| 399 | 400 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 400 | 401 | |
| 401 | 402 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 403 | + -mkdir -p $(OBJDIR) | |
| 402 | 404 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 403 | 405 | |
| 404 | 406 | # Run the test suite. |
| 405 | 407 | # Other flags that can be included in TESTFLAGS are: |
| 406 | 408 | # |
| @@ -412,11 +414,11 @@ | ||
| 412 | 414 | # -strict Treat known bugs as failures |
| 413 | 415 | # |
| 414 | 416 | # TESTFLAGS can also include names of specific test files to limit |
| 415 | 417 | # the run to just those test cases. |
| 416 | 418 | # |
| 417 | -test: $(OBJDIR) $(APPNAME) | |
| 419 | +test: $(APPNAME) | |
| 418 | 420 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 419 | 421 | |
| 420 | 422 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 421 | 423 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid <<<NEXT_LINE>>> |
| 422 | 424 | $(SRCDIR)/../manifest <<<NEXT_LINE>>> |
| @@ -552,23 +554,26 @@ | ||
| 552 | 554 | |
| 553 | 555 | writeln "\$(OBJDIR)/linenoise.o:\t\$(SRCDIR_extsrc)/linenoise.c \$(SRCDIR_extsrc)/linenoise.h" |
| 554 | 556 | writeln "\t\$(XTCC) -c \$(SRCDIR_extsrc)/linenoise.c -o \$@\n" |
| 555 | 557 | |
| 556 | 558 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 559 | +writeln "\t-mkdir -p \$(OBJDIR)\n" | |
| 557 | 560 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$@\n" |
| 558 | 561 | |
| 559 | 562 | writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" |
| 563 | +writeln "\t-mkdir -p \$(OBJDIR)\n" | |
| 560 | 564 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$@\n" |
| 561 | 565 | |
| 562 | 566 | writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c" |
| 567 | +writeln "\t-mkdir -p \$(OBJDIR)\n" | |
| 563 | 568 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$@\n" |
| 564 | 569 | |
| 565 | 570 | writeln [string map [list <<<NEXT_LINE>>> \\] { |
| 566 | -$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c | |
| 571 | +$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c $(OBJDIR)/mkversion | |
| 567 | 572 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 568 | 573 | |
| 569 | -$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c | |
| 574 | +$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c $(OBJDIR)/mkversion | |
| 570 | 575 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 571 | 576 | |
| 572 | 577 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 573 | 578 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry <<<NEXT_LINE>>> |
| 574 | 579 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore <<<NEXT_LINE>>> |
| 575 | 580 |
| --- tools/makemake.tcl | |
| +++ tools/makemake.tcl | |
| @@ -368,39 +368,41 @@ | |
| 368 | writeln [string map [list \ |
| 369 | <<<SQLITE_OPTIONS>>> [join $SQLITE_OPTIONS " \\\n "] \ |
| 370 | <<<SHELL_OPTIONS>>> [join $SHELL_OPTIONS " \\\n "] \ |
| 371 | <<<PIKCHR_OPTIONS>>> [join $PIKCHR_OPTIONS " \\\n "] \ |
| 372 | <<<NEXT_LINE>>> \\] { |
| 373 | all: $(OBJDIR) $(APPNAME) |
| 374 | |
| 375 | install: all |
| 376 | mkdir -p $(INSTALLDIR) |
| 377 | cp $(APPNAME) $(INSTALLDIR) |
| 378 | |
| 379 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 380 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 381 | |
| 382 | $(OBJDIR): |
| 383 | -mkdir $(OBJDIR) |
| 384 | |
| 385 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 386 | -mkdir -p $(OBJDIR) |
| 387 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 388 | |
| 389 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 390 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 391 | |
| 392 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 393 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 394 | |
| 395 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 396 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 397 | |
| 398 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 399 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 400 | |
| 401 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 402 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 403 | |
| 404 | # Run the test suite. |
| 405 | # Other flags that can be included in TESTFLAGS are: |
| 406 | # |
| @@ -412,11 +414,11 @@ | |
| 412 | # -strict Treat known bugs as failures |
| 413 | # |
| 414 | # TESTFLAGS can also include names of specific test files to limit |
| 415 | # the run to just those test cases. |
| 416 | # |
| 417 | test: $(OBJDIR) $(APPNAME) |
| 418 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 419 | |
| 420 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 421 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid <<<NEXT_LINE>>> |
| 422 | $(SRCDIR)/../manifest <<<NEXT_LINE>>> |
| @@ -552,23 +554,26 @@ | |
| 552 | |
| 553 | writeln "\$(OBJDIR)/linenoise.o:\t\$(SRCDIR_extsrc)/linenoise.c \$(SRCDIR_extsrc)/linenoise.h" |
| 554 | writeln "\t\$(XTCC) -c \$(SRCDIR_extsrc)/linenoise.c -o \$@\n" |
| 555 | |
| 556 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 557 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$@\n" |
| 558 | |
| 559 | writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" |
| 560 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$@\n" |
| 561 | |
| 562 | writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c" |
| 563 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$@\n" |
| 564 | |
| 565 | writeln [string map [list <<<NEXT_LINE>>> \\] { |
| 566 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c |
| 567 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 568 | |
| 569 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 570 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 571 | |
| 572 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 573 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry <<<NEXT_LINE>>> |
| 574 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore <<<NEXT_LINE>>> |
| 575 |
| --- tools/makemake.tcl | |
| +++ tools/makemake.tcl | |
| @@ -368,39 +368,41 @@ | |
| 368 | writeln [string map [list \ |
| 369 | <<<SQLITE_OPTIONS>>> [join $SQLITE_OPTIONS " \\\n "] \ |
| 370 | <<<SHELL_OPTIONS>>> [join $SHELL_OPTIONS " \\\n "] \ |
| 371 | <<<PIKCHR_OPTIONS>>> [join $PIKCHR_OPTIONS " \\\n "] \ |
| 372 | <<<NEXT_LINE>>> \\] { |
| 373 | all: $(APPNAME) |
| 374 | |
| 375 | install: all |
| 376 | mkdir -p $(INSTALLDIR) |
| 377 | cp $(APPNAME) $(INSTALLDIR) |
| 378 | |
| 379 | codecheck: $(TRANS_SRC) $(OBJDIR)/codecheck1 |
| 380 | $(OBJDIR)/codecheck1 $(TRANS_SRC) |
| 381 | |
| 382 | $(OBJDIR)/translate: $(SRCDIR_tools)/translate.c |
| 383 | -mkdir -p $(OBJDIR) |
| 384 | $(XBCC) -o $(OBJDIR)/translate $(SRCDIR_tools)/translate.c |
| 385 | |
| 386 | $(OBJDIR)/makeheaders: $(SRCDIR_tools)/makeheaders.c |
| 387 | -mkdir -p $(OBJDIR) |
| 388 | $(XBCC) -o $(OBJDIR)/makeheaders $(SRCDIR_tools)/makeheaders.c |
| 389 | |
| 390 | $(OBJDIR)/mkindex: $(SRCDIR_tools)/mkindex.c |
| 391 | -mkdir -p $(OBJDIR) |
| 392 | $(XBCC) -o $(OBJDIR)/mkindex $(SRCDIR_tools)/mkindex.c |
| 393 | |
| 394 | $(OBJDIR)/mkbuiltin: $(SRCDIR_tools)/mkbuiltin.c |
| 395 | -mkdir -p $(OBJDIR) |
| 396 | $(XBCC) -o $(OBJDIR)/mkbuiltin $(SRCDIR_tools)/mkbuiltin.c |
| 397 | |
| 398 | $(OBJDIR)/mkversion: $(SRCDIR_tools)/mkversion.c |
| 399 | -mkdir -p $(OBJDIR) |
| 400 | $(XBCC) -o $(OBJDIR)/mkversion $(SRCDIR_tools)/mkversion.c |
| 401 | |
| 402 | $(OBJDIR)/codecheck1: $(SRCDIR_tools)/codecheck1.c |
| 403 | -mkdir -p $(OBJDIR) |
| 404 | $(XBCC) -o $(OBJDIR)/codecheck1 $(SRCDIR_tools)/codecheck1.c |
| 405 | |
| 406 | # Run the test suite. |
| 407 | # Other flags that can be included in TESTFLAGS are: |
| 408 | # |
| @@ -412,11 +414,11 @@ | |
| 414 | # -strict Treat known bugs as failures |
| 415 | # |
| 416 | # TESTFLAGS can also include names of specific test files to limit |
| 417 | # the run to just those test cases. |
| 418 | # |
| 419 | test: $(APPNAME) |
| 420 | $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(TESTFLAGS) |
| 421 | |
| 422 | $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/phony.h |
| 423 | $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid <<<NEXT_LINE>>> |
| 424 | $(SRCDIR)/../manifest <<<NEXT_LINE>>> |
| @@ -552,23 +554,26 @@ | |
| 554 | |
| 555 | writeln "\$(OBJDIR)/linenoise.o:\t\$(SRCDIR_extsrc)/linenoise.c \$(SRCDIR_extsrc)/linenoise.h" |
| 556 | writeln "\t\$(XTCC) -c \$(SRCDIR_extsrc)/linenoise.c -o \$@\n" |
| 557 | |
| 558 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 559 | writeln "\t-mkdir -p \$(OBJDIR)\n" |
| 560 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$@\n" |
| 561 | |
| 562 | writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c" |
| 563 | writeln "\t-mkdir -p \$(OBJDIR)\n" |
| 564 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$@\n" |
| 565 | |
| 566 | writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c" |
| 567 | writeln "\t-mkdir -p \$(OBJDIR)\n" |
| 568 | writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$@\n" |
| 569 | |
| 570 | writeln [string map [list <<<NEXT_LINE>>> \\] { |
| 571 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c $(OBJDIR)/mkversion |
| 572 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 573 | |
| 574 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c $(OBJDIR)/mkversion |
| 575 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 576 | |
| 577 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST) |
| 578 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry <<<NEXT_LINE>>> |
| 579 | -sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore <<<NEXT_LINE>>> |
| 580 |
+2
-3
| --- www/cgi.wiki | ||
| +++ www/cgi.wiki | ||
| @@ -81,13 +81,12 @@ | ||
| 81 | 81 | the page title taken from the <tt>FOSSIL_REPOLIST_TITLE</tt> |
| 82 | 82 | environment variable. The variable can be defined in the CGI |
| 83 | 83 | control file using the [#setenv|<tt>setenv:</tt>] statement. |
| 84 | 84 | |
| 85 | 85 | The "Project Description" and "Login-Group" columns on the repolist page |
| 86 | -are optional. They are hidden by default. Show them by putting value "1" | |
| 87 | -in the global settings "show-repolist-desc" and "show-repolist-lg", or | |
| 88 | -by setting the <tt>FOSSIL_REPOLIST_SHOW</tt> environment variable to | |
| 86 | +are optional. They are hidden by default. Show them by | |
| 87 | +etting the <tt>FOSSIL_REPOLIST_SHOW</tt> environment variable to | |
| 89 | 88 | a string that contains substrings "description" and/or "login-group". |
| 90 | 89 | |
| 91 | 90 | The repolist-generated page recurses into subdirectories and will list |
| 92 | 91 | all <tt>*.fossil</tt> files found, with the following exceptions: |
| 93 | 92 | |
| 94 | 93 |
| --- www/cgi.wiki | |
| +++ www/cgi.wiki | |
| @@ -81,13 +81,12 @@ | |
| 81 | the page title taken from the <tt>FOSSIL_REPOLIST_TITLE</tt> |
| 82 | environment variable. The variable can be defined in the CGI |
| 83 | control file using the [#setenv|<tt>setenv:</tt>] statement. |
| 84 | |
| 85 | The "Project Description" and "Login-Group" columns on the repolist page |
| 86 | are optional. They are hidden by default. Show them by putting value "1" |
| 87 | in the global settings "show-repolist-desc" and "show-repolist-lg", or |
| 88 | by setting the <tt>FOSSIL_REPOLIST_SHOW</tt> environment variable to |
| 89 | a string that contains substrings "description" and/or "login-group". |
| 90 | |
| 91 | The repolist-generated page recurses into subdirectories and will list |
| 92 | all <tt>*.fossil</tt> files found, with the following exceptions: |
| 93 | |
| 94 |
| --- www/cgi.wiki | |
| +++ www/cgi.wiki | |
| @@ -81,13 +81,12 @@ | |
| 81 | the page title taken from the <tt>FOSSIL_REPOLIST_TITLE</tt> |
| 82 | environment variable. The variable can be defined in the CGI |
| 83 | control file using the [#setenv|<tt>setenv:</tt>] statement. |
| 84 | |
| 85 | The "Project Description" and "Login-Group" columns on the repolist page |
| 86 | are optional. They are hidden by default. Show them by |
| 87 | etting the <tt>FOSSIL_REPOLIST_SHOW</tt> environment variable to |
| 88 | a string that contains substrings "description" and/or "login-group". |
| 89 | |
| 90 | The repolist-generated page recurses into subdirectories and will list |
| 91 | all <tt>*.fossil</tt> files found, with the following exceptions: |
| 92 | |
| 93 |
+37
-18
| --- www/changes.wiki | ||
| +++ www/changes.wiki | ||
| @@ -1,12 +1,17 @@ | ||
| 1 | 1 | <title>Change Log</title> |
| 2 | 2 | |
| 3 | -<h2 id='v2_26'>Changes for version 2.26 (pending)</h2><ol> | |
| 3 | +<h2 id='v2_27'>Changes for version 2.27 (pending)</h2> | |
| 4 | + | |
| 5 | + * Enhance the chng= query parameter on the [/help?cmd=/timeline|timeline page] | |
| 6 | + so that it work with other query parameters like p=, d=, from=, and to=. | |
| 7 | + | |
| 8 | +<h2 id='v2_26'>Changes for version 2.26 (2025-04-30)</h2><ol> | |
| 4 | 9 | <li>Enhancements to [/help?cmd=diff|fossil diff] and similar: |
| 5 | 10 | <ol type="a"> |
| 6 | - <li> The --from can optionally accept a directory name as its argument, | |
| 7 | - and uses files under that directory as the baseline for the diff. | |
| 11 | + <li> The argument to the --from option can be a directory name, causing | |
| 12 | + Fossil to use files under that directory as the baseline for the diff. | |
| 8 | 13 | <li> For "gdiff", if no [/help?cmd=gdiff-command|gdiff-command setting] |
| 9 | 14 | is defined, Fossil tries to do a --tk diff if "tclsh" and "wish" |
| 10 | 15 | are available, or a --by diff if not. |
| 11 | 16 | <li> The "Reload" button is added to --tk diffs, to bring the displayed |
| 12 | 17 | diff up to date with the latest changes on disk. |
| @@ -84,13 +89,13 @@ | ||
| 84 | 89 | <li> Accept the "Z" (Zulu-time) suffix on date arguments for the |
| 85 | 90 | "ymd" and "yw" query parameters. |
| 86 | 91 | <li> The new "min" query parameter, when added to a from=,to= query, |
| 87 | 92 | collapses long runs of check-ins on the same branch into just |
| 88 | 93 | end-points. |
| 89 | - <li> The p= and d= parameters an reference different check-ins, which | |
| 90 | - case the timeline shows those check-ins that are both ancestors | |
| 91 | - of p= and descendants of d=. | |
| 94 | + <li> The p= and d= parameters can now reference different check-ins, | |
| 95 | + in which case the timeline shows those check-ins that are both | |
| 96 | + ancestors of p= and descendants of d=. | |
| 92 | 97 | <li> The saturation and intensity of user-specified checkin and branch |
| 93 | 98 | background colors are automatically adjusted to keep the colors |
| 94 | 99 | compatible with the current skin, unless the |
| 95 | 100 | [/help?cmd=raw-bgcolor|raw-bgcolor setting] is turned on. |
| 96 | 101 | </ol> |
| @@ -119,11 +124,11 @@ | ||
| 119 | 124 | COMMAND argument and only shows results for the specified |
| 120 | 125 | subcommand, not the entire command. |
| 121 | 126 | <li> The -u (--usage) option shows only the command-line syntax |
| 122 | 127 | <li> The -o (--options) option shows only the command-line options |
| 123 | 128 | </ol> |
| 124 | - <li>Enhancements to the ticket system: | |
| 129 | + <li>Enhancements to the [./tickets.wiki|ticket system]: | |
| 125 | 130 | <ol type="a"> |
| 126 | 131 | <li> Added the ability to attach wiki pages to a ticket for extended |
| 127 | 132 | descriptions. |
| 128 | 133 | <li> Added submenu to the 'View Ticket' page, to use it as |
| 129 | 134 | template for a new ticket. |
| @@ -136,22 +141,37 @@ | ||
| 136 | 141 | <li>Added the "hash" query parameter to the |
| 137 | 142 | [/help?cmd=/whatis|/whatis webpage]. |
| 138 | 143 | <li>Add a "user permissions changes" [/doc/trunk/www/alerts.md|subscription] |
| 139 | 144 | which alerts subscribers when an admin creates a new user or |
| 140 | 145 | when a user's permissions change. |
| 141 | - <li>Show project description on repository list. | |
| 146 | + <li>If the FOSSIL_REPOLIST_SHOW environment variable exists and contains | |
| 147 | + the substring "description", then the project description for each repository | |
| 148 | + is shown on the repository list page. The login-group for each project is | |
| 149 | + now only shown if the FOSSIL_REPOLIST_SHOW environment variable exists and | |
| 150 | + contains the substring "login-group". ([./cgi.wiki#repolist|More information]) | |
| 151 | + <li>The [/doc/trunk/www/th1.md|TH1 script language] is enhanced for improved | |
| 152 | + security: | |
| 153 | + <ol type="a"> | |
| 154 | + <li> TH1 now makes a distinction between | |
| 155 | + [/doc/trunk/www/th1.md#taint|tainted and untainted string values]. | |
| 156 | + This makes it more difficult to write custom TH1 scripts that | |
| 157 | + contain XSS or SQL-injection bugs. The | |
| 158 | + [/help?cmd=vuln-report|vuln-report] setting was added to control | |
| 159 | + what Fossil does when it encounters a potential TH1 | |
| 160 | + security problem. | |
| 161 | + <li> The "--th" option was removed from the [/help?cmd=pikchr|fossil pikchr] | |
| 162 | + command. | |
| 163 | + <li> The "enable_htmlify" TH1 command was removed. | |
| 164 | + </ol> | |
| 142 | 165 | <li>Make [/help?cmd=/chat|/chat] better-behaved during server outages, reducing |
| 143 | 166 | the frequency of reconnection attempts over time and providing feedback |
| 144 | 167 | to the user when the connection is down. |
| 145 | - <li>The [/doc/trunk/www/th1.md|TH1 script language] now makes a distinction | |
| 146 | - between [/doc/trunk/www/th1.md#taint|tainted and untainted string values]. | |
| 147 | - This is a security enhancement that makes it more difficult to write | |
| 148 | - custom TH1 scripts that contain XSS or SQL-injection bugs. As part of | |
| 149 | - this enhancement, the [/help?cmd=vuln-report|vuln-report] setting was | |
| 150 | - added to control what Fossil does when it encounters a potential TH1 | |
| 151 | - security problem. | |
| 152 | - <li>Diverse minor fixes and additions. | |
| 168 | + <li>The [/help?cmd=/sqlar|/sqlar] page does not work for users who are not logged | |
| 169 | + in, nor are links to that page displayed to users who are not logged in. Being | |
| 170 | + logged in as "anonymous" is sufficient to overcome this restriction, assuming | |
| 171 | + that "anonymous" can download tarballs and ZIP archives. | |
| 172 | + <li>Many other minor fixes and additions. | |
| 153 | 173 | </ol> |
| 154 | 174 | |
| 155 | 175 | <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2> |
| 156 | 176 | |
| 157 | 177 | * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories |
| @@ -1169,12 +1189,11 @@ | ||
| 1169 | 1189 | of rows in a timeline) are held in a cookie and thus persist |
| 1170 | 1190 | across multiple pages. |
| 1171 | 1191 | * Rework the skin editing process so that changes are implemented |
| 1172 | 1192 | on one of nine /draft pages, evaluated, then merged back to the |
| 1173 | 1193 | default. |
| 1174 | - * Added the [https://fossil-scm.org/skins/ardoise/timeline|Ardoise] | |
| 1175 | - skin. | |
| 1194 | + * Added the [/timeline?skin=ardoise&once|Ardoise] skin. | |
| 1176 | 1195 | * Fix the "fossil server" command on Unix to be much more responsive |
| 1177 | 1196 | to multiple simultaneous web requests. |
| 1178 | 1197 | * Use the IPv6 stack for the "fossil ui" and "fossil server" |
| 1179 | 1198 | commands on Windows. |
| 1180 | 1199 | * Support for [https://sqlite.org/sqlar|SQL Archives] as a download |
| 1181 | 1200 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -1,12 +1,17 @@ | |
| 1 | <title>Change Log</title> |
| 2 | |
| 3 | <h2 id='v2_26'>Changes for version 2.26 (pending)</h2><ol> |
| 4 | <li>Enhancements to [/help?cmd=diff|fossil diff] and similar: |
| 5 | <ol type="a"> |
| 6 | <li> The --from can optionally accept a directory name as its argument, |
| 7 | and uses files under that directory as the baseline for the diff. |
| 8 | <li> For "gdiff", if no [/help?cmd=gdiff-command|gdiff-command setting] |
| 9 | is defined, Fossil tries to do a --tk diff if "tclsh" and "wish" |
| 10 | are available, or a --by diff if not. |
| 11 | <li> The "Reload" button is added to --tk diffs, to bring the displayed |
| 12 | diff up to date with the latest changes on disk. |
| @@ -84,13 +89,13 @@ | |
| 84 | <li> Accept the "Z" (Zulu-time) suffix on date arguments for the |
| 85 | "ymd" and "yw" query parameters. |
| 86 | <li> The new "min" query parameter, when added to a from=,to= query, |
| 87 | collapses long runs of check-ins on the same branch into just |
| 88 | end-points. |
| 89 | <li> The p= and d= parameters an reference different check-ins, which |
| 90 | case the timeline shows those check-ins that are both ancestors |
| 91 | of p= and descendants of d=. |
| 92 | <li> The saturation and intensity of user-specified checkin and branch |
| 93 | background colors are automatically adjusted to keep the colors |
| 94 | compatible with the current skin, unless the |
| 95 | [/help?cmd=raw-bgcolor|raw-bgcolor setting] is turned on. |
| 96 | </ol> |
| @@ -119,11 +124,11 @@ | |
| 119 | COMMAND argument and only shows results for the specified |
| 120 | subcommand, not the entire command. |
| 121 | <li> The -u (--usage) option shows only the command-line syntax |
| 122 | <li> The -o (--options) option shows only the command-line options |
| 123 | </ol> |
| 124 | <li>Enhancements to the ticket system: |
| 125 | <ol type="a"> |
| 126 | <li> Added the ability to attach wiki pages to a ticket for extended |
| 127 | descriptions. |
| 128 | <li> Added submenu to the 'View Ticket' page, to use it as |
| 129 | template for a new ticket. |
| @@ -136,22 +141,37 @@ | |
| 136 | <li>Added the "hash" query parameter to the |
| 137 | [/help?cmd=/whatis|/whatis webpage]. |
| 138 | <li>Add a "user permissions changes" [/doc/trunk/www/alerts.md|subscription] |
| 139 | which alerts subscribers when an admin creates a new user or |
| 140 | when a user's permissions change. |
| 141 | <li>Show project description on repository list. |
| 142 | <li>Make [/help?cmd=/chat|/chat] better-behaved during server outages, reducing |
| 143 | the frequency of reconnection attempts over time and providing feedback |
| 144 | to the user when the connection is down. |
| 145 | <li>The [/doc/trunk/www/th1.md|TH1 script language] now makes a distinction |
| 146 | between [/doc/trunk/www/th1.md#taint|tainted and untainted string values]. |
| 147 | This is a security enhancement that makes it more difficult to write |
| 148 | custom TH1 scripts that contain XSS or SQL-injection bugs. As part of |
| 149 | this enhancement, the [/help?cmd=vuln-report|vuln-report] setting was |
| 150 | added to control what Fossil does when it encounters a potential TH1 |
| 151 | security problem. |
| 152 | <li>Diverse minor fixes and additions. |
| 153 | </ol> |
| 154 | |
| 155 | <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2> |
| 156 | |
| 157 | * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories |
| @@ -1169,12 +1189,11 @@ | |
| 1169 | of rows in a timeline) are held in a cookie and thus persist |
| 1170 | across multiple pages. |
| 1171 | * Rework the skin editing process so that changes are implemented |
| 1172 | on one of nine /draft pages, evaluated, then merged back to the |
| 1173 | default. |
| 1174 | * Added the [https://fossil-scm.org/skins/ardoise/timeline|Ardoise] |
| 1175 | skin. |
| 1176 | * Fix the "fossil server" command on Unix to be much more responsive |
| 1177 | to multiple simultaneous web requests. |
| 1178 | * Use the IPv6 stack for the "fossil ui" and "fossil server" |
| 1179 | commands on Windows. |
| 1180 | * Support for [https://sqlite.org/sqlar|SQL Archives] as a download |
| 1181 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -1,12 +1,17 @@ | |
| 1 | <title>Change Log</title> |
| 2 | |
| 3 | <h2 id='v2_27'>Changes for version 2.27 (pending)</h2> |
| 4 | |
| 5 | * Enhance the chng= query parameter on the [/help?cmd=/timeline|timeline page] |
| 6 | so that it work with other query parameters like p=, d=, from=, and to=. |
| 7 | |
| 8 | <h2 id='v2_26'>Changes for version 2.26 (2025-04-30)</h2><ol> |
| 9 | <li>Enhancements to [/help?cmd=diff|fossil diff] and similar: |
| 10 | <ol type="a"> |
| 11 | <li> The argument to the --from option can be a directory name, causing |
| 12 | Fossil to use files under that directory as the baseline for the diff. |
| 13 | <li> For "gdiff", if no [/help?cmd=gdiff-command|gdiff-command setting] |
| 14 | is defined, Fossil tries to do a --tk diff if "tclsh" and "wish" |
| 15 | are available, or a --by diff if not. |
| 16 | <li> The "Reload" button is added to --tk diffs, to bring the displayed |
| 17 | diff up to date with the latest changes on disk. |
| @@ -84,13 +89,13 @@ | |
| 89 | <li> Accept the "Z" (Zulu-time) suffix on date arguments for the |
| 90 | "ymd" and "yw" query parameters. |
| 91 | <li> The new "min" query parameter, when added to a from=,to= query, |
| 92 | collapses long runs of check-ins on the same branch into just |
| 93 | end-points. |
| 94 | <li> The p= and d= parameters can now reference different check-ins, |
| 95 | in which case the timeline shows those check-ins that are both |
| 96 | ancestors of p= and descendants of d=. |
| 97 | <li> The saturation and intensity of user-specified checkin and branch |
| 98 | background colors are automatically adjusted to keep the colors |
| 99 | compatible with the current skin, unless the |
| 100 | [/help?cmd=raw-bgcolor|raw-bgcolor setting] is turned on. |
| 101 | </ol> |
| @@ -119,11 +124,11 @@ | |
| 124 | COMMAND argument and only shows results for the specified |
| 125 | subcommand, not the entire command. |
| 126 | <li> The -u (--usage) option shows only the command-line syntax |
| 127 | <li> The -o (--options) option shows only the command-line options |
| 128 | </ol> |
| 129 | <li>Enhancements to the [./tickets.wiki|ticket system]: |
| 130 | <ol type="a"> |
| 131 | <li> Added the ability to attach wiki pages to a ticket for extended |
| 132 | descriptions. |
| 133 | <li> Added submenu to the 'View Ticket' page, to use it as |
| 134 | template for a new ticket. |
| @@ -136,22 +141,37 @@ | |
| 141 | <li>Added the "hash" query parameter to the |
| 142 | [/help?cmd=/whatis|/whatis webpage]. |
| 143 | <li>Add a "user permissions changes" [/doc/trunk/www/alerts.md|subscription] |
| 144 | which alerts subscribers when an admin creates a new user or |
| 145 | when a user's permissions change. |
| 146 | <li>If the FOSSIL_REPOLIST_SHOW environment variable exists and contains |
| 147 | the substring "description", then the project description for each repository |
| 148 | is shown on the repository list page. The login-group for each project is |
| 149 | now only shown if the FOSSIL_REPOLIST_SHOW environment variable exists and |
| 150 | contains the substring "login-group". ([./cgi.wiki#repolist|More information]) |
| 151 | <li>The [/doc/trunk/www/th1.md|TH1 script language] is enhanced for improved |
| 152 | security: |
| 153 | <ol type="a"> |
| 154 | <li> TH1 now makes a distinction between |
| 155 | [/doc/trunk/www/th1.md#taint|tainted and untainted string values]. |
| 156 | This makes it more difficult to write custom TH1 scripts that |
| 157 | contain XSS or SQL-injection bugs. The |
| 158 | [/help?cmd=vuln-report|vuln-report] setting was added to control |
| 159 | what Fossil does when it encounters a potential TH1 |
| 160 | security problem. |
| 161 | <li> The "--th" option was removed from the [/help?cmd=pikchr|fossil pikchr] |
| 162 | command. |
| 163 | <li> The "enable_htmlify" TH1 command was removed. |
| 164 | </ol> |
| 165 | <li>Make [/help?cmd=/chat|/chat] better-behaved during server outages, reducing |
| 166 | the frequency of reconnection attempts over time and providing feedback |
| 167 | to the user when the connection is down. |
| 168 | <li>The [/help?cmd=/sqlar|/sqlar] page does not work for users who are not logged |
| 169 | in, nor are links to that page displayed to users who are not logged in. Being |
| 170 | logged in as "anonymous" is sufficient to overcome this restriction, assuming |
| 171 | that "anonymous" can download tarballs and ZIP archives. |
| 172 | <li>Many other minor fixes and additions. |
| 173 | </ol> |
| 174 | |
| 175 | <h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2> |
| 176 | |
| 177 | * The "[/help?cmd=ui|fossil ui /]" command now works even for repositories |
| @@ -1169,12 +1189,11 @@ | |
| 1189 | of rows in a timeline) are held in a cookie and thus persist |
| 1190 | across multiple pages. |
| 1191 | * Rework the skin editing process so that changes are implemented |
| 1192 | on one of nine /draft pages, evaluated, then merged back to the |
| 1193 | default. |
| 1194 | * Added the [/timeline?skin=ardoise&once|Ardoise] skin. |
| 1195 | * Fix the "fossil server" command on Unix to be much more responsive |
| 1196 | to multiple simultaneous web requests. |
| 1197 | * Use the IPv6 stack for the "fossil ui" and "fossil server" |
| 1198 | commands on Windows. |
| 1199 | * Support for [https://sqlite.org/sqlar|SQL Archives] as a download |
| 1200 |
+1
-1
| --- www/containers.md | ||
| +++ www/containers.md | ||
| @@ -670,11 +670,11 @@ | ||
| 670 | 670 | |
| 671 | 671 | [pmmac]: https://podman.io/getting-started/installation.html#macos |
| 672 | 672 | [pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md |
| 673 | 673 | [Podman]: https://podman.io/ |
| 674 | 674 | [rl]: https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md |
| 675 | -[whatis]: https://podman.io/whatis.html | |
| 675 | +[whatis]: https://docs.podman.io/en/latest/index.html | |
| 676 | 676 | |
| 677 | 677 | |
| 678 | 678 | ### 6.3 <a id="nspawn"></a>`systemd-container` |
| 679 | 679 | |
| 680 | 680 | If even the Podman stack is too big for you, the next-best option I’m |
| 681 | 681 |
| --- www/containers.md | |
| +++ www/containers.md | |
| @@ -670,11 +670,11 @@ | |
| 670 | |
| 671 | [pmmac]: https://podman.io/getting-started/installation.html#macos |
| 672 | [pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md |
| 673 | [Podman]: https://podman.io/ |
| 674 | [rl]: https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md |
| 675 | [whatis]: https://podman.io/whatis.html |
| 676 | |
| 677 | |
| 678 | ### 6.3 <a id="nspawn"></a>`systemd-container` |
| 679 | |
| 680 | If even the Podman stack is too big for you, the next-best option I’m |
| 681 |
| --- www/containers.md | |
| +++ www/containers.md | |
| @@ -670,11 +670,11 @@ | |
| 670 | |
| 671 | [pmmac]: https://podman.io/getting-started/installation.html#macos |
| 672 | [pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md |
| 673 | [Podman]: https://podman.io/ |
| 674 | [rl]: https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md |
| 675 | [whatis]: https://docs.podman.io/en/latest/index.html |
| 676 | |
| 677 | |
| 678 | ### 6.3 <a id="nspawn"></a>`systemd-container` |
| 679 | |
| 680 | If even the Podman stack is too big for you, the next-best option I’m |
| 681 |
+37
-1
| --- www/customskin.md | ||
| +++ www/customskin.md | ||
| @@ -310,10 +310,11 @@ | ||
| 310 | 310 | with the "--skin ./newskin" option. If the argument to the --skin |
| 311 | 311 | option contains a "/" character, then the five control files are |
| 312 | 312 | read out of the directory named. You can then edit the control |
| 313 | 313 | files in the ./newskin folder using you favorite text editor, and |
| 314 | 314 | press "Reload" on your browser to see the effects. |
| 315 | + | |
| 315 | 316 | |
| 316 | 317 | ### Disabling The Web Browser Cache During Development |
| 317 | 318 | |
| 318 | 319 | Fossil is aggressive about asking the web browser to cache |
| 319 | 320 | resources. While developing a new skin, it is often helpful to |
| @@ -526,11 +527,46 @@ | ||
| 526 | 527 | Iterate until the desired look is achieved. |
| 527 | 528 | |
| 528 | 529 | 4. Copy/paste the resulting css.txt, details.txt, |
| 529 | 530 | header.txt, and footer.txt files |
| 530 | 531 | into the CSS, details, header, and footer configuration screens |
| 531 | - under the Admin/Skins menu. | |
| 532 | + under the Admin/Skins menu. Alternately, import them using the | |
| 533 | + process described below. | |
| 534 | + | |
| 535 | +An alternative to step 4 is to convert the skin files into a form | |
| 536 | +which can be imported into a repository using `fossil config import`. | |
| 537 | +It requires compiling [a small tool from the fossil source | |
| 538 | +tree](/file/tools/skintxt2config.c): | |
| 539 | + | |
| 540 | +> | |
| 541 | +``` | |
| 542 | +$ cc -o s2c /path/to/fossil/checkout/tools/skintxt2config.c | |
| 543 | +``` | |
| 544 | + | |
| 545 | +With that in place, the custom skin files can be converted with: | |
| 546 | + | |
| 547 | +> | |
| 548 | +``` | |
| 549 | +$ ./s2c yourskin/*.txt > skin.config | |
| 550 | +``` | |
| 551 | + | |
| 552 | +It can be imported into an arbitrary fossil repository with: | |
| 553 | + | |
| 554 | +> | |
| 555 | +``` | |
| 556 | +$ fossil config import skin.config | |
| 557 | +``` | |
| 558 | + | |
| 559 | +And it can be pushed to a remote repository with: | |
| 560 | + | |
| 561 | +> | |
| 562 | +``` | |
| 563 | +$ fossil config push skin | |
| 564 | +``` | |
| 565 | + | |
| 566 | +That approach has proven to be an effective way to locally develop | |
| 567 | +skin changes then push them to a "live" site. | |
| 532 | 568 | |
| 533 | 569 | |
| 534 | 570 | ## See Also |
| 535 | 571 | |
| 536 | 572 | * [Customizing the Timeline Graph](customgraph.md) |
| 537 | 573 |
| --- www/customskin.md | |
| +++ www/customskin.md | |
| @@ -310,10 +310,11 @@ | |
| 310 | with the "--skin ./newskin" option. If the argument to the --skin |
| 311 | option contains a "/" character, then the five control files are |
| 312 | read out of the directory named. You can then edit the control |
| 313 | files in the ./newskin folder using you favorite text editor, and |
| 314 | press "Reload" on your browser to see the effects. |
| 315 | |
| 316 | ### Disabling The Web Browser Cache During Development |
| 317 | |
| 318 | Fossil is aggressive about asking the web browser to cache |
| 319 | resources. While developing a new skin, it is often helpful to |
| @@ -526,11 +527,46 @@ | |
| 526 | Iterate until the desired look is achieved. |
| 527 | |
| 528 | 4. Copy/paste the resulting css.txt, details.txt, |
| 529 | header.txt, and footer.txt files |
| 530 | into the CSS, details, header, and footer configuration screens |
| 531 | under the Admin/Skins menu. |
| 532 | |
| 533 | |
| 534 | ## See Also |
| 535 | |
| 536 | * [Customizing the Timeline Graph](customgraph.md) |
| 537 |
| --- www/customskin.md | |
| +++ www/customskin.md | |
| @@ -310,10 +310,11 @@ | |
| 310 | with the "--skin ./newskin" option. If the argument to the --skin |
| 311 | option contains a "/" character, then the five control files are |
| 312 | read out of the directory named. You can then edit the control |
| 313 | files in the ./newskin folder using you favorite text editor, and |
| 314 | press "Reload" on your browser to see the effects. |
| 315 | |
| 316 | |
| 317 | ### Disabling The Web Browser Cache During Development |
| 318 | |
| 319 | Fossil is aggressive about asking the web browser to cache |
| 320 | resources. While developing a new skin, it is often helpful to |
| @@ -526,11 +527,46 @@ | |
| 527 | Iterate until the desired look is achieved. |
| 528 | |
| 529 | 4. Copy/paste the resulting css.txt, details.txt, |
| 530 | header.txt, and footer.txt files |
| 531 | into the CSS, details, header, and footer configuration screens |
| 532 | under the Admin/Skins menu. Alternately, import them using the |
| 533 | process described below. |
| 534 | |
| 535 | An alternative to step 4 is to convert the skin files into a form |
| 536 | which can be imported into a repository using `fossil config import`. |
| 537 | It requires compiling [a small tool from the fossil source |
| 538 | tree](/file/tools/skintxt2config.c): |
| 539 | |
| 540 | > |
| 541 | ``` |
| 542 | $ cc -o s2c /path/to/fossil/checkout/tools/skintxt2config.c |
| 543 | ``` |
| 544 | |
| 545 | With that in place, the custom skin files can be converted with: |
| 546 | |
| 547 | > |
| 548 | ``` |
| 549 | $ ./s2c yourskin/*.txt > skin.config |
| 550 | ``` |
| 551 | |
| 552 | It can be imported into an arbitrary fossil repository with: |
| 553 | |
| 554 | > |
| 555 | ``` |
| 556 | $ fossil config import skin.config |
| 557 | ``` |
| 558 | |
| 559 | And it can be pushed to a remote repository with: |
| 560 | |
| 561 | > |
| 562 | ``` |
| 563 | $ fossil config push skin |
| 564 | ``` |
| 565 | |
| 566 | That approach has proven to be an effective way to locally develop |
| 567 | skin changes then push them to a "live" site. |
| 568 | |
| 569 | |
| 570 | ## See Also |
| 571 | |
| 572 | * [Customizing the Timeline Graph](customgraph.md) |
| 573 |
+1
-1
| --- www/fossil-v-git.wiki | ||
| +++ www/fossil-v-git.wiki | ||
| @@ -342,11 +342,11 @@ | ||
| 342 | 342 | Fossil isn't entirely C and SQL code. Its web UI [./javascript.md | |
| 343 | 343 | uses JavaScript where |
| 344 | 344 | necessary]. The server-side |
| 345 | 345 | UI scripting uses a custom minimal |
| 346 | 346 | [https://en.wikipedia.org/wiki/Tcl|Tcl] dialect called |
| 347 | -[https://fossil-scm.org/xfer/doc/trunk/www/th1.md|TH1], which is | |
| 347 | +[./th1.md|TH1], which is | |
| 348 | 348 | embedded into Fossil itself. Fossil's build system and test suite are |
| 349 | 349 | largely based on Tcl.⁵ All of this is quite portable. |
| 350 | 350 | |
| 351 | 351 | About half of Git's code is POSIX C, and about a third is POSIX shell |
| 352 | 352 | code. This is largely why the so-called "Git for Windows" distributions |
| 353 | 353 |
| --- www/fossil-v-git.wiki | |
| +++ www/fossil-v-git.wiki | |
| @@ -342,11 +342,11 @@ | |
| 342 | Fossil isn't entirely C and SQL code. Its web UI [./javascript.md | |
| 343 | uses JavaScript where |
| 344 | necessary]. The server-side |
| 345 | UI scripting uses a custom minimal |
| 346 | [https://en.wikipedia.org/wiki/Tcl|Tcl] dialect called |
| 347 | [https://fossil-scm.org/xfer/doc/trunk/www/th1.md|TH1], which is |
| 348 | embedded into Fossil itself. Fossil's build system and test suite are |
| 349 | largely based on Tcl.⁵ All of this is quite portable. |
| 350 | |
| 351 | About half of Git's code is POSIX C, and about a third is POSIX shell |
| 352 | code. This is largely why the so-called "Git for Windows" distributions |
| 353 |
| --- www/fossil-v-git.wiki | |
| +++ www/fossil-v-git.wiki | |
| @@ -342,11 +342,11 @@ | |
| 342 | Fossil isn't entirely C and SQL code. Its web UI [./javascript.md | |
| 343 | uses JavaScript where |
| 344 | necessary]. The server-side |
| 345 | UI scripting uses a custom minimal |
| 346 | [https://en.wikipedia.org/wiki/Tcl|Tcl] dialect called |
| 347 | [./th1.md|TH1], which is |
| 348 | embedded into Fossil itself. Fossil's build system and test suite are |
| 349 | largely based on Tcl.⁵ All of this is quite portable. |
| 350 | |
| 351 | About half of Git's code is POSIX C, and about a third is POSIX shell |
| 352 | code. This is largely why the so-called "Git for Windows" distributions |
| 353 |
+1
-1
| --- www/gsoc-ideas.md | ||
| +++ www/gsoc-ideas.md | ||
| @@ -24,11 +24,11 @@ | ||
| 24 | 24 | # UI, Look and Feel |
| 25 | 25 | |
| 26 | 26 | Tasks for those interested in graphic/web design: |
| 27 | 27 | |
| 28 | 28 | * Add a quote button to the Forum, such as [discussed in this thread](https://fossil-scm.org/forum/forumpost/7ad03cd73d) |
| 29 | -* Improve the documentation history-browsing page to enable selection of 2 arbitrary versions to diff, similar to the [Mediawiki history feature enabled on Wikipedia](https://en.wikipedia.org/w/index.php?title=Fossil_(software)&action=history) | |
| 29 | +* Improve the documentation history-browsing page to enable selection of 2 arbitrary versions to diff, similar to the [Mediawiki history feature enabled on Wikipedia](https://en.wikipedia.org/w/index.php?title=Fossil_\(software\)&action=history) | |
| 30 | 30 | * Allow diffing of Forum posts |
| 31 | 31 | * General touch-ups in the existing skins. This may, depending on how deep one |
| 32 | 32 | cares to dig, require digging into C code to find, and potentially modify, how |
| 33 | 33 | the HTML is generated. |
| 34 | 34 | * Creation of one or more new skins. This does not specifically require any C |
| 35 | 35 |
| --- www/gsoc-ideas.md | |
| +++ www/gsoc-ideas.md | |
| @@ -24,11 +24,11 @@ | |
| 24 | # UI, Look and Feel |
| 25 | |
| 26 | Tasks for those interested in graphic/web design: |
| 27 | |
| 28 | * Add a quote button to the Forum, such as [discussed in this thread](https://fossil-scm.org/forum/forumpost/7ad03cd73d) |
| 29 | * Improve the documentation history-browsing page to enable selection of 2 arbitrary versions to diff, similar to the [Mediawiki history feature enabled on Wikipedia](https://en.wikipedia.org/w/index.php?title=Fossil_(software)&action=history) |
| 30 | * Allow diffing of Forum posts |
| 31 | * General touch-ups in the existing skins. This may, depending on how deep one |
| 32 | cares to dig, require digging into C code to find, and potentially modify, how |
| 33 | the HTML is generated. |
| 34 | * Creation of one or more new skins. This does not specifically require any C |
| 35 |
| --- www/gsoc-ideas.md | |
| +++ www/gsoc-ideas.md | |
| @@ -24,11 +24,11 @@ | |
| 24 | # UI, Look and Feel |
| 25 | |
| 26 | Tasks for those interested in graphic/web design: |
| 27 | |
| 28 | * Add a quote button to the Forum, such as [discussed in this thread](https://fossil-scm.org/forum/forumpost/7ad03cd73d) |
| 29 | * Improve the documentation history-browsing page to enable selection of 2 arbitrary versions to diff, similar to the [Mediawiki history feature enabled on Wikipedia](https://en.wikipedia.org/w/index.php?title=Fossil_\(software\)&action=history) |
| 30 | * Allow diffing of Forum posts |
| 31 | * General touch-ups in the existing skins. This may, depending on how deep one |
| 32 | cares to dig, require digging into C code to find, and potentially modify, how |
| 33 | the HTML is generated. |
| 34 | * Creation of one or more new skins. This does not specifically require any C |
| 35 |
+4
-4
| --- www/index.wiki | ||
| +++ www/index.wiki | ||
| @@ -84,16 +84,16 @@ | ||
| 84 | 84 | the repository are consistent prior to each commit. |
| 85 | 85 | |
| 86 | 86 | 8. <b>Free and Open-Source</b> — [../COPYRIGHT-BSD2.txt|2-clause BSD license]. |
| 87 | 87 | |
| 88 | 88 | <hr> |
| 89 | -<h3>Latest Release: 2.25 ([/timeline?c=version-2.25|2024-11-06])</h3> | |
| 89 | +<h3>Latest Release: 2.26 ([/timeline?c=version-2.26|2025-04-30])</h3> | |
| 90 | 90 | |
| 91 | 91 | * [/uv/download.html|Download] |
| 92 | - * [./changes.wiki#v2_25|Change Summary] | |
| 93 | - * [/timeline?p=version-2.25&bt=version-2.24&y=ci|Check-ins in version 2.25] | |
| 94 | - * [/timeline?df=version-2.25&y=ci|Check-ins derived from the 2.25 release] | |
| 92 | + * [./changes.wiki#v2_26|Change Summary] | |
| 93 | + * [/timeline?p=version-2.26&d=version-2.25&y=ci|Check-ins in version 2.26] | |
| 94 | + * [/timeline?df=version-2.26&y=ci|Check-ins derived from the 2.26 release] | |
| 95 | 95 | * [/timeline?t=release|Timeline of all past releases] |
| 96 | 96 | |
| 97 | 97 | <hr> |
| 98 | 98 | <h3>Quick Start</h3> |
| 99 | 99 | |
| 100 | 100 |
| --- www/index.wiki | |
| +++ www/index.wiki | |
| @@ -84,16 +84,16 @@ | |
| 84 | the repository are consistent prior to each commit. |
| 85 | |
| 86 | 8. <b>Free and Open-Source</b> — [../COPYRIGHT-BSD2.txt|2-clause BSD license]. |
| 87 | |
| 88 | <hr> |
| 89 | <h3>Latest Release: 2.25 ([/timeline?c=version-2.25|2024-11-06])</h3> |
| 90 | |
| 91 | * [/uv/download.html|Download] |
| 92 | * [./changes.wiki#v2_25|Change Summary] |
| 93 | * [/timeline?p=version-2.25&bt=version-2.24&y=ci|Check-ins in version 2.25] |
| 94 | * [/timeline?df=version-2.25&y=ci|Check-ins derived from the 2.25 release] |
| 95 | * [/timeline?t=release|Timeline of all past releases] |
| 96 | |
| 97 | <hr> |
| 98 | <h3>Quick Start</h3> |
| 99 | |
| 100 |
| --- www/index.wiki | |
| +++ www/index.wiki | |
| @@ -84,16 +84,16 @@ | |
| 84 | the repository are consistent prior to each commit. |
| 85 | |
| 86 | 8. <b>Free and Open-Source</b> — [../COPYRIGHT-BSD2.txt|2-clause BSD license]. |
| 87 | |
| 88 | <hr> |
| 89 | <h3>Latest Release: 2.26 ([/timeline?c=version-2.26|2025-04-30])</h3> |
| 90 | |
| 91 | * [/uv/download.html|Download] |
| 92 | * [./changes.wiki#v2_26|Change Summary] |
| 93 | * [/timeline?p=version-2.26&d=version-2.25&y=ci|Check-ins in version 2.26] |
| 94 | * [/timeline?df=version-2.26&y=ci|Check-ins derived from the 2.26 release] |
| 95 | * [/timeline?t=release|Timeline of all past releases] |
| 96 | |
| 97 | <hr> |
| 98 | <h3>Quick Start</h3> |
| 99 | |
| 100 |
+16
-18
| --- www/reviews.wiki | ||
| +++ www/reviews.wiki | ||
| @@ -35,33 +35,31 @@ | ||
| 35 | 35 | </div> |
| 36 | 36 | |
| 37 | 37 | <b>Stephan Beal writes on 2009-01-11:</b> |
| 38 | 38 | |
| 39 | 39 | <div class="indent"> |
| 40 | -Sometime in late 2007 I came across a link to fossil on | |
| 41 | -<a href="http://www.sqlite.org/">sqlite.org</a>. It | |
| 42 | -was a good thing I bookmarked it, because I was never able to find the | |
| 43 | -link again (it might have been in a bug report or something). The | |
| 44 | -reasons I first took a close look at it were (A) it stemmed from the | |
| 45 | -sqlite project, which I've held in high regards for years (e.g. I | |
| 46 | -wrote JavaScript bindings for it: | |
| 47 | -<a href="http://spiderape.sourceforge.net/plugins/sqlite/"> | |
| 48 | -http://spiderape.sourceforge.net/plugins/sqlite/</a>), and (B) it could | |
| 49 | -run as a CGI. That second point might seem a bit archaic, but in | |
| 50 | -practice CGI is the only way most hosted sites can set up a shared | |
| 51 | -source repository with multiple user IDs. (i'm not about to give out | |
| 52 | -my only account password or SSH key for my hosted sites, no matter how | |
| 53 | -much I trust the other developers, and none of my hosters allow me to | |
| 54 | -run standalone servers or add Apache modules.) | |
| 40 | +Sometime in late 2007 I came across a link to fossil on <a | |
| 41 | +href="https://sqlite.org/">sqlite.org</a>. It was a good thing I | |
| 42 | +bookmarked it, because I was never able to find the link again (it | |
| 43 | +might have been in a bug report or something). The reasons I first | |
| 44 | +took a close look at it were (A) it stemmed from the sqlite project, | |
| 45 | +which I've held in high regards for years (e.g. I wrote bindings for | |
| 46 | +it for Mozilla's SpiderMonkey JavaScript engine), and (B) it could run | |
| 47 | +as a CGI. That second point might seem a bit archaic, but in practice | |
| 48 | +CGI is the only way most hosted sites can set up a shared source | |
| 49 | +repository with multiple user IDs. (i'm not about to give out my only | |
| 50 | +account password or SSH key for my hosted sites, no matter how much I | |
| 51 | +trust the other developers, and none of my hosters allow me to run | |
| 52 | +standalone servers or add Apache modules.) | |
| 55 | 53 | |
| 56 | 54 | So I tried it out. The thing which bugged me most about it was having |
| 57 | 55 | to type "commit" or "com" instead of "ci" for checking in (as is |
| 58 | 56 | custom in all other systems I've used), despite the fact that fossil |
| 59 | 57 | uses "ci" as a filter in things like the timeline view. Looking back |
| 60 | 58 | now, I have used fossil for about about 95% of my work in the past |
| 61 | -year (<a href="http://blog.s11n.net/?p=71"><i>dead link</i></a>), in | |
| 62 | -over 15 source trees, and I now get tripped up when I have to use svn or cvs. | |
| 59 | +year, in over 15 source trees, and I now get tripped up when I have to | |
| 60 | +use svn or cvs. | |
| 63 | 61 | |
| 64 | 62 | So, having got over typing "fossil com -m ...", here's why I love it so much... |
| 65 | 63 | |
| 66 | 64 | Point #1: CGI |
| 67 | 65 | |
| @@ -70,11 +68,11 @@ | ||
| 70 | 68 | (they don't belong to those projects), which I cannot host in google |
| 71 | 69 | code (because google code doesn't allow/recognize Public Domain as a |
| 72 | 70 | license, and I refuse to relicense just to accommodate them), and for |
| 73 | 71 | which SourceForge is overkill (and way too slow). With fossil I can |
| 74 | 72 | create a new repo, have it installed on my hoster |
| 75 | -(http://fossil.wanderinghorse.net), and be commiting code to it within | |
| 73 | +(https://fossil.wanderinghorse.net), and be commiting code to it within | |
| 76 | 74 | 5 minutes. |
| 77 | 75 | |
| 78 | 76 | Point #2: Wiki |
| 79 | 77 | |
| 80 | 78 | I hate wikis. I really do. Always have. They all have a different |
| 81 | 79 |
| --- www/reviews.wiki | |
| +++ www/reviews.wiki | |
| @@ -35,33 +35,31 @@ | |
| 35 | </div> |
| 36 | |
| 37 | <b>Stephan Beal writes on 2009-01-11:</b> |
| 38 | |
| 39 | <div class="indent"> |
| 40 | Sometime in late 2007 I came across a link to fossil on |
| 41 | <a href="http://www.sqlite.org/">sqlite.org</a>. It |
| 42 | was a good thing I bookmarked it, because I was never able to find the |
| 43 | link again (it might have been in a bug report or something). The |
| 44 | reasons I first took a close look at it were (A) it stemmed from the |
| 45 | sqlite project, which I've held in high regards for years (e.g. I |
| 46 | wrote JavaScript bindings for it: |
| 47 | <a href="http://spiderape.sourceforge.net/plugins/sqlite/"> |
| 48 | http://spiderape.sourceforge.net/plugins/sqlite/</a>), and (B) it could |
| 49 | run as a CGI. That second point might seem a bit archaic, but in |
| 50 | practice CGI is the only way most hosted sites can set up a shared |
| 51 | source repository with multiple user IDs. (i'm not about to give out |
| 52 | my only account password or SSH key for my hosted sites, no matter how |
| 53 | much I trust the other developers, and none of my hosters allow me to |
| 54 | run standalone servers or add Apache modules.) |
| 55 | |
| 56 | So I tried it out. The thing which bugged me most about it was having |
| 57 | to type "commit" or "com" instead of "ci" for checking in (as is |
| 58 | custom in all other systems I've used), despite the fact that fossil |
| 59 | uses "ci" as a filter in things like the timeline view. Looking back |
| 60 | now, I have used fossil for about about 95% of my work in the past |
| 61 | year (<a href="http://blog.s11n.net/?p=71"><i>dead link</i></a>), in |
| 62 | over 15 source trees, and I now get tripped up when I have to use svn or cvs. |
| 63 | |
| 64 | So, having got over typing "fossil com -m ...", here's why I love it so much... |
| 65 | |
| 66 | Point #1: CGI |
| 67 | |
| @@ -70,11 +68,11 @@ | |
| 70 | (they don't belong to those projects), which I cannot host in google |
| 71 | code (because google code doesn't allow/recognize Public Domain as a |
| 72 | license, and I refuse to relicense just to accommodate them), and for |
| 73 | which SourceForge is overkill (and way too slow). With fossil I can |
| 74 | create a new repo, have it installed on my hoster |
| 75 | (http://fossil.wanderinghorse.net), and be commiting code to it within |
| 76 | 5 minutes. |
| 77 | |
| 78 | Point #2: Wiki |
| 79 | |
| 80 | I hate wikis. I really do. Always have. They all have a different |
| 81 |
| --- www/reviews.wiki | |
| +++ www/reviews.wiki | |
| @@ -35,33 +35,31 @@ | |
| 35 | </div> |
| 36 | |
| 37 | <b>Stephan Beal writes on 2009-01-11:</b> |
| 38 | |
| 39 | <div class="indent"> |
| 40 | Sometime in late 2007 I came across a link to fossil on <a |
| 41 | href="https://sqlite.org/">sqlite.org</a>. It was a good thing I |
| 42 | bookmarked it, because I was never able to find the link again (it |
| 43 | might have been in a bug report or something). The reasons I first |
| 44 | took a close look at it were (A) it stemmed from the sqlite project, |
| 45 | which I've held in high regards for years (e.g. I wrote bindings for |
| 46 | it for Mozilla's SpiderMonkey JavaScript engine), and (B) it could run |
| 47 | as a CGI. That second point might seem a bit archaic, but in practice |
| 48 | CGI is the only way most hosted sites can set up a shared source |
| 49 | repository with multiple user IDs. (i'm not about to give out my only |
| 50 | account password or SSH key for my hosted sites, no matter how much I |
| 51 | trust the other developers, and none of my hosters allow me to run |
| 52 | standalone servers or add Apache modules.) |
| 53 | |
| 54 | So I tried it out. The thing which bugged me most about it was having |
| 55 | to type "commit" or "com" instead of "ci" for checking in (as is |
| 56 | custom in all other systems I've used), despite the fact that fossil |
| 57 | uses "ci" as a filter in things like the timeline view. Looking back |
| 58 | now, I have used fossil for about about 95% of my work in the past |
| 59 | year, in over 15 source trees, and I now get tripped up when I have to |
| 60 | use svn or cvs. |
| 61 | |
| 62 | So, having got over typing "fossil com -m ...", here's why I love it so much... |
| 63 | |
| 64 | Point #1: CGI |
| 65 | |
| @@ -70,11 +68,11 @@ | |
| 68 | (they don't belong to those projects), which I cannot host in google |
| 69 | code (because google code doesn't allow/recognize Public Domain as a |
| 70 | license, and I refuse to relicense just to accommodate them), and for |
| 71 | which SourceForge is overkill (and way too slow). With fossil I can |
| 72 | create a new repo, have it installed on my hoster |
| 73 | (https://fossil.wanderinghorse.net), and be commiting code to it within |
| 74 | 5 minutes. |
| 75 | |
| 76 | Point #2: Wiki |
| 77 | |
| 78 | I hate wikis. I really do. Always have. They all have a different |
| 79 |
+21
-24
| --- www/th1.md | ||
| +++ www/th1.md | ||
| @@ -12,29 +12,43 @@ | ||
| 12 | 12 | time all of the test cases for SQLite were written in Tcl and Tcl could not |
| 13 | 13 | be easily compiled on the SymbianOS. So TH1 was developed as a cut-down |
| 14 | 14 | version of Tcl that would facilitate running the SQLite test scripts on |
| 15 | 15 | SymbianOS. |
| 16 | 16 | |
| 17 | -Fossil was first being designed at about the same time that TH1 was | |
| 18 | -being developed for testing SQLite on SymbianOS. | |
| 17 | +Fossil was first being designed at about the same time. | |
| 19 | 18 | Early prototypes of Fossil were written in pure Tcl. But as the development |
| 20 | 19 | shifted toward the use of C-code, the need arose to have a Tcl-like |
| 21 | 20 | scripting language to help with code generation. TH1 was small and |
| 22 | 21 | light-weight and used minimal resources and seemed ideally suited for the |
| 23 | 22 | task. |
| 24 | 23 | |
| 25 | -The name "TH1" stands "Test Harness 1", since that was its original purpose. | |
| 24 | +The name "TH1" stands for "Test Harness 1", | |
| 25 | +since its original purpose was to serve as testing harness | |
| 26 | +for SQLite. | |
| 26 | 27 | |
| 27 | -Overview | |
| --------- | ||
| 28 | +Where TH1 Is Used In Fossil | |
| 29 | +--------------------------- | |
| 30 | + | |
| 31 | + * In the header and footer for [skins](./customskin.md) | |
| 32 | + text within `<th1>...</th1>` is run as a TH1 script. | |
| 33 | + ([example](/builtin/skins/default/header.txt)) | |
| 34 | + | |
| 35 | + * This display of [tickets](./bugtheory.wiki) is controlled by TH1 | |
| 36 | + scripts, so that the ticket format can be customized for each | |
| 37 | + project. Administrators can visit the <b>/tktsetup</b> page in | |
| 38 | + their repositories to view and customize these scripts. | |
| 39 | + ([example usage](./custom_ticket.wiki)) | |
| 40 | + | |
| 41 | +Overview Of The Tcl/TH1 Language | |
| 42 | +-------------------------------- | |
| 28 | 43 | |
| 29 | 44 | TH1 is a string-processing language. All values are strings. Any numerical |
| 30 | 45 | operations are accomplished by converting from string to numeric, performing |
| 31 | 46 | the computation, then converting the result back into a string. (This might |
| 32 | 47 | seem inefficient, but it is faster than people imagine, and numeric |
| 33 | 48 | computations do not come up very often for the kinds of work that TH1 does, |
| 34 | -so it has never been a factor.) | |
| 49 | +so it has never been an issue.) | |
| 35 | 50 | |
| 36 | 51 | A TH1 script consists of a sequence of commands. |
| 37 | 52 | Each command is terminated by the first *unescaped* newline or ";" character. |
| 38 | 53 | The text of the command (excluding the newline or semicolon terminator) |
| 39 | 54 | is broken into space-separated tokens. The first token is the command |
| @@ -126,11 +140,11 @@ | ||
| 126 | 140 | custom TH1 scripts for headers or footers or tickets are added to a |
| 127 | 141 | repository. Note that the tainted/untainted distinction in strings does |
| 128 | 142 | not make it impossible to introduce XSS and SQL-injections vulnerabilities |
| 129 | 143 | using poorly-written TH1 scripts; it just makes it more difficult and |
| 130 | 144 | less likely to happen by accident. Developers must still consider the |
| 131 | -security implications TH1 customizations they add to Fossil, and take | |
| 145 | +security implications of TH1 customizations they add to Fossil, and take | |
| 132 | 146 | appropriate precautions when writing custom TH1. Peer review of TH1 |
| 133 | 147 | script changes is encouraged. |
| 134 | 148 | |
| 135 | 149 | In Fossil version 2.26, if the vuln-report setting is set to "block" |
| 136 | 150 | or "fatal", the [html](#html) and [query](#query) TH1 commands will |
| @@ -224,11 +238,10 @@ | ||
| 224 | 238 | * [copybtn](#copybtn) |
| 225 | 239 | * [date](#date) |
| 226 | 240 | * [decorate](#decorate) |
| 227 | 241 | * [defHeader](#defHeader) |
| 228 | 242 | * [dir](#dir) |
| 229 | - * [enable\_htmlify](#enable_htmlify) | |
| 230 | 243 | * [enable\_output](#enable_output) |
| 231 | 244 | * [encode64](#encode64) |
| 232 | 245 | * [getParameter](#getParameter) |
| 233 | 246 | * [glob\_match](#glob_match) |
| 234 | 247 | * [globalState](#globalState) |
| @@ -457,28 +470,10 @@ | ||
| 457 | 470 | the files matching the pattern GLOB within CHECKIN will be returned. |
| 458 | 471 | If DETAILS is non-zero, the result will be a list-of-lists, with each |
| 459 | 472 | element containing at least three elements: the file name, the file |
| 460 | 473 | size (in bytes), and the file last modification time (relative to the |
| 461 | 474 | time zone configured for the repository). |
| 462 | - | |
| 463 | -<a id="enable_htmlify"></a>TH1 enable\_htmlify Command | |
| ------------------------------------------------------- | ||
| 464 | - | |
| 465 | - * enable\_htmlify | |
| 466 | - * enable\_htmlify ?TRACE-LABEL? BOOLEAN | |
| 467 | - | |
| 468 | -By default, certain output from `puts` and similar commands is escaped | |
| 469 | -for HTML. The first call form returns the current state of that | |
| 470 | -feature: `1` for on and `0` for off. The second call form enables | |
| 471 | -(non-0) or disables (0) that feature and returns the *pre-call* state | |
| 472 | -of that feature (so that a second call can pass that value to restore | |
| 473 | -it to its previous state). The optional `TRACE-LABEL` argument causes | |
| 474 | -the TH1 tracing output (if enabled) to add a marker when the second | |
| 475 | -form of this command is invoked, and includes that label and the | |
| 476 | -boolean argument's value in the trace. If tracing is disabled, that | |
| 477 | -argument has no effect. | |
| 478 | - | |
| 479 | 475 | |
| 480 | 476 | <a id="enable_output"></a>TH1 enable\_output Command |
| 481 | 477 | ------------------------------------------------------ |
| 482 | 478 | |
| 483 | 479 | * enable\_output BOOLEAN |
| 484 | 480 |
| --- www/th1.md | |
| +++ www/th1.md | |
| @@ -12,29 +12,43 @@ | |
| 12 | time all of the test cases for SQLite were written in Tcl and Tcl could not |
| 13 | be easily compiled on the SymbianOS. So TH1 was developed as a cut-down |
| 14 | version of Tcl that would facilitate running the SQLite test scripts on |
| 15 | SymbianOS. |
| 16 | |
| 17 | Fossil was first being designed at about the same time that TH1 was |
| 18 | being developed for testing SQLite on SymbianOS. |
| 19 | Early prototypes of Fossil were written in pure Tcl. But as the development |
| 20 | shifted toward the use of C-code, the need arose to have a Tcl-like |
| 21 | scripting language to help with code generation. TH1 was small and |
| 22 | light-weight and used minimal resources and seemed ideally suited for the |
| 23 | task. |
| 24 | |
| 25 | The name "TH1" stands "Test Harness 1", since that was its original purpose. |
| 26 | |
| 27 | Overview |
| --------- | |
| 28 | |
| 29 | TH1 is a string-processing language. All values are strings. Any numerical |
| 30 | operations are accomplished by converting from string to numeric, performing |
| 31 | the computation, then converting the result back into a string. (This might |
| 32 | seem inefficient, but it is faster than people imagine, and numeric |
| 33 | computations do not come up very often for the kinds of work that TH1 does, |
| 34 | so it has never been a factor.) |
| 35 | |
| 36 | A TH1 script consists of a sequence of commands. |
| 37 | Each command is terminated by the first *unescaped* newline or ";" character. |
| 38 | The text of the command (excluding the newline or semicolon terminator) |
| 39 | is broken into space-separated tokens. The first token is the command |
| @@ -126,11 +140,11 @@ | |
| 126 | custom TH1 scripts for headers or footers or tickets are added to a |
| 127 | repository. Note that the tainted/untainted distinction in strings does |
| 128 | not make it impossible to introduce XSS and SQL-injections vulnerabilities |
| 129 | using poorly-written TH1 scripts; it just makes it more difficult and |
| 130 | less likely to happen by accident. Developers must still consider the |
| 131 | security implications TH1 customizations they add to Fossil, and take |
| 132 | appropriate precautions when writing custom TH1. Peer review of TH1 |
| 133 | script changes is encouraged. |
| 134 | |
| 135 | In Fossil version 2.26, if the vuln-report setting is set to "block" |
| 136 | or "fatal", the [html](#html) and [query](#query) TH1 commands will |
| @@ -224,11 +238,10 @@ | |
| 224 | * [copybtn](#copybtn) |
| 225 | * [date](#date) |
| 226 | * [decorate](#decorate) |
| 227 | * [defHeader](#defHeader) |
| 228 | * [dir](#dir) |
| 229 | * [enable\_htmlify](#enable_htmlify) |
| 230 | * [enable\_output](#enable_output) |
| 231 | * [encode64](#encode64) |
| 232 | * [getParameter](#getParameter) |
| 233 | * [glob\_match](#glob_match) |
| 234 | * [globalState](#globalState) |
| @@ -457,28 +470,10 @@ | |
| 457 | the files matching the pattern GLOB within CHECKIN will be returned. |
| 458 | If DETAILS is non-zero, the result will be a list-of-lists, with each |
| 459 | element containing at least three elements: the file name, the file |
| 460 | size (in bytes), and the file last modification time (relative to the |
| 461 | time zone configured for the repository). |
| 462 | |
| 463 | <a id="enable_htmlify"></a>TH1 enable\_htmlify Command |
| ------------------------------------------------------- | |
| 464 | |
| 465 | * enable\_htmlify |
| 466 | * enable\_htmlify ?TRACE-LABEL? BOOLEAN |
| 467 | |
| 468 | By default, certain output from `puts` and similar commands is escaped |
| 469 | for HTML. The first call form returns the current state of that |
| 470 | feature: `1` for on and `0` for off. The second call form enables |
| 471 | (non-0) or disables (0) that feature and returns the *pre-call* state |
| 472 | of that feature (so that a second call can pass that value to restore |
| 473 | it to its previous state). The optional `TRACE-LABEL` argument causes |
| 474 | the TH1 tracing output (if enabled) to add a marker when the second |
| 475 | form of this command is invoked, and includes that label and the |
| 476 | boolean argument's value in the trace. If tracing is disabled, that |
| 477 | argument has no effect. |
| 478 | |
| 479 | |
| 480 | <a id="enable_output"></a>TH1 enable\_output Command |
| 481 | ------------------------------------------------------ |
| 482 | |
| 483 | * enable\_output BOOLEAN |
| 484 |
| --- www/th1.md | |
| +++ www/th1.md | |
| @@ -12,29 +12,43 @@ | |
| 12 | time all of the test cases for SQLite were written in Tcl and Tcl could not |
| 13 | be easily compiled on the SymbianOS. So TH1 was developed as a cut-down |
| 14 | version of Tcl that would facilitate running the SQLite test scripts on |
| 15 | SymbianOS. |
| 16 | |
| 17 | Fossil was first being designed at about the same time. |
| 18 | Early prototypes of Fossil were written in pure Tcl. But as the development |
| 19 | shifted toward the use of C-code, the need arose to have a Tcl-like |
| 20 | scripting language to help with code generation. TH1 was small and |
| 21 | light-weight and used minimal resources and seemed ideally suited for the |
| 22 | task. |
| 23 | |
| 24 | The name "TH1" stands for "Test Harness 1", |
| 25 | since its original purpose was to serve as testing harness |
| 26 | for SQLite. |
| 27 | |
| --------- | |
| 28 | Where TH1 Is Used In Fossil |
| 29 | --------------------------- |
| 30 | |
| 31 | * In the header and footer for [skins](./customskin.md) |
| 32 | text within `<th1>...</th1>` is run as a TH1 script. |
| 33 | ([example](/builtin/skins/default/header.txt)) |
| 34 | |
| 35 | * This display of [tickets](./bugtheory.wiki) is controlled by TH1 |
| 36 | scripts, so that the ticket format can be customized for each |
| 37 | project. Administrators can visit the <b>/tktsetup</b> page in |
| 38 | their repositories to view and customize these scripts. |
| 39 | ([example usage](./custom_ticket.wiki)) |
| 40 | |
| 41 | Overview Of The Tcl/TH1 Language |
| 42 | -------------------------------- |
| 43 | |
| 44 | TH1 is a string-processing language. All values are strings. Any numerical |
| 45 | operations are accomplished by converting from string to numeric, performing |
| 46 | the computation, then converting the result back into a string. (This might |
| 47 | seem inefficient, but it is faster than people imagine, and numeric |
| 48 | computations do not come up very often for the kinds of work that TH1 does, |
| 49 | so it has never been an issue.) |
| 50 | |
| 51 | A TH1 script consists of a sequence of commands. |
| 52 | Each command is terminated by the first *unescaped* newline or ";" character. |
| 53 | The text of the command (excluding the newline or semicolon terminator) |
| 54 | is broken into space-separated tokens. The first token is the command |
| @@ -126,11 +140,11 @@ | |
| 140 | custom TH1 scripts for headers or footers or tickets are added to a |
| 141 | repository. Note that the tainted/untainted distinction in strings does |
| 142 | not make it impossible to introduce XSS and SQL-injections vulnerabilities |
| 143 | using poorly-written TH1 scripts; it just makes it more difficult and |
| 144 | less likely to happen by accident. Developers must still consider the |
| 145 | security implications of TH1 customizations they add to Fossil, and take |
| 146 | appropriate precautions when writing custom TH1. Peer review of TH1 |
| 147 | script changes is encouraged. |
| 148 | |
| 149 | In Fossil version 2.26, if the vuln-report setting is set to "block" |
| 150 | or "fatal", the [html](#html) and [query](#query) TH1 commands will |
| @@ -224,11 +238,10 @@ | |
| 238 | * [copybtn](#copybtn) |
| 239 | * [date](#date) |
| 240 | * [decorate](#decorate) |
| 241 | * [defHeader](#defHeader) |
| 242 | * [dir](#dir) |
| 243 | * [enable\_output](#enable_output) |
| 244 | * [encode64](#encode64) |
| 245 | * [getParameter](#getParameter) |
| 246 | * [glob\_match](#glob_match) |
| 247 | * [globalState](#globalState) |
| @@ -457,28 +470,10 @@ | |
| 470 | the files matching the pattern GLOB within CHECKIN will be returned. |
| 471 | If DETAILS is non-zero, the result will be a list-of-lists, with each |
| 472 | element containing at least three elements: the file name, the file |
| 473 | size (in bytes), and the file last modification time (relative to the |
| 474 | time zone configured for the repository). |
| ------------------------------------------------------- | |
| 475 | |
| 476 | <a id="enable_output"></a>TH1 enable\_output Command |
| 477 | ------------------------------------------------------ |
| 478 | |
| 479 | * enable\_output BOOLEAN |
| 480 |