Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | merge trunk |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | prevent-adding-ignored-files |
| Files: | files | file ages | folders |
| SHA1: |
78862afd3c0666396f07afc4a1878e84 |
| User & Date: | jan.nijtmans 2014-02-09 17:14:59.649 |
Context
|
2014-02-20
| ||
| 08:51 | When doing "fossil add foo.*" but the user forgets there is a foo.o besides the foo.c and foo.h, and "ignore-glob" contains the "*.o" pattern, fossil will properly warn for this situation and ask what to do. (for Fossil itself this is no issue, as the *.o files are kept in a separate directory, but not all projects do that). Example: /Localdata/workspace/tcl8.6/unix $ touch foo.c foo.h foo.o /Localdata/workspace/tcl8.6/unix $ fossil add foo.* file "foo.o" matches "ignore-glob". Add it (a=all/y/N)? n ADDED foo.c ADDED foo.h check-in: 6ec21b58a2 user: jan.nijtmans tags: trunk | |
|
2014-02-09
| ||
| 17:14 | merge trunk Closed-Leaf check-in: 78862afd3c user: jan.nijtmans tags: prevent-adding-ignored-files | |
|
2014-02-08
| ||
| 08:54 | Fix harmless compiler warning check-in: 0681b39b82 user: jan.nijtmans tags: trunk | |
|
2013-06-19
| ||
| 07:06 | rebase check-in: f836a1cdca user: jan.nijtmans tags: prevent-adding-ignored-files | |
Changes
Changes to .fossil-settings/ignore-glob.
|
| | | > | 1 2 3 4 5 | compat/openssl* compat/tcl* fossil fossil.exe win/fossil.exe |
Changes to .fossil-settings/keep-glob.
1 2 | fossil fossil.exe | > > > | 1 2 3 4 5 | compat/openssl* compat/tcl* fossil fossil.exe win/fossil.exe |
Added Makefile.Cygwin.in.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #!/usr/bin/make # # This is the top-level makefile for Fossil when the build is occurring # on the Cygwin platform. # #### The toplevel directory of the source tree. Fossil can be built # in a directory that is separate from the source tree. Just change # the following to point from the build directory to the src/ folder. # SRCDIR = @srcdir@/src #### The directory into which object code files should be written. # Having a "./" prefix in the value of this variable breaks our use of the # "makeheaders" tool when running make on the MinGW platform, apparently # due to some command line argument manipulation performed automatically # by the shell. # # OBJDIR = bld #### C Compiler and options for use in building executables that # will run on the platform that is doing the build. This is used # to compile code-generator programs as part of the build process. # See TCC below for the C compiler for building the finished binary. # BCC = @CC_FOR_BUILD@ #### The suffix to add to final executable file. When cross-compiling # to windows, make this ".exe". Otherwise leave it blank. # E = @EXEEXT@ TCC = @CC@ #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR =$(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@ FOSSIL_ENABLE_TCL_PRIVATE_STUBS = @FOSSIL_ENABLE_TCL_PRIVATE_STUBS@ SQLITE_CFLAGS += -DSQLITE_WIN32_NO_ANSI -DSQLITE_WINNT_MAX_PATH_CHARS=4096 include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile |
Changes to Makefile.in.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 50 51 | LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile | > | 40 41 42 43 44 45 46 47 48 49 50 51 52 | LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@ TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H INSTALLDIR = $(DESTDIR)@prefix@/bin USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@ FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@ FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@ FOSSIL_ENABLE_TCL_PRIVATE_STUBS = @FOSSIL_ENABLE_TCL_PRIVATE_STUBS@ include $(SRCDIR)/main.mk distclean: clean rm -f autoconfig.h config.log Makefile |
Changes to VERSION.
|
| | | 1 | 1.28 |
Changes to auto.def.
1 2 3 4 5 6 7 8 9 |
# System autoconfiguration. Try: ./configure --help
use cc cc-lib
options {
with-openssl:path|auto|none
=> {Look for openssl in the given path, or auto or none}
with-zlib:path => {Look for zlib in the given path}
with-tcl:path => {Enable Tcl integration, with Tcl in the specified path}
| | > > | | | | | | | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# System autoconfiguration. Try: ./configure --help
use cc cc-lib
options {
with-openssl:path|auto|none
=> {Look for openssl in the given path, or auto or none}
with-zlib:path => {Look for zlib in the given path}
with-tcl:path => {Enable Tcl integration, with Tcl in the specified path}
with-tcl-stubs=0 => {Enable Tcl integration via stubs library mechanism}
with-tcl-private-stubs=0
=> {Enable Tcl integration via private stubs mechanism}
internal-sqlite=1 => {Don't use the internal SQLite, use the system one}
static=0 => {Link a static executable}
lineedit=1 => {Disable line editing}
fossil-debug=0 => {Build with fossil debugging enabled}
json=0 => {Build with fossil JSON API enabled}
}
# sqlite wants these types if possible
cc-with {-includes {stdint.h inttypes.h}} {
cc-check-types uint32_t uint16_t int16_t uint8_t
}
# Use pread/pwrite system calls in place of seek + read/write if possible
define USE_PREAD [cc-check-functions pread]
# Find tclsh for the test suite. Can't yet use jimsh for this.
cc-check-progs tclsh
define EXTRA_CFLAGS ""
define EXTRA_LDFLAGS ""
define USE_SYSTEM_SQLITE 0
if {![opt-bool internal-sqlite]} {
proc find_internal_sqlite {} {
# On some systems (slackware), libsqlite3 requires -ldl to link. So
# search for the system SQLite once with -ldl, and once without. If
# the library can only be found with $extralibs set to -ldl, then
# the code below will append -ldl to LIBS.
#
foreach extralibs {{} {-ldl}} {
# Locate the system SQLite by searching for sqlite3_open(). Then check
# if sqlite3_strglob() can be found as well. If we can find open() but
# not strglob(), then the system SQLite is too old to link against
# fossil.
#
if {[cc-check-function-in-lib sqlite3_open sqlite3 $extralibs]} {
if {![cc-check-function-in-lib sqlite3_strglob sqlite3 $extralibs]} {
user-error "system sqlite3 too old (require >= 3.7.17)"
}
# Success. Update symbols and return.
#
define USE_SYSTEM_SQLITE 1
define-append LIBS $extralibs
return
}
}
user-error "system sqlite3 not found"
}
find_internal_sqlite
}
if {[string match *-solaris* [get-define host]]} {
define-append EXTRA_CFLAGS -D_XOPEN_SOURCE=500
}
if {[opt-bool fossil-debug]} {
define-append EXTRA_CFLAGS -DFOSSIL_DEBUG
}
if {[opt-bool json]} {
# Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON
|
| ︙ | ︙ | |||
94 95 96 97 98 99 100 101 102 |
}
if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} {
user-error "zlib not found please install it or specify the location with --with-zlib"
}
set tclpath [opt-val with-tcl]
if {$tclpath ne ""} {
# Note parse-tclconfig-sh is in autosetup/local.tcl
if {$tclpath eq "1"} {
| > > > > > > > > | | > | | > > > > | > | | | | | | | | > > | > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
}
if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} {
user-error "zlib not found please install it or specify the location with --with-zlib"
}
set tclpath [opt-val with-tcl]
if {$tclpath ne ""} {
set tclprivatestubs [opt-bool with-tcl-private-stubs]
# Note parse-tclconfig-sh is in autosetup/local.tcl
if {$tclpath eq "1"} {
if {$tclprivatestubs} {
set tclconfig(TCL_INCLUDE_SPEC) -Icompat/tcl-8.6/generic
set tclconfig(TCL_VERSION) {Private Stubs}
set tclconfig(TCL_PATCH_LEVEL) {}
set tclconfig(TCL_PREFIX) {compat/tcl-8.6}
set tclconfig(TCL_LD_FLAGS) { }
} else {
# Use the system Tcl. Look in some likely places.
array set tclconfig [parse-tclconfig-sh \
compat/tcl-8.6/unix compat/tcl-8.6/win \
/usr /usr/local /usr/share /opt/local]
set msg "on your system"
}
} else {
array set tclconfig [parse-tclconfig-sh $tclpath]
set msg "at $tclpath"
}
if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
user-error "Cannot find Tcl $msg"
}
set tclstubs [opt-bool with-tcl-stubs]
if {$tclprivatestubs} {
define FOSSIL_ENABLE_TCL_PRIVATE_STUBS
define USE_TCL_STUBS
} elseif {$tclstubs && $tclconfig(TCL_SUPPORTS_STUBS)} {
set libs "$tclconfig(TCL_STUB_LIB_SPEC)"
define FOSSIL_ENABLE_TCL_STUBS
define USE_TCL_STUBS
} else {
set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
}
set cflags $tclconfig(TCL_INCLUDE_SPEC)
if {!$tclprivatestubs} {
cc-with [list -cflags $cflags -libs $libs] {
if {$tclstubs} {
if {![cc-check-functions Tcl_InitStubs]} {
user-error "Cannot find a usable Tcl stubs library $msg"
}
} else {
if {![cc-check-functions Tcl_CreateInterp]} {
user-error "Cannot find a usable Tcl library $msg"
}
}
}
}
set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
if {!$tclprivatestubs} {
define-append LIBS $libs
}
define-append EXTRA_CFLAGS $cflags
define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
define FOSSIL_ENABLE_TCL
}
# Helper for openssl checking
proc check-for-openssl {msg {cflags {}}} {
|
| ︙ | ︙ | |||
232 233 234 235 236 237 238 239 |
if {![cc-check-functions getpassphrase]} {
# Haiku needs this
cc-check-function-in-lib getpass bsd
}
cc-check-function-in-lib dlopen dl
make-template Makefile.in
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
| > | 255 256 257 258 259 260 261 262 263 |
if {![cc-check-functions getpassphrase]} {
# Haiku needs this
cc-check-function-in-lib getpass bsd
}
cc-check-function-in-lib dlopen dl
make-template Makefile.in
make-template Makefile.Cygwin.in
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
|
Changes to autosetup/jimsh0.c.
| ︙ | ︙ | |||
183 184 185 186 187 188 189 | # define strtoull strtoul # endif #endif #define UCHAR(c) ((unsigned char)(c)) | | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | # define strtoull strtoul # endif #endif #define UCHAR(c) ((unsigned char)(c)) #define JIM_VERSION 74 #define JIM_OK 0 #define JIM_ERR 1 #define JIM_RETURN 2 #define JIM_BREAK 3 #define JIM_CONTINUE 4 #define JIM_SIGNAL 5 |
| ︙ | ︙ | |||
319 320 321 322 323 324 325 |
#define Jim_GetHashEntryVal(he) ((he)->val)
#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
#define Jim_GetHashTableSize(ht) ((ht)->size)
#define Jim_GetHashTableUsed(ht) ((ht)->used)
typedef struct Jim_Obj {
| < < > > | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
#define Jim_GetHashEntryVal(he) ((he)->val)
#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
#define Jim_GetHashTableSize(ht) ((ht)->size)
#define Jim_GetHashTableUsed(ht) ((ht)->used)
typedef struct Jim_Obj {
char *bytes;
const struct Jim_ObjType *typePtr;
int refCount;
int length;
union {
jim_wide wideValue;
int intValue;
|
| ︙ | ︙ | |||
663 664 665 666 667 668 669 |
JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
(Jim_HashTableIterator *iter);
JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
| < < | 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
(Jim_HashTableIterator *iter);
JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
Jim_Obj *objPtr);
JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
int *lenPtr);
JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
|
| ︙ | ︙ | |||
875 876 877 878 879 880 881 882 883 884 885 886 887 888 | JIM_EXPORT char *Jim_HistoryGetline(const char *prompt); JIM_EXPORT void Jim_HistoryAdd(const char *line); JIM_EXPORT void Jim_HistoryShow(void); JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp); JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base); JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName); JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp); JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command); | > > | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | JIM_EXPORT char *Jim_HistoryGetline(const char *prompt); JIM_EXPORT void Jim_HistoryAdd(const char *line); JIM_EXPORT void Jim_HistoryShow(void); JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp); JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base); JIM_EXPORT int Jim_CheckSignal(Jim_Interp *interp); #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask) JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName); JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp); JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command); |
| ︙ | ︙ | |||
5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 |
#ifdef JIM_MAINTAINER
#define JIM_DEBUG_COMMAND
#define JIM_DEBUG_PANIC
#endif
const char *jim_tt_name(int type);
#ifdef JIM_DEBUG_PANIC
static void JimPanicDump(int panic_condition, const char *fmt, ...);
#define JimPanic(X) JimPanicDump X
#else
#define JimPanic(X)
#endif
static char JimEmptyStringRep[] = "";
static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
int flags);
static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
const char *prefix, const char *const *tablePtr, const char *name);
static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
static int JimSign(jim_wide w);
static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr);
static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
| > > > > | 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 |
#ifdef JIM_MAINTAINER
#define JIM_DEBUG_COMMAND
#define JIM_DEBUG_PANIC
#endif
#define JIM_INTEGER_SPACE 24
const char *jim_tt_name(int type);
#ifdef JIM_DEBUG_PANIC
static void JimPanicDump(int panic_condition, const char *fmt, ...);
#define JimPanic(X) JimPanicDump X
#else
#define JimPanic(X)
#endif
static char JimEmptyStringRep[] = "";
static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
int flags);
static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len);
static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
const char *prefix, const char *const *tablePtr, const char *name);
static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
static int JimSign(jim_wide w);
static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr);
static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
|
| ︙ | ︙ | |||
5932 5933 5934 5935 5936 5937 5938 |
if (n > 0) {
n = utf8_strlen(s2, n);
}
return n;
}
#endif
| | > | > > | > > > > > > > > > > > > > > > > > > > > > > > > | | 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 |
if (n > 0) {
n = utf8_strlen(s2, n);
}
return n;
}
#endif
static int JimWideToString(char *buf, jim_wide wideValue)
{
int pos = 0;
if (wideValue == 0) {
buf[pos++] = '0';
}
else {
char tmp[JIM_INTEGER_SPACE];
int num = 0;
int i;
if (wideValue < 0) {
buf[pos++] = '-';
i = wideValue % 10;
tmp[num++] = (i > 0) ? (10 - i) : -i;
wideValue /= -10;
}
while (wideValue) {
tmp[num++] = wideValue % 10;
wideValue /= 10;
}
for (i = 0; i < num; i++) {
buf[pos++] = '0' + tmp[num - i - 1];
}
}
buf[pos] = 0;
return pos;
}
static int JimCheckConversion(const char *str, const char *endptr)
{
if (str[0] == '\0' || str == endptr) {
return JIM_ERR;
}
|
| ︙ | ︙ | |||
6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 |
ht->table = NULL;
ht->size = 0;
ht->sizemask = 0;
ht->used = 0;
ht->collisions = 0;
}
int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
{
JimResetHashTable(ht);
ht->type = type;
ht->privdata = privDataPtr;
return JIM_OK;
| > > > > > > > > | 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 |
ht->table = NULL;
ht->size = 0;
ht->sizemask = 0;
ht->used = 0;
ht->collisions = 0;
}
static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
{
iter->ht = ht;
iter->index = -1;
iter->entry = NULL;
iter->nextEntry = NULL;
}
int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
{
JimResetHashTable(ht);
ht->type = type;
ht->privdata = privDataPtr;
return JIM_OK;
|
| ︙ | ︙ | |||
6406 6407 6408 6409 6410 6411 6412 |
}
return NULL;
}
Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
{
Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
| | < < < < | 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 |
}
return NULL;
}
Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
{
Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
JimInitHashTableIterator(ht, iter);
return iter;
}
Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
{
while (1) {
if (iter->entry == NULL) {
|
| ︙ | ︙ | |||
10498 10499 10500 10501 10502 10503 10504 |
}
int Jim_GetExitCode(Jim_Interp *interp)
{
return interp->exitCode;
}
| < < | | | 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 |
}
int Jim_GetExitCode(Jim_Interp *interp)
{
return interp->exitCode;
}
static void UpdateStringOfInt(struct Jim_Obj *objPtr);
static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
static const Jim_ObjType intObjType = {
"int",
NULL,
NULL,
UpdateStringOfInt,
JIM_TYPE_NONE,
};
static const Jim_ObjType coercedDoubleObjType = {
"coerced-double",
NULL,
NULL,
UpdateStringOfInt,
JIM_TYPE_NONE,
};
static void UpdateStringOfInt(struct Jim_Obj *objPtr)
{
int len;
char buf[JIM_INTEGER_SPACE + 1];
len = JimWideToString(buf, JimWideValue(objPtr));
objPtr->bytes = Jim_Alloc(len + 1);
memcpy(objPtr->bytes, buf, len + 1);
objPtr->length = len;
}
int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
{
|
| ︙ | ︙ | |||
10753 10754 10755 10756 10757 10758 10759 |
}
dupPtr->typePtr = &listObjType;
}
#define JIM_ELESTR_SIMPLE 0
#define JIM_ELESTR_BRACE 1
#define JIM_ELESTR_QUOTE 2
| | | 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 |
}
dupPtr->typePtr = &listObjType;
}
#define JIM_ELESTR_SIMPLE 0
#define JIM_ELESTR_BRACE 1
#define JIM_ELESTR_QUOTE 2
static unsigned char ListElementQuotingType(const char *s, int len)
{
int i, level, blevel, trySimple = 1;
if (len == 0)
return JIM_ELESTR_BRACE;
if (s[0] == '"' || s[0] == '{') {
|
| ︙ | ︙ | |||
10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 |
*p = '\0';
return p - q;
}
static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
{
int i, bufLen, realLength;
const char *strRep;
char *p;
| > | > | > > > > | 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 |
*p = '\0';
return p - q;
}
static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
{
#define STATIC_QUOTING_LEN 32
int i, bufLen, realLength;
const char *strRep;
char *p;
unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
if (objc > STATIC_QUOTING_LEN) {
quotingType = Jim_Alloc(objc);
}
else {
quotingType = staticQuoting;
}
bufLen = 0;
for (i = 0; i < objc; i++) {
int len;
strRep = Jim_GetString(objv[i], &len);
quotingType[i] = ListElementQuotingType(strRep, len);
switch (quotingType[i]) {
|
| ︙ | ︙ | |||
10973 10974 10975 10976 10977 10978 10979 |
if (i + 1 != objc) {
*p++ = ' ';
realLength++;
}
}
*p = '\0';
objPtr->length = realLength;
| > > | > | 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 |
if (i + 1 != objc) {
*p++ = ' ';
realLength++;
}
}
*p = '\0';
objPtr->length = realLength;
if (quotingType != staticQuoting) {
Jim_Free(quotingType);
}
}
static void UpdateStringOfList(struct Jim_Obj *objPtr)
{
JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
}
|
| ︙ | ︙ | |||
10998 10999 11000 11001 11002 11003 11004 |
}
if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) {
Jim_Obj **listObjPtrPtr;
int len;
int i;
| | | 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 |
}
if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) {
Jim_Obj **listObjPtrPtr;
int len;
int i;
listObjPtrPtr = JimDictPairs(objPtr, &len);
for (i = 0; i < len; i++) {
Jim_IncrRefCount(listObjPtrPtr[i]);
}
Jim_FreeIntRep(interp, objPtr);
objPtr->typePtr = &listObjType;
|
| ︙ | ︙ | |||
11223 11224 11225 11226 11227 11228 11229 |
{
int currentLen = listPtr->internalRep.listValue.len;
int requiredLen = currentLen + elemc;
int i;
Jim_Obj **point;
if (requiredLen > listPtr->internalRep.listValue.maxLen) {
| > > > > > | | > > > | | 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 |
{
int currentLen = listPtr->internalRep.listValue.len;
int requiredLen = currentLen + elemc;
int i;
Jim_Obj **point;
if (requiredLen > listPtr->internalRep.listValue.maxLen) {
if (requiredLen < 2) {
requiredLen = 4;
}
else {
requiredLen *= 2;
}
listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
sizeof(Jim_Obj *) * requiredLen);
listPtr->internalRep.listValue.maxLen = requiredLen;
}
if (idx < 0) {
idx = currentLen;
}
point = listPtr->internalRep.listValue.ele + idx;
memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
for (i = 0; i < elemc; ++i) {
|
| ︙ | ︙ | |||
11521 11522 11523 11524 11525 11526 11527 |
Jim_FreeHashTable(objPtr->internalRep.ptr);
Jim_Free(objPtr->internalRep.ptr);
}
void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
{
Jim_HashTable *ht, *dupHt;
| | | | < | | | < | 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 |
Jim_FreeHashTable(objPtr->internalRep.ptr);
Jim_Free(objPtr->internalRep.ptr);
}
void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
{
Jim_HashTable *ht, *dupHt;
Jim_HashTableIterator htiter;
Jim_HashEntry *he;
ht = srcPtr->internalRep.ptr;
dupHt = Jim_Alloc(sizeof(*dupHt));
Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
if (ht->size != 0)
Jim_ExpandHashTable(dupHt, ht->size);
JimInitHashTableIterator(ht, &htiter);
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
const Jim_Obj *keyObjPtr = he->key;
Jim_Obj *valObjPtr = he->u.val;
Jim_IncrRefCount((Jim_Obj *)keyObjPtr);
Jim_IncrRefCount(valObjPtr);
Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
}
dupPtr->internalRep.ptr = dupHt;
dupPtr->typePtr = &dictObjType;
}
static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len)
{
Jim_HashTable *ht;
Jim_HashTableIterator htiter;
Jim_HashEntry *he;
Jim_Obj **objv;
int i;
ht = dictPtr->internalRep.ptr;
objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
JimInitHashTableIterator(ht, &htiter);
i = 0;
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
objv[i++] = (Jim_Obj *)he->key;
objv[i++] = he->u.val;
}
*len = i;
return objv;
}
static void UpdateStringOfDict(struct Jim_Obj *objPtr)
{
int len;
|
| ︙ | ︙ | |||
12087 12088 12089 12090 12091 12092 12093 |
int skip;
};
typedef struct Jim_ExprOperator
{
const char *name;
| > | | < | > | 12135 12136 12137 12138 12139 12140 12141 12142 12143 12144 12145 12146 12147 12148 12149 12150 12151 12152 12153 |
int skip;
};
typedef struct Jim_ExprOperator
{
const char *name;
int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
unsigned char precedence;
unsigned char arity;
unsigned char lazy;
unsigned char namelen;
} Jim_ExprOperator;
static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
{
Jim_IncrRefCount(obj);
e->stack[e->stacklen++] = obj;
}
|
| ︙ | ︙ | |||
12772 12773 12774 12775 12776 12777 12778 12779 |
{
LAZY_NONE,
LAZY_OP,
LAZY_LEFT,
LAZY_RIGHT
};
static const struct Jim_ExprOperator Jim_ExprOperators[] = {
| > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 12821 12822 12823 12824 12825 12826 12827 12828 12829 12830 12831 12832 12833 12834 12835 12836 12837 12838 12839 12840 12841 12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 12852 12853 12854 12855 12856 12857 12858 12859 12860 12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906 12907 12908 12909 12910 12911 12912 12913 12914 12915 12916 12917 12918 12919 12920 |
{
LAZY_NONE,
LAZY_OP,
LAZY_LEFT,
LAZY_RIGHT
};
#define OPRINIT(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
static const struct Jim_ExprOperator Jim_ExprOperators[] = {
OPRINIT("*", 110, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("/", 110, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("%", 110, 2, JimExprOpIntBin, LAZY_NONE),
OPRINIT("-", 100, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("+", 100, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("<<", 90, 2, JimExprOpIntBin, LAZY_NONE),
OPRINIT(">>", 90, 2, JimExprOpIntBin, LAZY_NONE),
OPRINIT("<<<", 90, 2, JimExprOpIntBin, LAZY_NONE),
OPRINIT(">>>", 90, 2, JimExprOpIntBin, LAZY_NONE),
OPRINIT("<", 80, 2, JimExprOpBin, LAZY_NONE),
OPRINIT(">", 80, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("<=", 80, 2, JimExprOpBin, LAZY_NONE),
OPRINIT(">=", 80, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("==", 70, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("!=", 70, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("&", 50, 2, JimExprOpIntBin, LAZY_NONE),
OPRINIT("^", 49, 2, JimExprOpIntBin, LAZY_NONE),
OPRINIT("|", 48, 2, JimExprOpIntBin, LAZY_NONE),
OPRINIT("&&", 10, 2, NULL, LAZY_OP),
OPRINIT(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT),
OPRINIT(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT),
OPRINIT("||", 9, 2, NULL, LAZY_OP),
OPRINIT(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT),
OPRINIT(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT),
OPRINIT("?", 5, 2, JimExprOpNull, LAZY_OP),
OPRINIT(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT),
OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
OPRINIT(":", 5, 2, JimExprOpNull, LAZY_OP),
OPRINIT(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT),
OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
OPRINIT("**", 250, 2, JimExprOpBin, LAZY_NONE),
OPRINIT("eq", 60, 2, JimExprOpStrBin, LAZY_NONE),
OPRINIT("ne", 60, 2, JimExprOpStrBin, LAZY_NONE),
OPRINIT("in", 55, 2, JimExprOpStrBin, LAZY_NONE),
OPRINIT("ni", 55, 2, JimExprOpStrBin, LAZY_NONE),
OPRINIT("!", 150, 1, JimExprOpNumUnary, LAZY_NONE),
OPRINIT("~", 150, 1, JimExprOpIntUnary, LAZY_NONE),
OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE),
OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE),
OPRINIT("int", 200, 1, JimExprOpNumUnary, LAZY_NONE),
OPRINIT("abs", 200, 1, JimExprOpNumUnary, LAZY_NONE),
OPRINIT("double", 200, 1, JimExprOpNumUnary, LAZY_NONE),
OPRINIT("round", 200, 1, JimExprOpNumUnary, LAZY_NONE),
OPRINIT("rand", 200, 0, JimExprOpNone, LAZY_NONE),
OPRINIT("srand", 200, 1, JimExprOpIntUnary, LAZY_NONE),
#ifdef JIM_MATH_FUNCTIONS
OPRINIT("sin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("cos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("tan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("asin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("acos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("atan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("floor", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("exp", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("log", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("log10", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary, LAZY_NONE),
OPRINIT("pow", 200, 2, JimExprOpBin, LAZY_NONE),
#endif
};
#undef OPRINIT
#define JIM_EXPR_OPERATORS_NUM \
(sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
static int JimParseExpression(struct JimParserCtx *pc)
{
|
| ︙ | ︙ | |||
13024 13025 13026 13027 13028 13029 13030 |
static int JimParseExprOperator(struct JimParserCtx *pc)
{
int i;
int bestIdx = -1, bestLen = 0;
for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
| | | < | < | | 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 |
static int JimParseExprOperator(struct JimParserCtx *pc)
{
int i;
int bestIdx = -1, bestLen = 0;
for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
const char * const opname = Jim_ExprOperators[i].name;
const int oplen = Jim_ExprOperators[i].namelen;
if (opname == NULL || opname[0] != pc->p[0]) {
continue;
}
if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) {
bestIdx = i + JIM_TT_EXPR_OP;
bestLen = oplen;
}
}
if (bestIdx == -1) {
return JIM_ERR;
}
|
| ︙ | ︙ | |||
13109 13110 13111 13112 13113 13114 13115 |
NULL,
JIM_TYPE_REFERENCES,
};
typedef struct ExprByteCode
{
| < > | 13159 13160 13161 13162 13163 13164 13165 13166 13167 13168 13169 13170 13171 13172 13173 13174 |
NULL,
JIM_TYPE_REFERENCES,
};
typedef struct ExprByteCode
{
ScriptToken *token;
int len;
int inUse;
} ExprByteCode;
static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
{
int i;
|
| ︙ | ︙ | |||
13853 13854 13855 13856 13857 13858 13859 |
}
typedef struct ScanFmtPartDescr
{
| | | | | | 13903 13904 13905 13906 13907 13908 13909 13910 13911 13912 13913 13914 13915 13916 13917 13918 13919 13920 13921 13922 |
}
typedef struct ScanFmtPartDescr
{
char *arg;
char *prefix;
size_t width;
int pos;
char type;
char modifier;
} ScanFmtPartDescr;
typedef struct ScanFmtStringObj
{
jim_wide size;
char *stringRep;
|
| ︙ | ︙ | |||
14869 14870 14871 14872 14873 14874 14875 |
argc += len - 1;
}
}
if (retcode == JIM_OK && argc) {
retcode = JimInvokeCommand(interp, argc, argv);
| < | > | 14919 14920 14921 14922 14923 14924 14925 14926 14927 14928 14929 14930 14931 14932 14933 14934 |
argc += len - 1;
}
}
if (retcode == JIM_OK && argc) {
retcode = JimInvokeCommand(interp, argc, argv);
if (Jim_CheckSignal(interp)) {
retcode = JIM_SIGNAL;
}
}
while (j-- > 0) {
Jim_DecrRefCount(interp, argv[j]);
|
| ︙ | ︙ | |||
15444 15445 15446 15447 15448 15449 15450 |
if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr));
if (he) {
callback(interp, listObjPtr, he, type);
}
}
else {
| | > | < | 15494 15495 15496 15497 15498 15499 15500 15501 15502 15503 15504 15505 15506 15507 15508 15509 15510 15511 15512 15513 15514 |
if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr));
if (he) {
callback(interp, listObjPtr, he, type);
}
}
else {
Jim_HashTableIterator htiter;
JimInitHashTableIterator(ht, &htiter);
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), he->key, 0)) {
callback(interp, listObjPtr, he, type);
}
}
}
return listObjPtr;
}
#define JIM_CMDLIST_COMMANDS 0
#define JIM_CMDLIST_PROCS 1
|
| ︙ | ︙ | |||
17793 17794 17795 17796 17797 17798 17799 |
argv += i;
if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
sig++;
}
interp->signal_level += sig;
| | | 17843 17844 17845 17846 17847 17848 17849 17850 17851 17852 17853 17854 17855 17856 17857 |
argv += i;
if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
sig++;
}
interp->signal_level += sig;
if (Jim_CheckSignal(interp)) {
exitCode = JIM_SIGNAL;
}
else {
exitCode = Jim_EvalObj(interp, argv[0]);
}
interp->signal_level -= sig;
|
| ︙ | ︙ | |||
17949 17950 17951 17952 17953 17954 17955 |
return JIM_OK;
}
static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *listObjPtr;
| | | | < | 17999 18000 18001 18002 18003 18004 18005 18006 18007 18008 18009 18010 18011 18012 18013 18014 18015 18016 18017 18018 18019 18020 18021 18022 18023 18024 18025 18026 |
return JIM_OK;
}
static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
Jim_Obj *listObjPtr;
Jim_HashTableIterator htiter;
Jim_HashEntry *he;
listObjPtr = Jim_NewListObj(interp, NULL, 0);
JimInitHashTableIterator(&interp->references, &htiter);
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
char buf[JIM_REFERENCE_SPACE + 1];
Jim_Reference *refPtr = he->u.val;
const unsigned long *refId = he->key;
JimFormatReference(buf, refPtr, *refId);
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
}
Jim_SetResult(interp, listObjPtr);
return JIM_OK;
}
#endif
static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
| ︙ | ︙ | |||
18003 18004 18005 18006 18007 18008 18009 |
static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
JimDictMatchCallbackType *callback, int type)
{
Jim_HashEntry *he;
Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
| | > | < | 18052 18053 18054 18055 18056 18057 18058 18059 18060 18061 18062 18063 18064 18065 18066 18067 18068 18069 18070 18071 18072 |
static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
JimDictMatchCallbackType *callback, int type)
{
Jim_HashEntry *he;
Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
Jim_HashTableIterator htiter;
JimInitHashTableIterator(ht, &htiter);
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) {
callback(interp, listObjPtr, he, type);
}
}
return listObjPtr;
}
int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr)
{
|
| ︙ | ︙ |
Added compat/tcl-8.6/generic/tcl.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 |
/*
* tcl.h --
*
* This header file describes the externally-visible facilities of the
* Tcl interpreter.
*
* Copyright (c) 1987-1994 The Regents of the University of California.
* Copyright (c) 1993-1996 Lucent Technologies.
* Copyright (c) 1994-1998 Sun Microsystems, Inc.
* Copyright (c) 1998-2000 by Scriptics Corporation.
* Copyright (c) 2002 by Kevin B. Kenny. All rights reserved.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#ifndef _TCL
#define _TCL
/*
* For C++ compilers, use extern "C"
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* The following defines are used to indicate the various release levels.
*/
#define TCL_ALPHA_RELEASE 0
#define TCL_BETA_RELEASE 1
#define TCL_FINAL_RELEASE 2
/*
* When version numbers change here, must also go into the following files and
* update the version numbers:
*
* library/init.tcl (1 LOC patch)
* unix/configure.in (2 LOC Major, 2 LOC minor, 1 LOC patch)
* win/configure.in (as above)
* win/tcl.m4 (not patchlevel)
* win/makefile.bc (not patchlevel) 2 LOC
* README (sections 0 and 2, with and without separator)
* macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 1 LOC
* macosx/Tcl.pbproj/default.pbxuser (not patchlevel) 1 LOC
* macosx/Tcl.xcode/project.pbxproj (not patchlevel) 2 LOC
* macosx/Tcl.xcode/default.pbxuser (not patchlevel) 1 LOC
* macosx/Tcl-Common.xcconfig (not patchlevel) 1 LOC
* win/README (not patchlevel) (sections 0 and 2)
* unix/tcl.spec (1 LOC patch)
* tools/tcl.hpj.in (not patchlevel, for windows installer)
*/
#define TCL_MAJOR_VERSION 8
#define TCL_MINOR_VERSION 6
#define TCL_RELEASE_LEVEL TCL_FINAL_RELEASE
#define TCL_RELEASE_SERIAL 0
#define TCL_VERSION "8.6"
#define TCL_PATCH_LEVEL "8.6.0"
/*
*----------------------------------------------------------------------------
* The following definitions set up the proper options for Windows compilers.
* We use this method because there is no autoconf equivalent.
*/
#ifndef __WIN32__
# if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) || defined(__BORLANDC__) || (defined(__WATCOMC__) && defined(__WINDOWS_386__))
# define __WIN32__
# ifndef WIN32
# define WIN32
# endif
# ifndef _WIN32
# define _WIN32
# endif
# endif
#endif
/*
* STRICT: See MSDN Article Q83456
*/
#ifdef __WIN32__
# ifndef STRICT
# define STRICT
# endif
#endif /* __WIN32__ */
/*
* Utility macros: STRINGIFY takes an argument and wraps it in "" (double
* quotation marks), JOIN joins two arguments.
*/
#ifndef STRINGIFY
# define STRINGIFY(x) STRINGIFY1(x)
# define STRINGIFY1(x) #x
#endif
#ifndef JOIN
# define JOIN(a,b) JOIN1(a,b)
# define JOIN1(a,b) a##b
#endif
/*
* A special definition used to allow this header file to be included from
* windows resource files so that they can obtain version information.
* RC_INVOKED is defined by default by the windows RC tool.
*
* Resource compilers don't like all the C stuff, like typedefs and function
* declarations, that occur below, so block them out.
*/
#ifndef RC_INVOKED
/*
* Special macro to define mutexes, that doesn't do anything if we are not
* using threads.
*/
#ifdef TCL_THREADS
#define TCL_DECLARE_MUTEX(name) static Tcl_Mutex name;
#else
#define TCL_DECLARE_MUTEX(name)
#endif
/*
* Tcl's public routine Tcl_FSSeek() uses the values SEEK_SET, SEEK_CUR, and
* SEEK_END, all #define'd by stdio.h .
*
* Also, many extensions need stdio.h, and they've grown accustomed to tcl.h
* providing it for them rather than #include-ing it themselves as they
* should, so also for their sake, we keep the #include to be consistent with
* prior Tcl releases.
*/
#include <stdio.h>
/*
*----------------------------------------------------------------------------
* Support for functions with a variable number of arguments.
*
* The following TCL_VARARGS* macros are to support old extensions
* written for older versions of Tcl where the macros permitted
* support for the varargs.h system as well as stdarg.h .
*
* New code should just directly be written to use stdarg.h conventions.
*/
#include <stdarg.h>
#ifndef TCL_NO_DEPRECATED
# define TCL_VARARGS(type, name) (type name, ...)
# define TCL_VARARGS_DEF(type, name) (type name, ...)
# define TCL_VARARGS_START(type, name, list) (va_start(list, name), name)
#endif
#if defined(__GNUC__) && (__GNUC__ > 2)
# define TCL_FORMAT_PRINTF(a,b) __attribute__ ((__format__ (__printf__, a, b)))
#else
# define TCL_FORMAT_PRINTF(a,b)
#endif
/*
* Allow a part of Tcl's API to be explicitly marked as deprecated.
*
* Used to make TIP 330/336 generate moans even if people use the
* compatibility macros. Change your code, guys! We won't support you forever.
*/
#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC__MINOR__ >= 5))
# define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__ (msg)))
# else
# define TCL_DEPRECATED_API(msg) __attribute__ ((__deprecated__))
# endif
#else
# define TCL_DEPRECATED_API(msg) /* nothing portable */
#endif
/*
*----------------------------------------------------------------------------
* Macros used to declare a function to be exported by a DLL. Used by Windows,
* maps to no-op declarations on non-Windows systems. The default build on
* windows is for a DLL, which causes the DLLIMPORT and DLLEXPORT macros to be
* nonempty. To build a static library, the macro STATIC_BUILD should be
* defined.
*
* Note: when building static but linking dynamically to MSVCRT we must still
* correctly decorate the C library imported function. Use CRTIMPORT
* for this purpose. _DLL is defined by the compiler when linking to
* MSVCRT.
*/
#if (defined(__WIN32__) && (defined(_MSC_VER) || (__BORLANDC__ >= 0x0550) || defined(__LCC__) || defined(__WATCOMC__) || (defined(__GNUC__) && defined(__declspec))))
# define HAVE_DECLSPEC 1
# ifdef STATIC_BUILD
# define DLLIMPORT
# define DLLEXPORT
# ifdef _DLL
# define CRTIMPORT __declspec(dllimport)
# else
# define CRTIMPORT
# endif
# else
# define DLLIMPORT __declspec(dllimport)
# define DLLEXPORT __declspec(dllexport)
# define CRTIMPORT __declspec(dllimport)
# endif
#else
# define DLLIMPORT
# if defined(__GNUC__) && __GNUC__ > 3
# define DLLEXPORT __attribute__ ((visibility("default")))
# else
# define DLLEXPORT
# endif
# define CRTIMPORT
#endif
/*
* These macros are used to control whether functions are being declared for
* import or export. If a function is being declared while it is being built
* to be included in a shared library, then it should have the DLLEXPORT
* storage class. If is being declared for use by a module that is going to
* link against the shared library, then it should have the DLLIMPORT storage
* class. If the symbol is beind declared for a static build or for use from a
* stub library, then the storage class should be empty.
*
* The convention is that a macro called BUILD_xxxx, where xxxx is the name of
* a library we are building, is set on the compile line for sources that are
* to be placed in the library. When this macro is set, the storage class will
* be set to DLLEXPORT. At the end of the header file, the storage class will
* be reset to DLLIMPORT.
*/
#undef TCL_STORAGE_CLASS
#ifdef BUILD_tcl
# define TCL_STORAGE_CLASS DLLEXPORT
#else
# ifdef USE_TCL_STUBS
# define TCL_STORAGE_CLASS
# else
# define TCL_STORAGE_CLASS DLLIMPORT
# endif
#endif
/*
* The following _ANSI_ARGS_ macro is to support old extensions
* written for older versions of Tcl where it permitted support
* for compilers written in the pre-prototype era of C.
*
* New code should use prototypes.
*/
#ifndef TCL_NO_DEPRECATED
# undef _ANSI_ARGS_
# define _ANSI_ARGS_(x) x
#endif
/*
* Definitions that allow this header file to be used either with or without
* ANSI C features.
*/
#ifndef INLINE
# define INLINE
#endif
#ifdef NO_CONST
# ifndef const
# define const
# endif
#endif
#ifndef CONST
# define CONST const
#endif
#ifdef USE_NON_CONST
# ifdef USE_COMPAT_CONST
# error define at most one of USE_NON_CONST and USE_COMPAT_CONST
# endif
# define CONST84
# define CONST84_RETURN
#else
# ifdef USE_COMPAT_CONST
# define CONST84
# define CONST84_RETURN const
# else
# define CONST84 const
# define CONST84_RETURN const
# endif
#endif
#ifndef CONST86
# define CONST86 CONST84
#endif
/*
* Make sure EXTERN isn't defined elsewhere.
*/
#ifdef EXTERN
# undef EXTERN
#endif /* EXTERN */
#ifdef __cplusplus
# define EXTERN extern "C" TCL_STORAGE_CLASS
#else
# define EXTERN extern TCL_STORAGE_CLASS
#endif
/*
*----------------------------------------------------------------------------
* The following code is copied from winnt.h. If we don't replicate it here,
* then <windows.h> can't be included after tcl.h, since tcl.h also defines
* VOID. This block is skipped under Cygwin and Mingw.
*/
#if defined(__WIN32__) && !defined(HAVE_WINNT_IGNORE_VOID)
#ifndef VOID
#define VOID void
typedef char CHAR;
typedef short SHORT;
typedef long LONG;
#endif
#endif /* __WIN32__ && !HAVE_WINNT_IGNORE_VOID */
/*
* Macro to use instead of "void" for arguments that must have type "void *"
* in ANSI C; maps them to type "char *" in non-ANSI systems.
*/
#ifndef NO_VOID
# define VOID void
#else
# define VOID char
#endif
/*
* Miscellaneous declarations.
*/
#ifndef _CLIENTDATA
# ifndef NO_VOID
typedef void *ClientData;
# else
typedef int *ClientData;
# endif
# define _CLIENTDATA
#endif
/*
* Darwin specific configure overrides (to support fat compiles, where
* configure runs only once for multiple architectures):
*/
#ifdef __APPLE__
# ifdef __LP64__
# undef TCL_WIDE_INT_TYPE
# define TCL_WIDE_INT_IS_LONG 1
# define TCL_CFG_DO64BIT 1
# else /* !__LP64__ */
# define TCL_WIDE_INT_TYPE long long
# undef TCL_WIDE_INT_IS_LONG
# undef TCL_CFG_DO64BIT
# endif /* __LP64__ */
# undef HAVE_STRUCT_STAT64
#endif /* __APPLE__ */
/*
* Define Tcl_WideInt to be a type that is (at least) 64-bits wide, and define
* Tcl_WideUInt to be the unsigned variant of that type (assuming that where
* we have one, we can have the other.)
*
* Also defines the following macros:
* TCL_WIDE_INT_IS_LONG - if wide ints are really longs (i.e. we're on a real
* 64-bit system.)
* Tcl_WideAsLong - forgetful converter from wideInt to long.
* Tcl_LongAsWide - sign-extending converter from long to wideInt.
* Tcl_WideAsDouble - converter from wideInt to double.
* Tcl_DoubleAsWide - converter from double to wideInt.
*
* The following invariant should hold for any long value 'longVal':
* longVal == Tcl_WideAsLong(Tcl_LongAsWide(longVal))
*
* Note on converting between Tcl_WideInt and strings. This implementation (in
* tclObj.c) depends on the function
* sprintf(...,"%" TCL_LL_MODIFIER "d",...).
*/
#if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG)
# if defined(__WIN32__)
# define TCL_WIDE_INT_TYPE __int64
# ifdef __BORLANDC__
# define TCL_LL_MODIFIER "L"
# else /* __BORLANDC__ */
# define TCL_LL_MODIFIER "I64"
# endif /* __BORLANDC__ */
# elif defined(__GNUC__)
# define TCL_WIDE_INT_TYPE long long
# define TCL_LL_MODIFIER "ll"
# else /* ! __WIN32__ && ! __GNUC__ */
/*
* Don't know what platform it is and configure hasn't discovered what is
* going on for us. Try to guess...
*/
# ifdef NO_LIMITS_H
# error please define either TCL_WIDE_INT_TYPE or TCL_WIDE_INT_IS_LONG
# else /* !NO_LIMITS_H */
# include <limits.h>
# if (INT_MAX < LONG_MAX)
# define TCL_WIDE_INT_IS_LONG 1
# else
# define TCL_WIDE_INT_TYPE long long
# endif
# endif /* NO_LIMITS_H */
# endif /* __WIN32__ */
#endif /* !TCL_WIDE_INT_TYPE & !TCL_WIDE_INT_IS_LONG */
#ifdef TCL_WIDE_INT_IS_LONG
# undef TCL_WIDE_INT_TYPE
# define TCL_WIDE_INT_TYPE long
#endif /* TCL_WIDE_INT_IS_LONG */
typedef TCL_WIDE_INT_TYPE Tcl_WideInt;
typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt;
#ifdef TCL_WIDE_INT_IS_LONG
# define Tcl_WideAsLong(val) ((long)(val))
# define Tcl_LongAsWide(val) ((long)(val))
# define Tcl_WideAsDouble(val) ((double)((long)(val)))
# define Tcl_DoubleAsWide(val) ((long)((double)(val)))
# ifndef TCL_LL_MODIFIER
# define TCL_LL_MODIFIER "l"
# endif /* !TCL_LL_MODIFIER */
#else /* TCL_WIDE_INT_IS_LONG */
/*
* The next short section of defines are only done when not running on Windows
* or some other strange platform.
*/
# ifndef TCL_LL_MODIFIER
# define TCL_LL_MODIFIER "ll"
# endif /* !TCL_LL_MODIFIER */
# define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val)))
# define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val)))
# define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val)))
# define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val)))
#endif /* TCL_WIDE_INT_IS_LONG */
#if defined(__WIN32__)
# ifdef __BORLANDC__
typedef struct stati64 Tcl_StatBuf;
# elif defined(_WIN64)
typedef struct __stat64 Tcl_StatBuf;
# elif (defined(_MSC_VER) && (_MSC_VER < 1400)) || defined(_USE_32BIT_TIME_T)
typedef struct _stati64 Tcl_StatBuf;
# else
typedef struct _stat32i64 Tcl_StatBuf;
# endif /* _MSC_VER < 1400 */
#elif defined(__CYGWIN__)
typedef struct _stat32i64 {
dev_t st_dev;
unsigned short st_ino;
unsigned short st_mode;
short st_nlink;
short st_uid;
short st_gid;
/* Here is a 2-byte gap */
dev_t st_rdev;
/* Here is a 4-byte gap */
long long st_size;
struct {long tv_sec;} st_atim;
struct {long tv_sec;} st_mtim;
struct {long tv_sec;} st_ctim;
/* Here is a 4-byte gap */
} Tcl_StatBuf;
#elif defined(HAVE_STRUCT_STAT64)
typedef struct stat64 Tcl_StatBuf;
#else
typedef struct stat Tcl_StatBuf;
#endif
/*
*----------------------------------------------------------------------------
* Data structures defined opaquely in this module. The definitions below just
* provide dummy types. A few fields are made visible in Tcl_Interp
* structures, namely those used for returning a string result from commands.
* Direct access to the result field is discouraged in Tcl 8.0. The
* interpreter result is either an object or a string, and the two values are
* kept consistent unless some C code sets interp->result directly.
* Programmers should use either the function Tcl_GetObjResult() or
* Tcl_GetStringResult() to read the interpreter's result. See the SetResult
* man page for details.
*
* Note: any change to the Tcl_Interp definition below must be mirrored in the
* "real" definition in tclInt.h.
*
* Note: Tcl_ObjCmdProc functions do not directly set result and freeProc.
* Instead, they set a Tcl_Obj member in the "real" structure that can be
* accessed with Tcl_GetObjResult() and Tcl_SetObjResult().
*/
typedef struct Tcl_Interp
#ifndef TCL_NO_DEPRECATED
{
/* TIP #330: Strongly discourage extensions from using the string
* result. */
#ifdef USE_INTERP_RESULT
char *result TCL_DEPRECATED_API("use Tcl_GetResult/Tcl_SetResult");
/* If the last command returned a string
* result, this points to it. */
void (*freeProc) (char *blockPtr)
TCL_DEPRECATED_API("use Tcl_GetResult/Tcl_SetResult");
/* Zero means the string result is statically
* allocated. TCL_DYNAMIC means it was
* allocated with ckalloc and should be freed
* with ckfree. Other values give the address
* of function to invoke to free the result.
* Tcl_Eval must free it before executing next
* command. */
#else
char *resultDontUse; /* Don't use in extensions! */
void (*freeProcDontUse) (char *); /* Don't use in extensions! */
#endif
#ifdef USE_INTERP_ERRORLINE
int errorLine TCL_DEPRECATED_API("use Tcl_GetErrorLine/Tcl_SetErrorLine");
/* When TCL_ERROR is returned, this gives the
* line number within the command where the
* error occurred (1 if first line). */
#else
int errorLineDontUse; /* Don't use in extensions! */
#endif
}
#endif /* TCL_NO_DEPRECATED */
Tcl_Interp;
typedef struct Tcl_AsyncHandler_ *Tcl_AsyncHandler;
typedef struct Tcl_Channel_ *Tcl_Channel;
typedef struct Tcl_ChannelTypeVersion_ *Tcl_ChannelTypeVersion;
typedef struct Tcl_Command_ *Tcl_Command;
typedef struct Tcl_Condition_ *Tcl_Condition;
typedef struct Tcl_Dict_ *Tcl_Dict;
typedef struct Tcl_EncodingState_ *Tcl_EncodingState;
typedef struct Tcl_Encoding_ *Tcl_Encoding;
typedef struct Tcl_Event Tcl_Event;
typedef struct Tcl_InterpState_ *Tcl_InterpState;
typedef struct Tcl_LoadHandle_ *Tcl_LoadHandle;
typedef struct Tcl_Mutex_ *Tcl_Mutex;
typedef struct Tcl_Pid_ *Tcl_Pid;
typedef struct Tcl_RegExp_ *Tcl_RegExp;
typedef struct Tcl_ThreadDataKey_ *Tcl_ThreadDataKey;
typedef struct Tcl_ThreadId_ *Tcl_ThreadId;
typedef struct Tcl_TimerToken_ *Tcl_TimerToken;
typedef struct Tcl_Trace_ *Tcl_Trace;
typedef struct Tcl_Var_ *Tcl_Var;
typedef struct Tcl_ZLibStream_ *Tcl_ZlibStream;
/*
*----------------------------------------------------------------------------
* Definition of the interface to functions implementing threads. A function
* following this definition is given to each call of 'Tcl_CreateThread' and
* will be called as the main fuction of the new thread created by that call.
*/
#if defined __WIN32__
typedef unsigned (__stdcall Tcl_ThreadCreateProc) (ClientData clientData);
#else
typedef void (Tcl_ThreadCreateProc) (ClientData clientData);
#endif
/*
* Threading function return types used for abstracting away platform
* differences when writing a Tcl_ThreadCreateProc. See the NewThread function
* in generic/tclThreadTest.c for it's usage.
*/
#if defined __WIN32__
# define Tcl_ThreadCreateType unsigned __stdcall
# define TCL_THREAD_CREATE_RETURN return 0
#else
# define Tcl_ThreadCreateType void
# define TCL_THREAD_CREATE_RETURN
#endif
/*
* Definition of values for default stacksize and the possible flags to be
* given to Tcl_CreateThread.
*/
#define TCL_THREAD_STACK_DEFAULT (0) /* Use default size for stack. */
#define TCL_THREAD_NOFLAGS (0000) /* Standard flags, default
* behaviour. */
#define TCL_THREAD_JOINABLE (0001) /* Mark the thread as joinable. */
/*
* Flag values passed to Tcl_StringCaseMatch.
*/
#define TCL_MATCH_NOCASE (1<<0)
/*
* Flag values passed to Tcl_GetRegExpFromObj.
*/
#define TCL_REG_BASIC 000000 /* BREs (convenience). */
#define TCL_REG_EXTENDED 000001 /* EREs. */
#define TCL_REG_ADVF 000002 /* Advanced features in EREs. */
#define TCL_REG_ADVANCED 000003 /* AREs (which are also EREs). */
#define TCL_REG_QUOTE 000004 /* No special characters, none. */
#define TCL_REG_NOCASE 000010 /* Ignore case. */
#define TCL_REG_NOSUB 000020 /* Don't care about subexpressions. */
#define TCL_REG_EXPANDED 000040 /* Expanded format, white space &
* comments. */
#define TCL_REG_NLSTOP 000100 /* \n doesn't match . or [^ ] */
#define TCL_REG_NLANCH 000200 /* ^ matches after \n, $ before. */
#define TCL_REG_NEWLINE 000300 /* Newlines are line terminators. */
#define TCL_REG_CANMATCH 001000 /* Report details on partial/limited
* matches. */
/*
* Flags values passed to Tcl_RegExpExecObj.
*/
#define TCL_REG_NOTBOL 0001 /* Beginning of string does not match ^. */
#define TCL_REG_NOTEOL 0002 /* End of string does not match $. */
/*
* Structures filled in by Tcl_RegExpInfo. Note that all offset values are
* relative to the start of the match string, not the beginning of the entire
* string.
*/
typedef struct Tcl_RegExpIndices {
long start; /* Character offset of first character in
* match. */
long end; /* Character offset of first character after
* the match. */
} Tcl_RegExpIndices;
typedef struct Tcl_RegExpInfo {
int nsubs; /* Number of subexpressions in the compiled
* expression. */
Tcl_RegExpIndices *matches; /* Array of nsubs match offset pairs. */
long extendStart; /* The offset at which a subsequent match
* might begin. */
long reserved; /* Reserved for later use. */
} Tcl_RegExpInfo;
/*
* Picky compilers complain if this typdef doesn't appear before the struct's
* reference in tclDecls.h.
*/
typedef Tcl_StatBuf *Tcl_Stat_;
typedef struct stat *Tcl_OldStat_;
/*
*----------------------------------------------------------------------------
* When a TCL command returns, the interpreter contains a result from the
* command. Programmers are strongly encouraged to use one of the functions
* Tcl_GetObjResult() or Tcl_GetStringResult() to read the interpreter's
* result. See the SetResult man page for details. Besides this result, the
* command function returns an integer code, which is one of the following:
*
* TCL_OK Command completed normally; the interpreter's result
* contains the command's result.
* TCL_ERROR The command couldn't be completed successfully; the
* interpreter's result describes what went wrong.
* TCL_RETURN The command requests that the current function return;
* the interpreter's result contains the function's
* return value.
* TCL_BREAK The command requests that the innermost loop be
* exited; the interpreter's result is meaningless.
* TCL_CONTINUE Go on to the next iteration of the current loop; the
* interpreter's result is meaningless.
*/
#define TCL_OK 0
#define TCL_ERROR 1
#define TCL_RETURN 2
#define TCL_BREAK 3
#define TCL_CONTINUE 4
#define TCL_RESULT_SIZE 200
/*
*----------------------------------------------------------------------------
* Flags to control what substitutions are performed by Tcl_SubstObj():
*/
#define TCL_SUBST_COMMANDS 001
#define TCL_SUBST_VARIABLES 002
#define TCL_SUBST_BACKSLASHES 004
#define TCL_SUBST_ALL 007
/*
* Argument descriptors for math function callbacks in expressions:
*/
typedef enum {
TCL_INT, TCL_DOUBLE, TCL_EITHER, TCL_WIDE_INT
} Tcl_ValueType;
typedef struct Tcl_Value {
Tcl_ValueType type; /* Indicates intValue or doubleValue is valid,
* or both. */
long intValue; /* Integer value. */
double doubleValue; /* Double-precision floating value. */
Tcl_WideInt wideValue; /* Wide (min. 64-bit) integer value. */
} Tcl_Value;
/*
* Forward declaration of Tcl_Obj to prevent an error when the forward
* reference to Tcl_Obj is encountered in the function types declared below.
*/
struct Tcl_Obj;
/*
*----------------------------------------------------------------------------
* Function types defined by Tcl:
*/
typedef int (Tcl_AppInitProc) (Tcl_Interp *interp);
typedef int (Tcl_AsyncProc) (ClientData clientData, Tcl_Interp *interp,
int code);
typedef void (Tcl_ChannelProc) (ClientData clientData, int mask);
typedef void (Tcl_CloseProc) (ClientData data);
typedef void (Tcl_CmdDeleteProc) (ClientData clientData);
typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
typedef void (Tcl_CmdTraceProc) (ClientData clientData, Tcl_Interp *interp,
int level, char *command, Tcl_CmdProc *proc,
ClientData cmdClientData, int argc, CONST84 char *argv[]);
typedef int (Tcl_CmdObjTraceProc) (ClientData clientData, Tcl_Interp *interp,
int level, const char *command, Tcl_Command commandInfo, int objc,
struct Tcl_Obj *const *objv);
typedef void (Tcl_CmdObjTraceDeleteProc) (ClientData clientData);
typedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr,
struct Tcl_Obj *dupPtr);
typedef int (Tcl_EncodingConvertProc) (ClientData clientData, const char *src,
int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst,
int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr);
typedef void (Tcl_EncodingFreeProc) (ClientData clientData);
typedef int (Tcl_EventProc) (Tcl_Event *evPtr, int flags);
typedef void (Tcl_EventCheckProc) (ClientData clientData, int flags);
typedef int (Tcl_EventDeleteProc) (Tcl_Event *evPtr, ClientData clientData);
typedef void (Tcl_EventSetupProc) (ClientData clientData, int flags);
typedef void (Tcl_ExitProc) (ClientData clientData);
typedef void (Tcl_FileProc) (ClientData clientData, int mask);
typedef void (Tcl_FileFreeProc) (ClientData clientData);
typedef void (Tcl_FreeInternalRepProc) (struct Tcl_Obj *objPtr);
typedef void (Tcl_FreeProc) (char *blockPtr);
typedef void (Tcl_IdleProc) (ClientData clientData);
typedef void (Tcl_InterpDeleteProc) (ClientData clientData,
Tcl_Interp *interp);
typedef int (Tcl_MathProc) (ClientData clientData, Tcl_Interp *interp,
Tcl_Value *args, Tcl_Value *resultPtr);
typedef void (Tcl_NamespaceDeleteProc) (ClientData clientData);
typedef int (Tcl_ObjCmdProc) (ClientData clientData, Tcl_Interp *interp,
int objc, struct Tcl_Obj *const *objv);
typedef int (Tcl_PackageInitProc) (Tcl_Interp *interp);
typedef int (Tcl_PackageUnloadProc) (Tcl_Interp *interp, int flags);
typedef void (Tcl_PanicProc) (const char *format, ...);
typedef void (Tcl_TcpAcceptProc) (ClientData callbackData, Tcl_Channel chan,
char *address, int port);
typedef void (Tcl_TimerProc) (ClientData clientData);
typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *interp, struct Tcl_Obj *objPtr);
typedef void (Tcl_UpdateStringProc) (struct Tcl_Obj *objPtr);
typedef char * (Tcl_VarTraceProc) (ClientData clientData, Tcl_Interp *interp,
CONST84 char *part1, CONST84 char *part2, int flags);
typedef void (Tcl_CommandTraceProc) (ClientData clientData, Tcl_Interp *interp,
const char *oldName, const char *newName, int flags);
typedef void (Tcl_CreateFileHandlerProc) (int fd, int mask, Tcl_FileProc *proc,
ClientData clientData);
typedef void (Tcl_DeleteFileHandlerProc) (int fd);
typedef void (Tcl_AlertNotifierProc) (ClientData clientData);
typedef void (Tcl_ServiceModeHookProc) (int mode);
typedef ClientData (Tcl_InitNotifierProc) (void);
typedef void (Tcl_FinalizeNotifierProc) (ClientData clientData);
typedef void (Tcl_MainLoopProc) (void);
/*
*----------------------------------------------------------------------------
* The following structure represents a type of object, which is a particular
* internal representation for an object plus a set of functions that provide
* standard operations on objects of that type.
*/
typedef struct Tcl_ObjType {
const char *name; /* Name of the type, e.g. "int". */
Tcl_FreeInternalRepProc *freeIntRepProc;
/* Called to free any storage for the type's
* internal rep. NULL if the internal rep does
* not need freeing. */
Tcl_DupInternalRepProc *dupIntRepProc;
/* Called to create a new object as a copy of
* an existing object. */
Tcl_UpdateStringProc *updateStringProc;
/* Called to update the string rep from the
* type's internal representation. */
Tcl_SetFromAnyProc *setFromAnyProc;
/* Called to convert the object's internal rep
* to this type. Frees the internal rep of the
* old type. Returns TCL_ERROR on failure. */
} Tcl_ObjType;
/*
* One of the following structures exists for each object in the Tcl system.
* An object stores a value as either a string, some internal representation,
* or both.
*/
typedef struct Tcl_Obj {
int refCount; /* When 0 the object will be freed. */
char *bytes; /* This points to the first byte of the
* object's string representation. The array
* must be followed by a null byte (i.e., at
* offset length) but may also contain
* embedded null characters. The array's
* storage is allocated by ckalloc. NULL means
* the string rep is invalid and must be
* regenerated from the internal rep. Clients
* should use Tcl_GetStringFromObj or
* Tcl_GetString to get a pointer to the byte
* array as a readonly value. */
int length; /* The number of bytes at *bytes, not
* including the terminating null. */
const Tcl_ObjType *typePtr; /* Denotes the object's type. Always
* corresponds to the type of the object's
* internal rep. NULL indicates the object has
* no internal rep (has no type). */
union { /* The internal representation: */
long longValue; /* - an long integer value. */
double doubleValue; /* - a double-precision floating value. */
void *otherValuePtr; /* - another, type-specific value. */
Tcl_WideInt wideValue; /* - a long long value. */
struct { /* - internal rep as two pointers. */
void *ptr1;
void *ptr2;
} twoPtrValue;
struct { /* - internal rep as a pointer and a long,
* the main use of which is a bignum's
* tightly packed fields, where the alloc,
* used and signum flags are packed into a
* single word with everything else hung
* off the pointer. */
void *ptr;
unsigned long value;
} ptrAndLongRep;
} internalRep;
} Tcl_Obj;
/*
* Macros to increment and decrement a Tcl_Obj's reference count, and to test
* whether an object is shared (i.e. has reference count > 1). Note: clients
* should use Tcl_DecrRefCount() when they are finished using an object, and
* should never call TclFreeObj() directly. TclFreeObj() is only defined and
* made public in tcl.h to support Tcl_DecrRefCount's macro definition.
*/
void Tcl_IncrRefCount(Tcl_Obj *objPtr);
void Tcl_DecrRefCount(Tcl_Obj *objPtr);
int Tcl_IsShared(Tcl_Obj *objPtr);
/*
*----------------------------------------------------------------------------
* The following structure contains the state needed by Tcl_SaveResult. No-one
* outside of Tcl should access any of these fields. This structure is
* typically allocated on the stack.
*/
typedef struct Tcl_SavedResult {
char *result;
Tcl_FreeProc *freeProc;
Tcl_Obj *objResultPtr;
char *appendResult;
int appendAvl;
int appendUsed;
char resultSpace[TCL_RESULT_SIZE+1];
} Tcl_SavedResult;
/*
*----------------------------------------------------------------------------
* The following definitions support Tcl's namespace facility. Note: the first
* five fields must match exactly the fields in a Namespace structure (see
* tclInt.h).
*/
typedef struct Tcl_Namespace {
char *name; /* The namespace's name within its parent
* namespace. This contains no ::'s. The name
* of the global namespace is "" although "::"
* is an synonym. */
char *fullName; /* The namespace's fully qualified name. This
* starts with ::. */
ClientData clientData; /* Arbitrary value associated with this
* namespace. */
Tcl_NamespaceDeleteProc *deleteProc;
/* Function invoked when deleting the
* namespace to, e.g., free clientData. */
struct Tcl_Namespace *parentPtr;
/* Points to the namespace that contains this
* one. NULL if this is the global
* namespace. */
} Tcl_Namespace;
/*
*----------------------------------------------------------------------------
* The following structure represents a call frame, or activation record. A
* call frame defines a naming context for a procedure call: its local scope
* (for local variables) and its namespace scope (used for non-local
* variables; often the global :: namespace). A call frame can also define the
* naming context for a namespace eval or namespace inscope command: the
* namespace in which the command's code should execute. The Tcl_CallFrame
* structures exist only while procedures or namespace eval/inscope's are
* being executed, and provide a Tcl call stack.
*
* A call frame is initialized and pushed using Tcl_PushCallFrame and popped
* using Tcl_PopCallFrame. Storage for a Tcl_CallFrame must be provided by the
* Tcl_PushCallFrame caller, and callers typically allocate them on the C call
* stack for efficiency. For this reason, Tcl_CallFrame is defined as a
* structure and not as an opaque token. However, most Tcl_CallFrame fields
* are hidden since applications should not access them directly; others are
* declared as "dummyX".
*
* WARNING!! The structure definition must be kept consistent with the
* CallFrame structure in tclInt.h. If you change one, change the other.
*/
typedef struct Tcl_CallFrame {
Tcl_Namespace *nsPtr;
int dummy1;
int dummy2;
void *dummy3;
void *dummy4;
void *dummy5;
int dummy6;
void *dummy7;
void *dummy8;
int dummy9;
void *dummy10;
void *dummy11;
void *dummy12;
void *dummy13;
} Tcl_CallFrame;
/*
*----------------------------------------------------------------------------
* Information about commands that is returned by Tcl_GetCommandInfo and
* passed to Tcl_SetCommandInfo. objProc is an objc/objv object-based command
* function while proc is a traditional Tcl argc/argv string-based function.
* Tcl_CreateObjCommand and Tcl_CreateCommand ensure that both objProc and
* proc are non-NULL and can be called to execute the command. However, it may
* be faster to call one instead of the other. The member isNativeObjectProc
* is set to 1 if an object-based function was registered by
* Tcl_CreateObjCommand, and to 0 if a string-based function was registered by
* Tcl_CreateCommand. The other function is typically set to a compatibility
* wrapper that does string-to-object or object-to-string argument conversions
* then calls the other function.
*/
typedef struct Tcl_CmdInfo {
int isNativeObjectProc; /* 1 if objProc was registered by a call to
* Tcl_CreateObjCommand; 0 otherwise.
* Tcl_SetCmdInfo does not modify this
* field. */
Tcl_ObjCmdProc *objProc; /* Command's object-based function. */
ClientData objClientData; /* ClientData for object proc. */
Tcl_CmdProc *proc; /* Command's string-based function. */
ClientData clientData; /* ClientData for string proc. */
Tcl_CmdDeleteProc *deleteProc;
/* Function to call when command is
* deleted. */
ClientData deleteData; /* Value to pass to deleteProc (usually the
* same as clientData). */
Tcl_Namespace *namespacePtr;/* Points to the namespace that contains this
* command. Note that Tcl_SetCmdInfo will not
* change a command's namespace; use
* TclRenameCommand or Tcl_Eval (of 'rename')
* to do that. */
} Tcl_CmdInfo;
/*
*----------------------------------------------------------------------------
* The structure defined below is used to hold dynamic strings. The only
* fields that clients should use are string and length, accessible via the
* macros Tcl_DStringValue and Tcl_DStringLength.
*/
#define TCL_DSTRING_STATIC_SIZE 200
typedef struct Tcl_DString {
char *string; /* Points to beginning of string: either
* staticSpace below or a malloced array. */
int length; /* Number of non-NULL characters in the
* string. */
int spaceAvl; /* Total number of bytes available for the
* string and its terminating NULL char. */
char staticSpace[TCL_DSTRING_STATIC_SIZE];
/* Space to use in common case where string is
* small. */
} Tcl_DString;
#define Tcl_DStringLength(dsPtr) ((dsPtr)->length)
#define Tcl_DStringValue(dsPtr) ((dsPtr)->string)
#define Tcl_DStringTrunc Tcl_DStringSetLength
/*
* Definitions for the maximum number of digits of precision that may be
* specified in the "tcl_precision" variable, and the number of bytes of
* buffer space required by Tcl_PrintDouble.
*/
#define TCL_MAX_PREC 17
#define TCL_DOUBLE_SPACE (TCL_MAX_PREC+10)
/*
* Definition for a number of bytes of buffer space sufficient to hold the
* string representation of an integer in base 10 (assuming the existence of
* 64-bit integers).
*/
#define TCL_INTEGER_SPACE 24
/*
* Flag values passed to Tcl_ConvertElement.
* TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to
* use backslash quoting instead.
* TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It
* is safe to leave the hash unquoted when the element is not the first
* element of a list, and this flag can be used by the caller to indicate
* that condition.
*/
#define TCL_DONT_USE_BRACES 1
#define TCL_DONT_QUOTE_HASH 8
/*
* Flag that may be passed to Tcl_GetIndexFromObj to force it to disallow
* abbreviated strings.
*/
#define TCL_EXACT 1
/*
*----------------------------------------------------------------------------
* Flag values passed to Tcl_RecordAndEval, Tcl_EvalObj, Tcl_EvalObjv.
* WARNING: these bit choices must not conflict with the bit choices for
* evalFlag bits in tclInt.h!
*
* Meanings:
* TCL_NO_EVAL: Just record this command
* TCL_EVAL_GLOBAL: Execute script in global namespace
* TCL_EVAL_DIRECT: Do not compile this script
* TCL_EVAL_INVOKE: Magical Tcl_EvalObjv mode for aliases/ensembles
* o Run in iPtr->lookupNsPtr or global namespace
* o Cut out of error traces
* o Don't reset the flags controlling ensemble
* error message rewriting.
* TCL_CANCEL_UNWIND: Magical Tcl_CancelEval mode that causes the
* stack for the script in progress to be
* completely unwound.
* TCL_EVAL_NOERR: Do no exception reporting at all, just return
* as the caller will report.
*/
#define TCL_NO_EVAL 0x010000
#define TCL_EVAL_GLOBAL 0x020000
#define TCL_EVAL_DIRECT 0x040000
#define TCL_EVAL_INVOKE 0x080000
#define TCL_CANCEL_UNWIND 0x100000
#define TCL_EVAL_NOERR 0x200000
/*
* Special freeProc values that may be passed to Tcl_SetResult (see the man
* page for details):
*/
#define TCL_VOLATILE ((Tcl_FreeProc *) 1)
#define TCL_STATIC ((Tcl_FreeProc *) 0)
#define TCL_DYNAMIC ((Tcl_FreeProc *) 3)
/*
* Flag values passed to variable-related functions.
* WARNING: these bit choices must not conflict with the bit choice for
* TCL_CANCEL_UNWIND, above.
*/
#define TCL_GLOBAL_ONLY 1
#define TCL_NAMESPACE_ONLY 2
#define TCL_APPEND_VALUE 4
#define TCL_LIST_ELEMENT 8
#define TCL_TRACE_READS 0x10
#define TCL_TRACE_WRITES 0x20
#define TCL_TRACE_UNSETS 0x40
#define TCL_TRACE_DESTROYED 0x80
#define TCL_INTERP_DESTROYED 0x100
#define TCL_LEAVE_ERR_MSG 0x200
#define TCL_TRACE_ARRAY 0x800
#ifndef TCL_REMOVE_OBSOLETE_TRACES
/* Required to support old variable/vdelete/vinfo traces. */
#define TCL_TRACE_OLD_STYLE 0x1000
#endif
/* Indicate the semantics of the result of a trace. */
#define TCL_TRACE_RESULT_DYNAMIC 0x8000
#define TCL_TRACE_RESULT_OBJECT 0x10000
/*
* Flag values for ensemble commands.
*/
#define TCL_ENSEMBLE_PREFIX 0x02/* Flag value to say whether to allow
* unambiguous prefixes of commands or to
* require exact matches for command names. */
/*
* Flag values passed to command-related functions.
*/
#define TCL_TRACE_RENAME 0x2000
#define TCL_TRACE_DELETE 0x4000
#define TCL_ALLOW_INLINE_COMPILATION 0x20000
/*
* The TCL_PARSE_PART1 flag is deprecated and has no effect. The part1 is now
* always parsed whenever the part2 is NULL. (This is to avoid a common error
* when converting code to use the new object based APIs and forgetting to
* give the flag)
*/
#ifndef TCL_NO_DEPRECATED
# define TCL_PARSE_PART1 0x400
#endif
/*
* Types for linked variables:
*/
#define TCL_LINK_INT 1
#define TCL_LINK_DOUBLE 2
#define TCL_LINK_BOOLEAN 3
#define TCL_LINK_STRING 4
#define TCL_LINK_WIDE_INT 5
#define TCL_LINK_CHAR 6
#define TCL_LINK_UCHAR 7
#define TCL_LINK_SHORT 8
#define TCL_LINK_USHORT 9
#define TCL_LINK_UINT 10
#define TCL_LINK_LONG 11
#define TCL_LINK_ULONG 12
#define TCL_LINK_FLOAT 13
#define TCL_LINK_WIDE_UINT 14
#define TCL_LINK_READ_ONLY 0x80
/*
*----------------------------------------------------------------------------
* Forward declarations of Tcl_HashTable and related types.
*/
typedef struct Tcl_HashKeyType Tcl_HashKeyType;
typedef struct Tcl_HashTable Tcl_HashTable;
typedef struct Tcl_HashEntry Tcl_HashEntry;
typedef unsigned (Tcl_HashKeyProc) (Tcl_HashTable *tablePtr, void *keyPtr);
typedef int (Tcl_CompareHashKeysProc) (void *keyPtr, Tcl_HashEntry *hPtr);
typedef Tcl_HashEntry * (Tcl_AllocHashEntryProc) (Tcl_HashTable *tablePtr,
void *keyPtr);
typedef void (Tcl_FreeHashEntryProc) (Tcl_HashEntry *hPtr);
/*
* This flag controls whether the hash table stores the hash of a key, or
* recalculates it. There should be no reason for turning this flag off as it
* is completely binary and source compatible unless you directly access the
* bucketPtr member of the Tcl_HashTableEntry structure. This member has been
* removed and the space used to store the hash value.
*/
#ifndef TCL_HASH_KEY_STORE_HASH
# define TCL_HASH_KEY_STORE_HASH 1
#endif
/*
* Structure definition for an entry in a hash table. No-one outside Tcl
* should access any of these fields directly; use the macros defined below.
*/
struct Tcl_HashEntry {
Tcl_HashEntry *nextPtr; /* Pointer to next entry in this hash bucket,
* or NULL for end of chain. */
Tcl_HashTable *tablePtr; /* Pointer to table containing entry. */
#if TCL_HASH_KEY_STORE_HASH
void *hash; /* Hash value, stored as pointer to ensure
* that the offsets of the fields in this
* structure are not changed. */
#else
Tcl_HashEntry **bucketPtr; /* Pointer to bucket that points to first
* entry in this entry's chain: used for
* deleting the entry. */
#endif
ClientData clientData; /* Application stores something here with
* Tcl_SetHashValue. */
union { /* Key has one of these forms: */
char *oneWordValue; /* One-word value for key. */
Tcl_Obj *objPtr; /* Tcl_Obj * key value. */
int words[1]; /* Multiple integer words for key. The actual
* size will be as large as necessary for this
* table's keys. */
char string[1]; /* String for key. The actual size will be as
* large as needed to hold the key. */
} key; /* MUST BE LAST FIELD IN RECORD!! */
};
/*
* Flags used in Tcl_HashKeyType.
*
* TCL_HASH_KEY_RANDOMIZE_HASH -
* There are some things, pointers for example
* which don't hash well because they do not use
* the lower bits. If this flag is set then the
* hash table will attempt to rectify this by
* randomising the bits and then using the upper
* N bits as the index into the table.
* TCL_HASH_KEY_SYSTEM_HASH - If this flag is set then all memory internally
* allocated for the hash table that is not for an
* entry will use the system heap.
*/
#define TCL_HASH_KEY_RANDOMIZE_HASH 0x1
#define TCL_HASH_KEY_SYSTEM_HASH 0x2
/*
* Structure definition for the methods associated with a hash table key type.
*/
#define TCL_HASH_KEY_TYPE_VERSION 1
struct Tcl_HashKeyType {
int version; /* Version of the table. If this structure is
* extended in future then the version can be
* used to distinguish between different
* structures. */
int flags; /* Flags, see above for details. */
Tcl_HashKeyProc *hashKeyProc;
/* Calculates a hash value for the key. If
* this is NULL then the pointer itself is
* used as a hash value. */
Tcl_CompareHashKeysProc *compareKeysProc;
/* Compares two keys and returns zero if they
* do not match, and non-zero if they do. If
* this is NULL then the pointers are
* compared. */
Tcl_AllocHashEntryProc *allocEntryProc;
/* Called to allocate memory for a new entry,
* i.e. if the key is a string then this could
* allocate a single block which contains
* enough space for both the entry and the
* string. Only the key field of the allocated
* Tcl_HashEntry structure needs to be filled
* in. If something else needs to be done to
* the key, i.e. incrementing a reference
* count then that should be done by this
* function. If this is NULL then Tcl_Alloc is
* used to allocate enough space for a
* Tcl_HashEntry and the key pointer is
* assigned to key.oneWordValue. */
Tcl_FreeHashEntryProc *freeEntryProc;
/* Called to free memory associated with an
* entry. If something else needs to be done
* to the key, i.e. decrementing a reference
* count then that should be done by this
* function. If this is NULL then Tcl_Free is
* used to free the Tcl_HashEntry. */
};
/*
* Structure definition for a hash table. Must be in tcl.h so clients can
* allocate space for these structures, but clients should never access any
* fields in this structure.
*/
#define TCL_SMALL_HASH_TABLE 4
struct Tcl_HashTable {
Tcl_HashEntry **buckets; /* Pointer to bucket array. Each element
* points to first entry in bucket's hash
* chain, or NULL. */
Tcl_HashEntry *staticBuckets[TCL_SMALL_HASH_TABLE];
/* Bucket array used for small tables (to
* avoid mallocs and frees). */
int numBuckets; /* Total number of buckets allocated at
* **bucketPtr. */
int numEntries; /* Total number of entries present in
* table. */
int rebuildSize; /* Enlarge table when numEntries gets to be
* this large. */
int downShift; /* Shift count used in hashing function.
* Designed to use high-order bits of
* randomized keys. */
int mask; /* Mask value used in hashing function. */
int keyType; /* Type of keys used in this table. It's
* either TCL_CUSTOM_KEYS, TCL_STRING_KEYS,
* TCL_ONE_WORD_KEYS, or an integer giving the
* number of ints that is the size of the
* key. */
Tcl_HashEntry *(*findProc) (Tcl_HashTable *tablePtr, const char *key);
Tcl_HashEntry *(*createProc) (Tcl_HashTable *tablePtr, const char *key,
int *newPtr);
const Tcl_HashKeyType *typePtr;
/* Type of the keys used in the
* Tcl_HashTable. */
};
/*
* Structure definition for information used to keep track of searches through
* hash tables:
*/
typedef struct Tcl_HashSearch {
Tcl_HashTable *tablePtr; /* Table being searched. */
int nextIndex; /* Index of next bucket to be enumerated after
* present one. */
Tcl_HashEntry *nextEntryPtr;/* Next entry to be enumerated in the current
* bucket. */
} Tcl_HashSearch;
/*
* Acceptable key types for hash tables:
*
* TCL_STRING_KEYS: The keys are strings, they are copied into the
* entry.
* TCL_ONE_WORD_KEYS: The keys are pointers, the pointer is stored
* in the entry.
* TCL_CUSTOM_TYPE_KEYS: The keys are arbitrary types which are copied
* into the entry.
* TCL_CUSTOM_PTR_KEYS: The keys are pointers to arbitrary types, the
* pointer is stored in the entry.
*
* While maintaining binary compatability the above have to be distinct values
* as they are used to differentiate between old versions of the hash table
* which don't have a typePtr and new ones which do. Once binary compatability
* is discarded in favour of making more wide spread changes TCL_STRING_KEYS
* can be the same as TCL_CUSTOM_TYPE_KEYS, and TCL_ONE_WORD_KEYS can be the
* same as TCL_CUSTOM_PTR_KEYS because they simply determine how the key is
* accessed from the entry and not the behaviour.
*/
#define TCL_STRING_KEYS (0)
#define TCL_ONE_WORD_KEYS (1)
#define TCL_CUSTOM_TYPE_KEYS (-2)
#define TCL_CUSTOM_PTR_KEYS (-1)
/*
* Structure definition for information used to keep track of searches through
* dictionaries. These fields should not be accessed by code outside
* tclDictObj.c
*/
typedef struct {
void *next; /* Search position for underlying hash
* table. */
int epoch; /* Epoch marker for dictionary being searched,
* or -1 if search has terminated. */
Tcl_Dict dictionaryPtr; /* Reference to dictionary being searched. */
} Tcl_DictSearch;
/*
*----------------------------------------------------------------------------
* Flag values to pass to Tcl_DoOneEvent to disable searches for some kinds of
* events:
*/
#define TCL_DONT_WAIT (1<<1)
#define TCL_WINDOW_EVENTS (1<<2)
#define TCL_FILE_EVENTS (1<<3)
#define TCL_TIMER_EVENTS (1<<4)
#define TCL_IDLE_EVENTS (1<<5) /* WAS 0x10 ???? */
#define TCL_ALL_EVENTS (~TCL_DONT_WAIT)
/*
* The following structure defines a generic event for the Tcl event system.
* These are the things that are queued in calls to Tcl_QueueEvent and
* serviced later by Tcl_DoOneEvent. There can be many different kinds of
* events with different fields, corresponding to window events, timer events,
* etc. The structure for a particular event consists of a Tcl_Event header
* followed by additional information specific to that event.
*/
struct Tcl_Event {
Tcl_EventProc *proc; /* Function to call to service this event. */
struct Tcl_Event *nextPtr; /* Next in list of pending events, or NULL. */
};
/*
* Positions to pass to Tcl_QueueEvent:
*/
typedef enum {
TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK
} Tcl_QueuePosition;
/*
* Values to pass to Tcl_SetServiceMode to specify the behavior of notifier
* event routines.
*/
#define TCL_SERVICE_NONE 0
#define TCL_SERVICE_ALL 1
/*
* The following structure keeps is used to hold a time value, either as an
* absolute time (the number of seconds from the epoch) or as an elapsed time.
* On Unix systems the epoch is Midnight Jan 1, 1970 GMT.
*/
typedef struct Tcl_Time {
long sec; /* Seconds. */
long usec; /* Microseconds. */
} Tcl_Time;
typedef void (Tcl_SetTimerProc) (CONST86 Tcl_Time *timePtr);
typedef int (Tcl_WaitForEventProc) (CONST86 Tcl_Time *timePtr);
/*
* TIP #233 (Virtualized Time)
*/
typedef void (Tcl_GetTimeProc) (Tcl_Time *timebuf, ClientData clientData);
typedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, ClientData clientData);
/*
*----------------------------------------------------------------------------
* Bits to pass to Tcl_CreateFileHandler and Tcl_CreateChannelHandler to
* indicate what sorts of events are of interest:
*/
#define TCL_READABLE (1<<1)
#define TCL_WRITABLE (1<<2)
#define TCL_EXCEPTION (1<<3)
/*
* Flag values to pass to Tcl_OpenCommandChannel to indicate the disposition
* of the stdio handles. TCL_STDIN, TCL_STDOUT, TCL_STDERR, are also used in
* Tcl_GetStdChannel.
*/
#define TCL_STDIN (1<<1)
#define TCL_STDOUT (1<<2)
#define TCL_STDERR (1<<3)
#define TCL_ENFORCE_MODE (1<<4)
/*
* Bits passed to Tcl_DriverClose2Proc to indicate which side of a channel
* should be closed.
*/
#define TCL_CLOSE_READ (1<<1)
#define TCL_CLOSE_WRITE (1<<2)
/*
* Value to use as the closeProc for a channel that supports the close2Proc
* interface.
*/
#define TCL_CLOSE2PROC ((Tcl_DriverCloseProc *) 1)
/*
* Channel version tag. This was introduced in 8.3.2/8.4.
*/
#define TCL_CHANNEL_VERSION_1 ((Tcl_ChannelTypeVersion) 0x1)
#define TCL_CHANNEL_VERSION_2 ((Tcl_ChannelTypeVersion) 0x2)
#define TCL_CHANNEL_VERSION_3 ((Tcl_ChannelTypeVersion) 0x3)
#define TCL_CHANNEL_VERSION_4 ((Tcl_ChannelTypeVersion) 0x4)
#define TCL_CHANNEL_VERSION_5 ((Tcl_ChannelTypeVersion) 0x5)
/*
* TIP #218: Channel Actions, Ids for Tcl_DriverThreadActionProc.
*/
#define TCL_CHANNEL_THREAD_INSERT (0)
#define TCL_CHANNEL_THREAD_REMOVE (1)
/*
* Typedefs for the various operations in a channel type:
*/
typedef int (Tcl_DriverBlockModeProc) (ClientData instanceData, int mode);
typedef int (Tcl_DriverCloseProc) (ClientData instanceData,
Tcl_Interp *interp);
typedef int (Tcl_DriverClose2Proc) (ClientData instanceData,
Tcl_Interp *interp, int flags);
typedef int (Tcl_DriverInputProc) (ClientData instanceData, char *buf,
int toRead, int *errorCodePtr);
typedef int (Tcl_DriverOutputProc) (ClientData instanceData,
CONST84 char *buf, int toWrite, int *errorCodePtr);
typedef int (Tcl_DriverSeekProc) (ClientData instanceData, long offset,
int mode, int *errorCodePtr);
typedef int (Tcl_DriverSetOptionProc) (ClientData instanceData,
Tcl_Interp *interp, const char *optionName,
const char *value);
typedef int (Tcl_DriverGetOptionProc) (ClientData instanceData,
Tcl_Interp *interp, CONST84 char *optionName,
Tcl_DString *dsPtr);
typedef void (Tcl_DriverWatchProc) (ClientData instanceData, int mask);
typedef int (Tcl_DriverGetHandleProc) (ClientData instanceData,
int direction, ClientData *handlePtr);
typedef int (Tcl_DriverFlushProc) (ClientData instanceData);
typedef int (Tcl_DriverHandlerProc) (ClientData instanceData,
int interestMask);
typedef Tcl_WideInt (Tcl_DriverWideSeekProc) (ClientData instanceData,
Tcl_WideInt offset, int mode, int *errorCodePtr);
/*
* TIP #218, Channel Thread Actions
*/
typedef void (Tcl_DriverThreadActionProc) (ClientData instanceData,
int action);
/*
* TIP #208, File Truncation (etc.)
*/
typedef int (Tcl_DriverTruncateProc) (ClientData instanceData,
Tcl_WideInt length);
/*
* struct Tcl_ChannelType:
*
* One such structure exists for each type (kind) of channel. It collects
* together in one place all the functions that are part of the specific
* channel type.
*
* It is recommend that the Tcl_Channel* functions are used to access elements
* of this structure, instead of direct accessing.
*/
typedef struct Tcl_ChannelType {
const char *typeName; /* The name of the channel type in Tcl
* commands. This storage is owned by channel
* type. */
Tcl_ChannelTypeVersion version;
/* Version of the channel type. */
Tcl_DriverCloseProc *closeProc;
/* Function to call to close the channel, or
* TCL_CLOSE2PROC if the close2Proc should be
* used instead. */
Tcl_DriverInputProc *inputProc;
/* Function to call for input on channel. */
Tcl_DriverOutputProc *outputProc;
/* Function to call for output on channel. */
Tcl_DriverSeekProc *seekProc;
/* Function to call to seek on the channel.
* May be NULL. */
Tcl_DriverSetOptionProc *setOptionProc;
/* Set an option on a channel. */
Tcl_DriverGetOptionProc *getOptionProc;
/* Get an option from a channel. */
Tcl_DriverWatchProc *watchProc;
/* Set up the notifier to watch for events on
* this channel. */
Tcl_DriverGetHandleProc *getHandleProc;
/* Get an OS handle from the channel or NULL
* if not supported. */
Tcl_DriverClose2Proc *close2Proc;
/* Function to call to close the channel if
* the device supports closing the read &
* write sides independently. */
Tcl_DriverBlockModeProc *blockModeProc;
/* Set blocking mode for the raw channel. May
* be NULL. */
/*
* Only valid in TCL_CHANNEL_VERSION_2 channels or later.
*/
Tcl_DriverFlushProc *flushProc;
/* Function to call to flush a channel. May be
* NULL. */
Tcl_DriverHandlerProc *handlerProc;
/* Function to call to handle a channel event.
* This will be passed up the stacked channel
* chain. */
/*
* Only valid in TCL_CHANNEL_VERSION_3 channels or later.
*/
Tcl_DriverWideSeekProc *wideSeekProc;
/* Function to call to seek on the channel
* which can handle 64-bit offsets. May be
* NULL, and must be NULL if seekProc is
* NULL. */
/*
* Only valid in TCL_CHANNEL_VERSION_4 channels or later.
* TIP #218, Channel Thread Actions.
*/
Tcl_DriverThreadActionProc *threadActionProc;
/* Function to call to notify the driver of
* thread specific activity for a channel. May
* be NULL. */
/*
* Only valid in TCL_CHANNEL_VERSION_5 channels or later.
* TIP #208, File Truncation.
*/
Tcl_DriverTruncateProc *truncateProc;
/* Function to call to truncate the underlying
* file to a particular length. May be NULL if
* the channel does not support truncation. */
} Tcl_ChannelType;
/*
* The following flags determine whether the blockModeProc above should set
* the channel into blocking or nonblocking mode. They are passed as arguments
* to the blockModeProc function in the above structure.
*/
#define TCL_MODE_BLOCKING 0 /* Put channel into blocking mode. */
#define TCL_MODE_NONBLOCKING 1 /* Put channel into nonblocking
* mode. */
/*
*----------------------------------------------------------------------------
* Enum for different types of file paths.
*/
typedef enum Tcl_PathType {
TCL_PATH_ABSOLUTE,
TCL_PATH_RELATIVE,
TCL_PATH_VOLUME_RELATIVE
} Tcl_PathType;
/*
* The following structure is used to pass glob type data amongst the various
* glob routines and Tcl_FSMatchInDirectory.
*/
typedef struct Tcl_GlobTypeData {
int type; /* Corresponds to bcdpfls as in 'find -t'. */
int perm; /* Corresponds to file permissions. */
Tcl_Obj *macType; /* Acceptable Mac type. */
Tcl_Obj *macCreator; /* Acceptable Mac creator. */
} Tcl_GlobTypeData;
/*
* Type and permission definitions for glob command.
*/
#define TCL_GLOB_TYPE_BLOCK (1<<0)
#define TCL_GLOB_TYPE_CHAR (1<<1)
#define TCL_GLOB_TYPE_DIR (1<<2)
#define TCL_GLOB_TYPE_PIPE (1<<3)
#define TCL_GLOB_TYPE_FILE (1<<4)
#define TCL_GLOB_TYPE_LINK (1<<5)
#define TCL_GLOB_TYPE_SOCK (1<<6)
#define TCL_GLOB_TYPE_MOUNT (1<<7)
#define TCL_GLOB_PERM_RONLY (1<<0)
#define TCL_GLOB_PERM_HIDDEN (1<<1)
#define TCL_GLOB_PERM_R (1<<2)
#define TCL_GLOB_PERM_W (1<<3)
#define TCL_GLOB_PERM_X (1<<4)
/*
* Flags for the unload callback function.
*/
#define TCL_UNLOAD_DETACH_FROM_INTERPRETER (1<<0)
#define TCL_UNLOAD_DETACH_FROM_PROCESS (1<<1)
/*
* Typedefs for the various filesystem operations:
*/
typedef int (Tcl_FSStatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf);
typedef int (Tcl_FSAccessProc) (Tcl_Obj *pathPtr, int mode);
typedef Tcl_Channel (Tcl_FSOpenFileChannelProc) (Tcl_Interp *interp,
Tcl_Obj *pathPtr, int mode, int permissions);
typedef int (Tcl_FSMatchInDirectoryProc) (Tcl_Interp *interp, Tcl_Obj *result,
Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types);
typedef Tcl_Obj * (Tcl_FSGetCwdProc) (Tcl_Interp *interp);
typedef int (Tcl_FSChdirProc) (Tcl_Obj *pathPtr);
typedef int (Tcl_FSLstatProc) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf);
typedef int (Tcl_FSCreateDirectoryProc) (Tcl_Obj *pathPtr);
typedef int (Tcl_FSDeleteFileProc) (Tcl_Obj *pathPtr);
typedef int (Tcl_FSCopyDirectoryProc) (Tcl_Obj *srcPathPtr,
Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr);
typedef int (Tcl_FSCopyFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr);
typedef int (Tcl_FSRemoveDirectoryProc) (Tcl_Obj *pathPtr, int recursive,
Tcl_Obj **errorPtr);
typedef int (Tcl_FSRenameFileProc) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr);
typedef void (Tcl_FSUnloadFileProc) (Tcl_LoadHandle loadHandle);
typedef Tcl_Obj * (Tcl_FSListVolumesProc) (void);
/* We have to declare the utime structure here. */
struct utimbuf;
typedef int (Tcl_FSUtimeProc) (Tcl_Obj *pathPtr, struct utimbuf *tval);
typedef int (Tcl_FSNormalizePathProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr,
int nextCheckpoint);
typedef int (Tcl_FSFileAttrsGetProc) (Tcl_Interp *interp, int index,
Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef);
typedef const char *CONST86 * (Tcl_FSFileAttrStringsProc) (Tcl_Obj *pathPtr,
Tcl_Obj **objPtrRef);
typedef int (Tcl_FSFileAttrsSetProc) (Tcl_Interp *interp, int index,
Tcl_Obj *pathPtr, Tcl_Obj *objPtr);
typedef Tcl_Obj * (Tcl_FSLinkProc) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr,
int linkType);
typedef int (Tcl_FSLoadFileProc) (Tcl_Interp *interp, Tcl_Obj *pathPtr,
Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr);
typedef int (Tcl_FSPathInFilesystemProc) (Tcl_Obj *pathPtr,
ClientData *clientDataPtr);
typedef Tcl_Obj * (Tcl_FSFilesystemPathTypeProc) (Tcl_Obj *pathPtr);
typedef Tcl_Obj * (Tcl_FSFilesystemSeparatorProc) (Tcl_Obj *pathPtr);
typedef void (Tcl_FSFreeInternalRepProc) (ClientData clientData);
typedef ClientData (Tcl_FSDupInternalRepProc) (ClientData clientData);
typedef Tcl_Obj * (Tcl_FSInternalToNormalizedProc) (ClientData clientData);
typedef ClientData (Tcl_FSCreateInternalRepProc) (Tcl_Obj *pathPtr);
typedef struct Tcl_FSVersion_ *Tcl_FSVersion;
/*
*----------------------------------------------------------------------------
* Data structures related to hooking into the filesystem
*/
/*
* Filesystem version tag. This was introduced in 8.4.
*/
#define TCL_FILESYSTEM_VERSION_1 ((Tcl_FSVersion) 0x1)
/*
* struct Tcl_Filesystem:
*
* One such structure exists for each type (kind) of filesystem. It collects
* together in one place all the functions that are part of the specific
* filesystem. Tcl always accesses the filesystem through one of these
* structures.
*
* Not all entries need be non-NULL; any which are NULL are simply ignored.
* However, a complete filesystem should provide all of these functions. The
* explanations in the structure show the importance of each function.
*/
typedef struct Tcl_Filesystem {
const char *typeName; /* The name of the filesystem. */
int structureLength; /* Length of this structure, so future binary
* compatibility can be assured. */
Tcl_FSVersion version; /* Version of the filesystem type. */
Tcl_FSPathInFilesystemProc *pathInFilesystemProc;
/* Function to check whether a path is in this
* filesystem. This is the most important
* filesystem function. */
Tcl_FSDupInternalRepProc *dupInternalRepProc;
/* Function to duplicate internal fs rep. May
* be NULL (but then fs is less efficient). */
Tcl_FSFreeInternalRepProc *freeInternalRepProc;
/* Function to free internal fs rep. Must be
* implemented if internal representations
* need freeing, otherwise it can be NULL. */
Tcl_FSInternalToNormalizedProc *internalToNormalizedProc;
/* Function to convert internal representation
* to a normalized path. Only required if the
* fs creates pure path objects with no
* string/path representation. */
Tcl_FSCreateInternalRepProc *createInternalRepProc;
/* Function to create a filesystem-specific
* internal representation. May be NULL if
* paths have no internal representation, or
* if the Tcl_FSPathInFilesystemProc for this
* filesystem always immediately creates an
* internal representation for paths it
* accepts. */
Tcl_FSNormalizePathProc *normalizePathProc;
/* Function to normalize a path. Should be
* implemented for all filesystems which can
* have multiple string representations for
* the same path object. */
Tcl_FSFilesystemPathTypeProc *filesystemPathTypeProc;
/* Function to determine the type of a path in
* this filesystem. May be NULL. */
Tcl_FSFilesystemSeparatorProc *filesystemSeparatorProc;
/* Function to return the separator
* character(s) for this filesystem. Must be
* implemented. */
Tcl_FSStatProc *statProc; /* Function to process a 'Tcl_FSStat()' call.
* Must be implemented for any reasonable
* filesystem. */
Tcl_FSAccessProc *accessProc;
/* Function to process a 'Tcl_FSAccess()'
* call. Must be implemented for any
* reasonable filesystem. */
Tcl_FSOpenFileChannelProc *openFileChannelProc;
/* Function to process a
* 'Tcl_FSOpenFileChannel()' call. Must be
* implemented for any reasonable
* filesystem. */
Tcl_FSMatchInDirectoryProc *matchInDirectoryProc;
/* Function to process a
* 'Tcl_FSMatchInDirectory()'. If not
* implemented, then glob and recursive copy
* functionality will be lacking in the
* filesystem. */
Tcl_FSUtimeProc *utimeProc; /* Function to process a 'Tcl_FSUtime()' call.
* Required to allow setting (not reading) of
* times with 'file mtime', 'file atime' and
* the open-r/open-w/fcopy implementation of
* 'file copy'. */
Tcl_FSLinkProc *linkProc; /* Function to process a 'Tcl_FSLink()' call.
* Should be implemented only if the
* filesystem supports links (reading or
* creating). */
Tcl_FSListVolumesProc *listVolumesProc;
/* Function to list any filesystem volumes
* added by this filesystem. Should be
* implemented only if the filesystem adds
* volumes at the head of the filesystem. */
Tcl_FSFileAttrStringsProc *fileAttrStringsProc;
/* Function to list all attributes strings
* which are valid for this filesystem. If not
* implemented the filesystem will not support
* the 'file attributes' command. This allows
* arbitrary additional information to be
* attached to files in the filesystem. */
Tcl_FSFileAttrsGetProc *fileAttrsGetProc;
/* Function to process a
* 'Tcl_FSFileAttrsGet()' call, used by 'file
* attributes'. */
Tcl_FSFileAttrsSetProc *fileAttrsSetProc;
/* Function to process a
* 'Tcl_FSFileAttrsSet()' call, used by 'file
* attributes'. */
Tcl_FSCreateDirectoryProc *createDirectoryProc;
/* Function to process a
* 'Tcl_FSCreateDirectory()' call. Should be
* implemented unless the FS is read-only. */
Tcl_FSRemoveDirectoryProc *removeDirectoryProc;
/* Function to process a
* 'Tcl_FSRemoveDirectory()' call. Should be
* implemented unless the FS is read-only. */
Tcl_FSDeleteFileProc *deleteFileProc;
/* Function to process a 'Tcl_FSDeleteFile()'
* call. Should be implemented unless the FS
* is read-only. */
Tcl_FSCopyFileProc *copyFileProc;
/* Function to process a 'Tcl_FSCopyFile()'
* call. If not implemented Tcl will fall back
* on open-r, open-w and fcopy as a copying
* mechanism, for copying actions initiated in
* Tcl (not C). */
Tcl_FSRenameFileProc *renameFileProc;
/* Function to process a 'Tcl_FSRenameFile()'
* call. If not implemented, Tcl will fall
* back on a copy and delete mechanism, for
* rename actions initiated in Tcl (not C). */
Tcl_FSCopyDirectoryProc *copyDirectoryProc;
/* Function to process a
* 'Tcl_FSCopyDirectory()' call. If not
* implemented, Tcl will fall back on a
* recursive create-dir, file copy mechanism,
* for copying actions initiated in Tcl (not
* C). */
Tcl_FSLstatProc *lstatProc; /* Function to process a 'Tcl_FSLstat()' call.
* If not implemented, Tcl will attempt to use
* the 'statProc' defined above instead. */
Tcl_FSLoadFileProc *loadFileProc;
/* Function to process a 'Tcl_FSLoadFile()'
* call. If not implemented, Tcl will fall
* back on a copy to native-temp followed by a
* Tcl_FSLoadFile on that temporary copy. */
Tcl_FSGetCwdProc *getCwdProc;
/* Function to process a 'Tcl_FSGetCwd()'
* call. Most filesystems need not implement
* this. It will usually only be called once,
* if 'getcwd' is called before 'chdir'. May
* be NULL. */
Tcl_FSChdirProc *chdirProc; /* Function to process a 'Tcl_FSChdir()' call.
* If filesystems do not implement this, it
* will be emulated by a series of directory
* access checks. Otherwise, virtual
* filesystems which do implement it need only
* respond with a positive return result if
* the dirName is a valid directory in their
* filesystem. They need not remember the
* result, since that will be automatically
* remembered for use by GetCwd. Real
* filesystems should carry out the correct
* action (i.e. call the correct system
* 'chdir' api). If not implemented, then 'cd'
* and 'pwd' will fail inside the
* filesystem. */
} Tcl_Filesystem;
/*
* The following definitions are used as values for the 'linkAction' flag to
* Tcl_FSLink, or the linkProc of any filesystem. Any combination of flags can
* be given. For link creation, the linkProc should create a link which
* matches any of the types given.
*
* TCL_CREATE_SYMBOLIC_LINK - Create a symbolic or soft link.
* TCL_CREATE_HARD_LINK - Create a hard link.
*/
#define TCL_CREATE_SYMBOLIC_LINK 0x01
#define TCL_CREATE_HARD_LINK 0x02
/*
*----------------------------------------------------------------------------
* The following structure represents the Notifier functions that you can
* override with the Tcl_SetNotifier call.
*/
typedef struct Tcl_NotifierProcs {
Tcl_SetTimerProc *setTimerProc;
Tcl_WaitForEventProc *waitForEventProc;
Tcl_CreateFileHandlerProc *createFileHandlerProc;
Tcl_DeleteFileHandlerProc *deleteFileHandlerProc;
Tcl_InitNotifierProc *initNotifierProc;
Tcl_FinalizeNotifierProc *finalizeNotifierProc;
Tcl_AlertNotifierProc *alertNotifierProc;
Tcl_ServiceModeHookProc *serviceModeHookProc;
} Tcl_NotifierProcs;
/*
*----------------------------------------------------------------------------
* The following data structures and declarations are for the new Tcl parser.
*
* For each word of a command, and for each piece of a word such as a variable
* reference, one of the following structures is created to describe the
* token.
*/
typedef struct Tcl_Token {
int type; /* Type of token, such as TCL_TOKEN_WORD; see
* below for valid types. */
const char *start; /* First character in token. */
int size; /* Number of bytes in token. */
int numComponents; /* If this token is composed of other tokens,
* this field tells how many of them there are
* (including components of components, etc.).
* The component tokens immediately follow
* this one. */
} Tcl_Token;
/*
* Type values defined for Tcl_Token structures. These values are defined as
* mask bits so that it's easy to check for collections of types.
*
* TCL_TOKEN_WORD - The token describes one word of a command,
* from the first non-blank character of the word
* (which may be " or {) up to but not including
* the space, semicolon, or bracket that
* terminates the word. NumComponents counts the
* total number of sub-tokens that make up the
* word. This includes, for example, sub-tokens
* of TCL_TOKEN_VARIABLE tokens.
* TCL_TOKEN_SIMPLE_WORD - This token is just like TCL_TOKEN_WORD except
* that the word is guaranteed to consist of a
* single TCL_TOKEN_TEXT sub-token.
* TCL_TOKEN_TEXT - The token describes a range of literal text
* that is part of a word. NumComponents is
* always 0.
* TCL_TOKEN_BS - The token describes a backslash sequence that
* must be collapsed. NumComponents is always 0.
* TCL_TOKEN_COMMAND - The token describes a command whose result
* must be substituted into the word. The token
* includes the enclosing brackets. NumComponents
* is always 0.
* TCL_TOKEN_VARIABLE - The token describes a variable substitution,
* including the dollar sign, variable name, and
* array index (if there is one) up through the
* right parentheses. NumComponents tells how
* many additional tokens follow to represent the
* variable name. The first token will be a
* TCL_TOKEN_TEXT token that describes the
* variable name. If the variable is an array
* reference then there will be one or more
* additional tokens, of type TCL_TOKEN_TEXT,
* TCL_TOKEN_BS, TCL_TOKEN_COMMAND, and
* TCL_TOKEN_VARIABLE, that describe the array
* index; numComponents counts the total number
* of nested tokens that make up the variable
* reference, including sub-tokens of
* TCL_TOKEN_VARIABLE tokens.
* TCL_TOKEN_SUB_EXPR - The token describes one subexpression of an
* expression, from the first non-blank character
* of the subexpression up to but not including
* the space, brace, or bracket that terminates
* the subexpression. NumComponents counts the
* total number of following subtokens that make
* up the subexpression; this includes all
* subtokens for any nested TCL_TOKEN_SUB_EXPR
* tokens. For example, a numeric value used as a
* primitive operand is described by a
* TCL_TOKEN_SUB_EXPR token followed by a
* TCL_TOKEN_TEXT token. A binary subexpression
* is described by a TCL_TOKEN_SUB_EXPR token
* followed by the TCL_TOKEN_OPERATOR token for
* the operator, then TCL_TOKEN_SUB_EXPR tokens
* for the left then the right operands.
* TCL_TOKEN_OPERATOR - The token describes one expression operator.
* An operator might be the name of a math
* function such as "abs". A TCL_TOKEN_OPERATOR
* token is always preceeded by one
* TCL_TOKEN_SUB_EXPR token for the operator's
* subexpression, and is followed by zero or more
* TCL_TOKEN_SUB_EXPR tokens for the operator's
* operands. NumComponents is always 0.
* TCL_TOKEN_EXPAND_WORD - This token is just like TCL_TOKEN_WORD except
* that it marks a word that began with the
* literal character prefix "{*}". This word is
* marked to be expanded - that is, broken into
* words after substitution is complete.
*/
#define TCL_TOKEN_WORD 1
#define TCL_TOKEN_SIMPLE_WORD 2
#define TCL_TOKEN_TEXT 4
#define TCL_TOKEN_BS 8
#define TCL_TOKEN_COMMAND 16
#define TCL_TOKEN_VARIABLE 32
#define TCL_TOKEN_SUB_EXPR 64
#define TCL_TOKEN_OPERATOR 128
#define TCL_TOKEN_EXPAND_WORD 256
/*
* Parsing error types. On any parsing error, one of these values will be
* stored in the error field of the Tcl_Parse structure defined below.
*/
#define TCL_PARSE_SUCCESS 0
#define TCL_PARSE_QUOTE_EXTRA 1
#define TCL_PARSE_BRACE_EXTRA 2
#define TCL_PARSE_MISSING_BRACE 3
#define TCL_PARSE_MISSING_BRACKET 4
#define TCL_PARSE_MISSING_PAREN 5
#define TCL_PARSE_MISSING_QUOTE 6
#define TCL_PARSE_MISSING_VAR_BRACE 7
#define TCL_PARSE_SYNTAX 8
#define TCL_PARSE_BAD_NUMBER 9
/*
* A structure of the following type is filled in by Tcl_ParseCommand. It
* describes a single command parsed from an input string.
*/
#define NUM_STATIC_TOKENS 20
typedef struct Tcl_Parse {
const char *commentStart; /* Pointer to # that begins the first of one
* or more comments preceding the command. */
int commentSize; /* Number of bytes in comments (up through
* newline character that terminates the last
* comment). If there were no comments, this
* field is 0. */
const char *commandStart; /* First character in first word of
* command. */
int commandSize; /* Number of bytes in command, including first
* character of first word, up through the
* terminating newline, close bracket, or
* semicolon. */
int numWords; /* Total number of words in command. May be
* 0. */
Tcl_Token *tokenPtr; /* Pointer to first token representing the
* words of the command. Initially points to
* staticTokens, but may change to point to
* malloc-ed space if command exceeds space in
* staticTokens. */
int numTokens; /* Total number of tokens in command. */
int tokensAvailable; /* Total number of tokens available at
* *tokenPtr. */
int errorType; /* One of the parsing error types defined
* above. */
/*
* The fields below are intended only for the private use of the parser.
* They should not be used by functions that invoke Tcl_ParseCommand.
*/
const char *string; /* The original command string passed to
* Tcl_ParseCommand. */
const char *end; /* Points to the character just after the last
* one in the command string. */
Tcl_Interp *interp; /* Interpreter to use for error reporting, or
* NULL. */
const char *term; /* Points to character in string that
* terminated most recent token. Filled in by
* ParseTokens. If an error occurs, points to
* beginning of region where the error
* occurred (e.g. the open brace if the close
* brace is missing). */
int incomplete; /* This field is set to 1 by Tcl_ParseCommand
* if the command appears to be incomplete.
* This information is used by
* Tcl_CommandComplete. */
Tcl_Token staticTokens[NUM_STATIC_TOKENS];
/* Initial space for tokens for command. This
* space should be large enough to accommodate
* most commands; dynamic space is allocated
* for very large commands that don't fit
* here. */
} Tcl_Parse;
/*
*----------------------------------------------------------------------------
* The following structure represents a user-defined encoding. It collects
* together all the functions that are used by the specific encoding.
*/
typedef struct Tcl_EncodingType {
const char *encodingName; /* The name of the encoding, e.g. "euc-jp".
* This name is the unique key for this
* encoding type. */
Tcl_EncodingConvertProc *toUtfProc;
/* Function to convert from external encoding
* into UTF-8. */
Tcl_EncodingConvertProc *fromUtfProc;
/* Function to convert from UTF-8 into
* external encoding. */
Tcl_EncodingFreeProc *freeProc;
/* If non-NULL, function to call when this
* encoding is deleted. */
ClientData clientData; /* Arbitrary value associated with encoding
* type. Passed to conversion functions. */
int nullSize; /* Number of zero bytes that signify
* end-of-string in this encoding. This number
* is used to determine the source string
* length when the srcLen argument is
* negative. Must be 1 or 2. */
} Tcl_EncodingType;
/*
* The following definitions are used as values for the conversion control
* flags argument when converting text from one character set to another:
*
* TCL_ENCODING_START - Signifies that the source buffer is the first
* block in a (potentially multi-block) input
* stream. Tells the conversion function to reset
* to an initial state and perform any
* initialization that needs to occur before the
* first byte is converted. If the source buffer
* contains the entire input stream to be
* converted, this flag should be set.
* TCL_ENCODING_END - Signifies that the source buffer is the last
* block in a (potentially multi-block) input
* stream. Tells the conversion routine to
* perform any finalization that needs to occur
* after the last byte is converted and then to
* reset to an initial state. If the source
* buffer contains the entire input stream to be
* converted, this flag should be set.
* TCL_ENCODING_STOPONERROR - If set, then the converter will return
* immediately upon encountering an invalid byte
* sequence or a source character that has no
* mapping in the target encoding. If clear, then
* the converter will skip the problem,
* substituting one or more "close" characters in
* the destination buffer and then continue to
* convert the source.
*/
#define TCL_ENCODING_START 0x01
#define TCL_ENCODING_END 0x02
#define TCL_ENCODING_STOPONERROR 0x04
/*
* The following definitions are the error codes returned by the conversion
* routines:
*
* TCL_OK - All characters were converted.
* TCL_CONVERT_NOSPACE - The output buffer would not have been large
* enough for all of the converted data; as many
* characters as could fit were converted though.
* TCL_CONVERT_MULTIBYTE - The last few bytes in the source string were
* the beginning of a multibyte sequence, but
* more bytes were needed to complete this
* sequence. A subsequent call to the conversion
* routine should pass the beginning of this
* unconverted sequence plus additional bytes
* from the source stream to properly convert the
* formerly split-up multibyte sequence.
* TCL_CONVERT_SYNTAX - The source stream contained an invalid
* character sequence. This may occur if the
* input stream has been damaged or if the input
* encoding method was misidentified. This error
* is reported only if TCL_ENCODING_STOPONERROR
* was specified.
* TCL_CONVERT_UNKNOWN - The source string contained a character that
* could not be represented in the target
* encoding. This error is reported only if
* TCL_ENCODING_STOPONERROR was specified.
*/
#define TCL_CONVERT_MULTIBYTE (-1)
#define TCL_CONVERT_SYNTAX (-2)
#define TCL_CONVERT_UNKNOWN (-3)
#define TCL_CONVERT_NOSPACE (-4)
/*
* The maximum number of bytes that are necessary to represent a single
* Unicode character in UTF-8. The valid values should be 3, 4 or 6
* (or perhaps 1 if we want to support a non-unicode enabled core). If 3 or
* 4, then Tcl_UniChar must be 2-bytes in size (UCS-2) (the default). If 6,
* then Tcl_UniChar must be 4-bytes in size (UCS-4). At this time UCS-2 mode
* is the default and recommended mode. UCS-4 is experimental and not
* recommended. It works for the core, but most extensions expect UCS-2.
*/
#ifndef TCL_UTF_MAX
#define TCL_UTF_MAX 3
#endif
/*
* This represents a Unicode character. Any changes to this should also be
* reflected in regcustom.h.
*/
#if TCL_UTF_MAX > 4
/*
* unsigned int isn't 100% accurate as it should be a strict 4-byte value
* (perhaps wchar_t). 64-bit systems may have troubles. The size of this
* value must be reflected correctly in regcustom.h and
* in tclEncoding.c.
* XXX: Tcl is currently UCS-2 and planning UTF-16 for the Unicode
* XXX: string rep that Tcl_UniChar represents. Changing the size
* XXX: of Tcl_UniChar is /not/ supported.
*/
typedef unsigned int Tcl_UniChar;
#else
typedef unsigned short Tcl_UniChar;
#endif
/*
*----------------------------------------------------------------------------
* TIP #59: The following structure is used in calls 'Tcl_RegisterConfig' to
* provide the system with the embedded configuration data.
*/
typedef struct Tcl_Config {
const char *key; /* Configuration key to register. ASCII
* encoded, thus UTF-8. */
const char *value; /* The value associated with the key. System
* encoding. */
} Tcl_Config;
/*
*----------------------------------------------------------------------------
* Flags for TIP#143 limits, detailing which limits are active in an
* interpreter. Used for Tcl_{Add,Remove}LimitHandler type argument.
*/
#define TCL_LIMIT_COMMANDS 0x01
#define TCL_LIMIT_TIME 0x02
/*
* Structure containing information about a limit handler to be called when a
* command- or time-limit is exceeded by an interpreter.
*/
typedef void (Tcl_LimitHandlerProc) (ClientData clientData, Tcl_Interp *interp);
typedef void (Tcl_LimitHandlerDeleteProc) (ClientData clientData);
/*
*----------------------------------------------------------------------------
* Override definitions for libtommath.
*/
typedef struct mp_int mp_int;
#define MP_INT_DECLARED
typedef unsigned int mp_digit;
#define MP_DIGIT_DECLARED
/*
*----------------------------------------------------------------------------
* Definitions needed for Tcl_ParseArgvObj routines.
* Based on tkArgv.c.
* Modifications from the original are copyright (c) Sam Bromley 2006
*/
typedef struct {
int type; /* Indicates the option type; see below. */
const char *keyStr; /* The key string that flags the option in the
* argv array. */
void *srcPtr; /* Value to be used in setting dst; usage
* depends on type.*/
void *dstPtr; /* Address of value to be modified; usage
* depends on type.*/
const char *helpStr; /* Documentation message describing this
* option. */
ClientData clientData; /* Word to pass to function callbacks. */
} Tcl_ArgvInfo;
/*
* Legal values for the type field of a Tcl_ArgInfo: see the user
* documentation for details.
*/
#define TCL_ARGV_CONSTANT 15
#define TCL_ARGV_INT 16
#define TCL_ARGV_STRING 17
#define TCL_ARGV_REST 18
#define TCL_ARGV_FLOAT 19
#define TCL_ARGV_FUNC 20
#define TCL_ARGV_GENFUNC 21
#define TCL_ARGV_HELP 22
#define TCL_ARGV_END 23
/*
* Types of callback functions for the TCL_ARGV_FUNC and TCL_ARGV_GENFUNC
* argument types:
*/
typedef int (Tcl_ArgvFuncProc)(ClientData clientData, Tcl_Obj *objPtr,
void *dstPtr);
typedef int (Tcl_ArgvGenFuncProc)(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *const *objv, void *dstPtr);
/*
* Shorthand for commonly used argTable entries.
*/
#define TCL_ARGV_AUTO_HELP \
{TCL_ARGV_HELP, "-help", NULL, NULL, \
"Print summary of command-line options and abort", NULL}
#define TCL_ARGV_AUTO_REST \
{TCL_ARGV_REST, "--", NULL, NULL, \
"Marks the end of the options", NULL}
#define TCL_ARGV_TABLE_END \
{TCL_ARGV_END, NULL, NULL, NULL, NULL, NULL}
/*
*----------------------------------------------------------------------------
* Definitions needed for Tcl_Zlib routines. [TIP #234]
*
* Constants for the format flags describing what sort of data format is
* desired/expected for the Tcl_ZlibDeflate, Tcl_ZlibInflate and
* Tcl_ZlibStreamInit functions.
*/
#define TCL_ZLIB_FORMAT_RAW 1
#define TCL_ZLIB_FORMAT_ZLIB 2
#define TCL_ZLIB_FORMAT_GZIP 4
#define TCL_ZLIB_FORMAT_AUTO 8
/*
* Constants that describe whether the stream is to operate in compressing or
* decompressing mode.
*/
#define TCL_ZLIB_STREAM_DEFLATE 16
#define TCL_ZLIB_STREAM_INFLATE 32
/*
* Constants giving compression levels. Use of TCL_ZLIB_COMPRESS_DEFAULT is
* recommended.
*/
#define TCL_ZLIB_COMPRESS_NONE 0
#define TCL_ZLIB_COMPRESS_FAST 1
#define TCL_ZLIB_COMPRESS_BEST 9
#define TCL_ZLIB_COMPRESS_DEFAULT (-1)
/*
* Constants for types of flushing, used with Tcl_ZlibFlush.
*/
#define TCL_ZLIB_NO_FLUSH 0
#define TCL_ZLIB_FLUSH 2
#define TCL_ZLIB_FULLFLUSH 3
#define TCL_ZLIB_FINALIZE 4
/*
*----------------------------------------------------------------------------
* Definitions needed for the Tcl_LoadFile function. [TIP #416]
*/
#define TCL_LOAD_GLOBAL 1
#define TCL_LOAD_LAZY 2
/*
*----------------------------------------------------------------------------
* Single public declaration for NRE.
*/
typedef int (Tcl_NRPostProc) (ClientData data[], Tcl_Interp *interp,
int result);
/*
*----------------------------------------------------------------------------
* The following constant is used to test for older versions of Tcl in the
* stubs tables.
*
* Jan Nijtman's plus patch uses 0xFCA1BACF, so we need to pick a different
* value since the stubs tables don't match.
*/
#define TCL_STUB_MAGIC ((int) 0xFCA3BACF)
/*
* The following function is required to be defined in all stubs aware
* extensions. The function is actually implemented in the stub library, not
* the main Tcl library, although there is a trivial implementation in the
* main library in case an extension is statically linked into an application.
*/
const char * Tcl_InitStubs(Tcl_Interp *interp, const char *version,
int exact);
const char * TclTomMathInitializeStubs(Tcl_Interp *interp,
const char *version, int epoch, int revision);
/*
* When not using stubs, make it a macro.
*/
#ifndef USE_TCL_STUBS
#define Tcl_InitStubs(interp, version, exact) \
Tcl_PkgInitStubsCheck(interp, version, exact)
#endif
/*
* TODO - tommath stubs export goes here!
*/
/*
* Public functions that are not accessible via the stubs table.
* Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171]
*/
#define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \
(Tcl_FindExecutable(argv[0]), (Tcl_CreateInterp)()))
EXTERN void Tcl_MainEx(int argc, char **argv,
Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp,
const char *version, int exact);
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr);
#endif
/*
*----------------------------------------------------------------------------
* Include the public function declarations that are accessible via the stubs
* table.
*/
#include "tclDecls.h"
/*
* Include platform specific public function declarations that are accessible
* via the stubs table.
*/
#include "tclPlatDecls.h"
/*
*----------------------------------------------------------------------------
* The following declarations either map ckalloc and ckfree to malloc and
* free, or they map them to functions with all sorts of debugging hooks
* defined in tclCkalloc.c.
*/
#ifdef TCL_MEM_DEBUG
# define ckalloc(x) \
((VOID *) Tcl_DbCkalloc((unsigned)(x), __FILE__, __LINE__))
# define ckfree(x) \
Tcl_DbCkfree((char *)(x), __FILE__, __LINE__)
# define ckrealloc(x,y) \
((VOID *) Tcl_DbCkrealloc((char *)(x), (unsigned)(y), __FILE__, __LINE__))
# define attemptckalloc(x) \
((VOID *) Tcl_AttemptDbCkalloc((unsigned)(x), __FILE__, __LINE__))
# define attemptckrealloc(x,y) \
((VOID *) Tcl_AttemptDbCkrealloc((char *)(x), (unsigned)(y), __FILE__, __LINE__))
#else /* !TCL_MEM_DEBUG */
/*
* If we are not using the debugging allocator, we should call the Tcl_Alloc,
* et al. routines in order to guarantee that every module is using the same
* memory allocator both inside and outside of the Tcl library.
*/
# define ckalloc(x) \
((VOID *) Tcl_Alloc((unsigned)(x)))
# define ckfree(x) \
Tcl_Free((char *)(x))
# define ckrealloc(x,y) \
((VOID *) Tcl_Realloc((char *)(x), (unsigned)(y)))
# define attemptckalloc(x) \
((VOID *) Tcl_AttemptAlloc((unsigned)(x)))
# define attemptckrealloc(x,y) \
((VOID *) Tcl_AttemptRealloc((char *)(x), (unsigned)(y)))
# undef Tcl_InitMemory
# define Tcl_InitMemory(x)
# undef Tcl_DumpActiveMemory
# define Tcl_DumpActiveMemory(x)
# undef Tcl_ValidateAllMemory
# define Tcl_ValidateAllMemory(x,y)
#endif /* !TCL_MEM_DEBUG */
#ifdef TCL_MEM_DEBUG
# define Tcl_IncrRefCount(objPtr) \
Tcl_DbIncrRefCount(objPtr, __FILE__, __LINE__)
# define Tcl_DecrRefCount(objPtr) \
Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__)
# define Tcl_IsShared(objPtr) \
Tcl_DbIsShared(objPtr, __FILE__, __LINE__)
#else
# define Tcl_IncrRefCount(objPtr) \
++(objPtr)->refCount
/*
* Use do/while0 idiom for optimum correctness without compiler warnings.
* http://c2.com/cgi/wiki?TrivialDoWhileLoop
*/
# define Tcl_DecrRefCount(objPtr) \
do { \
Tcl_Obj *_objPtr = (objPtr); \
if (--(_objPtr)->refCount <= 0) { \
TclFreeObj(_objPtr); \
} \
} while(0)
# define Tcl_IsShared(objPtr) \
((objPtr)->refCount > 1)
#endif
/*
* Macros and definitions that help to debug the use of Tcl objects. When
* TCL_MEM_DEBUG is defined, the Tcl_New declarations are overridden to call
* debugging versions of the object creation functions.
*/
#ifdef TCL_MEM_DEBUG
# undef Tcl_NewBignumObj
# define Tcl_NewBignumObj(val) \
Tcl_DbNewBignumObj(val, __FILE__, __LINE__)
# undef Tcl_NewBooleanObj
# define Tcl_NewBooleanObj(val) \
Tcl_DbNewBooleanObj(val, __FILE__, __LINE__)
# undef Tcl_NewByteArrayObj
# define Tcl_NewByteArrayObj(bytes, len) \
Tcl_DbNewByteArrayObj(bytes, len, __FILE__, __LINE__)
# undef Tcl_NewDoubleObj
# define Tcl_NewDoubleObj(val) \
Tcl_DbNewDoubleObj(val, __FILE__, __LINE__)
# undef Tcl_NewIntObj
# define Tcl_NewIntObj(val) \
Tcl_DbNewLongObj(val, __FILE__, __LINE__)
# undef Tcl_NewListObj
# define Tcl_NewListObj(objc, objv) \
Tcl_DbNewListObj(objc, objv, __FILE__, __LINE__)
# undef Tcl_NewLongObj
# define Tcl_NewLongObj(val) \
Tcl_DbNewLongObj(val, __FILE__, __LINE__)
# undef Tcl_NewObj
# define Tcl_NewObj() \
Tcl_DbNewObj(__FILE__, __LINE__)
# undef Tcl_NewStringObj
# define Tcl_NewStringObj(bytes, len) \
Tcl_DbNewStringObj(bytes, len, __FILE__, __LINE__)
# undef Tcl_NewWideIntObj
# define Tcl_NewWideIntObj(val) \
Tcl_DbNewWideIntObj(val, __FILE__, __LINE__)
#endif /* TCL_MEM_DEBUG */
/*
*----------------------------------------------------------------------------
* Macros for clients to use to access fields of hash entries:
*/
#define Tcl_GetHashValue(h) ((h)->clientData)
#define Tcl_SetHashValue(h, value) ((h)->clientData = (ClientData) (value))
#define Tcl_GetHashKey(tablePtr, h) \
((void *) (((tablePtr)->keyType == TCL_ONE_WORD_KEYS || \
(tablePtr)->keyType == TCL_CUSTOM_PTR_KEYS) \
? (h)->key.oneWordValue \
: (h)->key.string))
/*
* Macros to use for clients to use to invoke find and create functions for
* hash tables:
*/
#undef Tcl_FindHashEntry
#define Tcl_FindHashEntry(tablePtr, key) \
(*((tablePtr)->findProc))(tablePtr, (const char *)(key))
#undef Tcl_CreateHashEntry
#define Tcl_CreateHashEntry(tablePtr, key, newPtr) \
(*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr)
/*
*----------------------------------------------------------------------------
* Macros that eliminate the overhead of the thread synchronization functions
* when compiling without thread support.
*/
#ifndef TCL_THREADS
#undef Tcl_MutexLock
#define Tcl_MutexLock(mutexPtr)
#undef Tcl_MutexUnlock
#define Tcl_MutexUnlock(mutexPtr)
#undef Tcl_MutexFinalize
#define Tcl_MutexFinalize(mutexPtr)
#undef Tcl_ConditionNotify
#define Tcl_ConditionNotify(condPtr)
#undef Tcl_ConditionWait
#define Tcl_ConditionWait(condPtr, mutexPtr, timePtr)
#undef Tcl_ConditionFinalize
#define Tcl_ConditionFinalize(condPtr)
#endif /* TCL_THREADS */
/*
*----------------------------------------------------------------------------
* Deprecated Tcl functions:
*/
#ifndef TCL_NO_DEPRECATED
# undef Tcl_EvalObj
# define Tcl_EvalObj(interp,objPtr) \
Tcl_EvalObjEx((interp),(objPtr),0)
# undef Tcl_GlobalEvalObj
# define Tcl_GlobalEvalObj(interp,objPtr) \
Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL)
/*
* These function have been renamed. The old names are deprecated, but we
* define these macros for backwards compatibilty.
*/
# define Tcl_Ckalloc Tcl_Alloc
# define Tcl_Ckfree Tcl_Free
# define Tcl_Ckrealloc Tcl_Realloc
# define Tcl_Return Tcl_SetResult
# define Tcl_TildeSubst Tcl_TranslateFileName
# define panic Tcl_Panic
# define panicVA Tcl_PanicVA
#endif /* !TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------------
* Convenience declaration of Tcl_AppInit for backwards compatibility. This
* function is not *implemented* by the tcl library, so the storage class is
* neither DLLEXPORT nor DLLIMPORT.
*/
extern Tcl_AppInitProc Tcl_AppInit;
#endif /* RC_INVOKED */
/*
* end block for C++
*/
#ifdef __cplusplus
}
#endif
#endif /* _TCL */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Added compat/tcl-8.6/generic/tclDecls.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 |
/*
* tclDecls.h --
*
* Declarations of functions in the platform independent public Tcl API.
*
* Copyright (c) 1998-1999 by Scriptics Corporation.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#ifndef _TCLDECLS
#define _TCLDECLS
#undef TCL_STORAGE_CLASS
#ifdef BUILD_tcl
# define TCL_STORAGE_CLASS DLLEXPORT
#else
# ifdef USE_TCL_STUBS
# define TCL_STORAGE_CLASS
# else
# define TCL_STORAGE_CLASS DLLIMPORT
# endif
#endif
/*
* WARNING: This file is automatically generated by the tools/genStubs.tcl
* script. Any modifications to the function declarations below should be made
* in the generic/tcl.decls script.
*/
/* !BEGIN!: Do not edit below this line. */
/*
* Exported function declarations:
*/
/* 0 */
EXTERN int Tcl_PkgProvideEx(Tcl_Interp *interp,
const char *name, const char *version,
const void *clientData);
/* 1 */
EXTERN CONST84_RETURN char * Tcl_PkgRequireEx(Tcl_Interp *interp,
const char *name, const char *version,
int exact, void *clientDataPtr);
/* 2 */
EXTERN void Tcl_Panic(const char *format, ...) TCL_FORMAT_PRINTF(1, 2);
/* 3 */
EXTERN char * Tcl_Alloc(unsigned int size);
/* 4 */
EXTERN void Tcl_Free(char *ptr);
/* 5 */
EXTERN char * Tcl_Realloc(char *ptr, unsigned int size);
/* 6 */
EXTERN char * Tcl_DbCkalloc(unsigned int size, const char *file,
int line);
/* 7 */
EXTERN void Tcl_DbCkfree(char *ptr, const char *file, int line);
/* 8 */
EXTERN char * Tcl_DbCkrealloc(char *ptr, unsigned int size,
const char *file, int line);
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
/* 9 */
EXTERN void Tcl_CreateFileHandler(int fd, int mask,
Tcl_FileProc *proc, ClientData clientData);
#endif /* UNIX */
#ifdef MAC_OSX_TCL /* MACOSX */
/* 9 */
EXTERN void Tcl_CreateFileHandler(int fd, int mask,
Tcl_FileProc *proc, ClientData clientData);
#endif /* MACOSX */
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
/* 10 */
EXTERN void Tcl_DeleteFileHandler(int fd);
#endif /* UNIX */
#ifdef MAC_OSX_TCL /* MACOSX */
/* 10 */
EXTERN void Tcl_DeleteFileHandler(int fd);
#endif /* MACOSX */
/* 11 */
EXTERN void Tcl_SetTimer(const Tcl_Time *timePtr);
/* 12 */
EXTERN void Tcl_Sleep(int ms);
/* 13 */
EXTERN int Tcl_WaitForEvent(const Tcl_Time *timePtr);
/* 14 */
EXTERN int Tcl_AppendAllObjTypes(Tcl_Interp *interp,
Tcl_Obj *objPtr);
/* 15 */
EXTERN void Tcl_AppendStringsToObj(Tcl_Obj *objPtr, ...);
/* 16 */
EXTERN void Tcl_AppendToObj(Tcl_Obj *objPtr, const char *bytes,
int length);
/* 17 */
EXTERN Tcl_Obj * Tcl_ConcatObj(int objc, Tcl_Obj *const objv[]);
/* 18 */
EXTERN int Tcl_ConvertToType(Tcl_Interp *interp,
Tcl_Obj *objPtr, const Tcl_ObjType *typePtr);
/* 19 */
EXTERN void Tcl_DbDecrRefCount(Tcl_Obj *objPtr, const char *file,
int line);
/* 20 */
EXTERN void Tcl_DbIncrRefCount(Tcl_Obj *objPtr, const char *file,
int line);
/* 21 */
EXTERN int Tcl_DbIsShared(Tcl_Obj *objPtr, const char *file,
int line);
/* 22 */
EXTERN Tcl_Obj * Tcl_DbNewBooleanObj(int boolValue, const char *file,
int line);
/* 23 */
EXTERN Tcl_Obj * Tcl_DbNewByteArrayObj(const unsigned char *bytes,
int length, const char *file, int line);
/* 24 */
EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue,
const char *file, int line);
/* 25 */
EXTERN Tcl_Obj * Tcl_DbNewListObj(int objc, Tcl_Obj *const *objv,
const char *file, int line);
/* 26 */
EXTERN Tcl_Obj * Tcl_DbNewLongObj(long longValue, const char *file,
int line);
/* 27 */
EXTERN Tcl_Obj * Tcl_DbNewObj(const char *file, int line);
/* 28 */
EXTERN Tcl_Obj * Tcl_DbNewStringObj(const char *bytes, int length,
const char *file, int line);
/* 29 */
EXTERN Tcl_Obj * Tcl_DuplicateObj(Tcl_Obj *objPtr);
/* 30 */
EXTERN void TclFreeObj(Tcl_Obj *objPtr);
/* 31 */
EXTERN int Tcl_GetBoolean(Tcl_Interp *interp, const char *src,
int *boolPtr);
/* 32 */
EXTERN int Tcl_GetBooleanFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, int *boolPtr);
/* 33 */
EXTERN unsigned char * Tcl_GetByteArrayFromObj(Tcl_Obj *objPtr,
int *lengthPtr);
/* 34 */
EXTERN int Tcl_GetDouble(Tcl_Interp *interp, const char *src,
double *doublePtr);
/* 35 */
EXTERN int Tcl_GetDoubleFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, double *doublePtr);
/* 36 */
EXTERN int Tcl_GetIndexFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr,
CONST84 char *const *tablePtr,
const char *msg, int flags, int *indexPtr);
/* 37 */
EXTERN int Tcl_GetInt(Tcl_Interp *interp, const char *src,
int *intPtr);
/* 38 */
EXTERN int Tcl_GetIntFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, int *intPtr);
/* 39 */
EXTERN int Tcl_GetLongFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, long *longPtr);
/* 40 */
EXTERN CONST86 Tcl_ObjType * Tcl_GetObjType(const char *typeName);
/* 41 */
EXTERN char * Tcl_GetStringFromObj(Tcl_Obj *objPtr, int *lengthPtr);
/* 42 */
EXTERN void Tcl_InvalidateStringRep(Tcl_Obj *objPtr);
/* 43 */
EXTERN int Tcl_ListObjAppendList(Tcl_Interp *interp,
Tcl_Obj *listPtr, Tcl_Obj *elemListPtr);
/* 44 */
EXTERN int Tcl_ListObjAppendElement(Tcl_Interp *interp,
Tcl_Obj *listPtr, Tcl_Obj *objPtr);
/* 45 */
EXTERN int Tcl_ListObjGetElements(Tcl_Interp *interp,
Tcl_Obj *listPtr, int *objcPtr,
Tcl_Obj ***objvPtr);
/* 46 */
EXTERN int Tcl_ListObjIndex(Tcl_Interp *interp,
Tcl_Obj *listPtr, int index,
Tcl_Obj **objPtrPtr);
/* 47 */
EXTERN int Tcl_ListObjLength(Tcl_Interp *interp,
Tcl_Obj *listPtr, int *lengthPtr);
/* 48 */
EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp,
Tcl_Obj *listPtr, int first, int count,
int objc, Tcl_Obj *const objv[]);
/* 49 */
EXTERN Tcl_Obj * Tcl_NewBooleanObj(int boolValue);
/* 50 */
EXTERN Tcl_Obj * Tcl_NewByteArrayObj(const unsigned char *bytes,
int length);
/* 51 */
EXTERN Tcl_Obj * Tcl_NewDoubleObj(double doubleValue);
/* 52 */
EXTERN Tcl_Obj * Tcl_NewIntObj(int intValue);
/* 53 */
EXTERN Tcl_Obj * Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
/* 54 */
EXTERN Tcl_Obj * Tcl_NewLongObj(long longValue);
/* 55 */
EXTERN Tcl_Obj * Tcl_NewObj(void);
/* 56 */
EXTERN Tcl_Obj * Tcl_NewStringObj(const char *bytes, int length);
/* 57 */
EXTERN void Tcl_SetBooleanObj(Tcl_Obj *objPtr, int boolValue);
/* 58 */
EXTERN unsigned char * Tcl_SetByteArrayLength(Tcl_Obj *objPtr, int length);
/* 59 */
EXTERN void Tcl_SetByteArrayObj(Tcl_Obj *objPtr,
const unsigned char *bytes, int length);
/* 60 */
EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue);
/* 61 */
EXTERN void Tcl_SetIntObj(Tcl_Obj *objPtr, int intValue);
/* 62 */
EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, int objc,
Tcl_Obj *const objv[]);
/* 63 */
EXTERN void Tcl_SetLongObj(Tcl_Obj *objPtr, long longValue);
/* 64 */
EXTERN void Tcl_SetObjLength(Tcl_Obj *objPtr, int length);
/* 65 */
EXTERN void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes,
int length);
/* 66 */
EXTERN void Tcl_AddErrorInfo(Tcl_Interp *interp,
const char *message);
/* 67 */
EXTERN void Tcl_AddObjErrorInfo(Tcl_Interp *interp,
const char *message, int length);
/* 68 */
EXTERN void Tcl_AllowExceptions(Tcl_Interp *interp);
/* 69 */
EXTERN void Tcl_AppendElement(Tcl_Interp *interp,
const char *element);
/* 70 */
EXTERN void Tcl_AppendResult(Tcl_Interp *interp, ...);
/* 71 */
EXTERN Tcl_AsyncHandler Tcl_AsyncCreate(Tcl_AsyncProc *proc,
ClientData clientData);
/* 72 */
EXTERN void Tcl_AsyncDelete(Tcl_AsyncHandler async);
/* 73 */
EXTERN int Tcl_AsyncInvoke(Tcl_Interp *interp, int code);
/* 74 */
EXTERN void Tcl_AsyncMark(Tcl_AsyncHandler async);
/* 75 */
EXTERN int Tcl_AsyncReady(void);
/* 76 */
EXTERN void Tcl_BackgroundError(Tcl_Interp *interp);
/* 77 */
EXTERN char Tcl_Backslash(const char *src, int *readPtr);
/* 78 */
EXTERN int Tcl_BadChannelOption(Tcl_Interp *interp,
const char *optionName,
const char *optionList);
/* 79 */
EXTERN void Tcl_CallWhenDeleted(Tcl_Interp *interp,
Tcl_InterpDeleteProc *proc,
ClientData clientData);
/* 80 */
EXTERN void Tcl_CancelIdleCall(Tcl_IdleProc *idleProc,
ClientData clientData);
/* 81 */
EXTERN int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan);
/* 82 */
EXTERN int Tcl_CommandComplete(const char *cmd);
/* 83 */
EXTERN char * Tcl_Concat(int argc, CONST84 char *const *argv);
/* 84 */
EXTERN int Tcl_ConvertElement(const char *src, char *dst,
int flags);
/* 85 */
EXTERN int Tcl_ConvertCountedElement(const char *src,
int length, char *dst, int flags);
/* 86 */
EXTERN int Tcl_CreateAlias(Tcl_Interp *slave,
const char *slaveCmd, Tcl_Interp *target,
const char *targetCmd, int argc,
CONST84 char *const *argv);
/* 87 */
EXTERN int Tcl_CreateAliasObj(Tcl_Interp *slave,
const char *slaveCmd, Tcl_Interp *target,
const char *targetCmd, int objc,
Tcl_Obj *const objv[]);
/* 88 */
EXTERN Tcl_Channel Tcl_CreateChannel(const Tcl_ChannelType *typePtr,
const char *chanName,
ClientData instanceData, int mask);
/* 89 */
EXTERN void Tcl_CreateChannelHandler(Tcl_Channel chan, int mask,
Tcl_ChannelProc *proc, ClientData clientData);
/* 90 */
EXTERN void Tcl_CreateCloseHandler(Tcl_Channel chan,
Tcl_CloseProc *proc, ClientData clientData);
/* 91 */
EXTERN Tcl_Command Tcl_CreateCommand(Tcl_Interp *interp,
const char *cmdName, Tcl_CmdProc *proc,
ClientData clientData,
Tcl_CmdDeleteProc *deleteProc);
/* 92 */
EXTERN void Tcl_CreateEventSource(Tcl_EventSetupProc *setupProc,
Tcl_EventCheckProc *checkProc,
ClientData clientData);
/* 93 */
EXTERN void Tcl_CreateExitHandler(Tcl_ExitProc *proc,
ClientData clientData);
/* 94 */
EXTERN Tcl_Interp * Tcl_CreateInterp(void);
/* 95 */
EXTERN void Tcl_CreateMathFunc(Tcl_Interp *interp,
const char *name, int numArgs,
Tcl_ValueType *argTypes, Tcl_MathProc *proc,
ClientData clientData);
/* 96 */
EXTERN Tcl_Command Tcl_CreateObjCommand(Tcl_Interp *interp,
const char *cmdName, Tcl_ObjCmdProc *proc,
ClientData clientData,
Tcl_CmdDeleteProc *deleteProc);
/* 97 */
EXTERN Tcl_Interp * Tcl_CreateSlave(Tcl_Interp *interp,
const char *slaveName, int isSafe);
/* 98 */
EXTERN Tcl_TimerToken Tcl_CreateTimerHandler(int milliseconds,
Tcl_TimerProc *proc, ClientData clientData);
/* 99 */
EXTERN Tcl_Trace Tcl_CreateTrace(Tcl_Interp *interp, int level,
Tcl_CmdTraceProc *proc,
ClientData clientData);
/* 100 */
EXTERN void Tcl_DeleteAssocData(Tcl_Interp *interp,
const char *name);
/* 101 */
EXTERN void Tcl_DeleteChannelHandler(Tcl_Channel chan,
Tcl_ChannelProc *proc, ClientData clientData);
/* 102 */
EXTERN void Tcl_DeleteCloseHandler(Tcl_Channel chan,
Tcl_CloseProc *proc, ClientData clientData);
/* 103 */
EXTERN int Tcl_DeleteCommand(Tcl_Interp *interp,
const char *cmdName);
/* 104 */
EXTERN int Tcl_DeleteCommandFromToken(Tcl_Interp *interp,
Tcl_Command command);
/* 105 */
EXTERN void Tcl_DeleteEvents(Tcl_EventDeleteProc *proc,
ClientData clientData);
/* 106 */
EXTERN void Tcl_DeleteEventSource(Tcl_EventSetupProc *setupProc,
Tcl_EventCheckProc *checkProc,
ClientData clientData);
/* 107 */
EXTERN void Tcl_DeleteExitHandler(Tcl_ExitProc *proc,
ClientData clientData);
/* 108 */
EXTERN void Tcl_DeleteHashEntry(Tcl_HashEntry *entryPtr);
/* 109 */
EXTERN void Tcl_DeleteHashTable(Tcl_HashTable *tablePtr);
/* 110 */
EXTERN void Tcl_DeleteInterp(Tcl_Interp *interp);
/* 111 */
EXTERN void Tcl_DetachPids(int numPids, Tcl_Pid *pidPtr);
/* 112 */
EXTERN void Tcl_DeleteTimerHandler(Tcl_TimerToken token);
/* 113 */
EXTERN void Tcl_DeleteTrace(Tcl_Interp *interp, Tcl_Trace trace);
/* 114 */
EXTERN void Tcl_DontCallWhenDeleted(Tcl_Interp *interp,
Tcl_InterpDeleteProc *proc,
ClientData clientData);
/* 115 */
EXTERN int Tcl_DoOneEvent(int flags);
/* 116 */
EXTERN void Tcl_DoWhenIdle(Tcl_IdleProc *proc,
ClientData clientData);
/* 117 */
EXTERN char * Tcl_DStringAppend(Tcl_DString *dsPtr,
const char *bytes, int length);
/* 118 */
EXTERN char * Tcl_DStringAppendElement(Tcl_DString *dsPtr,
const char *element);
/* 119 */
EXTERN void Tcl_DStringEndSublist(Tcl_DString *dsPtr);
/* 120 */
EXTERN void Tcl_DStringFree(Tcl_DString *dsPtr);
/* 121 */
EXTERN void Tcl_DStringGetResult(Tcl_Interp *interp,
Tcl_DString *dsPtr);
/* 122 */
EXTERN void Tcl_DStringInit(Tcl_DString *dsPtr);
/* 123 */
EXTERN void Tcl_DStringResult(Tcl_Interp *interp,
Tcl_DString *dsPtr);
/* 124 */
EXTERN void Tcl_DStringSetLength(Tcl_DString *dsPtr, int length);
/* 125 */
EXTERN void Tcl_DStringStartSublist(Tcl_DString *dsPtr);
/* 126 */
EXTERN int Tcl_Eof(Tcl_Channel chan);
/* 127 */
EXTERN CONST84_RETURN char * Tcl_ErrnoId(void);
/* 128 */
EXTERN CONST84_RETURN char * Tcl_ErrnoMsg(int err);
/* 129 */
EXTERN int Tcl_Eval(Tcl_Interp *interp, const char *script);
/* 130 */
EXTERN int Tcl_EvalFile(Tcl_Interp *interp,
const char *fileName);
/* 131 */
EXTERN int Tcl_EvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
/* 132 */
EXTERN void Tcl_EventuallyFree(ClientData clientData,
Tcl_FreeProc *freeProc);
/* 133 */
EXTERN void Tcl_Exit(int status);
/* 134 */
EXTERN int Tcl_ExposeCommand(Tcl_Interp *interp,
const char *hiddenCmdToken,
const char *cmdName);
/* 135 */
EXTERN int Tcl_ExprBoolean(Tcl_Interp *interp, const char *expr,
int *ptr);
/* 136 */
EXTERN int Tcl_ExprBooleanObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, int *ptr);
/* 137 */
EXTERN int Tcl_ExprDouble(Tcl_Interp *interp, const char *expr,
double *ptr);
/* 138 */
EXTERN int Tcl_ExprDoubleObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, double *ptr);
/* 139 */
EXTERN int Tcl_ExprLong(Tcl_Interp *interp, const char *expr,
long *ptr);
/* 140 */
EXTERN int Tcl_ExprLongObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
long *ptr);
/* 141 */
EXTERN int Tcl_ExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
Tcl_Obj **resultPtrPtr);
/* 142 */
EXTERN int Tcl_ExprString(Tcl_Interp *interp, const char *expr);
/* 143 */
EXTERN void Tcl_Finalize(void);
/* 144 */
EXTERN void Tcl_FindExecutable(const char *argv0);
/* 145 */
EXTERN Tcl_HashEntry * Tcl_FirstHashEntry(Tcl_HashTable *tablePtr,
Tcl_HashSearch *searchPtr);
/* 146 */
EXTERN int Tcl_Flush(Tcl_Channel chan);
/* 147 */
EXTERN void Tcl_FreeResult(Tcl_Interp *interp);
/* 148 */
EXTERN int Tcl_GetAlias(Tcl_Interp *interp,
const char *slaveCmd,
Tcl_Interp **targetInterpPtr,
CONST84 char **targetCmdPtr, int *argcPtr,
CONST84 char ***argvPtr);
/* 149 */
EXTERN int Tcl_GetAliasObj(Tcl_Interp *interp,
const char *slaveCmd,
Tcl_Interp **targetInterpPtr,
CONST84 char **targetCmdPtr, int *objcPtr,
Tcl_Obj ***objv);
/* 150 */
EXTERN ClientData Tcl_GetAssocData(Tcl_Interp *interp,
const char *name,
Tcl_InterpDeleteProc **procPtr);
/* 151 */
EXTERN Tcl_Channel Tcl_GetChannel(Tcl_Interp *interp,
const char *chanName, int *modePtr);
/* 152 */
EXTERN int Tcl_GetChannelBufferSize(Tcl_Channel chan);
/* 153 */
EXTERN int Tcl_GetChannelHandle(Tcl_Channel chan, int direction,
ClientData *handlePtr);
/* 154 */
EXTERN ClientData Tcl_GetChannelInstanceData(Tcl_Channel chan);
/* 155 */
EXTERN int Tcl_GetChannelMode(Tcl_Channel chan);
/* 156 */
EXTERN CONST84_RETURN char * Tcl_GetChannelName(Tcl_Channel chan);
/* 157 */
EXTERN int Tcl_GetChannelOption(Tcl_Interp *interp,
Tcl_Channel chan, const char *optionName,
Tcl_DString *dsPtr);
/* 158 */
EXTERN CONST86 Tcl_ChannelType * Tcl_GetChannelType(Tcl_Channel chan);
/* 159 */
EXTERN int Tcl_GetCommandInfo(Tcl_Interp *interp,
const char *cmdName, Tcl_CmdInfo *infoPtr);
/* 160 */
EXTERN CONST84_RETURN char * Tcl_GetCommandName(Tcl_Interp *interp,
Tcl_Command command);
/* 161 */
EXTERN int Tcl_GetErrno(void);
/* 162 */
EXTERN CONST84_RETURN char * Tcl_GetHostName(void);
/* 163 */
EXTERN int Tcl_GetInterpPath(Tcl_Interp *askInterp,
Tcl_Interp *slaveInterp);
/* 164 */
EXTERN Tcl_Interp * Tcl_GetMaster(Tcl_Interp *interp);
/* 165 */
EXTERN const char * Tcl_GetNameOfExecutable(void);
/* 166 */
EXTERN Tcl_Obj * Tcl_GetObjResult(Tcl_Interp *interp);
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
/* 167 */
EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp,
const char *chanID, int forWriting,
int checkUsage, ClientData *filePtr);
#endif /* UNIX */
#ifdef MAC_OSX_TCL /* MACOSX */
/* 167 */
EXTERN int Tcl_GetOpenFile(Tcl_Interp *interp,
const char *chanID, int forWriting,
int checkUsage, ClientData *filePtr);
#endif /* MACOSX */
/* 168 */
EXTERN Tcl_PathType Tcl_GetPathType(const char *path);
/* 169 */
EXTERN int Tcl_Gets(Tcl_Channel chan, Tcl_DString *dsPtr);
/* 170 */
EXTERN int Tcl_GetsObj(Tcl_Channel chan, Tcl_Obj *objPtr);
/* 171 */
EXTERN int Tcl_GetServiceMode(void);
/* 172 */
EXTERN Tcl_Interp * Tcl_GetSlave(Tcl_Interp *interp,
const char *slaveName);
/* 173 */
EXTERN Tcl_Channel Tcl_GetStdChannel(int type);
/* 174 */
EXTERN CONST84_RETURN char * Tcl_GetStringResult(Tcl_Interp *interp);
/* 175 */
EXTERN CONST84_RETURN char * Tcl_GetVar(Tcl_Interp *interp,
const char *varName, int flags);
/* 176 */
EXTERN CONST84_RETURN char * Tcl_GetVar2(Tcl_Interp *interp,
const char *part1, const char *part2,
int flags);
/* 177 */
EXTERN int Tcl_GlobalEval(Tcl_Interp *interp,
const char *command);
/* 178 */
EXTERN int Tcl_GlobalEvalObj(Tcl_Interp *interp,
Tcl_Obj *objPtr);
/* 179 */
EXTERN int Tcl_HideCommand(Tcl_Interp *interp,
const char *cmdName,
const char *hiddenCmdToken);
/* 180 */
EXTERN int Tcl_Init(Tcl_Interp *interp);
/* 181 */
EXTERN void Tcl_InitHashTable(Tcl_HashTable *tablePtr,
int keyType);
/* 182 */
EXTERN int Tcl_InputBlocked(Tcl_Channel chan);
/* 183 */
EXTERN int Tcl_InputBuffered(Tcl_Channel chan);
/* 184 */
EXTERN int Tcl_InterpDeleted(Tcl_Interp *interp);
/* 185 */
EXTERN int Tcl_IsSafe(Tcl_Interp *interp);
/* 186 */
EXTERN char * Tcl_JoinPath(int argc, CONST84 char *const *argv,
Tcl_DString *resultPtr);
/* 187 */
EXTERN int Tcl_LinkVar(Tcl_Interp *interp, const char *varName,
char *addr, int type);
/* Slot 188 is reserved */
/* 189 */
EXTERN Tcl_Channel Tcl_MakeFileChannel(ClientData handle, int mode);
/* 190 */
EXTERN int Tcl_MakeSafe(Tcl_Interp *interp);
/* 191 */
EXTERN Tcl_Channel Tcl_MakeTcpClientChannel(ClientData tcpSocket);
/* 192 */
EXTERN char * Tcl_Merge(int argc, CONST84 char *const *argv);
/* 193 */
EXTERN Tcl_HashEntry * Tcl_NextHashEntry(Tcl_HashSearch *searchPtr);
/* 194 */
EXTERN void Tcl_NotifyChannel(Tcl_Channel channel, int mask);
/* 195 */
EXTERN Tcl_Obj * Tcl_ObjGetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, int flags);
/* 196 */
EXTERN Tcl_Obj * Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr,
int flags);
/* 197 */
EXTERN Tcl_Channel Tcl_OpenCommandChannel(Tcl_Interp *interp, int argc,
CONST84 char **argv, int flags);
/* 198 */
EXTERN Tcl_Channel Tcl_OpenFileChannel(Tcl_Interp *interp,
const char *fileName, const char *modeString,
int permissions);
/* 199 */
EXTERN Tcl_Channel Tcl_OpenTcpClient(Tcl_Interp *interp, int port,
const char *address, const char *myaddr,
int myport, int async);
/* 200 */
EXTERN Tcl_Channel Tcl_OpenTcpServer(Tcl_Interp *interp, int port,
const char *host,
Tcl_TcpAcceptProc *acceptProc,
ClientData callbackData);
/* 201 */
EXTERN void Tcl_Preserve(ClientData data);
/* 202 */
EXTERN void Tcl_PrintDouble(Tcl_Interp *interp, double value,
char *dst);
/* 203 */
EXTERN int Tcl_PutEnv(const char *assignment);
/* 204 */
EXTERN CONST84_RETURN char * Tcl_PosixError(Tcl_Interp *interp);
/* 205 */
EXTERN void Tcl_QueueEvent(Tcl_Event *evPtr,
Tcl_QueuePosition position);
/* 206 */
EXTERN int Tcl_Read(Tcl_Channel chan, char *bufPtr, int toRead);
/* 207 */
EXTERN void Tcl_ReapDetachedProcs(void);
/* 208 */
EXTERN int Tcl_RecordAndEval(Tcl_Interp *interp,
const char *cmd, int flags);
/* 209 */
EXTERN int Tcl_RecordAndEvalObj(Tcl_Interp *interp,
Tcl_Obj *cmdPtr, int flags);
/* 210 */
EXTERN void Tcl_RegisterChannel(Tcl_Interp *interp,
Tcl_Channel chan);
/* 211 */
EXTERN void Tcl_RegisterObjType(const Tcl_ObjType *typePtr);
/* 212 */
EXTERN Tcl_RegExp Tcl_RegExpCompile(Tcl_Interp *interp,
const char *pattern);
/* 213 */
EXTERN int Tcl_RegExpExec(Tcl_Interp *interp, Tcl_RegExp regexp,
const char *text, const char *start);
/* 214 */
EXTERN int Tcl_RegExpMatch(Tcl_Interp *interp, const char *text,
const char *pattern);
/* 215 */
EXTERN void Tcl_RegExpRange(Tcl_RegExp regexp, int index,
CONST84 char **startPtr,
CONST84 char **endPtr);
/* 216 */
EXTERN void Tcl_Release(ClientData clientData);
/* 217 */
EXTERN void Tcl_ResetResult(Tcl_Interp *interp);
/* 218 */
EXTERN int Tcl_ScanElement(const char *src, int *flagPtr);
/* 219 */
EXTERN int Tcl_ScanCountedElement(const char *src, int length,
int *flagPtr);
/* 220 */
EXTERN int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode);
/* 221 */
EXTERN int Tcl_ServiceAll(void);
/* 222 */
EXTERN int Tcl_ServiceEvent(int flags);
/* 223 */
EXTERN void Tcl_SetAssocData(Tcl_Interp *interp,
const char *name, Tcl_InterpDeleteProc *proc,
ClientData clientData);
/* 224 */
EXTERN void Tcl_SetChannelBufferSize(Tcl_Channel chan, int sz);
/* 225 */
EXTERN int Tcl_SetChannelOption(Tcl_Interp *interp,
Tcl_Channel chan, const char *optionName,
const char *newValue);
/* 226 */
EXTERN int Tcl_SetCommandInfo(Tcl_Interp *interp,
const char *cmdName,
const Tcl_CmdInfo *infoPtr);
/* 227 */
EXTERN void Tcl_SetErrno(int err);
/* 228 */
EXTERN void Tcl_SetErrorCode(Tcl_Interp *interp, ...);
/* 229 */
EXTERN void Tcl_SetMaxBlockTime(const Tcl_Time *timePtr);
/* 230 */
EXTERN void Tcl_SetPanicProc(Tcl_PanicProc *panicProc);
/* 231 */
EXTERN int Tcl_SetRecursionLimit(Tcl_Interp *interp, int depth);
/* 232 */
EXTERN void Tcl_SetResult(Tcl_Interp *interp, char *result,
Tcl_FreeProc *freeProc);
/* 233 */
EXTERN int Tcl_SetServiceMode(int mode);
/* 234 */
EXTERN void Tcl_SetObjErrorCode(Tcl_Interp *interp,
Tcl_Obj *errorObjPtr);
/* 235 */
EXTERN void Tcl_SetObjResult(Tcl_Interp *interp,
Tcl_Obj *resultObjPtr);
/* 236 */
EXTERN void Tcl_SetStdChannel(Tcl_Channel channel, int type);
/* 237 */
EXTERN CONST84_RETURN char * Tcl_SetVar(Tcl_Interp *interp,
const char *varName, const char *newValue,
int flags);
/* 238 */
EXTERN CONST84_RETURN char * Tcl_SetVar2(Tcl_Interp *interp,
const char *part1, const char *part2,
const char *newValue, int flags);
/* 239 */
EXTERN CONST84_RETURN char * Tcl_SignalId(int sig);
/* 240 */
EXTERN CONST84_RETURN char * Tcl_SignalMsg(int sig);
/* 241 */
EXTERN void Tcl_SourceRCFile(Tcl_Interp *interp);
/* 242 */
EXTERN int Tcl_SplitList(Tcl_Interp *interp,
const char *listStr, int *argcPtr,
CONST84 char ***argvPtr);
/* 243 */
EXTERN void Tcl_SplitPath(const char *path, int *argcPtr,
CONST84 char ***argvPtr);
/* 244 */
EXTERN void Tcl_StaticPackage(Tcl_Interp *interp,
const char *pkgName,
Tcl_PackageInitProc *initProc,
Tcl_PackageInitProc *safeInitProc);
/* 245 */
EXTERN int Tcl_StringMatch(const char *str, const char *pattern);
/* 246 */
EXTERN int Tcl_TellOld(Tcl_Channel chan);
/* 247 */
EXTERN int Tcl_TraceVar(Tcl_Interp *interp, const char *varName,
int flags, Tcl_VarTraceProc *proc,
ClientData clientData);
/* 248 */
EXTERN int Tcl_TraceVar2(Tcl_Interp *interp, const char *part1,
const char *part2, int flags,
Tcl_VarTraceProc *proc,
ClientData clientData);
/* 249 */
EXTERN char * Tcl_TranslateFileName(Tcl_Interp *interp,
const char *name, Tcl_DString *bufferPtr);
/* 250 */
EXTERN int Tcl_Ungets(Tcl_Channel chan, const char *str,
int len, int atHead);
/* 251 */
EXTERN void Tcl_UnlinkVar(Tcl_Interp *interp,
const char *varName);
/* 252 */
EXTERN int Tcl_UnregisterChannel(Tcl_Interp *interp,
Tcl_Channel chan);
/* 253 */
EXTERN int Tcl_UnsetVar(Tcl_Interp *interp, const char *varName,
int flags);
/* 254 */
EXTERN int Tcl_UnsetVar2(Tcl_Interp *interp, const char *part1,
const char *part2, int flags);
/* 255 */
EXTERN void Tcl_UntraceVar(Tcl_Interp *interp,
const char *varName, int flags,
Tcl_VarTraceProc *proc,
ClientData clientData);
/* 256 */
EXTERN void Tcl_UntraceVar2(Tcl_Interp *interp,
const char *part1, const char *part2,
int flags, Tcl_VarTraceProc *proc,
ClientData clientData);
/* 257 */
EXTERN void Tcl_UpdateLinkedVar(Tcl_Interp *interp,
const char *varName);
/* 258 */
EXTERN int Tcl_UpVar(Tcl_Interp *interp, const char *frameName,
const char *varName, const char *localName,
int flags);
/* 259 */
EXTERN int Tcl_UpVar2(Tcl_Interp *interp, const char *frameName,
const char *part1, const char *part2,
const char *localName, int flags);
/* 260 */
EXTERN int Tcl_VarEval(Tcl_Interp *interp, ...);
/* 261 */
EXTERN ClientData Tcl_VarTraceInfo(Tcl_Interp *interp,
const char *varName, int flags,
Tcl_VarTraceProc *procPtr,
ClientData prevClientData);
/* 262 */
EXTERN ClientData Tcl_VarTraceInfo2(Tcl_Interp *interp,
const char *part1, const char *part2,
int flags, Tcl_VarTraceProc *procPtr,
ClientData prevClientData);
/* 263 */
EXTERN int Tcl_Write(Tcl_Channel chan, const char *s, int slen);
/* 264 */
EXTERN void Tcl_WrongNumArgs(Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[], const char *message);
/* 265 */
EXTERN int Tcl_DumpActiveMemory(const char *fileName);
/* 266 */
EXTERN void Tcl_ValidateAllMemory(const char *file, int line);
/* 267 */
EXTERN void Tcl_AppendResultVA(Tcl_Interp *interp,
va_list argList);
/* 268 */
EXTERN void Tcl_AppendStringsToObjVA(Tcl_Obj *objPtr,
va_list argList);
/* 269 */
EXTERN char * Tcl_HashStats(Tcl_HashTable *tablePtr);
/* 270 */
EXTERN CONST84_RETURN char * Tcl_ParseVar(Tcl_Interp *interp,
const char *start, CONST84 char **termPtr);
/* 271 */
EXTERN CONST84_RETURN char * Tcl_PkgPresent(Tcl_Interp *interp,
const char *name, const char *version,
int exact);
/* 272 */
EXTERN CONST84_RETURN char * Tcl_PkgPresentEx(Tcl_Interp *interp,
const char *name, const char *version,
int exact, void *clientDataPtr);
/* 273 */
EXTERN int Tcl_PkgProvide(Tcl_Interp *interp, const char *name,
const char *version);
/* 274 */
EXTERN CONST84_RETURN char * Tcl_PkgRequire(Tcl_Interp *interp,
const char *name, const char *version,
int exact);
/* 275 */
EXTERN void Tcl_SetErrorCodeVA(Tcl_Interp *interp,
va_list argList);
/* 276 */
EXTERN int Tcl_VarEvalVA(Tcl_Interp *interp, va_list argList);
/* 277 */
EXTERN Tcl_Pid Tcl_WaitPid(Tcl_Pid pid, int *statPtr, int options);
/* 278 */
EXTERN void Tcl_PanicVA(const char *format, va_list argList);
/* 279 */
EXTERN void Tcl_GetVersion(int *major, int *minor,
int *patchLevel, int *type);
/* 280 */
EXTERN void Tcl_InitMemory(Tcl_Interp *interp);
/* 281 */
EXTERN Tcl_Channel Tcl_StackChannel(Tcl_Interp *interp,
const Tcl_ChannelType *typePtr,
ClientData instanceData, int mask,
Tcl_Channel prevChan);
/* 282 */
EXTERN int Tcl_UnstackChannel(Tcl_Interp *interp,
Tcl_Channel chan);
/* 283 */
EXTERN Tcl_Channel Tcl_GetStackedChannel(Tcl_Channel chan);
/* 284 */
EXTERN void Tcl_SetMainLoop(Tcl_MainLoopProc *proc);
/* Slot 285 is reserved */
/* 286 */
EXTERN void Tcl_AppendObjToObj(Tcl_Obj *objPtr,
Tcl_Obj *appendObjPtr);
/* 287 */
EXTERN Tcl_Encoding Tcl_CreateEncoding(const Tcl_EncodingType *typePtr);
/* 288 */
EXTERN void Tcl_CreateThreadExitHandler(Tcl_ExitProc *proc,
ClientData clientData);
/* 289 */
EXTERN void Tcl_DeleteThreadExitHandler(Tcl_ExitProc *proc,
ClientData clientData);
/* 290 */
EXTERN void Tcl_DiscardResult(Tcl_SavedResult *statePtr);
/* 291 */
EXTERN int Tcl_EvalEx(Tcl_Interp *interp, const char *script,
int numBytes, int flags);
/* 292 */
EXTERN int Tcl_EvalObjv(Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[], int flags);
/* 293 */
EXTERN int Tcl_EvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr,
int flags);
/* 294 */
EXTERN void Tcl_ExitThread(int status);
/* 295 */
EXTERN int Tcl_ExternalToUtf(Tcl_Interp *interp,
Tcl_Encoding encoding, const char *src,
int srcLen, int flags,
Tcl_EncodingState *statePtr, char *dst,
int dstLen, int *srcReadPtr,
int *dstWrotePtr, int *dstCharsPtr);
/* 296 */
EXTERN char * Tcl_ExternalToUtfDString(Tcl_Encoding encoding,
const char *src, int srcLen,
Tcl_DString *dsPtr);
/* 297 */
EXTERN void Tcl_FinalizeThread(void);
/* 298 */
EXTERN void Tcl_FinalizeNotifier(ClientData clientData);
/* 299 */
EXTERN void Tcl_FreeEncoding(Tcl_Encoding encoding);
/* 300 */
EXTERN Tcl_ThreadId Tcl_GetCurrentThread(void);
/* 301 */
EXTERN Tcl_Encoding Tcl_GetEncoding(Tcl_Interp *interp, const char *name);
/* 302 */
EXTERN CONST84_RETURN char * Tcl_GetEncodingName(Tcl_Encoding encoding);
/* 303 */
EXTERN void Tcl_GetEncodingNames(Tcl_Interp *interp);
/* 304 */
EXTERN int Tcl_GetIndexFromObjStruct(Tcl_Interp *interp,
Tcl_Obj *objPtr, const void *tablePtr,
int offset, const char *msg, int flags,
int *indexPtr);
/* 305 */
EXTERN void * Tcl_GetThreadData(Tcl_ThreadDataKey *keyPtr,
int size);
/* 306 */
EXTERN Tcl_Obj * Tcl_GetVar2Ex(Tcl_Interp *interp, const char *part1,
const char *part2, int flags);
/* 307 */
EXTERN ClientData Tcl_InitNotifier(void);
/* 308 */
EXTERN void Tcl_MutexLock(Tcl_Mutex *mutexPtr);
/* 309 */
EXTERN void Tcl_MutexUnlock(Tcl_Mutex *mutexPtr);
/* 310 */
EXTERN void Tcl_ConditionNotify(Tcl_Condition *condPtr);
/* 311 */
EXTERN void Tcl_ConditionWait(Tcl_Condition *condPtr,
Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr);
/* 312 */
EXTERN int Tcl_NumUtfChars(const char *src, int length);
/* 313 */
EXTERN int Tcl_ReadChars(Tcl_Channel channel, Tcl_Obj *objPtr,
int charsToRead, int appendFlag);
/* 314 */
EXTERN void Tcl_RestoreResult(Tcl_Interp *interp,
Tcl_SavedResult *statePtr);
/* 315 */
EXTERN void Tcl_SaveResult(Tcl_Interp *interp,
Tcl_SavedResult *statePtr);
/* 316 */
EXTERN int Tcl_SetSystemEncoding(Tcl_Interp *interp,
const char *name);
/* 317 */
EXTERN Tcl_Obj * Tcl_SetVar2Ex(Tcl_Interp *interp, const char *part1,
const char *part2, Tcl_Obj *newValuePtr,
int flags);
/* 318 */
EXTERN void Tcl_ThreadAlert(Tcl_ThreadId threadId);
/* 319 */
EXTERN void Tcl_ThreadQueueEvent(Tcl_ThreadId threadId,
Tcl_Event *evPtr, Tcl_QueuePosition position);
/* 320 */
EXTERN Tcl_UniChar Tcl_UniCharAtIndex(const char *src, int index);
/* 321 */
EXTERN Tcl_UniChar Tcl_UniCharToLower(int ch);
/* 322 */
EXTERN Tcl_UniChar Tcl_UniCharToTitle(int ch);
/* 323 */
EXTERN Tcl_UniChar Tcl_UniCharToUpper(int ch);
/* 324 */
EXTERN int Tcl_UniCharToUtf(int ch, char *buf);
/* 325 */
EXTERN CONST84_RETURN char * Tcl_UtfAtIndex(const char *src, int index);
/* 326 */
EXTERN int Tcl_UtfCharComplete(const char *src, int length);
/* 327 */
EXTERN int Tcl_UtfBackslash(const char *src, int *readPtr,
char *dst);
/* 328 */
EXTERN CONST84_RETURN char * Tcl_UtfFindFirst(const char *src, int ch);
/* 329 */
EXTERN CONST84_RETURN char * Tcl_UtfFindLast(const char *src, int ch);
/* 330 */
EXTERN CONST84_RETURN char * Tcl_UtfNext(const char *src);
/* 331 */
EXTERN CONST84_RETURN char * Tcl_UtfPrev(const char *src, const char *start);
/* 332 */
EXTERN int Tcl_UtfToExternal(Tcl_Interp *interp,
Tcl_Encoding encoding, const char *src,
int srcLen, int flags,
Tcl_EncodingState *statePtr, char *dst,
int dstLen, int *srcReadPtr,
int *dstWrotePtr, int *dstCharsPtr);
/* 333 */
EXTERN char * Tcl_UtfToExternalDString(Tcl_Encoding encoding,
const char *src, int srcLen,
Tcl_DString *dsPtr);
/* 334 */
EXTERN int Tcl_UtfToLower(char *src);
/* 335 */
EXTERN int Tcl_UtfToTitle(char *src);
/* 336 */
EXTERN int Tcl_UtfToUniChar(const char *src, Tcl_UniChar *chPtr);
/* 337 */
EXTERN int Tcl_UtfToUpper(char *src);
/* 338 */
EXTERN int Tcl_WriteChars(Tcl_Channel chan, const char *src,
int srcLen);
/* 339 */
EXTERN int Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr);
/* 340 */
EXTERN char * Tcl_GetString(Tcl_Obj *objPtr);
/* 341 */
EXTERN CONST84_RETURN char * Tcl_GetDefaultEncodingDir(void);
/* 342 */
EXTERN void Tcl_SetDefaultEncodingDir(const char *path);
/* 343 */
EXTERN void Tcl_AlertNotifier(ClientData clientData);
/* 344 */
EXTERN void Tcl_ServiceModeHook(int mode);
/* 345 */
EXTERN int Tcl_UniCharIsAlnum(int ch);
/* 346 */
EXTERN int Tcl_UniCharIsAlpha(int ch);
/* 347 */
EXTERN int Tcl_UniCharIsDigit(int ch);
/* 348 */
EXTERN int Tcl_UniCharIsLower(int ch);
/* 349 */
EXTERN int Tcl_UniCharIsSpace(int ch);
/* 350 */
EXTERN int Tcl_UniCharIsUpper(int ch);
/* 351 */
EXTERN int Tcl_UniCharIsWordChar(int ch);
/* 352 */
EXTERN int Tcl_UniCharLen(const Tcl_UniChar *uniStr);
/* 353 */
EXTERN int Tcl_UniCharNcmp(const Tcl_UniChar *ucs,
const Tcl_UniChar *uct,
unsigned long numChars);
/* 354 */
EXTERN char * Tcl_UniCharToUtfDString(const Tcl_UniChar *uniStr,
int uniLength, Tcl_DString *dsPtr);
/* 355 */
EXTERN Tcl_UniChar * Tcl_UtfToUniCharDString(const char *src, int length,
Tcl_DString *dsPtr);
/* 356 */
EXTERN Tcl_RegExp Tcl_GetRegExpFromObj(Tcl_Interp *interp,
Tcl_Obj *patObj, int flags);
/* 357 */
EXTERN Tcl_Obj * Tcl_EvalTokens(Tcl_Interp *interp,
Tcl_Token *tokenPtr, int count);
/* 358 */
EXTERN void Tcl_FreeParse(Tcl_Parse *parsePtr);
/* 359 */
EXTERN void Tcl_LogCommandInfo(Tcl_Interp *interp,
const char *script, const char *command,
int length);
/* 360 */
EXTERN int Tcl_ParseBraces(Tcl_Interp *interp,
const char *start, int numBytes,
Tcl_Parse *parsePtr, int append,
CONST84 char **termPtr);
/* 361 */
EXTERN int Tcl_ParseCommand(Tcl_Interp *interp,
const char *start, int numBytes, int nested,
Tcl_Parse *parsePtr);
/* 362 */
EXTERN int Tcl_ParseExpr(Tcl_Interp *interp, const char *start,
int numBytes, Tcl_Parse *parsePtr);
/* 363 */
EXTERN int Tcl_ParseQuotedString(Tcl_Interp *interp,
const char *start, int numBytes,
Tcl_Parse *parsePtr, int append,
CONST84 char **termPtr);
/* 364 */
EXTERN int Tcl_ParseVarName(Tcl_Interp *interp,
const char *start, int numBytes,
Tcl_Parse *parsePtr, int append);
/* 365 */
EXTERN char * Tcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr);
/* 366 */
EXTERN int Tcl_Chdir(const char *dirName);
/* 367 */
EXTERN int Tcl_Access(const char *path, int mode);
/* 368 */
EXTERN int Tcl_Stat(const char *path, struct stat *bufPtr);
/* 369 */
EXTERN int Tcl_UtfNcmp(const char *s1, const char *s2,
unsigned long n);
/* 370 */
EXTERN int Tcl_UtfNcasecmp(const char *s1, const char *s2,
unsigned long n);
/* 371 */
EXTERN int Tcl_StringCaseMatch(const char *str,
const char *pattern, int nocase);
/* 372 */
EXTERN int Tcl_UniCharIsControl(int ch);
/* 373 */
EXTERN int Tcl_UniCharIsGraph(int ch);
/* 374 */
EXTERN int Tcl_UniCharIsPrint(int ch);
/* 375 */
EXTERN int Tcl_UniCharIsPunct(int ch);
/* 376 */
EXTERN int Tcl_RegExpExecObj(Tcl_Interp *interp,
Tcl_RegExp regexp, Tcl_Obj *textObj,
int offset, int nmatches, int flags);
/* 377 */
EXTERN void Tcl_RegExpGetInfo(Tcl_RegExp regexp,
Tcl_RegExpInfo *infoPtr);
/* 378 */
EXTERN Tcl_Obj * Tcl_NewUnicodeObj(const Tcl_UniChar *unicode,
int numChars);
/* 379 */
EXTERN void Tcl_SetUnicodeObj(Tcl_Obj *objPtr,
const Tcl_UniChar *unicode, int numChars);
/* 380 */
EXTERN int Tcl_GetCharLength(Tcl_Obj *objPtr);
/* 381 */
EXTERN Tcl_UniChar Tcl_GetUniChar(Tcl_Obj *objPtr, int index);
/* 382 */
EXTERN Tcl_UniChar * Tcl_GetUnicode(Tcl_Obj *objPtr);
/* 383 */
EXTERN Tcl_Obj * Tcl_GetRange(Tcl_Obj *objPtr, int first, int last);
/* 384 */
EXTERN void Tcl_AppendUnicodeToObj(Tcl_Obj *objPtr,
const Tcl_UniChar *unicode, int length);
/* 385 */
EXTERN int Tcl_RegExpMatchObj(Tcl_Interp *interp,
Tcl_Obj *textObj, Tcl_Obj *patternObj);
/* 386 */
EXTERN void Tcl_SetNotifier(Tcl_NotifierProcs *notifierProcPtr);
/* 387 */
EXTERN Tcl_Mutex * Tcl_GetAllocMutex(void);
/* 388 */
EXTERN int Tcl_GetChannelNames(Tcl_Interp *interp);
/* 389 */
EXTERN int Tcl_GetChannelNamesEx(Tcl_Interp *interp,
const char *pattern);
/* 390 */
EXTERN int Tcl_ProcObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
/* 391 */
EXTERN void Tcl_ConditionFinalize(Tcl_Condition *condPtr);
/* 392 */
EXTERN void Tcl_MutexFinalize(Tcl_Mutex *mutex);
/* 393 */
EXTERN int Tcl_CreateThread(Tcl_ThreadId *idPtr,
Tcl_ThreadCreateProc *proc,
ClientData clientData, int stackSize,
int flags);
/* 394 */
EXTERN int Tcl_ReadRaw(Tcl_Channel chan, char *dst,
int bytesToRead);
/* 395 */
EXTERN int Tcl_WriteRaw(Tcl_Channel chan, const char *src,
int srcLen);
/* 396 */
EXTERN Tcl_Channel Tcl_GetTopChannel(Tcl_Channel chan);
/* 397 */
EXTERN int Tcl_ChannelBuffered(Tcl_Channel chan);
/* 398 */
EXTERN CONST84_RETURN char * Tcl_ChannelName(
const Tcl_ChannelType *chanTypePtr);
/* 399 */
EXTERN Tcl_ChannelTypeVersion Tcl_ChannelVersion(
const Tcl_ChannelType *chanTypePtr);
/* 400 */
EXTERN Tcl_DriverBlockModeProc * Tcl_ChannelBlockModeProc(
const Tcl_ChannelType *chanTypePtr);
/* 401 */
EXTERN Tcl_DriverCloseProc * Tcl_ChannelCloseProc(
const Tcl_ChannelType *chanTypePtr);
/* 402 */
EXTERN Tcl_DriverClose2Proc * Tcl_ChannelClose2Proc(
const Tcl_ChannelType *chanTypePtr);
/* 403 */
EXTERN Tcl_DriverInputProc * Tcl_ChannelInputProc(
const Tcl_ChannelType *chanTypePtr);
/* 404 */
EXTERN Tcl_DriverOutputProc * Tcl_ChannelOutputProc(
const Tcl_ChannelType *chanTypePtr);
/* 405 */
EXTERN Tcl_DriverSeekProc * Tcl_ChannelSeekProc(
const Tcl_ChannelType *chanTypePtr);
/* 406 */
EXTERN Tcl_DriverSetOptionProc * Tcl_ChannelSetOptionProc(
const Tcl_ChannelType *chanTypePtr);
/* 407 */
EXTERN Tcl_DriverGetOptionProc * Tcl_ChannelGetOptionProc(
const Tcl_ChannelType *chanTypePtr);
/* 408 */
EXTERN Tcl_DriverWatchProc * Tcl_ChannelWatchProc(
const Tcl_ChannelType *chanTypePtr);
/* 409 */
EXTERN Tcl_DriverGetHandleProc * Tcl_ChannelGetHandleProc(
const Tcl_ChannelType *chanTypePtr);
/* 410 */
EXTERN Tcl_DriverFlushProc * Tcl_ChannelFlushProc(
const Tcl_ChannelType *chanTypePtr);
/* 411 */
EXTERN Tcl_DriverHandlerProc * Tcl_ChannelHandlerProc(
const Tcl_ChannelType *chanTypePtr);
/* 412 */
EXTERN int Tcl_JoinThread(Tcl_ThreadId threadId, int *result);
/* 413 */
EXTERN int Tcl_IsChannelShared(Tcl_Channel channel);
/* 414 */
EXTERN int Tcl_IsChannelRegistered(Tcl_Interp *interp,
Tcl_Channel channel);
/* 415 */
EXTERN void Tcl_CutChannel(Tcl_Channel channel);
/* 416 */
EXTERN void Tcl_SpliceChannel(Tcl_Channel channel);
/* 417 */
EXTERN void Tcl_ClearChannelHandlers(Tcl_Channel channel);
/* 418 */
EXTERN int Tcl_IsChannelExisting(const char *channelName);
/* 419 */
EXTERN int Tcl_UniCharNcasecmp(const Tcl_UniChar *ucs,
const Tcl_UniChar *uct,
unsigned long numChars);
/* 420 */
EXTERN int Tcl_UniCharCaseMatch(const Tcl_UniChar *uniStr,
const Tcl_UniChar *uniPattern, int nocase);
/* 421 */
EXTERN Tcl_HashEntry * Tcl_FindHashEntry(Tcl_HashTable *tablePtr,
const void *key);
/* 422 */
EXTERN Tcl_HashEntry * Tcl_CreateHashEntry(Tcl_HashTable *tablePtr,
const void *key, int *newPtr);
/* 423 */
EXTERN void Tcl_InitCustomHashTable(Tcl_HashTable *tablePtr,
int keyType, const Tcl_HashKeyType *typePtr);
/* 424 */
EXTERN void Tcl_InitObjHashTable(Tcl_HashTable *tablePtr);
/* 425 */
EXTERN ClientData Tcl_CommandTraceInfo(Tcl_Interp *interp,
const char *varName, int flags,
Tcl_CommandTraceProc *procPtr,
ClientData prevClientData);
/* 426 */
EXTERN int Tcl_TraceCommand(Tcl_Interp *interp,
const char *varName, int flags,
Tcl_CommandTraceProc *proc,
ClientData clientData);
/* 427 */
EXTERN void Tcl_UntraceCommand(Tcl_Interp *interp,
const char *varName, int flags,
Tcl_CommandTraceProc *proc,
ClientData clientData);
/* 428 */
EXTERN char * Tcl_AttemptAlloc(unsigned int size);
/* 429 */
EXTERN char * Tcl_AttemptDbCkalloc(unsigned int size,
const char *file, int line);
/* 430 */
EXTERN char * Tcl_AttemptRealloc(char *ptr, unsigned int size);
/* 431 */
EXTERN char * Tcl_AttemptDbCkrealloc(char *ptr, unsigned int size,
const char *file, int line);
/* 432 */
EXTERN int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, int length);
/* 433 */
EXTERN Tcl_ThreadId Tcl_GetChannelThread(Tcl_Channel channel);
/* 434 */
EXTERN Tcl_UniChar * Tcl_GetUnicodeFromObj(Tcl_Obj *objPtr,
int *lengthPtr);
/* 435 */
EXTERN int Tcl_GetMathFuncInfo(Tcl_Interp *interp,
const char *name, int *numArgsPtr,
Tcl_ValueType **argTypesPtr,
Tcl_MathProc **procPtr,
ClientData *clientDataPtr);
/* 436 */
EXTERN Tcl_Obj * Tcl_ListMathFuncs(Tcl_Interp *interp,
const char *pattern);
/* 437 */
EXTERN Tcl_Obj * Tcl_SubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
int flags);
/* 438 */
EXTERN int Tcl_DetachChannel(Tcl_Interp *interp,
Tcl_Channel channel);
/* 439 */
EXTERN int Tcl_IsStandardChannel(Tcl_Channel channel);
/* 440 */
EXTERN int Tcl_FSCopyFile(Tcl_Obj *srcPathPtr,
Tcl_Obj *destPathPtr);
/* 441 */
EXTERN int Tcl_FSCopyDirectory(Tcl_Obj *srcPathPtr,
Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr);
/* 442 */
EXTERN int Tcl_FSCreateDirectory(Tcl_Obj *pathPtr);
/* 443 */
EXTERN int Tcl_FSDeleteFile(Tcl_Obj *pathPtr);
/* 444 */
EXTERN int Tcl_FSLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,
const char *sym1, const char *sym2,
Tcl_PackageInitProc **proc1Ptr,
Tcl_PackageInitProc **proc2Ptr,
Tcl_LoadHandle *handlePtr,
Tcl_FSUnloadFileProc **unloadProcPtr);
/* 445 */
EXTERN int Tcl_FSMatchInDirectory(Tcl_Interp *interp,
Tcl_Obj *result, Tcl_Obj *pathPtr,
const char *pattern, Tcl_GlobTypeData *types);
/* 446 */
EXTERN Tcl_Obj * Tcl_FSLink(Tcl_Obj *pathPtr, Tcl_Obj *toPtr,
int linkAction);
/* 447 */
EXTERN int Tcl_FSRemoveDirectory(Tcl_Obj *pathPtr,
int recursive, Tcl_Obj **errorPtr);
/* 448 */
EXTERN int Tcl_FSRenameFile(Tcl_Obj *srcPathPtr,
Tcl_Obj *destPathPtr);
/* 449 */
EXTERN int Tcl_FSLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf);
/* 450 */
EXTERN int Tcl_FSUtime(Tcl_Obj *pathPtr, struct utimbuf *tval);
/* 451 */
EXTERN int Tcl_FSFileAttrsGet(Tcl_Interp *interp, int index,
Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef);
/* 452 */
EXTERN int Tcl_FSFileAttrsSet(Tcl_Interp *interp, int index,
Tcl_Obj *pathPtr, Tcl_Obj *objPtr);
/* 453 */
EXTERN const char *CONST86 * Tcl_FSFileAttrStrings(Tcl_Obj *pathPtr,
Tcl_Obj **objPtrRef);
/* 454 */
EXTERN int Tcl_FSStat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf);
/* 455 */
EXTERN int Tcl_FSAccess(Tcl_Obj *pathPtr, int mode);
/* 456 */
EXTERN Tcl_Channel Tcl_FSOpenFileChannel(Tcl_Interp *interp,
Tcl_Obj *pathPtr, const char *modeString,
int permissions);
/* 457 */
EXTERN Tcl_Obj * Tcl_FSGetCwd(Tcl_Interp *interp);
/* 458 */
EXTERN int Tcl_FSChdir(Tcl_Obj *pathPtr);
/* 459 */
EXTERN int Tcl_FSConvertToPathType(Tcl_Interp *interp,
Tcl_Obj *pathPtr);
/* 460 */
EXTERN Tcl_Obj * Tcl_FSJoinPath(Tcl_Obj *listObj, int elements);
/* 461 */
EXTERN Tcl_Obj * Tcl_FSSplitPath(Tcl_Obj *pathPtr, int *lenPtr);
/* 462 */
EXTERN int Tcl_FSEqualPaths(Tcl_Obj *firstPtr,
Tcl_Obj *secondPtr);
/* 463 */
EXTERN Tcl_Obj * Tcl_FSGetNormalizedPath(Tcl_Interp *interp,
Tcl_Obj *pathPtr);
/* 464 */
EXTERN Tcl_Obj * Tcl_FSJoinToPath(Tcl_Obj *pathPtr, int objc,
Tcl_Obj *const objv[]);
/* 465 */
EXTERN ClientData Tcl_FSGetInternalRep(Tcl_Obj *pathPtr,
const Tcl_Filesystem *fsPtr);
/* 466 */
EXTERN Tcl_Obj * Tcl_FSGetTranslatedPath(Tcl_Interp *interp,
Tcl_Obj *pathPtr);
/* 467 */
EXTERN int Tcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName);
/* 468 */
EXTERN Tcl_Obj * Tcl_FSNewNativePath(
const Tcl_Filesystem *fromFilesystem,
ClientData clientData);
/* 469 */
EXTERN const void * Tcl_FSGetNativePath(Tcl_Obj *pathPtr);
/* 470 */
EXTERN Tcl_Obj * Tcl_FSFileSystemInfo(Tcl_Obj *pathPtr);
/* 471 */
EXTERN Tcl_Obj * Tcl_FSPathSeparator(Tcl_Obj *pathPtr);
/* 472 */
EXTERN Tcl_Obj * Tcl_FSListVolumes(void);
/* 473 */
EXTERN int Tcl_FSRegister(ClientData clientData,
const Tcl_Filesystem *fsPtr);
/* 474 */
EXTERN int Tcl_FSUnregister(const Tcl_Filesystem *fsPtr);
/* 475 */
EXTERN ClientData Tcl_FSData(const Tcl_Filesystem *fsPtr);
/* 476 */
EXTERN const char * Tcl_FSGetTranslatedStringPath(Tcl_Interp *interp,
Tcl_Obj *pathPtr);
/* 477 */
EXTERN CONST86 Tcl_Filesystem * Tcl_FSGetFileSystemForPath(Tcl_Obj *pathPtr);
/* 478 */
EXTERN Tcl_PathType Tcl_FSGetPathType(Tcl_Obj *pathPtr);
/* 479 */
EXTERN int Tcl_OutputBuffered(Tcl_Channel chan);
/* 480 */
EXTERN void Tcl_FSMountsChanged(const Tcl_Filesystem *fsPtr);
/* 481 */
EXTERN int Tcl_EvalTokensStandard(Tcl_Interp *interp,
Tcl_Token *tokenPtr, int count);
/* 482 */
EXTERN void Tcl_GetTime(Tcl_Time *timeBuf);
/* 483 */
EXTERN Tcl_Trace Tcl_CreateObjTrace(Tcl_Interp *interp, int level,
int flags, Tcl_CmdObjTraceProc *objProc,
ClientData clientData,
Tcl_CmdObjTraceDeleteProc *delProc);
/* 484 */
EXTERN int Tcl_GetCommandInfoFromToken(Tcl_Command token,
Tcl_CmdInfo *infoPtr);
/* 485 */
EXTERN int Tcl_SetCommandInfoFromToken(Tcl_Command token,
const Tcl_CmdInfo *infoPtr);
/* 486 */
EXTERN Tcl_Obj * Tcl_DbNewWideIntObj(Tcl_WideInt wideValue,
const char *file, int line);
/* 487 */
EXTERN int Tcl_GetWideIntFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, Tcl_WideInt *widePtr);
/* 488 */
EXTERN Tcl_Obj * Tcl_NewWideIntObj(Tcl_WideInt wideValue);
/* 489 */
EXTERN void Tcl_SetWideIntObj(Tcl_Obj *objPtr,
Tcl_WideInt wideValue);
/* 490 */
EXTERN Tcl_StatBuf * Tcl_AllocStatBuf(void);
/* 491 */
EXTERN Tcl_WideInt Tcl_Seek(Tcl_Channel chan, Tcl_WideInt offset,
int mode);
/* 492 */
EXTERN Tcl_WideInt Tcl_Tell(Tcl_Channel chan);
/* 493 */
EXTERN Tcl_DriverWideSeekProc * Tcl_ChannelWideSeekProc(
const Tcl_ChannelType *chanTypePtr);
/* 494 */
EXTERN int Tcl_DictObjPut(Tcl_Interp *interp, Tcl_Obj *dictPtr,
Tcl_Obj *keyPtr, Tcl_Obj *valuePtr);
/* 495 */
EXTERN int Tcl_DictObjGet(Tcl_Interp *interp, Tcl_Obj *dictPtr,
Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr);
/* 496 */
EXTERN int Tcl_DictObjRemove(Tcl_Interp *interp,
Tcl_Obj *dictPtr, Tcl_Obj *keyPtr);
/* 497 */
EXTERN int Tcl_DictObjSize(Tcl_Interp *interp, Tcl_Obj *dictPtr,
int *sizePtr);
/* 498 */
EXTERN int Tcl_DictObjFirst(Tcl_Interp *interp,
Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr,
Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr,
int *donePtr);
/* 499 */
EXTERN void Tcl_DictObjNext(Tcl_DictSearch *searchPtr,
Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr,
int *donePtr);
/* 500 */
EXTERN void Tcl_DictObjDone(Tcl_DictSearch *searchPtr);
/* 501 */
EXTERN int Tcl_DictObjPutKeyList(Tcl_Interp *interp,
Tcl_Obj *dictPtr, int keyc,
Tcl_Obj *const *keyv, Tcl_Obj *valuePtr);
/* 502 */
EXTERN int Tcl_DictObjRemoveKeyList(Tcl_Interp *interp,
Tcl_Obj *dictPtr, int keyc,
Tcl_Obj *const *keyv);
/* 503 */
EXTERN Tcl_Obj * Tcl_NewDictObj(void);
/* 504 */
EXTERN Tcl_Obj * Tcl_DbNewDictObj(const char *file, int line);
/* 505 */
EXTERN void Tcl_RegisterConfig(Tcl_Interp *interp,
const char *pkgName,
const Tcl_Config *configuration,
const char *valEncoding);
/* 506 */
EXTERN Tcl_Namespace * Tcl_CreateNamespace(Tcl_Interp *interp,
const char *name, ClientData clientData,
Tcl_NamespaceDeleteProc *deleteProc);
/* 507 */
EXTERN void Tcl_DeleteNamespace(Tcl_Namespace *nsPtr);
/* 508 */
EXTERN int Tcl_AppendExportList(Tcl_Interp *interp,
Tcl_Namespace *nsPtr, Tcl_Obj *objPtr);
/* 509 */
EXTERN int Tcl_Export(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
const char *pattern, int resetListFirst);
/* 510 */
EXTERN int Tcl_Import(Tcl_Interp *interp, Tcl_Namespace *nsPtr,
const char *pattern, int allowOverwrite);
/* 511 */
EXTERN int Tcl_ForgetImport(Tcl_Interp *interp,
Tcl_Namespace *nsPtr, const char *pattern);
/* 512 */
EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace(Tcl_Interp *interp);
/* 513 */
EXTERN Tcl_Namespace * Tcl_GetGlobalNamespace(Tcl_Interp *interp);
/* 514 */
EXTERN Tcl_Namespace * Tcl_FindNamespace(Tcl_Interp *interp,
const char *name,
Tcl_Namespace *contextNsPtr, int flags);
/* 515 */
EXTERN Tcl_Command Tcl_FindCommand(Tcl_Interp *interp, const char *name,
Tcl_Namespace *contextNsPtr, int flags);
/* 516 */
EXTERN Tcl_Command Tcl_GetCommandFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr);
/* 517 */
EXTERN void Tcl_GetCommandFullName(Tcl_Interp *interp,
Tcl_Command command, Tcl_Obj *objPtr);
/* 518 */
EXTERN int Tcl_FSEvalFileEx(Tcl_Interp *interp,
Tcl_Obj *fileName, const char *encodingName);
/* 519 */
EXTERN Tcl_ExitProc * Tcl_SetExitProc(Tcl_ExitProc *proc);
/* 520 */
EXTERN void Tcl_LimitAddHandler(Tcl_Interp *interp, int type,
Tcl_LimitHandlerProc *handlerProc,
ClientData clientData,
Tcl_LimitHandlerDeleteProc *deleteProc);
/* 521 */
EXTERN void Tcl_LimitRemoveHandler(Tcl_Interp *interp, int type,
Tcl_LimitHandlerProc *handlerProc,
ClientData clientData);
/* 522 */
EXTERN int Tcl_LimitReady(Tcl_Interp *interp);
/* 523 */
EXTERN int Tcl_LimitCheck(Tcl_Interp *interp);
/* 524 */
EXTERN int Tcl_LimitExceeded(Tcl_Interp *interp);
/* 525 */
EXTERN void Tcl_LimitSetCommands(Tcl_Interp *interp,
int commandLimit);
/* 526 */
EXTERN void Tcl_LimitSetTime(Tcl_Interp *interp,
Tcl_Time *timeLimitPtr);
/* 527 */
EXTERN void Tcl_LimitSetGranularity(Tcl_Interp *interp, int type,
int granularity);
/* 528 */
EXTERN int Tcl_LimitTypeEnabled(Tcl_Interp *interp, int type);
/* 529 */
EXTERN int Tcl_LimitTypeExceeded(Tcl_Interp *interp, int type);
/* 530 */
EXTERN void Tcl_LimitTypeSet(Tcl_Interp *interp, int type);
/* 531 */
EXTERN void Tcl_LimitTypeReset(Tcl_Interp *interp, int type);
/* 532 */
EXTERN int Tcl_LimitGetCommands(Tcl_Interp *interp);
/* 533 */
EXTERN void Tcl_LimitGetTime(Tcl_Interp *interp,
Tcl_Time *timeLimitPtr);
/* 534 */
EXTERN int Tcl_LimitGetGranularity(Tcl_Interp *interp, int type);
/* 535 */
EXTERN Tcl_InterpState Tcl_SaveInterpState(Tcl_Interp *interp, int status);
/* 536 */
EXTERN int Tcl_RestoreInterpState(Tcl_Interp *interp,
Tcl_InterpState state);
/* 537 */
EXTERN void Tcl_DiscardInterpState(Tcl_InterpState state);
/* 538 */
EXTERN int Tcl_SetReturnOptions(Tcl_Interp *interp,
Tcl_Obj *options);
/* 539 */
EXTERN Tcl_Obj * Tcl_GetReturnOptions(Tcl_Interp *interp, int result);
/* 540 */
EXTERN int Tcl_IsEnsemble(Tcl_Command token);
/* 541 */
EXTERN Tcl_Command Tcl_CreateEnsemble(Tcl_Interp *interp,
const char *name,
Tcl_Namespace *namespacePtr, int flags);
/* 542 */
EXTERN Tcl_Command Tcl_FindEnsemble(Tcl_Interp *interp,
Tcl_Obj *cmdNameObj, int flags);
/* 543 */
EXTERN int Tcl_SetEnsembleSubcommandList(Tcl_Interp *interp,
Tcl_Command token, Tcl_Obj *subcmdList);
/* 544 */
EXTERN int Tcl_SetEnsembleMappingDict(Tcl_Interp *interp,
Tcl_Command token, Tcl_Obj *mapDict);
/* 545 */
EXTERN int Tcl_SetEnsembleUnknownHandler(Tcl_Interp *interp,
Tcl_Command token, Tcl_Obj *unknownList);
/* 546 */
EXTERN int Tcl_SetEnsembleFlags(Tcl_Interp *interp,
Tcl_Command token, int flags);
/* 547 */
EXTERN int Tcl_GetEnsembleSubcommandList(Tcl_Interp *interp,
Tcl_Command token, Tcl_Obj **subcmdListPtr);
/* 548 */
EXTERN int Tcl_GetEnsembleMappingDict(Tcl_Interp *interp,
Tcl_Command token, Tcl_Obj **mapDictPtr);
/* 549 */
EXTERN int Tcl_GetEnsembleUnknownHandler(Tcl_Interp *interp,
Tcl_Command token, Tcl_Obj **unknownListPtr);
/* 550 */
EXTERN int Tcl_GetEnsembleFlags(Tcl_Interp *interp,
Tcl_Command token, int *flagsPtr);
/* 551 */
EXTERN int Tcl_GetEnsembleNamespace(Tcl_Interp *interp,
Tcl_Command token,
Tcl_Namespace **namespacePtrPtr);
/* 552 */
EXTERN void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc,
Tcl_ScaleTimeProc *scaleProc,
ClientData clientData);
/* 553 */
EXTERN void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc,
Tcl_ScaleTimeProc **scaleProc,
ClientData *clientData);
/* 554 */
EXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc(
const Tcl_ChannelType *chanTypePtr);
/* 555 */
EXTERN Tcl_Obj * Tcl_NewBignumObj(mp_int *value);
/* 556 */
EXTERN Tcl_Obj * Tcl_DbNewBignumObj(mp_int *value, const char *file,
int line);
/* 557 */
EXTERN void Tcl_SetBignumObj(Tcl_Obj *obj, mp_int *value);
/* 558 */
EXTERN int Tcl_GetBignumFromObj(Tcl_Interp *interp,
Tcl_Obj *obj, mp_int *value);
/* 559 */
EXTERN int Tcl_TakeBignumFromObj(Tcl_Interp *interp,
Tcl_Obj *obj, mp_int *value);
/* 560 */
EXTERN int Tcl_TruncateChannel(Tcl_Channel chan,
Tcl_WideInt length);
/* 561 */
EXTERN Tcl_DriverTruncateProc * Tcl_ChannelTruncateProc(
const Tcl_ChannelType *chanTypePtr);
/* 562 */
EXTERN void Tcl_SetChannelErrorInterp(Tcl_Interp *interp,
Tcl_Obj *msg);
/* 563 */
EXTERN void Tcl_GetChannelErrorInterp(Tcl_Interp *interp,
Tcl_Obj **msg);
/* 564 */
EXTERN void Tcl_SetChannelError(Tcl_Channel chan, Tcl_Obj *msg);
/* 565 */
EXTERN void Tcl_GetChannelError(Tcl_Channel chan, Tcl_Obj **msg);
/* 566 */
EXTERN int Tcl_InitBignumFromDouble(Tcl_Interp *interp,
double initval, mp_int *toInit);
/* 567 */
EXTERN Tcl_Obj * Tcl_GetNamespaceUnknownHandler(Tcl_Interp *interp,
Tcl_Namespace *nsPtr);
/* 568 */
EXTERN int Tcl_SetNamespaceUnknownHandler(Tcl_Interp *interp,
Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr);
/* 569 */
EXTERN int Tcl_GetEncodingFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr);
/* 570 */
EXTERN Tcl_Obj * Tcl_GetEncodingSearchPath(void);
/* 571 */
EXTERN int Tcl_SetEncodingSearchPath(Tcl_Obj *searchPath);
/* 572 */
EXTERN const char * Tcl_GetEncodingNameFromEnvironment(
Tcl_DString *bufPtr);
/* 573 */
EXTERN int Tcl_PkgRequireProc(Tcl_Interp *interp,
const char *name, int objc,
Tcl_Obj *const objv[], void *clientDataPtr);
/* 574 */
EXTERN void Tcl_AppendObjToErrorInfo(Tcl_Interp *interp,
Tcl_Obj *objPtr);
/* 575 */
EXTERN void Tcl_AppendLimitedToObj(Tcl_Obj *objPtr,
const char *bytes, int length, int limit,
const char *ellipsis);
/* 576 */
EXTERN Tcl_Obj * Tcl_Format(Tcl_Interp *interp, const char *format,
int objc, Tcl_Obj *const objv[]);
/* 577 */
EXTERN int Tcl_AppendFormatToObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, const char *format,
int objc, Tcl_Obj *const objv[]);
/* 578 */
EXTERN Tcl_Obj * Tcl_ObjPrintf(const char *format, ...) TCL_FORMAT_PRINTF(1, 2);
/* 579 */
EXTERN void Tcl_AppendPrintfToObj(Tcl_Obj *objPtr,
const char *format, ...) TCL_FORMAT_PRINTF(2, 3);
/* 580 */
EXTERN int Tcl_CancelEval(Tcl_Interp *interp,
Tcl_Obj *resultObjPtr, ClientData clientData,
int flags);
/* 581 */
EXTERN int Tcl_Canceled(Tcl_Interp *interp, int flags);
/* 582 */
EXTERN int Tcl_CreatePipe(Tcl_Interp *interp,
Tcl_Channel *rchan, Tcl_Channel *wchan,
int flags);
/* 583 */
EXTERN Tcl_Command Tcl_NRCreateCommand(Tcl_Interp *interp,
const char *cmdName, Tcl_ObjCmdProc *proc,
Tcl_ObjCmdProc *nreProc,
ClientData clientData,
Tcl_CmdDeleteProc *deleteProc);
/* 584 */
EXTERN int Tcl_NREvalObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
int flags);
/* 585 */
EXTERN int Tcl_NREvalObjv(Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[], int flags);
/* 586 */
EXTERN int Tcl_NRCmdSwap(Tcl_Interp *interp, Tcl_Command cmd,
int objc, Tcl_Obj *const objv[], int flags);
/* 587 */
EXTERN void Tcl_NRAddCallback(Tcl_Interp *interp,
Tcl_NRPostProc *postProcPtr,
ClientData data0, ClientData data1,
ClientData data2, ClientData data3);
/* 588 */
EXTERN int Tcl_NRCallObjProc(Tcl_Interp *interp,
Tcl_ObjCmdProc *objProc,
ClientData clientData, int objc,
Tcl_Obj *const objv[]);
/* 589 */
EXTERN unsigned Tcl_GetFSDeviceFromStat(const Tcl_StatBuf *statPtr);
/* 590 */
EXTERN unsigned Tcl_GetFSInodeFromStat(const Tcl_StatBuf *statPtr);
/* 591 */
EXTERN unsigned Tcl_GetModeFromStat(const Tcl_StatBuf *statPtr);
/* 592 */
EXTERN int Tcl_GetLinkCountFromStat(const Tcl_StatBuf *statPtr);
/* 593 */
EXTERN int Tcl_GetUserIdFromStat(const Tcl_StatBuf *statPtr);
/* 594 */
EXTERN int Tcl_GetGroupIdFromStat(const Tcl_StatBuf *statPtr);
/* 595 */
EXTERN int Tcl_GetDeviceTypeFromStat(const Tcl_StatBuf *statPtr);
/* 596 */
EXTERN Tcl_WideInt Tcl_GetAccessTimeFromStat(const Tcl_StatBuf *statPtr);
/* 597 */
EXTERN Tcl_WideInt Tcl_GetModificationTimeFromStat(
const Tcl_StatBuf *statPtr);
/* 598 */
EXTERN Tcl_WideInt Tcl_GetChangeTimeFromStat(const Tcl_StatBuf *statPtr);
/* 599 */
EXTERN Tcl_WideUInt Tcl_GetSizeFromStat(const Tcl_StatBuf *statPtr);
/* 600 */
EXTERN Tcl_WideUInt Tcl_GetBlocksFromStat(const Tcl_StatBuf *statPtr);
/* 601 */
EXTERN unsigned Tcl_GetBlockSizeFromStat(const Tcl_StatBuf *statPtr);
/* 602 */
EXTERN int Tcl_SetEnsembleParameterList(Tcl_Interp *interp,
Tcl_Command token, Tcl_Obj *paramList);
/* 603 */
EXTERN int Tcl_GetEnsembleParameterList(Tcl_Interp *interp,
Tcl_Command token, Tcl_Obj **paramListPtr);
/* 604 */
EXTERN int Tcl_ParseArgsObjv(Tcl_Interp *interp,
const Tcl_ArgvInfo *argTable, int *objcPtr,
Tcl_Obj *const *objv, Tcl_Obj ***remObjv);
/* 605 */
EXTERN int Tcl_GetErrorLine(Tcl_Interp *interp);
/* 606 */
EXTERN void Tcl_SetErrorLine(Tcl_Interp *interp, int lineNum);
/* 607 */
EXTERN void Tcl_TransferResult(Tcl_Interp *sourceInterp,
int result, Tcl_Interp *targetInterp);
/* 608 */
EXTERN int Tcl_InterpActive(Tcl_Interp *interp);
/* 609 */
EXTERN void Tcl_BackgroundException(Tcl_Interp *interp, int code);
/* 610 */
EXTERN int Tcl_ZlibDeflate(Tcl_Interp *interp, int format,
Tcl_Obj *data, int level,
Tcl_Obj *gzipHeaderDictObj);
/* 611 */
EXTERN int Tcl_ZlibInflate(Tcl_Interp *interp, int format,
Tcl_Obj *data, int buffersize,
Tcl_Obj *gzipHeaderDictObj);
/* 612 */
EXTERN unsigned int Tcl_ZlibCRC32(unsigned int crc,
const unsigned char *buf, int len);
/* 613 */
EXTERN unsigned int Tcl_ZlibAdler32(unsigned int adler,
const unsigned char *buf, int len);
/* 614 */
EXTERN int Tcl_ZlibStreamInit(Tcl_Interp *interp, int mode,
int format, int level, Tcl_Obj *dictObj,
Tcl_ZlibStream *zshandle);
/* 615 */
EXTERN Tcl_Obj * Tcl_ZlibStreamGetCommandName(Tcl_ZlibStream zshandle);
/* 616 */
EXTERN int Tcl_ZlibStreamEof(Tcl_ZlibStream zshandle);
/* 617 */
EXTERN int Tcl_ZlibStreamChecksum(Tcl_ZlibStream zshandle);
/* 618 */
EXTERN int Tcl_ZlibStreamPut(Tcl_ZlibStream zshandle,
Tcl_Obj *data, int flush);
/* 619 */
EXTERN int Tcl_ZlibStreamGet(Tcl_ZlibStream zshandle,
Tcl_Obj *data, int count);
/* 620 */
EXTERN int Tcl_ZlibStreamClose(Tcl_ZlibStream zshandle);
/* 621 */
EXTERN int Tcl_ZlibStreamReset(Tcl_ZlibStream zshandle);
/* 622 */
EXTERN void Tcl_SetStartupScript(Tcl_Obj *path,
const char *encoding);
/* 623 */
EXTERN Tcl_Obj * Tcl_GetStartupScript(const char **encodingPtr);
/* 624 */
EXTERN int Tcl_CloseEx(Tcl_Interp *interp, Tcl_Channel chan,
int flags);
/* 625 */
EXTERN int Tcl_NRExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
Tcl_Obj *resultPtr);
/* 626 */
EXTERN int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
int flags);
/* 627 */
EXTERN int Tcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,
const char *const symv[], int flags,
void *procPtrs, Tcl_LoadHandle *handlePtr);
/* 628 */
EXTERN void * Tcl_FindSymbol(Tcl_Interp *interp,
Tcl_LoadHandle handle, const char *symbol);
/* 629 */
EXTERN int Tcl_FSUnloadFile(Tcl_Interp *interp,
Tcl_LoadHandle handlePtr);
/* 630 */
EXTERN void Tcl_ZlibStreamSetCompressionDictionary(
Tcl_ZlibStream zhandle,
Tcl_Obj *compressionDictionaryObj);
typedef struct {
const struct TclPlatStubs *tclPlatStubs;
const struct TclIntStubs *tclIntStubs;
const struct TclIntPlatStubs *tclIntPlatStubs;
} TclStubHooks;
typedef struct TclStubs {
int magic;
const TclStubHooks *hooks;
int (*tcl_PkgProvideEx) (Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 0 */
CONST84_RETURN char * (*tcl_PkgRequireEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 1 */
void (*tcl_Panic) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 2 */
char * (*tcl_Alloc) (unsigned int size); /* 3 */
void (*tcl_Free) (char *ptr); /* 4 */
char * (*tcl_Realloc) (char *ptr, unsigned int size); /* 5 */
char * (*tcl_DbCkalloc) (unsigned int size, const char *file, int line); /* 6 */
void (*tcl_DbCkfree) (char *ptr, const char *file, int line); /* 7 */
char * (*tcl_DbCkrealloc) (char *ptr, unsigned int size, const char *file, int line); /* 8 */
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */
#endif /* UNIX */
#if defined(__WIN32__) /* WIN */
void (*reserved9)(void);
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, ClientData clientData); /* 9 */
#endif /* MACOSX */
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
void (*tcl_DeleteFileHandler) (int fd); /* 10 */
#endif /* UNIX */
#if defined(__WIN32__) /* WIN */
void (*reserved10)(void);
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
void (*tcl_DeleteFileHandler) (int fd); /* 10 */
#endif /* MACOSX */
void (*tcl_SetTimer) (const Tcl_Time *timePtr); /* 11 */
void (*tcl_Sleep) (int ms); /* 12 */
int (*tcl_WaitForEvent) (const Tcl_Time *timePtr); /* 13 */
int (*tcl_AppendAllObjTypes) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 14 */
void (*tcl_AppendStringsToObj) (Tcl_Obj *objPtr, ...); /* 15 */
void (*tcl_AppendToObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 16 */
Tcl_Obj * (*tcl_ConcatObj) (int objc, Tcl_Obj *const objv[]); /* 17 */
int (*tcl_ConvertToType) (Tcl_Interp *interp, Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 18 */
void (*tcl_DbDecrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 19 */
void (*tcl_DbIncrRefCount) (Tcl_Obj *objPtr, const char *file, int line); /* 20 */
int (*tcl_DbIsShared) (Tcl_Obj *objPtr, const char *file, int line); /* 21 */
Tcl_Obj * (*tcl_DbNewBooleanObj) (int boolValue, const char *file, int line); /* 22 */
Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, int length, const char *file, int line); /* 23 */
Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */
Tcl_Obj * (*tcl_DbNewListObj) (int objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */
Tcl_Obj * (*tcl_DbNewLongObj) (long longValue, const char *file, int line); /* 26 */
Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */
Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, int length, const char *file, int line); /* 28 */
Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */
void (*tclFreeObj) (Tcl_Obj *objPtr); /* 30 */
int (*tcl_GetBoolean) (Tcl_Interp *interp, const char *src, int *boolPtr); /* 31 */
int (*tcl_GetBooleanFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *boolPtr); /* 32 */
unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 33 */
int (*tcl_GetDouble) (Tcl_Interp *interp, const char *src, double *doublePtr); /* 34 */
int (*tcl_GetDoubleFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* 35 */
int (*tcl_GetIndexFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, CONST84 char *const *tablePtr, const char *msg, int flags, int *indexPtr); /* 36 */
int (*tcl_GetInt) (Tcl_Interp *interp, const char *src, int *intPtr); /* 37 */
int (*tcl_GetIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 38 */
int (*tcl_GetLongFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *longPtr); /* 39 */
CONST86 Tcl_ObjType * (*tcl_GetObjType) (const char *typeName); /* 40 */
char * (*tcl_GetStringFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 41 */
void (*tcl_InvalidateStringRep) (Tcl_Obj *objPtr); /* 42 */
int (*tcl_ListObjAppendList) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); /* 43 */
int (*tcl_ListObjAppendElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr); /* 44 */
int (*tcl_ListObjGetElements) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *objcPtr, Tcl_Obj ***objvPtr); /* 45 */
int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, int index, Tcl_Obj **objPtrPtr); /* 46 */
int (*tcl_ListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, int *lengthPtr); /* 47 */
int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, int first, int count, int objc, Tcl_Obj *const objv[]); /* 48 */
Tcl_Obj * (*tcl_NewBooleanObj) (int boolValue); /* 49 */
Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, int length); /* 50 */
Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */
Tcl_Obj * (*tcl_NewIntObj) (int intValue); /* 52 */
Tcl_Obj * (*tcl_NewListObj) (int objc, Tcl_Obj *const objv[]); /* 53 */
Tcl_Obj * (*tcl_NewLongObj) (long longValue); /* 54 */
Tcl_Obj * (*tcl_NewObj) (void); /* 55 */
Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, int length); /* 56 */
void (*tcl_SetBooleanObj) (Tcl_Obj *objPtr, int boolValue); /* 57 */
unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, int length); /* 58 */
void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, int length); /* 59 */
void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */
void (*tcl_SetIntObj) (Tcl_Obj *objPtr, int intValue); /* 61 */
void (*tcl_SetListObj) (Tcl_Obj *objPtr, int objc, Tcl_Obj *const objv[]); /* 62 */
void (*tcl_SetLongObj) (Tcl_Obj *objPtr, long longValue); /* 63 */
void (*tcl_SetObjLength) (Tcl_Obj *objPtr, int length); /* 64 */
void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, int length); /* 65 */
void (*tcl_AddErrorInfo) (Tcl_Interp *interp, const char *message); /* 66 */
void (*tcl_AddObjErrorInfo) (Tcl_Interp *interp, const char *message, int length); /* 67 */
void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */
void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */
void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */
Tcl_AsyncHandler (*tcl_AsyncCreate) (Tcl_AsyncProc *proc, ClientData clientData); /* 71 */
void (*tcl_AsyncDelete) (Tcl_AsyncHandler async); /* 72 */
int (*tcl_AsyncInvoke) (Tcl_Interp *interp, int code); /* 73 */
void (*tcl_AsyncMark) (Tcl_AsyncHandler async); /* 74 */
int (*tcl_AsyncReady) (void); /* 75 */
void (*tcl_BackgroundError) (Tcl_Interp *interp); /* 76 */
char (*tcl_Backslash) (const char *src, int *readPtr); /* 77 */
int (*tcl_BadChannelOption) (Tcl_Interp *interp, const char *optionName, const char *optionList); /* 78 */
void (*tcl_CallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 79 */
void (*tcl_CancelIdleCall) (Tcl_IdleProc *idleProc, ClientData clientData); /* 80 */
int (*tcl_Close) (Tcl_Interp *interp, Tcl_Channel chan); /* 81 */
int (*tcl_CommandComplete) (const char *cmd); /* 82 */
char * (*tcl_Concat) (int argc, CONST84 char *const *argv); /* 83 */
int (*tcl_ConvertElement) (const char *src, char *dst, int flags); /* 84 */
int (*tcl_ConvertCountedElement) (const char *src, int length, char *dst, int flags); /* 85 */
int (*tcl_CreateAlias) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int argc, CONST84 char *const *argv); /* 86 */
int (*tcl_CreateAliasObj) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int objc, Tcl_Obj *const objv[]); /* 87 */
Tcl_Channel (*tcl_CreateChannel) (const Tcl_ChannelType *typePtr, const char *chanName, ClientData instanceData, int mask); /* 88 */
void (*tcl_CreateChannelHandler) (Tcl_Channel chan, int mask, Tcl_ChannelProc *proc, ClientData clientData); /* 89 */
void (*tcl_CreateCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 90 */
Tcl_Command (*tcl_CreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 91 */
void (*tcl_CreateEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 92 */
void (*tcl_CreateExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 93 */
Tcl_Interp * (*tcl_CreateInterp) (void); /* 94 */
void (*tcl_CreateMathFunc) (Tcl_Interp *interp, const char *name, int numArgs, Tcl_ValueType *argTypes, Tcl_MathProc *proc, ClientData clientData); /* 95 */
Tcl_Command (*tcl_CreateObjCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 96 */
Tcl_Interp * (*tcl_CreateSlave) (Tcl_Interp *interp, const char *slaveName, int isSafe); /* 97 */
Tcl_TimerToken (*tcl_CreateTimerHandler) (int milliseconds, Tcl_TimerProc *proc, ClientData clientData); /* 98 */
Tcl_Trace (*tcl_CreateTrace) (Tcl_Interp *interp, int level, Tcl_CmdTraceProc *proc, ClientData clientData); /* 99 */
void (*tcl_DeleteAssocData) (Tcl_Interp *interp, const char *name); /* 100 */
void (*tcl_DeleteChannelHandler) (Tcl_Channel chan, Tcl_ChannelProc *proc, ClientData clientData); /* 101 */
void (*tcl_DeleteCloseHandler) (Tcl_Channel chan, Tcl_CloseProc *proc, ClientData clientData); /* 102 */
int (*tcl_DeleteCommand) (Tcl_Interp *interp, const char *cmdName); /* 103 */
int (*tcl_DeleteCommandFromToken) (Tcl_Interp *interp, Tcl_Command command); /* 104 */
void (*tcl_DeleteEvents) (Tcl_EventDeleteProc *proc, ClientData clientData); /* 105 */
void (*tcl_DeleteEventSource) (Tcl_EventSetupProc *setupProc, Tcl_EventCheckProc *checkProc, ClientData clientData); /* 106 */
void (*tcl_DeleteExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 107 */
void (*tcl_DeleteHashEntry) (Tcl_HashEntry *entryPtr); /* 108 */
void (*tcl_DeleteHashTable) (Tcl_HashTable *tablePtr); /* 109 */
void (*tcl_DeleteInterp) (Tcl_Interp *interp); /* 110 */
void (*tcl_DetachPids) (int numPids, Tcl_Pid *pidPtr); /* 111 */
void (*tcl_DeleteTimerHandler) (Tcl_TimerToken token); /* 112 */
void (*tcl_DeleteTrace) (Tcl_Interp *interp, Tcl_Trace trace); /* 113 */
void (*tcl_DontCallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 114 */
int (*tcl_DoOneEvent) (int flags); /* 115 */
void (*tcl_DoWhenIdle) (Tcl_IdleProc *proc, ClientData clientData); /* 116 */
char * (*tcl_DStringAppend) (Tcl_DString *dsPtr, const char *bytes, int length); /* 117 */
char * (*tcl_DStringAppendElement) (Tcl_DString *dsPtr, const char *element); /* 118 */
void (*tcl_DStringEndSublist) (Tcl_DString *dsPtr); /* 119 */
void (*tcl_DStringFree) (Tcl_DString *dsPtr); /* 120 */
void (*tcl_DStringGetResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 121 */
void (*tcl_DStringInit) (Tcl_DString *dsPtr); /* 122 */
void (*tcl_DStringResult) (Tcl_Interp *interp, Tcl_DString *dsPtr); /* 123 */
void (*tcl_DStringSetLength) (Tcl_DString *dsPtr, int length); /* 124 */
void (*tcl_DStringStartSublist) (Tcl_DString *dsPtr); /* 125 */
int (*tcl_Eof) (Tcl_Channel chan); /* 126 */
CONST84_RETURN char * (*tcl_ErrnoId) (void); /* 127 */
CONST84_RETURN char * (*tcl_ErrnoMsg) (int err); /* 128 */
int (*tcl_Eval) (Tcl_Interp *interp, const char *script); /* 129 */
int (*tcl_EvalFile) (Tcl_Interp *interp, const char *fileName); /* 130 */
int (*tcl_EvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 131 */
void (*tcl_EventuallyFree) (ClientData clientData, Tcl_FreeProc *freeProc); /* 132 */
void (*tcl_Exit) (int status); /* 133 */
int (*tcl_ExposeCommand) (Tcl_Interp *interp, const char *hiddenCmdToken, const char *cmdName); /* 134 */
int (*tcl_ExprBoolean) (Tcl_Interp *interp, const char *expr, int *ptr); /* 135 */
int (*tcl_ExprBooleanObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *ptr); /* 136 */
int (*tcl_ExprDouble) (Tcl_Interp *interp, const char *expr, double *ptr); /* 137 */
int (*tcl_ExprDoubleObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, double *ptr); /* 138 */
int (*tcl_ExprLong) (Tcl_Interp *interp, const char *expr, long *ptr); /* 139 */
int (*tcl_ExprLongObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, long *ptr); /* 140 */
int (*tcl_ExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **resultPtrPtr); /* 141 */
int (*tcl_ExprString) (Tcl_Interp *interp, const char *expr); /* 142 */
void (*tcl_Finalize) (void); /* 143 */
void (*tcl_FindExecutable) (const char *argv0); /* 144 */
Tcl_HashEntry * (*tcl_FirstHashEntry) (Tcl_HashTable *tablePtr, Tcl_HashSearch *searchPtr); /* 145 */
int (*tcl_Flush) (Tcl_Channel chan); /* 146 */
void (*tcl_FreeResult) (Tcl_Interp *interp); /* 147 */
int (*tcl_GetAlias) (Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *argcPtr, CONST84 char ***argvPtr); /* 148 */
int (*tcl_GetAliasObj) (Tcl_Interp *interp, const char *slaveCmd, Tcl_Interp **targetInterpPtr, CONST84 char **targetCmdPtr, int *objcPtr, Tcl_Obj ***objv); /* 149 */
ClientData (*tcl_GetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc **procPtr); /* 150 */
Tcl_Channel (*tcl_GetChannel) (Tcl_Interp *interp, const char *chanName, int *modePtr); /* 151 */
int (*tcl_GetChannelBufferSize) (Tcl_Channel chan); /* 152 */
int (*tcl_GetChannelHandle) (Tcl_Channel chan, int direction, ClientData *handlePtr); /* 153 */
ClientData (*tcl_GetChannelInstanceData) (Tcl_Channel chan); /* 154 */
int (*tcl_GetChannelMode) (Tcl_Channel chan); /* 155 */
CONST84_RETURN char * (*tcl_GetChannelName) (Tcl_Channel chan); /* 156 */
int (*tcl_GetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, Tcl_DString *dsPtr); /* 157 */
CONST86 Tcl_ChannelType * (*tcl_GetChannelType) (Tcl_Channel chan); /* 158 */
int (*tcl_GetCommandInfo) (Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); /* 159 */
CONST84_RETURN char * (*tcl_GetCommandName) (Tcl_Interp *interp, Tcl_Command command); /* 160 */
int (*tcl_GetErrno) (void); /* 161 */
CONST84_RETURN char * (*tcl_GetHostName) (void); /* 162 */
int (*tcl_GetInterpPath) (Tcl_Interp *askInterp, Tcl_Interp *slaveInterp); /* 163 */
Tcl_Interp * (*tcl_GetMaster) (Tcl_Interp *interp); /* 164 */
const char * (*tcl_GetNameOfExecutable) (void); /* 165 */
Tcl_Obj * (*tcl_GetObjResult) (Tcl_Interp *interp); /* 166 */
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */
#endif /* UNIX */
#if defined(__WIN32__) /* WIN */
void (*reserved167)(void);
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
int (*tcl_GetOpenFile) (Tcl_Interp *interp, const char *chanID, int forWriting, int checkUsage, ClientData *filePtr); /* 167 */
#endif /* MACOSX */
Tcl_PathType (*tcl_GetPathType) (const char *path); /* 168 */
int (*tcl_Gets) (Tcl_Channel chan, Tcl_DString *dsPtr); /* 169 */
int (*tcl_GetsObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 170 */
int (*tcl_GetServiceMode) (void); /* 171 */
Tcl_Interp * (*tcl_GetSlave) (Tcl_Interp *interp, const char *slaveName); /* 172 */
Tcl_Channel (*tcl_GetStdChannel) (int type); /* 173 */
CONST84_RETURN char * (*tcl_GetStringResult) (Tcl_Interp *interp); /* 174 */
CONST84_RETURN char * (*tcl_GetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 175 */
CONST84_RETURN char * (*tcl_GetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 176 */
int (*tcl_GlobalEval) (Tcl_Interp *interp, const char *command); /* 177 */
int (*tcl_GlobalEvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 178 */
int (*tcl_HideCommand) (Tcl_Interp *interp, const char *cmdName, const char *hiddenCmdToken); /* 179 */
int (*tcl_Init) (Tcl_Interp *interp); /* 180 */
void (*tcl_InitHashTable) (Tcl_HashTable *tablePtr, int keyType); /* 181 */
int (*tcl_InputBlocked) (Tcl_Channel chan); /* 182 */
int (*tcl_InputBuffered) (Tcl_Channel chan); /* 183 */
int (*tcl_InterpDeleted) (Tcl_Interp *interp); /* 184 */
int (*tcl_IsSafe) (Tcl_Interp *interp); /* 185 */
char * (*tcl_JoinPath) (int argc, CONST84 char *const *argv, Tcl_DString *resultPtr); /* 186 */
int (*tcl_LinkVar) (Tcl_Interp *interp, const char *varName, char *addr, int type); /* 187 */
void (*reserved188)(void);
Tcl_Channel (*tcl_MakeFileChannel) (ClientData handle, int mode); /* 189 */
int (*tcl_MakeSafe) (Tcl_Interp *interp); /* 190 */
Tcl_Channel (*tcl_MakeTcpClientChannel) (ClientData tcpSocket); /* 191 */
char * (*tcl_Merge) (int argc, CONST84 char *const *argv); /* 192 */
Tcl_HashEntry * (*tcl_NextHashEntry) (Tcl_HashSearch *searchPtr); /* 193 */
void (*tcl_NotifyChannel) (Tcl_Channel channel, int mask); /* 194 */
Tcl_Obj * (*tcl_ObjGetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags); /* 195 */
Tcl_Obj * (*tcl_ObjSetVar2) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); /* 196 */
Tcl_Channel (*tcl_OpenCommandChannel) (Tcl_Interp *interp, int argc, CONST84 char **argv, int flags); /* 197 */
Tcl_Channel (*tcl_OpenFileChannel) (Tcl_Interp *interp, const char *fileName, const char *modeString, int permissions); /* 198 */
Tcl_Channel (*tcl_OpenTcpClient) (Tcl_Interp *interp, int port, const char *address, const char *myaddr, int myport, int async); /* 199 */
Tcl_Channel (*tcl_OpenTcpServer) (Tcl_Interp *interp, int port, const char *host, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 200 */
void (*tcl_Preserve) (ClientData data); /* 201 */
void (*tcl_PrintDouble) (Tcl_Interp *interp, double value, char *dst); /* 202 */
int (*tcl_PutEnv) (const char *assignment); /* 203 */
CONST84_RETURN char * (*tcl_PosixError) (Tcl_Interp *interp); /* 204 */
void (*tcl_QueueEvent) (Tcl_Event *evPtr, Tcl_QueuePosition position); /* 205 */
int (*tcl_Read) (Tcl_Channel chan, char *bufPtr, int toRead); /* 206 */
void (*tcl_ReapDetachedProcs) (void); /* 207 */
int (*tcl_RecordAndEval) (Tcl_Interp *interp, const char *cmd, int flags); /* 208 */
int (*tcl_RecordAndEvalObj) (Tcl_Interp *interp, Tcl_Obj *cmdPtr, int flags); /* 209 */
void (*tcl_RegisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 210 */
void (*tcl_RegisterObjType) (const Tcl_ObjType *typePtr); /* 211 */
Tcl_RegExp (*tcl_RegExpCompile) (Tcl_Interp *interp, const char *pattern); /* 212 */
int (*tcl_RegExpExec) (Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 213 */
int (*tcl_RegExpMatch) (Tcl_Interp *interp, const char *text, const char *pattern); /* 214 */
void (*tcl_RegExpRange) (Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr); /* 215 */
void (*tcl_Release) (ClientData clientData); /* 216 */
void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */
int (*tcl_ScanElement) (const char *src, int *flagPtr); /* 218 */
int (*tcl_ScanCountedElement) (const char *src, int length, int *flagPtr); /* 219 */
int (*tcl_SeekOld) (Tcl_Channel chan, int offset, int mode); /* 220 */
int (*tcl_ServiceAll) (void); /* 221 */
int (*tcl_ServiceEvent) (int flags); /* 222 */
void (*tcl_SetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 223 */
void (*tcl_SetChannelBufferSize) (Tcl_Channel chan, int sz); /* 224 */
int (*tcl_SetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 225 */
int (*tcl_SetCommandInfo) (Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 226 */
void (*tcl_SetErrno) (int err); /* 227 */
void (*tcl_SetErrorCode) (Tcl_Interp *interp, ...); /* 228 */
void (*tcl_SetMaxBlockTime) (const Tcl_Time *timePtr); /* 229 */
void (*tcl_SetPanicProc) (Tcl_PanicProc *panicProc); /* 230 */
int (*tcl_SetRecursionLimit) (Tcl_Interp *interp, int depth); /* 231 */
void (*tcl_SetResult) (Tcl_Interp *interp, char *result, Tcl_FreeProc *freeProc); /* 232 */
int (*tcl_SetServiceMode) (int mode); /* 233 */
void (*tcl_SetObjErrorCode) (Tcl_Interp *interp, Tcl_Obj *errorObjPtr); /* 234 */
void (*tcl_SetObjResult) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr); /* 235 */
void (*tcl_SetStdChannel) (Tcl_Channel channel, int type); /* 236 */
CONST84_RETURN char * (*tcl_SetVar) (Tcl_Interp *interp, const char *varName, const char *newValue, int flags); /* 237 */
CONST84_RETURN char * (*tcl_SetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, const char *newValue, int flags); /* 238 */
CONST84_RETURN char * (*tcl_SignalId) (int sig); /* 239 */
CONST84_RETURN char * (*tcl_SignalMsg) (int sig); /* 240 */
void (*tcl_SourceRCFile) (Tcl_Interp *interp); /* 241 */
int (*tcl_SplitList) (Tcl_Interp *interp, const char *listStr, int *argcPtr, CONST84 char ***argvPtr); /* 242 */
void (*tcl_SplitPath) (const char *path, int *argcPtr, CONST84 char ***argvPtr); /* 243 */
void (*tcl_StaticPackage) (Tcl_Interp *interp, const char *pkgName, Tcl_PackageInitProc *initProc, Tcl_PackageInitProc *safeInitProc); /* 244 */
int (*tcl_StringMatch) (const char *str, const char *pattern); /* 245 */
int (*tcl_TellOld) (Tcl_Channel chan); /* 246 */
int (*tcl_TraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 247 */
int (*tcl_TraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 248 */
char * (*tcl_TranslateFileName) (Tcl_Interp *interp, const char *name, Tcl_DString *bufferPtr); /* 249 */
int (*tcl_Ungets) (Tcl_Channel chan, const char *str, int len, int atHead); /* 250 */
void (*tcl_UnlinkVar) (Tcl_Interp *interp, const char *varName); /* 251 */
int (*tcl_UnregisterChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 252 */
int (*tcl_UnsetVar) (Tcl_Interp *interp, const char *varName, int flags); /* 253 */
int (*tcl_UnsetVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 254 */
void (*tcl_UntraceVar) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 255 */
void (*tcl_UntraceVar2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *proc, ClientData clientData); /* 256 */
void (*tcl_UpdateLinkedVar) (Tcl_Interp *interp, const char *varName); /* 257 */
int (*tcl_UpVar) (Tcl_Interp *interp, const char *frameName, const char *varName, const char *localName, int flags); /* 258 */
int (*tcl_UpVar2) (Tcl_Interp *interp, const char *frameName, const char *part1, const char *part2, const char *localName, int flags); /* 259 */
int (*tcl_VarEval) (Tcl_Interp *interp, ...); /* 260 */
ClientData (*tcl_VarTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 261 */
ClientData (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 262 */
int (*tcl_Write) (Tcl_Channel chan, const char *s, int slen); /* 263 */
void (*tcl_WrongNumArgs) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message); /* 264 */
int (*tcl_DumpActiveMemory) (const char *fileName); /* 265 */
void (*tcl_ValidateAllMemory) (const char *file, int line); /* 266 */
void (*tcl_AppendResultVA) (Tcl_Interp *interp, va_list argList); /* 267 */
void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */
char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */
CONST84_RETURN char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, CONST84 char **termPtr); /* 270 */
CONST84_RETURN char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */
CONST84_RETURN char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */
int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */
CONST84_RETURN char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */
void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */
int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */
Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */
void (*tcl_PanicVA) (const char *format, va_list argList); /* 278 */
void (*tcl_GetVersion) (int *major, int *minor, int *patchLevel, int *type); /* 279 */
void (*tcl_InitMemory) (Tcl_Interp *interp); /* 280 */
Tcl_Channel (*tcl_StackChannel) (Tcl_Interp *interp, const Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan); /* 281 */
int (*tcl_UnstackChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 282 */
Tcl_Channel (*tcl_GetStackedChannel) (Tcl_Channel chan); /* 283 */
void (*tcl_SetMainLoop) (Tcl_MainLoopProc *proc); /* 284 */
void (*reserved285)(void);
void (*tcl_AppendObjToObj) (Tcl_Obj *objPtr, Tcl_Obj *appendObjPtr); /* 286 */
Tcl_Encoding (*tcl_CreateEncoding) (const Tcl_EncodingType *typePtr); /* 287 */
void (*tcl_CreateThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 288 */
void (*tcl_DeleteThreadExitHandler) (Tcl_ExitProc *proc, ClientData clientData); /* 289 */
void (*tcl_DiscardResult) (Tcl_SavedResult *statePtr); /* 290 */
int (*tcl_EvalEx) (Tcl_Interp *interp, const char *script, int numBytes, int flags); /* 291 */
int (*tcl_EvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 292 */
int (*tcl_EvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 293 */
void (*tcl_ExitThread) (int status); /* 294 */
int (*tcl_ExternalToUtf) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 295 */
char * (*tcl_ExternalToUtfDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 296 */
void (*tcl_FinalizeThread) (void); /* 297 */
void (*tcl_FinalizeNotifier) (ClientData clientData); /* 298 */
void (*tcl_FreeEncoding) (Tcl_Encoding encoding); /* 299 */
Tcl_ThreadId (*tcl_GetCurrentThread) (void); /* 300 */
Tcl_Encoding (*tcl_GetEncoding) (Tcl_Interp *interp, const char *name); /* 301 */
CONST84_RETURN char * (*tcl_GetEncodingName) (Tcl_Encoding encoding); /* 302 */
void (*tcl_GetEncodingNames) (Tcl_Interp *interp); /* 303 */
int (*tcl_GetIndexFromObjStruct) (Tcl_Interp *interp, Tcl_Obj *objPtr, const void *tablePtr, int offset, const char *msg, int flags, int *indexPtr); /* 304 */
void * (*tcl_GetThreadData) (Tcl_ThreadDataKey *keyPtr, int size); /* 305 */
Tcl_Obj * (*tcl_GetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, int flags); /* 306 */
ClientData (*tcl_InitNotifier) (void); /* 307 */
void (*tcl_MutexLock) (Tcl_Mutex *mutexPtr); /* 308 */
void (*tcl_MutexUnlock) (Tcl_Mutex *mutexPtr); /* 309 */
void (*tcl_ConditionNotify) (Tcl_Condition *condPtr); /* 310 */
void (*tcl_ConditionWait) (Tcl_Condition *condPtr, Tcl_Mutex *mutexPtr, const Tcl_Time *timePtr); /* 311 */
int (*tcl_NumUtfChars) (const char *src, int length); /* 312 */
int (*tcl_ReadChars) (Tcl_Channel channel, Tcl_Obj *objPtr, int charsToRead, int appendFlag); /* 313 */
void (*tcl_RestoreResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 314 */
void (*tcl_SaveResult) (Tcl_Interp *interp, Tcl_SavedResult *statePtr); /* 315 */
int (*tcl_SetSystemEncoding) (Tcl_Interp *interp, const char *name); /* 316 */
Tcl_Obj * (*tcl_SetVar2Ex) (Tcl_Interp *interp, const char *part1, const char *part2, Tcl_Obj *newValuePtr, int flags); /* 317 */
void (*tcl_ThreadAlert) (Tcl_ThreadId threadId); /* 318 */
void (*tcl_ThreadQueueEvent) (Tcl_ThreadId threadId, Tcl_Event *evPtr, Tcl_QueuePosition position); /* 319 */
Tcl_UniChar (*tcl_UniCharAtIndex) (const char *src, int index); /* 320 */
Tcl_UniChar (*tcl_UniCharToLower) (int ch); /* 321 */
Tcl_UniChar (*tcl_UniCharToTitle) (int ch); /* 322 */
Tcl_UniChar (*tcl_UniCharToUpper) (int ch); /* 323 */
int (*tcl_UniCharToUtf) (int ch, char *buf); /* 324 */
CONST84_RETURN char * (*tcl_UtfAtIndex) (const char *src, int index); /* 325 */
int (*tcl_UtfCharComplete) (const char *src, int length); /* 326 */
int (*tcl_UtfBackslash) (const char *src, int *readPtr, char *dst); /* 327 */
CONST84_RETURN char * (*tcl_UtfFindFirst) (const char *src, int ch); /* 328 */
CONST84_RETURN char * (*tcl_UtfFindLast) (const char *src, int ch); /* 329 */
CONST84_RETURN char * (*tcl_UtfNext) (const char *src); /* 330 */
CONST84_RETURN char * (*tcl_UtfPrev) (const char *src, const char *start); /* 331 */
int (*tcl_UtfToExternal) (Tcl_Interp *interp, Tcl_Encoding encoding, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); /* 332 */
char * (*tcl_UtfToExternalDString) (Tcl_Encoding encoding, const char *src, int srcLen, Tcl_DString *dsPtr); /* 333 */
int (*tcl_UtfToLower) (char *src); /* 334 */
int (*tcl_UtfToTitle) (char *src); /* 335 */
int (*tcl_UtfToUniChar) (const char *src, Tcl_UniChar *chPtr); /* 336 */
int (*tcl_UtfToUpper) (char *src); /* 337 */
int (*tcl_WriteChars) (Tcl_Channel chan, const char *src, int srcLen); /* 338 */
int (*tcl_WriteObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 339 */
char * (*tcl_GetString) (Tcl_Obj *objPtr); /* 340 */
CONST84_RETURN char * (*tcl_GetDefaultEncodingDir) (void); /* 341 */
void (*tcl_SetDefaultEncodingDir) (const char *path); /* 342 */
void (*tcl_AlertNotifier) (ClientData clientData); /* 343 */
void (*tcl_ServiceModeHook) (int mode); /* 344 */
int (*tcl_UniCharIsAlnum) (int ch); /* 345 */
int (*tcl_UniCharIsAlpha) (int ch); /* 346 */
int (*tcl_UniCharIsDigit) (int ch); /* 347 */
int (*tcl_UniCharIsLower) (int ch); /* 348 */
int (*tcl_UniCharIsSpace) (int ch); /* 349 */
int (*tcl_UniCharIsUpper) (int ch); /* 350 */
int (*tcl_UniCharIsWordChar) (int ch); /* 351 */
int (*tcl_UniCharLen) (const Tcl_UniChar *uniStr); /* 352 */
int (*tcl_UniCharNcmp) (const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 353 */
char * (*tcl_UniCharToUtfDString) (const Tcl_UniChar *uniStr, int uniLength, Tcl_DString *dsPtr); /* 354 */
Tcl_UniChar * (*tcl_UtfToUniCharDString) (const char *src, int length, Tcl_DString *dsPtr); /* 355 */
Tcl_RegExp (*tcl_GetRegExpFromObj) (Tcl_Interp *interp, Tcl_Obj *patObj, int flags); /* 356 */
Tcl_Obj * (*tcl_EvalTokens) (Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 357 */
void (*tcl_FreeParse) (Tcl_Parse *parsePtr); /* 358 */
void (*tcl_LogCommandInfo) (Tcl_Interp *interp, const char *script, const char *command, int length); /* 359 */
int (*tcl_ParseBraces) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 360 */
int (*tcl_ParseCommand) (Tcl_Interp *interp, const char *start, int numBytes, int nested, Tcl_Parse *parsePtr); /* 361 */
int (*tcl_ParseExpr) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr); /* 362 */
int (*tcl_ParseQuotedString) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append, CONST84 char **termPtr); /* 363 */
int (*tcl_ParseVarName) (Tcl_Interp *interp, const char *start, int numBytes, Tcl_Parse *parsePtr, int append); /* 364 */
char * (*tcl_GetCwd) (Tcl_Interp *interp, Tcl_DString *cwdPtr); /* 365 */
int (*tcl_Chdir) (const char *dirName); /* 366 */
int (*tcl_Access) (const char *path, int mode); /* 367 */
int (*tcl_Stat) (const char *path, struct stat *bufPtr); /* 368 */
int (*tcl_UtfNcmp) (const char *s1, const char *s2, unsigned long n); /* 369 */
int (*tcl_UtfNcasecmp) (const char *s1, const char *s2, unsigned long n); /* 370 */
int (*tcl_StringCaseMatch) (const char *str, const char *pattern, int nocase); /* 371 */
int (*tcl_UniCharIsControl) (int ch); /* 372 */
int (*tcl_UniCharIsGraph) (int ch); /* 373 */
int (*tcl_UniCharIsPrint) (int ch); /* 374 */
int (*tcl_UniCharIsPunct) (int ch); /* 375 */
int (*tcl_RegExpExecObj) (Tcl_Interp *interp, Tcl_RegExp regexp, Tcl_Obj *textObj, int offset, int nmatches, int flags); /* 376 */
void (*tcl_RegExpGetInfo) (Tcl_RegExp regexp, Tcl_RegExpInfo *infoPtr); /* 377 */
Tcl_Obj * (*tcl_NewUnicodeObj) (const Tcl_UniChar *unicode, int numChars); /* 378 */
void (*tcl_SetUnicodeObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int numChars); /* 379 */
int (*tcl_GetCharLength) (Tcl_Obj *objPtr); /* 380 */
Tcl_UniChar (*tcl_GetUniChar) (Tcl_Obj *objPtr, int index); /* 381 */
Tcl_UniChar * (*tcl_GetUnicode) (Tcl_Obj *objPtr); /* 382 */
Tcl_Obj * (*tcl_GetRange) (Tcl_Obj *objPtr, int first, int last); /* 383 */
void (*tcl_AppendUnicodeToObj) (Tcl_Obj *objPtr, const Tcl_UniChar *unicode, int length); /* 384 */
int (*tcl_RegExpMatchObj) (Tcl_Interp *interp, Tcl_Obj *textObj, Tcl_Obj *patternObj); /* 385 */
void (*tcl_SetNotifier) (Tcl_NotifierProcs *notifierProcPtr); /* 386 */
Tcl_Mutex * (*tcl_GetAllocMutex) (void); /* 387 */
int (*tcl_GetChannelNames) (Tcl_Interp *interp); /* 388 */
int (*tcl_GetChannelNamesEx) (Tcl_Interp *interp, const char *pattern); /* 389 */
int (*tcl_ProcObjCmd) (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); /* 390 */
void (*tcl_ConditionFinalize) (Tcl_Condition *condPtr); /* 391 */
void (*tcl_MutexFinalize) (Tcl_Mutex *mutex); /* 392 */
int (*tcl_CreateThread) (Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, ClientData clientData, int stackSize, int flags); /* 393 */
int (*tcl_ReadRaw) (Tcl_Channel chan, char *dst, int bytesToRead); /* 394 */
int (*tcl_WriteRaw) (Tcl_Channel chan, const char *src, int srcLen); /* 395 */
Tcl_Channel (*tcl_GetTopChannel) (Tcl_Channel chan); /* 396 */
int (*tcl_ChannelBuffered) (Tcl_Channel chan); /* 397 */
CONST84_RETURN char * (*tcl_ChannelName) (const Tcl_ChannelType *chanTypePtr); /* 398 */
Tcl_ChannelTypeVersion (*tcl_ChannelVersion) (const Tcl_ChannelType *chanTypePtr); /* 399 */
Tcl_DriverBlockModeProc * (*tcl_ChannelBlockModeProc) (const Tcl_ChannelType *chanTypePtr); /* 400 */
Tcl_DriverCloseProc * (*tcl_ChannelCloseProc) (const Tcl_ChannelType *chanTypePtr); /* 401 */
Tcl_DriverClose2Proc * (*tcl_ChannelClose2Proc) (const Tcl_ChannelType *chanTypePtr); /* 402 */
Tcl_DriverInputProc * (*tcl_ChannelInputProc) (const Tcl_ChannelType *chanTypePtr); /* 403 */
Tcl_DriverOutputProc * (*tcl_ChannelOutputProc) (const Tcl_ChannelType *chanTypePtr); /* 404 */
Tcl_DriverSeekProc * (*tcl_ChannelSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 405 */
Tcl_DriverSetOptionProc * (*tcl_ChannelSetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 406 */
Tcl_DriverGetOptionProc * (*tcl_ChannelGetOptionProc) (const Tcl_ChannelType *chanTypePtr); /* 407 */
Tcl_DriverWatchProc * (*tcl_ChannelWatchProc) (const Tcl_ChannelType *chanTypePtr); /* 408 */
Tcl_DriverGetHandleProc * (*tcl_ChannelGetHandleProc) (const Tcl_ChannelType *chanTypePtr); /* 409 */
Tcl_DriverFlushProc * (*tcl_ChannelFlushProc) (const Tcl_ChannelType *chanTypePtr); /* 410 */
Tcl_DriverHandlerProc * (*tcl_ChannelHandlerProc) (const Tcl_ChannelType *chanTypePtr); /* 411 */
int (*tcl_JoinThread) (Tcl_ThreadId threadId, int *result); /* 412 */
int (*tcl_IsChannelShared) (Tcl_Channel channel); /* 413 */
int (*tcl_IsChannelRegistered) (Tcl_Interp *interp, Tcl_Channel channel); /* 414 */
void (*tcl_CutChannel) (Tcl_Channel channel); /* 415 */
void (*tcl_SpliceChannel) (Tcl_Channel channel); /* 416 */
void (*tcl_ClearChannelHandlers) (Tcl_Channel channel); /* 417 */
int (*tcl_IsChannelExisting) (const char *channelName); /* 418 */
int (*tcl_UniCharNcasecmp) (const Tcl_UniChar *ucs, const Tcl_UniChar *uct, unsigned long numChars); /* 419 */
int (*tcl_UniCharCaseMatch) (const Tcl_UniChar *uniStr, const Tcl_UniChar *uniPattern, int nocase); /* 420 */
Tcl_HashEntry * (*tcl_FindHashEntry) (Tcl_HashTable *tablePtr, const void *key); /* 421 */
Tcl_HashEntry * (*tcl_CreateHashEntry) (Tcl_HashTable *tablePtr, const void *key, int *newPtr); /* 422 */
void (*tcl_InitCustomHashTable) (Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 423 */
void (*tcl_InitObjHashTable) (Tcl_HashTable *tablePtr); /* 424 */
ClientData (*tcl_CommandTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, ClientData prevClientData); /* 425 */
int (*tcl_TraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 426 */
void (*tcl_UntraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, ClientData clientData); /* 427 */
char * (*tcl_AttemptAlloc) (unsigned int size); /* 428 */
char * (*tcl_AttemptDbCkalloc) (unsigned int size, const char *file, int line); /* 429 */
char * (*tcl_AttemptRealloc) (char *ptr, unsigned int size); /* 430 */
char * (*tcl_AttemptDbCkrealloc) (char *ptr, unsigned int size, const char *file, int line); /* 431 */
int (*tcl_AttemptSetObjLength) (Tcl_Obj *objPtr, int length); /* 432 */
Tcl_ThreadId (*tcl_GetChannelThread) (Tcl_Channel channel); /* 433 */
Tcl_UniChar * (*tcl_GetUnicodeFromObj) (Tcl_Obj *objPtr, int *lengthPtr); /* 434 */
int (*tcl_GetMathFuncInfo) (Tcl_Interp *interp, const char *name, int *numArgsPtr, Tcl_ValueType **argTypesPtr, Tcl_MathProc **procPtr, ClientData *clientDataPtr); /* 435 */
Tcl_Obj * (*tcl_ListMathFuncs) (Tcl_Interp *interp, const char *pattern); /* 436 */
Tcl_Obj * (*tcl_SubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 437 */
int (*tcl_DetachChannel) (Tcl_Interp *interp, Tcl_Channel channel); /* 438 */
int (*tcl_IsStandardChannel) (Tcl_Channel channel); /* 439 */
int (*tcl_FSCopyFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 440 */
int (*tcl_FSCopyDirectory) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr); /* 441 */
int (*tcl_FSCreateDirectory) (Tcl_Obj *pathPtr); /* 442 */
int (*tcl_FSDeleteFile) (Tcl_Obj *pathPtr); /* 443 */
int (*tcl_FSLoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *sym1, const char *sym2, Tcl_PackageInitProc **proc1Ptr, Tcl_PackageInitProc **proc2Ptr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); /* 444 */
int (*tcl_FSMatchInDirectory) (Tcl_Interp *interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types); /* 445 */
Tcl_Obj * (*tcl_FSLink) (Tcl_Obj *pathPtr, Tcl_Obj *toPtr, int linkAction); /* 446 */
int (*tcl_FSRemoveDirectory) (Tcl_Obj *pathPtr, int recursive, Tcl_Obj **errorPtr); /* 447 */
int (*tcl_FSRenameFile) (Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr); /* 448 */
int (*tcl_FSLstat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 449 */
int (*tcl_FSUtime) (Tcl_Obj *pathPtr, struct utimbuf *tval); /* 450 */
int (*tcl_FSFileAttrsGet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 451 */
int (*tcl_FSFileAttrsSet) (Tcl_Interp *interp, int index, Tcl_Obj *pathPtr, Tcl_Obj *objPtr); /* 452 */
const char *CONST86 * (*tcl_FSFileAttrStrings) (Tcl_Obj *pathPtr, Tcl_Obj **objPtrRef); /* 453 */
int (*tcl_FSStat) (Tcl_Obj *pathPtr, Tcl_StatBuf *buf); /* 454 */
int (*tcl_FSAccess) (Tcl_Obj *pathPtr, int mode); /* 455 */
Tcl_Channel (*tcl_FSOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *modeString, int permissions); /* 456 */
Tcl_Obj * (*tcl_FSGetCwd) (Tcl_Interp *interp); /* 457 */
int (*tcl_FSChdir) (Tcl_Obj *pathPtr); /* 458 */
int (*tcl_FSConvertToPathType) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 459 */
Tcl_Obj * (*tcl_FSJoinPath) (Tcl_Obj *listObj, int elements); /* 460 */
Tcl_Obj * (*tcl_FSSplitPath) (Tcl_Obj *pathPtr, int *lenPtr); /* 461 */
int (*tcl_FSEqualPaths) (Tcl_Obj *firstPtr, Tcl_Obj *secondPtr); /* 462 */
Tcl_Obj * (*tcl_FSGetNormalizedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 463 */
Tcl_Obj * (*tcl_FSJoinToPath) (Tcl_Obj *pathPtr, int objc, Tcl_Obj *const objv[]); /* 464 */
ClientData (*tcl_FSGetInternalRep) (Tcl_Obj *pathPtr, const Tcl_Filesystem *fsPtr); /* 465 */
Tcl_Obj * (*tcl_FSGetTranslatedPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 466 */
int (*tcl_FSEvalFile) (Tcl_Interp *interp, Tcl_Obj *fileName); /* 467 */
Tcl_Obj * (*tcl_FSNewNativePath) (const Tcl_Filesystem *fromFilesystem, ClientData clientData); /* 468 */
const void * (*tcl_FSGetNativePath) (Tcl_Obj *pathPtr); /* 469 */
Tcl_Obj * (*tcl_FSFileSystemInfo) (Tcl_Obj *pathPtr); /* 470 */
Tcl_Obj * (*tcl_FSPathSeparator) (Tcl_Obj *pathPtr); /* 471 */
Tcl_Obj * (*tcl_FSListVolumes) (void); /* 472 */
int (*tcl_FSRegister) (ClientData clientData, const Tcl_Filesystem *fsPtr); /* 473 */
int (*tcl_FSUnregister) (const Tcl_Filesystem *fsPtr); /* 474 */
ClientData (*tcl_FSData) (const Tcl_Filesystem *fsPtr); /* 475 */
const char * (*tcl_FSGetTranslatedStringPath) (Tcl_Interp *interp, Tcl_Obj *pathPtr); /* 476 */
CONST86 Tcl_Filesystem * (*tcl_FSGetFileSystemForPath) (Tcl_Obj *pathPtr); /* 477 */
Tcl_PathType (*tcl_FSGetPathType) (Tcl_Obj *pathPtr); /* 478 */
int (*tcl_OutputBuffered) (Tcl_Channel chan); /* 479 */
void (*tcl_FSMountsChanged) (const Tcl_Filesystem *fsPtr); /* 480 */
int (*tcl_EvalTokensStandard) (Tcl_Interp *interp, Tcl_Token *tokenPtr, int count); /* 481 */
void (*tcl_GetTime) (Tcl_Time *timeBuf); /* 482 */
Tcl_Trace (*tcl_CreateObjTrace) (Tcl_Interp *interp, int level, int flags, Tcl_CmdObjTraceProc *objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc *delProc); /* 483 */
int (*tcl_GetCommandInfoFromToken) (Tcl_Command token, Tcl_CmdInfo *infoPtr); /* 484 */
int (*tcl_SetCommandInfoFromToken) (Tcl_Command token, const Tcl_CmdInfo *infoPtr); /* 485 */
Tcl_Obj * (*tcl_DbNewWideIntObj) (Tcl_WideInt wideValue, const char *file, int line); /* 486 */
int (*tcl_GetWideIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideInt *widePtr); /* 487 */
Tcl_Obj * (*tcl_NewWideIntObj) (Tcl_WideInt wideValue); /* 488 */
void (*tcl_SetWideIntObj) (Tcl_Obj *objPtr, Tcl_WideInt wideValue); /* 489 */
Tcl_StatBuf * (*tcl_AllocStatBuf) (void); /* 490 */
Tcl_WideInt (*tcl_Seek) (Tcl_Channel chan, Tcl_WideInt offset, int mode); /* 491 */
Tcl_WideInt (*tcl_Tell) (Tcl_Channel chan); /* 492 */
Tcl_DriverWideSeekProc * (*tcl_ChannelWideSeekProc) (const Tcl_ChannelType *chanTypePtr); /* 493 */
int (*tcl_DictObjPut) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj *valuePtr); /* 494 */
int (*tcl_DictObjGet) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr); /* 495 */
int (*tcl_DictObjRemove) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_Obj *keyPtr); /* 496 */
int (*tcl_DictObjSize) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int *sizePtr); /* 497 */
int (*tcl_DictObjFirst) (Tcl_Interp *interp, Tcl_Obj *dictPtr, Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 498 */
void (*tcl_DictObjNext) (Tcl_DictSearch *searchPtr, Tcl_Obj **keyPtrPtr, Tcl_Obj **valuePtrPtr, int *donePtr); /* 499 */
void (*tcl_DictObjDone) (Tcl_DictSearch *searchPtr); /* 500 */
int (*tcl_DictObjPutKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv, Tcl_Obj *valuePtr); /* 501 */
int (*tcl_DictObjRemoveKeyList) (Tcl_Interp *interp, Tcl_Obj *dictPtr, int keyc, Tcl_Obj *const *keyv); /* 502 */
Tcl_Obj * (*tcl_NewDictObj) (void); /* 503 */
Tcl_Obj * (*tcl_DbNewDictObj) (const char *file, int line); /* 504 */
void (*tcl_RegisterConfig) (Tcl_Interp *interp, const char *pkgName, const Tcl_Config *configuration, const char *valEncoding); /* 505 */
Tcl_Namespace * (*tcl_CreateNamespace) (Tcl_Interp *interp, const char *name, ClientData clientData, Tcl_NamespaceDeleteProc *deleteProc); /* 506 */
void (*tcl_DeleteNamespace) (Tcl_Namespace *nsPtr); /* 507 */
int (*tcl_AppendExportList) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *objPtr); /* 508 */
int (*tcl_Export) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int resetListFirst); /* 509 */
int (*tcl_Import) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern, int allowOverwrite); /* 510 */
int (*tcl_ForgetImport) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *pattern); /* 511 */
Tcl_Namespace * (*tcl_GetCurrentNamespace) (Tcl_Interp *interp); /* 512 */
Tcl_Namespace * (*tcl_GetGlobalNamespace) (Tcl_Interp *interp); /* 513 */
Tcl_Namespace * (*tcl_FindNamespace) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 514 */
Tcl_Command (*tcl_FindCommand) (Tcl_Interp *interp, const char *name, Tcl_Namespace *contextNsPtr, int flags); /* 515 */
Tcl_Command (*tcl_GetCommandFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 516 */
void (*tcl_GetCommandFullName) (Tcl_Interp *interp, Tcl_Command command, Tcl_Obj *objPtr); /* 517 */
int (*tcl_FSEvalFileEx) (Tcl_Interp *interp, Tcl_Obj *fileName, const char *encodingName); /* 518 */
Tcl_ExitProc * (*tcl_SetExitProc) (Tcl_ExitProc *proc); /* 519 */
void (*tcl_LimitAddHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData, Tcl_LimitHandlerDeleteProc *deleteProc); /* 520 */
void (*tcl_LimitRemoveHandler) (Tcl_Interp *interp, int type, Tcl_LimitHandlerProc *handlerProc, ClientData clientData); /* 521 */
int (*tcl_LimitReady) (Tcl_Interp *interp); /* 522 */
int (*tcl_LimitCheck) (Tcl_Interp *interp); /* 523 */
int (*tcl_LimitExceeded) (Tcl_Interp *interp); /* 524 */
void (*tcl_LimitSetCommands) (Tcl_Interp *interp, int commandLimit); /* 525 */
void (*tcl_LimitSetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 526 */
void (*tcl_LimitSetGranularity) (Tcl_Interp *interp, int type, int granularity); /* 527 */
int (*tcl_LimitTypeEnabled) (Tcl_Interp *interp, int type); /* 528 */
int (*tcl_LimitTypeExceeded) (Tcl_Interp *interp, int type); /* 529 */
void (*tcl_LimitTypeSet) (Tcl_Interp *interp, int type); /* 530 */
void (*tcl_LimitTypeReset) (Tcl_Interp *interp, int type); /* 531 */
int (*tcl_LimitGetCommands) (Tcl_Interp *interp); /* 532 */
void (*tcl_LimitGetTime) (Tcl_Interp *interp, Tcl_Time *timeLimitPtr); /* 533 */
int (*tcl_LimitGetGranularity) (Tcl_Interp *interp, int type); /* 534 */
Tcl_InterpState (*tcl_SaveInterpState) (Tcl_Interp *interp, int status); /* 535 */
int (*tcl_RestoreInterpState) (Tcl_Interp *interp, Tcl_InterpState state); /* 536 */
void (*tcl_DiscardInterpState) (Tcl_InterpState state); /* 537 */
int (*tcl_SetReturnOptions) (Tcl_Interp *interp, Tcl_Obj *options); /* 538 */
Tcl_Obj * (*tcl_GetReturnOptions) (Tcl_Interp *interp, int result); /* 539 */
int (*tcl_IsEnsemble) (Tcl_Command token); /* 540 */
Tcl_Command (*tcl_CreateEnsemble) (Tcl_Interp *interp, const char *name, Tcl_Namespace *namespacePtr, int flags); /* 541 */
Tcl_Command (*tcl_FindEnsemble) (Tcl_Interp *interp, Tcl_Obj *cmdNameObj, int flags); /* 542 */
int (*tcl_SetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *subcmdList); /* 543 */
int (*tcl_SetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *mapDict); /* 544 */
int (*tcl_SetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 545 */
int (*tcl_SetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int flags); /* 546 */
int (*tcl_GetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 547 */
int (*tcl_GetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 548 */
int (*tcl_GetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 549 */
int (*tcl_GetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 550 */
int (*tcl_GetEnsembleNamespace) (Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 551 */
void (*tcl_SetTimeProc) (Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, ClientData clientData); /* 552 */
void (*tcl_QueryTimeProc) (Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, ClientData *clientData); /* 553 */
Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) (const Tcl_ChannelType *chanTypePtr); /* 554 */
Tcl_Obj * (*tcl_NewBignumObj) (mp_int *value); /* 555 */
Tcl_Obj * (*tcl_DbNewBignumObj) (mp_int *value, const char *file, int line); /* 556 */
void (*tcl_SetBignumObj) (Tcl_Obj *obj, mp_int *value); /* 557 */
int (*tcl_GetBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 558 */
int (*tcl_TakeBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, mp_int *value); /* 559 */
int (*tcl_TruncateChannel) (Tcl_Channel chan, Tcl_WideInt length); /* 560 */
Tcl_DriverTruncateProc * (*tcl_ChannelTruncateProc) (const Tcl_ChannelType *chanTypePtr); /* 561 */
void (*tcl_SetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj *msg); /* 562 */
void (*tcl_GetChannelErrorInterp) (Tcl_Interp *interp, Tcl_Obj **msg); /* 563 */
void (*tcl_SetChannelError) (Tcl_Channel chan, Tcl_Obj *msg); /* 564 */
void (*tcl_GetChannelError) (Tcl_Channel chan, Tcl_Obj **msg); /* 565 */
int (*tcl_InitBignumFromDouble) (Tcl_Interp *interp, double initval, mp_int *toInit); /* 566 */
Tcl_Obj * (*tcl_GetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr); /* 567 */
int (*tcl_SetNamespaceUnknownHandler) (Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *handlerPtr); /* 568 */
int (*tcl_GetEncodingFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Encoding *encodingPtr); /* 569 */
Tcl_Obj * (*tcl_GetEncodingSearchPath) (void); /* 570 */
int (*tcl_SetEncodingSearchPath) (Tcl_Obj *searchPath); /* 571 */
const char * (*tcl_GetEncodingNameFromEnvironment) (Tcl_DString *bufPtr); /* 572 */
int (*tcl_PkgRequireProc) (Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *const objv[], void *clientDataPtr); /* 573 */
void (*tcl_AppendObjToErrorInfo) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 574 */
void (*tcl_AppendLimitedToObj) (Tcl_Obj *objPtr, const char *bytes, int length, int limit, const char *ellipsis); /* 575 */
Tcl_Obj * (*tcl_Format) (Tcl_Interp *interp, const char *format, int objc, Tcl_Obj *const objv[]); /* 576 */
int (*tcl_AppendFormatToObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, const char *format, int objc, Tcl_Obj *const objv[]); /* 577 */
Tcl_Obj * (*tcl_ObjPrintf) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 578 */
void (*tcl_AppendPrintfToObj) (Tcl_Obj *objPtr, const char *format, ...) TCL_FORMAT_PRINTF(2, 3); /* 579 */
int (*tcl_CancelEval) (Tcl_Interp *interp, Tcl_Obj *resultObjPtr, ClientData clientData, int flags); /* 580 */
int (*tcl_Canceled) (Tcl_Interp *interp, int flags); /* 581 */
int (*tcl_CreatePipe) (Tcl_Interp *interp, Tcl_Channel *rchan, Tcl_Channel *wchan, int flags); /* 582 */
Tcl_Command (*tcl_NRCreateCommand) (Tcl_Interp *interp, const char *cmdName, Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc, ClientData clientData, Tcl_CmdDeleteProc *deleteProc); /* 583 */
int (*tcl_NREvalObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 584 */
int (*tcl_NREvalObjv) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int flags); /* 585 */
int (*tcl_NRCmdSwap) (Tcl_Interp *interp, Tcl_Command cmd, int objc, Tcl_Obj *const objv[], int flags); /* 586 */
void (*tcl_NRAddCallback) (Tcl_Interp *interp, Tcl_NRPostProc *postProcPtr, ClientData data0, ClientData data1, ClientData data2, ClientData data3); /* 587 */
int (*tcl_NRCallObjProc) (Tcl_Interp *interp, Tcl_ObjCmdProc *objProc, ClientData clientData, int objc, Tcl_Obj *const objv[]); /* 588 */
unsigned (*tcl_GetFSDeviceFromStat) (const Tcl_StatBuf *statPtr); /* 589 */
unsigned (*tcl_GetFSInodeFromStat) (const Tcl_StatBuf *statPtr); /* 590 */
unsigned (*tcl_GetModeFromStat) (const Tcl_StatBuf *statPtr); /* 591 */
int (*tcl_GetLinkCountFromStat) (const Tcl_StatBuf *statPtr); /* 592 */
int (*tcl_GetUserIdFromStat) (const Tcl_StatBuf *statPtr); /* 593 */
int (*tcl_GetGroupIdFromStat) (const Tcl_StatBuf *statPtr); /* 594 */
int (*tcl_GetDeviceTypeFromStat) (const Tcl_StatBuf *statPtr); /* 595 */
Tcl_WideInt (*tcl_GetAccessTimeFromStat) (const Tcl_StatBuf *statPtr); /* 596 */
Tcl_WideInt (*tcl_GetModificationTimeFromStat) (const Tcl_StatBuf *statPtr); /* 597 */
Tcl_WideInt (*tcl_GetChangeTimeFromStat) (const Tcl_StatBuf *statPtr); /* 598 */
Tcl_WideUInt (*tcl_GetSizeFromStat) (const Tcl_StatBuf *statPtr); /* 599 */
Tcl_WideUInt (*tcl_GetBlocksFromStat) (const Tcl_StatBuf *statPtr); /* 600 */
unsigned (*tcl_GetBlockSizeFromStat) (const Tcl_StatBuf *statPtr); /* 601 */
int (*tcl_SetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *paramList); /* 602 */
int (*tcl_GetEnsembleParameterList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr); /* 603 */
int (*tcl_ParseArgsObjv) (Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, int *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remObjv); /* 604 */
int (*tcl_GetErrorLine) (Tcl_Interp *interp); /* 605 */
void (*tcl_SetErrorLine) (Tcl_Interp *interp, int lineNum); /* 606 */
void (*tcl_TransferResult) (Tcl_Interp *sourceInterp, int result, Tcl_Interp *targetInterp); /* 607 */
int (*tcl_InterpActive) (Tcl_Interp *interp); /* 608 */
void (*tcl_BackgroundException) (Tcl_Interp *interp, int code); /* 609 */
int (*tcl_ZlibDeflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int level, Tcl_Obj *gzipHeaderDictObj); /* 610 */
int (*tcl_ZlibInflate) (Tcl_Interp *interp, int format, Tcl_Obj *data, int buffersize, Tcl_Obj *gzipHeaderDictObj); /* 611 */
unsigned int (*tcl_ZlibCRC32) (unsigned int crc, const unsigned char *buf, int len); /* 612 */
unsigned int (*tcl_ZlibAdler32) (unsigned int adler, const unsigned char *buf, int len); /* 613 */
int (*tcl_ZlibStreamInit) (Tcl_Interp *interp, int mode, int format, int level, Tcl_Obj *dictObj, Tcl_ZlibStream *zshandle); /* 614 */
Tcl_Obj * (*tcl_ZlibStreamGetCommandName) (Tcl_ZlibStream zshandle); /* 615 */
int (*tcl_ZlibStreamEof) (Tcl_ZlibStream zshandle); /* 616 */
int (*tcl_ZlibStreamChecksum) (Tcl_ZlibStream zshandle); /* 617 */
int (*tcl_ZlibStreamPut) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int flush); /* 618 */
int (*tcl_ZlibStreamGet) (Tcl_ZlibStream zshandle, Tcl_Obj *data, int count); /* 619 */
int (*tcl_ZlibStreamClose) (Tcl_ZlibStream zshandle); /* 620 */
int (*tcl_ZlibStreamReset) (Tcl_ZlibStream zshandle); /* 621 */
void (*tcl_SetStartupScript) (Tcl_Obj *path, const char *encoding); /* 622 */
Tcl_Obj * (*tcl_GetStartupScript) (const char **encodingPtr); /* 623 */
int (*tcl_CloseEx) (Tcl_Interp *interp, Tcl_Channel chan, int flags); /* 624 */
int (*tcl_NRExprObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *resultPtr); /* 625 */
int (*tcl_NRSubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 626 */
int (*tcl_LoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 627 */
void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */
int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */
void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */
} TclStubs;
#ifdef __cplusplus
extern "C" {
#endif
extern const TclStubs *tclStubsPtr;
#ifdef __cplusplus
}
#endif
#if defined(USE_TCL_STUBS)
/*
* Inline function declarations:
*/
#define Tcl_PkgProvideEx \
(tclStubsPtr->tcl_PkgProvideEx) /* 0 */
#define Tcl_PkgRequireEx \
(tclStubsPtr->tcl_PkgRequireEx) /* 1 */
#define Tcl_Panic \
(tclStubsPtr->tcl_Panic) /* 2 */
#define Tcl_Alloc \
(tclStubsPtr->tcl_Alloc) /* 3 */
#define Tcl_Free \
(tclStubsPtr->tcl_Free) /* 4 */
#define Tcl_Realloc \
(tclStubsPtr->tcl_Realloc) /* 5 */
#define Tcl_DbCkalloc \
(tclStubsPtr->tcl_DbCkalloc) /* 6 */
#define Tcl_DbCkfree \
(tclStubsPtr->tcl_DbCkfree) /* 7 */
#define Tcl_DbCkrealloc \
(tclStubsPtr->tcl_DbCkrealloc) /* 8 */
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
#define Tcl_CreateFileHandler \
(tclStubsPtr->tcl_CreateFileHandler) /* 9 */
#endif /* UNIX */
#ifdef MAC_OSX_TCL /* MACOSX */
#define Tcl_CreateFileHandler \
(tclStubsPtr->tcl_CreateFileHandler) /* 9 */
#endif /* MACOSX */
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
#define Tcl_DeleteFileHandler \
(tclStubsPtr->tcl_DeleteFileHandler) /* 10 */
#endif /* UNIX */
#ifdef MAC_OSX_TCL /* MACOSX */
#define Tcl_DeleteFileHandler \
(tclStubsPtr->tcl_DeleteFileHandler) /* 10 */
#endif /* MACOSX */
#define Tcl_SetTimer \
(tclStubsPtr->tcl_SetTimer) /* 11 */
#define Tcl_Sleep \
(tclStubsPtr->tcl_Sleep) /* 12 */
#define Tcl_WaitForEvent \
(tclStubsPtr->tcl_WaitForEvent) /* 13 */
#define Tcl_AppendAllObjTypes \
(tclStubsPtr->tcl_AppendAllObjTypes) /* 14 */
#define Tcl_AppendStringsToObj \
(tclStubsPtr->tcl_AppendStringsToObj) /* 15 */
#define Tcl_AppendToObj \
(tclStubsPtr->tcl_AppendToObj) /* 16 */
#define Tcl_ConcatObj \
(tclStubsPtr->tcl_ConcatObj) /* 17 */
#define Tcl_ConvertToType \
(tclStubsPtr->tcl_ConvertToType) /* 18 */
#define Tcl_DbDecrRefCount \
(tclStubsPtr->tcl_DbDecrRefCount) /* 19 */
#define Tcl_DbIncrRefCount \
(tclStubsPtr->tcl_DbIncrRefCount) /* 20 */
#define Tcl_DbIsShared \
(tclStubsPtr->tcl_DbIsShared) /* 21 */
#define Tcl_DbNewBooleanObj \
(tclStubsPtr->tcl_DbNewBooleanObj) /* 22 */
#define Tcl_DbNewByteArrayObj \
(tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */
#define Tcl_DbNewDoubleObj \
(tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */
#define Tcl_DbNewListObj \
(tclStubsPtr->tcl_DbNewListObj) /* 25 */
#define Tcl_DbNewLongObj \
(tclStubsPtr->tcl_DbNewLongObj) /* 26 */
#define Tcl_DbNewObj \
(tclStubsPtr->tcl_DbNewObj) /* 27 */
#define Tcl_DbNewStringObj \
(tclStubsPtr->tcl_DbNewStringObj) /* 28 */
#define Tcl_DuplicateObj \
(tclStubsPtr->tcl_DuplicateObj) /* 29 */
#define TclFreeObj \
(tclStubsPtr->tclFreeObj) /* 30 */
#define Tcl_GetBoolean \
(tclStubsPtr->tcl_GetBoolean) /* 31 */
#define Tcl_GetBooleanFromObj \
(tclStubsPtr->tcl_GetBooleanFromObj) /* 32 */
#define Tcl_GetByteArrayFromObj \
(tclStubsPtr->tcl_GetByteArrayFromObj) /* 33 */
#define Tcl_GetDouble \
(tclStubsPtr->tcl_GetDouble) /* 34 */
#define Tcl_GetDoubleFromObj \
(tclStubsPtr->tcl_GetDoubleFromObj) /* 35 */
#define Tcl_GetIndexFromObj \
(tclStubsPtr->tcl_GetIndexFromObj) /* 36 */
#define Tcl_GetInt \
(tclStubsPtr->tcl_GetInt) /* 37 */
#define Tcl_GetIntFromObj \
(tclStubsPtr->tcl_GetIntFromObj) /* 38 */
#define Tcl_GetLongFromObj \
(tclStubsPtr->tcl_GetLongFromObj) /* 39 */
#define Tcl_GetObjType \
(tclStubsPtr->tcl_GetObjType) /* 40 */
#define Tcl_GetStringFromObj \
(tclStubsPtr->tcl_GetStringFromObj) /* 41 */
#define Tcl_InvalidateStringRep \
(tclStubsPtr->tcl_InvalidateStringRep) /* 42 */
#define Tcl_ListObjAppendList \
(tclStubsPtr->tcl_ListObjAppendList) /* 43 */
#define Tcl_ListObjAppendElement \
(tclStubsPtr->tcl_ListObjAppendElement) /* 44 */
#define Tcl_ListObjGetElements \
(tclStubsPtr->tcl_ListObjGetElements) /* 45 */
#define Tcl_ListObjIndex \
(tclStubsPtr->tcl_ListObjIndex) /* 46 */
#define Tcl_ListObjLength \
(tclStubsPtr->tcl_ListObjLength) /* 47 */
#define Tcl_ListObjReplace \
(tclStubsPtr->tcl_ListObjReplace) /* 48 */
#define Tcl_NewBooleanObj \
(tclStubsPtr->tcl_NewBooleanObj) /* 49 */
#define Tcl_NewByteArrayObj \
(tclStubsPtr->tcl_NewByteArrayObj) /* 50 */
#define Tcl_NewDoubleObj \
(tclStubsPtr->tcl_NewDoubleObj) /* 51 */
#define Tcl_NewIntObj \
(tclStubsPtr->tcl_NewIntObj) /* 52 */
#define Tcl_NewListObj \
(tclStubsPtr->tcl_NewListObj) /* 53 */
#define Tcl_NewLongObj \
(tclStubsPtr->tcl_NewLongObj) /* 54 */
#define Tcl_NewObj \
(tclStubsPtr->tcl_NewObj) /* 55 */
#define Tcl_NewStringObj \
(tclStubsPtr->tcl_NewStringObj) /* 56 */
#define Tcl_SetBooleanObj \
(tclStubsPtr->tcl_SetBooleanObj) /* 57 */
#define Tcl_SetByteArrayLength \
(tclStubsPtr->tcl_SetByteArrayLength) /* 58 */
#define Tcl_SetByteArrayObj \
(tclStubsPtr->tcl_SetByteArrayObj) /* 59 */
#define Tcl_SetDoubleObj \
(tclStubsPtr->tcl_SetDoubleObj) /* 60 */
#define Tcl_SetIntObj \
(tclStubsPtr->tcl_SetIntObj) /* 61 */
#define Tcl_SetListObj \
(tclStubsPtr->tcl_SetListObj) /* 62 */
#define Tcl_SetLongObj \
(tclStubsPtr->tcl_SetLongObj) /* 63 */
#define Tcl_SetObjLength \
(tclStubsPtr->tcl_SetObjLength) /* 64 */
#define Tcl_SetStringObj \
(tclStubsPtr->tcl_SetStringObj) /* 65 */
#define Tcl_AddErrorInfo \
(tclStubsPtr->tcl_AddErrorInfo) /* 66 */
#define Tcl_AddObjErrorInfo \
(tclStubsPtr->tcl_AddObjErrorInfo) /* 67 */
#define Tcl_AllowExceptions \
(tclStubsPtr->tcl_AllowExceptions) /* 68 */
#define Tcl_AppendElement \
(tclStubsPtr->tcl_AppendElement) /* 69 */
#define Tcl_AppendResult \
(tclStubsPtr->tcl_AppendResult) /* 70 */
#define Tcl_AsyncCreate \
(tclStubsPtr->tcl_AsyncCreate) /* 71 */
#define Tcl_AsyncDelete \
(tclStubsPtr->tcl_AsyncDelete) /* 72 */
#define Tcl_AsyncInvoke \
(tclStubsPtr->tcl_AsyncInvoke) /* 73 */
#define Tcl_AsyncMark \
(tclStubsPtr->tcl_AsyncMark) /* 74 */
#define Tcl_AsyncReady \
(tclStubsPtr->tcl_AsyncReady) /* 75 */
#define Tcl_BackgroundError \
(tclStubsPtr->tcl_BackgroundError) /* 76 */
#define Tcl_Backslash \
(tclStubsPtr->tcl_Backslash) /* 77 */
#define Tcl_BadChannelOption \
(tclStubsPtr->tcl_BadChannelOption) /* 78 */
#define Tcl_CallWhenDeleted \
(tclStubsPtr->tcl_CallWhenDeleted) /* 79 */
#define Tcl_CancelIdleCall \
(tclStubsPtr->tcl_CancelIdleCall) /* 80 */
#define Tcl_Close \
(tclStubsPtr->tcl_Close) /* 81 */
#define Tcl_CommandComplete \
(tclStubsPtr->tcl_CommandComplete) /* 82 */
#define Tcl_Concat \
(tclStubsPtr->tcl_Concat) /* 83 */
#define Tcl_ConvertElement \
(tclStubsPtr->tcl_ConvertElement) /* 84 */
#define Tcl_ConvertCountedElement \
(tclStubsPtr->tcl_ConvertCountedElement) /* 85 */
#define Tcl_CreateAlias \
(tclStubsPtr->tcl_CreateAlias) /* 86 */
#define Tcl_CreateAliasObj \
(tclStubsPtr->tcl_CreateAliasObj) /* 87 */
#define Tcl_CreateChannel \
(tclStubsPtr->tcl_CreateChannel) /* 88 */
#define Tcl_CreateChannelHandler \
(tclStubsPtr->tcl_CreateChannelHandler) /* 89 */
#define Tcl_CreateCloseHandler \
(tclStubsPtr->tcl_CreateCloseHandler) /* 90 */
#define Tcl_CreateCommand \
(tclStubsPtr->tcl_CreateCommand) /* 91 */
#define Tcl_CreateEventSource \
(tclStubsPtr->tcl_CreateEventSource) /* 92 */
#define Tcl_CreateExitHandler \
(tclStubsPtr->tcl_CreateExitHandler) /* 93 */
#define Tcl_CreateInterp \
(tclStubsPtr->tcl_CreateInterp) /* 94 */
#define Tcl_CreateMathFunc \
(tclStubsPtr->tcl_CreateMathFunc) /* 95 */
#define Tcl_CreateObjCommand \
(tclStubsPtr->tcl_CreateObjCommand) /* 96 */
#define Tcl_CreateSlave \
(tclStubsPtr->tcl_CreateSlave) /* 97 */
#define Tcl_CreateTimerHandler \
(tclStubsPtr->tcl_CreateTimerHandler) /* 98 */
#define Tcl_CreateTrace \
(tclStubsPtr->tcl_CreateTrace) /* 99 */
#define Tcl_DeleteAssocData \
(tclStubsPtr->tcl_DeleteAssocData) /* 100 */
#define Tcl_DeleteChannelHandler \
(tclStubsPtr->tcl_DeleteChannelHandler) /* 101 */
#define Tcl_DeleteCloseHandler \
(tclStubsPtr->tcl_DeleteCloseHandler) /* 102 */
#define Tcl_DeleteCommand \
(tclStubsPtr->tcl_DeleteCommand) /* 103 */
#define Tcl_DeleteCommandFromToken \
(tclStubsPtr->tcl_DeleteCommandFromToken) /* 104 */
#define Tcl_DeleteEvents \
(tclStubsPtr->tcl_DeleteEvents) /* 105 */
#define Tcl_DeleteEventSource \
(tclStubsPtr->tcl_DeleteEventSource) /* 106 */
#define Tcl_DeleteExitHandler \
(tclStubsPtr->tcl_DeleteExitHandler) /* 107 */
#define Tcl_DeleteHashEntry \
(tclStubsPtr->tcl_DeleteHashEntry) /* 108 */
#define Tcl_DeleteHashTable \
(tclStubsPtr->tcl_DeleteHashTable) /* 109 */
#define Tcl_DeleteInterp \
(tclStubsPtr->tcl_DeleteInterp) /* 110 */
#define Tcl_DetachPids \
(tclStubsPtr->tcl_DetachPids) /* 111 */
#define Tcl_DeleteTimerHandler \
(tclStubsPtr->tcl_DeleteTimerHandler) /* 112 */
#define Tcl_DeleteTrace \
(tclStubsPtr->tcl_DeleteTrace) /* 113 */
#define Tcl_DontCallWhenDeleted \
(tclStubsPtr->tcl_DontCallWhenDeleted) /* 114 */
#define Tcl_DoOneEvent \
(tclStubsPtr->tcl_DoOneEvent) /* 115 */
#define Tcl_DoWhenIdle \
(tclStubsPtr->tcl_DoWhenIdle) /* 116 */
#define Tcl_DStringAppend \
(tclStubsPtr->tcl_DStringAppend) /* 117 */
#define Tcl_DStringAppendElement \
(tclStubsPtr->tcl_DStringAppendElement) /* 118 */
#define Tcl_DStringEndSublist \
(tclStubsPtr->tcl_DStringEndSublist) /* 119 */
#define Tcl_DStringFree \
(tclStubsPtr->tcl_DStringFree) /* 120 */
#define Tcl_DStringGetResult \
(tclStubsPtr->tcl_DStringGetResult) /* 121 */
#define Tcl_DStringInit \
(tclStubsPtr->tcl_DStringInit) /* 122 */
#define Tcl_DStringResult \
(tclStubsPtr->tcl_DStringResult) /* 123 */
#define Tcl_DStringSetLength \
(tclStubsPtr->tcl_DStringSetLength) /* 124 */
#define Tcl_DStringStartSublist \
(tclStubsPtr->tcl_DStringStartSublist) /* 125 */
#define Tcl_Eof \
(tclStubsPtr->tcl_Eof) /* 126 */
#define Tcl_ErrnoId \
(tclStubsPtr->tcl_ErrnoId) /* 127 */
#define Tcl_ErrnoMsg \
(tclStubsPtr->tcl_ErrnoMsg) /* 128 */
#define Tcl_Eval \
(tclStubsPtr->tcl_Eval) /* 129 */
#define Tcl_EvalFile \
(tclStubsPtr->tcl_EvalFile) /* 130 */
#define Tcl_EvalObj \
(tclStubsPtr->tcl_EvalObj) /* 131 */
#define Tcl_EventuallyFree \
(tclStubsPtr->tcl_EventuallyFree) /* 132 */
#define Tcl_Exit \
(tclStubsPtr->tcl_Exit) /* 133 */
#define Tcl_ExposeCommand \
(tclStubsPtr->tcl_ExposeCommand) /* 134 */
#define Tcl_ExprBoolean \
(tclStubsPtr->tcl_ExprBoolean) /* 135 */
#define Tcl_ExprBooleanObj \
(tclStubsPtr->tcl_ExprBooleanObj) /* 136 */
#define Tcl_ExprDouble \
(tclStubsPtr->tcl_ExprDouble) /* 137 */
#define Tcl_ExprDoubleObj \
(tclStubsPtr->tcl_ExprDoubleObj) /* 138 */
#define Tcl_ExprLong \
(tclStubsPtr->tcl_ExprLong) /* 139 */
#define Tcl_ExprLongObj \
(tclStubsPtr->tcl_ExprLongObj) /* 140 */
#define Tcl_ExprObj \
(tclStubsPtr->tcl_ExprObj) /* 141 */
#define Tcl_ExprString \
(tclStubsPtr->tcl_ExprString) /* 142 */
#define Tcl_Finalize \
(tclStubsPtr->tcl_Finalize) /* 143 */
#define Tcl_FindExecutable \
(tclStubsPtr->tcl_FindExecutable) /* 144 */
#define Tcl_FirstHashEntry \
(tclStubsPtr->tcl_FirstHashEntry) /* 145 */
#define Tcl_Flush \
(tclStubsPtr->tcl_Flush) /* 146 */
#define Tcl_FreeResult \
(tclStubsPtr->tcl_FreeResult) /* 147 */
#define Tcl_GetAlias \
(tclStubsPtr->tcl_GetAlias) /* 148 */
#define Tcl_GetAliasObj \
(tclStubsPtr->tcl_GetAliasObj) /* 149 */
#define Tcl_GetAssocData \
(tclStubsPtr->tcl_GetAssocData) /* 150 */
#define Tcl_GetChannel \
(tclStubsPtr->tcl_GetChannel) /* 151 */
#define Tcl_GetChannelBufferSize \
(tclStubsPtr->tcl_GetChannelBufferSize) /* 152 */
#define Tcl_GetChannelHandle \
(tclStubsPtr->tcl_GetChannelHandle) /* 153 */
#define Tcl_GetChannelInstanceData \
(tclStubsPtr->tcl_GetChannelInstanceData) /* 154 */
#define Tcl_GetChannelMode \
(tclStubsPtr->tcl_GetChannelMode) /* 155 */
#define Tcl_GetChannelName \
(tclStubsPtr->tcl_GetChannelName) /* 156 */
#define Tcl_GetChannelOption \
(tclStubsPtr->tcl_GetChannelOption) /* 157 */
#define Tcl_GetChannelType \
(tclStubsPtr->tcl_GetChannelType) /* 158 */
#define Tcl_GetCommandInfo \
(tclStubsPtr->tcl_GetCommandInfo) /* 159 */
#define Tcl_GetCommandName \
(tclStubsPtr->tcl_GetCommandName) /* 160 */
#define Tcl_GetErrno \
(tclStubsPtr->tcl_GetErrno) /* 161 */
#define Tcl_GetHostName \
(tclStubsPtr->tcl_GetHostName) /* 162 */
#define Tcl_GetInterpPath \
(tclStubsPtr->tcl_GetInterpPath) /* 163 */
#define Tcl_GetMaster \
(tclStubsPtr->tcl_GetMaster) /* 164 */
#define Tcl_GetNameOfExecutable \
(tclStubsPtr->tcl_GetNameOfExecutable) /* 165 */
#define Tcl_GetObjResult \
(tclStubsPtr->tcl_GetObjResult) /* 166 */
#if !defined(__WIN32__) && !defined(MAC_OSX_TCL) /* UNIX */
#define Tcl_GetOpenFile \
(tclStubsPtr->tcl_GetOpenFile) /* 167 */
#endif /* UNIX */
#ifdef MAC_OSX_TCL /* MACOSX */
#define Tcl_GetOpenFile \
(tclStubsPtr->tcl_GetOpenFile) /* 167 */
#endif /* MACOSX */
#define Tcl_GetPathType \
(tclStubsPtr->tcl_GetPathType) /* 168 */
#define Tcl_Gets \
(tclStubsPtr->tcl_Gets) /* 169 */
#define Tcl_GetsObj \
(tclStubsPtr->tcl_GetsObj) /* 170 */
#define Tcl_GetServiceMode \
(tclStubsPtr->tcl_GetServiceMode) /* 171 */
#define Tcl_GetSlave \
(tclStubsPtr->tcl_GetSlave) /* 172 */
#define Tcl_GetStdChannel \
(tclStubsPtr->tcl_GetStdChannel) /* 173 */
#define Tcl_GetStringResult \
(tclStubsPtr->tcl_GetStringResult) /* 174 */
#define Tcl_GetVar \
(tclStubsPtr->tcl_GetVar) /* 175 */
#define Tcl_GetVar2 \
(tclStubsPtr->tcl_GetVar2) /* 176 */
#define Tcl_GlobalEval \
(tclStubsPtr->tcl_GlobalEval) /* 177 */
#define Tcl_GlobalEvalObj \
(tclStubsPtr->tcl_GlobalEvalObj) /* 178 */
#define Tcl_HideCommand \
(tclStubsPtr->tcl_HideCommand) /* 179 */
#define Tcl_Init \
(tclStubsPtr->tcl_Init) /* 180 */
#define Tcl_InitHashTable \
(tclStubsPtr->tcl_InitHashTable) /* 181 */
#define Tcl_InputBlocked \
(tclStubsPtr->tcl_InputBlocked) /* 182 */
#define Tcl_InputBuffered \
(tclStubsPtr->tcl_InputBuffered) /* 183 */
#define Tcl_InterpDeleted \
(tclStubsPtr->tcl_InterpDeleted) /* 184 */
#define Tcl_IsSafe \
(tclStubsPtr->tcl_IsSafe) /* 185 */
#define Tcl_JoinPath \
(tclStubsPtr->tcl_JoinPath) /* 186 */
#define Tcl_LinkVar \
(tclStubsPtr->tcl_LinkVar) /* 187 */
/* Slot 188 is reserved */
#define Tcl_MakeFileChannel \
(tclStubsPtr->tcl_MakeFileChannel) /* 189 */
#define Tcl_MakeSafe \
(tclStubsPtr->tcl_MakeSafe) /* 190 */
#define Tcl_MakeTcpClientChannel \
(tclStubsPtr->tcl_MakeTcpClientChannel) /* 191 */
#define Tcl_Merge \
(tclStubsPtr->tcl_Merge) /* 192 */
#define Tcl_NextHashEntry \
(tclStubsPtr->tcl_NextHashEntry) /* 193 */
#define Tcl_NotifyChannel \
(tclStubsPtr->tcl_NotifyChannel) /* 194 */
#define Tcl_ObjGetVar2 \
(tclStubsPtr->tcl_ObjGetVar2) /* 195 */
#define Tcl_ObjSetVar2 \
(tclStubsPtr->tcl_ObjSetVar2) /* 196 */
#define Tcl_OpenCommandChannel \
(tclStubsPtr->tcl_OpenCommandChannel) /* 197 */
#define Tcl_OpenFileChannel \
(tclStubsPtr->tcl_OpenFileChannel) /* 198 */
#define Tcl_OpenTcpClient \
(tclStubsPtr->tcl_OpenTcpClient) /* 199 */
#define Tcl_OpenTcpServer \
(tclStubsPtr->tcl_OpenTcpServer) /* 200 */
#define Tcl_Preserve \
(tclStubsPtr->tcl_Preserve) /* 201 */
#define Tcl_PrintDouble \
(tclStubsPtr->tcl_PrintDouble) /* 202 */
#define Tcl_PutEnv \
(tclStubsPtr->tcl_PutEnv) /* 203 */
#define Tcl_PosixError \
(tclStubsPtr->tcl_PosixError) /* 204 */
#define Tcl_QueueEvent \
(tclStubsPtr->tcl_QueueEvent) /* 205 */
#define Tcl_Read \
(tclStubsPtr->tcl_Read) /* 206 */
#define Tcl_ReapDetachedProcs \
(tclStubsPtr->tcl_ReapDetachedProcs) /* 207 */
#define Tcl_RecordAndEval \
(tclStubsPtr->tcl_RecordAndEval) /* 208 */
#define Tcl_RecordAndEvalObj \
(tclStubsPtr->tcl_RecordAndEvalObj) /* 209 */
#define Tcl_RegisterChannel \
(tclStubsPtr->tcl_RegisterChannel) /* 210 */
#define Tcl_RegisterObjType \
(tclStubsPtr->tcl_RegisterObjType) /* 211 */
#define Tcl_RegExpCompile \
(tclStubsPtr->tcl_RegExpCompile) /* 212 */
#define Tcl_RegExpExec \
(tclStubsPtr->tcl_RegExpExec) /* 213 */
#define Tcl_RegExpMatch \
(tclStubsPtr->tcl_RegExpMatch) /* 214 */
#define Tcl_RegExpRange \
(tclStubsPtr->tcl_RegExpRange) /* 215 */
#define Tcl_Release \
(tclStubsPtr->tcl_Release) /* 216 */
#define Tcl_ResetResult \
(tclStubsPtr->tcl_ResetResult) /* 217 */
#define Tcl_ScanElement \
(tclStubsPtr->tcl_ScanElement) /* 218 */
#define Tcl_ScanCountedElement \
(tclStubsPtr->tcl_ScanCountedElement) /* 219 */
#define Tcl_SeekOld \
(tclStubsPtr->tcl_SeekOld) /* 220 */
#define Tcl_ServiceAll \
(tclStubsPtr->tcl_ServiceAll) /* 221 */
#define Tcl_ServiceEvent \
(tclStubsPtr->tcl_ServiceEvent) /* 222 */
#define Tcl_SetAssocData \
(tclStubsPtr->tcl_SetAssocData) /* 223 */
#define Tcl_SetChannelBufferSize \
(tclStubsPtr->tcl_SetChannelBufferSize) /* 224 */
#define Tcl_SetChannelOption \
(tclStubsPtr->tcl_SetChannelOption) /* 225 */
#define Tcl_SetCommandInfo \
(tclStubsPtr->tcl_SetCommandInfo) /* 226 */
#define Tcl_SetErrno \
(tclStubsPtr->tcl_SetErrno) /* 227 */
#define Tcl_SetErrorCode \
(tclStubsPtr->tcl_SetErrorCode) /* 228 */
#define Tcl_SetMaxBlockTime \
(tclStubsPtr->tcl_SetMaxBlockTime) /* 229 */
#define Tcl_SetPanicProc \
(tclStubsPtr->tcl_SetPanicProc) /* 230 */
#define Tcl_SetRecursionLimit \
(tclStubsPtr->tcl_SetRecursionLimit) /* 231 */
#define Tcl_SetResult \
(tclStubsPtr->tcl_SetResult) /* 232 */
#define Tcl_SetServiceMode \
(tclStubsPtr->tcl_SetServiceMode) /* 233 */
#define Tcl_SetObjErrorCode \
(tclStubsPtr->tcl_SetObjErrorCode) /* 234 */
#define Tcl_SetObjResult \
(tclStubsPtr->tcl_SetObjResult) /* 235 */
#define Tcl_SetStdChannel \
(tclStubsPtr->tcl_SetStdChannel) /* 236 */
#define Tcl_SetVar \
(tclStubsPtr->tcl_SetVar) /* 237 */
#define Tcl_SetVar2 \
(tclStubsPtr->tcl_SetVar2) /* 238 */
#define Tcl_SignalId \
(tclStubsPtr->tcl_SignalId) /* 239 */
#define Tcl_SignalMsg \
(tclStubsPtr->tcl_SignalMsg) /* 240 */
#define Tcl_SourceRCFile \
(tclStubsPtr->tcl_SourceRCFile) /* 241 */
#define Tcl_SplitList \
(tclStubsPtr->tcl_SplitList) /* 242 */
#define Tcl_SplitPath \
(tclStubsPtr->tcl_SplitPath) /* 243 */
#define Tcl_StaticPackage \
(tclStubsPtr->tcl_StaticPackage) /* 244 */
#define Tcl_StringMatch \
(tclStubsPtr->tcl_StringMatch) /* 245 */
#define Tcl_TellOld \
(tclStubsPtr->tcl_TellOld) /* 246 */
#define Tcl_TraceVar \
(tclStubsPtr->tcl_TraceVar) /* 247 */
#define Tcl_TraceVar2 \
(tclStubsPtr->tcl_TraceVar2) /* 248 */
#define Tcl_TranslateFileName \
(tclStubsPtr->tcl_TranslateFileName) /* 249 */
#define Tcl_Ungets \
(tclStubsPtr->tcl_Ungets) /* 250 */
#define Tcl_UnlinkVar \
(tclStubsPtr->tcl_UnlinkVar) /* 251 */
#define Tcl_UnregisterChannel \
(tclStubsPtr->tcl_UnregisterChannel) /* 252 */
#define Tcl_UnsetVar \
(tclStubsPtr->tcl_UnsetVar) /* 253 */
#define Tcl_UnsetVar2 \
(tclStubsPtr->tcl_UnsetVar2) /* 254 */
#define Tcl_UntraceVar \
(tclStubsPtr->tcl_UntraceVar) /* 255 */
#define Tcl_UntraceVar2 \
(tclStubsPtr->tcl_UntraceVar2) /* 256 */
#define Tcl_UpdateLinkedVar \
(tclStubsPtr->tcl_UpdateLinkedVar) /* 257 */
#define Tcl_UpVar \
(tclStubsPtr->tcl_UpVar) /* 258 */
#define Tcl_UpVar2 \
(tclStubsPtr->tcl_UpVar2) /* 259 */
#define Tcl_VarEval \
(tclStubsPtr->tcl_VarEval) /* 260 */
#define Tcl_VarTraceInfo \
(tclStubsPtr->tcl_VarTraceInfo) /* 261 */
#define Tcl_VarTraceInfo2 \
(tclStubsPtr->tcl_VarTraceInfo2) /* 262 */
#define Tcl_Write \
(tclStubsPtr->tcl_Write) /* 263 */
#define Tcl_WrongNumArgs \
(tclStubsPtr->tcl_WrongNumArgs) /* 264 */
#define Tcl_DumpActiveMemory \
(tclStubsPtr->tcl_DumpActiveMemory) /* 265 */
#define Tcl_ValidateAllMemory \
(tclStubsPtr->tcl_ValidateAllMemory) /* 266 */
#define Tcl_AppendResultVA \
(tclStubsPtr->tcl_AppendResultVA) /* 267 */
#define Tcl_AppendStringsToObjVA \
(tclStubsPtr->tcl_AppendStringsToObjVA) /* 268 */
#define Tcl_HashStats \
(tclStubsPtr->tcl_HashStats) /* 269 */
#define Tcl_ParseVar \
(tclStubsPtr->tcl_ParseVar) /* 270 */
#define Tcl_PkgPresent \
(tclStubsPtr->tcl_PkgPresent) /* 271 */
#define Tcl_PkgPresentEx \
(tclStubsPtr->tcl_PkgPresentEx) /* 272 */
#define Tcl_PkgProvide \
(tclStubsPtr->tcl_PkgProvide) /* 273 */
#define Tcl_PkgRequire \
(tclStubsPtr->tcl_PkgRequire) /* 274 */
#define Tcl_SetErrorCodeVA \
(tclStubsPtr->tcl_SetErrorCodeVA) /* 275 */
#define Tcl_VarEvalVA \
(tclStubsPtr->tcl_VarEvalVA) /* 276 */
#define Tcl_WaitPid \
(tclStubsPtr->tcl_WaitPid) /* 277 */
#define Tcl_PanicVA \
(tclStubsPtr->tcl_PanicVA) /* 278 */
#define Tcl_GetVersion \
(tclStubsPtr->tcl_GetVersion) /* 279 */
#define Tcl_InitMemory \
(tclStubsPtr->tcl_InitMemory) /* 280 */
#define Tcl_StackChannel \
(tclStubsPtr->tcl_StackChannel) /* 281 */
#define Tcl_UnstackChannel \
(tclStubsPtr->tcl_UnstackChannel) /* 282 */
#define Tcl_GetStackedChannel \
(tclStubsPtr->tcl_GetStackedChannel) /* 283 */
#define Tcl_SetMainLoop \
(tclStubsPtr->tcl_SetMainLoop) /* 284 */
/* Slot 285 is reserved */
#define Tcl_AppendObjToObj \
(tclStubsPtr->tcl_AppendObjToObj) /* 286 */
#define Tcl_CreateEncoding \
(tclStubsPtr->tcl_CreateEncoding) /* 287 */
#define Tcl_CreateThreadExitHandler \
(tclStubsPtr->tcl_CreateThreadExitHandler) /* 288 */
#define Tcl_DeleteThreadExitHandler \
(tclStubsPtr->tcl_DeleteThreadExitHandler) /* 289 */
#define Tcl_DiscardResult \
(tclStubsPtr->tcl_DiscardResult) /* 290 */
#define Tcl_EvalEx \
(tclStubsPtr->tcl_EvalEx) /* 291 */
#define Tcl_EvalObjv \
(tclStubsPtr->tcl_EvalObjv) /* 292 */
#define Tcl_EvalObjEx \
(tclStubsPtr->tcl_EvalObjEx) /* 293 */
#define Tcl_ExitThread \
(tclStubsPtr->tcl_ExitThread) /* 294 */
#define Tcl_ExternalToUtf \
(tclStubsPtr->tcl_ExternalToUtf) /* 295 */
#define Tcl_ExternalToUtfDString \
(tclStubsPtr->tcl_ExternalToUtfDString) /* 296 */
#define Tcl_FinalizeThread \
(tclStubsPtr->tcl_FinalizeThread) /* 297 */
#define Tcl_FinalizeNotifier \
(tclStubsPtr->tcl_FinalizeNotifier) /* 298 */
#define Tcl_FreeEncoding \
(tclStubsPtr->tcl_FreeEncoding) /* 299 */
#define Tcl_GetCurrentThread \
(tclStubsPtr->tcl_GetCurrentThread) /* 300 */
#define Tcl_GetEncoding \
(tclStubsPtr->tcl_GetEncoding) /* 301 */
#define Tcl_GetEncodingName \
(tclStubsPtr->tcl_GetEncodingName) /* 302 */
#define Tcl_GetEncodingNames \
(tclStubsPtr->tcl_GetEncodingNames) /* 303 */
#define Tcl_GetIndexFromObjStruct \
(tclStubsPtr->tcl_GetIndexFromObjStruct) /* 304 */
#define Tcl_GetThreadData \
(tclStubsPtr->tcl_GetThreadData) /* 305 */
#define Tcl_GetVar2Ex \
(tclStubsPtr->tcl_GetVar2Ex) /* 306 */
#define Tcl_InitNotifier \
(tclStubsPtr->tcl_InitNotifier) /* 307 */
#define Tcl_MutexLock \
(tclStubsPtr->tcl_MutexLock) /* 308 */
#define Tcl_MutexUnlock \
(tclStubsPtr->tcl_MutexUnlock) /* 309 */
#define Tcl_ConditionNotify \
(tclStubsPtr->tcl_ConditionNotify) /* 310 */
#define Tcl_ConditionWait \
(tclStubsPtr->tcl_ConditionWait) /* 311 */
#define Tcl_NumUtfChars \
(tclStubsPtr->tcl_NumUtfChars) /* 312 */
#define Tcl_ReadChars \
(tclStubsPtr->tcl_ReadChars) /* 313 */
#define Tcl_RestoreResult \
(tclStubsPtr->tcl_RestoreResult) /* 314 */
#define Tcl_SaveResult \
(tclStubsPtr->tcl_SaveResult) /* 315 */
#define Tcl_SetSystemEncoding \
(tclStubsPtr->tcl_SetSystemEncoding) /* 316 */
#define Tcl_SetVar2Ex \
(tclStubsPtr->tcl_SetVar2Ex) /* 317 */
#define Tcl_ThreadAlert \
(tclStubsPtr->tcl_ThreadAlert) /* 318 */
#define Tcl_ThreadQueueEvent \
(tclStubsPtr->tcl_ThreadQueueEvent) /* 319 */
#define Tcl_UniCharAtIndex \
(tclStubsPtr->tcl_UniCharAtIndex) /* 320 */
#define Tcl_UniCharToLower \
(tclStubsPtr->tcl_UniCharToLower) /* 321 */
#define Tcl_UniCharToTitle \
(tclStubsPtr->tcl_UniCharToTitle) /* 322 */
#define Tcl_UniCharToUpper \
(tclStubsPtr->tcl_UniCharToUpper) /* 323 */
#define Tcl_UniCharToUtf \
(tclStubsPtr->tcl_UniCharToUtf) /* 324 */
#define Tcl_UtfAtIndex \
(tclStubsPtr->tcl_UtfAtIndex) /* 325 */
#define Tcl_UtfCharComplete \
(tclStubsPtr->tcl_UtfCharComplete) /* 326 */
#define Tcl_UtfBackslash \
(tclStubsPtr->tcl_UtfBackslash) /* 327 */
#define Tcl_UtfFindFirst \
(tclStubsPtr->tcl_UtfFindFirst) /* 328 */
#define Tcl_UtfFindLast \
(tclStubsPtr->tcl_UtfFindLast) /* 329 */
#define Tcl_UtfNext \
(tclStubsPtr->tcl_UtfNext) /* 330 */
#define Tcl_UtfPrev \
(tclStubsPtr->tcl_UtfPrev) /* 331 */
#define Tcl_UtfToExternal \
(tclStubsPtr->tcl_UtfToExternal) /* 332 */
#define Tcl_UtfToExternalDString \
(tclStubsPtr->tcl_UtfToExternalDString) /* 333 */
#define Tcl_UtfToLower \
(tclStubsPtr->tcl_UtfToLower) /* 334 */
#define Tcl_UtfToTitle \
(tclStubsPtr->tcl_UtfToTitle) /* 335 */
#define Tcl_UtfToUniChar \
(tclStubsPtr->tcl_UtfToUniChar) /* 336 */
#define Tcl_UtfToUpper \
(tclStubsPtr->tcl_UtfToUpper) /* 337 */
#define Tcl_WriteChars \
(tclStubsPtr->tcl_WriteChars) /* 338 */
#define Tcl_WriteObj \
(tclStubsPtr->tcl_WriteObj) /* 339 */
#define Tcl_GetString \
(tclStubsPtr->tcl_GetString) /* 340 */
#define Tcl_GetDefaultEncodingDir \
(tclStubsPtr->tcl_GetDefaultEncodingDir) /* 341 */
#define Tcl_SetDefaultEncodingDir \
(tclStubsPtr->tcl_SetDefaultEncodingDir) /* 342 */
#define Tcl_AlertNotifier \
(tclStubsPtr->tcl_AlertNotifier) /* 343 */
#define Tcl_ServiceModeHook \
(tclStubsPtr->tcl_ServiceModeHook) /* 344 */
#define Tcl_UniCharIsAlnum \
(tclStubsPtr->tcl_UniCharIsAlnum) /* 345 */
#define Tcl_UniCharIsAlpha \
(tclStubsPtr->tcl_UniCharIsAlpha) /* 346 */
#define Tcl_UniCharIsDigit \
(tclStubsPtr->tcl_UniCharIsDigit) /* 347 */
#define Tcl_UniCharIsLower \
(tclStubsPtr->tcl_UniCharIsLower) /* 348 */
#define Tcl_UniCharIsSpace \
(tclStubsPtr->tcl_UniCharIsSpace) /* 349 */
#define Tcl_UniCharIsUpper \
(tclStubsPtr->tcl_UniCharIsUpper) /* 350 */
#define Tcl_UniCharIsWordChar \
(tclStubsPtr->tcl_UniCharIsWordChar) /* 351 */
#define Tcl_UniCharLen \
(tclStubsPtr->tcl_UniCharLen) /* 352 */
#define Tcl_UniCharNcmp \
(tclStubsPtr->tcl_UniCharNcmp) /* 353 */
#define Tcl_UniCharToUtfDString \
(tclStubsPtr->tcl_UniCharToUtfDString) /* 354 */
#define Tcl_UtfToUniCharDString \
(tclStubsPtr->tcl_UtfToUniCharDString) /* 355 */
#define Tcl_GetRegExpFromObj \
(tclStubsPtr->tcl_GetRegExpFromObj) /* 356 */
#define Tcl_EvalTokens \
(tclStubsPtr->tcl_EvalTokens) /* 357 */
#define Tcl_FreeParse \
(tclStubsPtr->tcl_FreeParse) /* 358 */
#define Tcl_LogCommandInfo \
(tclStubsPtr->tcl_LogCommandInfo) /* 359 */
#define Tcl_ParseBraces \
(tclStubsPtr->tcl_ParseBraces) /* 360 */
#define Tcl_ParseCommand \
(tclStubsPtr->tcl_ParseCommand) /* 361 */
#define Tcl_ParseExpr \
(tclStubsPtr->tcl_ParseExpr) /* 362 */
#define Tcl_ParseQuotedString \
(tclStubsPtr->tcl_ParseQuotedString) /* 363 */
#define Tcl_ParseVarName \
(tclStubsPtr->tcl_ParseVarName) /* 364 */
#define Tcl_GetCwd \
(tclStubsPtr->tcl_GetCwd) /* 365 */
#define Tcl_Chdir \
(tclStubsPtr->tcl_Chdir) /* 366 */
#define Tcl_Access \
(tclStubsPtr->tcl_Access) /* 367 */
#define Tcl_Stat \
(tclStubsPtr->tcl_Stat) /* 368 */
#define Tcl_UtfNcmp \
(tclStubsPtr->tcl_UtfNcmp) /* 369 */
#define Tcl_UtfNcasecmp \
(tclStubsPtr->tcl_UtfNcasecmp) /* 370 */
#define Tcl_StringCaseMatch \
(tclStubsPtr->tcl_StringCaseMatch) /* 371 */
#define Tcl_UniCharIsControl \
(tclStubsPtr->tcl_UniCharIsControl) /* 372 */
#define Tcl_UniCharIsGraph \
(tclStubsPtr->tcl_UniCharIsGraph) /* 373 */
#define Tcl_UniCharIsPrint \
(tclStubsPtr->tcl_UniCharIsPrint) /* 374 */
#define Tcl_UniCharIsPunct \
(tclStubsPtr->tcl_UniCharIsPunct) /* 375 */
#define Tcl_RegExpExecObj \
(tclStubsPtr->tcl_RegExpExecObj) /* 376 */
#define Tcl_RegExpGetInfo \
(tclStubsPtr->tcl_RegExpGetInfo) /* 377 */
#define Tcl_NewUnicodeObj \
(tclStubsPtr->tcl_NewUnicodeObj) /* 378 */
#define Tcl_SetUnicodeObj \
(tclStubsPtr->tcl_SetUnicodeObj) /* 379 */
#define Tcl_GetCharLength \
(tclStubsPtr->tcl_GetCharLength) /* 380 */
#define Tcl_GetUniChar \
(tclStubsPtr->tcl_GetUniChar) /* 381 */
#define Tcl_GetUnicode \
(tclStubsPtr->tcl_GetUnicode) /* 382 */
#define Tcl_GetRange \
(tclStubsPtr->tcl_GetRange) /* 383 */
#define Tcl_AppendUnicodeToObj \
(tclStubsPtr->tcl_AppendUnicodeToObj) /* 384 */
#define Tcl_RegExpMatchObj \
(tclStubsPtr->tcl_RegExpMatchObj) /* 385 */
#define Tcl_SetNotifier \
(tclStubsPtr->tcl_SetNotifier) /* 386 */
#define Tcl_GetAllocMutex \
(tclStubsPtr->tcl_GetAllocMutex) /* 387 */
#define Tcl_GetChannelNames \
(tclStubsPtr->tcl_GetChannelNames) /* 388 */
#define Tcl_GetChannelNamesEx \
(tclStubsPtr->tcl_GetChannelNamesEx) /* 389 */
#define Tcl_ProcObjCmd \
(tclStubsPtr->tcl_ProcObjCmd) /* 390 */
#define Tcl_ConditionFinalize \
(tclStubsPtr->tcl_ConditionFinalize) /* 391 */
#define Tcl_MutexFinalize \
(tclStubsPtr->tcl_MutexFinalize) /* 392 */
#define Tcl_CreateThread \
(tclStubsPtr->tcl_CreateThread) /* 393 */
#define Tcl_ReadRaw \
(tclStubsPtr->tcl_ReadRaw) /* 394 */
#define Tcl_WriteRaw \
(tclStubsPtr->tcl_WriteRaw) /* 395 */
#define Tcl_GetTopChannel \
(tclStubsPtr->tcl_GetTopChannel) /* 396 */
#define Tcl_ChannelBuffered \
(tclStubsPtr->tcl_ChannelBuffered) /* 397 */
#define Tcl_ChannelName \
(tclStubsPtr->tcl_ChannelName) /* 398 */
#define Tcl_ChannelVersion \
(tclStubsPtr->tcl_ChannelVersion) /* 399 */
#define Tcl_ChannelBlockModeProc \
(tclStubsPtr->tcl_ChannelBlockModeProc) /* 400 */
#define Tcl_ChannelCloseProc \
(tclStubsPtr->tcl_ChannelCloseProc) /* 401 */
#define Tcl_ChannelClose2Proc \
(tclStubsPtr->tcl_ChannelClose2Proc) /* 402 */
#define Tcl_ChannelInputProc \
(tclStubsPtr->tcl_ChannelInputProc) /* 403 */
#define Tcl_ChannelOutputProc \
(tclStubsPtr->tcl_ChannelOutputProc) /* 404 */
#define Tcl_ChannelSeekProc \
(tclStubsPtr->tcl_ChannelSeekProc) /* 405 */
#define Tcl_ChannelSetOptionProc \
(tclStubsPtr->tcl_ChannelSetOptionProc) /* 406 */
#define Tcl_ChannelGetOptionProc \
(tclStubsPtr->tcl_ChannelGetOptionProc) /* 407 */
#define Tcl_ChannelWatchProc \
(tclStubsPtr->tcl_ChannelWatchProc) /* 408 */
#define Tcl_ChannelGetHandleProc \
(tclStubsPtr->tcl_ChannelGetHandleProc) /* 409 */
#define Tcl_ChannelFlushProc \
(tclStubsPtr->tcl_ChannelFlushProc) /* 410 */
#define Tcl_ChannelHandlerProc \
(tclStubsPtr->tcl_ChannelHandlerProc) /* 411 */
#define Tcl_JoinThread \
(tclStubsPtr->tcl_JoinThread) /* 412 */
#define Tcl_IsChannelShared \
(tclStubsPtr->tcl_IsChannelShared) /* 413 */
#define Tcl_IsChannelRegistered \
(tclStubsPtr->tcl_IsChannelRegistered) /* 414 */
#define Tcl_CutChannel \
(tclStubsPtr->tcl_CutChannel) /* 415 */
#define Tcl_SpliceChannel \
(tclStubsPtr->tcl_SpliceChannel) /* 416 */
#define Tcl_ClearChannelHandlers \
(tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */
#define Tcl_IsChannelExisting \
(tclStubsPtr->tcl_IsChannelExisting) /* 418 */
#define Tcl_UniCharNcasecmp \
(tclStubsPtr->tcl_UniCharNcasecmp) /* 419 */
#define Tcl_UniCharCaseMatch \
(tclStubsPtr->tcl_UniCharCaseMatch) /* 420 */
#define Tcl_FindHashEntry \
(tclStubsPtr->tcl_FindHashEntry) /* 421 */
#define Tcl_CreateHashEntry \
(tclStubsPtr->tcl_CreateHashEntry) /* 422 */
#define Tcl_InitCustomHashTable \
(tclStubsPtr->tcl_InitCustomHashTable) /* 423 */
#define Tcl_InitObjHashTable \
(tclStubsPtr->tcl_InitObjHashTable) /* 424 */
#define Tcl_CommandTraceInfo \
(tclStubsPtr->tcl_CommandTraceInfo) /* 425 */
#define Tcl_TraceCommand \
(tclStubsPtr->tcl_TraceCommand) /* 426 */
#define Tcl_UntraceCommand \
(tclStubsPtr->tcl_UntraceCommand) /* 427 */
#define Tcl_AttemptAlloc \
(tclStubsPtr->tcl_AttemptAlloc) /* 428 */
#define Tcl_AttemptDbCkalloc \
(tclStubsPtr->tcl_AttemptDbCkalloc) /* 429 */
#define Tcl_AttemptRealloc \
(tclStubsPtr->tcl_AttemptRealloc) /* 430 */
#define Tcl_AttemptDbCkrealloc \
(tclStubsPtr->tcl_AttemptDbCkrealloc) /* 431 */
#define Tcl_AttemptSetObjLength \
(tclStubsPtr->tcl_AttemptSetObjLength) /* 432 */
#define Tcl_GetChannelThread \
(tclStubsPtr->tcl_GetChannelThread) /* 433 */
#define Tcl_GetUnicodeFromObj \
(tclStubsPtr->tcl_GetUnicodeFromObj) /* 434 */
#define Tcl_GetMathFuncInfo \
(tclStubsPtr->tcl_GetMathFuncInfo) /* 435 */
#define Tcl_ListMathFuncs \
(tclStubsPtr->tcl_ListMathFuncs) /* 436 */
#define Tcl_SubstObj \
(tclStubsPtr->tcl_SubstObj) /* 437 */
#define Tcl_DetachChannel \
(tclStubsPtr->tcl_DetachChannel) /* 438 */
#define Tcl_IsStandardChannel \
(tclStubsPtr->tcl_IsStandardChannel) /* 439 */
#define Tcl_FSCopyFile \
(tclStubsPtr->tcl_FSCopyFile) /* 440 */
#define Tcl_FSCopyDirectory \
(tclStubsPtr->tcl_FSCopyDirectory) /* 441 */
#define Tcl_FSCreateDirectory \
(tclStubsPtr->tcl_FSCreateDirectory) /* 442 */
#define Tcl_FSDeleteFile \
(tclStubsPtr->tcl_FSDeleteFile) /* 443 */
#define Tcl_FSLoadFile \
(tclStubsPtr->tcl_FSLoadFile) /* 444 */
#define Tcl_FSMatchInDirectory \
(tclStubsPtr->tcl_FSMatchInDirectory) /* 445 */
#define Tcl_FSLink \
(tclStubsPtr->tcl_FSLink) /* 446 */
#define Tcl_FSRemoveDirectory \
(tclStubsPtr->tcl_FSRemoveDirectory) /* 447 */
#define Tcl_FSRenameFile \
(tclStubsPtr->tcl_FSRenameFile) /* 448 */
#define Tcl_FSLstat \
(tclStubsPtr->tcl_FSLstat) /* 449 */
#define Tcl_FSUtime \
(tclStubsPtr->tcl_FSUtime) /* 450 */
#define Tcl_FSFileAttrsGet \
(tclStubsPtr->tcl_FSFileAttrsGet) /* 451 */
#define Tcl_FSFileAttrsSet \
(tclStubsPtr->tcl_FSFileAttrsSet) /* 452 */
#define Tcl_FSFileAttrStrings \
(tclStubsPtr->tcl_FSFileAttrStrings) /* 453 */
#define Tcl_FSStat \
(tclStubsPtr->tcl_FSStat) /* 454 */
#define Tcl_FSAccess \
(tclStubsPtr->tcl_FSAccess) /* 455 */
#define Tcl_FSOpenFileChannel \
(tclStubsPtr->tcl_FSOpenFileChannel) /* 456 */
#define Tcl_FSGetCwd \
(tclStubsPtr->tcl_FSGetCwd) /* 457 */
#define Tcl_FSChdir \
(tclStubsPtr->tcl_FSChdir) /* 458 */
#define Tcl_FSConvertToPathType \
(tclStubsPtr->tcl_FSConvertToPathType) /* 459 */
#define Tcl_FSJoinPath \
(tclStubsPtr->tcl_FSJoinPath) /* 460 */
#define Tcl_FSSplitPath \
(tclStubsPtr->tcl_FSSplitPath) /* 461 */
#define Tcl_FSEqualPaths \
(tclStubsPtr->tcl_FSEqualPaths) /* 462 */
#define Tcl_FSGetNormalizedPath \
(tclStubsPtr->tcl_FSGetNormalizedPath) /* 463 */
#define Tcl_FSJoinToPath \
(tclStubsPtr->tcl_FSJoinToPath) /* 464 */
#define Tcl_FSGetInternalRep \
(tclStubsPtr->tcl_FSGetInternalRep) /* 465 */
#define Tcl_FSGetTranslatedPath \
(tclStubsPtr->tcl_FSGetTranslatedPath) /* 466 */
#define Tcl_FSEvalFile \
(tclStubsPtr->tcl_FSEvalFile) /* 467 */
#define Tcl_FSNewNativePath \
(tclStubsPtr->tcl_FSNewNativePath) /* 468 */
#define Tcl_FSGetNativePath \
(tclStubsPtr->tcl_FSGetNativePath) /* 469 */
#define Tcl_FSFileSystemInfo \
(tclStubsPtr->tcl_FSFileSystemInfo) /* 470 */
#define Tcl_FSPathSeparator \
(tclStubsPtr->tcl_FSPathSeparator) /* 471 */
#define Tcl_FSListVolumes \
(tclStubsPtr->tcl_FSListVolumes) /* 472 */
#define Tcl_FSRegister \
(tclStubsPtr->tcl_FSRegister) /* 473 */
#define Tcl_FSUnregister \
(tclStubsPtr->tcl_FSUnregister) /* 474 */
#define Tcl_FSData \
(tclStubsPtr->tcl_FSData) /* 475 */
#define Tcl_FSGetTranslatedStringPath \
(tclStubsPtr->tcl_FSGetTranslatedStringPath) /* 476 */
#define Tcl_FSGetFileSystemForPath \
(tclStubsPtr->tcl_FSGetFileSystemForPath) /* 477 */
#define Tcl_FSGetPathType \
(tclStubsPtr->tcl_FSGetPathType) /* 478 */
#define Tcl_OutputBuffered \
(tclStubsPtr->tcl_OutputBuffered) /* 479 */
#define Tcl_FSMountsChanged \
(tclStubsPtr->tcl_FSMountsChanged) /* 480 */
#define Tcl_EvalTokensStandard \
(tclStubsPtr->tcl_EvalTokensStandard) /* 481 */
#define Tcl_GetTime \
(tclStubsPtr->tcl_GetTime) /* 482 */
#define Tcl_CreateObjTrace \
(tclStubsPtr->tcl_CreateObjTrace) /* 483 */
#define Tcl_GetCommandInfoFromToken \
(tclStubsPtr->tcl_GetCommandInfoFromToken) /* 484 */
#define Tcl_SetCommandInfoFromToken \
(tclStubsPtr->tcl_SetCommandInfoFromToken) /* 485 */
#define Tcl_DbNewWideIntObj \
(tclStubsPtr->tcl_DbNewWideIntObj) /* 486 */
#define Tcl_GetWideIntFromObj \
(tclStubsPtr->tcl_GetWideIntFromObj) /* 487 */
#define Tcl_NewWideIntObj \
(tclStubsPtr->tcl_NewWideIntObj) /* 488 */
#define Tcl_SetWideIntObj \
(tclStubsPtr->tcl_SetWideIntObj) /* 489 */
#define Tcl_AllocStatBuf \
(tclStubsPtr->tcl_AllocStatBuf) /* 490 */
#define Tcl_Seek \
(tclStubsPtr->tcl_Seek) /* 491 */
#define Tcl_Tell \
(tclStubsPtr->tcl_Tell) /* 492 */
#define Tcl_ChannelWideSeekProc \
(tclStubsPtr->tcl_ChannelWideSeekProc) /* 493 */
#define Tcl_DictObjPut \
(tclStubsPtr->tcl_DictObjPut) /* 494 */
#define Tcl_DictObjGet \
(tclStubsPtr->tcl_DictObjGet) /* 495 */
#define Tcl_DictObjRemove \
(tclStubsPtr->tcl_DictObjRemove) /* 496 */
#define Tcl_DictObjSize \
(tclStubsPtr->tcl_DictObjSize) /* 497 */
#define Tcl_DictObjFirst \
(tclStubsPtr->tcl_DictObjFirst) /* 498 */
#define Tcl_DictObjNext \
(tclStubsPtr->tcl_DictObjNext) /* 499 */
#define Tcl_DictObjDone \
(tclStubsPtr->tcl_DictObjDone) /* 500 */
#define Tcl_DictObjPutKeyList \
(tclStubsPtr->tcl_DictObjPutKeyList) /* 501 */
#define Tcl_DictObjRemoveKeyList \
(tclStubsPtr->tcl_DictObjRemoveKeyList) /* 502 */
#define Tcl_NewDictObj \
(tclStubsPtr->tcl_NewDictObj) /* 503 */
#define Tcl_DbNewDictObj \
(tclStubsPtr->tcl_DbNewDictObj) /* 504 */
#define Tcl_RegisterConfig \
(tclStubsPtr->tcl_RegisterConfig) /* 505 */
#define Tcl_CreateNamespace \
(tclStubsPtr->tcl_CreateNamespace) /* 506 */
#define Tcl_DeleteNamespace \
(tclStubsPtr->tcl_DeleteNamespace) /* 507 */
#define Tcl_AppendExportList \
(tclStubsPtr->tcl_AppendExportList) /* 508 */
#define Tcl_Export \
(tclStubsPtr->tcl_Export) /* 509 */
#define Tcl_Import \
(tclStubsPtr->tcl_Import) /* 510 */
#define Tcl_ForgetImport \
(tclStubsPtr->tcl_ForgetImport) /* 511 */
#define Tcl_GetCurrentNamespace \
(tclStubsPtr->tcl_GetCurrentNamespace) /* 512 */
#define Tcl_GetGlobalNamespace \
(tclStubsPtr->tcl_GetGlobalNamespace) /* 513 */
#define Tcl_FindNamespace \
(tclStubsPtr->tcl_FindNamespace) /* 514 */
#define Tcl_FindCommand \
(tclStubsPtr->tcl_FindCommand) /* 515 */
#define Tcl_GetCommandFromObj \
(tclStubsPtr->tcl_GetCommandFromObj) /* 516 */
#define Tcl_GetCommandFullName \
(tclStubsPtr->tcl_GetCommandFullName) /* 517 */
#define Tcl_FSEvalFileEx \
(tclStubsPtr->tcl_FSEvalFileEx) /* 518 */
#define Tcl_SetExitProc \
(tclStubsPtr->tcl_SetExitProc) /* 519 */
#define Tcl_LimitAddHandler \
(tclStubsPtr->tcl_LimitAddHandler) /* 520 */
#define Tcl_LimitRemoveHandler \
(tclStubsPtr->tcl_LimitRemoveHandler) /* 521 */
#define Tcl_LimitReady \
(tclStubsPtr->tcl_LimitReady) /* 522 */
#define Tcl_LimitCheck \
(tclStubsPtr->tcl_LimitCheck) /* 523 */
#define Tcl_LimitExceeded \
(tclStubsPtr->tcl_LimitExceeded) /* 524 */
#define Tcl_LimitSetCommands \
(tclStubsPtr->tcl_LimitSetCommands) /* 525 */
#define Tcl_LimitSetTime \
(tclStubsPtr->tcl_LimitSetTime) /* 526 */
#define Tcl_LimitSetGranularity \
(tclStubsPtr->tcl_LimitSetGranularity) /* 527 */
#define Tcl_LimitTypeEnabled \
(tclStubsPtr->tcl_LimitTypeEnabled) /* 528 */
#define Tcl_LimitTypeExceeded \
(tclStubsPtr->tcl_LimitTypeExceeded) /* 529 */
#define Tcl_LimitTypeSet \
(tclStubsPtr->tcl_LimitTypeSet) /* 530 */
#define Tcl_LimitTypeReset \
(tclStubsPtr->tcl_LimitTypeReset) /* 531 */
#define Tcl_LimitGetCommands \
(tclStubsPtr->tcl_LimitGetCommands) /* 532 */
#define Tcl_LimitGetTime \
(tclStubsPtr->tcl_LimitGetTime) /* 533 */
#define Tcl_LimitGetGranularity \
(tclStubsPtr->tcl_LimitGetGranularity) /* 534 */
#define Tcl_SaveInterpState \
(tclStubsPtr->tcl_SaveInterpState) /* 535 */
#define Tcl_RestoreInterpState \
(tclStubsPtr->tcl_RestoreInterpState) /* 536 */
#define Tcl_DiscardInterpState \
(tclStubsPtr->tcl_DiscardInterpState) /* 537 */
#define Tcl_SetReturnOptions \
(tclStubsPtr->tcl_SetReturnOptions) /* 538 */
#define Tcl_GetReturnOptions \
(tclStubsPtr->tcl_GetReturnOptions) /* 539 */
#define Tcl_IsEnsemble \
(tclStubsPtr->tcl_IsEnsemble) /* 540 */
#define Tcl_CreateEnsemble \
(tclStubsPtr->tcl_CreateEnsemble) /* 541 */
#define Tcl_FindEnsemble \
(tclStubsPtr->tcl_FindEnsemble) /* 542 */
#define Tcl_SetEnsembleSubcommandList \
(tclStubsPtr->tcl_SetEnsembleSubcommandList) /* 543 */
#define Tcl_SetEnsembleMappingDict \
(tclStubsPtr->tcl_SetEnsembleMappingDict) /* 544 */
#define Tcl_SetEnsembleUnknownHandler \
(tclStubsPtr->tcl_SetEnsembleUnknownHandler) /* 545 */
#define Tcl_SetEnsembleFlags \
(tclStubsPtr->tcl_SetEnsembleFlags) /* 546 */
#define Tcl_GetEnsembleSubcommandList \
(tclStubsPtr->tcl_GetEnsembleSubcommandList) /* 547 */
#define Tcl_GetEnsembleMappingDict \
(tclStubsPtr->tcl_GetEnsembleMappingDict) /* 548 */
#define Tcl_GetEnsembleUnknownHandler \
(tclStubsPtr->tcl_GetEnsembleUnknownHandler) /* 549 */
#define Tcl_GetEnsembleFlags \
(tclStubsPtr->tcl_GetEnsembleFlags) /* 550 */
#define Tcl_GetEnsembleNamespace \
(tclStubsPtr->tcl_GetEnsembleNamespace) /* 551 */
#define Tcl_SetTimeProc \
(tclStubsPtr->tcl_SetTimeProc) /* 552 */
#define Tcl_QueryTimeProc \
(tclStubsPtr->tcl_QueryTimeProc) /* 553 */
#define Tcl_ChannelThreadActionProc \
(tclStubsPtr->tcl_ChannelThreadActionProc) /* 554 */
#define Tcl_NewBignumObj \
(tclStubsPtr->tcl_NewBignumObj) /* 555 */
#define Tcl_DbNewBignumObj \
(tclStubsPtr->tcl_DbNewBignumObj) /* 556 */
#define Tcl_SetBignumObj \
(tclStubsPtr->tcl_SetBignumObj) /* 557 */
#define Tcl_GetBignumFromObj \
(tclStubsPtr->tcl_GetBignumFromObj) /* 558 */
#define Tcl_TakeBignumFromObj \
(tclStubsPtr->tcl_TakeBignumFromObj) /* 559 */
#define Tcl_TruncateChannel \
(tclStubsPtr->tcl_TruncateChannel) /* 560 */
#define Tcl_ChannelTruncateProc \
(tclStubsPtr->tcl_ChannelTruncateProc) /* 561 */
#define Tcl_SetChannelErrorInterp \
(tclStubsPtr->tcl_SetChannelErrorInterp) /* 562 */
#define Tcl_GetChannelErrorInterp \
(tclStubsPtr->tcl_GetChannelErrorInterp) /* 563 */
#define Tcl_SetChannelError \
(tclStubsPtr->tcl_SetChannelError) /* 564 */
#define Tcl_GetChannelError \
(tclStubsPtr->tcl_GetChannelError) /* 565 */
#define Tcl_InitBignumFromDouble \
(tclStubsPtr->tcl_InitBignumFromDouble) /* 566 */
#define Tcl_GetNamespaceUnknownHandler \
(tclStubsPtr->tcl_GetNamespaceUnknownHandler) /* 567 */
#define Tcl_SetNamespaceUnknownHandler \
(tclStubsPtr->tcl_SetNamespaceUnknownHandler) /* 568 */
#define Tcl_GetEncodingFromObj \
(tclStubsPtr->tcl_GetEncodingFromObj) /* 569 */
#define Tcl_GetEncodingSearchPath \
(tclStubsPtr->tcl_GetEncodingSearchPath) /* 570 */
#define Tcl_SetEncodingSearchPath \
(tclStubsPtr->tcl_SetEncodingSearchPath) /* 571 */
#define Tcl_GetEncodingNameFromEnvironment \
(tclStubsPtr->tcl_GetEncodingNameFromEnvironment) /* 572 */
#define Tcl_PkgRequireProc \
(tclStubsPtr->tcl_PkgRequireProc) /* 573 */
#define Tcl_AppendObjToErrorInfo \
(tclStubsPtr->tcl_AppendObjToErrorInfo) /* 574 */
#define Tcl_AppendLimitedToObj \
(tclStubsPtr->tcl_AppendLimitedToObj) /* 575 */
#define Tcl_Format \
(tclStubsPtr->tcl_Format) /* 576 */
#define Tcl_AppendFormatToObj \
(tclStubsPtr->tcl_AppendFormatToObj) /* 577 */
#define Tcl_ObjPrintf \
(tclStubsPtr->tcl_ObjPrintf) /* 578 */
#define Tcl_AppendPrintfToObj \
(tclStubsPtr->tcl_AppendPrintfToObj) /* 579 */
#define Tcl_CancelEval \
(tclStubsPtr->tcl_CancelEval) /* 580 */
#define Tcl_Canceled \
(tclStubsPtr->tcl_Canceled) /* 581 */
#define Tcl_CreatePipe \
(tclStubsPtr->tcl_CreatePipe) /* 582 */
#define Tcl_NRCreateCommand \
(tclStubsPtr->tcl_NRCreateCommand) /* 583 */
#define Tcl_NREvalObj \
(tclStubsPtr->tcl_NREvalObj) /* 584 */
#define Tcl_NREvalObjv \
(tclStubsPtr->tcl_NREvalObjv) /* 585 */
#define Tcl_NRCmdSwap \
(tclStubsPtr->tcl_NRCmdSwap) /* 586 */
#define Tcl_NRAddCallback \
(tclStubsPtr->tcl_NRAddCallback) /* 587 */
#define Tcl_NRCallObjProc \
(tclStubsPtr->tcl_NRCallObjProc) /* 588 */
#define Tcl_GetFSDeviceFromStat \
(tclStubsPtr->tcl_GetFSDeviceFromStat) /* 589 */
#define Tcl_GetFSInodeFromStat \
(tclStubsPtr->tcl_GetFSInodeFromStat) /* 590 */
#define Tcl_GetModeFromStat \
(tclStubsPtr->tcl_GetModeFromStat) /* 591 */
#define Tcl_GetLinkCountFromStat \
(tclStubsPtr->tcl_GetLinkCountFromStat) /* 592 */
#define Tcl_GetUserIdFromStat \
(tclStubsPtr->tcl_GetUserIdFromStat) /* 593 */
#define Tcl_GetGroupIdFromStat \
(tclStubsPtr->tcl_GetGroupIdFromStat) /* 594 */
#define Tcl_GetDeviceTypeFromStat \
(tclStubsPtr->tcl_GetDeviceTypeFromStat) /* 595 */
#define Tcl_GetAccessTimeFromStat \
(tclStubsPtr->tcl_GetAccessTimeFromStat) /* 596 */
#define Tcl_GetModificationTimeFromStat \
(tclStubsPtr->tcl_GetModificationTimeFromStat) /* 597 */
#define Tcl_GetChangeTimeFromStat \
(tclStubsPtr->tcl_GetChangeTimeFromStat) /* 598 */
#define Tcl_GetSizeFromStat \
(tclStubsPtr->tcl_GetSizeFromStat) /* 599 */
#define Tcl_GetBlocksFromStat \
(tclStubsPtr->tcl_GetBlocksFromStat) /* 600 */
#define Tcl_GetBlockSizeFromStat \
(tclStubsPtr->tcl_GetBlockSizeFromStat) /* 601 */
#define Tcl_SetEnsembleParameterList \
(tclStubsPtr->tcl_SetEnsembleParameterList) /* 602 */
#define Tcl_GetEnsembleParameterList \
(tclStubsPtr->tcl_GetEnsembleParameterList) /* 603 */
#define Tcl_ParseArgsObjv \
(tclStubsPtr->tcl_ParseArgsObjv) /* 604 */
#define Tcl_GetErrorLine \
(tclStubsPtr->tcl_GetErrorLine) /* 605 */
#define Tcl_SetErrorLine \
(tclStubsPtr->tcl_SetErrorLine) /* 606 */
#define Tcl_TransferResult \
(tclStubsPtr->tcl_TransferResult) /* 607 */
#define Tcl_InterpActive \
(tclStubsPtr->tcl_InterpActive) /* 608 */
#define Tcl_BackgroundException \
(tclStubsPtr->tcl_BackgroundException) /* 609 */
#define Tcl_ZlibDeflate \
(tclStubsPtr->tcl_ZlibDeflate) /* 610 */
#define Tcl_ZlibInflate \
(tclStubsPtr->tcl_ZlibInflate) /* 611 */
#define Tcl_ZlibCRC32 \
(tclStubsPtr->tcl_ZlibCRC32) /* 612 */
#define Tcl_ZlibAdler32 \
(tclStubsPtr->tcl_ZlibAdler32) /* 613 */
#define Tcl_ZlibStreamInit \
(tclStubsPtr->tcl_ZlibStreamInit) /* 614 */
#define Tcl_ZlibStreamGetCommandName \
(tclStubsPtr->tcl_ZlibStreamGetCommandName) /* 615 */
#define Tcl_ZlibStreamEof \
(tclStubsPtr->tcl_ZlibStreamEof) /* 616 */
#define Tcl_ZlibStreamChecksum \
(tclStubsPtr->tcl_ZlibStreamChecksum) /* 617 */
#define Tcl_ZlibStreamPut \
(tclStubsPtr->tcl_ZlibStreamPut) /* 618 */
#define Tcl_ZlibStreamGet \
(tclStubsPtr->tcl_ZlibStreamGet) /* 619 */
#define Tcl_ZlibStreamClose \
(tclStubsPtr->tcl_ZlibStreamClose) /* 620 */
#define Tcl_ZlibStreamReset \
(tclStubsPtr->tcl_ZlibStreamReset) /* 621 */
#define Tcl_SetStartupScript \
(tclStubsPtr->tcl_SetStartupScript) /* 622 */
#define Tcl_GetStartupScript \
(tclStubsPtr->tcl_GetStartupScript) /* 623 */
#define Tcl_CloseEx \
(tclStubsPtr->tcl_CloseEx) /* 624 */
#define Tcl_NRExprObj \
(tclStubsPtr->tcl_NRExprObj) /* 625 */
#define Tcl_NRSubstObj \
(tclStubsPtr->tcl_NRSubstObj) /* 626 */
#define Tcl_LoadFile \
(tclStubsPtr->tcl_LoadFile) /* 627 */
#define Tcl_FindSymbol \
(tclStubsPtr->tcl_FindSymbol) /* 628 */
#define Tcl_FSUnloadFile \
(tclStubsPtr->tcl_FSUnloadFile) /* 629 */
#define Tcl_ZlibStreamSetCompressionDictionary \
(tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */
#endif /* defined(USE_TCL_STUBS) */
/* !END!: Do not edit above this line. */
#if defined(USE_TCL_STUBS)
# undef Tcl_CreateInterp
# undef Tcl_FindExecutable
# undef Tcl_GetStringResult
# undef Tcl_Init
# undef Tcl_SetPanicProc
# undef Tcl_SetVar
# undef Tcl_StaticPackage
# undef TclFSGetNativePath
# define Tcl_CreateInterp() (tclStubsPtr->tcl_CreateInterp())
# define Tcl_GetStringResult(interp) (tclStubsPtr->tcl_GetStringResult(interp))
# define Tcl_Init(interp) (tclStubsPtr->tcl_Init(interp))
# define Tcl_SetPanicProc(proc) (tclStubsPtr->tcl_SetPanicProc(proc))
# define Tcl_SetVar(interp, varName, newValue, flags) \
(tclStubsPtr->tcl_SetVar(interp, varName, newValue, flags))
#endif
#if defined(_WIN32) && defined(UNICODE)
# define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg)))
# define Tcl_MainEx Tcl_MainExW
EXTERN void Tcl_MainExW(int argc, wchar_t **argv,
Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
#endif
#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT
#endif /* _TCLDECLS */
|
Added compat/tcl-8.6/generic/tclPlatDecls.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
/*
* tclPlatDecls.h --
*
* Declarations of platform specific Tcl APIs.
*
* Copyright (c) 1998-1999 by Scriptics Corporation.
* All rights reserved.
*/
#ifndef _TCLPLATDECLS
#define _TCLPLATDECLS
#undef TCL_STORAGE_CLASS
#ifdef BUILD_tcl
# define TCL_STORAGE_CLASS DLLEXPORT
#else
# ifdef USE_TCL_STUBS
# define TCL_STORAGE_CLASS
# else
# define TCL_STORAGE_CLASS DLLIMPORT
# endif
#endif
/*
* WARNING: This file is automatically generated by the tools/genStubs.tcl
* script. Any modifications to the function declarations below should be made
* in the generic/tcl.decls script.
*/
/*
* TCHAR is needed here for win32, so if it is not defined yet do it here.
* This way, we don't need to include <tchar.h> just for one define.
*/
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(_TCHAR_DEFINED)
# if defined(_UNICODE)
typedef wchar_t TCHAR;
# else
typedef char TCHAR;
# endif
# define _TCHAR_DEFINED
#endif
/* !BEGIN!: Do not edit below this line. */
/*
* Exported function declarations:
*/
#if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */
/* 0 */
EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len,
Tcl_DString *dsPtr);
/* 1 */
EXTERN char * Tcl_WinTCharToUtf(const TCHAR *str, int len,
Tcl_DString *dsPtr);
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
/* 0 */
EXTERN int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp,
const char *bundleName, int hasResourceFile,
int maxPathLen, char *libraryPath);
/* 1 */
EXTERN int Tcl_MacOSXOpenVersionedBundleResources(
Tcl_Interp *interp, const char *bundleName,
const char *bundleVersion,
int hasResourceFile, int maxPathLen,
char *libraryPath);
#endif /* MACOSX */
typedef struct TclPlatStubs {
int magic;
void *hooks;
#if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */
TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */
char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath); /* 0 */
int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath); /* 1 */
#endif /* MACOSX */
} TclPlatStubs;
#ifdef __cplusplus
extern "C" {
#endif
extern const TclPlatStubs *tclPlatStubsPtr;
#ifdef __cplusplus
}
#endif
#if defined(USE_TCL_STUBS)
/*
* Inline function declarations:
*/
#if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */
#define Tcl_WinUtfToTChar \
(tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */
#define Tcl_WinTCharToUtf \
(tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
#define Tcl_MacOSXOpenBundleResources \
(tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */
#define Tcl_MacOSXOpenVersionedBundleResources \
(tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */
#endif /* MACOSX */
#endif /* defined(USE_TCL_STUBS) */
/* !END!: Do not edit above this line. */
#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT
#endif /* _TCLPLATDECLS */
|
Changes to src/add.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | ** This file contains code used to check-out versions of the project ** from the local repository. */ #include "config.h" #include "add.h" #include <assert.h> #include <dirent.h> | | < < < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** This file contains code used to check-out versions of the project ** from the local repository. */ #include "config.h" #include "add.h" #include <assert.h> #include <dirent.h> #include "cygsup.h" /* ** This routine returns the names of files in a working checkout that ** are created by Fossil itself, and hence should not be added, deleted, ** or merge, and should be omitted from "clean" and "extra" lists. ** ** Return the N-th name. The first name has N==0. When all names have |
| ︙ | ︙ | |||
268 269 270 271 272 273 274 |
if( zCleanFlag==0 ){
zCleanFlag = db_get("clean-glob", 0);
}
if( zIgnoreFlag==0 ){
zIgnoreFlag = db_get("ignore-glob", 0);
}
vid = db_lget_int("checkout",0);
| < < < > > > > > | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
if( zCleanFlag==0 ){
zCleanFlag = db_get("clean-glob", 0);
}
if( zIgnoreFlag==0 ){
zIgnoreFlag = db_get("ignore-glob", 0);
}
vid = db_lget_int("checkout",0);
db_begin_transaction();
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
filename_collation());
pClean = glob_create(zCleanFlag);
pIgnore = glob_create(zIgnoreFlag);
nRoot = strlen(g.zLocalRoot);
/* Load the names of all files that are to be added into sfile temp table */
for(i=2; i<g.argc; i++){
char *zName;
int isDir;
Blob fullName;
/* file_tree_name() throws a fatal error if g.argv[i] is outside of the
** checkout. */
file_tree_name(g.argv[i], &fullName, 1);
blob_reset(&fullName);
file_canonical_name(g.argv[i], &fullName, 0);
zName = blob_str(&fullName);
isDir = file_wd_isdir(zName);
if( isDir==1 ){
vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore);
}else if( isDir==0 ){
fossil_warning("not found: %s", zName);
}else if( file_access(zName, R_OK) ){
fossil_fatal("cannot open %s", zName);
}else{
char *zTreeName = &zName[nRoot];
if( !forceFlag ){
|
| ︙ | ︙ | |||
347 348 349 350 351 352 353 |
** Options:
** --case-sensitive <BOOL> override case-sensitive setting
**
** See also: addremove, add
*/
void delete_cmd(void){
int i;
| < < < < < | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
** Options:
** --case-sensitive <BOOL> override case-sensitive setting
**
** See also: addremove, add
*/
void delete_cmd(void){
int i;
Stmt loop;
capture_case_sensitive_option();
db_must_be_within_tree();
db_begin_transaction();
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
filename_collation());
for(i=2; i<g.argc; i++){
Blob treeName;
char *zTreeName;
|
| ︙ | ︙ | |||
528 529 530 531 532 533 534 |
if( zCleanFlag==0 ){
zCleanFlag = db_get("clean-glob", 0);
}
if( zIgnoreFlag==0 ){
zIgnoreFlag = db_get("ignore-glob", 0);
}
vid = db_lget_int("checkout",0);
| < < < | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 |
if( zCleanFlag==0 ){
zCleanFlag = db_get("clean-glob", 0);
}
if( zIgnoreFlag==0 ){
zIgnoreFlag = db_get("ignore-glob", 0);
}
vid = db_lget_int("checkout",0);
db_begin_transaction();
/* step 1:
** Populate the temp table "sfile" with the names of all unmanaged
** files currently in the check-out, except for files that match the
** --ignore or ignore-glob patterns and dot-files. Then add all of
** the files in the sfile temp table to the set of managed files.
*/
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
filename_collation());
n = strlen(g.zLocalRoot);
blob_init(&path, g.zLocalRoot, n-1);
/* now we read the complete file structure into a temp table */
pClean = glob_create(zCleanFlag);
pIgnore = glob_create(zIgnoreFlag);
vfile_scan(&path, blob_size(&path), scanFlags, pClean, pIgnore);
glob_free(pIgnore);
glob_free(pClean);
nAdd = add_files_in_sfile(vid);
/* step 2: search for missing files */
db_prepare(&q,
"SELECT pathname, %Q || pathname, deleted FROM vfile"
|
| ︙ | ︙ | |||
587 588 589 590 591 592 593 |
/*
** Rename a single file.
**
** The original name of the file is zOrig. The new filename is zNew.
*/
static void mv_one_file(int vid, const char *zOrig, const char *zNew){
int x = db_int(-1, "SELECT deleted FROM vfile WHERE pathname=%Q %s",
| | | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 |
/*
** Rename a single file.
**
** The original name of the file is zOrig. The new filename is zNew.
*/
static void mv_one_file(int vid, const char *zOrig, const char *zNew){
int x = db_int(-1, "SELECT deleted FROM vfile WHERE pathname=%Q %s",
zNew, filename_collation());
if( x>=0 ){
if( x==0 ){
fossil_fatal("cannot rename '%s' to '%s' since another file named '%s'"
" is currently under management", zOrig, zNew, zNew);
}else{
fossil_fatal("cannot rename '%s' to '%s' since the delete of '%s' has "
"not yet been committed", zOrig, zNew, zNew);
|
| ︙ | ︙ | |||
634 635 636 637 638 639 640 |
Blob dest;
Stmt q;
capture_case_sensitive_option();
db_must_be_within_tree();
vid = db_lget_int("checkout", 0);
if( vid==0 ){
| | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
Blob dest;
Stmt q;
capture_case_sensitive_option();
db_must_be_within_tree();
vid = db_lget_int("checkout", 0);
if( vid==0 ){
fossil_fatal("no checkout rename files in");
}
if( g.argc<4 ){
usage("OLDNAME NEWNAME");
}
zDest = g.argv[g.argc-1];
db_begin_transaction();
file_tree_name(zDest, &dest, 1);
|
| ︙ | ︙ |
Changes to src/allrepo.c.
| ︙ | ︙ | |||
56 57 58 59 60 61 62 |
if( find_option(zArg, zShort, 0)!=0 ){
blob_appendf(pExtra, " --%s", zArg);
}
}
static void collect_argument_value(Blob *pExtra, const char *zArg){
const char *zValue = find_option(zArg, 0, 1);
if( zValue ){
| > | > > > | | > > > > > > > > > > > > > > | | | | | | < | > | > | > > > | > | | | > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
if( find_option(zArg, zShort, 0)!=0 ){
blob_appendf(pExtra, " --%s", zArg);
}
}
static void collect_argument_value(Blob *pExtra, const char *zArg){
const char *zValue = find_option(zArg, 0, 1);
if( zValue ){
if( zValue[0] ){
blob_appendf(pExtra, " --%s %s", zArg, zValue);
}else{
blob_appendf(pExtra, " --%s \"\"", zArg);
}
}
}
/*
** COMMAND: all
**
** Usage: %fossil all (changes|clean|extra|ignore|list|ls|pull|push|rebuild|sync)
**
** The ~/.fossil file records the location of all repositories for a
** user. This command performs certain operations on all repositories
** that can be useful before or after a period of disconnected operation.
**
** On Win32 systems, the file is named "_fossil" and is located in
** %LOCALAPPDATA%, %APPDATA% or %HOMEPATH%.
**
** Available operations are:
**
** changes Shows all local checkouts that have uncommitted changes.
** This operation has no additional options.
**
** clean Delete all "extra" files in all local checkouts. Extreme
** caution should be exercised with this command because its
** effects cannot be undone. Use of the --dry-run option to
** carefully review the local checkouts to be operated upon
** and the --whatif option to carefully review the files to
** be deleted beforehand is highly recommended. The command
** line options supported by the clean command itself, if any
** are present, are passed along verbatim.
**
** extra Shows extra files from all local checkouts. The command
** line options supported by the extra command itself, if any
** are present, are passed along verbatim.
**
** ignore Arguments are repositories that should be ignored by
** subsequent clean, extra, list, pull, push, rebuild, and
** sync operations. The -c|--ckout option causes the listed
** local checkouts to be ignored instead.
**
** list | ls Display the location of all repositories. The -c|--ckout
** option causes all local checkouts to be listed instead.
**
** pull Run a "pull" operation on all repositories. Only the
** --verbose option is supported.
**
** push Run a "push" on all repositories. Only the --verbose
** option is supported.
**
** rebuild Rebuild on all repositories. The command line options
** supported by the rebuild command itself, if any are
** present, are passed along verbatim. The --force and
** --randomize options are not supported.
**
** sync Run a "sync" on all repositories. Only the --verbose
** option is supported.
**
** Repositories are automatically added to the set of known repositories
** when one of the following commands are run against the repository:
** clone, info, pull, push, or sync. Even previously ignored repositories
** are added back to the list of repositories by these commands.
**
** Options:
** --dontstop Continue with other repositories even after an error.
** --dry-run If given, display instead of run actions.
*/
void all_cmd(void){
int n;
Stmt q;
const char *zCmd;
char *zSyscmd;
char *zFossil;
char *zQFilename;
Blob extra;
int useCheckouts = 0;
int quiet = 0;
int dryRunFlag = 0;
int stopOnError = find_option("dontstop",0,0)==0;
int rc;
int nToDel = 0;
dryRunFlag = find_option("dry-run","n",0)!=0;
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
if( g.argc<3 ){
usage("changes|clean|extra|ignore|list|ls|pull|push|rebuild|sync");
}
n = strlen(g.argv[2]);
db_open_config(1);
blob_zero(&extra);
zCmd = g.argv[2];
if( g.zLogin ) blob_appendf(&extra, " -U %s", g.zLogin);
if( strncmp(zCmd, "list", n)==0 || strncmp(zCmd,"ls",n)==0 ){
zCmd = "list";
useCheckouts = find_option("ckout","c",0)!=0;
}else if( strncmp(zCmd, "clean", n)==0 ){
zCmd = "clean --chdir";
collect_argument(&extra, "allckouts",0);
collect_argument_value(&extra, "case-sensitive");
collect_argument_value(&extra, "clean");
collect_argument(&extra, "dirsonly",0);
collect_argument(&extra, "dotfiles",0);
collect_argument(&extra, "emptydirs",0);
collect_argument(&extra, "force","f");
collect_argument_value(&extra, "ignore");
collect_argument_value(&extra, "keep");
collect_argument(&extra, "temp",0);
collect_argument(&extra, "verbose","v");
collect_argument(&extra, "whatif",0);
useCheckouts = 1;
}else if( strncmp(zCmd, "extra", n)==0 ){
zCmd = "extra --chdir";
collect_argument(&extra, "abs-paths",0);
collect_argument_value(&extra, "case-sensitive");
collect_argument(&extra, "dotfiles",0);
collect_argument_value(&extra, "ignore");
collect_argument(&extra, "rel-paths",0);
useCheckouts = 1;
stopOnError = 0;
quiet = 1;
}else if( strncmp(zCmd, "push", n)==0 ){
zCmd = "push -autourl -R";
collect_argument(&extra, "verbose","v");
}else if( strncmp(zCmd, "pull", n)==0 ){
zCmd = "pull -autourl -R";
collect_argument(&extra, "verbose","v");
}else if( strncmp(zCmd, "rebuild", n)==0 ){
|
| ︙ | ︙ | |||
151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
collect_argument(&extra, "analyze",0);
collect_argument(&extra, "wal",0);
collect_argument(&extra, "stats",0);
}else if( strncmp(zCmd, "sync", n)==0 ){
zCmd = "sync -autourl -R";
collect_argument(&extra, "verbose","v");
}else if( strncmp(zCmd, "test-integrity", n)==0 ){
zCmd = "test-integrity";
}else if( strncmp(zCmd, "test-orphans", n)==0 ){
zCmd = "test-orphans -R";
}else if( strncmp(zCmd, "test-missing", n)==0 ){
zCmd = "test-missing -q -R";
collect_argument(&extra, "notshunned",0);
}else if( strncmp(zCmd, "changes", n)==0 ){
| > | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
collect_argument(&extra, "analyze",0);
collect_argument(&extra, "wal",0);
collect_argument(&extra, "stats",0);
}else if( strncmp(zCmd, "sync", n)==0 ){
zCmd = "sync -autourl -R";
collect_argument(&extra, "verbose","v");
}else if( strncmp(zCmd, "test-integrity", n)==0 ){
collect_argument(&extra, "parse", 0);
zCmd = "test-integrity";
}else if( strncmp(zCmd, "test-orphans", n)==0 ){
zCmd = "test-orphans -R";
}else if( strncmp(zCmd, "test-missing", n)==0 ){
zCmd = "test-missing -q -R";
collect_argument(&extra, "notshunned",0);
}else if( strncmp(zCmd, "changes", n)==0 ){
|
| ︙ | ︙ | |||
182 183 184 185 186 187 188 |
}
fossil_free(zSql);
}
db_end_transaction(0);
return;
}else{
fossil_fatal("\"all\" subcommand should be one of: "
| | | | | | | < | < | < | < > > > | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
}
fossil_free(zSql);
}
db_end_transaction(0);
return;
}else{
fossil_fatal("\"all\" subcommand should be one of: "
"changes clean extra ignore list ls push pull rebuild sync");
}
verify_all_options();
zFossil = quoteFilename(g.nameOfExe);
if( useCheckouts ){
db_prepare(&q,
"SELECT DISTINCT substr(name, 7), name COLLATE nocase"
" FROM global_config"
" WHERE substr(name, 1, 6)=='ckout:'"
" ORDER BY 1"
);
}else{
db_prepare(&q,
"SELECT DISTINCT substr(name, 6), name COLLATE nocase"
" FROM global_config"
" WHERE substr(name, 1, 5)=='repo:'"
" ORDER BY 1"
);
}
db_multi_exec("CREATE TEMP TABLE todel(x TEXT)");
while( db_step(&q)==SQLITE_ROW ){
const char *zFilename = db_column_text(&q, 0);
if( file_access(zFilename, 0)
|| !file_is_canonical(zFilename)
|| (useCheckouts && file_isdir(zFilename)!=1)
){
db_multi_exec("INSERT INTO todel VALUES(%Q)", db_column_text(&q, 1));
nToDel++;
continue;
}
if( zCmd[0]=='l' ){
fossil_print("%s\n", zFilename);
continue;
}
zQFilename = quoteFilename(zFilename);
|
| ︙ | ︙ | |||
236 237 238 239 240 241 242 |
}
}
db_finalize(&q);
/* If any repositories whose names appear in the ~/.fossil file could not
** be found, remove those names from the ~/.fossil file.
*/
| | < < < < | < < < < < | | < | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
}
}
db_finalize(&q);
/* If any repositories whose names appear in the ~/.fossil file could not
** be found, remove those names from the ~/.fossil file.
*/
if( nToDel>0 ){
const char *zSql = "DELETE FROM global_config WHERE name IN toDel";
if( dryRunFlag ){
fossil_print("%s\n", zSql);
}else{
db_multi_exec(zSql);
}
}
}
|
Changes to src/attach.c.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 |
const char *zTkt = P("tkt");
Blob sql;
Stmt q;
if( zPage && zTkt ) zTkt = 0;
login_check_credentials();
blob_zero(&sql);
| | | < > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
const char *zTkt = P("tkt");
Blob sql;
Stmt q;
if( zPage && zTkt ) zTkt = 0;
login_check_credentials();
blob_zero(&sql);
blob_appendf(&sql,
"SELECT datetime(mtime%s), src, target, filename,"
" comment, user,"
" (SELECT uuid FROM blob WHERE rid=attachid), attachid"
" FROM attachment",
timeline_utc()
);
if( zPage ){
if( g.perm.RdWiki==0 ) login_needed();
style_header("Attachments To %h", zPage);
blob_appendf(&sql, " WHERE target=%Q", zPage);
}else if( zTkt ){
if( g.perm.RdTkt==0 ) login_needed();
|
| ︙ | ︙ | |||
212 213 214 215 216 217 218 |
rid, attachRid
);
}else{
rid = content_put(pAttach);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
| | | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
rid, attachRid
);
}else{
rid = content_put(pAttach);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
manifest_crosslink(rid, pAttach, MC_NONE);
}
/*
** WEBPAGE: attachadd
**
** tkt=TICKETUUID
|
| ︙ | ︙ | |||
303 304 305 306 307 308 309 |
blob_appendf(&manifest, "A %F%s %F %s\n",
zName, addCompress ? ".gz" : "", zTarget, zUUID);
zComment = PD("comment", "");
while( fossil_isspace(zComment[0]) ) zComment++;
n = strlen(zComment);
while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; }
if( n>0 ){
| | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
blob_appendf(&manifest, "A %F%s %F %s\n",
zName, addCompress ? ".gz" : "", zTarget, zUUID);
zComment = PD("comment", "");
while( fossil_isspace(zComment[0]) ) zComment++;
n = strlen(zComment);
while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; }
if( n>0 ){
blob_appendf(&manifest, "C %#F\n", n, zComment);
}
zDate = date_in_standard_format("now");
blob_appendf(&manifest, "D %s\n", zDate);
blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
md5sum_blob(&manifest, &cksum);
blob_appendf(&manifest, "Z %b\n", &cksum);
attach_put(&manifest, rid, needModerator);
|
| ︙ | ︙ | |||
335 336 337 338 339 340 341 |
}else{
@ <input type="hidden" name="page" value="%h(zPage)" />
}
@ <input type="hidden" name="from" value="%h(zFrom)" />
@ <input type="submit" name="ok" value="Add Attachment" />
@ <input type="submit" name="cancel" value="Cancel" />
@ </div>
| | | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
}else{
@ <input type="hidden" name="page" value="%h(zPage)" />
}
@ <input type="hidden" name="from" value="%h(zFrom)" />
@ <input type="submit" name="ok" value="Add Attachment" />
@ <input type="submit" name="cancel" value="Cancel" />
@ </div>
captcha_generate(0);
@ </form>
style_footer();
}
/*
** WEBPAGE: ainfo
** URL: /ainfo?name=ARTIFACTID
|
| ︙ | ︙ | |||
382 383 384 385 386 387 388 |
g.zTop, zUuid);
}else{
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
g.zTop, zUuid);
}
}
#endif
| | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
g.zTop, zUuid);
}else{
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
g.zTop, zUuid);
}
}
#endif
pAttach = manifest_get(rid, CFTYPE_ATTACHMENT, 0);
if( pAttach==0 ) fossil_redirect_home();
zTarget = pAttach->zAttachTarget;
zSrc = pAttach->zAttachSrc;
ridSrc = db_int(0,"SELECT rid FROM blob WHERE uuid='%s'", zSrc);
zName = pAttach->zAttachName;
zDesc = pAttach->zComment;
if( validate16(zTarget, strlen(zTarget))
|
| ︙ | ︙ | |||
429 430 431 432 433 434 435 |
blob_appendf(&manifest, "A %F %F\n", zFile, zTarget);
zDate = date_in_standard_format("now");
blob_appendf(&manifest, "D %s\n", zDate);
blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
md5sum_blob(&manifest, &cksum);
blob_appendf(&manifest, "Z %b\n", &cksum);
rid = content_put(&manifest);
| | > | > | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
blob_appendf(&manifest, "A %F %F\n", zFile, zTarget);
zDate = date_in_standard_format("now");
blob_appendf(&manifest, "D %s\n", zDate);
blob_appendf(&manifest, "U %F\n", g.zLogin ? g.zLogin : "nobody");
md5sum_blob(&manifest, &cksum);
blob_appendf(&manifest, "Z %b\n", &cksum);
rid = content_put(&manifest);
manifest_crosslink(rid, &manifest, MC_NONE);
db_end_transaction(0);
@ <p>The attachment below has been deleted.</p>
}
if( P("del")
&& ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki))
){
form_begin(0, "%R/ainfo/%s", zUuid);
@ <p>Confirm you want to delete the attachment shown below.
@ <input type="submit" name="confirm" value="Confirm">
@ </form>
}
isModerator = g.perm.Admin ||
(zTktUuid && g.perm.ModTkt) ||
(zWikiName && g.perm.ModWiki);
if( isModerator && (zModAction = P("modaction"))!=0 ){
if( strcmp(zModAction,"delete")==0 ){
moderation_disapprove(rid);
if( zTktUuid ){
cgi_redirectf("%R/tktview/%s", zTktUuid);
}else{
cgi_redirectf("%R/wiki?name=%t", zWikiName);
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 |
void attachment_list(
const char *zTarget, /* Object that things are attached to */
const char *zHeader /* Header to display with attachments */
){
int cnt = 0;
Stmt q;
db_prepare(&q,
| | | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
void attachment_list(
const char *zTarget, /* Object that things are attached to */
const char *zHeader /* Header to display with attachments */
){
int cnt = 0;
Stmt q;
db_prepare(&q,
"SELECT datetime(mtime%s), filename, user,"
" (SELECT uuid FROM blob WHERE rid=attachid), src"
" FROM attachment"
" WHERE isLatest AND src!='' AND target=%Q"
" ORDER BY mtime DESC",
timeline_utc(), zTarget
);
while( db_step(&q)==SQLITE_ROW ){
const char *zDate = db_column_text(&q, 0);
const char *zFile = db_column_text(&q, 1);
const char *zUser = db_column_text(&q, 2);
const char *zUuid = db_column_text(&q, 3);
const char *zSrc = db_column_text(&q, 4);
|
| ︙ | ︙ |
Changes to src/bag.c.
| ︙ | ︙ | |||
73 74 75 76 77 78 79 | #define bag_hash(i) (i*101) /* ** Change the size of the hash table on a bag so that ** it contains N slots ** ** Completely reconstruct the hash table from scratch. Deleted | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
#define bag_hash(i) (i*101)
/*
** Change the size of the hash table on a bag so that
** it contains N slots
**
** Completely reconstruct the hash table from scratch. Deleted
** entries (indicated by a -1) are removed. When finished, it
** should be the case that p->cnt==p->used.
*/
static void bag_resize(Bag *p, int newSize){
int i;
Bag old;
int nDel = 0; /* Number of deleted entries */
int nLive = 0; /* Number of live entries */
|
| ︙ | ︙ |
Changes to src/bisect.c.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
const char *zDefault;
const char *zDesc;
} aBisectOption[] = {
{ "auto-next", "on", "Automatically run \"bisect next\" after each "
"\"bisect good\" or \"bisect bad\"" },
{ "direct-only", "on", "Follow only primary parent-child links, not "
"merges\n" },
};
/*
** Return the value of a boolean bisect option.
*/
int bisect_option(const char *zName){
unsigned int i;
| > > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
const char *zDefault;
const char *zDesc;
} aBisectOption[] = {
{ "auto-next", "on", "Automatically run \"bisect next\" after each "
"\"bisect good\" or \"bisect bad\"" },
{ "direct-only", "on", "Follow only primary parent-child links, not "
"merges\n" },
{ "display", "chart", "Command to run after \"next\". \"chart\", "
"\"log\", \"status\", or \"none\"" },
};
/*
** Return the value of a boolean bisect option.
*/
int bisect_option(const char *zName){
unsigned int i;
|
| ︙ | ︙ | |||
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
db_lset_int("bisect-good", rid);
}
db_multi_exec(
"REPLACE INTO vvar(name,value) VALUES('bisect-log',"
"COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')"
" || '%d')", rid);
}
/*
** COMMAND: bisect
**
** Usage: %fossil bisect SUBCOMMAND ...
**
** Run various subcommands useful for searching for bugs.
**
** fossil bisect bad ?VERSION?
**
** Identify version VERSION as non-working. If VERSION is omitted,
** the current checkout is marked as non-working.
**
** fossil bisect good ?VERSION?
**
** Identify version VERSION as working. If VERSION is omitted,
** the current checkout is marked as working.
**
** fossil bisect log
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
db_lset_int("bisect-good", rid);
}
db_multi_exec(
"REPLACE INTO vvar(name,value) VALUES('bisect-log',"
"COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')"
" || '%d')", rid);
}
/*
** Show a chart of bisect "good" and "bad" versions. The chart can be
** sorted either chronologically by bisect time, or by check-in time.
*/
static void bisect_chart(int sortByCkinTime){
char *zLog = db_lget("bisect-log","");
Blob log, id;
Stmt q;
int cnt = 0;
blob_init(&log, zLog, -1);
db_multi_exec(
"CREATE TEMP TABLE bilog("
" seq INTEGER PRIMARY KEY," /* Sequence of events */
" stat TEXT," /* Type of occurrence */
" rid INTEGER" /* Check-in number */
");"
);
db_prepare(&q, "INSERT OR IGNORE INTO bilog(seq,stat,rid)"
" VALUES(:seq,:stat,:rid)");
while( blob_token(&log, &id) ){
int rid = atoi(blob_str(&id));
db_bind_int(&q, ":seq", ++cnt);
db_bind_text(&q, ":stat", rid>0 ? "GOOD" : "BAD");
db_bind_int(&q, ":rid", rid>=0 ? rid : -rid);
db_step(&q);
db_reset(&q);
}
db_bind_int(&q, ":seq", ++cnt);
db_bind_text(&q, ":stat", "CURRENT");
db_bind_int(&q, ":rid", db_lget_int("checkout", 0));
db_step(&q);
db_finalize(&q);
db_prepare(&q,
"SELECT bilog.seq, bilog.stat,"
" substr(blob.uuid,1,16), datetime(event.mtime)"
" FROM bilog, blob, event"
" WHERE blob.rid=bilog.rid AND event.objid=bilog.rid"
" AND event.type='ci'"
" ORDER BY %s",
(sortByCkinTime ? "event.mtime DESC" : "bilog.rowid ASC")
);
while( db_step(&q)==SQLITE_ROW ){
fossil_print("%3d %-7s %s %s\n",
db_column_int(&q, 0),
db_column_text(&q, 1),
db_column_text(&q, 3),
db_column_text(&q, 2));
}
db_finalize(&q);
}
/*
** COMMAND: bisect
**
** Usage: %fossil bisect SUBCOMMAND ...
**
** Run various subcommands useful for searching for bugs.
**
** fossil bisect bad ?VERSION?
**
** Identify version VERSION as non-working. If VERSION is omitted,
** the current checkout is marked as non-working.
**
** fossil bisect good ?VERSION?
**
** Identify version VERSION as working. If VERSION is omitted,
** the current checkout is marked as working.
**
** fossil bisect log
** fossil bisect chart
**
** Show a log of "good" and "bad" versions. "bisect log" shows the
** events in the order that they were tested. "bisect chart" shows
** them in order of check-in.
**
** fossil bisect next
**
** Update to the next version that is halfway between the working and
** non-working versions.
**
** fossil bisect options ?NAME? ?VALUE?
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
** Undo the most recent "good" or "bad" command.
**
** Summary:
**
** fossil bisect bad ?VERSION?
** fossil bisect good ?VERSION?
** fossil bisect log
** fossil bisect next
** fossil bisect options
** fossil bisect reset
** fossil bisect status
** fossil bisect undo
*/
void bisect_cmd(void){
int n;
const char *zCmd;
int foundCmd = 0;
db_must_be_within_tree();
if( g.argc<3 ){
usage("bad|good|log|next|options|reset|status|undo");
}
zCmd = g.argv[2];
n = strlen(zCmd);
if( n==0 ) zCmd = "-";
| > | | | | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
** Undo the most recent "good" or "bad" command.
**
** Summary:
**
** fossil bisect bad ?VERSION?
** fossil bisect good ?VERSION?
** fossil bisect log
** fossil bisect chart
** fossil bisect next
** fossil bisect options
** fossil bisect reset
** fossil bisect status
** fossil bisect undo
*/
void bisect_cmd(void){
int n;
const char *zCmd;
int foundCmd = 0;
db_must_be_within_tree();
if( g.argc<3 ){
usage("bad|good|log|next|options|reset|status|undo");
}
zCmd = g.argv[2];
n = strlen(zCmd);
if( n==0 ) zCmd = "-";
if( strncmp(zCmd, "bad", n)==0 ){
int ridBad;
foundCmd = 1;
if( g.argc==3 ){
ridBad = db_lget_int("checkout",0);
}else{
ridBad = name_to_typed_rid(g.argv[3], "ci");
}
if( ridBad>0 ){
bisect_append_log(-ridBad);
if( bisect_option("auto-next") && db_lget_int("bisect-good",0)>0 ){
zCmd = "next";
n = 4;
}
}
}else if( strncmp(zCmd, "good", n)==0 ){
int ridGood;
foundCmd = 1;
if( g.argc==3 ){
ridGood = db_lget_int("checkout",0);
}else{
ridGood = name_to_typed_rid(g.argv[3], "ci");
}
if( ridGood>0 ){
bisect_append_log(ridGood);
if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){
zCmd = "next";
n = 4;
}
}
}else if( strncmp(zCmd, "undo", n)==0 ){
char *zLog;
Blob log, id;
int ridBad = 0;
int ridGood = 0;
int cnt = 0, i;
foundCmd = 1;
db_begin_transaction();
|
| ︙ | ︙ | |||
296 297 298 299 300 301 302 |
if( ridBad && ridGood ){
zCmd = "next";
n = 4;
}
}
/* No else here so that the above commands can morph themselves into
** a "next" command */
| | > > > > | | | < < < < < < < < < < < | | < < | > | < < > > | | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
if( ridBad && ridGood ){
zCmd = "next";
n = 4;
}
}
/* No else here so that the above commands can morph themselves into
** a "next" command */
if( strncmp(zCmd, "next", n)==0 ){
PathNode *pMid;
char *zDisplay = db_lget("bisect-display","chart");
int m = (int)strlen(zDisplay);
bisect_path();
pMid = path_midpoint();
if( pMid==0 ){
fossil_print("bisect complete\n");
}else{
g.argv[1] = "update";
g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
g.argc = 3;
g.fNoSync = 1;
update_cmd();
}
if( strncmp(zDisplay,"chart",m)==0 ){
bisect_chart(1);
}else if( strncmp(zDisplay, "log", m)==0 ){
bisect_chart(0);
}else if( strncmp(zDisplay, "status", m)==0 ){
bisect_list(1);
}
}else if( strncmp(zCmd, "log", n)==0 ){
bisect_chart(0);
}else if( strncmp(zCmd, "chart", n)==0 ){
bisect_chart(1);
}else if( strncmp(zCmd, "options", n)==0 ){
if( g.argc==3 ){
unsigned int i;
for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){
char *z = mprintf("bisect-%s", aBisectOption[i].zName);
fossil_print(" %-15s %-6s ", aBisectOption[i].zName,
db_lget(z, (char*)aBisectOption[i].zDefault));
fossil_free(z);
|
| ︙ | ︙ | |||
361 362 363 364 365 366 367 |
}
if( i>=sizeof(aBisectOption)/sizeof(aBisectOption[0]) ){
fossil_fatal("no such bisect option: %s", g.argv[3]);
}
}else{
usage("bisect option ?NAME? ?VALUE?");
}
| | | | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
}
if( i>=sizeof(aBisectOption)/sizeof(aBisectOption[0]) ){
fossil_fatal("no such bisect option: %s", g.argv[3]);
}
}else{
usage("bisect option ?NAME? ?VALUE?");
}
}else if( strncmp(zCmd, "reset", n)==0 ){
db_multi_exec(
"DELETE FROM vvar WHERE name IN "
" ('bisect-good', 'bisect-bad', 'bisect-log')"
);
}else if( strncmp(zCmd, "vlist", n)==0
|| strncmp(zCmd, "ls", n)==0
|| strncmp(zCmd, "status", n)==0
){
int fAll = find_option("all", "a", 0)!=0;
bisect_list(!fAll);
}else if( !foundCmd ){
usage("bad|good|log|next|options|reset|status|undo");
}
}
|
Changes to src/blob.c.
| ︙ | ︙ | |||
221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
/*
** Initialize a blob to a nul-terminated string.
** Any prior data in the blob is discarded.
*/
void blob_set(Blob *pBlob, const char *zStr){
blob_init(pBlob, zStr, -1);
}
/*
** Initialize a blob to an empty string.
*/
void blob_zero(Blob *pBlob){
static const char zEmpty[] = "";
assert_blob_is_reset(pBlob);
| > > > > > > > > > | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
/*
** Initialize a blob to a nul-terminated string.
** Any prior data in the blob is discarded.
*/
void blob_set(Blob *pBlob, const char *zStr){
blob_init(pBlob, zStr, -1);
}
/*
** Initialize a blob to a nul-terminated string obtained from fossil_malloc().
** The blob will take responsibility for freeing the string.
*/
void blob_set_dynamic(Blob *pBlob, char *zStr){
blob_init(pBlob, zStr, -1);
pBlob->xRealloc = blobReallocMalloc;
}
/*
** Initialize a blob to an empty string.
*/
void blob_zero(Blob *pBlob){
static const char zEmpty[] = "";
assert_blob_is_reset(pBlob);
|
| ︙ | ︙ | |||
698 699 700 701 702 703 704 | /* ** Initialize a blob to be the content of a file. If the filename ** is blank or "-" then read from standard input. ** ** Any prior content of the blob is discarded, not freed. ** | | | | 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 |
/*
** Initialize a blob to be the content of a file. If the filename
** is blank or "-" then read from standard input.
**
** Any prior content of the blob is discarded, not freed.
**
** Return the number of bytes read. Calls fossil_fatal() error (i.e.
** it exit()s and does not return).
*/
int blob_read_from_file(Blob *pBlob, const char *zFilename){
int size, got;
FILE *in;
if( zFilename==0 || zFilename[0]==0
|| (zFilename[0]=='-' && zFilename[1]==0) ){
return blob_read_from_channel(pBlob, stdin, -1);
}
size = file_wd_size(zFilename);
blob_zero(pBlob);
if( size<0 ){
fossil_fatal("no such file: %s", zFilename);
}
if( size==0 ){
return 0;
}
blob_resize(pBlob, size);
in = fossil_fopen(zFilename, "rb");
if( in==0 ){
fossil_fatal("cannot open %s for reading", zFilename);
}
got = fread(blob_buffer(pBlob), 1, size, in);
fclose(in);
if( got<size ){
blob_resize(pBlob, got);
}
return got;
|
| ︙ | ︙ | |||
742 743 744 745 746 747 748 |
** On windows, zeros blob and returns 0.
*/
int blob_read_link(Blob *pBlob, const char *zFilename){
#if !defined(_WIN32)
char zBuf[1024];
ssize_t len = readlink(zFilename, zBuf, 1023);
if( len < 0 ){
| | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 |
** On windows, zeros blob and returns 0.
*/
int blob_read_link(Blob *pBlob, const char *zFilename){
#if !defined(_WIN32)
char zBuf[1024];
ssize_t len = readlink(zFilename, zBuf, 1023);
if( len < 0 ){
fossil_fatal("cannot read symbolic link %s", zFilename);
}
zBuf[len] = 0; /* null-terminate */
blob_zero(pBlob);
blob_appendf(pBlob, "%s", zBuf);
return len;
#else
blob_zero(pBlob);
|
| ︙ | ︙ | |||
764 765 766 767 768 769 770 |
**
** If the filename is blank or "-" then write to standard output.
**
** Return the number of bytes written.
*/
int blob_write_to_file(Blob *pBlob, const char *zFilename){
FILE *out;
| | | | | | < | 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
**
** If the filename is blank or "-" then write to standard output.
**
** Return the number of bytes written.
*/
int blob_write_to_file(Blob *pBlob, const char *zFilename){
FILE *out;
int nWrote;
if( zFilename[0]==0 || (zFilename[0]=='-' && zFilename[1]==0) ){
nWrote = blob_size(pBlob);
#if defined(_WIN32)
if( fossil_utf8_to_console(blob_buffer(pBlob), nWrote, 0) >= 0 ){
return nWrote;
}
#endif
fwrite(blob_buffer(pBlob), 1, nWrote, stdout);
}else{
int i, nName;
char *zName, zBuf[1000];
nName = strlen(zFilename);
if( nName>=sizeof(zBuf) ){
zName = mprintf("%s", zFilename);
|
| ︙ | ︙ | |||
814 815 816 817 818 819 820 |
}
out = fossil_fopen(zName, "wb");
if( out==0 ){
fossil_fatal_recursive("unable to open file \"%s\" for writing", zName);
return 0;
}
if( zName!=zBuf ) free(zName);
| < | | | | | | | > | | 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 |
}
out = fossil_fopen(zName, "wb");
if( out==0 ){
fossil_fatal_recursive("unable to open file \"%s\" for writing", zName);
return 0;
}
if( zName!=zBuf ) free(zName);
blob_is_init(pBlob);
nWrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out);
fclose(out);
if( nWrote!=blob_size(pBlob) ){
fossil_fatal_recursive("short write: %d of %d bytes to %s", nWrote,
blob_size(pBlob), zFilename);
}
}
return nWrote;
}
/*
** Compress a blob pIn. Store the result in pOut. It is ok for pIn and
** pOut to be the same blob.
**
** pOut must either be the same as pIn or else uninitialized.
|
| ︙ | ︙ | |||
976 977 978 979 980 981 982 |
int i;
Blob b1, b2, b3;
for(i=2; i<g.argc; i++){
blob_read_from_file(&b1, g.argv[i]);
blob_compress(&b1, &b2);
blob_uncompress(&b2, &b3);
if( blob_compare(&b1, &b3) ){
| | | | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 |
int i;
Blob b1, b2, b3;
for(i=2; i<g.argc; i++){
blob_read_from_file(&b1, g.argv[i]);
blob_compress(&b1, &b2);
blob_uncompress(&b2, &b3);
if( blob_compare(&b1, &b3) ){
fossil_fatal("compress/uncompress cycle failed for %s", g.argv[i]);
}
blob_reset(&b1);
blob_reset(&b2);
blob_reset(&b3);
}
fossil_print("ok\n");
}
#if defined(_WIN32) || defined(__CYGWIN__)
/*
** Convert every \n character in the given blob into \r\n.
*/
void blob_add_cr(Blob *p){
char *z = p->aData;
int j = p->nUsed;
int i, n;
|
| ︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 |
if( starts_with_utf8_bom(pBlob, &bomSize) ){
struct Blob temp;
zUtf8 = blob_str(pBlob) + bomSize;
blob_zero(&temp);
blob_append(&temp, zUtf8, -1);
blob_swap(pBlob, &temp);
blob_reset(&temp);
| < < | < < | 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 |
if( starts_with_utf8_bom(pBlob, &bomSize) ){
struct Blob temp;
zUtf8 = blob_str(pBlob) + bomSize;
blob_zero(&temp);
blob_append(&temp, zUtf8, -1);
blob_swap(pBlob, &temp);
blob_reset(&temp);
}else if( starts_with_utf16_bom(pBlob, &bomSize, &bomReverse) ){
zUtf8 = blob_buffer(pBlob);
if( bomReverse ){
/* Found BOM, but with reversed bytes */
unsigned int i = blob_size(pBlob);
while( i>0 ){
/* swap bytes of unicode representation */
char zTemp = zUtf8[--i];
zUtf8[i] = zUtf8[i-1];
zUtf8[--i] = zTemp;
}
}
/* Make sure the blob contains two terminating 0-bytes */
blob_append(pBlob, "", 1);
zUtf8 = blob_str(pBlob) + bomSize;
zUtf8 = fossil_unicode_to_utf8(zUtf8);
blob_set_dynamic(pBlob, zUtf8);
#if defined(_WIN32)
}else if( useMbcs ){
zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob));
blob_reset(pBlob);
blob_append(pBlob, zUtf8, -1);
fossil_mbcs_free(zUtf8);
#endif /* _WIN32 */
}
}
|
Changes to src/branch.c.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 |
zDateOvrd = find_option("date-override",0,1);
zUserOvrd = find_option("user-override",0,1);
verify_all_options();
if( g.argc<5 ){
usage("new BRANCH-NAME BASIS ?OPTIONS?");
}
db_find_and_open_repository(0, 0);
| | > | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
zDateOvrd = find_option("date-override",0,1);
zUserOvrd = find_option("user-override",0,1);
verify_all_options();
if( g.argc<5 ){
usage("new BRANCH-NAME BASIS ?OPTIONS?");
}
db_find_and_open_repository(0, 0);
noSign = db_get_boolean("omitsign", 0)|noSign;
if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
/* fossil branch new name */
zBranch = g.argv[3];
if( zBranch==0 || zBranch[0]==0 ){
fossil_fatal("branch name cannot be empty");
}
if( db_exists(
"SELECT 1 FROM tagxref"
" WHERE tagtype>0"
" AND tagid=(SELECT tagid FROM tag WHERE tagname='sym-%q')",
zBranch)!=0 ){
fossil_fatal("branch \"%s\" already exists", zBranch);
}
user_select();
db_begin_transaction();
rootid = name_to_typed_rid(g.argv[4], "ci");
if( rootid==0 ){
fossil_fatal("unable to locate check-in off of which to branch");
}
pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
if( pParent==0 ){
fossil_fatal("%s is not a valid check-in", g.argv[4]);
}
/* Create a manifest for the new branch */
blob_zero(&branch);
if( pParent->zBaseline ){
|
| ︙ | ︙ | |||
148 149 150 151 152 153 154 |
db_end_transaction(1);
fossil_exit(1);
}
}
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
if( brid==0 ){
| | | | | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
db_end_transaction(1);
fossil_exit(1);
}
}
brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
if( brid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&branch) );
content_deltify(rootid, brid, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid);
fossil_print("New branch: %s\n", zUuid);
if( g.argc==3 ){
fossil_print(
|
| ︙ | ︙ | |||
277 278 279 280 281 282 283 |
while( db_step(&q)==SQLITE_ROW ){
const char *zBr = db_column_text(&q, 0);
int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
fossil_print("%s%s\n", (isCur ? "* " : " "), zBr);
}
db_finalize(&q);
}else{
| | | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
while( db_step(&q)==SQLITE_ROW ){
const char *zBr = db_column_text(&q, 0);
int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
fossil_print("%s%s\n", (isCur ? "* " : " "), zBr);
}
db_finalize(&q);
}else{
fossil_fatal("branch subcommand should be one of: "
"new list ls");
}
}
/*
** WEBPAGE: brlist
**
|
| ︙ | ︙ | |||
323 324 325 326 327 328 329 |
}else{
style_submenu_element("All", "All", "brlist?all");
}
login_anonymous_available();
style_sidebox_begin("Nomenclature:", "33%");
@ <ol>
@ <li> An <div class="sideboxDescribed">%z(href("brlist"))
| | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
}else{
style_submenu_element("All", "All", "brlist?all");
}
login_anonymous_available();
style_sidebox_begin("Nomenclature:", "33%");
@ <ol>
@ <li> An <div class="sideboxDescribed">%z(href("brlist"))
@ open branch</a></div> is a branch that has one or more
@ <div class="sideboxDescribed">%z(href("leaves"))open leaves.</a></div>
@ The presence of open leaves presumably means
@ that the branch is still being extended with new check-ins.</li>
@ <li> A <div class="sideboxDescribed">%z(href("brlist?closed"))
@ closed branch</a></div> is a branch with only
@ <div class="sideboxDescribed">%z(href("leaves?closed"))
@ closed leaves</a></div>.
@ Closed branches are fixed and do not change (unless they are first
|
| ︙ | ︙ |
Changes to src/browse.c.
| ︙ | ︙ | |||
69 70 71 72 73 74 75 | ** to the "dir" page for the directory. ** ** There is no hyperlink on the file element of the path. ** ** The computed string is appended to the pOut blob. pOut should ** have already been initialized. */ | | > > > > > > | | | | > > > > > > | < | | < < < < > | | > | | | < > | < < < < > > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
** to the "dir" page for the directory.
**
** There is no hyperlink on the file element of the path.
**
** The computed string is appended to the pOut blob. pOut should
** have already been initialized.
*/
void hyperlinked_path(
const char *zPath, /* Path to render */
Blob *pOut, /* Write into this blob */
const char *zCI, /* check-in name, or NULL */
const char *zURI, /* "dir" or "tree" */
const char *zREx /* Extra query parameters */
){
int i, j;
char *zSep = "";
for(i=0; zPath[i]; i=j){
for(j=i; zPath[j] && zPath[j]!='/'; j++){}
if( zPath[j] && g.perm.Hyperlink ){
if( zCI ){
char *zLink = href("%R/%s?ci=%S&name=%#T%s", zURI, zCI, j, zPath,zREx);
blob_appendf(pOut, "%s%z%#h</a>",
zSep, zLink, j-i, &zPath[i]);
}else{
char *zLink = href("%R/%s?name=%#T%s", zURI, j, zPath, zREx);
blob_appendf(pOut, "%s%z%#h</a>",
zSep, zLink, j-i, &zPath[i]);
}
}else{
blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
}
zSep = "/";
while( zPath[j]=='/' ){ j++; }
}
}
/*
** WEBPAGE: dir
**
** Query parameters:
**
** name=PATH Directory to display. Optional. Top-level if missing
** ci=LABEL Show only files in this check-in. Optional.
*/
void page_dir(void){
char *zD = fossil_strdup(P("name"));
int nD = zD ? strlen(zD)+1 : 0;
int mxLen;
int nCol, nRow;
int cnt, i;
char *zPrefix;
Stmt q;
const char *zCI = P("ci");
int rid = 0;
char *zUuid = 0;
Blob dirname;
Manifest *pM = 0;
const char *zSubdirLink;
int linkTrunk = 1;
int linkTip = 1;
HQuery sURI;
if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
style_header("File List");
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
pathelementFunc, 0, 0);
url_initialize(&sURI, "dir");
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
*/
if( zCI ){
pM = manifest_get_by_name(zCI, &rid);
if( pM ){
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
linkTrunk = trunkRid && rid != trunkRid;
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
url_add_parameter(&sURI, "ci", zCI);
}else{
zCI = 0;
}
}
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
url_add_parameter(&sURI, "name", zD);
blob_append(&dirname, "in directory ", -1);
hyperlinked_path(zD, &dirname, zCI, "dir", "");
zPrefix = mprintf("%s/", zD);
style_submenu_element("Top-Level", "Top-Level", "%s",
url_render(&sURI, "name", 0, 0, 0));
}else{
blob_append(&dirname, "in the top-level directory", -1);
zPrefix = "";
}
if( linkTrunk ){
style_submenu_element("Trunk", "Trunk", "%s",
url_render(&sURI, "ci", "trunk", 0, 0));
}
if( linkTip ){
style_submenu_element("Tip", "Tip", "%s",
url_render(&sURI, "ci", "tip", 0, 0));
}
if( zCI ){
char zShort[20];
memcpy(zShort, zUuid, 10);
zShort[10] = 0;
@ <h2>Files of check-in [%z(href("vinfo?name=%T",zUuid))%s(zShort)</a>]
@ %s(blob_str(&dirname))</h2>
zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix);
if( nD==0 ){
style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
zUuid);
}
}else{
@ <h2>The union of all files from all check-ins
@ %s(blob_str(&dirname))</h2>
zSubdirLink = mprintf("%R/dir?name=%T", zPrefix);
}
style_submenu_element("All", "All", "%s",
url_render(&sURI, "ci", 0, 0, 0));
style_submenu_element("Tree-View", "Tree-View", "%s",
url_render(&sURI, "type", "tree", 0, 0));
/* Compute the temporary table "localfiles" containing the names
** of all files and subdirectories in the zD[] directory.
**
** Subdirectory names begin with "/". This causes them to sort
** first and it also gives us an easy way to distinguish files
** from directories in the loop that follows.
|
| ︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
}
}
db_finalize(&q);
manifest_destroy(pM);
@ </ul></td></tr></table>
style_footer();
}
/*
** Return a CSS class name based on the given filename's extension.
** Result must be freed by the caller.
**/
const char *fileext_class(const char *zFilename){
char *zClass;
const char *zExt = strrchr(zFilename, '.');
int isExt = zExt && zExt!=zFilename && zExt[1];
int i;
for( i=1; isExt && zExt[i]; i++ ) isExt &= fossil_isalnum(zExt[i]);
if( isExt ){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
}
}
db_finalize(&q);
manifest_destroy(pM);
@ </ul></td></tr></table>
style_footer();
}
/*
** Objects used by the "tree" webpage.
*/
typedef struct FileTreeNode FileTreeNode;
typedef struct FileTree FileTree;
/*
** A single line of the file hierarchy
*/
struct FileTreeNode {
FileTreeNode *pNext; /* Next line in sequence */
FileTreeNode *pPrev; /* Previous line */
FileTreeNode *pParent; /* Directory containing this line */
char *zName; /* Name of this entry. The "tail" */
char *zFullName; /* Full pathname of this entry */
char *zUuid; /* SHA1 hash of this file. May be NULL. */
unsigned nFullName; /* Length of zFullName */
unsigned iLevel; /* Levels of parent directories */
u8 isDir; /* True if there are children */
u8 isLast; /* True if this is the last child of its parent */
};
/*
** A complete file hierarchy
*/
struct FileTree {
FileTreeNode *pFirst; /* First line of the list */
FileTreeNode *pLast; /* Last line of the list */
};
/*
** Add one or more new FileTreeNodes to the FileTree object so that the
** leaf object zPathname is at the end of the node list
*/
static void tree_add_node(
FileTree *pTree, /* Tree into which nodes are added */
const char *zPath, /* The full pathname of file to add */
const char *zUuid /* UUID of the file. Might be NULL. */
){
int i;
FileTreeNode *pParent;
FileTreeNode *pChild;
pChild = pTree->pLast;
pParent = pChild ? pChild->pParent : 0;
while( pParent!=0 &&
( strncmp(pParent->zFullName, zPath, pParent->nFullName)!=0
|| zPath[pParent->nFullName]!='/' )
){
pChild = pParent;
pParent = pChild->pParent;
}
i = pParent ? pParent->nFullName+1 : 0;
if( pChild ) pChild->isLast = 0;
while( zPath[i] ){
FileTreeNode *pNew;
int iStart = i;
int nByte;
while( zPath[i] && zPath[i]!='/' ){ i++; }
nByte = sizeof(*pNew) + i + 1;
if( zUuid!=0 && zPath[i]==0 ) nByte += UUID_SIZE+1;
pNew = fossil_malloc( nByte );
pNew->zFullName = (char*)&pNew[1];
memcpy(pNew->zFullName, zPath, i);
pNew->zFullName[i] = 0;
pNew->nFullName = i;
if( zUuid!=0 && zPath[i]==0 ){
pNew->zUuid = pNew->zFullName + i + 1;
memcpy(pNew->zUuid, zUuid, UUID_SIZE+1);
}else{
pNew->zUuid = 0;
}
pNew->zName = pNew->zFullName + iStart;
if( pTree->pLast ){
pTree->pLast->pNext = pNew;
}else{
pTree->pFirst = pNew;
}
pNew->pPrev = pTree->pLast;
pNew->pNext = 0;
pNew->pParent = pParent;
pTree->pLast = pNew;
pNew->iLevel = pParent ? pParent->iLevel+1 : 0;
pNew->isDir = zPath[i]=='/';
pNew->isLast = 1;
while( zPath[i]=='/' ){ i++; }
pParent = pNew;
}
}
/*
** WEBPAGE: tree
**
** Query parameters:
**
** name=PATH Directory to display. Optional
** ci=LABEL Show only files in this check-in. Optional.
** re=REGEXP Show only files matching REGEXP. Optional.
** expand Begin with the tree fully expanded.
** nofiles Show directories (folders) only. Omit files.
*/
void page_tree(void){
char *zD = fossil_strdup(P("name"));
int nD = zD ? strlen(zD)+1 : 0;
const char *zCI = P("ci");
int rid = 0;
char *zUuid = 0;
Blob dirname;
Manifest *pM = 0;
int nFile = 0; /* Number of files (or folders with "nofiles") */
int linkTrunk = 1; /* include link to "trunk" */
int linkTip = 1; /* include link to "tip" */
const char *zRE; /* the value for the re=REGEXP query parameter */
const char *zObjType; /* "files" by default or "folders" for "nofiles" */
char *zREx = ""; /* Extra parameters for path hyperlinks */
ReCompiled *pRE = 0; /* Compiled regular expression */
FileTreeNode *p; /* One line of the tree */
FileTree sTree; /* The complete tree of files */
HQuery sURI; /* Hyperlink */
int startExpanded; /* True to start out with the tree expanded */
int showDirOnly; /* Show directories only. Omit files */
int nDir = 0; /* Number of directories. Used for ID attributes */
char *zProjectName = db_get("project-name", 0);
if( strcmp(PD("type",""),"flat")==0 ){ page_dir(); return; }
memset(&sTree, 0, sizeof(sTree));
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
pathelementFunc, 0, 0);
url_initialize(&sURI, "tree");
if( P("nofiles")!=0 ){
showDirOnly = 1;
url_add_parameter(&sURI, "nofiles", "1");
style_header("Folder Hierarchy");
}else{
showDirOnly = 0;
style_header("File Tree");
}
if( P("expand")!=0 ){
startExpanded = 1;
url_add_parameter(&sURI, "expand", "1");
}else{
startExpanded = 0;
}
/* If a regular expression is specified, compile it */
zRE = P("re");
if( zRE ){
re_compile(&pRE, zRE, 0);
url_add_parameter(&sURI, "re", zRE);
zREx = mprintf("&re=%T", zRE);
}
/* If the name= parameter is an empty string, make it a NULL pointer */
if( zD && strlen(zD)==0 ){ zD = 0; }
/* If a specific check-in is requested, fetch and parse it. If the
** specific check-in does not exist, clear zCI. zCI==0 will cause all
** files from all check-ins to be displayed.
*/
if( zCI ){
pM = manifest_get_by_name(zCI, &rid);
if( pM ){
int trunkRid = symbolic_name_to_rid("tag:trunk", "ci");
linkTrunk = trunkRid && rid != trunkRid;
linkTip = rid != symbolic_name_to_rid("tip", "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
url_add_parameter(&sURI, "ci", zCI);
}else{
zCI = 0;
}
}
/* Compute the title of the page */
blob_zero(&dirname);
if( zD ){
url_add_parameter(&sURI, "name", zD);
blob_append(&dirname, "within directory ", -1);
hyperlinked_path(zD, &dirname, zCI, "tree", zREx);
if( zRE ) blob_appendf(&dirname, " matching \"%s\"", zRE);
style_submenu_element("Top-Level", "Top-Level", "%s",
url_render(&sURI, "name", 0, 0, 0));
}else{
if( zRE ){
blob_appendf(&dirname, "matching \"%s\"", zRE);
}
}
if( zCI ){
style_submenu_element("All", "All", "%s",
url_render(&sURI, "ci", 0, 0, 0));
if( nD==0 && !showDirOnly ){
style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
zUuid);
}
}
if( linkTrunk ){
style_submenu_element("Trunk", "Trunk", "%s",
url_render(&sURI, "ci", "trunk", 0, 0));
}
if ( linkTip ){
style_submenu_element("Tip", "Tip", "%s",
url_render(&sURI, "ci", "tip", 0, 0));
}
if( !showDirOnly ){
style_submenu_element("Flat-View", "Flat-View", "%s",
url_render(&sURI, "type", "flat", 0, 0));
}
/* Compute the file hierarchy.
*/
if( zCI ){
Stmt ins, q;
ManifestFile *pFile;
db_multi_exec(
"CREATE TEMP TABLE filelist("
" x TEXT PRIMARY KEY COLLATE nocase,"
" uuid TEXT"
") WITHOUT ROWID;"
);
db_prepare(&ins, "INSERT OR IGNORE INTO filelist VALUES(:f,:u)");
manifest_file_rewind(pM);
while( (pFile = manifest_file_next(pM,0))!=0 ){
if( nD>0
&& (fossil_strncmp(pFile->zName, zD, nD-1)!=0
|| pFile->zName[nD-1]!='/')
){
continue;
}
if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
db_bind_text(&ins, ":f", pFile->zName);
db_bind_text(&ins, ":u", pFile->zUuid);
db_step(&ins);
db_reset(&ins);
}
db_finalize(&ins);
db_prepare(&q, "SELECT x, uuid FROM filelist ORDER BY x");
while( db_step(&q)==SQLITE_ROW ){
tree_add_node(&sTree, db_column_text(&q,0), db_column_text(&q,1));
nFile++;
}
db_finalize(&q);
}else{
Stmt q;
db_prepare(&q, "SELECT name FROM filename ORDER BY name COLLATE nocase");
while( db_step(&q)==SQLITE_ROW ){
const char *z = db_column_text(&q, 0);
if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
continue;
}
if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
tree_add_node(&sTree, z, 0);
nFile++;
}
db_finalize(&q);
}
if( showDirOnly ){
for(nFile=0, p=sTree.pFirst; p; p=p->pNext){
if( p->isDir && p->nFullName>nD ) nFile++;
}
zObjType = "folders";
style_submenu_element("Files","Files","%s",
url_render(&sURI,"nofiles",0,0,0));
}else{
zObjType = "files";
style_submenu_element("Folders","Folders","%s",
url_render(&sURI,"nofiles","1",0,0));
}
if( zCI ){
@ <h2>%d(nFile) %s(zObjType) of check-in
if( sqlite3_strnicmp(zCI, zUuid, (int)strlen(zCI))!=0 ){
@ "%h(zCI)"
}
@ [%z(href("vinfo?name=%T",zUuid))%S(zUuid)</a>] %s(blob_str(&dirname))</h2>
}else{
int n = db_int(0, "SELECT count(*) FROM plink");
@ <h2>%d(nFile) %s(zObjType) from all %d(n) check-ins
@ %s(blob_str(&dirname))</h2>
}
/* Generate tree of lists.
**
** Each file and directory is a list element: <li>. Files have class=file
** and if the filename as the suffix "xyz" the file also has class=file-xyz.
** Directories have class=dir. The directory specfied by the name= query
** parameter (or the top-level directory if there is no name= query parameter)
** adds class=subdir.
**
** The <li> element for directories also contains a sublist <ul>
** for the contents of that directory.
*/
@ <div class="filetree"><ul>
if( nD ){
@ <li class="dir last">
}else{
@ <li class="dir subdir last">
}
@ %z(href("%s",url_render(&sURI,"name",0,0,0)))%h(zProjectName)</a>
@ <ul>
for(p=sTree.pFirst, nDir=0; p; p=p->pNext){
const char *zLastClass = p->isLast ? " last" : "";
if( p->isDir ){
const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : "";
@ <li class="dir%s(zSubdirClass)%s(zLastClass)">
@ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a>
if( startExpanded || p->nFullName<=nD ){
@ <ul id="dir%d(nDir)">
}else{
@ <ul id="dir%d(nDir)" class="collapsed">
}
nDir++;
}else if( !showDirOnly ){
const char *zFileClass = fileext_class(p->zName);
char *zLink;
if( zCI ){
zLink = href("%R/artifact/%S",p->zUuid);
}else{
zLink = href("%R/finfo?name=%T",p->zFullName);
}
@ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a>
}
if( p->isLast ){
int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0);
while( nClose-- > 0 ){
@ </ul>
}
}
}
@ </ul>
@ </ul></div>
@ <script>(function(){
@ function isExpanded(ul){
@ return ul.className=='';
@ }
@
@ function toggleDir(ul, useInitValue){
@ if( !useInitValue ){
@ expandMap[ul.id] = !isExpanded(ul);
@ history.replaceState(expandMap, '');
@ }
@ ul.className = expandMap[ul.id] ? '' : 'collapsed';
@ }
@
@ function toggleAll(tree, useInitValue){
@ var lists = tree.querySelectorAll('.subdir > ul > li ul');
@ if( !useInitValue ){
@ var expand = true; /* Default action: make all sublists visible */
@ for( var i=0; lists[i]; i++ ){
@ if( isExpanded(lists[i]) ){
@ expand = false; /* Any already visible - make them all hidden */
@ break;
@ }
@ }
@ expandMap = {'*': expand};
@ history.replaceState(expandMap, '');
@ }
@ var className = expandMap['*'] ? '' : 'collapsed';
@ for( var i=0; lists[i]; i++ ){
@ lists[i].className = className;
@ }
@ }
@
@ function checkState(){
@ expandMap = history.state || {};
@ if( '*' in expandMap ) toggleAll(outer_ul, true);
@ for( var id in expandMap ){
@ if( id!=='*' ) toggleDir(gebi(id), true);
@ }
@ }
@
@ function belowSubdir(node){
@ do{
@ node = node.parentNode;
@ if( node==subdir ) return true;
@ } while( node && node!=outer_ul );
@ return false;
@ }
@
@ var history = window.history || {};
@ if( !history.replaceState ) history.replaceState = function(){};
@ var outer_ul = document.querySelector('.filetree > ul');
@ var subdir = outer_ul.querySelector('.subdir');
@ var expandMap = {};
@ checkState();
@ outer_ul.onclick = function(e){
@ e = e || window.event;
@ var a = e.target || e.srcElement;
@ if( a.nodeName!='A' ) return true;
@ if( a.parentNode==subdir ){
@ toggleAll(outer_ul);
@ return false;
@ }
@ if( !belowSubdir(a) ) return true;
@ var ul = a.nextSibling;
@ while( ul && ul.nodeName!='UL' ) ul = ul.nextSibling;
@ if( !ul ) return true; /* This is a file link, not a directory */
@ toggleDir(ul);
@ return false;
@ }
@ }())</script>
style_footer();
/* We could free memory used by sTree here if we needed to. But
** the process is about to exit, so doing so would not really accomplish
** anything useful. */
}
/*
** Return a CSS class name based on the given filename's extension.
** Result must be freed by the caller.
**/
const char *fileext_class(const char *zFilename){
char *zClass;
const char *zExt = strrchr(zFilename, '.');
int isExt = zExt && zExt!=zFilename && zExt[1];
int i;
for( i=1; isExt && zExt[i]; i++ ) isExt &= fossil_isalnum(zExt[i]);
if( isExt ){
zClass = mprintf("file file-%s", zExt+1);
for ( i=5; zClass[i]; i++ ) zClass[i] = fossil_tolower(zClass[i]);
}else{
zClass = mprintf("file");
}
return zClass;
}
|
| ︙ | ︙ | |||
329 330 331 332 333 334 335 |
" fid INTEGER,"
" mid INTEGER,"
" mtime DATETIME,"
" pathname TEXT"
");"
"CREATE INDEX fileage_fid ON fileage(fid);"
);
| | | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
" fid INTEGER,"
" mid INTEGER,"
" mtime DATETIME,"
" pathname TEXT"
");"
"CREATE INDEX fileage_fid ON fileage(fid);"
);
pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0);
if( pManifest==0 ) return 1;
manifest_file_rewind(pManifest);
db_prepare(&ins,
"INSERT INTO temp.fileage(fid, pathname)"
" SELECT rid, :path FROM blob WHERE uuid=:uuid"
);
while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
|
| ︙ | ︙ | |||
402 403 404 405 406 407 408 409 410 411 |
if( !g.perm.Read ){ login_needed(); return; }
zName = P("name");
if( zName==0 ) zName = "tip";
rid = symbolic_name_to_rid(zName, "ci");
if( rid==0 ){
fossil_fatal("not a valid check-in: %s", zName);
}
style_header("File Ages", zName);
compute_fileage(rid);
baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
| > | | | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 |
if( !g.perm.Read ){ login_needed(); return; }
zName = P("name");
if( zName==0 ) zName = "tip";
rid = symbolic_name_to_rid(zName, "ci");
if( rid==0 ){
fossil_fatal("not a valid check-in: %s", zName);
}
style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T", zName);
style_header("File Ages", zName);
compute_fileage(rid);
baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
zBaseTime = db_text("","SELECT datetime(%.20g%s)", baseTime, timeline_utc());
@ <h2>File Ages For Check-in
@ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2>
@
@ <p>The times given are relative to
@ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the
@ check-in time for
@ %z(href("%R/info?name=%T",zName))%h(zName)</a></p>
@
@ <table border=0 cellspacing=0 cellpadding=0>
db_prepare(&q,
"SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname"
|
| ︙ | ︙ |
Changes to src/captcha.c.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | ** ******************************************************************************* ** ** This file contains code to a simple text-based CAPTCHA. Though easily ** defeated by a sophisticated attacker, this CAPTCHA does at least make ** scripting attacks more difficult. */ | < > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** ******************************************************************************* ** ** This file contains code to a simple text-based CAPTCHA. Though easily ** defeated by a sophisticated attacker, this CAPTCHA does at least make ** scripting attacks more difficult. */ #include "config.h" #include <assert.h> #include "captcha.h" #if INTERFACE #define CAPTCHA 3 /* Which captcha rendering to use */ #endif /* |
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
/*
** Render an 8-character hexadecimal string as ascii art.
** Space to hold the result is obtained from malloc() and should be freed
** by the caller.
*/
char *captcha_render(const char *zPw){
| | | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
/*
** Render an 8-character hexadecimal string as ascii art.
** Space to hold the result is obtained from malloc() and should be freed
** by the caller.
*/
char *captcha_render(const char *zPw){
char *z = fossil_malloc( 9*6*strlen(zPw) + 7 );
int i, j, k, m;
k = 0;
for(i=0; i<6; i++){
for(j=0; zPw[j]; j++){
unsigned char v = hexValue(zPw[j]);
v = (aFont1[v] >> ((5-i)*4)) & 0xf;
for(m=8; m>=1; m = m>>1){
if( v & m ){
z[k++] = 'X';
z[k++] = 'X';
}else{
z[k++] = ' ';
z[k++] = ' ';
}
}
z[k++] = ' ';
z[k++] = ' ';
}
z[k++] = '\n';
}
z[k] = 0;
return z;
}
#endif /* CAPTCHA==1 */
#if CAPTCHA==2
static const char *const azFont2[] = {
/* 0 */
|
| ︙ | ︙ | |||
146 147 148 149 150 151 152 | /* 7 */ " ____ ", "|__ |", " / / ", " /_/ ", /* 8 */ | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | /* 7 */ " ____ ", "|__ |", " / / ", " /_/ ", /* 8 */ " ___ ", "( _ )", "/ _ \\", "\\___/", /* 9 */ " ___ ", "/ _ \\", |
| ︙ | ︙ | |||
200 201 202 203 204 205 206 |
/*
** Render an 8-digit hexadecimal string as ascii arg.
** Space to hold the result is obtained from malloc() and should be freed
** by the caller.
*/
char *captcha_render(const char *zPw){
| | | | | | | | | | | | | | | | | | | | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
/*
** Render an 8-digit hexadecimal string as ascii arg.
** Space to hold the result is obtained from malloc() and should be freed
** by the caller.
*/
char *captcha_render(const char *zPw){
char *z = fossil_malloc( 7*4*strlen(zPw) + 5 );
int i, j, k, m;
const char *zChar;
k = 0;
for(i=0; i<4; i++){
for(j=0; zPw[j]; j++){
unsigned char v = hexValue(zPw[j]);
zChar = azFont2[4*v + i];
for(m=0; zChar[m]; m++){
z[k++] = zChar[m];
}
}
z[k++] = '\n';
}
z[k] = 0;
return z;
}
#endif /* CAPTCHA==2 */
#if CAPTCHA==3
static const char *const azFont3[] = {
/* 0 */
" ___ ",
" / _ \\ ",
"| | | |",
"| | | |",
"| |_| |",
" \\___/ ",
/* 1 */
" __ ",
"/_ |",
" | |",
" | |",
" | |",
" |_|",
/* 2 */
" ___ ",
"|__ \\ ",
" ) |",
" / / ",
" / /_ ",
"|____|",
/* 3 */
" ____ ",
"|___ \\ ",
" __) |",
" |__ < ",
" ___) |",
"|____/ ",
/* 4 */
" _ _ ",
"| || | ",
"| || |_ ",
"|__ _|",
" | | ",
" |_| ",
/* 5 */
" _____ ",
"| ____|",
"| |__ ",
"|___ \\ ",
" ___) |",
"|____/ ",
/* 6 */
" __ ",
" / / ",
" / /_ ",
"| '_ \\ ",
"| (_) |",
" \\___/ ",
/* 7 */
" ______ ",
"|____ |",
" / / ",
" / / ",
" / / ",
" /_/ ",
/* 8 */
" ___ ",
" / _ \\ ",
"| (_) |",
" > _ < ",
"| (_) |",
" \\___/ ",
/* 9 */
" ___ ",
" / _ \\ ",
"| (_) |",
" \\__, |",
" / / ",
" /_/ ",
/* A */
" ",
" /\\ ",
" / \\ ",
" / /\\ \\ ",
" / ____ \\ ",
"/_/ \\_\\",
/* B */
" ____ ",
"| _ \\ ",
"| |_) |",
"| _ < ",
"| |_) |",
"|____/ ",
/* C */
" _____ ",
" / ____|",
"| | ",
"| | ",
"| |____ ",
" \\_____|",
/* D */
" _____ ",
"| __ \\ ",
"| | | |",
"| | | |",
"| |__| |",
"|_____/ ",
/* E */
" ______ ",
"| ____|",
"| |__ ",
"| __| ",
"| |____ ",
"|______|",
/* F */
" ______ ",
"| ____|",
"| |__ ",
"| __| ",
"| | ",
"|_| ",
};
/*
** Render an 8-digit hexadecimal string as ascii arg.
** Space to hold the result is obtained from malloc() and should be freed
** by the caller.
*/
char *captcha_render(const char *zPw){
char *z = fossil_malloc( 10*6*strlen(zPw) + 7 );
int i, j, k, m;
const char *zChar;
unsigned char x;
int y;
k = 0;
for(i=0; i<6; i++){
x = 0;
for(j=0; zPw[j]; j++){
unsigned char v = hexValue(zPw[j]);
x = (x<<4) + v;
switch( x ){
case 0x7a:
case 0xfa:
y = 3;
break;
case 0x47:
y = 2;
break;
case 0xf6:
case 0xa9:
case 0xa4:
case 0xa1:
case 0x9a:
case 0x76:
case 0x61:
case 0x67:
case 0x69:
case 0x41:
case 0x42:
case 0x43:
case 0x4a:
y = 1;
break;
default:
y = 0;
break;
}
zChar = azFont3[6*v + i];
while( y && zChar[0]==' ' ){ y--; zChar++; }
while( y && z[k-1]==' ' ){ y--; k--; }
for(m=0; zChar[m]; m++){
z[k++] = zChar[m];
}
}
z[k++] = '\n';
}
z[k] = 0;
return z;
}
#endif /* CAPTCHA==3 */
/*
** COMMAND: test-captcha
*/
void test_captcha(void){
|
| ︙ | ︙ | |||
443 444 445 446 447 448 449 | /* ** Return true if a CAPTCHA is required for editing wiki or tickets or for ** adding attachments. ** ** A CAPTCHA is required in those cases if the user is not logged in (if they ** are user "nobody") and if the "require-captcha" setting is true. The | | | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
/*
** Return true if a CAPTCHA is required for editing wiki or tickets or for
** adding attachments.
**
** A CAPTCHA is required in those cases if the user is not logged in (if they
** are user "nobody") and if the "require-captcha" setting is true. The
** "require-captcha" setting is controlled on the Admin/Access page. It
** defaults to true.
*/
int captcha_needed(void){
if( g.zLogin!=0 ) return 0;
return db_get_boolean("require-captcha", 1);
}
|
| ︙ | ︙ | |||
494 495 496 497 498 499 500 | /* ** Generate a captcha display together with the necessary hidden parameter ** for the seed and the entry box into which the user will type the text of ** the captcha. This is typically done at the very bottom of a form. ** ** This routine is a no-op if no captcha is required. */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
/*
** Generate a captcha display together with the necessary hidden parameter
** for the seed and the entry box into which the user will type the text of
** the captcha. This is typically done at the very bottom of a form.
**
** This routine is a no-op if no captcha is required.
*/
void captcha_generate(int showButton){
unsigned int uSeed;
const char *zDecoded;
char *zCaptcha;
if( !captcha_needed() ) return;
uSeed = captcha_seed();
zDecoded = captcha_decode(uSeed);
zCaptcha = captcha_render(zDecoded);
@ <div class="captcha"><table class="captcha"><tr><td><pre>
@ %h(zCaptcha)
@ </pre>
@ Enter security code shown above:
@ <input type="hidden" name="captchaseed" value="%u(uSeed)" />
@ <input type="text" name="captcha" size=8 />
if( showButton ){
@ <input type="submit" value="Submit">
}
@ </td></tr></table></div>
}
/*
** WEBPAGE: test-captcha
*/
void captcha_test(void){
const char *zPw = P("name");
if( zPw==0 || zPw[0]==0 ){
u64 x;
sqlite3_randomness(sizeof(x), &x);
zPw = mprintf("%016llx", x);
}
style_header("Captcha Test");
@ <pre>
@ %s(captcha_render(zPw))
@ </pre>
style_footer();
}
/*
** Check to see if the current request is coming from an agent that might
** be a spider. If the agent is not a spider, then return 0 without doing
** anything. But if the user agent appears to be a spider, offer
** a captcha challenge to allow the user agent to prove that it is human
** and return non-zero.
*/
int exclude_spiders(const char *zPage){
const char *zCookieValue;
char *zCookieName;
if( g.isHuman ) return 0;
#if 0
{
const char *zReferer = P("HTTP_REFERER");
if( zReferer && strncmp(g.zBaseURL, zReferer, strlen(g.zBaseURL))==0 ){
return 0;
}
}
#endif
zCookieName = mprintf("fossil-cc-%.10s", db_get("project-code","x"));
zCookieValue = P(zCookieName);
if( zCookieValue && atoi(zCookieValue)==1 ) return 0;
if( captcha_is_correct() ){
cgi_set_cookie(zCookieName, "1", login_cookie_path(), 8*3600);
return 0;
}
/* This appears to be a spider. Offer the captcha */
style_header("Verification");
form_begin(0, "%s", zPage);
cgi_query_parameters_to_hidden();
@ <p>Please demonstrate that you are human, not a spider or robot</p>
captcha_generate(1);
@ </form>
style_footer();
return 1;
}
|
Changes to src/cgi.c.
| ︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
typedef int socklen_t;
#endif
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "cgi.h"
#if INTERFACE
/*
** Shortcuts for cgi_parameter. P("x") returns the value of query parameter
** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y")
** does the same except "y" is returned in place of NULL if there is not match.
*/
#define P(x) cgi_parameter((x),0)
#define PD(x,y) cgi_parameter((x),(y))
#define PT(x) cgi_parameter_trimmed((x),0)
#define PDT(x,y) cgi_parameter_trimmed((x),(y))
/*
** Destinations for output text.
*/
#define CGI_HEADER 0
#define CGI_BODY 1
#endif /* INTERFACE */
/*
** The HTTP reply is generated in two pieces: the header and the body.
** These pieces are generated separately because they are not necessary
** produced in order. Parts of the header might be built after all or
** part of the body. The header and body are accumulated in separate
| > > > > > > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
typedef int socklen_t;
#endif
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "cgi.h"
#include "cygsup.h"
#if INTERFACE
/*
** Shortcuts for cgi_parameter. P("x") returns the value of query parameter
** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y")
** does the same except "y" is returned in place of NULL if there is not match.
*/
#define P(x) cgi_parameter((x),0)
#define PD(x,y) cgi_parameter((x),(y))
#define PT(x) cgi_parameter_trimmed((x),0)
#define PDT(x,y) cgi_parameter_trimmed((x),(y))
/*
** Destinations for output text.
*/
#define CGI_HEADER 0
#define CGI_BODY 1
/*
** Flags for SSH HTTP clients
*/
#define CGI_SSH_CLIENT 0x0001 /* Client is SSH */
#define CGI_SSH_COMPAT 0x0002 /* Compat for old SSH transport */
#define CGI_SSH_FOSSIL 0x0004 /* Use new Fossil SSH transport */
#endif /* INTERFACE */
/*
** The HTTP reply is generated in two pieces: the header and the body.
** These pieces are generated separately because they are not necessary
** produced in order. Parts of the header might be built after all or
** part of the body. The header and body are accumulated in separate
|
| ︙ | ︙ | |||
256 257 258 259 260 261 262 |
for( zTok = strtok_r(zBuf, ",\"",&zPos);
zTok && fossil_stricmp(zTok,zETag);
zTok = strtok_r(0, ",\"",&zPos)){}
fossil_free(zBuf);
if(zTok) return 1;
}
}
| | > > > > > > > > > > | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
for( zTok = strtok_r(zBuf, ",\"",&zPos);
zTok && fossil_stricmp(zTok,zETag);
zTok = strtok_r(0, ",\"",&zPos)){}
fossil_free(zBuf);
if(zTok) return 1;
}
}
return 0;
}
#endif
/*
** Return true if the response should be sent with Content-Encoding: gzip.
*/
static int is_gzippable(void){
if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
return strncmp(zContentType, "text/", 5)==0
|| strglob("application/*xml", zContentType)
|| strglob("application/*javascript", zContentType);
}
/*
** Do a normal HTTP reply
*/
void cgi_reply(void){
int total_size;
if( iReplyStatus<=0 ){
|
| ︙ | ︙ | |||
338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
cgi_combine_header_and_body();
blob_compress(&cgiContent[0], &cgiContent[0]);
}
if( iReplyStatus != 304 ) {
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
}else{
total_size = 0;
}
fprintf(g.httpOut, "\r\n");
if( total_size>0 && iReplyStatus != 304 ){
| > > > > > > > > > > > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
cgi_combine_header_and_body();
blob_compress(&cgiContent[0], &cgiContent[0]);
}
if( iReplyStatus != 304 ) {
if( is_gzippable() ){
int i;
gzip_begin(0);
for( i=0; i<2; i++ ){
int size = blob_size(&cgiContent[i]);
if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
blob_reset(&cgiContent[i]);
}
gzip_finish(&cgiContent[0]);
fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
}
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
}else{
total_size = 0;
}
fprintf(g.httpOut, "\r\n");
if( total_size>0 && iReplyStatus != 304 ){
|
| ︙ | ︙ | |||
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
static int nUsedQP = 0; /* Space actually used in aParamQP[] */
static int sortQP = 0; /* True if aParamQP[] needs sorting */
static int seqQP = 0; /* Sequence numbers */
static struct QParam { /* One entry for each query parameter or cookie */
const char *zName; /* Parameter or cookie name */
const char *zValue; /* Value of the query parameter or cookie */
int seq; /* Order of insertion */
} *aParamQP; /* An array of all parameters and cookies */
/*
** Add another query parameter or cookie to the parameter set.
** zName is the name of the query parameter or cookie and zValue
** is its fully decoded value.
**
** zName and zValue are not copied and must not change or be
** deallocated after this routine returns.
*/
| > | > | | | | | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
static int nUsedQP = 0; /* Space actually used in aParamQP[] */
static int sortQP = 0; /* True if aParamQP[] needs sorting */
static int seqQP = 0; /* Sequence numbers */
static struct QParam { /* One entry for each query parameter or cookie */
const char *zName; /* Parameter or cookie name */
const char *zValue; /* Value of the query parameter or cookie */
int seq; /* Order of insertion */
int isQP; /* True for query parameters */
} *aParamQP; /* An array of all parameters and cookies */
/*
** Add another query parameter or cookie to the parameter set.
** zName is the name of the query parameter or cookie and zValue
** is its fully decoded value.
**
** zName and zValue are not copied and must not change or be
** deallocated after this routine returns.
*/
void cgi_set_parameter_nocopy(const char *zName, const char *zValue, int isQP){
if( nAllocQP<=nUsedQP ){
nAllocQP = nAllocQP*2 + 10;
if( nAllocQP>1000 ){
/* Prevent a DOS service attack against the framework */
fossil_fatal("Too many query parameters");
}
aParamQP = fossil_realloc( aParamQP, nAllocQP*sizeof(aParamQP[0]) );
}
aParamQP[nUsedQP].zName = zName;
aParamQP[nUsedQP].zValue = zValue;
if( g.fHttpTrace ){
fprintf(stderr, "# cgi: %s = [%s]\n", zName, zValue);
}
aParamQP[nUsedQP].seq = seqQP++;
aParamQP[nUsedQP].isQP = isQP;
nUsedQP++;
sortQP = 1;
}
/*
** Add another query parameter or cookie to the parameter set.
** zName is the name of the query parameter or cookie and zValue
** is its fully decoded value.
**
** Copies are made of both the zName and zValue parameters.
*/
void cgi_set_parameter(const char *zName, const char *zValue){
cgi_set_parameter_nocopy(mprintf("%s",zName), mprintf("%s",zValue), 0);
}
/*
** Replace a parameter with a new value.
*/
void cgi_replace_parameter(const char *zName, const char *zValue){
int i;
for(i=0; i<nUsedQP; i++){
if( fossil_strcmp(aParamQP[i].zName,zName)==0 ){
aParamQP[i].zValue = zValue;
return;
}
}
cgi_set_parameter_nocopy(zName, zValue, 0);
}
/*
** Add a query parameter. The zName portion is fixed but a copy
** must be made of zValue.
*/
void cgi_setenv(const char *zName, const char *zValue){
cgi_set_parameter_nocopy(zName, mprintf("%s",zValue), 0);
}
/*
** Add a list of query parameters or cookies to the parameter set.
**
** Each parameter is of the form NAME=VALUE. Both the NAME and the
** VALUE may be url-encoded ("+" for space, "%HH" for other special
** characters). But this routine assumes that NAME contains no
|
| ︙ | ︙ | |||
491 492 493 494 495 496 497 498 499 500 501 502 503 504 |
** before the NAME is ignored.
**
** The input string "z" is modified but no copies is made. "z"
** should not be deallocated or changed again after this routine
** returns or it will corrupt the parameter table.
*/
static void add_param_list(char *z, int terminator){
while( *z ){
char *zName;
char *zValue;
while( fossil_isspace(*z) ){ z++; }
zName = z;
while( *z && *z!='=' && *z!=terminator ){ z++; }
if( *z=='=' ){
| > | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 |
** before the NAME is ignored.
**
** The input string "z" is modified but no copies is made. "z"
** should not be deallocated or changed again after this routine
** returns or it will corrupt the parameter table.
*/
static void add_param_list(char *z, int terminator){
int isQP = terminator=='&';
while( *z ){
char *zName;
char *zValue;
while( fossil_isspace(*z) ){ z++; }
zName = z;
while( *z && *z!='=' && *z!=terminator ){ z++; }
if( *z=='=' ){
|
| ︙ | ︙ | |||
512 513 514 515 516 517 518 |
}
dehttpize(zValue);
}else{
if( *z ){ *z++ = 0; }
zValue = "";
}
if( fossil_islower(zName[0]) ){
| | | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 |
}
dehttpize(zValue);
}else{
if( *z ){ *z++ = 0; }
zValue = "";
}
if( fossil_islower(zName[0]) ){
cgi_set_parameter_nocopy(zName, zValue, isQP);
}
#ifdef FOSSIL_ENABLE_JSON
json_setenv( zName, cson_value_new_string(zValue,strlen(zValue)) );
#endif /* FOSSIL_ENABLE_JSON */
}
}
|
| ︙ | ︙ | |||
580 581 582 583 584 585 586 |
*pnContent = i;
i += nBoundry;
break;
}
}
*pz = &z[i];
get_line_from_string(pz, pLen);
| | | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
*pnContent = i;
i += nBoundry;
break;
}
}
*pz = &z[i];
get_line_from_string(pz, pLen);
return z;
}
/*
** Tokenize a line of text into as many as nArg tokens. Make
** azArg[] point to the start of each token.
**
** Tokens consist of space or semi-colon delimited words or
|
| ︙ | ︙ | |||
656 657 658 659 660 661 662 |
zBoundry = get_line_from_string(&z, &len);
if( zBoundry==0 ) return;
while( (zLine = get_line_from_string(&z, &len))!=0 ){
if( zLine[0]==0 ){
int nContent = 0;
zValue = get_bounded_content(&z, &len, zBoundry, &nContent);
if( zName && zValue && fossil_islower(zName[0]) ){
| | | | | | | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
zBoundry = get_line_from_string(&z, &len);
if( zBoundry==0 ) return;
while( (zLine = get_line_from_string(&z, &len))!=0 ){
if( zLine[0]==0 ){
int nContent = 0;
zValue = get_bounded_content(&z, &len, zBoundry, &nContent);
if( zName && zValue && fossil_islower(zName[0]) ){
cgi_set_parameter_nocopy(zName, zValue, 1);
if( showBytes ){
cgi_set_parameter_nocopy(mprintf("%s:bytes", zName),
mprintf("%d",nContent), 1);
}
}
zName = 0;
showBytes = 0;
}else{
nArg = tokenize_line(zLine, sizeof(azArg)/sizeof(azArg[0]), azArg);
for(i=0; i<nArg; i++){
int c = fossil_tolower(azArg[i][0]);
int n = strlen(azArg[i]);
if( c=='c' && sqlite3_strnicmp(azArg[i],"content-disposition:",n)==0 ){
i++;
}else if( c=='n' && sqlite3_strnicmp(azArg[i],"name=",n)==0 ){
zName = azArg[++i];
}else if( c=='f' && sqlite3_strnicmp(azArg[i],"filename=",n)==0 ){
char *z = azArg[++i];
if( zName && z && fossil_islower(zName[0]) ){
cgi_set_parameter_nocopy(mprintf("%s:filename",zName), z, 1);
}
showBytes = 1;
}else if( c=='c' && sqlite3_strnicmp(azArg[i],"content-type:",n)==0 ){
char *z = azArg[++i];
if( zName && z && fossil_islower(zName[0]) ){
cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z, 1);
}
}
}
}
}
}
#ifdef FOSSIL_ENABLE_JSON
/*
** Internal helper for cson_data_source_FILE_n().
*/
|
| ︙ | ︙ | |||
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 |
fprintf(stderr, "# failed to open %s\n", zFile);
return;
}
}
fputs(z, pLog);
}
/*
** Initialize the query parameter database. Information is pulled from
** the QUERY_STRING environment variable (if it exists), from standard
** input if there is POST data, and from HTTP_COOKIE.
*/
void cgi_init(void){
char *z;
const char *zType;
int len;
#ifdef FOSSIL_ENABLE_JSON
json_main_bootstrap();
#endif
g.isHTTP = 1;
cgi_destination(CGI_BODY);
z = (char*)P("HTTP_COOKIE");
if( z ){
z = mprintf("%s",z);
add_param_list(z, ';');
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | > | | 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 |
fprintf(stderr, "# failed to open %s\n", zFile);
return;
}
}
fputs(z, pLog);
}
/* Forward declaration */
static NORETURN void malformed_request(const char *zMsg);
/*
** Initialize the query parameter database. Information is pulled from
** the QUERY_STRING environment variable (if it exists), from standard
** input if there is POST data, and from HTTP_COOKIE.
**
** REQUEST_URI, PATH_INFO, and SCRIPT_NAME are related as follows:
**
** REQUEST_URI == SCRIPT_NAME + PATH_INFO
**
** Where "+" means concatenate. Fossil requires SCRIPT_NAME. If
** REQUEST_URI is provided but PATH_INFO is not, then PATH_INFO is
** computed from REQUEST_URI and SCRIPT_NAME. If PATH_INFO is provided
** but REQUEST_URI is not, then compute REQUEST_URI from PATH_INFO and
** SCRIPT_NAME. If neither REQUEST_URI nor PATH_INFO are provided, then
** assume that PATH_INFO is an empty string and set REQUEST_URI equal
** to PATH_INFO.
**
** SCGI typically omits PATH_INFO. CGI sometimes omits REQUEST_URI and
** PATH_INFO when it is empty.
*/
void cgi_init(void){
char *z;
const char *zType;
int len;
const char *zRequestUri = cgi_parameter("REQUEST_URI",0);
const char *zScriptName = cgi_parameter("SCRIPT_NAME",0);
const char *zPathInfo = cgi_parameter("PATH_INFO","");
#ifdef FOSSIL_ENABLE_JSON
json_main_bootstrap();
#endif
g.isHTTP = 1;
cgi_destination(CGI_BODY);
if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME");
if( zRequestUri==0 ){
const char *z = zPathInfo;
if( zPathInfo==0 ){
malformed_request("missing PATH_INFO and/or REQUEST_URI");
}
if( z[0]=='/' ) z++;
zRequestUri = mprintf("%s/%s", zScriptName, z);
cgi_set_parameter("REQUEST_URI", zRequestUri);
}
if( zPathInfo==0 ){
int i, j;
for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){}
for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
cgi_set_parameter("PATH_INFO", mprintf("%.*s", j-i, zRequestUri+i));
}
z = (char*)P("HTTP_COOKIE");
if( z ){
z = mprintf("%s",z);
add_param_list(z, ';');
}
z = (char*)P("QUERY_STRING");
if( z ){
z = mprintf("%s",z);
add_param_list(z, '&');
}
z = (char*)P("REMOTE_ADDR");
if( z ){
g.zIpAddr = mprintf("%s", z);
}
len = atoi(PD("CONTENT_LENGTH", "0"));
g.zContentType = zType = P("CONTENT_TYPE");
blob_zero(&g.cgiIn);
if( len>0 && zType ){
if( fossil_strcmp(zType,"application/x-www-form-urlencoded")==0
|| strncmp(zType,"multipart/form-data",19)==0 ){
z = fossil_malloc( len+1 );
len = fread(z, 1, len, g.httpIn);
z[len] = 0;
cgi_trace(z);
if( zType[0]=='a' ){
add_param_list(z, '&');
|
| ︙ | ︙ | |||
877 878 879 880 881 882 883 |
g.json.isJsonMode = 1;
cgi_parse_POST_JSON(g.httpIn, (unsigned int)len);
/* FIXMEs:
- See if fossil really needs g.cgiIn to be set for this purpose
(i don't think it does). If it does then fill g.cgiIn and
refactor to parse the JSON from there.
| | | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 |
g.json.isJsonMode = 1;
cgi_parse_POST_JSON(g.httpIn, (unsigned int)len);
/* FIXMEs:
- See if fossil really needs g.cgiIn to be set for this purpose
(i don't think it does). If it does then fill g.cgiIn and
refactor to parse the JSON from there.
- After parsing POST JSON, copy the "first layer" of keys/values
to cgi_setenv(), honoring the upper-case distinction used
in add_param_list(). However...
- If we do that then we might get a disconnect in precedence of
GET/POST arguments. i prefer for GET entries to take precedence
over like-named POST entries, but in order for that to happen we
|
| ︙ | ︙ | |||
965 966 967 968 969 970 971 |
/* If no match is found and the name begins with an upper-case
** letter, then check to see if there is an environment variable
** with the given name.
*/
if( fossil_isupper(zName[0]) ){
const char *zValue = fossil_getenv(zName);
if( zValue ){
| | | 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 |
/* If no match is found and the name begins with an upper-case
** letter, then check to see if there is an environment variable
** with the given name.
*/
if( fossil_isupper(zName[0]) ){
const char *zValue = fossil_getenv(zName);
if( zValue ){
cgi_set_parameter_nocopy(zName, zValue, 0);
CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
return zValue;
}
}
CGIDEBUG(("no-match [%s]\n", zName));
return zDefault;
}
|
| ︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 |
if( !showAll ){
if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue;
if( fossil_strnicmp("fossil-",zName,7)==0 ) continue;
}
cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue);
}
}
/*
** This routine works like "printf" except that it has the
** extra formatting capabilities such as %h and %t.
*/
void cgi_printf(const char *zFormat, ...){
va_list ap;
| > > > > > > > > > > > > > > > | 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 |
if( !showAll ){
if( fossil_stricmp("HTTP_COOKIE",zName)==0 ) continue;
if( fossil_strnicmp("fossil-",zName,7)==0 ) continue;
}
cgi_printf("%h = %h <br />\n", zName, aParamQP[i].zValue);
}
}
/*
** Export all query parameters (but not cookies or environment variables)
** as hidden values of a form.
*/
void cgi_query_parameters_to_hidden(void){
int i;
const char *zN, *zV;
for(i=0; i<nUsedQP; i++){
if( aParamQP[i].isQP==0 ) continue;
zN = aParamQP[i].zName;
zV = aParamQP[i].zValue;
@ <input type="hidden" name="%h(zN)" value="%h(zV)">
}
}
/*
** This routine works like "printf" except that it has the
** extra formatting capabilities such as %h and %t.
*/
void cgi_printf(const char *zFormat, ...){
va_list ap;
|
| ︙ | ︙ | |||
1090 1091 1092 1093 1094 1095 1096 | vxprintf(pContent,zFormat,ap); } /* ** Send a reply indicating that the HTTP request was malformed */ | | | | 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 |
vxprintf(pContent,zFormat,ap);
}
/*
** Send a reply indicating that the HTTP request was malformed
*/
static NORETURN void malformed_request(const char *zMsg){
cgi_set_status(501, "Not Implemented");
cgi_printf(
"<html><body><p>Bad Request: %s</p></body></html>\n", zMsg
);
cgi_reply();
fossil_exit(0);
}
/*
** Panic and die while processing a webpage.
|
| ︙ | ︙ | |||
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 |
va_start(ap, zFormat);
vxprintf(pContent,zFormat,ap);
va_end(ap);
cgi_reply();
fossil_exit(1);
}
}
/*
** Remove the first space-delimited token from a string and return
** a pointer to it. Add a NULL to the string to terminate the token.
** Make *zLeftOver point to the start of the next token.
*/
static char *extract_token(char *zInput, char **zLeftOver){
| > > > > > > > > > > > > > > | 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 |
va_start(ap, zFormat);
vxprintf(pContent,zFormat,ap);
va_end(ap);
cgi_reply();
fossil_exit(1);
}
}
/* z[] is the value of an X-FORWARDED-FOR: line in an HTTP header.
** Return a pointer to a string containing the real IP address, or a
** NULL pointer to stick with the IP address previously computed and
** loaded into g.zIpAddr.
*/
static const char *cgi_accept_forwarded_for(const char *z){
int i;
if( fossil_strcmp(g.zIpAddr, "127.0.0.1")!=0 ) return 0;
i = strlen(z)-1;
while( i>=0 && z[i]!=',' && !fossil_isspace(z[i]) ) i--;
return &z[++i];
}
/*
** Remove the first space-delimited token from a string and return
** a pointer to it. Add a NULL to the string to terminate the token.
** Make *zLeftOver point to the start of the next token.
*/
static char *extract_token(char *zInput, char **zLeftOver){
|
| ︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 |
char *z, *zToken;
int i;
struct sockaddr_in remoteName;
socklen_t size = sizeof(struct sockaddr_in);
char zLine[2000]; /* A single line of input. */
g.fullHttpReply = 1;
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
| | > | | | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > | > | > | > | < | > > > > > > > | | > > > > > > > | > > | > > > > > | < < > | < > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 |
char *z, *zToken;
int i;
struct sockaddr_in remoteName;
socklen_t size = sizeof(struct sockaddr_in);
char zLine[2000]; /* A single line of input. */
g.fullHttpReply = 1;
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
malformed_request("missing HTTP header");
}
blob_append(&g.httpHeader, zLine, -1);
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken==0 ){
malformed_request("malformed HTTP header");
}
if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
&& fossil_strcmp(zToken,"HEAD")!=0 ){
malformed_request("unsupported HTTP method");
}
cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
cgi_setenv("REQUEST_METHOD",zToken);
zToken = extract_token(z, &z);
if( zToken==0 ){
malformed_request("malformed URL in HTTP header");
}
cgi_setenv("REQUEST_URI", zToken);
cgi_setenv("SCRIPT_NAME", "");
for(i=0; zToken[i] && zToken[i]!='?'; i++){}
if( zToken[i] ) zToken[i++] = 0;
cgi_setenv("PATH_INFO", zToken);
cgi_setenv("QUERY_STRING", &zToken[i]);
if( zIpAddr==0 &&
getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName,
&size)>=0
){
zIpAddr = inet_ntoa(remoteName.sin_addr);
}
if( zIpAddr ){
cgi_setenv("REMOTE_ADDR", zIpAddr);
g.zIpAddr = mprintf("%s", zIpAddr);
}
/* Get all the optional fields that follow the first line.
*/
while( fgets(zLine,sizeof(zLine),g.httpIn) ){
char *zFieldName;
char *zVal;
cgi_trace(zLine);
blob_append(&g.httpHeader, zLine, -1);
zFieldName = extract_token(zLine,&zVal);
if( zFieldName==0 || *zFieldName==0 ) break;
while( fossil_isspace(*zVal) ){ zVal++; }
i = strlen(zVal);
while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
zVal[i] = 0;
for(i=0; zFieldName[i]; i++){
zFieldName[i] = fossil_tolower(zFieldName[i]);
}
if( fossil_strcmp(zFieldName,"accept-encoding:")==0 ){
cgi_setenv("HTTP_ACCEPT_ENCODING", zVal);
}else if( fossil_strcmp(zFieldName,"content-length:")==0 ){
cgi_setenv("CONTENT_LENGTH", zVal);
}else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
cgi_setenv("CONTENT_TYPE", zVal);
}else if( fossil_strcmp(zFieldName,"cookie:")==0 ){
cgi_setenv("HTTP_COOKIE", zVal);
}else if( fossil_strcmp(zFieldName,"https:")==0 ){
cgi_setenv("HTTPS", zVal);
}else if( fossil_strcmp(zFieldName,"host:")==0 ){
cgi_setenv("HTTP_HOST", zVal);
}else if( fossil_strcmp(zFieldName,"if-none-match:")==0 ){
cgi_setenv("HTTP_IF_NONE_MATCH", zVal);
}else if( fossil_strcmp(zFieldName,"if-modified-since:")==0 ){
cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
}else if( fossil_strcmp(zFieldName,"referer:")==0 ){
cgi_setenv("HTTP_REFERER", zVal);
}else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){
cgi_setenv("HTTP_USER_AGENT", zVal);
}else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
const char *zIpAddr = cgi_accept_forwarded_for(zVal);
if( zIpAddr!=0 ){
g.zIpAddr = mprintf("%s", zIpAddr);
cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
}
}
}
cgi_init();
cgi_trace(0);
}
/*
** This routine handles a single HTTP request from an SSH client which is
** coming in on g.httpIn and which replies on g.httpOut
**
** Once all the setup is finished, this procedure returns
** and subsequent code handles the actual generation of the webpage.
**
** It is called in a loop so some variables will need to be replaced
*/
void cgi_handle_ssh_http_request(const char *zIpAddr){
static int nCycles = 0;
static char *zCmd = 0;
char *z, *zToken;
const char *zType = 0;
int i, content_length = 0;
char zLine[2000]; /* A single line of input. */
if( zIpAddr ){
if( nCycles==0 ){
cgi_setenv("REMOTE_ADDR", zIpAddr);
g.zIpAddr = mprintf("%s", zIpAddr);
}
}else{
fossil_panic("missing SSH IP address");
}
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
malformed_request("missing HTTP header");
}
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken==0 ){
malformed_request("malformed HTTP header");
}
if( fossil_strcmp(zToken, "echo")==0 ){
/* start looking for probes to complete transport_open */
zCmd = cgi_handle_ssh_probes(zLine, sizeof(zLine), z, zToken);
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
malformed_request("missing HTTP header");
}
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken==0 ){
malformed_request("malformed HTTP header");
}
}else if( zToken && strlen(zToken)==0 && zCmd ){
/* transport_flip request and continued transport_open */
cgi_handle_ssh_transport(zCmd);
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
malformed_request("missing HTTP header");
}
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken==0 ){
malformed_request("malformed HTTP header");
}
}
if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
&& fossil_strcmp(zToken,"HEAD")!=0 ){
malformed_request("unsupported HTTP method");
}
if( nCycles==0 ){
cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
cgi_setenv("REQUEST_METHOD",zToken);
}
zToken = extract_token(z, &z);
if( zToken==0 ){
malformed_request("malformed URL in HTTP header");
}
if( nCycles==0 ){
cgi_setenv("REQUEST_URI", zToken);
cgi_setenv("SCRIPT_NAME", "");
}
for(i=0; zToken[i] && zToken[i]!='?'; i++){}
if( zToken[i] ) zToken[i++] = 0;
if( nCycles==0 ){
cgi_setenv("PATH_INFO", zToken);
}else{
cgi_replace_parameter("PATH_INFO", mprintf("%s",zToken));
}
/* Get all the optional fields that follow the first line.
*/
while( fgets(zLine,sizeof(zLine),g.httpIn) ){
char *zFieldName;
char *zVal;
cgi_trace(zLine);
zFieldName = extract_token(zLine,&zVal);
if( zFieldName==0 || *zFieldName==0 ) break;
while( fossil_isspace(*zVal) ){ zVal++; }
i = strlen(zVal);
while( i>0 && fossil_isspace(zVal[i-1]) ){ i--; }
zVal[i] = 0;
for(i=0; zFieldName[i]; i++){
zFieldName[i] = fossil_tolower(zFieldName[i]);
}
if( fossil_strcmp(zFieldName,"content-length:")==0 ){
content_length = atoi(zVal);
}else if( fossil_strcmp(zFieldName,"content-type:")==0 ){
g.zContentType = zType = mprintf("%s", zVal);
}else if( fossil_strcmp(zFieldName,"host:")==0 ){
if( nCycles==0 ){
cgi_setenv("HTTP_HOST", zVal);
}
}else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){
if( nCycles==0 ){
cgi_setenv("HTTP_USER_AGENT", zVal);
}
}else if( fossil_strcmp(zFieldName,"x-fossil-transport:")==0 ){
if( fossil_strnicmp(zVal, "ssh", 3)==0 ){
if( nCycles==0 ){
g.fSshClient |= CGI_SSH_FOSSIL;
g.fullHttpReply = 0;
}
}
}
}
if( nCycles==0 ){
if( ! ( g.fSshClient & CGI_SSH_FOSSIL ) ){
/* did not find new fossil ssh transport */
g.fSshClient &= ~CGI_SSH_CLIENT;
g.fullHttpReply = 1;
cgi_replace_parameter("REMOTE_ADDR", "127.0.0.1");
}
}
cgi_reset_content();
cgi_destination(CGI_BODY);
if( content_length>0 && zType ){
blob_zero(&g.cgiIn);
if( fossil_strcmp(zType, "application/x-fossil")==0 ){
blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
blob_uncompress(&g.cgiIn, &g.cgiIn);
}else if( fossil_strcmp(zType, "application/x-fossil-debug")==0 ){
blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
}else if( fossil_strcmp(zType, "application/x-fossil-uncompressed")==0 ){
blob_read_from_channel(&g.cgiIn, g.httpIn, content_length);
}
}
cgi_trace(0);
nCycles++;
}
/*
** This routine handles the old fossil SSH probes
*/
char *cgi_handle_ssh_probes(char *zLine, int zSize, char *z, char *zToken){
/* Start looking for probes */
while( fossil_strcmp(zToken, "echo")==0 ){
zToken = extract_token(z, &z);
if( zToken==0 ){
malformed_request("malformed probe");
}
if( fossil_strncmp(zToken, "test", 4)==0 ||
fossil_strncmp(zToken, "probe-", 6)==0 ){
fprintf(g.httpOut, "%s\n", zToken);
fflush(g.httpOut);
}else{
malformed_request("malformed probe");
}
if( fgets(zLine, zSize, g.httpIn)==0 ){
malformed_request("malformed probe");
}
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken==0 ){
malformed_request("malformed probe");
}
}
/* Got all probes now first transport_open is completed
** so return the command that was requested
*/
g.fSshClient |= CGI_SSH_COMPAT;
return mprintf("%s", zToken);
}
/*
** This routine handles the old fossil SSH transport_flip
** and transport_open communications if detected.
*/
void cgi_handle_ssh_transport(const char *zCmd){
char *z, *zToken;
char zLine[2000]; /* A single line of input. */
/* look for second newline of transport_flip */
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
malformed_request("incorrect transport_flip");
}
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken && strlen(zToken)==0 ){
/* look for path to fossil */
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
if ( zCmd==0 ){
malformed_request("missing fossil command");
}else{
/* no new command so exit */
fossil_exit(0);
}
}
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken==0 ){
malformed_request("malformed fossil command");
}
/* see if we've seen the command */
if( zCmd && zCmd[0] && fossil_strcmp(zToken, zCmd)==0 ){
return;
}else{
malformed_request("transport_open failed");
}
}else{
malformed_request("transport_flip failed");
}
}
/*
** This routine handles a single SCGI request which is coming in on
** g.httpIn and which replies on g.httpOut
**
** The SCGI request is read from g.httpIn and is used to initialize
** entries in the cgi_parameter() hash, as if those entries were
** environment variables. A call to cgi_init() completes
** the setup. Once all the setup is finished, this procedure returns
** and subsequent code handles the actual generation of the webpage.
*/
void cgi_handle_scgi_request(void){
char *zHdr;
char *zToFree;
int nHdr = 0;
int nRead;
int n, m;
char c;
while( (c = fgetc(g.httpIn))!=EOF && fossil_isdigit(c) ){
nHdr = nHdr*10 + c - '0';
}
if( nHdr<16 ) malformed_request("SCGI header too short");
zToFree = zHdr = fossil_malloc(nHdr);
nRead = (int)fread(zHdr, 1, nHdr, g.httpIn);
if( nRead<nHdr ) malformed_request("cannot read entire SCGI header");
nHdr = nRead;
while( nHdr ){
for(n=0; n<nHdr && zHdr[n]; n++){}
for(m=n+1; m<nHdr && zHdr[m]; m++){}
if( m>=nHdr ) malformed_request("SCGI header formatting error");
cgi_set_parameter(zHdr, zHdr+n+1);
zHdr += m+1;
nHdr -= m+1;
}
fossil_free(zToFree);
fgetc(g.httpIn); /* Read past the "," separating header from content */
cgi_init();
}
#if INTERFACE
/*
** Bitmap values for the flags parameter to cgi_http_server().
*/
#define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
#define HTTP_SERVER_SCGI 0x0002 /* SCGI instead of HTTP */
#endif /* INTERFACE */
/*
** Maximum number of child processes that we can have running
** at one time before we start slowing things down.
*/
|
| ︙ | ︙ | |||
1331 1332 1333 1334 1335 1336 1337 |
}else{
fossil_fatal("unable to open listening socket on any"
" port in the range %d..%d", mnPort, mxPort);
}
}
if( iPort>mxPort ) return 1;
listen(listener,10);
| < | > | < > > > > > > > > > > | 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 |
}else{
fossil_fatal("unable to open listening socket on any"
" port in the range %d..%d", mnPort, mxPort);
}
}
if( iPort>mxPort ) return 1;
listen(listener,10);
fossil_print("Listening for %s requests on TCP port %d\n",
(flags & HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
fflush(stdout);
if( zBrowser ){
zBrowser = mprintf(zBrowser, iPort);
#if defined(__CYGWIN__)
/* On Cygwin, we can do better than "echo" */
if( memcmp(zBrowser, "echo ", 5)==0 ){
wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5);
wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */
if( (size_t)ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){
fossil_warning("cannot start browser\n");
}
}else
#endif
if( system(zBrowser)<0 ){
fossil_warning("cannot start browser: %s\n", zBrowser);
}
}
while( 1 ){
if( nchildren>MAX_PARALLEL ){
/* Slow down if connections are arriving too fast */
|
| ︙ | ︙ | |||
1383 1384 1385 1386 1387 1388 1389 |
}
}
/* Bury dead children */
while( waitpid(0, 0, WNOHANG)>0 ){
nchildren--;
}
}
| | | 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 |
}
}
/* Bury dead children */
while( waitpid(0, 0, WNOHANG)>0 ){
nchildren--;
}
}
/* NOT REACHED */
fossil_exit(1);
#endif
/* NOT REACHED */
return 0;
}
|
| ︙ | ︙ | |||
1471 1472 1473 1474 1475 1476 1477 |
}else if( p->tm_mon>11 ){
p->tm_year += p->tm_mon/12;
p->tm_mon %= 12;
}
isLeapYr = p->tm_year%4==0 && (p->tm_year%100!=0 || (p->tm_year+300)%400==0);
p->tm_yday = priorDays[p->tm_mon] + p->tm_mday - 1;
if( isLeapYr && p->tm_mon>1 ) p->tm_yday++;
| | > > > > > > > > > > > > > > > > > > | 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 |
}else if( p->tm_mon>11 ){
p->tm_year += p->tm_mon/12;
p->tm_mon %= 12;
}
isLeapYr = p->tm_year%4==0 && (p->tm_year%100!=0 || (p->tm_year+300)%400==0);
p->tm_yday = priorDays[p->tm_mon] + p->tm_mday - 1;
if( isLeapYr && p->tm_mon>1 ) p->tm_yday++;
nDay = (p->tm_year-70)*365 + (p->tm_year-69)/4 -p->tm_year/100 +
(p->tm_year+300)/400 + p->tm_yday;
t = ((nDay*24 + p->tm_hour)*60 + p->tm_min)*60 + p->tm_sec;
return t;
}
/*
** Check the objectTime against the If-Modified-Since request header. If the
** object time isn't any newer than the header, we immediately send back
** a 304 reply and exit.
*/
void cgi_modified_since(time_t objectTime){
const char *zIf = P("HTTP_IF_MODIFIED_SINCE");
if( zIf==0 ) return;
if( objectTime > cgi_rfc822_parsedate(zIf) ) return;
cgi_set_status(304,"Not Modified");
cgi_reset_content();
cgi_reply();
fossil_exit(0);
}
/*
** Check to see if the remote client is SSH and return
** its IP or return default
*/
const char *cgi_ssh_remote_addr(const char *zDefault){
char *zIndex;
const char *zSshConn = fossil_getenv("SSH_CONNECTION");
if( zSshConn && zSshConn[0] ){
char *zSshClient = mprintf("%s",zSshConn);
if( (zIndex = strchr(zSshClient,' '))!=0 ){
zSshClient[zIndex-zSshClient] = '\0';
return zSshClient;
}
}
return zDefault;
}
|
Changes to src/checkin.c.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 44 45 46 |
int missingIsFatal, /* MISSING and NOT_A_FILE are fatal errors */
int cwdRelative /* Report relative to the current working dir */
){
Stmt q;
int nPrefix = strlen(zPrefix);
int nErr = 0;
Blob rewrittenPathname;
db_prepare(&q,
"SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
" FROM vfile "
| > > > > > > > > > > > > > > > > > > > > | | > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
int missingIsFatal, /* MISSING and NOT_A_FILE are fatal errors */
int cwdRelative /* Report relative to the current working dir */
){
Stmt q;
int nPrefix = strlen(zPrefix);
int nErr = 0;
Blob rewrittenPathname;
Blob where;
const char *zName;
int i;
blob_zero(&where);
for(i=2; i<g.argc; i++) {
Blob fname;
file_tree_name(g.argv[i], &fname, 1);
zName = blob_str(&fname);
if( fossil_strcmp(zName, ".")==0 ) {
blob_reset(&where);
break;
}
blob_appendf(&where, " %s (pathname=%Q %s) "
"OR (pathname>'%q/' %s AND pathname<'%q0' %s)",
(blob_size(&where)>0) ? "OR" : "AND", zName,
filename_collation(), zName, filename_collation(),
zName, filename_collation());
}
db_prepare(&q,
"SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
" FROM vfile "
" WHERE is_selected(id) %s"
" AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1",
blob_str(&where)
);
blob_zero(&rewrittenPathname);
while( db_step(&q)==SQLITE_ROW ){
const char *zPathname = db_column_text(&q,0);
const char *zDisplayName = zPathname;
int isDeleted = db_column_int(&q, 1);
int isChnged = db_column_int(&q,2);
|
| ︙ | ︙ | |||
80 81 82 83 84 85 86 |
nErr++;
}
}
}else if( isNew ){
blob_appendf(report, "ADDED %s\n", zDisplayName);
}else if( isDeleted ){
blob_appendf(report, "DELETED %s\n", zDisplayName);
| | > | | | | > > > | > > | | > | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
nErr++;
}
}
}else if( isNew ){
blob_appendf(report, "ADDED %s\n", zDisplayName);
}else if( isDeleted ){
blob_appendf(report, "DELETED %s\n", zDisplayName);
}else if( isChnged ){
if( isChnged==2 ){
blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName);
}else if( isChnged==3 ){
blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
}else if( isChnged==4 ){
blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
}else if( isChnged==5 ){
blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
}else if( file_contains_merge_marker(zFullName) ){
blob_appendf(report, "CONFLICT %s\n", zDisplayName);
}else{
blob_appendf(report, "EDITED %s\n", zDisplayName);
}
}else if( isRenamed ){
blob_appendf(report, "RENAMED %s\n", zDisplayName);
}else{
report->nUsed -= nPrefix;
}
free(zFullName);
}
blob_reset(&rewrittenPathname);
db_finalize(&q);
db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
" WHERE id<=0");
while( db_step(&q)==SQLITE_ROW ){
const char *zLabel = "MERGED_WITH";
switch( db_column_int(&q, 1) ){
case -1: zLabel = "CHERRYPICK "; break;
case -2: zLabel = "BACKOUT "; break;
case -4: zLabel = "INTEGRATE "; break;
}
blob_append(report, zPrefix, nPrefix);
blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0));
}
db_finalize(&q);
if( nErr ){
fossil_fatal("aborting due to prior errors");
|
| ︙ | ︙ | |||
215 216 217 218 219 220 221 | db_record_repository_filename(0); changes_cmd(); } /* ** COMMAND: ls ** | | | > > > > > > > > > > > > > > > > > > > | | | | | > | < | < | | | | | | | | | | | > > > > > > > > > > > | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
db_record_repository_filename(0);
changes_cmd();
}
/*
** COMMAND: ls
**
** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
**
** Show the names of all files in the current checkout. The -v provides
** extra information about each file. If FILENAMES are included, only
** the files listed (or their children if they are directories) are shown.
**
** Options:
** --age Show when each file was committed
** -v|--verbose Provide extra information about each file.
**
** See also: changes, extra, status
*/
void ls_cmd(void){
int vid;
Stmt q;
int verboseFlag;
int showAge;
char *zOrderBy = "pathname";
Blob where;
int i;
const char *zName;
verboseFlag = find_option("verbose","v", 0)!=0;
if( !verboseFlag ){
verboseFlag = find_option("l","l", 0)!=0; /* deprecated */
}
showAge = find_option("age",0,0)!=0;
db_must_be_within_tree();
vid = db_lget_int("checkout", 0);
if( find_option("t","t",0)!=0 ){
if( showAge ){
zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid);
}else{
zOrderBy = "mtime DESC";
}
}
verify_all_options();
blob_zero(&where);
for(i=2; i<g.argc; i++){
Blob fname;
file_tree_name(g.argv[i], &fname, 1);
zName = blob_str(&fname);
if( fossil_strcmp(zName, ".")==0 ) {
blob_reset(&where);
break;
}
blob_appendf(&where, " %s (pathname=%Q %s) "
"OR (pathname>'%q/' %s AND pathname<'%q0' %s)",
(blob_size(&where)>0) ? "OR" : "WHERE", zName,
filename_collation(), zName, filename_collation(),
zName, filename_collation());
}
vfile_check_signature(vid, 0);
if( showAge ){
db_prepare(&q,
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
" datetime(checkin_mtime(%d,rid),'unixepoch'%s)"
" FROM vfile %s"
" ORDER BY %s", vid, timeline_utc(), blob_str(&where), zOrderBy
);
}else{
db_prepare(&q,
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
" FROM vfile %s"
" ORDER BY %s", blob_str(&where), zOrderBy
);
}
blob_reset(&where);
while( db_step(&q)==SQLITE_ROW ){
const char *zPathname = db_column_text(&q,0);
int isDeleted = db_column_int(&q, 1);
int isNew = db_column_int(&q,2)==0;
int chnged = db_column_int(&q,3);
int renamed = db_column_int(&q,4);
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
const char *type = "";
if( verboseFlag ){
if( isNew ){
type = "ADDED ";
}else if( isDeleted ){
type = "DELETED ";
}else if( !file_wd_isfile_or_link(zFullName) ){
if( file_access(zFullName, 0)==0 ){
type = "NOT_A_FILE ";
}else{
type = "MISSING ";
}
}else if( chnged ){
if( chnged==2 ){
type = "UPDATED_BY_MERGE ";
}else if( chnged==3 ){
type = "ADDED_BY_MERGE ";
}else if( chnged==4 ){
type = "UPDATED_BY_INTEGRATE ";
}else if( chnged==5 ){
type = "ADDED_BY_INTEGRATE ";
}else if( file_contains_merge_marker(zFullName) ){
type = "CONFLICT ";
}else{
type = "EDITED ";
}
}else if( renamed ){
type = "RENAMED ";
}else{
type = "UNCHANGED ";
}
}
if( showAge ){
fossil_print("%s%s %s\n", type, db_column_text(&q, 5), zPathname);
}else{
fossil_print("%s%s\n", type, zPathname);
}
free(zFullName);
}
db_finalize(&q);
}
/*
** Create a TEMP table named SFILE and add all unmanaged files named on
** the command-line to that table. If directories are named, then add
** all unmanaged files contained underneath those directories. If there
** are no files or directories named on the command-line, then add all
** unmanaged files anywhere in the checkout.
*/
static void locate_unmanaged_files(
int argc, /* Number of command-line arguments to examine */
char **argv, /* values of command-line arguments */
unsigned scanFlags, /* Zero or more SCAN_xxx flags */
Glob *pIgnore1, /* Do not add files that match this GLOB */
Glob *pIgnore2 /* Omit files matching this GLOB too */
){
Blob name; /* Name of a candidate file or directory */
char *zName; /* Name of a candidate file or directory */
int isDir; /* 1 for a directory, 0 if doesn't exist, 2 for anything else */
int i; /* Loop counter */
int nRoot; /* length of g.zLocalRoot */
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
filename_collation());
nRoot = (int)strlen(g.zLocalRoot);
if( argc==0 ){
blob_init(&name, g.zLocalRoot, nRoot - 1);
vfile_scan(&name, blob_size(&name), scanFlags, pIgnore1, pIgnore2);
blob_reset(&name);
}else{
for(i=0; i<argc; i++){
file_canonical_name(argv[i], &name, 0);
zName = blob_str(&name);
isDir = file_wd_isdir(zName);
if( isDir==1 ){
vfile_scan(&name, nRoot-1, scanFlags, pIgnore1, pIgnore2);
}else if( isDir==0 ){
fossil_warning("not found: %s", &zName[nRoot]);
}else if( file_access(zName, R_OK) ){
fossil_fatal("cannot open %s", &zName[nRoot]);
}else{
db_multi_exec(
"INSERT OR IGNORE INTO sfile(x) VALUES(%Q)",
&zName[nRoot]
);
}
blob_reset(&name);
}
}
}
/*
** COMMAND: extras
** Usage: %fossil extras ?OPTIONS? ?PATH1 ...?
**
** Print a list of all files in the source tree that are not part of
** the current checkout. See also the "clean" command. If paths are
** specified, only files in the given directories will be listed.
**
** Files and subdirectories whose names begin with "." are normally
** ignored but can be included by adding the --dotfiles option.
**
** The GLOBPATTERN is a comma-separated list of GLOB expressions for
** files that are ignored. The GLOBPATTERN specified by the "ignore-glob"
** is used if the --ignore option is omitted.
|
| ︙ | ︙ | |||
324 325 326 327 328 329 330 |
** --ignore <CSG> ignore files matching patterns from the argument
** --rel-paths Display pathnames relative to the current working
** directory.
**
** See also: changes, clean, status
*/
void extra_cmd(void){
| < < < < < < | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
** --ignore <CSG> ignore files matching patterns from the argument
** --rel-paths Display pathnames relative to the current working
** directory.
**
** See also: changes, clean, status
*/
void extra_cmd(void){
Stmt q;
const char *zIgnoreFlag = find_option("ignore",0,1);
unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
int cwdRelative = 0;
Glob *pIgnore;
Blob rewrittenPathname;
const char *zPathname, *zDisplayName;
if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
capture_case_sensitive_option();
db_must_be_within_tree();
cwdRelative = determine_cwd_relative_option();
if( zIgnoreFlag==0 ){
zIgnoreFlag = db_get("ignore-glob", 0);
}
pIgnore = glob_create(zIgnoreFlag);
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
glob_free(pIgnore);
db_prepare(&q,
"SELECT x FROM sfile"
" WHERE x NOT IN (%s)"
" ORDER BY 1",
fossil_all_reserved_names(0)
);
|
| ︙ | ︙ | |||
375 376 377 378 379 380 381 | } blob_reset(&rewrittenPathname); db_finalize(&q); } /* ** COMMAND: clean | | | > > > > > > > > > > > > > > > > > | > < < < > > > > | > > > < < < < > | > | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | > | | | | | | > > > | > | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 |
}
blob_reset(&rewrittenPathname);
db_finalize(&q);
}
/*
** COMMAND: clean
** Usage: %fossil clean ?OPTIONS? ?PATH1 ...?
**
** Delete all "extra" files in the source tree. "Extra" files are
** files that are not officially part of the checkout. This operation
** cannot be undone. If paths are specified, only the directories or
** files specified will be considered for cleaning.
**
** You will be prompted before removing each eligible file unless the
** --force flag is in use or it matches the --clean option. The
** GLOBPATTERN specified by the "ignore-glob" setting is used if the
** --ignore option is omitted, the same with "clean-glob" and --clean
** as well as "keep-glob" and --keep. If you are sure you wish to
** remove all "extra" files except the ones specified with --ignore
** and --keep, you can specify the optional -f|--force flag and no
** prompts will be issued. If a file matches both --keep and --clean,
** --keep takes precedence.
**
** Files and subdirectories whose names begin with "." are
** normally kept. They are handled if the "--dotfiles" option
** is used.
**
** Options:
** --allckouts Check for empty directories within any checkouts
** that may be nested within the current one. This
** option should be used with great care because the
** empty-dirs setting (and other applicable settings)
** belonging to the other repositories, if any, will
** not be checked.
** --case-sensitive <BOOL> override case-sensitive setting
** --dirsonly Only remove empty directories. No files will
** be removed. Using this option will automatically
** enable the --emptydirs option as well.
** --dotfiles Include files beginning with a dot (".").
** --emptydirs Remove any empty directories that are not
** explicitly exempted via the empty-dirs setting
** or another applicable setting or command line
** argument. Matching files, if any, are removed
** prior to checking for any empty directories;
** therefore, directories that contain only files
** that were removed will be removed as well.
** -f|--force Remove files without prompting.
** --clean <CSG> Never prompt for files matching this
** comma separated list of glob patterns.
** --ignore <CSG> Ignore files matching patterns from the
** comma separated list of glob patterns.
** --keep <CSG> Keep files matching this comma separated
** list of glob patterns.
** -n|--dry-run If given, display instead of run actions.
** --temp Remove only Fossil-generated temporary files.
** -v|--verbose Show all files as they are removed.
**
** See also: addremove, extra, status
*/
void clean_cmd(void){
int allFileFlag, allDirFlag, dryRunFlag, verboseFlag;
int emptyDirsFlag, dirsOnlyFlag;
unsigned scanFlags = 0;
const char *zIgnoreFlag, *zKeepFlag, *zCleanFlag;
Glob *pIgnore, *pKeep, *pClean;
int nRoot;
dryRunFlag = find_option("dry-run","n",0)!=0;
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
if( !dryRunFlag ){
dryRunFlag = find_option("whatif",0,0)!=0;
}
allFileFlag = allDirFlag = find_option("force","f",0)!=0;
dirsOnlyFlag = find_option("dirsonly",0,0)!=0;
emptyDirsFlag = find_option("emptydirs","d",0)!=0 || dirsOnlyFlag;
if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
if( find_option("allckouts",0,0)!=0 ) scanFlags |= SCAN_NESTED;
zIgnoreFlag = find_option("ignore",0,1);
verboseFlag = find_option("verbose","v",0)!=0;
zKeepFlag = find_option("keep",0,1);
zCleanFlag = find_option("clean",0,1);
capture_case_sensitive_option();
db_must_be_within_tree();
if( zIgnoreFlag==0 ){
zIgnoreFlag = db_get("ignore-glob", 0);
}
if( zKeepFlag==0 ){
zKeepFlag = db_get("keep-glob", 0);
}
if( zCleanFlag==0 ){
zCleanFlag = db_get("clean-glob", 0);
}
verify_all_options();
pIgnore = glob_create(zIgnoreFlag);
pKeep = glob_create(zKeepFlag);
pClean = glob_create(zCleanFlag);
nRoot = (int)strlen(g.zLocalRoot);
if( !dirsOnlyFlag ){
Stmt q;
Blob repo;
locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, pKeep);
db_prepare(&q,
"SELECT %Q || x FROM sfile"
" WHERE x NOT IN (%s)"
" ORDER BY 1",
g.zLocalRoot, fossil_all_reserved_names(0)
);
if( file_tree_name(g.zRepositoryName, &repo, 0) ){
db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo);
}
db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
if( !allFileFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
Blob ans;
char cReply;
char *prompt = mprintf("Remove unmanaged file \"%s\" (a=all/y/N)? ",
zName+nRoot);
blob_zero(&ans);
prompt_user(prompt, &ans);
cReply = blob_str(&ans)[0];
if( cReply=='a' || cReply=='A' ){
allFileFlag = 1;
}else if( cReply!='y' && cReply!='Y' ){
blob_reset(&ans);
continue;
}
blob_reset(&ans);
}
if ( dryRunFlag || file_delete(zName)==0 ){
if( verboseFlag || dryRunFlag ){
fossil_print("Removed unmanaged file: %s\n", zName+nRoot);
}
}else if( verboseFlag ){
fossil_print("Could not remove file: %s\n", zName+nRoot);
}
}
db_finalize(&q);
}
if( emptyDirsFlag ){
Glob *pEmptyDirs = glob_create(db_get("empty-dirs", 0));
Stmt q;
Blob root;
blob_init(&root, g.zLocalRoot, nRoot - 1);
vfile_dir_scan(&root, blob_size(&root), scanFlags, pIgnore, pKeep,
pEmptyDirs);
blob_reset(&root);
db_prepare(&q,
"SELECT %Q || x FROM dscan_temp"
" WHERE x NOT IN (%s) AND y = 0"
" ORDER BY 1 DESC",
g.zLocalRoot, fossil_all_reserved_names(0)
);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
if( !allDirFlag && !dryRunFlag && !glob_match(pClean, zName+nRoot) ){
Blob ans;
char cReply;
char *prompt = mprintf("Remove empty directory \"%s\" (a=all/y/N)? ",
zName+nRoot);
blob_zero(&ans);
prompt_user(prompt, &ans);
cReply = blob_str(&ans)[0];
if( cReply=='a' || cReply=='A' ){
allDirFlag = 1;
}else if( cReply!='y' && cReply!='Y' ){
blob_reset(&ans);
continue;
}
blob_reset(&ans);
}
if ( dryRunFlag || file_rmdir(zName)==0 ){
if( verboseFlag || dryRunFlag ){
fossil_print("Removed unmanaged directory: %s\n", zName+nRoot);
}
}else if( verboseFlag ){
fossil_print("Could not remove directory: %s\n", zName+nRoot);
}
}
db_finalize(&q);
glob_free(pEmptyDirs);
}
glob_free(pClean);
glob_free(pKeep);
glob_free(pIgnore);
}
/*
** Prompt the user for a check-in or stash comment (given in pPrompt),
** gather the response, then return the response in pComment.
**
** Lines of the prompt that begin with # are discarded. Excess whitespace
|
| ︙ | ︙ | |||
516 517 518 519 520 521 522 |
zEditor = db_get("editor", 0);
if( zEditor==0 ){
zEditor = fossil_getenv("VISUAL");
}
if( zEditor==0 ){
zEditor = fossil_getenv("EDITOR");
}
| | | > > > > > > > < > > | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
zEditor = db_get("editor", 0);
if( zEditor==0 ){
zEditor = fossil_getenv("VISUAL");
}
if( zEditor==0 ){
zEditor = fossil_getenv("EDITOR");
}
#if defined(_WIN32) || defined(__CYGWIN__)
if( zEditor==0 ){
zEditor = mprintf("%s\\notepad.exe", fossil_getenv("SYSTEMROOT"));
#if defined(__CYGWIN__)
zEditor = fossil_utf8_to_filename(zEditor);
blob_add_cr(pPrompt);
#endif
}
#endif
if( zEditor==0 ){
blob_append(pPrompt,
"#\n"
"# Since no default text editor is set using EDITOR or VISUAL\n"
"# environment variables or the \"fossil set editor\" command,\n"
"# and because no comment was specified using the \"-m\" or \"-M\"\n"
"# command-line options, you will need to enter the comment below.\n"
"# Type \".\" on a line by itself when you are done:\n", -1);
zFile = mprintf("-");
}else{
Blob fname;
blob_zero(&fname);
file_relative_name(g.zLocalRoot, &fname, 1);
zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'",
blob_str(&fname));
blob_reset(&fname);
}
#if defined(_WIN32)
blob_add_cr(pPrompt);
#endif
blob_write_to_file(pPrompt, zFile);
if( zEditor ){
zCmd = mprintf("%s \"%s\"", zEditor, zFile);
|
| ︙ | ︙ | |||
603 604 605 606 607 608 609 |
static void prepare_commit_comment(
Blob *pComment,
char *zInit,
CheckinInfo *p,
int parent_rid
){
Blob prompt;
| | | > > > > > > > | 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 |
static void prepare_commit_comment(
Blob *pComment,
char *zInit,
CheckinInfo *p,
int parent_rid
){
Blob prompt;
#if defined(_WIN32) || defined(__CYGWIN__)
int bomSize;
const unsigned char *bom = get_utf8_bom(&bomSize);
blob_init(&prompt, (const char *) bom, bomSize);
if( zInit && zInit[0]) {
blob_append(&prompt, zInit, -1);
}
#else
blob_init(&prompt, zInit, -1);
#endif
blob_append(&prompt,
"\n"
"# Enter commit message for this check-in. Lines beginning with # are ignored.\n"
"#\n", -1
);
blob_appendf(&prompt, "# user: %s\n", p->zUserOvrd ? p->zUserOvrd : g.zLogin);
if( p->zBranch && p->zBranch[0] ){
blob_appendf(&prompt, "# tags: %s\n#\n", p->zBranch);
}else{
char *zTags = info_tags_of_checkin(parent_rid, 1);
if( zTags ) blob_appendf(&prompt, "# tags: %z\n#\n", zTags);
}
status_report(&prompt, "# ", 1, 0);
if( g.markPrivate ){
blob_append(&prompt,
"# PRIVATE BRANCH: This check-in will be private and will not sync to\n"
"# repositories.\n"
"#\n", -1
);
}
if( p->integrateFlag ){
blob_append(&prompt,
"#\n"
"# All merged-in branches will be closed due to the --integrate flag\n"
"#\n", -1
);
}
prompt_for_user_comment(pComment, &prompt);
blob_reset(&prompt);
}
/*
** Populate the Global.aCommitFile[] based on the command line arguments
|
| ︙ | ︙ | |||
655 656 657 658 659 660 661 662 663 |
** allocated and remains NULL. Other parts of the code interpret this
** to mean "all files".
**
** Returns 1 if there was a warning, 0 otherwise.
*/
int select_commit_files(void){
int result = 0;
if( g.argc>2 ){
int ii, jj=0;
| > | < > > | > > > | | > > > > > | > > > > > > > > | < < | > > > > > | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 |
** allocated and remains NULL. Other parts of the code interpret this
** to mean "all files".
**
** Returns 1 if there was a warning, 0 otherwise.
*/
int select_commit_files(void){
int result = 0;
assert( g.aCommitFile==0 );
if( g.argc>2 ){
int ii, jj=0;
Blob fname;
Stmt q;
const char *zCollate;
Bag toCommit;
zCollate = filename_collation();
blob_zero(&fname);
bag_init(&toCommit);
for(ii=2; ii<g.argc; ii++){
int cnt = 0;
file_tree_name(g.argv[ii], &fname, 1);
if( fossil_strcmp(blob_str(&fname),".")==0 ){
bag_clear(&toCommit);
return result;
}
db_prepare(&q,
"SELECT id FROM vfile WHERE pathname=%Q %s"
" OR (pathname>'%q/' %s AND pathname<'%q0' %s)",
blob_str(&fname), zCollate, blob_str(&fname),
zCollate, blob_str(&fname), zCollate);
while( db_step(&q)==SQLITE_ROW ){
cnt++;
bag_insert(&toCommit, db_column_int(&q, 0));
}
db_finalize(&q);
if( cnt==0 ){
fossil_warning("fossil knows nothing about: %s", g.argv[ii]);
result = 1;
}
blob_reset(&fname);
}
g.aCommitFile = fossil_malloc( (bag_count(&toCommit)+1) * sizeof(g.aCommitFile[0]) );
for(ii=bag_first(&toCommit); ii>0; ii=bag_next(&toCommit, ii)){
g.aCommitFile[jj++] = ii;
}
g.aCommitFile[jj] = 0;
bag_clear(&toCommit);
}
return result;
}
/*
** Make sure the current check-in with timestamp zDate is younger than its
** ancestor identified rid and zUuid. Throw a fatal error if not.
|
| ︙ | ︙ | |||
748 749 750 751 752 753 754 755 756 757 758 759 760 761 |
** The following structure holds some of the information needed to construct a
** check-in manifest.
*/
struct CheckinInfo {
Blob *pComment; /* Check-in comment text */
const char *zMimetype; /* Mimetype of check-in command. May be NULL */
int verifyDate; /* Verify that child is younger */
Blob *pCksum; /* Repository checksum. May be 0 */
const char *zDateOvrd; /* Date override. If 0 then use 'now' */
const char *zUserOvrd; /* User override. If 0 then use g.zLogin */
const char *zBranch; /* Branch name. May be 0 */
const char *zColor; /* One-time background color. May be 0 */
const char *zBrClr; /* Persistent branch color. May be 0 */
const char **azTag; /* Tags to apply to this check-in */
| > > | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 |
** The following structure holds some of the information needed to construct a
** check-in manifest.
*/
struct CheckinInfo {
Blob *pComment; /* Check-in comment text */
const char *zMimetype; /* Mimetype of check-in command. May be NULL */
int verifyDate; /* Verify that child is younger */
int closeFlag; /* Close the branch being committed */
int integrateFlag; /* Close merged-in branches */
Blob *pCksum; /* Repository checksum. May be 0 */
const char *zDateOvrd; /* Date override. If 0 then use 'now' */
const char *zUserOvrd; /* User override. If 0 then use g.zLogin */
const char *zBranch; /* Branch name. May be 0 */
const char *zColor; /* One-time background color. May be 0 */
const char *zBrClr; /* Persistent branch color. May be 0 */
const char **azTag; /* Tags to apply to this check-in */
|
| ︙ | ︙ | |||
770 771 772 773 774 775 776 |
const char *zBaselineUuid, /* UUID of baseline, or zero */
Manifest *pBaseline, /* Make it a delta manifest if not zero */
int vid, /* BLOB.id for the parent check-in */
CheckinInfo *p, /* Information about the check-in */
int *pnFBcard /* OUT: Number of generated B- and F-cards */
){
char *zDate; /* Date of the check-in */
| | | < > | > > > > > > > > | > > > | 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 |
const char *zBaselineUuid, /* UUID of baseline, or zero */
Manifest *pBaseline, /* Make it a delta manifest if not zero */
int vid, /* BLOB.id for the parent check-in */
CheckinInfo *p, /* Information about the check-in */
int *pnFBcard /* OUT: Number of generated B- and F-cards */
){
char *zDate; /* Date of the check-in */
char *zParentUuid = 0; /* UUID of parent check-in */
Blob filename; /* A single filename */
int nBasename; /* Size of base filename */
Stmt q; /* Various queries */
Blob mcksum; /* Manifest checksum */
ManifestFile *pFile; /* File from the baseline */
int nFBcard = 0; /* Number of B-cards and F-cards */
int i; /* Loop counter */
const char *zColor; /* Modified value of p->zColor */
assert( pBaseline==0 || pBaseline->zBaseline==0 );
assert( pBaseline==0 || zBaselineUuid!=0 );
blob_zero(pOut);
if( vid ){
zParentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d AND "
"EXISTS(SELECT 1 FROM event WHERE event.type='ci' and event.objid=%d)",
vid, vid);
if( !zParentUuid ){
fossil_fatal("Could not find a valid check-in for RID %d. "
"Possible checkout/repo mismatch.", vid);
}
}
if( pBaseline ){
blob_appendf(pOut, "B %s\n", zBaselineUuid);
manifest_file_rewind(pBaseline);
pFile = manifest_file_next(pBaseline, 0);
nFBcard++;
}else{
pFile = 0;
}
if( blob_size(p->pComment)!=0 ){
blob_appendf(pOut, "C %F\n", blob_str(p->pComment));
}else{
blob_append(pOut, "C (no\\scomment)\n", 16);
}
zDate = date_in_standard_format(p->zDateOvrd ? p->zDateOvrd : "now");
blob_appendf(pOut, "D %s\n", zDate);
zDate[10] = ' ';
db_prepare(&q,
"SELECT pathname, uuid, origname, blob.rid, isexe, islink,"
" is_selected(vfile.id)"
" FROM vfile JOIN blob ON vfile.mrid=blob.rid"
|
| ︙ | ︙ | |||
875 876 877 878 879 880 881 |
blob_appendf(pOut, "F %F\n", pFile->zName);
pFile = manifest_file_next(pBaseline, 0);
nFBcard++;
}
if( p->zMimetype && p->zMimetype[0] ){
blob_appendf(pOut, "N %F\n", p->zMimetype);
}
| > | | | | | | | | | | | | | | | | < | | > > | | | | | > > | | > | > > > > > > > > > > > > > > > > < | 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 |
blob_appendf(pOut, "F %F\n", pFile->zName);
pFile = manifest_file_next(pBaseline, 0);
nFBcard++;
}
if( p->zMimetype && p->zMimetype[0] ){
blob_appendf(pOut, "N %F\n", p->zMimetype);
}
if( vid ){
blob_appendf(pOut, "P %s", zParentUuid);
if( p->verifyDate ) checkin_verify_younger(vid, zParentUuid, zDate);
free(zParentUuid);
db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0 OR id<-2");
while( db_step(&q)==SQLITE_ROW ){
char *zMergeUuid;
int mid = db_column_int(&q, 0);
if( (!g.markPrivate && content_is_private(mid)) || (mid == vid) ) continue;
zMergeUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid);
if( zMergeUuid ){
blob_appendf(pOut, " %s", zMergeUuid);
if( p->verifyDate ) checkin_verify_younger(mid, zMergeUuid, zDate);
free(zMergeUuid);
}
}
db_finalize(&q);
blob_appendf(pOut, "\n");
}
free(zDate);
db_prepare(&q,
"SELECT CASE vmerge.id WHEN -1 THEN '+' ELSE '-' END || blob.uuid, merge"
" FROM vmerge, blob"
" WHERE (vmerge.id=-1 OR vmerge.id=-2)"
" AND blob.rid=vmerge.merge"
" ORDER BY 1");
while( db_step(&q)==SQLITE_ROW ){
const char *zCherrypickUuid = db_column_text(&q, 0);
int mid = db_column_int(&q, 1);
if( mid != vid ){
blob_appendf(pOut, "Q %s\n", zCherrypickUuid);
}
}
db_finalize(&q);
if( p->pCksum ) blob_appendf(pOut, "R %b\n", p->pCksum);
zColor = p->zColor;
if( p->zBranch && p->zBranch[0] ){
/* Set tags for the new branch */
if( p->zBrClr && p->zBrClr[0] ){
zColor = 0;
blob_appendf(pOut, "T *bgcolor * %F\n", p->zBrClr);
}
blob_appendf(pOut, "T *branch * %F\n", p->zBranch);
blob_appendf(pOut, "T *sym-%F *\n", p->zBranch);
}
if( zColor && zColor[0] ){
/* One-time background color */
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
}
if( p->closeFlag ){
blob_appendf(pOut, "T +closed *\n");
}
db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
" WHERE id %s ORDER BY 1",
p->integrateFlag ? "IN(0,-4)" : "=(-4)");
while( db_step(&q)==SQLITE_ROW ){
const char *zIntegrateUuid = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
if( is_a_leaf(rid) && !db_exists("SELECT 1 FROM tagxref "
" WHERE tagid=%d AND rid=%d AND tagtype>0", TAG_CLOSED, rid)){
blob_appendf(pOut, "T +closed %s\n", zIntegrateUuid);
}
}
db_finalize(&q);
if( p->azTag ){
for(i=0; p->azTag[i]; i++){
/* Add a symbolic tag to this check-in. The tag names have already
** been sorted and converted using the %F format */
assert( i==0 || strcmp(p->azTag[i-1], p->azTag[i])<=0 );
blob_appendf(pOut, "T +sym-%s *\n", p->azTag[i]);
}
}
if( p->zBranch && p->zBranch[0] ){
/* For a new branch, cancel all prior propagating tags */
db_prepare(&q,
"SELECT tagname FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
" AND tagtype==2 AND tagname GLOB 'sym-*'"
" AND tagname!='sym-'||%Q"
" ORDER BY tagname",
vid, p->zBranch);
|
| ︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 |
}
zDisable = "\"crnl-glob\" setting";
}else{
if( encodingOk ){
return 0; /* We don't want encoding warnings for this file. */
}
zWarning = "Unicode";
| < < < | 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 |
}
zDisable = "\"crnl-glob\" setting";
}else{
if( encodingOk ){
return 0; /* We don't want encoding warnings for this file. */
}
zWarning = "Unicode";
zDisable = "\"encoding-glob\" setting";
}
file_relative_name(zFilename, &fname, 0);
blob_zero(&ans);
zMsg = mprintf(
"%s contains %s. Use --no-warnings or the %s to disable this warning.\n"
"Commit anyhow (a=all/%sy/N)? ",
|
| ︙ | ︙ | |||
1140 1141 1142 1143 1144 1145 1146 | ** interactive user or these warnings should be skipped for some other ** reason, the --no-warnings option may be used. A check-in is not ** allowed against a closed leaf. ** ** The --private option creates a private check-in that is never synced. ** Children of private check-ins are automatically private. ** | | > > > > > > > | > | 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 |
** interactive user or these warnings should be skipped for some other
** reason, the --no-warnings option may be used. A check-in is not
** allowed against a closed leaf.
**
** The --private option creates a private check-in that is never synced.
** Children of private check-ins are automatically private.
**
** The --tag option applies the symbolic tag name to the check-in.
**
** The --sha1sum option detects edited files by computing each file's
** SHA1 hash rather than just checking for changes to its size or mtime.
**
** Options:
** --allow-conflict allow unresolved merge conflicts
** --allow-empty allow a commit with no changes
** --allow-fork allow the commit to fork
** --allow-older allow a commit older than its ancestor
** --baseline use a baseline manifest in the commit process
** --bgcolor COLOR apply COLOR to this one check-in only
** --branch NEW-BRANCH-NAME check in to this new branch
** --branchcolor COLOR apply given COLOR to the branch
** --close close the branch being committed
** --delta use a delta manifest in the commit process
** --integrate close all merged-in branches
** -m|--comment COMMENT-TEXT use COMMENT-TEXT as commit comment
** -M|--message-file FILE read the commit comment from given file
** --mimetype MIMETYPE mimetype of check-in comment
** -n|--dry-run If given, display instead of run actions
** --no-warnings omit all warnings about file contents
** --nosign do not attempt to sign this commit with gpg
** --private do not sync changes and their descendants
** --sha1sum verify file status using SHA1 hashing rather
** than relying on file mtimes
** --tag TAG-NAME assign given tag TAG-NAME to the checkin
**
** See also: branch, changes, checkout, extra, sync
*/
void commit_cmd(void){
int hasChanges; /* True if unsaved changes exist */
int vid; /* blob-id of parent version */
int nrid; /* blob-id of a modified file */
int nvid; /* Blob-id of the new check-in */
Blob comment; /* Check-in comment */
const char *zComment; /* Check-in comment */
Stmt q; /* Various queries */
char *zUuid; /* UUID of the new check-in */
int useSha1sum = 0; /* True to verify file status using SHA1 hashing */
int noSign = 0; /* True to omit signing the manifest using GPG */
int isAMerge = 0; /* True if checking in a merge */
int noWarningFlag = 0; /* True if skipping all warnings */
int forceFlag = 0; /* Undocumented: Disables all checks */
int forceDelta = 0; /* Force a delta-manifest */
int forceBaseline = 0; /* Force a baseline-manifest */
int allowConflict = 0; /* Allow unresolve merge conflicts */
|
| ︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 |
int nConflict = 0; /* Number of unresolved merge conflicts */
int abortCommit = 0;
Blob ans;
char cReply;
memset(&sCiInfo, 0, sizeof(sCiInfo));
url_proxy_options();
noSign = find_option("nosign",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
if( forceDelta && forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
dryRunFlag = find_option("dry-run","n",0)!=0;
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
zComment = find_option("comment","m",1);
forceFlag = find_option("force", "f", 0)!=0;
allowConflict = find_option("allow-conflict",0,0)!=0;
allowEmpty = find_option("allow-empty",0,0)!=0;
allowFork = find_option("allow-fork",0,0)!=0;
allowOlder = find_option("allow-older",0,0)!=0;
noWarningFlag = find_option("no-warnings", 0, 0)!=0;
sCiInfo.zBranch = find_option("branch","b",1);
sCiInfo.zColor = find_option("bgcolor",0,1);
sCiInfo.zBrClr = find_option("branchcolor",0,1);
sCiInfo.zMimetype = find_option("mimetype",0,1);
while( (zTag = find_option("tag",0,1))!=0 ){
if( zTag[0]==0 ) continue;
sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2));
sCiInfo.azTag[nTag++] = zTag;
sCiInfo.azTag[nTag] = 0;
}
| > > > | 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 |
int nConflict = 0; /* Number of unresolved merge conflicts */
int abortCommit = 0;
Blob ans;
char cReply;
memset(&sCiInfo, 0, sizeof(sCiInfo));
url_proxy_options();
useSha1sum = find_option("sha1sum", 0, 0)!=0;
noSign = find_option("nosign",0,0)!=0;
forceDelta = find_option("delta",0,0)!=0;
forceBaseline = find_option("baseline",0,0)!=0;
if( forceDelta && forceBaseline ){
fossil_fatal("cannot use --delta and --baseline together");
}
dryRunFlag = find_option("dry-run","n",0)!=0;
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
zComment = find_option("comment","m",1);
forceFlag = find_option("force", "f", 0)!=0;
allowConflict = find_option("allow-conflict",0,0)!=0;
allowEmpty = find_option("allow-empty",0,0)!=0;
allowFork = find_option("allow-fork",0,0)!=0;
allowOlder = find_option("allow-older",0,0)!=0;
noWarningFlag = find_option("no-warnings", 0, 0)!=0;
sCiInfo.zBranch = find_option("branch","b",1);
sCiInfo.zColor = find_option("bgcolor",0,1);
sCiInfo.zBrClr = find_option("branchcolor",0,1);
sCiInfo.closeFlag = find_option("close",0,0)!=0;
sCiInfo.integrateFlag = find_option("integrate",0,0)!=0;
sCiInfo.zMimetype = find_option("mimetype",0,1);
while( (zTag = find_option("tag",0,1))!=0 ){
if( zTag[0]==0 ) continue;
sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag, sizeof(char*)*(nTag+2));
sCiInfo.azTag[nTag++] = zTag;
sCiInfo.azTag[nTag] = 0;
}
|
| ︙ | ︙ | |||
1312 1313 1314 1315 1316 1317 1318 |
*/
if( select_commit_files() ){
blob_zero(&ans);
prompt_user("continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
}
| | < | | | | | | | 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 |
*/
if( select_commit_files() ){
blob_zero(&ans);
prompt_user("continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
}
isAMerge = db_exists("SELECT 1 FROM vmerge WHERE id=0 OR id<-2");
if( g.aCommitFile && isAMerge ){
fossil_fatal("cannot do a partial commit of a merge");
}
/* Doing "fossil mv fileA fileB; fossil add fileA; fossil commit fileA"
** will generate a manifest that has two fileA entries, which is illegal.
** When you think about it, the sequence above makes no sense. So detect
** it and disallow it. Ticket [0ff64b0a5fc8].
*/
if( g.aCommitFile ){
db_prepare(&q,
"SELECT v1.pathname, v2.pathname"
" FROM vfile AS v1, vfile AS v2"
" WHERE is_selected(v1.id)"
" AND v2.origname IS NOT NULL"
" AND v2.origname=v1.pathname"
" AND NOT is_selected(v2.id)");
if( db_step(&q)==SQLITE_ROW ){
const char *zFrom = db_column_text(&q, 0);
const char *zTo = db_column_text(&q, 1);
fossil_fatal("cannot do a partial commit of '%s' without '%s' because "
"'%s' was renamed to '%s'", zFrom, zTo, zFrom, zTo);
}
db_finalize(&q);
}
user_select();
/*
** Check that the user exists.
*/
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
fossil_fatal("no such user: %s", g.zLogin);
}
hasChanges = unsaved_changes(useSha1sum ? CKSIG_SHA1 : 0);
db_begin_transaction();
db_record_repository_filename(0);
if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
fossil_fatal("nothing has changed; use --allow-empty to override");
}
/* If none of the files that were named on the command line have
|
| ︙ | ︙ | |||
1374 1375 1376 1377 1378 1379 1380 1381 |
fossil_fatal("none of the selected files have changed; use "
"--allow-empty to override.");
}
/*
** Do not allow a commit that will cause a fork unless the --allow-fork
** or --force flags is used, or unless this is a private check-in.
*/
| > > > > > | | 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 |
fossil_fatal("none of the selected files have changed; use "
"--allow-empty to override.");
}
/*
** Do not allow a commit that will cause a fork unless the --allow-fork
** or --force flags is used, or unless this is a private check-in.
** The initial commit MUST have tags "trunk" and "sym-trunk".
*/
if( !vid ){
if( sCiInfo.zBranch==0 ){
sCiInfo.zBranch = db_get("main-branch", "trunk");
}
}else if( sCiInfo.zBranch==0 && allowFork==0 && forceFlag==0
&& g.markPrivate==0 && !is_a_leaf(vid)
){
fossil_fatal("would fork. \"update\" first or use --allow-fork.");
}
/*
** Do not allow a commit against a closed leaf
|
| ︙ | ︙ | |||
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 |
if( zComment ){
blob_zero(&comment);
blob_append(&comment, zComment, -1);
}else if( zComFile ){
blob_zero(&comment);
blob_read_from_file(&comment, zComFile);
blob_to_utf8_no_bom(&comment, 1);
}else{
char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
prepare_commit_comment(&comment, zInit, &sCiInfo, vid);
if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
blob_zero(&ans);
prompt_user("unchanged check-in comment. continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
}
free(zInit);
}
if( blob_size(&comment)==0 ){
| > > > | | | | | > | 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 |
if( zComment ){
blob_zero(&comment);
blob_append(&comment, zComment, -1);
}else if( zComFile ){
blob_zero(&comment);
blob_read_from_file(&comment, zComFile);
blob_to_utf8_no_bom(&comment, 1);
}else if(dryRunFlag){
blob_zero(&comment);
}else{
char *zInit = db_text(0, "SELECT value FROM vvar WHERE name='ci-comment'");
prepare_commit_comment(&comment, zInit, &sCiInfo, vid);
if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
blob_zero(&ans);
prompt_user("unchanged check-in comment. continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply!='y' && cReply!='Y' ) fossil_exit(1);;
}
free(zInit);
}
if( blob_size(&comment)==0 ){
if( !dryRunFlag ){
blob_zero(&ans);
prompt_user("empty check-in comment. continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply!='y' && cReply!='Y' ){
fossil_exit(1);
}
}
}else{
db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
db_end_transaction(0);
db_begin_transaction();
}
|
| ︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 |
"use --allow-conflict to override");
}else if( abortCommit ){
fossil_fatal("one or more files were converted on your request; "
"please re-test before committing");
}
/* Create the new manifest */
| < < < | | 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 |
"use --allow-conflict to override");
}else if( abortCommit ){
fossil_fatal("one or more files were converted on your request; "
"please re-test before committing");
}
/* Create the new manifest */
sCiInfo.pComment = &comment;
sCiInfo.pCksum = useCksum ? &cksum1 : 0;
sCiInfo.verifyDate = !allowOlder && !forceFlag;
if( forceDelta ){
blob_zero(&manifest);
}else{
create_manifest(&manifest, 0, 0, vid, &sCiInfo, &szB);
}
/* See if a delta-manifest would be more appropriate */
if( !forceBaseline ){
const char *zBaselineUuid;
Manifest *pParent;
Manifest *pBaseline;
pParent = manifest_get(vid, CFTYPE_MANIFEST, 0);
if( pParent && pParent->zBaseline ){
zBaselineUuid = pParent->zBaseline;
pBaseline = manifest_get_by_name(zBaselineUuid, 0);
}else{
zBaselineUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
pBaseline = pParent;
}
|
| ︙ | ︙ | |||
1541 1542 1543 1544 1545 1546 1547 |
if( forceDelta || (szD*szD)<(szB*3-9) ){
blob_reset(&manifest);
manifest = delta;
}else{
blob_reset(&delta);
}
}else if( forceDelta ){
| | < > | | > > > > > > > > > > > > > > > > | 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 |
if( forceDelta || (szD*szD)<(szB*3-9) ){
blob_reset(&manifest);
manifest = delta;
}else{
blob_reset(&delta);
}
}else if( forceDelta ){
fossil_fatal("unable to find a baseline-manifest for the delta");
}
}
if( !noSign && !g.markPrivate && clearsign(&manifest, &manifest) ){
blob_zero(&ans);
prompt_user("unable to sign manifest. continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply!='y' && cReply!='Y' ){
fossil_exit(1);
}
}
/* If the -n|--dry-run option is specified, output the manifest file
** and rollback the transaction.
*/
if( dryRunFlag ){
blob_write_to_file(&manifest, "");
}
if( outputManifest ){
zManifestFile = mprintf("%smanifest", g.zLocalRoot);
blob_write_to_file(&manifest, zManifestFile);
blob_reset(&manifest);
blob_read_from_file(&manifest, zManifestFile);
free(zManifestFile);
}
nvid = content_put(&manifest);
if( nvid==0 ){
fossil_fatal("trouble committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid);
if( manifest_crosslink(nvid, &manifest,
dryRunFlag ? MC_NONE : MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&manifest) );
content_deltify(vid, nvid, 0);
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid);
db_prepare(&q, "SELECT uuid,merge FROM vmerge JOIN blob ON merge=rid"
" WHERE id=-4");
while( db_step(&q)==SQLITE_ROW ){
const char *zIntegrateUuid = db_column_text(&q, 0);
if( is_a_leaf(db_column_int(&q, 1)) ){
fossil_print("Closed: %s\n", zIntegrateUuid);
}else{
fossil_print("Not_Closed: %s (not a leaf any more)\n", zIntegrateUuid);
}
}
db_finalize(&q);
fossil_print("New_Version: %s\n", zUuid);
if( outputManifest ){
zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot);
blob_zero(&muuid);
blob_appendf(&muuid, "%s\n", zUuid);
blob_write_to_file(&muuid, zManifestFile);
free(zManifestFile);
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 | ** Check to see if there is an existing checkout that has been ** modified. Return values: ** ** 0: There is an existing checkout but it is unmodified ** 1: There is a modified checkout - there are unsaved changes ** 2: There is no existing checkout */ | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
** Check to see if there is an existing checkout that has been
** modified. Return values:
**
** 0: There is an existing checkout but it is unmodified
** 1: There is a modified checkout - there are unsaved changes
** 2: There is no existing checkout
*/
int unsaved_changes(unsigned int cksigFlags){
int vid;
db_must_be_within_tree();
vid = db_lget_int("checkout",0);
if( vid==0 ) return 2;
vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE);
return db_exists("SELECT 1 FROM vfile WHERE chnged"
" OR coalesce(origname!=pathname,0)");
}
/*
** Undo the current check-out. Unlink all files from the disk.
** Clear the VFILE table.
|
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
*/
int load_vfile(const char *zName){
Blob uuid;
int vid;
blob_init(&uuid, zName, -1);
if( name_to_uuid(&uuid, 1, "ci") ){
| | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
*/
int load_vfile(const char *zName){
Blob uuid;
int vid;
blob_init(&uuid, zName, -1);
if( name_to_uuid(&uuid, 1, "ci") ){
fossil_fatal(g.zErrMsg);
}
vid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &uuid);
if( vid==0 ){
fossil_fatal("no such check-in: %s", g.argv[2]);
}
if( !is_a_version(vid) ){
fossil_fatal("object [%.10s] is not a check-in", blob_str(&uuid));
|
| ︙ | ︙ | |||
101 102 103 104 105 106 107 | Blob filename; int baseLen; Manifest *pManifest; ManifestFile *pFile; /* Check the EXE permission status of all files */ | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
Blob filename;
int baseLen;
Manifest *pManifest;
ManifestFile *pFile;
/* Check the EXE permission status of all files
*/
pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0);
if( pManifest==0 ) return;
blob_zero(&filename);
blob_appendf(&filename, "%s", g.zLocalRoot);
baseLen = blob_size(&filename);
manifest_file_rewind(pManifest);
while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
int isExe;
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
forceFlag = find_option("force","f",0)!=0;
keepFlag = find_option("keep",0,0)!=0;
latestFlag = find_option("latest",0,0)!=0;
promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0;
if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
usage("VERSION|--latest ?--force? ?--keep?");
}
| | | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
forceFlag = find_option("force","f",0)!=0;
keepFlag = find_option("keep",0,0)!=0;
latestFlag = find_option("latest",0,0)!=0;
promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0;
if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
usage("VERSION|--latest ?--force? ?--keep?");
}
if( !forceFlag && unsaved_changes(0)==1 ){
fossil_fatal("there are unsaved changes in the current checkout");
}
if( forceFlag ){
db_multi_exec("DELETE FROM vfile");
prior = 0;
}else{
prior = db_lget_int("checkout",0);
}
if( latestFlag ){
compute_leaves(db_lget_int("checkout",0), 1);
zVers = db_text(0, "SELECT uuid FROM leaves, event, blob"
" WHERE event.objid=leaves.rid AND blob.rid=leaves.rid"
" ORDER BY event.mtime DESC");
if( zVers==0 ){
zVers = db_text(0, "SELECT uuid FROM event, blob"
" WHERE event.objid=blob.rid AND event.type='ci'"
" ORDER BY event.mtime DESC");
}
if( zVers==0 ){
return;
}
}else{
zVers = g.argv[2];
}
vid = load_vfile(zVers);
if( prior==vid ){
return;
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 | /* ** COMMAND: close* ** ** Usage: %fossil close ?OPTIONS? ** ** The opposite of "open". Close the current database connection. ** Require a -f or --force flag if there are unsaved changed in the | | | > > > > > > > | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
/*
** COMMAND: close*
**
** Usage: %fossil close ?OPTIONS?
**
** The opposite of "open". Close the current database connection.
** Require a -f or --force flag if there are unsaved changed in the
** current check-out or if there is non-empty stash.
**
** Options:
** --force|-f necessary to close a check out with uncommitted changes
**
** See also: open
*/
void close_cmd(void){
int forceFlag = find_option("force","f",0)!=0;
db_must_be_within_tree();
if( !forceFlag && unsaved_changes(0)==1 ){
fossil_fatal("there are unsaved changes in the current checkout");
}
if( !forceFlag
&& db_exists("SELECT 1 FROM %s.sqlite_master WHERE name='stash'",
db_name("localdb"))
&& db_exists("SELECT 1 FROM %s.stash", db_name("localdb"))
){
fossil_fatal("closing the checkout will delete your stash");
}
if( db_is_writeable("repository") ){
db_multi_exec("DELETE FROM config WHERE name='ckout:%q'", g.zLocalRoot);
}
unlink_local_database(1);
db_close(1);
unlink_local_database(0);
}
|
Changes to src/clone.c.
| ︙ | ︙ | |||
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
/*
** COMMAND: clone
**
** Usage: %fossil clone ?OPTIONS? URL FILENAME
**
** Make a clone of a repository specified by URL in the local
** file named FILENAME.
**
** By default, your current login name is used to create the default
** admin user. This can be overridden using the -A|--admin-user
** parameter.
**
** Options:
** --admin-user|-A USERNAME Make USERNAME the administrator
** --private Also clone private branches
** --ssl-identity=filename Use the SSL identity if requested by the server
**
** See also: init
*/
void clone_cmd(void){
char *zPassword;
const char *zDefaultUser; /* Optional name of the default user */
int nErr = 0;
int bPrivate = 0; /* Also clone private branches */
if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
url_proxy_options();
if( g.argc < 4 ){
usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
}
db_open_config(0);
if( file_size(g.argv[3])>0 ){
| > > > > > > > > > > > > > > > > > > > > | < < | > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
/*
** COMMAND: clone
**
** Usage: %fossil clone ?OPTIONS? URL FILENAME
**
** Make a clone of a repository specified by URL in the local
** file named FILENAME.
**
** URL must be in one of the following form: ([...] mean optional)
** HTTP/HTTPS protocol:
** http[s]://[userid[:password]@]host[:port][/path]
**
** SSH protocol:
** ssh://[userid[:password]@]host[:port]/path/to/repo.fossil\\
** [?fossil=path/to/fossil.exe]
**
** Filesystem:
** [file://]path/to/repo.fossil
**
** Note: For ssh and filesystem, path must have an extra leading
** '/' to use an absolute path.
**
** By default, your current login name is used to create the default
** admin user. This can be overridden using the -A|--admin-user
** parameter.
**
** Options:
** --admin-user|-A USERNAME Make USERNAME the administrator
** --once Don't save url.
** --private Also clone private branches
** --ssl-identity=filename Use the SSL identity if requested by the server
** --ssh-command|-c 'command' Use this SSH command
**
** See also: init
*/
void clone_cmd(void){
char *zPassword;
const char *zDefaultUser; /* Optional name of the default user */
int nErr = 0;
int bPrivate = 0; /* Also clone private branches */
int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
zDefaultUser = find_option("admin-user","A",1);
clone_ssh_find_options();
url_proxy_options();
if( g.argc < 4 ){
usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
}
db_open_config(0);
if( file_size(g.argv[3])>0 ){
fossil_fatal("file already exists: %s", g.argv[3]);
}
url_parse(g.argv[2], urlFlags);
if( zDefaultUser==0 && g.urlUser!=0 ) zDefaultUser = g.urlUser;
if( g.urlIsFile ){
file_copy(g.urlName, g.argv[3]);
db_close(1);
db_open_repository(g.argv[3]);
db_record_repository_filename(g.argv[3]);
url_remember();
if( !bPrivate ) delete_private_content();
|
| ︙ | ︙ | |||
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
db_open_repository(g.argv[3]);
db_begin_transaction();
db_record_repository_filename(g.argv[3]);
db_initial_setup(0, 0, zDefaultUser, 0);
user_select();
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA, 0);
url_remember();
if( g.zSSLIdentity!=0 ){
/* If the --ssl-identity option was specified, store it as a setting */
Blob fn;
blob_zero(&fn);
file_canonical_name(g.zSSLIdentity, &fn, 0);
db_set("ssl-identity", blob_str(&fn), 0);
blob_reset(&fn);
}
db_multi_exec(
"REPLACE INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))), now());"
);
url_enable_proxy(0);
url_get_password_if_needed();
g.xlinkClusterOnly = 1;
nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
g.xlinkClusterOnly = 0;
verify_cancel();
db_end_transaction(0);
db_close(1);
| > > | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
db_open_repository(g.argv[3]);
db_begin_transaction();
db_record_repository_filename(g.argv[3]);
db_initial_setup(0, 0, zDefaultUser, 0);
user_select();
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA, 0);
db_set("rebuilt", get_version(), 0);
url_remember();
if( g.zSSLIdentity!=0 ){
/* If the --ssl-identity option was specified, store it as a setting */
Blob fn;
blob_zero(&fn);
file_canonical_name(g.zSSLIdentity, &fn, 0);
db_set("ssl-identity", blob_str(&fn), 0);
blob_reset(&fn);
}
db_multi_exec(
"REPLACE INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))), now());"
);
url_enable_proxy(0);
clone_ssh_db_set_options();
url_get_password_if_needed();
g.xlinkClusterOnly = 1;
nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
g.xlinkClusterOnly = 0;
verify_cancel();
db_end_transaction(0);
db_close(1);
|
| ︙ | ︙ | |||
172 173 174 175 176 177 178 |
fossil_print("Rebuilding repository meta-data...\n");
rebuild_db(0, 1, 0);
fossil_print("project-id: %s\n", db_get("project-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
db_end_transaction(0);
}
| > > > > > > > > > > > > > > > > > > > > > > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
fossil_print("Rebuilding repository meta-data...\n");
rebuild_db(0, 1, 0);
fossil_print("project-id: %s\n", db_get("project-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
db_end_transaction(0);
}
/*
** Look for SSH clone command line options and setup in globals.
*/
void clone_ssh_find_options(void){
const char *zSshCmd; /* SSH command string */
zSshCmd = find_option("ssh-command","c",1);
if( zSshCmd && zSshCmd[0] ){
g.zSshCmd = mprintf("%s", zSshCmd);
}
}
/*
** Set SSH options discovered in global variables (set from command line
** options).
*/
void clone_ssh_db_set_options(void){
if( g.zSshCmd && g.zSshCmd[0] ){
db_set("ssh-command", g.zSshCmd, 0);
}
}
|
Changes to src/comformat.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 | /* ** Given a comment string zText, format that string for printing ** on a TTY. Assume that the output cursors is indent spaces from ** the left margin and that a single line can contain no more than ** lineLength characters. Indent all subsequent lines by indent. ** | < < > | | > > > > > > > > > | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/*
** Given a comment string zText, format that string for printing
** on a TTY. Assume that the output cursors is indent spaces from
** the left margin and that a single line can contain no more than
** lineLength characters. Indent all subsequent lines by indent.
**
** Return the number of newlines that are output.
*/
int comment_print(const char *zText, int indent, int lineLength){
int tlen = lineLength - indent;
int si, sk, i, k;
int doIndent = 0;
char *zBuf;
char zBuffer[400];
int lineCnt = 0;
if( tlen<=0 ){
tlen = strlen(zText);
}
if( tlen >= (sizeof(zBuffer)) ){
zBuf = fossil_malloc(tlen+1);
}else{
zBuf = zBuffer;
}
for(;;){
while( fossil_isspace(zText[0]) ){ zText++; }
if( zText[0]==0 ){
if( doIndent==0 ){
fossil_print("\n");
lineCnt = 1;
}
if( zBuf!=zBuffer) fossil_free(zBuf);
return lineCnt;
}
for(sk=si=i=k=0; zText[i] && k<tlen; i++){
char c = zText[i];
if( fossil_isspace(c) ){
si = i;
sk = k;
|
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
}
if( doIndent ){
fossil_print("%*s", indent, "");
}
doIndent = 1;
if( sk>0 && zText[i] ){
zText += si;
| < < < < > | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
}
if( doIndent ){
fossil_print("%*s", indent, "");
}
doIndent = 1;
if( sk>0 && zText[i] ){
zText += si;
zBuf[sk] = 0;
}else{
zText += i;
zBuf[k] = 0;
}
fossil_print("%s\n", zBuf);
lineCnt++;
}
}
/*
** Test the comment printing
**
|
| ︙ | ︙ |
Changes to src/config.h.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** some linux distributions, and possibly other unixes as well. */ #define _LARGE_FILE 1 #ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 #endif #define _LARGEFILE_SOURCE 1 #ifdef HAVE_AUTOCONFIG_H #include "autoconfig.h" #endif #ifndef _RC_COMPILE_ | > > > > > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** some linux distributions, and possibly other unixes as well. */ #define _LARGE_FILE 1 #ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 #endif #define _LARGEFILE_SOURCE 1 /* Make sure that in Win32 MinGW builds, _USE_32BIT_TIME_T is always defined. */ #if defined(_WIN32) && !defined(_WIN64) && !defined(_MSC_VER) && !defined(_USE_32BIT_TIME_T) # define _USE_32BIT_TIME_T #endif #ifdef HAVE_AUTOCONFIG_H #include "autoconfig.h" #endif #ifndef _RC_COMPILE_ |
| ︙ | ︙ | |||
80 81 82 83 84 85 86 | # elif defined(__GNUC__) # define COMPILER_NAME "gcc-" __VERSION__ # else # define COMPILER_NAME "unknown" # endif #endif | | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | # elif defined(__GNUC__) # define COMPILER_NAME "gcc-" __VERSION__ # else # define COMPILER_NAME "unknown" # endif #endif #if !defined(_RC_COMPILE_) && !defined(SQLITE_AMALGAMATION) #include "sqlite3.h" /* ** On Solaris, getpass() will only return up to 8 characters. getpassphrase() returns up to 257. */ #if HAVE_GETPASSPHRASE |
| ︙ | ︙ |
Changes to src/configure.c.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#define CONFIGSET_XFER 0x000080 /* Transfer configuration */
#define CONFIGSET_ALL 0x0000ff /* Everything */
#define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */
#define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */
#endif /* INTERFACE */
/*
** Names of the configuration sets
*/
static struct {
const char *zName; /* Name of the configuration set */
| > > > > > > > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#define CONFIGSET_XFER 0x000080 /* Transfer configuration */
#define CONFIGSET_ALL 0x0000ff /* Everything */
#define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */
#define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */
/*
** This mask is used for the common TH1 configuration settings (i.e. those
** that are not specific to one particular subsystem, such as the transfer
** subsystem).
*/
#define CONFIGSET_TH1 (CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER)
#endif /* INTERFACE */
/*
** Names of the configuration sets
*/
static struct {
const char *zName; /* Name of the configuration set */
|
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
{ "index-page", CONFIGSET_SKIN },
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "adunit", CONFIGSET_SKIN },
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
{ "adunit-omit-if-user", CONFIGSET_SKIN },
| | > | | > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
{ "index-page", CONFIGSET_SKIN },
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "adunit", CONFIGSET_SKIN },
{ "adunit-omit-if-admin", CONFIGSET_SKIN },
{ "adunit-omit-if-user", CONFIGSET_SKIN },
{ "th1-setup", CONFIGSET_TH1 },
{ "th1-uri-regexp", CONFIGSET_TH1 },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", CONFIGSET_TH1 },
{ "tcl-setup", CONFIGSET_TH1 },
#endif
{ "project-name", CONFIGSET_PROJ },
{ "short-project-name", CONFIGSET_PROJ },
{ "project-description", CONFIGSET_PROJ },
{ "manifest", CONFIGSET_PROJ },
{ "binary-glob", CONFIGSET_PROJ },
{ "clean-glob", CONFIGSET_PROJ },
{ "ignore-glob", CONFIGSET_PROJ },
{ "keep-glob", CONFIGSET_PROJ },
{ "crnl-glob", CONFIGSET_PROJ },
|
| ︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
{ "@concealed", CONFIGSET_ADDR },
{ "@shun", CONFIGSET_SHUN },
{ "xfer-common-script", CONFIGSET_XFER },
{ "xfer-push-script", CONFIGSET_XFER },
};
static int iConfig = 0;
/*
** Return name of first configuration property matching the given mask.
*/
| > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
{ "@concealed", CONFIGSET_ADDR },
{ "@shun", CONFIGSET_SHUN },
{ "xfer-common-script", CONFIGSET_XFER },
{ "xfer-push-script", CONFIGSET_XFER },
{ "xfer-commit-script", CONFIGSET_XFER },
{ "xfer-ticket-script", CONFIGSET_XFER },
};
static int iConfig = 0;
/*
** Return name of first configuration property matching the given mask.
*/
|
| ︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
@ DELETE FROM reportfmt;
@ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
@ DROP TABLE _xfer_user;
@ DROP TABLE _xfer_reportfmt;
;
db_multi_exec(zSQL);
}
/*
** Return true if z[] is not a "safe" SQL token. A safe token is one of:
**
** * A string literal
** * A blob literal
** * An integer literal (no floating point)
| > > > > > > > > > > > > > > > | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
@ DELETE FROM reportfmt;
@ INSERT INTO reportfmt SELECT * FROM _xfer_reportfmt;
@ DROP TABLE _xfer_user;
@ DROP TABLE _xfer_reportfmt;
;
db_multi_exec(zSQL);
}
/*
** Mask of modified configuration sets
*/
static int rebuildMask = 0;
/*
** Rebuild auxiliary tables as required by configuration changes.
*/
void configure_rebuild(void){
if( rebuildMask & CONFIGSET_TKT ){
ticket_rebuild();
}
rebuildMask = 0;
}
/*
** Return true if z[] is not a "safe" SQL token. A safe token is one of:
**
** * A string literal
** * A blob literal
** * An integer literal (no floating point)
|
| ︙ | ︙ | |||
556 557 558 559 560 561 562 563 564 565 566 567 568 569 |
blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]);
}
blob_appendf(&sql, " WHERE %s=%s AND mtime<%s",
aType[ii].zPrimKey, azToken[1], azToken[0]);
db_multi_exec("%s", blob_str(&sql));
}
blob_reset(&sql);
}else{
/* Otherwise, the old format */
if( (configure_is_exportable(zName) & groupMask)==0 ) return;
if( fossil_strcmp(zName, "logo-image")==0 ){
Stmt ins;
db_prepare(&ins,
"REPLACE INTO config(name, value, mtime) VALUES(:name, :value, now())"
| > | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 |
blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]);
}
blob_appendf(&sql, " WHERE %s=%s AND mtime<%s",
aType[ii].zPrimKey, azToken[1], azToken[0]);
db_multi_exec("%s", blob_str(&sql));
}
blob_reset(&sql);
rebuildMask |= thisMask;
}else{
/* Otherwise, the old format */
if( (configure_is_exportable(zName) & groupMask)==0 ) return;
if( fossil_strcmp(zName, "logo-image")==0 ){
Stmt ins;
db_prepare(&ins,
"REPLACE INTO config(name, value, mtime) VALUES(:name, :value, now())"
|
| ︙ | ︙ | |||
938 939 940 941 942 943 944 945 946 947 948 949 950 |
db_multi_exec(zRepositorySchemaDefaultReports);
}
}
db_end_transaction(0);
fossil_print("Configuration reset to factory defaults.\n");
fossil_print("To recover, use: %s %s import %s\n",
g.argv[0], g.argv[1], zBackup);
}else
{
fossil_fatal("METHOD should be one of:"
" export import merge pull push reset");
}
}
| > > | 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 |
db_multi_exec(zRepositorySchemaDefaultReports);
}
}
db_end_transaction(0);
fossil_print("Configuration reset to factory defaults.\n");
fossil_print("To recover, use: %s %s import %s\n",
g.argv[0], g.argv[1], zBackup);
rebuildMask |= mask;
}else
{
fossil_fatal("METHOD should be one of:"
" export import merge pull push reset");
}
configure_rebuild();
}
|
Changes to src/content.c.
| ︙ | ︙ | |||
25 26 27 28 29 30 31 |
** The artifact retrieval cache
*/
static struct {
i64 szTotal; /* Total size of all entries in the cache */
int n; /* Current number of cache entries */
int nAlloc; /* Number of slots allocated in a[] */
int nextAge; /* Age counter for implementing LRU */
| < | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
** The artifact retrieval cache
*/
static struct {
i64 szTotal; /* Total size of all entries in the cache */
int n; /* Current number of cache entries */
int nAlloc; /* Number of slots allocated in a[] */
int nextAge; /* Age counter for implementing LRU */
struct cacheLine { /* One instance of this for each cache entry */
int rid; /* Artifact id */
int age; /* Age. Newer is larger */
Blob content; /* Content of the artifact */
} *a; /* The positive cache */
Bag inCache; /* Set of artifacts currently in cache */
|
| ︙ | ︙ | |||
113 114 115 116 117 118 119 | bag_clear(&contentCache.available); bag_clear(&contentCache.inCache); contentCache.n = 0; contentCache.szTotal = 0; } /* | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
bag_clear(&contentCache.available);
bag_clear(&contentCache.inCache);
contentCache.n = 0;
contentCache.szTotal = 0;
}
/*
** Return the srcid associated with rid. Or return 0 if rid is
** original content and not a delta.
*/
static int findSrcid(int rid){
static Stmt q;
int srcid;
db_static_prepare(&q, "SELECT srcid FROM delta WHERE rid=:rid");
db_bind_int(&q, ":rid", rid);
|
| ︙ | ︙ | |||
153 154 155 156 157 158 159 |
** Check to see if content is available for artifact "rid". Return
** true if it is. Return false if rid is a phantom or depends on
** a phantom.
*/
int content_is_available(int rid){
int srcid;
int depth = 0; /* Limit to recursion depth */
| | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
** Check to see if content is available for artifact "rid". Return
** true if it is. Return false if rid is a phantom or depends on
** a phantom.
*/
int content_is_available(int rid){
int srcid;
int depth = 0; /* Limit to recursion depth */
while( depth++ < 10000000 ){
if( bag_find(&contentCache.missing, rid) ){
return 0;
}
if( bag_find(&contentCache.available, rid) ){
return 1;
}
if( content_size(rid, -1)<0 ){
|
| ︙ | ︙ | |||
387 388 389 390 391 392 393 |
while( rid ){
int nChildUsed = 0;
int i;
/* Parse the object rid itself */
if( linkFlag ){
content_get(rid, &content);
| | | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
while( rid ){
int nChildUsed = 0;
int i;
/* Parse the object rid itself */
if( linkFlag ){
content_get(rid, &content);
manifest_crosslink(rid, &content, MC_NONE);
assert( blob_is_reset(&content) );
}
/* Parse all delta-manifests that depend on baseline-manifest rid */
db_prepare(&q, "SELECT rid FROM orphan WHERE baseline=%d", rid);
while( db_step(&q)==SQLITE_ROW ){
int child = db_column_int(&q, 0);
if( nChildUsed>=nChildAlloc ){
nChildAlloc = nChildAlloc*2 + 10;
aChild = fossil_realloc(aChild, nChildAlloc*sizeof(aChild));
}
aChild[nChildUsed++] = child;
}
db_finalize(&q);
for(i=0; i<nChildUsed; i++){
content_get(aChild[i], &content);
manifest_crosslink(aChild[i], &content, MC_NONE);
assert( blob_is_reset(&content) );
}
if( nChildUsed ){
db_multi_exec("DELETE FROM orphan WHERE baseline=%d", rid);
}
/* Recursively dephantomize all artifacts that are derived by
** delta from artifact rid and which have not already been
** cross-linked. */
nChildUsed = 0;
db_prepare(&q,
"SELECT rid FROM delta"
" WHERE srcid=%d"
" AND NOT EXISTS(SELECT 1 FROM mlink WHERE mid=delta.rid)",
rid
);
while( db_step(&q)==SQLITE_ROW ){
int child = db_column_int(&q, 0);
|
| ︙ | ︙ | |||
454 455 456 457 458 459 460 | } /* ** Write content into the database. Return the record ID. If the ** content is already in the database, just return the record ID. ** ** If srcId is specified, then pBlob is delta content from | | | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | } /* ** Write content into the database. Return the record ID. If the ** content is already in the database, just return the record ID. ** ** If srcId is specified, then pBlob is delta content from ** the srcId record. srcId might be a phantom. ** ** pBlob is normally uncompressed text. But if nBlob>0 then the ** pBlob value has already been compressed and nBlob is its uncompressed ** size. If nBlob>0 then zUuid must be valid. ** ** zUuid is the UUID of the artifact, if it is specified. When srcId is ** specified then zUuid must always be specified. If srcId is zero, |
| ︙ | ︙ | |||
485 486 487 488 489 490 491 | int size; int rid; Stmt s1; Blob cmpr; Blob hash; int markAsUnclustered = 0; int isDephantomize = 0; | | < | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
int size;
int rid;
Stmt s1;
Blob cmpr;
Blob hash;
int markAsUnclustered = 0;
int isDephantomize = 0;
assert( g.repositoryOpen );
assert( pBlob!=0 );
assert( srcId==0 || zUuid!=0 );
if( zUuid==0 ){
assert( nBlob==0 );
sha1sum_blob(pBlob, &hash);
}else{
blob_init(&hash, zUuid, -1);
}
if( nBlob ){
size = nBlob;
|
| ︙ | ︙ | |||
580 581 582 583 584 585 586 |
/* If the srcId is specified, then the data we just added is
** really a delta. Record this fact in the delta table.
*/
if( srcId ){
db_multi_exec("REPLACE INTO delta(rid,srcid) VALUES(%d,%d)", rid, srcId);
}
| | | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 |
/* If the srcId is specified, then the data we just added is
** really a delta. Record this fact in the delta table.
*/
if( srcId ){
db_multi_exec("REPLACE INTO delta(rid,srcid) VALUES(%d,%d)", rid, srcId);
}
if( !isDephantomize && bag_find(&contentCache.missing, rid) &&
(srcId==0 || content_is_available(srcId)) ){
content_mark_available(rid);
}
if( isDephantomize ){
after_dephantomize(rid, 0);
}
/* Add the element to the unclustered table if has never been
** previously seen.
*/
if( markAsUnclustered ){
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d)", rid);
}
|
| ︙ | ︙ | |||
628 629 630 631 632 633 634 |
/*
** Create a new phantom with the given UUID and return its artifact ID.
*/
int content_new(const char *zUuid, int isPrivate){
int rid;
static Stmt s1, s2, s3;
| | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 |
/*
** Create a new phantom with the given UUID and return its artifact ID.
*/
int content_new(const char *zUuid, int isPrivate){
int rid;
static Stmt s1, s2, s3;
assert( g.repositoryOpen );
db_begin_transaction();
if( uuid_is_shunned(zUuid) ){
db_end_transaction(0);
return 0;
}
db_static_prepare(&s1,
|
| ︙ | ︙ | |||
727 728 729 730 731 732 733 |
int rc;
db_static_prepare(&s1,
"SELECT 1 FROM private WHERE rid=:rid"
);
db_bind_int(&s1, ":rid", rid);
rc = db_step(&s1);
db_reset(&s1);
| | | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 |
int rc;
db_static_prepare(&s1,
"SELECT 1 FROM private WHERE rid=:rid"
);
db_bind_int(&s1, ":rid", rid);
rc = db_step(&s1);
db_reset(&s1);
return rc==SQLITE_ROW;
}
/*
** Make sure an artifact is public.
*/
void content_make_public(int rid){
static Stmt s1;
db_static_prepare(&s1,
"DELETE FROM private WHERE rid=:rid"
);
db_bind_int(&s1, ":rid", rid);
|
| ︙ | ︙ | |||
758 759 760 761 762 763 764 | ** the source of the delta. It is OK to delta private->private and ** public->private and public->public. Just no private->public delta. ** ** If srcid is a delta that depends on rid, then srcid is ** converted to undeltaed text. ** ** If either rid or srcid contain less than 50 bytes, or if the | | | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 |
** the source of the delta. It is OK to delta private->private and
** public->private and public->public. Just no private->public delta.
**
** If srcid is a delta that depends on rid, then srcid is
** converted to undeltaed text.
**
** If either rid or srcid contain less than 50 bytes, or if the
** resulting delta does not achieve a compression of at least 25%
** the rid is left untouched.
**
** Return 1 if a delta is made and 0 if no delta occurs.
*/
int content_deltify(int rid, int srcid, int force){
int s;
Blob data, src, delta;
|
| ︙ | ︙ | |||
825 826 827 828 829 830 831 |
void test_content_deltify_cmd(void){
if( g.argc!=5 ) usage("RID SRCID FORCE");
db_must_be_within_tree();
content_deltify(atoi(g.argv[2]), atoi(g.argv[3]), atoi(g.argv[4]));
}
/*
| > > > > > > > > > > > > > | > > > > > > > > > | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 |
void test_content_deltify_cmd(void){
if( g.argc!=5 ) usage("RID SRCID FORCE");
db_must_be_within_tree();
content_deltify(atoi(g.argv[2]), atoi(g.argv[3]), atoi(g.argv[4]));
}
/*
** Return true if Blob p looks like it might be a parsable control artifact.
*/
static int looks_like_control_artifact(Blob *p){
const char *z = blob_buffer(p);
int n = blob_size(p);
if( n<10 ) return 0;
if( strncmp(z, "-----BEGIN PGP SIGNED MESSAGE-----", 34)==0 ) return 1;
if( z[0]<'A' || z[0]>'Z' || z[1]!=' ' || z[0]=='I' ) return 0;
if( z[n-1]!='\n' ) return 0;
return 1;
}
/*
** COMMAND: test-integrity ?OPTIONS?
**
** Verify that all content can be extracted from the BLOB table correctly.
** If the BLOB table is correct, then the repository can always be
** successfully reconstructed using "fossil rebuild".
**
** Options:
**
** --parse Parse all manifests, wikis, tickets, events, and
** so forth, reporting any errors found.
*/
void test_integrity(void){
Stmt q;
Blob content;
Blob cksum;
int n1 = 0;
int n2 = 0;
int nErr = 0;
int total;
int nCA = 0;
int anCA[10];
int bParse = find_option("parse",0,0)!=0;
db_find_and_open_repository(OPEN_ANY_SCHEMA, 2);
memset(anCA, 0, sizeof(anCA));
/* Make sure no public artifact is a delta from a private artifact */
db_prepare(&q,
"SELECT "
" rid, (SELECT uuid FROM blob WHERE rid=delta.rid),"
" srcid, (SELECT uuid FROM blob WHERE rid=delta.srcid)"
" FROM delta"
|
| ︙ | ︙ | |||
861 862 863 864 865 866 867 |
fossil_print(
"public artifact %S (%d) is a delta from private artifact %S (%d)\n",
zId, rid, zSrc, srcid
);
nErr++;
}
db_finalize(&q);
| | | 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 |
fossil_print(
"public artifact %S (%d) is a delta from private artifact %S (%d)\n",
zId, rid, zSrc, srcid
);
nErr++;
}
db_finalize(&q);
db_prepare(&q, "SELECT rid, uuid, size FROM blob ORDER BY rid");
total = db_int(0, "SELECT max(rid) FROM blob");
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
const char *zUuid = db_column_text(&q, 1);
int size = db_column_int(&q, 2);
n1++;
|
| ︙ | ︙ | |||
887 888 889 890 891 892 893 |
}
sha1sum_blob(&content, &cksum);
if( fossil_strcmp(blob_str(&cksum), zUuid)!=0 ){
fossil_print("checksum mismatch on artifact %d: wanted %s but got %s\n",
rid, zUuid, blob_str(&cksum));
nErr++;
}
| > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 |
}
sha1sum_blob(&content, &cksum);
if( fossil_strcmp(blob_str(&cksum), zUuid)!=0 ){
fossil_print("checksum mismatch on artifact %d: wanted %s but got %s\n",
rid, zUuid, blob_str(&cksum));
nErr++;
}
if( bParse && looks_like_control_artifact(&content) ){
Blob err;
int i, n;
char *z;
Manifest *p;
char zFirstLine[400];
blob_zero(&err);
z = blob_buffer(&content);
n = blob_size(&content);
for(i=0; i<n && z[i] && z[i]!='\n' && i<sizeof(zFirstLine)-1; i++){}
memcpy(zFirstLine, z, i);
zFirstLine[i] = 0;
p = manifest_parse(&content, 0, &err);
if( p==0 ){
fossil_print("manifest_parse failed for %s:\n%s\n",
blob_str(&cksum), blob_str(&err));
if( strncmp(blob_str(&err), "line 1:", 7)==0 ){
fossil_print("\"%s\"\n", zFirstLine);
}
}else{
anCA[p->type]++;
manifest_destroy(p);
nCA++;
}
blob_reset(&err);
}else{
blob_reset(&content);
}
blob_reset(&cksum);
n2++;
}
db_finalize(&q);
fossil_print("%d non-phantom blobs (out of %d total) checked: %d errors\n",
n2, n1, nErr);
if( bParse ){
static const char *const azType[] = { 0, "manifest", "cluster",
"control", "wiki", "ticket", "attachment", "event" };
int i;
fossil_print("%d total control artifacts\n", nCA);
for(i=1; i<count(azType); i++){
if( anCA[i] ) fossil_print(" %d %ss\n", anCA[i], azType[i]);
}
}
}
/*
** COMMAND: test-orphans
**
** Search the repository for orphaned artifacts
*/
|
| ︙ | ︙ | |||
991 992 993 994 995 996 997 |
fossil_print("%s: %s\n %s %s %S (%d) %s\n",
zErrType, zUuid, zRole, zCFType, zSrc, p->rid, zDate);
if( zDetail && zDetail[0] ){
fossil_print(" %s\n", zDetail);
}
fossil_free(zSrc);
fossil_free(zDate);
| | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 |
fossil_print("%s: %s\n %s %s %S (%d) %s\n",
zErrType, zUuid, zRole, zCFType, zSrc, p->rid, zDate);
if( zDetail && zDetail[0] ){
fossil_print(" %s\n", zDetail);
}
fossil_free(zSrc);
fossil_free(zDate);
rc = 1;
}
return rc;
}
/*
** COMMAND: test-missing
**
|
| ︙ | ︙ | |||
1038 1039 1040 1041 1042 1043 1044 |
content_get(rid, &content);
p = manifest_parse(&content, rid, 0);
if( p ){
nArtifact++;
nErr += check_exists(p->zBaseline, flags, p, "baseline of", 0);
nErr += check_exists(p->zAttachSrc, flags, p, "file of", 0);
for(i=0; i<p->nFile; i++){
| | | | 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 |
content_get(rid, &content);
p = manifest_parse(&content, rid, 0);
if( p ){
nArtifact++;
nErr += check_exists(p->zBaseline, flags, p, "baseline of", 0);
nErr += check_exists(p->zAttachSrc, flags, p, "file of", 0);
for(i=0; i<p->nFile; i++){
nErr += check_exists(p->aFile[i].zUuid, flags, p, "file of",
p->aFile[i].zName);
}
for(i=0; i<p->nParent; i++){
nErr += check_exists(p->azParent[i], flags, p, "parent of", 0);
}
for(i=0; i<p->nCherrypick; i++){
nErr += check_exists(p->aCherrypick[i].zCPTarget+1, flags, p,
"cherry-pick target of", 0);
nErr += check_exists(p->aCherrypick[i].zCPBase, flags, p,
"cherry-pick baseline of", 0);
}
for(i=0; i<p->nCChild; i++){
nErr += check_exists(p->azCChild[i], flags, p, "in", 0);
}
for(i=0; i<p->nTag; i++){
nErr += check_exists(p->aTag[i].zUuid, flags, p, "target of", 0);
}
manifest_destroy(p);
}
}
db_finalize(&q);
if( nErr>0 || quietFlag==0 ){
fossil_print("%d missing or shunned references in %d control artifacts\n",
nErr, nArtifact);
}
}
|
Changes to src/cson_amalgamation.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 | # define JSON_PARSER_DLL_API # endif #else # define JSON_PARSER_DLL_API #endif /* Determine the integer type use to parse non-floating point numbers */ | > > > > | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # define JSON_PARSER_DLL_API # endif #else # define JSON_PARSER_DLL_API #endif /* Determine the integer type use to parse non-floating point numbers */ #ifdef _WIN32 typedef __int64 JSON_int_t; #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%I64d" #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%I64d" #elif __STDC_VERSION__ >= 199901L || HAVE_LONG_LONG == 1 typedef long long JSON_int_t; #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%lld" #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%lld" #else typedef long JSON_int_t; #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%ld" #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%ld" |
| ︙ | ︙ | |||
97 98 99 100 101 102 103 |
\param value A representation of the parsed value. This parameter is NULL for
JSON_T_ARRAY_BEGIN, JSON_T_ARRAY_END, JSON_T_OBJECT_BEGIN, JSON_T_OBJECT_END,
JSON_T_NULL, JSON_T_TRUE, and JSON_T_FALSE. String values are always returned
as zero-terminated C strings.
\return Non-zero if parsing should continue, else zero.
*/
| | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
\param value A representation of the parsed value. This parameter is NULL for
JSON_T_ARRAY_BEGIN, JSON_T_ARRAY_END, JSON_T_OBJECT_BEGIN, JSON_T_OBJECT_END,
JSON_T_NULL, JSON_T_TRUE, and JSON_T_FALSE. String values are always returned
as zero-terminated C strings.
\return Non-zero if parsing should continue, else zero.
*/
typedef int (*JSON_parser_callback)(void* ctx, int type, const JSON_value* value);
/**
A typedef for allocator functions semantically compatible with malloc().
*/
typedef void* (*JSON_malloc_t)(size_t n);
/**
|
| ︙ | ︙ | |||
227 228 229 230 231 232 233 |
#endif
#endif /* JSON_PARSER_H */
/* end file parser/JSON_parser.h */
/* begin file parser/JSON_parser.c */
/*
| | < < | > > | > > | < | | | | | | | | | | | | | | | | | | | | | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
#endif
#endif /* JSON_PARSER_H */
/* end file parser/JSON_parser.h */
/* begin file parser/JSON_parser.c */
/*
Copyright (c) 2007-2013 Jean Gressmann (jean@0x42.de)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
Changelog:
2013-09-08
Updated license to to be compatible with Debian license requirements.
2012-06-06
Fix for invalid UTF16 characters and some comment fixex (thomas.h.moog@intel.com).
2010-11-25
Support for custom memory allocation (sgbeal@googlemail.com).
2010-05-07
Added error handling for memory allocation failure (sgbeal@googlemail.com).
Added diagnosis errors for invalid JSON.
2010-03-25
Fixed buffer overrun in grow_parse_buffer & cleaned up code.
2009-10-19
Replaced long double in JSON_value_struct with double after reports
of strtold being broken on some platforms (charles@transmissionbt.com).
2009-05-17
Incorporated benrudiak@googlemail.com fix for UTF16 decoding.
2009-05-14
Fixed float parsing bug related to a locale being set that didn't
use '.' as decimal point character (charles@transmissionbt.com).
2008-10-14
Renamed states.IN to states.IT to avoid name clash which IN macro
defined in windef.h (alexey.pelykh@gmail.com)
2008-07-19
Removed some duplicate code & debugging variable (charles@transmissionbt.com)
2008-05-28
Made JSON_value structure ansi C compliant. This bug was report by
trisk@acm.jhu.edu
2008-05-20
Fixed bug reported by charles@transmissionbt.com where the switching
from static to dynamic parse buffer did not copy the static parse
buffer's content.
*/
#include <assert.h>
#include <ctype.h>
|
| ︙ | ︙ | |||
356 357 358 359 360 361 362 |
size_t parse_buffer_count;
signed char static_stack[JSON_PARSER_STACK_SIZE];
char static_parse_buffer[JSON_PARSER_PARSE_BUFFER_SIZE];
JSON_malloc_t malloc;
JSON_free_t free;
};
| | | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
size_t parse_buffer_count;
signed char static_stack[JSON_PARSER_STACK_SIZE];
char static_parse_buffer[JSON_PARSER_PARSE_BUFFER_SIZE];
JSON_malloc_t malloc;
JSON_free_t free;
};
#define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
/*
Characters are mapped into these character classes. This allows for
a significant reduction in the size of the state transition table.
*/
|
| ︙ | ︙ | |||
397 398 399 400 401 402 403 |
C_LOW_R, /* r */
C_LOW_S, /* s */
C_LOW_T, /* t */
C_LOW_U, /* u */
C_ABCDF, /* ABCDF */
C_E, /* E */
C_ETC, /* everything else */
| | | | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 |
C_LOW_R, /* r */
C_LOW_S, /* s */
C_LOW_T, /* t */
C_LOW_U, /* u */
C_ABCDF, /* ABCDF */
C_E, /* E */
C_ETC, /* everything else */
C_STAR, /* * */
NR_CLASSES
};
static const signed char ascii_class[128] = {
/*
This array maps the 128 ASCII characters into character classes.
The remaining Unicode characters should be mapped to C_ETC.
Non-whitespace control characters are errors.
*/
__, __, __, __, __, __, __, __,
__, C_WHITE, C_WHITE, __, __, C_WHITE, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
C_SPACE, C_ETC, C_QUOTE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ETC, C_STAR, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH,
C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT,
C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E, C_ABCDF, C_ETC,
C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
C_ETC, C_ETC, C_ETC, C_LSQRB, C_BACKS, C_RSQRB, C_ETC, C_ETC,
|
| ︙ | ︙ | |||
530 531 532 533 534 535 536 |
/*fal F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__,__},
/*fals F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__,__},
/*false F4*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__,__},
/*nu N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__,__},
/*nul N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__,__},
/*null N3*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__},
/*/ C1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,C2},
| | | | | | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 |
/*fal F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__,__},
/*fals F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__,__},
/*false F4*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__,__},
/*nu N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__,__},
/*nul N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__,__},
/*null N3*/ {__,__,__,__,__,__,__,__,__,__,CB,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__},
/*/ C1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,C2},
/*/star C2*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3},
/** C3*/ {C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,CE,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C2,C3},
/*_. FX*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__,__},
/*\ D1*/ {__,__,__,__,__,__,__,__,__,D2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
/*\ D2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,U1,__,__,__,__},
};
/*
These modes can be pushed on the stack.
*/
enum modes {
MODE_ARRAY = 1,
MODE_DONE = 2,
MODE_KEY = 3,
MODE_OBJECT = 4
};
static void set_error(JSON_parser jc)
{
switch (jc->state) {
case GO:
switch (jc->current_char) {
case '{': case '}': case '[': case ']':
jc->error = JSON_E_UNBALANCED_COLLECTION;
break;
default:
jc->error = JSON_E_INVALID_CHAR;
break;
}
break;
case OB:
jc->error = JSON_E_EXPECTED_KEY;
break;
case AR:
jc->error = JSON_E_UNBALANCED_COLLECTION;
|
| ︙ | ︙ | |||
598 599 600 601 602 603 604 |
static int
push(JSON_parser jc, int mode)
{
/*
Push a mode onto the stack. Return false if there is overflow.
*/
assert(jc->top <= jc->stack_capacity);
| | | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 |
static int
push(JSON_parser jc, int mode)
{
/*
Push a mode onto the stack. Return false if there is overflow.
*/
assert(jc->top <= jc->stack_capacity);
if (jc->depth < 0) {
if (jc->top == jc->stack_capacity) {
const size_t bytes_to_copy = jc->stack_capacity * sizeof(jc->stack[0]);
const size_t new_capacity = jc->stack_capacity * 2;
const size_t bytes_to_allocate = new_capacity * sizeof(jc->stack[0]);
void* mem = JSON_parser_malloc(jc->malloc, bytes_to_allocate, "stack");
if (!mem) {
|
| ︙ | ︙ | |||
647 648 649 650 651 652 653 |
#define parse_buffer_clear(jc) \
do {\
jc->parse_buffer_count = 0;\
jc->parse_buffer[0] = 0;\
} while (0)
| | | | | | | | | | | | | | | | | | | | | | | | | 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
#define parse_buffer_clear(jc) \
do {\
jc->parse_buffer_count = 0;\
jc->parse_buffer[0] = 0;\
} while (0)
#define parse_buffer_pop_back_char(jc)\
do {\
assert(jc->parse_buffer_count >= 1);\
--jc->parse_buffer_count;\
jc->parse_buffer[jc->parse_buffer_count] = 0;\
} while (0)
void delete_JSON_parser(JSON_parser jc)
{
if (jc) {
if (jc->stack != &jc->static_stack[0]) {
jc->free((void*)jc->stack);
}
if (jc->parse_buffer != &jc->static_parse_buffer[0]) {
jc->free((void*)jc->parse_buffer);
}
jc->free((void*)jc);
}
}
int JSON_parser_reset(JSON_parser jc)
{
if (NULL == jc) {
return false;
}
jc->state = GO;
jc->top = -1;
/* parser has been used previously? */
if (NULL == jc->parse_buffer) {
/* Do we want non-bound stack? */
if (jc->depth > 0) {
jc->stack_capacity = jc->depth;
if (jc->depth <= (int)COUNTOF(jc->static_stack)) {
jc->stack = &jc->static_stack[0];
} else {
const size_t bytes_to_alloc = jc->stack_capacity * sizeof(jc->stack[0]);
jc->stack = (signed char*)JSON_parser_malloc(jc->malloc, bytes_to_alloc, "stack");
if (jc->stack == NULL) {
return false;
}
}
} else {
jc->stack_capacity = (int)COUNTOF(jc->static_stack);
jc->depth = -1;
jc->stack = &jc->static_stack[0];
}
/* set up the parse buffer */
jc->parse_buffer = &jc->static_parse_buffer[0];
jc->parse_buffer_capacity = COUNTOF(jc->static_parse_buffer);
}
/* set parser to start */
push(jc, MODE_DONE);
parse_buffer_clear(jc);
return true;
}
JSON_parser
new_JSON_parser(JSON_config const * config)
{
/*
new_JSON_parser starts the checking process by constructing a JSON_parser
object. It takes a depth parameter that restricts the level of maximum
nesting.
To continue the process, call JSON_parser_char for each character in the
JSON text, and then call JSON_parser_done to obtain the final result.
These functions are fully reentrant.
*/
int use_std_malloc = false;
JSON_config default_config;
JSON_parser jc;
JSON_malloc_t alloc;
/* set to default configuration if none was provided */
if (NULL == config) {
/* initialize configuration */
init_JSON_config(&default_config);
config = &default_config;
}
/* use std malloc if either the allocator or deallocator function isn't set */
use_std_malloc = NULL == config->malloc || NULL == config->free;
alloc = use_std_malloc ? malloc : config->malloc;
jc = (JSON_parser)JSON_parser_malloc(alloc, sizeof(*jc), "parser");
if (NULL == jc) {
return NULL;
}
/* configure the parser */
memset(jc, 0, sizeof(*jc));
jc->malloc = alloc;
jc->free = use_std_malloc ? free : config->free;
jc->callback = config->callback;
jc->ctx = config->callback_ctx;
jc->allow_comments = (signed char)(config->allow_comments != 0);
jc->handle_floats_manually = (signed char)(config->handle_floats_manually != 0);
jc->decimal_point = *localeconv()->decimal_point;
/* We need to be able to push at least one object */
jc->depth = config->depth == 0 ? 1 : config->depth;
/* reset the parser */
if (!JSON_parser_reset(jc)) {
jc->free(jc);
return NULL;
}
return jc;
}
static int parse_buffer_grow(JSON_parser jc)
{
const size_t bytes_to_copy = jc->parse_buffer_count * sizeof(jc->parse_buffer[0]);
const size_t new_capacity = jc->parse_buffer_capacity * 2;
const size_t bytes_to_allocate = new_capacity * sizeof(jc->parse_buffer[0]);
void* mem = JSON_parser_malloc(jc->malloc, bytes_to_allocate, "parse buffer");
if (mem == NULL) {
jc->error = JSON_E_OUT_OF_MEMORY;
return false;
}
assert(new_capacity > 0);
memcpy(mem, jc->parse_buffer, bytes_to_copy);
if (jc->parse_buffer != &jc->static_parse_buffer[0]) {
jc->free(jc->parse_buffer);
}
jc->parse_buffer = (char*)mem;
jc->parse_buffer_capacity = new_capacity;
return true;
}
static int parse_buffer_reserve_for(JSON_parser jc, unsigned chars)
{
while (jc->parse_buffer_count + chars + 1 > jc->parse_buffer_capacity) {
if (!parse_buffer_grow(jc)) {
assert(jc->error == JSON_E_OUT_OF_MEMORY);
return false;
}
}
return true;
}
#define parse_buffer_has_space_for(jc, count) \
(jc->parse_buffer_count + (count) + 1 <= jc->parse_buffer_capacity)
#define parse_buffer_push_back_char(jc, c)\
|
| ︙ | ︙ | |||
824 825 826 827 828 829 830 |
assert( \
jc->type == JSON_T_NULL || \
jc->type == JSON_T_FALSE || \
jc->type == JSON_T_TRUE || \
jc->type == JSON_T_FLOAT || \
jc->type == JSON_T_INTEGER || \
jc->type == JSON_T_STRING)
| | | | | | | | | | | | | | | | > > > > | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 |
assert( \
jc->type == JSON_T_NULL || \
jc->type == JSON_T_FALSE || \
jc->type == JSON_T_TRUE || \
jc->type == JSON_T_FLOAT || \
jc->type == JSON_T_INTEGER || \
jc->type == JSON_T_STRING)
static int parse_parse_buffer(JSON_parser jc)
{
if (jc->callback) {
JSON_value value, *arg = NULL;
if (jc->type != JSON_T_NONE) {
assert_is_non_container_type(jc);
switch(jc->type) {
case JSON_T_FLOAT:
arg = &value;
if (jc->handle_floats_manually) {
value.vu.str.value = jc->parse_buffer;
value.vu.str.length = jc->parse_buffer_count;
} else {
/* not checking with end pointer b/c there may be trailing ws */
value.vu.float_value = strtod(jc->parse_buffer, NULL);
}
break;
case JSON_T_INTEGER:
arg = &value;
sscanf(jc->parse_buffer, JSON_PARSER_INTEGER_SSCANF_TOKEN, &value.vu.integer_value);
break;
case JSON_T_STRING:
arg = &value;
value.vu.str.value = jc->parse_buffer;
value.vu.str.length = jc->parse_buffer_count;
break;
}
if (!(*jc->callback)(jc->ctx, jc->type, arg)) {
return false;
}
}
}
parse_buffer_clear(jc);
return true;
}
#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800)
#define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00)
#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000)
static const unsigned char utf8_lead_bits[4] = { 0x00, 0xC0, 0xE0, 0xF0 };
static int decode_unicode_char(JSON_parser jc)
{
int i;
unsigned uc = 0;
char* p;
int trail_bytes;
assert(jc->parse_buffer_count >= 6);
p = &jc->parse_buffer[jc->parse_buffer_count - 4];
for (i = 12; i >= 0; i -= 4, ++p) {
unsigned x = *p;
if (x >= 'a') {
x -= ('a' - 10);
} else if (x >= 'A') {
x -= ('A' - 10);
} else {
x &= ~0x30u;
}
assert(x < 16);
uc |= x << i;
}
/* clear UTF-16 char from buffer */
jc->parse_buffer_count -= 6;
jc->parse_buffer[jc->parse_buffer_count] = 0;
if (uc == 0xffff || uc == 0xfffe) {
return false;
}
/* attempt decoding ... */
if (jc->utf16_high_surrogate) {
if (IS_LOW_SURROGATE(uc)) {
uc = DECODE_SURROGATE_PAIR(jc->utf16_high_surrogate, uc);
trail_bytes = 3;
jc->utf16_high_surrogate = 0;
} else {
|
| ︙ | ︙ | |||
929 930 931 932 933 934 935 |
} else if (IS_LOW_SURROGATE(uc)) {
/* low surrogate without a preceding high surrogate */
return false;
} else {
trail_bytes = 2;
}
}
| | | | | | 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 |
} else if (IS_LOW_SURROGATE(uc)) {
/* low surrogate without a preceding high surrogate */
return false;
} else {
trail_bytes = 2;
}
}
jc->parse_buffer[jc->parse_buffer_count++] = (char) ((uc >> (trail_bytes * 6)) | utf8_lead_bits[trail_bytes]);
for (i = trail_bytes * 6 - 6; i >= 0; i -= 6) {
jc->parse_buffer[jc->parse_buffer_count++] = (char) (((uc >> i) & 0x3F) | 0x80);
}
jc->parse_buffer[jc->parse_buffer_count] = 0;
return true;
}
static int add_escaped_char_to_parse_buffer(JSON_parser jc, int next_char)
{
assert(parse_buffer_has_space_for(jc, 1));
jc->escaped = 0;
/* remove the backslash */
parse_buffer_pop_back_char(jc);
switch(next_char) {
case 'b':
parse_buffer_push_back_char(jc, '\b');
break;
|
| ︙ | ︙ | |||
990 991 992 993 994 995 996 |
static int add_char_to_parse_buffer(JSON_parser jc, int next_char, int next_class)
{
if (!parse_buffer_reserve_for(jc, 1)) {
assert(JSON_E_OUT_OF_MEMORY == jc->error);
return false;
}
| | | | | 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
static int add_char_to_parse_buffer(JSON_parser jc, int next_char, int next_class)
{
if (!parse_buffer_reserve_for(jc, 1)) {
assert(JSON_E_OUT_OF_MEMORY == jc->error);
return false;
}
if (jc->escaped) {
if (!add_escaped_char_to_parse_buffer(jc, next_char)) {
jc->error = JSON_E_INVALID_ESCAPE_SEQUENCE;
return false;
}
} else if (!jc->comment) {
if ((jc->type != JSON_T_NONE) | !((next_class == C_SPACE) | (next_class == C_WHITE)) /* non-white-space */) {
parse_buffer_push_back_char(jc, (char)next_char);
}
}
return true;
}
#define assert_type_isnt_string_null_or_bool(jc) \
assert(jc->type != JSON_T_FALSE); \
assert(jc->type != JSON_T_TRUE); \
assert(jc->type != JSON_T_NULL); \
|
| ︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 |
UTF-32. It returns true if things are looking ok so far. If it rejects the
text, it returns false.
*/
int next_class, next_state;
/*
Store the current char for error handling
| | | | | | | 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
UTF-32. It returns true if things are looking ok so far. If it rejects the
text, it returns false.
*/
int next_class, next_state;
/*
Store the current char for error handling
*/
jc->current_char = next_char;
/*
Determine the character's class.
*/
if (next_char < 0) {
jc->error = JSON_E_INVALID_CHAR;
return false;
}
if (next_char >= 128) {
next_class = C_ETC;
} else {
next_class = ascii_class[next_char];
if (next_class <= __) {
set_error(jc);
return false;
}
}
if (!add_char_to_parse_buffer(jc, next_char, next_class)) {
return false;
}
/*
Get the next state from the state transition table.
*/
next_state = state_transition_table[jc->state][next_class];
if (next_state >= 0) {
/*
Change the state.
*/
jc->state = (signed char)next_state;
} else {
/*
Or perform one of the actions.
*/
switch (next_state) {
/* Unicode character */
case UC:
if(!decode_unicode_char(jc)) {
jc->error = JSON_E_INVALID_UNICODE_SEQUENCE;
return false;
}
/* check if we need to read a second UTF-16 char */
if (jc->utf16_high_surrogate) {
|
| ︙ | ︙ | |||
1085 1086 1087 1088 1089 1090 1091 |
jc->escaped = 1;
jc->state = ES;
break;
/* integer detected by minus */
case MX:
jc->type = JSON_T_INTEGER;
jc->state = MI;
| | | | | | | | | | | | | | | | | | | | | | | | 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 |
jc->escaped = 1;
jc->state = ES;
break;
/* integer detected by minus */
case MX:
jc->type = JSON_T_INTEGER;
jc->state = MI;
break;
/* integer detected by zero */
case ZX:
jc->type = JSON_T_INTEGER;
jc->state = ZE;
break;
/* integer detected by 1-9 */
case IX:
jc->type = JSON_T_INTEGER;
jc->state = IT;
break;
/* floating point number detected by exponent*/
case DE:
assert_type_isnt_string_null_or_bool(jc);
jc->type = JSON_T_FLOAT;
jc->state = E1;
break;
/* floating point number detected by fraction */
case DF:
assert_type_isnt_string_null_or_bool(jc);
if (!jc->handle_floats_manually) {
/*
Some versions of strtod (which underlies sscanf) don't support converting
C-locale formated floating point values.
*/
assert(jc->parse_buffer[jc->parse_buffer_count-1] == '.');
jc->parse_buffer[jc->parse_buffer_count-1] = jc->decimal_point;
}
jc->type = JSON_T_FLOAT;
jc->state = FX;
break;
/* string begin " */
case SB:
parse_buffer_clear(jc);
assert(jc->type == JSON_T_NONE);
jc->type = JSON_T_STRING;
jc->state = ST;
break;
/* n */
case NU:
assert(jc->type == JSON_T_NONE);
jc->type = JSON_T_NULL;
jc->state = N1;
break;
/* f */
case FA:
assert(jc->type == JSON_T_NONE);
jc->type = JSON_T_FALSE;
jc->state = F1;
break;
/* t */
case TR:
assert(jc->type == JSON_T_NONE);
jc->type = JSON_T_TRUE;
jc->state = T1;
break;
/* closing comment */
case CE:
jc->comment = 0;
assert(jc->parse_buffer_count == 0);
assert(jc->type == JSON_T_NONE);
jc->state = jc->before_comment_state;
break;
/* opening comment */
case CB:
if (!jc->allow_comments) {
return false;
}
parse_buffer_pop_back_char(jc);
if (!parse_parse_buffer(jc)) {
return false;
}
assert(jc->parse_buffer_count == 0);
assert(jc->type != JSON_T_STRING);
switch (jc->stack[jc->top]) {
case MODE_ARRAY:
case MODE_OBJECT:
switch(jc->state) {
case VA:
case AR:
jc->before_comment_state = jc->state;
break;
default:
jc->before_comment_state = OK;
break;
}
break;
default:
jc->before_comment_state = jc->state;
break;
}
jc->type = JSON_T_NONE;
jc->state = C1;
jc->comment = 1;
break;
/* empty } */
case -9:
parse_buffer_clear(jc);
if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_END, NULL)) {
return false;
}
if (!pop(jc, MODE_KEY)) {
return false;
}
|
| ︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 |
if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_ARRAY_END, NULL)) {
return false;
}
if (!pop(jc, MODE_ARRAY)) {
jc->error = JSON_E_UNBALANCED_COLLECTION;
return false;
}
| | | 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 |
if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_ARRAY_END, NULL)) {
return false;
}
if (!pop(jc, MODE_ARRAY)) {
jc->error = JSON_E_UNBALANCED_COLLECTION;
return false;
}
jc->type = JSON_T_NONE;
jc->state = OK;
break;
/* { */ case -6:
parse_buffer_pop_back_char(jc);
if (jc->callback && !(*jc->callback)(jc->ctx, JSON_T_OBJECT_BEGIN, NULL)) {
|
| ︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 |
/* string end " */ case -4:
parse_buffer_pop_back_char(jc);
switch (jc->stack[jc->top]) {
case MODE_KEY:
assert(jc->type == JSON_T_STRING);
jc->type = JSON_T_NONE;
jc->state = CO;
| | | 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 |
/* string end " */ case -4:
parse_buffer_pop_back_char(jc);
switch (jc->stack[jc->top]) {
case MODE_KEY:
assert(jc->type == JSON_T_STRING);
jc->type = JSON_T_NONE;
jc->state = CO;
if (jc->callback) {
JSON_value value;
value.vu.str.value = jc->parse_buffer;
value.vu.str.length = jc->parse_buffer_count;
if (!(*jc->callback)(jc->ctx, JSON_T_KEY, &value)) {
return false;
}
|
| ︙ | ︙ | |||
1351 1352 1353 1354 1355 1356 1357 |
return false;
}
int JSON_parser_is_legal_white_space_string(const char* s)
{
int c, char_class;
| | | | | | | | | > | 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 |
return false;
}
int JSON_parser_is_legal_white_space_string(const char* s)
{
int c, char_class;
if (s == NULL) {
return false;
}
for (; *s; ++s) {
c = *s;
if (c < 0 || c >= 128) {
return false;
}
char_class = ascii_class[c];
if (char_class != C_SPACE && char_class != C_WHITE) {
return false;
}
}
return true;
}
int JSON_parser_get_last_error(JSON_parser jc)
{
return jc->error;
}
void init_JSON_config(JSON_config* config)
{
if (config) {
memset(config, 0, sizeof(*config));
config->depth = JSON_PARSER_STACK_SIZE - 1;
config->malloc = malloc;
config->free = free;
}
}
/* end file parser/JSON_parser.c */
/* begin file ./cson.c */
#include <assert.h>
#include <stdlib.h> /* malloc()/free() */
#include <string.h>
#include <errno.h>
|
| ︙ | ︙ | |||
1570 1571 1572 1573 1574 1575 1576 |
{
unsigned int length;
};
#define cson_string_empty_m {0/*length*/}
static const cson_string cson_string_empty = cson_string_empty_m;
| | > > > > > > > > > > > > > > > < | < | 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 |
{
unsigned int length;
};
#define cson_string_empty_m {0/*length*/}
static const cson_string cson_string_empty = cson_string_empty_m;
/**
Assumes V is a (cson_value*) ans V->value is a (T*). Returns
V->value cast to a (T*).
*/
#define CSON_CAST(T,V) ((T*)((V)->value))
/**
Assumes V is a pointer to memory which is allocated as part of a
cson_value instance (the bytes immediately after that part).
Returns a pointer a a cson_value by subtracting sizeof(cson_value)
from that address and casting it to a (cson_value*)
*/
#define CSON_VCAST(V) ((cson_value *)(((unsigned char *)(V))-sizeof(cson_value)))
/**
CSON_INT(V) assumes that V is a (cson_value*) of type
CSON_TYPE_INTEGER. This macro returns a (cson_int_t*) representing
its value (how that is stored depends on whether we are running in
32- or 64-bit mode).
*/
#if CSON_VOID_PTR_IS_BIG
# define CSON_INT(V) ((cson_int_t*)(&((V)->value)))
#else
# define CSON_INT(V) ((cson_int_t*)(V)->value)
#endif
#define CSON_DBL(V) CSON_CAST(cson_double_t,(V))
#define CSON_STR(V) CSON_CAST(cson_string,(V))
#define CSON_OBJ(V) CSON_CAST(cson_object,(V))
#define CSON_ARRAY(V) CSON_CAST(cson_array,(V))
/**
Holds special shared "constant" (though they are non-const)
values.
*/
static struct CSON_EMPTY_HOLDER_
{
char trueValue;
cson_string stringValue;
} CSON_EMPTY_HOLDER = {
1/*trueValue*/,
|
| ︙ | ︙ | |||
1803 1804 1805 1806 1807 1808 1809 | works. Frees any resources owned by val, but does not free val itself (which may be stack-allocated). If !val or val->api or val->api->cleanup are NULL then this is a no-op. If v is a container type (object or array) its children are also | | | 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 | works. Frees any resources owned by val, but does not free val itself (which may be stack-allocated). If !val or val->api or val->api->cleanup are NULL then this is a no-op. If v is a container type (object or array) its children are also cleaned up, recursively. After calling this, val will have the special "undefined" type. */ static void cson_value_clean( cson_value * val ); /** Increments cv's reference count by 1. As a special case, values |
| ︙ | ︙ | |||
1883 1884 1885 1886 1887 1888 1889 |
return str ? str->length : 0;
}
/**
Fetches v's string value as a non-const string.
| | | 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 |
return str ? str->length : 0;
}
/**
Fetches v's string value as a non-const string.
cson_strings are intended to be immutable, but this form provides
access to the immutable bits, which are v->length bytes long. A
length-0 string is returned as NULL from here, as opposed to
"". (This is a side-effect of the string allocation mechanism.)
Returns NULL if !v or if v is the internal empty-string singleton.
*/
static char * cson_string_str(cson_string *v)
{
|
| ︙ | ︙ | |||
3775 3776 3777 3778 3779 3780 3781 |
ch = cson_utf8Read(pos, end, &next);
if( 0 == ch ) break;
assert( next > pos );
clen = next - pos;
assert( clen );
if( 1 == clen )
{ /* ASCII */
| > > > > > > > | > > > > > > > > > > > > > | 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 |
ch = cson_utf8Read(pos, end, &next);
if( 0 == ch ) break;
assert( next > pos );
clen = next - pos;
assert( clen );
if( 1 == clen )
{ /* ASCII */
#if defined(CSON_FOSSIL_MODE)
/* Workaround for fossil repo artifact
f460839cff85d4e4f1360b366bb2858cef1411ea,
which has what appears to be latin1-encoded
text. file(1) thinks it's a FORTRAN program.
*/
if(0xfffd==ch){
assert(*pos != ch);
/* MARKER("ch=%04x, *pos=%04x\n", ch, *pos); */
ch = *pos
/* We should arguably translate to '?', and
will if this problem ever comes up with a
non-latin1 encoding. For latin1 this
workaround incidentally corrects the output
to proper UTF8-escaped characters, and only
for that reason is it being kept around.
*/;
goto assume_latin1;
}
#endif
assert( (*pos == ch) && "Invalid UTF8" );
escChar[1] = 0;
switch(ch)
{
case '\t': escChar[1] = 't'; break;
case '\r': escChar[1] = 'r'; break;
case '\n': escChar[1] = 'n'; break;
case '\f': escChar[1] = 'f'; break;
|
| ︙ | ︙ | |||
3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 |
{
rc = f(state, (char const *)pos, clen);
}
continue;
}
else
{ /* UTF: transform it to \uXXXX */
memset(ubuf,0,UBLen);
rc = sprintf(ubuf, "\\u%04x",ch);
if( rc != 6 )
{
rc = cson_rc.RangeError;
break;
}
| > > > | 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 |
{
rc = f(state, (char const *)pos, clen);
}
continue;
}
else
{ /* UTF: transform it to \uXXXX */
#if defined(CSON_FOSSIL_MODE)
assume_latin1:
#endif
memset(ubuf,0,UBLen);
rc = sprintf(ubuf, "\\u%04x",ch);
if( rc != 6 )
{
rc = cson_rc.RangeError;
break;
}
|
| ︙ | ︙ | |||
4099 4100 4101 4102 4103 4104 4105 |
if(i < (ar->list.count-1))
{
rc = f(state, ",", 1);
if( 0 == rc )
{
rc = doIndent
? cson_output_indent( f, state, fmt->indentation, level )
| | | 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 |
if(i < (ar->list.count-1))
{
rc = f(state, ",", 1);
if( 0 == rc )
{
rc = doIndent
? cson_output_indent( f, state, fmt->indentation, level )
: 0 /*f( state, " ", 1 )*/;
}
}
}
}
--level;
if( doIndent && (0 == rc) )
{
|
| ︙ | ︙ | |||
4177 4178 4179 4180 4181 4182 4183 |
if(i < (obj->kvp.count-1))
{
rc = f(state, ",", 1);
if( 0 == rc )
{
rc = doIndent
? cson_output_indent( f, state, fmt->indentation, level )
| | | 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 |
if(i < (obj->kvp.count-1))
{
rc = f(state, ",", 1);
if( 0 == rc )
{
rc = doIndent
? cson_output_indent( f, state, fmt->indentation, level )
: 0 /*f( state, " ", 1 )*/;
}
}
}
}
--level;
if( doIndent && (0 == rc) )
{
|
| ︙ | ︙ | |||
4390 4391 4392 4393 4394 4395 4396 |
if( npos >= sb->capacity )
{
const cson_size_t oldCap = sb->capacity;
const cson_size_t asz = npos * 2;
if( asz < npos ) return cson_rc.ArgError; /* overflow */
else if( 0 != cson_buffer_reserve( sb, asz ) ) return cson_rc.AllocError;
assert( (sb->capacity > oldCap) && "Internal error in memory buffer management!" );
| | | 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 |
if( npos >= sb->capacity )
{
const cson_size_t oldCap = sb->capacity;
const cson_size_t asz = npos * 2;
if( asz < npos ) return cson_rc.ArgError; /* overflow */
else if( 0 != cson_buffer_reserve( sb, asz ) ) return cson_rc.AllocError;
assert( (sb->capacity > oldCap) && "Internal error in memory buffer management!" );
/* make sure it gets NUL terminated. */
memset( sb->mem + oldCap, 0, (sb->capacity - oldCap) );
}
for( i = 0; i < n; ++i, ++sb->used )
{
sb->mem[sb->used] = data[i];
}
return 0;
|
| ︙ | ︙ |
Changes to src/cson_amalgamation.h.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 | /** @typedef some_long_int_type cson_int_t Typedef for JSON-like integer types. This is (long long) where feasible, otherwise (long). */ | > > > > | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | /** @typedef some_long_int_type cson_int_t Typedef for JSON-like integer types. This is (long long) where feasible, otherwise (long). */ #ifdef _WIN32 typedef __int64 cson_int_t; #define CSON_INT_T_SFMT "I64d" #define CSON_INT_T_PFMT "I64d" #elif (__STDC_VERSION__ >= 199901L) || (HAVE_LONG_LONG == 1) typedef long long cson_int_t; #define CSON_INT_T_SFMT "lld" #define CSON_INT_T_PFMT "lld" #else typedef long cson_int_t; #define CSON_INT_T_SFMT "ld" #define CSON_INT_T_PFMT "ld" |
| ︙ | ︙ |
Added src/cygsup.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
/*
** Copyright (c) 2007 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains preprocessor directives used to help integrate with the
** Cygwin runtime and build environment. The intent of this file is to keep
** the Cygwin-specific preprocessor directives together.
*/
#if defined(__CYGWIN__) && !defined(CYGSUP_H)
#define CYGSUP_H
/*
*******************************************************************************
** Include any Cygwin-specific headers here. **
*******************************************************************************
*/
#include <wchar.h>
#include <sys/cygwin.h>
/*
*******************************************************************************
** Define any Cygwin-specific preprocessor macros here. All macros defined in
** this section should be wrapped with #ifndef, in order to allow them to be
** externally overridden.
*******************************************************************************
*/
#ifndef CP_UTF8
# define CP_UTF8 65001
#endif
#ifndef WINBASEAPI
# define WINBASEAPI __declspec(dllimport)
#endif
#ifndef WINADVAPI
# define WINADVAPI __declspec(dllimport)
#endif
#ifndef SHSTDAPI
# define SHSTDAPI __declspec(dllimport)
#endif
#ifndef STDAPI
# define STDAPI __stdcall
#endif
#ifndef WINAPI
# define WINAPI __stdcall
#endif
/*
*******************************************************************************
** Declare any Cygwin-specific Win32 or other APIs here. Functions declared in
** this section should use the built-in ANSI C types in order to make sure this
** header file continues to work as a self-contained unit.
**
** On Cygwin64, "long" is 64-bit but in Win64 it's 32-bit. That's why in the
** signatures below "long" should not be used. They now use "int" instead.
*******************************************************************************
*/
WINADVAPI extern WINAPI int RegOpenKeyExW(
void *, /* HKEY */
const wchar_t *, /* LPCWSTR */
unsigned int, /* DWORD */
unsigned int, /* REGSAM */
void * /* PHKEY */
);
WINADVAPI extern WINAPI int RegQueryValueExW(
void *, /* HKEY */
const wchar_t *, /* LPCWSTR */
unsigned int *, /* LPDWORD */
unsigned int *, /* LPDWORD */
unsigned char *, /* LPBYTE */
unsigned int * /* LPDWORD */
);
SHSTDAPI extern STDAPI void *ShellExecuteW(
void *, /* HWND */
const wchar_t *, /* LPCWSTR */
const wchar_t *, /* LPCWSTR */
const wchar_t *, /* LPCWSTR */
const wchar_t *, /* LPCWSTR */
int /* INT */
);
WINBASEAPI extern WINAPI int WideCharToMultiByte(
unsigned int, /* UINT */
unsigned int, /* DWORD */
const wchar_t *, /* LPCWSTR */
int, /* int */
char *, /* LPSTR */
int, /* int */
const char *, /* LPCSTR */
int * /* LPBOOL */
);
WINBASEAPI extern WINAPI int MultiByteToWideChar(
unsigned int, /* UINT */
unsigned int, /* DWORD */
const char *, /* LPCSTR */
int, /* int */
wchar_t *, /* LPWSTR */
int /* int */
);
#endif /* defined(__CYGWIN__) && !defined(CYGSUP_H) */
|
Changes to src/db.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
#if INTERFACE
/*
** An single SQL statement is represented as an instance of the following
** structure.
*/
struct Stmt {
Blob sql; /* The SQL for this statement */
| | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#if INTERFACE
/*
** An single SQL statement is represented as an instance of the following
** structure.
*/
struct Stmt {
Blob sql; /* The SQL for this statement */
sqlite3_stmt *pStmt; /* The results of sqlite3_prepare_v2() */
Stmt *pNext, *pPrev; /* List of all unfinalized statements */
int nStep; /* Number of sqlite3_step() calls */
};
/*
** Copy this to initialize a Stmt object to a clean/empty state. This
** is useful to help avoid assertions when performing cleanup in some
|
| ︙ | ︙ | |||
106 107 108 109 110 111 112 |
** the following structure.
*/
static struct DbLocalData {
int nBegin; /* Nesting depth of BEGIN */
int doRollback; /* True to force a rollback */
int nCommitHook; /* Number of commit hooks */
Stmt *pAllStmt; /* List of all unfinalized statements */
| | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
** the following structure.
*/
static struct DbLocalData {
int nBegin; /* Nesting depth of BEGIN */
int doRollback; /* True to force a rollback */
int nCommitHook; /* Number of commit hooks */
Stmt *pAllStmt; /* List of all unfinalized statements */
int nPrepare; /* Number of calls to sqlite3_prepare_v2() */
int nDeleteOnFail; /* Number of entries in azDeleteOnFail[] */
struct sCommitHook {
int (*xHook)(void); /* Functions to call at db_end_transaction() */
int sequence; /* Call functions in sequence order */
} aHook[5];
char *azDeleteOnFail[3]; /* Files to delete on a failure */
char *azBeforeCommit[5]; /* Commands to run prior to COMMIT */
|
| ︙ | ︙ | |||
313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
}
int db_bind_double(Stmt *pStmt, const char *zParamName, double rValue){
return sqlite3_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue);
}
int db_bind_text(Stmt *pStmt, const char *zParamName, const char *zValue){
return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue,
-1, SQLITE_STATIC);
}
int db_bind_null(Stmt *pStmt, const char *zParamName){
return sqlite3_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName));
}
int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){
return sqlite3_bind_blob(pStmt->pStmt, paramIdx(pStmt, zParamName),
blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
| > > > > | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
}
int db_bind_double(Stmt *pStmt, const char *zParamName, double rValue){
return sqlite3_bind_double(pStmt->pStmt, paramIdx(pStmt, zParamName), rValue);
}
int db_bind_text(Stmt *pStmt, const char *zParamName, const char *zValue){
return sqlite3_bind_text(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue,
-1, SQLITE_STATIC);
}
int db_bind_text16(Stmt *pStmt, const char *zParamName, const char *zValue){
return sqlite3_bind_text16(pStmt->pStmt, paramIdx(pStmt, zParamName), zValue,
-1, SQLITE_STATIC);
}
int db_bind_null(Stmt *pStmt, const char *zParamName){
return sqlite3_bind_null(pStmt->pStmt, paramIdx(pStmt, zParamName));
}
int db_bind_blob(Stmt *pStmt, const char *zParamName, Blob *pBlob){
return sqlite3_bind_blob(pStmt->pStmt, paramIdx(pStmt, zParamName),
blob_buffer(pBlob), blob_size(pBlob), SQLITE_STATIC);
|
| ︙ | ︙ | |||
397 398 399 400 401 402 403 | pStmt->pPrev = 0; return rc; } /* ** Return the rowid of the most recent insert */ | | | > > > > | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
pStmt->pPrev = 0;
return rc;
}
/*
** Return the rowid of the most recent insert
*/
int db_last_insert_rowid(void){
i64 x = sqlite3_last_insert_rowid(g.db);
if( x<0 || x>(i64)2147483647 ){
fossil_fatal("rowid out of range (0..2147483647)");
}
return (int)x;
}
/*
** Return the number of rows that were changed by the most recent
** INSERT, UPDATE, or DELETE. Auxiliary changes caused by triggers
** or other side effects are not counted.
*/
|
| ︙ | ︙ | |||
703 704 705 706 707 708 709 |
/*
** Open a database file. Return a pointer to the new database
** connection. An error results in process abort.
*/
LOCAL sqlite3 *db_open(const char *zDbName){
int rc;
| < > > > < | | 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
/*
** Open a database file. Return a pointer to the new database
** connection. An error results in process abort.
*/
LOCAL sqlite3 *db_open(const char *zDbName){
int rc;
sqlite3 *db;
#if defined(__CYGWIN__)
zDbName = fossil_utf8_to_filename(zDbName);
#endif
if( g.fSqlTrace ) fossil_trace("-- sqlite3_open: [%s]\n", zDbName);
rc = sqlite3_open_v2(
zDbName, &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
g.zVfsName
);
if( rc!=SQLITE_OK ){
db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
}
sqlite3_busy_timeout(db, 5000);
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
|
| ︙ | ︙ | |||
820 821 822 823 824 825 826 |
if( file_isdir(zHome)!=1 ){
fossil_fatal("invalid home directory: %s", zHome);
}
#if defined(_WIN32) || defined(__CYGWIN__)
/* . filenames give some window systems problems and many apps problems */
zDbName = mprintf("%//_fossil", zHome);
#else
| < < < > > > < < | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 |
if( file_isdir(zHome)!=1 ){
fossil_fatal("invalid home directory: %s", zHome);
}
#if defined(_WIN32) || defined(__CYGWIN__)
/* . filenames give some window systems problems and many apps problems */
zDbName = mprintf("%//_fossil", zHome);
#else
zDbName = mprintf("%s/.fossil", zHome);
#endif
if( file_size(zDbName)<1024*3 ){
if( file_access(zHome, W_OK) ){
fossil_fatal("home directory %s must be writeable", zHome);
}
db_init_database(zDbName, zConfigSchema, (char*)0);
}
if( file_access(zDbName, W_OK) ){
fossil_fatal("configuration file %s must be writeable", zDbName);
}
if( useAttach ){
db_open_or_attach(zDbName, "configdb", &g.useAttach);
g.dbConfig = 0;
g.zConfigDbType = 0;
}else{
g.useAttach = 0;
g.dbConfig = db_open(zDbName);
|
| ︙ | ︙ | |||
935 936 937 938 939 940 941 |
int i, n;
char zPwd[2000];
static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" };
if( g.localOpen) return 1;
file_getcwd(zPwd, sizeof(zPwd)-20);
n = strlen(zPwd);
| < | | | | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 |
int i, n;
char zPwd[2000];
static const char aDbName[][10] = { "_FOSSIL_", ".fslckout", ".fos" };
if( g.localOpen) return 1;
file_getcwd(zPwd, sizeof(zPwd)-20);
n = strlen(zPwd);
while( n>0 ){
for(i=0; i<count(aDbName); i++){
sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "/%s", aDbName[i]);
if( isValidLocalDb(zPwd) ){
/* Found a valid checkout database file */
zPwd[n] = 0;
while( n>0 && zPwd[n-1]=='/' ){
n--;
zPwd[n] = 0;
}
g.zLocalRoot = mprintf("%s/", zPwd);
g.localOpen = 1;
db_open_config(0);
db_open_repository(zDbName);
return 1;
}
}
n--;
while( n>1 && zPwd[n]!='/' ){ n--; }
while( n>1 && zPwd[n-1]=='/' ){ n--; }
zPwd[n] = 0;
}
/* A checkout database file could not be found */
return 0;
}
|
| ︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 |
}else{
#ifdef FOSSIL_ENABLE_JSON
g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
#endif
fossil_panic("not a valid repository: %s", zDbName);
}
}
| > > > > > | < | 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
}else{
#ifdef FOSSIL_ENABLE_JSON
g.json.resultCode = FSL_JSON_E_DB_NOT_VALID;
#endif
fossil_panic("not a valid repository: %s", zDbName);
}
}
#if defined(__CYGWIN__)
g.zRepositoryName = fossil_utf8_to_filename(zDbName);
#else
g.zRepositoryName = mprintf("%s", zDbName);
#endif
db_open_or_attach(g.zRepositoryName, "repository", 0);
g.repositoryOpen = 1;
/* Cache "allow-symlinks" option, because we'll need it on every stat call */
g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
}
/*
** Flags for the db_find_and_open_repository() function.
*/
|
| ︙ | ︙ | |||
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 |
){
char *zDate;
Blob hash;
Blob manifest;
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA, 0);
if( makeServerCodes ){
db_multi_exec(
"INSERT INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))),now());"
"INSERT INTO config(name,value,mtime)"
" VALUES('project-code', lower(hex(randomblob(20))),now());"
);
| > | 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 |
){
char *zDate;
Blob hash;
Blob manifest;
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA, 0);
db_set("rebuilt", get_version(), 0);
if( makeServerCodes ){
db_multi_exec(
"INSERT INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))),now());"
"INSERT INTO config(name,value,mtime)"
" VALUES('project-code', lower(hex(randomblob(20))),now());"
);
|
| ︙ | ︙ | |||
1352 1353 1354 1355 1356 1357 1358 |
/*
** Copy all settings from the supplied template repository.
*/
db_multi_exec(
"INSERT OR REPLACE INTO config"
" SELECT name,value,mtime FROM settingSrc.config"
" WHERE (name IN %s OR name IN %s)"
| | > | 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 |
/*
** Copy all settings from the supplied template repository.
*/
db_multi_exec(
"INSERT OR REPLACE INTO config"
" SELECT name,value,mtime FROM settingSrc.config"
" WHERE (name IN %s OR name IN %s)"
" AND name NOT GLOB 'project-*'"
" AND name NOT GLOB 'short-project-*';",
configure_inop_rhs(CONFIGSET_ALL),
db_setting_inop_rhs()
);
db_multi_exec(
"REPLACE INTO reportfmt SELECT * FROM settingSrc.reportfmt;"
);
|
| ︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 |
if( zInitialDate ){
int rid;
blob_zero(&manifest);
blob_appendf(&manifest, "C initial\\sempty\\scheck-in\n");
zDate = date_in_standard_format(zInitialDate);
blob_appendf(&manifest, "D %s\n", zDate);
| < > > > | | 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 |
if( zInitialDate ){
int rid;
blob_zero(&manifest);
blob_appendf(&manifest, "C initial\\sempty\\scheck-in\n");
zDate = date_in_standard_format(zInitialDate);
blob_appendf(&manifest, "D %s\n", zDate);
md5sum_init();
/* The R-card is necessary here because without it
* fossil versions earlier than versions 1.27 would
* interpret this artifact as a "control". */
blob_appendf(&manifest, "R %s\n", md5sum_finish(0));
blob_appendf(&manifest, "T *branch * trunk\n");
blob_appendf(&manifest, "T *sym-trunk *\n");
blob_appendf(&manifest, "U %F\n", g.zLogin);
md5sum_blob(&manifest, &hash);
blob_appendf(&manifest, "Z %b\n", &hash);
blob_reset(&hash);
rid = content_put(&manifest);
manifest_crosslink(rid, &manifest, MC_NONE);
}
}
/*
** COMMAND: new*
** COMMAND: init
**
|
| ︙ | ︙ | |||
1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 |
** checked out file */
z = db_get_do_versionable(zName, z);
}
if( z==0 ){
z = zDefault;
}
return z;
}
void db_set(const char *zName, const char *zValue, int globalFlag){
db_begin_transaction();
if( globalFlag ){
db_swap_connections();
db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
zName, zValue);
| > > > > > > > > > > > > | 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 |
** checked out file */
z = db_get_do_versionable(zName, z);
}
if( z==0 ){
z = zDefault;
}
return z;
}
char *db_get_mtime(const char *zName, char *zFormat, char *zDefault){
char *z = 0;
if( g.repositoryOpen ){
z = db_text(0, "SELECT mtime FROM config WHERE name=%Q", zName);
}
if( z==0 ){
z = zDefault;
}else if( zFormat!=0 ){
z = db_text(0, "SELECT strftime(%Q,%Q,'unixepoch');", zFormat, z);
}
return z;
}
void db_set(const char *zName, const char *zValue, int globalFlag){
db_begin_transaction();
if( globalFlag ){
db_swap_connections();
db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)",
zName, zValue);
|
| ︙ | ︙ | |||
1967 1968 1969 1970 1971 1972 1973 |
** Options:
** --keep Only modify the manifest and manifest.uuid files
** --nested Allow opening a repository inside an opened checkout
**
** See also: close
*/
void cmd_open(void){
| < > > | < < < | < | | < | | | | | > > | | | | | | | | | < | 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 |
** Options:
** --keep Only modify the manifest and manifest.uuid files
** --nested Allow opening a repository inside an opened checkout
**
** See also: close
*/
void cmd_open(void){
int keepFlag;
int allowNested;
char **oldArgv;
int oldArgc;
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0 };
url_proxy_options();
keepFlag = find_option("keep",0,0)!=0;
allowNested = find_option("nested",0,0)!=0;
if( g.argc!=3 && g.argc!=4 ){
usage("REPOSITORY-FILENAME ?VERSION?");
}
if( !allowNested && db_open_local(0) ){
fossil_fatal("already within an open tree rooted at %s", g.zLocalRoot);
}
db_open_repository(g.argv[2]);
#if defined(_WIN32) || defined(__CYGWIN__)
# define LOCALDB_NAME "./_FOSSIL_"
#else
# define LOCALDB_NAME "./.fslckout"
#endif
db_init_database(LOCALDB_NAME, zLocalSchema,
#ifdef FOSSIL_LOCAL_WAL
"COMMIT; PRAGMA journal_mode=WAL; BEGIN;",
#endif
(char*)0);
db_delete_on_failure(LOCALDB_NAME);
db_open_local(0);
db_lset("repository", g.argv[2]);
db_record_repository_filename(g.argv[2]);
db_lset_int("checkout", 0);
oldArgv = g.argv;
oldArgc = g.argc;
azNewArgv[0] = g.argv[0];
g.argv = azNewArgv;
g.argc = 3;
if( oldArgc==4 ){
azNewArgv[g.argc-1] = oldArgv[3];
}else if( !db_exists("SELECT 1 FROM event WHERE type='ci'") ){
azNewArgv[g.argc-1] = "--latest";
}else{
azNewArgv[g.argc-1] = db_get("main-branch", "trunk");
}
if( keepFlag ){
azNewArgv[g.argc++] = "--keep";
}
checkout_cmd();
g.argc = 2;
info_cmd();
}
/*
** Print the value of a setting named zName
*/
static void print_setting(
const struct stControlSettings *ctrlSetting,
|
| ︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 |
{ "ssl-ca-location",0, 40, 0, "" },
{ "ssl-identity", 0, 40, 0, "" },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", 0, 0, 0, "off" },
{ "tcl-setup", 0, 40, 0, "" },
#endif
{ "th1-setup", 0, 40, 0, "" },
{ "web-browser", 0, 32, 0, "" },
{ "white-foreground", 0, 0, 0, "off" },
{ 0,0,0,0,0 }
};
/*
** COMMAND: settings
| > | 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 |
{ "ssl-ca-location",0, 40, 0, "" },
{ "ssl-identity", 0, 40, 0, "" },
#ifdef FOSSIL_ENABLE_TCL
{ "tcl", 0, 0, 0, "off" },
{ "tcl-setup", 0, 40, 0, "" },
#endif
{ "th1-setup", 0, 40, 0, "" },
{ "th1-uri-regexp",0, 40, 0, "" },
{ "web-browser", 0, 32, 0, "" },
{ "white-foreground", 0, 0, 0, "off" },
{ 0,0,0,0,0 }
};
/*
** COMMAND: settings
|
| ︙ | ︙ | |||
2183 2184 2185 2186 2187 2188 2189 | ** Default: on ** ** binary-glob The VALUE is a comma or newline-separated list of ** (versionable) GLOB patterns that should be treated as binary files ** for committing and merging purposes. Example: *.jpg ** ** case-sensitive If TRUE, the files whose names differ only in case | | | 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 | ** Default: on ** ** binary-glob The VALUE is a comma or newline-separated list of ** (versionable) GLOB patterns that should be treated as binary files ** for committing and merging purposes. Example: *.jpg ** ** case-sensitive If TRUE, the files whose names differ only in case ** are considered distinct. If FALSE files whose names ** differ only in case are the same file. Defaults to ** TRUE for unix and FALSE for Cygwin, Mac and Windows. ** ** clean-glob The VALUE is a comma or newline-separated list of GLOB ** (versionable) patterns specifying files that the "clean" command will ** delete without prompting even when the -force flag has ** not been used. Example: *.a *.lib *.o |
| ︙ | ︙ | |||
2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 | ** tcl-setup This is the setup script to be evaluated after creating ** and initializing the Tcl interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-setup This is the setup script to be evaluated after creating ** and initializing the TH1 interpreter. By default, this ** is empty and no extra setup is performed. ** ** web-browser A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. ** ** Options: | > > > > | 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 | ** tcl-setup This is the setup script to be evaluated after creating ** and initializing the Tcl interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-setup This is the setup script to be evaluated after creating ** and initializing the TH1 interpreter. By default, this ** is empty and no extra setup is performed. ** ** th1-uri-regexp Specify which URI's are allowed in HTTP requests from ** TH1 scripts. If empty, no HTTP requests are allowed ** whatsoever. The default is an empty string. ** ** web-browser A shell command used to launch your preferred ** web browser when given a URL as an argument. ** Defaults to "start" on windows, "open" on Mac, ** and "firefox" on Unix. ** ** Options: |
| ︙ | ︙ | |||
2381 2382 2383 2384 2385 2386 2387 |
isManifest = 0;
print_setting(&ctrlSettings[i], db_open_local(0));
}
if( isManifest && g.localOpen ){
manifest_to_disk(db_lget_int("checkout", 0));
}
}else{
| | | 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 |
isManifest = 0;
print_setting(&ctrlSettings[i], db_open_local(0));
}
if( isManifest && g.localOpen ){
manifest_to_disk(db_lget_int("checkout", 0));
}
}else{
usage("?PROPERTY? ?VALUE? ?-global?");
}
}
/*
** The input in a timespan measured in days. Return a string which
** describes that timespan in units of seconds, minutes, hours, days,
** or years, depending on its duration.
|
| ︙ | ︙ | |||
2427 2428 2429 2430 2431 2432 2433 |
if( g.argc!=3 ) usage("TIMESTAMP");
sqlite3_open(":memory:", &g.db);
rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]);
fossil_print("Time differences: %s\n", db_timespan_name(rDiff));
sqlite3_close(g.db);
g.db = 0;
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 |
if( g.argc!=3 ) usage("TIMESTAMP");
sqlite3_open(":memory:", &g.db);
rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]);
fossil_print("Time differences: %s\n", db_timespan_name(rDiff));
sqlite3_close(g.db);
g.db = 0;
}
/*
** COMMAND: test-without-rowid
** %fossil test-without-rowid FILENAME...
**
** Change the Fossil repository FILENAME to make use of the WITHOUT ROWID
** optimization. FILENAME can also be the ~/.fossil file or a local
** .fslckout or _FOSSIL_ file.
**
** The purpose of this command is for testing the WITHOUT ROWID capabilities
** of SQLite. There is no big advantage to using WITHOUT ROWID in Fossil.
**
** Options:
** --dryrun | -n No changes. Just print what would happen.
*/
void test_without_rowid(void){
int i, j;
Stmt q;
Blob allSql;
int dryRun = find_option("dry-run", "n", 0)!=0;
for(i=2; i<g.argc; i++){
db_open_or_attach(g.argv[i], "main", 0);
blob_init(&allSql, "BEGIN;\n", -1);
db_prepare(&q,
"SELECT name, sql FROM main.sqlite_master "
" WHERE type='table' AND sql NOT LIKE '%%WITHOUT ROWID%%'"
" AND name IN ('global_config','shun','concealed','config',"
" 'plink','tagxref','backlink','vcache');"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zTName = db_column_text(&q, 0);
const char *zOrigSql = db_column_text(&q, 1);
Blob newSql;
blob_init(&newSql, 0, 0);
for(j=0; zOrigSql[j]; j++){
if( fossil_strnicmp(zOrigSql+j,"unique",6)==0 ){
blob_append(&newSql, zOrigSql, j);
blob_append(&newSql, "PRIMARY KEY", -1);
zOrigSql += j+6;
j = -1;
}
}
blob_append(&newSql, zOrigSql, -1);
blob_appendf(&allSql,
"ALTER TABLE %s RENAME TO x_%s;\n"
"%s WITHOUT ROWID;\n"
"INSERT INTO %s SELECT * FROM x_%s;\n"
"DROP TABLE x_%s;\n",
zTName, zTName, blob_str(&newSql), zTName, zTName, zTName
);
fossil_print("Converting table %s of %s to WITHOUT ROWID.\n", zTName, g.argv[i]);
blob_reset(&newSql);
}
blob_appendf(&allSql, "COMMIT;\n");
db_finalize(&q);
if( dryRun ){
fossil_print("SQL that would have been evaluated:\n");
fossil_print("-------------------------------------------------------------\n");
fossil_print("%s", blob_str(&allSql));
}else{
db_multi_exec("%s", blob_str(&allSql));
}
blob_reset(&allSql);
db_close(1);
}
}
|
Changes to src/delta.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** This module implements the delta compress algorithm. ** ** Though developed specifically for fossil, the code in this file ** is generally applicable and is thus easily separated from the ** fossil source code base. Nothing in this file depends on anything ** else in fossil. */ #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> #include "delta.h" /* | > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** This module implements the delta compress algorithm. ** ** Though developed specifically for fossil, the code in this file ** is generally applicable and is thus easily separated from the ** fossil source code base. Nothing in this file depends on anything ** else in fossil. */ #include "config.h" #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <string.h> #include "delta.h" /* |
| ︙ | ︙ |
Changes to src/deltacmd.c.
| ︙ | ︙ | |||
142 143 144 145 146 147 148 |
blob_read_from_file(&f1, g.argv[2]);
blob_read_from_file(&f2, g.argv[3]);
blob_delta_create(&f1, &f2, &d12);
blob_delta_create(&f2, &f1, &d21);
blob_delta_apply(&f1, &d12, &a2);
blob_delta_apply(&f2, &d21, &a1);
if( blob_compare(&f1,&a1) || blob_compare(&f2, &a2) ){
| | | 142 143 144 145 146 147 148 149 150 151 152 |
blob_read_from_file(&f1, g.argv[2]);
blob_read_from_file(&f2, g.argv[3]);
blob_delta_create(&f1, &f2, &d12);
blob_delta_create(&f2, &f1, &d21);
blob_delta_apply(&f1, &d12, &a2);
blob_delta_apply(&f2, &d21, &a1);
if( blob_compare(&f1,&a1) || blob_compare(&f2, &a2) ){
fossil_fatal("delta test failed");
}
fossil_print("ok\n");
}
|
Changes to src/descendants.c.
| ︙ | ︙ | |||
155 156 157 158 159 160 161 |
}
/*
** Load the record ID rid and up to N-1 closest ancestors into
** the "ok" table.
*/
void compute_ancestors(int rid, int N, int directOnly){
| | | | > | < | | | > > > | < < | | < < < < < < < < < < < < < < < < < < | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
}
/*
** Load the record ID rid and up to N-1 closest ancestors into
** the "ok" table.
*/
void compute_ancestors(int rid, int N, int directOnly){
db_multi_exec(
"WITH RECURSIVE "
" ancestor(rid, mtime) AS ("
" SELECT %d, mtime FROM event WHERE objid=%d "
" UNION "
" SELECT plink.pid, event.mtime"
" FROM ancestor, plink, event"
" WHERE plink.cid=ancestor.rid"
" AND event.objid=plink.pid %s"
" ORDER BY mtime DESC LIMIT %d"
" )"
"INSERT INTO ok"
" SELECT rid FROM ancestor;",
rid, rid, directOnly ? "AND plink.isPrim" : "", N
);
}
/*
** Compute up to N direct ancestors (merge ancestors do not count)
** for the check-in rid and put them in a table named "ancestor".
** Label each generation with consecutive integers going backwards
** in time such that rid has the smallest generation number and the oldest
** direct ancestor as the largest generation number.
*/
void compute_direct_ancestors(int rid, int N){
Stmt ins;
Stmt q;
int gen = 0;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER UNIQUE NOT NULL,"
" generation INTEGER PRIMARY KEY);"
"DELETE FROM ancestor;"
"INSERT INTO ancestor VALUES(%d, 0);", rid
);
db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
db_prepare(&q,
"SELECT pid FROM plink"
|
| ︙ | ︙ | |||
327 328 329 330 331 332 333 |
compute_leaves(base, 0);
db_prepare(&q,
"%s"
" AND event.objid IN (SELECT rid FROM leaves)"
" ORDER BY event.mtime DESC",
timeline_query_for_tty()
);
| | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
compute_leaves(base, 0);
db_prepare(&q,
"%s"
" AND event.objid IN (SELECT rid FROM leaves)"
" ORDER BY event.mtime DESC",
timeline_query_for_tty()
);
print_timeline(&q, -20, 79, 0);
db_finalize(&q);
}
/*
** COMMAND: leaves*
**
** Usage: %fossil leaves ?OPTIONS?
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 |
*/
#define DIFF_CANNOT_COMPUTE_BINARY \
"cannot compute difference between binary files\n"
#define DIFF_CANNOT_COMPUTE_SYMLINK \
"cannot compute difference between symlink and regular file\n"
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
*/
#define DIFF_CANNOT_COMPUTE_BINARY \
"cannot compute difference between binary files\n"
#define DIFF_CANNOT_COMPUTE_SYMLINK \
"cannot compute difference between symlink and regular file\n"
#define DIFF_TOO_MANY_CHANGES \
"more than 10,000 changes\n"
/*
** Maximum length of a line in a text file, in bytes. (2**13 = 8192 bytes)
*/
#define LENGTH_MASK_SZ 13
#define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
#endif /* INTERFACE */
/*
** Information about each line of a file being diffed.
**
** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
** of the line. If any line is longer than LENGTH_MASK characters,
** the file is considered binary.
|
| ︙ | ︙ | |||
202 203 204 205 206 207 208 | } /* Return results */ *pnLine = nLine; return a; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
}
/* Return results */
*pnLine = nLine;
return a;
}
/*
** Return true if two DLine elements are identical.
*/
static int same_dline(DLine *pA, DLine *pB){
return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
}
|
| ︙ | ︙ | |||
511 512 513 514 515 516 517 |
char cPrefix, /* One of " ", "+", or "-" */
DLine *pLine, /* The line to be output */
int html, /* True if generating HTML. False for plain text */
ReCompiled *pRe /* Colorize only if line matches this Regex */
){
blob_append(pOut, &cPrefix, 1);
if( html ){
| < | < < | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
char cPrefix, /* One of " ", "+", or "-" */
DLine *pLine, /* The line to be output */
int html, /* True if generating HTML. False for plain text */
ReCompiled *pRe /* Colorize only if line matches this Regex */
){
blob_append(pOut, &cPrefix, 1);
if( html ){
if( pRe && re_dline_match(pRe, pLine, 1)==0 ){
cPrefix = ' ';
}else if( cPrefix=='+' ){
blob_append(pOut, "<span class=\"diffadd\">", -1);
}else if( cPrefix=='-' ){
blob_append(pOut, "<span class=\"diffrm\">", -1);
}
htmlize_to_blob(pOut, pLine->z, (pLine->h & LENGTH_MASK));
if( cPrefix!=' ' ){
blob_append(pOut, "</span>", -1);
}
}else{
blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK);
}
blob_append(pOut, "\n", 1);
|
| ︙ | ︙ | |||
574 575 576 577 578 579 580 | int r; /* Index into R[] */ int nr; /* Number of COPY/DELETE/INSERT triples to process */ int mxr; /* Maximum value for r */ int na, nb; /* Number of lines shown from A and B */ int i, j; /* Loop counters */ int m; /* Number of lines to output */ int skip; /* Number of lines to skip */ | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | int r; /* Index into R[] */ int nr; /* Number of COPY/DELETE/INSERT triples to process */ int mxr; /* Maximum value for r */ int na, nb; /* Number of lines shown from A and B */ int i, j; /* Loop counters */ int m; /* Number of lines to output */ int skip; /* Number of lines to skip */ static int nChunk = 0; /* Number of diff chunks seen so far */ int nContext; /* Number of lines of context */ int showLn; /* Show line numbers */ int html; /* Render as HTML */ int showDivider = 0; /* True to show the divider between diff blocks */ nContext = diff_context_lines(diffFlags); showLn = (diffFlags & DIFF_LINENO)!=0; |
| ︙ | ︙ | |||
655 656 657 658 659 660 661 |
nChunk++;
if( showLn ){
if( !showDivider ){
/* Do not show a top divider */
showDivider = 1;
}else if( html ){
blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
| < > | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
nChunk++;
if( showLn ){
if( !showDivider ){
/* Do not show a top divider */
showDivider = 1;
}else if( html ){
blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
}else{
blob_appendf(pOut, "%.80c\n", '.');
}
if( html ) blob_appendf(pOut, "<span id=\"chunk%d\"></span>", nChunk);
}else{
if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
/*
* If the patch changes an empty file or results in an empty file,
* the block header must use 0,0 as position indicator and not 1,0.
* Otherwise, patch would be confused and may reject the diff.
*/
|
| ︙ | ︙ | |||
725 726 727 728 729 730 731 |
}
/*
** Status of a single output line
*/
typedef struct SbsLine SbsLine;
struct SbsLine {
| | < | > > > > > | > > > > > > > > > | > > > > > | > > > > | | | | > < < | | < | < | | | > > > < > | < | < | < | < < > | < | > | < | < < | | > > > > > > > > | < | | > > > | | > | > | | | | | | > > > | | < < > | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 |
}
/*
** Status of a single output line
*/
typedef struct SbsLine SbsLine;
struct SbsLine {
Blob *apCols[5]; /* Array of pointers to output columns */
int width; /* Maximum width of a column in the output */
unsigned char escHtml; /* True to escape html characters */
int iStart; /* Write zStart prior to character iStart */
const char *zStart; /* A <span> tag */
int iEnd; /* Write </span> prior to character iEnd */
int iStart2; /* Write zStart2 prior to character iStart2 */
const char *zStart2; /* A <span> tag */
int iEnd2; /* Write </span> prior to character iEnd2 */
ReCompiled *pRe; /* Only colorize matching lines, if not NULL */
};
/*
** Column indices for SbsLine.apCols[]
*/
#define SBS_LNA 0 /* Left line number */
#define SBS_TXTA 1 /* Left text */
#define SBS_MKR 2 /* Middle separator column */
#define SBS_LNB 3 /* Right line number */
#define SBS_TXTB 4 /* Right text */
/*
** Append newlines to all columns.
*/
static void sbsWriteNewlines(SbsLine *p){
int i;
for( i=p->escHtml ? SBS_LNA : SBS_TXTB; i<=SBS_TXTB; i++ ){
blob_append(p->apCols[i], "\n", 1);
}
}
/*
** Append n spaces to the column.
*/
static void sbsWriteSpace(SbsLine *p, int n, int col){
blob_appendf(p->apCols[col], "%*s", n, "");
}
/*
** Write the text of pLine into column iCol of p.
**
** If outputting HTML, write the full line. Otherwise, only write the
** width characters. Translate tabs into spaces. Add newlines if col
** is SBS_TXTB. Translate HTML characters if escHtml is true. Pad the
** rendering to width bytes if col is SBS_TXTA and escHtml is false.
**
** This comment contains multibyte unicode characters (ü, Æ, ð) in order
** to test the ability of the diff code to handle such characters.
*/
static void sbsWriteText(SbsLine *p, DLine *pLine, int col){
Blob *pCol = p->apCols[col];
int n = pLine->h & LENGTH_MASK;
int i; /* Number of input characters consumed */
int k; /* Cursor position */
int needEndSpan = 0;
const char *zIn = pLine->z;
int w = p->width;
int colorize = p->escHtml;
if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){
colorize = 0;
}
for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){
char c = zIn[i];
if( colorize ){
if( i==p->iStart ){
int x = strlen(p->zStart);
blob_append(pCol, p->zStart, x);
needEndSpan = 1;
if( p->iStart2 ){
p->iStart = p->iStart2;
p->zStart = p->zStart2;
p->iStart2 = 0;
}
}else if( i==p->iEnd ){
blob_append(pCol, "</span>", 7);
needEndSpan = 0;
if( p->iEnd2 ){
p->iEnd = p->iEnd2;
p->iEnd2 = 0;
}
}
}
if( c=='\t' && !p->escHtml ){
blob_append(pCol, " ", 1);
while( (k&7)!=7 && (p->escHtml || k<w) ){
blob_append(pCol, " ", 1);
k++;
}
}else if( c=='\r' || c=='\f' ){
blob_append(pCol, " ", 1);
}else if( c=='<' && p->escHtml ){
blob_append(pCol, "<", 4);
}else if( c=='&' && p->escHtml ){
blob_append(pCol, "&", 5);
}else if( c=='>' && p->escHtml ){
blob_append(pCol, ">", 4);
}else if( c=='"' && p->escHtml ){
blob_append(pCol, """, 6);
}else{
blob_append(pCol, &zIn[i], 1);
if( (c&0xc0)==0x80 ) k--;
}
}
if( needEndSpan ){
blob_append(pCol, "</span>", 7);
}
if( col==SBS_TXTB ){
sbsWriteNewlines(p);
}else if( !p->escHtml ){
sbsWriteSpace(p, w-k, SBS_TXTA);
}
}
/*
** Append a column to the final output blob.
*/
static void sbsWriteColumn(Blob *pOut, Blob *pCol, int col){
blob_appendf(pOut,
"<td><div class=\"diff%scol\">\n"
"<pre>\n"
"%s"
"</pre>\n"
"</div></td>\n",
col % 3 ? (col == SBS_MKR ? "mkr" : "txt") : "ln",
blob_str(pCol)
);
}
/*
** Append a separator line to column iCol
*/
static void sbsWriteSep(SbsLine *p, int len, int col){
char ch = '.';
if( len<1 ){
len = 1;
ch = ' ';
}
blob_appendf(p->apCols[col], "<span class=\"diffhr\">%.*c</span>\n", len, ch);
}
/*
** Append the appropriate marker into the center column of the diff.
*/
static void sbsWriteMarker(SbsLine *p, const char *zTxt, const char *zHtml){
blob_append(p->apCols[SBS_MKR], p->escHtml ? zHtml : zTxt, -1);
}
/*
** Append a line number to the column.
*/
static void sbsWriteLineno(SbsLine *p, int ln, int col){
if( p->escHtml ){
blob_appendf(p->apCols[col], "%d", ln+1);
}else{
char zLn[7];
sqlite3_snprintf(7, zLn, "%5d ", ln+1);
blob_appendf(p->apCols[col], "%s ", zLn);
}
}
/*
** The two text segments zLeft and zRight are known to be different on
** both ends, but they might have a common segment in the middle. If
** they do not have a common segment, return 0. If they do have a large
** common segment, return 1 and before doing so set:
|
| ︙ | ︙ | |||
1016 1017 1018 1019 1020 1021 1022 |
if( nSuffix<nShort ){
while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--;
}
if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
}
if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
| < | | | | | | | | | | | | | | | | | | | | | | | | 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 |
if( nSuffix<nShort ){
while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--;
}
if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
}
if( nPrefix+nSuffix > nShort ) nPrefix = nShort - nSuffix;
/* A single chunk of text inserted on the right */
if( nPrefix+nSuffix==nLeft ){
sbsWriteLineno(p, lnLeft, SBS_LNA);
p->iStart2 = p->iEnd2 = 0;
p->iStart = p->iEnd = -1;
sbsWriteText(p, pLeft, SBS_TXTA);
if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){
sbsWriteMarker(p, " ", "");
}else{
sbsWriteMarker(p, " | ", "|");
}
sbsWriteLineno(p, lnRight, SBS_LNB);
p->iStart = nPrefix;
p->iEnd = nRight - nSuffix;
p->zStart = zClassAdd;
sbsWriteText(p, pRight, SBS_TXTB);
return;
}
/* A single chunk of text deleted from the left */
if( nPrefix+nSuffix==nRight ){
/* Text deleted from the left */
sbsWriteLineno(p, lnLeft, SBS_LNA);
p->iStart2 = p->iEnd2 = 0;
p->iStart = nPrefix;
p->iEnd = nLeft - nSuffix;
p->zStart = zClassRm;
sbsWriteText(p, pLeft, SBS_TXTA);
sbsWriteMarker(p, " | ", "|");
sbsWriteLineno(p, lnRight, SBS_LNB);
p->iStart = p->iEnd = -1;
sbsWriteText(p, pRight, SBS_TXTB);
return;
}
/* At this point we know that there is a chunk of text that has
** changed between the left and the right. Check to see if there
** is a large unchanged section in the middle of that changed block.
*/
nLeftDiff = nLeft - nSuffix - nPrefix;
nRightDiff = nRight - nSuffix - nPrefix;
if( p->escHtml
&& nLeftDiff >= 6
&& nRightDiff >= 6
&& textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
){
sbsWriteLineno(p, lnLeft, SBS_LNA);
p->iStart = nPrefix;
p->iEnd = nPrefix + aLCS[0];
if( aLCS[2]==0 ){
sbsShiftLeft(p, pLeft->z);
p->zStart = zClassRm;
}else{
p->zStart = zClassChng;
}
p->iStart2 = nPrefix + aLCS[1];
p->iEnd2 = nLeft - nSuffix;
p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
sbsSimplifyLine(p, zLeft);
sbsWriteText(p, pLeft, SBS_TXTA);
sbsWriteMarker(p, " | ", "|");
sbsWriteLineno(p, lnRight, SBS_LNB);
p->iStart = nPrefix;
p->iEnd = nPrefix + aLCS[2];
if( aLCS[0]==0 ){
sbsShiftLeft(p, pRight->z);
p->zStart = zClassAdd;
}else{
p->zStart = zClassChng;
}
p->iStart2 = nPrefix + aLCS[3];
p->iEnd2 = nRight - nSuffix;
p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
sbsSimplifyLine(p, zRight);
sbsWriteText(p, pRight, SBS_TXTB);
return;
}
/* If all else fails, show a single big change between left and right */
sbsWriteLineno(p, lnLeft, SBS_LNA);
p->iStart2 = p->iEnd2 = 0;
p->iStart = nPrefix;
p->iEnd = nLeft - nSuffix;
p->zStart = zClassChng;
sbsWriteText(p, pLeft, SBS_TXTA);
sbsWriteMarker(p, " | ", "|");
sbsWriteLineno(p, lnRight, SBS_LNB);
p->iEnd = nRight - nSuffix;
sbsWriteText(p, pRight, SBS_TXTB);
}
/*
** Minimum of two values
*/
static int minInt(int a, int b){ return a<b ? a : b; }
|
| ︙ | ︙ | |||
1355 1356 1357 1358 1359 1360 1361 | int r; /* Index into R[] */ int nr; /* Number of COPY/DELETE/INSERT triples to process */ int mxr; /* Maximum value for r */ int na, nb; /* Number of lines shown from A and B */ int i, j; /* Loop counters */ int m, ma, mb;/* Number of lines to output */ int skip; /* Number of lines to skip */ | | > < < > > > > > > > > > > > | 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 |
int r; /* Index into R[] */
int nr; /* Number of COPY/DELETE/INSERT triples to process */
int mxr; /* Maximum value for r */
int na, nb; /* Number of lines shown from A and B */
int i, j; /* Loop counters */
int m, ma, mb;/* Number of lines to output */
int skip; /* Number of lines to skip */
static int nChunk = 0; /* Number of chunks of diff output seen so far */
SbsLine s; /* Output line buffer */
int nContext; /* Lines of context above and below each change */
int showDivider = 0; /* True to show the divider */
Blob aCols[5]; /* Array of column blobs */
memset(&s, 0, sizeof(s));
s.width = diff_width(diffFlags);
nContext = diff_context_lines(diffFlags);
s.escHtml = (diffFlags & DIFF_HTML)!=0;
if( s.escHtml ){
for(i=SBS_LNA; i<=SBS_TXTB; i++){
blob_zero(&aCols[i]);
s.apCols[i] = &aCols[i];
}
}else{
for(i=SBS_LNA; i<=SBS_TXTB; i++){
s.apCols[i] = pOut;
}
}
s.pRe = pRe;
s.iStart = -1;
s.iStart2 = 0;
s.iEnd = -1;
A = p->aFrom;
B = p->aTo;
R = p->aEdit;
mxr = p->nEdit;
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
for(r=0; r<mxr; r += 3*nr){
/* Figure out how many triples to show in a single block */
for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
/* printf("r=%d nr=%d\n", r, nr); */
/* If there is a regex, skip this block (generate no diff output)
** if the regex matches or does not match both insert and delete.
|
| ︙ | ︙ | |||
1434 1435 1436 1437 1438 1439 1440 |
na += R[r+i*3];
nb += R[r+i*3];
}
/* Draw the separator between blocks */
if( showDivider ){
if( s.escHtml ){
| | > > | > > > > | < | | | | | < | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 |
na += R[r+i*3];
nb += R[r+i*3];
}
/* Draw the separator between blocks */
if( showDivider ){
if( s.escHtml ){
char zLn[10];
sqlite3_snprintf(sizeof(zLn), zLn, "%d", a+skip+1);
sbsWriteSep(&s, strlen(zLn), SBS_LNA);
sbsWriteSep(&s, s.width, SBS_TXTA);
sbsWriteSep(&s, 0, SBS_MKR);
sqlite3_snprintf(sizeof(zLn), zLn, "%d", b+skip+1);
sbsWriteSep(&s, strlen(zLn), SBS_LNB);
sbsWriteSep(&s, s.width, SBS_TXTB);
}else{
blob_appendf(pOut, "%.*c\n", s.width*2+16, '.');
}
}
showDivider = 1;
nChunk++;
if( s.escHtml ){
blob_appendf(s.apCols[SBS_LNA], "<span id=\"chunk%d\"></span>", nChunk);
}
/* Show the initial common area */
a += skip;
b += skip;
m = R[r] - skip;
for(j=0; j<m; j++){
sbsWriteLineno(&s, a+j, SBS_LNA);
s.iStart = s.iEnd = -1;
sbsWriteText(&s, &A[a+j], SBS_TXTA);
sbsWriteMarker(&s, " ", "");
sbsWriteLineno(&s, b+j, SBS_LNB);
sbsWriteText(&s, &B[b+j], SBS_TXTB);
}
a += m;
b += m;
/* Show the differences */
for(i=0; i<nr; i++){
unsigned char *alignment;
|
| ︙ | ︙ | |||
1483 1484 1485 1486 1487 1488 1489 |
mb += R[r+i*3+2] + m;
}
alignment = sbsAlignment(&A[a], ma, &B[b], mb);
for(j=0; ma+mb>0; j++){
if( alignment[j]==1 ){
/* Delete one line from the left */
| < | | < | < | < < < < | | < < < < > | | < < | | | | | < < < | | | | | < < | | | | | > > > > | > > > > < | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 |
mb += R[r+i*3+2] + m;
}
alignment = sbsAlignment(&A[a], ma, &B[b], mb);
for(j=0; ma+mb>0; j++){
if( alignment[j]==1 ){
/* Delete one line from the left */
sbsWriteLineno(&s, a, SBS_LNA);
s.iStart = 0;
s.zStart = "<span class=\"diffrm\">";
s.iEnd = LENGTH(&A[a]);
sbsWriteText(&s, &A[a], SBS_TXTA);
sbsWriteMarker(&s, " <", "<");
sbsWriteNewlines(&s);
assert( ma>0 );
ma--;
a++;
}else if( alignment[j]==3 ){
/* The left line is changed into the right line */
sbsWriteLineChange(&s, &A[a], a, &B[b], b);
assert( ma>0 && mb>0 );
ma--;
mb--;
a++;
b++;
}else if( alignment[j]==2 ){
/* Insert one line on the right */
if( !s.escHtml ){
sbsWriteSpace(&s, s.width + 7, SBS_TXTA);
}
sbsWriteMarker(&s, " > ", ">");
sbsWriteLineno(&s, b, SBS_LNB);
s.iStart = 0;
s.zStart = "<span class=\"diffadd\">";
s.iEnd = LENGTH(&B[b]);
sbsWriteText(&s, &B[b], SBS_TXTB);
assert( mb>0 );
mb--;
b++;
}else{
/* Delete from the left and insert on the right */
sbsWriteLineno(&s, a, SBS_LNA);
s.iStart = 0;
s.zStart = "<span class=\"diffrm\">";
s.iEnd = LENGTH(&A[a]);
sbsWriteText(&s, &A[a], SBS_TXTA);
sbsWriteMarker(&s, " | ", "|");
sbsWriteLineno(&s, b, SBS_LNB);
s.iStart = 0;
s.zStart = "<span class=\"diffadd\">";
s.iEnd = LENGTH(&B[b]);
sbsWriteText(&s, &B[b], SBS_TXTB);
ma--;
mb--;
a++;
b++;
}
}
fossil_free(alignment);
if( i<nr-1 ){
m = R[r+i*3+3];
for(j=0; j<m; j++){
sbsWriteLineno(&s, a+j, SBS_LNA);
s.iStart = s.iEnd = -1;
sbsWriteText(&s, &A[a+j], SBS_TXTA);
sbsWriteMarker(&s, " ", "");
sbsWriteLineno(&s, b+j, SBS_LNB);
sbsWriteText(&s, &B[b+j], SBS_TXTB);
}
b += m;
a += m;
}
}
/* Show the final common area */
assert( nr==i );
m = R[r+nr*3];
if( m>nContext ) m = nContext;
for(j=0; j<m; j++){
sbsWriteLineno(&s, a+j, SBS_LNA);
s.iStart = s.iEnd = -1;
sbsWriteText(&s, &A[a+j], SBS_TXTA);
sbsWriteMarker(&s, " ", "");
sbsWriteLineno(&s, b+j, SBS_LNB);
sbsWriteText(&s, &B[b+j], SBS_TXTB);
}
}
if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){
blob_append(pOut, "<table class=\"sbsdiffcols\"><tr>\n", -1);
for(i=SBS_LNA; i<=SBS_TXTB; i++){
sbsWriteColumn(pOut, s.apCols[i], i);
blob_reset(s.apCols[i]);
}
blob_append(pOut, "</tr></table>\n", -1);
}
}
/*
** Compute the optimal longest common subsequence (LCS) using an
** exhaustive search. This version of the LCS is only used for
** shorter input strings since runtime is O(N*N) where N is the
** input string length.
|
| ︙ | ︙ | |||
1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 |
** appropriate default if no width is given.
*/
int diff_width(u64 diffFlags){
int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
if( w==0 ) w = 80;
return w;
}
/*
** Generate a report of the differences between files pA and pB.
** If pOut is not NULL then a unified diff is appended there. It
** is assumed that pOut has already been initialized. If pOut is
** NULL, then a pointer to an array of integers is returned.
** The integers come in triples. For each triple,
| > > > > > > > > > > > | 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 |
** appropriate default if no width is given.
*/
int diff_width(u64 diffFlags){
int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
if( w==0 ) w = 80;
return w;
}
/*
** Append the error message to pOut.
*/
void diff_errmsg(Blob *pOut, const char *msg, int diffFlags){
if( diffFlags & DIFF_HTML ){
blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg);
}else{
blob_append(pOut, msg, -1);
}
}
/*
** Generate a report of the differences between files pA and pB.
** If pOut is not NULL then a unified diff is appended there. It
** is assumed that pOut has already been initialized. If pOut is
** NULL, then a pointer to an array of integers is returned.
** The integers come in triples. For each triple,
|
| ︙ | ︙ | |||
2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 |
if( diffFlags & DIFF_INVERT ){
Blob *pTemp = pA_Blob;
pA_Blob = pB_Blob;
pB_Blob = pTemp;
}
ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
/* Prepare the input files */
memset(&c, 0, sizeof(c));
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
&c.nFrom, ignoreEolWs);
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
&c.nTo, ignoreEolWs);
if( c.aFrom==0 || c.aTo==0 ){
fossil_free(c.aFrom);
fossil_free(c.aTo);
if( pOut ){
| > > | < < < | < | 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 |
if( diffFlags & DIFF_INVERT ){
Blob *pTemp = pA_Blob;
pA_Blob = pB_Blob;
pB_Blob = pTemp;
}
ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
blob_to_utf8_no_bom(pA_Blob, 0);
blob_to_utf8_no_bom(pB_Blob, 0);
/* Prepare the input files */
memset(&c, 0, sizeof(c));
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
&c.nFrom, ignoreEolWs);
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
&c.nTo, ignoreEolWs);
if( c.aFrom==0 || c.aTo==0 ){
fossil_free(c.aFrom);
fossil_free(c.aTo);
if( pOut ){
diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
}
return 0;
}
/* Compute the difference */
diff_all(&c);
if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
int i, m, n;
int *a = c.aEdit;
int mx = c.nEdit;
for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
if( n>10000 ){
fossil_free(c.aFrom);
fossil_free(c.aTo);
fossil_free(c.aEdit);
diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
return 0;
}
}
if( (diffFlags & DIFF_NOOPT)==0 ){
diff_optimize(&c);
}
|
| ︙ | ︙ | |||
2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 |
ReCompiled *pRe = 0; /* Regex filter for diff output */
if( find_option("tk",0,0)!=0 ){
diff_tk("test-diff", 2);
return;
}
find_option("i",0,0);
zRe = find_option("regexp","e",1);
if( zRe ){
const char *zErr = re_compile(&pRe, zRe, 0);
if( zErr ) fossil_fatal("regex error: %s", zErr);
}
diffFlag = diff_options();
verify_all_options();
| > | 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 |
ReCompiled *pRe = 0; /* Regex filter for diff output */
if( find_option("tk",0,0)!=0 ){
diff_tk("test-diff", 2);
return;
}
find_option("i",0,0);
find_option("v",0,0);
zRe = find_option("regexp","e",1);
if( zRe ){
const char *zErr = re_compile(&pRe, zRe, 0);
if( zErr ) fossil_fatal("regex error: %s", zErr);
}
diffFlag = diff_options();
verify_all_options();
|
| ︙ | ︙ | |||
2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 |
int nVers; /* Number of versions analyzed */
int bLimit; /* True if the iLimit was reached */
struct AnnVers {
const char *zFUuid; /* File being analyzed */
const char *zMUuid; /* Check-in containing the file */
const char *zDate; /* Date of the check-in */
const char *zBgColor; /* Suggested background color */
unsigned cnt; /* Number of lines contributed by this check-in */
} *aVers; /* For each check-in analyzed */
char **azVers; /* Names of versions analyzed */
};
/*
** Initialize the annotation process by specifying the file that is
| > | 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 |
int nVers; /* Number of versions analyzed */
int bLimit; /* True if the iLimit was reached */
struct AnnVers {
const char *zFUuid; /* File being analyzed */
const char *zMUuid; /* Check-in containing the file */
const char *zDate; /* Date of the check-in */
const char *zBgColor; /* Suggested background color */
const char *zUser; /* Name of user who did the check-in */
unsigned cnt; /* Number of lines contributed by this check-in */
} *aVers; /* For each check-in analyzed */
char **azVers; /* Names of versions analyzed */
};
/*
** Initialize the annotation process by specifying the file that is
|
| ︙ | ︙ | |||
2303 2304 2305 2306 2307 2308 2309 |
Stmt q; /* Query returning all ancestor versions */
Stmt ins; /* Inserts into the temporary VSEEN table */
int cnt = 0; /* Number of versions examined */
/* Initialize the annotation */
rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
if( rid==0 ){
| | | > | > | 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 |
Stmt q; /* Query returning all ancestor versions */
Stmt ins; /* Inserts into the temporary VSEEN table */
int cnt = 0; /* Number of versions examined */
/* Initialize the annotation */
rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
if( rid==0 ){
fossil_fatal("file #%d is unchanged in manifest #%d", fnid, mid);
}
if( !content_get(rid, &toAnnotate) ){
fossil_fatal("unable to retrieve content of artifact #%d", rid);
}
if( iLimit<=0 ) iLimit = 1000000000;
annotation_start(p, &toAnnotate);
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS vseen(rid INTEGER PRIMARY KEY);"
"DELETE FROM vseen;"
);
db_prepare(&ins, "INSERT OR IGNORE INTO vseen(rid) VALUES(:rid)");
db_prepare(&q,
"SELECT (SELECT uuid FROM blob WHERE rid=mlink.fid),"
" (SELECT uuid FROM blob WHERE rid=mlink.mid),"
" date(event.mtime),"
" coalesce(event.euser,event.user),"
" mlink.pid"
" FROM mlink, event"
" WHERE mlink.fid=:rid"
" AND event.objid=mlink.mid"
" AND mlink.pid NOT IN vseen"
" ORDER BY %s event.mtime",
(annFlags & ANN_FILE_ANCEST)!=0 ?
"(mlink.mid IN (SELECT rid FROM ancestor)) DESC,":""
);
db_bind_int(&q, ":rid", rid);
if( iLimit==0 ) iLimit = 1000000000;
while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){
int prevId = db_column_int(&q, 4);
p->aVers = fossil_realloc(p->aVers, (p->nVers+1)*sizeof(p->aVers[0]));
p->aVers[p->nVers].zFUuid = fossil_strdup(db_column_text(&q, 0));
p->aVers[p->nVers].zMUuid = fossil_strdup(db_column_text(&q, 1));
p->aVers[p->nVers].zDate = fossil_strdup(db_column_text(&q, 2));
p->aVers[p->nVers].zUser = fossil_strdup(db_column_text(&q, 3));
if( p->nVers ){
content_get(rid, &step);
annotation_step(p, &step, p->nVers-1);
blob_reset(&step);
}
p->nVers++;
db_bind_int(&ins, ":rid", rid);
|
| ︙ | ︙ | |||
2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 | x2 = c2&0xff; c |= (x1*(n-i) + x2*i)/n & 0xff; return c; } /* ** WEBPAGE: annotate ** ** Query parameters: ** ** checkin=ID The manifest ID at which to start the annotation ** filename=FILENAME The filename. ** filevers Show file versions rather than check-in versions ** log=BOOLEAN Show a log of versions analyzed | > | 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 | x2 = c2&0xff; c |= (x1*(n-i) + x2*i)/n & 0xff; return c; } /* ** WEBPAGE: annotate ** WEBPAGE: blame ** ** Query parameters: ** ** checkin=ID The manifest ID at which to start the annotation ** filename=FILENAME The filename. ** filevers Show file versions rather than check-in versions ** log=BOOLEAN Show a log of versions analyzed |
| ︙ | ︙ | |||
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 |
int showLog = 0; /* True to display the log */
const char *zFilename; /* Name of file to annotate */
const char *zCI; /* The check-in containing zFilename */
Annotator ann;
HQuery url;
struct AnnVers *p;
unsigned clr1, clr2, clr;
/* Gather query parameters */
showLog = atoi(PD("log","1"));
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
mid = name_to_typed_rid(PD("checkin","0"),"ci");
zFilename = P("filename");
fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
iLimit = atoi(PD("limit","20"));
if( P("filevers") ) annFlags |= ANN_FILE_VERS;
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
| > > | 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 |
int showLog = 0; /* True to display the log */
const char *zFilename; /* Name of file to annotate */
const char *zCI; /* The check-in containing zFilename */
Annotator ann;
HQuery url;
struct AnnVers *p;
unsigned clr1, clr2, clr;
int bBlame = g.zPath[0]=='b';/* True for BLAME output. False for ANNOTATE. */
/* Gather query parameters */
showLog = atoi(PD("log","1"));
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( exclude_spiders("annotate") ) return;
mid = name_to_typed_rid(PD("checkin","0"),"ci");
zFilename = P("filename");
fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
if( mid==0 || fnid==0 ){ fossil_redirect_home(); }
iLimit = atoi(PD("limit","20"));
if( P("filevers") ) annFlags |= ANN_FILE_VERS;
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){
|
| ︙ | ︙ | |||
2433 2434 2435 2436 2437 2438 2439 |
url_add_parameter(&url, "filename", zFilename);
if( iLimit!=20 ){
url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
}
url_add_parameter(&url, "log", showLog ? "1" : "0");
if( showLog ){
style_submenu_element("Hide Log", "Hide Log",
| | | | | | | 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 |
url_add_parameter(&url, "filename", zFilename);
if( iLimit!=20 ){
url_add_parameter(&url, "limit", sqlite3_mprintf("%d", iLimit));
}
url_add_parameter(&url, "log", showLog ? "1" : "0");
if( showLog ){
style_submenu_element("Hide Log", "Hide Log",
"%s", url_render(&url, "log", "0", 0, 0));
}else{
style_submenu_element("Show Log", "Show Log",
"%s", url_render(&url, "log", "1", 0, 0));
}
if( ann.bLimit ){
char *z1, *z2;
style_submenu_element("All Ancestors", "All Ancestors",
"%s", url_render(&url, "limit", "-1", 0, 0));
z1 = sqlite3_mprintf("%d Ancestors", iLimit+20);
z2 = sqlite3_mprintf("%d", iLimit+20);
style_submenu_element(z1, z1, "%s", url_render(&url, "limit", z2, 0, 0));
}
if( iLimit>20 ){
style_submenu_element("20 Ancestors", "20 Ancestors",
"%s", url_render(&url, "limit", "20", 0, 0));
}
if( db_get_boolean("white-foreground", 0) ){
clr1 = 0xa04040;
clr2 = 0x4059a0;
}else{
clr1 = 0xffb5b5; /* Recent changes: red (hot) */
clr2 = 0xb5e0ff; /* Older changes: blue (cold) */
|
| ︙ | ︙ | |||
2507 2508 2509 2510 2511 2512 2513 |
for(i=0; i<ann.nOrig; i++){
int iVers = ann.aOrig[i].iVers;
char *z = (char*)ann.aOrig[i].z;
int n = ann.aOrig[i].n;
char zPrefix[300];
z[n] = 0;
if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
| > > | | | | | > > > > > > > > > > > > | | | | | > > | | > > | 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 |
for(i=0; i<ann.nOrig; i++){
int iVers = ann.aOrig[i].iVers;
char *z = (char*)ann.aOrig[i].z;
int n = ann.aOrig[i].n;
char zPrefix[300];
z[n] = 0;
if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
if( bBlame ){
if( iVers>=0 ){
struct AnnVers *p = ann.aVers+iVers;
char *zLink = xhref("target='infowindow'", "%R/info/%S", p->zMUuid);
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
"<span style='background-color:%s'>"
"%s%.10s</a> %s</span> %13.13s:",
p->zBgColor, zLink, p->zMUuid, p->zDate, p->zUser);
fossil_free(zLink);
}else{
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%36s", "");
}
}else{
if( iVers>=0 ){
struct AnnVers *p = ann.aVers+iVers;
char *zLink = xhref("target='infowindow'", "%R/info/%S", p->zMUuid);
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
"<span style='background-color:%s'>"
"%s%.10s</a> %s</span> %4d:",
p->zBgColor, zLink, p->zMUuid, p->zDate, i+1);
fossil_free(zLink);
}else{
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%22s%4d:", "", i+1);
}
}
@ %s(zPrefix) %h(z)
}
@ </pre>
style_footer();
}
/*
** COMMAND: annotate
** COMMAND: blame
**
** %fossil (annotate|blame) ?OPTIONS? FILENAME
**
** Output the text of a file with markings to show when each line of
** the file was last modified. The "annotate" command shows line numbers
** and omits the username. The "blame" command shows the user who made each
** checkin and omits the line number.
**
** Options:
** --filevers Show file version numbers rather than check-in versions
** -l|--log List all versions analyzed
** -n|--limit N Only look backwards in time by N versions
**
** See also: info, finfo, timeline
|
| ︙ | ︙ | |||
2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 |
Annotator ann; /* The annotation of the file */
int i; /* Loop counter */
const char *zLimit; /* The value to the -n|--limit option */
int iLimit; /* How far back in time to look */
int showLog; /* True to show the log */
int fileVers; /* Show file version instead of check-in versions */
int annFlags = 0; /* Flags to control annotation properties */
zLimit = find_option("limit","n",1);
if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
iLimit = atoi(zLimit);
showLog = find_option("log","l",0)!=0;
fileVers = find_option("filevers",0,0)!=0;
db_must_be_within_tree();
if( g.argc<3 ) {
| > > | 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 |
Annotator ann; /* The annotation of the file */
int i; /* Loop counter */
const char *zLimit; /* The value to the -n|--limit option */
int iLimit; /* How far back in time to look */
int showLog; /* True to show the log */
int fileVers; /* Show file version instead of check-in versions */
int annFlags = 0; /* Flags to control annotation properties */
int bBlame = 0; /* True for BLAME output. False for ANNOTATE. */
bBlame = g.argv[1][0]=='b';
zLimit = find_option("limit","n",1);
if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1";
iLimit = atoi(zLimit);
showLog = find_option("log","l",0)!=0;
fileVers = find_option("filevers",0,0)!=0;
db_must_be_within_tree();
if( g.argc<3 ) {
|
| ︙ | ︙ | |||
2585 2586 2587 2588 2589 2590 2591 |
if( iLimit<=0 ) iLimit = 1000000000;
compute_direct_ancestors(cid, 1000000);
mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
" WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid"
" ORDER BY ancestor.generation ASC LIMIT 1",
fid, fnid);
if( mid==0 ){
| | | < > > | < | | | < < | | < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < > > | < > > | < < < < < < < < < < < < < < < < < < < < < < > > | 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 |
if( iLimit<=0 ) iLimit = 1000000000;
compute_direct_ancestors(cid, 1000000);
mid = db_int(0, "SELECT mlink.mid FROM mlink, ancestor "
" WHERE mlink.fid=%d AND mlink.fnid=%d AND mlink.mid=ancestor.rid"
" ORDER BY ancestor.generation ASC LIMIT 1",
fid, fnid);
if( mid==0 ){
fossil_fatal("unable to find manifest");
}
annFlags |= ANN_FILE_ANCEST;
annotate_file(&ann, fnid, mid, iLimit, annFlags);
if( showLog ){
struct AnnVers *p;
for(p=ann.aVers, i=0; i<ann.nVers; i++, p++){
fossil_print("version %3d: %s %.10s file %.10s\n",
i+1, p->zDate, p->zMUuid, p->zFUuid);
}
fossil_print("---------------------------------------------------\n");
}
for(i=0; i<ann.nOrig; i++){
int iVers = ann.aOrig[i].iVers;
char *z = (char*)ann.aOrig[i].z;
int n = ann.aOrig[i].n;
struct AnnVers *p;
if( iLimit>ann.nVers && iVers<0 ) iVers = ann.nVers-1;
p = ann.aVers + iVers;
if( bBlame ){
if( iVers>=0 ){
fossil_print("%.10s %s %13.13s: %.*s\n",
fileVers ? p->zFUuid : p->zMUuid, p->zDate, p->zUser, n, z);
}else{
fossil_print("%35s %.*s\n", "", n, z);
}
}else{
if( iVers>=0 ){
fossil_print("%.10s %s %5d: %.*s\n",
fileVers ? p->zFUuid : p->zMUuid, p->zDate, i+1, n, z);
}else{
fossil_print("%21s %5d: %.*s\n",
"", i+1, n, z);
}
}
}
}
|
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
595 596 597 598 599 600 601 |
zName = "diff-command";
}
return db_get(zName, zDefault);
}
/* A Tcl/Tk script used to render diff output.
*/
| | > | | < | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > | > > > > > > > > > > > > | > > > > > > > | > > > > | < > > > > > > > > > > > > > > > > | > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | < | < > > > > | > > | > > > > > > > > > > > > > > > > > > | > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > | 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 |
zName = "diff-command";
}
return db_get(zName, zDefault);
}
/* A Tcl/Tk script used to render diff output.
*/
static const char zDiffScript[] =
@ package require Tk
@
@ array set CFG {
@ TITLE {Fossil Diff}
@ LN_COL_BG #dddddd
@ LN_COL_FG #444444
@ TXT_COL_BG #ffffff
@ TXT_COL_FG #000000
@ MKR_COL_BG #444444
@ MKR_COL_FG #dddddd
@ CHNG_BG #d0d0ff
@ ADD_BG #c0ffc0
@ RM_BG #ffc0c0
@ HR_FG #888888
@ HR_PAD_TOP 4
@ HR_PAD_BTM 8
@ FN_BG #444444
@ FN_FG #ffffff
@ FN_PAD 5
@ PADX 5
@ WIDTH 80
@ HEIGHT 45
@ LB_HEIGHT 25
@ }
@
@ if {![namespace exists ttk]} {
@ interp alias {} ::ttk::scrollbar {} ::scrollbar
@ interp alias {} ::ttk::menubutton {} ::menubutton
@ }
@
@ proc dehtml {x} {
@ set x [regsub -all {<[^>]*>} $x {}]
@ return [string map {& & < < > > ' ' " \"} $x]
@ }
@
@ proc cols {} {
@ return [list .lnA .txtA .mkr .lnB .txtB]
@ }
@
@ proc colType {c} {
@ regexp {[a-z]+} $c type
@ return $type
@ }
@
@ proc readDiffs {fossilcmd} {
@ set in [open $fossilcmd r]
@ fconfigure $in -encoding utf-8
@ set nDiffs 0
@ array set widths {txt 0 ln 0 mkr 0}
@ while {[gets $in line] != -1} {
@ if {![regexp {^=+\s+(.*?)\s+=+$} $line all fn]} {
@ continue
@ }
@ if {[string compare -length 6 [gets $in] "<table"]} {
@ continue
@ }
@ incr nDiffs
@ set idx [expr {$nDiffs > 1 ? [.txtA index end] : "1.0"}]
@ .wfiles.lb insert end $fn
@
@ foreach c [cols] {
@ while {[gets $in] ne "<pre>"} continue
@
@ if {$nDiffs > 1} {
@ $c insert end \n -
@ }
@ if {[colType $c] eq "txt"} {
@ $c insert end $fn\n fn
@ } else {
@ $c insert end \n fn
@ }
@ $c insert end \n -
@
@ set type [colType $c]
@ set str {}
@ while {[set line [gets $in]] ne "</pre>"} {
@ set len [string length [dehtml $line]]
@ if {$len > $widths($type)} {
@ set widths($type) $len
@ }
@ append str $line\n
@ }
@
@ set re {<span class="diff([a-z]+)">([^<]*)</span>}
@ # Use \r as separator since it can't appear in the diff output (it gets
@ # converted to a space).
@ set str [regsub -all $re $str "\r\\1\r\\2\r"]
@ foreach {pre class mid} [split $str \r] {
@ if {$class ne ""} {
@ $c insert end [dehtml $pre] - [dehtml $mid] [list $class -]
@ } else {
@ $c insert end [dehtml $pre] -
@ }
@ }
@ }
@ }
@ close $in
@
@ foreach c [cols] {
@ set type [colType $c]
@ if {$type ne "txt"} {
@ $c config -width $widths($type)
@ }
@ $c config -state disabled
@ }
@ if {$nDiffs <= [.wfiles.lb cget -height]} {
@ .wfiles.lb config -height $nDiffs
@ grid remove .wfiles.sb
@ }
@
@ return $nDiffs
@ }
@
@ proc viewDiff {idx} {
@ .txtA yview $idx
@ .txtA xview moveto 0
@ }
@
@ proc cycleDiffs {{reverse 0}} {
@ if {$reverse} {
@ set range [.txtA tag prevrange fn @0,0 1.0]
@ if {$range eq ""} {
@ viewDiff {fn.last -1c}
@ } else {
@ viewDiff [lindex $range 0]
@ }
@ } else {
@ set range [.txtA tag nextrange fn {@0,0 +1c} end]
@ if {$range eq "" || [lindex [.txtA yview] 1] == 1} {
@ viewDiff fn.first
@ } else {
@ viewDiff [lindex $range 0]
@ }
@ }
@ }
@
@ proc xvis {col} {
@ set view [$col xview]
@ return [expr {[lindex $view 1]-[lindex $view 0]}]
@ }
@
@ proc scroll-x {args} {
@ set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}]
@ eval $c xview $args
@ }
@
@ interp alias {} scroll-y {} .txtA yview
@
@ proc noop {args} {}
@
@ proc enableSync {axis} {
@ update idletasks
@ interp alias {} sync-$axis {}
@ rename _sync-$axis sync-$axis
@ }
@
@ proc disableSync {axis} {
@ rename sync-$axis _sync-$axis
@ interp alias {} sync-$axis {} noop
@ }
@
@ proc sync-x {col first last} {
@ disableSync x
@ $col xview moveto [expr {$first*[xvis $col]/($last-$first)}]
@ foreach side {A B} {
@ set sb .sbx$side
@ set xview [.txt$side xview]
@ if {[lindex $xview 0] > 0 || [lindex $xview 1] < 1} {
@ grid $sb
@ eval $sb set $xview
@ } else {
@ grid remove $sb
@ }
@ }
@ enableSync x
@ }
@
@ proc sync-y {first last} {
@ disableSync y
@ foreach c [cols] {
@ $c yview moveto $first
@ }
@ if {$first > 0 || $last < 1} {
@ grid .sby
@ .sby set $first $last
@ } else {
@ grid remove .sby
@ }
@ enableSync y
@ }
@
@ wm withdraw .
@ wm title . $CFG(TITLE)
@ wm iconname . $CFG(TITLE)
@ bind . <q> exit
@ bind . <Destroy> {after 0 exit}
@ bind . <Tab> {cycleDiffs; break}
@ bind . <<PrevWindow>> {cycleDiffs 1; break}
@ bind . <Return> {
@ event generate .files <1>
@ event generate .files <ButtonRelease-1>
@ break
@ }
@ foreach {key axis args} {
@ Up y {scroll -5 units}
@ Down y {scroll 5 units}
@ Left x {scroll -5 units}
@ Right x {scroll 5 units}
@ Prior y {scroll -1 page}
@ Next y {scroll 1 page}
@ Home y {moveto 0}
@ End y {moveto 1}
@ } {
@ bind . <$key> "scroll-$axis $args; break"
@ bind . <Shift-$key> continue
@ }
@
@ ::ttk::menubutton .files -text "Files"
@ toplevel .wfiles
@ wm withdraw .wfiles
@ update idletasks
@ wm transient .wfiles .
@ wm overrideredirect .wfiles 1
@ listbox .wfiles.lb -width 0 -height $CFG(LB_HEIGHT) -activestyle none \
@ -yscroll {.wfiles.sb set}
@ ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
@ grid .wfiles.lb .wfiles.sb -sticky ns
@ bind .files <1> {
@ set x [winfo rootx %W]
@ set y [expr {[winfo rooty %W]+[winfo height %W]}]
@ wm geometry .wfiles +$x+$y
@ wm deiconify .wfiles
@ focus .wfiles.lb
@ }
@ bind .wfiles <FocusOut> {wm withdraw .wfiles}
@ bind .wfiles <Escape> {focus .}
@ foreach evt {1 Return} {
@ bind .wfiles.lb <$evt> {
@ catch {
@ set idx [lindex [.txtA tag ranges fn] [expr {[%W curselection]*2}]]
@ viewDiff $idx
@ }
@ focus .
@ break
@ }
@ }
@ bind .wfiles.lb <Motion> {
@ %W selection clear 0 end
@ %W selection set @%x,%y
@ }
@
@ foreach {side syncCol} {A .txtB B .txtA} {
@ set ln .ln$side
@ text $ln
@ $ln tag config - -justify right
@
@ set txt .txt$side
@ text $txt -width $CFG(WIDTH) -height $CFG(HEIGHT) -wrap none \
@ -xscroll "sync-x $syncCol"
@ catch {$txt config -tabstyle wordprocessor} ;# Required for Tk>=8.5
@ foreach tag {add rm chng} {
@ $txt tag config $tag -background $CFG([string toupper $tag]_BG)
@ $txt tag lower $tag
@ }
@ $txt tag config fn -background $CFG(FN_BG) -foreground $CFG(FN_FG) \
@ -justify center
@ }
@ text .mkr
@
@ foreach c [cols] {
@ set keyPrefix [string toupper [colType $c]]_COL_
@ if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}}
@ $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \
@ -padx $CFG(PADX) -yscroll sync-y
@ $c tag config hr -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \
@ -foreground $CFG(HR_FG)
@ $c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD)
@ bindtags $c ". $c Text all"
@ bind $c <1> {focus %W}
@ }
@
@ ::ttk::scrollbar .sby -command {.txtA yview} -orient vertical
@ ::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal
@ ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal
@ frame .spacer
@
@ if {[readDiffs $fossilcmd] == 0} {
@ tk_messageBox -type ok -title $CFG(TITLE) -message "No changes"
@ exit
@ }
@ update idletasks
@
@ grid rowconfigure . 1 -weight 1
@ grid columnconfigure . 1 -weight 1
@ grid columnconfigure . 4 -weight 1
@ grid .files -row 0 -columnspan 6
@ eval grid [cols] -row 1 -sticky nsew
@ grid .sby -row 1 -column 5 -sticky ns
@ grid .sbxA -row 2 -columnspan 2 -sticky ew
@ grid .spacer -row 2 -column 2
@ grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew
@
@ .spacer config -height [winfo height .sbxA]
@ wm deiconify .
;
/*
** Show diff output in a Tcl/Tk window, in response to the --tk option
** to the diff command.
**
** If fossil has direct access to a Tcl interpreter (either loaded
** dynamically through stubs or linked in statically), we can use it
** directly. Otherwise:
** (1) Write the Tcl/Tk script used for rendering into a temp file.
** (2) Invoke "tclsh" on the temp file using fossil_system().
** (3) Delete the temp file.
*/
void diff_tk(const char *zSubCmd, int firstArg){
int i;
Blob script;
char *zTempFile = 0;
char *zCmd;
blob_zero(&script);
blob_appendf(&script, "set fossilcmd {| \"%/\" %s --html -y -i -v",
g.nameOfExe, zSubCmd);
for(i=firstArg; i<g.argc; i++){
const char *z = g.argv[i];
if( z[0]=='-' ){
if( strglob("*-html",z) ) continue;
if( strglob("*-y",z) ) continue;
if( strglob("*-i",z) ) continue;
/* The undocumented --script FILENAME option causes the Tk script to
** be written into the FILENAME instead of being run. This is used
** for testing and debugging. */
if( strglob("*-script",z) && i<g.argc-1 ){
i++;
zTempFile = g.argv[i];
continue;
}
}
blob_append(&script, " ", 1);
shell_escape(&script, z);
}
blob_appendf(&script, "}\n%s", zDiffScript);
if( zTempFile ){
blob_write_to_file(&script, zTempFile);
fossil_print("To see diff, run: tclsh \"%s\"\n", zTempFile);
}else{
#if defined(FOSSIL_ENABLE_TCL)
Th_FossilInit(TH_INIT_DEFAULT);
if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
blob_size(&script), 1)==TCL_OK ){
blob_reset(&script);
return;
}
/*
* If evaluation of the Tcl script fails, the reason may be that Tk
* could not be found by the loaded Tcl, or that Tcl cannot be loaded
* dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
* to using the external "tclsh", if available.
*/
#endif
zTempFile = write_blob_to_temp_file(&script);
zCmd = mprintf("tclsh \"%s\"", zTempFile);
fossil_system(zCmd);
file_delete(zTempFile);
fossil_free(zCmd);
}
blob_reset(&script);
}
/*
** Returns non-zero if files that may be binary should be used with external
** diff programs.
*/
int diff_include_binary_files(void){
|
| ︙ | ︙ | |||
710 711 712 713 714 715 716 | ** ** Show the difference between the current version of each of the FILEs ** specified (as they exist on disk) and that same file as it was checked ** out. Or if the FILE arguments are omitted, show the unsaved changed ** currently in the working check-out. ** ** If the "--from VERSION" or "-r VERSION" option is used it specifies | | | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 | ** ** Show the difference between the current version of each of the FILEs ** specified (as they exist on disk) and that same file as it was checked ** out. Or if the FILE arguments are omitted, show the unsaved changed ** currently in the working check-out. ** ** If the "--from VERSION" or "-r VERSION" option is used it specifies ** the source check-in for the diff operation. If not specified, the ** source check-in is the base check-in for the current check-out. ** ** If the "--to VERSION" option appears, it specifies the check-in from ** which the second version of the file or files is taken. If there is ** no "--to" option then the (possibly edited) files in the current check-out ** are used. ** |
| ︙ | ︙ | |||
737 738 739 740 741 742 743 | ** as binary when considering if they should be used with external diff program. ** This option overrides the "binary-glob" setting. ** ** Options: ** --binary PATTERN Treat files that match the glob PATTERN as binary ** --branch BRANCH Show diff of all changes on BRANCH ** --brief Show filenames only | | | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | ** as binary when considering if they should be used with external diff program. ** This option overrides the "binary-glob" setting. ** ** Options: ** --binary PATTERN Treat files that match the glob PATTERN as binary ** --branch BRANCH Show diff of all changes on BRANCH ** --brief Show filenames only ** --context|-c N Use N lines of context ** --diff-binary BOOL Include binary files when using external commands ** --from|-r VERSION select VERSION as source for the diff ** --internal|-i use internal diff logic ** --side-by-side|-y side-by-side diff ** --tk Launch a Tcl/Tk GUI for display ** --to VERSION select VERSION as target for the diff ** --unified unified diff |
| ︙ | ︙ |
Changes to src/doc.c.
| ︙ | ︙ | |||
447 448 449 450 451 452 453 |
Manifest *pM;
ManifestFile *pFile;
/* Add the vid baseline to the cache */
if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){
db_multi_exec("DELETE FROM vcache");
}
| | | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
Manifest *pM;
ManifestFile *pFile;
/* Add the vid baseline to the cache */
if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){
db_multi_exec("DELETE FROM vcache");
}
pM = manifest_get(vid, CFTYPE_MANIFEST, 0);
if( pM==0 ){
goto doc_not_found;
}
db_prepare(&s,
"INSERT INTO vcache(vid,fname,rid)"
" SELECT %d, :fname, rid FROM blob"
" WHERE uuid=:uuid",
|
| ︙ | ︙ | |||
481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
/* Get the file content */
if( content_get(rid, &filebody)==0 ){
goto doc_not_found;
}
db_end_transaction(0);
}
/* The file is now contained in the filebody blob. Deliver the
** file to the user
*/
zMime = P("mimetype");
if( zMime==0 ){
zMime = mimetype_from_name(zName);
| > | 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
/* Get the file content */
if( content_get(rid, &filebody)==0 ){
goto doc_not_found;
}
db_end_transaction(0);
}
blob_to_utf8_no_bom(&filebody, 0);
/* The file is now contained in the filebody blob. Deliver the
** file to the user
*/
zMime = P("mimetype");
if( zMime==0 ){
zMime = mimetype_from_name(zName);
|
| ︙ | ︙ |
Changes to src/encode.c.
| ︙ | ︙ | |||
159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
zOut[i++] = '%';
zOut[i++] = "0123456789ABCDEF"[(c>>4)&0xf];
zOut[i++] = "0123456789ABCDEF"[c&0xf];
}
zIn++;
}
zOut[i] = 0;
return zOut;
}
/*
** Convert the input string into a form that is suitable for use as
** a token in the HTTP protocol. Spaces are encoded as '+' and special
** characters are encoded as "%HH" where HH is a two-digit hexadecimal
| > | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
zOut[i++] = '%';
zOut[i++] = "0123456789ABCDEF"[(c>>4)&0xf];
zOut[i++] = "0123456789ABCDEF"[c&0xf];
}
zIn++;
}
zOut[i] = 0;
#undef IsSafeChar
return zOut;
}
/*
** Convert the input string into a form that is suitable for use as
** a token in the HTTP protocol. Spaces are encoded as '+' and special
** characters are encoded as "%HH" where HH is a two-digit hexadecimal
|
| ︙ | ︙ |
Changes to src/event.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 | ** ** Milestones ** Blog posts ** New articles ** Process checkpoints ** Announcements */ #include <assert.h> #include <ctype.h> | > < | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
**
** Milestones
** Blog posts
** New articles
** Process checkpoints
** Announcements
*/
#include "config.h"
#include <assert.h>
#include <ctype.h>
#include "event.h"
/*
** Output a hyperlink to an event given its tagid.
*/
void hyperlink_to_event_tagid(int tagid){
char *zEventId;
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
if( !zVerbose ){
zVerbose = P("detail"); /* deprecated */
}
verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
/* Extract the event content.
*/
| | | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
if( !zVerbose ){
zVerbose = P("detail"); /* deprecated */
}
verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
/* Extract the event content.
*/
pEvent = manifest_get(rid, CFTYPE_EVENT, 0);
if( pEvent==0 ){
fossil_fatal("Object #%d is not an event", rid);
}
blob_init(&fullbody, pEvent->zWiki, -1);
if( wiki_find_title(&fullbody, &title, &tail) ){
style_header(blob_str(&title));
}else{
style_header("Event %S", zEventId);
tail = fullbody;
|
| ︙ | ︙ | |||
255 256 257 258 259 260 261 |
/* If editing an existing event, extract the key fields to use as
** a starting point for the edit.
*/
if( rid && (zBody==0 || zETime==0 || zComment==0 || zTags==0) ){
Manifest *pEvent;
| | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
/* If editing an existing event, extract the key fields to use as
** a starting point for the edit.
*/
if( rid && (zBody==0 || zETime==0 || zComment==0 || zTags==0) ){
Manifest *pEvent;
pEvent = manifest_get(rid, CFTYPE_EVENT, 0);
if( pEvent && pEvent->type==CFTYPE_EVENT ){
if( zBody==0 ) zBody = pEvent->zWiki;
if( zETime==0 ){
zETime = db_text(0, "SELECT datetime(%.17g)", pEvent->rEventDate);
}
if( zComment==0 ) zComment = pEvent->zComment;
}
|
| ︙ | ︙ | |||
278 279 280 281 282 283 284 |
);
}
}
zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){
char *zDate;
Blob cksum;
| | > > > > | > | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
);
}
}
zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){
char *zDate;
Blob cksum;
int nrid, n;
blob_zero(&event);
db_begin_transaction();
login_verify_csrf_secret();
while( fossil_isspace(zComment[0]) ) zComment++;
n = strlen(zComment);
while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; }
if( n>0 ){
blob_appendf(&event, "C %#F\n", n, zComment);
}
zDate = date_in_standard_format("now");
blob_appendf(&event, "D %s\n", zDate);
free(zDate);
zETime[10] = 'T';
blob_appendf(&event, "E %s %s\n", zETime, zEventId);
zETime[10] = ' ';
if( rid ){
|
| ︙ | ︙ | |||
344 345 346 347 348 349 350 |
}
blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
md5sum_blob(&event, &cksum);
blob_appendf(&event, "Z %b\n", &cksum);
blob_reset(&cksum);
nrid = content_put(&event);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
| | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
}
blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
md5sum_blob(&event, &cksum);
blob_appendf(&event, "Z %b\n", &cksum);
blob_reset(&cksum);
nrid = content_put(&event);
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
manifest_crosslink(nrid, &event, MC_NONE);
assert( blob_is_reset(&event) );
content_deltify(rid, nrid, 0);
db_end_transaction(0);
cgi_redirectf("event?name=%T", zEventId);
}
if( P("cancel")!=0 ){
cgi_redirectf("event?name=%T", zEventId);
|
| ︙ | ︙ | |||
397 398 399 400 401 402 403 | if( n<20 ) n = 20; if( n>40 ) n = 40; @ <form method="post" action="%s(g.zTop)/eventedit"><div> login_insert_csrf_secret(); @ <input type="hidden" name="name" value="%h(zEventId)" /> @ <table border="0" cellspacing="10"> | | | | | | | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | if( n<20 ) n = 20; if( n>40 ) n = 40; @ <form method="post" action="%s(g.zTop)/eventedit"><div> login_insert_csrf_secret(); @ <input type="hidden" name="name" value="%h(zEventId)" /> @ <table border="0" cellspacing="10"> @ <tr><th align="right" valign="top">Event Time (UTC):</th> @ <td valign="top"> @ <input type="text" name="t" size="25" value="%h(zETime)" /> @ </td></tr> @ <tr><th align="right" valign="top">Timeline Comment:</th> @ <td valign="top"> @ <textarea name="c" class="eventedit" cols="80" @ rows="3" wrap="virtual">%h(zComment)</textarea> @ </td></tr> @ <tr><th align="right" valign="top">Background Color:</th> @ <td valign="top"> render_color_chooser(0, zClr, 0, "clr", "cclr"); @ </td></tr> @ <tr><th align="right" valign="top">Tags:</th> @ <td valign="top"> @ <input type="text" name="g" size="40" value="%h(zTags)" /> @ </td></tr> @ <tr><th align="right" valign="top">Page Content:</th> @ <td valign="top"> @ <textarea name="w" class="eventedit" cols="80" @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea> @ </td></tr> @ <tr><td colspan="2"> @ <input type="submit" name="preview" value="Preview Your Changes" /> @ <input type="submit" name="submit" value="Apply These Changes" /> @ <input type="submit" name="cancel" value="Cancel" /> @ </td></tr></table> @ </div></form> style_footer(); } |
Changes to src/export.c.
| ︙ | ︙ | |||
136 137 138 139 140 141 142 |
if( markfile_in!=0 ){
Stmt qb,qc;
char line[100];
FILE *f;
f = fossil_fopen(markfile_in, "r");
if( f==0 ){
| | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
if( markfile_in!=0 ){
Stmt qb,qc;
char line[100];
FILE *f;
f = fossil_fopen(markfile_in, "r");
if( f==0 ){
fossil_fatal("cannot open %s for reading", markfile_in);
}
db_prepare(&qb, "INSERT OR IGNORE INTO oldblob VALUES (:rid)");
db_prepare(&qc, "INSERT OR IGNORE INTO oldcommit VALUES (:rid)");
while( fgets(line, sizeof(line), f)!=0 ){
if( *line == 'b' ){
db_bind_text(&qb, ":rid", line + 1);
db_step(&qb);
db_reset(&qb);
bag_insert(&blobs, atoi(line + 1));
}else if( *line == 'c' ){
db_bind_text(&qc, ":rid", line + 1);
db_step(&qc);
db_reset(&qc);
bag_insert(&vers, atoi(line + 1));
}else{
fossil_fatal("bad input from %s: %s", markfile_in, line);
}
}
db_finalize(&qb);
db_finalize(&qc);
fclose(f);
}
|
| ︙ | ︙ | |||
333 334 335 336 337 338 339 |
db_finalize(&q);
bag_clear(&vers);
if( markfile_out!=0 ){
FILE *f;
f = fossil_fopen(markfile_out, "w");
if( f == 0 ){
| | | | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
db_finalize(&q);
bag_clear(&vers);
if( markfile_out!=0 ){
FILE *f;
f = fossil_fopen(markfile_out, "w");
if( f == 0 ){
fossil_fatal("cannot open %s for writing", markfile_out);
}
db_prepare(&q, "SELECT rid FROM oldblob");
while( db_step(&q)==SQLITE_ROW ){
fprintf(f, "b%d\n", db_column_int(&q, 0));
}
db_finalize(&q);
db_prepare(&q, "SELECT rid FROM oldcommit");
while( db_step(&q)==SQLITE_ROW ){
fprintf(f, "c%d\n", db_column_int(&q, 0));
}
db_finalize(&q);
if( ferror(f)!=0 || fclose(f)!=0 ) {
fossil_fatal("error while writing %s", markfile_out);
}
}
}
|
Changes to src/file.c.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 | # include <direct.h> # include <windows.h> # include <sys/utime.h> #else # include <sys/time.h> #endif | > | < < > | > > > > > | | > > > > > > | > > > | > | | < > > > | < < < | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# include <direct.h>
# include <windows.h>
# include <sys/utime.h>
#else
# include <sys/time.h>
#endif
#if INTERFACE
#include <dirent.h>
#if defined(_WIN32)
# define DIR _WDIR
# define dirent _wdirent
# define opendir _wopendir
# define readdir _wreaddir
# define closedir _wclosedir
#endif /* _WIN32 */
#if defined(_WIN32) && (defined(__MSVCRT__) || defined(_MSC_VER))
struct fossilStat {
i64 st_size;
i64 st_mtime;
int st_mode;
};
#endif
#endif /* INTERFACE */
#if !defined(_WIN32) || !(defined(__MSVCRT__) || defined(_MSC_VER))
# define fossilStat stat
#endif
/*
** On Windows S_ISLNK always returns FALSE.
*/
#if !defined(S_ISLNK)
# define S_ISLNK(x) (0)
#endif
static int fileStatValid = 0;
static struct fossilStat fileStat;
/*
** Fill stat buf with information received from stat() or lstat().
** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
**
*/
static int fossil_stat(const char *zFilename, struct fossilStat *buf, int isWd){
#if !defined(_WIN32)
int rc;
char *zMbcs = fossil_utf8_to_filename(zFilename);
if( isWd && g.allowSymlinks ){
rc = lstat(zMbcs, buf);
}else{
rc = stat(zMbcs, buf);
}
fossil_filename_free(zMbcs);
return rc;
#else
return win32_stat(zFilename, buf, isWd);
#endif
}
/*
** Fill in the fileStat variable for the file named zFilename.
** If zFilename==0, then use the previous value of fileStat if
** there is a previous value.
**
|
| ︙ | ︙ | |||
301 302 303 304 305 306 307 |
/*
** Wrapper around the access() system call.
*/
int file_access(const char *zFilename, int flags){
#ifdef _WIN32
| | < < > < | < > | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
/*
** Wrapper around the access() system call.
*/
int file_access(const char *zFilename, int flags){
#ifdef _WIN32
return win32_access(zFilename, flags);
#else
char *zMbcs = fossil_utf8_to_filename(zFilename);
int rc = access(zMbcs, flags);
fossil_filename_free(zMbcs);
return rc;
#endif
}
/*
** Wrapper around the chdir() system call.
** If bChroot=1, do a chroot to this dir as well
** (UNIX only)
*/
int file_chdir(const char *zChDir, int bChroot){
#ifdef _WIN32
return win32_chdir(zChDir, bChroot);
#else
char *zPath = fossil_utf8_to_filename(zChDir);
int rc = chdir(zPath);
if( !rc && bChroot ){
rc = chroot(zPath);
if( !rc ) rc = chdir("/");
}
fossil_filename_free(zPath);
return rc;
#endif
}
/*
** Find an unused filename similar to zBase with zSuffix appended.
**
** Make the name relative to the working directory if relFlag is true.
**
|
| ︙ | ︙ | |||
418 419 420 421 422 423 424 425 426 427 428 |
}
/*
** Set the mtime for a file.
*/
void file_set_mtime(const char *zFilename, i64 newMTime){
#if !defined(_WIN32)
struct timeval tv[2];
memset(tv, 0, sizeof(tv[0])*2);
tv[0].tv_sec = newMTime;
tv[1].tv_sec = newMTime;
| > | | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
}
/*
** Set the mtime for a file.
*/
void file_set_mtime(const char *zFilename, i64 newMTime){
#if !defined(_WIN32)
char *zMbcs;
struct timeval tv[2];
memset(tv, 0, sizeof(tv[0])*2);
tv[0].tv_sec = newMTime;
tv[1].tv_sec = newMTime;
zMbcs = fossil_utf8_to_filename(zFilename);
utimes(zMbcs, tv);
#else
struct _utimbuf tb;
wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
tb.actime = newMTime;
tb.modtime = newMTime;
_wutime(zMbcs, &tb);
|
| ︙ | ︙ | |||
459 460 461 462 463 464 465 466 |
iMTime = file_wd_mtime(zFile);
zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
}
/*
** Delete a file.
*/
| > > | > | | > | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
iMTime = file_wd_mtime(zFile);
zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
}
/*
** Delete a file.
**
** Returns zero upon success.
*/
int file_delete(const char *zFilename){
int rc;
#ifdef _WIN32
wchar_t *z = fossil_utf8_to_filename(zFilename);
rc = _wunlink(z);
#else
char *z = fossil_utf8_to_filename(zFilename);
rc = unlink(zFilename);
#endif
fossil_filename_free(z);
return rc;
}
/*
** Create the directory named in the argument, if it does not already
** exist. If forceFlag is 1, delete any prior non-directory object
** with the same name.
**
|
| ︙ | ︙ | |||
491 492 493 494 495 496 497 498 499 500 501 502 503 504 |
if( rc!=1 ){
#if defined(_WIN32)
wchar_t *zMbcs = fossil_utf8_to_filename(zName);
rc = _wmkdir(zMbcs);
#else
char *zMbcs = fossil_utf8_to_filename(zName);
rc = mkdir(zName, 0755);
#endif
fossil_filename_free(zMbcs);
return rc;
}
return 0;
}
| > > > > > > > > > > > > > > > > > > > > > > > | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
if( rc!=1 ){
#if defined(_WIN32)
wchar_t *zMbcs = fossil_utf8_to_filename(zName);
rc = _wmkdir(zMbcs);
#else
char *zMbcs = fossil_utf8_to_filename(zName);
rc = mkdir(zName, 0755);
#endif
fossil_filename_free(zMbcs);
return rc;
}
return 0;
}
/*
** Removes the directory named in the argument, if it exists. The directory
** must be empty and cannot be the current directory or the root directory.
**
** Returns zero upon success.
*/
int file_rmdir(const char *zName){
int rc = file_wd_isdir(zName);
if( rc==2 ) return 1; /* cannot remove normal file */
if( rc==1 ){
#if defined(_WIN32)
wchar_t *zMbcs = fossil_utf8_to_filename(zName);
rc = _wrmdir(zMbcs);
#else
char *zMbcs = fossil_utf8_to_filename(zName);
rc = rmdir(zName);
#endif
fossil_filename_free(zMbcs);
return rc;
}
return 0;
}
|
| ︙ | ︙ | |||
661 662 663 664 665 666 667 |
i += 2;
continue;
}
}
if( j>=0 ) z[j] = z[i];
j++;
}
| | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 |
i += 2;
continue;
}
}
if( j>=0 ) z[j] = z[i];
j++;
}
if( j==0 ) z[j++] = '/';
z[j] = 0;
return j;
}
/*
** COMMAND: test-simplify-name
**
|
| ︙ | ︙ | |||
694 695 696 697 698 699 700 |
**
** On windows, the name is converted from unicode to UTF8 and all '\\'
** characters are converted to '/'. No conversions are needed on
** unix.
*/
void file_getcwd(char *zBuf, int nBuf){
#ifdef _WIN32
| < < < < < < < < < < < < < | < | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 |
**
** On windows, the name is converted from unicode to UTF8 and all '\\'
** characters are converted to '/'. No conversions are needed on
** unix.
*/
void file_getcwd(char *zBuf, int nBuf){
#ifdef _WIN32
win32_getcwd(zBuf, nBuf);
#else
if( getcwd(zBuf, nBuf-1)==0 ){
if( errno==ERANGE ){
fossil_fatal("pwd too big: max %d\n", nBuf-1);
}else{
fossil_fatal("cannot find current working directory; %s",
strerror(errno));
|
| ︙ | ︙ | |||
749 750 751 752 753 754 755 756 757 758 |
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
** If the slash parameter is non-zero, the trailing slash, if any,
** is retained.
*/
void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
if( file_is_absolute_path(zOrigName) ){
#if defined(_WIN32) || defined(__CYGWIN__)
char *zOut;
| > > > > > > > > > > > > > > > > > > < < < < | < < < < < < < < < < | < < < > | | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 |
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
** If the slash parameter is non-zero, the trailing slash, if any,
** is retained.
*/
void file_canonical_name(const char *zOrigName, Blob *pOut, int slash){
blob_zero(pOut);
if( file_is_absolute_path(zOrigName) ){
blob_appendf(pOut, "%/", zOrigName);
}else{
char zPwd[2000];
file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
if( zPwd[0]=='/' && strlen(zPwd)==1 ){
/* when on '/', don't add an extra '/' */
if( zOrigName[0]=='.' && strlen(zOrigName)==1 ){
/* '.' when on '/' mean '/' */
blob_appendf(pOut, "%/", zPwd);
}else{
blob_appendf(pOut, "%/%/", zPwd, zOrigName);
}
}else{
blob_appendf(pOut, "%//%/", zPwd, zOrigName);
}
}
#if defined(_WIN32) || defined(__CYGWIN__)
{
char *zOut;
/*
** On Windows/cygwin, normalize the drive letter to upper case.
*/
zOut = blob_str(pOut);
if( fossil_islower(zOut[0]) && zOut[1]==':' && zOut[2]=='/' ){
zOut[0] = fossil_toupper(zOut[0]);
}
}
#endif
blob_resize(pOut, file_simplify_name(blob_buffer(pOut),
blob_size(pOut), slash));
}
/*
** COMMAND: test-canonical-name
** Usage: %fossil test-canonical-name FILENAME...
**
** Test the operation of the canonical name generator.
** Also test Fossil's ability to measure attributes of a file.
*/
void cmd_test_canonical_name(void){
int i;
Blob x;
int slashFlag = find_option("slash",0,0)!=0;
blob_zero(&x);
for(i=2; i<g.argc; i++){
char zBuf[100];
const char *zName = g.argv[i];
file_canonical_name(zName, &x, slashFlag);
fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x));
blob_reset(&x);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_wd_size(zName));
fossil_print(" file_size = %s\n", zBuf);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_wd_mtime(zName));
fossil_print(" file_mtime = %s\n", zBuf);
fossil_print(" file_isfile = %d\n", file_wd_isfile(zName));
|
| ︙ | ︙ | |||
874 875 876 877 878 879 880 |
i = 1;
#if defined(_WIN32) || defined(__CYGWIN__)
while( zPath[i] && fossil_tolower(zPwd[i])==fossil_tolower(zPath[i]) ) i++;
#else
while( zPath[i] && zPwd[i]==zPath[i] ) i++;
#endif
if( zPath[i]==0 ){
| | | | > > > > > > > > | > > | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 |
i = 1;
#if defined(_WIN32) || defined(__CYGWIN__)
while( zPath[i] && fossil_tolower(zPwd[i])==fossil_tolower(zPath[i]) ) i++;
#else
while( zPath[i] && zPwd[i]==zPath[i] ) i++;
#endif
if( zPath[i]==0 ){
memcpy(&tmp, pOut, sizeof(tmp));
if( zPwd[i]==0 ){
blob_set(pOut, ".");
}else{
blob_set(pOut, "..");
for(j=i+1; zPwd[j]; j++){
if( zPwd[j]=='/' ){
blob_append(pOut, "/..", 3);
}
}
}
if( slash && i>0 && zPath[strlen(zPath)-1]=='/'){
blob_append(pOut, "/", 1);
}
blob_reset(&tmp);
return;
}
if( zPwd[i]==0 && zPath[i]=='/' ){
memcpy(&tmp, pOut, sizeof(tmp));
blob_set(pOut, "./");
blob_append(pOut, &zPath[i+1], -1);
blob_reset(&tmp);
return;
}
while( zPath[i-1]!='/' ){ i--; }
if( zPwd[0]=='/' && strlen(zPwd)==1 ){
/* If on '/', don't go to higher level */
blob_zero(&tmp);
}else{
blob_set(&tmp, "../");
}
for(j=i; zPwd[j]; j++){
if( zPwd[j]=='/' ){
blob_append(&tmp, "../", 3);
}
}
blob_append(&tmp, &zPath[i], -1);
blob_reset(pOut);
memcpy(pOut, &tmp, sizeof(tmp));
}
}
/*
** COMMAND: test-relative-name
**
** Test the operation of the relative name generator.
*/
void cmd_test_relative_name(void){
int i;
Blob x;
int slashFlag = find_option("slash",0,0)!=0;
blob_zero(&x);
for(i=2; i<g.argc; i++){
file_relative_name(g.argv[i], &x, slashFlag);
fossil_print("%s\n", blob_buffer(&x));
blob_reset(&x);
}
}
/*
** Compute a pathname for a file relative to the root of the local
|
| ︙ | ︙ | |||
956 957 958 959 960 961 962 |
if( filenames_are_case_sensitive() ){
xCmp = fossil_strncmp;
}else{
xCmp = fossil_strnicmp;
}
/* Special case. zOrigName refers to g.zLocalRoot directory. */
| | > | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 |
if( filenames_are_case_sensitive() ){
xCmp = fossil_strncmp;
}else{
xCmp = fossil_strnicmp;
}
/* Special case. zOrigName refers to g.zLocalRoot directory. */
if( (nFull==nLocalRoot-1 && xCmp(zLocalRoot, zFull, nFull)==0)
|| (nFull==1 && zFull[0]=='/' && nLocalRoot==1 && zLocalRoot[0]=='/') ){
blob_append(pOut, ".", 1);
blob_reset(&localRoot);
blob_reset(&full);
return 1;
}
if( nFull<=nLocalRoot || xCmp(zLocalRoot, zFull, nLocalRoot) ){
|
| ︙ | ︙ | |||
1136 1137 1138 1139 1140 1141 1142 |
blob_read_from_file(&onDisk, zName);
}
rc = blob_compare(&onDisk, pContent);
blob_reset(&onDisk);
return rc==0;
}
| < < < < < < < < < < < < < < < < | 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
blob_read_from_file(&onDisk, zName);
}
rc = blob_compare(&onDisk, pContent);
blob_reset(&onDisk);
return rc==0;
}
/*
** Return the value of an environment variable as UTF8.
** Use fossil_filename_free() to release resources.
*/
char *fossil_getenv(const char *zName){
#ifdef _WIN32
wchar_t *uName = fossil_utf8_to_unicode(zName);
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
41 42 43 44 45 46 47 | ** to stdout. The -p mode is another form of the "cat" command. ** ** Options: ** -b|--brief display a brief (one line / revision) summary ** --case-sensitive B Enable or disable case-sensitive filenames. B is a ** boolean: "yes", "no", "true", "false", etc. ** -l|--log select log mode (the default) | | > > | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
** to stdout. The -p mode is another form of the "cat" command.
**
** Options:
** -b|--brief display a brief (one line / revision) summary
** --case-sensitive B Enable or disable case-sensitive filenames. B is a
** boolean: "yes", "no", "true", "false", etc.
** -l|--log select log mode (the default)
** -n|--limit N display the first N changes. N=0 means no limit.
** --offset P skip P changes
** -p|--print select print mode
** -r|--revision R print the given revision (or ckout, if none is given)
** to stdout (only in print mode)
** -s|--status select status mode (print a status indicator for FILE)
** -W|--width <num> With of lines (default 79). Must be >22 or 0
** (= no limit, resulting in a single line per entry).
**
** See also: artifact, cat, descendants, info, leaves
*/
void finfo_cmd(void){
capture_case_sensitive_option();
db_must_be_within_tree();
if( find_option("status","s",0) ){
Stmt q;
Blob line;
Blob fname;
int vid;
if( g.argc!=3 ) usage("-s|--status FILENAME");
vid = db_lget_int("checkout", 0);
if( vid==0 ){
fossil_fatal("no checkout to finfo files in");
}
vfile_check_signature(vid, CKSIG_ENOTFILE);
file_tree_name(g.argv[2], &fname, 1);
db_prepare(&q,
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
" FROM vfile WHERE vfile.pathname=%B %s",
&fname, filename_collation());
|
| ︙ | ︙ | |||
132 133 134 135 136 137 138 139 |
}else{
Blob line;
Stmt q;
Blob fname;
int rid;
const char *zFilename;
const char *zLimit;
const char *zOffset;
| > | > > > > > | | > | | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
}else{
Blob line;
Stmt q;
Blob fname;
int rid;
const char *zFilename;
const char *zLimit;
const char *zWidth;
const char *zOffset;
int iLimit, iOffset, iBrief, iWidth;
if( find_option("log","l",0) ){
/* this is the default, no-op */
}
zLimit = find_option("limit","n",1);
zWidth = find_option("width","W",1);
iLimit = zLimit ? atoi(zLimit) : -1;
iWidth = zWidth ? atoi(zWidth) : 79;
zOffset = find_option("offset",0,1);
iOffset = zOffset ? atoi(zOffset) : 0;
iBrief = (find_option("brief","b",0) == 0);
if( (iWidth!=0) && (iWidth<=22) ){
fossil_fatal("--width|-W value must be >22 or 0");
}
if( g.argc!=3 ){
usage("?-l|--log? ?-b|--brief? FILENAME");
}
file_tree_name(g.argv[2], &fname, 1);
rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
&fname, filename_collation());
if( rid==0 ){
fossil_fatal("no history for file: %b", &fname);
}
zFilename = blob_str(&fname);
db_prepare(&q,
"SELECT b.uuid, ci.uuid, date(event.mtime%s),"
" coalesce(event.ecomment, event.comment),"
" coalesce(event.euser, event.user),"
" (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
" AND tagxref.rid=mlink.mid)" /* Tags */
" FROM mlink, blob b, event, blob ci, filename"
" WHERE filename.name=%Q %s"
" AND mlink.fnid=filename.fnid"
" AND b.rid=mlink.fid"
" AND event.objid=mlink.mid"
" AND event.objid=ci.rid"
" ORDER BY event.mtime DESC LIMIT %d OFFSET %d",
timeline_utc(), TAG_BRANCH, zFilename, filename_collation(),
iLimit, iOffset
);
blob_zero(&line);
if( iBrief ){
fossil_print("History of %s\n", blob_str(&fname));
}
while( db_step(&q)==SQLITE_ROW ){
const char *zFileUuid = db_column_text(&q, 0);
const char *zCiUuid = db_column_text(&q,1);
const char *zDate = db_column_text(&q, 2);
const char *zCom = db_column_text(&q, 3);
const char *zUser = db_column_text(&q, 4);
const char *zBr = db_column_text(&q, 5);
char *zOut;
if( zBr==0 ) zBr = "trunk";
if( iBrief ){
fossil_print("%s ", zDate);
zOut = sqlite3_mprintf(
"[%.10s] %s (user: %s, artifact: [%.10s], branch: %s)",
zCiUuid, zCom, zUser, zFileUuid, zBr);
comment_print(zOut, 11, iWidth);
sqlite3_free(zOut);
}else{
blob_reset(&line);
blob_appendf(&line, "%.10s ", zCiUuid);
blob_appendf(&line, "%.10s ", zDate);
blob_appendf(&line, "%8.8s ", zUser);
blob_appendf(&line, "%8.8s ", zBr);
blob_appendf(&line,"%-39.39s", zCom );
comment_print(blob_str(&line), 0, iWidth);
}
}
db_finalize(&q);
blob_reset(&fname);
}
}
|
| ︙ | ︙ | |||
284 285 286 287 288 289 290 |
style_header("File History");
login_anonymous_available();
url_initialize(&url, "finfo");
if( brBg ) url_add_parameter(&url, "brbg", 0);
if( uBg ) url_add_parameter(&url, "ubg", 0);
baseCheckin = name_to_rid_www("ci");
if( baseCheckin ) firstChngOnly = 1;
| | | | | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
style_header("File History");
login_anonymous_available();
url_initialize(&url, "finfo");
if( brBg ) url_add_parameter(&url, "brbg", 0);
if( uBg ) url_add_parameter(&url, "ubg", 0);
baseCheckin = name_to_rid_www("ci");
if( baseCheckin ) firstChngOnly = 1;
if( !firstChngOnly ) url_add_parameter(&url, "fco", "0");
zPrevDate[0] = 0;
zFilename = PD("name","");
url_add_parameter(&url, "name", zFilename);
blob_zero(&sql);
blob_appendf(&sql,
"SELECT"
" datetime(event.mtime%s)," /* Date of change */
" coalesce(event.ecomment, event.comment)," /* Check-in comment */
" coalesce(event.euser, event.user)," /* User who made chng */
" mlink.pid," /* Parent file rid */
" mlink.fid," /* File rid */
" (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
" (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */
" (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */
" event.bgcolor," /* Background color */
" (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
" AND tagxref.rid=mlink.mid)," /* Tags */
" mlink.mid," /* check-in ID */
" mlink.pfnid", /* Previous filename */
timeline_utc(), TAG_BRANCH
);
if( firstChngOnly ){
#if 0
blob_appendf(&sql, ", min(event.mtime)");
#else
blob_appendf(&sql,
", min(CASE (SELECT value FROM tagxref"
" WHERE tagtype>0 AND tagid=%d"
" AND tagxref.rid=mlink.mid)"
" WHEN 'trunk' THEN event.mtime-10000 ELSE event.mtime END)",
TAG_BRANCH);
#endif
}
|
| ︙ | ︙ | |||
352 353 354 355 356 357 358 |
if( baseCheckin==0 ){
if( firstChngOnly ){
style_submenu_element("Full", "Show all changes","%s",
url_render(&url, "fco", "0", 0, 0));
}else{
style_submenu_element("Simplified",
"Show only first use of a change","%s",
| | | | | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
if( baseCheckin==0 ){
if( firstChngOnly ){
style_submenu_element("Full", "Show all changes","%s",
url_render(&url, "fco", "0", 0, 0));
}else{
style_submenu_element("Simplified",
"Show only first use of a change","%s",
url_render(&url, "fco", 0, 0, 0));
}
}
db_prepare(&q, blob_str(&sql));
if( P("showsql")!=0 ){
@ <p>SQL: %h(blob_str(&sql))</p>
}
blob_reset(&sql);
blob_zero(&title);
if( baseCheckin ){
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
char *zLink = href("%R/info/%S", zUuid);
blob_appendf(&title, "Ancestors of file ");
hyperlinked_path(zFilename, &title, zUuid, "tree", "");
blob_appendf(&title, " from check-in %z%.10s</a>", zLink, zUuid);
fossil_free(zUuid);
}else{
blob_appendf(&title, "History of files named ");
hyperlinked_path(zFilename, &title, 0, "tree", "");
}
@ <h2>%b(&title)</h2>
blob_reset(&title);
pGraph = graph_init();
@ <div id="canvas" style="position:relative;width:1px;height:1px;"
@ onclick="clickOnGraph(event)"></div>
@ <table id="timelineTable" class="timelineTable">
|
| ︙ | ︙ | |||
453 454 455 456 457 458 459 460 461 462 |
}
hyperlink_to_uuid(zShortCkin);
@ %w(zCom) (user:
hyperlink_to_user(zUser, zDate, "");
@ branch: %h(zBr))
if( g.perm.Hyperlink && zUuid ){
const char *z = zFilename;
if( fpid ){
@ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zPUuid,zUuid))[diff]</a>
}
| > > > > > < < < > > | > > > | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
}
hyperlink_to_uuid(zShortCkin);
@ %w(zCom) (user:
hyperlink_to_user(zUser, zDate, "");
@ branch: %h(zBr))
if( g.perm.Hyperlink && zUuid ){
const char *z = zFilename;
@ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z))
@ [annotate]</a>
@ %z(href("%R/blame?checkin=%S&filename=%h",zCkin,z))
@ [blame]</a>
@ %z(href("%R/timeline?n=200&uf=%S",zUuid))[checkins using]</a>
if( fpid ){
@ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zPUuid,zUuid))[diff]</a>
}
}
if( fDebug & FINFO_DEBUG_MLINK ){
int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid);
int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid);
@ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid) sz=%d(sz)
if( srcid ){
@ srcid=%d(srcid)
}
}
@ </td></tr>
}
db_finalize(&q);
if( pGraph ){
graph_finish(pGraph, 0);
if( pGraph->nErr ){
|
| ︙ | ︙ |
Changes to src/glob.c.
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
**
** [...] Matches one character from the enclosed list of
** characters.
**
** [^...] Matches one character not in the enclosed list.
*/
int strglob(const char *zGlob, const char *z){
| < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
**
** [...] Matches one character from the enclosed list of
** characters.
**
** [^...] Matches one character not in the enclosed list.
*/
int strglob(const char *zGlob, const char *z){
return sqlite3_strglob(zGlob, z)==0;
}
/*
** Return true (non-zero) if zString matches any of the patterns in
** the Glob. The value returned is actually a 1-based index of the pattern
** that matched. Return 0 if none of the patterns match zString.
**
** A NULL glob matches nothing.
*/
int glob_match(Glob *pGlob, const char *zString){
int i;
if( pGlob==0 ) return 0;
for(i=0; i<pGlob->nPattern; i++){
if( sqlite3_strglob(pGlob->azPattern[i], zString)==0 ) return i+1;
}
return 0;
}
/*
** Free all memory associated with the given Glob object
*/
|
| ︙ | ︙ | |||
250 251 252 253 254 255 256 | ** ** Usage: %fossil test-glob PATTERN STRING... ** ** PATTERN is a comma- and whitespace-separated list of optionally ** quoted glob patterns. Show which of the STRINGs that follow match ** the PATTERN. ** | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
**
** Usage: %fossil test-glob PATTERN STRING...
**
** PATTERN is a comma- and whitespace-separated list of optionally
** quoted glob patterns. Show which of the STRINGs that follow match
** the PATTERN.
**
** If PATTERN begins with "@" the rest of the pattern is understood
** to be a setting name (such as binary-glob, crln-glob, or encoding-glob)
** and the value of that setting is used as the actually glob pattern.
*/
void glob_test_cmd(void){
Glob *pGlob;
int i;
char *zPattern;
|
| ︙ | ︙ |
Changes to src/graph.c.
| ︙ | ︙ | |||
196 197 198 199 200 201 202 | pRow->rid = rid; pRow->nParent = nParent; pRow->zBranch = persistBranchName(p, zBranch); if( zUuid==0 ) zUuid = ""; sqlite3_snprintf(sizeof(pRow->zUuid), pRow->zUuid, "%s", zUuid); pRow->isLeaf = isLeaf; memset(pRow->aiRiser, -1, sizeof(pRow->aiRiser)); | | | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
pRow->rid = rid;
pRow->nParent = nParent;
pRow->zBranch = persistBranchName(p, zBranch);
if( zUuid==0 ) zUuid = "";
sqlite3_snprintf(sizeof(pRow->zUuid), pRow->zUuid, "%s", zUuid);
pRow->isLeaf = isLeaf;
memset(pRow->aiRiser, -1, sizeof(pRow->aiRiser));
if( zBgClr==0 ) zBgClr = "";
pRow->zBgClr = persistBranchName(p, zBgClr);
memcpy(pRow->aParent, aParent, sizeof(aParent[0])*nParent);
if( p->pFirst==0 ){
p->pFirst = pRow;
}else{
p->pLast->pNext = pRow;
}
|
| ︙ | ︙ |
Changes to src/gzip.c.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 | ** ** This file contains code used to incrementally generate a GZIP compressed ** file. The GZIP format is described in RFC-1952. ** ** State information is stored in static variables, so this implementation ** can only be building up a single GZIP file at a time. */ #include <assert.h> #include <zlib.h> | > < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
**
** This file contains code used to incrementally generate a GZIP compressed
** file. The GZIP format is described in RFC-1952.
**
** State information is stored in static variables, so this implementation
** can only be building up a single GZIP file at a time.
*/
#include "config.h"
#include <assert.h>
#include <zlib.h>
#include "gzip.h"
/*
** State information for the GZIP file under construction.
*/
struct gzip_state {
int eState; /* 0: idle 1: header 2: compressing */
|
| ︙ | ︙ | |||
53 54 55 56 57 58 59 | char aHdr[10]; assert( gzip.eState==0 ); blob_zero(&gzip.out); aHdr[0] = 0x1f; aHdr[1] = 0x8b; aHdr[2] = 8; aHdr[3] = 0; | | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
char aHdr[10];
assert( gzip.eState==0 );
blob_zero(&gzip.out);
aHdr[0] = 0x1f;
aHdr[1] = 0x8b;
aHdr[2] = 8;
aHdr[3] = 0;
if( now==-1 ){
now = db_int64(0, "SELECT (julianday('now') - 2440587.5)*86400.0");
}
put32(&aHdr[4], now&0xffffffff);
aHdr[8] = 2;
aHdr[9] = 255;
blob_append(&gzip.out, aHdr, 10);
gzip.iCRC = 0;
gzip.eState = 1;
}
/*
** Add nIn bytes of content from pIn to the gzip file.
*/
#define GZIP_BUFSZ 100000
void gzip_step(const char *pIn, int nIn){
char *zOutBuf;
int nOut;
nOut = nIn + nIn/10 + 100;
if( nOut<100000 ) nOut = 100000;
zOutBuf = fossil_malloc(nOut);
gzip.stream.avail_in = nIn;
gzip.stream.next_in = (unsigned char*)pIn;
gzip.stream.avail_out = nOut;
gzip.stream.next_out = (unsigned char*)zOutBuf;
|
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
** Compress a file using gzip.
*/
void test_gzip_cmd(void){
Blob b;
char *zOut;
if( g.argc!=3 ) usage("FILENAME");
sqlite3_open(":memory:", &g.db);
| | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
** Compress a file using gzip.
*/
void test_gzip_cmd(void){
Blob b;
char *zOut;
if( g.argc!=3 ) usage("FILENAME");
sqlite3_open(":memory:", &g.db);
gzip_begin(-1);
blob_read_from_file(&b, g.argv[2]);
zOut = mprintf("%s.gz", g.argv[2]);
gzip_step(blob_buffer(&b), blob_size(&b));
blob_reset(&b);
gzip_finish(&b);
blob_write_to_file(&b, zOut);
blob_reset(&b);
fossil_free(zOut);
}
|
Changes to src/http.c.
| ︙ | ︙ | |||
108 109 110 111 112 113 114 |
char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]);
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
fossil_free(zCredentials);
}
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
| | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]);
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
fossil_free(zCredentials);
}
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
if( g.urlIsSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
if( g.fHttpTrace ){
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
}else{
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
}
blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
}
|
| ︙ | ︙ | |||
141 142 143 144 145 146 147 | int rc = 0; /* Result code */ int iHttpVersion; /* Which version of HTTP protocol server uses */ char *zLine; /* A single line of the reply header */ int i; /* Loop counter */ int isError = 0; /* True if the reply is an error message */ int isCompressed = 1; /* True if the reply is compressed */ | | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
int rc = 0; /* Result code */
int iHttpVersion; /* Which version of HTTP protocol server uses */
char *zLine; /* A single line of the reply header */
int i; /* Loop counter */
int isError = 0; /* True if the reply is an error message */
int isCompressed = 1; /* True if the reply is compressed */
if( transport_open(GLOBAL_URL()) ){
fossil_warning(transport_errmsg(GLOBAL_URL()));
return 1;
}
/* Construct the login card and prepare the complete payload */
blob_zero(&login);
if( useLogin ) http_build_login_card(pSend, &login);
if( g.fHttpTrace ){
|
| ︙ | ︙ | |||
188 189 190 191 192 193 194 |
transport_log(out);
free(zOutFile);
}
/*
** Send the request to the server.
*/
| | | | | > > > > > > > > > > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
transport_log(out);
free(zOutFile);
}
/*
** Send the request to the server.
*/
transport_send(GLOBAL_URL(), &hdr);
transport_send(GLOBAL_URL(), &payload);
blob_reset(&hdr);
blob_reset(&payload);
transport_flip(GLOBAL_URL());
/*
** Read and interpret the server reply
*/
closeConnection = 1;
iLength = -1;
while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
/* printf("[%s]\n", zLine); fflush(stdout); */
if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
if( rc!=200 && rc!=302 ){
int ii;
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
while( zLine[ii]==' ' ) ii++;
fossil_warning("server says: %s", &zLine[ii]);
goto write_err;
}
if( iHttpVersion==0 ){
closeConnection = 1;
}else{
closeConnection = 0;
}
}else if( g.urlIsSsh && fossil_strnicmp(zLine, "status:", 7)==0 ){
if( sscanf(zLine, "Status: %d", &rc)!=1 ) goto write_err;
if( rc!=200 && rc!=302 ){
int ii;
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
while( zLine[ii]==' ' ) ii++;
fossil_warning("server says: %s", &zLine[ii]);
goto write_err;
}
closeConnection = 0;
}else if( fossil_strnicmp(zLine, "content-length:", 15)==0 ){
for(i=15; fossil_isspace(zLine[i]); i++){}
iLength = atoi(&zLine[i]);
}else if( fossil_strnicmp(zLine, "connection:", 11)==0 ){
char c;
for(i=11; fossil_isspace(zLine[i]); i++){}
c = zLine[i];
|
| ︙ | ︙ | |||
242 243 244 245 246 247 248 |
j = strlen(zLine) - 1;
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
j -= 4;
zLine[j] = 0;
}
fossil_print("redirect to %s\n", &zLine[i]);
url_parse(&zLine[i], 0);
| | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
j = strlen(zLine) - 1;
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
j -= 4;
zLine[j] = 0;
}
fossil_print("redirect to %s\n", &zLine[i]);
url_parse(&zLine[i], 0);
transport_close(GLOBAL_URL());
return http_exchange(pSend, pReply, useLogin, maxRedirect);
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
isCompressed = 0;
}else if( fossil_strnicmp(&zLine[14],
"application/x-fossil-uncompressed", -1)==0 ){
isCompressed = 0;
|
| ︙ | ︙ | |||
269 270 271 272 273 274 275 | } /* ** Extract the reply payload that follows the header */ blob_zero(pReply); blob_resize(pReply, iLength); | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
}
/*
** Extract the reply payload that follows the header
*/
blob_zero(pReply);
blob_resize(pReply, iLength);
iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength);
blob_resize(pReply, iLength);
if( isError ){
char *z;
int i, j;
z = blob_str(pReply);
for(i=j=0; z[i]; i++, j++){
if( z[i]=='<' ){
|
| ︙ | ︙ | |||
293 294 295 296 297 298 299 300 | /* ** Close the connection to the server if appropriate. ** ** FIXME: There is some bug in the lower layers that prevents the ** connection from remaining open. The easiest fix for now is to ** simply close and restart the connection for each round-trip. */ | > > | | | | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
/*
** Close the connection to the server if appropriate.
**
** FIXME: There is some bug in the lower layers that prevents the
** connection from remaining open. The easiest fix for now is to
** simply close and restart the connection for each round-trip.
**
** For SSH we will leave the connection open.
*/
if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
if( closeConnection ){
transport_close(GLOBAL_URL());
}else{
transport_rewind(GLOBAL_URL());
}
return 0;
/*
** Jump to here if an error is seen.
*/
write_err:
transport_close(GLOBAL_URL());
return 1;
}
|
Changes to src/http_socket.c.
| ︙ | ︙ | |||
129 130 131 132 133 134 135 | ** by global variables that are set using url_parse(): ** ** g.urlName Name of the server. Ex: www.fossil-scm.org ** g.urlPort TCP/IP port to use. Ex: 80 ** ** Return the number of errors. */ | | | | | | | > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
** by global variables that are set using url_parse():
**
** g.urlName Name of the server. Ex: www.fossil-scm.org
** g.urlPort TCP/IP port to use. Ex: 80
**
** Return the number of errors.
*/
int socket_open(UrlData *pUrlData){
static struct sockaddr_in addr; /* The server address */
static int addrIsInit = 0; /* True once addr is initialized */
socket_global_init();
if( !addrIsInit ){
addr.sin_family = AF_INET;
addr.sin_port = htons(pUrlData->port);
*(int*)&addr.sin_addr = inet_addr(pUrlData->name);
if( -1 == *(int*)&addr.sin_addr ){
#ifndef FOSSIL_STATIC_LINK
struct hostent *pHost;
pHost = gethostbyname(pUrlData->name);
if( pHost!=0 ){
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
}else
#endif
{
socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
return 1;
}
}
addrIsInit = 1;
/* Set the Global.zIpAddr variable to the server we are talking to.
** This is used to populate the ipaddr column of the rcvfrom table,
** if any files are received from the server.
*/
g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
}
iSocket = socket(AF_INET,SOCK_STREAM,0);
if( iSocket<0 ){
socket_set_errmsg("cannot create a socket");
return 1;
}
if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
pUrlData->port);
socket_close();
return 1;
}
#if !defined(_WIN32)
signal(SIGPIPE, SIG_IGN);
#endif
return 0;
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
/*
** Receive content back from the open socket connection.
*/
size_t socket_receive(void *NotUsed, void *pContent, size_t N){
ssize_t got;
size_t total = 0;
while( N>0 ){
| > | > > > > > > > > > > > > > > > > > | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
/*
** Receive content back from the open socket connection.
*/
size_t socket_receive(void *NotUsed, void *pContent, size_t N){
ssize_t got;
size_t total = 0;
while( N>0 ){
/* WinXP fails for large values of N. So limit it to 64KiB. */
got = recv(iSocket, pContent, N>65536 ? 65536 : N, 0);
if( got<=0 ) break;
total += (size_t)got;
N -= (size_t)got;
pContent = (void*)&((char*)pContent)[got];
}
return total;
}
/*
** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
** populated. For hostnames with more than one IP (or if overridden in
** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
*/
void socket_ssh_resolve_addr(UrlData *pUrlData){
struct hostent *pHost; /* Used to make best effort for rcvfrom */
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
pHost = gethostbyname(pUrlData->name);
if( pHost!=0 ){
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
}
}
|
Changes to src/http_ssl.c.
| ︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 180 |
*/
void ssl_close(void){
if( iBio!=NULL ){
(void)BIO_reset(iBio);
BIO_free_all(iBio);
}
}
/*
** Open an SSL connection. The identify of the server is determined
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | < < < < | | | | < | | | | | > > > | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
*/
void ssl_close(void){
if( iBio!=NULL ){
(void)BIO_reset(iBio);
BIO_free_all(iBio);
}
}
/* See RFC2817 for details */
static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
int rc, httpVerMin;
char *bbuf;
Blob snd, reply;
int done=0,end=0;
blob_zero(&snd);
blob_appendf(&snd, "CONNECT %s:%d HTTP/1.1\r\n", pUrlData->hostname,
pUrlData->proxyOrigPort);
blob_appendf(&snd, "Host: %s:%d\r\n", pUrlData->hostname, pUrlData->proxyOrigPort);
if( pUrlData->proxyAuth ){
blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth);
}
blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1);
blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent());
blob_append(&snd, "\r\n", 2);
BIO_write(bio, blob_buffer(&snd), blob_size(&snd));
blob_reset(&snd);
/* Wait for end of reply */
blob_zero(&reply);
do{
int len;
char buf[256];
len = BIO_read(bio, buf, sizeof(buf));
blob_append(&reply, buf, len);
bbuf = blob_buffer(&reply);
len = blob_size(&reply);
while(end < len) {
if(bbuf[end] == '\r') {
if(len - end < 4) {
/* need more data */
break;
}
if(memcmp(&bbuf[end], "\r\n\r\n", 4) == 0) {
done = 1;
break;
}
}
end++;
}
}while(!done);
sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc);
blob_reset(&reply);
return rc;
}
/*
** Open an SSL connection. The identify of the server is determined
** by variables that are set using url_parse():
**
** pUrlData->name Name of the server. Ex: www.fossil-scm.org
** pUrlData->port TCP/IP port to use. Ex: 80
**
** Return the number of errors.
*/
int ssl_open(UrlData *pUrlData){
X509 *cert;
int hasSavedCertificate = 0;
int trusted = 0;
unsigned long e;
ssl_global_init();
/* Get certificate for current server from global config and
* (if we have it in config) add it to certificate store.
*/
cert = ssl_get_certificate(pUrlData, &trusted);
if ( cert!=NULL ){
X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
X509_free(cert);
hasSavedCertificate = 1;
}
if( pUrlData->useProxy ){
int rc;
BIO *sBio;
char *connStr;
connStr = mprintf("%s:%d", g.urlName, pUrlData->port);
sBio = BIO_new_connect(connStr);
free(connStr);
if( BIO_do_connect(sBio)<=0 ){
ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));
ssl_close();
return 1;
}
rc = establish_proxy_tunnel(pUrlData, sBio);
if( rc<200||rc>299 ){
ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc);
return 1;
}
pUrlData->path = pUrlData->proxyUrlPath;
iBio = BIO_new_ssl(sslCtx, 1);
BIO_push(iBio, sBio);
}else{
iBio = BIO_new_ssl_connect(sslCtx);
}
if( iBio==NULL ) {
ssl_set_errmsg("SSL: cannot open SSL (%s)",
ERR_reason_error_string(ERR_get_error()));
return 1;
}
BIO_get_ssl(iBio, &ssl);
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
if( !SSL_set_tlsext_host_name(ssl, (pUrlData->useProxy?pUrlData->hostname:pUrlData->name)) ){
fossil_warning("WARNING: failed to set server name indication (SNI), "
"continuing without it.\n");
}
#endif
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
if( !pUrlData->useProxy ){
BIO_set_conn_hostname(iBio, pUrlData->name);
BIO_set_conn_int_port(iBio, &pUrlData->port);
if( BIO_do_connect(iBio)<=0 ){
ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
pUrlData->name, pUrlData->port, ERR_reason_error_string(ERR_get_error()));
ssl_close();
return 1;
}
}
if( BIO_do_handshake(iBio)<=0 ) {
ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
pUrlData->useProxy?pUrlData->hostname:pUrlData->name,
pUrlData->useProxy?pUrlData->proxyOrigPort:pUrlData->port,
ERR_reason_error_string(ERR_get_error()));
ssl_close();
return 1;
}
/* Check if certificate is valid */
cert = SSL_get_peer_certificate(ssl);
if ( cert==NULL ){
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
"SHA1 fingerprint above\n"
" * use the global ssl-ca-location setting to specify your CA root\n"
" certificates list\n\n"
"If you are not expecting this message, answer no and "
"contact your server\nadministrator.\n\n"
"Accept certificate for host %s (a=always/y/N)? ",
X509_verify_cert_error_string(e), desc, warning,
| | | | | | | | | | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
"SHA1 fingerprint above\n"
" * use the global ssl-ca-location setting to specify your CA root\n"
" certificates list\n\n"
"If you are not expecting this message, answer no and "
"contact your server\nadministrator.\n\n"
"Accept certificate for host %s (a=always/y/N)? ",
X509_verify_cert_error_string(e), desc, warning,
pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
BIO_free(mem);
prompt_user(prompt, &ans);
free(prompt);
cReply = blob_str(&ans)[0];
blob_reset(&ans);
if( cReply!='y' && cReply!='Y' && cReply!='a' && cReply!='A') {
X509_free(cert);
ssl_set_errmsg("SSL certificate declined");
ssl_close();
return 1;
}
if( cReply=='a' || cReply=='A') {
if ( trusted==0 ){
prompt_user("\nSave this certificate as fully trusted (a=always/N)? ",
&ans);
cReply = blob_str(&ans)[0];
trusted = ( cReply=='a' || cReply=='A' );
blob_reset(&ans);
}
ssl_save_certificate(pUrlData, cert, trusted);
}
}
/* Set the Global.zIpAddr variable to the server we are talking to.
** This is used to populate the ipaddr column of the rcvfrom table,
** if any files are received from the server.
*/
{
/* IPv4 only code */
const unsigned char *ip = (const unsigned char *) BIO_get_conn_ip(iBio);
g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
}
X509_free(cert);
return 0;
}
/*
** Save certificate to global config.
*/
void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
BIO *mem;
char *zCert, *zHost;
mem = BIO_new(BIO_s_mem());
PEM_write_bio_X509(mem, cert);
BIO_write(mem, "", 1); /* nul-terminate mem buffer */
BIO_get_mem_data(mem, &zCert);
zHost = mprintf("cert:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
db_set(zHost, zCert, 1);
free(zHost);
zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
db_set_int(zHost, trusted, 1);
free(zHost);
BIO_free(mem);
}
/*
** Get certificate for g.urlName from global config.
** Return NULL if no certificate found.
*/
X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
char *zHost, *zCert;
BIO *mem;
X509 *cert;
zHost = mprintf("cert:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
zCert = db_get(zHost, NULL);
free(zHost);
if ( zCert==NULL )
return NULL;
if ( pTrusted!=0 ){
zHost = mprintf("trusted:%s", pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
*pTrusted = db_get_int(zHost, 0);
free(zHost);
}
mem = BIO_new(BIO_s_mem());
BIO_puts(mem, zCert);
cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
|
| ︙ | ︙ |
Changes to src/http_transport.c.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
i64 nSent; /* Number of bytes sent */
i64 nRcvd; /* Number of bytes received */
FILE *pFile; /* File I/O for FILE: */
char *zOutFile; /* Name of outbound file for FILE: */
char *zInFile; /* Name of inbound file for FILE: */
FILE *pLog; /* Log output here */
} transport = {
| | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | | | | | | > | | | | | | > < < < < < < < < < < < < < < | < < < < < < > > | | | < < < < < < < < | | < | > | < < < | > | > | > > | | | | | | < < < | < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < | | | | | | | | | | | | | | | | | | < < | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
i64 nSent; /* Number of bytes sent */
i64 nRcvd; /* Number of bytes received */
FILE *pFile; /* File I/O for FILE: */
char *zOutFile; /* Name of outbound file for FILE: */
char *zInFile; /* Name of inbound file for FILE: */
FILE *pLog; /* Log output here */
} transport = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
** Information about the connection to the SSH subprocess when
** using the ssh:// sync method.
*/
static int sshPid; /* Process id of ssh subprocess */
static int sshIn; /* From ssh subprocess to this process */
static FILE *sshOut; /* From this to ssh subprocess */
/*
** Return the current transport error message.
*/
const char *transport_errmsg(UrlData *pUrlData){
#ifdef FOSSIL_ENABLE_SSL
if( pUrlData->isHttps ){
return ssl_errmsg();
}
#endif
return socket_errmsg();
}
/*
** Retrieve send/receive counts from the transport layer. If "resetFlag"
** is true, then reset the counts.
*/
void transport_stats(i64 *pnSent, i64 *pnRcvd, int resetFlag){
if( pnSent ) *pnSent = transport.nSent;
if( pnRcvd ) *pnRcvd = transport.nRcvd;
if( resetFlag ){
transport.nSent = 0;
transport.nRcvd = 0;
}
}
/*
** Default SSH command
*/
#ifdef __MINGW32__
static char zDefaultSshCmd[] = "ssh -T";
#else
static char zDefaultSshCmd[] = "ssh -e none -T";
#endif
/*
** SSH initialization of the transport layer
*/
int transport_ssh_open(UrlData *pUrlData){
/* For SSH we need to create and run SSH fossil http
** to talk to the remote machine.
*/
const char *zSsh; /* The base SSH command */
Blob zCmd; /* The SSH command */
char *zHost; /* The host name to contact */
int n; /* Size of prefix string */
socket_ssh_resolve_addr(pUrlData);
zSsh = db_get("ssh-command", zDefaultSshCmd);
blob_init(&zCmd, zSsh, -1);
if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
#ifdef __MINGW32__
blob_appendf(&zCmd, " -P %d", pUrlData->port);
#else
blob_appendf(&zCmd, " -p %d", pUrlData->port);
#endif
}
if( g.fSshTrace ){
fossil_force_newline();
fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
}
if( pUrlData->user && pUrlData->user[0] ){
zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
}else{
zHost = mprintf("%s", pUrlData->name);
}
n = blob_size(&zCmd);
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, zHost);
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, mprintf("%s", pUrlData->fossil));
blob_append(&zCmd, " test-http", 10);
if( pUrlData->path && pUrlData->path[0] ){
blob_append(&zCmd, " ", 1);
shell_escape(&zCmd, mprintf("%s", pUrlData->path));
}
if( g.fSshTrace ){
fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
}
free(zHost);
popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
if( sshPid==0 ){
socket_set_errmsg("cannot start ssh tunnel using [%b]", &zCmd);
}
blob_reset(&zCmd);
return sshPid==0;
}
/*
** Open a connection to the server. The server is defined by the following
** global variables:
**
** g.urlName Name of the server. Ex: www.fossil-scm.org
** g.urlPort TCP/IP port. Ex: 80
** g.urlIsHttps Use TLS for the connection
**
** Return the number of errors.
*/
int transport_open(UrlData *pUrlData){
int rc = 0;
if( transport.isOpen==0 ){
if( pUrlData->isSsh ){
rc = transport_ssh_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
rc = ssl_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
#else
socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
rc = 1;
#endif
}else if( pUrlData->isFile ){
sqlite3_uint64 iRandId;
sqlite3_randomness(sizeof(iRandId), &iRandId);
transport.zOutFile = mprintf("%s-%llu-out.http",
g.zRepositoryName, iRandId);
transport.zInFile = mprintf("%s-%llu-in.http",
g.zRepositoryName, iRandId);
transport.pFile = fossil_fopen(transport.zOutFile, "wb");
if( transport.pFile==0 ){
fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
}
transport.isOpen = 1;
}else{
rc = socket_open(pUrlData);
if( rc==0 ) transport.isOpen = 1;
}
}
return rc;
}
/*
** Close the current connection
*/
void transport_close(UrlData *pUrlData){
if( transport.isOpen ){
free(transport.pBuf);
transport.pBuf = 0;
transport.nAlloc = 0;
transport.nUsed = 0;
transport.iCursor = 0;
if( transport.pLog ){
fclose(transport.pLog);
transport.pLog = 0;
}
if( pUrlData->isSsh ){
transport_ssh_close();
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
ssl_close();
#endif
}else if( pUrlData->isFile ){
if( transport.pFile ){
fclose(transport.pFile);
transport.pFile = 0;
}
file_delete(transport.zInFile);
file_delete(transport.zOutFile);
free(transport.zInFile);
free(transport.zOutFile);
}else{
socket_close();
}
transport.isOpen = 0;
}
}
/*
** Send content over the wire.
*/
void transport_send(UrlData *pUrlData, Blob *toSend){
char *z = blob_buffer(toSend);
int n = blob_size(toSend);
transport.nSent += n;
if( pUrlData->isSsh ){
fwrite(z, 1, n, sshOut);
fflush(sshOut);
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
int sent;
while( n>0 ){
sent = ssl_send(0, z, n);
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
if( sent<=0 ) break;
n -= sent;
}
#endif
}else if( pUrlData->isFile ){
fwrite(z, 1, n, transport.pFile);
}else{
int sent;
while( n>0 ){
sent = socket_send(0, z, n);
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
if( sent<=0 ) break;
n -= sent;
}
}
}
/*
** This routine is called when the outbound message is complete and
** it is time to being receiving a reply.
*/
void transport_flip(UrlData *pUrlData){
if( pUrlData->isFile ){
char *zCmd;
fclose(transport.pFile);
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
g.nameOfExe, pUrlData->name, transport.zOutFile, transport.zInFile
);
fossil_system(zCmd);
free(zCmd);
transport.pFile = fossil_fopen(transport.zInFile, "rb");
}
}
|
| ︙ | ︙ | |||
427 428 429 430 431 432 433 | transport.pLog = pLog; } /* ** This routine is called when the inbound message has been received ** and it is time to start sending again. */ | | | | | | | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
transport.pLog = pLog;
}
/*
** This routine is called when the inbound message has been received
** and it is time to start sending again.
*/
void transport_rewind(UrlData *pUrlData){
if( pUrlData->isFile ){
transport_close(pUrlData);
}
}
/*
** Read N bytes of content directly from the wire and write into
** the buffer.
*/
static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){
int got;
if( sshIn ){
int x;
int wanted = N;
got = 0;
while( wanted>0 ){
x = read(sshIn, &zBuf[got], wanted);
if( x<=0 ) break;
got += x;
wanted -= x;
}
}else if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
got = ssl_receive(0, zBuf, N);
#else
got = 0;
#endif
}else if( pUrlData->isFile ){
got = fread(zBuf, 1, N, transport.pFile);
}else{
got = socket_receive(0, zBuf, N);
}
/* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
if( transport.pLog ){
fwrite(zBuf, 1, got, transport.pLog);
fflush(transport.pLog);
}
return got;
}
/*
** Read N bytes of content from the wire and store in the supplied buffer.
** Return the number of bytes actually received.
*/
int transport_receive(UrlData *pUrlData, char *zBuf, int N){
int onHand; /* Bytes current held in the transport buffer */
int nByte = 0; /* Bytes of content received */
onHand = transport.nUsed - transport.iCursor;
if( g.fSshTrace){
printf("Reading %d bytes with %d on hand... ", N, onHand);
fflush(stdout);
|
| ︙ | ︙ | |||
496 497 498 499 500 501 502 |
transport.iCursor = 0;
}
N -= toMove;
zBuf += toMove;
nByte += toMove;
}
if( N>0 ){
| | | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
transport.iCursor = 0;
}
N -= toMove;
zBuf += toMove;
nByte += toMove;
}
if( N>0 ){
int got = transport_fetch(pUrlData, zBuf, N);
if( got>0 ){
nByte += got;
transport.nRcvd += got;
}
}
if( g.fSshTrace ) printf("Got %d bytes\n", nByte);
return nByte;
}
/*
** Load up to N new bytes of content into the transport.pBuf buffer.
** The buffer itself might be moved. And the transport.iCursor value
** might be reset to 0.
*/
static void transport_load_buffer(UrlData *pUrlData, int N){
int i, j;
if( transport.nAlloc==0 ){
transport.nAlloc = N;
transport.pBuf = fossil_malloc( N );
transport.iCursor = 0;
transport.nUsed = 0;
}
|
| ︙ | ︙ | |||
533 534 535 536 537 538 539 |
if( transport.nUsed + N > transport.nAlloc ){
char *pNew;
transport.nAlloc = transport.nUsed + N;
pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
transport.pBuf = pNew;
}
if( N>0 ){
| | | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
if( transport.nUsed + N > transport.nAlloc ){
char *pNew;
transport.nAlloc = transport.nUsed + N;
pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
transport.pBuf = pNew;
}
if( N>0 ){
i = transport_fetch(pUrlData, &transport.pBuf[transport.nUsed], N);
if( i>0 ){
transport.nRcvd += i;
transport.nUsed += i;
}
}
}
/*
** Fetch a single line of input where a line is all text up to the next
** \n character or until the end of input. Remove all trailing whitespace
** from the received line and zero-terminate the result. Return a pointer
** to the line.
**
** Each call to this routine potentially overwrites the returned buffer.
*/
char *transport_receive_line(UrlData *pUrlData){
int i;
int iStart;
i = iStart = transport.iCursor;
while(1){
if( i >= transport.nUsed ){
transport_load_buffer(pUrlData, pUrlData->isSsh ? 2 : 1000);
i -= iStart;
iStart = 0;
if( i >= transport.nUsed ){
transport.pBuf[i] = 0;
transport.iCursor = i;
break;
}
|
| ︙ | ︙ | |||
579 580 581 582 583 584 585 |
}
i++;
}
if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
return &transport.pBuf[iStart];
}
| > > > | | < < | < | > > > > > > > > > > > > | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
}
i++;
}
if( g.fSshTrace ) printf("Got line: [%s]\n", &transport.pBuf[iStart]);
return &transport.pBuf[iStart];
}
/*
** Global transport shutdown
*/
void transport_global_shutdown(UrlData *pUrlData){
if( pUrlData->isSsh ){
transport_ssh_close();
}
if( pUrlData->isHttps ){
#ifdef FOSSIL_ENABLE_SSL
ssl_global_shutdown();
#endif
}else{
socket_global_shutdown();
}
}
/*
** Close SSH transport.
*/
void transport_ssh_close(void){
if( sshPid ){
/*printf("Closing SSH tunnel: ");*/
fflush(stdout);
pclose2(sshIn, sshOut, sshPid);
sshPid = 0;
}
}
|
Changes to src/import.c.
| ︙ | ︙ | |||
417 418 419 420 421 422 423 |
){
gg.zFrom = gg.zPrevCheckin;
gg.zPrevCheckin = 0;
}
if( gg.zFrom==0 ) return;
rid = fast_uuid_to_rid(gg.zFrom);
if( rid==0 ) return;
| | | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
){
gg.zFrom = gg.zPrevCheckin;
gg.zPrevCheckin = 0;
}
if( gg.zFrom==0 ) return;
rid = fast_uuid_to_rid(gg.zFrom);
if( rid==0 ) return;
p = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( p==0 ) return;
manifest_file_rewind(p);
while( (pOld = manifest_file_next(p, 0))!=0 ){
pNew = import_add_file();
pNew->zName = fossil_strdup(pOld->zName);
pNew->isExe = pOld->zPerm && strstr(pOld->zPerm, "x")!=0;
pNew->isLink = pOld->zPerm && strstr(pOld->zPerm, "l")!=0;
|
| ︙ | ︙ | |||
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
if( memcmp(zLine, "mark ", 5)==0 ){
trim_newline(&zLine[5]);
fossil_free(gg.zMark);
gg.zMark = fossil_strdup(&zLine[5]);
}else
if( memcmp(zLine, "tagger ", 7)==0 || memcmp(zLine, "committer ",10)==0 ){
sqlite3_int64 secSince1970;
for(i=0; zLine[i] && zLine[i]!='<'; i++){}
if( zLine[i]==0 ) goto malformed_line;
z = &zLine[i+1];
for(i=i+1; zLine[i] && zLine[i]!='>'; i++){}
if( zLine[i]==0 ) goto malformed_line;
zLine[i] = 0;
fossil_free(gg.zUser);
gg.zUser = fossil_strdup(z);
secSince1970 = 0;
for(i=i+2; fossil_isdigit(zLine[i]); i++){
secSince1970 = secSince1970*10 + zLine[i] - '0';
}
fossil_free(gg.zDate);
gg.zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", secSince1970);
gg.zDate[10] = 'T';
}else
if( memcmp(zLine, "from ", 5)==0 ){
trim_newline(&zLine[5]);
fossil_free(gg.zFromMark);
| > > > > > > > > > > > > > > > | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
if( memcmp(zLine, "mark ", 5)==0 ){
trim_newline(&zLine[5]);
fossil_free(gg.zMark);
gg.zMark = fossil_strdup(&zLine[5]);
}else
if( memcmp(zLine, "tagger ", 7)==0 || memcmp(zLine, "committer ",10)==0 ){
sqlite3_int64 secSince1970;
int hastz;
char tzdir;
int tz;
for(i=0; zLine[i] && zLine[i]!='<'; i++){}
if( zLine[i]==0 ) goto malformed_line;
z = &zLine[i+1];
for(i=i+1; zLine[i] && zLine[i]!='>'; i++){}
if( zLine[i]==0 ) goto malformed_line;
zLine[i] = 0;
fossil_free(gg.zUser);
gg.zUser = fossil_strdup(z);
secSince1970 = 0;
/* We don't use sscanf here because of int64 portability issues. */
for(i=i+2; fossil_isdigit(zLine[i]); i++){
secSince1970 = secSince1970*10 + zLine[i] - '0';
}
/* Read in optional timezone modifier (we don't know if it's strictly
* optional, but better to be sure). */
tzdir = '+';
tz = 0;
hastz = sscanf(&zLine[i], " %c%d", &tzdir, &tz);
if ((hastz == 1) || (hastz > 2)) goto malformed_line;
secSince1970 += ((tzdir == '-') ? -1 : 1) *
((tz/100)*3600 + (tz%100)*60);
fossil_free(gg.zDate);
gg.zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", secSince1970);
gg.zDate[10] = 'T';
}else
if( memcmp(zLine, "from ", 5)==0 ){
trim_newline(&zLine[5]);
fossil_free(gg.zFromMark);
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
"SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d",
db_column_int(&q, 1)
);
fossil_print("%-13s %s %s\n", zType, zUuid, zDate);
free(zDate);
}
db_finalize(&q);
}
zTags = info_tags_of_checkin(rid, 0);
if( zTags && zTags[0] ){
fossil_print("tags: %s\n", zTags);
}
free(zTags);
if( zComment ){
| > > > > > > > > > > > > > > > > | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
"SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d",
db_column_int(&q, 1)
);
fossil_print("%-13s %s %s\n", zType, zUuid, zDate);
free(zDate);
}
db_finalize(&q);
}
if( zUuid ){
fossil_print("%-13s ", "leaf:");
if(is_a_leaf(rid)){
if(db_int(0, "SELECT 1 FROM tagxref AS tx"
" WHERE tx.rid=%d"
" AND tx.tagid=%d"
" AND tx.tagtype>0",
rid, TAG_CLOSED)){
fossil_print("%s\n", "closed");
}else{
fossil_print("%s\n", "open");
}
}else{
fossil_print("no\n");
}
}
zTags = info_tags_of_checkin(rid, 0);
if( zTags && zTags[0] ){
fossil_print("tags: %s\n", zTags);
}
free(zTags);
if( zComment ){
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 |
}
fossil_print("checkins: %d\n",
db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));
}else{
int rid;
rid = name_to_rid(g.argv[2]);
if( rid==0 ){
| | | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
}
fossil_print("checkins: %d\n",
db_int(-1, "SELECT count(*) FROM event WHERE type='ci' /*scan*/"));
}else{
int rid;
rid = name_to_rid(g.argv[2]);
if( rid==0 ){
fossil_fatal("no such object: %s\n", g.argv[2]);
}
show_common_info(rid, "uuid:", 1, 1);
}
}
/*
** Show information about all tags on a given node.
*/
static void showTags(int rid, const char *zNotGlob){
Stmt q;
int cnt = 0;
db_prepare(&q,
"SELECT tag.tagid, tagname, "
" (SELECT uuid FROM blob WHERE rid=tagxref.srcid AND rid!=%d),"
" value, datetime(tagxref.mtime%s), tagtype,"
" (SELECT uuid FROM blob WHERE rid=tagxref.origid AND rid!=%d)"
" FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid"
" WHERE tagxref.rid=%d AND tagname NOT GLOB '%q'"
" ORDER BY tagname /*sort*/", rid, timeline_utc(), rid, rid, zNotGlob
);
while( db_step(&q)==SQLITE_ROW ){
const char *zTagname = db_column_text(&q, 1);
const char *zSrcUuid = db_column_text(&q, 2);
const char *zValue = db_column_text(&q, 3);
const char *zDate = db_column_text(&q, 4);
int tagtype = db_column_int(&q, 5);
|
| ︙ | ︙ | |||
314 315 316 317 318 319 320 |
content_get(toid, &to);
}else{
blob_zero(&to);
}
blob_zero(&out);
if( diffFlags & DIFF_SIDEBYSIDE ){
text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
| < < | | < | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
content_get(toid, &to);
}else{
blob_zero(&to);
}
blob_zero(&out);
if( diffFlags & DIFF_SIDEBYSIDE ){
text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
@ %s(blob_str(&out))
}else{
text_diff(&from, &to, &out, pRe,
diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
@ <pre class="udiff">
@ %s(blob_str(&out))
@ </pre>
}
blob_reset(&from);
blob_reset(&to);
blob_reset(&out);
}
/*
** Write a line of web-page output that shows changes that have occurred
** to a file between two check-ins.
*/
static void append_file_change_line(
const char *zName, /* Name of the file that has changed */
|
| ︙ | ︙ | |||
357 358 359 360 361 362 363 |
}else if( fossil_strcmp(zNew, zOld)==0 ){
@ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
@ for %h(zName)</p>
}else{
@ <p>Changes to %h(zName)</p>
}
if( diffFlags ){
| < < | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
}else if( fossil_strcmp(zNew, zOld)==0 ){
@ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
@ for %h(zName)</p>
}else{
@ <p>Changes to %h(zName)</p>
}
if( diffFlags ){
append_diff(zOld, zNew, diffFlags, pRe);
}
}else{
if( zOld && zNew ){
if( fossil_strcmp(zOld, zNew)!=0 ){
@ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
@ from %z(href("%R/artifact/%s",zOld))[%S(zOld)]</a>
@ to %z(href("%R/artifact/%s",zNew))[%S(zNew)].</a>
|
| ︙ | ︙ | |||
383 384 385 386 387 388 389 |
@ <p>Deleted %z(href("%s/finfo?name=%T",g.zTop,zName))%h(zName)</a>
@ version %z(href("%R/artifact/%s",zOld))[%S(zOld)]</a>
}else{
@ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
@ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
}
if( diffFlags ){
| < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 |
@ <p>Deleted %z(href("%s/finfo?name=%T",g.zTop,zName))%h(zName)</a>
@ version %z(href("%R/artifact/%s",zOld))[%S(zOld)]</a>
}else{
@ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
@ version %z(href("%R/artifact/%s",zNew))[%S(zNew)]</a>
}
if( diffFlags ){
append_diff(zOld, zNew, diffFlags, pRe);
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
@
@ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a>
}
}
}
/*
** Generate javascript to enhance HTML diffs.
*/
void append_diff_javascript(int sideBySide){
if( !sideBySide ) return;
@ <script>(function(){
@ var SCROLL_LEN = 25;
@ function initSbsDiff(diff){
@ var txtCols = diff.querySelectorAll('.difftxtcol');
@ var txtPres = diff.querySelectorAll('.difftxtcol pre');
@ var width = Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth);
@ for(var i=0; i<2; i++){
@ txtPres[i].style.width = width + 'px';
@ txtCols[i].onscroll = function(e){
@ txtCols[0].scrollLeft = txtCols[1].scrollLeft = this.scrollLeft;
@ };
@ }
@ diff.tabIndex = 0;
@ diff.onkeydown = function(e){
@ e = e || event;
@ var len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
@ if( !len ) return;
@ txtCols[0].scrollLeft += len;
@ return false;
@ };
@ }
@
@ var diffs = document.querySelectorAll('.sbsdiffcols');
@ for(var i=0; i<diffs.length; i++){
@ initSbsDiff(diffs[i]);
@ }
@ }())</script>
}
/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/
u64 construct_diff_flags(int verboseFlag, int sideBySide){
u64 diffFlags;
|
| ︙ | ︙ | |||
443 444 445 446 447 448 449 |
** If the /ci page is used (instead of /vinfo or /info) then the
** default behavior is to show unified diffs of all file changes.
** With /vinfo and /info, only a list of the changed files are
** shown, without diffs. This behavior is inverted if the
** "show-version-diffs" setting is turned on.
*/
void ci_page(void){
| | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
** If the /ci page is used (instead of /vinfo or /info) then the
** default behavior is to show unified diffs of all file changes.
** With /vinfo and /info, only a list of the changed files are
** shown, without diffs. This behavior is inverted if the
** "show-version-diffs" setting is turned on.
*/
void ci_page(void){
Stmt q1, q2, q3;
int rid;
int isLeaf;
int verboseFlag; /* True to show diffs */
int sideBySide; /* True for side-by-side diffs */
u64 diffFlags; /* Flag parameter for text_diff() */
const char *zName; /* Name of the checkin to be displayed */
const char *zUuid; /* UUID of zName */
|
| ︙ | ︙ | |||
474 475 476 477 478 479 480 |
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zParent = db_text(0,
"SELECT uuid FROM plink, blob"
" WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim",
rid
);
isLeaf = is_a_leaf(rid);
| | | | | | | | > | | | | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 |
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zParent = db_text(0,
"SELECT uuid FROM plink, blob"
" WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim",
rid
);
isLeaf = is_a_leaf(rid);
db_prepare(&q1,
"SELECT uuid, datetime(mtime%s), user, comment,"
" datetime(omtime%s), mtime"
" FROM blob, event"
" WHERE blob.rid=%d"
" AND event.objid=%d",
timeline_utc(), timeline_utc(), rid, rid
);
sideBySide = !is_false(PD("sbs","1"));
if( db_step(&q1)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q1, 0);
char *zTitle = mprintf("Check-in [%.10s]", zUuid);
char *zEUser, *zEComment;
const char *zUser;
const char *zComment;
const char *zDate;
const char *zOrigDate;
style_header(zTitle);
login_anonymous_available();
free(zTitle);
zEUser = db_text(0,
"SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=%d AND tagtype>0",
TAG_USER, rid);
zEComment = db_text(0,
"SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
TAG_COMMENT, rid);
zUser = db_column_text(&q1, 2);
zComment = db_column_text(&q1, 3);
zDate = db_column_text(&q1,1);
zOrigDate = db_column_text(&q1, 4);
@ <div class="section">Overview</div>
@ <table class="label-value">
@ <tr><th>SHA1 Hash:</th><td>%s(zUuid)
if( g.perm.Setup ){
@ (Record ID: %d(rid))
}
@ </td></tr>
|
| ︙ | ︙ | |||
534 535 536 537 538 539 540 |
if( zEComment ){
@ <tr><th>Edited Comment:</th><td class="infoComment">%!w(zEComment)</td></tr>
@ <tr><th>Original Comment:</th><td class="infoComment">%!w(zComment)</td></tr>
}else{
@ <tr><th>Comment:</th><td class="infoComment">%!w(zComment)</td></tr>
}
if( g.perm.Admin ){
| | | | | | | > > > | > > > > > > > > > | | | | | | | | | | | | > > | | 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
if( zEComment ){
@ <tr><th>Edited Comment:</th><td class="infoComment">%!w(zEComment)</td></tr>
@ <tr><th>Original Comment:</th><td class="infoComment">%!w(zComment)</td></tr>
}else{
@ <tr><th>Comment:</th><td class="infoComment">%!w(zComment)</td></tr>
}
if( g.perm.Admin ){
db_prepare(&q2,
"SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
" FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
" WHERE blob.rid=%d",
rid
);
if( db_step(&q2)==SQLITE_ROW ){
const char *zIpAddr = db_column_text(&q2, 0);
const char *zUser = db_column_text(&q2, 1);
const char *zDate = db_column_text(&q2, 2);
if( zUser==0 || zUser[0]==0 ) zUser = "unknown";
@ <tr><th>Received From:</th>
@ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
}
db_finalize(&q2);
}
if( g.perm.Hyperlink ){
char *zPJ = db_get("short-project-name", 0);
Blob projName;
int jj;
if( zPJ==0 ) zPJ = db_get("project-name", "unnamed");
blob_zero(&projName);
blob_append(&projName, zPJ, -1);
blob_trim(&projName);
zPJ = blob_str(&projName);
for(jj=0; zPJ[jj]; jj++){
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
zPJ[jj] = '_';
}
}
@ <tr><th>Timelines:</th><td>
@ %z(href("%R/timeline?f=%S&unhide",zUuid))family</a>
if( zParent ){
@ | %z(href("%R/timeline?p=%S&unhide",zUuid))ancestors</a>
}
if( !isLeaf ){
@ | %z(href("%R/timeline?d=%S&unhide",zUuid))descendants</a>
}
if( zParent && !isLeaf ){
@ | %z(href("%R/timeline?dp=%S&unhide",zUuid))both</a>
}
db_prepare(&q2,"SELECT substr(tag.tagname,5) FROM tagxref, tag "
" WHERE rid=%d AND tagtype>0 "
" AND tag.tagid=tagxref.tagid "
" AND +tag.tagname GLOB 'sym-*'", rid);
while( db_step(&q2)==SQLITE_ROW ){
const char *zTagName = db_column_text(&q2, 0);
@ | %z(href("%R/timeline?r=%T&unhide",zTagName))%h(zTagName)</a>
}
db_finalize(&q2);
/* The Download: line */
if( g.perm.Zip ){
char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s",
zPJ, zUuid, zUuid);
@ </td></tr>
@ <tr><th>Downloads:</th><td>
@ %z(href("%s",zUrl))Tarball</a>
@ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zPJ,zUuid,zUuid))
@ ZIP archive</a>
fossil_free(zUrl);
}
@ </td></tr>
@ <tr><th>Other Links:</th>
@ <td>
@ %z(href("%R/tree?ci=%S",zUuid))files</a>
@ | %z(href("%R/fileage?name=%S",zUuid))file ages</a>
@ | %z(href("%R/tree?ci=%S&nofiles",zUuid))folders</a>
@ | %z(href("%R/artifact/%S",zUuid))manifest</a>
if( g.perm.Write ){
@ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
}
@ </td>
@ </tr>
blob_reset(&projName);
}
@ </table>
}else{
style_header("Check-in Information");
login_anonymous_available();
}
db_finalize(&q1);
showTags(rid, "");
if( zParent ){
@ <div class="section">Changes</div>
@ <div class="sectionmenu">
verboseFlag = g.zPath[0]!='c';
if( db_get_boolean("show-version-diffs", 0)==0 ){
verboseFlag = !verboseFlag;
|
| ︙ | ︙ | |||
649 650 651 652 653 654 655 |
}
@ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid))
@ patch</a></div>
if( pRe ){
@ <p><b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b></p>
}
| | | | | | | | | > | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 |
}
@ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid))
@ patch</a></div>
if( pRe ){
@ <p><b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b></p>
}
db_prepare(&q3,
"SELECT name,"
" mperm,"
" (SELECT uuid FROM blob WHERE rid=mlink.pid),"
" (SELECT uuid FROM blob WHERE rid=mlink.fid),"
" (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)"
" FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
" WHERE mlink.mid=%d"
" AND (mlink.fid>0"
" OR mlink.fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=%d))"
" ORDER BY name /*sort*/",
rid, rid
);
diffFlags = construct_diff_flags(verboseFlag, sideBySide);
while( db_step(&q3)==SQLITE_ROW ){
const char *zName = db_column_text(&q3,0);
int mperm = db_column_int(&q3, 1);
const char *zOld = db_column_text(&q3,2);
const char *zNew = db_column_text(&q3,3);
const char *zOldName = db_column_text(&q3, 4);
append_file_change_line(zName, zOld, zNew, zOldName, diffFlags,pRe,mperm);
}
db_finalize(&q3);
}
append_diff_javascript(sideBySide);
style_footer();
}
/*
** WEBPAGE: winfo
** URL: /winfo?name=UUID
**
|
| ︙ | ︙ | |||
694 695 696 697 698 699 700 |
Blob wiki;
int modPending;
const char *zModAction;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
rid = name_to_rid_www("name");
| | | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
Blob wiki;
int modPending;
const char *zModAction;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
rid = name_to_rid_www("name");
if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))==0 ){
style_header("Wiki Page Information Error");
@ No such object: %h(P("name"))
style_footer();
return;
}
if( g.perm.ModWiki && (zModAction = P("modaction"))!=0 ){
if( strcmp(zModAction,"delete")==0 ){
|
| ︙ | ︙ | |||
805 806 807 808 809 810 811 |
}
return 0;
}
if( !is_a_version(rid) ){
webpage_error("Artifact %s is not a checkin.", P(zParam));
return 0;
}
| | | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 |
}
return 0;
}
if( !is_a_version(rid) ){
webpage_error("Artifact %s is not a checkin.", P(zParam));
return 0;
}
return manifest_get(rid, CFTYPE_MANIFEST, 0);
}
/*
** Output a description of a check-in
*/
static void checkin_description(int rid){
Stmt q;
|
| ︙ | ︙ | |||
873 874 875 876 877 878 879 | /* ** WEBPAGE: vdiff ** URL: /vdiff ** ** Query parameters: ** | | | | | | > > < < | 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 |
/*
** WEBPAGE: vdiff
** URL: /vdiff
**
** Query parameters:
**
** from=TAG Left side of the comparison
** to=TAG Right side of the comparison
** branch=TAG Show all changes on a particular branch
** v=BOOLEAN Default true. If false, only list files that have changed
** sbs=BOOLEAN Side-by-side diff if true. Unified diff if false
** glob=STRING only diff files matching this glob
**
**
** Show all differences between two checkins.
*/
void vdiff_page(void){
int ridFrom, ridTo;
int verboseFlag = 0;
int sideBySide = 0;
u64 diffFlags = 0;
Manifest *pFrom, *pTo;
ManifestFile *pFileFrom, *pFileTo;
const char *zBranch;
const char *zFrom;
const char *zTo;
const char *zRe;
const char *zVerbose;
const char *zGlob;
ReCompiled *pRe = 0;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
login_anonymous_available();
zRe = P("regex");
if( zRe ) re_compile(&pRe, zRe, 0);
zBranch = P("branch");
if( zBranch && zBranch[0] ){
cgi_replace_parameter("from", mprintf("root:%s", zBranch));
cgi_replace_parameter("to", zBranch);
}
|
| ︙ | ︙ | |||
921 922 923 924 925 926 927 928 929 930 931 |
zVerbose = P("verbose");
}
if( !zVerbose ){
zVerbose = P("detail"); /* deprecated */
}
verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
if( !verboseFlag && sideBySide ) verboseFlag = 1;
zFrom = P("from");
zTo = P("to");
if( !sideBySide ){
style_submenu_element("Side-by-side Diff", "sbsdiff",
| > > > > > > > > > > | | > | | > | > > > > > | > > > > > > > > | | > > | | | > < > > | | | | > | | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 |
zVerbose = P("verbose");
}
if( !zVerbose ){
zVerbose = P("detail"); /* deprecated */
}
verboseFlag = (zVerbose!=0) && !is_false(zVerbose);
if( !verboseFlag && sideBySide ) verboseFlag = 1;
zGlob = P("glob");
zFrom = P("from");
zTo = P("to");
if(zGlob && !*zGlob){
zGlob = NULL;
}
if( sideBySide || verboseFlag ){
style_submenu_element("Hide Diff", "hidediff",
"%R/vdiff?from=%T&to=%T&sbs=0%s%T",
zFrom, zTo,
zGlob ? "&glob=" : "", zGlob ? zGlob : "");
}
if( !sideBySide ){
style_submenu_element("Side-by-side Diff", "sbsdiff",
"%R/vdiff?from=%T&to=%T&sbs=1%s%T",
zFrom, zTo,
zGlob ? "&glob=" : "", zGlob ? zGlob : "");
}
if( sideBySide || !verboseFlag ) {
style_submenu_element("Unified Diff", "udiff",
"%R/vdiff?from=%T&to=%T&sbs=0&v%s%T",
zFrom, zTo,
zGlob ? "&glob=" : "", zGlob ? zGlob : "");
}
style_submenu_element("Invert", "invert",
"%R/vdiff?from=%T&to=%T&sbs=%d%s%s%T", zTo, zFrom,
sideBySide, (verboseFlag && !sideBySide)?"&v":"",
zGlob ? "&glob=" : "", zGlob ? zGlob : "");
if( zGlob ){
style_submenu_element("Clear glob", "clearglob",
"%R/vdiff?from=%T&to=%T&sbs=%d%s", zFrom, zTo,
sideBySide, (verboseFlag && !sideBySide)?"&v":"");
}else{
style_submenu_element("Patch", "patch",
"%R/vpatch?from=%T&to=%T", zFrom, zTo);
}
style_header("Check-in Differences");
@ <h2>Difference From:</h2><blockquote>
checkin_description(ridFrom);
@ </blockquote><h2>To:</h2><blockquote>
checkin_description(ridTo);
@ </blockquote>
if( pRe ){
@ <p><b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b></p>
}
if( zGlob ){
@ <p><b>Only files matching the glob "%h(zGlob)" are shown.</b></p>
}
@<hr /><p>
manifest_file_rewind(pFrom);
pFileFrom = manifest_file_next(pFrom, 0);
manifest_file_rewind(pTo);
pFileTo = manifest_file_next(pTo, 0);
diffFlags = construct_diff_flags(verboseFlag, sideBySide);
while( pFileFrom || pFileTo ){
int cmp;
if( pFileFrom==0 ){
cmp = +1;
}else if( pFileTo==0 ){
cmp = -1;
}else{
cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
}
if( cmp<0 ){
if(!zGlob || strglob(zGlob, pFileFrom->zName)){
append_file_change_line(pFileFrom->zName,
pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0);
}
pFileFrom = manifest_file_next(pFrom, 0);
}else if( cmp>0 ){
if(!zGlob || strglob(zGlob, pFileTo->zName)){
append_file_change_line(pFileTo->zName,
0, pFileTo->zUuid, 0, diffFlags, pRe,
manifest_file_mperm(pFileTo));
}
pFileTo = manifest_file_next(pTo, 0);
}else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
pFileFrom = manifest_file_next(pFrom, 0);
pFileTo = manifest_file_next(pTo, 0);
}else{
if(!zGlob || (strglob(zGlob, pFileFrom->zName)
|| strglob(zGlob, pFileTo->zName))){
append_file_change_line(pFileFrom->zName,
pFileFrom->zUuid,
pFileTo->zUuid, 0, diffFlags, pRe,
manifest_file_mperm(pFileTo));
}
pFileFrom = manifest_file_next(pFrom, 0);
pFileTo = manifest_file_next(pTo, 0);
}
}
manifest_destroy(pFrom);
manifest_destroy(pTo);
append_diff_javascript(sideBySide);
style_footer();
}
#if INTERFACE
/*
** Possible return values from object_description()
*/
|
| ︙ | ︙ | |||
1086 1087 1088 1089 1090 1091 1092 1093 1094 |
hyperlink_to_uuid(zVers);
if( zBr && zBr[0] ){
@ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
}
@ - %!w(zCom) (user:
hyperlink_to_user(zUser,zDate,")");
if( g.perm.Hyperlink ){
@ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
@ [annotate]</a>
| > | > | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 |
hyperlink_to_uuid(zVers);
if( zBr && zBr[0] ){
@ on branch %z(href("%R/timeline?r=%T",zBr))%h(zBr)</a>
}
@ - %!w(zCom) (user:
hyperlink_to_user(zUser,zDate,")");
if( g.perm.Hyperlink ){
@ %z(href("%R/finfo?name=%T&ci=%S",zName,zVers))[ancestry]</a>
@ %z(href("%R/annotate?checkin=%S&filename=%T",zVers,zName))
@ [annotate]</a>
@ %z(href("%R/blame?checkin=%S&filename=%T",zVers,zName))
@ [blame]</a>
}
cnt++;
if( pDownloadName && blob_size(pDownloadName)==0 ){
blob_append(pDownloadName, zName, -1);
}
}
if( prevName ){
|
| ︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 |
** difference between the two artifacts. Show diff side by side unless sbs
** is 0. Generate plaintext if "patch" is present.
*/
void diff_page(void){
int v1, v2;
int isPatch;
int sideBySide;
| < < | | < > < < < < < < < < < < < < < | | | | | > > | > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | < | | < > > > > > > | 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 |
** difference between the two artifacts. Show diff side by side unless sbs
** is 0. Generate plaintext if "patch" is present.
*/
void diff_page(void){
int v1, v2;
int isPatch;
int sideBySide;
char *zV1;
char *zV2;
const char *zRe;
ReCompiled *pRe = 0;
u64 diffFlags;
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
v1 = name_to_rid_www("v1");
v2 = name_to_rid_www("v2");
if( v1==0 || v2==0 ) fossil_redirect_home();
zRe = P("regex");
if( zRe ) re_compile(&pRe, zRe, 0);
isPatch = P("patch")!=0;
if( isPatch ){
Blob c1, c2, *pOut;
pOut = cgi_output_blob();
cgi_set_content_type("text/plain");
diffFlags = 4;
content_get(v1, &c1);
content_get(v2, &c2);
text_diff(&c1, &c2, pOut, pRe, diffFlags);
blob_reset(&c1);
blob_reset(&c2);
return;
}
sideBySide = !is_false(PD("sbs","1"));
zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
diffFlags = construct_diff_flags(1, sideBySide) | DIFF_HTML;
style_header("Diff");
style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
g.zTop, P("v1"), P("v2"));
if( !sideBySide ){
style_submenu_element("Side-by-side Diff", "sbsdiff",
"%s/fdiff?v1=%T&v2=%T&sbs=1",
g.zTop, P("v1"), P("v2"));
}else{
style_submenu_element("Unified Diff", "udiff",
"%s/fdiff?v1=%T&v2=%T&sbs=0",
g.zTop, P("v1"), P("v2"));
}
if( P("smhdr")!=0 ){
@ <h2>Differences From Artifact
@ %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a> To
@ %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>.</h2>
}else{
@ <h2>Differences From
@ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]</a>:</h2>
object_description(v1, 0, 0);
@ <h2>To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]</a>:</h2>
object_description(v2, 0, 0);
}
if( pRe ){
@ <b>Only differences that match regular expression "%h(zRe)"
@ are shown.</b>
}
@ <hr />
append_diff(zV1, zV2, diffFlags, pRe);
append_diff_javascript(sideBySide);
style_footer();
}
/*
** WEBPAGE: raw
** URL: /raw?name=ARTIFACTID&m=TYPE
**
** Return the uninterpreted content of an artifact. Used primarily
** to view artifacts that are images.
*/
void rawartifact_page(void){
int rid;
char *zUuid;
const char *zMime;
Blob content;
rid = name_to_rid_www("name");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
if( fossil_strcmp(P("name"), zUuid)==0 ){
g.isConst = 1;
}
free(zUuid);
zMime = P("m");
if( zMime==0 ){
char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
" WHERE mlink.fid=%d"
" AND filename.fnid=mlink.fnid", rid);
if( !zFName ){
/* Look also at the attachment table */
|
| ︙ | ︙ | |||
1425 1426 1427 1428 1429 1430 1431 |
rid = name_to_rid_www("name");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
if( g.perm.Admin ){
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
| | | 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 |
rid = name_to_rid_www("name");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
if( g.perm.Admin ){
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
style_submenu_element("Unshun","Unshun", "%s/shun?accept=%s&sub=1#delshun",
g.zTop, zUuid);
}else{
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
g.zTop, zUuid);
}
}
style_header("Hex Artifact Content");
|
| ︙ | ︙ | |||
1467 1468 1469 1470 1471 1472 1473 |
ManifestFile *pFile;
zCI = P("ci");
if( zCI==0 ) return 0;
zFilename = P("filename");
if( zFilename==0 ) return 0;
cirid = name_to_rid_www("ci");
| | | 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 |
ManifestFile *pFile;
zCI = P("ci");
if( zCI==0 ) return 0;
zFilename = P("filename");
if( zFilename==0 ) return 0;
cirid = name_to_rid_www("ci");
pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0);
if( pManifest==0 ) return 0;
manifest_file_rewind(pManifest);
while( (pFile = manifest_file_next(pManifest,0))!=0 ){
if( fossil_strcmp(zFilename, pFile->zName)==0 ){
int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid);
manifest_destroy(pManifest);
return rid;
|
| ︙ | ︙ | |||
1575 1576 1577 1578 1579 1580 1581 |
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
if( g.perm.Admin ){
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
| | | | 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 |
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if( rid==0 ) fossil_redirect_home();
if( g.perm.Admin ){
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
style_submenu_element("Unshun","Unshun", "%s/shun?accept=%s&sub=1#accshun",
g.zTop, zUuid);
}else{
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
g.zTop, zUuid);
}
}
style_header("Artifact Content");
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( g.perm.Setup ){
@ <h2>Artifact %s(zUuid) (%d(rid)):</h2>
}else{
@ <h2>Artifact %s(zUuid):</h2>
}
blob_zero(&downloadName);
objType = object_description(rid, 0, &downloadName);
style_submenu_element("Download", "Download",
"%R/raw/%T?name=%s", blob_str(&downloadName), zUuid);
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
style_submenu_element("Checkins Using", "Checkins Using",
"%R/timeline?n=200&uf=%s",zUuid);
}
asText = P("txt")!=0;
zMime = mimetype_from_name(blob_str(&downloadName));
if( zMime ){
if( fossil_strcmp(zMime, "text/html")==0 ){
if( asText ){
style_submenu_element("Html", "Html",
|
| ︙ | ︙ | |||
1629 1630 1631 1632 1633 1634 1635 |
}
@ <hr />
content_get(rid, &content);
if( renderAsWiki ){
wiki_convert(&content, 0, 0);
}else if( renderAsHtml ){
@ <iframe src="%R/raw/%T(blob_str(&downloadName))?name=%s(zUuid)"
| | | > < | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 |
}
@ <hr />
content_get(rid, &content);
if( renderAsWiki ){
wiki_convert(&content, 0, 0);
}else if( renderAsHtml ){
@ <iframe src="%R/raw/%T(blob_str(&downloadName))?name=%s(zUuid)"
@ width="100%%" frameborder="0" marginwidth="0" marginheight="0"
@ sandbox="allow-same-origin"
@ onload="this.height = this.contentDocument.documentElement.scrollHeight;">
@ </iframe>
}else{
style_submenu_element("Hex","Hex", "%s/hexdump?name=%s", g.zTop, zUuid);
blob_to_utf8_no_bom(&content, 0);
zMime = mimetype_from_content(&content);
@ <blockquote>
if( zMime==0 ){
const char *zLn = P("ln");
const char *z;
z = blob_str(&content);
if( zLn ){
output_text_with_line_numbers(z, zLn);
}else{
@ <pre>
@ %h(z)
@ </pre>
|
| ︙ | ︙ | |||
1683 1684 1685 1686 1687 1688 1689 |
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(); return; }
rid = name_to_rid_www("name");
if( rid==0 ){ fossil_redirect_home(); }
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( g.perm.Admin ){
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
| | | | 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 |
login_check_credentials();
if( !g.perm.RdTkt ){ login_needed(); return; }
rid = name_to_rid_www("name");
if( rid==0 ){ fossil_redirect_home(); }
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( g.perm.Admin ){
if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){
style_submenu_element("Unshun","Unshun", "%s/shun?accept=%s&sub=1#accshun",
g.zTop, zUuid);
}else{
style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
g.zTop, zUuid);
}
}
pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTktChng==0 ) fossil_redirect_home();
zDate = db_text(0, "SELECT datetime(%.12f)", pTktChng->rDate);
memcpy(zTktName, pTktChng->zTicketUuid, UUID_SIZE+1);
if( g.perm.ModTkt && (zModAction = P("modaction"))!=0 ){
if( strcmp(zModAction,"delete")==0 ){
moderation_disapprove(rid);
cgi_redirectf("%R/tktview/%s", zTktName);
|
| ︙ | ︙ | |||
1732 1733 1734 1735 1736 1737 1738 |
}
modPending = moderation_pending(rid);
if( modPending ){
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
}
@ <tr><th>Ticket:</th>
@ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
| | | 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 |
}
modPending = moderation_pending(rid);
if( modPending ){
@ <span class="modpending">*** Awaiting Moderator Approval ***</span>
}
@ <tr><th>Ticket:</th>
@ <td>%z(href("%R/tktview/%s",zTktName))%s(zTktName)</a>
if( zTktTitle ){
@<br>%h(zTktTitle)
}
@</td></tr>
@ <tr><th>Date:</th><td>
hyperlink_to_date(zDate, "</td></tr>");
@ <tr><th>User:</th><td>
hyperlink_to_user(pTktChng->zUser, zDate, "</td></tr>");
|
| ︙ | ︙ | |||
2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 |
const char *zColor;
const char *zNewColor;
const char *zNewTagFlag;
const char *zNewTag;
const char *zNewBrFlag;
const char *zNewBranch;
const char *zCloseFlag;
int fPropagateColor; /* True if color propagates before edit */
int fNewPropagateColor; /* True if color propagates after edit */
const char *zChngTime = 0; /* Value of chngtime= query param, if any */
char *zUuid;
Blob comment;
Stmt q;
login_check_credentials();
if( !g.perm.Write ){ login_needed(); return; }
rid = name_to_typed_rid(P("r"), "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zComment = db_text(0, "SELECT coalesce(ecomment,comment)"
| > > > > | 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 |
const char *zColor;
const char *zNewColor;
const char *zNewTagFlag;
const char *zNewTag;
const char *zNewBrFlag;
const char *zNewBranch;
const char *zCloseFlag;
const char *zHideFlag;
int fPropagateColor; /* True if color propagates before edit */
int fNewPropagateColor; /* True if color propagates after edit */
int fHasHidden = 0; /* True if hidden tag already set */
int fHasClosed = 0; /* True if closed tag already set */
const char *zChngTime = 0; /* Value of chngtime= query param, if any */
char *zUuid;
Blob comment;
char *zBranchName = 0;
Stmt q;
login_check_credentials();
if( !g.perm.Write ){ login_needed(); return; }
rid = name_to_typed_rid(P("r"), "ci");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
zComment = db_text(0, "SELECT coalesce(ecomment,comment)"
|
| ︙ | ︙ | |||
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 |
rid, TAG_BGCOLOR)==2;
fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor;
zNewTagFlag = P("newtag") ? " checked" : "";
zNewTag = PDT("tagname","");
zNewBrFlag = P("newbr") ? " checked" : "";
zNewBranch = PDT("brname","");
zCloseFlag = P("close") ? " checked" : "";
if( P("apply") ){
Blob ctrl;
char *zNow;
int nChng = 0;
login_verify_csrf_secret();
blob_zero(&ctrl);
| > | 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 |
rid, TAG_BGCOLOR)==2;
fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor;
zNewTagFlag = P("newtag") ? " checked" : "";
zNewTag = PDT("tagname","");
zNewBrFlag = P("newbr") ? " checked" : "";
zNewBranch = PDT("brname","");
zCloseFlag = P("close") ? " checked" : "";
zHideFlag = P("hide") ? " checked" : "";
if( P("apply") ){
Blob ctrl;
char *zNow;
int nChng = 0;
login_verify_csrf_secret();
blob_zero(&ctrl);
|
| ︙ | ︙ | |||
2105 2106 2107 2108 2109 2110 2111 2112 |
char zLabel[30];
sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid);
if( P(zLabel) ){
db_multi_exec("REPLACE INTO newtags VALUES(%Q,'-',NULL)", zTag);
}
}
db_finalize(&q);
if( zCloseFlag[0] ){
| > > > | > | 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 |
char zLabel[30];
sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid);
if( P(zLabel) ){
db_multi_exec("REPLACE INTO newtags VALUES(%Q,'-',NULL)", zTag);
}
}
db_finalize(&q);
if( zHideFlag[0] ){
db_multi_exec("REPLACE INTO newtags VALUES('hidden','*',NULL)");
}
if( zCloseFlag[0] ){
db_multi_exec("REPLACE INTO newtags VALUES('closed','%s',NULL)",
is_a_leaf(rid)?"+":"*");
}
if( zNewTagFlag[0] && zNewTag[0] ){
db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','+',NULL)", zNewTag);
}
if( zNewBrFlag[0] && zNewBranch[0] ){
db_multi_exec(
"REPLACE INTO newtags "
|
| ︙ | ︙ | |||
2147 2148 2149 2150 2151 2152 2153 |
Blob cksum;
blob_appendf(&ctrl, "U %F\n", g.zLogin);
md5sum_blob(&ctrl, &cksum);
blob_appendf(&ctrl, "Z %b\n", &cksum);
db_begin_transaction();
g.markPrivate = content_is_private(rid);
nrid = content_put(&ctrl);
| | > > > > > > > > > > > > > > > > > > > > > | 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 |
Blob cksum;
blob_appendf(&ctrl, "U %F\n", g.zLogin);
md5sum_blob(&ctrl, &cksum);
blob_appendf(&ctrl, "Z %b\n", &cksum);
db_begin_transaction();
g.markPrivate = content_is_private(rid);
nrid = content_put(&ctrl);
manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS);
assert( blob_is_reset(&ctrl) );
db_end_transaction(0);
}
cgi_redirectf("ci?name=%s", zUuid);
}
blob_zero(&comment);
blob_append(&comment, zNewComment, -1);
zUuid[10] = 0;
style_header("Edit Check-in [%s]", zUuid);
/*
** chgcbn/chgbn: Handle change of (checkbox for) branch name in
** remaining of form.
*/
@ <script>
@ function chgcbn(checked, branch){
@ val = gebi('brname').value.trim();
@ if( !val || !checked ) val = branch;
@ if( checked ) gebi('brname').select();
@ gebi('hbranch').textContent = val;
@ cidbrid = document.getElementById('cbranch');
@ if( cidbrid ) cidbrid.textContent = val;
@ }
@ function chgbn(val, branch){
@ if( !val ) val = branch;
@ gebi('newbr').checked = (val!=branch);
@ gebi('hbranch').textContent = val;
@ cidbrid = document.getElementById('cbranch');
@ if( cidbrid ) cidbrid.textContent = val;
@ }
@ </script>
if( P("preview") ){
Blob suffix;
int nTag = 0;
@ <b>Preview:</b>
@ <blockquote>
@ <table border=0>
if( zNewColor && zNewColor[0] ){
|
| ︙ | ︙ | |||
2203 2204 2205 2206 2207 2208 2209 |
@ <p>Make changes to attributes of check-in
@ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
form_begin(0, "%R/ci_edit");
login_insert_csrf_secret();
@ <div><input type="hidden" name="r" value="%S(zUuid)" />
@ <table border="0" cellspacing="10">
| | | | | | | > > > | > > > > > > > > > > > > | | | > > > > > > | | > | > | > > > > > > > | | > | < < < < | | | | | | > > > > > > > > > | > > | 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 |
@ <p>Make changes to attributes of check-in
@ [%z(href("%R/ci/%s",zUuid))%s(zUuid)</a>]:</p>
form_begin(0, "%R/ci_edit");
login_insert_csrf_secret();
@ <div><input type="hidden" name="r" value="%S(zUuid)" />
@ <table border="0" cellspacing="10">
@ <tr><th align="right" valign="top">User:</th>
@ <td valign="top">
@ <input type="text" name="u" size="20" value="%h(zNewUser)" />
@ </td></tr>
@ <tr><th align="right" valign="top">Comment:</th>
@ <td valign="top">
@ <textarea name="c" rows="10" cols="80">%h(zNewComment)</textarea>
@ </td></tr>
@ <tr><th align="right" valign="top">Check-in Time:</th>
@ <td valign="top">
@ <input type="text" name="dt" size="20" value="%h(zNewDate)" />
@ </td></tr>
if( zChngTime ){
@ <tr><th align="right" valign="top">Timestamp of this change:</th>
@ <td valign="top">
@ <input type="text" name="chngtime" size="20" value="%h(zChngTime)" />
@ </td></tr>
}
@ <tr><th align="right" valign="top">Background Color:</th>
@ <td valign="top">
render_color_chooser(fNewPropagateColor, zNewColor, "pclr", "clr", "clrcust");
@ </td></tr>
@ <tr><th align="right" valign="top">Tags:</th>
@ <td valign="top">
@ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) />
@ Add the following new tag name to this check-in:</label>
@ <input type="text" style="width:15;" name="tagname" value="%h(zNewTag)"
@ onkeyup="gebi('newtag').checked=!!this.value" />
zBranchName = db_text(0, "SELECT value FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid"
" AND tagxref.tagid=%d", rid, TAG_BRANCH);
db_prepare(&q,
"SELECT tag.tagid, tagname, tagxref.value FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid"
" ORDER BY CASE WHEN tagname GLOB 'sym-*' THEN substr(tagname,5)"
" ELSE tagname END /*sort*/",
rid
);
while( db_step(&q)==SQLITE_ROW ){
int tagid = db_column_int(&q, 0);
const char *zTagName = db_column_text(&q, 1);
int isSpecialTag = fossil_strncmp(zTagName, "sym-", 4)!=0;
char zLabel[30];
if( tagid == TAG_CLOSED ){
fHasClosed = 1;
}else if( (tagid == TAG_COMMENT) || (tagid == TAG_BRANCH) ){
continue;
}else if( tagid==TAG_HIDDEN ){
fHasHidden = 1;
}else if( !isSpecialTag && zTagName &&
fossil_strcmp(&zTagName[4], zBranchName)==0){
continue;
}
sqlite3_snprintf(sizeof(zLabel), zLabel, "c%d", tagid);
@ <br /><label>
if( P(zLabel) ){
@ <input type="checkbox" name="c%d(tagid)" checked="checked" />
}else{
@ <input type="checkbox" name="c%d(tagid)" />
}
if( isSpecialTag ){
@ Cancel special tag <b>%h(zTagName)</b></label>
}else{
@ Cancel tag <b>%h(&zTagName[4])</b></label>
}
}
db_finalize(&q);
@ </td></tr>
if( !zBranchName ){
zBranchName = db_get("main-branch", "trunk");
}
if( !zNewBranch || !zNewBranch[0]){
zNewBranch = zBranchName;
}
@ <tr><th align="right" valign="top">Branching:</th>
@ <td valign="top">
@ <label><input id="newbr" type="checkbox" name="newbr"%s(zNewBrFlag)
@ onchange="chgcbn(this.checked,'%h(zBranchName)')" />
@ Make this check-in the start of a new branch named:</label>
@ <input id="brname" type="text" style="width:15;" name="brname"
@ value="%h(zNewBranch)"
@ onkeyup="chgbn(this.value.trim(),'%h(zBranchName)')" /></td></tr>
if( !fHasHidden ){
@ <tr><th align="right" valign="top">Branch Hiding:</th>
@ <td valign="top">
@ <label><input type="checkbox" id="hidebr" name="hide"%s(zHideFlag) />
@ Hide branch
@ <span style="font-weight:bold" id="hbranch">%h(zBranchName)</span>
@ from the timeline starting from this check-in</label>
@ </td></tr>
}
if( !fHasClosed ){
if( is_a_leaf(rid) ){
@ <tr><th align="right" valign="top">Leaf Closure:</th>
@ <td valign="top">
@ <label><input type="checkbox" name="close"%s(zCloseFlag) />
@ Mark this leaf as "closed" so that it no longer appears on the
@ "leaves" page and is no longer labeled as a "<b>Leaf</b>"</label>
@ </td></tr>
}else if( zBranchName ){
@ <tr><th align="right" valign="top">Branch Closure:</th>
@ <td valign="top">
@ <label><input type="checkbox" name="close"%s(zCloseFlag) />
@ Mark branch
@ <span style="font-weight:bold" id="cbranch">%h(zBranchName)</span>
@ as "closed" so that its leafs no longer appear on the "leaves" page
@ and are no longer labeled as a leaf "<b>Leaf</b>"</label>
@ </td></tr>
}
}
if( zBranchName ) fossil_free(zBranchName);
@ <tr><td colspan="2">
@ <input type="submit" name="preview" value="Preview" />
@ <input type="submit" name="apply" value="Apply Changes" />
@ <input type="submit" name="cancel" value="Cancel" />
@ </td></tr>
@ </table>
@ </div></form>
style_footer();
}
|
Changes to src/json.c.
| ︙ | ︙ | |||
265 266 267 268 269 270 271 | zStr = vmprintf(fmt,vargs); va_end(vargs); v = cson_value_new_string(zStr, strlen(zStr)); free(zStr); return v; } | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
zStr = vmprintf(fmt,vargs);
va_end(vargs);
v = cson_value_new_string(zStr, strlen(zStr));
free(zStr);
return v;
}
cson_value * json_new_int( i64 v ){
return cson_value_new_integer((cson_int_t)v);
}
/*
** Gets a POST/POST.payload/GET/COOKIE/ENV value. The returned memory
** is owned by the g.json object (one of its sub-objects). Returns
** NULL if no match is found.
|
| ︙ | ︙ | |||
985 986 987 988 989 990 991 |
FILE * inFile = NULL;
char const * jfile = find_option("json-input",NULL,1);
if(!jfile || !*jfile){
break;
}
inFile = (0==strcmp("-",jfile))
? stdin
| | | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 |
FILE * inFile = NULL;
char const * jfile = find_option("json-input",NULL,1);
if(!jfile || !*jfile){
break;
}
inFile = (0==strcmp("-",jfile))
? stdin
: fossil_fopen(jfile,"rb");
if(!inFile){
g.json.resultCode = FSL_JSON_E_FILE_OPEN_FAILED;
fossil_fatal("Could not open JSON file [%s].",jfile)
/* Does not return. */
;
}
cgi_parse_POST_JSON(inFile, 0);
|
| ︙ | ︙ | |||
1978 1979 1980 1981 1982 1983 1984 | SETBUF(jo, "projectCode"); cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME))); jv2 = cson_value_new_object(); jo2 = cson_value_get_object(jv2); cson_object_set(jo, "sqlite", jv2); sqlite3_snprintf(BufLen, zBuf, "%.19s [%.10s] (%s)", | | | 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 |
SETBUF(jo, "projectCode");
cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
jv2 = cson_value_new_object();
jo2 = cson_value_get_object(jv2);
cson_object_set(jo, "sqlite", jv2);
sqlite3_snprintf(BufLen, zBuf, "%.19s [%.10s] (%s)",
sqlite3_sourceid(), &sqlite3_sourceid()[20], sqlite3_libversion());
SETBUF(jo2, "version");
zDb = db_name("repository");
cson_object_set(jo2, "pageCount", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA %s.page_count", zDb)));
cson_object_set(jo2, "pageSize", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA %s.page_size", zDb)));
cson_object_set(jo2, "freeList", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA %s.freelist_count", zDb)));
sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA %s.encoding", zDb));
SETBUF(jo2, "encoding");
|
| ︙ | ︙ | |||
2003 2004 2005 2006 2007 2008 2009 | ** Creates a comma-separated list of command names ** taken from zPages. zPages must be an array of objects ** whose final entry MUST have a NULL name value or results ** are undefined. ** ** The list is appended to pOut. The number of items (not bytes) ** appended are returned. If filterByMode is non-0 then the result | | | 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 |
** Creates a comma-separated list of command names
** taken from zPages. zPages must be an array of objects
** whose final entry MUST have a NULL name value or results
** are undefined.
**
** The list is appended to pOut. The number of items (not bytes)
** appended are returned. If filterByMode is non-0 then the result
** list will contain only commands which are able to run in the
** current run mode (CLI vs. HTTP).
*/
static int json_pagedefs_to_string(JsonPageDef const * zPages,
Blob * pOut, int filterByMode){
int i = 0;
for( ; zPages->name; ++zPages, ++i ){
if(filterByMode){
|
| ︙ | ︙ |
Changes to src/json_artifact.c.
| ︙ | ︙ | |||
108 109 110 111 112 113 114 |
if( db_step(&q)==SQLITE_ROW ){
cson_object * o;
cson_value * tmpV = NULL;
const char *zUuid = db_column_text(&q, 0);
const char *zUser;
const char *zComment;
char * zEUser, * zEComment;
| | | | | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
if( db_step(&q)==SQLITE_ROW ){
cson_object * o;
cson_value * tmpV = NULL;
const char *zUuid = db_column_text(&q, 0);
const char *zUser;
const char *zComment;
char * zEUser, * zEComment;
i64 mtime, omtime;
v = cson_value_new_object();
o = cson_value_get_object(v);
#define SET(K,V) cson_object_set(o,(K), (V))
SET("type", eventTypeLabel );
SET("uuid",json_new_string(zUuid));
SET("isLeaf", cson_value_new_bool(is_a_leaf(rid)));
mtime = db_column_int64(&q,1);
SET("timestamp",json_new_int(mtime));
omtime = db_column_int64(&q,2);
if(omtime && (omtime!=mtime)){
SET("originTime",json_new_int(omtime));
}
zUser = db_column_text(&q,3);
zEUser = db_text(0,
"SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
TAG_USER, rid);
if(zEUser){
SET("user", json_new_string(zEUser));
if(0!=fossil_strcmp(zEUser,zUser)){
SET("originUser",json_new_string(zUser));
}
free(zEUser);
}else{
SET("user",json_new_string(zUser));
}
zComment = db_column_text(&q,4);
zEComment = db_text(0,
"SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
TAG_COMMENT, rid);
if(zEComment){
SET("comment",json_new_string(zEComment));
if(0 != fossil_strcmp(zEComment,zComment)){
SET("originComment", json_new_string(zComment));
}
free(zEComment);
}else{
SET("comment",json_new_string(zComment));
}
|
| ︙ | ︙ | |||
190 191 192 193 194 195 196 |
return NULL;
}
if(!eventTypeLabel){
eventTypeLabel = json_new_string("ticket");
json_gc_add("$EVENT_TYPE_LABEL(ticket)", eventTypeLabel);
}
| | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
return NULL;
}
if(!eventTypeLabel){
eventTypeLabel = json_new_string("ticket");
json_gc_add("$EVENT_TYPE_LABEL(ticket)", eventTypeLabel);
}
pTktChng = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTktChng==0 ){
g.json.resultCode = FSL_JSON_E_MANIFEST_READ_FAILED;
return NULL;
}
pay = cson_new_object();
cson_object_set(pay, "eventType", eventTypeLabel );
cson_object_set(pay, "uuid", json_new_string(pTktChng->zTicketUuid));
|
| ︙ | ︙ | |||
468 469 470 471 472 473 474 |
assert( 0 != g.json.resultCode );
goto veryend;
handle_entry:
pay = cson_new_object();
assert( (NULL != zType) && "Internal dispatching error." );
for( ; dispatcher->name; ++dispatcher ){
| | | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
assert( 0 != g.json.resultCode );
goto veryend;
handle_entry:
pay = cson_new_object();
assert( (NULL != zType) && "Internal dispatching error." );
for( ; dispatcher->name; ++dispatcher ){
if(0!=fossil_strcmp(dispatcher->name, zType)){
continue;
}else{
entry = (*dispatcher->func)(pay, rid);
break;
}
}
if(!g.json.resultCode){
|
| ︙ | ︙ |
Changes to src/json_branch.c.
| ︙ | ︙ | |||
216 217 218 219 220 221 222 |
db_begin_transaction();
rootid = name_to_typed_rid(zBasis, "ci");
if( rootid==0 ){
zOpt->rcErrMsg = "Basis branch not found.";
return FSL_JSON_E_RESOURCE_NOT_FOUND;
}
| | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
db_begin_transaction();
rootid = name_to_typed_rid(zBasis, "ci");
if( rootid==0 ){
zOpt->rcErrMsg = "Basis branch not found.";
return FSL_JSON_E_RESOURCE_NOT_FOUND;
}
pParent = manifest_get(rootid, CFTYPE_MANIFEST, 0);
if( pParent==0 ){
zOpt->rcErrMsg = "Could not read parent manifest.";
return FSL_JSON_E_UNKNOWN;
}
/* Create a manifest for the new branch */
blob_zero(&branch);
|
| ︙ | ︙ | |||
286 287 288 289 290 291 292 |
blob_appendf(&branch, "U %F\n", g.zLogin);
md5sum_blob(&branch, &mcksum);
blob_appendf(&branch, "Z %b\n", &mcksum);
brid = content_put(&branch);
if( brid==0 ){
| | | | | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
blob_appendf(&branch, "U %F\n", g.zLogin);
md5sum_blob(&branch, &mcksum);
blob_appendf(&branch, "Z %b\n", &mcksum);
brid = content_put(&branch);
if( brid==0 ){
fossil_fatal("Problem committing manifest: %s", g.zErrMsg);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
if( manifest_crosslink(brid, &branch, MC_PERMIT_HOOKS)==0 ){
fossil_fatal("%s\n", g.zErrMsg);
}
assert( blob_is_reset(&branch) );
content_deltify(rootid, brid, 0);
if( zNewRid ){
*zNewRid = brid;
}
|
| ︙ | ︙ |
Changes to src/json_config.c.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 |
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
static const struct JsonConfigProperty {
char const * name;
int groupMask;
} JsonConfigProperties[] = {
| | > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
static const struct JsonConfigProperty {
char const * name;
int groupMask;
} JsonConfigProperties[] = {
{ "css", CONFIGSET_CSS },
{ "header", CONFIGSET_SKIN },
{ "footer", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", CONFIGSET_SKIN },
{ "background-mimetype", CONFIGSET_SKIN },
{ "background-image", CONFIGSET_SKIN },
{ "index-page", CONFIGSET_SKIN },
{ "timeline-block-markup", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
{ "project-name", CONFIGSET_PROJ },
{ "project-description", CONFIGSET_PROJ },
{ "manifest", CONFIGSET_PROJ },
{ "binary-glob", CONFIGSET_PROJ },
{ "clean-glob", CONFIGSET_PROJ },
{ "encoding-glob", CONFIGSET_PROJ },
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
zName = json_command_arg(i);
for( ; zName; zName = json_command_arg(++i) ){
if(0==(strcmp("all", zName))){
confMask = CONFIGSET_ALL;
}else if(0==(strcmp("project", zName))){
confMask |= CONFIGSET_PROJ;
}else if(0==(strcmp("skin", zName))){
| | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
zName = json_command_arg(i);
for( ; zName; zName = json_command_arg(++i) ){
if(0==(strcmp("all", zName))){
confMask = CONFIGSET_ALL;
}else if(0==(strcmp("project", zName))){
confMask |= CONFIGSET_PROJ;
}else if(0==(strcmp("skin", zName))){
confMask |= (CONFIGSET_CSS|CONFIGSET_SKIN);
}else if(0==(strcmp("ticket", zName))){
confMask |= CONFIGSET_TKT;
}else if(0==(strcmp("skin-backup", zName))){
optSkinBackups = 1;
}else{
json_set_err( FSL_JSON_E_INVALID_ARGS,
"Unknown config area: %s", zName);
|
| ︙ | ︙ |
Changes to src/json_finfo.c.
| ︙ | ︙ | |||
72 73 74 75 76 77 78 | /*4*/ " coalesce(event.euser, event.user)," /*5*/ " coalesce(event.ecomment, event.comment)," /*6*/ " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ /*7*/ " event.bgcolor," /*8*/ " b.size," /*9*/ " (mlink.pid==0) AS isNew," /*10*/ " (mlink.fid==0) AS isDel" | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
/*4*/ " coalesce(event.euser, event.user),"
/*5*/ " coalesce(event.ecomment, event.comment),"
/*6*/ " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
/*7*/ " event.bgcolor,"
/*8*/ " b.size,"
/*9*/ " (mlink.pid==0) AS isNew,"
/*10*/ " (mlink.fid==0) AS isDel"
" FROM mlink, blob b, event, blob ci, filename"
" WHERE filename.name=%Q"
" AND mlink.fnid=filename.fnid"
" AND b.rid=mlink.fid"
" AND event.objid=mlink.mid"
" AND event.objid=ci.rid",
zFilename
);
|
| ︙ | ︙ | |||
123 124 125 126 127 128 129 |
cson_object * row = cson_new_object();
int const isNew = db_column_int(&q,9);
int const isDel = db_column_int(&q,10);
cson_array_append( checkins, cson_object_value(row) );
cson_object_set(row, "checkin", json_new_string( db_column_text(&q,1) ));
cson_object_set(row, "uuid", json_new_string( db_column_text(&q,2) ));
/*cson_object_set(row, "parentArtifact", json_new_string( db_column_text(&q,6) ));*/
| | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
cson_object * row = cson_new_object();
int const isNew = db_column_int(&q,9);
int const isDel = db_column_int(&q,10);
cson_array_append( checkins, cson_object_value(row) );
cson_object_set(row, "checkin", json_new_string( db_column_text(&q,1) ));
cson_object_set(row, "uuid", json_new_string( db_column_text(&q,2) ));
/*cson_object_set(row, "parentArtifact", json_new_string( db_column_text(&q,6) ));*/
cson_object_set(row, "timestamp", json_new_int( db_column_int64(&q,3) ));
cson_object_set(row, "user", json_new_string( db_column_text(&q,4) ));
cson_object_set(row, "comment", json_new_string( db_column_text(&q,5) ));
/*cson_object_set(row, "bgColor", json_new_string( db_column_text(&q,7) ));*/
cson_object_set(row, "size", json_new_int( db_column_int64(&q,8) ));
cson_object_set(row, "state",
json_new_string(json_artifact_status_to_string(isNew,isDel)));
if( (0 < limit) && (++currentRow >= limit) ){
break;
}
}
db_finalize(&q);
|
| ︙ | ︙ |
Changes to src/json_status.c.
| ︙ | ︙ | |||
124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
zStatus = "missing";
++nErr;
}
}else if( 2==isChnged ){
zStatus = "updatedByMerge";
}else if( 3==isChnged ){
zStatus = "addedByMerge";
}else if( 1==isChnged ){
if( file_contains_merge_marker(zFullName) ){
zStatus = "conflict";
}else{
zStatus = "edited";
}
}
| > > > > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
zStatus = "missing";
++nErr;
}
}else if( 2==isChnged ){
zStatus = "updatedByMerge";
}else if( 3==isChnged ){
zStatus = "addedByMerge";
}else if( 4==isChnged ){
zStatus = "updatedByIntegrate";
}else if( 5==isChnged ){
zStatus = "addedByIntegrate";
}else if( 1==isChnged ){
if( file_contains_merge_marker(zFullName) ){
zStatus = "conflict";
}else{
zStatus = "edited";
}
}
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
" WHERE id<=0");
while( db_step(&q)==SQLITE_ROW ){
const char *zLabel = "MERGED_WITH";
switch( db_column_int(&q, 1) ){
case -1: zLabel = "CHERRYPICK "; break;
case -2: zLabel = "BACKOUT "; break;
}
blob_append(report, zPrefix, nPrefix);
blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0));
}
db_finalize(&q);
if( nErr ){
fossil_fatal("aborting due to prior errors");
}
#endif
return cson_object_value( oPay );
}
#endif /* FOSSIL_ENABLE_JSON */
| > | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
" WHERE id<=0");
while( db_step(&q)==SQLITE_ROW ){
const char *zLabel = "MERGED_WITH";
switch( db_column_int(&q, 1) ){
case -1: zLabel = "CHERRYPICK "; break;
case -2: zLabel = "BACKOUT "; break;
case -4: zLabel = "INTEGRATE "; break;
}
blob_append(report, zPrefix, nPrefix);
blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0));
}
db_finalize(&q);
if( nErr ){
fossil_fatal("aborting due to prior errors");
}
#endif
return cson_object_value( oPay );
}
#endif /* FOSSIL_ENABLE_JSON */
|
Changes to src/json_timeline.c.
| ︙ | ︙ | |||
96 97 98 99 100 101 102 |
/* Field order MUST match that from json_timeline_temp_table()!!! */
static const char zBaseSql[] =
@ SELECT
@ NULL,
@ blob.rid,
@ uuid,
@ CAST(strftime('%%s',event.mtime) AS INTEGER),
| | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
/* Field order MUST match that from json_timeline_temp_table()!!! */
static const char zBaseSql[] =
@ SELECT
@ NULL,
@ blob.rid,
@ uuid,
@ CAST(strftime('%%s',event.mtime) AS INTEGER),
@ datetime(event.mtime),
@ coalesce(ecomment, comment),
@ coalesce(euser, user),
@ blob.rid IN leaf,
@ bgcolor,
@ event.type,
@ (SELECT group_concat(substr(tagname,5), ',') FROM tag, tagxref
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
|
| ︙ | ︙ | |||
122 123 124 125 126 127 128 | ** "tag" or "branch" request properties (CLI: --tag/--branch) ** are set. Limits the query to a particular branch/tag. ** ** tag works like HTML mode's "t" option and branch works like HTML ** mode's "r" option. They are very similar, but subtly different - ** tag mode shows only entries with a given tag but branch mode can ** also reveal some with "related" tags (meaning they were merged into | | > > > > > > > > > > | | > > > > > > > | > > > > > | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
** "tag" or "branch" request properties (CLI: --tag/--branch)
** are set. Limits the query to a particular branch/tag.
**
** tag works like HTML mode's "t" option and branch works like HTML
** mode's "r" option. They are very similar, but subtly different -
** tag mode shows only entries with a given tag but branch mode can
** also reveal some with "related" tags (meaning they were merged into
** the requested branch, or back).
**
** pSql is the target blob to append the query [subset]
** to.
**
** Returns a positive value if it modifies pSql, 0 if it
** does not. It returns a negative value if the tag
** provided to the request was not found (pSql is not modified
** in that case).
**
** If payload is not NULL then on success its "tag" or "branch"
** property is set to the tag/branch name found in the request.
**
** Only one of "tag" or "branch" modes will work at a time, and if
** both are specified, which one takes precedence is unspecified.
*/
static char json_timeline_add_tag_branch_clause(Blob *pSql,
cson_object * pPayload){
char const * zTag = NULL;
char const * zBranch = NULL;
char const * zMiOnly = NULL;
char const * zUnhide = NULL;
int tagid = 0;
if(! g.perm.Read ){
return 0;
}
zTag = json_find_option_cstr("tag",NULL,NULL);
if(!zTag || !*zTag){
zBranch = json_find_option_cstr("branch",NULL,NULL);
if(!zBranch || !*zBranch){
return 0;
}
zTag = zBranch;
zMiOnly = json_find_option_cstr("mionly",NULL,NULL);
}
zUnhide = json_find_option_cstr("unhide",NULL,NULL);
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",
zTag);
if(tagid<=0){
return -1;
}
if(pPayload){
cson_object_set( pPayload, zBranch ? "branch" : "tag", json_new_string(zTag) );
}
blob_appendf(pSql,
" AND ("
" EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
tagid);
if(!zUnhide){
blob_appendf(pSql,
" AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=blob.rid"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
TAG_HIDDEN);
}
if(zBranch){
/* from "r" flag code in page_timeline().*/
blob_appendf(pSql,
" OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
tagid);
if( !zUnhide ){
blob_appendf(pSql,
" AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
TAG_HIDDEN);
}
if( zMiOnly==0 ){
blob_appendf(pSql,
" OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
tagid);
if( !zUnhide ){
blob_appendf(pSql,
" AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
TAG_HIDDEN);
}
}
}
blob_append(pSql," ) ",3);
return 1;
}
/*
** Helper for the timeline family of functions. Possibly appends 1
** AND clause and an ORDER BY clause to pSql, depending on the state
|
| ︙ | ︙ | |||
628 629 630 631 632 633 634 |
/* convert each row into a JSON object...*/
int rc;
int const rid = db_column_int(&q,0);
Manifest * pMan = NULL;
cson_value * rowV;
cson_object * row;
/*printf("rid=%d\n",rid);*/
| | | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
/* convert each row into a JSON object...*/
int rc;
int const rid = db_column_int(&q,0);
Manifest * pMan = NULL;
cson_value * rowV;
cson_object * row;
/*printf("rid=%d\n",rid);*/
pMan = manifest_get(rid, CFTYPE_TICKET, 0);
if(!pMan){
/* this might be an attachment? I'm seeing this with
rid 15380, uuid [1292fef05f2472108].
/json/artifact/1292fef05f2472108 returns not-found,
probably because we haven't added artifact/ticket
yet(?).
|
| ︙ | ︙ |
Changes to src/json_wiki.c.
| ︙ | ︙ | |||
80 81 82 83 84 85 86 |
** the page.
**
** The returned value, if not NULL, is-a JSON Object owned by the
** caller. If it returns NULL then it may set g.json's error state.
*/
cson_value * json_get_wiki_page_by_rid(int rid, char contentFormat){
Manifest * pWiki = NULL;
| | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
** the page.
**
** The returned value, if not NULL, is-a JSON Object owned by the
** caller. If it returns NULL then it may set g.json's error state.
*/
cson_value * json_get_wiki_page_by_rid(int rid, char contentFormat){
Manifest * pWiki = NULL;
if( NULL == (pWiki = manifest_get(rid, CFTYPE_WIKI, 0)) ){
json_set_err( FSL_JSON_E_UNKNOWN,
"Error reading wiki page from manifest (rid=%d).",
rid );
return NULL;
}else{
unsigned int len = 0;
cson_object * pay = cson_new_object();
|
| ︙ | ︙ | |||
526 527 528 529 530 531 532 |
if(r2<0){
goto ambiguous;
}else if(0==r2){
goto invalid;
}
zErrTag = zV1;
| | | | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 |
if(r2<0){
goto ambiguous;
}else if(0==r2){
goto invalid;
}
zErrTag = zV1;
pW1 = manifest_get(r1, CFTYPE_WIKI, 0);
if( pW1==0 ) {
goto manifest;
}
zErrTag = zV2;
pW2 = manifest_get(r2, CFTYPE_WIKI, 0);
if( pW2==0 ) {
goto manifest;
}
blob_init(&w1, pW1->zWiki, -1);
blob_zero(&w2);
blob_init(&w2, pW2->zWiki, -1);
|
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 | ** not really the point. The anonymous login keeps search-engine ** crawlers and site download tools like wget from walking change ** logs and downloading diffs of very version of the archive that ** has ever existed, and things like that. */ #include "config.h" #include "login.h" | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** not really the point. The anonymous login keeps search-engine ** crawlers and site download tools like wget from walking change ** logs and downloading diffs of very version of the archive that ** has ever existed, and things like that. */ #include "config.h" #include "login.h" #if defined(_WIN32) # include <windows.h> /* for Sleep */ # if defined(__MINGW32__) || defined(_MSC_VER) # define sleep Sleep /* windows does not have sleep, but Sleep */ # endif #endif #include <time.h> |
| ︙ | ︙ | |||
67 68 69 70 71 72 73 | /* ** Return a path appropriate for setting a cookie. ** ** The path is g.zTop for single-repo cookies. It is "/" for ** cookies of a login-group. */ | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
/*
** Return a path appropriate for setting a cookie.
**
** The path is g.zTop for single-repo cookies. It is "/" for
** cookies of a login-group.
*/
const char *login_cookie_path(void){
if( login_group_name()==0 ){
return g.zTop;
}else{
return "/";
}
}
|
| ︙ | ︙ | |||
110 111 112 113 114 115 116 |
}else{
fossil_redirect_home();
}
}
/*
** The IP address of the client is stored as part of login cookies.
| | | | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
}else{
fossil_redirect_home();
}
}
/*
** The IP address of the client is stored as part of login cookies.
** But some clients are behind firewalls that shift the IP address
** with each HTTP request. To allow such (broken) clients to log in,
** extract just a prefix of the IP address.
*/
static char *ipPrefix(const char *zIP){
int i, j;
static int ip_prefix_terms = -1;
if( ip_prefix_terms<0 ){
ip_prefix_terms = db_get_int("ip-prefix-terms",2);
}
|
| ︙ | ︙ | |||
342 343 344 345 346 347 348 |
**
** This is a no-op if g.userUid is 0.
*/
void login_clear_login_data(){
if(!g.userUid){
return;
}else{
| | | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
**
** This is a no-op if g.userUid is 0.
*/
void login_clear_login_data(){
if(!g.userUid){
return;
}else{
char const * cookie = login_cookie_name();
/* To logout, change the cookie value to an empty string */
cgi_set_cookie(cookie, "",
login_cookie_path(), -86400);
db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, "
" cexpire=0 WHERE uid=%d"
" AND login NOT IN ('anonymous','nobody',"
" 'developer','reader')", g.userUid);
|
| ︙ | ︙ | |||
389 390 391 392 393 394 395 |
int i;
if( zAgent==0 ) return 0; /* If no UserAgent, then probably a bot */
for(i=0; zAgent[i]; i++){
if( prefix_match("bot", zAgent+i) ) return 0;
if( prefix_match("spider", zAgent+i) ) return 0;
if( prefix_match("crawl", zAgent+i) ) return 0;
/* If a URI appears in the User-Agent, it is probably a bot */
| | | > | | | | | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
int i;
if( zAgent==0 ) return 0; /* If no UserAgent, then probably a bot */
for(i=0; zAgent[i]; i++){
if( prefix_match("bot", zAgent+i) ) return 0;
if( prefix_match("spider", zAgent+i) ) return 0;
if( prefix_match("crawl", zAgent+i) ) return 0;
/* If a URI appears in the User-Agent, it is probably a bot */
if( strncmp("http", zAgent+i,4)==0 ) return 0;
}
if( strncmp(zAgent, "Mozilla/", 8)==0 ){
if( atoi(&zAgent[8])<4 ) return 0; /* Many bots advertise as Mozilla/3 */
if( strglob("*Firefox/[1-9]*", zAgent) ) return 1;
if( strglob("*Chrome/[1-9]*", zAgent) ) return 1;
if( strglob("*(compatible;?MSIE?[1789]*", zAgent) ) return 1;
if( strglob("*Trident/[1-9]*;?rv:[1-9]*", zAgent) ) return 1; /* IE11+ */
if( strglob("*AppleWebKit/[1-9]*(KHTML*", zAgent) ) return 1;
return 0;
}
if( strncmp(zAgent, "Opera/", 6)==0 ) return 1;
if( strncmp(zAgent, "Safari/", 7)==0 ) return 1;
if( strncmp(zAgent, "Lynx/", 5)==0 ) return 1;
if( strncmp(zAgent, "NetSurf/", 8)==0 ) return 1;
return 0;
}
/*
** COMMAND: test-ishuman
**
** Read lines of text from standard input. Interpret each line of text
|
| ︙ | ︙ | |||
469 470 471 472 473 474 475 476 477 478 |
const char *zAnonPw = 0;
const char *zGoto = P("g");
int anonFlag;
char *zErrMsg = "";
int uid; /* User id logged in user */
char *zSha1Pw;
const char *zIpAddr; /* IP address of requestor */
login_check_credentials();
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
| > | | | | | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
const char *zAnonPw = 0;
const char *zGoto = P("g");
int anonFlag;
char *zErrMsg = "";
int uid; /* User id logged in user */
char *zSha1Pw;
const char *zIpAddr; /* IP address of requestor */
const char *zReferer;
login_check_credentials();
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
zUsername = P("u");
zPasswd = P("p");
anonFlag = P("anon")!=0;
if( P("out")!=0 ){
login_clear_login_data();
redirect_to_g();
}
if( g.perm.Password && zPasswd
&& (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
){
/* The user requests a password change */
zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
if( db_int(1, "SELECT 0 FROM user"
" WHERE uid=%d"
" AND (constant_time_cmp(pw,%Q)=0"
" OR constant_time_cmp(pw,%Q)=0)",
g.userUid, zSha1Pw, zPasswd) ){
sleep(1);
zErrMsg =
@ <p><span class="loginError">
@ You entered an incorrect old password while attempting to change
@ your password. Your password is unchanged.
@ </span></p>
;
}else if( fossil_strcmp(zNew1,zNew2)!=0 ){
zErrMsg =
@ <p><span class="loginError">
@ The two copies of your new passwords do not match.
@ Your password is unchanged.
@ </span></p>
;
}else{
char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0);
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 |
}else{
redirect_to_g();
return;
}
}
}
zIpAddr = PD("REMOTE_ADDR","nil"); /* Complete IP address for logging */
uid = login_is_valid_anonymous(zUsername, zPasswd, P("cs"));
if( uid>0 ){
login_set_anon_cookie(zIpAddr, NULL);
record_login_attempt("anonymous", zIpAddr, 1);
redirect_to_g();
}
if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
/* Attempting to log in as a user other than anonymous.
*/
uid = login_search_uid(zUsername, zPasswd);
if( uid<=0 ){
sleep(1);
| > | | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 |
}else{
redirect_to_g();
return;
}
}
}
zIpAddr = PD("REMOTE_ADDR","nil"); /* Complete IP address for logging */
zReferer = P("HTTP_REFERER");
uid = login_is_valid_anonymous(zUsername, zPasswd, P("cs"));
if( uid>0 ){
login_set_anon_cookie(zIpAddr, NULL);
record_login_attempt("anonymous", zIpAddr, 1);
redirect_to_g();
}
if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
/* Attempting to log in as a user other than anonymous.
*/
uid = login_search_uid(zUsername, zPasswd);
if( uid<=0 ){
sleep(1);
zErrMsg =
@ <p><span class="loginError">
@ You entered an unknown user or an incorrect password.
@ </span></p>
;
record_login_attempt(zUsername, zIpAddr, 0);
}else{
/* Non-anonymous login is successful. Set a cookie of the form:
|
| ︙ | ︙ | |||
567 568 569 570 571 572 573 574 575 576 577 578 579 580 |
@ %s(zErrMsg)
if( zGoto && P("anon")==0 ){
@ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
}
form_begin(0, "%R/login");
if( zGoto ){
@ <input type="hidden" name="g" value="%h(zGoto)" />
}
@ <table class="login_out">
@ <tr>
@ <td class="login_out_label">User ID:</td>
if( anonFlag ){
@ <td><input type="text" id="u" name="u" value="anonymous" size="30" /></td>
}else{
| > > | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
@ %s(zErrMsg)
if( zGoto && P("anon")==0 ){
@ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
}
form_begin(0, "%R/login");
if( zGoto ){
@ <input type="hidden" name="g" value="%h(zGoto)" />
}else if( zReferer && strncmp(g.zBaseURL, zReferer, strlen(g.zBaseURL))==0 ){
@ <input type="hidden" name="g" value="%h(zReferer)" />
}
@ <table class="login_out">
@ <tr>
@ <td class="login_out_label">User ID:</td>
if( anonFlag ){
@ <td><input type="text" id="u" name="u" value="anonymous" size="30" /></td>
}else{
|
| ︙ | ︙ | |||
596 597 598 599 600 601 602 |
@ onClick="chngAction(this.form)" /></td>
@ </tr>
@ </table>
@ <script type="text/JavaScript">
@ gebi('u').focus()
@ function chngAction(form){
if( g.sslNotAvailable==0
| | | | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 |
@ onClick="chngAction(this.form)" /></td>
@ </tr>
@ </table>
@ <script type="text/JavaScript">
@ gebi('u').focus()
@ function chngAction(form){
if( g.sslNotAvailable==0
&& strncmp(g.zBaseURL,"https:",6)!=0
&& db_get_boolean("https-login",0)
){
char *zSSL = mprintf("https:%s", &g.zBaseURL[5]);
@ if( form.u.value!="anonymous" ){
@ form.action = "%h(zSSL)/login";
@ }
}
@ }
@ </script>
if( g.zLogin==0 ){
@ <p>Enter
}else{
@ <p>You are currently logged in as <b>%h(g.zLogin)</b></p>
@ <p>To change your login to a different user, enter
}
@ your user-id and password at the left and press the
@ "Login" button. Your user name will be stored in a browser cookie.
@ You must configure your web browser to accept cookies in order for
@ the login to take.</p>
if( db_get_boolean("self-register", 0) ){
@ <p>If you do not have an account, you can
@ <a href="%s(g.zTop)/register?g=%T(P("G"))">create one</a>.
}
if( zAnonPw ){
unsigned int uSeed = captcha_seed();
char const *zDecoded = captcha_decode(uSeed);
int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
char *zCaptcha = captcha_render(zDecoded);
|
| ︙ | ︙ | |||
669 670 671 672 673 674 675 |
@ </form>
}
style_footer();
}
/*
** Attempt to find login credentials for user zLogin on a peer repository
| | | | > > > > | | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
@ </form>
}
style_footer();
}
/*
** Attempt to find login credentials for user zLogin on a peer repository
** with project code zCode. Transfer those credentials to the local
** repository.
**
** Return true if a transfer was made and false if not.
*/
static int login_transfer_credentials(
const char *zLogin, /* Login we are looking for */
const char *zCode, /* Project code of peer repository */
const char *zHash, /* HASH from login cookie HASH/CODE/LOGIN */
const char *zRemoteAddr /* Request comes from here */
){
sqlite3 *pOther = 0; /* The other repository */
sqlite3_stmt *pStmt; /* Query against the other repository */
char *zSQL; /* SQL of the query against other repo */
char *zOtherRepo; /* Filename of the other repository */
int rc; /* Result code from SQLite library functions */
int nXfer = 0; /* Number of credentials transferred */
zOtherRepo = db_text(0,
"SELECT value FROM config WHERE name='peer-repo-%q'",
zCode
);
if( zOtherRepo==0 ) return 0; /* No such peer repository */
rc = sqlite3_open_v2(
zOtherRepo, &pOther,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
g.zVfsName
);
if( rc==SQLITE_OK ){
sqlite3_create_function(pOther,"now",0,SQLITE_ANY,0,db_now_function,0,0);
sqlite3_create_function(pOther, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
sqlite3_busy_timeout(pOther, 5000);
zSQL = mprintf(
"SELECT cexpire FROM user"
" WHERE login=%Q"
" AND ipaddr=%Q"
" AND length(cap)>0"
" AND length(pw)>0"
|
| ︙ | ︙ | |||
745 746 747 748 749 750 751 |
const char *zRemoteAddr /* Abbreviated IP address for valid login */
){
int uid;
if( fossil_strcmp(zLogin, "anonymous")==0 ) return 0;
if( fossil_strcmp(zLogin, "nobody")==0 ) return 0;
if( fossil_strcmp(zLogin, "developer")==0 ) return 0;
if( fossil_strcmp(zLogin, "reader")==0 ) return 0;
| | | < > > > > | > | | | > > > > > | > > | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 |
const char *zRemoteAddr /* Abbreviated IP address for valid login */
){
int uid;
if( fossil_strcmp(zLogin, "anonymous")==0 ) return 0;
if( fossil_strcmp(zLogin, "nobody")==0 ) return 0;
if( fossil_strcmp(zLogin, "developer")==0 ) return 0;
if( fossil_strcmp(zLogin, "reader")==0 ) return 0;
uid = db_int(0,
"SELECT uid FROM user"
" WHERE login=%Q"
" AND ipaddr=%Q"
" AND cexpire>julianday('now')"
" AND length(cap)>0"
" AND length(pw)>0"
" AND constant_time_cmp(cookie,%Q)=0",
zLogin, zRemoteAddr, zCookie
);
return uid;
}
/*
** This routine examines the login cookie to see if it exists and
** is valid. If the login cookie checks out, it then sets global
** variables appropriately.
**
** g.userUid Database USER.UID value. Might be -1 for "nobody"
** g.zLogin Database USER.LOGIN value. NULL for user "nobody"
** g.perm Permissions granted to this user
** g.isHuman True if the user is human, not a spider or robot
**
*/
void login_check_credentials(void){
int uid = 0; /* User id */
const char *zCookie; /* Text of the login cookie */
const char *zIpAddr; /* Raw IP address of the requestor */
char *zRemoteAddr; /* Abbreviated IP address of the requestor */
const char *zCap = 0; /* Capability string */
const char *zPublicPages = 0; /* GLOB patterns of public pages */
const char *zLogin = 0; /* Login user for credentials */
/* Only run this check once. */
if( g.userUid!=0 ) return;
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
/* If the HTTP connection is coming over 127.0.0.1 and if
** local login is disabled and if we are using HTTP and not HTTPS,
** then there is no need to check user credentials.
**
** This feature allows the "fossil ui" command to give the user
** full access rights without having to log in.
*/
zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil"));
if( ( fossil_strcmp(zIpAddr, "127.0.0.1")==0 ||
g.fSshClient & CGI_SSH_CLIENT )
&& g.useLocalauth
&& db_get_int("localauth",0)==0
&& P("HTTPS")==0
){
if( g.localOpen ) zLogin = db_lget("default-user",0);
if( zLogin!=0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sx";
g.noPswd = 1;
g.isHuman = 1;
sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
}
/* Check the login cookie to see if it matches a known valid user.
*/
if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){
/* Parse the cookie value up into HASH/ARG/USER */
|
| ︙ | ︙ | |||
829 830 831 832 833 834 835 |
/* Cookies of the form "HASH/TIME/anonymous". The TIME must not be
** too old and the sha1 hash of TIME/IPADDR/SECRET must match HASH.
** SECRET is the "captcha-secret" value in the repository.
*/
double rTime = atof(zArg);
Blob b;
blob_zero(&b);
| | | | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 |
/* Cookies of the form "HASH/TIME/anonymous". The TIME must not be
** too old and the sha1 hash of TIME/IPADDR/SECRET must match HASH.
** SECRET is the "captcha-secret" value in the repository.
*/
double rTime = atof(zArg);
Blob b;
blob_zero(&b);
blob_appendf(&b, "%s/%s/%s",
zArg, zRemoteAddr, db_get("captcha-secret",""));
sha1sum_blob(&b, &b);
if( fossil_strcmp(zHash, blob_str(&b))==0 ){
uid = db_int(0,
"SELECT uid FROM user WHERE login='anonymous'"
" AND length(cap)>0"
" AND length(pw)>0"
" AND %.17g+0.25>julianday('now')",
rTime
);
}
|
| ︙ | ︙ | |||
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 |
/* Set the global variables recording the userid and login. The
** "nobody" user is a special case in that g.zLogin==0.
*/
g.userUid = uid;
if( fossil_strcmp(g.zLogin,"nobody")==0 ){
g.zLogin = 0;
}
/* Set the capabilities */
login_replace_capabilities(zCap, 0);
login_set_anon_nobody_capabilities();
/* The auto-hyperlink setting allows hyperlinks to be displayed for users
** who do not have the "h" permission as long as their UserAgent string
** makes it appear that they are human. Check to see if auto-hyperlink is
** enabled for this repository and make appropriate adjustments to the
** permission flags if it is.
*/
| > > | > < | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 |
/* Set the global variables recording the userid and login. The
** "nobody" user is a special case in that g.zLogin==0.
*/
g.userUid = uid;
if( fossil_strcmp(g.zLogin,"nobody")==0 ){
g.zLogin = 0;
}
g.isHuman = g.zLogin==0 ? isHuman(P("HTTP_USER_AGENT")) : 1;
/* Set the capabilities */
login_replace_capabilities(zCap, 0);
login_set_anon_nobody_capabilities();
/* The auto-hyperlink setting allows hyperlinks to be displayed for users
** who do not have the "h" permission as long as their UserAgent string
** makes it appear that they are human. Check to see if auto-hyperlink is
** enabled for this repository and make appropriate adjustments to the
** permission flags if it is.
*/
if( zCap[0]
&& !g.perm.Hyperlink
&& g.isHuman
&& db_get_boolean("auto-hyperlink",1)
){
g.perm.Hyperlink = 1;
g.javascriptHyperlink = 1;
}
/* If the public-pages glob pattern is defined and REQUEST_URI matches
** one of the globs in public-pages, then also add in all default-perms
|
| ︙ | ︙ | |||
982 983 984 985 986 987 988 |
return;
}
for(i=0; zCap[i]; i++){
switch( zCap[i] ){
case 's': g.perm.Setup = 1; /* Fall thru into Admin */
case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip =
g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
| | | 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
return;
}
for(i=0; zCap[i]; i++){
switch( zCap[i] ){
case 's': g.perm.Setup = 1; /* Fall thru into Admin */
case 'a': g.perm.Admin = g.perm.RdTkt = g.perm.WrTkt = g.perm.Zip =
g.perm.RdWiki = g.perm.WrWiki = g.perm.NewWiki =
g.perm.ApndWiki = g.perm.Hyperlink = g.perm.Clone =
g.perm.NewTkt = g.perm.Password = g.perm.RdAddr =
g.perm.TktFmt = g.perm.Attach = g.perm.ApndTkt =
g.perm.ModWiki = g.perm.ModTkt = 1;
/* Fall thru into Read/Write */
case 'i': g.perm.Read = g.perm.Write = 1; break;
case 'o': g.perm.Read = 1; break;
case 'z': g.perm.Zip = 1; break;
|
| ︙ | ︙ | |||
1005 1006 1007 1008 1009 1010 1011 |
case 'm': g.perm.ApndWiki = 1; break;
case 'f': g.perm.NewWiki = 1; break;
case 'l': g.perm.ModWiki = 1; break;
case 'e': g.perm.RdAddr = 1; break;
case 'r': g.perm.RdTkt = 1; break;
case 'n': g.perm.NewTkt = 1; break;
| | | | > | 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 |
case 'm': g.perm.ApndWiki = 1; break;
case 'f': g.perm.NewWiki = 1; break;
case 'l': g.perm.ModWiki = 1; break;
case 'e': g.perm.RdAddr = 1; break;
case 'r': g.perm.RdTkt = 1; break;
case 'n': g.perm.NewTkt = 1; break;
case 'w': g.perm.WrTkt = g.perm.RdTkt = g.perm.NewTkt =
g.perm.ApndTkt = 1; break;
case 'c': g.perm.ApndTkt = 1; break;
case 'q': g.perm.ModTkt = 1; break;
case 't': g.perm.TktFmt = 1; break;
case 'b': g.perm.Attach = 1; break;
case 'x': g.perm.Private = 1; break;
/* The "u" privileges is a little different. It recursively
** inherits all privileges of the user named "reader" */
case 'u': {
if( (flags & LOGIN_IGNORE_UV)==0 ){
const char *zUser;
zUser = db_text("", "SELECT cap FROM user WHERE login='reader'");
login_set_capabilities(zUser, flags | LOGIN_IGNORE_UV);
}
break;
}
/* The "v" privileges is a little different. It recursively
** inherits all privileges of the user named "developer" */
case 'v': {
if( (flags & LOGIN_IGNORE_UV)==0 ){
const char *zDev;
zDev = db_text("", "SELECT cap FROM user WHERE login='developer'");
login_set_capabilities(zDev, flags | LOGIN_IGNORE_UV);
}
break;
}
}
}
}
/*
** Zeroes out g.perm and calls login_set_capabilities(zCap,flags).
*/
void login_replace_capabilities(const char *zCap, unsigned flags){
memset(&g.perm, 0, sizeof(g.perm));
login_set_capabilities(zCap, flags);
login_anon_once = 1;
}
/*
** If the current login lacks any of the capabilities listed in
** the input, then return 0. If all capabilities are present, then
** return 1.
*/
|
| ︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 |
Stmt q; /* Query of all peer-* entries in CONFIG */
if( zPrefix==0 ) zPrefix = "";
if( zSuffix==0 ) zSuffix = "";
if( pzErrorMsg ) *pzErrorMsg = 0;
zSelfCode = abbreviated_project_code(db_get("project-code", "x"));
blob_zero(&err);
| | | > > > > | 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 |
Stmt q; /* Query of all peer-* entries in CONFIG */
if( zPrefix==0 ) zPrefix = "";
if( zSuffix==0 ) zSuffix = "";
if( pzErrorMsg ) *pzErrorMsg = 0;
zSelfCode = abbreviated_project_code(db_get("project-code", "x"));
blob_zero(&err);
db_prepare(&q,
"SELECT name, value FROM config"
" WHERE name GLOB 'peer-repo-*'"
" AND name <> 'peer-repo-%q'"
" ORDER BY +value",
zSelfCode
);
while( db_step(&q)==SQLITE_ROW ){
const char *zRepoName = db_column_text(&q, 1);
if( file_size(zRepoName)<0 ){
/* Silently remove non-existent repositories from the login group. */
const char *zLabel = db_column_text(&q, 0);
db_multi_exec(
"DELETE FROM config WHERE name GLOB 'peer-*-%q'",
&zLabel[10]
);
continue;
}
rc = sqlite3_open_v2(
zRepoName, &pPeer,
SQLITE_OPEN_READWRITE,
g.zVfsName
);
if( rc!=SQLITE_OK ){
blob_appendf(&err, "%s%s: %s%s", zPrefix, zRepoName,
sqlite3_errmsg(pPeer), zSuffix);
nErr++;
sqlite3_close(pPeer);
continue;
}
|
| ︙ | ︙ | |||
1416 1417 1418 1419 1420 1421 1422 |
char *zSelfProjCode; /* Our project-code */
char *zSql; /* SQL to run on all peers */
const char *zSelf; /* The ATTACH name of our repository */
*pzErrMsg = 0; /* Default to no errors */
zSelf = db_name("repository");
| | | 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 |
char *zSelfProjCode; /* Our project-code */
char *zSql; /* SQL to run on all peers */
const char *zSelf; /* The ATTACH name of our repository */
*pzErrMsg = 0; /* Default to no errors */
zSelf = db_name("repository");
/* Get the full pathname of the other repository */
file_canonical_name(zRepo, &fullName, 0);
zRepo = mprintf(blob_str(&fullName));
blob_reset(&fullName);
/* Get the full pathname for our repository. Also the project code
** and project name for ourself. */
file_canonical_name(g.zRepositoryName, &fullName, 0);
|
| ︙ | ︙ | |||
1443 1444 1445 1446 1447 1448 1449 |
}
/* Make sure the other repository is a valid Fossil database */
if( file_size(zRepo)<0 ){
*pzErrMsg = mprintf("repository file \"%s\" does not exist", zRepo);
return;
}
| | > > > > | 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 |
}
/* Make sure the other repository is a valid Fossil database */
if( file_size(zRepo)<0 ){
*pzErrMsg = mprintf("repository file \"%s\" does not exist", zRepo);
return;
}
rc = sqlite3_open_v2(
zRepo, &pOther,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
g.zVfsName
);
if( rc!=SQLITE_OK ){
*pzErrMsg = mprintf(sqlite3_errmsg(pOther));
}else{
rc = sqlite3_exec(pOther, "SELECT count(*) FROM user", 0, 0, pzErrMsg);
}
sqlite3_close(pOther);
if( rc ) return;
|
| ︙ | ︙ |
Added src/lookslike.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
/*
** Copyright (c) 2013 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to try to guess if a particular file is
** text or binary, what types of line endings it uses, is it UTF8 or
** UTF16, etc.
*/
#include "config.h"
#include "lookslike.h"
#include <assert.h>
#if INTERFACE
/*
** This macro is designed to return non-zero if the specified blob contains
** data that MAY be binary in nature; otherwise, zero will be returned.
*/
#define looks_like_binary(blob) \
((looks_like_utf8((blob), LOOK_BINARY) & LOOK_BINARY) != LOOK_NONE)
/*
** Output flags for the looks_like_utf8() and looks_like_utf16() routines used
** to convey status information about the blob content.
*/
#define LOOK_NONE ((int)0x00000000) /* Nothing special was found. */
#define LOOK_NUL ((int)0x00000001) /* One or more NUL chars were found. */
#define LOOK_CR ((int)0x00000002) /* One or more CR chars were found. */
#define LOOK_LONE_CR ((int)0x00000004) /* An unpaired CR char was found. */
#define LOOK_LF ((int)0x00000008) /* One or more LF chars were found. */
#define LOOK_LONE_LF ((int)0x00000010) /* An unpaired LF char was found. */
#define LOOK_CRLF ((int)0x00000020) /* One or more CR/LF pairs were found. */
#define LOOK_LONG ((int)0x00000040) /* An over length line was found. */
#define LOOK_ODD ((int)0x00000080) /* An odd number of bytes was found. */
#define LOOK_SHORT ((int)0x00000100) /* Unable to perform full check. */
#define LOOK_INVALID ((int)0x00000200) /* Invalid sequence was found. */
#define LOOK_BINARY (LOOK_NUL | LOOK_LONG | LOOK_SHORT) /* May be binary. */
#define LOOK_EOL (LOOK_LONE_CR | LOOK_LONE_LF | LOOK_CRLF) /* Line seps. */
#endif /* INTERFACE */
/*
** This function attempts to scan each logical line within the blob to
** determine the type of content it appears to contain. The return value
** is a combination of one or more of the LOOK_XXX flags (see above):
**
** !LOOK_BINARY -- The content appears to consist entirely of text; however,
** the encoding may not be UTF-8.
**
** LOOK_BINARY -- The content appears to be binary because it contains one
** or more embedded NUL characters or an extremely long line.
** Since this function does not understand UTF-16, it may
** falsely consider UTF-16 text to be binary.
**
** Additional flags (i.e. those other than the ones included in LOOK_BINARY)
** may be present in the result as well; however, they should not impact the
** determination of text versus binary content.
**
************************************ WARNING **********************************
**
** This function does not validate that the blob content is properly formed
** UTF-8. It assumes that all code points are the same size. It does not
** validate any code points. It makes no attempt to detect if any [invalid]
** switches between UTF-8 and other encodings occur.
**
** The only code points that this function cares about are the NUL character,
** carriage-return, and line-feed.
**
** This function examines the contents of the blob until one of the flags
** specified in "stopFlags" is set.
**
************************************ WARNING **********************************
*/
int looks_like_utf8(const Blob *pContent, int stopFlags){
const char *z = blob_buffer(pContent);
unsigned int n = blob_size(pContent);
int j, c, flags = LOOK_NONE; /* Assume UTF-8 text, prove otherwise */
if( n==0 ) return flags; /* Empty file -> text */
c = *z;
if( c==0 ){
flags |= LOOK_NUL; /* NUL character in a file -> binary */
}else if( c=='\r' ){
flags |= LOOK_CR;
if( n<=1 || z[1]!='\n' ){
flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
}
}
j = (c!='\n');
if( !j ) flags |= (LOOK_LF | LOOK_LONE_LF); /* Found LF as first char */
while( !(flags&stopFlags) && --n>0 ){
int c2 = c;
c = *++z; ++j;
if( c==0 ){
flags |= LOOK_NUL; /* NUL character in a file -> binary */
}else if( c=='\n' ){
flags |= LOOK_LF;
if( c2=='\r' ){
flags |= (LOOK_CR | LOOK_CRLF); /* Found LF preceded by CR */
}else{
flags |= LOOK_LONE_LF;
}
if( j>LENGTH_MASK ){
flags |= LOOK_LONG; /* Very long line -> binary */
}
j = 0;
}else if( c=='\r' ){
flags |= LOOK_CR;
if( n<=1 || z[1]!='\n' ){
flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
}
}
}
if( n ){
flags |= LOOK_SHORT; /* The whole blob was not examined */
}
if( j>LENGTH_MASK ){
flags |= LOOK_LONG; /* Very long line -> binary */
}
return flags;
}
/*
** Define the type needed to represent a Unicode (UTF-16) character.
*/
#ifndef WCHAR_T
# ifdef _WIN32
# define WCHAR_T wchar_t
# else
# define WCHAR_T unsigned short
# endif
#endif
/*
** Maximum length of a line in a text file, in UTF-16 characters. (4096)
** The number of bytes represented by this value cannot exceed LENGTH_MASK
** bytes, because that is the line buffer size used by the diff engine.
*/
#define UTF16_LENGTH_MASK_SZ (LENGTH_MASK_SZ-(sizeof(WCHAR_T)-sizeof(char)))
#define UTF16_LENGTH_MASK ((1<<UTF16_LENGTH_MASK_SZ)-1)
/*
** This macro is used to swap the byte order of a UTF-16 character in the
** looks_like_utf16() function.
*/
#define UTF16_SWAP(ch) ((((ch) << 8) & 0xFF00) | (((ch) >> 8) & 0xFF))
#define UTF16_SWAP_IF(expr,ch) ((expr) ? UTF16_SWAP((ch)) : (ch))
/*
** This function attempts to scan each logical line within the blob to
** determine the type of content it appears to contain. The return value
** is a combination of one or more of the LOOK_XXX flags (see above):
**
** !LOOK_BINARY -- The content appears to consist entirely of text; however,
** the encoding may not be UTF-16.
**
** LOOK_BINARY -- The content appears to be binary because it contains one
** or more embedded NUL characters or an extremely long line.
** Since this function does not understand UTF-8, it may
** falsely consider UTF-8 text to be binary.
**
** Additional flags (i.e. those other than the ones included in LOOK_BINARY)
** may be present in the result as well; however, they should not impact the
** determination of text versus binary content.
**
************************************ WARNING **********************************
**
** This function does not validate that the blob content is properly formed
** UTF-16. It assumes that all code points are the same size. It does not
** validate any code points. It makes no attempt to detect if any [invalid]
** switches between the UTF-16be and UTF-16le encodings occur.
**
** The only code points that this function cares about are the NUL character,
** carriage-return, and line-feed.
**
** This function examines the contents of the blob until one of the flags
** specified in "stopFlags" is set.
**
************************************ WARNING **********************************
*/
int looks_like_utf16(const Blob *pContent, int bReverse, int stopFlags){
const WCHAR_T *z = (WCHAR_T *)blob_buffer(pContent);
unsigned int n = blob_size(pContent);
int j, c, flags = LOOK_NONE; /* Assume UTF-16 text, prove otherwise */
if( n==0 ) return flags; /* Empty file -> text */
if( n%sizeof(WCHAR_T) ){
flags |= LOOK_ODD; /* Odd number of bytes -> binary (UTF-8?) */
if( n<sizeof(WCHAR_T) ) return flags; /* One byte -> binary (UTF-8?) */
}
c = *z;
if( bReverse ){
c = UTF16_SWAP(c);
}
if( c==0 ){
flags |= LOOK_NUL; /* NUL character in a file -> binary */
}else if( c=='\r' ){
flags |= LOOK_CR;
if( n<(2*sizeof(WCHAR_T)) || UTF16_SWAP_IF(bReverse, z[1])!='\n' ){
flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
}
}
j = (c!='\n');
if( !j ) flags |= (LOOK_LF | LOOK_LONE_LF); /* Found LF as first char */
while( 1 ){
int c2 = c;
if( flags&stopFlags ) break;
n -= sizeof(WCHAR_T);
if( n<sizeof(WCHAR_T) ) break;
c = *++z;
if( bReverse ){
c = UTF16_SWAP(c);
}
++j;
if( c==0 ){
flags |= LOOK_NUL; /* NUL character in a file -> binary */
}else if( c=='\n' ){
flags |= LOOK_LF;
if( c2=='\r' ){
flags |= (LOOK_CR | LOOK_CRLF); /* Found LF preceded by CR */
}else{
flags |= LOOK_LONE_LF;
}
if( j>UTF16_LENGTH_MASK ){
flags |= LOOK_LONG; /* Very long line -> binary */
}
j = 0;
}else if( c=='\r' ){
flags |= LOOK_CR;
if( n<(2*sizeof(WCHAR_T)) || UTF16_SWAP_IF(bReverse, z[1])!='\n' ){
flags |= LOOK_LONE_CR; /* More chars, next char is not LF */
}
}
}
if( n ){
flags |= LOOK_SHORT; /* The whole blob was not examined */
}
if( j>UTF16_LENGTH_MASK ){
flags |= LOOK_LONG; /* Very long line -> binary */
}
return flags;
}
/*
** This function returns an array of bytes representing the byte-order-mark
** for UTF-8.
*/
const unsigned char *get_utf8_bom(int *pnByte){
static const unsigned char bom[] = {
0xEF, 0xBB, 0xBF, 0x00, 0x00, 0x00
};
if( pnByte ) *pnByte = 3;
return bom;
}
/*
** This function returns non-zero if the blob starts with a UTF-8
** byte-order-mark (BOM).
*/
int starts_with_utf8_bom(const Blob *pContent, int *pnByte){
const char *z = blob_buffer(pContent);
int bomSize = 0;
const unsigned char *bom = get_utf8_bom(&bomSize);
if( pnByte ) *pnByte = bomSize;
if( blob_size(pContent)<bomSize ) return 0;
return memcmp(z, bom, bomSize)==0;
}
/*
** This function returns non-zero if the blob starts with a UTF-16
** byte-order-mark (BOM), either in the endianness of the machine
** or in reversed byte order. The UTF-32 BOM is ruled out by checking
** if the UTF-16 BOM is not immediately followed by (utf16) 0.
** pnByte is only set when the function returns 1.
**
** pbReverse is always set, even when no BOM is found. Without a BOM,
** it is set to 1 on little-endian and 0 on big-endian platforms. See
** clause D98 of conformance (section 3.10) of the Unicode standard.
*/
int starts_with_utf16_bom(
const Blob *pContent, /* IN: Blob content to perform BOM detection on. */
int *pnByte, /* OUT: The number of bytes used for the BOM. */
int *pbReverse /* OUT: Non-zero for BOM in reverse byte-order. */
){
const unsigned short *z = (unsigned short *)blob_buffer(pContent);
int bomSize = sizeof(unsigned short);
int size = blob_size(pContent);
if( size<bomSize ) goto noBom; /* No: cannot read BOM. */
if( size>=(2*bomSize) && z[1]==0 ) goto noBom; /* No: possible UTF-32. */
if( z[0]==0xfeff ){
if( pbReverse ) *pbReverse = 0;
}else if( z[0]==0xfffe ){
if( pbReverse ) *pbReverse = 1;
}else{
static const int one = 1;
noBom:
if( pbReverse ) *pbReverse = *(char *) &one;
return 0; /* No: UTF-16 byte-order-mark not found. */
}
if( pnByte ) *pnByte = bomSize;
return 1; /* Yes. */
}
/*
** Returns non-zero if the specified content could be valid UTF-16.
*/
int could_be_utf16(const Blob *pContent, int *pbReverse){
return (blob_size(pContent) % sizeof(WCHAR_T) == 0) ?
starts_with_utf16_bom(pContent, 0, pbReverse) : 0;
}
/*
** COMMAND: test-looks-like-utf
**
** Usage: %fossil test-looks-like-utf FILENAME
**
** Options:
** --utf8 Ignoring BOM and file size, force UTF-8 checking
** --utf16 Ignoring BOM and file size, force UTF-16 checking
**
** FILENAME is the name of a file to check for textual content in the UTF-8
** and/or UTF-16 encodings.
*/
void looks_like_utf_test_cmd(void){
Blob blob; /* the contents of the specified file */
int fUtf8; /* return value of starts_with_utf8_bom() */
int fUtf16; /* return value of starts_with_utf16_bom() */
int fUnicode; /* return value of could_be_utf16() */
int lookFlags; /* output flags from looks_like_utf8/utf16() */
int bRevUtf16 = 0; /* non-zero -> UTF-16 byte order reversed */
int bRevUnicode = 0; /* non-zero -> UTF-16 byte order reversed */
int fForceUtf8 = find_option("utf8",0,0)!=0;
int fForceUtf16 = find_option("utf16",0,0)!=0;
if( g.argc!=3 ) usage("FILENAME");
blob_read_from_file(&blob, g.argv[2]);
fUtf8 = starts_with_utf8_bom(&blob, 0);
fUtf16 = starts_with_utf16_bom(&blob, 0, &bRevUtf16);
if( fForceUtf8 ){
fUnicode = 0;
}else{
fUnicode = could_be_utf16(&blob, &bRevUnicode) || fForceUtf16;
}
lookFlags = fUnicode ? looks_like_utf16(&blob, bRevUnicode, 0) :
looks_like_utf8(&blob, 0);
fossil_print("File \"%s\" has %d bytes.\n",g.argv[2],blob_size(&blob));
fossil_print("Starts with UTF-8 BOM: %s\n",fUtf8?"yes":"no");
fossil_print("Starts with UTF-16 BOM: %s\n",
fUtf16?(bRevUtf16?"reversed":"yes"):"no");
fossil_print("Looks like UTF-%s: %s\n",fUnicode?"16":"8",
(lookFlags&LOOK_BINARY)?"no":"yes");
fossil_print("Has flag LOOK_NUL: %s\n",(lookFlags&LOOK_NUL)?"yes":"no");
fossil_print("Has flag LOOK_CR: %s\n",(lookFlags&LOOK_CR)?"yes":"no");
fossil_print("Has flag LOOK_LONE_CR: %s\n",
(lookFlags&LOOK_LONE_CR)?"yes":"no");
fossil_print("Has flag LOOK_LF: %s\n",(lookFlags&LOOK_LF)?"yes":"no");
fossil_print("Has flag LOOK_LONE_LF: %s\n",
(lookFlags&LOOK_LONE_LF)?"yes":"no");
fossil_print("Has flag LOOK_CRLF: %s\n",(lookFlags&LOOK_CRLF)?"yes":"no");
fossil_print("Has flag LOOK_LONG: %s\n",(lookFlags&LOOK_LONG)?"yes":"no");
fossil_print("Has flag LOOK_INVALID: %s\n",
(lookFlags&LOOK_INVALID)?"yes":"no");
fossil_print("Has flag LOOK_ODD: %s\n",(lookFlags&LOOK_ODD)?"yes":"no");
fossil_print("Has flag LOOK_SHORT: %s\n",(lookFlags&LOOK_SHORT)?"yes":"no");
blob_reset(&blob);
}
|
Changes to src/main.c.
| ︙ | ︙ | |||
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
*/
struct TclContext {
int argc; /* Number of original (expanded) arguments. */
char **argv; /* Full copy of the original (expanded) arguments. */
void *library; /* The Tcl library module handle. */
void *xFindExecutable; /* See tcl_FindExecutableProc in th_tcl.c. */
void *xCreateInterp; /* See tcl_CreateInterpProc in th_tcl.c. */
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
char *setup; /* The optional Tcl setup script. */
void *xPreEval; /* Optional, called before Tcl_Eval*(). */
void *pPreContext; /* Optional, provided to xPreEval(). */
void *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
/*
** All global variables are in this structure.
*/
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
char *nameOfExe; /* Full path of executable. */
int isConst; /* True if the output is unchanging */
sqlite3 *db; /* The connection to the databases */
sqlite3 *dbConfig; /* Separate connection for global_config table */
int useAttach; /* True if global_config is attached to repository */
const char *zConfigDbName;/* Path of the config database. NULL if not open */
sqlite3_int64 now; /* Seconds since 1970 */
int repositoryOpen; /* True if the main repository database is open */
char *zRepositoryName; /* Name of the repository database */
const char *zMainDbType;/* "configdb", "localdb", or "repository" */
const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
int localOpen; /* True if the local database is open */
char *zLocalRoot; /* The directory holding the local database */
int minPrefix; /* Number of digits needed for a distinct UUID */
int fSqlTrace; /* True if --sqltrace flag is present */
int fSqlStats; /* True if --sqltrace or --sqlstats are present */
int fSqlPrint; /* True if -sqlprint flag is present */
int fQuiet; /* True if -quiet flag is present */
int fHttpTrace; /* Trace outbound HTTP requests */
int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
int fSshTrace; /* Trace the SSH setup traffic */
int fNoSync; /* Do not do an autosync ever. --nosync */
char *zPath; /* Name of webpage being served */
char *zExtra; /* Extra path information past the webpage name */
char *zBaseURL; /* Full text of the URL being served */
char *zTop; /* Parent directory of zPath */
const char *zContentType; /* The content type of the input HTTP request */
int iErrPriority; /* Priority of current error message */
| > > > > > > > > > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
*/
struct TclContext {
int argc; /* Number of original (expanded) arguments. */
char **argv; /* Full copy of the original (expanded) arguments. */
void *library; /* The Tcl library module handle. */
void *xFindExecutable; /* See tcl_FindExecutableProc in th_tcl.c. */
void *xCreateInterp; /* See tcl_CreateInterpProc in th_tcl.c. */
void *xDeleteInterp; /* See tcl_DeleteInterpProc in th_tcl.c. */
void *xFinalize; /* See tcl_FinalizeProc in th_tcl.c. */
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
int useObjProc; /* Non-zero if an objProc can be called directly. */
char *setup; /* The optional Tcl setup script. */
void *xPreEval; /* Optional, called before Tcl_Eval*(). */
void *pPreContext; /* Optional, provided to xPreEval(). */
void *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
/*
** All global variables are in this structure.
*/
#define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
struct Global {
int argc; char **argv; /* Command-line arguments to the program */
char *nameOfExe; /* Full path of executable. */
const char *zErrlog; /* Log errors to this file, if not NULL */
int isConst; /* True if the output is unchanging */
const char *zVfsName; /* The VFS to use for database connections */
sqlite3 *db; /* The connection to the databases */
sqlite3 *dbConfig; /* Separate connection for global_config table */
int useAttach; /* True if global_config is attached to repository */
const char *zConfigDbName;/* Path of the config database. NULL if not open */
sqlite3_int64 now; /* Seconds since 1970 */
int repositoryOpen; /* True if the main repository database is open */
char *zRepositoryName; /* Name of the repository database */
const char *zMainDbType;/* "configdb", "localdb", or "repository" */
const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
int localOpen; /* True if the local database is open */
char *zLocalRoot; /* The directory holding the local database */
int minPrefix; /* Number of digits needed for a distinct UUID */
int fSqlTrace; /* True if --sqltrace flag is present */
int fSqlStats; /* True if --sqltrace or --sqlstats are present */
int fSqlPrint; /* True if -sqlprint flag is present */
int fQuiet; /* True if -quiet flag is present */
int fHttpTrace; /* Trace outbound HTTP requests */
int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
int fSshTrace; /* Trace the SSH setup traffic */
int fSshClient; /* HTTP client flags for SSH client */
char *zSshCmd; /* SSH command string */
int fNoSync; /* Do not do an autosync ever. --nosync */
char *zPath; /* Name of webpage being served */
char *zExtra; /* Extra path information past the webpage name */
char *zBaseURL; /* Full text of the URL being served */
char *zTop; /* Parent directory of zPath */
const char *zContentType; /* The content type of the input HTTP request */
int iErrPriority; /* Priority of current error message */
|
| ︙ | ︙ | |||
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ int clockSkewSeen; /* True if clocks on client and server out of sync */ int wikiFlags; /* Wiki conversion flags applied to %w and %W */ char isHTTP; /* True if server/CGI modes, else assume CLI. */ char javascriptHyperlink; /* If true, set href= using script, not HTML */ int urlIsFile; /* True if a "file:" url */ int urlIsHttps; /* True if a "https:" url */ int urlIsSsh; /* True if an "ssh:" url */ char *urlName; /* Hostname for http: or filename for file: */ char *urlHostname; /* The HOST: parameter on http headers */ char *urlProtocol; /* "http" or "https" */ int urlPort; /* TCP port number for http: or https: */ int urlDfltPort; /* The default port for the given protocol */ char *urlPath; /* Pathname for http: */ char *urlUser; /* User id for http: */ char *urlPasswd; /* Password for http: */ char *urlCanonical; /* Canonical representation of the URL */ char *urlProxyAuth; /* Proxy-Authorizer: string */ char *urlFossil; /* The fossil query parameter on ssh: */ | > > > > > < | > > > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
int *aCommitFile; /* Array of files to be committed */
int markPrivate; /* All new artifacts are private if true */
int clockSkewSeen; /* True if clocks on client and server out of sync */
int wikiFlags; /* Wiki conversion flags applied to %w and %W */
char isHTTP; /* True if server/CGI modes, else assume CLI. */
char javascriptHyperlink; /* If true, set href= using script, not HTML */
Blob httpHeader; /* Complete text of the HTTP request header */
/*
** NOTE: These members MUST be kept in sync with those in the "UrlData"
** structure defined in "url.c".
*/
int urlIsFile; /* True if a "file:" url */
int urlIsHttps; /* True if a "https:" url */
int urlIsSsh; /* True if an "ssh:" url */
char *urlName; /* Hostname for http: or filename for file: */
char *urlHostname; /* The HOST: parameter on http headers */
char *urlProtocol; /* "http" or "https" */
int urlPort; /* TCP port number for http: or https: */
int urlDfltPort; /* The default port for the given protocol */
char *urlPath; /* Pathname for http: */
char *urlUser; /* User id for http: */
char *urlPasswd; /* Password for http: */
char *urlCanonical; /* Canonical representation of the URL */
char *urlProxyAuth; /* Proxy-Authorizer: string */
char *urlFossil; /* The fossil query parameter on ssh: */
unsigned urlFlags; /* Boolean flags controlling URL processing */
int useProxy; /* Used to remember that a proxy is in use */
char *proxyUrlPath;
int proxyOrigPort; /* Tunneled port number for https through proxy */
const char *zLogin; /* Login name. "" if not logged in. */
const char *zSSLIdentity; /* Value of --ssl-identity option, filename of
** SSL client identity */
int useLocalauth; /* No login required if from 127.0.0.1 */
int noPswd; /* Logged in without password (on 127.0.0.1) */
int userUid; /* Integer user id */
int isHuman; /* True if access by a human, not a spider or bot */
/* Information used to populate the RCVFROM table */
int rcvid; /* The rcvid. 0 if not yet defined. */
char *zIpAddr; /* The remote IP address */
char *zNonce; /* The nonce used for login */
/* permissions used by the server */
|
| ︙ | ︙ | |||
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
}
/*
** atexit() handler which frees up "some" of the resources
** used by fossil.
*/
static void fossil_atexit(void) {
#ifdef FOSSIL_ENABLE_JSON
cson_value_free(g.json.gc.v);
memset(&g.json, 0, sizeof(g.json));
#endif
free(g.zErrMsg);
if(g.db){
db_close(0);
}
}
/*
** Convert all arguments from mbcs (or unicode) to UTF-8. Then
** search g.argv for arguments "--args FILENAME". If found, then
** (1) remove the two arguments from g.argv
** (2) Read the file FILENAME
| > > > > > > > > > > > > > > > > > > > > > > > > | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
}
/*
** atexit() handler which frees up "some" of the resources
** used by fossil.
*/
static void fossil_atexit(void) {
#if defined(_WIN32) && !defined(_WIN64) && defined(FOSSIL_ENABLE_TCL) && \
defined(USE_TCL_STUBS)
/*
** If Tcl is compiled on Windows using the latest MinGW, Fossil can crash
** when exiting while a stubs-enabled Tcl is still loaded. This is due to
** a bug in MinGW, see:
**
** http://comments.gmane.org/gmane.comp.gnu.mingw.user/41724
**
** The workaround is to manually unload the loaded Tcl library prior to
** exiting the process. This issue does not impact 64-bit Windows.
*/
unloadTcl(g.interp, &g.tcl);
#endif
#ifdef FOSSIL_ENABLE_JSON
cson_value_free(g.json.gc.v);
memset(&g.json, 0, sizeof(g.json));
#endif
free(g.zErrMsg);
if(g.db){
db_close(0);
}
/*
** FIXME: The next two lines cannot always be enabled; however, they
** are very useful for tracking down TH1 memory leaks.
*/
if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){
if( g.interp ){
Th_DeleteInterp(g.interp); g.interp = 0;
}
assert( Th_GetOutstandingMalloc()==0 );
}
}
/*
** Convert all arguments from mbcs (or unicode) to UTF-8. Then
** search g.argv for arguments "--args FILENAME". If found, then
** (1) remove the two arguments from g.argv
** (2) Read the file FILENAME
|
| ︙ | ︙ | |||
368 369 370 371 372 373 374 | Blob line = empty_blob; /* One line of the file */ unsigned int nLine; /* Number of lines in the file*/ unsigned int i, j, k; /* Loop counters */ int n; /* Number of bytes in one line */ char *z; /* General use string pointer */ char **newArgv; /* New expanded g.argv under construction */ char const * zFileName; /* input file name */ | | | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | Blob line = empty_blob; /* One line of the file */ unsigned int nLine; /* Number of lines in the file*/ unsigned int i, j, k; /* Loop counters */ int n; /* Number of bytes in one line */ char *z; /* General use string pointer */ char **newArgv; /* New expanded g.argv under construction */ char const * zFileName; /* input file name */ FILE *inFile; /* input FILE */ #if defined(_WIN32) wchar_t buf[MAX_PATH]; #endif g.argc = argc; g.argv = argv; sqlite3_initialize(); |
| ︙ | ︙ | |||
398 399 400 401 402 403 404 |
if( z[0]=='-' ) z++;
if( z[0]==0 ) return; /* Stop searching at "--" */
if( fossil_strcmp(z, "args")==0 ) break;
}
if( i>=g.argc-1 ) return;
zFileName = g.argv[i+1];
| | | | | | | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
if( z[0]=='-' ) z++;
if( z[0]==0 ) return; /* Stop searching at "--" */
if( fossil_strcmp(z, "args")==0 ) break;
}
if( i>=g.argc-1 ) return;
zFileName = g.argv[i+1];
inFile = (0==strcmp("-",zFileName))
? stdin
: fossil_fopen(zFileName,"rb");
if(!inFile){
fossil_fatal("Cannot open -args file [%s]", zFileName);
}else{
blob_read_from_channel(&file, inFile, -1);
if(stdin != inFile){
fclose(inFile);
}
inFile = NULL;
}
blob_to_utf8_no_bom(&file, 1);
z = blob_str(&file);
for(k=0, nLine=1; z[k]; k++) if( z[k]=='\n' ) nLine++;
newArgv = fossil_malloc( sizeof(char*)*(g.argc + nLine*2) );
for(j=0; j<i; j++) newArgv[j] = g.argv[j];
|
| ︙ | ︙ | |||
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 |
/* Error logs from SQLite */
static void fossil_sqlite_log(void *notUsed, int iCode, const char *zErrmsg){
#ifdef __APPLE__
/* Disable the file alias warning on apple products because Time Machine
** creates lots of aliases and the warning alarms people. */
if( iCode==SQLITE_WARNING ) return;
#endif
fossil_warning("%s: %s", sqlite_error_code_name(iCode), zErrmsg);
}
/*
** This procedure runs first.
*/
#if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
int _dowildcard = -1; /* This turns on command-line globbing in MinGW-w64 */
int wmain(int argc, wchar_t **argv)
#else
int main(int argc, char **argv)
#endif
{
const char *zCmdName = "unknown";
int idx;
int rc;
sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
memset(&g, 0, sizeof(g));
g.now = time(0);
#ifdef FOSSIL_ENABLE_JSON
#if defined(NDEBUG)
g.json.errorDetailParanoia = 2 /* FIXME: make configurable
One problem we have here is that this
code is needed before the db is opened,
so we can't sql for it.*/;
#else
g.json.errorDetailParanoia = 0;
#endif
g.json.outOpt = cson_output_opt_empty;
g.json.outOpt.addNewline = 1;
g.json.outOpt.indentation = 1 /* in CGI/server mode this can be configured */;
#endif /* FOSSIL_ENABLE_JSON */
expand_args_option(argc, argv);
#ifdef FOSSIL_ENABLE_TCL
memset(&g.tcl, 0, sizeof(TclContext));
g.tcl.argc = g.argc;
g.tcl.argv = copy_args(g.argc, g.argv); /* save full arguments */
#endif
g.mainTimerId = fossil_timer_start();
if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
zCmdName = "cgi";
g.isHTTP = 1;
}else if( g.argc<2 ){
fossil_print(
"Usage: %s COMMAND ...\n"
" or: %s help -- for a list of common commands\n"
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
/* Error logs from SQLite */
static void fossil_sqlite_log(void *notUsed, int iCode, const char *zErrmsg){
#ifdef __APPLE__
/* Disable the file alias warning on apple products because Time Machine
** creates lots of aliases and the warning alarms people. */
if( iCode==SQLITE_WARNING ) return;
#endif
if( iCode==SQLITE_SCHEMA ) return;
fossil_warning("%s: %s", sqlite_error_code_name(iCode), zErrmsg);
}
/*
** This procedure runs first.
*/
#if defined(_WIN32) && !defined(BROKEN_MINGW_CMDLINE)
int _dowildcard = -1; /* This turns on command-line globbing in MinGW-w64 */
int wmain(int argc, wchar_t **argv)
#else
#if defined(_WIN32)
int _CRT_glob = 0x0001; /* See MinGW bug #2062 */
#endif
int main(int argc, char **argv)
#endif
{
const char *zCmdName = "unknown";
int idx;
int rc;
if( sqlite3_libversion_number()<3008003 ){
fossil_fatal("Unsuitable SQLite version %s, must be at least 3.8.3",
sqlite3_libversion());
}
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
memset(&g, 0, sizeof(g));
g.now = time(0);
g.httpHeader = empty_blob;
#ifdef FOSSIL_ENABLE_JSON
#if defined(NDEBUG)
g.json.errorDetailParanoia = 2 /* FIXME: make configurable
One problem we have here is that this
code is needed before the db is opened,
so we can't sql for it.*/;
#else
g.json.errorDetailParanoia = 0;
#endif
g.json.outOpt = cson_output_opt_empty;
g.json.outOpt.addNewline = 1;
g.json.outOpt.indentation = 1 /* in CGI/server mode this can be configured */;
#endif /* FOSSIL_ENABLE_JSON */
expand_args_option(argc, argv);
#ifdef FOSSIL_ENABLE_TCL
memset(&g.tcl, 0, sizeof(TclContext));
g.tcl.argc = g.argc;
g.tcl.argv = copy_args(g.argc, g.argv); /* save full arguments */
#endif
g.mainTimerId = fossil_timer_start();
g.zVfsName = find_option("vfs",0,1);
if( g.zVfsName==0 ){
g.zVfsName = fossil_getenv("FOSSIL_VFS");
#if defined(__CYGWIN__)
if( g.zVfsName==0 ){
g.zVfsName = "win32-longpath";
}
#endif
}
if( g.zVfsName ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName);
if( pVfs ){
sqlite3_vfs_register(pVfs, 1);
}else{
fossil_fatal("no such VFS: \"%s\"", g.zVfsName);
}
}
if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
zCmdName = "cgi";
g.isHTTP = 1;
}else if( g.argc<2 ){
fossil_print(
"Usage: %s COMMAND ...\n"
" or: %s help -- for a list of common commands\n"
|
| ︙ | ︙ | |||
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
const char *zChdir = find_option("chdir",0,1);
g.isHTTP = 0;
g.fQuiet = find_option("quiet", 0, 0)!=0;
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
if( g.fSqlTrace ) g.fSqlStats = 1;
g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
g.zLogin = find_option("user", "U", 1);
g.zSSLIdentity = find_option("ssl-identity", 0, 1);
if( find_option("utc",0,0) ) g.fTimeFormat = 1;
if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
if( zChdir && file_chdir(zChdir, 0) ){
fossil_fatal("unable to change directories to %s", zChdir);
}
if( find_option("help",0,0)!=0 ){
/* --help anywhere on the command line is translated into
** "fossil help argv[1] argv[2]..." */
int i;
char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+2) );
for(i=1; i<g.argc; i++) zNewArgv[i+1] = g.argv[i];
zNewArgv[i+1] = 0;
zNewArgv[0] = g.argv[0];
zNewArgv[1] = "help";
g.argc++;
g.argv = zNewArgv;
}
zCmdName = g.argv[1];
}
rc = name_search(zCmdName, aCommand, count(aCommand), &idx);
if( rc==1 ){
fossil_fatal("%s: unknown command: %s\n"
"%s: use \"help\" for more information\n",
g.argv[0], zCmdName, g.argv[0]);
}else if( rc==2 ){
int i, n;
| > > > > > > > | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 |
const char *zChdir = find_option("chdir",0,1);
g.isHTTP = 0;
g.fQuiet = find_option("quiet", 0, 0)!=0;
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
g.fSshClient = 0;
g.zSshCmd = 0;
if( g.fSqlTrace ) g.fSqlStats = 1;
g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
g.zLogin = find_option("user", "U", 1);
g.zSSLIdentity = find_option("ssl-identity", 0, 1);
g.zErrlog = find_option("errorlog", 0, 1);
if( find_option("utc",0,0) ) g.fTimeFormat = 1;
if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
if( zChdir && file_chdir(zChdir, 0) ){
fossil_fatal("unable to change directories to %s", zChdir);
}
if( find_option("help",0,0)!=0 ){
/* --help anywhere on the command line is translated into
** "fossil help argv[1] argv[2]..." */
int i;
char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+2) );
for(i=1; i<g.argc; i++) zNewArgv[i+1] = g.argv[i];
zNewArgv[i+1] = 0;
zNewArgv[0] = g.argv[0];
zNewArgv[1] = "help";
g.argc++;
g.argv = zNewArgv;
}
zCmdName = g.argv[1];
}
#ifndef _WIN32
if( !is_valid_fd(2) ) fossil_panic("file descriptor 2 not open");
/* if( is_valid_fd(3) ) fossil_warning("file descriptor 3 is open"); */
#endif
rc = name_search(zCmdName, aCommand, count(aCommand), &idx);
if( rc==1 ){
fossil_fatal("%s: unknown command: %s\n"
"%s: use \"help\" for more information\n",
g.argv[0], zCmdName, g.argv[0]);
}else if( rc==2 ){
int i, n;
|
| ︙ | ︙ | |||
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 |
aCmd[nCmd++] = aWebpage[i].zName;
}
}
assert(nCmd && "page list is empty?");
multi_column_list(aCmd, nCmd);
}
/*
** COMMAND: version
**
** Usage: %fossil version ?-verbose|-v?
**
** Print the source code version number for the fossil executable.
** If the verbose option is specified, additional details will
** be output about what optional features this binary was compiled
** with
*/
void version_cmd(void){
| > > > > > > > > > > > > > > > > > > > > > | < > > > > | > | > > > | > > > > > > > > | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
aCmd[nCmd++] = aWebpage[i].zName;
}
}
assert(nCmd && "page list is empty?");
multi_column_list(aCmd, nCmd);
}
/*
** This function returns a human readable version string.
*/
const char *get_version(){
static const char version[] = RELEASE_VERSION " " MANIFEST_VERSION " "
MANIFEST_DATE " UTC";
return version;
}
/*
** This function returns the user-agent string for Fossil, for
** use in HTTP(S) requests.
*/
const char *get_user_agent(){
static const char version[] = "Fossil/" RELEASE_VERSION " (" MANIFEST_DATE
" " MANIFEST_VERSION ")";
return version;
}
/*
** COMMAND: version
**
** Usage: %fossil version ?-verbose|-v?
**
** Print the source code version number for the fossil executable.
** If the verbose option is specified, additional details will
** be output about what optional features this binary was compiled
** with
*/
void version_cmd(void){
fossil_print("This is fossil version %s\n", get_version());
if(!find_option("verbose","v",0)){
return;
}else{
#if defined(FOSSIL_ENABLE_TCL)
int rc;
const char *zRc;
#endif
fossil_print("Compiled on %s %s using %s (%d-bit)\n",
__DATE__, __TIME__, COMPILER_NAME, sizeof(void*)*8);
fossil_print("SQLite %s %.30s\n", sqlite3_libversion(), sqlite3_sourceid());
fossil_print("Schema version %s\n", AUX_SCHEMA);
fossil_print("zlib %s, loaded %s\n", ZLIB_VERSION, zlibVersion());
#if defined(FOSSIL_ENABLE_SSL)
fossil_print("SSL (%s)\n", OPENSSL_VERSION_TEXT);
#endif
#if defined(FOSSIL_ENABLE_TCL)
Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL);
rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1);
zRc = Th_ReturnCodeName(rc, 0);
fossil_print("TCL (Tcl %s, loaded %s: %s)\n",
TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0)
);
#endif
#if defined(USE_TCL_STUBS)
fossil_print("USE_TCL_STUBS\n");
#endif
#if defined(FOSSIL_ENABLE_TCL_STUBS)
fossil_print("TCL_STUBS\n");
#endif
#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
fossil_print("TCL_PRIVATE_STUBS\n");
#endif
#if defined(FOSSIL_ENABLE_JSON)
fossil_print("JSON (API %s)\n", FOSSIL_JSON_API_VERSION);
#endif
}
}
|
| ︙ | ︙ | |||
986 987 988 989 990 991 992 993 994 995 996 997 998 999 |
}
}
if( j>0 ){
@ </ul></td>
}
@ </tr></table>
}
style_footer();
}
/*
** WEBPAGE: test-all-help
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 |
}
}
if( j>0 ){
@ </ul></td>
}
@ </tr></table>
@ <h1>Unsupported commands:</h1>
@ <table border="0"><tr>
for(i=j=0; i<count(aCommand); i++){
const char *z = aCommand[i].zName;
if( strncmp(z,"test",4)!=0 ) continue;
j++;
}
n = (j+3)/4;
for(i=j=0; i<count(aCommand); i++){
const char *z = aCommand[i].zName;
if( strncmp(z,"test",4)!=0 ) continue;
if( j==0 ){
@ <td valign="top"><ul>
}
if( aCmdHelp[i].zText && *aCmdHelp[i].zText ){
@ <li><a href="%s(g.zTop)/help?cmd=%s(z)">%s(z)</a></li>
}else{
@ <li>%s(z)</li>
}
j++;
if( j>=n ){
@ </ul></td>
j = 0;
}
}
if( j>0 ){
@ </ul></td>
}
@ </tr></table>
}
style_footer();
}
/*
** WEBPAGE: test-all-help
**
|
| ︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 |
static char *enter_chroot_jail(char *zRepo){
#if !defined(_WIN32)
if( getuid()==0 ){
int i;
struct stat sStat;
Blob dir;
char *zDir;
file_canonical_name(zRepo, &dir, 0);
zDir = blob_str(&dir);
if( file_isdir(zDir)==1 ){
if( file_chdir(zDir, 1) ){
fossil_fatal("unable to chroot into %s", zDir);
}
zRepo = "/";
}else{
for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
| > > > | < < < < | 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 |
static char *enter_chroot_jail(char *zRepo){
#if !defined(_WIN32)
if( getuid()==0 ){
int i;
struct stat sStat;
Blob dir;
char *zDir;
if( g.db!=0 ){
db_close(1);
}
file_canonical_name(zRepo, &dir, 0);
zDir = blob_str(&dir);
if( file_isdir(zDir)==1 ){
if( file_chdir(zDir, 1) ){
fossil_fatal("unable to chroot into %s", zDir);
}
zRepo = "/";
}else{
for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
if( zDir[i]!='/' ) fossil_fatal("bad repository name: %s", zRepo);
if( i>0 ){
zDir[i] = 0;
if( file_chdir(zDir, 1) ){
fossil_fatal("unable to chroot into %s", zDir);
}
zDir[i] = '/';
}
zRepo = &zDir[i];
}
if( stat(zRepo, &sStat)!=0 ){
fossil_fatal("cannot stat() repository: %s", zRepo);
}
i = setgid(sStat.st_gid);
i = i || setuid(sStat.st_uid);
if(i){
fossil_fatal("setgid/uid() failed with errno %d", errno);
}
}
#endif
return zRepo;
}
/*
** Preconditions:
|
| ︙ | ︙ | |||
1264 1265 1266 1267 1268 1269 1270 |
zRepo, zPathInfo, zNewScript);
}
}
/* Find the page that the user has requested, construct and deliver that
** page.
*/
| > | | 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 |
zRepo, zPathInfo, zNewScript);
}
}
/* Find the page that the user has requested, construct and deliver that
** page.
*/
if( g.zContentType &&
strncmp(g.zContentType, "application/x-fossil", 20)==0 ){
zPathInfo = "/xfer";
}
set_base_url(0);
if( zPathInfo==0 || zPathInfo[0]==0
|| (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode){
|
| ︙ | ︙ | |||
1361 1362 1363 1364 1365 1366 1367 |
** handling below, and by disabling it in JSON mode I can remove
** lots of special-case handling in several JSON handlers.
*/
#ifdef FOSSIL_ENABLE_JSON
if(!g.json.isJsonMode){
#endif
dehttpize(g.zExtra);
| | | 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 |
** handling below, and by disabling it in JSON mode I can remove
** lots of special-case handling in several JSON handlers.
*/
#ifdef FOSSIL_ENABLE_JSON
if(!g.json.isJsonMode){
#endif
dehttpize(g.zExtra);
cgi_set_parameter_nocopy("name", g.zExtra, 1);
#ifdef FOSSIL_ENABLE_JSON
}
#endif
}
/* Locate the method specified by the path and execute the function
** that implements that method.
|
| ︙ | ︙ | |||
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 |
while( blob_line(&config, &line) ){
if( !blob_token(&line, &key) ) continue;
if( blob_buffer(&key)[0]=='#' ) continue;
if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
g.fDebug = fossil_fopen(blob_str(&value), "ab");
blob_reset(&value);
continue;
}
if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
cgi_setenv("HOME", blob_str(&value));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
| > > > > | 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 |
while( blob_line(&config, &line) ){
if( !blob_token(&line, &key) ) continue;
if( blob_buffer(&key)[0]=='#' ) continue;
if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
g.fDebug = fossil_fopen(blob_str(&value), "ab");
blob_reset(&value);
continue;
}
if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
g.zErrlog = mprintf("%s", blob_str(&value));
continue;
}
if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
cgi_setenv("HOME", blob_str(&value));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
|
| ︙ | ︙ | |||
1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 |
** --localauth enable automatic login for local connections
** --host NAME specify hostname of the server
** --https signal a request coming in via https
** --nossl signal that no SSL connections are available
** --notfound URL use URL as "HTTP 404, object not found" page.
** --files GLOB comma-separate glob patterns for static file to serve
** --baseurl URL base URL (useful with reverse proxies)
**
** See also: cgi, server, winsrv
*/
void cmd_http(void){
const char *zIpAddr;
const char *zNotFound;
const char *zHost;
const char *zAltBase;
const char *zFileGlob;
/* The winhttp module passes the --files option as --files-urlenc with
** the argument being URL encoded, to avoid wildcard expansion in the
** shell. This option is for internal use and is undocumented.
*/
zFileGlob = find_option("files-urlenc",0,1);
if( zFileGlob ){
char *z = mprintf("%s", zFileGlob);
dehttpize(z);
zFileGlob = z;
}else{
zFileGlob = find_option("files",0,1);
}
zNotFound = find_option("notfound", 0, 1);
g.useLocalauth = find_option("localauth", 0, 0)!=0;
g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
zAltBase = find_option("baseurl", 0, 1);
if( zAltBase ) set_base_url(zAltBase);
if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
zHost = find_option("host", 0, 1);
if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
g.cgiOutput = 1;
if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
fossil_fatal("no repository specified");
}
g.fullHttpReply = 1;
if( g.argc==6 ){
g.httpIn = fossil_fopen(g.argv[3], "rb");
g.httpOut = fossil_fopen(g.argv[4], "wb");
zIpAddr = g.argv[5];
}else{
g.httpIn = stdin;
g.httpOut = stdout;
zIpAddr = 0;
}
find_server_repository(0);
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
| > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > < > > > > > > | | > | 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 |
** --localauth enable automatic login for local connections
** --host NAME specify hostname of the server
** --https signal a request coming in via https
** --nossl signal that no SSL connections are available
** --notfound URL use URL as "HTTP 404, object not found" page.
** --files GLOB comma-separate glob patterns for static file to serve
** --baseurl URL base URL (useful with reverse proxies)
** --scgi Interpret input as SCGI rather than HTTP
**
** See also: cgi, server, winsrv
*/
void cmd_http(void){
const char *zIpAddr;
const char *zNotFound;
const char *zHost;
const char *zAltBase;
const char *zFileGlob;
int useSCGI;
/* The winhttp module passes the --files option as --files-urlenc with
** the argument being URL encoded, to avoid wildcard expansion in the
** shell. This option is for internal use and is undocumented.
*/
zFileGlob = find_option("files-urlenc",0,1);
if( zFileGlob ){
char *z = mprintf("%s", zFileGlob);
dehttpize(z);
zFileGlob = z;
}else{
zFileGlob = find_option("files",0,1);
}
zNotFound = find_option("notfound", 0, 1);
g.useLocalauth = find_option("localauth", 0, 0)!=0;
g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
useSCGI = find_option("scgi", 0, 0)!=0;
zAltBase = find_option("baseurl", 0, 1);
if( zAltBase ) set_base_url(zAltBase);
if( find_option("https",0,0)!=0 ) cgi_replace_parameter("HTTPS","on");
zHost = find_option("host", 0, 1);
if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
g.cgiOutput = 1;
if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
fossil_fatal("no repository specified");
}
g.fullHttpReply = 1;
if( g.argc==6 ){
g.httpIn = fossil_fopen(g.argv[3], "rb");
g.httpOut = fossil_fopen(g.argv[4], "wb");
zIpAddr = g.argv[5];
}else{
g.httpIn = stdin;
g.httpOut = stdout;
zIpAddr = 0;
}
if( zIpAddr==0 ){
zIpAddr = cgi_ssh_remote_addr(0);
if( zIpAddr && zIpAddr[0] ){
g.fSshClient |= CGI_SSH_CLIENT;
}
}
find_server_repository(0);
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
if( useSCGI ){
cgi_handle_scgi_request();
}else if( g.fSshClient & CGI_SSH_CLIENT ){
ssh_request_loop(zIpAddr, glob_create(zFileGlob));
}else{
cgi_handle_http_request(zIpAddr);
}
process_one_web_page(zNotFound, glob_create(zFileGlob));
}
/*
** Process all requests in a single SSH connection if possible.
*/
void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){
do{
cgi_handle_ssh_http_request(zIpAddr);
process_one_web_page(0, FileGlob);
blob_reset(&g.cgiIn);
} while ( g.fSshClient & CGI_SSH_FOSSIL ||
g.fSshClient & CGI_SSH_COMPAT );
}
/*
** Note that the following command is used by ssh:// processing.
**
** COMMAND: test-http
** Works like the http command but gives setup permission to all users.
**
*/
void cmd_test_http(void){
const char *zIpAddr; /* IP address of remote client */
Th_InitTraceLog();
login_set_capabilities("sx", 0);
g.useLocalauth = 1;
g.httpIn = stdin;
g.httpOut = stdout;
find_server_repository(0);
g.cgiOutput = 1;
g.fullHttpReply = 1;
zIpAddr = cgi_ssh_remote_addr(0);
if( zIpAddr && zIpAddr[0] ){
g.fSshClient |= CGI_SSH_CLIENT;
ssh_request_loop(zIpAddr, 0);
}else{
cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
cgi_handle_http_request(0);
process_one_web_page(0, 0);
}
}
#if !defined(_WIN32)
#if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
/*
** Search for an executable on the PATH environment variable.
** Return true (1) if found and false (0) if not found.
|
| ︙ | ︙ | |||
1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 |
** --localauth enable automatic login for requests from localhost
** --localhost listen on 127.0.0.1 only (always true for "ui")
** -P|--port TCPPORT listen to request on port TCPPORT
** --th-trace trace TH1 execution (for debugging purposes)
** --baseurl URL Use URL as the base (useful for reverse proxies)
** --notfound URL Redirect
** --files GLOBLIST Comma-separated list of glob patterns for static files
**
** See also: cgi, http, winsrv
*/
void cmd_webserver(void){
int iPort, mxPort; /* Range of TCP ports allowed */
const char *zPort; /* Value of the --port option */
const char *zBrowser; /* Name of web browser program */
| > | 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 |
** --localauth enable automatic login for requests from localhost
** --localhost listen on 127.0.0.1 only (always true for "ui")
** -P|--port TCPPORT listen to request on port TCPPORT
** --th-trace trace TH1 execution (for debugging purposes)
** --baseurl URL Use URL as the base (useful for reverse proxies)
** --notfound URL Redirect
** --files GLOBLIST Comma-separated list of glob patterns for static files
** --scgi Accept SCGI rather than HTTP
**
** See also: cgi, http, winsrv
*/
void cmd_webserver(void){
int iPort, mxPort; /* Range of TCP ports allowed */
const char *zPort; /* Value of the --port option */
const char *zBrowser; /* Name of web browser program */
|
| ︙ | ︙ | |||
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 |
zFileGlob = find_option("files", 0, 1);
g.useLocalauth = find_option("localauth", 0, 0)!=0;
Th_InitTraceLog();
zPort = find_option("port", "P", 1);
zNotFound = find_option("notfound", 0, 1);
zAltBase = find_option("baseurl", 0, 1);
if( zAltBase ){
set_base_url(zAltBase);
}
if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
isUiCmd = g.argv[1][0]=='u';
if( isUiCmd ){
flags |= HTTP_SERVER_LOCALHOST;
g.useLocalauth = 1;
| > > > > < < | 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 |
zFileGlob = find_option("files", 0, 1);
g.useLocalauth = find_option("localauth", 0, 0)!=0;
Th_InitTraceLog();
zPort = find_option("port", "P", 1);
zNotFound = find_option("notfound", 0, 1);
zAltBase = find_option("baseurl", 0, 1);
if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;
if( zAltBase ){
set_base_url(zAltBase);
}
if ( find_option("localhost", 0, 0)!=0 ){
flags |= HTTP_SERVER_LOCALHOST;
}
if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
isUiCmd = g.argv[1][0]=='u';
if( isUiCmd ){
flags |= HTTP_SERVER_LOCALHOST;
g.useLocalauth = 1;
}
find_server_repository(isUiCmd && zNotFound==0);
if( zPort ){
int i;
for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){}
if( i>0 ){
zIpAddr = mprintf("%.*s", i, zPort);
|
| ︙ | ︙ | |||
1862 1863 1864 1865 1866 1867 1868 |
g.httpOut = stdout;
if( g.fHttpTrace || g.fSqlTrace ){
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
}
g.cgiOutput = 1;
find_server_repository(isUiCmd && zNotFound==0);
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
| > > > | > | 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 |
g.httpOut = stdout;
if( g.fHttpTrace || g.fSqlTrace ){
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
}
g.cgiOutput = 1;
find_server_repository(isUiCmd && zNotFound==0);
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
if( flags & HTTP_SERVER_SCGI ){
cgi_handle_scgi_request();
}else{
cgi_handle_http_request(0);
}
process_one_web_page(zNotFound, glob_create(zFileGlob));
#else
/* Win32 implementation */
if( isUiCmd ){
zBrowser = db_get("web-browser", "start");
if( zIpAddr ){
zBrowserCmd = mprintf("%s http://%s:%%d/ &", zBrowser, zIpAddr);
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 75 76 77 78 | $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ | > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/lookslike.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ |
| ︙ | ︙ | |||
111 112 113 114 115 116 117 118 119 120 121 122 123 124 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ | > | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ |
| ︙ | ︙ | |||
173 174 175 176 177 178 179 180 181 182 183 184 185 186 | $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ | > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/lookslike_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ |
| ︙ | ︙ | |||
219 220 221 222 223 224 225 226 227 228 229 230 231 232 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ | > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ |
| ︙ | ︙ | |||
281 282 283 284 285 286 287 288 289 290 291 292 293 294 | $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ | > | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/lookslike.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ |
| ︙ | ︙ | |||
327 328 329 330 331 332 333 334 335 336 337 338 339 340 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil$(E) | > | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winfile.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil$(E) |
| ︙ | ︙ | |||
366 367 368 369 370 371 372 373 374 375 376 377 378 379 | # build is done from, i.e. the checkout belongs to. Do not sync/push # the repository after running the tests. test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o | > > > > > > > > > > > > | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
# build is done from, i.e. the checkout belongs to. Do not sync/push
# the repository after running the tests.
test: $(OBJDIR) $(APPNAME)
$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
# Setup the options used to compile the included SQLite library.
SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DSQLITE_ENABLE_LOCKING_STYLE=0 \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_DEFAULT_FILE_FORMAT=4 \
-DSQLITE_OMIT_DEPRECATED \
-DSQLITE_ENABLE_EXPLAIN_COMMENTS
# Setup the options used to compile the included SQLite shell.
SHELL_OPTIONS = -Dmain=sqlite3_shell \
-DSQLITE_OMIT_LOAD_EXTENSION=1
# The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
# to 1. If it is set to 1, then there is no need to build or link
# the sqlite3.o object. Instead, the system sqlite will be linked
# using -lsqlite3.
SQLITE3_OBJ.1 =
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
|
| ︙ | ︙ | |||
400 401 402 403 404 405 406 | clean: rm -rf $(OBJDIR)/* $(APPNAME) $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(OBJDIR)/mkindex $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h | | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | clean: rm -rf $(OBJDIR)/* $(APPNAME) $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex $(OBJDIR)/mkindex $(TRANS_SRC) >$@ $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_dir_.c:$(OBJDIR)/json_dir.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/unicode_.c:$(OBJDIR)/unicode.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h $(OBJDIR)/util_.c:$(OBJDIR)/util.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h touch $(OBJDIR)/headers $(OBJDIR)/headers: Makefile $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h Makefile: $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c |
| ︙ | ︙ | |||
790 791 792 793 794 795 796 797 798 799 800 801 802 803 | $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/main.c >$(OBJDIR)/main_.c $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c $(OBJDIR)/main.h: $(OBJDIR)/headers | > > > > > > > | 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers $(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h: $(OBJDIR)/headers $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/main.c >$(OBJDIR)/main_.c $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c $(OBJDIR)/main.h: $(OBJDIR)/headers |
| ︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers | > > > > > > > | 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winfile_.c: $(SRCDIR)/winfile.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/winfile.c >$(OBJDIR)/winfile_.c $(OBJDIR)/winfile.o: $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winfile.o -c $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h: $(OBJDIR)/headers |
| ︙ | ︙ | |||
1148 1149 1150 1151 1152 1153 1154 | $(OBJDIR)/translate $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c | | | | 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 | $(OBJDIR)/translate $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o $(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h $(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o $(OBJDIR)/th.o: $(SRCDIR)/th.c $(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c $(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o |
| ︙ | ︙ |
Changes to src/makemake.tcl.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 75 76 77 78 79 80 81 | json_status json_tag json_timeline json_user json_wiki leaf login main manifest markdown markdown_html md5 merge merge3 | > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | json_status json_tag json_timeline json_user json_wiki leaf login lookslike main manifest markdown markdown_html md5 merge merge3 |
| ︙ | ︙ | |||
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | user utf8 util verify vfile wiki wikiformat winhttp wysiwyg xfer xfersetup zip http_ssl } # Name of the final application # set name fossil # The "writeln" command sends output to the target makefile. # | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
user
utf8
util
verify
vfile
wiki
wikiformat
winfile
winhttp
wysiwyg
xfer
xfersetup
zip
http_ssl
}
# Options used to compile the included SQLite library.
#
set SQLITE_OPTIONS {
-DSQLITE_OMIT_LOAD_EXTENSION=1
-DSQLITE_ENABLE_LOCKING_STYLE=0
-DSQLITE_THREADSAFE=0
-DSQLITE_DEFAULT_FILE_FORMAT=4
-DSQLITE_OMIT_DEPRECATED
-DSQLITE_ENABLE_EXPLAIN_COMMENTS
}
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4
#lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI
#lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096
# Options used to compile the included SQLite shell.
#
set SHELL_OPTIONS {
-Dmain=sqlite3_shell
-DSQLITE_OMIT_LOAD_EXTENSION=1
}
# Options used to compile the included SQLite shell on Windows.
#
set SHELL_WIN32_OPTIONS $SHELL_OPTIONS
lappend SHELL_WIN32_OPTIONS -Dgetenv=fossil_getenv
lappend SHELL_WIN32_OPTIONS -Dfopen=fossil_fopen
# Name of the final application
#
set name fossil
# The "writeln" command sends output to the target makefile.
#
|
| ︙ | ︙ | |||
183 184 185 186 187 188 189 |
foreach s [lsort $src] {
writeln -nonewline " \\\n \$(OBJDIR)/$s.o"
}
writeln "\n"
writeln "APPNAME = $name\$(E)"
writeln "\n"
| | > > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
foreach s [lsort $src] {
writeln -nonewline " \\\n \$(OBJDIR)/$s.o"
}
writeln "\n"
writeln "APPNAME = $name\$(E)"
writeln "\n"
writeln [string map [list \
<<<SQLITE_OPTIONS>>> [join $SQLITE_OPTIONS " \\\n "] \
<<<SHELL_OPTIONS>>> [join $SHELL_OPTIONS " \\\n "]] {
all: $(OBJDIR) $(APPNAME)
install: $(APPNAME)
mkdir -p $(INSTALLDIR)
mv $(APPNAME) $(INSTALLDIR)
$(OBJDIR):
|
| ︙ | ︙ | |||
215 216 217 218 219 220 221 222 223 224 225 226 227 228 | test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ $(SRCDIR)/../manifest \ $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o | > > > > > > | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | test: $(OBJDIR) $(APPNAME) $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME) $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \ $(SRCDIR)/../manifest \ $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h # Setup the options used to compile the included SQLite library. SQLITE_OPTIONS = <<<SQLITE_OPTIONS>>> # Setup the options used to compile the included SQLite shell. SHELL_OPTIONS = <<<SHELL_OPTIONS>>> # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set # to 1. If it is set to 1, then there is no need to build or link # the sqlite3.o object. Instead, the system sqlite will be linked # using -lsqlite3. SQLITE3_OBJ.1 = SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o |
| ︙ | ︙ | |||
251 252 253 254 255 256 257 | # $(SRCDIR)/../manifest: # noop clean: rm -rf $(OBJDIR)/* $(APPNAME) | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
#
$(SRCDIR)/../manifest:
# noop
clean:
rm -rf $(OBJDIR)/* $(APPNAME)
}]
set mhargs {}
foreach s [lsort $src] {
append mhargs " \$(OBJDIR)/${s}_.c:\$(OBJDIR)/$s.h"
set extra_h($s) {}
}
append mhargs " \$(SRCDIR)/sqlite3.h"
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 |
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(OBJDIR)/translate \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.h:\t\$(OBJDIR)/headers"
}
| < < < < < < < < | < < | < | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(OBJDIR)/translate \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.h:\t\$(OBJDIR)/headers"
}
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"
writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
writeln {
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
#
# The list of all the targets that do not correspond to real files. This stops
# 'make' from getting confused when someone makes an error in a rule.
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 | # # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 | | > > > > | | | | | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 | # # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 #### Load Tcl using the stubs library mechanism # # FOSSIL_ENABLE_TCL_STUBS = 1 #### Load Tcl using the private stubs mechanism # # FOSSIL_ENABLE_TCL_PRIVATE_STUBS = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### Check if the workaround for the MinGW command line handling needs to # be enabled by default. # ifndef MINGW_IS_32BIT_ONLY ifeq (,$(findstring w64-mingw32,$(PREFIX))) MINGW_IS_32BIT_ONLY = 1 endif endif #### The directories where the zlib include and library files are located. # ZINCDIR = $(SRCDIR)/../compat/zlib ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | # TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # ifdef FOSSIL_ENABLE_TCL_STUBS LIBTCL = -ltclstub86 else LIBTCL = -ltcl86 endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. | > > > > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | # TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # ifdef FOSSIL_ENABLE_TCL_STUBS ifndef FOSSIL_ENABLE_TCL_PRIVATE_STUBS LIBTCL = -ltclstub86 endif TCLTARGET = libtclstub86.a else LIBTCL = -ltcl86 TCLTARGET = binaries endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. |
| ︙ | ︙ | |||
488 489 490 491 492 493 494 | else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With MinGW command line handling workaround | | > > > > | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 | else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With MinGW command line handling workaround ifdef MINGW_IS_32BIT_ONLY TCC += -DBROKEN_MINGW_CMDLINE=1 RCC += -DBROKEN_MINGW_CMDLINE=1 endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 RCC += -DFOSSIL_ENABLE_TCL=1 # Either statically linked or via stubs ifdef FOSSIL_ENABLE_TCL_STUBS TCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS RCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS ifdef FOSSIL_ENABLE_TCL_PRIVATE_STUBS TCC += -DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 RCC += -DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 endif else TCC += -DSTATIC_BUILD RCC += -DSTATIC_BUILD endif endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 RCC += -DFOSSIL_ENABLE_JSON=1 endif #### We add the -static option here so that we can build a static # executable that will run in a chroot jail. # LIB = -static # MinGW: If available, use the Unicode capable runtime startup code. ifndef MINGW_IS_32BIT_ONLY LIB += -municode endif # OpenSSL: Add the necessary libraries required, if enabled. ifdef FOSSIL_ENABLE_SSL LIB += -lssl -lcrypto -lgdi32 endif |
| ︙ | ︙ | |||
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
writeln {
all: $(OBJDIR) $(APPNAME)
$(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h
ifdef USE_WINDOWS
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR))
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR))
else
$(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR)
$(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR)
endif
$(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o
install: $(OBJDIR) $(APPNAME)
ifdef USE_WINDOWS
$(MKDIR) $(subst /,\,$(INSTALLDIR))
$(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR))
| > > | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 |
writeln {
all: $(OBJDIR) $(APPNAME)
$(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h
ifdef USE_WINDOWS
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR))
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR))
$(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR))
else
$(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR)
$(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR)
$(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR)
endif
$(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o
install: $(OBJDIR) $(APPNAME)
ifdef USE_WINDOWS
$(MKDIR) $(subst /,\,$(INSTALLDIR))
$(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR))
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 693 694 695 696 697 698 699 | ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: | > > > > > > > > > > > > > > > > > | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean openssl: zlib cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) --with-zlib-lib=$(PWD)/$(ZLIBDIR) --with-zlib-include=$(PWD)/$(ZLIBDIR) zlib mingw $(MAKE) -C $(OPENSSLLIBDIR) build_libs clean-openssl: $(MAKE) -C $(OPENSSLLIBDIR) clean tcl: cd $(TCLSRCDIR)/win;./configure $(MAKE) -C $(TCLSRCDIR)/win $(TCLTARGET) clean-tcl: $(MAKE) -C $(TCLSRCDIR)/win distclean $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: |
| ︙ | ︙ | |||
734 735 736 737 738 739 740 741 |
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(TRANSLATE) \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/${s}.h:\t\$(OBJDIR)/headers\n"
}
| > > > > > > > > > | < | < | | < < | | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 |
writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
writeln "\t\$(TRANSLATE) \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
writeln "\t\$(XTCC) -o \$(OBJDIR)/$s.o -c \$(OBJDIR)/${s}_.c\n"
writeln "\$(OBJDIR)/${s}.h:\t\$(OBJDIR)/headers\n"
}
set MINGW_SQLITE_OPTIONS $SQLITE_OPTIONS
lappend MINGW_SQLITE_OPTIONS -D_HAVE_SQLITE_CONFIG_H
lappend MINGW_SQLITE_OPTIONS -DSQLITE_USE_MALLOC_H
lappend MINGW_SQLITE_OPTIONS -DSQLITE_USE_MSIZE
set j " \\\n "
writeln "SQLITE_OPTIONS = [join $MINGW_SQLITE_OPTIONS $j]\n"
set j " \\\n "
writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS $j]\n"
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c \$(SRCDIR)/../win/Makefile.mingw"
writeln "\t\$(XTCC) \$(SQLITE_OPTIONS) \$(SQLITE_CFLAGS) -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o\n"
writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_dir.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_status.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"
writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h \$(SRCDIR)/../win/Makefile.mingw"
writeln "\t\$(XTCC) \$(SHELL_OPTIONS) \$(SHELL_CFLAGS) -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"
writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
writeln "\t\$(XTCC) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"
|
| ︙ | ︙ | |||
800 801 802 803 804 805 806 | SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 } | | > | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 |
SSL =
CFLAGS = -o
BCC = $(DMDIR)\bin\dmc $(CFLAGS)
TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
}
writeln "SQLITE_OPTIONS = [join $SQLITE_OPTIONS { }]\n"
writeln "SHELL_OPTIONS = [join $SHELL_WIN32_OPTIONS { }]\n"
writeln -nonewline "SRC = "
foreach s [lsort $src] {
writeln -nonewline "${s}_.c "
}
writeln "\n"
writeln -nonewline "OBJ = "
foreach s [lsort $src] {
|
| ︙ | ︙ | |||
853 854 855 856 857 858 859 | mkindex$E: $(SRCDIR)\mkindex.c $(BCC) -o$@ $** version$E: $B\src\mkversion.c $(BCC) -o$@ $** $(OBJDIR)\shell$O : $(SRCDIR)\shell.c | | | | 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 | mkindex$E: $(SRCDIR)\mkindex.c $(BCC) -o$@ $** version$E: $B\src\mkversion.c $(BCC) -o$@ $** $(OBJDIR)\shell$O : $(SRCDIR)\shell.c $(TCC) -o$@ -c $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $** $(OBJDIR)\sqlite3$O : $(SRCDIR)\sqlite3.c $(TCC) -o$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** $(OBJDIR)\th$O : $(SRCDIR)\th.c $(TCC) -o$@ -c $** $(OBJDIR)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) -o$@ -c $** |
| ︙ | ︙ | |||
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 | # B = .. SRCDIR = $B\src OBJDIR = . OX = . O = .obj E = .exe # Uncomment to enable JSON API # FOSSIL_ENABLE_JSON = 1 # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 !ifdef FOSSIL_ENABLE_SSL | > > > > | | | | | | | | > > > > > > > > > | | | | | | | | | | | | > > > > > | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 |
#
B = ..
SRCDIR = $B\src
OBJDIR = .
OX = .
O = .obj
E = .exe
P = .pdb
# Uncomment to enable debug symbols
# DEBUG = 1
# Uncomment to enable JSON API
# FOSSIL_ENABLE_JSON = 1
# Uncomment to enable SSL support
# FOSSIL_ENABLE_SSL = 1
!ifdef FOSSIL_ENABLE_SSL
SSLINCDIR = $(B)\compat\openssl-1.0.1f\include
SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
!endif
# zlib options
ZINCDIR = $(B)\compat\zlib
ZLIBDIR = $(B)\compat\zlib
ZLIB = zlib.lib
INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
!ifdef FOSSIL_ENABLE_SSL
INCL = $(INCL) -I$(SSLINCDIR)
!endif
CFLAGS = -nologo
LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO
!ifdef DEBUG
CFLAGS = $(CFLAGS) -Zi -MTd -Od
LDFLAGS = $(LDFLAGS) /DEBUG
!else
CFLAGS = $(CFLAGS) -MT -O2
!endif
BCC = $(CC) $(CFLAGS)
TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL)
RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL)
LIBS = $(ZLIB) ws2_32.lib advapi32.lib
LIBDIR = -LIBPATH:$(ZLIBDIR)
!ifdef FOSSIL_ENABLE_JSON
TCC = $(TCC) -DFOSSIL_ENABLE_JSON=1
RCC = $(RCC) -DFOSSIL_ENABLE_JSON=1
!endif
!ifdef FOSSIL_ENABLE_SSL
TCC = $(TCC) -DFOSSIL_ENABLE_SSL=1
RCC = $(RCC) -DFOSSIL_ENABLE_SSL=1
LIBS = $(LIBS) $(SSLLIB)
LIBDIR = $(LIBDIR) -LIBPATH:$(SSLLIBDIR)
!endif
}
regsub -all {[-]D} [join $SQLITE_OPTIONS { }] {/D} MSC_SQLITE_OPTIONS
set j " \\\n "
writeln "SQLITE_OPTIONS = [join $MSC_SQLITE_OPTIONS $j]\n"
regsub -all {[-]D} [join $SHELL_WIN32_OPTIONS { }] {/D} MSC_SHELL_OPTIONS
set j " \\\n "
writeln "SHELL_OPTIONS = [join $MSC_SHELL_OPTIONS $j]\n"
writeln -nonewline "SRC = "
set i 0
foreach s [lsort $src] {
if {$i > 0} {
writeln " \\"
writeln -nonewline " "
}
|
| ︙ | ︙ | |||
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
}
writeln -nonewline "\$(OX)\\$s\$O"; incr i
}
writeln " \\"
writeln -nonewline " \$(OX)\\fossil.res\n"
writeln {
APPNAME = $(OX)\fossil$(E)
all: $(OX) $(APPNAME)
zlib:
@echo Building zlib from "$(ZLIBDIR)"...
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
cd $(OX)
| > | | 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 |
}
writeln -nonewline "\$(OX)\\$s\$O"; incr i
}
writeln " \\"
writeln -nonewline " \$(OX)\\fossil.res\n"
writeln {
APPNAME = $(OX)\fossil$(E)
PDBNAME = $(OX)\fossil$(P)
all: $(OX) $(APPNAME)
zlib:
@echo Building zlib from "$(ZLIBDIR)"...
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
cd $(OX)
link $(LDFLAGS) -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
$(OX)\linkopts: $B\win\Makefile.msc}
set redir {>}
foreach s [lsort [concat $src $AdditionalObj]] {
writeln "\techo \$(OX)\\$s.obj $redir \$@"
set redir {>>}
}
|
| ︙ | ︙ | |||
1045 1046 1047 1048 1049 1050 1051 | mkindex$E: $(SRCDIR)\mkindex.c $(BCC) $** mkversion$E: $B\src\mkversion.c $(BCC) $** | | | | | | 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | mkindex$E: $(SRCDIR)\mkindex.c $(BCC) $** mkversion$E: $B\src\mkversion.c $(BCC) $** $(OX)\shell$O : $(SRCDIR)\shell.c $B\win\Makefile.msc $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c $(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c $B\win\Makefile.msc $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SRCDIR)\sqlite3.c $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** |
| ︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | clean: -del $(OX)\*.obj -del *.obj -del *_.c -del *.h -del *.map | | | > | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 | clean: -del $(OX)\*.obj -del *.obj -del *_.c -del *.h -del *.map -del *.res -del headers -del linkopts -del vc*.pdb realclean: clean -del $(APPNAME) -del $(PDBNAME) -del translate$E -del mkindex$E -del makeheaders$E -del mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h |
| ︙ | ︙ | |||
1139 1140 1141 1142 1143 1144 1145 | ############################################################################## # Begin win/Makefile.PellesCGMake output # puts "building ../win/Makefile.PellesCGMake" set output_file [open ../win/Makefile.PellesCGMake w] fconfigure $output_file -translation binary | | > > | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 |
##############################################################################
# Begin win/Makefile.PellesCGMake output
#
puts "building ../win/Makefile.PellesCGMake"
set output_file [open ../win/Makefile.PellesCGMake w]
fconfigure $output_file -translation binary
writeln [string map [list \
<<<SQLITE_OPTIONS>>> [join $SQLITE_OPTIONS { }] \
<<<SHELL_OPTIONS>>> [join $SHELL_WIN32_OPTIONS { }]] {#
##############################################################################
# WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl")
##############################################################################
#
# This file is automatically generated. Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
|
| ︙ | ︙ | |||
1226 1227 1228 1229 1230 1231 1232 | UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the sqlite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) | | | | 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 | UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the sqlite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) SQLITEDEFINES=<<<SQLITE_OPTIONS>>> # define the sqlite shell files, which need special flags on compile SQLITESHELLSRC=shell.c ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) SQLITESHELLDEFINES=<<<SHELL_OPTIONS>>> # define the th scripting files, which need special flags on compile THSRC=th.c th_lang.c ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) # define the zlib files, needed by this compile |
| ︙ | ︙ | |||
1329 1330 1331 1332 1333 1334 1335 | del /F $(TRANSLATEDSRC) del /F *.h headers del /F $(RESOURCE) .PHONY: clobber clobber: clean del /F *.exe | | | 1415 1416 1417 1418 1419 1420 1421 1422 | del /F $(TRANSLATEDSRC) del /F *.h headers del /F $(RESOURCE) .PHONY: clobber clobber: clean del /F *.exe }] |
Changes to src/manifest.c.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 | /* ** File permissions used by Fossil internally. */ #define PERM_REG 0 /* regular file */ #define PERM_EXE 1 /* executable */ #define PERM_LNK 2 /* symlink */ /* ** A single F-card within a manifest */ | > > > > > > | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/*
** File permissions used by Fossil internally.
*/
#define PERM_REG 0 /* regular file */
#define PERM_EXE 1 /* executable */
#define PERM_LNK 2 /* symlink */
/*
** Flags for use with manifest_crosslink().
*/
#define MC_NONE 0 /* default handling */
#define MC_PERMIT_HOOKS 1 /* permit hooks to execute */
/*
** A single F-card within a manifest
*/
struct ManifestFile {
char *zName; /* Name of a file */
char *zUuid; /* UUID of the file */
char *zPerm; /* File permissions */
char *zPrior; /* Prior name if the name was changed */
};
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 | int nFileAlloc; /* Slots allocated in aFile[] */ int iFile; /* Index of current file in iterator */ ManifestFile *aFile; /* One entry for each F-card */ int nParent; /* Number of parents. */ int nParentAlloc; /* Slots allocated in azParent[] */ char **azParent; /* UUIDs of parents. One for each P card argument */ int nCherrypick; /* Number of entries in aCherrypick[] */ | | | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
int nFileAlloc; /* Slots allocated in aFile[] */
int iFile; /* Index of current file in iterator */
ManifestFile *aFile; /* One entry for each F-card */
int nParent; /* Number of parents. */
int nParentAlloc; /* Slots allocated in azParent[] */
char **azParent; /* UUIDs of parents. One for each P card argument */
int nCherrypick; /* Number of entries in aCherrypick[] */
struct {
char *zCPTarget; /* UUID of cherry-picked version w/ +|- prefix */
char *zCPBase; /* UUID of cherry-pick baseline. NULL for singletons */
} *aCherrypick;
int nCChild; /* Number of cluster children */
int nCChildAlloc; /* Number of closts allocated in azCChild[] */
char **azCChild; /* UUIDs of referenced objects in a cluster. M cards */
int nTag; /* Number of T Cards */
int nTagAlloc; /* Slots allocated in aTag[] */
struct TagType {
char *zName; /* Name of the tag */
char *zUuid; /* UUID that the tag is applied to */
char *zValue; /* Value if the tag is really a property */
} *aTag; /* One for each T card */
int nField; /* Number of J cards */
int nFieldAlloc; /* Slots allocated in aField[] */
struct {
char *zName; /* Key or field name */
char *zValue; /* Value of the field */
} *aField; /* One for each J card */
};
#endif
/*
|
| ︙ | ︙ | |||
243 244 245 246 247 248 249 | /* ** Verify the Z-card checksum on the artifact, if there is such a ** checksum. Return 0 if there is no Z-card. Return 1 if the Z-card ** exists and is correct. Return 2 if the Z-card exists and has the wrong ** value. ** | | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
/*
** Verify the Z-card checksum on the artifact, if there is such a
** checksum. Return 0 if there is no Z-card. Return 1 if the Z-card
** exists and is correct. Return 2 if the Z-card exists and has the wrong
** value.
**
** 0123456789 123456789 123456789 123456789
** Z aea84f4f863865a8d59d0384e4d2a41c
*/
static int verify_z_card(const char *z, int n){
if( n<35 ) return 0;
if( z[n-35]!='Z' || z[n-34]!=' ' ) return 0;
md5sum_init();
md5sum_step_text(z, n-35);
|
| ︙ | ︙ | |||
351 352 353 354 355 356 357 | ManifestText x; char cPrevType = 0; char cType; char *z; int n; char *zUuid; int sz = 0; | | | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
ManifestText x;
char cPrevType = 0;
char cType;
char *z;
int n;
char *zUuid;
int sz = 0;
int isRepeat, hasSelfRefTag = 0;
static Bag seen;
const char *zErr = 0;
if( rid==0 ){
isRepeat = 1;
}else if( bag_find(&seen, rid) ){
isRepeat = 1;
|
| ︙ | ︙ | |||
376 377 378 379 380 381 382 |
n = blob_size(pContent);
if( n<=0 || z[n-1]!='\n' ){
blob_reset(pContent);
blob_appendf(pErr, n ? "not terminated with \\n" : "zero-length");
return 0;
}
| | < < < < < < > > > > > > > | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
n = blob_size(pContent);
if( n<=0 || z[n-1]!='\n' ){
blob_reset(pContent);
blob_appendf(pErr, n ? "not terminated with \\n" : "zero-length");
return 0;
}
/* Strip off the PGP signature if there is one.
*/
remove_pgp_signature(&z, &n);
/* Verify that the first few characters of the artifact look like
** a control artifact.
*/
if( n<10 || z[0]<'A' || z[0]>'Z' || z[1]!=' ' ){
blob_reset(pContent);
blob_appendf(pErr, "line 1 not recognized");
return 0;
}
/* Then verify the Z-card.
*/
if( verify_z_card(z, n)==2 ){
blob_reset(pContent);
blob_appendf(pErr, "incorrect Z-card cksum");
return 0;
}
/* Allocate a Manifest object to hold the parsed control artifact.
*/
p = fossil_malloc( sizeof(*p) );
memset(p, 0, sizeof(*p));
memcpy(&p->content, pContent, sizeof(p->content));
|
| ︙ | ︙ | |||
426 427 428 429 430 431 432 |
*/
case 'A': {
char *zName, *zTarget, *zSrc;
int nTarget = 0, nSrc = 0;
zName = next_token(&x, 0);
zTarget = next_token(&x, &nTarget);
zSrc = next_token(&x, &nSrc);
| | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 |
*/
case 'A': {
char *zName, *zTarget, *zSrc;
int nTarget = 0, nSrc = 0;
zName = next_token(&x, 0);
zTarget = next_token(&x, &nTarget);
zSrc = next_token(&x, &nSrc);
if( zName==0 || zTarget==0 ) goto manifest_syntax_error;
if( p->zAttachName!=0 ) goto manifest_syntax_error;
defossilize(zName);
if( !file_is_simple_pathname(zName, 0) ){
SYNTAX("invalid filename on A-card");
}
defossilize(zTarget);
if( (nTarget!=UUID_SIZE || !validate16(zTarget, UUID_SIZE))
|
| ︙ | ︙ | |||
466 467 468 469 470 471 472 |
}
/*
** C <comment>
**
** Comment text is fossil-encoded. There may be no more than
| | > | | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 |
}
/*
** C <comment>
**
** Comment text is fossil-encoded. There may be no more than
** one C line. C lines are required for manifests, are optional
** for Events and Attachments, and are disallowed on all other
** control files.
*/
case 'C': {
if( p->zComment!=0 ) SYNTAX("more than one C-card");
p->zComment = next_token(&x, 0);
if( p->zComment==0 ) SYNTAX("missing comment text on C-card");
defossilize(p->zComment);
break;
|
| ︙ | ︙ | |||
494 495 496 497 498 499 500 |
if( p->rDate<=0.0 ) SYNTAX("cannot parse date on D-card");
break;
}
/*
** E <timestamp> <uuid>
**
| | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
if( p->rDate<=0.0 ) SYNTAX("cannot parse date on D-card");
break;
}
/*
** E <timestamp> <uuid>
**
** An "event" card that contains the timestamp of the event in the
** format YYYY-MM-DDtHH:MM:SS and a unique identifier for the event.
** The event timestamp is distinct from the D timestamp. The D
** timestamp is when the artifact was created whereas the E timestamp
** is when the specific event is said to occur.
*/
case 'E': {
if( p->rEventDate>0.0 ) SYNTAX("more than one E-card");
|
| ︙ | ︙ | |||
541 542 543 544 545 546 547 |
defossilize(zPriorName);
if( !file_is_simple_pathname(zPriorName, 0) ){
SYNTAX("F-card old filename is not a simple path");
}
}
if( p->nFile>=p->nFileAlloc ){
p->nFileAlloc = p->nFileAlloc*2 + 10;
| | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
defossilize(zPriorName);
if( !file_is_simple_pathname(zPriorName, 0) ){
SYNTAX("F-card old filename is not a simple path");
}
}
if( p->nFile>=p->nFileAlloc ){
p->nFileAlloc = p->nFileAlloc*2 + 10;
p->aFile = fossil_realloc(p->aFile,
p->nFileAlloc*sizeof(p->aFile[0]) );
}
i = p->nFile++;
p->aFile[i].zName = zName;
p->aFile[i].zUuid = zUuid;
p->aFile[i].zPerm = zPerm;
p->aFile[i].zPrior = zPriorName;
|
| ︙ | ︙ | |||
658 659 660 661 662 663 664 |
defossilize(p->zMimetype);
break;
}
/*
** P <uuid> ...
**
| | | > > | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
defossilize(p->zMimetype);
break;
}
/*
** P <uuid> ...
**
** Specify one or more other artifacts which are the parents of
** this artifact. The first parent is the primary parent. All
** others are parents by merge. Note that the initial empty
** checkin historically has an empty P-card, so empty P-cards
** must be accepted.
*/
case 'P': {
while( (zUuid = next_token(&x, &sz))!=0 ){
if( sz!=UUID_SIZE ) SYNTAX("wrong size UUID on P-card");
if( !validate16(zUuid, UUID_SIZE) )SYNTAX("invalid UUID on P-card");
if( p->nParent>=p->nParentAlloc ){
p->nParentAlloc = p->nParentAlloc*2 + 5;
|
| ︙ | ︙ | |||
714 715 716 717 718 719 720 |
/*
** R <md5sum>
**
** Specify the MD5 checksum over the name and content of all files
** in the manifest.
*/
case 'R': {
| | | > > > > > > | > | > | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
/*
** R <md5sum>
**
** Specify the MD5 checksum over the name and content of all files
** in the manifest.
*/
case 'R': {
if( p->zRepoCksum!=0 ) SYNTAX("more than one R-card");
p->zRepoCksum = next_token(&x, &sz);
if( sz!=32 ) SYNTAX("wrong size cksum on R-card");
if( !validate16(p->zRepoCksum, 32) ) SYNTAX("malformed R-card cksum");
break;
}
/*
** T (+|*|-)<tagname> <uuid> ?<value>?
**
** Create or cancel a tag or property. The tagname is fossil-encoded.
** The first character of the name must be either "+" to create a
** singleton tag, "*" to create a propagating tag, or "-" to create
** anti-tag that undoes a prior "+" or blocks propagation of of
** a "*".
**
** The tag is applied to <uuid>. If <uuid> is "*" then the tag is
** applied to the current manifest. If <value> is provided then
** the tag is really a property with the given value.
**
** Tags are not allowed in clusters. Multiple T lines are allowed.
*/
case 'T': {
char *zName, *zValue;
zName = next_token(&x, 0);
if( zName==0 ) SYNTAX("missing name on T-card");
zUuid = next_token(&x, &sz);
if( zUuid==0 ) SYNTAX("missing UUID on T-card");
zValue = next_token(&x, 0);
if( zValue ) defossilize(zValue);
if( sz==UUID_SIZE && validate16(zUuid, UUID_SIZE) ){
/* A valid uuid */
if( p->zEventId ) SYNTAX("non-self-referential T-card in event");
}else if( sz==1 && zUuid[0]=='*' ){
zUuid = 0;
hasSelfRefTag = 1;
if( p->zEventId && zName[0]!='+' ){
SYNTAX("propagating T-card in event");
}
}else{
SYNTAX("malformed UUID on T-card");
}
defossilize(zName);
if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
SYNTAX("T-card name does not begin with '-', '+', or '*'");
}
if( validate16(&zName[1], strlen(&zName[1])) ){
/* Do not allow tags whose names look like UUIDs */
SYNTAX("T-card name looks like a UUID");
}
if( p->nTag>=p->nTagAlloc ){
p->nTagAlloc = p->nTagAlloc*2 + 10;
p->aTag = fossil_realloc(p->aTag, p->nTagAlloc*sizeof(p->aTag[0]) );
}
i = p->nTag++;
p->aTag[i].zName = zName;
p->aTag[i].zUuid = zUuid;
p->aTag[i].zValue = zValue;
if( i>0 ){
int c = fossil_strcmp(p->aTag[i-1].zName, zName);
if( c>0 || (c==0 && fossil_strcmp(p->aTag[i-1].zUuid, zUuid)>=0) ){
SYNTAX("T-card in the wrong order");
}
}
break;
}
/*
** U ?<login>?
**
** Identify the user who created this control file by their
** login. Only one U line is allowed. Prohibited in clusters.
** If the user name is omitted, take that to be "anonymous".
*/
case 'U': {
if( p->zUser!=0 ) SYNTAX("more than one U-card");
p->zUser = next_token(&x, 0);
if( p->zUser==0 ){
p->zUser = "anonymous";
}else{
defossilize(p->zUser);
}
break;
|
| ︙ | ︙ | |||
847 848 849 850 851 852 853 |
default: {
SYNTAX("unrecognized card");
}
}
}
if( x.z<x.zEnd ) SYNTAX("extra characters at end of card");
| < | < < < < < < < | < < | | | | | | | > > | > | | | | | | | | | | | | < | | | | | | > | | | > > > > > > | | | < > > | | | | < | | < < < < < < < < < < | | < < | | | | | | | | | 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 |
default: {
SYNTAX("unrecognized card");
}
}
}
if( x.z<x.zEnd ) SYNTAX("extra characters at end of card");
if( p->nCChild>0 ){
if( p->zAttachName
|| p->zBaseline
|| p->zComment
|| p->rDate>0.0
|| p->zEventId
|| p->nFile>0
|| p->nField>0
|| p->zTicketUuid
|| p->zWikiTitle
|| p->zMimetype
|| p->nParent>0
|| p->nCherrypick>0
|| p->zRepoCksum
|| p->nTag>0
|| p->zUser
|| p->zWiki
){
SYNTAX("cluster contains a card other than M- or Z-");
}
if( !seenZ ) SYNTAX("missing Z-card on cluster");
p->type = CFTYPE_CLUSTER;
}else if( p->zEventId ){
if( p->rDate<=0.0 ) SYNTAX("missing date on event");
if( p->nFile>0 ) SYNTAX("F-card in event");
if( p->zRepoCksum ) SYNTAX("R-card in event");
if( p->zBaseline ) SYNTAX("B-card in event");
if( p->nField>0 ) SYNTAX("J-card in event");
if( p->zTicketUuid ) SYNTAX("K-card in event");
if( p->zWikiTitle!=0 ) SYNTAX("L-card in event");
if( p->zWiki==0 ) SYNTAX("missing W-card on event");
if( p->zAttachName ) SYNTAX("A-card in event");
if( !seenZ ) SYNTAX("missing Z-card on event");
p->type = CFTYPE_EVENT;
}else if( hasSelfRefTag || p->nFile>0 || p->zRepoCksum!=0 || p->zBaseline ){
if( p->rDate<=0.0 ) SYNTAX("missing date on manifest");
if( p->nField>0 ) SYNTAX("J-card in manifest");
if( p->zTicketUuid ) SYNTAX("K-card in manifest");
if( p->zWiki ) SYNTAX("W-card in manifest");
if( p->zWikiTitle ) SYNTAX("L-card in manifest");
if( p->zTicketUuid ) SYNTAX("K-card in manifest");
if( p->zAttachName ) SYNTAX("A-card in manifest");
p->type = CFTYPE_MANIFEST;
}else if( p->nField>0 || p->zTicketUuid!=0 ){
if( p->rDate<=0.0 ) SYNTAX("missing date on ticket");
if( p->zWiki ) SYNTAX("W-card in ticket");
if( p->zWikiTitle ) SYNTAX("L-card in ticket");
if( p->nField==0 ) SYNTAX("missing J-card on ticket");
if( p->nTag>0 ) SYNTAX("T-card in ticket");
if( p->zTicketUuid==0 ) SYNTAX("missing K-card on ticket");
if( p->zUser==0 ) SYNTAX("missing U-card on ticket");
if( p->zAttachName ) SYNTAX("A-card in ticket");
if( p->zMimetype) SYNTAX("N-card in ticket");
if( !seenZ ) SYNTAX("missing Z-card on ticket");
p->type = CFTYPE_TICKET;
}else if( p->zWiki!=0 || p->zWikiTitle!=0 ){
if( p->rDate<=0.0 ) SYNTAX("missing date on wiki");
if( p->nTag>0 ) SYNTAX("T-card in wiki");
if( p->zWiki==0 ) SYNTAX("missing W-card on wiki");
if( p->zWikiTitle==0 ) SYNTAX("missing L-card on wiki");
if( p->zAttachName ) SYNTAX("A-card in wiki");
if( !seenZ ) SYNTAX("missing Z-card on wiki");
p->type = CFTYPE_WIKI;
}else if( p->zAttachName ){
if( p->rDate<=0.0 ) SYNTAX("missing date on attachment");
if( p->nTag>0 ) SYNTAX("T-card in attachment");
if( !seenZ ) SYNTAX("missing Z-card on attachment");
p->type = CFTYPE_ATTACHMENT;
}else{
if( p->rDate<=0.0 ) SYNTAX("missing date on control");
if( p->nParent>0 ) SYNTAX("P-card in control");
if( p->zMimetype ) SYNTAX("N-card in control");
if( !seenZ ) SYNTAX("missing Z-card on control");
p->type = CFTYPE_CONTROL;
}
md5sum_init();
if( !isRepeat ) g.parseCnt[p->type]++;
return p;
manifest_syntax_error:
if( zErr ){
blob_appendf(pErr, "line %d: %s", lineNo, zErr);
}else{
blob_appendf(pErr, "unknown error on line %d", lineNo);
}
md5sum_init();
manifest_destroy(p);
return 0;
}
/*
** Get a manifest given the rid for the control artifact. Return
** a pointer to the manifest on success or NULL if there is a failure.
*/
Manifest *manifest_get(int rid, int cfType, Blob *pErr){
Blob content;
Manifest *p;
if( !rid ) return 0;
p = manifest_cache_find(rid);
if( p ){
if( cfType!=CFTYPE_ANY && cfType!=p->type ){
manifest_cache_insert(p);
p = 0;
}
return p;
}
content_get(rid, &content);
p = manifest_parse(&content, rid, pErr);
if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
manifest_destroy(p);
p = 0;
}
return p;
}
/*
** Given a checkin name, load and parse the manifest for that checkin.
** Throw a fatal error if anything goes wrong.
*/
Manifest *manifest_get_by_name(const char *zName, int *pRid){
int rid;
Manifest *p;
rid = name_to_typed_rid(zName, "ci");
if( !is_a_version(rid) ){
fossil_fatal("no such checkin: %s", zName);
}
if( pRid ) *pRid = rid;
p = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( p==0 ){
fossil_fatal("cannot parse manifest for checkin: %s", zName);
}
return p;
}
/*
|
| ︙ | ︙ | |||
1035 1036 1037 1038 1039 1040 1041 |
** throw an error. If the baseline is a manifest, throw an
** error if throwError is true, or record that p is an orphan
** and return 1 if throwError is false.
*/
static int fetch_baseline(Manifest *p, int throwError){
if( p->zBaseline!=0 && p->pBaseline==0 ){
int rid = uuid_to_rid(p->zBaseline, 1);
| | | | 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 |
** throw an error. If the baseline is a manifest, throw an
** error if throwError is true, or record that p is an orphan
** and return 1 if throwError is false.
*/
static int fetch_baseline(Manifest *p, int throwError){
if( p->zBaseline!=0 && p->pBaseline==0 ){
int rid = uuid_to_rid(p->zBaseline, 1);
p->pBaseline = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( p->pBaseline==0 ){
if( !throwError ){
db_multi_exec(
"INSERT OR IGNORE INTO orphan(rid, baseline) VALUES(%d,%d)",
p->rid, rid
);
return 1;
}
fossil_fatal("cannot access baseline manifest %S", p->zBaseline);
}
}
return 0;
}
/*
|
| ︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | /* ** Advance to the next manifest-file. ** ** Return NULL for end-of-records or if there is an error. If an error ** occurs and pErr!=0 then store 1 in *pErr. */ ManifestFile *manifest_file_next( | | | 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 |
/*
** Advance to the next manifest-file.
**
** Return NULL for end-of-records or if there is an error. If an error
** occurs and pErr!=0 then store 1 in *pErr.
*/
ManifestFile *manifest_file_next(
Manifest *p,
int *pErr
){
ManifestFile *pOut = 0;
if( pErr ) *pErr = 0;
if( p->pBaseline==0 ){
/* Manifest p is a baseline-manifest. Just scan down the list
** of files. */
|
| ︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 |
db_exec(&s1);
if( pid && fid ){
content_deltify(pid, fid, 0);
}
}
/*
| | | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 |
db_exec(&s1);
if( pid && fid ){
content_deltify(pid, fid, 0);
}
}
/*
** Do a binary search to find a file in the p->aFile[] array.
**
** As an optimization, guess that the file we seek is at index p->iFile.
** That will usually be the case. If it is not found there, then do the
** actual binary search.
**
** Update p->iFile to be the index of the file that is found.
*/
|
| ︙ | ︙ | |||
1256 1257 1258 1259 1260 1261 1262 | } /* ** Locate a file named zName in the aFile[] array of the given manifest. ** Return a pointer to the appropriate ManifestFile object. Return NULL ** if not found. ** | | | | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 |
}
/*
** Locate a file named zName in the aFile[] array of the given manifest.
** Return a pointer to the appropriate ManifestFile object. Return NULL
** if not found.
**
** This routine works even if p is a delta-manifest. The pointer
** returned might be to the baseline.
**
** We assume that filenames are in sorted order and use a binary search.
*/
ManifestFile *manifest_file_seek(Manifest *p, const char *zName){
ManifestFile *pFile;
pFile = manifest_file_seek_base(p, zName);
if( pFile && pFile->zUuid==0 ) return 0;
if( pFile==0 && p->zBaseline ){
fetch_baseline(p, 1);
pFile = manifest_file_seek_base(p->pBaseline, zName);
}
return pFile;
|
| ︙ | ︙ | |||
1355 1356 1357 1358 1359 1360 1361 |
if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
manifest_destroy(*ppOther);
return;
}
isPublic = !content_is_private(cid);
/* Try to make the parent manifest a delta from the child, if that
| | | | | 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 |
if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
manifest_destroy(*ppOther);
return;
}
isPublic = !content_is_private(cid);
/* Try to make the parent manifest a delta from the child, if that
** is an appropriate thing to do. For a new baseline, make the
** previous baseline a delta from the current baseline.
*/
if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
content_deltify(pid, cid, 0);
}else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
content_deltify(pParent->pBaseline->rid, cid, 0);
}
/* Remember all children less than a few seconds younger than their parent,
** as we might want to fudge the times for those children.
*/
if( pChild->rDate<pParent->rDate+AGE_FUDGE_WINDOW
&& manifest_crosslink_busy
){
db_multi_exec(
"INSERT OR REPLACE INTO time_fudge VALUES(%d, %.17g, %d, %.17g);",
pParent->rid, pParent->rDate, pChild->rid, pChild->rDate
);
}
/* First look at all files in pChild, ignoring its baseline. This
** is where most of the changes will be found.
*/
for(i=0, pChildFile=pChild->aFile; i<pChild->nFile; i++, pChildFile++){
int mperm = manifest_file_mperm(pChildFile);
if( pChildFile->zPrior ){
pParentFile = manifest_file_seek(pParent, pChildFile->zPrior);
if( pParentFile ){
/* File with name change */
add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
|
| ︙ | ︙ | |||
1443 1444 1445 1446 1447 1448 1449 |
}else if( pChild->zBaseline==0 ){
/* pChild is a baseline. Look for files that are present in pParent
** but are missing from pChild and mark them as having been deleted. */
manifest_file_rewind(pParent);
while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
pChildFile = manifest_file_seek(pChild, pParentFile->zName);
if( pChildFile==0 && pParentFile->zUuid!=0 ){
| | | 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 |
}else if( pChild->zBaseline==0 ){
/* pChild is a baseline. Look for files that are present in pParent
** but are missing from pChild and mark them as having been deleted. */
manifest_file_rewind(pParent);
while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
pChildFile = manifest_file_seek(pChild, pParentFile->zName);
if( pChildFile==0 && pParentFile->zUuid!=0 ){
add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0,
isPublic, 0);
}
}
}
manifest_cache_insert(*ppOther);
}
|
| ︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 | #define AGE_ADJUST_INCREMENT (25.0/86400000.0) /* 25 milliseconds */ #endif /* LOCAL_INTERFACE */ /* ** Finish up a sequence of manifest_crosslink calls. */ | | > > > > > > > > > > > > | 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 |
#define AGE_ADJUST_INCREMENT (25.0/86400000.0) /* 25 milliseconds */
#endif /* LOCAL_INTERFACE */
/*
** Finish up a sequence of manifest_crosslink calls.
*/
int manifest_crosslink_end(int flags){
Stmt q, u;
int i;
int rc = TH_OK;
int permitHooks = (flags & MC_PERMIT_HOOKS);
const char *zScript = 0;
assert( manifest_crosslink_busy==1 );
if( permitHooks ){
rc = xfer_run_common_script();
if( rc==TH_OK ){
zScript = xfer_ticket_code();
}
}
db_prepare(&q, "SELECT uuid FROM pending_tkt");
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
ticket_rebuild_entry(zUuid);
if( permitHooks && rc==TH_OK ){
rc = xfer_run_script(zScript, zUuid);
}
}
db_finalize(&q);
db_multi_exec("DROP TABLE pending_tkt");
/* If multiple check-ins happen close together in time, adjust their
** times by a few milliseconds to make sure they appear in chronological
** order.
|
| ︙ | ︙ | |||
1521 1522 1523 1524 1525 1526 1527 |
db_reset(&q);
if( sqlite3_changes(g.db)==0 ) break;
db_step(&u);
db_reset(&u);
}
db_finalize(&q);
db_finalize(&u);
| > | | | < | > > > | 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 |
db_reset(&q);
if( sqlite3_changes(g.db)==0 ) break;
db_step(&u);
db_reset(&u);
}
db_finalize(&q);
db_finalize(&u);
if( db_exists("SELECT 1 FROM time_fudge") ){
db_multi_exec(
"UPDATE event SET mtime=(SELECT m1 FROM time_fudge WHERE mid=objid)"
" WHERE objid IN (SELECT mid FROM time_fudge);"
);
}
db_multi_exec("DROP TABLE time_fudge;");
db_end_transaction(0);
manifest_crosslink_busy = 0;
return ( rc!=TH_ERROR );
}
/*
** Make an entry in the event table for a ticket change artifact.
*/
void manifest_ticket_event(
int rid, /* Artifact ID of the change ticket artifact */
|
| ︙ | ︙ | |||
1556 1557 1558 1559 1560 1561 1562 |
blob_zero(&comment);
blob_zero(&brief);
if( once ){
once = 0;
zTitleExpr = db_get("ticket-title-expr", "title");
zStatusColumn = db_get("ticket-status-column", "status");
}
| | | | 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 |
blob_zero(&comment);
blob_zero(&brief);
if( once ){
once = 0;
zTitleExpr = db_get("ticket-title-expr", "title");
zStatusColumn = db_get("ticket-status-column", "status");
}
zTitle = db_text("unknown",
"SELECT %s FROM ticket WHERE tkt_uuid='%s'",
zTitleExpr, pManifest->zTicketUuid
);
if( !isNew ){
for(i=0; i<pManifest->nField; i++){
if( fossil_strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
zNewStatus = pManifest->aField[i].zValue;
}
}
if( zNewStatus ){
blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
zNewStatus, pManifest->zTicketUuid, zTitle
);
if( pManifest->nField>1 ){
blob_appendf(&comment, " plus %d other change%s",
pManifest->nField-1, pManifest->nField==2 ? "" : "s");
}
blob_appendf(&brief, "%h ticket [%.10s].",
zNewStatus, pManifest->zTicketUuid);
}else{
zNewStatus = db_text("unknown",
"SELECT %s FROM ticket WHERE tkt_uuid='%s'",
zStatusColumn, pManifest->zTicketUuid
);
blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
"%d other change%s",
pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
pManifest->nField==1 ? "" : "s"
|
| ︙ | ︙ | |||
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 |
"VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)",
tktTagId, pManifest->rDate, rid, pManifest->zUser,
blob_str(&comment), blob_str(&brief)
);
blob_reset(&comment);
blob_reset(&brief);
}
/*
** Scan artifact rid/pContent to see if it is a control artifact of
** any key:
**
** * Manifest
** * Control
** * Wiki Page
** * Ticket Change
** * Cluster
** * Attachment
** * Event
**
** If the input is a control artifact, then make appropriate entries
** in the auxiliary tables of the database in order to crosslink the
** artifact.
**
| > > > > > > > > > > > > > > | | | > > > > > > > > > > | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 |
"VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)",
tktTagId, pManifest->rDate, rid, pManifest->zUser,
blob_str(&comment), blob_str(&brief)
);
blob_reset(&comment);
blob_reset(&brief);
}
/*
** This is the comparison function used to sort the tag array.
*/
static int tag_compare(const void *a, const void *b){
struct TagType *pA = (struct TagType*)a;
struct TagType *pB = (struct TagType*)b;
int c;
c = fossil_strcmp(pA->zUuid, pB->zUuid);
if( c==0 ){
c = fossil_strcmp(pA->zName, pB->zName);
}
return c;
}
/*
** Scan artifact rid/pContent to see if it is a control artifact of
** any key:
**
** * Manifest
** * Control
** * Wiki Page
** * Ticket Change
** * Cluster
** * Attachment
** * Event
**
** If the input is a control artifact, then make appropriate entries
** in the auxiliary tables of the database in order to crosslink the
** artifact.
**
** If global variable g.xlinkClusterOnly is true, then ignore all
** control artifacts other than clusters.
**
** This routine always resets the pContent blob before returning.
**
** Historical note: This routine original processed manifests only.
** Processing for other control artifacts was added later. The name
** of the routine, "manifest_crosslink", and the name of this source
** file, is a legacy of its original use.
*/
int manifest_crosslink(int rid, Blob *pContent, int flags){
int i, rc = TH_OK;
Manifest *p;
Stmt q;
int parentid = 0;
int permitHooks = (flags & MC_PERMIT_HOOKS);
const char *zScript = 0;
const char *zUuid = 0;
if( (p = manifest_cache_find(rid))!=0 ){
blob_reset(pContent);
}else if( (p = manifest_parse(pContent, rid, 0))==0 ){
assert( blob_is_reset(pContent) || pContent==0 );
fossil_error(1, "syntax error in manifest");
return 0;
}
if( g.xlinkClusterOnly && p->type!=CFTYPE_CLUSTER ){
manifest_destroy(p);
assert( blob_is_reset(pContent) );
fossil_error(1, "no manifest");
return 0;
}
if( p->type==CFTYPE_MANIFEST && fetch_baseline(p, 0) ){
manifest_destroy(p);
assert( blob_is_reset(pContent) );
fossil_error(1, "cannot fetch baseline manifest");
return 0;
}
db_begin_transaction();
if( p->type==CFTYPE_MANIFEST ){
if( permitHooks ){
zScript = xfer_commit_code();
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
}
if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
char *zCom;
for(i=0; i<p->nParent; i++){
int pid = uuid_to_rid(p->azParent[i], 1);
db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
"VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, p->rDate);
if( i==0 ){
|
| ︙ | ︙ | |||
1698 1699 1700 1701 1702 1703 1704 |
" %.17g"
" ),"
" %d,%Q,%Q,"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>0),"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),%.17g);",
TAG_DATE, rid, p->rDate,
| | | | | 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 |
" %.17g"
" ),"
" %d,%Q,%Q,"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>0),"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),%.17g);",
TAG_DATE, rid, p->rDate,
rid, p->zUser, p->zComment,
TAG_BGCOLOR, rid,
TAG_USER, rid,
TAG_COMMENT, rid, p->rDate
);
zCom = db_text(0, "SELECT coalesce(ecomment, comment) FROM event"
" WHERE rowid=last_insert_rowid()");
wiki_extract_links(zCom, rid, 0, p->rDate, 1, WIKI_INLINE);
free(zCom);
/* If this is a delta-manifest, record the fact that this repository
** contains delta manifests, to free the "commit" logic to generate
** new delta manifests.
*/
if( p->zBaseline!=0 ){
static int once = 1;
if( once ){
db_set_int("seen-delta-manifest", 1, 0);
once = 0;
}
}
}
}
if( p->type==CFTYPE_CLUSTER ){
|
| ︙ | ︙ | |||
1753 1754 1755 1756 1757 1758 1759 |
}
if( tid ){
switch( p->aTag[i].zName[0] ){
case '-': type = 0; break; /* Cancel prior occurrences */
case '+': type = 1; break; /* Apply to target only */
case '*': type = 2; break; /* Propagate to descendants */
default:
| | | | 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 |
}
if( tid ){
switch( p->aTag[i].zName[0] ){
case '-': type = 0; break; /* Cancel prior occurrences */
case '+': type = 1; break; /* Apply to target only */
case '*': type = 2; break; /* Propagate to descendants */
default:
fossil_error(1, "unknown tag type in manifest: %s", p->aTag);
return 0;
}
tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue,
rid, p->rDate, tid);
}
}
if( parentid ){
tag_propagate_all(parentid);
}
}
|
| ︙ | ︙ | |||
1797 1798 1799 1800 1801 1802 1803 |
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment,"
" bgcolor,euser,ecomment)"
"VALUES('w',%.17g,%d,%Q,%Q,"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
| | | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 |
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment,"
" bgcolor,euser,ecomment)"
"VALUES('w',%.17g,%d,%Q,%Q,"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype>1),"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
p->rDate, rid, p->zUser, zComment,
TAG_BGCOLOR, rid,
TAG_BGCOLOR, rid,
TAG_USER, rid,
TAG_COMMENT, rid
);
free(zComment);
}
|
| ︙ | ︙ | |||
1847 1848 1849 1850 1851 1852 1853 |
if( subsequent ){
content_deltify(rid, subsequent, 0);
}else{
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)"
"VALUES('e',%.17g,%d,%d,%Q,%Q,"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
| | | 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 |
if( subsequent ){
content_deltify(rid, subsequent, 0);
}else{
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)"
"VALUES('e',%.17g,%d,%d,%Q,%Q,"
" (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
p->rEventDate, rid, tagid, p->zUser, p->zComment,
TAG_BGCOLOR, rid
);
}
}
if( p->type==CFTYPE_TICKET ){
char *zTag;
|
| ︙ | ︙ | |||
1879 1880 1881 1882 1883 1884 1885 |
"(SELECT max(mtime) FROM attachment"
" WHERE target=%Q AND filename=%Q))"
" WHERE target=%Q AND filename=%Q",
p->zAttachTarget, p->zAttachName,
p->zAttachTarget, p->zAttachName
);
if( strlen(p->zAttachTarget)!=UUID_SIZE
| | | | | > > > > > | > | < | | > > > > > > | | > > > | > > > | | | < < | | > > > > > > > | > > > > > > | | | 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 |
"(SELECT max(mtime) FROM attachment"
" WHERE target=%Q AND filename=%Q))"
" WHERE target=%Q AND filename=%Q",
p->zAttachTarget, p->zAttachName,
p->zAttachTarget, p->zAttachName
);
if( strlen(p->zAttachTarget)!=UUID_SIZE
|| !validate16(p->zAttachTarget, UUID_SIZE)
){
char *zComment;
if( p->zAttachSrc && p->zAttachSrc[0] ){
zComment = mprintf(
"Add attachment [/artifact/%S|%h] to wiki page [%h]",
p->zAttachSrc, p->zAttachName, p->zAttachTarget);
}else{
zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]",
p->zAttachName, p->zAttachTarget);
}
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('w',%.17g,%d,%Q,%Q)",
p->rDate, rid, p->zUser, zComment
);
free(zComment);
}else{
char *zComment;
if( p->zAttachSrc && p->zAttachSrc[0] ){
zComment = mprintf(
"Add attachment [/artifact/%S|%h] to ticket [%S]",
p->zAttachSrc, p->zAttachName, p->zAttachTarget);
}else{
zComment = mprintf("Delete attachment \"%h\" from ticket [%.10s]",
p->zAttachName, p->zAttachTarget);
}
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('t',%.17g,%d,%Q,%Q)",
p->rDate, rid, p->zUser, zComment
);
free(zComment);
}
}
if( p->type==CFTYPE_CONTROL ){
Blob comment;
int i;
const char *zName;
const char *zValue;
const char *zTagUuid;
int branchMove = 0;
blob_zero(&comment);
if( p->zComment ){
blob_appendf(&comment, " %s.", p->zComment);
}
/* Next loop expects tags to be sorted on UUID, so sort it. */
qsort(p->aTag, p->nTag, sizeof(p->aTag[0]), tag_compare);
for(i=0; i<p->nTag; i++){
zTagUuid = p->aTag[i].zUuid;
if( !zTagUuid ) continue;
if( i==0 || fossil_strcmp(zTagUuid, p->aTag[i-1].zUuid)!=0 ){
blob_appendf(&comment,
" Edit [%S]:",
zTagUuid);
branchMove = 0;
if( permitHooks && db_exists("SELECT 1 FROM event, blob"
" WHERE event.type='ci' AND event.objid=blob.rid"
" AND blob.uuid='%s'", zTagUuid) ){
zScript = xfer_commit_code();
zUuid = zTagUuid;
}
}
zName = p->aTag[i].zName;
zValue = p->aTag[i].zValue;
if( strcmp(zName, "*branch")==0 ){
blob_appendf(&comment,
" Move to branch [/timeline?r=%h&nd&dp=%S&unhide | %h].",
zValue, zTagUuid, zValue);
branchMove = 1;
continue;
}else if( strcmp(zName, "*bgcolor")==0 ){
blob_appendf(&comment,
" Change branch background color to \"%h\".", zValue);
continue;
}else if( strcmp(zName, "+bgcolor")==0 ){
blob_appendf(&comment,
" Change background color to \"%h\".", zValue);
continue;
}else if( strcmp(zName, "-bgcolor")==0 ){
blob_appendf(&comment, " Cancel background color");
}else if( strcmp(zName, "+comment")==0 ){
blob_appendf(&comment, " Edit check-in comment.");
continue;
}else if( strcmp(zName, "+user")==0 ){
blob_appendf(&comment, " Change user to \"%h\".", zValue);
continue;
}else if( strcmp(zName, "+date")==0 ){
blob_appendf(&comment, " Timestamp %h.", zValue);
continue;
}else if( memcmp(zName, "-sym-",5)==0 ){
if( !branchMove ) blob_appendf(&comment, " Cancel tag \"%h\"", &zName[5]);
}else if( memcmp(zName, "*sym-",5)==0 ){
if( !branchMove ){
blob_appendf(&comment, " Add propagating tag \"%h\"", &zName[5]);
}
}else if( memcmp(zName, "+sym-",5)==0 ){
blob_appendf(&comment, " Add tag \"%h\"", &zName[5]);
}else if( strcmp(zName, "+closed")==0 ){
blob_append(&comment, " Marked \"Closed\"", -1);
}else if( strcmp(zName, "-closed")==0 ){
blob_append(&comment, " Removed the \"Closed\" mark", -1);
}else {
if( zName[0]=='-' ){
blob_appendf(&comment, " Cancel \"%h\"", &zName[1]);
}else if( zName[0]=='+' ){
blob_appendf(&comment, " Add \"%h\"", &zName[1]);
}else{
blob_appendf(&comment, " Add propagating \"%h\"", &zName[1]);
}
if( zValue && zValue[0] ){
blob_appendf(&comment, " with value \"%h\".", zValue);
}else{
blob_appendf(&comment, ".");
}
continue;
}
if( zValue && zValue[0] ){
blob_appendf(&comment, " with note \"%h\".", zValue);
}else{
blob_appendf(&comment, ".");
}
}
/*blob_appendf(&comment, " [[/info/%S | details]]");*/
if( blob_size(&comment)==0 ) blob_append(&comment, " ", 1);
db_multi_exec(
"REPLACE INTO event(type,mtime,objid,user,comment)"
"VALUES('g',%.17g,%d,%Q,%Q)",
p->rDate, rid, p->zUser, blob_str(&comment)+1
);
blob_reset(&comment);
}
db_end_transaction(0);
if( permitHooks ){
rc = xfer_run_common_script();
if( rc==TH_OK ){
rc = xfer_run_script(zScript, zUuid);
}
}
if( p->type==CFTYPE_MANIFEST ){
manifest_cache_insert(p);
}else{
manifest_destroy(p);
}
assert( blob_is_reset(pContent) );
return ( rc!=TH_ERROR );
}
/*
** COMMAND: test-crosslink
**
** Usage: %fossil test-crosslink RECORDID
**
** Run the manifest_crosslink() routine on the artifact with the given
** record ID. This is typically done in the debugger.
*/
void test_crosslink_cmd(void){
int rid;
Blob content;
db_find_and_open_repository(0, 0);
if( g.argc!=3 ) usage("RECORDID");
rid = name_to_rid(g.argv[2]);
content_get(rid, &content);
manifest_crosslink(rid, &content, MC_NONE);
}
|
Changes to src/markdown.c.
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
int work_active;
struct Blob *work;
};
/* html_tag -- structure for quick HTML tag search (inspired from discount) */
struct html_tag {
| | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
int work_active;
struct Blob *work;
};
/* html_tag -- structure for quick HTML tag search (inspired from discount) */
struct html_tag {
const char *text;
int size;
};
/********************
* GLOBAL VARIABLES *
********************/
/* block_tags -- recognised block tags, sorted by cmp_html_tag */
static const struct html_tag block_tags[] = {
{ "p", 1 },
{ "dl", 2 },
{ "h1", 2 },
{ "h2", 2 },
{ "h3", 2 },
{ "h4", 2 },
{ "h5", 2 },
|
| ︙ | ︙ | |||
274 275 276 277 278 279 280 | const struct html_tag *htb = b; if( hta->size!=htb->size ) return hta->size-htb->size; return fossil_strnicmp(hta->text, htb->text, hta->size); } /* find_block_tag -- returns the current block tag */ | | | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
const struct html_tag *htb = b;
if( hta->size!=htb->size ) return hta->size-htb->size;
return fossil_strnicmp(hta->text, htb->text, hta->size);
}
/* find_block_tag -- returns the current block tag */
static const struct html_tag *find_block_tag(const char *data, size_t size){
size_t i = 0;
struct html_tag key;
/* looking for the word end */
while( i<size
&& ((data[i]>='0' && data[i]<='9')
|| (data[i]>='A' && data[i]<='Z')
|
| ︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | /********************************* * BLOCK-LEVEL PARSING FUNCTIONS * *********************************/ /* is_empty -- returns the line length when it is empty, 0 otherwise */ | | | 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 |
/*********************************
* BLOCK-LEVEL PARSING FUNCTIONS *
*********************************/
/* is_empty -- returns the line length when it is empty, 0 otherwise */
static size_t is_empty(const char *data, size_t size){
size_t i;
for(i=0; i<size && data[i]!='\n'; i++){
if( data[i]!=' ' && data[i]!='\t' ) return 0;
}
return i+1;
}
|
| ︙ | ︙ | |||
1629 1630 1631 1632 1633 1634 1635 | } return skip; } /* htmlblock_end -- checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */ /* returns the length on match, 0 otherwise */ | | | 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 |
}
return skip;
}
/* htmlblock_end -- checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */
/* returns the length on match, 0 otherwise */
static size_t htmlblock_end(const struct html_tag *tag, const char *data, size_t size){
size_t i, w;
/* assuming data[0]=='<' && data[1]=='/' already tested */
/* checking tag is a match */
if( (tag->size+3)>=size
|| fossil_strnicmp(data+2, tag->text, tag->size)
|
| ︙ | ︙ | |||
1666 1667 1668 1669 1670 1671 1672 |
static size_t parse_htmlblock(
struct Blob *ob,
struct render *rndr,
char *data,
size_t size
){
size_t i, j = 0;
| | | 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 |
static size_t parse_htmlblock(
struct Blob *ob,
struct render *rndr,
char *data,
size_t size
){
size_t i, j = 0;
const struct html_tag *curtag;
int found;
size_t work_size = 0;
struct Blob work = BLOB_INITIALIZER;
/* identification of the opening tag */
if( size<2 || data[0]!='<' ) return 0;
curtag = find_block_tag(data+1, size-1);
|
| ︙ | ︙ |
Changes to src/md5.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include <string.h> #include <stdio.h> #include <sqlite3.h> #include "md5.h" /* * If compiled on a machine that doesn't have a 32-bit integer, | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include "config.h" #include <string.h> #include <stdio.h> #include <sqlite3.h> #include "md5.h" /* * If compiled on a machine that doesn't have a 32-bit integer, |
| ︙ | ︙ | |||
161 162 163 164 165 166 167 |
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
static void MD5Init(MD5Context *ctx){
| | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
}
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
static void MD5Init(MD5Context *ctx){
ctx->isInit = 1;
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
|
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
/*
** Print information about a particular check-in.
*/
void print_checkin_description(int rid, int indent, const char *zLabel){
Stmt q;
db_prepare(&q,
| | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/*
** Print information about a particular check-in.
*/
void print_checkin_description(int rid, int indent, const char *zLabel){
Stmt q;
db_prepare(&q,
"SELECT datetime(mtime%s),"
" coalesce(euser,user), coalesce(ecomment,comment),"
" (SELECT uuid FROM blob WHERE rid=%d),"
" (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref"
" WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
" AND tagxref.rid=%d AND tagxref.tagtype>0)"
" FROM event WHERE objid=%d", timeline_utc(), rid, rid, rid);
if( db_step(&q)==SQLITE_ROW ){
const char *zTagList = db_column_text(&q, 4);
char *zCom;
if( zTagList && zTagList[0] ){
zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
}else{
zCom = mprintf("%s", db_column_text(&q,2));
|
| ︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
**
** --case-sensitive BOOL Override the case-sensitive setting. If false,
** files whose names differ only in case are taken
** to be the same file.
**
** -f|--force Force the merge even if it would be a no-op.
**
** -n|--dry-run If given, display instead of run actions
**
** -v|--verbose Show additional details of the merge
*/
void merge_cmd(void){
int vid; /* Current version "V" */
int mid; /* Version we are merging from "M" */
int pid; /* The pivot version - most recent common ancestor P */
int verboseFlag; /* True if the -v|--verbose option is present */
int pickFlag; /* True if the --cherrypick option is present */
int backoutFlag; /* True if the --backout option is present */
int dryRunFlag; /* True if the --dry-run or -n option is present */
int forceFlag; /* True if the --force or -f option is present */
const char *zBinGlob; /* The value of --binary */
const char *zPivot; /* The value of --baseline */
int debugFlag; /* True if --debug is present */
| > > > | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
**
** --case-sensitive BOOL Override the case-sensitive setting. If false,
** files whose names differ only in case are taken
** to be the same file.
**
** -f|--force Force the merge even if it would be a no-op.
**
** --integrate Merged branch will be closed when committing.
**
** -n|--dry-run If given, display instead of run actions
**
** -v|--verbose Show additional details of the merge
*/
void merge_cmd(void){
int vid; /* Current version "V" */
int mid; /* Version we are merging from "M" */
int pid; /* The pivot version - most recent common ancestor P */
int verboseFlag; /* True if the -v|--verbose option is present */
int integrateFlag; /* True if the --integrate option is present */
int pickFlag; /* True if the --cherrypick option is present */
int backoutFlag; /* True if the --backout option is present */
int dryRunFlag; /* True if the --dry-run or -n option is present */
int forceFlag; /* True if the --force or -f option is present */
const char *zBinGlob; /* The value of --binary */
const char *zPivot; /* The value of --baseline */
int debugFlag; /* True if --debug is present */
|
| ︙ | ︙ | |||
126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
undo_capture_command_line();
verboseFlag = find_option("verbose","v",0)!=0;
if( !verboseFlag ){
verboseFlag = find_option("detail",0,0)!=0; /* deprecated */
}
pickFlag = find_option("cherrypick",0,0)!=0;
backoutFlag = find_option("backout",0,0)!=0;
debugFlag = find_option("debug",0,0)!=0;
zBinGlob = find_option("binary",0,1);
dryRunFlag = find_option("dry-run","n",0)!=0;
if( !dryRunFlag ){
dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */
}
| > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
undo_capture_command_line();
verboseFlag = find_option("verbose","v",0)!=0;
if( !verboseFlag ){
verboseFlag = find_option("detail",0,0)!=0; /* deprecated */
}
pickFlag = find_option("cherrypick",0,0)!=0;
integrateFlag = find_option("integrate",0,0)!=0;
backoutFlag = find_option("backout",0,0)!=0;
debugFlag = find_option("debug",0,0)!=0;
zBinGlob = find_option("binary",0,1);
dryRunFlag = find_option("dry-run","n",0)!=0;
if( !dryRunFlag ){
dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */
}
|
| ︙ | ︙ | |||
160 161 162 163 164 165 166 |
/* No version specified on the command-line so pick the most recent
** leaf that is (1) not the version currently checked out and (2)
** has not already been merged into the current checkout and (3)
** the leaf is not closed and (4) the leaf is in the same branch
** as the current checkout.
*/
Stmt q;
| | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
/* No version specified on the command-line so pick the most recent
** leaf that is (1) not the version currently checked out and (2)
** has not already been merged into the current checkout and (3)
** the leaf is not closed and (4) the leaf is in the same branch
** as the current checkout.
*/
Stmt q;
if( pickFlag || backoutFlag || integrateFlag){
fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
}
mid = db_int(0,
"SELECT leaf.rid"
" FROM leaf, event"
" WHERE leaf.rid=event.objid"
" AND leaf.rid!=%d" /* Constraint (1) */
" AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
db_text(0, "SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=%d AND tagtype>0",
TAG_BRANCH, vid)
);
}
db_prepare(&q,
"SELECT blob.uuid,"
| | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
db_text(0, "SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=%d AND tagtype>0",
TAG_BRANCH, vid)
);
}
db_prepare(&q,
"SELECT blob.uuid,"
" datetime(event.mtime%s),"
" coalesce(ecomment, comment),"
" coalesce(euser, user)"
" FROM event, blob"
" WHERE event.objid=%d AND blob.rid=%d",
timeline_utc(), mid, mid
);
if( db_step(&q)==SQLITE_ROW ){
char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"",
db_column_text(&q, 0), db_column_text(&q, 1),
db_column_text(&q, 3), db_column_text(&q, 2));
comment_print(zCom, 0, 79);
fossil_free(zCom);
|
| ︙ | ︙ | |||
218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
if( pid==0 || !is_a_version(pid) ){
fossil_fatal("not a version: %s", zPivot);
}
if( pickFlag ){
fossil_fatal("incompatible options: --cherrypick & --baseline");
}
}else if( pickFlag || backoutFlag ){
pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid);
if( pid<=0 ){
fossil_fatal("cannot find an ancestor for %s", g.argv[2]);
}
}else{
pivot_set_primary(mid);
pivot_set_secondary(vid);
| > > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
if( pid==0 || !is_a_version(pid) ){
fossil_fatal("not a version: %s", zPivot);
}
if( pickFlag ){
fossil_fatal("incompatible options: --cherrypick & --baseline");
}
}else if( pickFlag || backoutFlag ){
if( integrateFlag ){
fossil_fatal("incompatible options: --integrate & --cherrypick or --backout");
}
pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid);
if( pid<=0 ){
fossil_fatal("cannot find an ancestor for %s", g.argv[2]);
}
}else{
pivot_set_primary(mid);
pivot_set_secondary(vid);
|
| ︙ | ︙ | |||
249 250 251 252 253 254 255 256 |
fossil_fatal("not a version: record #%d", pid);
}
if( !forceFlag && mid==pid ){
fossil_print("Merge skipped because it is a no-op. "
" Use --force to override.\n");
return;
}
if( verboseFlag ){
| > > > > | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
fossil_fatal("not a version: record #%d", pid);
}
if( !forceFlag && mid==pid ){
fossil_print("Merge skipped because it is a no-op. "
" Use --force to override.\n");
return;
}
if( integrateFlag && !is_a_leaf(mid)){
fossil_warning("ignoring --integrate: %s is not a leaf", g.argv[2]);
integrateFlag = 0;
}
if( verboseFlag ){
print_checkin_description(mid, 12, integrateFlag?"integrate:":"merge-from:");
print_checkin_description(pid, 12, "baseline:");
}
vfile_check_signature(vid, CKSIG_ENOTFILE);
db_begin_transaction();
if( !dryRunFlag ) undo_begin();
load_vfile_from_rid(mid);
load_vfile_from_rid(pid);
|
| ︙ | ︙ | |||
432 433 434 435 436 437 438 |
int idm = db_column_int(&q, 0);
int rowid = db_column_int(&q, 1);
int idv;
const char *zName;
char *zFullName;
db_multi_exec(
"INSERT INTO vfile(vid,chnged,deleted,rid,mrid,isexe,islink,pathname)"
| | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
int idm = db_column_int(&q, 0);
int rowid = db_column_int(&q, 1);
int idv;
const char *zName;
char *zFullName;
db_multi_exec(
"INSERT INTO vfile(vid,chnged,deleted,rid,mrid,isexe,islink,pathname)"
" SELECT %d,%d,0,rid,mrid,isexe,islink,pathname FROM vfile WHERE id=%d",
vid, integrateFlag?5:3, idm
);
idv = db_last_insert_rowid();
db_multi_exec("UPDATE fv SET idv=%d WHERE rowid=%d", idv, rowid);
zName = db_column_text(&q, 2);
zFullName = mprintf("%s%s", g.zLocalRoot, zName);
if( file_wd_isfile_or_link(zFullName) ){
fossil_print("ADDED %s (overwrites an unmanaged file)\n", zName);
|
| ︙ | ︙ | |||
472 473 474 475 476 477 478 |
const char *zName = db_column_text(&q, 2);
int islinkm = db_column_int(&q, 3);
/* Copy content from idm over into idv. Overwrite idv. */
fossil_print("UPDATE %s\n", zName);
if( !dryRunFlag ){
undo_save(zName);
db_multi_exec(
| | | | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 |
const char *zName = db_column_text(&q, 2);
int islinkm = db_column_int(&q, 3);
/* Copy content from idm over into idv. Overwrite idv. */
fossil_print("UPDATE %s\n", zName);
if( !dryRunFlag ){
undo_save(zName);
db_multi_exec(
"UPDATE vfile SET mtime=0, mrid=%d, chnged=%d, islink=%d "
" WHERE id=%d", ridm, integrateFlag?4:2, islinkm, idv
);
vfile_to_disk(0, idv, 0, 0);
}
}
db_finalize(&q);
/*
|
| ︙ | ︙ | |||
642 643 644 645 646 647 648 649 650 651 652 653 654 |
"REPLACE INTO vvar(name,value)"
" SELECT 'ci-comment', coalesce(ecomment,comment) FROM event"
" WHERE type='ci' AND objid=%d",
mid
);
}else if( backoutFlag ){
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-2,%d)",pid);
}else{
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid);
}
undo_finish();
db_end_transaction(dryRunFlag);
}
| > > | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 |
"REPLACE INTO vvar(name,value)"
" SELECT 'ci-comment', coalesce(ecomment,comment) FROM event"
" WHERE type='ci' AND objid=%d",
mid
);
}else if( backoutFlag ){
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-2,%d)",pid);
}else if( integrateFlag ){
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(-4,%d)",mid);
}else{
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid);
}
undo_finish();
db_end_transaction(dryRunFlag);
}
|
Changes to src/merge3.c.
| ︙ | ︙ | |||
338 339 340 341 342 343 344 | blob_read_from_file(&file, zFullpath); rc = contains_merge_marker(&file); blob_reset(&file); return rc; } /* | | | | > > > > | > > > > > > > > > > > > > > > | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
blob_read_from_file(&file, zFullpath);
rc = contains_merge_marker(&file);
blob_reset(&file);
return rc;
}
/*
** COMMAND: 3-way-merge*
**
** Usage: %fossil 3-way-merge BASELINE V1 V2 MERGED
**
** Inputs are files BASELINE, V1, and V2. The file MERGED is generated
** as output.
**
** BASELINE is a common ancestor of two files V1 and V2 that have diverging
** edits. The generated output file MERGED is the combination of all
** changes in both V1 and V2.
**
** This command has no effect on the Fossil repository. It is a utility
** command made available for the convenience of users. This command can
** be used, for example, to help import changes from an upstream project.
**
** Suppose an upstream project has a file named "Xup.c" which is imported
** with modifications to the local project as "Xlocal.c". Suppose further
** that the "Xbase.c" is an exact copy of the last imported "Xup.c".
** Then to import the latest "Xup.c" while preserving all the local changes:
**
** fossil 3-way-merge Xbase.c Xlocal.c Xup.c Xlocal.c
** cp Xup.c Xbase.c
** # Verify that everything still works
** fossil commit
**
*/
void delta_3waymerge_cmd(void){
Blob pivot, v1, v2, merged;
if( g.argc!=6 ){
usage("PIVOT V1 V2 MERGED");
}
if( blob_read_from_file(&pivot, g.argv[2])<0 ){
|
| ︙ | ︙ |
Changes to src/moderate.c.
| ︙ | ︙ | |||
62 63 64 65 66 67 68 |
return rc;
}
/*
** Check to see if the object identified by RID is used for anything.
*/
static int object_used(int rid){
| | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
return rc;
}
/*
** Check to see if the object identified by RID is used for anything.
*/
static int object_used(int rid){
static const char *const aTabField[] = {
"modreq", "attachRid",
"mlink", "mid",
"mlink", "fid",
"tagxref", "srcid",
"tagxref", "rid",
};
int i;
|
| ︙ | ︙ |
Changes to src/name.c.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | ** ******************************************************************************* ** ** This file contains code used to convert user-supplied object names into ** canonical UUIDs. ** ** A user-supplied object name is any unique prefix of a valid UUID but | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ** ******************************************************************************* ** ** This file contains code used to convert user-supplied object names into ** canonical UUIDs. ** ** A user-supplied object name is any unique prefix of a valid UUID but ** not necessarily in canonical form. */ #include "config.h" #include "name.h" #include <assert.h> /* ** Return TRUE if the string begins with something that looks roughly |
| ︙ | ︙ | |||
48 49 50 51 52 53 54 | /* ** Convert a symbolic name into a RID. Acceptable forms: ** ** * SHA1 hash ** * SHA1 hash prefix of at least 4 characters ** * Symbolic Name ** * "tag:" + symbolic name | | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
/*
** Convert a symbolic name into a RID. Acceptable forms:
**
** * SHA1 hash
** * SHA1 hash prefix of at least 4 characters
** * Symbolic Name
** * "tag:" + symbolic name
** * Date or date-time
** * "date:" + Date or date-time
** * symbolic-name ":" date-time
** * "tip"
**
** The following additional forms are available in local checkouts:
**
** * "current"
** * "prev" or "previous"
** * "next"
**
** Return the RID of the matching artifact. Or return 0 if the name does not
** match any known object. Or return -1 if the name is ambiguous.
**
** The zType parameter specifies the type of artifact: ci, t, w, e, g.
** If zType is NULL or "" or "*" then any type of artifact will serve.
** zType is "ci" in most use cases since we are usually searching for
** a check-in.
*/
int symbolic_name_to_rid(const char *zTag, const char *zType){
int vid;
int rid = 0;
|
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
if( rid ) return rid;
}
/* special keywords: "prev", "previous", "current", and "next" */
if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){
if( fossil_strcmp(zTag, "current")==0 ){
rid = vid;
| | | | | | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
if( rid ) return rid;
}
/* special keywords: "prev", "previous", "current", and "next" */
if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){
if( fossil_strcmp(zTag, "current")==0 ){
rid = vid;
}else if( fossil_strcmp(zTag, "prev")==0
|| fossil_strcmp(zTag, "previous")==0 ){
rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid);
}else if( fossil_strcmp(zTag, "next")==0 ){
rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d"
" ORDER BY isprim DESC, mtime DESC", vid);
}
if( rid ) return rid;
}
/* Date and times */
if( memcmp(zTag, "date:", 5)==0 ){
rid = db_int(0,
"SELECT objid FROM event"
" WHERE mtime<=julianday(%Q,'utc') AND type GLOB '%q'"
" ORDER BY mtime DESC LIMIT 1",
&zTag[5], zType);
return rid;
}
if( fossil_isdate(zTag) ){
rid = db_int(0,
"SELECT objid FROM event"
" WHERE mtime<=julianday(%Q,'utc') AND type GLOB '%q'"
" ORDER BY mtime DESC LIMIT 1",
zTag, zType);
if( rid) return rid;
}
/* Deprecated date & time formats: "local:" + date-time and
** "utc:" + date-time */
if( memcmp(zTag, "local:", 6)==0 ){
rid = db_int(0,
"SELECT objid FROM event"
" WHERE mtime<=julianday(%Q) AND type GLOB '%q'"
" ORDER BY mtime DESC LIMIT 1",
&zTag[6], zType);
return rid;
}
if( memcmp(zTag, "utc:", 4)==0 ){
rid = db_int(0,
"SELECT objid FROM event"
" WHERE mtime<=julianday('%qz') AND type GLOB '%q'"
" ORDER BY mtime DESC LIMIT 1",
&zTag[4], zType);
return rid;
}
/* "tag:" + symbolic-name */
if( memcmp(zTag, "tag:", 4)==0 ){
rid = db_int(0,
"SELECT event.objid, max(event.mtime)"
" FROM tag, tagxref, event"
" WHERE tag.tagname='sym-%q' "
" AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
" AND event.objid=tagxref.rid "
" AND event.type GLOB '%q'",
&zTag[4], zType
);
return rid;
}
/* root:TAG -> The origin of the branch */
if( memcmp(zTag, "root:", 5)==0 ){
Stmt q;
int rc;
char *zBr;
rid = symbolic_name_to_rid(zTag+5, zType);
zBr = db_text("trunk","SELECT value FROM tagxref"
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 |
" AND event.objid=tagxref.rid "
" AND event.type GLOB '%q'",
zTag, zType
);
if( rid>0 ) return rid;
/* Undocumented: numeric tags get translated directly into the RID */
| > > | | | | | | | | | | > | | | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
" AND event.objid=tagxref.rid "
" AND event.type GLOB '%q'",
zTag, zType
);
if( rid>0 ) return rid;
/* Undocumented: numeric tags get translated directly into the RID */
if( memcmp(zTag, "rid:", 4)==0 ){
zTag += 4;
for(i=0; fossil_isdigit(zTag[i]); i++){}
if( zTag[i]==0 ){
if( strcmp(zType,"*")==0 ){
rid = atoi(zTag);
}else{
rid = db_int(0,
"SELECT event.objid"
" FROM event"
" WHERE event.objid=%s"
" AND event.type GLOB '%q'", zTag, zType);
}
}
}
return rid;
}
/*
** This routine takes a user-entered UUID which might be in mixed
** case and might only be a prefix of the full UUID and converts it
** into the full-length UUID in canonical form.
**
** If the input is not a UUID or a UUID prefix, then try to resolve
** the name as a tag. If multiple tags match, pick the latest.
** If the input name matches "tag:*" then always resolve as a tag.
**
** If the input is not a tag, then try to match it as an ISO-8601 date
** string YYYY-MM-DD HH:MM:SS and pick the nearest check-in to that date.
** If the input is of the form "date:*" then always resolve the name as
** a date. The forms "utc:*" and "local:" are deprecated.
**
** Return 0 on success. Return 1 if the name cannot be resolved.
** Return 2 name is ambiguous.
*/
int name_to_uuid(Blob *pName, int iErrPriority, const char *zType){
char *zName = blob_str(pName);
int rid = symbolic_name_to_rid(zName, zType);
|
| ︙ | ︙ | |||
374 375 376 377 378 379 380 |
int name_to_rid(const char *zName){
return name_to_typed_rid(zName, "*");
}
/*
** WEBPAGE: ambiguous
** URL: /ambiguous?name=UUID&src=WEBPAGE
| | | | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
int name_to_rid(const char *zName){
return name_to_typed_rid(zName, "*");
}
/*
** WEBPAGE: ambiguous
** URL: /ambiguous?name=UUID&src=WEBPAGE
**
** The UUID given by the name parameter is ambiguous. Display a page
** that shows all possible choices and let the user select between them.
*/
void ambiguous_page(void){
Stmt q;
const char *zName = P("name");
const char *zSrc = P("src");
char *z;
if( zName==0 || zName[0]==0 || zSrc==0 || zSrc[0]==0 ){
fossil_redirect_home();
}
style_header("Ambiguous Artifact ID");
@ <p>The artifact id <b>%h(zName)</b> is ambiguous and might
@ mean any of the following:
@ <ol>
|
| ︙ | ︙ | |||
453 454 455 456 457 458 459 |
if( rid<0 ){
fossil_print("Ambiguous artifact name prefix: %s\n", zName);
}else if( rid==0 ){
fossil_print("Unknown artifact: %s\n", zName);
}else{
Stmt q;
db_prepare(&q,
| | | | | | | | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
if( rid<0 ){
fossil_print("Ambiguous artifact name prefix: %s\n", zName);
}else if( rid==0 ){
fossil_print("Unknown artifact: %s\n", zName);
}else{
Stmt q;
db_prepare(&q,
"SELECT uuid, size, datetime(mtime%s), ipaddr,"
" (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref"
" WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
" AND tagxref.rid=blob.rid AND tagxref.tagtype>0)"
" FROM blob, rcvfrom"
" WHERE rid=%d"
" AND rcvfrom.rcvid=blob.rcvid",
timeline_utc(), rid);
if( db_step(&q)==SQLITE_ROW ){
const char *zTagList = db_column_text(&q, 4);
if( verboseFlag ){
fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
fossil_print("size: %d bytes\n", db_column_int(&q,1));
fossil_print("received: %s from %s\n",
db_column_text(&q, 2),
db_column_text(&q, 3));
}else{
fossil_print("artifact: %s\n", db_column_text(&q,0));
fossil_print("size: %d bytes\n", db_column_int(&q,1));
}
if( zTagList && zTagList[0] ){
fossil_print("tags: %s\n", zTagList);
}
}
db_finalize(&q);
db_prepare(&q,
"SELECT type, datetime(mtime%s),"
" coalesce(euser,user), coalesce(ecomment,comment)"
" FROM event WHERE objid=%d", timeline_utc(), rid);
if( db_step(&q)==SQLITE_ROW ){
const char *zType;
switch( db_column_text(&q,0)[0] ){
case 'c': zType = "Check-in"; break;
case 'w': zType = "Wiki-edit"; break;
case 'e': zType = "Event"; break;
case 't': zType = "Ticket-change"; break;
case 'g': zType = "Tag-change"; break;
default: zType = "Unknown"; break;
}
fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
db_column_text(&q, 1));
fossil_print("comment: ");
comment_print(db_column_text(&q,3), 10, 78);
}
db_finalize(&q);
db_prepare(&q,
"SELECT filename.name, blob.uuid, datetime(event.mtime%s),"
" coalesce(euser,user), coalesce(ecomment,comment)"
" FROM mlink, filename, blob, event"
" WHERE mlink.fid=%d"
" AND filename.fnid=mlink.fnid"
" AND event.objid=mlink.mid"
" AND blob.rid=mlink.mid"
" ORDER BY event.mtime DESC /*sort*/",
timeline_utc(), rid);
while( db_step(&q)==SQLITE_ROW ){
fossil_print("file: %s\n", db_column_text(&q,0));
fossil_print(" part of [%.10s] by %s on %s\n",
db_column_text(&q, 1),
db_column_text(&q, 3),
db_column_text(&q, 2));
fossil_print(" ");
comment_print(db_column_text(&q,4), 10, 78);
}
db_finalize(&q);
}
}
|
Changes to src/pivot.c.
| ︙ | ︙ | |||
80 81 82 83 84 85 86 |
Stmt q1, q2, u1, i1;
int rid = 0;
/* aqueue must contain at least one primary and one other. Otherwise
** we abort early
*/
if( db_int(0, "SELECT count(distinct src) FROM aqueue")<2 ){
| | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
Stmt q1, q2, u1, i1;
int rid = 0;
/* aqueue must contain at least one primary and one other. Otherwise
** we abort early
*/
if( db_int(0, "SELECT count(distinct src) FROM aqueue")<2 ){
fossil_fatal("lack both primary and secondary files");
}
/* Prepare queries we will be needing
**
** The first query finds the oldest pending version on the aqueue. This
** will be next one searched.
*/
|
| ︙ | ︙ |
Changes to src/popen.c.
| ︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include <fcntl.h>
/*
** Print a fatal error and quit.
*/
static void win32_fatal_error(const char *zMsg){
fossil_fatal("%s", zMsg);
}
#endif
/*
** The following macros are used to cast pointers to integers and
** integers to pointers. The way you do this varies from one compiler
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
| > > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#include <fcntl.h>
/*
** Print a fatal error and quit.
*/
static void win32_fatal_error(const char *zMsg){
fossil_fatal("%s", zMsg);
}
#else
#include <signal.h>
#include <sys/wait.h>
#endif
/*
** The following macros are used to cast pointers to integers and
** integers to pointers. The way you do this varies from one compiler
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
|
| ︙ | ︙ | |||
169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
close(pin[0]);
close(pin[1]);
close(pout[0]);
close(pout[1]);
*pChildPid = 0;
return 1;
}
if( *pChildPid==0 ){
int fd;
int nErr = 0;
/* This is the child process */
close(0);
fd = dup(pout[0]);
if( fd!=0 ) nErr++;
| > | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
close(pin[0]);
close(pin[1]);
close(pout[0]);
close(pout[1]);
*pChildPid = 0;
return 1;
}
signal(SIGPIPE,SIG_IGN);
if( *pChildPid==0 ){
int fd;
int nErr = 0;
/* This is the child process */
close(0);
fd = dup(pout[0]);
if( fd!=0 ) nErr++;
|
| ︙ | ︙ | |||
209 210 211 212 213 214 215 216 217 | /* Not implemented, yet */ close(fdIn); fclose(pOut); #else close(fdIn); fclose(pOut); kill(childPid, SIGINT); #endif } | > | 213 214 215 216 217 218 219 220 221 222 |
/* Not implemented, yet */
close(fdIn);
fclose(pOut);
#else
close(fdIn);
fclose(pOut);
kill(childPid, SIGINT);
while( waitpid(0, 0, WNOHANG)>0 ) {}
#endif
}
|
Changes to src/printf.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | */ #include "config.h" #include "printf.h" #if defined(_WIN32) # include <io.h> # include <fcntl.h> #endif /* ** Conversion types fall into various categories as defined by the ** following enumeration. */ #define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */ #define etFLOAT 2 /* Floating point. %f */ | > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | */ #include "config.h" #include "printf.h" #if defined(_WIN32) # include <io.h> # include <fcntl.h> #endif #include <time.h> /* ** Conversion types fall into various categories as defined by the ** following enumeration. */ #define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */ #define etFLOAT 2 /* Floating point. %f */ |
| ︙ | ︙ | |||
856 857 858 859 860 861 862 | #endif assert( toStdErr==0 || toStdErr==1 ); fwrite(z, 1, n, toStdErr ? stderr : stdout); fflush(toStdErr ? stderr : stdout); } /* | | | 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 |
#endif
assert( toStdErr==0 || toStdErr==1 );
fwrite(z, 1, n, toStdErr ? stderr : stdout);
fflush(toStdErr ? stderr : stdout);
}
/*
** Force the standard output cursor to move to the beginning
** of a line, if it is not there already.
*/
void fossil_force_newline(void){
if( g.cgiOutput==0 && stdoutAtBOL==0 ) fossil_puts("\n", 0);
}
/*
|
| ︙ | ︙ | |||
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 |
b = empty_blob;
vxprintf(&b, zFormat, ap);
fossil_puts(blob_str(&b), 1);
blob_reset(&b);
va_end(ap);
}
/*
** The following variable becomes true while processing a fatal error
** or a panic. If additional "recursive-fatal" errors occur while
** shutting down, the recursive errors are silently ignored.
*/
static int mainInFatalError = 0;
/*
** Print an error message, rollback all databases, and quit. These
** routines never return.
*/
NORETURN void fossil_panic(const char *zFormat, ...){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > | > > > > | > | < | > > < < | > | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 |
b = empty_blob;
vxprintf(&b, zFormat, ap);
fossil_puts(blob_str(&b), 1);
blob_reset(&b);
va_end(ap);
}
/*
** Write a message to the error log, if the error log filename is
** defined.
*/
static void fossil_errorlog(const char *zFormat, ...){
struct tm *pNow;
time_t now;
FILE *out;
const char *z;
int i;
va_list ap;
static const char *const azEnv[] = { "HTTP_HOST", "HTTP_USER_AGENT",
"PATH_INFO", "QUERY_STRING", "REMOTE_ADDR", "REQUEST_METHOD",
"REQUEST_URI", "SCRIPT_NAME" };
if( g.zErrlog==0 ) return;
out = fossil_fopen(g.zErrlog, "a");
if( out==0 ) return;
now = time(0);
pNow = gmtime(&now);
fprintf(out, "------------- %04d-%02d-%02d %02d:%02d:%02d UTC ------------\n",
pNow->tm_year+1900, pNow->tm_mon+1, pNow->tm_mday+1,
pNow->tm_hour, pNow->tm_min, pNow->tm_sec);
va_start(ap, zFormat);
vfprintf(out, zFormat, ap);
fprintf(out, "\n");
va_end(ap);
for(i=0; i<sizeof(azEnv)/sizeof(azEnv[0]); i++){
char *p;
if( (p = fossil_getenv(azEnv[i]))!=0 ){
fprintf(out, "%s=%s\n", azEnv[i], p);
fossil_filename_free(p);
}else if( (z = P(azEnv[i]))!=0 ){
fprintf(out, "%s=%s\n", azEnv[i], z);
}
}
fclose(out);
}
/*
** The following variable becomes true while processing a fatal error
** or a panic. If additional "recursive-fatal" errors occur while
** shutting down, the recursive errors are silently ignored.
*/
static int mainInFatalError = 0;
/*
** Print an error message, rollback all databases, and quit. These
** routines never return.
*/
NORETURN void fossil_panic(const char *zFormat, ...){
va_list ap;
int rc = 1;
char z[1000];
static int once = 0;
if( once ) exit(1);
once = 1;
mainInFatalError = 1;
db_force_rollback();
va_start(ap, zFormat);
sqlite3_vsnprintf(sizeof(z),z,zFormat, ap);
va_end(ap);
fossil_errorlog("panic: %s", z);
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode ){
json_err( 0, z, 1 );
if( g.isHTTP ){
rc = 0 /* avoid HTTP 500 */;
}
}
else
#endif
{
if( g.cgiOutput ){
cgi_printf("<p class=\"generalError\">%h</p>", z);
cgi_reply();
}else if( !g.fQuiet ){
fossil_force_newline();
fossil_puts("Fossil internal error: ", 1);
fossil_puts(z, 1);
fossil_puts("\n", 1);
}
}
exit(rc);
}
NORETURN void fossil_fatal(const char *zFormat, ...){
char *z;
int rc = 1;
va_list ap;
mainInFatalError = 1;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
fossil_errorlog("fatal: %s", z);
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode ){
json_err( g.json.resultCode, z, 1 );
if( g.isHTTP ){
rc = 0 /* avoid HTTP 500 */;
}
}
|
| ︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 |
va_list ap;
int rc = 1;
if( mainInFatalError ) return;
mainInFatalError = 1;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode ){
json_err( g.json.resultCode, z, 1 );
if( g.isHTTP ){
rc = 0 /* avoid HTTP 500 */;
}
} else
| > | 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 |
va_list ap;
int rc = 1;
if( mainInFatalError ) return;
mainInFatalError = 1;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
fossil_errorlog("fatal: %s", z);
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode ){
json_err( g.json.resultCode, z, 1 );
if( g.isHTTP ){
rc = 0 /* avoid HTTP 500 */;
}
} else
|
| ︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 |
/* Print a warning message */
void fossil_warning(const char *zFormat, ...){
char *z;
va_list ap;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode){
json_warn( FSL_JSON_W_UNKNOWN, z );
}else
#endif
{
if( g.cgiOutput ){
| > | 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 |
/* Print a warning message */
void fossil_warning(const char *zFormat, ...){
char *z;
va_list ap;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
fossil_errorlog("warning: %s", z);
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode){
json_warn( FSL_JSON_W_UNKNOWN, z );
}else
#endif
{
if( g.cgiOutput ){
|
| ︙ | ︙ |
Changes to src/rebuild.c.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 | @ CREATE TABLE IF NOT EXISTS shun( @ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form @ mtime INTEGER, -- When added. Seconds since 1970 @ scom TEXT -- Optional text explaining why the shun occurred @ ); @ @ -- Artifacts that should not be pushed are stored in the "private" | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | @ CREATE TABLE IF NOT EXISTS shun( @ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form @ mtime INTEGER, -- When added. Seconds since 1970 @ scom TEXT -- Optional text explaining why the shun occurred @ ); @ @ -- Artifacts that should not be pushed are stored in the "private" @ -- table. @ -- @ CREATE TABLE IF NOT EXISTS private(rid INTEGER PRIMARY KEY); @ @ -- Some ticket content (such as the originators email address or contact @ -- information) needs to be obscured to protect privacy. This is achieved @ -- by storing an SHA1 hash of the content. For display, the hash is @ -- mapped back into the original text using this table. @ -- @ -- This table contains sensitive information and should not be shared @ -- with unauthorized users. @ -- @ CREATE TABLE IF NOT EXISTS concealed( @ hash TEXT PRIMARY KEY, -- The SHA1 hash of content @ mtime INTEGER, -- Time created. Seconds since 1970 |
| ︙ | ︙ | |||
151 152 153 154 155 156 157 |
" WHERE name='concealed' AND sql GLOB '* mtime *'");
if( rc==0 ){
db_multi_exec(
"ALTER TABLE concealed ADD COLUMN mtime INTEGER;"
"UPDATE concealed SET mtime=now();"
);
}
| | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
" WHERE name='concealed' AND sql GLOB '* mtime *'");
if( rc==0 ){
db_multi_exec(
"ALTER TABLE concealed ADD COLUMN mtime INTEGER;"
"UPDATE concealed SET mtime=now();"
);
}
}
/*
** Variables used to store state information about an on-going "rebuild"
** or "deconstruct".
*/
static int totalSize; /* Total number of artifacts to process */
static int processCnt; /* Number processed so far */
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
/* Fix up the "blob.size" field if needed. */
if( size!=blob_size(pBase) ){
db_multi_exec(
"UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid
);
}
| | | | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
/* Fix up the "blob.size" field if needed. */
if( size!=blob_size(pBase) ){
db_multi_exec(
"UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid
);
}
/* Find all children of artifact rid */
db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid");
db_bind_int(&q1, ":rid", rid);
bag_init(&children);
while( db_step(&q1)==SQLITE_ROW ){
int cid = db_column_int(&q1, 0);
if( !bag_find(&bagDone, cid) ){
bag_insert(&children, cid);
}
}
nChild = bag_count(&children);
db_reset(&q1);
/* Crosslink the artifact */
if( nChild==0 ){
pUse = pBase;
}else{
blob_copy(©, pBase);
pUse = ©
}
if( zFNameFormat==0 ){
/* We are doing "fossil rebuild" */
manifest_crosslink(rid, pUse, MC_NONE);
}else{
/* We are doing "fossil deconstruct" */
char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength);
blob_write_to_file(pUse,zFile);
free(zFile);
free(zUuid);
blob_reset(pUse);
}
assert( blob_is_reset(pUse) );
rebuild_step_done(rid);
/* Call all children recursively */
rid = 0;
for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){
static Stmt q2;
int sz;
db_static_prepare(&q2, "SELECT content, size FROM blob WHERE rid=:rid");
db_bind_int(&q2, ":rid", cid);
|
| ︙ | ︙ | |||
347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
zTable = db_text(0,
"SELECT name FROM sqlite_master /*scan*/"
" WHERE type='table'"
" AND name NOT IN ('blob','delta','rcvfrom','user',"
"'config','shun','private','reportfmt',"
"'concealed','accesslog','modreq')"
" AND name NOT GLOB 'sqlite_*'"
);
if( zTable==0 ) break;
db_multi_exec("DROP TABLE %Q", zTable);
free(zTable);
}
db_multi_exec(zRepositorySchema2);
ticket_create_table(0);
| > | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
zTable = db_text(0,
"SELECT name FROM sqlite_master /*scan*/"
" WHERE type='table'"
" AND name NOT IN ('blob','delta','rcvfrom','user',"
"'config','shun','private','reportfmt',"
"'concealed','accesslog','modreq')"
" AND name NOT GLOB 'sqlite_*'"
" AND name NOT GLOB 'fx_*'"
);
if( zTable==0 ) break;
db_multi_exec("DROP TABLE %Q", zTable);
free(zTable);
}
db_multi_exec(zRepositorySchema2);
ticket_create_table(0);
|
| ︙ | ︙ | |||
409 410 411 412 413 414 415 |
}
}else{
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
rebuild_step_done(rid);
}
}
db_finalize(&s);
| | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
}
}else{
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
rebuild_step_done(rid);
}
}
db_finalize(&s);
manifest_crosslink_end(MC_NONE);
rebuild_tag_trunk();
if( ttyOutput && !g.fQuiet && totalSize>0 ){
processCnt += incrSize;
percent_complete((processCnt*1000)/totalSize);
}
if( doClustering ) create_cluster();
if( ttyOutput && !g.fQuiet && totalSize>0 ){
|
| ︙ | ︙ | |||
578 579 580 581 582 583 584 |
}
db_begin_transaction();
ttyOutput = 1;
errCnt = rebuild_db(randomizeFlag, 1, doClustering);
reconstruct_private_table();
db_multi_exec(
"REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());"
| | > | | 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 |
}
db_begin_transaction();
ttyOutput = 1;
errCnt = rebuild_db(randomizeFlag, 1, doClustering);
reconstruct_private_table();
db_multi_exec(
"REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());"
"REPLACE INTO config(name,value,mtime) VALUES('aux-schema','%s',now());"
"REPLACE INTO config(name,value,mtime) VALUES('rebuilt','%s',now());",
CONTENT_SCHEMA, AUX_SCHEMA, get_version()
);
if( errCnt && !forceFlag ){
fossil_print(
"%d errors. Rolling back changes. Use --force to force a commit.\n",
errCnt
);
db_end_transaction(1);
|
| ︙ | ︙ | |||
604 605 606 607 608 609 610 |
db_open_repository(g.zRepositoryName);
if( newPagesize ){
db_multi_exec("PRAGMA page_size=%d", newPagesize);
runVacuum = 1;
}
if( runDeanalyze ){
db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
| | > | | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
db_open_repository(g.zRepositoryName);
if( newPagesize ){
db_multi_exec("PRAGMA page_size=%d", newPagesize);
runVacuum = 1;
}
if( runDeanalyze ){
db_multi_exec("DROP TABLE IF EXISTS sqlite_stat1;"
"DROP TABLE IF EXISTS sqlite_stat3;"
"DROP TABLE IF EXISTS sqlite_stat4;");
}
if( runAnalyze ){
fossil_print("Analyzing the database... "); fflush(stdout);
db_multi_exec("ANALYZE;");
fossil_print("done\n");
}
if( runVacuum ){
fossil_print("Vacuuming the database... "); fflush(stdout);
db_multi_exec("VACUUM");
fossil_print("done\n");
}
if( activateWal ){
db_multi_exec("PRAGMA journal_mode=WAL;");
}
}
if( showStats ){
static const struct { int idx; const char *zLabel; } aStat[] = {
{ CFTYPE_ANY, "Artifacts:" },
{ CFTYPE_MANIFEST, "Manifests:" },
{ CFTYPE_CLUSTER, "Clusters:" },
{ CFTYPE_CONTROL, "Tags:" },
{ CFTYPE_WIKI, "Wikis:" },
{ CFTYPE_TICKET, "Tickets:" },
{ CFTYPE_ATTACHMENT,"Attachments:" },
|
| ︙ | ︙ | |||
682 683 684 685 686 687 688 |
usage("?REPOSITORY-FILENAME?");
}
db_close(1);
db_open_repository(g.zRepositoryName);
}
db_begin_transaction();
create_cluster();
| | | | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
usage("?REPOSITORY-FILENAME?");
}
db_close(1);
db_open_repository(g.zRepositoryName);
}
db_begin_transaction();
create_cluster();
db_end_transaction(0);
}
/*
** COMMAND: test-clusters
**
** Verify that all non-private and non-shunned artifacts are accessible
** through the cluster chain.
*/
void test_clusters_cmd(void){
Bag pending;
Stmt q;
int n;
db_find_and_open_repository(0, 2);
bag_init(&pending);
db_multi_exec(
"CREATE TEMP TABLE xdone(x INTEGER PRIMARY KEY);"
"INSERT INTO xdone SELECT rid FROM unclustered;"
"INSERT OR IGNORE INTO xdone SELECT rid FROM private;"
"INSERT OR IGNORE INTO xdone"
|
| ︙ | ︙ | |||
717 718 719 720 721 722 723 |
bag_insert(&pending, db_column_int(&q, 0));
}
db_finalize(&q);
while( bag_count(&pending)>0 ){
Manifest *p;
int rid = bag_first(&pending);
int i;
| | | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 |
bag_insert(&pending, db_column_int(&q, 0));
}
db_finalize(&q);
while( bag_count(&pending)>0 ){
Manifest *p;
int rid = bag_first(&pending);
int i;
bag_remove(&pending, rid);
p = manifest_get(rid, CFTYPE_CLUSTER, 0);
if( p==0 ){
fossil_fatal("bad cluster: rid=%d", rid);
}
for(i=0; i<p->nCChild; i++){
const char *zUuid = p->azCChild[i];
int crid = name_to_rid(zUuid);
if( crid==0 ){
|
| ︙ | ︙ | |||
856 857 858 859 860 861 862 |
continue;
}
zUtf8Name = fossil_filename_to_utf8(pEntry->d_name);
zSubpath = mprintf("%s/%s", zPath, zUtf8Name);
fossil_filename_free(zUtf8Name);
if( file_isdir(zSubpath)==1 ){
recon_read_dir(zSubpath);
| | | | | | | | | | | < | | | > > | | 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 |
continue;
}
zUtf8Name = fossil_filename_to_utf8(pEntry->d_name);
zSubpath = mprintf("%s/%s", zPath, zUtf8Name);
fossil_filename_free(zUtf8Name);
if( file_isdir(zSubpath)==1 ){
recon_read_dir(zSubpath);
}else{
blob_init(&path, 0, 0);
blob_appendf(&path, "%s", zSubpath);
if( blob_read_from_file(&aContent, blob_str(&path))==-1 ){
fossil_fatal("some unknown error occurred while reading \"%s\"",
blob_str(&path));
}
content_put(&aContent);
blob_reset(&path);
blob_reset(&aContent);
fossil_print("\r%d", ++nFileRead);
fflush(stdout);
}
free(zSubpath);
}
closedir(d);
}else {
fossil_fatal("encountered error %d while trying to open \"%s\".",
errno, g.argv[3]);
}
fossil_filename_free(zUnicodePath);
}
/*
** COMMAND: reconstruct*
|
| ︙ | ︙ | |||
917 918 919 920 921 922 923 | reconstruct_private_table(); /* Skip the verify_before_commit() step on a reconstruct. Most artifacts ** will have been changed and verification therefore takes a really, really ** long time. */ verify_cancel(); | | | | 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 |
reconstruct_private_table();
/* Skip the verify_before_commit() step on a reconstruct. Most artifacts
** will have been changed and verification therefore takes a really, really
** long time.
*/
verify_cancel();
db_end_transaction(0);
fossil_print("project-id: %s\n", db_get("project-code", 0));
fossil_print("server-id: %s\n", db_get("server-code", 0));
zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword);
}
/*
** COMMAND: deconstruct*
**
** Usage %fossil deconstruct ?OPTIONS? DESTINATION
**
**
** This command exports all artifacts of a given repository and
** writes all artifacts to the file system. The DESTINATION directory
** will be populated with subdirectories AA and files AA/BBBBBBBBB.., where
** AABBBBBBBBB.. is the 40 character artifact ID, AA the first 2 characters.
** If -L|--prefixlength is given, the length (default 2) of the directory
** prefix can be set to 0,1,..,9 characters.
**
** Options:
** -R|--repository REPOSITORY deconstruct given REPOSITORY
** -L|--prefixlength N set the length of the names of the DESTINATION
** subdirectories to N
** --private Include private artifacts.
**
** See also: rebuild, reconstruct
|
| ︙ | ︙ |
Changes to src/report.c.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 | ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* | | > > > > | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** Code to generate the ticket listings
*/
#include "config.h"
#include <time.h>
#include "report.h"
#include <assert.h>
/* Forward references to static routines */
static void report_format_hints(void);
#ifndef SQLITE_RECURSIVE
# define SQLITE_RECURSIVE 33
#endif
/*
** WEBPAGE: /reportlist
*/
void view_list(void){
const char *zScript;
Blob ril; /* Report Item List */
Stmt q;
int rn = 0;
int cnt = 0;
login_check_credentials();
if( !g.perm.RdTkt && !g.perm.NewTkt ){ login_needed(); return; }
style_header("Ticket Main Menu");
if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST<br />\n", -1);
zScript = ticket_reportlist_code();
if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST_SCRIPT<br />\n", -1);
blob_zero(&ril);
ticket_init();
db_prepare(&q, "SELECT rn, title, owner FROM reportfmt ORDER BY title");
while( db_step(&q)==SQLITE_ROW ){
const char *zTitle = db_column_text(&q, 1);
const char *zOwner = db_column_text(&q, 2);
|
| ︙ | ︙ | |||
64 65 66 67 68 69 70 |
if( g.perm.Write && zOwner && zOwner[0] ){
blob_appendf(&ril, "(by <i>%h</i>) ", zOwner);
}
if( g.perm.TktFmt ){
blob_appendf(&ril, "[%zcopy</a>] ",
href("%R/rptedit?rn=%d©=1", rn));
}
| | | > | | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
if( g.perm.Write && zOwner && zOwner[0] ){
blob_appendf(&ril, "(by <i>%h</i>) ", zOwner);
}
if( g.perm.TktFmt ){
blob_appendf(&ril, "[%zcopy</a>] ",
href("%R/rptedit?rn=%d©=1", rn));
}
if( g.perm.Admin
|| (g.perm.WrTkt && zOwner && fossil_strcmp(g.zLogin,zOwner)==0)
){
blob_appendf(&ril, "[%zedit</a>]",
href("%R/rptedit?rn=%d", rn));
}
if( g.perm.TktFmt ){
blob_appendf(&ril, "[%zsql</a>]",
href("%R/rptsql?rn=%d", rn));
}
blob_appendf(&ril, "</li>\n");
}
db_finalize(&q);
Th_Store("report_items", blob_str(&ril));
Th_Render(zScript);
blob_reset(&ril);
if( g.thTrace ) Th_Trace("END_REPORTLIST<br />\n", -1);
style_footer();
}
/*
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
"mlink",
"plink",
"event",
"tag",
"tagxref",
};
int i;
for(i=0; i<sizeof(azAllowed)/sizeof(azAllowed[0]); i++){
if( fossil_stricmp(zArg1, azAllowed[i])==0 ) break;
}
if( i>=sizeof(azAllowed)/sizeof(azAllowed[0]) ){
*(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1);
rc = SQLITE_DENY;
}else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){
rc = SQLITE_IGNORE;
}
break;
}
default: {
*(char**)pError = mprintf("only SELECT statements are allowed");
rc = SQLITE_DENY;
break;
}
}
return rc;
}
/*
** Activate the query authorizer
*/
static void report_restrict_sql(char **pzErr){
| > > > > > > > > < | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
"mlink",
"plink",
"event",
"tag",
"tagxref",
};
int i;
if( fossil_strncmp(zArg1, "fx_", 3)==0 ){
break;
}
for(i=0; i<sizeof(azAllowed)/sizeof(azAllowed[0]); i++){
if( fossil_stricmp(zArg1, azAllowed[i])==0 ) break;
}
if( i>=sizeof(azAllowed)/sizeof(azAllowed[0]) ){
*(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1);
rc = SQLITE_DENY;
}else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){
rc = SQLITE_IGNORE;
}
break;
}
case SQLITE_RECURSIVE: {
*(char**)pError = mprintf("recursive queries are not allowed");
rc = SQLITE_DENY;
break;
}
default: {
*(char**)pError = mprintf("only SELECT statements are allowed");
rc = SQLITE_DENY;
break;
}
}
return rc;
}
/*
** Activate the query authorizer
*/
static void report_restrict_sql(char **pzErr){
sqlite3_set_authorizer(g.db, report_query_authorizer, (void*)pzErr);
}
static void report_unrestrict_sql(void){
sqlite3_set_authorizer(g.db, 0, 0);
}
|
| ︙ | ︙ | |||
248 249 250 251 252 253 254 |
** was found. We don't actually check what's after that.
*/
return mprintf("Semi-colon detected! "
"Only a single SQL statement is allowed");
}
}
}
| | | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
** was found. We don't actually check what's after that.
*/
return mprintf("Semi-colon detected! "
"Only a single SQL statement is allowed");
}
}
}
/* Compile the statement and check for illegal accesses or syntax errors. */
report_restrict_sql(&zErr);
rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, &zTail);
if( rc!=SQLITE_OK ){
zErr = mprintf("Syntax error: %s", sqlite3_errmsg(g.db));
}
if( !sqlite3_stmt_readonly(pStmt) ){
zErr = mprintf("SQL must not modify the database");
}
if( pStmt ){
|
| ︙ | ︙ | |||
369 370 371 372 373 374 375 |
cgi_redirect("reportlist");
return;
}
if( zTitle && zSQL ){
if( zSQL[0]==0 ){
zErr = "Please supply an SQL query statement";
}else if( (zTitle = trim_string(zTitle))[0]==0 ){
| | | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
cgi_redirect("reportlist");
return;
}
if( zTitle && zSQL ){
if( zSQL[0]==0 ){
zErr = "Please supply an SQL query statement";
}else if( (zTitle = trim_string(zTitle))[0]==0 ){
zErr = "Please supply a title";
}else{
zErr = verify_sql_statement(zSQL);
}
if( zErr==0
&& db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d",
zTitle, rn)
){
|
| ︙ | ︙ | |||
636 637 638 639 640 641 642 | /* ** The callback function for db_query */ static int generate_html( void *pUser, /* Pointer to output state */ int nArg, /* Number of columns in this result row */ | | | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 |
/*
** The callback function for db_query
*/
static int generate_html(
void *pUser, /* Pointer to output state */
int nArg, /* Number of columns in this result row */
const char **azArg, /* Text of data in all columns */
const char **azName /* Names of the columns */
){
struct GenerateHTML *pState = (struct GenerateHTML*)pUser;
int i;
const char *zTid; /* Ticket UUID. (value of column named '#') */
const char *zBg = 0; /* Use this background color */
/* Do initialization
*/
if( pState->nCount==0 ){
/* Turn off the authorizer. It is no longer doing anything since the
** query has already been prepared.
*/
|
| ︙ | ︙ | |||
696 697 698 699 700 701 702 |
}
/* The first time this routine is called, output a table header
*/
@ <thead><tr>
zTid = 0;
for(i=0; i<nArg; i++){
| | | 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 |
}
/* The first time this routine is called, output a table header
*/
@ <thead><tr>
zTid = 0;
for(i=0; i<nArg; i++){
const char *zName = azName[i];
if( i==pState->iBg ) continue;
if( pState->iNewRow>=0 && i>=pState->iNewRow ){
if( g.perm.Write && zTid ){
@ <th> </th>
zTid = 0;
}
if( zName[0]=='_' ) zName++;
|
| ︙ | ︙ | |||
739 740 741 742 743 744 745 |
/* Output the data for this entry from the database
*/
zBg = pState->iBg>=0 ? azArg[pState->iBg] : 0;
if( zBg==0 ) zBg = "white";
@ <tr style="background-color:%h(zBg)">
zTid = 0;
for(i=0; i<nArg; i++){
| | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 |
/* Output the data for this entry from the database
*/
zBg = pState->iBg>=0 ? azArg[pState->iBg] : 0;
if( zBg==0 ) zBg = "white";
@ <tr style="background-color:%h(zBg)">
zTid = 0;
for(i=0; i<nArg; i++){
const char *zData;
if( i==pState->iBg ) continue;
zData = azArg[i];
if( zData==0 ) zData = "";
if( pState->iNewRow>=0 && i>=pState->iNewRow ){
if( zTid && g.perm.Write ){
@ <td valign="top">%z(href("%R/tktedit/%h",zTid))edit</a></td>
zTid = 0;
|
| ︙ | ︙ | |||
801 802 803 804 805 806 807 | /* ** Output a row as a tab-separated line of text. */ static int output_tab_separated( void *pUser, /* Pointer to row-count integer */ int nArg, /* Number of columns in this result row */ | | | | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
/*
** Output a row as a tab-separated line of text.
*/
static int output_tab_separated(
void *pUser, /* Pointer to row-count integer */
int nArg, /* Number of columns in this result row */
const char **azArg, /* Text of data in all columns */
const char **azName /* Names of the columns */
){
int *pCount = (int*)pUser;
int i;
if( *pCount==0 ){
for(i=0; i<nArg; i++){
output_no_tabs(azName[i]);
|
| ︙ | ︙ | |||
826 827 828 829 830 831 832 |
}
/*
** Generate HTML that describes a color key.
*/
void output_color_key(const char *zClrKey, int horiz, char *zTabArgs){
int i, j, k;
| | > | | 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
}
/*
** Generate HTML that describes a color key.
*/
void output_color_key(const char *zClrKey, int horiz, char *zTabArgs){
int i, j, k;
const char *zSafeKey;
char *zToFree;
while( fossil_isspace(*zClrKey) ) zClrKey++;
if( zClrKey[0]==0 ) return;
@ <table %s(zTabArgs)>
if( horiz ){
@ <tr>
}
zSafeKey = zToFree = mprintf("%h", zClrKey);
while( zSafeKey[0] ){
while( fossil_isspace(*zSafeKey) ) zSafeKey++;
for(i=0; zSafeKey[i] && !fossil_isspace(zSafeKey[i]); i++){}
for(j=i; fossil_isspace(zSafeKey[j]); j++){}
for(k=j; zSafeKey[k] && zSafeKey[k]!='\n' && zSafeKey[k]!='\r'; k++){}
if( !horiz ){
cgi_printf("<tr style=\"background-color: %.*s;\"><td>%.*s</td></tr>\n",
|
| ︙ | ︙ | |||
859 860 861 862 863 864 865 | @ </table> } /* ** Execute a single read-only SQL statement. Invoke xCallback() on each ** row. */ | | > | | | | 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 |
@ </table>
}
/*
** Execute a single read-only SQL statement. Invoke xCallback() on each
** row.
*/
static int db_exec_readonly(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
int (*xCallback)(void*,int,const char**, const char**),
/* Invoke this callback routine */
void *pArg, /* First argument to xCallback() */
char **pzErrMsg /* Write error messages here */
){
int rc = SQLITE_OK; /* Return code */
const char *zLeftover; /* Tail of unprocessed SQL */
sqlite3_stmt *pStmt = 0; /* The current SQL statement */
const char **azCols = 0; /* Names of result columns */
int nCol; /* Number of columns of output */
const char **azVals = 0; /* Text of all output columns */
int i; /* Loop counter */
pStmt = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
assert( rc==SQLITE_OK || pStmt==0 );
if( rc!=SQLITE_OK ){
return rc;
|
| ︙ | ︙ | |||
898 899 900 901 902 903 904 |
nCol = sqlite3_column_count(pStmt);
azVals = fossil_malloc(2*nCol*sizeof(const char*) + 1);
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
if( azCols==0 ){
azCols = &azVals[nCol];
for(i=0; i<nCol; i++){
| | | | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 |
nCol = sqlite3_column_count(pStmt);
azVals = fossil_malloc(2*nCol*sizeof(const char*) + 1);
while( (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
if( azCols==0 ){
azCols = &azVals[nCol];
for(i=0; i<nCol; i++){
azCols[i] = sqlite3_column_name(pStmt, i);
}
}
for(i=0; i<nCol; i++){
azVals[i] = (const char *)sqlite3_column_text(pStmt, i);
}
if( xCallback(pArg, nCol, azVals, azCols) ){
break;
}
}
rc = sqlite3_finalize(pStmt);
fossil_free(azVals);
|
| ︙ | ︙ | |||
1051 1052 1053 1054 1055 1056 1057 |
}
count = 0;
if( !tabs ){
struct GenerateHTML sState;
db_multi_exec("PRAGMA empty_result_callbacks=ON");
| | | | | | | 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 |
}
count = 0;
if( !tabs ){
struct GenerateHTML sState;
db_multi_exec("PRAGMA empty_result_callbacks=ON");
style_submenu_element("Raw", "Raw",
"rptview?tablist=1&%h", PD("QUERY_STRING",""));
if( g.perm.Admin
|| (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){
style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn);
}
if( g.perm.TktFmt ){
style_submenu_element("SQL", "SQL", "rptsql?rn=%d",rn);
}
if( g.perm.NewTkt ){
style_submenu_element("New Ticket", "Create a new ticket",
"%s/tktnew", g.zTop);
}
style_header(zTitle);
output_color_key(zClrKey, 1,
"border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\"");
@ <table border="1" cellpadding="2" cellspacing="0" class="report"
@ id="reportTable">
sState.rn = rn;
sState.nCount = 0;
report_restrict_sql(&zErr1);
db_exec_readonly(g.db, zSql, generate_html, &sState, &zErr2);
report_unrestrict_sql();
@ </tbody></table>
if( zErr1 ){
@ <p class="reportError">Error: %h(zErr1)</p>
}else if( zErr2 ){
@ <p class="reportError">Error: %h(zErr2)</p>
}
output_table_sorting_javascript("reportTable","");
style_footer();
}else{
report_restrict_sql(&zErr1);
db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
report_unrestrict_sql();
cgi_set_content_type("text/plain");
}
}
/*
** report number for full table ticket export
|
| ︙ | ︙ | |||
1163 1164 1165 1166 1167 1168 1169 |
}
for(j=i; fossil_isspace(z[j]); j++){}
if( j>i ){
fossil_print("%*s", j-i, "");
}
z += j;
}
| | | | | 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 |
}
for(j=i; fossil_isspace(z[j]); j++){}
if( j>i ){
fossil_print("%*s", j-i, "");
}
z += j;
}
break;
}
}
/*
** Output a row as a tab-separated line of text.
*/
int output_separated_file(
void *pUser, /* Pointer to row-count integer */
int nArg, /* Number of columns in this result row */
const char **azArg, /* Text of data in all columns */
const char **azName /* Names of the columns */
){
int *pCount = (int*)pUser;
int i;
if( *pCount==0 ){
for(i=0; i<nArg; i++){
output_no_tabs_file(azName[i]);
|
| ︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 | } /* ** Generate a report. The rn query parameter is the report number. ** The output is written to stdout as flat file. The zFilter parameter ** is a full WHERE-condition. */ | | | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 |
}
/*
** Generate a report. The rn query parameter is the report number.
** The output is written to stdout as flat file. The zFilter parameter
** is a full WHERE-condition.
*/
void rptshow(
const char *zRep,
const char *zSepIn,
const char *zFilter,
tTktShowEncoding enc
){
Stmt q;
char *zSql;
|
| ︙ | ︙ | |||
1237 1238 1239 1240 1241 1242 1243 |
if( zFilter ){
zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter);
}
count = 0;
tktEncode = enc;
zSep = zSepIn;
report_restrict_sql(&zErr1);
| | | 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 |
if( zFilter ){
zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter);
}
count = 0;
tktEncode = enc;
zSep = zSepIn;
report_restrict_sql(&zErr1);
db_exec_readonly(g.db, zSql, output_separated_file, &count, &zErr2);
report_unrestrict_sql();
if( zFilter ){
free(zSql);
}
}
|
Changes to src/rss.c.
| ︙ | ︙ | |||
158 159 160 161 162 163 164 | @ <link>%s(g.zBaseURL)</link> @ <description>%h(zProjectDescr)</description> @ <pubDate>%s(zPubDate)</pubDate> @ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator> free(zPubDate); db_prepare(&q, blob_str(&bSQL)); blob_reset( &bSQL ); | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
@ <link>%s(g.zBaseURL)</link>
@ <description>%h(zProjectDescr)</description>
@ <pubDate>%s(zPubDate)</pubDate>
@ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator>
free(zPubDate);
db_prepare(&q, blob_str(&bSQL));
blob_reset( &bSQL );
while( db_step(&q)==SQLITE_ROW && nLine<nLimit ){
const char *zId = db_column_text(&q, 1);
const char *zCom = db_column_text(&q, 3);
const char *zAuthor = db_column_text(&q, 4);
char *zPrefix = "";
char *zDate;
int nChild = db_column_int(&q, 5);
int nParent = db_column_int(&q, 6);
|
| ︙ | ︙ | |||
194 195 196 197 198 199 200 201 202 203 204 205 |
free(zDate);
nLine++;
}
db_finalize(&q);
@ </channel>
@ </rss>
if( zFreeProjectName != 0 ){
free( zFreeProjectName );
}
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
free(zDate);
nLine++;
}
db_finalize(&q);
@ </channel>
@ </rss>
if( zFreeProjectName != 0 ){
free( zFreeProjectName );
}
}
/*
** COMMAND: rss
**
** The CLI variant of the /timeline.rss page, this produces an RSS
** feed of the timeline to stdout. Options:
**
** -type|y FLAG
** may be: all (default), ci (show checkins only), t (show tickets only),
** w (show wiki only). LIMIT is the number of items to show.
**
** -tkt UUID
** Filters for only those events for the specified ticket.
**
** -tag TAG
** filters for a tag
**
** -wiki NAME
** Filters on a specific wiki page.
**
** Only one of -tkt, -tag, or -wiki may be used.
**
** -name FILENAME
** filters for a specific file. This may be combined with one of the other
** filters (useful for looking at a specific branch).
**
** -url STRING
** Sets the RSS feed's root URL to the given string. The default is
** "URL-PLACEHOLDER" (without quotes).
*/
void cmd_timeline_rss(void){
Stmt q;
int nLine=0;
char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0;
Blob bSQL;
const char *zType = find_option("type","y",1); /* Type of events. All if NULL */
const char *zTicketUuid = find_option("tkt",NULL,1);
const char *zTag = find_option("tag",NULL,1);
const char *zFilename = find_option("name",NULL,1);
const char *zWiki = find_option("wiki",NULL,1);
const char *zLimit = find_option("limit", "n",1);
const char *zBaseURL = find_option("url", NULL, 1);
int nLimit = atoi( (zLimit && *zLimit) ? zLimit : "20" );
int nTagId;
const char zSQL1[] =
@ SELECT
@ blob.rid,
@ uuid,
@ event.mtime,
@ coalesce(ecomment,comment),
@ coalesce(euser,user),
@ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim),
@ (SELECT count(*) FROM plink WHERE cid=blob.rid)
@ FROM event, blob
@ WHERE blob.rid=event.objid
;
if(!zType || !*zType){
zType = "all";
}
if(!zBaseURL || !*zBaseURL){
zBaseURL = "URL-PLACEHOLDER";
}
db_find_and_open_repository(0, 0);
blob_zero(&bSQL);
blob_append( &bSQL, zSQL1, -1 );
if( zType[0]!='a' ){
blob_appendf(&bSQL, " AND event.type=%Q", zType);
}
if( zTicketUuid ){
nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
zTicketUuid);
if ( nTagId==0 ){
nTagId = -1;
}
}else if( zTag ){
nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'",
zTag);
if ( nTagId==0 ){
nTagId = -1;
}
}else if( zWiki ){
nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'",
zWiki);
if ( nTagId==0 ){
nTagId = -1;
}
}else{
nTagId = 0;
}
if( nTagId==-1 ){
blob_appendf(&bSQL, " AND 0");
}else if( nTagId!=0 ){
blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId);
}
if( zFilename ){
blob_appendf(&bSQL,
" AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)",
zFilename, filename_collation()
);
}
blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 );
zProjectName = db_get("project-name", 0);
if( zProjectName==0 ){
zFreeProjectName = zProjectName = mprintf("Fossil source repository for: %s",
zBaseURL);
}
zProjectDescr = db_get("project-description", 0);
if( zProjectDescr==0 ){
zProjectDescr = zProjectName;
}
zPubDate = cgi_rfc822_datestamp(time(NULL));
fossil_print("<?xml version=\"1.0\"?>");
fossil_print("<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">");
fossil_print("<channel>\n");
fossil_print("<title>%h</title>\n", zProjectName);
fossil_print("<link>%s</link>\n", zBaseURL);
fossil_print("<description>%h</description>\n", zProjectDescr);
fossil_print("<pubDate>%s</pubDate>\n", zPubDate);
fossil_print("<generator>Fossil version %s %s</generator>\n",
MANIFEST_VERSION, MANIFEST_DATE);
free(zPubDate);
db_prepare(&q, blob_str(&bSQL));
blob_reset( &bSQL );
while( db_step(&q)==SQLITE_ROW && nLine<nLimit ){
const char *zId = db_column_text(&q, 1);
const char *zCom = db_column_text(&q, 3);
const char *zAuthor = db_column_text(&q, 4);
char *zPrefix = "";
char *zDate;
int nChild = db_column_int(&q, 5);
int nParent = db_column_int(&q, 6);
time_t ts;
ts = (time_t)((db_column_double(&q,2) - 2440587.5)*86400.0);
zDate = cgi_rfc822_datestamp(ts);
if( nParent>1 && nChild>1 ){
zPrefix = "*MERGE/FORK* ";
}else if( nParent>1 ){
zPrefix = "*MERGE* ";
}else if( nChild>1 ){
zPrefix = "*FORK* ";
}
fossil_print("<item>");
fossil_print("<title>%s%h</title>\n", zPrefix, zCom);
fossil_print("<link>%s/info/%s</link>\n", zBaseURL, zId);
fossil_print("<description>%s%h</description>\n", zPrefix, zCom);
fossil_print("<pubDate>%s</pubDate>\n", zDate);
fossil_print("<dc:creator>%h</dc:creator>\n", zAuthor);
fossil_print("<guid>%s/info/%s</guid>\n", g.zBaseURL, zId);
fossil_print("</item>\n");
free(zDate);
nLine++;
}
db_finalize(&q);
fossil_print("</channel>\n");
fossil_print("</rss>\n");
if( zFreeProjectName != 0 ){
free( zFreeProjectName );
}
}
|
Changes to src/schema.c.
| ︙ | ︙ | |||
433 434 435 436 437 438 439 | ** Predefined tagid values */ #if INTERFACE # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ # define TAG_USER 3 /* User who made a checking */ # define TAG_DATE 4 /* The date of a check-in */ | | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | ** Predefined tagid values */ #if INTERFACE # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ # define TAG_USER 3 /* User who made a checking */ # define TAG_DATE 4 /* The date of a check-in */ # define TAG_HIDDEN 5 /* Do not display in timeline */ # define TAG_PRIVATE 6 /* Do not sync */ # define TAG_CLUSTER 7 /* A cluster */ # define TAG_BRANCH 8 /* Value is name of the current branch */ # define TAG_CLOSED 9 /* Do not display this check-in as a leaf */ # define TAG_PARENT 10 /* Change to parentage on a checkin */ #endif #if EXPORT_INTERFACE # define MAX_INT_TAG 16 /* The largest pre-assigned tag id */ |
| ︙ | ︙ | |||
473 474 475 476 477 478 479 | @ -- Each entry in the vfile table represents a single file in the @ -- current checkout. @ -- @ -- The file.rid field is 0 for files or folders that have been @ -- added but not yet committed. @ -- @ -- Vfile.chnged is 0 for unmodified files, 1 for files that have | | > | | | < | | | | | > | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | @ -- Each entry in the vfile table represents a single file in the @ -- current checkout. @ -- @ -- The file.rid field is 0 for files or folders that have been @ -- added but not yet committed. @ -- @ -- Vfile.chnged is 0 for unmodified files, 1 for files that have @ -- been edited or which have been subjected to a 3-way merge. @ -- Vfile.chnged is 2 if the file has been replaced from a different @ -- version by the merge and 3 if the file has been added by a merge. @ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been @ -- done by an --integrate merge. The difference between vfile.chnged==2|4 @ -- and a regular add is that with vfile.chnged==2|4 we know that the @ -- current version of the file is already in the repository. @ -- @ CREATE TABLE vfile( @ id INTEGER PRIMARY KEY, -- ID of the checked out file @ vid INTEGER REFERENCES blob, -- The baseline this file is part of. @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add 4:i-chng 5:i-add @ deleted BOOLEAN DEFAULT 0, -- True if deleted @ isexe BOOLEAN, -- True if file should be executable @ islink BOOLEAN, -- True if file should be symlink @ rid INTEGER, -- Originally from this repository record @ mrid INTEGER, -- Based on this record due to a merge @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 @ pathname TEXT, -- Full pathname relative to root @ origname TEXT, -- Original pathname. NULL if unchanged @ UNIQUE(pathname,vid) @ ); @ @ -- This table holds a record of uncommitted merges in the local @ -- file tree. If a VFILE entry with id has merged with another @ -- record, there is an entry in this table with (id,merge) where @ -- merge is the RECORD table entry that the file merged against. @ -- An id of 0 or <-3 here means the version record itself. When @ -- id==(-1) that is a cherrypick merge, id==(-2) that is a @ -- backout merge and id==(-4) is a integrate merge. @ @ CREATE TABLE vmerge( @ id INTEGER REFERENCES vfile, -- VFILE entry that has been merged @ merge INTEGER, -- Merged with this record @ UNIQUE(id, merge) @ ); @ @ -- Identifier for this file type. @ -- The integer is the same as 'FSLC'. @ PRAGMA application_id=252006674; ; |
Changes to src/search.c.
| ︙ | ︙ | |||
104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
int iPrev = 999;
int score = 10;
int iBonus = 0;
int i, j;
unsigned char seen[8];
memset(seen, 0, sizeof(seen));
for(i=0; zDoc[i]; i++){
char c = zDoc[i];
if( isBoundary[c&0xff] ) continue;
for(j=0; j<p->nTerm; j++){
int n = p->a[j].n;
if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0 ){
score += 1;
| > | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
int iPrev = 999;
int score = 10;
int iBonus = 0;
int i, j;
unsigned char seen[8];
memset(seen, 0, sizeof(seen));
if( zDoc==0 ) return score;
for(i=0; zDoc[i]; i++){
char c = zDoc[i];
if( isBoundary[c&0xff] ) continue;
for(j=0; j<p->nTerm; j++){
int n = p->a[j].n;
if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0 ){
score += 1;
|
| ︙ | ︙ | |||
132 133 134 135 136 137 138 |
while( !isBoundary[zDoc[i]&0xff] ){ i++; }
}
/* Every term must be seen or else the score is zero */
for(j=0; j<p->nTerm; j++){
if( !seen[j] ) return 0;
}
| | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
while( !isBoundary[zDoc[i]&0xff] ){ i++; }
}
/* Every term must be seen or else the score is zero */
for(j=0; j<p->nTerm; j++){
if( !seen[j] ) return 0;
}
return score;
}
/*
** This is an SQLite function that scores its input using
** a pre-computed pattern.
*/
|
| ︙ | ︙ | |||
164 165 166 167 168 169 170 |
search_score_sqlfunc, 0, 0);
}
/*
** Testing the search function.
**
** COMMAND: search*
| | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | > > > > | | | | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
search_score_sqlfunc, 0, 0);
}
/*
** Testing the search function.
**
** COMMAND: search*
** %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern...
**
** Search for timeline entries matching all words
** provided on the command line. Whole-word matches
** scope more highly than partial matches.
**
** Outputs, by default, some top-N fraction of the
** results. The -all option can be used to output
** all matches, regardless of their search score.
** The -limit option can be used to limit the number
** of entries returned. The -width option can be
** used to set the output width used when printing
** matches.
*/
void search_cmd(void){
Search *p;
Blob pattern;
int i;
Blob sql = empty_blob;
Stmt q;
int iBest;
char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop
off the end of the
results. */
char const * zLimit = find_option("limit","n",1);
const char *zWidth = find_option("width","W",1);
int nLimit = zLimit ? atoi(zLimit) : -1000; /* Max number of matching
lines/entries to list */
int width;
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("--width|-W value must be >20 or 0");
}
}else{
width = 79;
}
db_must_be_within_tree();
if( g.argc<2 ) return;
blob_init(&pattern, g.argv[2], -1);
for(i=3; i<g.argc; i++){
blob_appendf(&pattern, " %s", g.argv[i]);
}
p = search_init(blob_str(&pattern));
blob_reset(&pattern);
search_sql_setup(p);
db_multi_exec(
"CREATE TEMP TABLE srch(rid,uuid,date,comment,x);"
"CREATE INDEX srch_idx1 ON srch(x);"
"INSERT INTO srch(rid,uuid,date,comment,x)"
" SELECT blob.rid, uuid, datetime(event.mtime%s),"
" coalesce(ecomment,comment),"
" score(coalesce(ecomment,comment)) AS y"
" FROM event, blob"
" WHERE blob.rid=event.objid AND y>0;",
timeline_utc()
);
iBest = db_int(0, "SELECT max(x) FROM srch");
blob_append(&sql,
"SELECT rid, uuid, date, comment, 0, 0 FROM srch "
"WHERE 1 ", -1);
if(!fAll){
blob_appendf(&sql,"AND x>%d ", iBest/3);
}
blob_append(&sql, "ORDER BY x DESC, date DESC ", -1);
db_prepare(&q, blob_str(&sql));
blob_reset(&sql);
print_timeline(&q, nLimit, width, 0);
db_finalize(&q);
}
|
Changes to src/setup.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Implementation of the Setup page */ | < > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Implementation of the Setup page */ #include "config.h" #include <assert.h> #include "setup.h" /* ** The table of web pages supported by this application is generated ** automatically by the "mkindex" program and written into a file ** named "page_index.h". We include that file here to get access ** to the table. |
| ︙ | ︙ | |||
195 196 197 198 199 200 201 | } @ </table> @ </td><td class="usetupColumnLayout"> @ <span class="note">Notes:</span> @ <ol> @ <li><p>The permission flags are as follows:</p> @ <table> | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
}
@ </table>
@ </td><td class="usetupColumnLayout">
@ <span class="note">Notes:</span>
@ <ol>
@ <li><p>The permission flags are as follows:</p>
@ <table>
@ <tr><th valign="top">a</th>
@ <td><i>Admin:</i> Create and delete users</td></tr>
@ <tr><th valign="top">b</th>
@ <td><i>Attach:</i> Add attachments to wiki or tickets</td></tr>
@ <tr><th valign="top">c</th>
@ <td><i>Append-Tkt:</i> Append to tickets</td></tr>
@ <tr><th valign="top">d</th>
@ <td><i>Delete:</i> Delete wiki and tickets</td></tr>
@ <tr><th valign="top">e</th>
@ <td><i>Email:</i> View sensitive data such as EMail addresses</td></tr>
@ <tr><th valign="top">f</th>
@ <td><i>New-Wiki:</i> Create new wiki pages</td></tr>
@ <tr><th valign="top">g</th>
@ <td><i>Clone:</i> Clone the repository</td></tr>
@ <tr><th valign="top">h</th>
@ <td><i>Hyperlinks:</i> Show hyperlinks to detailed
@ repository history</td></tr>
@ <tr><th valign="top">i</th>
@ <td><i>Check-In:</i> Commit new versions in the repository</td></tr>
@ <tr><th valign="top">j</th>
@ <td><i>Read-Wiki:</i> View wiki pages</td></tr>
@ <tr><th valign="top">k</th>
@ <td><i>Write-Wiki:</i> Edit wiki pages</td></tr>
@ <tr><th valign="top">l</th>
@ <td><i>Mod-Wiki:</i> Moderator for wiki pages</td></tr>
@ <tr><th valign="top">m</th>
@ <td><i>Append-Wiki:</i> Append to wiki pages</td></tr>
@ <tr><th valign="top">n</th>
@ <td><i>New-Tkt:</i> Create new tickets</td></tr>
@ <tr><th valign="top">o</th>
@ <td><i>Check-Out:</i> Check out versions</td></tr>
@ <tr><th valign="top">p</th>
@ <td><i>Password:</i> Change your own password</td></tr>
@ <tr><th valign="top">q</th>
@ <td><i>Mod-Tkt:</i> Moderator for tickets</td></tr>
@ <tr><th valign="top">r</th>
@ <td><i>Read-Tkt:</i> View tickets</td></tr>
@ <tr><th valign="top">s</th>
@ <td><i>Setup/Super-user:</i> Setup and configure this website</td></tr>
@ <tr><th valign="top">t</th>
@ <td><i>Tkt-Report:</i> Create new bug summary reports</td></tr>
@ <tr><th valign="top">u</th>
@ <td><i>Reader:</i> Inherit privileges of
@ user <tt>reader</tt></td></tr>
@ <tr><th valign="top">v</th>
@ <td><i>Developer:</i> Inherit privileges of
@ user <tt>developer</tt></td></tr>
@ <tr><th valign="top">w</th>
@ <td><i>Write-Tkt:</i> Edit tickets</td></tr>
@ <tr><th valign="top">x</th>
@ <td><i>Private:</i> Push and/or pull private branches</td></tr>
@ <tr><th valign="top">z</th>
@ <td><i>Zip download:</i> Download a ZIP archive or tarball</td></tr>
@ </table>
@ </li>
@
@ <li><p>
@ Every user, logged in or not, inherits the privileges of
@ <span class="usertype">nobody</span>.
@ </p></li>
|
| ︙ | ︙ | |||
598 599 600 601 602 603 604 |
}
@ </table>
@ </div></form>
@ </div>
@ <h2>Privileges And Capabilities:</h2>
@ <ul>
if( higherUser ){
| | | 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 |
}
@ </table>
@ </div></form>
@ </div>
@ <h2>Privileges And Capabilities:</h2>
@ <ul>
if( higherUser ){
@ <li><p class="missingPriv">
@ User %h(zLogin) has Setup privileges and you only have Admin privileges
@ so you are not permitted to make changes to %h(zLogin).
@ </p></li>
@
}
@ <li><p>
@ The <span class="capability">Setup</span> user can make arbitrary
|
| ︙ | ︙ | |||
725 726 727 728 729 730 731 | @ <li><p> @ No login is required for user <span class="usertype">nobody</span>. The @ capabilities of the <span class="usertype">nobody</span> user are @ inherited by all users, regardless of whether or not they are logged in. @ To disable universal access to the repository, make sure no user named @ <span class="usertype">nobody</span> exists or that the @ <span class="usertype">nobody</span> user has no capabilities | | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | @ <li><p> @ No login is required for user <span class="usertype">nobody</span>. The @ capabilities of the <span class="usertype">nobody</span> user are @ inherited by all users, regardless of whether or not they are logged in. @ To disable universal access to the repository, make sure no user named @ <span class="usertype">nobody</span> exists or that the @ <span class="usertype">nobody</span> user has no capabilities @ enabled. The password for <span class="usertype">nobody</span> is ignored. @ To avoid problems with spiders overloading the server, it is recommended @ that the <span class="capability">h</span> (Hyperlinks) capability be @ turned off for the <span class="usertype">nobody</span> user. @ </p></li> @ @ <li><p> @ Login is required for user <span class="usertype">anonymous</span> but the |
| ︙ | ︙ | |||
810 811 812 813 814 815 816 |
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
zVal = zQ;
}
| | | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
zVal = zQ;
}
@ <input type="text" id="%s(zQParm)" name="%s(zQParm)" value="%h(zVal)" size="%d(width)"
if( disabled ){
@ disabled="disabled"
}
@ /> <b>%s(zLabel)</b>
}
/*
|
| ︙ | ︙ | |||
847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
}
@ cols="%d(cols)">%h(z)</textarea>
if( zLabel && *zLabel ){
@ <span class="textareaLabel">%s(zLabel)</span>
}
}
}
/*
** WEBPAGE: setup_access
*/
void setup_access(void){
login_check_credentials();
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 |
}
@ cols="%d(cols)">%h(z)</textarea>
if( zLabel && *zLabel ){
@ <span class="textareaLabel">%s(zLabel)</span>
}
}
}
/*
** Generate a text box for an attribute.
*/
static void multiple_choice_attribute(
const char *zLabel, /* The text label on the menu */
const char *zVar, /* The corresponding row in the VAR table */
const char *zQP, /* The query parameter */
const char *zDflt, /* Default value if VAR table entry does not exist */
int nChoice, /* Number of choices */
const char *const *azChoice /* Choices. 2 per choice: (VAR value, Display) */
){
const char *z = db_get(zVar, (char*)zDflt);
const char *zQ = P(zQP);
int i;
if( zQ && fossil_strcmp(zQ,z)!=0){
login_verify_csrf_secret();
db_set(zVar, zQ, 0);
z = zQ;
}
@ <select size="1" name="%s(zQP)" id="id%s(zQP)">
for(i=0; i<nChoice*2; i+=2){
const char *zSel = fossil_strcmp(azChoice[i],z)==0 ? " selected" : "";
@ <option value="%h(azChoice[i])"%s(zSel)>%h(azChoice[i+1])</option>
}
@ </select>
}
/*
** WEBPAGE: setup_access
*/
void setup_access(void){
login_check_credentials();
|
| ︙ | ︙ | |||
946 947 948 949 950 951 952 |
"auto-hyperlink", "autohyperlink", 1, 0);
@ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
@ including user "nobody", as long as (1) the User-Agent string in the
@ HTTP header indicates that the request is coming from an actual human
@ being and not a a robot or spider and (2) the user agent is able to
@ run Javascript in order to set the href= attribute of hyperlinks. Bots
@ and spiders can forge a User-Agent string that makes them seem to be a
| | | | 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 |
"auto-hyperlink", "autohyperlink", 1, 0);
@ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users
@ including user "nobody", as long as (1) the User-Agent string in the
@ HTTP header indicates that the request is coming from an actual human
@ being and not a a robot or spider and (2) the user agent is able to
@ run Javascript in order to set the href= attribute of hyperlinks. Bots
@ and spiders can forge a User-Agent string that makes them seem to be a
@ normal browser and they can run javascript just like browsers. But most
@ bots do not go to that much trouble so this is normally an effective defense.</p>
@
@ <p>You do not normally want a bot to walk your entire repository because
@ if it does, your server will end up computing diffs and annotations for
@ every historical version of every file and creating ZIPs and tarballs of
@ every historical check-in, which can use a lot of CPU and bandwidth
@ even for relatively small projects.</p>
@
@ <p>Additional parameters that control this behavior:</p>
@ <blockquote>
onoff_attribute("Require mouse movement before enabling hyperlinks",
"auto-hyperlink-mouseover", "ahmo", 0, 0);
@ <br>
entry_attribute("Delay before enabling hyperlinks (milliseconds)", 5,
"auto-hyperlink-delay", "ah-delay", "10", 0);
|
| ︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 |
@ is not currently part of any login-group.
@ To join a login group, fill out the form below.</p>
@
@ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
login_insert_csrf_secret();
@ <blockquote><table border="0">
@
| | | | | | 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 |
@ is not currently part of any login-group.
@ To join a login group, fill out the form below.</p>
@
@ <form action="%s(g.zTop)/setup_login_group" method="post"><div>
login_insert_csrf_secret();
@ <blockquote><table border="0">
@
@ <tr><th align="right">Repository filename in group to join:</th>
@ <td width="5"></td><td>
@ <input type="text" size="50" value="%h(zRepo)" name="repo"></td></tr>
@
@ <tr><th align="right">Login on the above repo:</th>
@ <td width="5"></td><td>
@ <input type="text" size="20" value="%h(zLogin)" name="login"></td></tr>
@
@ <tr><th align="right">Password:</th>
@ <td width="5"></td><td>
@ <input type="password" size="20" name="pw"></td></tr>
@
@ <tr><th align="right">Name of login-group:</th>
@ <td width="5"></td><td>
@ <input type="text" size="30" value="%h(zNewName)" name="newname">
@ (only used if creating a new login-group).</td></tr>
@
@ <tr><td colspan="3" align="center">
@ <input type="submit" value="Join" name="join"></td></tr>
@ </table></blockquote></div></form>
|
| ︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 |
/*
** WEBPAGE: setup_timeline
*/
void setup_timeline(void){
double tmDiff;
char zTmDiff[20];
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Timeline Display Preferences");
db_begin_transaction();
| > > > > > > | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 |
/*
** WEBPAGE: setup_timeline
*/
void setup_timeline(void){
double tmDiff;
char zTmDiff[20];
static const char *const azTimeFormats[] = {
"0", "HH:MM",
"1", "HH:MM:SS",
"2", "YYYY-MM-DD HH:MM",
"3", "YYMMDD HH:MM"
};
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Timeline Display Preferences");
db_begin_transaction();
|
| ︙ | ︙ | |||
1149 1150 1151 1152 1153 1154 1155 |
@ without any wiki or HTML interpretation.</p>
@ <hr />
onoff_attribute("Use Universal Coordinated Time (UTC)",
"timeline-utc", "utc", 1, 0);
@ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or
@ Zulu) instead of in local time. On this server, local time is currently
| < > > > > > > > > | | 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 |
@ without any wiki or HTML interpretation.</p>
@ <hr />
onoff_attribute("Use Universal Coordinated Time (UTC)",
"timeline-utc", "utc", 1, 0);
@ <p>Show times as UTC (also sometimes called Greenwich Mean Time (GMT) or
@ Zulu) instead of in local time. On this server, local time is currently
tmDiff = db_double(0.0, "SELECT julianday('now')");
tmDiff = db_double(0.0,
"SELECT (julianday(%.17g,'localtime')-julianday(%.17g))*24.0",
tmDiff, tmDiff);
sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", tmDiff);
if( strcmp(zTmDiff, "0.0")==0 ){
@ the same as UTC and so this setting will make no difference in
@ the display.</p>
}else if( tmDiff<0.0 ){
sqlite3_snprintf(sizeof(zTmDiff), zTmDiff, "%.1f", -tmDiff);
@ %s(zTmDiff) hours behind UTC.</p>
}else{
@ %s(zTmDiff) hours ahead of UTC.</p>
}
@ <hr />
multiple_choice_attribute("Per-Item Time Format", "timeline-date-format", "tdf", "0",
4, azTimeFormats);
@ <p>If the "HH:MM" or "HH:MM:SS" format is selected, then the date is shown
@ in a separate box (using CSS class "timelineDate") whenever the date changes.
@ With the "YYYY-MM-DD HH:MM" and "YYMMDD ..." formats, the complete date
@ and time is shown on every timeline entry (using the CSS class "timelineTime").</p>
@ <hr />
onoff_attribute("Show version differences by default",
"show-version-diffs", "vdiff", 0, 0);
@ <p>The version-information pages linked from the timeline can either
@ show complete diffs of all file changes, or can just list the names of
@ the files that have changed. Users can get to either page by
@ clicking. This setting selects the default.</p>
@ <hr />
entry_attribute("Max timeline comment length", 6,
"timeline-max-comment", "tmc", "0", 0);
|
| ︙ | ︙ | |||
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
struct stControlSettings const *pSet;
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Settings");
db_open_local(0);
db_begin_transaction();
@ <p>This page provides a simple interface to the "fossil setting" command.
@ See the "fossil help setting" output below for further information on
@ the meaning of each setting.</p><hr />
@ <form action="%s(g.zTop)/setup_settings" method="post"><div>
| > | 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 |
struct stControlSettings const *pSet;
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
(void) aCmdHelp; /* NOTE: Silence compiler warning. */
style_header("Settings");
db_open_local(0);
db_begin_transaction();
@ <p>This page provides a simple interface to the "fossil setting" command.
@ See the "fossil help setting" output below for further information on
@ the meaning of each setting.</p><hr />
@ <form action="%s(g.zTop)/setup_settings" method="post"><div>
|
| ︙ | ︙ | |||
1270 1271 1272 1273 1274 1275 1276 |
style_header("WWW Configuration");
db_begin_transaction();
@ <form action="%s(g.zTop)/setup_config" method="post"><div>
login_insert_csrf_secret();
@ <hr />
entry_attribute("Project Name", 60, "project-name", "pn", "", 0);
@ <p>Give your project a name so visitors know what this site is about.
| | > > > > > > > > | 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 |
style_header("WWW Configuration");
db_begin_transaction();
@ <form action="%s(g.zTop)/setup_config" method="post"><div>
login_insert_csrf_secret();
@ <hr />
entry_attribute("Project Name", 60, "project-name", "pn", "", 0);
@ <p>Give your project a name so visitors know what this site is about.
@ The project name will also be used as the RSS feed title.
@ </p>
@ <hr />
textarea_attribute("Project Description", 3, 80,
"project-description", "pd", "", 0);
@ <p>Describe your project. This will be used in page headers for search
@ engines as well as a short RSS description.</p>
@ <hr />
entry_attribute("Tarball and ZIP-archive Prefix", 20, "short-project-name", "spn", "", 0);
@ <p>This is used as a prefix on the names of generated tarballs and ZIP archive.
@ For best results, keep this prefix brief and avoid special characters such
@ as "/" and "\".
@ If no tarball prefix is specified, then the full Project Name above is used.
@ </p>
@ <hr />
onoff_attribute("Enable WYSIWYG Wiki Editing",
"wysiwyg-wiki", "wysiwyg-wiki", 0, 0);
@ <p>Enable what-you-see-is-what-you-get (WYSIWYG) editing of wiki pages.
@ The WYSIWYG editor generates HTML instead of markup, which makes
@ subsequent manual editing more difficult.</p>
@ <hr />
|
| ︙ | ︙ | |||
1485 1486 1487 1488 1489 1490 1491 |
onoff_attribute("Moderate ticket changes",
"modreq-tkt", "modreq-tkt", 0, 0);
@ <p>When enabled, any change to tickets is subject to the approval
@ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
@ Ticket changes enter the system and are shown locally, but are not
@ synced until they are approved. The moderator has the option to
@ delete the change rather than approve it. Ticket changes made by
| | | 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 |
onoff_attribute("Moderate ticket changes",
"modreq-tkt", "modreq-tkt", 0, 0);
@ <p>When enabled, any change to tickets is subject to the approval
@ a ticket moderator - a user with the "q" or Mod-Tkt privilege.
@ Ticket changes enter the system and are shown locally, but are not
@ synced until they are approved. The moderator has the option to
@ delete the change rather than approve it. Ticket changes made by
@ a user who has the Mod-Tkt privilege are never subject to
@ moderation.
@
@ <hr />
onoff_attribute("Moderate wiki changes",
"modreq-wiki", "modreq-wiki", 0, 0);
@ <p>When enabled, any change to wiki is subject to the approval
@ a ticket moderator - a user with the "l" or Mod-Wiki privilege.
|
| ︙ | ︙ | |||
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 |
db_end_transaction(0);
}
/*
** WEBPAGE: setup_logo
*/
void setup_logo(void){
const char *zLogoMime = db_get("logo-mimetype","image/gif");
const char *aLogoImg = P("logoim");
int szLogoImg = atoi(PD("logoim:bytes","0"));
const char *zBgMime = db_get("background-mimetype","image/gif");
const char *aBgImg = P("bgim");
int szBgImg = atoi(PD("bgim:bytes","0"));
if( szLogoImg>0 ){
zLogoMime = PD("logoim:mimetype","image/gif");
}
if( szBgImg>0 ){
| > > | 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 |
db_end_transaction(0);
}
/*
** WEBPAGE: setup_logo
*/
void setup_logo(void){
const char *zLogoMtime = db_get_mtime("logo-image", 0, 0);
const char *zLogoMime = db_get("logo-mimetype","image/gif");
const char *aLogoImg = P("logoim");
int szLogoImg = atoi(PD("logoim:bytes","0"));
const char *zBgMtime = db_get_mtime("background-image", 0, 0);
const char *zBgMime = db_get("background-mimetype","image/gif");
const char *aBgImg = P("bgim");
int szBgImg = atoi(PD("bgim:bytes","0"));
if( szLogoImg>0 ){
zLogoMime = PD("logoim:mimetype","image/gif");
}
if( szBgImg>0 ){
|
| ︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 |
);
db_end_transaction(0);
cgi_redirect("setup_logo");
}
style_header("Edit Project Logo And Background");
@ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
@ and looks like this:</p>
| | | 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 |
);
db_end_transaction(0);
cgi_redirect("setup_logo");
}
style_header("Edit Project Logo And Background");
@ <p>The current project logo has a MIME-Type of <b>%h(zLogoMime)</b>
@ and looks like this:</p>
@ <blockquote><p><img src="%s(g.zTop)/logo/%z(zLogoMtime)" alt="logo" border="1" />
@ </p></blockquote>
@
@ <form action="%s(g.zTop)/setup_logo" method="post"
@ enctype="multipart/form-data"><div>
@ <p>The logo is accessible to all users at this URL:
@ <a href="%s(g.zBaseURL)/logo">%s(g.zBaseURL)/logo</a>.
@ The logo may or may not appear on each
|
| ︙ | ︙ | |||
1638 1639 1640 1641 1642 1643 1644 | @ <input type="submit" name="setlogo" value="Change Logo" /> @ <input type="submit" name="clrlogo" value="Revert To Default" /></p> @ </div></form> @ <hr /> @ @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b> @ and looks like this:</p> | | | 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 | @ <input type="submit" name="setlogo" value="Change Logo" /> @ <input type="submit" name="clrlogo" value="Revert To Default" /></p> @ </div></form> @ <hr /> @ @ <p>The current background image has a MIME-Type of <b>%h(zBgMime)</b> @ and looks like this:</p> @ <blockquote><p><img src="%s(g.zTop)/background/%z(zBgMtime)" alt="background" border=1 /> @ </p></blockquote> @ @ <form action="%s(g.zTop)/setup_logo" method="post" @ enctype="multipart/form-data"><div> @ <p>The background image is accessible to all users at this URL: @ <a href="%s(g.zBaseURL)/background">%s(g.zBaseURL)/background</a>. @ The background image may or may not appear on each |
| ︙ | ︙ |
Changes to src/sha1.c.
1 2 3 | /* ** This implementation of SHA1. */ | < > | 1 2 3 4 5 6 7 8 9 10 11 12 | /* ** This implementation of SHA1. */ #include "config.h" #include <sys/types.h> #include "sha1.h" /* ** The SHA1 implementation below is adapted from: ** ** $NetBSD: sha1.c,v 1.6 2009/11/06 20:31:18 joerg Exp $ |
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
const unsigned char *data,
unsigned int len
){
unsigned int i, j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
| | | | | | | | | | | | | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
const unsigned char *data,
unsigned int len
){
unsigned int i, j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
context->count[1] += (len>>29)+1;
j = (j >> 3) & 63;
if ((j + len) > 63) {
(void)memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64)
SHA1Transform(context->state, &data[i]);
j = 0;
} else {
i = 0;
}
(void)memcpy(&context->buffer[j], &data[i], len - i);
}
/*
* Add padding and return the message digest.
*/
static void SHA1Final(SHA1Context *context, unsigned char digest[20]){
unsigned int i;
unsigned char finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
SHA1Update(context, (const unsigned char *)"\200", 1);
while ((context->count[0] & 504) != 448)
SHA1Update(context, (const unsigned char *)"\0", 1);
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
if (digest) {
for (i = 0; i < 20; i++)
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
}
/*
** Convert a digest into base-16. digest should be declared as
** "unsigned char digest[20]" in the calling function. The SHA1
|
| ︙ | ︙ |
Changes to src/shell.c.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 | # include <editline/editline.h> #endif #if defined(HAVE_READLINE) && HAVE_READLINE==1 # include <readline/readline.h> # include <readline/history.h> #endif #if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1) | < | | > > > > > < < < > > > > > > > > > > > > > > > > > > > | > > > | > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# include <editline/editline.h>
#endif
#if defined(HAVE_READLINE) && HAVE_READLINE==1
# include <readline/readline.h>
# include <readline/history.h>
#endif
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
# define add_history(X)
# define read_history(X)
# define write_history(X)
# define stifle_history(X)
#endif
#if defined(_WIN32) || defined(WIN32)
# include <io.h>
#define isatty(h) _isatty(h)
#define access(f,m) _access((f),(m))
#undef popen
#define popen _popen
#undef pclose
#define pclose _pclose
#else
/* Make sure isatty() has a prototype.
*/
extern int isatty(int);
/* popen and pclose are not C89 functions and so are sometimes omitted from
** the <stdio.h> header */
extern FILE *popen(const char*,const char*);
extern int pclose(FILE*);
#endif
#if defined(_WIN32_WCE)
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
* thus we always assume that we have a console. That can be
* overridden with the -batch command line option.
*/
#define isatty(x) 1
#endif
/* ctype macros that work with signed characters */
#define IsSpace(X) isspace((unsigned char)X)
#define IsDigit(X) isdigit((unsigned char)X)
#define ToLower(X) (char)tolower((unsigned char)X)
/* True if the timer is enabled */
static int enableTimer = 0;
/* Return the current wall-clock time */
static sqlite3_int64 timeOfDay(void){
static sqlite3_vfs *clockVfs = 0;
sqlite3_int64 t;
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){
clockVfs->xCurrentTimeInt64(clockVfs, &t);
}else{
double r;
clockVfs->xCurrentTime(clockVfs, &r);
t = (sqlite3_int64)(r*86400000.0);
}
return t;
}
#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
&& !defined(__minux)
#include <sys/time.h>
#include <sys/resource.h>
/* Saved resource information for the beginning of an operation */
static struct rusage sBegin; /* CPU time at start */
static sqlite3_int64 iBegin; /* Wall-clock time at start */
/*
** Begin timing an operation
*/
static void beginTimer(void){
if( enableTimer ){
getrusage(RUSAGE_SELF, &sBegin);
iBegin = timeOfDay();
}
}
/* Return the difference of two time_structs in seconds */
static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
return (pEnd->tv_usec - pStart->tv_usec)*0.000001 +
(double)(pEnd->tv_sec - pStart->tv_sec);
}
/*
** Print the timing results.
*/
static void endTimer(void){
if( enableTimer ){
struct rusage sEnd;
sqlite3_int64 iEnd = timeOfDay();
getrusage(RUSAGE_SELF, &sEnd);
printf("Run Time: real %.3f user %f sys %f\n",
(iEnd - iBegin)*0.001,
timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
}
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER 1
#elif (defined(_WIN32) || defined(WIN32))
#include <windows.h>
/* Saved resource information for the beginning of an operation */
static HANDLE hProcess;
static FILETIME ftKernelBegin;
static FILETIME ftUserBegin;
static sqlite3_int64 ftWallBegin;
typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
static GETPROCTIMES getProcessTimesAddr = NULL;
/*
** Check to see if we have timer support. Return 1 if necessary
** support found (or found previously).
*/
|
| ︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
/*
** Begin timing an operation
*/
static void beginTimer(void){
if( enableTimer && getProcessTimesAddr ){
FILETIME ftCreation, ftExit;
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
}
}
/* Return the difference of two FILETIME structs in seconds */
static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
return (double) ((i64End - i64Start) / 10000000.0);
}
/*
** Print the timing results.
*/
static void endTimer(void){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
| > > | > | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
/*
** Begin timing an operation
*/
static void beginTimer(void){
if( enableTimer && getProcessTimesAddr ){
FILETIME ftCreation, ftExit;
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
ftWallBegin = timeOfDay();
}
}
/* Return the difference of two FILETIME structs in seconds */
static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
return (double) ((i64End - i64Start) / 10000000.0);
}
/*
** Print the timing results.
*/
static void endTimer(void){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
printf("Run Time: real %.3f user %f sys %f\n",
(ftWallEnd - ftWallBegin)*0.001,
timeDiff(&ftUserBegin, &ftUserEnd),
timeDiff(&ftKernelBegin, &ftKernelEnd));
}
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
|
| ︙ | ︙ | |||
328 329 330 331 332 333 334 | /* ** This routine reads a line of text from FILE in, stores ** the text in memory obtained from malloc() and returns a pointer ** to the text. NULL is returned at end of file, or if malloc() ** fails. ** | | | | < | | < < < < < < < < < | < < < | < | | > > > > > > > > | | < < < | < < > > | > > > > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 |
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
** fails.
**
** If zLine is not NULL then it is a malloced buffer returned from
** a previous call to this routine that may be reused.
*/
static char *local_getline(char *zLine, FILE *in){
int nLine = zLine==0 ? 0 : 100;
int n = 0;
while( 1 ){
if( n+100>nLine ){
nLine = nLine*2 + 100;
zLine = realloc(zLine, nLine);
if( zLine==0 ) return 0;
}
if( fgets(&zLine[n], nLine - n, in)==0 ){
if( n==0 ){
free(zLine);
return 0;
}
zLine[n] = 0;
break;
}
while( zLine[n] ) n++;
if( n>0 && zLine[n-1]=='\n' ){
n--;
if( n>0 && zLine[n-1]=='\r' ) n--;
zLine[n] = 0;
break;
}
}
return zLine;
}
/*
** Retrieve a single line of input text.
**
** If in==0 then read from standard input and prompt before each line.
** If isContinuation is true, then a continuation prompt is appropriate.
** If isContinuation is zero, then the main prompt should be used.
**
** If zPrior is not NULL then it is a buffer from a prior call to this
** routine that can be reused.
**
** The result is stored in space obtained from malloc() and must either
** be freed by the caller or else passed back into this routine via the
** zPrior argument for reuse.
*/
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
char *zPrompt;
char *zResult;
if( in!=0 ){
zResult = local_getline(zPrior, in);
}else{
zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if defined(HAVE_READLINE) && HAVE_READLINE==1
free(zPrior);
zResult = readline(zPrompt);
if( zResult && *zResult ) add_history(zResult);
#else
printf("%s", zPrompt);
fflush(stdout);
zResult = local_getline(zPrior, stdin);
#endif
}
return zResult;
}
struct previous_mode_data {
int valid; /* Is there legit data in here? */
int mode;
int showHeader;
|
| ︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 |
char nullvalue[20]; /* The text to print when a NULL comes back from
** the database */
struct previous_mode_data explainPrev;
/* Holds the mode information just before
** .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */
const char *zDbFilename; /* name of the database file */
const char *zVfs; /* Name of VFS to use */
sqlite3_stmt *pStmt; /* Current statement if any. */
FILE *pLog; /* Write log output here */
};
/*
** These are the allowed modes.
*/
#define MODE_Line 0 /* One column per line. Blank line between records */
#define MODE_Column 1 /* One record per line in neat columns */
| > > > > | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
char nullvalue[20]; /* The text to print when a NULL comes back from
** the database */
struct previous_mode_data explainPrev;
/* Holds the mode information just before
** .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */
const char *zDbFilename; /* name of the database file */
char *zFreeOnClose; /* Filename to free when closing */
const char *zVfs; /* Name of VFS to use */
sqlite3_stmt *pStmt; /* Current statement if any. */
FILE *pLog; /* Write log output here */
int *aiIndent; /* Array of indents used in MODE_Explain */
int nIndent; /* Size of array aiIndent[] */
int iIndent; /* Index of current op in aiIndent[] */
};
/*
** These are the allowed modes.
*/
#define MODE_Line 0 /* One column per line. Blank line between records */
#define MODE_Column 1 /* One record per line in neat columns */
|
| ︙ | ︙ | |||
550 551 552 553 554 555 556 |
fputc('t', out);
}else if( c=='\n' ){
fputc('\\', out);
fputc('n', out);
}else if( c=='\r' ){
fputc('\\', out);
fputc('r', out);
| | > | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 |
fputc('t', out);
}else if( c=='\n' ){
fputc('\\', out);
fputc('n', out);
}else if( c=='\r' ){
fputc('\\', out);
fputc('r', out);
}else if( !isprint(c&0xff) ){
fprintf(out, "\\%03o", c&0xff);
}else{
fputc(c, out);
}
}
fputc('"', out);
}
/*
** Output the given string with characters that are special to
** HTML escaped.
*/
static void output_html_string(FILE *out, const char *z){
int i;
if( z==0 ) z = "";
while( *z ){
for(i=0; z[i]
&& z[i]!='<'
&& z[i]!='&'
&& z[i]!='>'
&& z[i]!='\"'
&& z[i]!='\'';
|
| ︙ | ︙ | |||
736 737 738 739 740 741 742 |
for(i=0; i<nArg; i++){
int w;
if( i<ArraySize(p->actualWidth) ){
w = p->actualWidth[i];
}else{
w = 10;
}
| | < > > > > > > | 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 |
for(i=0; i<nArg; i++){
int w;
if( i<ArraySize(p->actualWidth) ){
w = p->actualWidth[i];
}else{
w = 10;
}
if( p->mode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
w = strlen30(azArg[i]);
}
if( i==1 && p->aiIndent && p->pStmt ){
if( p->iIndent<p->nIndent ){
fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
}
p->iIndent++;
}
if( w<0 ){
fprintf(p->out,"%*.*s%s",-w,-w,
azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
}else{
fprintf(p->out,"%-*.*s%s",w,w,
azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
|
| ︙ | ︙ | |||
967 968 969 970 971 972 973 |
const char *zFirstRow /* Print before first row, if not NULL */
){
sqlite3_stmt *pSelect;
int rc;
int nResult;
int i;
const char *z;
| | | | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
const char *zFirstRow /* Print before first row, if not NULL */
){
sqlite3_stmt *pSelect;
int rc;
int nResult;
int i;
const char *z;
rc = sqlite3_prepare_v2(p->db, zSelect, -1, &pSelect, 0);
if( rc!=SQLITE_OK || !pSelect ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
return rc;
}
rc = sqlite3_step(pSelect);
nResult = sqlite3_column_count(pSelect);
while( rc==SQLITE_ROW ){
if( zFirstRow ){
fprintf(p->out, "%s", zFirstRow);
|
| ︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 |
fprintf(p->out, ";\n");
}
rc = sqlite3_step(pSelect);
}
rc = sqlite3_finalize(pSelect);
if( rc!=SQLITE_OK ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
| | | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 |
fprintf(p->out, ";\n");
}
rc = sqlite3_step(pSelect);
}
rc = sqlite3_finalize(pSelect);
if( rc!=SQLITE_OK ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++;
}
return rc;
}
/*
** Allocate space and save off current error string.
*/
|
| ︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 |
if( pArg && pArg->out && db && pArg->pStmt ){
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
fprintf(pArg->out, "Fullscan Steps: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
fprintf(pArg->out, "Sort Operations: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset);
fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur);
}
return 0;
}
/*
** Execute a statement or set of statements. Print
** any result rows/columns depending on the current mode
** set via the supplied callback.
**
** This is very similar to SQLite's built-in sqlite3_exec()
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
if( pArg && pArg->out && db && pArg->pStmt ){
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
fprintf(pArg->out, "Fullscan Steps: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
fprintf(pArg->out, "Sort Operations: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset);
fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
}
return 0;
}
/*
** Parameter azArray points to a zero-terminated array of strings. zStr
** points to a single nul-terminated string. Return non-zero if zStr
** is equal, according to strcmp(), to any of the strings in the array.
** Otherwise, return zero.
*/
static int str_in_array(const char *zStr, const char **azArray){
int i;
for(i=0; azArray[i]; i++){
if( 0==strcmp(zStr, azArray[i]) ) return 1;
}
return 0;
}
/*
** If compiled statement pSql appears to be an EXPLAIN statement, allocate
** and populate the callback_data.aiIndent[] array with the number of
** spaces each opcode should be indented before it is output.
**
** The indenting rules are:
**
** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent
** all opcodes that occur between the p2 jump destination and the opcode
** itself by 2 spaces.
**
** * For each "Goto", if the jump destination is earlier in the program
** and ends on one of:
** Yield SeekGt SeekLt RowSetRead Rewind
** then indent all opcodes between the earlier instruction
** and "Goto" by 2 spaces.
*/
static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
const char *zSql; /* The text of the SQL statement */
const char *z; /* Used to check if this is an EXPLAIN */
int *abYield = 0; /* True if op is an OP_Yield */
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
int iOp; /* Index of operation in p->aiIndent[] */
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 };
const char *azGoto[] = { "Goto", 0 };
/* Try to figure out if this is really an EXPLAIN statement. If this
** cannot be verified, return early. */
zSql = sqlite3_sql(pSql);
if( zSql==0 ) return;
for(z=zSql; *z==' ' || *z=='\t' || *z=='\n' || *z=='\f' || *z=='\r'; z++);
if( sqlite3_strnicmp(z, "explain", 7) ) return;
for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
int i;
int iAddr = sqlite3_column_int(pSql, 0);
const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
/* Set p2 to the P2 field of the current opcode. Then, assuming that
** p2 is an instruction address, set variable p2op to the index of that
** instruction in the aiIndent[] array. p2 and p2op may be different if
** the current instruction is part of a sub-program generated by an
** SQL trigger or foreign key. */
int p2 = sqlite3_column_int(pSql, 3);
int p2op = (p2 + (iOp-iAddr));
/* Grow the p->aiIndent array as required */
if( iOp>=nAlloc ){
nAlloc += 100;
p->aiIndent = (int*)sqlite3_realloc(p->aiIndent, nAlloc*sizeof(int));
abYield = (int*)sqlite3_realloc(abYield, nAlloc*sizeof(int));
}
abYield[iOp] = str_in_array(zOp, azYield);
p->aiIndent[iOp] = 0;
p->nIndent = iOp+1;
if( str_in_array(zOp, azNext) ){
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
}
if( str_in_array(zOp, azGoto) && p2op<p->nIndent && abYield[p2op] ){
for(i=p2op+1; i<iOp; i++) p->aiIndent[i] += 2;
}
}
p->iIndent = 0;
sqlite3_free(abYield);
sqlite3_reset(pSql);
}
/*
** Free the array allocated by explain_data_prepare().
*/
static void explain_data_delete(struct callback_data *p){
sqlite3_free(p->aiIndent);
p->aiIndent = 0;
p->nIndent = 0;
p->iIndent = 0;
}
/*
** Execute a statement or set of statements. Print
** any result rows/columns depending on the current mode
** set via the supplied callback.
**
** This is very similar to SQLite's built-in sqlite3_exec()
|
| ︙ | ︙ | |||
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 |
if( pArg && pArg->mode==MODE_Explain ){
const char *zExplain = 0;
sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
if( zExplain && zExplain[0] ){
fprintf(pArg->out, "%s", zExplain);
}
}
/* perform the first step. this will tell us if we
** have a result set or not and how wide it is.
*/
rc = sqlite3_step(pStmt);
/* if we have a result set... */
if( SQLITE_ROW == rc ){
/* if we have a callback... */
if( xCallback ){
/* allocate space for col name ptr, value ptr, and type */
int nCol = sqlite3_column_count(pStmt);
void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
if( !pData ){
rc = SQLITE_NOMEM;
}else{
char **azCols = (char **)pData; /* Names of result columns */
char **azVals = &azCols[nCol]; /* Results */
int *aiTypes = (int *)&azVals[nCol]; /* Result types */
| > > > > > > | > > | > | > | 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 |
if( pArg && pArg->mode==MODE_Explain ){
const char *zExplain = 0;
sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
if( zExplain && zExplain[0] ){
fprintf(pArg->out, "%s", zExplain);
}
}
/* If the shell is currently in ".explain" mode, gather the extra
** data required to add indents to the output.*/
if( pArg && pArg->mode==MODE_Explain ){
explain_data_prepare(pArg, pStmt);
}
/* perform the first step. this will tell us if we
** have a result set or not and how wide it is.
*/
rc = sqlite3_step(pStmt);
/* if we have a result set... */
if( SQLITE_ROW == rc ){
/* if we have a callback... */
if( xCallback ){
/* allocate space for col name ptr, value ptr, and type */
int nCol = sqlite3_column_count(pStmt);
void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
if( !pData ){
rc = SQLITE_NOMEM;
}else{
char **azCols = (char **)pData; /* Names of result columns */
char **azVals = &azCols[nCol]; /* Results */
int *aiTypes = (int *)&azVals[nCol]; /* Result types */
int i, x;
assert(sizeof(int) <= sizeof(char *));
/* save off ptrs to column names */
for(i=0; i<nCol; i++){
azCols[i] = (char *)sqlite3_column_name(pStmt, i);
}
do{
/* extract the data and data types */
for(i=0; i<nCol; i++){
aiTypes[i] = x = sqlite3_column_type(pStmt, i);
if( x==SQLITE_BLOB && pArg && pArg->mode==MODE_Insert ){
azVals[i] = "";
}else{
azVals[i] = (char*)sqlite3_column_text(pStmt, i);
}
if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
rc = SQLITE_NOMEM;
break; /* from for */
}
} /* end for */
/* if data and types extracted successfully... */
|
| ︙ | ︙ | |||
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 |
}
}else{
do{
rc = sqlite3_step(pStmt);
} while( rc == SQLITE_ROW );
}
}
/* print usage stats if stats on */
if( pArg && pArg->statsOn ){
display_stats(db, pArg, 0);
}
/* Finalize the statement just executed. If this fails, save a
| > > | 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 |
}
}else{
do{
rc = sqlite3_step(pStmt);
} while( rc == SQLITE_ROW );
}
}
explain_data_delete(pArg);
/* print usage stats if stats on */
if( pArg && pArg->statsOn ){
display_stats(db, pArg, 0);
}
/* Finalize the statement just executed. If this fails, save a
|
| ︙ | ︙ | |||
1274 1275 1276 1277 1278 1279 1280 |
if( nArg!=3 ) return 1;
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
if( strcmp(zTable, "sqlite_sequence")==0 ){
zPrepStmt = "DELETE FROM sqlite_sequence;\n";
| | | 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 |
if( nArg!=3 ) return 1;
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
if( strcmp(zTable, "sqlite_sequence")==0 ){
zPrepStmt = "DELETE FROM sqlite_sequence;\n";
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
fprintf(p->out, "ANALYZE sqlite_master;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
char *zIns;
if( !p->writableSchema ){
fprintf(p->out, "PRAGMA writable_schema=ON;\n");
|
| ︙ | ︙ | |||
1306 1307 1308 1309 1310 1311 1312 |
char *zTmp = 0;
int nRow = 0;
zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
zTableInfo = appendText(zTableInfo, zTable, '"');
zTableInfo = appendText(zTableInfo, ");", 0);
| | | 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 |
char *zTmp = 0;
int nRow = 0;
zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
zTableInfo = appendText(zTableInfo, zTable, '"');
zTableInfo = appendText(zTableInfo, ");", 0);
rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0);
free(zTableInfo);
if( rc!=SQLITE_OK || !pTableInfo ){
return 1;
}
zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
/* Always quote the table name, even if it appears to be pure ascii,
|
| ︙ | ︙ | |||
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 | /* ** Text of a help message */ static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail ON|OFF Stop after hitting an error. Default OFF\n" ".databases List names and files of attached databases\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" ".echo ON|OFF Turn command echo on or off\n" ".exit Exit this program\n" ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" | > | 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 | /* ** Text of a help message */ static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail ON|OFF Stop after hitting an error. Default OFF\n" ".clone NEWDB Clone data into NEWDB from the existing database\n" ".databases List names and files of attached databases\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" ".echo ON|OFF Turn command echo on or off\n" ".exit Exit this program\n" ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" |
| ︙ | ︙ | |||
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 | " html HTML <table> code\n" " insert SQL insert statements for TABLE\n" " line One value per line\n" " list Values delimited by .separator string\n" " tabs Tab-separated values\n" " tcl TCL list elements\n" ".nullvalue STRING Use STRING in place of NULL values\n" ".output FILENAME Send output to FILENAME\n" ".output stdout Send output to the screen\n" ".print STRING... Print literal STRING\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" | > | 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 | " html HTML <table> code\n" " insert SQL insert statements for TABLE\n" " line One value per line\n" " list Values delimited by .separator string\n" " tabs Tab-separated values\n" " tcl TCL list elements\n" ".nullvalue STRING Use STRING in place of NULL values\n" ".open ?FILENAME? Close existing database and reopen FILENAME\n" ".output FILENAME Send output to FILENAME\n" ".output stdout Send output to the screen\n" ".print STRING... Print literal STRING\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" |
| ︙ | ︙ | |||
1460 1461 1462 1463 1464 1465 1466 | /* Forward reference */ static int process_input(struct callback_data *p, FILE *in); /* ** Make sure the database is open. If it is not, then open it. If ** the database fails to open, print an error message and exit. */ | | > > > > | > | < < | < | < < | < < < | | 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 |
/* Forward reference */
static int process_input(struct callback_data *p, FILE *in);
/*
** Make sure the database is open. If it is not, then open it. If
** the database fails to open, print an error message and exit.
*/
static void open_db(struct callback_data *p, int keepAlive){
if( p->db==0 ){
sqlite3_initialize();
sqlite3_open(p->zDbFilename, &p->db);
db = p->db;
if( db && sqlite3_errcode(db)==SQLITE_OK ){
sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
shellstaticFunc, 0, 0);
}
if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
fprintf(stderr,"Error: unable to open database \"%s\": %s\n",
p->zDbFilename, sqlite3_errmsg(db));
if( keepAlive ) return;
exit(1);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
}
}
/*
** Do C-language style dequoting.
**
** \t -> tab
** \n -> newline
** \r -> carriage return
** \" -> "
** \NNN -> ascii character NNN in octal
** \\ -> backslash
*/
static void resolve_backslashes(char *z){
int i, j;
char c;
for(i=j=0; (c = z[i])!=0; i++, j++){
if( c=='\\' ){
c = z[++i];
if( c=='n' ){
c = '\n';
}else if( c=='t' ){
c = '\t';
}else if( c=='r' ){
c = '\r';
}else if( c=='\\' ){
c = '\\';
}else if( c>='0' && c<='7' ){
c -= '0';
if( z[i+1]>='0' && z[i+1]<='7' ){
i++;
c = (c<<3) + z[i] - '0';
if( z[i+1]>='0' && z[i+1]<='7' ){
i++;
c = (c<<3) + z[i] - '0';
}
}
}
}
z[j] = c;
}
z[j] = 0;
}
/*
** Return the value of a hexadecimal digit. Return -1 if the input
** is not a hex digit.
*/
static int hexDigitValue(char c){
if( c>='0' && c<='9' ) return c - '0';
if( c>='a' && c<='f' ) return c - 'a' + 10;
if( c>='A' && c<='F' ) return c - 'A' + 10;
return -1;
}
/*
** Interpret zArg as an integer value, possibly with suffixes.
*/
static sqlite3_int64 integerValue(const char *zArg){
sqlite3_int64 v = 0;
|
| ︙ | ︙ | |||
1560 1561 1562 1563 1564 1565 1566 |
int isNeg = 0;
if( zArg[0]=='-' ){
isNeg = 1;
zArg++;
}else if( zArg[0]=='+' ){
zArg++;
}
| > > > > > > > > | | | | > | > > > > > > > > > > > > > > > > > > > > > > > | 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 |
int isNeg = 0;
if( zArg[0]=='-' ){
isNeg = 1;
zArg++;
}else if( zArg[0]=='+' ){
zArg++;
}
if( zArg[0]=='0' && zArg[1]=='x' ){
int x;
zArg += 2;
while( (x = hexDigitValue(zArg[0]))>=0 ){
v = (v<<4) + x;
zArg++;
}
}else{
while( IsDigit(zArg[0]) ){
v = v*10 + zArg[0] - '0';
zArg++;
}
}
for(i=0; i<ArraySize(aMult); i++){
if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
v *= aMult[i].iMult;
break;
}
}
return isNeg? -v : v;
}
/*
** Interpret zArg as either an integer or a boolean value. Return 1 or 0
** for TRUE and FALSE. Return the integer value if appropriate.
*/
static int booleanValue(char *zArg){
int i;
if( zArg[0]=='0' && zArg[1]=='x' ){
for(i=2; hexDigitValue(zArg[i])>=0; i++){}
}else{
for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
}
if( i>0 && zArg[i]==0 ) return (int)(integerValue(zArg) & 0xffffffff);
if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
return 1;
}
if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
return 0;
}
fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
zArg);
return 0;
}
/*
** Close an output file, assuming it is not stderr or stdout
*/
static void output_file_close(FILE *f){
if( f && f!=stdout && f!=stderr ) fclose(f);
}
|
| ︙ | ︙ | |||
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 |
** A no-op routine that runs with the ".breakpoint" doc-command. This is
** a useful spot to set a debugger breakpoint.
*/
static void test_breakpoint(void){
static int nCall = 0;
nCall++;
}
/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 |
** A no-op routine that runs with the ".breakpoint" doc-command. This is
** a useful spot to set a debugger breakpoint.
*/
static void test_breakpoint(void){
static int nCall = 0;
nCall++;
}
/*
** An object used to read a CSV file
*/
typedef struct CSVReader CSVReader;
struct CSVReader {
const char *zFile; /* Name of the input file */
FILE *in; /* Read the CSV text from this input stream */
char *z; /* Accumulated text for a field */
int n; /* Number of bytes in z */
int nAlloc; /* Space allocated for z[] */
int nLine; /* Current line number */
int cTerm; /* Character that terminated the most recent field */
int cSeparator; /* The separator character. (Usually ",") */
};
/* Append a single byte to z[] */
static void csv_append_char(CSVReader *p, int c){
if( p->n+1>=p->nAlloc ){
p->nAlloc += p->nAlloc + 100;
p->z = sqlite3_realloc(p->z, p->nAlloc);
if( p->z==0 ){
fprintf(stderr, "out of memory\n");
exit(1);
}
}
p->z[p->n++] = (char)c;
}
/* Read a single field of CSV text. Compatible with rfc4180 and extended
** with the option of having a separator other than ",".
**
** + Input comes from p->in.
** + Store results in p->z of length p->n. Space to hold p->z comes
** from sqlite3_malloc().
** + Use p->cSep as the separator. The default is ",".
** + Keep track of the line number in p->nLine.
** + Store the character that terminates the field in p->cTerm. Store
** EOF on end-of-file.
** + Report syntax errors on stderr
*/
static char *csv_read_one_field(CSVReader *p){
int c, pc, ppc;
int cSep = p->cSeparator;
p->n = 0;
c = fgetc(p->in);
if( c==EOF || seenInterrupt ){
p->cTerm = EOF;
return 0;
}
if( c=='"' ){
int startLine = p->nLine;
int cQuote = c;
pc = ppc = 0;
while( 1 ){
c = fgetc(p->in);
if( c=='\n' ) p->nLine++;
if( c==cQuote ){
if( pc==cQuote ){
pc = 0;
continue;
}
}
if( (c==cSep && pc==cQuote)
|| (c=='\n' && pc==cQuote)
|| (c=='\n' && pc=='\r' && ppc==cQuote)
|| (c==EOF && pc==cQuote)
){
do{ p->n--; }while( p->z[p->n]!=cQuote );
p->cTerm = c;
break;
}
if( pc==cQuote && c!='\r' ){
fprintf(stderr, "%s:%d: unescaped %c character\n",
p->zFile, p->nLine, cQuote);
}
if( c==EOF ){
fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
p->zFile, startLine, cQuote);
p->cTerm = EOF;
break;
}
csv_append_char(p, c);
ppc = pc;
pc = c;
}
}else{
while( c!=EOF && c!=cSep && c!='\n' ){
csv_append_char(p, c);
c = fgetc(p->in);
}
if( c=='\n' ){
p->nLine++;
if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;
}
p->cTerm = c;
}
if( p->z ) p->z[p->n] = 0;
return p->z;
}
/*
** Try to transfer data for table zTable. If an error is seen while
** moving forward, try to go backwards. The backwards movement won't
** work for WITHOUT ROWID tables.
*/
static void tryToCloneData(
struct callback_data *p,
sqlite3 *newDb,
const char *zTable
){
sqlite3_stmt *pQuery = 0;
sqlite3_stmt *pInsert = 0;
char *zQuery = 0;
char *zInsert = 0;
int rc;
int i, j, n;
int nTable = (int)strlen(zTable);
int k = 0;
int cnt = 0;
const int spinRate = 10000;
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
fprintf(stderr, "Error %d: %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
zQuery);
goto end_data_xfer;
}
n = sqlite3_column_count(pQuery);
zInsert = sqlite3_malloc(200 + nTable + n*3);
if( zInsert==0 ){
fprintf(stderr, "out of memory\n");
goto end_data_xfer;
}
sqlite3_snprintf(200+nTable,zInsert,
"INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
i = (int)strlen(zInsert);
for(j=1; j<n; j++){
memcpy(zInsert+i, ",?", 2);
i += 2;
}
memcpy(zInsert+i, ");", 3);
rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
if( rc ){
fprintf(stderr, "Error %d: %s on [%s]\n",
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
zQuery);
goto end_data_xfer;
}
for(k=0; k<2; k++){
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
for(i=0; i<n; i++){
switch( sqlite3_column_type(pQuery, i) ){
case SQLITE_NULL: {
sqlite3_bind_null(pInsert, i+1);
break;
}
case SQLITE_INTEGER: {
sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
break;
}
case SQLITE_FLOAT: {
sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
break;
}
case SQLITE_TEXT: {
sqlite3_bind_text(pInsert, i+1,
(const char*)sqlite3_column_text(pQuery,i),
-1, SQLITE_STATIC);
break;
}
case SQLITE_BLOB: {
sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
sqlite3_column_bytes(pQuery,i),
SQLITE_STATIC);
break;
}
}
} /* End for */
rc = sqlite3_step(pInsert);
if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
sqlite3_errmsg(newDb));
}
sqlite3_reset(pInsert);
cnt++;
if( (cnt%spinRate)==0 ){
printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
fflush(stdout);
}
} /* End while */
if( rc==SQLITE_DONE ) break;
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
zTable);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
break;
}
} /* End for(k=0...) */
end_data_xfer:
sqlite3_finalize(pQuery);
sqlite3_finalize(pInsert);
sqlite3_free(zQuery);
sqlite3_free(zInsert);
}
/*
** Try to transfer all rows of the schema that match zWhere. For
** each row, invoke xForEach() on the object defined by that row.
** If an error is encountered while moving forward through the
** sqlite_master table, try again moving backwards.
*/
static void tryToCloneSchema(
struct callback_data *p,
sqlite3 *newDb,
const char *zWhere,
void (*xForEach)(struct callback_data*,sqlite3*,const char*)
){
sqlite3_stmt *pQuery = 0;
char *zQuery = 0;
int rc;
const unsigned char *zName;
const unsigned char *zSql;
char *zErrMsg = 0;
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
" WHERE %s", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
fprintf(stderr, "Error: (%d) %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
zQuery);
goto end_schema_xfer;
}
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
printf("%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}
if( xForEach ){
xForEach(p, newDb, (const char*)zName);
}
printf("done\n");
}
if( rc!=SQLITE_DONE ){
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
" WHERE %s ORDER BY rowid DESC", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
fprintf(stderr, "Error: (%d) %s on [%s]\n",
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
zQuery);
goto end_schema_xfer;
}
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
zName = sqlite3_column_text(pQuery, 0);
zSql = sqlite3_column_text(pQuery, 1);
printf("%s... ", zName); fflush(stdout);
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
if( zErrMsg ){
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}
if( xForEach ){
xForEach(p, newDb, (const char*)zName);
}
printf("done\n");
}
}
end_schema_xfer:
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
}
/*
** Open a new database file named "zNewDb". Try to recover as much information
** as possible out of the main database (which might be corrupt) and write it
** into zNewDb.
*/
static void tryToClone(struct callback_data *p, const char *zNewDb){
int rc;
sqlite3 *newDb = 0;
if( access(zNewDb,0)==0 ){
fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
return;
}
rc = sqlite3_open(zNewDb, &newDb);
if( rc ){
fprintf(stderr, "Cannot create output database: %s\n",
sqlite3_errmsg(newDb));
}else{
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
tryToCloneSchema(p, newDb, "type!='table'", 0);
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
}
sqlite3_close(newDb);
}
/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
|
| ︙ | ︙ | |||
1640 1641 1642 1643 1644 1645 1646 |
*/
while( zLine[i] && nArg<ArraySize(azArg) ){
while( IsSpace(zLine[i]) ){ i++; }
if( zLine[i]==0 ) break;
if( zLine[i]=='\'' || zLine[i]=='"' ){
int delim = zLine[i++];
azArg[nArg++] = &zLine[i];
| | > > > < | < < | 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 |
*/
while( zLine[i] && nArg<ArraySize(azArg) ){
while( IsSpace(zLine[i]) ){ i++; }
if( zLine[i]==0 ) break;
if( zLine[i]=='\'' || zLine[i]=='"' ){
int delim = zLine[i++];
azArg[nArg++] = &zLine[i];
while( zLine[i] && zLine[i]!=delim ){
if( zLine[i]=='\\' && delim=='"' && zLine[i+1]!=0 ) i++;
i++;
}
if( zLine[i]==delim ){
zLine[i++] = 0;
}
if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
}else{
azArg[nArg++] = &zLine[i];
while( zLine[i] && !IsSpace(zLine[i]) ){ i++; }
if( zLine[i] ) zLine[i++] = 0;
resolve_backslashes(azArg[nArg-1]);
}
}
/* Process the input line.
*/
if( nArg==0 ) return 0; /* no tokens, no error */
n = strlen30(azArg[0]);
c = azArg[0][0];
if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){
const char *zDestFile = 0;
const char *zDb = 0;
sqlite3 *pDest;
sqlite3_backup *pBackup;
int j;
for(j=1; j<nArg; j++){
const char *z = azArg[j];
if( z[0]=='-' ){
while( z[0]=='-' ) z++;
/* No options to process at this time */
{
fprintf(stderr, "unknown option: %s\n", azArg[j]);
return 1;
}
}else if( zDestFile==0 ){
zDestFile = azArg[j];
}else if( zDb==0 ){
|
| ︙ | ︙ | |||
1697 1698 1699 1700 1701 1702 1703 |
if( zDb==0 ) zDb = "main";
rc = sqlite3_open(zDestFile, &pDest);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
sqlite3_close(pDest);
return 1;
}
| < < < < < | | 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 |
if( zDb==0 ) zDb = "main";
rc = sqlite3_open(zDestFile, &pDest);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
sqlite3_close(pDest);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
if( pBackup==0 ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
sqlite3_close(pDest);
return 1;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
|
| ︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 |
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
test_breakpoint();
}else
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
struct callback_data data;
char *zErrMsg = 0;
| > > > > | | | 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 |
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
test_breakpoint();
}else
if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
tryToClone(p, azArg[1]);
}else
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
struct callback_data data;
char *zErrMsg = 0;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 1;
data.mode = MODE_Column;
data.colWidth[0] = 3;
data.colWidth[1] = 15;
data.colWidth[2] = 58;
data.cnt = 0;
sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
if( zErrMsg ){
fprintf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}
}else
if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
open_db(p, 0);
/* When playing back a "dump", the content might appear in an order
** which causes immediate foreign key constraints to be violated.
** So disable foreign-key constraint enforcement to prevent problems. */
fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
fprintf(p->out, "BEGIN TRANSACTION;\n");
p->writableSchema = 0;
sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
|
| ︙ | ︙ | |||
1804 1805 1806 1807 1808 1809 1810 |
}else
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
p->echoOn = booleanValue(azArg[1]);
}else
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
| | | 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 |
}else
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
p->echoOn = booleanValue(azArg[1]);
}else
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
if( nArg>1 && (rc = (int)integerValue(azArg[1]))!=0 ) exit(rc);
rc = 2;
}else
if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
if(val == 1) {
if(!p->explainPrev.valid) {
|
| ︙ | ︙ | |||
1826 1827 1828 1829 1830 1831 1832 |
** explain mode. However, always executing it allows us an easy
** was to reset to explain mode in case the user previously
** did an .explain followed by a .width, .mode or .header
** command.
*/
p->mode = MODE_Explain;
p->showHeader = 1;
| | | 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 |
** explain mode. However, always executing it allows us an easy
** was to reset to explain mode in case the user previously
** did an .explain followed by a .width, .mode or .header
** command.
*/
p->mode = MODE_Explain;
p->showHeader = 1;
memset(p->colWidth,0,sizeof(p->colWidth));
p->colWidth[0] = 4; /* addr */
p->colWidth[1] = 13; /* opcode */
p->colWidth[2] = 4; /* P1 */
p->colWidth[3] = 4; /* P2 */
p->colWidth[4] = 4; /* P3 */
p->colWidth[5] = 13; /* P4 */
p->colWidth[6] = 2; /* P5 */
|
| ︙ | ︙ | |||
1857 1858 1859 1860 1861 1862 1863 |
if( HAS_TIMER ){
fprintf(stderr,"%s",zTimerHelp);
}
}else
if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
char *zTable = azArg[2]; /* Insert data into this table */
| | > < < | | < > > | > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | < < < | < < < < < < | < < | < > | > | | > > > | | < < < < < | < < | | < | > > | > | | | < < < < | < < < < < < < < < < | | < | > | < < < | > | | | > | | | 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 |
if( HAS_TIMER ){
fprintf(stderr,"%s",zTimerHelp);
}
}else
if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
char *zTable = azArg[2]; /* Insert data into this table */
char *zFile = azArg[1]; /* Name of file to extra content from */
sqlite3_stmt *pStmt = NULL; /* A statement */
int nCol; /* Number of columns in the table */
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
int needCommit; /* True to COMMIT or ROLLBACK at end */
int nSep; /* Number of bytes in p->separator[] */
char *zSql; /* An SQL statement */
CSVReader sCsv; /* Reader context */
int (*xCloser)(FILE*); /* Procedure to close th3 connection */
seenInterrupt = 0;
memset(&sCsv, 0, sizeof(sCsv));
open_db(p, 0);
nSep = strlen30(p->separator);
if( nSep==0 ){
fprintf(stderr, "Error: non-null separator required for import\n");
return 1;
}
if( nSep>1 ){
fprintf(stderr, "Error: multi-character separators not allowed"
" for import\n");
return 1;
}
sCsv.zFile = zFile;
sCsv.nLine = 1;
if( sCsv.zFile[0]=='|' ){
sCsv.in = popen(sCsv.zFile+1, "r");
sCsv.zFile = "<pipe>";
xCloser = pclose;
}else{
sCsv.in = fopen(sCsv.zFile, "rb");
xCloser = fclose;
}
if( sCsv.in==0 ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
return 1;
}
sCsv.cSeparator = p->separator[0];
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
if( zSql==0 ){
fprintf(stderr, "Error: out of memory\n");
xCloser(sCsv.in);
return 1;
}
nByte = strlen30(zSql);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
char cSep = '(';
while( csv_read_one_field(&sCsv) ){
zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCsv.z);
cSep = ',';
if( sCsv.cTerm!=sCsv.cSeparator ) break;
}
if( cSep=='(' ){
sqlite3_free(zCreate);
sqlite3_free(sCsv.z);
xCloser(sCsv.in);
fprintf(stderr,"%s: empty file\n", sCsv.zFile);
return 1;
}
zCreate = sqlite3_mprintf("%z\n)", zCreate);
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
sqlite3_free(zCreate);
if( rc ){
fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
sqlite3_errmsg(db));
sqlite3_free(sCsv.z);
xCloser(sCsv.in);
return 1;
}
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
}
sqlite3_free(zSql);
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
xCloser(sCsv.in);
return 1;
}
nCol = sqlite3_column_count(pStmt);
sqlite3_finalize(pStmt);
pStmt = 0;
if( nCol==0 ) return 0; /* no columns, no error */
zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
if( zSql==0 ){
fprintf(stderr, "Error: out of memory\n");
xCloser(sCsv.in);
return 1;
}
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
j = strlen30(zSql);
for(i=1; i<nCol; i++){
zSql[j++] = ',';
zSql[j++] = '?';
}
zSql[j++] = ')';
zSql[j] = 0;
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
if (pStmt) sqlite3_finalize(pStmt);
xCloser(sCsv.in);
return 1;
}
needCommit = sqlite3_get_autocommit(db);
if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
do{
int startLine = sCsv.nLine;
for(i=0; i<nCol; i++){
char *z = csv_read_one_field(&sCsv);
if( z==0 && i==0 ) break;
sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
if( i<nCol-1 && sCsv.cTerm!=sCsv.cSeparator ){
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
"filling the rest with NULL\n",
sCsv.zFile, startLine, nCol, i+1);
i++;
while( i<nCol ){ sqlite3_bind_null(pStmt, i); i++; }
}
}
if( sCsv.cTerm==sCsv.cSeparator ){
do{
csv_read_one_field(&sCsv);
i++;
}while( sCsv.cTerm==sCsv.cSeparator );
fprintf(stderr, "%s:%d: expected %d columns but found %d - "
"extras ignored\n",
sCsv.zFile, startLine, nCol, i);
}
if( i>=nCol ){
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine,
sqlite3_errmsg(db));
}
}
}while( sCsv.cTerm!=EOF );
xCloser(sCsv.in);
sqlite3_free(sCsv.z);
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
}else
if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
struct callback_data data;
char *zErrMsg = 0;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.mode = MODE_List;
if( nArg==1 ){
rc = sqlite3_exec(p->db,
"SELECT name FROM sqlite_master "
"WHERE type='index' AND name NOT LIKE 'sqlite_%' "
|
| ︙ | ︙ | |||
2051 2052 2053 2054 2055 2056 2057 |
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
const char *zFile, *zProc;
char *zErrMsg = 0;
zFile = azArg[1];
zProc = nArg>=3 ? azArg[2] : 0;
| | | 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 |
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
const char *zFile, *zProc;
char *zErrMsg = 0;
zFile = azArg[1];
zProc = nArg>=3 ? azArg[2] : 0;
open_db(p, 0);
rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
rc = 1;
}
}else
|
| ︙ | ︙ | |||
2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 |
}
}else
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
"%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
}else
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
if( p->outfile[0]=='|' ){
pclose(p->out);
}else{
output_file_close(p->out);
}
| > > > > > > > > > > > > > > > > > > > > | 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 |
}
}else
if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
"%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
}else
if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
sqlite3 *savedDb = p->db;
const char *zSavedFilename = p->zDbFilename;
char *zNewFilename = 0;
p->db = 0;
if( nArg>=2 ){
p->zDbFilename = zNewFilename = sqlite3_mprintf("%s", azArg[1]);
}
open_db(p, 1);
if( p->db!=0 ){
sqlite3_close(savedDb);
sqlite3_free(p->zFreeOnClose);
p->zFreeOnClose = zNewFilename;
}else{
sqlite3_free(zNewFilename);
p->db = savedDb;
p->zDbFilename = zSavedFilename;
}
}else
if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
if( p->outfile[0]=='|' ){
pclose(p->out);
}else{
output_file_close(p->out);
}
|
| ︙ | ︙ | |||
2200 2201 2202 2203 2204 2205 2206 |
}
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
sqlite3_close(pSrc);
return 1;
}
| | | 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 |
}
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
sqlite3_close(pSrc);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
if( pBackup==0 ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
sqlite3_close(pSrc);
return 1;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
|
| ︙ | ︙ | |||
2230 2231 2232 2233 2234 2235 2236 |
}
sqlite3_close(pSrc);
}else
if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
struct callback_data data;
char *zErrMsg = 0;
| | | 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 |
}
sqlite3_close(pSrc);
}else
if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
struct callback_data data;
char *zErrMsg = 0;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.mode = MODE_Semi;
if( nArg>1 ){
int i;
for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
if( strcmp(azArg[1],"sqlite_master")==0 ){
|
| ︙ | ︙ | |||
2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 |
}else if( rc != SQLITE_OK ){
fprintf(stderr,"Error: querying schema information\n");
rc = 1;
}else{
rc = 0;
}
}else
if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
sqlite3_snprintf(sizeof(p->separator), p->separator,
"%.*s", (int)sizeof(p->separator)-1, azArg[1]);
}else
if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
| > > > > > > > > > > > > > > > > > > > > > > > | 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 |
}else if( rc != SQLITE_OK ){
fprintf(stderr,"Error: querying schema information\n");
rc = 1;
}else{
rc = 0;
}
}else
#ifdef SQLITE_DEBUG
/* Undocumented commands for internal testing. Subject to change
** without notice. */
if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){
if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){
int i, v;
for(i=1; i<nArg; i++){
v = booleanValue(azArg[i]);
fprintf(p->out, "%s: %d 0x%x\n", azArg[i], v, v);
}
}
if( strncmp(azArg[0]+9, "integer", n-9)==0 ){
int i; sqlite3_int64 v;
for(i=1; i<nArg; i++){
char zBuf[200];
v = integerValue(azArg[i]);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%s: %lld 0x%llx\n", azArg[i], v, v);
fprintf(p->out, "%s", zBuf);
}
}
}else
#endif
if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
sqlite3_snprintf(sizeof(p->separator), p->separator,
"%.*s", (int)sizeof(p->separator)-1, azArg[1]);
}else
if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
|
| ︙ | ︙ | |||
2338 2339 2340 2341 2342 2343 2344 |
if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
sqlite3_stmt *pStmt;
char **azResult;
int nRow, nAlloc;
char *zSql = 0;
int ii;
| | | 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 |
if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
sqlite3_stmt *pStmt;
char **azResult;
int nRow, nAlloc;
char *zSql = 0;
int ii;
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ) return rc;
zSql = sqlite3_mprintf(
"SELECT name FROM sqlite_master"
" WHERE type IN ('table','view')"
" AND name NOT LIKE 'sqlite_%%'"
" AND name LIKE ?1");
|
| ︙ | ︙ | |||
2438 2439 2440 2441 2442 2443 2444 |
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
};
int testctrl = -1;
int rc = 0;
int i, n;
| | | | 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 |
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
};
int testctrl = -1;
int rc = 0;
int i, n;
open_db(p, 0);
/* convert testctrl text option to value. allow any unique prefix
** of the option name, or a numerical value. */
n = strlen30(azArg[1]);
for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
if( testctrl<0 ){
testctrl = aCtrl[i].ctrlCode;
}else{
fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
testctrl = -1;
break;
}
}
}
if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
}else{
switch(testctrl){
/* sqlite3_test_control(int, db, int) */
case SQLITE_TESTCTRL_OPTIMIZATIONS:
|
| ︙ | ︙ | |||
2488 2489 2490 2491 2492 2493 2494 |
fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
}
break;
/* sqlite3_test_control(int, uint) */
case SQLITE_TESTCTRL_PENDING_BYTE:
if( nArg==3 ){
| | | | 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 |
fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
}
break;
/* sqlite3_test_control(int, uint) */
case SQLITE_TESTCTRL_PENDING_BYTE:
if( nArg==3 ){
unsigned int opt = (unsigned int)integerValue(azArg[2]);
rc = sqlite3_test_control(testctrl, opt);
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
} else {
fprintf(stderr,"Error: testctrl %s takes a single unsigned"
" int option\n", azArg[1]);
}
break;
/* sqlite3_test_control(int, int) */
case SQLITE_TESTCTRL_ASSERT:
case SQLITE_TESTCTRL_ALWAYS:
if( nArg==3 ){
int opt = booleanValue(azArg[2]);
rc = sqlite3_test_control(testctrl, opt);
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
} else {
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
azArg[1]);
}
break;
|
| ︙ | ︙ | |||
2537 2538 2539 2540 2541 2542 2543 |
azArg[1]);
break;
}
}
}else
if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
| | | | | 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 |
azArg[1]);
break;
}
}
}else
if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
open_db(p, 0);
sqlite3_busy_timeout(p->db, (int)integerValue(azArg[1]));
}else
if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
&& nArg==2
){
enableTimer = booleanValue(azArg[1]);
}else
if( c=='t' && strncmp(azArg[0], "trace", n)==0 && nArg>1 ){
open_db(p, 0);
output_file_close(p->traceOut);
p->traceOut = output_file_open(azArg[1]);
#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
if( p->traceOut==0 ){
sqlite3_trace(p->db, 0, 0);
}else{
sqlite3_trace(p->db, sql_trace_callback, p->traceOut);
|
| ︙ | ︙ | |||
2588 2589 2590 2591 2592 2593 2594 |
}else
#endif
if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
int j;
assert( nArg<=ArraySize(azArg) );
for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
| | | | 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 |
}else
#endif
if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
int j;
assert( nArg<=ArraySize(azArg) );
for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
p->colWidth[j-1] = (int)integerValue(azArg[j]);
}
}else
{
fprintf(stderr, "Error: unknown command or invalid arguments: "
" \"%s\". Enter \".help\" for help\n", azArg[0]);
rc = 1;
}
return rc;
}
/*
** Return TRUE if a semicolon occurs anywhere in the first N characters
** of string z[].
*/
static int line_contains_semicolon(const char *z, int N){
int i;
for(i=0; i<N; i++){ if( z[i]==';' ) return 1; }
return 0;
}
/*
** Test to see if a line consists entirely of whitespace.
|
| ︙ | ︙ | |||
2640 2641 2642 2643 2644 2645 2646 | } /* ** Return TRUE if the line typed in is an SQL command terminator other ** than a semi-colon. The SQL Server style "go" command is understood ** as is the Oracle "/". */ | | | | | > | > | | | | | | < | | > > > | < < < < < | | > > | | | | > > > > > > | | < > < < < < < < | | | | < < | | < | | 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 |
}
/*
** Return TRUE if the line typed in is an SQL command terminator other
** than a semi-colon. The SQL Server style "go" command is understood
** as is the Oracle "/".
*/
static int line_is_command_terminator(const char *zLine){
while( IsSpace(zLine[0]) ){ zLine++; };
if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
return 1; /* Oracle */
}
if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
&& _all_whitespace(&zLine[2]) ){
return 1; /* SQL Server */
}
return 0;
}
/*
** Return true if zSql is a complete SQL statement. Return false if it
** ends in the middle of a string literal or C-style comment.
*/
static int line_is_complete(char *zSql, int nSql){
int rc;
if( zSql==0 ) return 1;
zSql[nSql] = ';';
zSql[nSql+1] = 0;
rc = sqlite3_complete(zSql);
zSql[nSql] = 0;
return rc;
}
/*
** Read input from *in and process it. If *in==0 then input
** is interactive - the user is typing it it. Otherwise, input
** is coming from a file or device. A prompt is issued and history
** is saved only if input is interactive. An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.
**
** Return the number of errors.
*/
static int process_input(struct callback_data *p, FILE *in){
char *zLine = 0; /* A single input line */
char *zSql = 0; /* Accumulated SQL text */
int nLine; /* Length of current line */
int nSql = 0; /* Bytes of zSql[] used */
int nAlloc = 0; /* Allocated zSql[] space */
int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */
char *zErrMsg; /* Error message returned */
int rc; /* Error code */
int errCnt = 0; /* Number of errors seen */
int lineno = 0; /* Current line number */
int startline = 0; /* Line number for start of current input */
while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
fflush(p->out);
zLine = one_input_line(in, zLine, nSql>0);
if( zLine==0 ){
/* End of input */
if( stdin_is_interactive ) printf("\n");
break;
}
if( seenInterrupt ){
if( in!=0 ) break;
seenInterrupt = 0;
}
lineno++;
if( nSql==0 && _all_whitespace(zLine) ){
if( p->echoOn ) printf("%s\n", zLine);
continue;
}
if( zLine && zLine[0]=='.' && nSql==0 ){
if( p->echoOn ) printf("%s\n", zLine);
rc = do_meta_command(zLine, p);
if( rc==2 ){ /* exit requested */
break;
}else if( rc ){
errCnt++;
}
continue;
}
if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
memcpy(zLine,";",2);
}
nLine = strlen30(zLine);
if( nSql+nLine+2>=nAlloc ){
nAlloc = nSql+nLine+100;
zSql = realloc(zSql, nAlloc);
if( zSql==0 ){
fprintf(stderr, "Error: out of memory\n");
exit(1);
}
}
nSqlPrior = nSql;
if( nSql==0 ){
int i;
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
assert( nAlloc>0 && zSql!=0 );
memcpy(zSql, zLine+i, nLine+1-i);
startline = lineno;
nSql = nLine-i;
}else{
zSql[nSql++] = '\n';
memcpy(zSql+nSql, zLine, nLine+1);
nSql += nLine;
}
if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
&& sqlite3_complete(zSql) ){
p->cnt = 0;
open_db(p, 0);
BEGIN_TIMER;
rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
END_TIMER;
if( rc || zErrMsg ){
char zPrefix[100];
if( in!=0 || !stdin_is_interactive ){
sqlite3_snprintf(sizeof(zPrefix), zPrefix,
"Error: near line %d:", startline);
}else{
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
}
if( zErrMsg!=0 ){
fprintf(stderr, "%s %s\n", zPrefix, zErrMsg);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}else{
fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
}
errCnt++;
}
nSql = 0;
}else if( nSql && _all_whitespace(zSql) ){
if( p->echoOn ) printf("%s\n", zSql);
nSql = 0;
}
}
if( nSql ){
if( !_all_whitespace(zSql) ){
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
}
free(zSql);
}
free(zLine);
return errCnt>0;
|
| ︙ | ︙ | |||
2967 2968 2969 2970 2971 2972 2973 | char *zErrMsg = 0; struct callback_data data; const char *zInitFile = 0; char *zFirstCmd = 0; int i; int rc = 0; | | | | | 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 |
char *zErrMsg = 0;
struct callback_data data;
const char *zInitFile = 0;
char *zFirstCmd = 0;
int i;
int rc = 0;
if( sqlite3_libversion_number()<3008003 ){
fprintf(stderr, "Unsuitable SQLite version %s, must be at least 3.8.3",
sqlite3_libversion());
exit(1);
}
Argv0 = argv[0];
main_init(&data);
stdin_is_interactive = isatty(0);
/* Make sure we have a valid signal handler early, before anything
|
| ︙ | ︙ | |||
3020 3021 3022 3023 3024 3025 3026 |
/* Need to check for batch mode here to so we can avoid printing
** informational messages (like from process_sqliterc) before
** we do the actual processing of arguments later in a second pass.
*/
stdin_is_interactive = 0;
}else if( strcmp(z,"-heap")==0 ){
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
| < | 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 |
/* Need to check for batch mode here to so we can avoid printing
** informational messages (like from process_sqliterc) before
** we do the actual processing of arguments later in a second pass.
*/
stdin_is_interactive = 0;
}else if( strcmp(z,"-heap")==0 ){
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
const char *zSize;
sqlite3_int64 szHeap;
zSize = cmdline_option_value(argc, argv, ++i);
szHeap = integerValue(zSize);
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
|
| ︙ | ︙ | |||
3080 3081 3082 3083 3084 3085 3086 |
/* Go ahead and open the database file if it already exists. If the
** file does not exist, delay opening it. This prevents empty database
** files from being created if a user mistypes the database name argument
** to the sqlite command-line tool.
*/
if( access(data.zDbFilename, 0)==0 ){
| | | 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 |
/* Go ahead and open the database file if it already exists. If the
** file does not exist, delay opening it. This prevents empty database
** files from being created if a user mistypes the database name argument
** to the sqlite command-line tool.
*/
if( access(data.zDbFilename, 0)==0 ){
open_db(&data, 0);
}
/* Process the initialization file if there is one. If no -init option
** is given on the command line, look for a file named ~/.sqliterc and
** try to process it.
*/
rc = process_sqliterc(&data,zInitFile);
|
| ︙ | ︙ | |||
3160 3161 3162 3163 3164 3165 3166 |
}else if( strcmp(z,"-cmd")==0 ){
if( i==argc-1 ) break;
z = cmdline_option_value(argc,argv,++i);
if( z[0]=='.' ){
rc = do_meta_command(z, &data);
if( rc && bail_on_error ) return rc==2 ? 0 : rc;
}else{
| | | 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 |
}else if( strcmp(z,"-cmd")==0 ){
if( i==argc-1 ) break;
z = cmdline_option_value(argc,argv,++i);
if( z[0]=='.' ){
rc = do_meta_command(z, &data);
if( rc && bail_on_error ) return rc==2 ? 0 : rc;
}else{
open_db(&data, 0);
rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
if( zErrMsg!=0 ){
fprintf(stderr,"Error: %s\n", zErrMsg);
if( bail_on_error ) return rc!=0 ? rc : 1;
}else if( rc!=0 ){
fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
if( bail_on_error ) return rc;
|
| ︙ | ︙ | |||
3184 3185 3186 3187 3188 3189 3190 |
if( zFirstCmd ){
/* Run just the command that follows the database name
*/
if( zFirstCmd[0]=='.' ){
rc = do_meta_command(zFirstCmd, &data);
if( rc==2 ) rc = 0;
}else{
| | | 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 |
if( zFirstCmd ){
/* Run just the command that follows the database name
*/
if( zFirstCmd[0]=='.' ){
rc = do_meta_command(zFirstCmd, &data);
if( rc==2 ) rc = 0;
}else{
open_db(&data, 0);
rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
if( zErrMsg!=0 ){
fprintf(stderr,"Error: %s\n", zErrMsg);
return rc!=0 ? rc : 1;
}else if( rc!=0 ){
fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);
return rc;
|
| ︙ | ︙ | |||
3231 3232 3233 3234 3235 3236 3237 3238 3239 |
rc = process_input(&data, stdin);
}
}
set_table_name(&data, 0);
if( data.db ){
sqlite3_close(data.db);
}
return rc;
}
| > | 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 |
rc = process_input(&data, stdin);
}
}
set_table_name(&data, 0);
if( data.db ){
sqlite3_close(data.db);
}
sqlite3_free(data.zFreeOnClose);
return rc;
}
|
Changes to src/shun.c.
| ︙ | ︙ | |||
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
login_insert_csrf_secret();
@ <input type="text" name="uuid" value="%h(PD("shun",""))" size="50" />
@ <input type="submit" name="add" value="Shun" />
@ </div></form>
@ </blockquote>
@
@ <p>Enter the UUID of a previous shunned artifact to cause it to be
@ accepted again in the repository. The artifact content is not
@ restored because the content is unknown. The only change is that
@ the formerly shunned artifact will be accepted on subsequent sync
@ operations.</p>
@
@ <blockquote>
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
login_insert_csrf_secret();
| > | | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
login_insert_csrf_secret();
@ <input type="text" name="uuid" value="%h(PD("shun",""))" size="50" />
@ <input type="submit" name="add" value="Shun" />
@ </div></form>
@ </blockquote>
@
@ <a name="delshun"></a>
@ <p>Enter the UUID of a previous shunned artifact to cause it to be
@ accepted again in the repository. The artifact content is not
@ restored because the content is unknown. The only change is that
@ the formerly shunned artifact will be accepted on subsequent sync
@ operations.</p>
@
@ <blockquote>
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
login_insert_csrf_secret();
@ <input type="text" name="uuid" value="%h(PD("accept", ""))" size="50" />
@ <input type="submit" name="sub" value="Accept" />
@ </div></form>
@ </blockquote>
@
@ <p>Press the Rebuild button below to rebuild the repository. The
@ content of newly shunned artifacts is not purged until the repository
@ is rebuilt. On larger repositories, the rebuild may take minute or
|
| ︙ | ︙ | |||
291 292 293 294 295 296 297 |
db_prepare(&q,
"SELECT login, datetime(rcvfrom.mtime), rcvfrom.ipaddr"
" FROM rcvfrom LEFT JOIN user USING(uid)"
" WHERE rcvid=%d",
rcvid
);
@ <table cellspacing="15" cellpadding="0" border="0">
| | | | | | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
db_prepare(&q,
"SELECT login, datetime(rcvfrom.mtime), rcvfrom.ipaddr"
" FROM rcvfrom LEFT JOIN user USING(uid)"
" WHERE rcvid=%d",
rcvid
);
@ <table cellspacing="15" cellpadding="0" border="0">
@ <tr><th valign="top" align="right">rcvid:</th>
@ <td valign="top">%d(rcvid)</td></tr>
if( db_step(&q)==SQLITE_ROW ){
const char *zUser = db_column_text(&q, 0);
const char *zDate = db_column_text(&q, 1);
const char *zIpAddr = db_column_text(&q, 2);
@ <tr><th valign="top" align="right">User:</th>
@ <td valign="top">%s(zUser)</td></tr>
@ <tr><th valign="top" align="right">Date:</th>
@ <td valign="top">%s(zDate)</td></tr>
@ <tr><th valign="top" align="right">IP Address:</th>
@ <td valign="top">%s(zIpAddr)</td></tr>
}
db_finalize(&q);
db_prepare(&q,
"SELECT rid, uuid, size FROM blob WHERE rcvid=%d", rcvid
);
@ <tr><th valign="top" align="right">Artifacts:</th>
@ <td valign="top">
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
const char *zUuid = db_column_text(&q, 1);
int size = db_column_int(&q, 2);
@ <a href="%s(g.zTop)/info/%s(zUuid)">%s(zUuid)</a>
@ (rid: %d(rid), size: %d(size))<br />
}
@ </td></tr>
@ </table>
db_finalize(&q);
style_footer();
}
|
Changes to src/skins.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Implementation of the Setup page for "skins". */ | < > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** Implementation of the Setup page for "skins". */ #include "config.h" #include <assert.h> #include "skins.h" /* @-comment: ## */ /* ** A black-and-white theme with the project title in a bar across the top ** and no logo image. */ |
| ︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
@ div.content {
@ padding: 0ex 0ex 0ex 0ex;
@ }
@ /* Hyperlink colors */
@ div.content a { color: #604000; }
@ div.content a:link { color: #604000;}
@ div.content a:visited { color: #600000; }
@
@ /* Some pages have section dividers */
@ div.section {
@ margin-bottom: 0px;
@ margin-top: 1em;
@ padding: 1px 1px 1px 1px;
@ font-size: 1.2em;
| > > > > > > > | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
@ div.content {
@ padding: 0ex 0ex 0ex 0ex;
@ }
@ /* Hyperlink colors */
@ div.content a { color: #604000; }
@ div.content a:link { color: #604000;}
@ div.content a:visited { color: #600000; }
@
@ /* <verbatim> blocks */
@ pre.verbatim {
@ background-color: #ffffff;
@ padding: 0.5em;
@ white-space: pre-wrap;
@ }
@
@ /* Some pages have section dividers */
@ div.section {
@ margin-bottom: 0px;
@ margin-top: 1em;
@ padding: 1px 1px 1px 1px;
@ font-size: 1.2em;
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
| | | | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="title"><small>$<project_name></small><br />$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
370 371 372 373 374 375 376 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
| | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="title">$<title></div>
@ <div class="status">
@ <div class="logo">$<project_name></div><br/>
|
| ︙ | ︙ | |||
393 394 395 396 397 398 399 |
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
| | | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
611 612 613 614 615 616 617 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
| | | | | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <img src="$logo_image_url" alt="logo">
@ <br />$<project_name>
@ </div>
@ <div class="title">$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
872 873 874 875 876 877 878 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
| | | | | 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen">
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <img src="$logo_image_url" alt="logo">
@ <br />$<project_name>
@ </div>
@ <div class="title">$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss" />
| | | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 |
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss" />
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen" />
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <th1>
@ ##
|
| ︙ | ︙ | |||
1167 1168 1169 1170 1171 1172 1173 | @ set logourl $baseurl @ } @ return $logourl @ } @ set logourl [getLogoUrl $baseurl] @ </th1> @ <a href="$logourl"> | | | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 |
@ set logourl $baseurl
@ }
@ return $logourl
@ }
@ set logourl [getLogoUrl $baseurl]
@ </th1>
@ <a href="$logourl">
@ <img src="$logo_image_url" border="0" alt="$project_name">
@ </a>
@ </div>
@ <div class="title"><small>$<project_name></small><br />$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href=''$home/brlist''>Branches</a>\n"
@ html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href=''$home/reportlist''>Tickets</a>\n"
|
| ︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 |
@ set fossilUrl http://www.fossil-scm.org
@ </th1>
@ This page was generated in about
@ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
@ <a href="$fossilUrl/">Fossil</a>
@ version $release_version $tclVersion
@ <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
| | | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
@ set fossilUrl http://www.fossil-scm.org
@ </th1>
@ This page was generated in about
@ <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
@ <a href="$fossilUrl/">Fossil</a>
@ version $release_version $tclVersion
@ <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
@ <a href="$fossilUrl/index.html/timeline?c=$manifest_date&y=ci">$manifest_date</a>
@ </div>
@ </body></html>
@ ');
;
/*
** An array of available built-in skins.
|
| ︙ | ︙ |
Changes to src/sqlcmd.c.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 |
zName = (const char*)sqlite3_value_text(argv[0]);
if( zName==0 ) return;
g.db = sqlite3_context_db_handle(context);
g.repositoryOpen = 1;
rid = name_to_rid(zName);
if( rid==0 ) return;
if( content_get(rid, &cx) ){
| | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
zName = (const char*)sqlite3_value_text(argv[0]);
if( zName==0 ) return;
g.db = sqlite3_context_db_handle(context);
g.repositoryOpen = 1;
rid = name_to_rid(zName);
if( rid==0 ) return;
if( content_get(rid, &cx) ){
sqlite3_result_blob(context, blob_buffer(&cx), blob_size(&cx),
SQLITE_TRANSIENT);
blob_reset(&cx);
}
}
/*
** Implementation of the "compress(X)" SQL function. The input X is
|
| ︙ | ︙ | |||
122 123 124 125 126 127 128 |
sqlcmd_decompress, 0, 0);
re_add_sql_func(db);
g.repositoryOpen = 1;
g.db = db;
return SQLITE_OK;
}
| < | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
sqlcmd_decompress, 0, 0);
re_add_sql_func(db);
g.repositoryOpen = 1;
g.db = db;
return SQLITE_OK;
}
/*
** COMMAND: sqlite3
**
** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
**
** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
** If DATABASE is omitted, then the repository that serves the working
** directory is opened.
**
** WARNING: Careless use of this command can corrupt a Fossil repository
** in ways that are unrecoverable. Be sure you know what you are doing before
** running any SQL commands that modifies the repository database.
*/
void cmd_sqlite3(void){
extern int sqlite3_shell(int, char**);
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
db_close(1);
sqlite3_shutdown();
sqlite3_shell(g.argc-1, g.argv+1);
g.db = 0;
}
|
| ︙ | ︙ |
Changes to src/sqlite3.c.
more than 10,000 changes
Changes to src/sqlite3.h.
| ︙ | ︙ | |||
103 104 105 106 107 108 109 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ | | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.8.3" #define SQLITE_VERSION_NUMBER 3008003 #define SQLITE_SOURCE_ID "2014-01-27 15:02:07 be1acb610f7e594b417dd8409b7a7aa8f3af5f77" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
366 367 368 369 370 371 372 | ** is not changed. ** ** Restrictions: ** ** <ul> ** <li> The application must insure that the 1st parameter to sqlite3_exec() ** is a valid and open [database connection]. | | | 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | ** is not changed. ** ** Restrictions: ** ** <ul> ** <li> The application must insure that the 1st parameter to sqlite3_exec() ** is a valid and open [database connection]. ** <li> The application must not close the [database connection] specified by ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. ** <li> The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. ** </ul> */ SQLITE_API int sqlite3_exec( sqlite3*, /* An open database */ |
| ︙ | ︙ | |||
443 444 445 446 447 448 449 | ** address this, newer versions of SQLite (version 3.3.8 and later) include ** support for additional result codes that provide more detailed information ** about errors. The extended result codes are enabled or disabled ** on a per database connection basis using the ** [sqlite3_extended_result_codes()] API. ** ** Some of the available extended result codes are listed here. | | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | ** address this, newer versions of SQLite (version 3.3.8 and later) include ** support for additional result codes that provide more detailed information ** about errors. The extended result codes are enabled or disabled ** on a per database connection basis using the ** [sqlite3_extended_result_codes()] API. ** ** Some of the available extended result codes are listed here. ** One may expect the number of extended result codes will increase ** over time. Software that uses extended result codes should expect ** to see new result codes in future releases of SQLite. ** ** The SQLITE_OK result code will never be extended. It will always ** be exactly zero. */ #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) |
| ︙ | ︙ | |||
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | > > > > > > > | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
| ︙ | ︙ | |||
548 549 550 551 552 553 554 | ** first then the size of the file is extended, never the other ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** information is written to disk in the same order as calls ** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that ** after reboot following a crash or power loss, the only bytes in a ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are | | > | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | ** first then the size of the file is extended, never the other ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** information is written to disk in the same order as calls ** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that ** after reboot following a crash or power loss, the only bytes in a ** file that were written at the application level might have changed ** and that adjacent bytes, even bytes within the same sector are ** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN ** flag indicate that a file cannot be deleted when open. */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 #define SQLITE_IOCAP_ATOMIC1K 0x00000004 #define SQLITE_IOCAP_ATOMIC2K 0x00000008 #define SQLITE_IOCAP_ATOMIC4K 0x00000010 #define SQLITE_IOCAP_ATOMIC8K 0x00000020 |
| ︙ | ︙ | |||
779 780 781 782 783 784 785 | ** <li>[[SQLITE_FCNTL_FILE_POINTER]] ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with a particular database ** connection. See the [sqlite3_file_control()] documentation for ** additional information. ** ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] | > > > | | | < > | > > > > | | | > > > > > > > | | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | ** <li>[[SQLITE_FCNTL_FILE_POINTER]] ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with a particular database ** connection. See the [sqlite3_file_control()] documentation for ** additional information. ** ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] ** No longer in use. ** ** <li>[[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and ** sent to the VFS immediately before the xSync method is invoked on a ** database file descriptor. Or, if the xSync method is not invoked ** because the user has configured SQLite with ** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place ** of the xSync method. In most cases, the pointer argument passed with ** this file-control is NULL. However, if the database file is being synced ** as part of a multi-database commit, the argument points to a nul-terminated ** string containing the transactions master-journal file name. VFSes that ** do not need this signal should silently ignore this opcode. Applications ** should not call [sqlite3_file_control()] with this opcode as doing so may ** disrupt the operation of the specialized VFSes that do require it. ** ** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]] ** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite ** and sent to the VFS after a transaction has been committed immediately ** but before the database is unlocked. VFSes that do not need this signal ** should silently ignore this opcode. Applications should not call ** [sqlite3_file_control()] with this opcode as doing so may disrupt the ** operation of the specialized VFSes that do require it. ** ** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]] ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic ** retry counts and intervals for certain disk I/O operations for the ** windows [VFS] in order to provide robustness in the presence of ** anti-virus programs. By default, the windows VFS will retry file read, ** file write, and file delete operations up to 10 times, with a delay |
| ︙ | ︙ | |||
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if ** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_MMAP_SIZE 18 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only | > > > > > > > > > > > > > > > > > > | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 | ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if ** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** ** <li>[[SQLITE_FCNTL_TRACE]] ** The [SQLITE_FCNTL_TRACE] file control provides advisory information ** to the VFS about what the higher layers of the SQLite stack are doing. ** This file control is used by some VFS activity tracing [shims]. ** The argument is a zero-terminated string. Higher layers in the ** SQLite stack may generate instances of this file control if ** the [SQLITE_USE_FCNTL_TRACE] compile-time option is enabled. ** ** <li>[[SQLITE_FCNTL_HAS_MOVED]] ** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a ** pointer to an integer and it writes a boolean into that integer depending ** on whether or not the file has been renamed, moved, or deleted since it ** was first opened. ** ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_MMAP_SIZE 18 #define SQLITE_FCNTL_TRACE 19 #define SQLITE_FCNTL_HAS_MOVED 20 #define SQLITE_FCNTL_SYNC 21 #define SQLITE_FCNTL_COMMIT_PHASETWO 22 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only |
| ︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | ** a memory allocation given a particular requested size. Most memory ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** | | | 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 | ** a memory allocation given a particular requested size. Most memory ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** ** The xInit method initializes the memory allocator. For example, ** it might allocate any require mutexes or initialize internal data ** structures. The xShutdown method is invoked (indirectly) by ** [sqlite3_shutdown()] and should deallocate any resources acquired ** by xInit. The pAppData pointer is used as the only parameter to ** xInit and xShutdown. ** ** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes |
| ︙ | ︙ | |||
1608 1609 1610 1611 1612 1613 1614 | ** log message after formatting via [sqlite3_snprintf()]. ** The SQLite logging interface is not reentrant; the logger function ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger ** function must be threadsafe. </dd> ** ** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI | | | | | | | | | | 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 | ** log message after formatting via [sqlite3_snprintf()]. ** The SQLite logging interface is not reentrant; the logger function ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger ** function must be threadsafe. </dd> ** ** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI ** <dd>^(This option takes a single argument of type int. If non-zero, then ** URI handling is globally enabled. If the parameter is zero, then URI handling ** is globally disabled.)^ ^If URI handling is globally enabled, all filenames ** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or ** specified as part of [ATTACH] commands are interpreted as URIs, regardless ** of whether or not the [SQLITE_OPEN_URI] flag is set when the database ** connection is opened. ^If it is globally disabled, filenames are ** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the ** database connection is opened. ^(By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** [SQLITE_USE_URI] symbol defined.)^ ** ** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN ** <dd>^This option takes a single integer argument which is interpreted as ** a boolean in order to enable or disable the use of covering indices for ** full table scans in the query optimizer. ^The default setting is determined ** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on" ** if that compile-time option is omitted. ** The ability to disable the use of covering indices for full table scans ** is because some incorrectly coded legacy applications might malfunction ** when the optimization is enabled. Providing the ability to ** disable the optimization allows the older, buggy application code to work ** without change even with newer versions of SQLite. ** ** [[SQLITE_CONFIG_PCACHE]] [[SQLITE_CONFIG_GETPCACHE]] ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE ** <dd> These options are obsolete and should not be used by new code. ** They are retained for backwards compatibility but are now no-ops. |
| ︙ | ︙ | |||
1657 1658 1659 1660 1661 1662 1663 | ** the connection being passed as the second parameter is being closed. The ** third parameter is passed NULL In this case. An example of using this ** configuration option can be seen in the "test_sqllog.c" source file in ** the canonical SQLite source tree.</dd> ** ** [[SQLITE_CONFIG_MMAP_SIZE]] ** <dt>SQLITE_CONFIG_MMAP_SIZE | | | | | | > > > > > > > | 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 | ** the connection being passed as the second parameter is being closed. The ** third parameter is passed NULL In this case. An example of using this ** configuration option can be seen in the "test_sqllog.c" source file in ** the canonical SQLite source tree.</dd> ** ** [[SQLITE_CONFIG_MMAP_SIZE]] ** <dt>SQLITE_CONFIG_MMAP_SIZE ** <dd>^SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values ** that are the default mmap size limit (the default setting for ** [PRAGMA mmap_size]) and the maximum allowed mmap size limit. ** ^The default setting can be overridden by each database connection using ** either the [PRAGMA mmap_size] command, or by using the ** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size ** cannot be changed at run-time. Nor may the maximum allowed mmap size ** exceed the compile-time maximum mmap size set by the ** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^ ** ^If either argument to this option is negative, then that argument is ** changed to its compile-time default. ** ** [[SQLITE_CONFIG_WIN32_HEAPSIZE]] ** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE ** <dd>^This option is only available if SQLite is compiled for Windows ** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined. ** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value ** that specifies the maximum size of the created heap. ** </dl> */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ |
| ︙ | ︙ | |||
1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** | > | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */ #define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** |
| ︙ | ︙ | |||
1768 1769 1770 1771 1772 1773 1774 | ** codes are disabled by default for historical compatibility. */ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid ** | > | | | | | | | > | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 | ** codes are disabled by default for historical compatibility. */ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid ** ** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables) ** has a unique 64-bit signed ** integer key called the [ROWID | "rowid"]. ^The rowid is always available ** as an undeclared column named ROWID, OID, or _ROWID_ as long as those ** names are not also used by explicitly declared columns. ^If ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** ** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the ** most recent successful [INSERT] into a rowid table or [virtual table] ** on database connection D. ** ^Inserts into [WITHOUT ROWID] tables are not recorded. ** ^If no successful [INSERT]s into rowid tables ** have ever occurred on the database connection D, ** then sqlite3_last_insert_rowid(D) returns zero. ** ** ^(If an [INSERT] occurs within a trigger or within a [virtual table] ** method, then this routine will return the [rowid] of the inserted ** row as long as the trigger or virtual table method is running. ** But once the trigger or virtual table method ends, the value returned ** by this routine reverts to what it was before the trigger or virtual ** table method began.)^ |
| ︙ | ︙ | |||
2346 2347 2348 2349 2350 2351 2352 2353 | ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for ** the build-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. ** | > | | | > | | 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 | ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for ** the build-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. ** ^If N is less than one, then P can be a NULL pointer. ** ** ^If this routine has not been previously called or if the previous ** call had N less than one, then the PRNG is seeded using randomness ** obtained from the xRandomness method of the default [sqlite3_vfs] object. ** ^If the previous call to this routine had an N of 1 or more then ** the pseudo-randomness is generated ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks |
| ︙ | ︙ | |||
2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 | #define SQLITE_REINDEX 27 /* Index Name NULL */ #define SQLITE_ANALYZE 28 /* Table Name NULL */ #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ /* ** CAPI3REF: Tracing And Profiling Functions ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** | > | 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 | #define SQLITE_REINDEX 27 /* Index Name NULL */ #define SQLITE_ANALYZE 28 /* Table Name NULL */ #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ #define SQLITE_RECURSIVE 33 /* NULL NULL */ /* ** CAPI3REF: Tracing And Profiling Functions ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** |
| ︙ | ︙ | |||
2553 2554 2555 2556 2557 2558 2559 | ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** ** ^The parameter P is passed through as the only parameter to the | | | > | 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 | ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** ** ^The parameter P is passed through as the only parameter to the ** callback function X. ^The parameter N is the approximate number of ** [virtual machine instructions] that are evaluated between successive ** invocations of the callback X. ^If N is less than one then the progress ** handler is disabled. ** ** ^Only a single progress handler may be defined at one time per ** [database connection]; setting a new progress handler cancels the ** old one. ^Setting parameter X to NULL disables the progress handler. ** ^The progress handler is also disabled by setting N to a value less ** than 1. ** |
| ︙ | ︙ | |||
3089 3090 3091 3092 3093 3094 3095 | ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. | < | 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 | ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. ** </li> ** </ol> */ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ |
| ︙ | ︙ | |||
3751 3752 3753 3754 3755 3756 3757 | ** ** <blockquote> ** <table border="1"> ** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion ** ** <tr><td> NULL <td> INTEGER <td> Result is 0 ** <tr><td> NULL <td> FLOAT <td> Result is 0.0 | | | | | | | | | | 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 | ** ** <blockquote> ** <table border="1"> ** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion ** ** <tr><td> NULL <td> INTEGER <td> Result is 0 ** <tr><td> NULL <td> FLOAT <td> Result is 0.0 ** <tr><td> NULL <td> TEXT <td> Result is a NULL pointer ** <tr><td> NULL <td> BLOB <td> Result is a NULL pointer ** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float ** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer ** <tr><td> INTEGER <td> BLOB <td> Same as INTEGER->TEXT ** <tr><td> FLOAT <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float ** <tr><td> FLOAT <td> BLOB <td> [CAST] to BLOB ** <tr><td> TEXT <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> TEXT <td> FLOAT <td> [CAST] to REAL ** <tr><td> TEXT <td> BLOB <td> No change ** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL ** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed ** </table> ** </blockquote>)^ ** ** The table above makes reference to standard C library functions atoi() ** and atof(). SQLite does not really use these functions. It has its ** own equivalent internal routines. The atoi() and atof() names are |
| ︙ | ︙ | |||
3819 3820 3821 3822 3823 3824 3825 | ** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() ** with calls to sqlite3_column_bytes(). ** ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings ** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned | | | 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 | ** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() ** with calls to sqlite3_column_bytes(). ** ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings ** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned ** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** ** ^(If a memory allocation error occurs during the evaluation of any ** of these routines, a default value is returned. The default value ** is either the integer 0, the floating point number 0.0, or a NULL ** pointer. Subsequent calls to [sqlite3_errcode()] will return ** [SQLITE_NOMEM].)^ |
| ︙ | ︙ | |||
3928 3929 3930 3931 3932 3933 3934 | ** aggregate may take any number of arguments between 0 and the limit ** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third ** parameter is less than -1 or greater than 127 then the behavior is ** undefined. ** ** ^The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for | > | > | < | > | > < > | > > > > > > | 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 | ** aggregate may take any number of arguments between 0 and the limit ** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third ** parameter is less than -1 or greater than 127 then the behavior is ** undefined. ** ** ^The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for ** its parameters. The application should set this parameter to ** [SQLITE_UTF16LE] if the function implementation invokes ** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the ** implementation invokes [sqlite3_value_text16be()] on an input, or ** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8] ** otherwise. ^The same SQL function may be registered multiple times using ** different preferred text encodings, with different implementations for ** each encoding. ** ^When multiple implementations of the same function are available, SQLite ** will pick the one that involves the least amount of data conversion. ** ** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC] ** to signal that the function will always return the same result given ** the same inputs within a single SQL statement. Most SQL functions are ** deterministic. The built-in [random()] SQL function is an example of a ** function that is not deterministic. The SQLite query planner is able to ** perform additional optimizations on deterministic functions, so use ** of the [SQLITE_DETERMINISTIC] flag is recommended where possible. ** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** ** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc |
| ︙ | ︙ | |||
4022 4023 4024 4025 4026 4027 4028 | ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ #define SQLITE_UTF8 1 #define SQLITE_UTF16LE 2 #define SQLITE_UTF16BE 3 #define SQLITE_UTF16 4 /* Use native byte order */ | | > > > > > > > > > > | 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 | ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ #define SQLITE_UTF8 1 #define SQLITE_UTF16LE 2 #define SQLITE_UTF16BE 3 #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ /* ** CAPI3REF: Function Flags ** ** These constants may be ORed together with the ** [SQLITE_UTF8 | preferred text encoding] as the fourth argument ** to [sqlite3_create_function()], [sqlite3_create_function16()], or ** [sqlite3_create_function_v2()]. */ #define SQLITE_DETERMINISTIC 0x800 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain ** backwards compatibility with older code, these functions continue ** to be supported. However, new applications should avoid |
| ︙ | ︙ | |||
4175 4176 4177 4178 4179 4180 4181 | ** registered the application defined function. */ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data ** | | | | | | > | | < | < | | | < | | > | > | | > | > | > > > | > > > | | | | | 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 | ** registered the application defined function. */ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data ** ** These functions may be used by (non-aggregate) SQL functions to ** associate metadata with argument values. If the same value is passed to ** multiple invocations of the same SQL function during query execution, under ** some circumstances the associated metadata may be preserved. An example ** of where this might be useful is in a regular-expression matching ** function. The compiled version of the regular expression can be stored as ** metadata associated with the pattern string. ** Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** ** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata ** associated by the sqlite3_set_auxdata() function with the Nth argument ** value to the application-defined function. ^If there is no metadata ** associated with the function argument, this sqlite3_get_auxdata() interface ** returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th ** argument of the application-defined function. ^Subsequent ** calls to sqlite3_get_auxdata(C,N) return P from the most recent ** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or ** NULL if the metadata has been discarded. ** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL, ** SQLite will invoke the destructor function X with parameter P exactly ** once, when the metadata is discarded. ** SQLite is free to discard the metadata at any time, including: <ul> ** <li> when the corresponding function parameter changes, or ** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the ** SQL statement, or ** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or ** <li> during the original sqlite3_set_auxdata() call when a memory ** allocation error occurs. </ul>)^ ** ** Note the last bullet in particular. The destructor X in ** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the ** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata() ** should be called near the end of the function implementation and the ** function implementation should not make any use of P after ** sqlite3_set_auxdata() has been called. ** ** ^(In practice, metadata is preserved between function calls for ** function parameters that are compile-time constants, including literal ** values and [parameters] and expressions composed from the same.)^ ** ** These routines must be called from the same thread in which ** the SQL function is running. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); |
| ︙ | ︙ | |||
4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 | ** The code to implement this API is not available in the public release ** of SQLite. */ SQLITE_API int sqlite3_key( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The key */ ); /* ** Change the key on an open database. If the current database is not ** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the ** database is decrypted. ** ** The code to implement this API is not available in the public release ** of SQLite. */ SQLITE_API int sqlite3_rekey( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The new key */ ); /* ** Specify the activation key for a SEE database. Unless ** activated, none of the SEE routines will work. */ SQLITE_API void sqlite3_activate_see( const char *zPassPhrase /* Activation phrase */ | > > > > > > > > > > | 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 | ** The code to implement this API is not available in the public release ** of SQLite. */ SQLITE_API int sqlite3_key( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The key */ ); SQLITE_API int sqlite3_key_v2( sqlite3 *db, /* Database to be rekeyed */ const char *zDbName, /* Name of the database */ const void *pKey, int nKey /* The key */ ); /* ** Change the key on an open database. If the current database is not ** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the ** database is decrypted. ** ** The code to implement this API is not available in the public release ** of SQLite. */ SQLITE_API int sqlite3_rekey( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The new key */ ); SQLITE_API int sqlite3_rekey_v2( sqlite3 *db, /* Database to be rekeyed */ const char *zDbName, /* Name of the database */ const void *pKey, int nKey /* The new key */ ); /* ** Specify the activation key for a SEE database. Unless ** activated, none of the SEE routines will work. */ SQLITE_API void sqlite3_activate_see( const char *zPassPhrase /* Activation phrase */ |
| ︙ | ︙ | |||
4778 4779 4780 4781 4782 4783 4784 | SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument | | > | > | 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 | SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument ** to be invoked whenever a row is updated, inserted or deleted in ** a rowid table. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], ** or [SQLITE_UPDATE], depending on the operation that caused the callback ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. ** ^The final callback parameter is the [rowid] of the row. ** ^In the case of an update, this is the [rowid] after the update takes place. ** ** ^(The update hook is not invoked when internal system tables are ** modified (i.e. sqlite_master and sqlite_sequence).)^ ** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified. ** ** ^In the current implementation, the update hook ** is not invoked when duplication rows are deleted because of an ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future ** release of SQLite. |
| ︙ | ︙ | |||
4877 4878 4879 4880 4881 4882 4883 | SQLITE_API int sqlite3_release_memory(int); /* ** CAPI3REF: Free Memory Used By A Database Connection ** ** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap ** memory as possible from database connection D. Unlike the | | | | 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 | SQLITE_API int sqlite3_release_memory(int); /* ** CAPI3REF: Free Memory Used By A Database Connection ** ** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap ** memory as possible from database connection D. Unlike the ** [sqlite3_release_memory()] interface, this interface is in effect even ** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is ** omitted. ** ** See also: [sqlite3_release_memory()] */ SQLITE_API int sqlite3_db_release_memory(sqlite3*); /* |
| ︙ | ︙ | |||
5112 5113 5114 5115 5116 5117 5118 | ** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], ** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. ** ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already ** on the list of automatic extensions is a harmless no-op. ^No entry point ** will be called more than once for each database connection that is opened. ** | | > > > > > > > > > > > > > | 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 | ** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], ** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. ** ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already ** on the list of automatic extensions is a harmless no-op. ^No entry point ** will be called more than once for each database connection that is opened. ** ** See also: [sqlite3_reset_auto_extension()] ** and [sqlite3_cancel_auto_extension()] */ SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void)); /* ** CAPI3REF: Cancel Automatic Extension Loading ** ** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the ** initialization routine X that was registered using a prior call to ** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)] ** routine returns 1 if initialization routine X was successfully ** unregistered and it returns 0 if X was not on the list of initialization ** routines. */ SQLITE_API int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void)); /* ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously ** registered using [sqlite3_auto_extension()]. */ SQLITE_API void sqlite3_reset_auto_extension(void); |
| ︙ | ︙ | |||
5240 5241 5242 5243 5244 5245 5246 | ** ^[sqlite3_free()] is used to free idxPtr if and only if ** needToFreeIdxPtr is true. ** ** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in ** the correct order to satisfy the ORDER BY clause so that no separate ** sorting step is required. ** | | > | > | | > > > > > > > > > > | 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 |
** ^[sqlite3_free()] is used to free idxPtr if and only if
** needToFreeIdxPtr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
** sorting step is required.
**
** ^The estimatedCost value is an estimate of the cost of a particular
** strategy. A cost of N indicates that the cost of the strategy is similar
** to a linear scan of an SQLite table with N rows. A cost of log(N)
** indicates that the expense of the operation is similar to that of a
** binary search on a unique indexed field of an SQLite table with N rows.
**
** ^The estimatedRows value is an estimate of the number of rows that
** will be returned by the strategy.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite version 3.8.2. If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002.
*/
struct sqlite3_index_info {
/* Inputs */
int nConstraint; /* Number of entries in aConstraint */
struct sqlite3_index_constraint {
int iColumn; /* Column on left-hand side of constraint */
unsigned char op; /* Constraint operator */
|
| ︙ | ︙ | |||
5268 5269 5270 5271 5272 5273 5274 |
int argvIndex; /* if >0, constraint is part of argv to xFilter */
unsigned char omit; /* Do not code a test for this constraint */
} *aConstraintUsage;
int idxNum; /* Number used to identify the index */
char *idxStr; /* String, possibly obtained from sqlite3_malloc */
int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
int orderByConsumed; /* True if output is already ordered */
| | > > | 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 |
int argvIndex; /* if >0, constraint is part of argv to xFilter */
unsigned char omit; /* Do not code a test for this constraint */
} *aConstraintUsage;
int idxNum; /* Number used to identify the index */
char *idxStr; /* String, possibly obtained from sqlite3_malloc */
int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
int orderByConsumed; /* True if output is already ordered */
double estimatedCost; /* Estimated cost of using this index */
/* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
};
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
** These macros defined the allowed values for the
** [sqlite3_index_info].aConstraint[].op field. Each value represents
|
| ︙ | ︙ | |||
5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 | ** commit if the transaction continues to completion.)^ ** ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces ** and the built-in [zeroblob] SQL function can be used, if desired, ** to create an empty, zero-filled blob in which to read or write using ** this interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. | > > > | 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 | ** commit if the transaction continues to completion.)^ ** ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** ** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID] ** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces ** and the built-in [zeroblob] SQL function can be used, if desired, ** to create an empty, zero-filled blob in which to read or write using ** this interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. |
| ︙ | ︙ | |||
5995 5996 5997 5998 5999 6000 6001 | #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 | > | | 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 | #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_LAST 20 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for |
| ︙ | ︙ | |||
6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 | ** wal file in wal mode databases, or the number of pages written to the ** database file in rollback mode databases. Any pages written as part of ** transaction rollback or database recovery operations are not included. ** If an IO or other error occurs while writing a page to disk, the effect ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 | > > > > > > > | | 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 | ** wal file in wal mode databases, or the number of pages written to the ** database file in rollback mode databases. Any pages written as part of ** transaction rollback or database recovery operations are not included. ** If an IO or other error occurs while writing a page to disk, the effect ** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The ** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0. ** </dd> ** ** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt> ** <dd>This parameter returns zero for the current value if and only if ** all foreign key constraints (deferred or immediate) have been ** resolved.)^ ^The highwater mark is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_CACHE_WRITE 9 #define SQLITE_DBSTATUS_DEFERRED_FKS 10 #define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** ** ^(Each prepared statement maintains various ** [SQLITE_STMTSTATUS counters] that measure the number |
| ︙ | ︙ | |||
6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 | ** ** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> ** <dd>^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run.</dd> ** </dl> */ #define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 /* ** CAPI3REF: Custom Page Cache Object ** ** The sqlite3_pcache type is opaque. It is implemented by ** the pluggable module. The SQLite core has no knowledge of ** its size or internal structure and never deals with the | > > > > > > > > > > | 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 | ** ** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> ** <dd>^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run.</dd> ** ** [[SQLITE_STMTSTATUS_VM_STEP]] <dt>SQLITE_STMTSTATUS_VM_STEP</dt> ** <dd>^This is the number of virtual machine operations executed ** by the prepared statement if that number is less than or equal ** to 2147483647. The number of virtual machine operations can be ** used as a proxy for the total work done by the prepared statement. ** If the number of virtual machine operations exceeds 2147483647 ** then the value returned by this statement status code is undefined. ** </dd> ** </dl> */ #define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 /* ** CAPI3REF: Custom Page Cache Object ** ** The sqlite3_pcache type is opaque. It is implemented by ** the pluggable module. The SQLite core has no knowledge of ** its size or internal structure and never deals with the |
| ︙ | ︙ | |||
7177 7178 7179 7180 7181 7182 7183 | #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif | | | 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 | #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* _SQLITE3_H_ */ /* ** 2010 August 30 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** |
| ︙ | ︙ |
Changes to src/stash.c.
| ︙ | ︙ | |||
156 157 158 159 160 161 162 |
int vid; /* Current checkout */
zComment = find_option("comment", "m", 1);
verify_all_options();
if( zComment==0 ){
Blob prompt; /* Prompt for stash comment */
Blob comment; /* User comment reply */
| | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
int vid; /* Current checkout */
zComment = find_option("comment", "m", 1);
verify_all_options();
if( zComment==0 ){
Blob prompt; /* Prompt for stash comment */
Blob comment; /* User comment reply */
#if defined(_WIN32) || defined(__CYGWIN__)
int bomSize;
const unsigned char *bom = get_utf8_bom(&bomSize);
blob_init(&prompt, (const char *) bom, bomSize);
#else
blob_zero(&prompt);
#endif
blob_append(&prompt,
"\n"
"# Enter a description of what is being stashed. Lines beginning\n"
"# with \"#\" are ignored. Stash comments are plain text except\n"
"# newlines are not preserved.\n",
-1);
prompt_for_user_comment(&comment, &prompt);
blob_reset(&prompt);
zComment = blob_str(&comment);
}
stashid = db_lget_int("stash-next", 1);
|
| ︙ | ︙ | |||
637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
diff_tk((zCmd[0]=='s' ? "stash show" : "stash diff"), 3);
return;
}
if( find_option("internal","i",0)==0 ){
zDiffCmd = diff_command_external(0);
}
diffFlags = diff_options();
if( g.argc>4 ) usage(mprintf("%s STASHID", zCmd));
if( zDiffCmd ){
zBinGlob = diff_get_binary_glob();
fIncludeBinary = diff_include_binary_files();
}
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
stash_diff(stashid, zDiffCmd, zBinGlob, zCmd[0]=='s', fIncludeBinary,
| > | 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
diff_tk((zCmd[0]=='s' ? "stash show" : "stash diff"), 3);
return;
}
if( find_option("internal","i",0)==0 ){
zDiffCmd = diff_command_external(0);
}
diffFlags = diff_options();
if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
if( g.argc>4 ) usage(mprintf("%s STASHID", zCmd));
if( zDiffCmd ){
zBinGlob = diff_get_binary_glob();
fIncludeBinary = diff_include_binary_files();
}
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
stash_diff(stashid, zDiffCmd, zBinGlob, zCmd[0]=='s', fIncludeBinary,
|
| ︙ | ︙ |
Changes to src/stat.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the stat web page ** */ | < > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to implement the stat web page
**
*/
#include "config.h"
#include <string.h>
#include "stat.h"
/*
** For a sufficiently large integer, provide an alternative
** representation as MB or GB or TB.
*/
static void bigSizeName(int nOut, char *zOut, sqlite3_int64 v){
|
| ︙ | ︙ | |||
53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
if( g.perm.Admin ){
style_submenu_element("URLs", "URLs and Checkouts", "urllist");
}
@ <table class="label-value">
@ <tr><th>Repository Size:</th><td>
fsize = file_size(g.zRepositoryName);
bigSizeName(sizeof(zBuf), zBuf, fsize);
@ %s(zBuf)
@ </td></tr>
| > | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
brief = P("brief")!=0;
style_header("Repository Statistics");
if( g.perm.Admin ){
style_submenu_element("URLs", "URLs and Checkouts", "urllist");
style_submenu_element("Schema", "Repository Schema", "repo_schema");
}
@ <table class="label-value">
@ <tr><th>Repository Size:</th><td>
fsize = file_size(g.zRepositoryName);
bigSizeName(sizeof(zBuf), zBuf, fsize);
@ %s(zBuf)
@ </td></tr>
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 |
@ %d(n) days or approximately %.2f(n/365.2425) years.
@ </td></tr>
@ <tr><th>Project ID:</th><td>%h(db_get("project-code",""))</td></tr>
@ <tr><th>Fossil Version:</th><td>
@ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
@ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
@ </td></tr>
| | > > > | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
@ %d(n) days or approximately %.2f(n/365.2425) years.
@ </td></tr>
@ <tr><th>Project ID:</th><td>%h(db_get("project-code",""))</td></tr>
@ <tr><th>Fossil Version:</th><td>
@ %h(MANIFEST_DATE) %h(MANIFEST_VERSION)
@ (%h(RELEASE_VERSION)) [compiled using %h(COMPILER_NAME)]
@ </td></tr>
@ <tr><th>SQLite Version:</th><td>%.19s(sqlite3_sourceid())
@ [%.10s(&sqlite3_sourceid()[20])] (%s(sqlite3_libversion()))</td></tr>
@ <tr><th>Repository Rebuilt:</th><td>
@ %h(db_get_mtime("rebuilt","%Y-%m-%d %H:%M:%S","Never"))
@ By Fossil %h(db_get("rebuilt","Unknown"))</td></tr>
@ <tr><th>Database Stats:</th><td>
zDb = db_name("repository");
@ %d(db_int(0, "PRAGMA %s.page_count", zDb)) pages,
@ %d(db_int(0, "PRAGMA %s.page_size", zDb)) bytes/page,
@ %d(db_int(0, "PRAGMA %s.freelist_count", zDb)) free pages,
@ %s(db_text(0, "PRAGMA %s.encoding", zDb)),
@ %s(db_text(0, "PRAGMA %s.journal_mode", zDb)) mode
|
| ︙ | ︙ | |||
218 219 220 221 222 223 224 |
fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
fossil_print("%*s%s %s [%s] (%s)\n",
colWidth, "fossil-version:",
MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
COMPILER_NAME);
fossil_print("%*s%.19s [%.10s] (%s)\n",
colWidth, "sqlite-version:",
| | | < < > | | > > > > > > > > > > > > > > > > > > > > > > > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code",""));
fossil_print("%*s%s %s [%s] (%s)\n",
colWidth, "fossil-version:",
MANIFEST_DATE, MANIFEST_VERSION, RELEASE_VERSION,
COMPILER_NAME);
fossil_print("%*s%.19s [%.10s] (%s)\n",
colWidth, "sqlite-version:",
sqlite3_sourceid(), &sqlite3_sourceid()[20],
sqlite3_libversion());
zDb = db_name("repository");
fossil_print("%*s%d pages, %d bytes/pg, %d free pages, "
"%s, %s mode\n",
colWidth, "database-stats:",
db_int(0, "PRAGMA %s.page_count", zDb),
db_int(0, "PRAGMA %s.page_size", zDb),
db_int(0, "PRAGMA %s.freelist_count", zDb),
db_text(0, "PRAGMA %s.encoding", zDb),
db_text(0, "PRAGMA %s.journal_mode", zDb));
}
/*
** WEBPAGE: urllist
**
** Show ways in which this repository has been accessed
*/
void urllist_page(void){
Stmt q;
int cnt;
login_check_credentials();
if( !g.perm.Admin ){ login_needed(); return; }
style_header("URLs and Checkouts");
style_submenu_element("Stat", "Repository Stats", "stat");
style_submenu_element("Schema", "Repository Schema", "repo_schema");
@ <div class="section">URLs</div>
@ <table border="0" width='100%%'>
db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch')"
" FROM config WHERE name GLOB 'baseurl:*' ORDER BY 2 DESC");
cnt = 0;
while( db_step(&q)==SQLITE_ROW ){
@ <tr><td width='100%%'>%h(db_column_text(&q,0))</td>
@ <td><nobr>%h(db_column_text(&q,1))</nobr></td></tr>
cnt++;
}
db_finalize(&q);
if( cnt==0 ){
@ <tr><td>(none)</td>
}
@ </table>
@ <div class="section">Checkouts</div>
@ <table border="0" width='100%%'>
db_prepare(&q, "SELECT substr(name,7), datetime(mtime,'unixepoch')"
" FROM config WHERE name GLOB 'ckout:*' ORDER BY 2 DESC");
cnt = 0;
while( db_step(&q)==SQLITE_ROW ){
@ <tr><td width='100%%'>%h(db_column_text(&q,0))</td>
@ <td><nobr>%h(db_column_text(&q,1))</nobr></td></tr>
cnt++;
}
db_finalize(&q);
if( cnt==0 ){
@ <tr><td>(none)</td>
}
@ </table>
style_footer();
}
/*
** WEBPAGE: repo_schema
**
** Show the repository schema
*/
void repo_schema_page(void){
Stmt q;
login_check_credentials();
if( !g.perm.Admin ){ login_needed(); return; }
style_header("Repository Schema");
style_submenu_element("Stat", "Repository Stats", "stat");
style_submenu_element("URLs", "URLs and Checkouts", "urllist");
db_prepare(&q, "SELECT sql FROM %s.sqlite_master WHERE sql IS NOT NULL",
db_name("repository"));
@ <pre>
while( db_step(&q)==SQLITE_ROW ){
@ %h(db_column_text(&q, 0));
}
@ </pre>
db_finalize(&q);
style_footer();
}
|
Changes to src/style.c.
| ︙ | ︙ | |||
67 68 69 70 71 72 73 | ** The form of the anchor tag is determined by the g.javascriptHyperlink ** variable. The href="URL" form is used if g.javascriptHyperlink is false. ** If g.javascriptHyperlink is true then the ** id="ID" form is used and javascript is generated in the footer to cause ** href values to be inserted after the page has loaded. If ** g.perm.History is false, then the <a id="ID"> form is still ** generated but the javascript is not generated so the links never | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | ** The form of the anchor tag is determined by the g.javascriptHyperlink ** variable. The href="URL" form is used if g.javascriptHyperlink is false. ** If g.javascriptHyperlink is true then the ** id="ID" form is used and javascript is generated in the footer to cause ** href values to be inserted after the page has loaded. If ** g.perm.History is false, then the <a id="ID"> form is still ** generated but the javascript is not generated so the links never ** activate. ** ** If the user lacks the Hyperlink (h) property and the "auto-hyperlink" ** setting is true, then g.perm.Hyperlink is changed from 0 to 1 and ** g.javascriptHyperlink is set to 1. The g.javascriptHyperlink defaults ** to 0 and only changes to one if the user lacks the Hyperlink (h) property ** and the "auto-hyperlink" setting is enabled. ** |
| ︙ | ︙ | |||
110 111 112 113 114 115 116 |
return zHUrl;
}
if( nHref>=nHrefAlloc ){
nHrefAlloc = nHrefAlloc*2 + 10;
aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
}
aHref[nHref++] = zUrl;
| | | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
return zHUrl;
}
if( nHref>=nHrefAlloc ){
nHrefAlloc = nHrefAlloc*2 + 10;
aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
}
aHref[nHref++] = zUrl;
return mprintf("<a %s id='a%d' href='%R/honeypot'>", zExtra, nHref);
}
char *href(const char *zFormat, ...){
char *zUrl;
va_list ap;
va_start(ap, zFormat);
zUrl = vmprintf(zFormat, ap);
va_end(ap);
if( g.perm.Hyperlink && !g.javascriptHyperlink ){
char *zHUrl = mprintf("<a href=\"%h\">", zUrl);
fossil_free(zUrl);
return zHUrl;
}
if( nHref>=nHrefAlloc ){
nHrefAlloc = nHrefAlloc*2 + 10;
aHref = fossil_realloc(aHref, nHrefAlloc*sizeof(aHref[0]));
}
aHref[nHref++] = zUrl;
return mprintf("<a id='a%d' href='%R/honeypot'>", nHref);
}
/*
** Generate <form method="post" action=ARG>. The ARG value is inserted
** by javascript.
*/
void form_begin(const char *zOtherArgs, const char *zAction, ...){
|
| ︙ | ︙ | |||
173 174 175 176 177 178 179 |
@ gebi("a%d(i+1)").href="%s(aHref[i])";
}
}
for(i=0; i<nFormAction; i++){
@ gebi("form%d(i+1)").action="%s(aFormAction[i])";
}
@ }
| > > > > > > > | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
@ gebi("a%d(i+1)").href="%s(aHref[i])";
}
}
for(i=0; i<nFormAction; i++){
@ gebi("form%d(i+1)").action="%s(aFormAction[i])";
}
@ }
if( strglob("*Opera Mini/[1-9]*", P("HTTP_USER_AGENT")) ){
/* Special case for Opera Mini, which executes JS server-side */
@ var isOperaMini = Object.prototype.toString.call(window.operamini)
@ === "[object OperaMini]";
@ if( isOperaMini ){
@ setTimeout("setAllHrefs();",%d(nDelay));
@ }
}else if( db_get_boolean("auto-hyperlink-mouseover",0) ){
/* Require mouse movement prior to activating hyperlinks */
@ document.getElementsByTagName("body")[0].onmousemove=function(){
@ setTimeout("setAllHrefs();",%d(nDelay));
@ this.onmousemove = null;
@ }
}else{
/* Active hyperlinks right away */
|
| ︙ | ︙ | |||
234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
}else{
va_list ap;
va_start(ap, zFormat);
local_zCurrentPage = vmprintf(zFormat, ap);
va_end(ap);
}
}
/*
** Draw the header.
*/
void style_header(const char *zTitleFormat, ...){
va_list ap;
char *zTitle;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
}else{
va_list ap;
va_start(ap, zFormat);
local_zCurrentPage = vmprintf(zFormat, ap);
va_end(ap);
}
}
/*
** Create a TH1 variable containing the URL for the specified config resource.
** The resulting variable name will be of the form $[zVarPrefix]_url.
*/
static void url_var(
const char *zVarPrefix,
const char *zConfigName,
const char *zPageName
){
char *zMtime = db_get_mtime(zConfigName, 0, 0);
char *zUrl = mprintf("%s/%s/%s%.5s", g.zTop, zPageName, zMtime,
MANIFEST_UUID);
char *zVarName = mprintf("%s_url", zVarPrefix);
Th_Store(zVarName, zUrl);
free(zMtime);
free(zUrl);
free(zVarName);
}
/*
** Create a TH1 variable containing the URL for the specified config image.
** The resulting variable name will be of the form $[zImageName]_image_url.
*/
static void image_url_var(const char *zImageName){
char *zVarPrefix = mprintf("%s_image", zImageName);
char *zConfigName = mprintf("%s-image", zImageName);
url_var(zVarPrefix, zConfigName, zImageName);
free(zVarPrefix);
free(zConfigName);
}
/*
** Draw the header.
*/
void style_header(const char *zTitleFormat, ...){
va_list ap;
char *zTitle;
|
| ︙ | ︙ | |||
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
/* Generate the header up through the main menu */
Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
Th_Store("title", zTitle);
Th_Store("baseurl", g.zBaseURL);
Th_Store("home", g.zTop);
Th_Store("index_page", db_get("index-page","/home"));
Th_Store("current_page", local_zCurrentPage ? local_zCurrentPage : g.zPath);
Th_Store("release_version", RELEASE_VERSION);
Th_Store("manifest_version", MANIFEST_VERSION);
Th_Store("manifest_date", MANIFEST_DATE);
Th_Store("compiler_name", COMPILER_NAME);
if( g.zLogin ){
Th_Store("login", g.zLogin);
}
if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1);
Th_Render(zHeader);
if( g.thTrace ) Th_Trace("END_HEADER<br />\n", -1);
Th_Unstore("title"); /* Avoid collisions with ticket field names */
| > > > > | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
/* Generate the header up through the main menu */
Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
Th_Store("title", zTitle);
Th_Store("baseurl", g.zBaseURL);
Th_Store("home", g.zTop);
Th_Store("index_page", db_get("index-page","/home"));
Th_Store("current_page", local_zCurrentPage ? local_zCurrentPage : g.zPath);
Th_Store("csrf_token", g.zCsrfToken);
Th_Store("release_version", RELEASE_VERSION);
Th_Store("manifest_version", MANIFEST_VERSION);
Th_Store("manifest_date", MANIFEST_DATE);
Th_Store("compiler_name", COMPILER_NAME);
url_var("stylesheet", "css", "style.css");
image_url_var("logo");
image_url_var("background");
if( g.zLogin ){
Th_Store("login", g.zLogin);
}
if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1);
Th_Render(zHeader);
if( g.thTrace ) Th_Trace("END_HEADER<br />\n", -1);
Th_Unstore("title"); /* Avoid collisions with ticket field names */
|
| ︙ | ︙ | |||
396 397 398 399 400 401 402 | const char zDefaultHeader[] = @ <html> @ <head> @ <base href="$baseurl/$current_page" /> @ <title>$<project_name>: $<title></title> @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" @ href="$home/timeline.rss" /> | | | | | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
const char zDefaultHeader[] =
@ <html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@ href="$home/timeline.rss" />
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@ media="screen" />
@ </head>
@ <body>
@ <div class="header">
@ <div class="logo">
@ <img src="$logo_image_url" alt="logo" />
@ </div>
@ <div class="title"><small>$<project_name></small><br />$<title></div>
@ <div class="status"><th1>
@ if {[info exists login]} {
@ puts "Logged in as $login"
@ } else {
@ puts "Not logged in"
@ }
@ </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href='$home$index_page'>Home</a>\n"
@ if {[anycap jor]} {
@ html "<a href='$home/timeline'>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@ html "<a href='$home/tree?ci=tip'>Files</a>\n"
@ }
@ if {[hascap o]} {
@ html "<a href='$home/brlist'>Branches</a>\n"
@ html "<a href='$home/taglist'>Tags</a>\n"
@ }
@ if {[hascap r]} {
@ html "<a href='$home/reportlist'>Tickets</a>\n"
|
| ︙ | ︙ | |||
460 461 462 463 464 465 466 | @ </div> @ </body></html> ; /* ** The default Cascading Style Sheet. ** It's assembled by different strings for each class. | | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
@ </div>
@ </body></html>
;
/*
** The default Cascading Style Sheet.
** It's assembled by different strings for each class.
** The default css contains all definitions.
** The style sheet, send to the client only contains the ones,
** not defined in the user defined css.
*/
const char zDefaultCSS[] =
@ /* General settings for the entire page */
@ body {
@ margin: 0ex 1ex;
|
| ︙ | ︙ | |||
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
@ border: 0;
},
{ "td.timelineTableCell",
"the format for the timeline data cells",
@ vertical-align: top;
@ text-align: left;
},
{ "span.timelineLeaf",
"the format for the timeline leaf marks",
@ font-weight: bold;
},
{ "a.timelineHistLink",
"the format for the timeline version links",
@
},
{ "span.timelineHistDsp",
"the format for the timeline version display(no history permission!)",
@ font-weight: bold;
},
{ "td.timelineTime",
"the format for the timeline time display",
@ vertical-align: top;
@ text-align: right;
},
{ "td.timelineGraph",
"the format for the grap placeholder cells in timelines",
@ width: 20px;
@ text-align: left;
@ vertical-align: top;
},
| > > > > > > | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
@ border: 0;
},
{ "td.timelineTableCell",
"the format for the timeline data cells",
@ vertical-align: top;
@ text-align: left;
},
{ "tr.timelineCurrent td.timelineTableCell",
"the format for the timeline data cell of the current checkout",
@ padding: .1em .2em;
@ border: 1px dashed #446979;
},
{ "span.timelineLeaf",
"the format for the timeline leaf marks",
@ font-weight: bold;
},
{ "a.timelineHistLink",
"the format for the timeline version links",
@
},
{ "span.timelineHistDsp",
"the format for the timeline version display(no history permission!)",
@ font-weight: bold;
},
{ "td.timelineTime",
"the format for the timeline time display",
@ vertical-align: top;
@ text-align: right;
@ white-space: nowrap;
},
{ "td.timelineGraph",
"the format for the grap placeholder cells in timelines",
@ width: 20px;
@ text-align: left;
@ vertical-align: top;
},
|
| ︙ | ︙ | |||
721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
},
{ "ul.browser",
"format for the list in the file browser",
@ margin-left: 0.5em;
@ padding-left: 0.5em;
@ white-space: nowrap;
},
{ "table.login_out",
"table format for login/out label/input table",
@ text-align: left;
@ margin-right: 10px;
@ margin-left: 10px;
@ margin-top: 10px;
},
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 |
},
{ "ul.browser",
"format for the list in the file browser",
@ margin-left: 0.5em;
@ padding-left: 0.5em;
@ white-space: nowrap;
},
{ ".filetree",
"tree-view file browser",
@ margin: 1em 0;
@ line-height: 1.5;
},
{ ".filetree ul",
"tree-view lists",
@ margin: 0;
@ padding: 0;
@ list-style: none;
},
{ ".filetree ul.collapsed",
"tree-view collapsed list",
@ display: none;
},
{ ".filetree ul ul",
"tree-view lists below the root",
@ position: relative;
@ margin: 0 0 0 21px;
},
{ ".filetree li",
"tree-view lists items",
@ position: relative;
},
{ ".filetree li li:before",
"tree-view node lines",
@ content: '';
@ position: absolute;
@ top: -.8em;
@ left: -14px;
@ width: 14px;
@ height: 1.5em;
@ border-left: 2px solid #aaa;
@ border-bottom: 2px solid #aaa;
},
{ ".filetree li > ul:before",
"tree-view directory lines",
@ content: '';
@ position: absolute;
@ top: -1.5em;
@ bottom: 0;
@ left: -35px;
@ border-left: 2px solid #aaa;
},
{ ".filetree li.last > ul:before",
"hide lines for last-child directories",
@ display: none;
},
{ ".filetree a",
"tree-view links",
@ position: relative;
@ z-index: 1;
@ display: inline-block;
@ min-height: 16px;
@ padding-left: 21px;
@ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP\/\/\/yEhIf\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAIvlIKpxqcfmgOUvoaqDSCxrEEfF14GqFXImJZsu73wepJzVMNxrtNTj3NATMKhpwAAOw==);
@ background-position: center left;
@ background-repeat: no-repeat;
},
{ ".filetree .dir > a",
"tree-view directory links",
@ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=);
},
{ "table.login_out",
"table format for login/out label/input table",
@ text-align: left;
@ margin-right: 10px;
@ margin-left: 10px;
@ margin-top: 10px;
},
|
| ︙ | ︙ | |||
963 964 965 966 967 968 969 |
@ color: red;
},
{ "ul.filelist",
"List of files in a timeline",
@ margin-top: 3px;
@ line-height: 100%;
},
| | | | > > > > | > | | > > > | > > > > > > > > > > > | > > > > > > > | 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 |
@ color: red;
},
{ "ul.filelist",
"List of files in a timeline",
@ margin-top: 3px;
@ line-height: 100%;
},
{ "table.sbsdiffcols",
"side-by-side diff display (column-based)",
@ width: 90%;
@ border-spacing: 0;
@ font-size: xx-small;
},
{ "table.sbsdiffcols td",
"sbs diff table cell",
@ padding: 0;
@ vertical-align: top;
},
{ "table.sbsdiffcols pre",
"sbs diff pre block",
@ margin: 0;
@ padding: 0;
@ border: 0;
@ font-size: inherit;
@ background: inherit;
@ color: inherit;
},
{ "div.difflncol",
"diff line number column",
@ padding-right: 1em;
@ text-align: right;
@ color: #a0a0a0;
},
{ "div.difftxtcol",
"diff text column",
@ width: 45em;
@ overflow-x: auto;
},
{ "div.diffmkrcol",
"diff marker column",
@ padding: 0 1em;
},
{ "span.diffchng",
"changes in a diff",
@ background-color: #c0c0ff;
},
{ "span.diffadd",
"added code in a diff",
@ background-color: #c0ffc0;
},
{ "span.diffrm",
"deleted in a diff",
@ background-color: #ffc8c8;
},
{ "span.diffhr",
"suppressed lines in a diff",
@ display: inline-block;
@ margin: .5em 0 1em;
@ color: #0000ff;
},
{ "span.diffln",
"line numbers in a diff",
@ color: #a0a0a0;
},
{ "span.modpending",
|
| ︙ | ︙ | |||
1020 1021 1022 1023 1024 1025 1026 |
@ text-align: right;
@ padding: 0.2ex 2ex;
},
{ ".statistics-report-graph-line",
"for the /stats_report views",
@ background-color: #446979;
},
| | > > > > > > > > > > > > > > > > > | | | | | | | 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 |
@ text-align: right;
@ padding: 0.2ex 2ex;
},
{ ".statistics-report-graph-line",
"for the /stats_report views",
@ background-color: #446979;
},
{ ".statistics-report-table-events th",
"",
@ padding: 0 1em 0 1em;
},
{ ".statistics-report-table-events td",
"",
@ padding: 0.1em 1em 0.1em 1em;
},
{ ".statistics-report-row-year",
"",
@ text-align: left;
},
{ ".statistics-report-graph-line",
"for the /stats_report views",
@ background-color: #446979;
},
{ ".statistics-report-week-number-label",
"for the /stats_report views",
@ text-align: right;
@ font-size: 0.8em;
},
{ ".statistics-report-week-of-year-list",
"for the /stats_report views",
@ font-size: 0.8em;
},
{ "tr.row0",
"even table row color",
@ /* use default */
},
{ "tr.row1",
"odd table row color",
@ /* Use default */
},
{ "#canvas", "timeline graph node colors",
@ color: black;
@ background-color: white;
},
{ 0,
0,
0
}
};
/*
** Append all of the default CSS to the CGI output.
*/
void cgi_append_default_css(void) {
int i;
for (i=0;cssDefaultList[i].elementClass;i++){
if (cssDefaultList[i].elementClass[0]){
cgi_printf("/* %s */\n%s {\n%s\n}\n\n",
cssDefaultList[i].comment,
cssDefaultList[i].elementClass,
cssDefaultList[i].value
);
}else{
cgi_printf("%s",
cssDefaultList[i].value
);
}
}
}
/*
** WEBPAGE: style.css
*/
|
| ︙ | ︙ | |||
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 |
}
/* Process through TH1 in order to give an opportunity to substitute
** variables such as $baseurl.
*/
Th_Store("baseurl", g.zBaseURL);
Th_Store("home", g.zTop);
Th_Render(blob_str(&css));
/* Tell CGI that the content returned by this page is considered cacheable */
g.isConst = 1;
}
/*
** WEBPAGE: test_env
*/
void page_test_env(void){
char c;
int i;
int showAll;
char zCap[30];
login_check_credentials();
if( !g.perm.Admin && !g.perm.Setup && !db_get_boolean("test_env_enable",0) ){
login_needed();
return;
}
style_header("Environment Test");
showAll = atoi(PD("showall","0"));
if( !showAll ){
style_submenu_element("Show Cookies", "Show Cookies",
"%s/test_env?showall=1", g.zTop);
}else{
style_submenu_element("Hide Cookies", "Hide Cookies",
"%s/test_env", g.zTop);
}
#if !defined(_WIN32)
@ uid=%d(getuid()), gid=%d(getgid())<br />
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br />
@ g.zTop = %h(g.zTop)<br />
for(i=0, c='a'; c<='z'; c++){
if( login_has_capability(&c, 1) ) zCap[i++] = c;
}
zCap[i] = 0;
@ g.userUid = %d(g.userUid)<br />
@ g.zLogin = %h(g.zLogin)<br />
@ capabilities = %s(zCap)<br />
@ <hr>
P("HTTP_USER_AGENT");
| > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > | 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 |
}
/* Process through TH1 in order to give an opportunity to substitute
** variables such as $baseurl.
*/
Th_Store("baseurl", g.zBaseURL);
Th_Store("home", g.zTop);
image_url_var("logo");
image_url_var("background");
Th_Render(blob_str(&css));
/* Tell CGI that the content returned by this page is considered cacheable */
g.isConst = 1;
}
/*
** WEBPAGE: test_env
*/
void page_test_env(void){
char c;
int i;
int showAll;
char zCap[30];
static const char *const azCgiVars[] = {
"COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",
"HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING",
"HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST",
"HTTP_USER_AGENT", "HTTP_REFERER", "PATH_INFO", "PATH_TRANSLATED",
"QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", "REQUEST_METHOD",
"REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_PROTOCOL",
};
login_check_credentials();
if( !g.perm.Admin && !g.perm.Setup && !db_get_boolean("test_env_enable",0) ){
login_needed();
return;
}
for(i=0; i<count(azCgiVars); i++) (void)P(azCgiVars[i]);
style_header("Environment Test");
showAll = atoi(PD("showall","0"));
if( !showAll ){
style_submenu_element("Show Cookies", "Show Cookies",
"%s/test_env?showall=1", g.zTop);
}else{
style_submenu_element("Hide Cookies", "Hide Cookies",
"%s/test_env", g.zTop);
}
#if !defined(_WIN32)
@ uid=%d(getuid()), gid=%d(getgid())<br />
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br />
@ g.zTop = %h(g.zTop)<br />
for(i=0, c='a'; c<='z'; c++){
if( login_has_capability(&c, 1) ) zCap[i++] = c;
}
zCap[i] = 0;
@ g.userUid = %d(g.userUid)<br />
@ g.zLogin = %h(g.zLogin)<br />
@ g.isHuman = %d(g.isHuman)<br />
@ capabilities = %s(zCap)<br />
@ <hr>
P("HTTP_USER_AGENT");
cgi_print_all(showAll);
if( showAll && blob_size(&g.httpHeader)>0 ){
@ <hr>
@ <pre>
@ %h(blob_str(&g.httpHeader))
@ </pre>
}
if( g.perm.Setup ){
const char *zRedir = P("redirect");
if( zRedir ) cgi_redirect(zRedir);
}
style_footer();
if( g.perm.Admin && P("err") ) fossil_fatal("%s", P("err"));
}
/*
** This page is a honeypot for spiders and bots.
**
** WEBPAGE: honeypot
*/
void honeypot_page(void){
cgi_set_status(403, "Forbidden");
@ <p>Please enable javascript or log in to see this content</p>
}
|
Changes to src/sync.c.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
}else{
/* Autosync defaults on. To make it default off, "return" here. */
}
url_parse(0, URL_REMEMBER);
if( g.urlProtocol==0 ) return 0;
if( g.urlUser!=0 && g.urlPasswd==0 ){
g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
}
#if 0 /* Disabled for now */
if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
/* When doing an automatic pull, also automatically pull shuns from
** the server if pull_shuns is enabled.
**
** TODO: What happens if the shun list gets really big?
** Maybe the shunning list should only be pulled on every 10th
| > > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
}else{
/* Autosync defaults on. To make it default off, "return" here. */
}
url_parse(0, URL_REMEMBER);
if( g.urlProtocol==0 ) return 0;
if( g.urlUser!=0 && g.urlPasswd==0 ){
g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
g.urlFlags |= URL_PROMPT_PW;
url_prompt_for_password();
}
url_remember();
#if 0 /* Disabled for now */
if( (flags & AUTOSYNC_PULL)!=0 && db_get_boolean("auto-shun",1) ){
/* When doing an automatic pull, also automatically pull shuns from
** the server if pull_shuns is enabled.
**
** TODO: What happens if the shun list gets really big?
** Maybe the shunning list should only be pulled on every 10th
|
| ︙ | ︙ | |||
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
if( find_option("private",0,0)!=0 ){
*pSyncFlags |= SYNC_PRIVATE;
}
if( find_option("verbose","v",0)!=0 ){
*pSyncFlags |= SYNC_VERBOSE;
}
url_proxy_options();
db_find_and_open_repository(0, 0);
db_open_config(0);
if( g.argc==2 ){
if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
}else if( g.argc==3 ){
zUrl = g.argv[2];
}
url_parse(zUrl, urlFlags);
if( g.urlProtocol==0 ){
if( urlOptional ) fossil_exit(0);
usage("URL");
}
user_select();
if( g.argc==2 ){
if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
| > > > > > > > > > > > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
if( find_option("once",0,0)!=0 ) urlFlags &= ~URL_REMEMBER;
if( find_option("private",0,0)!=0 ){
*pSyncFlags |= SYNC_PRIVATE;
}
if( find_option("verbose","v",0)!=0 ){
*pSyncFlags |= SYNC_VERBOSE;
}
/* The --verily option to sync, push, and pull forces extra igot cards
** to be exchanged. This can overcome malfunctions in the sync protocol.
*/
if( find_option("verily",0,0)!=0 ){
*pSyncFlags |= SYNC_RESYNC;
}
url_proxy_options();
clone_ssh_find_options();
db_find_and_open_repository(0, 0);
db_open_config(0);
if( g.argc==2 ){
if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN;
}else if( g.argc==3 ){
zUrl = g.argv[2];
}
if( urlFlags & URL_REMEMBER ){
clone_ssh_db_set_options();
}
url_parse(zUrl, urlFlags);
url_remember();
if( g.urlProtocol==0 ){
if( urlOptional ) fossil_exit(0);
usage("URL");
}
user_select();
if( g.argc==2 ){
if( ((*pSyncFlags) & (SYNC_PUSH|SYNC_PULL))==(SYNC_PUSH|SYNC_PULL) ){
|
| ︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 | ** COMMAND: pull ** ** Usage: %fossil pull ?URL? ?options? ** ** Pull changes from a remote repository into the local repository. ** Use the "-R REPO" or "--repository REPO" command-line options ** to specify an alternative repository file. ** ** If the URL is not specified, then the URL from the most recent ** clone, push, pull, remote-url, or sync command is used. ** ** The URL specified normally becomes the new "remote-url" used for ** subsequent push, pull, and sync operations. However, the "--once" ** command-line option makes the URL a one-time-use URL that is not | > > | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | ** COMMAND: pull ** ** Usage: %fossil pull ?URL? ?options? ** ** Pull changes from a remote repository into the local repository. ** Use the "-R REPO" or "--repository REPO" command-line options ** to specify an alternative repository file. ** ** See clone usage for possible URL formats. ** ** If the URL is not specified, then the URL from the most recent ** clone, push, pull, remote-url, or sync command is used. ** ** The URL specified normally becomes the new "remote-url" used for ** subsequent push, pull, and sync operations. However, the "--once" ** command-line option makes the URL a one-time-use URL that is not |
| ︙ | ︙ | |||
156 157 158 159 160 161 162 163 164 165 166 167 168 169 | ** COMMAND: push ** ** Usage: %fossil push ?URL? ?options? ** ** Push changes in the local repository over into a remote repository. ** Use the "-R REPO" or "--repository REPO" command-line options ** to specify an alternative repository file. ** ** If the URL is not specified, then the URL from the most recent ** clone, push, pull, remote-url, or sync command is used. ** ** The URL specified normally becomes the new "remote-url" used for ** subsequent push, pull, and sync operations. However, the "--once" ** command-line option makes the URL a one-time-use URL that is not | > > | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | ** COMMAND: push ** ** Usage: %fossil push ?URL? ?options? ** ** Push changes in the local repository over into a remote repository. ** Use the "-R REPO" or "--repository REPO" command-line options ** to specify an alternative repository file. ** ** See clone usage for possible URL formats. ** ** If the URL is not specified, then the URL from the most recent ** clone, push, pull, remote-url, or sync command is used. ** ** The URL specified normally becomes the new "remote-url" used for ** subsequent push, pull, and sync operations. However, the "--once" ** command-line option makes the URL a one-time-use URL that is not |
| ︙ | ︙ | |||
191 192 193 194 195 196 197 | ** Usage: %fossil sync ?URL? ?options? ** ** Synchronize the local repository with a remote repository. This is ** the equivalent of running both "push" and "pull" at the same time. ** Use the "-R REPO" or "--repository REPO" command-line options ** to specify an alternative repository file. ** | | < < | | | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | ** Usage: %fossil sync ?URL? ?options? ** ** Synchronize the local repository with a remote repository. This is ** the equivalent of running both "push" and "pull" at the same time. ** Use the "-R REPO" or "--repository REPO" command-line options ** to specify an alternative repository file. ** ** See clone usage for possible URL formats. ** ** If the URL is not specified, then the URL from the most recent ** successful clone, push, pull, remote-url, or sync command is used. ** ** The URL specified normally becomes the new "remote-url" used for ** subsequent push, pull, and sync operations. However, the "--once" ** command-line option makes the URL a one-time-use URL that is not ** saved. ** ** Use the --private option to sync private branches with the |
| ︙ | ︙ | |||
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
** and "sync" commands.
**
** The remote-url is set automatically by a "clone" command or by any
** "sync", "push", or "pull" command that specifies an explicit URL.
** The default remote-url is used by auto-syncing and by "sync", "push",
** "pull" that omit the server URL.
**
** See also: clone, push, pull, sync
*/
void remote_url_cmd(void){
char *zUrl;
db_find_and_open_repository(0, 0);
if( g.argc!=2 && g.argc!=3 ){
usage("remote-url ?URL|off?");
}
if( g.argc==3 ){
db_unset("last-sync-url", 0);
db_unset("last-sync-pw", 0);
if( is_false(g.argv[2]) ) return;
| > > | > | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
** and "sync" commands.
**
** The remote-url is set automatically by a "clone" command or by any
** "sync", "push", or "pull" command that specifies an explicit URL.
** The default remote-url is used by auto-syncing and by "sync", "push",
** "pull" that omit the server URL.
**
** See clone usage for possible URL formats.
**
** See also: clone, push, pull, sync
*/
void remote_url_cmd(void){
char *zUrl;
db_find_and_open_repository(0, 0);
if( g.argc!=2 && g.argc!=3 ){
usage("remote-url ?URL|off?");
}
if( g.argc==3 ){
db_unset("last-sync-url", 0);
db_unset("last-sync-pw", 0);
if( is_false(g.argv[2]) ) return;
url_parse(g.argv[2], URL_REMEMBER|URL_PROMPT_PW|URL_ASK_REMEMBER_PW);
}
url_remember();
zUrl = db_get("last-sync-url", 0);
if( zUrl==0 ){
fossil_print("off\n");
return;
}else{
url_parse(zUrl, 0);
fossil_print("%s\n", g.urlCanonical);
}
}
|
Changes to src/tag.c.
| ︙ | ︙ | |||
324 325 326 327 328 329 330 |
}else{
blob_appendf(&ctrl, "\n");
}
blob_appendf(&ctrl, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
md5sum_blob(&ctrl, &cksum);
blob_appendf(&ctrl, "Z %b\n", &cksum);
nrid = content_put(&ctrl);
| | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
}else{
blob_appendf(&ctrl, "\n");
}
blob_appendf(&ctrl, "U %F\n", zUserOvrd ? zUserOvrd : g.zLogin);
md5sum_blob(&ctrl, &cksum);
blob_appendf(&ctrl, "Z %b\n", &cksum);
nrid = content_put(&ctrl);
manifest_crosslink(nrid, &ctrl, MC_PERMIT_HOOKS);
assert( blob_is_reset(&ctrl) );
}
/*
** COMMAND: tag
** Usage: %fossil tag SUBCOMMAND ...
**
|
| ︙ | ︙ | |||
346 347 348 349 350 351 352 | ** the tag value propagates to all descendants of CHECK-IN ** ** %fossil tag cancel ?--raw? TAGNAME CHECK-IN ** ** Remove the tag TAGNAME from CHECK-IN, and also remove ** the propagation of the tag to any descendants. ** | | | > | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | ** the tag value propagates to all descendants of CHECK-IN ** ** %fossil tag cancel ?--raw? TAGNAME CHECK-IN ** ** Remove the tag TAGNAME from CHECK-IN, and also remove ** the propagation of the tag to any descendants. ** ** %fossil tag find ?--raw? ?-t|--type TYPE? ?-n|--limit #? TAGNAME ** ** List all objects that use TAGNAME. TYPE can be "ci" for ** checkins or "e" for events. The limit option limits the number ** of results to the given value. ** ** %fossil tag list ?--raw? ?CHECK-IN? ** ** List all tags, or if CHECK-IN is supplied, list ** all tags and their values for CHECK-IN. ** ** The option --raw allows the manipulation of all types of tags |
| ︙ | ︙ | |||
385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
** in order to import history from other scm systems
*/
void tag_cmd(void){
int n;
int fRaw = find_option("raw","",0)!=0;
int fPropagate = find_option("propagate","",0)!=0;
const char *zPrefix = fRaw ? "" : "sym-";
db_find_and_open_repository(0, 0);
if( g.argc<3 ){
goto tag_cmd_usage;
}
n = strlen(g.argv[2]);
if( n==0 ){
| > > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
** in order to import history from other scm systems
*/
void tag_cmd(void){
int n;
int fRaw = find_option("raw","",0)!=0;
int fPropagate = find_option("propagate","",0)!=0;
const char *zPrefix = fRaw ? "" : "sym-";
char const * zFindLimit = find_option("limit","n",1);
int const nFindLimit = zFindLimit ? atoi(zFindLimit) : -2000;
db_find_and_open_repository(0, 0);
if( g.argc<3 ){
goto tag_cmd_usage;
}
n = strlen(g.argv[2]);
if( n==0 ){
|
| ︙ | ︙ | |||
426 427 428 429 430 431 432 433 434 |
tag_add_artifact(zPrefix, g.argv[3], g.argv[4], 0, 0, 0, 0);
db_end_transaction(0);
}else
if( strncmp(g.argv[2],"find",n)==0 ){
Stmt q;
const char *zType = find_option("type","t",1);
if( zType==0 || zType[0]==0 ) zType = "*";
if( g.argc!=4 ){
| > | | > > > > > | > > | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 |
tag_add_artifact(zPrefix, g.argv[3], g.argv[4], 0, 0, 0, 0);
db_end_transaction(0);
}else
if( strncmp(g.argv[2],"find",n)==0 ){
Stmt q;
const char *zType = find_option("type","t",1);
Blob sql = empty_blob;
if( zType==0 || zType[0]==0 ) zType = "*";
if( g.argc!=4 ){
usage("find ?--raw? ?-t|--type TYPE? ?-n|--limit #? TAGNAME");
}
if( fRaw ){
blob_appendf(&sql,
"SELECT blob.uuid FROM tagxref, blob"
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
" AND tagxref.tagtype>0"
" AND blob.rid=tagxref.rid",
g.argv[3]
);
if( nFindLimit>0 ){
blob_appendf(&sql, " LIMIT %d", nFindLimit);
}
db_prepare(&q, "%s", blob_str(&sql));
blob_reset(&sql);
while( db_step(&q)==SQLITE_ROW ){
fossil_print("%s\n", db_column_text(&q, 0));
}
db_finalize(&q);
}else{
int tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",
g.argv[3]);
if( tagid>0 ){
blob_appendf(&sql,
"%s"
" AND event.type GLOB '%q'"
" AND blob.rid IN ("
" SELECT rid FROM tagxref"
" WHERE tagtype>0 AND tagid=%d"
")"
" ORDER BY event.mtime DESC",
timeline_query_for_tty(), zType, tagid
);
db_prepare(&q, "%s", blob_str(&sql));
blob_reset(&sql);
print_timeline(&q, nFindLimit, 79, 0);
db_finalize(&q);
}
}
}else
if( strncmp(g.argv[2],"list",n)==0 ){
Stmt q;
|
| ︙ | ︙ |
Changes to src/tar.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to generate tarballs. */ #include <assert.h> #include <zlib.h> | > < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to generate tarballs.
*/
#include "config.h"
#include <assert.h>
#include <zlib.h>
#include "tar.h"
/*
** State information for the tarball builder.
*/
static struct tarball_t {
unsigned char *aHdr; /* Space for building headers */
|
| ︙ | ︙ | |||
334 335 336 337 338 339 340 |
const char *zName, /* Name of directory including final "/" */
int nName, /* Characters in zName */
unsigned int mTime /* Modification time */
){
int i;
for(i=nName-1; i>0 && zName[i]!='/'; i--){}
if( i<=0 ) return;
| | | > | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
const char *zName, /* Name of directory including final "/" */
int nName, /* Characters in zName */
unsigned int mTime /* Modification time */
){
int i;
for(i=nName-1; i>0 && zName[i]!='/'; i--){}
if( i<=0 ) return;
if( i<tball.nPrevDirAlloc
&& strncmp(tball.zPrevDir, zName, i)==0
&& tball.zPrevDir[i]==0 ) return;
db_multi_exec("INSERT OR IGNORE INTO dir VALUES('%#q')", i, zName);
if( sqlite3_changes(g.db)==0 ) return;
tar_add_directory_of(zName, i-1, mTime);
tar_add_header(zName, i, 0755, mTime, 0, '5');
if( i >= tball.nPrevDirAlloc ){
int nsize = tball.nPrevDirAlloc * 2;
if(i+1 > nsize)
|
| ︙ | ︙ | |||
425 426 427 428 429 430 431 |
int i;
Blob zip;
Blob file;
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
sqlite3_open(":memory:", &g.db);
| | | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 |
int i;
Blob zip;
Blob file;
if( g.argc<3 ){
usage("ARCHIVE FILE....");
}
sqlite3_open(":memory:", &g.db);
tar_begin(-1);
for(i=3; i<g.argc; i++){
blob_zero(&file);
blob_read_from_file(&file, g.argv[i]);
tar_add_file(g.argv[i], &file,
file_wd_perm(g.argv[i]), file_wd_mtime(g.argv[i]));
blob_reset(&file);
}
|
| ︙ | ︙ | |||
477 478 479 480 481 482 483 |
blob_zero(&filename);
if( zDir && zDir[0] ){
blob_appendf(&filename, "%s/", zDir);
}
nPrefix = blob_size(&filename);
| | | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
blob_zero(&filename);
if( zDir && zDir[0] ){
blob_appendf(&filename, "%s/", zDir);
}
nPrefix = blob_size(&filename);
pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( pManifest ){
mTime = (pManifest->rDate - 2440587.5)*86400.0;
tar_begin(mTime);
if( db_get_boolean("manifest", 0) ){
blob_append(&filename, "manifest", -1);
zName = blob_str(&filename);
tar_add_file(zName, &mfile, 0, mTime);
|
| ︙ | ︙ |
Changes to src/th.c.
1 2 | /* | | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/*
** The implementation of the TH core. This file contains the parser, and
** the implementation of the interface in th.h.
*/
#include "config.h"
#include "th.h"
#include <string.h>
#include <assert.h>
typedef struct Th_Command Th_Command;
typedef struct Th_Frame Th_Frame;
typedef struct Th_Variable Th_Variable;
/*
** Interpreter structure.
*/
struct Th_Interp {
Th_Vtab *pVtab; /* Copy of the argument passed to Th_CreateInterp() */
char *zResult; /* Current interpreter result (Th_Malloc()ed) */
int nResult; /* number of bytes in zResult */
Th_Hash *paCmd; /* Table of registered commands */
Th_Frame *pFrame; /* Current execution frame */
int isListMode; /* True if thSplitList() should operate in "list" mode */
};
/*
|
| ︙ | ︙ | |||
39 40 41 42 43 44 45 | ** Each stack frame (variable scope) is represented by an instance ** of this structure. Variable values set using the Th_SetVar command ** are stored in the Th_Frame.paVar hash table member of the associated ** stack frame object. ** ** When an interpreter is created, a single Th_Frame structure is also ** allocated - the global variable scope. Th_Interp.pFrame (the current | | | | | | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
** Each stack frame (variable scope) is represented by an instance
** of this structure. Variable values set using the Th_SetVar command
** are stored in the Th_Frame.paVar hash table member of the associated
** stack frame object.
**
** When an interpreter is created, a single Th_Frame structure is also
** allocated - the global variable scope. Th_Interp.pFrame (the current
** interpreter frame) is initialised to point to this Th_Frame. It is
** not deleted for the lifetime of the interpreter (because the global
** frame never goes out of scope).
**
** New stack frames are created by the Th_InFrame() function. Before
** invoking its callback function, Th_InFrame() allocates a new Th_Frame
** structure with pCaller set to the current frame (Th_Interp.pFrame),
** and sets the current frame to the new frame object. After the callback
** has been invoked, the allocated Th_Frame is deleted and the value
** of the current frame pointer restored.
**
** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions
** access variable values in the current frame. If they need to access
** the global frame, they do so by traversing the pCaller pointer list.
** Likewise, the Th_LinkVar() function uses the pCaller pointers to
** link to variables located in the global or other stack frames.
*/
struct Th_Frame {
Th_Hash *paVar; /* Variables defined in this scope */
Th_Frame *pCaller; /* Calling frame */
};
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
** a hash table mapping between array key name (a th1 string) and
** a pointer to the Th_Variable structure holding the scalar
** value.
*/
struct Th_Variable {
int nRef; /* Number of references to this structure */
int nData; /* Number of bytes at Th_Variable.zData */
| | | | | | | | | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
** a hash table mapping between array key name (a th1 string) and
** a pointer to the Th_Variable structure holding the scalar
** value.
*/
struct Th_Variable {
int nRef; /* Number of references to this structure */
int nData; /* Number of bytes at Th_Variable.zData */
char *zData; /* Data for scalar variables */
Th_Hash *pHash; /* Data for array variables */
};
/*
** Hash table API:
*/
#define TH_HASHSIZE 257
struct Th_Hash {
Th_HashEntry *a[TH_HASHSIZE];
};
static int thEvalLocal(Th_Interp *, const char *, int);
static int thSplitList(Th_Interp*, const char*, int, char***, int **, int*);
static int thHexdigit(char c);
static int thEndOfLine(const char *, int);
static int thPushFrame(Th_Interp*, Th_Frame*);
static void thPopFrame(Th_Interp*);
static int thFreeVariable(Th_HashEntry*, void*);
static int thFreeCommand(Th_HashEntry*, void*);
/*
** The following are used by both the expression and language parsers.
** Given that the start of the input string (z, n) is a language
** construct of the relevant type (a command enclosed in [], an escape
** sequence etc.), these functions determine the number of bytes
** of the input consumed by the construct. For example:
**
** int nByte;
** thNextCommand(interp, "[expr $a+1] $nIter", 18, &nByte);
**
** results in variable nByte being set to 11. Or,
**
** thNextVarname(interp, "$a+1", 4, &nByte);
**
** results in nByte being set to 2.
*/
static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
/*
** Given that the input string (z, n) contains a language construct of
** the relevant type (a command enclosed in [], an escape sequence
** like "\xFF" or a variable reference like "${varname}", perform
** substitution on the string and store the resulting string in
** the interpreter result.
*/
static int thSubstCommand(Th_Interp*, const char *z, int n);
static int thSubstEscape (Th_Interp*, const char *z, int n);
static int thSubstVarname(Th_Interp*, const char *z, int n);
/*
** Given that there is a th1 word located at the start of the input
** string (z, n), determine the length in bytes of that word. If the
** isCmd argument is non-zero, then an unescaped ";" byte not
** located inside of a block or quoted string is considered to mark
** the end of the word.
*/
static int thNextWord(Th_Interp*, const char *z, int n, int *pN, int isCmd);
/*
** Perform substitution on the word contained in the input string (z, n).
** Store the resulting string in the interpreter result.
|
| ︙ | ︙ | |||
173 174 175 176 177 178 179 | /* ** Append nAdd bytes of content copied from zAdd to the end of buffer ** pBuffer. If there is not enough space currently allocated, resize ** the allocation to make space. */ static int thBufferWrite( | | | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
/*
** Append nAdd bytes of content copied from zAdd to the end of buffer
** pBuffer. If there is not enough space currently allocated, resize
** the allocation to make space.
*/
static int thBufferWrite(
Th_Interp *interp,
Buffer *pBuffer,
const char *zAdd,
int nAdd
){
int nReq;
if( nAdd<0 ){
nAdd = th_strlen(zAdd);
}
|
| ︙ | ︙ | |||
255 256 257 258 259 260 261 262 | /* ** Argument pEntry points to an entry in a stack frame hash table ** (Th_Frame.paVar). Decrement the reference count of the Th_Variable ** structure that the entry points to. Free the Th_Variable if its ** reference count reaches 0. ** ** Argument pContext is a pointer to the interpreter structure. */ | > > | > > > > > | > | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
/*
** Argument pEntry points to an entry in a stack frame hash table
** (Th_Frame.paVar). Decrement the reference count of the Th_Variable
** structure that the entry points to. Free the Th_Variable if its
** reference count reaches 0.
**
** Argument pContext is a pointer to the interpreter structure.
**
** Returns non-zero if the Th_Variable was actually freed.
*/
static int thFreeVariable(Th_HashEntry *pEntry, void *pContext){
Th_Variable *pValue = (Th_Variable *)pEntry->pData;
pValue->nRef--;
assert( pValue->nRef>=0 );
if( pValue->nRef==0 ){
Th_Interp *interp = (Th_Interp *)pContext;
Th_Free(interp, pValue->zData);
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext);
Th_HashDelete(interp, pValue->pHash);
}
Th_Free(interp, pValue);
pEntry->pData = 0;
return 1;
}
return 0;
}
/*
** Argument pEntry points to an entry in the command hash table
** (Th_Interp.paCmd). Delete the Th_Command structure that the
** entry points to.
**
** Argument pContext is a pointer to the interpreter structure.
**
** Always returns non-zero.
*/
static int thFreeCommand(Th_HashEntry *pEntry, void *pContext){
Th_Command *pCommand = (Th_Command *)pEntry->pData;
if( pCommand->xDel ){
pCommand->xDel((Th_Interp *)pContext, pCommand->pContext);
}
Th_Free((Th_Interp *)pContext, pEntry->pData);
pEntry->pData = 0;
return 1;
}
/*
** Push a new frame onto the stack.
*/
static int thPushFrame(Th_Interp *interp, Th_Frame *pFrame){
pFrame->paVar = Th_HashNew(interp);
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 | Th_Frame *pFrame = interp->pFrame; Th_HashIterate(interp, pFrame->paVar, thFreeVariable, (void *)interp); Th_HashDelete(interp, pFrame->paVar); interp->pFrame = pFrame->pCaller; } /* | | | | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
Th_Frame *pFrame = interp->pFrame;
Th_HashIterate(interp, pFrame->paVar, thFreeVariable, (void *)interp);
Th_HashDelete(interp, pFrame->paVar);
interp->pFrame = pFrame->pCaller;
}
/*
** The first part of the string (zInput,nInput) contains an escape
** sequence. Set *pnEscape to the number of bytes in the escape sequence.
** If there is a parse error, return TH_ERROR and set the interpreter
** result to an error message. Otherwise return TH_OK.
*/
static int thNextEscape(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnEscape
){
int i = 2;
assert(nInput>0);
assert(zInput[0]=='\\');
|
| ︙ | ︙ | |||
341 342 343 344 345 346 347 | } *pnEscape = i; return TH_OK; } /* ** The first part of the string (zInput,nInput) contains a variable | | | | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
}
*pnEscape = i;
return TH_OK;
}
/*
** The first part of the string (zInput,nInput) contains a variable
** reference. Set *pnVarname to the number of bytes in the variable
** reference. If there is a parse error, return TH_ERROR and set the
** interpreter result to an error message. Otherwise return TH_OK.
*/
int thNextVarname(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnVarname
){
int i;
assert(nInput>0);
assert(zInput[0]=='$');
|
| ︙ | ︙ | |||
398 399 400 401 402 403 404 | *pnVarname = i; return TH_OK; } /* ** The first part of the string (zInput,nInput) contains a command | | | | | | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
*pnVarname = i;
return TH_OK;
}
/*
** The first part of the string (zInput,nInput) contains a command
** enclosed in a "[]" block. Set *pnCommand to the number of bytes in
** the variable reference. If there is a parse error, return TH_ERROR
** and set the interpreter result to an error message. Otherwise return
** TH_OK.
*/
int thNextCommand(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnCommand
){
int nBrace = 0;
int nSquare = 0;
int i;
assert(nInput>0);
|
| ︙ | ︙ | |||
435 436 437 438 439 440 441 | *pnCommand = i; return TH_OK; } /* | | | | | | | | | | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
*pnCommand = i;
return TH_OK;
}
/*
** Set *pnSpace to the number of whitespace bytes at the start of
** input string (zInput, nInput). Always return TH_OK.
*/
int thNextSpace(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnSpace
){
int i;
for(i=0; i<nInput && th_isspace(zInput[i]); i++);
*pnSpace = i;
return TH_OK;
}
/*
** The first byte of the string (zInput,nInput) is not white-space.
** Set *pnWord to the number of bytes in the th1 word that starts
** with this byte. If a complete word cannot be parsed or some other
** error occurs, return TH_ERROR and set the interpreter result to
** an error message. Otherwise return TH_OK.
**
** If the isCmd argument is non-zero, then an unescaped ";" byte not
** located inside of a block or quoted string is considered to mark
** the end of the word.
*/
static int thNextWord(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnWord,
int isCmd
){
int iEnd = 0;
assert( !th_isspace(zInput[0]) );
|
| ︙ | ︙ | |||
528 529 530 531 532 533 534 | assert(nWord>=2); assert(zWord[0]=='[' && zWord[nWord-1]==']'); return thEvalLocal(interp, &zWord[1], nWord-2); } /* ** The input string (zWord, nWord) contains a th1 variable reference | | | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 |
assert(nWord>=2);
assert(zWord[0]=='[' && zWord[nWord-1]==']');
return thEvalLocal(interp, &zWord[1], nWord-2);
}
/*
** The input string (zWord, nWord) contains a th1 variable reference
** (a '$' byte followed by a variable name). Perform substitution on
** the input string and store the resulting string in the interpreter
** result.
*/
static int thSubstVarname(
Th_Interp *interp,
const char *zWord,
int nWord
){
|
| ︙ | ︙ | |||
569 570 571 572 573 574 575 |
}
}
return Th_GetVar(interp, &zWord[1], nWord-1);
}
/*
** The input string (zWord, nWord) contains a th1 escape sequence.
| | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
}
}
return Th_GetVar(interp, &zWord[1], nWord-1);
}
/*
** The input string (zWord, nWord) contains a th1 escape sequence.
** Perform substitution on the input string and store the resulting
** string in the interpreter result.
*/
static int thSubstEscape(
Th_Interp *interp,
const char *zWord,
int nWord
){
|
| ︙ | ︙ | |||
605 606 607 608 609 610 611 | Th_SetResult(interp, &c, 1); return TH_OK; } /* ** The input string (zWord, nWord) contains a th1 word. Perform | | | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
Th_SetResult(interp, &c, 1);
return TH_OK;
}
/*
** The input string (zWord, nWord) contains a th1 word. Perform
** substitution on the input string and store the resulting
** string in the interpreter result.
*/
static int thSubstWord(
Th_Interp *interp,
const char *zWord,
int nWord
){
|
| ︙ | ︙ | |||
637 638 639 640 641 642 643 |
int nGet;
int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
int (*xSubst)(Th_Interp *, const char*, int) = 0;
switch( zWord[i] ){
case '\\':
| | | | | 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
int nGet;
int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
int (*xSubst)(Th_Interp *, const char*, int) = 0;
switch( zWord[i] ){
case '\\':
xGet = thNextEscape; xSubst = thSubstEscape;
break;
case '[':
if( !interp->isListMode ){
xGet = thNextCommand; xSubst = thSubstCommand;
break;
}
case '$':
if( !interp->isListMode ){
xGet = thNextVarname; xSubst = thSubstVarname;
break;
}
default: {
thBufferWrite(interp, &output, &zWord[i], 1);
continue; /* Go to the next iteration of the for(...) loop */
}
}
|
| ︙ | ︙ | |||
682 683 684 685 686 687 688 | /* ** Return true if one of the following is true of the buffer pointed ** to by zInput, length nInput: ** ** + It is empty, or ** + It contains nothing but white-space, or | | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
/*
** Return true if one of the following is true of the buffer pointed
** to by zInput, length nInput:
**
** + It is empty, or
** + It contains nothing but white-space, or
** + It contains no non-white-space characters before the first
** newline character.
**
** Otherwise return false.
*/
static int thEndOfLine(const char *zInput, int nInput){
int i;
for(i=0; i<nInput && zInput[i]!='\n' && th_isspace(zInput[i]); i++);
|
| ︙ | ︙ | |||
722 723 724 725 726 727 728 | ** Th_SplitList(interp, zList, nList, &argv, &argl, &argc); ** ** // Free all memory allocated by Th_SplitList(). The arrays pointed ** // to by argv and argl are invalidated by this call. ** // ** Th_Free(interp, argv); ** | | | | | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 |
** Th_SplitList(interp, zList, nList, &argv, &argl, &argc);
**
** // Free all memory allocated by Th_SplitList(). The arrays pointed
** // to by argv and argl are invalidated by this call.
** //
** Th_Free(interp, argv);
**
*/
static int thSplitList(
Th_Interp *interp, /* Interpreter context */
const char *zList, /* Pointer to buffer containing input list */
int nList, /* Size of buffer pointed to by zList */
char ***pazElem, /* OUT: Array of list elements */
int **panElem, /* OUT: Lengths of each list element */
int *pnCount /* OUT: Number of list elements */
){
int rc = TH_OK;
Buffer strbuf;
Buffer lenbuf;
|
| ︙ | ︙ | |||
771 772 773 774 775 776 777 |
}
}
assert((lenbuf.nBuf/sizeof(int))==nCount);
assert((pazElem && panElem) || (!pazElem && !panElem));
if( pazElem && rc==TH_OK ){
int i;
| | | | | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 |
}
}
assert((lenbuf.nBuf/sizeof(int))==nCount);
assert((pazElem && panElem) || (!pazElem && !panElem));
if( pazElem && rc==TH_OK ){
int i;
char *zElem;
int *anElem;
char **azElem = Th_Malloc(interp,
sizeof(char*) * nCount + /* azElem */
sizeof(int) * nCount + /* anElem */
strbuf.nBuf /* space for list element strings */
);
anElem = (int *)&azElem[nCount];
zElem = (char *)&anElem[nCount];
memcpy(anElem, lenbuf.zBuf, lenbuf.nBuf);
memcpy(zElem, strbuf.zBuf, strbuf.nBuf);
for(i=0; i<nCount;i++){
azElem[i] = zElem;
zElem += (anElem[i] + 1);
}
*pazElem = azElem;
*panElem = anElem;
}
if( pnCount ){
*pnCount = nCount;
}
finish:
thBufferFree(interp, &strbuf);
thBufferFree(interp, &lenbuf);
return rc;
}
/*
|
| ︙ | ︙ | |||
873 874 875 876 877 878 879 |
/* Call the command procedure. */
if( rc==TH_OK ){
Th_Command *p = (Th_Command *)(pEntry->pData);
const char **azArg = (const char **)argv;
rc = p->xProc(interp, p->pContext, argc, azArg, argl);
}
| | | | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 |
/* Call the command procedure. */
if( rc==TH_OK ){
Th_Command *p = (Th_Command *)(pEntry->pData);
const char **azArg = (const char **)argv;
rc = p->xProc(interp, p->pContext, argc, azArg, argl);
}
/* If an error occurred, add this command to the stack trace report. */
if( rc==TH_ERROR ){
char *zRes;
int nRes;
char *zStack = 0;
int nStack = 0;
zRes = Th_TakeResult(interp, &nRes);
if( TH_OK==Th_GetVar(interp, (char *)"::th_stack_trace", -1) ){
zStack = Th_TakeResult(interp, &nStack);
}
Th_ListAppend(interp, &zStack, &nStack, zFirst, zInput-zFirst);
Th_SetVar(interp, (char *)"::th_stack_trace", -1, zStack, nStack);
Th_SetResult(interp, zRes, nRes);
|
| ︙ | ︙ | |||
909 910 911 912 913 914 915 | ** Th_Frame structure. If unsuccessful (no such frame), return 0 and ** leave an error message in the interpreter result. ** ** Argument iFrame is interpreted as follows: ** ** * If iFrame is 0, this means the current frame. ** | | | | | 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 |
** Th_Frame structure. If unsuccessful (no such frame), return 0 and
** leave an error message in the interpreter result.
**
** Argument iFrame is interpreted as follows:
**
** * If iFrame is 0, this means the current frame.
**
** * If iFrame is negative, then the nth frame up the stack, where
** n is the absolute value of iFrame. A value of -1 means the
** calling procedure.
**
** * If iFrame is +ve, then the nth frame from the bottom of the
** stack. An iFrame value of 1 means the toplevel (global) frame.
*/
static Th_Frame *getFrame(Th_Interp *interp, int iFrame){
Th_Frame *p = interp->pFrame;
int i;
if( iFrame>0 ){
for(i=0; p; i++){
|
| ︙ | ︙ | |||
945 946 947 948 949 950 951 | return p; } /* ** Evaluate th1 script (zProgram, nProgram) in the frame identified by ** argument iFrame. Leave either an error message or a result in the | | | | | 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 |
return p;
}
/*
** Evaluate th1 script (zProgram, nProgram) in the frame identified by
** argument iFrame. Leave either an error message or a result in the
** interpreter result and return a th1 error code (TH_OK, TH_ERROR,
** TH_RETURN, TH_CONTINUE or TH_BREAK).
*/
int Th_Eval(Th_Interp *interp, int iFrame, const char *zProgram, int nProgram){
int rc = TH_OK;
Th_Frame *pSavedFrame = interp->pFrame;
/* Set Th_Interp.pFrame to the frame that this script is to be
** evaluated in. The current frame is saved in pSavedFrame and will
** be restored before this function returns.
*/
interp->pFrame = getFrame(interp, iFrame);
if( !interp->pFrame ){
rc = TH_ERROR;
}else{
int nInput = nProgram;
if( nInput<0 ){
nInput = th_strlen(zProgram);
}
rc = thEvalLocal(interp, zProgram, nInput);
}
interp->pFrame = pSavedFrame;
|
| ︙ | ︙ | |||
992 993 994 995 996 997 998 | ** array variable. If the variable is a scalar, *pzInner is set to 0. ** If it is an array variable, (*pzInner, *pnInner) is set to the ** array key name. */ static int thAnalyseVarname( const char *zVarname, int nVarname, | | | | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 |
** array variable. If the variable is a scalar, *pzInner is set to 0.
** If it is an array variable, (*pzInner, *pnInner) is set to the
** array key name.
*/
static int thAnalyseVarname(
const char *zVarname,
int nVarname,
const char **pzOuter, /* OUT: Pointer to scalar/array name */
int *pnOuter, /* OUT: Number of bytes at *pzOuter */
const char **pzInner, /* OUT: Pointer to array key (or null) */
int *pnInner, /* OUT: Number of bytes at *pzInner */
int *pisGlobal /* OUT: Set to true if this is a global ref */
){
const char *zOuter = zVarname;
int nOuter;
const char *zInner = 0;
int nInner = 0;
|
| ︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 1046 1047 | *pnOuter = nOuter; *pzInner = zInner; *pnInner = nInner; *pisGlobal = isGlobal; return TH_OK; } /* ** Input string (zVar, nVar) contains a variable name. This function locates | > > > > > > > > > > > > > > > | > | | | | > > > > > > > | > > > > | > > > > > > | > > | > | | | | > | | | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 |
*pnOuter = nOuter;
*pzInner = zInner;
*pnInner = nInner;
*pisGlobal = isGlobal;
return TH_OK;
}
/*
** The Find structure is used to return extra information to callers of the
** thFindValue function. The fields within it are populated by thFindValue
** as soon as the necessary information is available. Callers should check
** each field of interest upon return.
*/
struct Find {
Th_HashEntry *pValueEntry; /* Pointer to the scalar or array hash entry */
Th_HashEntry *pElemEntry; /* Pointer to array element hash entry, if any */
const char *zElem; /* Name of array element, if applicable */
int nElem; /* Length of array element name, if applicable */
};
typedef struct Find Find;
/*
** Input string (zVar, nVar) contains a variable name. This function locates
** the Th_Variable structure associated with the named variable. The
** variable name may be a global or local scalar or array variable
**
** If the create argument is non-zero and the named variable does not exist
** it is created. Otherwise, an error is left in the interpreter result
** and NULL returned.
**
** If the arrayok argument is false and the named variable is an array,
** an error is left in the interpreter result and NULL returned. If
** arrayok is true an array name is Ok.
*/
static Th_Variable *thFindValue(
Th_Interp *interp,
const char *zVar, /* Pointer to variable name */
int nVar, /* Number of bytes at nVar */
int create, /* If true, create the variable if not found */
int arrayok, /* If true, an array is Ok. Otherwise array==error */
int noerror, /* If false, set interpreter result to error */
Find *pFind /* If non-zero, place output here */
){
const char *zOuter;
int nOuter;
const char *zInner;
int nInner;
int isGlobal;
Th_HashEntry *pEntry;
Th_Frame *pFrame = interp->pFrame;
Th_Variable *pValue;
thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal);
if( pFind ){
memset(pFind, 0, sizeof(Find));
pFind->zElem = zInner;
pFind->nElem = nInner;
}
if( isGlobal ){
while( pFrame->pCaller ) pFrame = pFrame->pCaller;
}
pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create);
assert(pEntry || create<=0);
if( pFind ){
pFind->pValueEntry = pEntry;
}
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
pValue = Th_Malloc(interp, sizeof(Th_Variable));
pValue->nRef = 1;
pEntry->pData = (void *)pValue;
}
if( zInner ){
if( pValue->zData ){
if( !noerror ){
Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter);
}
return 0;
}
if( !pValue->pHash ){
if( !create ){
goto no_such_var;
}
pValue->pHash = Th_HashNew(interp);
}
pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create);
assert(pEntry || create<=0);
if( pFind ){
pFind->pElemEntry = pEntry;
}
if( !pEntry ){
goto no_such_var;
}
pValue = (Th_Variable *)pEntry->pData;
if( !pValue ){
assert(create);
pValue = Th_Malloc(interp, sizeof(Th_Variable));
pValue->nRef = 1;
pEntry->pData = (void *)pValue;
}
}else{
if( pValue->pHash && !arrayok ){
if( !noerror ){
Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter);
}
return 0;
}
}
return pValue;
no_such_var:
if( !noerror ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
}
return 0;
}
/*
** String (zVar, nVar) must contain the name of a scalar variable or
** array member. Look up the variable, store its current value in
** the interpreter result and return TH_OK.
**
** If the named variable does not exist, return TH_ERROR and leave
** an error message in the interpreter result.
*/
int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 0, 0, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( !pValue->zData ){
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
return TH_ERROR;
}
return Th_SetResult(interp, pValue->zData, pValue->nData);
}
/*
** Return true if variable (zVar, nVar) exists.
*/
int Th_ExistsVar(Th_Interp *interp, const char *zVar, int nVar){
Th_Variable *pValue = thFindValue(interp, zVar, nVar, 0, 1, 1, 0);
return pValue && (pValue->zData || pValue->pHash);
}
/*
** String (zVar, nVar) must contain the name of a scalar variable or
** array member. If the variable does not exist it is created. The
** variable is set to the value supplied in string (zValue, nValue).
**
** If (zVar, nVar) refers to an existing array, TH_ERROR is returned
** and an error message left in the interpreter result.
*/
int Th_SetVar(
Th_Interp *interp,
const char *zVar,
int nVar,
const char *zValue,
int nValue
){
Th_Variable *pValue;
pValue = thFindValue(interp, zVar, nVar, 1, 0, 0, 0);
if( !pValue ){
return TH_ERROR;
}
if( nValue<0 ){
nValue = th_strlen(zValue);
}
|
| ︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 | /* ** Create a variable link so that accessing variable (zLocal, nLocal) is ** the same as accessing variable (zLink, nLink) in stack frame iFrame. */ int Th_LinkVar( Th_Interp *interp, /* Interpreter */ | | | | > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | | | | | > > > > > > > > | | 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 |
/*
** Create a variable link so that accessing variable (zLocal, nLocal) is
** the same as accessing variable (zLink, nLink) in stack frame iFrame.
*/
int Th_LinkVar(
Th_Interp *interp, /* Interpreter */
const char *zLocal, int nLocal, /* Local varname */
int iFrame, /* Stack frame of linked var */
const char *zLink, int nLink /* Linked varname */
){
Th_Frame *pSavedFrame = interp->pFrame;
Th_Frame *pFrame;
Th_HashEntry *pEntry;
Th_Variable *pValue;
pFrame = getFrame(interp, iFrame);
if( !pFrame ){
return TH_ERROR;
}
pSavedFrame = interp->pFrame;
interp->pFrame = pFrame;
pValue = thFindValue(interp, zLink, nLink, 1, 1, 0, 0);
interp->pFrame = pSavedFrame;
pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1);
if( pEntry->pData ){
Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal);
return TH_ERROR;
}
pEntry->pData = (void *)pValue;
pValue->nRef++;
return TH_OK;
}
/*
** Input string (zVar, nVar) must contain the name of a scalar variable,
** an array, or an array member. If the identified variable exists, it
** is deleted and TH_OK returned. Otherwise, an error message is left
** in the interpreter result and TH_ERROR is returned.
*/
int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){
Find find;
Th_Variable *pValue;
Th_HashEntry *pEntry;
int rc = TH_ERROR;
pValue = thFindValue(interp, zVar, nVar, 0, 1, 0, &find);
if( !pValue ){
return rc;
}
if( pValue->zData || pValue->pHash ){
rc = TH_OK;
}else {
Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
}
/*
** The variable may be shared by more than one frame; therefore, make sure
** it is actually freed prior to freeing the parent structure. The values
** for the variable must be freed now so the variable appears undefined in
** all frames. The hash entry in the current frame must also be deleted
** now; otherwise, if the current stack frame is later popped, it will try
** to delete a variable which has already been freed.
*/
if( find.zElem ){
pEntry = find.pElemEntry;
}else{
pEntry = find.pValueEntry;
}
assert( pEntry );
assert( pValue );
if( thFreeVariable(pEntry, (void *)interp) ){
if( find.zElem ){
Th_Variable *pValue2 = find.pValueEntry->pData;
Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1);
}else if( pEntry->pData ){
Th_Free(interp, pEntry->pData);
pEntry->pData = 0;
}
}else{
if( pValue->zData ){
Th_Free(interp, pValue->zData);
pValue->zData = 0;
}
if( pValue->pHash ){
Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp);
Th_HashDelete(interp, pValue->pHash);
pValue->pHash = 0;
}
if( find.zElem ){
Th_Variable *pValue2 = find.pValueEntry->pData;
Th_HashFind(interp, pValue2->pHash, find.zElem, find.nElem, -1);
}
}
if( !find.zElem ){
Th_HashFind(interp, interp->pFrame->paVar, zVar, nVar, -1);
}
return rc;
}
/*
** Return an allocated buffer containing a copy of string (z, n). The
** caller is responsible for eventually calling Th_Free() to free
** the returned buffer.
*/
|
| ︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 |
*/
int Th_ErrorMessage(Th_Interp *interp, const char *zPre, const char *z, int n){
if( interp ){
char *zRes = 0;
int nRes = 0;
Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0);
| | | 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 |
*/
int Th_ErrorMessage(Th_Interp *interp, const char *zPre, const char *z, int n){
if( interp ){
char *zRes = 0;
int nRes = 0;
Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0);
Th_StringAppend(interp, &zRes, &nRes, zPre, -1);
if( zRes[nRes-1]=='"' ){
Th_StringAppend(interp, &zRes, &nRes, z, n);
Th_StringAppend(interp, &zRes, &nRes, (const char *)"\"", 1);
}else{
Th_StringAppend(interp, &zRes, &nRes, (const char *)" ", 1);
Th_StringAppend(interp, &zRes, &nRes, z, n);
|
| ︙ | ︙ | |||
1370 1371 1372 1373 1374 1375 1376 |
return zResult;
}else{
return (char *)Th_Malloc(pInterp, 1);
}
}
| | | | | | 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 |
return zResult;
}else{
return (char *)Th_Malloc(pInterp, 1);
}
}
/*
** Wrappers around the supplied malloc() and free()
*/
void *Th_Malloc(Th_Interp *pInterp, int nByte){
void *p = pInterp->pVtab->xMalloc(nByte);
if( p ){
memset(p, 0, nByte);
}
return p;
}
void Th_Free(Th_Interp *pInterp, void *z){
if( z ){
pInterp->pVtab->xFree(z);
}
}
/*
** Install a new th1 command.
**
** If a command of the same name already exists, it is deleted automatically.
*/
int Th_CreateCommand(
Th_Interp *interp,
const char *zName, /* New command name */
Th_CommandProc xProc, /* Command callback proc */
void *pContext, /* Value to pass as second arg to xProc */
void (*xDel)(Th_Interp *, void *) /* Command destructor callback */
){
Th_HashEntry *pEntry;
Th_Command *pCommand;
|
| ︙ | ︙ | |||
1414 1415 1416 1417 1418 1419 1420 |
}else{
pCommand = Th_Malloc(interp, sizeof(Th_Command));
}
pCommand->xProc = xProc;
pCommand->pContext = pContext;
pCommand->xDel = xDel;
pEntry->pData = (void *)pCommand;
| | | | | | | | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 |
}else{
pCommand = Th_Malloc(interp, sizeof(Th_Command));
}
pCommand->xProc = xProc;
pCommand->pContext = pContext;
pCommand->xDel = xDel;
pEntry->pData = (void *)pCommand;
return TH_OK;
}
/*
** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0,
** the command is deleted instead of renamed.
**
** If successful, TH_OK is returned. If command zName does not exist, or
** if command zNew already exists, an error message is left in the
** interpreter result and TH_ERROR is returned.
*/
int Th_RenameCommand(
Th_Interp *interp,
const char *zName, /* Existing command name */
int nName, /* Number of bytes at zName */
const char *zNew, /* New command name */
int nNew /* Number of bytes at zNew */
){
Th_HashEntry *pEntry;
Th_HashEntry *pNewEntry;
pEntry = Th_HashFind(interp, interp->paCmd, zName, nName, 0);
if( !pEntry ){
|
| ︙ | ︙ | |||
1488 1489 1490 1491 1492 1493 1494 | ** Split a th1 list into its component elements. The list to split is ** passed via arguments (zList, nList). If successful, TH_OK is returned. ** If an error occurs (if (zList, nList) is not a valid list) an error ** message is left in the interpreter result and TH_ERROR returned. ** ** If successful, *pnCount is set to the number of elements in the list. ** panElem is set to point at an array of *pnCount integers - the lengths | | | 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 | ** Split a th1 list into its component elements. The list to split is ** passed via arguments (zList, nList). If successful, TH_OK is returned. ** If an error occurs (if (zList, nList) is not a valid list) an error ** message is left in the interpreter result and TH_ERROR returned. ** ** If successful, *pnCount is set to the number of elements in the list. ** panElem is set to point at an array of *pnCount integers - the lengths ** of the element values. *pazElem is set to point at an array of ** pointers to buffers containing the array element's data. ** ** To free the arrays allocated at *pazElem and *panElem, the caller ** should call Th_Free() on *pazElem only. Exactly one such call to ** Th_Free() must be made per call to Th_SplitList(). ** ** Example: |
| ︙ | ︙ | |||
1514 1515 1516 1517 1518 1519 1520 | ** } ** ** Th_Free(interp, azElem); ** */ int Th_SplitList( Th_Interp *interp, | | | | | | | | | 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 |
** }
**
** Th_Free(interp, azElem);
**
*/
int Th_SplitList(
Th_Interp *interp,
const char *zList, /* Pointer to buffer containing list */
int nList, /* Number of bytes at zList */
char ***pazElem, /* OUT: Array of pointers to element data */
int **panElem, /* OUT: Array of element data lengths */
int *pnCount /* OUT: Number of elements in list */
){
int rc;
interp->isListMode = 1;
rc = thSplitList(interp, zList, nList, pazElem, panElem, pnCount);
interp->isListMode = 0;
if( rc ){
Th_ErrorMessage(interp, "Expected list, got: \"", zList, nList);
}
return rc;
}
/*
** Append a new element to an existing th1 list. The element to append
** to the list is (zElem, nElem).
**
** A pointer to the existing list must be stored at *pzList when this
** function is called. The length must be stored in *pnList. The value
** of *pzList must either be NULL (in which case *pnList must be 0), or
** a pointer to memory obtained from Th_Malloc().
**
** This function calls Th_Free() to free the buffer at *pzList and sets
** *pzList to point to a new buffer containing the new list value. *pnList
** is similarly updated before returning. The return value is always TH_OK.
**
** Example:
**
** char *zList = 0;
** int nList = 0;
** for (...) {
** char *zElem = <some expression>;
** Th_ListAppend(interp, &zList, &nList, zElem, -1);
** }
** Th_SetResult(interp, zList, nList);
** Th_Free(interp, zList);
**
*/
int Th_ListAppend(
Th_Interp *interp, /* Interpreter context */
char **pzList, /* IN/OUT: Ptr to ptr to list */
int *pnList, /* IN/OUT: Current length of *pzList */
const char *zElem, /* Data to append */
int nElem /* Length of nElem */
){
Buffer output;
int i;
int hasSpecialChar = 0;
int hasEscapeChar = 0;
|
| ︙ | ︙ | |||
1612 1613 1614 1615 1616 1617 1618 | /* ** Append a new element to an existing th1 string. This function uses ** the same interface as the Th_ListAppend() function. */ int Th_StringAppend( Th_Interp *interp, /* Interpreter context */ | | | | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 |
/*
** Append a new element to an existing th1 string. This function uses
** the same interface as the Th_ListAppend() function.
*/
int Th_StringAppend(
Th_Interp *interp, /* Interpreter context */
char **pzStr, /* IN/OUT: Ptr to ptr to list */
int *pnStr, /* IN/OUT: Current length of *pzStr */
const char *zElem, /* Data to append */
int nElem /* Length of nElem */
){
char *zNew;
int nNew;
if( nElem<0 ){
nElem = th_strlen(zElem);
|
| ︙ | ︙ | |||
1636 1637 1638 1639 1640 1641 1642 | Th_Free(interp, *pzStr); *pzStr = zNew; *pnStr = nNew; return TH_OK; } | | | | 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 |
Th_Free(interp, *pzStr);
*pzStr = zNew;
*pnStr = nNew;
return TH_OK;
}
/*
** Delete an interpreter.
*/
void Th_DeleteInterp(Th_Interp *interp){
assert(interp->pFrame);
assert(0==interp->pFrame->pCaller);
/* Delete the contents of the global frame. */
thPopFrame(interp);
/* Delete any result currently stored in the interpreter. */
Th_SetResult(interp, 0, 0);
/* Delete all registered commands and the command hash-table itself. */
Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp);
Th_HashDelete(interp, interp->paCmd);
/* Delete the interpreter structure itself. */
Th_Free(interp, (void *)interp);
}
/*
** Create a new interpreter.
*/
Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){
Th_Interp *p;
/* Allocate and initialise the interpreter and the global frame */
p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame));
|
| ︙ | ︙ | |||
1691 1692 1693 1694 1695 1696 1697 |
typedef struct Expr Expr;
struct Expr {
Operator *pOp;
Expr *pParent;
Expr *pLeft;
Expr *pRight;
| | | 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 |
typedef struct Expr Expr;
struct Expr {
Operator *pOp;
Expr *pParent;
Expr *pLeft;
Expr *pRight;
char *zValue; /* Pointer to literal value */
int nValue; /* Length of literal value buffer */
};
/* Unary operators */
#define OP_UNARY_MINUS 2
#define OP_UNARY_PLUS 3
#define OP_BITWISE_NOT 4
|
| ︙ | ︙ | |||
1747 1748 1749 1750 1751 1752 1753 |
/* Note: all unary operators have (iPrecedence==1) */
{"-", OP_UNARY_MINUS, 1, ARG_NUMBER},
{"+", OP_UNARY_PLUS, 1, ARG_NUMBER},
{"~", OP_BITWISE_NOT, 1, ARG_INTEGER},
{"!", OP_LOGICAL_NOT, 1, ARG_INTEGER},
/* Binary operators. It is important to the parsing in Th_Expr() that
| | | 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 |
/* Note: all unary operators have (iPrecedence==1) */
{"-", OP_UNARY_MINUS, 1, ARG_NUMBER},
{"+", OP_UNARY_PLUS, 1, ARG_NUMBER},
{"~", OP_BITWISE_NOT, 1, ARG_INTEGER},
{"!", OP_LOGICAL_NOT, 1, ARG_INTEGER},
/* Binary operators. It is important to the parsing in Th_Expr() that
* the two-character symbols ("==") appear before the one-character
* ones ("="). And that the priorities of all binary operators are
* integers between 2 and 12.
*/
{"<<", OP_LEFTSHIFT, 4, ARG_INTEGER},
{">>", OP_RIGHTSHIFT, 4, ARG_INTEGER},
{"<=", OP_LE, 5, ARG_NUMBER},
{">=", OP_GE, 5, ARG_NUMBER},
|
| ︙ | ︙ | |||
1773 1774 1775 1776 1777 1778 1779 |
{"-", OP_SUBTRACT, 3, ARG_NUMBER},
{"<", OP_LT, 5, ARG_NUMBER},
{">", OP_GT, 5, ARG_NUMBER},
{"&", OP_BITWISE_AND, 8, ARG_INTEGER},
{"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
| | | | | | | 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 |
{"-", OP_SUBTRACT, 3, ARG_NUMBER},
{"<", OP_LT, 5, ARG_NUMBER},
{">", OP_GT, 5, ARG_NUMBER},
{"&", OP_BITWISE_AND, 8, ARG_INTEGER},
{"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
{0,0,0,0}
};
/*
** The first part of the string (zInput,nInput) contains a number.
** Set *pnVarname to the number of bytes in the numeric string.
*/
static int thNextNumber(
Th_Interp *interp,
const char *zInput,
int nInput,
int *pnLiteral
){
int i;
int seenDot = 0;
for(i=0; i<nInput; i++){
char c = zInput[i];
if( (seenDot || c!='.') && !th_isdigit(c) ) break;
|
| ︙ | ︙ | |||
1853 1854 1855 1856 1857 1858 1859 |
if( rc==TH_OK ){
eArgType = pExpr->pOp->eArgType;
if( eArgType==ARG_NUMBER ){
if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft))
&& (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight))
){
eArgType = ARG_INTEGER;
| | | | > > > > > > > | > > > > > > > | 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 |
if( rc==TH_OK ){
eArgType = pExpr->pOp->eArgType;
if( eArgType==ARG_NUMBER ){
if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft))
&& (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight))
){
eArgType = ARG_INTEGER;
}else if(
(zLeft && TH_OK!=Th_ToDouble(interp, zLeft, nLeft, &fLeft)) ||
(zRight && TH_OK!=Th_ToDouble(interp, zRight, nRight, &fRight))
){
/* A type error. */
rc = TH_ERROR;
}
}else if( eArgType==ARG_INTEGER ){
rc = Th_ToInt(interp, zLeft, nLeft, &iLeft);
if( rc==TH_OK && zRight ){
rc = Th_ToInt(interp, zRight, nRight, &iRight);
}
}
}
if( rc==TH_OK && eArgType==ARG_INTEGER ){
int iRes = 0;
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: iRes = iLeft*iRight; break;
case OP_DIVIDE:
if( !iRight ){
Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
rc = TH_ERROR;
goto finish;
}
iRes = iLeft/iRight;
break;
case OP_MODULUS:
if( !iRight ){
Th_ErrorMessage(interp, "Modulo by 0:", zLeft, nLeft);
rc = TH_ERROR;
goto finish;
}
iRes = iLeft%iRight;
break;
case OP_ADD: iRes = iLeft+iRight; break;
case OP_SUBTRACT: iRes = iLeft-iRight; break;
case OP_LEFTSHIFT: iRes = iLeft<<iRight; break;
case OP_RIGHTSHIFT: iRes = iLeft>>iRight; break;
case OP_LT: iRes = iLeft<iRight; break;
case OP_GT: iRes = iLeft>iRight; break;
case OP_LE: iRes = iLeft<=iRight; break;
|
| ︙ | ︙ | |||
1897 1898 1899 1900 1901 1902 1903 |
case OP_UNARY_PLUS: iRes = +iLeft; break;
case OP_LOGICAL_NOT: iRes = !iLeft; break;
default: assert(!"Internal error");
}
Th_SetResultInt(interp, iRes);
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
switch( pExpr->pOp->eOp ) {
| | > > > > > > | > | | | | | | | | > > > > | 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 |
case OP_UNARY_PLUS: iRes = +iLeft; break;
case OP_LOGICAL_NOT: iRes = !iLeft; break;
default: assert(!"Internal error");
}
Th_SetResultInt(interp, iRes);
}else if( rc==TH_OK && eArgType==ARG_NUMBER ){
switch( pExpr->pOp->eOp ) {
case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight); break;
case OP_DIVIDE:
if( fRight==0.0 ){
Th_ErrorMessage(interp, "Divide by 0:", zLeft, nLeft);
rc = TH_ERROR;
goto finish;
}
Th_SetResultDouble(interp, fLeft/fRight);
break;
case OP_ADD: Th_SetResultDouble(interp, fLeft+fRight); break;
case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight); break;
case OP_LT: Th_SetResultInt(interp, fLeft<fRight); break;
case OP_GT: Th_SetResultInt(interp, fLeft>fRight); break;
case OP_LE: Th_SetResultInt(interp, fLeft<=fRight); break;
case OP_GE: Th_SetResultInt(interp, fLeft>=fRight); break;
case OP_EQ: Th_SetResultInt(interp, fLeft==fRight); break;
case OP_NE: Th_SetResultInt(interp, fLeft!=fRight); break;
case OP_UNARY_MINUS: Th_SetResultDouble(interp, -fLeft); break;
case OP_UNARY_PLUS: Th_SetResultDouble(interp, +fLeft); break;
default: assert(!"Internal error");
}
}else if( rc==TH_OK ){
int iEqual = 0;
assert( eArgType==ARG_STRING );
if( nRight==nLeft && 0==memcmp(zRight, zLeft, nRight) ){
iEqual = 1;
}
switch( pExpr->pOp->eOp ) {
case OP_SEQ: Th_SetResultInt(interp, iEqual); break;
case OP_SNE: Th_SetResultInt(interp, !iEqual); break;
default: assert(!"Internal error");
}
}
finish:
Th_Free(interp, zLeft);
Th_Free(interp, zRight);
}
return rc;
}
|
| ︙ | ︙ | |||
1944 1945 1946 1947 1948 1949 1950 |
assert(nToken>0);
#define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft))
for(jj=0; jj<nToken; jj++){
if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){
int nNest = 1;
| | | 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 |
assert(nToken>0);
#define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft))
for(jj=0; jj<nToken; jj++){
if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){
int nNest = 1;
int iLeft = jj;
for(jj++; jj<nToken; jj++){
Operator *pOp = apToken[jj]->pOp;
if( pOp && pOp->eOp==OP_OPEN_BRACKET ) nNest++;
if( pOp && pOp->eOp==OP_CLOSE_BRACKET ) nNest--;
if( nNest==0 ) break;
}
|
| ︙ | ︙ | |||
2018 2019 2020 2021 2022 2023 2024 | } /* ** Parse a string containing a TH expression to a list of tokens. */ static int exprParse( Th_Interp *interp, /* Interpreter to leave error message in */ | | | 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 |
}
/*
** Parse a string containing a TH expression to a list of tokens.
*/
static int exprParse(
Th_Interp *interp, /* Interpreter to leave error message in */
const char *zExpr, /* Pointer to input string */
int nExpr, /* Number of bytes at zExpr */
Expr ***papToken, /* OUT: Array of tokens. */
int *pnToken /* OUT: Size of token array */
){
int i;
int rc = TH_OK;
|
| ︙ | ︙ | |||
2093 2094 2095 2096 2097 2098 2099 |
assert( !pNew->pOp );
pNew->zValue = Th_Malloc(interp, pNew->nValue);
memcpy(pNew->zValue, z, pNew->nValue);
i += pNew->nValue;
}
if( (nToken%16)==0 ){
/* Grow the apToken array. */
| | | 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 |
assert( !pNew->pOp );
pNew->zValue = Th_Malloc(interp, pNew->nValue);
memcpy(pNew->zValue, z, pNew->nValue);
i += pNew->nValue;
}
if( (nToken%16)==0 ){
/* Grow the apToken array. */
Expr **apTokenOld = apToken;
apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16));
memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken);
}
/* Put the new token at the end of the apToken array */
apToken[nToken] = pNew;
nToken++;
|
| ︙ | ︙ | |||
2118 2119 2120 2121 2122 2123 2124 | } /* ** Evaluate the string (zExpr, nExpr) as a Th expression. Store ** the result in the interpreter interp and return TH_OK if ** successful. If an error occurs, store an error message in ** the interpreter result and return an error code. | | | | 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 |
}
/*
** Evaluate the string (zExpr, nExpr) as a Th expression. Store
** the result in the interpreter interp and return TH_OK if
** successful. If an error occurs, store an error message in
** the interpreter result and return an error code.
*/
int Th_Expr(Th_Interp *interp, const char *zExpr, int nExpr){
int rc; /* Return Code */
int i; /* Loop counter */
int nToken = 0;
Expr **apToken = 0;
if( nExpr<0 ){
nExpr = th_strlen(zExpr);
}
/* Parse the expression to a list of tokens. */
rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken);
/* If the parsing was successful, create an expression tree from
** the parsed list of tokens. If successful, apToken[0] is set
** to point to the root of the expression tree.
*/
if( rc==TH_OK ){
rc = exprMakeTree(interp, apToken, nToken);
}
if( rc!=TH_OK ){
Th_ErrorMessage(interp, "syntax error in expression: \"", zExpr, nExpr);
|
| ︙ | ︙ | |||
2173 2174 2175 2176 2177 2178 2179 | return p; } /* ** Iterate through all values currently stored in the hash table. Invoke ** the callback function xCallback for each entry. The second argument ** passed to xCallback is a copy of the fourth argument passed to this | | > | | | | > | | | | 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 |
return p;
}
/*
** Iterate through all values currently stored in the hash table. Invoke
** the callback function xCallback for each entry. The second argument
** passed to xCallback is a copy of the fourth argument passed to this
** function. The return value from the callback function xCallback is
** ignored.
*/
void Th_HashIterate(
Th_Interp *interp,
Th_Hash *pHash,
int (*xCallback)(Th_HashEntry *pEntry, void *pContext),
void *pContext
){
int i;
for(i=0; i<TH_HASHSIZE; i++){
Th_HashEntry *pEntry;
Th_HashEntry *pNext;
for(pEntry=pHash->a[i]; pEntry; pEntry=pNext){
pNext = pEntry->pNext;
xCallback(pEntry, pContext);
}
}
}
/*
** Helper function for Th_HashDelete(). Always returns non-zero.
*/
static int xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){
Th_Free((Th_Interp *)pContext, (void *)pEntry);
return 1;
}
/*
** Free a hash-table previously allocated by Th_HashNew().
*/
void Th_HashDelete(Th_Interp *interp, Th_Hash *pHash){
if( pHash ){
Th_HashIterate(interp, pHash, xFreeHashEntry, (void *)interp);
Th_Free(interp, pHash);
}
}
/*
** This function is used to insert or delete hash table items, or to
** query a hash table for an existing item.
**
** If parameter op is less than zero, then the hash-table element
** identified by (zKey, nKey) is removed from the hash-table if it
** exists. NULL is returned.
**
** Otherwise, if the hash-table contains an item with key (zKey, nKey),
** a pointer to the associated Th_HashEntry is returned. If parameter
** op is greater than zero, then a new entry is added if one cannot
** be found. If op is zero, then NULL is returned if the item is
** not already present in the hash-table.
*/
Th_HashEntry *Th_HashFind(
Th_Interp *interp,
Th_Hash *pHash,
const char *zKey,
int nKey,
int op /* -ve = delete, 0 = find, +ve = insert */
){
unsigned int iKey = 0;
int i;
|
| ︙ | ︙ | |||
2292 2293 2294 2295 2296 2297 2298 | ** '\n' 0x0A ** '\v' 0x0B ** '\f' 0x0C ** '\r' 0x0D ** ** Whitespace characters have the 0x01 flag set. Decimal digits have the ** 0x2 flag set. Single byte printable characters have the 0x4 flag set. | | | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 |
** '\n' 0x0A
** '\v' 0x0B
** '\f' 0x0C
** '\r' 0x0D
**
** Whitespace characters have the 0x01 flag set. Decimal digits have the
** 0x2 flag set. Single byte printable characters have the 0x4 flag set.
** Alphabet characters have the 0x8 bit set.
**
** The special list characters have the 0x10 flag set
**
** { } [ ] \ ; ' "
**
** " 0x22
**
|
| ︙ | ︙ | |||
2340 2341 2342 2343 2344 2345 2346 |
int th_isalnum(char c){
return (aCharProp[(unsigned char)c] & 0x0A);
}
#ifndef LONGDOUBLE_TYPE
# define LONGDOUBLE_TYPE long double
#endif
| < | 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 |
int th_isalnum(char c){
return (aCharProp[(unsigned char)c] & 0x0A);
}
#ifndef LONGDOUBLE_TYPE
# define LONGDOUBLE_TYPE long double
#endif
/*
** Return TRUE if z is a pure numeric string. Return FALSE if the
** string contains any character which is not part of a number. If
** the string is numeric and contains the '.' character, set *realnum
** to TRUE (otherwise FALSE).
|
| ︙ | ︙ | |||
2444 2445 2446 2447 2448 2449 2450 | } *pResult = sign<0 ? -v1 : v1; return z - zBegin; } /* ** Try to convert the string passed as arguments (z, n) to an integer. | | | | | 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 |
}
*pResult = sign<0 ? -v1 : v1;
return z - zBegin;
}
/*
** Try to convert the string passed as arguments (z, n) to an integer.
** If successful, store the result in *piOut and return TH_OK.
**
** If the string cannot be converted to an integer, return TH_ERROR.
** If the interp argument is not NULL, leave an error message in the
** interpreter result too.
*/
int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){
int i = 0;
int iOut = 0;
if( n<0 ){
|
| ︙ | ︙ | |||
2479 2480 2481 2482 2483 2484 2485 | *piOut = iOut; return TH_OK; } /* ** Try to convert the string passed as arguments (z, n) to a double. | | | | | | | | 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 |
*piOut = iOut;
return TH_OK;
}
/*
** Try to convert the string passed as arguments (z, n) to a double.
** If successful, store the result in *pfOut and return TH_OK.
**
** If the string cannot be converted to a double, return TH_ERROR.
** If the interp argument is not NULL, leave an error message in the
** interpreter result too.
*/
int Th_ToDouble(
Th_Interp *interp,
const char *z,
int n,
double *pfOut
){
if( !sqlite3IsNumber((const char *)z, 0) ){
Th_ErrorMessage(interp, "expected number, got: \"", z, n);
return TH_ERROR;
}
|
| ︙ | ︙ | |||
2514 2515 2516 2517 2518 2519 2520 |
char *z = &zBuf[32];
if( iVal<0 ){
isNegative = 1;
iVal = iVal * -1;
}
*(--z) = '\0';
| | | | | | | | | | | 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 |
char *z = &zBuf[32];
if( iVal<0 ){
isNegative = 1;
iVal = iVal * -1;
}
*(--z) = '\0';
*(--z) = (char)(48+((unsigned)iVal%10));
while( (iVal = ((unsigned)iVal/10))>0 ){
*(--z) = (char)(48+((unsigned)iVal%10));
assert(z>zBuf);
}
if( isNegative ){
*(--z) = '-';
}
return Th_SetResult(interp, z, -1);
}
/*
** Set the result of the interpreter to the th1 representation of
** the double fVal and return TH_OK.
*/
int Th_SetResultDouble(Th_Interp *interp, double fVal){
int i; /* Iterator variable */
double v = fVal; /* Input value */
char zBuf[128]; /* Output buffer */
char *z = zBuf; /* Output cursor */
int iDot = 0; /* Digit after which to place decimal point */
int iExp = 0; /* Exponent (NN in eNN) */
const char *zExp; /* String representation of iExp */
/* Precision: */
#define INSIGNIFICANT 0.000000000001
#define ROUNDER 0.0000000000005
double insignificant = INSIGNIFICANT;
/* If the real value is negative, write a '-' character to the
* output and transform v to the corresponding positive number.
*/
if( v<0.0 ){
*z++ = '-';
v *= -1.0;
}
/* Normalize v to a value between 1.0 and 10.0. Integer
* variable iExp is set to the exponent. i.e the original
* value is (v * 10^iExp) (or the negative thereof).
*/
if( v>0.0 ){
while( (v+ROUNDER)>=10.0 ) { iExp++; v *= 0.1; }
while( (v+ROUNDER)<1.0 ) { iExp--; v *= 10.0; }
}
v += ROUNDER;
/* For a small (<12) positive exponent, move the decimal point
|
| ︙ | ︙ |
Changes to src/th.h.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 | typedef struct Th_Vtab Th_Vtab; /* ** Opaque handle for interpeter. */ typedef struct Th_Interp Th_Interp; | | | | | | | | | | | | | | | | | | | | | | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | typedef struct Th_Vtab Th_Vtab; /* ** Opaque handle for interpeter. */ typedef struct Th_Interp Th_Interp; /* ** Create and delete interpreters. */ Th_Interp * Th_CreateInterp(Th_Vtab *pVtab); void Th_DeleteInterp(Th_Interp *); /* ** Evaluate an TH program in the stack frame identified by parameter ** iFrame, according to the following rules: ** ** * If iFrame is 0, this means the current frame. ** ** * If iFrame is negative, then the nth frame up the stack, where n is ** the absolute value of iFrame. A value of -1 means the calling ** procedure. ** ** * If iFrame is +ve, then the nth frame from the bottom of the stack. ** An iFrame value of 1 means the toplevel (global) frame. */ int Th_Eval(Th_Interp *interp, int iFrame, const char *zProg, int nProg); /* ** Evaluate a TH expression. The result is stored in the ** interpreter result. */ int Th_Expr(Th_Interp *interp, const char *, int); /* ** Access TH variables in the current stack frame. If the variable name ** begins with "::", the lookup is in the top level (global) frame. */ int Th_ExistsVar(Th_Interp *, const char *, int); int Th_GetVar(Th_Interp *, const char *, int); int Th_SetVar(Th_Interp *, const char *, int, const char *, int); int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int); int Th_UnsetVar(Th_Interp *, const char *, int); typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *); /* ** Register new commands. */ int Th_CreateCommand( Th_Interp *interp, const char *zName, /* int (*xProc)(Th_Interp *, void *, int, const char **, int *), */ Th_CommandProc xProc, void *pContext, void (*xDel)(Th_Interp *, void *) ); /* ** Delete or rename commands. */ int Th_RenameCommand(Th_Interp *, const char *, int, const char *, int); /* ** Push a new stack frame (local variable context) onto the interpreter ** stack, call the function supplied as parameter xCall with the two ** context arguments, ** ** xCall(interp, pContext1, pContext2) ** ** , then pop the frame off of the interpreter stack. The value returned ** by the xCall() function is returned as the result of this function. ** ** This is intended for use by the implementation of commands such as ** those created by [proc]. */ int Th_InFrame(Th_Interp *interp, int (*xCall)(Th_Interp *, void *pContext1, void *pContext2), void *pContext1, void *pContext2 ); /* ** Valid return codes for xProc callbacks. */ #define TH_OK 0 #define TH_ERROR 1 #define TH_BREAK 2 #define TH_RETURN 3 #define TH_CONTINUE 4 /* ** Set and get the interpreter result. */ int Th_SetResult(Th_Interp *, const char *, int); const char *Th_GetResult(Th_Interp *, int *); char *Th_TakeResult(Th_Interp *, int *); /* ** Set an error message as the interpreter result. This also ** sets the global stack-trace variable $::th_stack_trace. */ int Th_ErrorMessage(Th_Interp *, const char *, const char *, int); /* ** Access the memory management functions associated with the specified ** interpreter. */ void *Th_Malloc(Th_Interp *, int); void Th_Free(Th_Interp *, void *); /* ** Functions for handling TH lists. */ int Th_ListAppend(Th_Interp *, char **, int *, const char *, int); int Th_SplitList(Th_Interp *, const char *, int, char ***, int **, int *); int Th_StringAppend(Th_Interp *, char **, int *, const char *, int); /* ** Functions for handling numbers and pointers. */ int Th_ToInt(Th_Interp *, const char *, int, int *); int Th_ToDouble(Th_Interp *, const char *, int, double *); int Th_SetResultInt(Th_Interp *, int); int Th_SetResultDouble(Th_Interp *, double); |
| ︙ | ︙ | |||
153 154 155 156 157 158 159 | /* ** Interfaces to register the language extensions. */ int th_register_language(Th_Interp *interp); /* th_lang.c */ int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */ int th_register_vfs(Th_Interp *interp); /* th_vfs.c */ int th_register_testvfs(Th_Interp *interp); /* th_testvfs.c */ | > > > > > | > > > | | | | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
/*
** Interfaces to register the language extensions.
*/
int th_register_language(Th_Interp *interp); /* th_lang.c */
int th_register_sqlite(Th_Interp *interp); /* th_sqlite.c */
int th_register_vfs(Th_Interp *interp); /* th_vfs.c */
int th_register_testvfs(Th_Interp *interp); /* th_testvfs.c */
#ifdef FOSSIL_ENABLE_TCL
/*
** Interfaces to the full Tcl core library from "th_tcl.c".
*/
int th_register_tcl(Th_Interp *, void *);
int unloadTcl(Th_Interp *, void *);
int evaluateTclWithEvents(Th_Interp *, void *, const char *, int, int);
#endif
/*
** General purpose hash table from th_lang.c.
*/
typedef struct Th_Hash Th_Hash;
typedef struct Th_HashEntry Th_HashEntry;
struct Th_HashEntry {
void *pData;
char *zKey;
int nKey;
Th_HashEntry *pNext; /* Internal use only */
};
Th_Hash *Th_HashNew(Th_Interp *);
void Th_HashDelete(Th_Interp *, Th_Hash *);
void Th_HashIterate(Th_Interp*,Th_Hash*,int (*x)(Th_HashEntry*, void*),void*);
Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const char*, int, int);
/*
** Useful functions from th_lang.c.
*/
int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);
typedef struct Th_SubCommand {const char *zName; Th_CommandProc xProc;} Th_SubCommand;
int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,const Th_SubCommand*);
|
Changes to src/th_lang.c.
1 2 | /* | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
/*
** This file contains the implementation of all of the TH language
** built-in commands.
**
** All built-in commands are implemented using the public interface
** declared in th.h, so this file serves as both a part of the language
** implementation and an example of how to extend the language with
** new commands.
*/
#include "config.h"
#include "th.h"
#include <string.h>
#include <assert.h>
int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg){
Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1);
return TH_ERROR;
}
/*
** Syntax:
**
** catch script ?varname?
*/
static int catch_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int rc;
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "catch script ?varname?");
}
rc = Th_Eval(interp, 0, argv[1], -1);
if( argc==3 ){
int nResult;
const char *zResult = Th_GetResult(interp, &nResult);
Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
}
Th_SetResultInt(interp, rc);
return TH_OK;
}
/*
** TH Syntax:
**
** if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN?
*/
static int if_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int rc = TH_OK;
int iCond; /* Result of evaluating expression */
int i;
|
| ︙ | ︙ | |||
92 93 94 95 96 97 98 | return rc; wrong_args: return Th_WrongNumArgs(interp, "if ..."); } /* | | | | | | | | | | | | | | | | | | | | | | | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
return rc;
wrong_args:
return Th_WrongNumArgs(interp, "if ...");
}
/*
** TH Syntax:
**
** expr expr
*/
static int expr_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "expr expression");
}
return Th_Expr(interp, argv[1], argl[1]);
}
/*
** Evaluate the th1 script (zBody, nBody) in the local stack frame.
** Return the result of the evaluation, except if the result
** is TH_CONTINUE, return TH_OK instead.
*/
static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){
int rc = Th_Eval(interp, 0, zBody, nBody);
if( rc==TH_CONTINUE ){
rc = TH_OK;
}
return rc;
}
/*
** TH Syntax:
**
** for init condition incr script
*/
static int for_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int rc;
int iCond;
if( argc!=5 ){
return Th_WrongNumArgs(interp, "for init condition incr script");
}
/* Evaluate the 'init' script */
rc = Th_Eval(interp, 0, argv[1], -1);
while( rc==TH_OK
&& TH_OK==(rc = Th_Expr(interp, argv[2], -1))
&& TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond))
&& iCond
&& TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4]))
){
rc = Th_Eval(interp, 0, argv[3], -1);
}
if( rc==TH_BREAK ) rc = TH_OK;
return rc;
}
/*
** TH Syntax:
**
** list ?arg1 ?arg2? ...?
*/
static int list_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
char *zList = 0;
int nList = 0;
int i;
for(i=1; i<argc; i++){
Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
}
Th_SetResult(interp, zList, nList);
Th_Free(interp, zList);
return TH_OK;
}
/*
** TH Syntax:
**
** lindex list index
*/
static int lindex_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int iElem;
int rc;
char **azElem;
int *anElem;
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
Th_Free(interp, azElem);
}
return rc;
}
/*
| | | | | | | | | | | | | | | | | | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
Th_Free(interp, azElem);
}
return rc;
}
/*
** TH Syntax:
**
** llength list
*/
static int llength_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int nElem;
int rc;
if( argc!=2 ){
return Th_WrongNumArgs(interp, "llength list");
}
rc = Th_SplitList(interp, argv[1], argl[1], 0, 0, &nElem);
if( rc==TH_OK ){
Th_SetResultInt(interp, nElem);
}
return rc;
}
/*
** TH Syntax:
**
** set varname ?value?
*/
static int set_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "set varname ?value?");
}
if( argc==3 ){
Th_SetVar(interp, argv[1], argl[1], argv[2], argl[2]);
}
return Th_GetVar(interp, argv[1], argl[1]);
}
/*
** When a new command is created using the built-in [proc] command, an
** instance of the following structure is allocated and populated. A
** pointer to the structure is passed as the context (second) argument
** to function proc_call1() when the new command is executed.
*/
typedef struct ProcDefn ProcDefn;
struct ProcDefn {
int nParam; /* Number of formal (non "args") parameters */
char **azParam; /* Parameter names */
int *anParam; /* Lengths of parameter names */
char **azDefault; /* Default values */
int *anDefault; /* Lengths of default values */
int hasArgs; /* True if there is an "args" parameter */
char *zProgram; /* Body of proc */
int nProgram; /* Number of bytes at zProgram */
char *zUsage; /* Usage message */
int nUsage; /* Number of bytes at zUsage */
};
/* This structure is used to temporarily store arguments passed to an
** invocation of a command created using [proc]. A pointer to an
** instance is passed as the second argument to the proc_call2() function.
*/
typedef struct ProcArgs ProcArgs;
struct ProcArgs {
int argc;
const char **argv;
int *argl;
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 | int i; ProcDefn *p = (ProcDefn *)pContext1; ProcArgs *pArgs = (ProcArgs *)pContext2; /* Check if there are the right number of arguments. If there are ** not, generate a usage message for the command. */ | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
int i;
ProcDefn *p = (ProcDefn *)pContext1;
ProcArgs *pArgs = (ProcArgs *)pContext2;
/* Check if there are the right number of arguments. If there are
** not, generate a usage message for the command.
*/
if( (pArgs->argc>(p->nParam+1) && !p->hasArgs)
|| (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1])
){
char *zUsage = 0;
int nUsage = 0;
Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]);
Th_StringAppend(interp, &zUsage, &nUsage, p->zUsage, p->nUsage);
Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"", 1);
|
| ︙ | ︙ | |||
372 373 374 375 376 377 378 | /* ** This function is the command callback registered for all commands ** created using the [proc] command. The second argument, pContext, ** is a pointer to the associated ProcDefn structure. */ static int proc_call1( Th_Interp *interp, | | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
/*
** This function is the command callback registered for all commands
** created using the [proc] command. The second argument, pContext,
** is a pointer to the associated ProcDefn structure.
*/
static int proc_call1(
Th_Interp *interp,
void *pContext,
int argc,
const char **argv,
int *argl
){
int rc;
ProcDefn *p = (ProcDefn *)pContext;
ProcArgs procargs;
|
| ︙ | ︙ | |||
398 399 400 401 402 403 404 |
if( rc==TH_RETURN ){
rc = TH_OK;
}
return rc;
}
/*
| | | | | | | | | | | | | | | | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
if( rc==TH_RETURN ){
rc = TH_OK;
}
return rc;
}
/*
** This function is registered as the delete callback for all commands
** created using the built-in [proc] command. It is called automatically
** when a command created using [proc] is deleted.
**
** It frees the ProcDefn structure allocated when the command was created.
*/
static void proc_del(Th_Interp *interp, void *pContext){
ProcDefn *p = (ProcDefn *)pContext;
Th_Free(interp, (void *)p->zUsage);
Th_Free(interp, (void *)p);
}
/*
** TH Syntax:
**
** proc name arglist code
*/
static int proc_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int rc;
const char *zName;
ProcDefn *p;
int nByte;
int i;
char *zSpace;
char **azParam;
int *anParam;
int nParam;
char *zUsage = 0; /* Build up a usage message here */
int nUsage = 0; /* Number of bytes at zUsage */
if( argc!=4 ){
return Th_WrongNumArgs(interp, "proc name arglist code");
}
if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
return TH_ERROR;
}
/* Allocate the new ProcDefn structure. */
nByte = sizeof(ProcDefn) + /* ProcDefn structure */
(sizeof(char *) + sizeof(int)) * nParam + /* azParam, anParam */
(sizeof(char *) + sizeof(int)) * nParam + /* azDefault, anDefault */
argl[3] + /* zProgram */
argl[2]; /* Space for copies of parameter names and default values */
p = (ProcDefn *)Th_Malloc(interp, nByte);
/* If the last parameter in the parameter list is "args", then set the
** ProcDefn.hasArgs flag. The "args" parameter does not require an
** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
*/
if( anParam[nParam-1]==4 && 0==memcmp(azParam[nParam-1], "args", 4) ){
p->hasArgs = 1;
nParam--;
}
p->nParam = nParam;
p->azParam = (char **)&p[1];
p->anParam = (int *)&p->azParam[nParam];
p->azDefault = (char **)&p->anParam[nParam];
p->anDefault = (int *)&p->azDefault[nParam];
p->zProgram = (char *)&p->anDefault[nParam];
memcpy(p->zProgram, argv[3], argl[3]);
p->nProgram = argl[3];
zSpace = &p->zProgram[p->nProgram];
for(i=0; i<nParam; i++){
char **az;
int *an;
int n;
if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){
goto error_out;
}
|
| ︙ | ︙ | |||
519 520 521 522 523 524 525 |
if( p->hasArgs ){
Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ?args...?", -1);
}
p->zUsage = zUsage;
p->nUsage = nUsage;
/* Register the new command with the th1 interpreter. */
| | | | | | | | | | | | | | | | | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 |
if( p->hasArgs ){
Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ?args...?", -1);
}
p->zUsage = zUsage;
p->nUsage = nUsage;
/* Register the new command with the th1 interpreter. */
zName = argv[1];
rc = Th_CreateCommand(interp, zName, proc_call1, (void *)p, proc_del);
if( rc==TH_OK ){
Th_SetResult(interp, 0, 0);
}
Th_Free(interp, azParam);
return TH_OK;
error_out:
Th_Free(interp, azParam);
Th_Free(interp, zUsage);
return TH_ERROR;
}
/*
** TH Syntax:
**
** rename oldcmd newcmd
*/
static int rename_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=3 ){
return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
}
return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
}
/*
** TH Syntax:
**
** break ?value...?
** continue ?value...?
** ok ?value...?
** error ?value...?
*/
static int simple_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=1 && argc!=2 ){
return Th_WrongNumArgs(interp, "return ?value?");
}
if( argc==2 ){
Th_SetResult(interp, argv[1], argl[1]);
}
return FOSSIL_PTR_TO_INT(ctx);
}
/*
** TH Syntax:
**
** return ?-code code? ?value?
*/
static int return_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int iCode = TH_RETURN;
if( argc<1 || argc>4 ){
return Th_WrongNumArgs(interp, "return ?-code code? ?value?");
}
if( argc>2 ){
|
| ︙ | ︙ | |||
636 637 638 639 640 641 642 |
}
if( iRes==0 ){
iRes = nLeft-nRight;
}
if( iRes<0 ) iRes = -1;
if( iRes>0 ) iRes = 1;
| | < < < < | > > > | > | | | | | | | > | 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 |
}
if( iRes==0 ){
iRes = nLeft-nRight;
}
if( iRes<0 ) iRes = -1;
if( iRes>0 ) iRes = 1;
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string first NEEDLE HAYSTACK
*/
static int string_first_command(
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
){
int nNeedle;
int nHaystack;
int iRes = -1;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string first needle haystack");
}
nNeedle = argl[2];
nHaystack = argl[3];
if( nNeedle && nHaystack && nNeedle<=nHaystack ){
const char *zNeedle = argv[2];
const char *zHaystack = argv[3];
int i;
for(i=0; i<=(nHaystack-nNeedle); i++){
if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
iRes = i;
break;
}
}
}
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string is CLASS STRING
|
| ︙ | ︙ | |||
709 710 711 712 713 714 715 |
** TH Syntax:
**
** string last NEEDLE HAYSTACK
*/
static int string_last_command(
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
){
| < < < | < | > > > | > | | | | | | | > | 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 |
** TH Syntax:
**
** string last NEEDLE HAYSTACK
*/
static int string_last_command(
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
){
int nNeedle;
int nHaystack;
int iRes = -1;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string last needle haystack");
}
nNeedle = argl[2];
nHaystack = argl[3];
if( nNeedle && nHaystack && nNeedle<=nHaystack ){
const char *zNeedle = argv[2];
const char *zHaystack = argv[3];
int i;
for(i=nHaystack-nNeedle; i>=0; i--){
if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
iRes = i;
break;
}
}
}
return Th_SetResultInt(interp, iRes);
}
/*
** TH Syntax:
**
** string length STRING
|
| ︙ | ︙ | |||
865 866 867 868 869 870 871 | /* ** TH Syntax: ** ** unset VAR */ static int unset_command( | | | | | | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 |
/*
** TH Syntax:
**
** unset VAR
*/
static int unset_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
if( argc!=2 ){
return Th_WrongNumArgs(interp, "unset var");
}
return Th_UnsetVar(interp, argv[1], argl[1]);
}
int Th_CallSubCommand(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl,
const Th_SubCommand *aSub
){
if( argc>1 ){
int i;
for(i=0; aSub[i].zName; i++){
const char *zName = aSub[i].zName;
if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){
return aSub[i].xProc(interp, ctx, argc, argv, argl);
}
}
}
if(argc<2){
Th_ErrorMessage(interp, "Expected sub-command for", argv[0], argl[0]);
|
| ︙ | ︙ | |||
914 915 916 917 918 919 920 | ** string is CLASS STRING ** string last NEEDLE HAYSTACK ?STARTINDEX? ** string length STRING ** string range STRING FIRST LAST ** string repeat STRING COUNT */ static int string_command( | | | | 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 |
** string is CLASS STRING
** string last NEEDLE HAYSTACK ?STARTINDEX?
** string length STRING
** string range STRING FIRST LAST
** string repeat STRING COUNT
*/
static int string_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
static const Th_SubCommand aSub[] = {
{ "compare", string_compare_command },
{ "first", string_first_command },
{ "is", string_is_command },
{ "last", string_last_command },
{ "length", string_length_command },
{ "range", string_range_command },
{ "repeat", string_repeat_command },
|
| ︙ | ︙ | |||
942 943 944 945 946 947 948 | /* ** TH Syntax: ** ** info exists VARNAME */ static int info_command( | | | | | | | | | 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
/*
** TH Syntax:
**
** info exists VARNAME
*/
static int info_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
static const Th_SubCommand aSub[] = {
{ "exists", info_exists_command },
{ 0, 0 }
};
return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
}
/*
** Convert the script level frame specification (used by the commands
** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as
** used by Th_LinkVar() and Th_Eval(). If successful, write the integer
** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR
** and leave an error message in the interpreter result.
*/
static int thToFrame(
Th_Interp *interp,
const char *zFrame,
int nFrame,
int *piFrame
){
int iFrame;
if( th_isdigit(zFrame[0]) ){
int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame);
if( rc!=TH_OK ) return rc;
iFrame = iFrame * -1;
|
| ︙ | ︙ | |||
990 991 992 993 994 995 996 | /* ** TH Syntax: ** ** uplevel ?LEVEL? SCRIPT */ static int uplevel_command( | | | | | | | | | | | | | | 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
/*
** TH Syntax:
**
** uplevel ?LEVEL? SCRIPT
*/
static int uplevel_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int iFrame = -1;
if( argc!=2 && argc!=3 ){
return Th_WrongNumArgs(interp, "uplevel ?level? script...");
}
if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
return TH_ERROR;
}
return Th_Eval(interp, iFrame, argv[argc-1], -1);
}
/*
** TH Syntax:
**
** upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...?
*/
static int upvar_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int iVar = 1;
int iFrame = -1;
int rc = TH_OK;
int i;
if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
iVar++;
}
if( argc==iVar || (argc-iVar)%2 ){
return Th_WrongNumArgs(interp,
"upvar frame othervar myvar ?othervar myvar...?");
}
for(i=iVar; rc==TH_OK && i<argc; i=i+2){
rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
}
return rc;
}
/*
** TH Syntax:
**
** breakpoint ARGS
**
** This command does nothing at all. Its purpose in life is to serve
** as a point for setting breakpoints in a debugger.
*/
static int breakpoint_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
int cnt = 0;
cnt++;
return TH_OK;
}
|
| ︙ | ︙ | |||
1076 1077 1078 1079 1080 1081 1082 |
{"expr", expr_command, 0},
{"for", for_command, 0},
{"if", if_command, 0},
{"info", info_command, 0},
{"lindex", lindex_command, 0},
{"list", list_command, 0},
{"llength", llength_command, 0},
| | | | | | | 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 |
{"expr", expr_command, 0},
{"for", for_command, 0},
{"if", if_command, 0},
{"info", info_command, 0},
{"lindex", lindex_command, 0},
{"list", list_command, 0},
{"llength", llength_command, 0},
{"proc", proc_command, 0},
{"rename", rename_command, 0},
{"set", set_command, 0},
{"string", string_command, 0},
{"unset", unset_command, 0},
{"uplevel", uplevel_command, 0},
{"upvar", upvar_command, 0},
{"breakpoint", breakpoint_command, 0},
{"return", return_command, 0},
{"break", simple_command, (void *)TH_BREAK},
{"continue", simple_command, (void *)TH_CONTINUE},
{"error", simple_command, (void *)TH_ERROR},
{0, 0, 0}
};
size_t i;
/* Add the language commands. */
for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
void *ctx;
if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
ctx = aCommand[i].pContext;
Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
}
return TH_OK;
}
|
Changes to src/th_main.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** This file contains an interface between the TH scripting language ** (an independent project) and fossil. */ #include "config.h" #include "th_main.h" #include "sqlite3.h" /* ** Global variable counting the number of outstanding calls to malloc() ** made by the th1 implementation. This is used to catch memory leaks ** in the interpreter. Obviously, it also means th1 is not threadsafe. */ static int nOutstandingMalloc = 0; | > > > > > > > > > > > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | ** This file contains an interface between the TH scripting language ** (an independent project) and fossil. */ #include "config.h" #include "th_main.h" #include "sqlite3.h" #if INTERFACE /* ** Flag parameters to the Th_FossilInit() routine used to control the ** interpreter creation and initialization process. */ #define TH_INIT_NONE ((u32)0x00000000) /* No flags. */ #define TH_INIT_NEED_CONFIG ((u32)0x00000001) /* Open configuration first? */ #define TH_INIT_FORCE_TCL ((u32)0x00000002) /* Force Tcl to be enabled? */ #define TH_INIT_FORCE_RESET ((u32)0x00000004) /* Force TH commands re-added? */ #define TH_INIT_FORCE_SETUP ((u32)0x00000008) /* Force eval of setup script? */ #define TH_INIT_DEFAULT (TH_INIT_NONE) /* Default flags. */ #endif /* ** Global variable counting the number of outstanding calls to malloc() ** made by the th1 implementation. This is used to catch memory leaks ** in the interpreter. Obviously, it also means th1 is not threadsafe. */ static int nOutstandingMalloc = 0; |
| ︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
static void xFree(void *p){
if( p ){
nOutstandingMalloc--;
}
free(p);
}
static Th_Vtab vtab = { xMalloc, xFree };
/*
** Generate a TH1 trace message if debugging is enabled.
*/
void Th_Trace(const char *zFormat, ...){
va_list ap;
va_start(ap, zFormat);
| > > > > > > > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
static void xFree(void *p){
if( p ){
nOutstandingMalloc--;
}
free(p);
}
static Th_Vtab vtab = { xMalloc, xFree };
/*
** Returns the number of outstanding TH1 memory allocations.
*/
int Th_GetOutstandingMalloc(){
return nOutstandingMalloc;
}
/*
** Generate a TH1 trace message if debugging is enabled.
*/
void Th_Trace(const char *zFormat, ...){
va_list ap;
va_start(ap, zFormat);
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
void Th_PrintTraceLog(){
if( g.thTrace ){
fossil_print("\n------------------ BEGIN TRACE LOG ------------------\n");
fossil_print("%s", blob_str(&g.thLog));
fossil_print("\n------------------- END TRACE LOG -------------------\n");
}
}
/*
** True if output is enabled. False if disabled.
*/
static int enableOutput = 1;
/*
| > > > > > > > > > > > > > > > > > > > > > > > | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
void Th_PrintTraceLog(){
if( g.thTrace ){
fossil_print("\n------------------ BEGIN TRACE LOG ------------------\n");
fossil_print("%s", blob_str(&g.thLog));
fossil_print("\n------------------- END TRACE LOG -------------------\n");
}
}
/*
** TH command: httpize STRING
**
** Escape all characters of STRING which have special meaning in URI
** components. Return a new string result.
*/
static int httpizeCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
char *zOut;
if( argc!=2 ){
return Th_WrongNumArgs(interp, "httpize STRING");
}
zOut = httpize((char*)argv[1], argl[1]);
Th_SetResult(interp, zOut, -1);
free(zOut);
return TH_OK;
}
/*
** True if output is enabled. False if disabled.
*/
static int enableOutput = 1;
/*
|
| ︙ | ︙ | |||
240 241 242 243 244 245 246 |
void *p,
int argc,
const char **argv,
int *argl
){
char *zOut;
if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){
| | | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
void *p,
int argc,
const char **argv,
int *argl
){
char *zOut;
if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){
zOut = db_text("??", "SELECT datetime('now'%s)", timeline_utc());
}else{
zOut = db_text("??", "SELECT datetime('now')");
}
Th_SetResult(interp, zOut, -1);
free(zOut);
return TH_OK;
}
|
| ︙ | ︙ | |||
281 282 283 284 285 286 287 | /* ** TH command: hasfeature STRING ** ** Return true if the fossil binary has the given compile-time feature ** enabled. The set of features includes: ** | | | > | > | | | | > > > > > | > > > > > | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
/*
** TH command: hasfeature STRING
**
** Return true if the fossil binary has the given compile-time feature
** enabled. The set of features includes:
**
** "ssl" = FOSSIL_ENABLE_SSL
** "tcl" = FOSSIL_ENABLE_TCL
** "useTclStubs" = USE_TCL_STUBS
** "tclStubs" = FOSSIL_ENABLE_TCL_STUBS
** "tclPrivateStubs" = FOSSIL_ENABLE_TCL_PRIVATE_STUBS
** "json" = FOSSIL_ENABLE_JSON
** "markdown" = FOSSIL_ENABLE_MARKDOWN
**
*/
static int hasfeatureCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
int rc = 0;
char const * zArg;
if( argc!=2 ){
return Th_WrongNumArgs(interp, "hasfeature STRING");
}
zArg = (char const*)argv[1];
if(NULL==zArg){
/* placeholder for following ifdefs... */
}
#if defined(FOSSIL_ENABLE_SSL)
else if( 0 == fossil_strnicmp( zArg, "ssl\0", 4 ) ){
rc = 1;
}
#endif
#if defined(FOSSIL_ENABLE_TCL)
else if( 0 == fossil_strnicmp( zArg, "tcl\0", 4 ) ){
rc = 1;
}
#endif
#if defined(USE_TCL_STUBS)
else if( 0 == fossil_strnicmp( zArg, "useTclStubs\0", 12 ) ){
rc = 1;
}
#endif
#if defined(FOSSIL_ENABLE_TCL_STUBS)
else if( 0 == fossil_strnicmp( zArg, "tclStubs\0", 9 ) ){
rc = 1;
}
#endif
#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
else if( 0 == fossil_strnicmp( zArg, "tclPrivateStubs\0", 16 ) ){
rc = 1;
}
#endif
#if defined(FOSSIL_ENABLE_JSON)
else if( 0 == fossil_strnicmp( zArg, "json\0", 5 ) ){
rc = 1;
}
#endif
else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){
rc = 1;
}
if( g.thTrace ){
Th_Trace("[hasfeature %#h] => %d<br />\n", argl[1], zArg, rc);
}
Th_SetResultInt(interp, rc);
return TH_OK;
|
| ︙ | ︙ | |||
428 429 430 431 432 433 434 |
char **azElem;
int i;
if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem);
blob_init(&name, (char*)argv[1], argl[1]);
zValue = Th_Fetch(blob_str(&name), &nValue);
| < | > > | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
char **azElem;
int i;
if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem);
blob_init(&name, (char*)argv[1], argl[1]);
zValue = Th_Fetch(blob_str(&name), &nValue);
zH = htmlize(blob_buffer(&name), blob_size(&name));
z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height);
free(zH);
sendText(z, -1, 0);
free(z);
blob_reset(&name);
for(i=0; i<nElem; i++){
zH = htmlize((char*)azElem[i], aszElem[i]);
if( zValue && aszElem[i]==nValue
&& memcmp(zValue, azElem[i], nValue)==0 ){
|
| ︙ | ︙ | |||
501 502 503 504 505 506 507 |
static int repositoryCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
| < < > | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 |
static int repositoryCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
if( argc!=1 && argc!=2 ){
return Th_WrongNumArgs(interp, "repository ?BOOLEAN?");
}
if( argc==2 ){
int openRepository = 0;
if( Th_ToInt(interp, argv[1], argl[1], &openRepository) ){
return TH_ERROR;
}
if( openRepository ) db_find_and_open_repository(OPEN_OK_NOT_FOUND, 0);
}
Th_SetResult(interp, g.zRepositoryName, -1);
return TH_OK;
|
| ︙ | ︙ | |||
800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
}else{
Th_SetResult(interp, zErr, -1);
rc = TH_ERROR;
}
re_free(pRe);
return rc;
}
/*
** Make sure the interpreter has been initialized. Initialize it if
** it has not been already.
**
** The interpreter is stored in the g.interp global variable.
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 |
}else{
Th_SetResult(interp, zErr, -1);
rc = TH_ERROR;
}
re_free(pRe);
return rc;
}
/*
** TH command: http ?-asynchronous? ?--? url ?payload?
**
** Perform an HTTP or HTTPS request for the specified URL. If a
** payload is present, it will be interpreted as text/plain and
** the POST method will be used; otherwise, the GET method will
** be used. Upon success, if the -asynchronous option is used, an
** empty string is returned as the result; otherwise, the response
** from the server is returned as the result. Synchronous requests
** are not currently implemented.
*/
#define HTTP_WRONGNUMARGS "http ?-asynchronous? ?--? url ?payload?"
static int httpCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
int nArg = 1;
int fAsynchronous = 0;
const char *zType, *zRegexp;
Blob payload;
ReCompiled *pRe = 0;
UrlData urlData;
if( argc<2 || argc>5 ){
return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS);
}
if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){
fAsynchronous = 1; nArg++;
}
if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++;
if( nArg+1!=argc && nArg+2!=argc ){
return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS);
}
memset(&urlData, '\0', sizeof(urlData));
url_parse_local(argv[nArg], 0, &urlData);
if( urlData.isSsh || urlData.isFile ){
Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0);
return TH_ERROR;
}
zRegexp = db_get("th1-uri-regexp", 0);
if( zRegexp && zRegexp[0] ){
const char *zErr = re_compile(&pRe, zRegexp, 0);
if( zErr ){
Th_SetResult(interp, zErr, -1);
return TH_ERROR;
}
}
if( !pRe || !re_match(pRe, (const unsigned char *)urlData.canonical, -1) ){
Th_SetResult(interp, "url not allowed", -1);
re_free(pRe);
return TH_ERROR;
}
re_free(pRe);
blob_zero(&payload);
if( nArg+2==argc ){
blob_append(&payload, argv[nArg+1], argl[nArg+1]);
zType = "POST";
}else{
zType = "GET";
}
if( fAsynchronous ){
const char *zSep, *zParams;
Blob hdr;
zParams = strrchr(argv[nArg], '?');
if( strlen(urlData.path)>0 && zParams!=argv[nArg] ){
zSep = "";
}else{
zSep = "/";
}
blob_zero(&hdr);
blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n",
zType, zSep, urlData.path, zParams ? zParams : "");
if( urlData.proxyAuth ){
blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth);
}
if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){
char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]);
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
fossil_free(zCredentials);
}
blob_appendf(&hdr, "Host: %s\r\n"
"User-Agent: %s\r\n", urlData.hostname, get_user_agent());
if( zType[0]=='P' ){
blob_appendf(&hdr, "Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %d\r\n\r\n", blob_size(&payload));
}else{
blob_appendf(&hdr, "\r\n");
}
if( transport_open(&urlData) ){
Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0);
blob_reset(&hdr);
blob_reset(&payload);
return TH_ERROR;
}
transport_send(&urlData, &hdr);
transport_send(&urlData, &payload);
blob_reset(&hdr);
blob_reset(&payload);
transport_close(&urlData);
Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results. */
return TH_OK;
}else{
Th_ErrorMessage(interp,
"synchronous requests are not yet implemented", 0, 0);
blob_reset(&payload);
return TH_ERROR;
}
}
/*
** Make sure the interpreter has been initialized. Initialize it if
** it has not been already.
**
** The interpreter is stored in the g.interp global variable.
*/
void Th_FossilInit(u32 flags){
int wasInit = 0;
int needConfig = flags & TH_INIT_NEED_CONFIG;
int forceReset = flags & TH_INIT_FORCE_RESET;
int forceTcl = flags & TH_INIT_FORCE_TCL;
int forceSetup = flags & TH_INIT_FORCE_SETUP;
static unsigned int aFlags[] = { 0, 1, WIKI_LINKSONLY };
static struct _Command {
const char *zName;
Th_CommandProc xProc;
void *pContext;
} aCommand[] = {
{"anycap", anycapCmd, 0},
{"combobox", comboboxCmd, 0},
{"date", dateCmd, 0},
{"decorate", wikiCmd, (void*)&aFlags[2]},
{"enable_output", enableOutputCmd, 0},
{"httpize", httpizeCmd, 0},
{"hascap", hascapCmd, 0},
{"hasfeature", hasfeatureCmd, 0},
{"html", putsCmd, (void*)&aFlags[0]},
{"htmlize", htmlizeCmd, 0},
{"http", httpCmd, 0},
{"linecount", linecntCmd, 0},
{"puts", putsCmd, (void*)&aFlags[1]},
{"query", queryCmd, 0},
{"randhex", randhexCmd, 0},
{"regexp", regexpCmd, 0},
{"repository", repositoryCmd, 0},
{"setting", settingCmd, 0},
|
| ︙ | ︙ | |||
847 848 849 850 851 852 853 |
** repository and/or the global configuration. Since the caller
** passed a non-zero value for the needConfig parameter, make sure
** the necessary database connections are open prior to continuing.
*/
db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0);
db_open_config(0);
}
| | > > | > > > | > > | | 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 |
** repository and/or the global configuration. Since the caller
** passed a non-zero value for the needConfig parameter, make sure
** the necessary database connections are open prior to continuing.
*/
db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0);
db_open_config(0);
}
if( forceReset || forceTcl || g.interp==0 ){
int created = 0;
int i;
if( g.interp==0 ){
g.interp = Th_CreateInterp(&vtab);
created = 1;
}
if( forceReset || created ){
th_register_language(g.interp); /* Basic scripting commands. */
}
#ifdef FOSSIL_ENABLE_TCL
if( forceTcl || fossil_getenv("TH1_ENABLE_TCL")!=0 ||
db_get_boolean("tcl", 0) ){
if( !g.tcl.setup ){
g.tcl.setup = db_get("tcl-setup", 0); /* Grab Tcl setup script. */
}
th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */
}
#endif
for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
|
| ︙ | ︙ | |||
891 892 893 894 895 896 897 |
}
}
/*
** Store a string value in a variable in the interpreter.
*/
void Th_Store(const char *zName, const char *zValue){
| | | | 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 |
}
}
/*
** Store a string value in a variable in the interpreter.
*/
void Th_Store(const char *zName, const char *zValue){
Th_FossilInit(TH_INIT_DEFAULT);
if( zValue ){
if( g.thTrace ){
Th_Trace("set %h {%h}<br />\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
}
}
/*
** Store an integer value in a variable in the interpreter.
*/
void Th_StoreInt(const char *zName, int iValue){
Blob value;
char *zValue;
Th_FossilInit(TH_INIT_DEFAULT);
blob_zero(&value);
blob_appendf(&value, "%d", iValue);
zValue = blob_str(&value);
if( g.thTrace ){
Th_Trace("set %h {%h}<br />\n", zName, zValue);
}
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
|
| ︙ | ︙ | |||
932 933 934 935 936 937 938 |
/*
** Retrieve a string value from the interpreter. If no such
** variable exists, return NULL.
*/
char *Th_Fetch(const char *zName, int *pSize){
int rc;
| | | 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 |
/*
** Retrieve a string value from the interpreter. If no such
** variable exists, return NULL.
*/
char *Th_Fetch(const char *zName, int *pSize){
int rc;
Th_FossilInit(TH_INIT_DEFAULT);
rc = Th_GetVar(g.interp, (char*)zName, -1);
if( rc==TH_OK ){
return (char*)Th_GetResult(g.interp, pSize);
}else{
return 0;
}
}
|
| ︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 |
** on either stdout or into CGI.
*/
int Th_Render(const char *z){
int i = 0;
int n;
int rc = TH_OK;
char *zResult;
| | | 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 |
** on either stdout or into CGI.
*/
int Th_Render(const char *z){
int i = 0;
int n;
int rc = TH_OK;
char *zResult;
Th_FossilInit(TH_INIT_DEFAULT);
while( z[i] ){
if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
const char *zVar;
int nVar;
int encode = 1;
sendText(z, i, 0);
if( z[i+1]=='<' ){
|
| ︙ | ︙ | |||
1092 1093 1094 1095 1096 1097 1098 |
if( find_option("th-open-config", 0, 0)!=0 ){
db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0);
db_open_config(0);
}
if( g.argc!=3 ){
usage("script");
}
| | | 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 |
if( find_option("th-open-config", 0, 0)!=0 ){
db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0);
db_open_config(0);
}
if( g.argc!=3 ){
usage("script");
}
Th_FossilInit(TH_INIT_DEFAULT);
rc = Th_Eval(g.interp, 0, g.argv[2], -1);
zRc = Th_ReturnCodeName(rc, 1);
fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0));
Th_PrintTraceLog();
}
|
Changes to src/th_tcl.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | #include "config.h" #ifdef FOSSIL_ENABLE_TCL #include "th.h" #include "tcl.h" | < < < < < < < < < < < < | | | | | | | | | | > > > > > > > | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
#include "config.h"
#ifdef FOSSIL_ENABLE_TCL
#include "th.h"
#include "tcl.h"
/*
** These macros are designed to reduce the redundant code required to marshal
** arguments from TH1 to Tcl.
*/
#define USE_ARGV_TO_OBJV() \
int objc; \
Tcl_Obj **objv; \
int obji;
#define COPY_ARGV_TO_OBJV() \
objc = argc-1; \
objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *))); \
for(obji=1; obji<argc; obji++){ \
objv[obji-1] = Tcl_NewStringObj(argv[obji], argl[obji]); \
Tcl_IncrRefCount(objv[obji-1]); \
}
#define FREE_ARGV_TO_OBJV() \
for(obji=1; obji<argc; obji++){ \
Tcl_DecrRefCount(objv[obji-1]); \
} \
ckfree((char *)objv);
/*
** Fetch the Tcl interpreter from the specified void pointer, cast to a Tcl
** context.
*/
#define GET_CTX_TCL_INTERP(ctx) \
((struct TclContext *)(ctx))->interp
/*
** Fetch the (logically boolean) value from the specified void pointer that
** indicates whether or not we can/should use direct objProc calls.
*/
#define GET_CTX_TCL_USEOBJPROC(ctx) \
((struct TclContext *)(ctx))->useObjProc
/*
** Define the Tcl shared library name, some exported function names, and some
** cross-platform macros for use with the Tcl stubs mechanism, when enabled.
*/
#if defined(USE_TCL_STUBS)
# if defined(_WIN32)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# ifndef TCL_LIBRARY_NAME
# define TCL_LIBRARY_NAME "tcl86.dll\0"
# endif
|
| ︙ | ︙ | |||
112 113 114 115 116 117 118 | # endif # ifndef TCL_MINOR_OFFSET # define TCL_MINOR_OFFSET (8) # endif # endif /* defined(__CYGWIN__) */ # endif /* defined(_WIN32) */ # ifndef TCL_FINDEXECUTABLE_NAME | | | > > > > > > | > > | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
# endif
# ifndef TCL_MINOR_OFFSET
# define TCL_MINOR_OFFSET (8)
# endif
# endif /* defined(__CYGWIN__) */
# endif /* defined(_WIN32) */
# ifndef TCL_FINDEXECUTABLE_NAME
# define TCL_FINDEXECUTABLE_NAME "_Tcl_FindExecutable\0"
# endif
# ifndef TCL_CREATEINTERP_NAME
# define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp\0"
# endif
# ifndef TCL_DELETEINTERP_NAME
# define TCL_DELETEINTERP_NAME "_Tcl_DeleteInterp\0"
# endif
# ifndef TCL_FINALIZE_NAME
# define TCL_FINALIZE_NAME "_Tcl_Finalize\0"
# endif
#endif /* defined(USE_TCL_STUBS) */
/*
** The function types for Tcl_FindExecutable and Tcl_CreateInterp are needed
** when the Tcl library is being loaded dynamically by a stubs-enabled
** application (i.e. the inverse of using a stubs-enabled package). These are
** the only Tcl API functions that MUST be called prior to being able to call
** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). For complete
** cleanup if the Tcl stubs initialization fails somehow, the Tcl_DeleteInterp
** and Tcl_Finalize function types are also required.
*/
typedef void (tcl_FindExecutableProc) (const char * argv0);
typedef Tcl_Interp *(tcl_CreateInterpProc) (void);
typedef void (tcl_DeleteInterpProc) (Tcl_Interp *interp);
typedef void (tcl_FinalizeProc) (void);
/*
** The function types for the "hook" functions to be called before and after a
** TH1 command makes a call to evaluate a Tcl script. If the "pre" function
** returns anything but TH_OK, then evaluation of the Tcl script is skipped and
** that value is used as the return code. If the "post" function returns
** anything other than its rc argument, that will become the new return code
** for the command.
*/
typedef int (tcl_NotifyProc) (
void *pContext, /* The context for this notification. */
Th_Interp *interp, /* The TH1 interpreter being used. */
void *ctx, /* The original TH1 command context. */
int argc, /* Number of arguments for the TH1 command. */
const char **argv, /* Array of arguments for the TH1 command. */
int *argl, /* Array of lengths for the TH1 command arguments. */
int rc /* Recommended notification return value. */
);
/*
** Are we using our own private implementation of the Tcl stubs mechanism? If
** this is enabled, it prevents the user from having to link against the Tcl
** stubs library for the target platform, which may not be readily available.
*/
#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
/*
** HACK: Using some preprocessor magic and a private static variable, redirect
** the Tcl API calls [found within this file] to the function pointers
** that will be contained in our private Tcl stubs table. This takes
** advantage of the fact that the Tcl headers always define the Tcl API
** functions in terms of the "tclStubsPtr" variable.
*/
#define tclStubsPtr privateTclStubsPtr
static const TclStubs *tclStubsPtr = NULL;
/*
** Create a Tcl interpreter structure that mirrors just enough fields to get
** it up and running successfully with our private implementation of the Tcl
** stubs mechanism.
*/
struct PrivateTclInterp {
char *result;
Tcl_FreeProc *freeProc;
int errorLine;
const struct TclStubs *stubTable;
};
/*
** Fossil can now be compiled without linking to the actual Tcl stubs library.
** In that case, this function will be used to perform those steps that would
** normally be performed within the Tcl stubs library.
*/
static int initTclStubs(
Th_Interp *interp,
Tcl_Interp *tclInterp
){
tclStubsPtr = ((struct PrivateTclInterp *)tclInterp)->stubTable;
if( !tclStubsPtr || (tclStubsPtr->magic!=TCL_STUB_MAGIC) ){
Th_ErrorMessage(interp,
"could not initialize Tcl stubs: incompatible mechanism",
(const char *)"", 0);
return TH_ERROR;
}
/* NOTE: At this point, the Tcl API functions should be available. */
if( Tcl_PkgRequireEx(tclInterp, "Tcl", "8.4", 0, (void *)&tclStubsPtr)==0 ){
Th_ErrorMessage(interp,
"could not initialize Tcl stubs: incompatible version",
(const char *)"", 0);
return TH_ERROR;
}
return TH_OK;
}
#endif /* defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) */
/*
** Is the loaded version of Tcl one where querying and/or calling the objProc
** for a command does not work for some reason? The following special cases
** are currently handled by this function:
**
** 1. All versions of Tcl 8.4 have a bug that causes a crash when calling into
** the Tcl_GetCommandFromObj function via stubs (i.e. the stubs table entry
** is NULL).
**
** 2. Various beta builds of Tcl 8.6, namely 1 and 2, have an NRE-specific bug
** in Tcl_EvalObjCmd (SF bug #3399564) that cause a panic when calling into
** the objProc directly.
**
** For both of the above cases, the Tcl_EvalObjv function must be used instead
** of the more direct route of querying and calling the objProc directly.
*/
static int canUseObjProc(){
int major = -1, minor = -1, patchLevel = -1, type = -1;
Tcl_GetVersion(&major, &minor, &patchLevel, &type);
if( major<0 || minor<0 || patchLevel<0 || type<0 ){
return 0; /* NOTE: Invalid version info, assume bad. */
}
if( major==8 && minor==4 ){
return 0; /* NOTE: Disabled on Tcl 8.4, missing public API. */
}
if( major==8 && minor==6 && type==TCL_BETA_RELEASE && patchLevel<3 ){
return 0; /* NOTE: Disabled on Tcl 8.6b1/b2, SF bug #3399564. */
}
return 1; /* NOTE: For all other cases, assume good. */
}
/*
** Creates and initializes a Tcl interpreter for use with the specified TH1
** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
** by the caller. This must be declared here because quite a few functions in
** this file need to use it before it can be defined.
*/
static int createTclInterp(Th_Interp *interp, void *pContext);
/*
** Returns the Tcl interpreter result as a string with the associated length.
** If the Tcl interpreter or the Tcl result are NULL, the length will be 0.
** If the length pointer is NULL, the length will not be stored.
*/
static char *getTclResult(
Tcl_Interp *pInterp,
int *pN
){
Tcl_Obj *resultPtr;
if( !pInterp ){ /* This should not happen. */
if( pN ) *pN = 0;
return 0;
}
resultPtr = Tcl_GetObjResult(pInterp);
if( !resultPtr ){ /* This should not happen either? */
if( pN ) *pN = 0;
|
| ︙ | ︙ | |||
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
*/
struct TclContext {
int argc; /* Number of original arguments. */
char **argv; /* Full copy of the original arguments. */
void *library; /* The Tcl library module handle. */
tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */
tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
char *setup; /* The optional Tcl setup script. */
tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
void *pPreContext; /* Optional, provided to xPreEval(). */
tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
| > > > | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
*/
struct TclContext {
int argc; /* Number of original arguments. */
char **argv; /* Full copy of the original arguments. */
void *library; /* The Tcl library module handle. */
tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */
tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */
tcl_DeleteInterpProc *xDeleteInterp; /* Tcl_DeleteInterp() pointer. */
tcl_FinalizeProc *xFinalize; /* Tcl_Finalize() pointer. */
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
int useObjProc; /* Non-zero if an objProc can be called directly. */
char *setup; /* The optional Tcl setup script. */
tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
void *pPreContext; /* Optional, provided to xPreEval(). */
tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 |
const char **argv,
int *argl,
int rc
){
struct TclContext *tclContext = (struct TclContext *)ctx;
tcl_NotifyProc *xNotifyProc;
| | | | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
const char **argv,
int *argl,
int rc
){
struct TclContext *tclContext = (struct TclContext *)ctx;
tcl_NotifyProc *xNotifyProc;
if( !tclContext ){
Th_ErrorMessage(interp,
"invalid Tcl context", (const char *)"", 0);
return TH_ERROR;
}
xNotifyProc = bIsPost ? tclContext->xPostEval : tclContext->xPreEval;
if( xNotifyProc ){
rc = xNotifyProc(bIsPost ?
tclContext->pPostContext : tclContext->pPreContext,
interp, ctx, argc, argv, argl, rc);
}
return rc;
}
|
| ︙ | ︙ | |||
356 357 358 359 360 361 362 |
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
Tcl_Interp *tclInterp;
| < < < < < < < | > > > | | | | | | | | | | | | | | | | < | < < < | | > > | > > > | > | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 |
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
Tcl_Interp *tclInterp;
int rc = TH_OK;
int nResult;
const char *zResult;
USE_ARGV_TO_OBJV();
if( createTclInterp(interp, ctx)!=TH_OK ){
return TH_ERROR;
}
if( argc<2 ){
return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?");
}
tclInterp = GET_CTX_TCL_INTERP(ctx);
if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
return TH_ERROR;
}
rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
if( rc!=TH_OK ){
return rc;
}
Tcl_Preserve((ClientData)tclInterp);
#if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV
if( GET_CTX_TCL_USEOBJPROC(ctx) ){
Tcl_Command command;
Tcl_CmdInfo cmdInfo;
Tcl_Obj *objPtr = Tcl_NewStringObj(argv[1], argl[1]);
Tcl_IncrRefCount(objPtr);
command = Tcl_GetCommandFromObj(tclInterp, objPtr);
if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){
Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
Tcl_DecrRefCount(objPtr);
Tcl_Release((ClientData)tclInterp);
return TH_ERROR;
}
if( !cmdInfo.objProc ){
Th_ErrorMessage(interp, "cannot invoke Tcl command:", argv[1], argl[1]);
Tcl_DecrRefCount(objPtr);
Tcl_Release((ClientData)tclInterp);
return TH_ERROR;
}
Tcl_DecrRefCount(objPtr);
COPY_ARGV_TO_OBJV();
Tcl_ResetResult(tclInterp);
rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv);
FREE_ARGV_TO_OBJV();
}else
#endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */
{
COPY_ARGV_TO_OBJV();
rc = Tcl_EvalObjv(tclInterp, objc, objv, 0);
FREE_ARGV_TO_OBJV();
}
zResult = getTclResult(tclInterp, &nResult);
Th_SetResult(interp, zResult, nResult);
Tcl_Release((ClientData)tclInterp);
rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc);
return rc;
}
/*
** Syntax:
**
** th1Eval arg
*/
static int Th1EvalObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[]
){
Th_Interp *th1Interp;
int nArg;
const char *arg;
int rc;
if( objc!=2 ){
|
| ︙ | ︙ | |||
458 459 460 461 462 463 464 | ** ** th1Expr arg */ static int Th1ExprObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, | | | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 |
**
** th1Expr arg
*/
static int Th1ExprObjCmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[]
){
Th_Interp *th1Interp;
int nArg;
const char *arg;
int rc;
if( objc!=2 ){
|
| ︙ | ︙ | |||
499 500 501 502 503 504 505 |
{"tclInvoke", tclInvoke_command, 0},
{0, 0, 0}
};
/*
** Called if the Tcl interpreter is deleted. Removes the Tcl integration
** commands from the TH1 interpreter.
| | > | | > > | > | > > > | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 |
{"tclInvoke", tclInvoke_command, 0},
{0, 0, 0}
};
/*
** Called if the Tcl interpreter is deleted. Removes the Tcl integration
** commands from the TH1 interpreter.
*/
static void Th1DeleteProc(
ClientData clientData,
Tcl_Interp *interp
){
int i;
Th_Interp *th1Interp = (Th_Interp *)clientData;
if( !th1Interp ) return;
/* Remove the Tcl integration commands. */
for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
Th_RenameCommand(th1Interp, aCommand[i].zName, -1, NULL, 0);
}
}
/*
** When Tcl stubs support is enabled, attempts to dynamically load the Tcl
** shared library and fetch the function pointers necessary to create an
** interpreter and initialize the stubs mechanism; otherwise, simply setup
** the function pointers provided by the caller with the statically linked
** functions.
*/
static int loadTcl(
Th_Interp *interp,
void **pLibrary,
tcl_FindExecutableProc **pxFindExecutable,
tcl_CreateInterpProc **pxCreateInterp,
tcl_DeleteInterpProc **pxDeleteInterp,
tcl_FinalizeProc **pxFinalize
){
#if defined(USE_TCL_STUBS)
char fileName[] = TCL_LIBRARY_NAME;
#endif /* defined(USE_TCL_STUBS) */
if( !pLibrary || !pxFindExecutable || !pxCreateInterp ||
!pxDeleteInterp || !pxFinalize ){
Th_ErrorMessage(interp,
"invalid Tcl loader argument(s)", (const char *)"", 0);
return TH_ERROR;
}
#if defined(USE_TCL_STUBS)
do {
void *library = dlopen(fileName, RTLD_NOW | RTLD_GLOBAL);
if( library ){
tcl_FindExecutableProc *xFindExecutable;
tcl_CreateInterpProc *xCreateInterp;
tcl_DeleteInterpProc *xDeleteInterp;
tcl_FinalizeProc *xFinalize;
const char *procName = TCL_FINDEXECUTABLE_NAME;
xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName + 1);
if( !xFindExecutable ){
xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName);
}
if( !xFindExecutable ){
Th_ErrorMessage(interp,
|
| ︙ | ︙ | |||
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 |
xCreateInterp = (tcl_CreateInterpProc *)dlsym(library, procName);
}
if( !xCreateInterp ){
Th_ErrorMessage(interp,
"could not locate Tcl_CreateInterp", (const char *)"", 0);
dlclose(library);
return TH_ERROR;
}
*pLibrary = library;
*pxFindExecutable = xFindExecutable;
*pxCreateInterp = xCreateInterp;
return TH_OK;
}
} while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */
Th_ErrorMessage(interp,
| > > > > > > > > > > > > > > > > > > > > > > > > > | | > > | | > | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 |
xCreateInterp = (tcl_CreateInterpProc *)dlsym(library, procName);
}
if( !xCreateInterp ){
Th_ErrorMessage(interp,
"could not locate Tcl_CreateInterp", (const char *)"", 0);
dlclose(library);
return TH_ERROR;
}
procName = TCL_DELETEINTERP_NAME;
xDeleteInterp = (tcl_DeleteInterpProc *)dlsym(library, procName + 1);
if( !xDeleteInterp ){
xDeleteInterp = (tcl_DeleteInterpProc *)dlsym(library, procName);
}
if( !xDeleteInterp ){
Th_ErrorMessage(interp,
"could not locate Tcl_DeleteInterp", (const char *)"", 0);
dlclose(library);
return TH_ERROR;
}
procName = TCL_FINALIZE_NAME;
xFinalize = (tcl_FinalizeProc *)dlsym(library, procName + 1);
if( !xFinalize ){
xFinalize = (tcl_FinalizeProc *)dlsym(library, procName);
}
if( !xFinalize ){
Th_ErrorMessage(interp,
"could not locate Tcl_Finalize", (const char *)"", 0);
dlclose(library);
return TH_ERROR;
}
*pLibrary = library;
*pxFindExecutable = xFindExecutable;
*pxCreateInterp = xCreateInterp;
*pxDeleteInterp = xDeleteInterp;
*pxFinalize = xFinalize;
return TH_OK;
}
} while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */
fileName[TCL_MINOR_OFFSET] = 'x';
Th_ErrorMessage(interp,
"could not load any supported Tcl 8.6, 8.5, or 8.4 shared library \"",
fileName, -1);
return TH_ERROR;
#else
*pLibrary = 0;
*pxFindExecutable = Tcl_FindExecutable;
*pxCreateInterp = Tcl_CreateInterp;
*pxDeleteInterp = Tcl_DeleteInterp;
*pxFinalize = Tcl_Finalize;
return TH_OK;
#endif /* defined(USE_TCL_STUBS) */
}
/*
** Sets the "argv0", "argc", and "argv" script variables in the Tcl interpreter
** based on the supplied command line arguments.
*/
static int setTclArguments(
Tcl_Interp *pInterp,
int argc,
char **argv
){
Tcl_Obj *objPtr;
Tcl_Obj *resultObjPtr;
Tcl_Obj *listPtr;
int rc = TCL_OK;
if( argc<=0 || !argv ){
return TCL_OK;
}
objPtr = Tcl_NewStringObj(argv[0], -1);
Tcl_IncrRefCount(objPtr);
resultObjPtr = Tcl_SetVar2Ex(pInterp, "argv0", NULL, objPtr,
TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG);
|
| ︙ | ︙ | |||
635 636 637 638 639 640 641 642 643 644 645 646 |
if( !resultObjPtr ){
rc = TCL_ERROR;
}
}
Tcl_DecrRefCount(listPtr);
return rc;
}
/*
** Creates and initializes a Tcl interpreter for use with the specified TH1
** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
** by the caller.
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > | > > > > > > > > > > > | > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 |
if( !resultObjPtr ){
rc = TCL_ERROR;
}
}
Tcl_DecrRefCount(listPtr);
return rc;
}
/*
** Evaluate a Tcl script, creating the Tcl interpreter if necessary. If the
** Tcl script succeeds, start a Tcl event loop until there are no more events
** remaining to process -OR- the script calls [exit]. If the bWait argument
** is zero, only process events that are already in the queue; otherwise,
** process events until the script terminates the Tcl event loop.
*/
int evaluateTclWithEvents(
Th_Interp *interp,
void *pContext,
const char *zScript,
int nScript,
int bWait
){
struct TclContext *tclContext = (struct TclContext *)pContext;
Tcl_Interp *tclInterp;
int rc;
int flags = TCL_ALL_EVENTS;
if( createTclInterp(interp, pContext)!=TH_OK ){
return TH_ERROR;
}
tclInterp = tclContext->interp;
rc = Tcl_EvalEx(tclInterp, zScript, nScript, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ) return rc;
if( !bWait ) flags |= TCL_DONT_WAIT;
while( Tcl_DoOneEvent(flags) ){
/* do nothing */
}
return rc;
}
/*
** Creates and initializes a Tcl interpreter for use with the specified TH1
** interpreter. Stores the created Tcl interpreter in the Tcl context supplied
** by the caller.
*/
static int createTclInterp(
Th_Interp *interp,
void *pContext
){
struct TclContext *tclContext = (struct TclContext *)pContext;
int argc;
char **argv;
char *argv0 = 0;
Tcl_Interp *tclInterp;
char *setup;
if( !tclContext ){
Th_ErrorMessage(interp,
"invalid Tcl context", (const char *)"", 0);
return TH_ERROR;
}
if( tclContext->interp ){
return TH_OK;
}
if( loadTcl(interp, &tclContext->library, &tclContext->xFindExecutable,
&tclContext->xCreateInterp, &tclContext->xDeleteInterp,
&tclContext->xFinalize)!=TH_OK ){
return TH_ERROR;
}
argc = tclContext->argc;
argv = tclContext->argv;
if( argc>0 && argv ){
argv0 = argv[0];
}
tclContext->xFindExecutable(argv0);
tclInterp = tclContext->xCreateInterp();
if( !tclInterp ){
Th_ErrorMessage(interp,
"could not create Tcl interpreter", (const char *)"", 0);
return TH_ERROR;
}
#if defined(USE_TCL_STUBS)
#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
if( initTclStubs(interp, tclInterp)!=TH_OK ){
tclContext->xDeleteInterp(tclInterp);
tclInterp = 0;
return TH_ERROR;
}
#else
if( !Tcl_InitStubs(tclInterp, "8.4", 0) ){
Th_ErrorMessage(interp,
"could not initialize Tcl stubs", (const char *)"", 0);
tclContext->xDeleteInterp(tclInterp);
tclInterp = 0;
return TH_ERROR;
}
#endif /* defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) */
#endif /* defined(USE_TCL_STUBS) */
if( Tcl_InterpDeleted(tclInterp) ){
Th_ErrorMessage(interp,
"Tcl interpreter appears to be deleted", (const char *)"", 0);
Tcl_DeleteInterp(tclInterp); /* TODO: Redundant? */
tclInterp = 0;
return TH_ERROR;
}
tclContext->interp = tclInterp;
if( Tcl_Init(tclInterp)!=TCL_OK ){
Th_ErrorMessage(interp,
"Tcl initialization error:", Tcl_GetStringResult(tclInterp), -1);
Tcl_DeleteInterp(tclInterp);
tclContext->interp = tclInterp = 0;
return TH_ERROR;
}
if( setTclArguments(tclInterp, argc, argv)!=TCL_OK ){
Th_ErrorMessage(interp,
"Tcl error setting arguments:", Tcl_GetStringResult(tclInterp), -1);
Tcl_DeleteInterp(tclInterp);
tclContext->interp = tclInterp = 0;
return TH_ERROR;
}
/*
** Determine if an objProc can be called directly for a Tcl command invoked
** via the tclInvoke TH1 command.
*/
tclContext->useObjProc = canUseObjProc();
/* Add the TH1 integration commands to Tcl. */
Tcl_CallWhenDeleted(tclInterp, Th1DeleteProc, interp);
Tcl_CreateObjCommand(tclInterp, "th1Eval", Th1EvalObjCmd, interp, NULL);
Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL);
/* If necessary, evaluate the custom Tcl setup script. */
setup = tclContext->setup;
if( setup && Tcl_Eval(tclInterp, setup)!=TCL_OK ){
Th_ErrorMessage(interp,
"Tcl setup script error:", Tcl_GetStringResult(tclInterp), -1);
Tcl_DeleteInterp(tclInterp);
tclContext->interp = tclInterp = 0;
return TH_ERROR;
}
return TH_OK;
}
/*
** Finalizes and unloads the previously loaded Tcl library, if applicable.
*/
int unloadTcl(
Th_Interp *interp,
void *pContext
){
struct TclContext *tclContext = (struct TclContext *)pContext;
Tcl_Interp *tclInterp;
tcl_FinalizeProc *xFinalize;
#if defined(USE_TCL_STUBS)
void *library;
#endif /* defined(USE_TCL_STUBS) */
if( !tclContext ){
Th_ErrorMessage(interp,
"invalid Tcl context", (const char *)"", 0);
return TH_ERROR;
}
/*
** Grab the Tcl_Finalize function pointer prior to deleting the Tcl
** interpreter because the memory backing the Tcl stubs table will
** be going away.
*/
xFinalize = tclContext->xFinalize;
/*
** If the Tcl interpreter has been created, formally delete it now.
*/
tclInterp = tclContext->interp;
if( tclInterp ){
Tcl_DeleteInterp(tclInterp);
tclContext->interp = tclInterp = 0;
}
/*
** If the Tcl library is not finalized prior to unloading it, a deadlock
** can occur in some circumstances (i.e. the [clock] thread is running).
*/
if( xFinalize ) xFinalize();
#if defined(USE_TCL_STUBS)
/*
** If Tcl is compiled on Windows using the latest MinGW, Fossil can crash
** when exiting while a stubs-enabled Tcl is still loaded. This is due to
** a bug in MinGW, see:
**
** http://comments.gmane.org/gmane.comp.gnu.mingw.user/41724
**
** The workaround is to manually unload the loaded Tcl library prior to
** exiting the process.
*/
library = tclContext->library;
if( library ){
dlclose(library);
tclContext->library = library = 0;
}
#endif /* defined(USE_TCL_STUBS) */
return TH_OK;
}
/*
** Register the Tcl language commands with interpreter interp.
** Usually this is called soon after interpreter creation.
*/
int th_register_tcl(
Th_Interp *interp,
void *pContext
){
int i;
/* Add the Tcl integration commands to TH1. */
for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
void *ctx;
if( !aCommand[i].zName || !aCommand[i].xProc ) continue;
ctx = aCommand[i].pContext;
/* Use Tcl interpreter for context? */
if( !ctx ) ctx = pContext;
Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
}
return TH_OK;
}
#endif /* FOSSIL_ENABLE_TCL */
|
Changes to src/timeline.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to implement the timeline web page ** */ #include <string.h> #include <time.h> | > < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to implement the timeline web page
**
*/
#include "config.h"
#include <string.h>
#include <time.h>
#include "timeline.h"
/*
** Shorten a UUID so that is the minimum length needed to contain
** at least one digit in the range 'a'..'f'. The minimum length is 10.
*/
static void shorten_uuid(char *zDest, const char *zSrc){
|
| ︙ | ︙ | |||
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
#define TIMELINE_BRIEF 0x0004 /* Combine adjacent elements of same object */
#define TIMELINE_GRAPH 0x0008 /* Compute a graph */
#define TIMELINE_DISJOINT 0x0010 /* Elements are not contiguous */
#define TIMELINE_FCHANGES 0x0020 /* Detail file changes */
#define TIMELINE_BRCOLOR 0x0040 /* Background color by branch name */
#define TIMELINE_UCOLOR 0x0080 /* Background color by user */
#define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */
#endif
/*
** Hash a string and use the hash to determine a background color.
*/
char *hash_color(const char *z){
int i; /* Loop counter */
| > | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
#define TIMELINE_BRIEF 0x0004 /* Combine adjacent elements of same object */
#define TIMELINE_GRAPH 0x0008 /* Compute a graph */
#define TIMELINE_DISJOINT 0x0010 /* Elements are not contiguous */
#define TIMELINE_FCHANGES 0x0020 /* Detail file changes */
#define TIMELINE_BRCOLOR 0x0040 /* Background color by branch name */
#define TIMELINE_UCOLOR 0x0080 /* Background color by user */
#define TIMELINE_FRENAMES 0x0100 /* Detail only file name changes */
#define TIMELINE_UNHIDE 0x0200 /* Unhide check-ins with "hidden" tag */
#endif
/*
** Hash a string and use the hash to determine a background color.
*/
char *hash_color(const char *z){
int i; /* Loop counter */
|
| ︙ | ︙ | |||
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
char zPrevDate[20];
GraphContext *pGraph = 0;
int prevWasDivider = 0; /* True if previous output row was <hr> */
int fchngQueryInit = 0; /* True if fchngQuery is initialized */
Stmt fchngQuery; /* Query for file changes on check-ins */
static Stmt qbranch;
int pendingEndTr = 0; /* True if a </td></tr> is needed */
zPrevDate[0] = 0;
mxWikiLen = db_get_int("timeline-max-comment", 0);
if( tmFlags & TIMELINE_GRAPH ){
pGraph = graph_init();
/* style is not moved to css, because this is
** a technical div for the timeline graph
*/
@ <div id="canvas" style="position:relative;height:0px;width:0px;"
@ onclick="clickOnGraph(event)"></div>
| > > > > > > > > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
char zPrevDate[20];
GraphContext *pGraph = 0;
int prevWasDivider = 0; /* True if previous output row was <hr> */
int fchngQueryInit = 0; /* True if fchngQuery is initialized */
Stmt fchngQuery; /* Query for file changes on check-ins */
static Stmt qbranch;
int pendingEndTr = 0; /* True if a </td></tr> is needed */
int vid = 0; /* Current checkout version */
int dateFormat = 0; /* 0: HH:MM 1: HH:MM:SS
2: YYYY-MM-DD HH:MM
3: YYMMDD HH:MM */
if( fossil_strcmp(g.zIpAddr, "127.0.0.1")==0 && db_open_local(0) ){
vid = db_lget_int("checkout", 0);
}
zPrevDate[0] = 0;
mxWikiLen = db_get_int("timeline-max-comment", 0);
dateFormat = db_get_int("timeline-date-format", 0);
if( tmFlags & TIMELINE_GRAPH ){
pGraph = graph_init();
/* style is not moved to css, because this is
** a technical div for the timeline graph
*/
@ <div id="canvas" style="position:relative;height:0px;width:0px;"
@ onclick="clickOnGraph(event)"></div>
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 |
const char *zUser = db_column_text(pQuery, 4);
const char *zTagList = db_column_text(pQuery, 8);
int tagid = db_column_int(pQuery, 9);
const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
const char *zBr = 0; /* Branch */
int commentColumn = 3; /* Column containing comment text */
int modPending; /* Pending moderation */
| | > | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
const char *zUser = db_column_text(pQuery, 4);
const char *zTagList = db_column_text(pQuery, 8);
int tagid = db_column_int(pQuery, 9);
const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
const char *zBr = 0; /* Branch */
int commentColumn = 3; /* Column containing comment text */
int modPending; /* Pending moderation */
char zTime[20];
if( zDate==0 ) zDate = "YYYY-MM-DD HH:MM:SS"; /* Something wrong with the repo */
modPending = moderation_pending(rid);
if( tagid ){
if( modPending ) tagid = -tagid;
if( tagid==prevTagid ){
if( tmFlags & TIMELINE_BRIEF ){
suppressCnt++;
continue;
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 |
if( !prevWasDivider ){
@ <tr><td colspan="3"><hr /></td></tr>
}
prevWasDivider = 1;
continue;
}
prevWasDivider = 0;
| > | | | | | | | | > > > > > > > > > > > > > > > > > > | > | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
if( !prevWasDivider ){
@ <tr><td colspan="3"><hr /></td></tr>
}
prevWasDivider = 1;
continue;
}
prevWasDivider = 0;
if( dateFormat<2 ){
if( fossil_strnicmp(zDate, zPrevDate, 10) ){
sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
@ <tr><td>
@ <div class="divider timelineDate">%s(zPrevDate)</div>
@ </td><td></td><td></td></tr>
}
memcpy(zTime, &zDate[11], 5+dateFormat*3);
zTime[5+dateFormat*3] = 0;
}else if(3==dateFormat){
/* YYMMDD HH:MM */
int pos = 0;
zTime[pos++] = zDate[2]; zTime[pos++] = zDate[3]; /* YY */
zTime[pos++] = zDate[5]; zTime[pos++] = zDate[6]; /* MM */
zTime[pos++] = zDate[8]; zTime[pos++] = zDate[9]; /* DD */
zTime[pos++] = ' ';
zTime[pos++] = zDate[11]; zTime[pos++] = zDate[12]; /* HH */
zTime[pos++] = ':';
zTime[pos++] = zDate[14]; zTime[pos++] = zDate[15]; /* MM */
zTime[pos++] = 0;
}else{
/* YYYY-MM-DD HH:MM */
sqlite3_snprintf(sizeof(zTime), zTime, "%.16s", zDate);
}
if( rid == vid ){
@ <tr class="timelineCurrent">
}else {
@ <tr>
}
@ <td class="timelineTime">%s(zTime)</td>
@ <td class="timelineGraph">
if( tmFlags & TIMELINE_UCOLOR ) zBgClr = zUser ? hash_color(zUser) : 0;
if( zType[0]=='c'
&& (pGraph || zBgClr==0 || (tmFlags & TIMELINE_BRCOLOR)!=0)
){
db_reset(&qbranch);
|
| ︙ | ︙ | |||
559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
int omitDescenders, /* True to omit descenders */
int fileDiff /* True for file diff. False for check-in diff */
){
if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
GraphRow *pRow;
int i;
char cSep;
@ <script type="text/JavaScript">
@ /* <![CDATA[ */
@ var railPitch=%d(pGraph->iRailPitch);
/* the rowinfo[] array contains all the information needed to generate
** the graph. Each entry contains information for a single row:
**
| > | 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
int omitDescenders, /* True to omit descenders */
int fileDiff /* True for file diff. False for check-in diff */
){
if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
GraphRow *pRow;
int i;
char cSep;
@ <script type="text/JavaScript">
@ /* <![CDATA[ */
@ var railPitch=%d(pGraph->iRailPitch);
/* the rowinfo[] array contains all the information needed to generate
** the graph. Each entry contains information for a single row:
**
|
| ︙ | ︙ | |||
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
}
if( cSep=='[' ) cgi_printf("[");
cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
}
cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
graph_free(pGraph);
@ var canvasDiv = gebi("canvas");
@ function drawBox(color,x0,y0,x1,y1){
@ var n = document.createElement("div");
@ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
@ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
@ var w = x1-x0+1;
@ var h = y1-y0+1;
@ n.style.position = "absolute";
@ n.style.overflow = "hidden";
@ n.style.left = x0+"px";
@ n.style.top = y0+"px";
@ n.style.width = w+"px";
@ n.style.height = h+"px";
@ n.style.backgroundColor = color;
| > > > > > < | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 |
}
if( cSep=='[' ) cgi_printf("[");
cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
}
cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
graph_free(pGraph);
@ var canvasDiv = gebi("canvas");
@ var canvasStyle = window.getComputedStyle && window.getComputedStyle(canvasDiv,null);
@ var lineColor = (canvasStyle && canvasStyle.getPropertyValue('color')) || 'black';
@ var bgColor = (canvasStyle && canvasStyle.getPropertyValue('background-color')) || 'white';
@ if( bgColor=='transparent' ) bgColor = 'white';
@ var boxColor = lineColor;
@ function drawBox(color,x0,y0,x1,y1){
@ var n = document.createElement("div");
@ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
@ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
@ var w = x1-x0+1;
@ var h = y1-y0+1;
@ n.style.position = "absolute";
@ n.style.overflow = "hidden";
@ n.style.left = x0+"px";
@ n.style.top = y0+"px";
@ n.style.width = w+"px";
@ n.style.height = h+"px";
@ n.style.backgroundColor = color;
@ canvasDiv.appendChild(n);
@ return n;
@ }
@ function absoluteY(id){
@ var obj = gebi(id);
@ if( !obj ) return;
@ var top = 0;
|
| ︙ | ︙ | |||
679 680 681 682 683 684 685 |
@ do{
@ left += obj.offsetLeft;
@ }while( obj = obj.offsetParent );
@ }
@ return left;
@ }
@ function drawUpArrow(x,y0,y1){
| | | | | | | | | | | | | > > > | | | | 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 |
@ do{
@ left += obj.offsetLeft;
@ }while( obj = obj.offsetParent );
@ }
@ return left;
@ }
@ function drawUpArrow(x,y0,y1){
@ drawBox(lineColor,x,y0,x+1,y1);
@ if( y0+10>=y1 ){
@ drawBox(lineColor,x-1,y0+1,x+2,y0+2);
@ drawBox(lineColor,x-2,y0+3,x+3,y0+4);
@ }else{
@ drawBox(lineColor,x-1,y0+2,x+2,y0+4);
@ drawBox(lineColor,x-2,y0+5,x+3,y0+7);
@ }
@ }
@ function drawThinArrow(y,xFrom,xTo){
@ if( xFrom<xTo ){
@ drawBox(lineColor,xFrom,y,xTo,y);
@ drawBox(lineColor,xTo-3,y-1,xTo-2,y+1);
@ drawBox(lineColor,xTo-4,y-2,xTo-4,y+2);
@ }else{
@ drawBox(lineColor,xTo,y,xFrom,y);
@ drawBox(lineColor,xTo+2,y-1,xTo+3,y+1);
@ drawBox(lineColor,xTo+4,y-2,xTo+4,y+2);
@ }
@ }
@ function drawThinLine(x0,y0,x1,y1){
@ drawBox(lineColor,x0,y0,x1,y1);
@ }
@ function drawNodeBox(color,x0,y0,x1,y1){
@ drawBox(color,x0,y0,x1,y1).style.cursor = "pointer";
@ }
@ function drawNode(p, left, btm){
@ drawNodeBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6);
@ drawNodeBox(p.bg||bgColor,p.x-4,p.y-4,p.x+5,p.y+5);
@ if( p.u>0 ) drawUpArrow(p.x, rowinfo[p.u-1].y+6, p.y-5);
@ if( p.f&1 ) drawNodeBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2);
if( !omitDescenders ){
@ if( p.u==0 ) drawUpArrow(p.x, 0, p.y-5);
@ if( p.d ) drawUpArrow(p.x, p.y+6, btm);
}
@ if( p.mo>0 ){
@ var x1 = p.mo + left - 1;
@ var y1 = p.y-3;
|
| ︙ | ︙ | |||
730 731 732 733 734 735 736 |
@ }
@ var n = p.au.length;
@ for(var i=0; i<n; i+=2){
@ var x1 = p.au[i]*railPitch + left;
@ var x0 = x1>p.x ? p.x+7 : p.x-6;
@ var u = rowinfo[p.au[i+1]-1];
@ if(u.id<p.id){
| | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 |
@ }
@ var n = p.au.length;
@ for(var i=0; i<n; i+=2){
@ var x1 = p.au[i]*railPitch + left;
@ var x0 = x1>p.x ? p.x+7 : p.x-6;
@ var u = rowinfo[p.au[i+1]-1];
@ if(u.id<p.id){
@ drawBox(lineColor,x0,p.y,x1,p.y+1);
@ drawUpArrow(x1, u.y+6, p.y);
@ }else{
@ drawBox("#600000",x0,p.y,x1,p.y+1);
@ drawBox("#600000",x1-1,p.y,x1,u.y+1);
@ drawBox("#600000",x1,u.y,u.x-6,u.y+1);
@ drawBox("#600000",u.x-9,u.y-1,u.x-8,u.y+2);
@ drawBox("#600000",u.x-11,u.y-2,u.x-10,u.y+3);
|
| ︙ | ︙ | |||
813 814 815 816 817 818 819 |
@ canvasDiv.removeChild(selBox);
@ selBox = null;
@ selRow = null;
@ }else{
if( fileDiff ){
@ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
}else{
| > > > | > | 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
@ canvasDiv.removeChild(selBox);
@ selBox = null;
@ selRow = null;
@ }else{
if( fileDiff ){
@ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
}else{
if( db_get_boolean("show-version-diffs", 0)==0 ){
@ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=0";
}else{
@ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=1";
}
}
@ }
@ }
@ var lastId = "m"+rowinfo[rowinfo.length-1].id;
@ var lastY = 0;
@ function checkHeight(){
@ var h = absoluteY(lastId);
|
| ︙ | ︙ | |||
861 862 863 864 865 866 867 |
}
/*
** Return a pointer to a constant string that forms the basis
** for a timeline query for the WWW interface.
*/
const char *timeline_query_for_www(void){
| | | | | 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 |
}
/*
** Return a pointer to a constant string that forms the basis
** for a timeline query for the WWW interface.
*/
const char *timeline_query_for_www(void){
static const char *zBase = 0;
static const char zBaseSql[] =
@ SELECT
@ blob.rid AS blobRid,
@ uuid AS uuid,
@ datetime(event.mtime%s) AS timestamp,
@ coalesce(ecomment, comment) AS comment,
@ coalesce(euser, user) AS user,
@ blob.rid IN leaf AS leaf,
@ bgcolor AS bgColor,
@ event.type AS eventType,
@ (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
@ AND tagxref.rid=blob.rid AND tagxref.tagtype>0) AS tags,
@ tagid AS tagid,
@ brief AS brief,
@ event.mtime AS mtime
@ FROM event CROSS JOIN blob
@ WHERE blob.rid=event.objid
;
if( zBase==0 ){
zBase = mprintf(zBaseSql, timeline_utc());
}
return zBase;
}
/*
** Generate a submenu element with a single parameter change.
*/
|
| ︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 |
const char *zBefore = P("b"); /* Events before this time */
const char *zCirca = P("c"); /* Events near this time */
const char *zTagName = P("t"); /* Show events with this tag */
const char *zBrName = P("r"); /* Show events related to this tag */
const char *zSearch = P("s"); /* Search string */
const char *zUses = P("uf"); /* Only show checkins hold this file */
const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */
int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */
int tagid; /* Tag ID */
int tmFlags; /* Timeline flags */
const char *zThisTag = 0; /* Suppress links to this tag */
const char *zThisUser = 0; /* Suppress links to this user */
HQuery url; /* URL for various branch links */
| > | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
const char *zBefore = P("b"); /* Events before this time */
const char *zCirca = P("c"); /* Events near this time */
const char *zTagName = P("t"); /* Show events with this tag */
const char *zBrName = P("r"); /* Show events related to this tag */
const char *zSearch = P("s"); /* Search string */
const char *zUses = P("uf"); /* Only show checkins hold this file */
const char *zYearMonth = P("ym"); /* Show checkins for the given YYYY-MM */
const char *zYearWeek = P("yw"); /* Show checkins for the given YYYY-WW (weak-of-year) */
int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
int renameOnly = P("namechng")!=0; /* Show only checkins that rename files */
int tagid; /* Tag ID */
int tmFlags; /* Timeline flags */
const char *zThisTag = 0; /* Suppress links to this tag */
const char *zThisUser = 0; /* Suppress links to this user */
HQuery url; /* URL for various branch links */
|
| ︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 |
tagid = 0;
}
if( zType[0]=='a' ){
tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
}else{
tmFlags = TIMELINE_GRAPH;
}
if( P("ng")!=0 || zSearch!=0 ){
tmFlags &= ~TIMELINE_GRAPH;
url_add_parameter(&url, "ng", 0);
}
if( P("brbg")!=0 ){
tmFlags |= TIMELINE_BRCOLOR;
url_add_parameter(&url, "brbg", 0);
}
if( P("ubg")!=0 ){
tmFlags |= TIMELINE_UCOLOR;
url_add_parameter(&url, "ubg", 0);
}
if( zUses!=0 ){
int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses);
if( ufid ){
| > > > > > | 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 |
tagid = 0;
}
if( zType[0]=='a' ){
tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
}else{
tmFlags = TIMELINE_GRAPH;
}
url_add_parameter(&url, "n", mprintf("%d", nEntry));
if( P("ng")!=0 || zSearch!=0 ){
tmFlags &= ~TIMELINE_GRAPH;
url_add_parameter(&url, "ng", 0);
}
if( P("brbg")!=0 ){
tmFlags |= TIMELINE_BRCOLOR;
url_add_parameter(&url, "brbg", 0);
}
if( P("unhide")!=0 ){
tmFlags |= TIMELINE_UNHIDE;
url_add_parameter(&url, "unhide", 0);
}
if( P("ubg")!=0 ){
tmFlags |= TIMELINE_UCOLOR;
url_add_parameter(&url, "ubg", 0);
}
if( zUses!=0 ){
int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses);
if( ufid ){
|
| ︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 |
blob_zero(&sql);
blob_zero(&desc);
blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
blob_append(&sql, timeline_query_for_www(), -1);
if( P("fc")!=0 || P("v")!=0 || P("detail")!=0 ){
tmFlags |= TIMELINE_FCHANGES;
url_add_parameter(&url, "v", 0);
}
if( !useDividers ) url_add_parameter(&url, "nd", 0);
if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){
/* If from= and to= are present, display all nodes on a path connecting
** the two */
PathNode *p = 0;
const char *zFrom = 0;
| > > > > > | 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 |
blob_zero(&sql);
blob_zero(&desc);
blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
blob_append(&sql, timeline_query_for_www(), -1);
if( P("fc")!=0 || P("v")!=0 || P("detail")!=0 ){
tmFlags |= TIMELINE_FCHANGES;
url_add_parameter(&url, "v", 0);
}
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
blob_appendf(&sql, " AND NOT EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)",
TAG_HIDDEN);
}
if( !useDividers ) url_add_parameter(&url, "nd", 0);
if( ((from_rid && to_rid) || (me_rid && you_rid)) && g.perm.Read ){
/* If from= and to= are present, display all nodes on a path connecting
** the two */
PathNode *p = 0;
const char *zFrom = 0;
|
| ︙ | ︙ | |||
1141 1142 1143 1144 1145 1146 1147 |
while( p ){
blob_appendf(&sql, ",%d", p->rid);
p = p->u.pTo;
}
blob_append(&sql, ")", -1);
path_reset();
blob_append(&desc, "All nodes on the path from ", -1);
| | | | 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 |
while( p ){
blob_appendf(&sql, ",%d", p->rid);
p = p->u.pTo;
}
blob_append(&sql, ")", -1);
path_reset();
blob_append(&desc, "All nodes on the path from ", -1);
blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h", zFrom), zFrom);
blob_append(&desc, " to ", -1);
blob_appendf(&desc, "%z[%h]</a>", href("%R/info/%h",zTo), zTo);
tmFlags |= TIMELINE_DISJOINT;
db_multi_exec("%s", blob_str(&sql));
}else if( (p_rid || d_rid) && g.perm.Read ){
/* If p= or d= is present, ignore all other parameters other than n= */
char *zUuid;
int np, nd;
|
| ︙ | ︙ | |||
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
blob_appendf(&desc, "%d ancestors", np);
db_multi_exec("%s", blob_str(&sql));
}
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
}
blob_appendf(&desc, " of %z[%.10s]</a>",
href("%R/info/%s", zUuid), zUuid);
}else if( f_rid && g.perm.Read ){
/* If f= is present, ignore all other parameters other than n= */
char *zUuid;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
"INSERT INTO ok VALUES(%d);"
"INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;"
"INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;",
f_rid, f_rid, f_rid
);
blob_appendf(&sql, " AND event.objid IN ok");
db_multi_exec("%s", blob_str(&sql));
if( useDividers ) timeline_add_dividers(0, f_rid);
blob_appendf(&desc, "Parents and children of check-in ");
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
tmFlags |= TIMELINE_DISJOINT;
}else{
/* Otherwise, a timeline based on a span of time */
int n;
const char *zEType = "timeline item";
char *zDate;
| > > > > > > > > > > > > > > > > > < < > > > > | > > > > > > > | > > > > > | 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 |
blob_appendf(&desc, "%d ancestors", np);
db_multi_exec("%s", blob_str(&sql));
}
if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
}
blob_appendf(&desc, " of %z[%.10s]</a>",
href("%R/info/%s", zUuid), zUuid);
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
if( p_rid ){
url_add_parameter(&url, "p", zUuid);
}
if( d_rid ){
if( p_rid ){
/* If both p= and d= are set, we don't have the uuid of d yet. */
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
}
url_add_parameter(&url, "d", zUuid);
}
timeline_submenu(&url, "Unhide", "unhide", "", 0);
}
}else if( f_rid && g.perm.Read ){
/* If f= is present, ignore all other parameters other than n= */
char *zUuid;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);"
"INSERT INTO ok VALUES(%d);"
"INSERT OR IGNORE INTO ok SELECT pid FROM plink WHERE cid=%d;"
"INSERT OR IGNORE INTO ok SELECT cid FROM plink WHERE pid=%d;",
f_rid, f_rid, f_rid
);
blob_appendf(&sql, " AND event.objid IN ok");
db_multi_exec("%s", blob_str(&sql));
if( useDividers ) timeline_add_dividers(0, f_rid);
blob_appendf(&desc, "Parents and children of check-in ");
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid);
blob_appendf(&desc, "%z[%.10s]</a>", href("%R/info/%s", zUuid), zUuid);
tmFlags |= TIMELINE_DISJOINT;
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
url_add_parameter(&url, "f", zUuid);
timeline_submenu(&url, "Unhide", "unhide", "", 0);
}
}else{
/* Otherwise, a timeline based on a span of time */
int n;
const char *zEType = "timeline item";
char *zDate;
if( zUses ){
blob_appendf(&sql, " AND event.objid IN usesfile ");
}
if( renameOnly ){
blob_appendf(&sql, " AND event.objid IN rnfile ");
}
if( zYearMonth ){
blob_appendf(&sql, " AND %Q=strftime('%%Y-%%m',event.mtime) ",
zYearMonth);
}
else if( zYearWeek ){
blob_appendf(&sql, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
zYearWeek);
}
if( tagid>0 ){
blob_appendf(&sql,
"AND (EXISTS(SELECT 1 FROM tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);
if( zBrName ){
url_add_parameter(&url, "r", zBrName);
/* The next two blob_appendf() calls add SQL that causes checkins that
** are not part of the branch which are parents or children of the
** branch to be included in the report. This related check-ins are
** useful in helping to visualize what has happened on a quiescent
** branch that is infrequently merged with a much more activate branch.
*/
blob_appendf(&sql,
" OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
tagid
);
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
blob_appendf(&sql,
" AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
" WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)",
TAG_HIDDEN
);
}
if( P("mionly")==0 ){
blob_appendf(&sql,
" OR EXISTS(SELECT 1 FROM plink CROSS JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
tagid
);
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
blob_appendf(&sql, " AND NOT EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
" WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)",
TAG_HIDDEN);
}
}else{
url_add_parameter(&url, "mionly", "1");
}
}else{
url_add_parameter(&url, "t", zTagName);
}
blob_appendf(&sql, ")");
|
| ︙ | ︙ | |||
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 |
}
blob_appendf(&sql, " LIMIT %d", nEntry);
db_multi_exec("%s", blob_str(&sql));
n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/");
if( zYearMonth ){
blob_appendf(&desc, "%s events for %h", zEType, zYearMonth);
}else if( zAfter==0 && zBefore==0 && zCirca==0 ){
blob_appendf(&desc, "%d most recent %ss", n, zEType);
}else{
blob_appendf(&desc, "%d %ss", n, zEType);
}
if( zUses ){
char *zFilenames = names_of_file(zUses);
| > > | 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 |
}
blob_appendf(&sql, " LIMIT %d", nEntry);
db_multi_exec("%s", blob_str(&sql));
n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/");
if( zYearMonth ){
blob_appendf(&desc, "%s events for %h", zEType, zYearMonth);
}else if( zYearWeek ){
blob_appendf(&desc, "%s events for year/week %h", zEType, zYearWeek);
}else if( zAfter==0 && zBefore==0 && zCirca==0 ){
blob_appendf(&desc, "%d most recent %ss", n, zEType);
}else{
blob_appendf(&desc, "%d %ss", n, zEType);
}
if( zUses ){
char *zFilenames = names_of_file(zUses);
|
| ︙ | ︙ | |||
1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 |
}
if( zType[0]=='a' || zType[0]=='c' ){
if( tmFlags & TIMELINE_FCHANGES ){
timeline_submenu(&url, "Hide Files", "v", 0, 0);
}else{
timeline_submenu(&url, "Show Files", "v", "", 0);
}
}
}
}
if( P("showsql") ){
@ <blockquote>%h(blob_str(&sql))</blockquote>
}
blob_zero(&sql);
db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
@ <h2>%b(&desc)</h2>
blob_reset(&desc);
www_print_timeline(&q, tmFlags, zThisUser, zThisTag, 0);
db_finalize(&q);
style_footer();
}
/*
** The input query q selects various records. Print a human-readable
** summary of those records.
**
| > > > > > > | > > > | > > | < > > | > > > > > > > > > | | | 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 |
}
if( zType[0]=='a' || zType[0]=='c' ){
if( tmFlags & TIMELINE_FCHANGES ){
timeline_submenu(&url, "Hide Files", "v", 0, 0);
}else{
timeline_submenu(&url, "Show Files", "v", "", 0);
}
if( (tmFlags & TIMELINE_UNHIDE)==0 ){
timeline_submenu(&url, "Unhide", "unhide", "", 0);
}
}
}
}
if( P("showsql") ){
@ <blockquote>%h(blob_str(&sql))</blockquote>
}
blob_zero(&sql);
db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
@ <h2>%b(&desc)</h2>
blob_reset(&desc);
www_print_timeline(&q, tmFlags, zThisUser, zThisTag, 0);
db_finalize(&q);
style_footer();
}
/*
** The input query q selects various records. Print a human-readable
** summary of those records.
**
** Limit number of lines or entries printed to nLimit. If nLimit is zero
** there is no limit. If nLimit is greater than zero, limit the number of
** complete entries printed. If nLimit is less than zero, attempt to limit
** the number of lines printed (this is basically the legacy behavior).
** The line limit, if used, is approximate because it is only checked on a
** per-entry basis. If verbose mode, the file name details are considered
** to be part of the entry.
**
** The query should return these columns:
**
** 0. rid
** 1. uuid
** 2. Date/Time
** 3. Comment string and user
** 4. Number of non-merge children
** 5. Number of parents
** 6. mtime
** 7. branch
*/
void print_timeline(Stmt *q, int nLimit, int width, int verboseFlag){
int nAbsLimit = (nLimit >= 0) ? nLimit : -nLimit;
int nLine = 0;
int nEntry = 0;
char zPrevDate[20];
const char *zCurrentUuid = 0;
int fchngQueryInit = 0; /* True if fchngQuery is initialized */
Stmt fchngQuery; /* Query for file changes on check-ins */
int rc;
zPrevDate[0] = 0;
if( g.localOpen ){
int rid = db_lget_int("checkout", 0);
zCurrentUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
}
while( (rc=db_step(q))==SQLITE_ROW ){
int rid = db_column_int(q, 0);
const char *zId = db_column_text(q, 1);
const char *zDate = db_column_text(q, 2);
const char *zCom = db_column_text(q, 3);
int nChild = db_column_int(q, 4);
int nParent = db_column_int(q, 5);
char *zFree = 0;
int n = 0;
char zPrefix[80];
char zUuid[UUID_SIZE+1];
if( nAbsLimit!=0 ){
if( nLimit<0 && nLine>=nAbsLimit ){
fossil_print("--- line limit (%d) reached ---\n", nAbsLimit);
break; /* line count limit hit, stop. */
}else if( nEntry>=nAbsLimit ){
fossil_print("--- entry limit (%d) reached ---\n", nAbsLimit);
break; /* entry count limit hit, stop. */
}
}
sqlite3_snprintf(sizeof(zUuid), zUuid, "%.10s", zId);
if( fossil_strnicmp(zDate, zPrevDate, 10) ){
fossil_print("=== %.10s ===\n", zDate);
memcpy(zPrevDate, zDate, 10);
nLine++; /* record another line */
}
if( zCom==0 ) zCom = "";
fossil_print("%.8s ", &zDate[11]);
zPrefix[0] = 0;
if( nParent>1 ){
sqlite3_snprintf(sizeof(zPrefix), zPrefix, "*MERGE* ");
n = strlen(zPrefix);
|
| ︙ | ︙ | |||
1516 1517 1518 1519 1520 1521 1522 |
n = strlen(zPrefix);
}
if( fossil_strcmp(zCurrentUuid,zId)==0 ){
sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*CURRENT* ");
n += strlen(zPrefix);
}
zFree = sqlite3_mprintf("[%.10s] %s%s", zUuid, zPrefix, zCom);
| | | 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 |
n = strlen(zPrefix);
}
if( fossil_strcmp(zCurrentUuid,zId)==0 ){
sqlite3_snprintf(sizeof(zPrefix)-n, &zPrefix[n], "*CURRENT* ");
n += strlen(zPrefix);
}
zFree = sqlite3_mprintf("[%.10s] %s%s", zUuid, zPrefix, zCom);
nLine += comment_print(zFree, 9, width); /* record another X lines */
sqlite3_free(zFree);
if(verboseFlag){
if( !fchngQueryInit ){
db_prepare(&fchngQuery,
"SELECT (pid==0) AS isnew,"
" (fid==0) AS isdel,"
|
| ︙ | ︙ | |||
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 |
if( isNew ){
fossil_print(" ADDED %s\n",zFilename);
}else if( isDel ){
fossil_print(" DELETED %s\n",zFilename);
}else{
fossil_print(" EDITED %s\n", zFilename);
}
}
db_reset(&fchngQuery);
}
}
if( fchngQueryInit ) db_finalize(&fchngQuery);
}
/*
** Return a pointer to a static string that forms the basis for
** a timeline query for display on a TTY.
*/
const char *timeline_query_for_tty(void){
static const char zBaseSql[] =
@ SELECT
@ blob.rid AS rid,
@ uuid,
| > > > > > > > > > > > | > > > | | 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 |
if( isNew ){
fossil_print(" ADDED %s\n",zFilename);
}else if( isDel ){
fossil_print(" DELETED %s\n",zFilename);
}else{
fossil_print(" EDITED %s\n", zFilename);
}
nLine++; /* record another line */
}
db_reset(&fchngQuery);
}
nEntry++; /* record another complete entry */
}
if( rc==SQLITE_DONE ){
/* Did the underlying query actually have all entries? */
if( nAbsLimit==0 ){
fossil_print("+++ end of timeline (%d) +++\n", nEntry);
}else{
fossil_print("+++ no more data (%d) +++\n", nEntry);
}
}
if( fchngQueryInit ) db_finalize(&fchngQuery);
}
/*
** Return a pointer to a static string that forms the basis for
** a timeline query for display on a TTY.
*/
const char *timeline_query_for_tty(void){
static const char *zBase = 0;
static const char zBaseSql[] =
@ SELECT
@ blob.rid AS rid,
@ uuid,
@ datetime(event.mtime%s) AS mDateTime,
@ coalesce(ecomment,comment)
@ || ' (user: ' || coalesce(euser,user,'?')
@ || (SELECT case when length(x)>0 then ' tags: ' || x else '' end
@ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
@ FROM tag, tagxref
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
@ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
@ || ')' as comment,
@ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim)
@ AS primPlinkCount,
@ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount,
@ event.mtime AS mtime,
@ tagxref.value AS branch
@ FROM tag CROSS JOIN event CROSS JOIN blob
@ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
@ AND tagxref.tagtype>0
@ AND tagxref.rid=blob.rid
@ WHERE blob.rid=event.objid
@ AND tag.tagname='branch'
;
if( zBase==0 ){
zBase = mprintf(zBaseSql, timeline_utc());
}
return zBase;
}
/*
** Return true if the input string is a date in the ISO 8601 format:
** YYYY-MM-DD.
*/
static int isIsoDate(const char *z){
|
| ︙ | ︙ | |||
1618 1619 1620 1621 1622 1623 1624 | ** ** The BASELINE can be any unique prefix of 4 characters or more. ** The DATETIME should be in the ISO8601 format. For ** examples: "2007-08-18 07:21:21". You can also say "current" ** for the current version or "now" for the current time. ** ** Options: | | > > > > | > > > > > | > > > > > > > > > > | > | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 |
**
** The BASELINE can be any unique prefix of 4 characters or more.
** The DATETIME should be in the ISO8601 format. For
** examples: "2007-08-18 07:21:21". You can also say "current"
** for the current version or "now" for the current time.
**
** Options:
** -n|--limit N Output the first N entries (default 20 lines).
** N=0 means no limit.
** --offset P skip P changes
** -t|--type TYPE Output items from the given types only, such as:
** ci = file commits only
** e = events only
** t = tickets only
** w = wiki commits only
** -v|--verbose Output the list of files changed by each commit
** and the type of each change (edited, deleted,
** etc.) after the checkin comment.
** -W|--width <num> With of lines (default 79). Must be >20 or 0
** (= no limit, resulting in a single line per entry).
*/
void timeline_cmd(void){
Stmt q;
int n, k, width;
const char *zLimit;
const char *zWidth;
const char *zOffset;
const char *zType;
char *zOrigin;
char *zDate;
Blob sql;
int objid = 0;
Blob uuid;
int mode = 0 ; /* 0:none 1: before 2:after 3:children 4:parents */
int verboseFlag = 0 ;
int iOffset;
verboseFlag = find_option("verbose","v", 0)!=0;
if( !verboseFlag){
verboseFlag = find_option("showfiles","f", 0)!=0; /* deprecated */
}
db_find_and_open_repository(0, 0);
zLimit = find_option("limit","n",1);
zWidth = find_option("width","W",1);
zType = find_option("type","t",1);
if ( !zLimit ){
zLimit = find_option("count",0,1);
}
if( zLimit ){
n = atoi(zLimit);
}else{
n = -20;
}
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("--width|-W value must be >20 or 0");
}
}else{
width = 79;
}
zOffset = find_option("offset",0,1);
iOffset = zOffset ? atoi(zOffset) : 0;
if( g.argc>=4 ){
k = strlen(g.argv[2]);
if( strncmp(g.argv[2],"before",k)==0 ){
mode = 1;
}else if( strncmp(g.argv[2],"after",k)==0 && k>1 ){
mode = 2;
}else if( strncmp(g.argv[2],"descendants",k)==0 ){
mode = 3;
}else if( strncmp(g.argv[2],"children",k)==0 ){
mode = 3;
}else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){
mode = 4;
}else if( strncmp(g.argv[2],"parents",k)==0 ){
mode = 4;
}else if(!zType && !zLimit){
usage("?WHEN? ?BASELINE|DATETIME? ?-n|--limit #? ?-t|--type TYPE? "
"?-W|--width WIDTH?");
}
if( '-' != *g.argv[3] ){
zOrigin = g.argv[3];
}else{
zOrigin = "now";
}
}else if( g.argc==3 ){
|
| ︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 1737 1738 |
}
blob_appendf(&sql, " AND blob.rid IN ok");
}
if( zType && (zType[0]!='a') ){
blob_appendf(&sql, " AND event.type=%Q ", zType);
}
blob_appendf(&sql, " ORDER BY event.mtime DESC");
db_prepare(&q, blob_str(&sql));
blob_reset(&sql);
| > > > > > | | < < < | < < > > | < | | | 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 |
}
blob_appendf(&sql, " AND blob.rid IN ok");
}
if( zType && (zType[0]!='a') ){
blob_appendf(&sql, " AND event.type=%Q ", zType);
}
blob_appendf(&sql, " ORDER BY event.mtime DESC");
if( iOffset>0 ){
/* Don't handle LIMIT here, otherwise print_timeline()
* will not determine the end-marker correctly! */
blob_appendf(&sql, " LIMIT -1 OFFSET %d", iOffset);
}
db_prepare(&q, blob_str(&sql));
blob_reset(&sql);
print_timeline(&q, n, width, verboseFlag);
db_finalize(&q);
}
/*
** Return one of two things:
**
** ",'localtime'" if the timeline-utc property is set to 0.
**
** "" (empty string) otherwise.
*/
const char *timeline_utc(){
if( g.fTimeFormat==0 ){
if( db_get_int("timeline-utc", 1) ){
g.fTimeFormat = 1;
}else{
g.fTimeFormat = 2;
}
}
if( g.fTimeFormat==1 ){
return "";
}else{
return ",'localtime'";
}
}
/*
** COMMAND: test-timewarp-list
**
|
| ︙ | ︙ | |||
1821 1822 1823 1824 1825 1826 1827 |
" FROM plink p, plink c, blob"
" WHERE p.cid=c.pid AND p.mtime>c.mtime"
" AND blob.rid=c.cid"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
@ <li>
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < | | | > > > > > | > | | > > > > > > > > > > > > > | | | > | > | | | | | | | | | | > > > > > > | | > > > > > > > > > > | | > | < | > | > | < < < > | < > > > > | | > | > > > > > > > | | | > > | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | | < > > > > > | | | > | 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 |
" FROM plink p, plink c, blob"
" WHERE p.cid=c.pid AND p.mtime>c.mtime"
" AND blob.rid=c.cid"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
@ <li>
@ <a href="%s(g.zTop)/timeline?p=%S(zUuid)&d=%S(zUuid)&unhide">%S(zUuid)</a>
}
db_finalize(&q);
style_footer();
}
/*
** Used by stats_report_xxxxx() to remember which type of events
** to show. Populated by stats_report_init_view() and holds the
** return value of that function.
*/
static int statsReportType = 0;
/*
** Set by stats_report_init_view() to one of the y=XXXX values
** accepted by /timeline?y=XXXX.
*/
static char const * statsReportTimelineYFlag = NULL;
/*
** Creates a TEMP VIEW named v_reports which is a wrapper around the
** EVENT table filtered on event.type. It looks for the request
** parameter 'type' (reminder: we "should" use 'y' for consistency
** with /timeline, but /reports uses 'y' for the year) and expects it
** to contain one of the conventional values from event.type or the
** value "all", which is treated as equivalent to "*". By default (if
** no 'y' is specified), "*" is assumed (that is also the default for
** invalid/unknown filter values). That 'y' filter is the one used for
** the event list. Note that a filter of "*" or "all" is equivalent to
** querying against the full event table. The view, however, adds an
** abstraction level to simplify the implementation code for the
** various /reports pages.
**
** Returns one of: 'c', 'w', 'g', 't', 'e', representing the type of
** filter it applies, or '*' if no filter is applied (i.e. if "all" is
** used).
*/
static int stats_report_init_view(){
char const * zType = PD("type","*"); /* analog to /timeline?y=... */
char const * zRealType = NULL; /* normalized form of zType */
int rc = 0; /* result code */
assert( !statsReportType && "Must not be called more than once." );
switch( (zType && *zType) ? *zType : 0 ){
case 'c':
case 'C':
zRealType = "ci";
rc = *zRealType;
break;
case 'e':
case 'E':
zRealType = "e";
rc = *zRealType;
break;
case 'g':
case 'G':
zRealType = "g";
rc = *zRealType;
break;
case 't':
case 'T':
zRealType = "t";
rc = *zRealType;
break;
case 'w':
case 'W':
zRealType = "w";
rc = *zRealType;
break;
default:
rc = '*';
break;
}
assert(0 != rc);
if(zRealType){
statsReportTimelineYFlag = zRealType;
db_multi_exec("CREATE TEMP VIEW v_reports AS "
"SELECT * FROM event WHERE type GLOB %Q",
zRealType);
}else{
statsReportTimelineYFlag = "a";
db_multi_exec("CREATE TEMP VIEW v_reports AS "
"SELECT * FROM event");
}
return statsReportType = rc;
}
/*
** Returns a string suitable (for a given value of suitable) for
** use in a label with the header of the /reports pages, dependent
** on the 'type' flag. See stats_report_init_view().
** The returned bytes are static.
*/
static char const * stats_report_label_for_type(){
assert( statsReportType && "Must call stats_report_init_view() first." );
switch( statsReportType ){
case 'c':
return "checkins";
case 'w':
return "wiki changes";
case 't':
return "ticket changes";
case 'g':
return "tag changes";
default:
return "all types";
}
}
/*
** A helper for the /reports family of pages which prints out a menu
** of links for the various type=XXX flags. zCurrentViewName must be
** the name/value of the 'view' parameter which is in effect at the
** time this is called. e.g. if called from the 'byuser' view then
** zCurrentViewName must be "byuser". Any URL parameters which need to
** be added to the generated URLs should be passed in zParam. The
** caller is expected to have already encoded any zParam in the %T or
** %t encoding. */
static void stats_report_event_types_menu(char const * zCurrentViewName,
char const * zParam){
char * zTop;
if(zParam && !*zParam){
zParam = NULL;
}
zTop = mprintf("%s/reports?view=%s%s%s", g.zTop, zCurrentViewName,
zParam ? "&" : "", zParam);
cgi_printf("<div>");
cgi_printf("<span>Event types:</span> ");
if('*' == statsReportType){
cgi_printf(" <strong>all</strong>", zTop);
}else{
cgi_printf(" <a href='%s'>all</a>", zTop);
}
if('c' == statsReportType){
cgi_printf(" <strong>checkins</strong>", zTop);
}else{
cgi_printf(" <a href='%s&type=ci'>checkins</a>", zTop);
}
if( 't' == statsReportType ){
cgi_printf(" <strong>tickets</strong>", zTop);
}else{
cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
}
if( 'g' == statsReportType ){
cgi_printf(" <strong>tags</strong>", zTop);
}else{
cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
}
if( 'w' == statsReportType ){
cgi_printf(" <strong>wiki</strong>", zTop);
}else{
cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
}
fossil_free(zTop);
cgi_printf("</div>");
}
/*
** Helper for stats_report_by_month_year(), which generates a list of
** week numbers. zTimeframe should be either a timeframe in the form YYYY
** or YYYY-MM.
*/
static void stats_report_output_week_links(const char * zTimeframe){
Stmt stWeek = empty_Stmt;
char yearPart[5] = {0,0,0,0,0};
memcpy(yearPart, zTimeframe, 4);
db_prepare(&stWeek,
"SELECT DISTINCT strftime('%%W',mtime) AS wk, "
"count(*) AS n, "
"substr(date(mtime),1,%d) AS ym "
"FROM v_reports "
"WHERE ym=%Q AND mtime < current_timestamp "
"GROUP BY wk ORDER BY wk",
strlen(zTimeframe),
zTimeframe);
while( SQLITE_ROW == db_step(&stWeek) ){
const char * zWeek = db_column_text(&stWeek,0);
const int nCount = db_column_int(&stWeek,1);
cgi_printf("<a href='%s/timeline?"
"yw=%t-%t&n=%d&y=%s'>%s</a>",
g.zTop, yearPart, zWeek,
nCount, statsReportTimelineYFlag, zWeek);
}
db_finalize(&stWeek);
}
/*
** Implements the "byyear" and "bymonth" reports for /reports.
** If includeMonth is true then it generates the "bymonth" report,
** else the "byyear" report. If zUserName is not NULL and not empty
** then the report is restricted to events created by the named user
** account.
*/
static void stats_report_by_month_year(char includeMonth,
char includeWeeks,
const char * zUserName){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int nEventTotal = 0; /* Total event count */
int rowClass = 0; /* counter for alternating
row colors */
Blob sql = empty_blob; /* SQL */
const char * zTimeLabel = includeMonth ? "Year/Month" : "Year";
char zPrevYear[5] = {0}; /* For keeping track of when
we change years while looping */
int nEventsPerYear = 0; /* Total event count for the
current year */
char showYearTotal = 0; /* Flag telling us when to show
the per-year event totals */
Blob header = empty_blob; /* Page header text */
int nMaxEvents = 1; /* for calculating length of graph
bars. */
int iterations = 0; /* number of weeks/months we iterate
over */
stats_report_init_view();
stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear", NULL );
blob_appendf(&header, "Timeline Events (%s) by year%s",
stats_report_label_for_type(),
(includeMonth ? "/month" : ""));
blob_appendf(&sql,
"SELECT substr(date(mtime),1,%d) AS timeframe, "
"count(*) AS eventCount "
"FROM v_reports ",
includeMonth ? 7 : 4);
if(zUserName&&*zUserName){
blob_appendf(&sql, " WHERE user=%Q ", zUserName);
blob_appendf(&header," for user %q", zUserName);
}
blob_append(&sql,
" GROUP BY timeframe"
" ORDER BY timeframe DESC",
-1);
db_prepare(&query, blob_str(&sql));
blob_reset(&sql);
@ <h1>%b(&header)</h1>
@ <table class='statistics-report-table-events' border='0' cellpadding='2'
@ cellspacing='0' id='statsTable'>
@ <thead>
@ <th>%s(zTimeLabel)</th>
@ <th>Events</th>
@ <th width='90%%'><!-- relative commits graph --></th>
@ </thead><tbody>
blob_reset(&header);
/*
Run the query twice. The first time we calculate the maximum
number of events for a given row. Maybe someone with better SQL
Fu can re-implement this with a single query.
*/
while( SQLITE_ROW == db_step(&query) ){
const int nCount = db_column_int(&query, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
++iterations;
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
const char * zTimeframe = db_column_text(&query, 0);
const int nCount = db_column_int(&query, 1);
int nSize = nCount
? (int)(100 * nCount / nMaxEvents)
: 1;
showYearTotal = 0;
if(!nSize) nSize = 1;
if(includeMonth){
/* For Month/year view, add a separator for each distinct year. */
if(!*zPrevYear ||
(0!=fossil_strncmp(zPrevYear,zTimeframe,4))){
showYearTotal = *zPrevYear;
if(showYearTotal){
rowClass = ++nRowNumber % 2;
@ <tr class='row%d(rowClass)'>
@ <td></td>
@ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
@</tr>
}
nEventsPerYear = 0;
memcpy(zPrevYear,zTimeframe,4);
rowClass = ++nRowNumber % 2;
@ <tr class='row%d(rowClass)'>
@ <th colspan='3' class='statistics-report-row-year'>%s(zPrevYear)</th>
@ </tr>
}
}
rowClass = ++nRowNumber % 2;
nEventTotal += nCount;
nEventsPerYear += nCount;
@<tr class='row%d(rowClass)'>
@ <td>
if(includeMonth){
cgi_printf("<a href='%s/timeline?"
"ym=%t&n=%d&y=%s",
g.zTop, zTimeframe, nCount,
statsReportTimelineYFlag );
/* Reminder: n=nCount is not actually correct for bymonth unless
that was the only user who caused events.
*/
if( zUserName && *zUserName ){
cgi_printf("&u=%t", zUserName);
}
cgi_printf("' target='_new'>%s</a>",zTimeframe);
}else {
cgi_printf("<a href='?view=byweek&y=%s&type=%c",
zTimeframe, (char)statsReportType);
if(zUserName && *zUserName){
cgi_printf("&u=%t", zUserName);
}
cgi_printf("'>%s</a>", zTimeframe);
}
@ </td><td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
@ style='height:16px;width:%d(nSize)%%;'>
@ </div></td>
@</tr>
if(includeWeeks){
/* This part works fine for months but it terribly slow (4.5s on my PC),
so it's only shown for by-year for now. Suggestions/patches for
a better/faster layout are welcomed. */
@ <tr class='row%d(rowClass)'>
@ <td colspan='2' class='statistics-report-week-number-label'>Week #:</td>
@ <td class='statistics-report-week-of-year-list'>
stats_report_output_week_links(zTimeframe);
@ </td></tr>
}
/*
Potential improvement: calculate the min/max event counts and
use percent-based graph bars.
*/
}
db_finalize(&query);
if(includeMonth && !showYearTotal && *zPrevYear){
/* Add final year total separator. */
rowClass = ++nRowNumber % 2;
@ <tr class='row%d(rowClass)'>
@ <td></td>
@ <td colspan='2'>Yearly total: %d(nEventsPerYear)</td>
@</tr>
}
@ </tbody></table>
if(nEventTotal){
char const * zAvgLabel = includeMonth ? "month" : "year";
int nAvg = iterations ? (nEventTotal/iterations) : 0;
@ <br><div>Total events: %d(nEventTotal)
@ <br>Average per active %s(zAvgLabel): %d(nAvg)
@ </div>
}
if( !includeMonth ){
output_table_sorting_javascript("statsTable","tnx");
}
}
/*
** Implements the "byuser" view for /reports.
*/
static void stats_report_by_user(){
Stmt query = empty_Stmt;
int nRowNumber = 0; /* current TR number */
int nEventTotal = 0; /* Total event count */
int rowClass = 0; /* counter for alternating
row colors */
Blob sql = empty_blob; /* SQL */
int nMaxEvents = 1; /* max number of events for
all rows. */
stats_report_init_view();
stats_report_event_types_menu("byuser", NULL);
blob_append(&sql,
"SELECT user, "
"COUNT(*) AS eventCount "
"FROM v_reports "
"GROUP BY user ORDER BY eventCount DESC",
-1);
db_prepare(&query, blob_str(&sql));
blob_reset(&sql);
@ <h1>Timeline Events
@ (%s(stats_report_label_for_type())) by User</h1>
@ <table class='statistics-report-table-events' border='0'
@ cellpadding='2' cellspacing='0' id='statsTable'>
@ <thead><tr>
@ <th>User</th>
@ <th>Events</th>
@ <th width='90%%'><!-- relative commits graph --></th>
@ </tr></thead><tbody>
while( SQLITE_ROW == db_step(&query) ){
const int nCount = db_column_int(&query, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
}
db_reset(&query);
while( SQLITE_ROW == db_step(&query) ){
const char * zUser = db_column_text(&query, 0);
const int nCount = db_column_int(&query, 1);
int nSize = nCount
? (int)(100 * nCount / nMaxEvents)
: 0;
if(!nCount) continue /* arguable! Possible? */;
else if(!nSize) nSize = 1;
rowClass = ++nRowNumber % 2;
nEventTotal += nCount;
@<tr class='row%d(rowClass)'>
@ <td>
@ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
@ </td><td>%d(nCount)</td>
@ <td>
@ <div class='statistics-report-graph-line'
@ style='height:16px;width:%d(nSize)%%;'>
@ </div></td>
@</tr>
/*
Potential improvement: calculate the min/max event counts and
use percent-based graph bars.
*/
}
@ </tbody></table>
db_finalize(&query);
output_table_sorting_javascript("statsTable","tnx");
}
/*
** Helper for stats_report_by_month_year(), which generates a list of
** week numbers. zTimeframe should be either a timeframe in the form YYYY
** or YYYY-MM.
*/
static void stats_report_year_weeks(const char * zUserName){
const char * zYear = P("y");
int nYear = zYear ? strlen(zYear) : 0;
int i = 0;
Stmt qYears = empty_Stmt;
char * zDefaultYear = NULL;
Blob sql = empty_blob;
int nMaxEvents = 1; /* max number of events for
all rows. */
int iterations = 0; /* # of active time periods. */
stats_report_init_view();
if(4==nYear){
Blob urlParams = empty_blob;
blob_appendf(&urlParams, "y=%T", zYear);
stats_report_event_types_menu("byweek", blob_str(&urlParams));
blob_reset(&urlParams);
}else{
stats_report_event_types_menu("byweek", NULL);
}
blob_append(&sql,
"SELECT DISTINCT substr(date(mtime),1,4) AS y "
"FROM v_reports WHERE 1 ", -1);
if(zUserName&&*zUserName){
blob_appendf(&sql,"AND user=%Q ", zUserName);
}
blob_append(&sql,"GROUP BY y ORDER BY y", -1);
db_prepare(&qYears, blob_str(&sql));
blob_reset(&sql);
cgi_printf("Select year: ");
while( SQLITE_ROW == db_step(&qYears) ){
const char * zT = db_column_text(&qYears, 0);
if( i++ ){
cgi_printf(" ");
}
cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
(char)statsReportType);
if(zUserName && *zUserName){
cgi_printf("&user=%t",zUserName);
}
cgi_printf("'>%s</a>",zT);
}
db_finalize(&qYears);
cgi_printf("<br/>");
if(!zYear || !*zYear){
zDefaultYear = db_text("????", "SELECT strftime('%%Y')");
zYear = zDefaultYear;
nYear = 4;
}
if(4 == nYear){
Stmt stWeek = empty_Stmt;
int rowCount = 0;
int total = 0;
Blob header = empty_blob;
blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
"of %h", stats_report_label_for_type(),
zYear);
blob_appendf(&sql,
"SELECT DISTINCT strftime('%%%%W',mtime) AS wk, "
"count(*) AS n "
"FROM v_reports "
"WHERE %Q=substr(date(mtime),1,4) "
"AND mtime < current_timestamp ",
zYear);
if(zUserName&&*zUserName){
blob_appendf(&sql, " AND user=%Q ", zUserName);
blob_appendf(&header," for user %h", zUserName);
}
blob_appendf(&sql, "GROUP BY wk ORDER BY wk DESC");
cgi_printf("<h1>%h</h1>", blob_str(&header));
blob_reset(&header);
cgi_printf("<table class='statistics-report-table-events' "
"border='0' cellpadding='2' width='100%%' "
"cellspacing='0' id='statsTable'>");
cgi_printf("<thead><tr>"
"<th>Week</th>"
"<th>Events</th>"
"<th width='90%%'><!-- relative commits graph --></th>"
"</tr></thead>"
"<tbody>");
db_prepare(&stWeek, blob_str(&sql));
blob_reset(&sql);
while( SQLITE_ROW == db_step(&stWeek) ){
const int nCount = db_column_int(&stWeek, 1);
if(nCount>nMaxEvents){
nMaxEvents = nCount;
}
++iterations;
}
db_reset(&stWeek);
while( SQLITE_ROW == db_step(&stWeek) ){
const char * zWeek = db_column_text(&stWeek,0);
const int nCount = db_column_int(&stWeek,1);
int nSize = nCount
? (int)(100 * nCount / nMaxEvents)
: 0;
if(!nSize) nSize = 1;
total += nCount;
cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
cgi_printf("<td><a href='%s/timeline?yw=%t-%s&n=%d&y=%s",
g.zTop, zYear, zWeek, nCount,
statsReportTimelineYFlag);
if(zUserName && *zUserName){
cgi_printf("&u=%t",zUserName);
}
cgi_printf("'>%s</a></td>",zWeek);
cgi_printf("<td>%d</td>",nCount);
cgi_printf("<td>");
if(nCount){
cgi_printf("<div class='statistics-report-graph-line'"
"style='height:16px;width:%d%%;'></div>",
nSize);
}
cgi_printf("</td></tr>");
}
db_finalize(&stWeek);
free(zDefaultYear);
cgi_printf("</tbody></table>");
if(total){
int nAvg = iterations ? (total/iterations) : 0;
cgi_printf("<br><div>Total events: %d<br>"
"Average per active week: %d</div>",
total, nAvg);
}
output_table_sorting_javascript("statsTable","tnx");
}
}
/*
** WEBPAGE: reports
**
** Shows activity reports for the repository.
**
** Query Parameters:
**
** view=REPORT_NAME Valid values: bymonth, byyear, byuser
** user=NAME Restricts statistics to the given user
** type=TYPE Restricts the report to a specific event type:
** ci (checkin), w (wiki), t (ticket), g (tag)
** Defaulting to all event types.
**
** The view-specific query parameters include:
**
** view=byweek:
**
** y=YYYY The year to report (default is the server's
** current year).
*/
void stats_report_page(){
HQuery url; /* URL for various branch links */
const char * zView = P("view"); /* Which view/report to show. */
const char *zUserName = P("user");
login_check_credentials();
if( !g.perm.Read ){ login_needed(); return; }
if(!zUserName) zUserName = P("u");
url_initialize(&url, "reports");
if(zUserName && *zUserName){
url_add_parameter(&url,"user", zUserName);
timeline_submenu(&url, "(Remove User Flag)", "view", zView, "user");
}
timeline_submenu(&url, "By Year", "view", "byyear", 0);
timeline_submenu(&url, "By Month", "view", "bymonth", 0);
timeline_submenu(&url, "By Week", "view", "byweek", 0);
timeline_submenu(&url, "By User", "view", "byuser", "user");
url_reset(&url);
style_header("Activity Reports");
if(0==fossil_strcmp(zView,"byyear")){
stats_report_by_month_year(0, 0, zUserName);
}else if(0==fossil_strcmp(zView,"bymonth")){
stats_report_by_month_year(1, 0, zUserName);
}else if(0==fossil_strcmp(zView,"byweek")){
stats_report_year_weeks(zUserName);
}else if(0==fossil_strcmp(zView,"byuser")){
stats_report_by_user();
}else{
@ <h1>Select a report to show:</h1>
@ <ul>
@ <li><a href='?view=byyear'>Events by year</a></li>
@ <li><a href='?view=bymonth'>Events by month</a></li>
@ <li><a href='?view=byweek'>Events by calendar week</a></li>
@ <li><a href='?view=byuser'>Events by user</a></li>
@ </ul>
}
style_footer();
}
|
Changes to src/tkt.c.
| ︙ | ︙ | |||
135 136 137 138 139 140 141 |
*/
static void initializeVariablesFromDb(void){
const char *zName;
Stmt q;
int i, n, size, j;
zName = PD("name","-none-");
| | | > | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
*/
static void initializeVariablesFromDb(void){
const char *zName;
Stmt q;
int i, n, size, j;
zName = PD("name","-none-");
db_prepare(&q, "SELECT datetime(tkt_mtime%s) AS tkt_datetime, *"
" FROM ticket WHERE tkt_uuid GLOB '%q*'",
timeline_utc(), zName);
if( db_step(&q)==SQLITE_ROW ){
n = db_column_count(&q);
for(i=0; i<n; i++){
const char *zVal = db_column_text(&q, i);
const char *zName = db_column_name(&q, i);
char *zRevealed = 0;
if( zVal==0 ){
|
| ︙ | ︙ | |||
294 295 296 297 298 299 300 |
db_multi_exec("DELETE FROM ticketchng WHERE tkt_id=%d;", tktid);
}
db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
tktid = 0;
db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
| | | | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
db_multi_exec("DELETE FROM ticketchng WHERE tkt_id=%d;", tktid);
}
db_multi_exec("DELETE FROM ticket WHERE tkt_id=%d", tktid);
tktid = 0;
db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid);
while( db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTicket ){
tktid = ticket_insert(pTicket, rid, tktid);
manifest_ticket_event(rid, pTicket, createFlag, tagid);
manifest_destroy(pTicket);
}
createFlag = 0;
}
db_finalize(&q);
}
/*
** Create the TH1 interpreter and load the "common" code.
*/
void ticket_init(void){
const char *zConfig;
Th_FossilInit(TH_INIT_DEFAULT);
zConfig = ticket_common_code();
Th_Eval(g.interp, 0, zConfig, -1);
}
/*
** Create the TH1 interpreter and load the "change" code.
*/
int ticket_change(void){
const char *zConfig;
Th_FossilInit(TH_INIT_DEFAULT);
zConfig = ticket_change_code();
return Th_Eval(g.interp, 0, zConfig, -1);
}
/*
** Recreate the TICKET and TICKETCHNG tables.
*/
|
| ︙ | ︙ | |||
511 512 513 514 515 516 517 |
aField[idx].zAppend = mprintf("%.*s", argl[2], argv[2]);
return TH_OK;
}
/*
** Write a ticket into the repository.
*/
| | > | | > > > | > > | 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
aField[idx].zAppend = mprintf("%.*s", argl[2], argv[2]);
return TH_OK;
}
/*
** Write a ticket into the repository.
*/
static int ticket_put(
Blob *pTicket, /* The text of the ticket change record */
const char *zTktId, /* The ticket to which this change is applied */
int needMod /* True if moderation is needed */
){
int result;
int rid = content_put_ex(pTicket, 0, 0, 0, needMod);
if( rid==0 ){
fossil_fatal("trouble committing ticket: %s", g.zErrMsg);
}
if( needMod ){
moderation_table_create();
db_multi_exec(
"INSERT INTO modreq(objid, tktid) VALUES(%d,'%s')",
rid, zTktId
);
}else{
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d);", rid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", rid);
}
manifest_crosslink_begin();
result = (manifest_crosslink(rid, pTicket, MC_NONE)==0);
assert( blob_is_reset(pTicket) );
if( !result ){
result = manifest_crosslink_end(MC_PERMIT_HOOKS);
}else{
manifest_crosslink_end(MC_NONE);
}
return result;
}
/*
** Subscript command: submit_ticket
**
** Construct and submit a new ticket artifact. The fields of the artifact
** are the names of the columns in the TICKET table. The content is
|
| ︙ | ︙ | |||
619 620 621 622 623 624 625 |
if( g.zPath[0]=='d' ){
/* If called from /debug_tktnew or /debug_tktedit... */
@ <font color="blue">
@ <p>Ticket artifact that would have been submitted:</p>
@ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote>
@ <hr /></font>
return TH_OK;
| > | | | | < > | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
if( g.zPath[0]=='d' ){
/* If called from /debug_tktnew or /debug_tktedit... */
@ <font color="blue">
@ <p>Ticket artifact that would have been submitted:</p>
@ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote>
@ <hr /></font>
return TH_OK;
}else{
if( g.thTrace ){
Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
"}<br />\n",
blob_str(&tktchng));
}
ticket_put(&tktchng, zUuid,
(g.perm.ModTkt==0 && db_get_boolean("modreq-tkt",0)==1));
}
return ticket_change();
}
|
| ︙ | ︙ | |||
674 675 676 677 678 679 680 |
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
(void*)&zNewUuid, 0);
if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
return;
}
| | | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 |
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
(void*)&zNewUuid, 0);
if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
return;
}
captcha_generate(0);
@ </form>
if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
style_footer();
}
/*
** WEBPAGE: tktedit
|
| ︙ | ︙ | |||
742 743 744 745 746 747 748 |
Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
return;
}
| | | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
return;
}
captcha_generate(0);
@ </form>
if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
style_footer();
}
/*
** Check the ticket table schema in zSchema to see if it appears to
|
| ︙ | ︙ | |||
900 901 902 903 904 905 906 |
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
if( tagid==0 ){
@ No such ticket: %h(zUuid)
style_footer();
return;
}
db_prepare(&q,
| | | | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 |
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",zUuid);
if( tagid==0 ){
@ No such ticket: %h(zUuid)
style_footer();
return;
}
db_prepare(&q,
"SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL"
" FROM event, blob"
" WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
" AND blob.rid=event.objid"
" UNION "
"SELECT datetime(mtime%s), attachid, uuid, src, filename, user"
" FROM attachment, blob"
" WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
" AND blob.rid=attachid"
" ORDER BY 1",
timeline_utc(), tagid, timeline_utc(), tagid
);
while( db_step(&q)==SQLITE_ROW ){
Manifest *pTicket;
char zShort[12];
const char *zDate = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
const char *zChngUuid = db_column_text(&q, 2);
|
| ︙ | ︙ | |||
941 942 943 944 945 946 947 |
@ "%z(href("%R/artifact/%S",zSrc))%s(zFile)</a>"
}
@ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
@ (rid %d(rid)) by
hyperlink_to_user(zUser,zDate," on");
hyperlink_to_date(zDate, ".</p>");
}else{
| | | 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 |
@ "%z(href("%R/artifact/%S",zSrc))%s(zFile)</a>"
}
@ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
@ (rid %d(rid)) by
hyperlink_to_user(zUser,zDate," on");
hyperlink_to_date(zDate, ".</p>");
}else{
pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTicket ){
@
@ <li><p>Ticket change
@ [%z(href("%R/artifact/%T",zChngUuid))%s(zShort)</a>]
@ (rid %d(rid)) by
hyperlink_to_user(pTicket->zUser,zDate," on");
hyperlink_to_date(zDate, ":");
|
| ︙ | ︙ | |||
1026 1027 1028 1029 1030 1031 1032 | ** options can be: ** ?-l|--limit LIMITCHAR? ** ?-q|--quote? ** ?-R|--repository FILE? ** ** Run the ticket report, identified by the report format title ** used in the gui. The data is written as flat file on stdout, | | | 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 | ** options can be: ** ?-l|--limit LIMITCHAR? ** ?-q|--quote? ** ?-R|--repository FILE? ** ** Run the ticket report, identified by the report format title ** used in the gui. The data is written as flat file on stdout, ** using TAB as separator. The separator can be changed using ** the -l or --limit option. ** ** If TICKETFILTER is given on the commandline, the query is ** limited with a new WHERE-condition. ** example: Report lists a column # with the uuid ** TICKETFILTER may be [#]='uuuuuuuuu' ** example: Report only lists rows with status not open |
| ︙ | ︙ | |||
1109 1110 1111 1112 1113 1114 1115 |
** Check that the user exists.
*/
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", zUser) ){
fossil_fatal("no such user: %s", zUser);
}
if( g.argc<3 ){
| | | | 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 |
** Check that the user exists.
*/
if( !db_exists("SELECT 1 FROM user WHERE login=%Q", zUser) ){
fossil_fatal("no such user: %s", zUser);
}
if( g.argc<3 ){
usage("add|change|list|set|show|history");
}
n = strlen(g.argv[2]);
if( n==1 && g.argv[2][0]=='s' ){
/* set/show cannot be distinguished, so show the usage */
usage("add|change|list|set|show|history");
}
if( strncmp(g.argv[2],"list",n)==0 ){
if( g.argc==3 ){
usage("list fields|reports");
}else{
n = strlen(g.argv[3]);
if( !strncmp(g.argv[3],"fields",n) ){
|
| ︙ | ︙ | |||
1209 1210 1211 1212 1213 1214 1215 |
}
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
zTktUuid);
if( tagid==0 ){
fossil_fatal("no such ticket %h", zTktUuid);
}
db_prepare(&q,
| | | | | | | | | | | | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 |
}
tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
zTktUuid);
if( tagid==0 ){
fossil_fatal("no such ticket %h", zTktUuid);
}
db_prepare(&q,
"SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL"
" FROM event, blob"
" WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
" AND blob.rid=event.objid"
" UNION "
"SELECT datetime(mtime%s), attachid, uuid, src, "
" filename, user"
" FROM attachment, blob"
" WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
" AND blob.rid=attachid"
" ORDER BY 1 DESC",
timeline_utc(), tagid, timeline_utc(), tagid
);
while( db_step(&q)==SQLITE_ROW ){
Manifest *pTicket;
char zShort[12];
const char *zDate = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
const char *zChngUuid = db_column_text(&q, 2);
const char *zFile = db_column_text(&q, 4);
memcpy(zShort, zChngUuid, 10);
zShort[10] = 0;
if( zFile!=0 ){
const char *zSrc = db_column_text(&q, 3);
const char *zUser = db_column_text(&q, 5);
if( zSrc==0 || zSrc[0]==0 ){
fossil_print("Delete attachment %s\n", zFile);
}else{
fossil_print("Add attachment %s\n", zFile);
}
fossil_print(" by %s on %s\n", zUser, zDate);
}else{
pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
if( pTicket ){
int i;
fossil_print("Ticket Change by %s on %s:\n",
pTicket->zUser, zDate);
for(i=0; i<pTicket->nField; i++){
Blob val;
const char *z;
z = pTicket->aField[i].zName;
blob_set(&val, pTicket->aField[i].zValue);
if( z[0]=='+' ){
fossil_print(" Append to ");
z++;
}else{
fossil_print(" Change ");
}
fossil_print("%h: ",z);
if( blob_size(&val)>50 || contains_newline(&val)) {
fossil_print("\n ",blob_str(&val));
comment_print(blob_str(&val),4,79);
}else{
fossil_print("%s\n",blob_str(&val));
}
blob_reset(&val);
}
|
| ︙ | ︙ | |||
1341 1342 1343 1344 1345 1346 1347 |
aField[i].zName, strlen(zValue), zValue);
}
}
blob_appendf(&tktchng, "K %s\n", zTktUuid);
blob_appendf(&tktchng, "U %F\n", zUser);
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
| | > > | > | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 |
aField[i].zName, strlen(zValue), zValue);
}
}
blob_appendf(&tktchng, "K %s\n", zTktUuid);
blob_appendf(&tktchng, "U %F\n", zUser);
md5sum_blob(&tktchng, &cksum);
blob_appendf(&tktchng, "Z %b\n", &cksum);
if( ticket_put(&tktchng, zTktUuid, 0) ){
fossil_fatal("%s\n", g.zErrMsg);
}else{
fossil_print("ticket %s succeeded for %s\n",
(eCmd==set?"set":"add"),zTktUuid);
}
}
}
}
|
Changes to src/translate.c.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ** to insert special codes (ex: \n and \") for many common characters, ** which interferes with the readability of the HTML. ** ** This tool allows us to put raw HTML, without the special codes, in ** the middle of a C program. This program then translates the text ** into standard C by inserting all necessary backslashes and other ** punctuation. ** */ #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> | > > > > > > > > > > > > > > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | ** to insert special codes (ex: \n and \") for many common characters, ** which interferes with the readability of the HTML. ** ** This tool allows us to put raw HTML, without the special codes, in ** the middle of a C program. This program then translates the text ** into standard C by inserting all necessary backslashes and other ** punctuation. ** ** Enhancement #1: ** ** If the last non-whitespace character prior to the first "@" of a ** @-block is "=" or "," then the @-block is a string literal initializer ** rather than text that is to be output via cgi_printf(). Render it ** as such. ** ** Enhancement #2: ** ** Comments of the form: "/* @-comment: CC" cause CC to become a ** comment character for the @-substitution. Typical values for CC are ** "--" (for SQL text) or "#" (for TCL script) or "//" (for C++ code). ** Lines of subsequent @-blocks that begin with CC are omitted from the ** output. ** */ #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> |
| ︙ | ︙ |
Changes to src/unicode.c.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 | ** The most significant 22 bits in each 32-bit value contain the first ** codepoint in the range. The least significant 10 bits are used to store ** the size of the range (always at least 1). In other words, the value ** ((C<<22) + N) represents a range of N codepoints starting with codepoint ** C. It is not possible to represent a range larger than 1023 codepoints ** using this format. */ | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
** The most significant 22 bits in each 32-bit value contain the first
** codepoint in the range. The least significant 10 bits are used to store
** the size of the range (always at least 1). In other words, the value
** ((C<<22) + N) represents a range of N codepoints starting with codepoint
** C. It is not possible to represent a range larger than 1023 codepoints
** using this format.
*/
static const unsigned int aEntry[] = {
0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07,
0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01,
0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401,
0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01,
0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01,
0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802,
0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F,
|
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
123 124 125 126 127 128 129 |
}
verboseFlag = find_option("verbose","v",0)!=0;
debugFlag = find_option("debug",0,0)!=0;
setmtimeFlag = find_option("setmtime",0,0)!=0;
capture_case_sensitive_option();
db_must_be_within_tree();
vid = db_lget_int("checkout", 0);
| | < < | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
}
verboseFlag = find_option("verbose","v",0)!=0;
debugFlag = find_option("debug",0,0)!=0;
setmtimeFlag = find_option("setmtime",0,0)!=0;
capture_case_sensitive_option();
db_must_be_within_tree();
vid = db_lget_int("checkout", 0);
user_select();
if( !dryRunFlag && !internalUpdate ){
autosync(SYNC_PULL + SYNC_VERBOSE*verboseFlag);
}
/* Create any empty directories now, as well as after the update,
** so changes in settings are reflected now */
if( !dryRunFlag ) ensure_empty_dirs_created();
|
| ︙ | ︙ | |||
185 186 187 188 189 190 191 |
compute_leaves(vid, closeCode);
db_prepare(&q,
"%s "
" AND event.objid IN leaves"
" ORDER BY event.mtime DESC",
timeline_query_for_tty()
);
| | | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
compute_leaves(vid, closeCode);
db_prepare(&q,
"%s "
" AND event.objid IN leaves"
" ORDER BY event.mtime DESC",
timeline_query_for_tty()
);
print_timeline(&q, -100, 79, 0);
db_finalize(&q);
fossil_fatal("Multiple descendants");
}
}
tid = db_int(0, "SELECT rid FROM leaves, event"
" WHERE event.objid=leaves.rid"
" ORDER BY event.mtime DESC");
if( tid==0 ) tid = vid;
}
if( tid==0 ){
return;
}
db_begin_transaction();
vfile_check_signature(vid, CKSIG_ENOTFILE);
if( !dryRunFlag && !internalUpdate ) undo_begin();
load_vfile_from_rid(tid);
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 |
" idt INTEGER," /* VFILE entry for target version */
" chnged BOOLEAN," /* True if current version has been edited */
" islinkv BOOLEAN," /* True if current file is a link */
" islinkt BOOLEAN," /* True if target file is a link */
" ridv INTEGER," /* Record ID for current version */
" ridt INTEGER," /* Record ID for target */
" isexe BOOLEAN," /* Does target have execute permission? */
| | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
" idt INTEGER," /* VFILE entry for target version */
" chnged BOOLEAN," /* True if current version has been edited */
" islinkv BOOLEAN," /* True if current file is a link */
" islinkt BOOLEAN," /* True if target file is a link */
" ridv INTEGER," /* Record ID for current version */
" ridt INTEGER," /* Record ID for target */
" isexe BOOLEAN," /* Does target have execute permission? */
" deleted BOOLEAN DEFAULT 0,"/* File marked by "rm" to become unmanaged */
" fnt TEXT %s" /* Filename of same file on target version */
");",
filename_collation(), filename_collation()
);
/* Add files found in the current version
*/
|
| ︙ | ︙ | |||
353 354 355 356 357 358 359 |
" isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1"
);
db_prepare(&mtimeXfer,
"UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)"
" WHERE id=:idt"
);
assert( g.zLocalRoot!=0 );
| | | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
" isexe, islinkv, islinkt, deleted FROM fv ORDER BY 1"
);
db_prepare(&mtimeXfer,
"UPDATE vfile SET mtime=(SELECT mtime FROM vfile WHERE id=:idv)"
" WHERE id=:idt"
);
assert( g.zLocalRoot!=0 );
assert( strlen(g.zLocalRoot)>0 );
assert( g.zLocalRoot[strlen(g.zLocalRoot)-1]=='/' );
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0); /* The filename from root */
int idv = db_column_int(&q, 1); /* VFILE entry for current */
int ridv = db_column_int(&q, 2); /* RecordID for current */
int idt = db_column_int(&q, 3); /* VFILE entry for target */
int ridt = db_column_int(&q, 4); /* RecordID for target */
|
| ︙ | ︙ | |||
398 399 400 401 402 403 404 |
}
undo_save(zName);
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt>0 && idv>0 && ridt!=ridv && (chnged==0 || deleted) ){
/* The file is unedited. Change it to the target version */
undo_save(zName);
if( deleted ){
| | | | < | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
}
undo_save(zName);
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt>0 && idv>0 && ridt!=ridv && (chnged==0 || deleted) ){
/* The file is unedited. Change it to the target version */
undo_save(zName);
if( deleted ){
fossil_print("UPDATE %s - change to unmanaged file\n", zName);
}else{
fossil_print("UPDATE %s\n", zName);
}
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt>0 && idv>0 && !deleted && file_wd_size(zFullPath)<0 ){
/* The file missing from the local check-out. Restore it to the
** version that appears in the target. */
fossil_print("UPDATE %s\n", zName);
undo_save(zName);
if( !dryRunFlag ) vfile_to_disk(0, idt, 0, 0);
}else if( idt==0 && idv>0 ){
if( ridv==0 ){
/* Added in current checkout. Continue to hold the file as
** as an addition */
db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv);
|
| ︙ | ︙ | |||
633 634 635 636 637 638 639 |
}else{
rid = db_lget_int("checkout", 0);
}
if( !is_a_version(rid) ){
if( errCode>0 ) return errCode;
fossil_fatal("no such checkin: %s", revision);
}
| | | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
}else{
rid = db_lget_int("checkout", 0);
}
if( !is_a_version(rid) ){
if( errCode>0 ) return errCode;
fossil_fatal("no such checkin: %s", revision);
}
pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( pManifest ){
pFile = manifest_file_find(pManifest, file);
if( pFile ){
int rc;
rid = uuid_to_rid(pFile->zUuid, 0);
if( pIsExe ) *pIsExe = ( manifest_file_mperm(pFile)==PERM_EXE );
|
| ︙ | ︙ | |||
657 658 659 660 661 662 663 |
if( errCode<=0 ){
fossil_fatal("file %s does not exist in checkin: %s", file, revision);
}
}else if( errCode<=0 ){
if( revision==0 ){
revision = db_text("current", "SELECT uuid FROM blob WHERE rid=%d", rid);
}
| | | 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 |
if( errCode<=0 ){
fossil_fatal("file %s does not exist in checkin: %s", file, revision);
}
}else if( errCode<=0 ){
if( revision==0 ){
revision = db_text("current", "SELECT uuid FROM blob WHERE rid=%d", rid);
}
fossil_fatal("could not parse manifest for checkin: %s", revision);
}
return errCode;
}
/*
** COMMAND: revert
|
| ︙ | ︙ |
Changes to src/url.c.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
**
*******************************************************************************
**
** This file contains code for parsing URLs that appear on the command-line
*/
#include "config.h"
#include "url.h"
#if INTERFACE
/*
** Flags for url_parse()
*/
#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
#define URL_PROMPTED 0x010 /* Prompted for PW already */
#endif /* INTERFACE */
/*
** Convert a string to lower-case.
*/
static void url_tolower(char *z){
while( *z ){
*z = fossil_tolower(*z);
z++;
}
}
/*
** Parse the given URL, which describes a sync server. Populate variables
** in the global "g" structure as follows:
**
** g.urlIsFile True if FILE:
** g.urlIsHttps True if HTTPS:
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
**
*******************************************************************************
**
** This file contains code for parsing URLs that appear on the command-line
*/
#include "config.h"
#include "url.h"
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#ifndef isatty
#define isatty(d) _isatty(d)
#endif
#ifndef fileno
#define fileno(s) _fileno(s)
#endif
#endif
#if INTERFACE
/*
** Flags for url_parse()
*/
#define URL_PROMPT_PW 0x001 /* Prompt for password if needed */
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
#define URL_PROMPTED 0x010 /* Prompted for PW already */
/*
** The URL related data used with this subsystem.
*/
struct UrlData {
/*
** NOTE: These members MUST be kept in sync with the related ones in the
** "Global" structure defined in "main.c".
*/
int isFile; /* True if a "file:" url */
int isHttps; /* True if a "https:" url */
int isSsh; /* True if an "ssh:" url */
char *name; /* Hostname for http: or filename for file: */
char *hostname; /* The HOST: parameter on http headers */
char *protocol; /* "http" or "https" */
int port; /* TCP port number for http: or https: */
int dfltPort; /* The default port for the given protocol */
char *path; /* Pathname for http: */
char *user; /* User id for http: */
char *passwd; /* Password for http: */
char *canonical; /* Canonical representation of the URL */
char *proxyAuth; /* Proxy-Authorizer: string */
char *fossil; /* The fossil query parameter on ssh: */
unsigned flags; /* Boolean flags controlling URL processing */
int useProxy; /* Used to remember that a proxy is in use */
char *proxyUrlPath;
int proxyOrigPort; /* Tunneled port number for https through proxy */
};
#endif /* INTERFACE */
/*
** Convert a string to lower-case.
*/
static void url_tolower(char *z){
while( *z ){
*z = fossil_tolower(*z);
z++;
}
}
/*
** Parse the given URL. Populate members of the provided UrlData structure
** as follows:
**
** isFile True if FILE:
** isHttps True if HTTPS:
** isSsh True if SSH:
** protocol "http" or "https" or "file"
** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
** port TCP port number for HTTP or HTTPS.
** dfltPort Default TCP port number (80 or 443).
** path Path name for HTTP or HTTPS.
** user Userid.
** passwd Password.
** hostname HOST:PORT or just HOST if port is the default.
** canonical The URL in canonical form, omitting the password
**
*/
void url_parse_local(
const char *zUrl,
unsigned int urlFlags,
UrlData *pUrlData
){
int i, j, c;
char *zFile = 0;
if( zUrl==0 ){
zUrl = db_get("last-sync-url", 0);
if( zUrl==0 ) return;
if( pUrlData->passwd==0 ){
pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
}
}
if( strncmp(zUrl, "http://", 7)==0
|| strncmp(zUrl, "https://", 8)==0
|| strncmp(zUrl, "ssh://", 6)==0
){
int iStart;
char *zLogin;
char *zExe;
char cQuerySep = '?';
pUrlData->isFile = 0;
pUrlData->useProxy = 0;
if( zUrl[4]=='s' ){
pUrlData->isHttps = 1;
pUrlData->protocol = "https";
pUrlData->dfltPort = 443;
iStart = 8;
}else if( zUrl[0]=='s' ){
pUrlData->isSsh = 1;
pUrlData->protocol = "ssh";
pUrlData->dfltPort = 22;
pUrlData->fossil = "fossil";
iStart = 6;
}else{
pUrlData->isHttps = 0;
pUrlData->protocol = "http";
pUrlData->dfltPort = 80;
iStart = 7;
}
for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
if( c=='@' ){
/* Parse up the user-id and password */
for(j=iStart; j<i && zUrl[j]!=':'; j++){}
pUrlData->user = mprintf("%.*s", j-iStart, &zUrl[iStart]);
dehttpize(pUrlData->user);
if( j<i ){
if( ( urlFlags & URL_REMEMBER ) && pUrlData->isSsh==0 ){
urlFlags |= URL_ASK_REMEMBER_PW;
}
pUrlData->passwd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
dehttpize(pUrlData->passwd);
}
if( pUrlData->isSsh ){
urlFlags &= ~URL_ASK_REMEMBER_PW;
}
zLogin = mprintf("%t@", pUrlData->user);
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
i = j;
}else{
for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
zLogin = mprintf("");
}
url_tolower(pUrlData->name);
if( c==':' ){
pUrlData->port = 0;
i++;
while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
pUrlData->port = pUrlData->port*10 + c - '0';
i++;
}
pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
}else{
pUrlData->port = pUrlData->dfltPort;
pUrlData->hostname = pUrlData->name;
}
dehttpize(pUrlData->name);
pUrlData->path = mprintf("%s", &zUrl[i]);
for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
if( pUrlData->path[i] ){
pUrlData->path[i] = 0;
i++;
}
zExe = mprintf("");
while( pUrlData->path[i]!=0 ){
char *zName, *zValue;
zName = &pUrlData->path[i];
zValue = zName;
while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
if( pUrlData->path[i]=='=' ){
pUrlData->path[i] = 0;
i++;
zValue = &pUrlData->path[i];
while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; }
}
if( pUrlData->path[i] ){
pUrlData->path[i] = 0;
i++;
}
if( fossil_strcmp(zName,"fossil")==0 ){
pUrlData->fossil = zValue;
dehttpize(pUrlData->fossil);
zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
cQuerySep = '&';
}
}
dehttpize(pUrlData->path);
if( pUrlData->dfltPort==pUrlData->port ){
pUrlData->canonical = mprintf(
"%s://%s%T%T%s",
pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
);
}else{
pUrlData->canonical = mprintf(
"%s://%s%T:%d%T%s",
pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
pUrlData->path, zExe
);
}
if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
free(zLogin);
}else if( strncmp(zUrl, "file:", 5)==0 ){
pUrlData->isFile = 1;
if( zUrl[5]=='/' && zUrl[6]=='/' ){
i = 7;
}else{
i = 5;
}
zFile = mprintf("%s", &zUrl[i]);
}else if( file_isfile(zUrl) ){
pUrlData->isFile = 1;
zFile = mprintf("%s", zUrl);
}else if( file_isdir(zUrl)==1 ){
zFile = mprintf("%s/FOSSIL", zUrl);
if( file_isfile(zFile) ){
pUrlData->isFile = 1;
}else{
free(zFile);
fossil_fatal("unknown repository: %s", zUrl);
}
}else{
fossil_fatal("unknown repository: %s", zUrl);
}
if( urlFlags ) pUrlData->flags = urlFlags;
if( pUrlData->isFile ){
Blob cfile;
dehttpize(zFile);
file_canonical_name(zFile, &cfile, 0);
free(zFile);
pUrlData->protocol = "file";
pUrlData->path = "";
pUrlData->name = mprintf("%b", &cfile);
pUrlData->canonical = mprintf("file://%T", pUrlData->name);
blob_reset(&cfile);
}else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
url_prompt_for_password_local(pUrlData);
}else if( pUrlData->user!=0 && ( urlFlags & URL_ASK_REMEMBER_PW ) ){
if( isatty(fileno(stdin)) ){
if( save_password_prompt(pUrlData->passwd) ){
pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
}else{
pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
}
}
}
}
/*
** Parse the given URL, which describes a sync server. Populate variables
** in the global "g" structure as follows:
**
** g.urlIsFile True if FILE:
** g.urlIsHttps True if HTTPS:
|
| ︙ | ︙ | |||
62 63 64 65 66 67 68 | ** ** HTTP url format as follows (HTTPS is the same with a different scheme): ** ** http://userid:password@host:port/path ** ** SSH url format is: ** | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
**
** HTTP url format as follows (HTTPS is the same with a different scheme):
**
** http://userid:password@host:port/path
**
** SSH url format is:
**
** ssh://userid@host:port/path?fossil=path/to/fossil.exe
**
*/
void url_parse(const char *zUrl, unsigned int urlFlags){
url_parse_local(zUrl, urlFlags, GLOBAL_URL());
}
/*
** COMMAND: test-urlparser
**
** Usage: %fossil test-urlparser URL ?options?
**
|
| ︙ | ︙ | |||
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
zProxy = fossil_getenv("http_proxy");
}
}
if( zProxy && zProxy[0] && !is_false(zProxy)
&& !g.urlIsSsh && !g.urlIsFile ){
char *zOriginalUrl = g.urlCanonical;
char *zOriginalHost = g.urlHostname;
char *zOriginalUser = g.urlUser;
char *zOriginalPasswd = g.urlPasswd;
unsigned uOriginalFlags = g.urlFlags;
g.urlUser = 0;
g.urlPasswd = "";
url_parse(zProxy, 0);
if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
g.urlPath = zOriginalUrl;
g.urlHostname = zOriginalHost;
if( g.urlUser ){
char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
char *zCredentials2 = encode64(zCredentials1, -1);
g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
free(zCredentials1);
}
g.urlUser = zOriginalUser;
g.urlPasswd = zOriginalPasswd;
g.urlFlags = uOriginalFlags;
}
}
#if INTERFACE
/*
** An instance of this object is used to build a URL with query parameters.
| > > > > > > > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
zProxy = fossil_getenv("http_proxy");
}
}
if( zProxy && zProxy[0] && !is_false(zProxy)
&& !g.urlIsSsh && !g.urlIsFile ){
char *zOriginalUrl = g.urlCanonical;
char *zOriginalHost = g.urlHostname;
int fOriginalIsHttps = g.urlIsHttps;
char *zOriginalUser = g.urlUser;
char *zOriginalPasswd = g.urlPasswd;
char *zOriginalUrlPath = g.urlPath;
int iOriginalPort = g.urlPort;
unsigned uOriginalFlags = g.urlFlags;
g.urlUser = 0;
g.urlPasswd = "";
url_parse(zProxy, 0);
if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical);
g.urlPath = zOriginalUrl;
g.urlHostname = zOriginalHost;
if( g.urlUser ){
char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd);
char *zCredentials2 = encode64(zCredentials1, -1);
g.urlProxyAuth = mprintf("Basic %z", zCredentials2);
free(zCredentials1);
}
g.urlUser = zOriginalUser;
g.urlPasswd = zOriginalPasswd;
g.urlIsHttps = fOriginalIsHttps;
g.useProxy = 1;
g.proxyUrlPath = zOriginalUrlPath;
g.proxyOrigPort = iOriginalPort;
g.urlFlags = uOriginalFlags;
}
}
#if INTERFACE
/*
** An instance of this object is used to build a URL with query parameters.
|
| ︙ | ︙ | |||
433 434 435 436 437 438 439 |
blob_appendf(&p->url, "%s%s", zSep, zName2);
if( zValue2[0] ) blob_appendf(&p->url, "=%T", zValue2);
}
return blob_str(&p->url);
}
/*
| | > | | | | | < < < < < < < | > | | < | < < < | < < | > | > > > > > > > > | > | | | | < > | < | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
blob_appendf(&p->url, "%s%s", zSep, zName2);
if( zValue2[0] ) blob_appendf(&p->url, "=%T", zValue2);
}
return blob_str(&p->url);
}
/*
** Prompt the user for the password that corresponds to the "user" member of
** the provided UrlData structure. Store the result into the "passwd" member
** of the provided UrlData structure.
*/
void url_prompt_for_password_local(UrlData *pUrlData){
if( pUrlData->isSsh || pUrlData->isFile ) return;
if( isatty(fileno(stdin))
&& (pUrlData->flags & URL_PROMPT_PW)!=0
&& (pUrlData->flags & URL_PROMPTED)==0
){
pUrlData->flags |= URL_PROMPTED;
pUrlData->passwd = prompt_for_user_password(pUrlData->user);
if( pUrlData->passwd[0]
&& (pUrlData->flags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
){
if( save_password_prompt(pUrlData->passwd) ){
pUrlData->flags |= URL_REMEMBER_PW;
}else{
pUrlData->flags &= ~URL_REMEMBER_PW;
}
}
}else{
fossil_fatal("missing or incorrect password for user \"%s\"",
pUrlData->user);
}
}
/*
** Prompt the user for the password for g.urlUser. Store the result
** in g.urlPasswd.
*/
void url_prompt_for_password(void){
url_prompt_for_password_local(GLOBAL_URL());
}
/*
** Remember the URL and password if requested.
*/
void url_remember(void){
if( g.urlFlags & URL_REMEMBER ){
db_set("last-sync-url", g.urlCanonical, 0);
if( g.urlUser!=0 && g.urlPasswd!=0 && ( g.urlFlags & URL_REMEMBER_PW ) ){
db_set("last-sync-pw", obscure(g.urlPasswd), 0);
}
}
}
/* Preemptively prompt for a password if a username is given in the
** URL but no password.
*/
void url_get_password_if_needed(void){
if( (g.urlUser && g.urlUser[0])
&& (g.urlPasswd==0 || g.urlPasswd[0]==0)
&& isatty(fileno(stdin))
){
url_prompt_for_password();
}
}
|
Changes to src/user.c.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
while( fossil_isspace(*z) ){ z++; }
for(i=0; z[i]; i++){
if( z[i]=='\r' || z[i]=='\n' ){
while( i>0 && fossil_isspace(z[i-1]) ){ i--; }
z[i] = 0;
break;
}
| | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
while( fossil_isspace(*z) ){ z++; }
for(i=0; z[i]; i++){
if( z[i]=='\r' || z[i]=='\n' ){
while( i>0 && fossil_isspace(z[i-1]) ){ i--; }
z[i] = 0;
break;
}
if( z[i]>0 && z[i]<' ' ) z[i] = ' ';
}
blob_append(pBlob, z, -1);
}
#if defined(_WIN32) || defined(__BIONIC__)
#ifdef __MINGW32__
#include <conio.h>
|
| ︙ | ︙ | |||
126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
fossil_print("Passphrases do not match. Try again...\n");
}else{
break;
}
}
blob_reset(&secondTry);
}
/*
** Prompt the user to enter a single line of text.
*/
void prompt_user(const char *zPrompt, Blob *pIn){
char *z;
char zLine[1000];
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
fossil_print("Passphrases do not match. Try again...\n");
}else{
break;
}
}
blob_reset(&secondTry);
}
/*
** Prompt to save Fossil user password
*/
int save_password_prompt(const char *passwd){
Blob x;
char c;
const char *old = db_get("last-sync-pw", 0);
if( (old!=0) && fossil_strcmp(unobscure(old), passwd)==0 ){
return 0;
}
prompt_user("remember password (Y/n)? ", &x);
c = blob_str(&x)[0];
blob_reset(&x);
return ( c!='n' && c!='N' );
}
/*
** Prompt for Fossil user password
*/
char *prompt_for_user_password(const char *zUser){
char *zPrompt = mprintf("\rpassword for %s: ", zUser);
char *zPw;
Blob x;
fossil_force_newline();
prompt_for_password(zPrompt, &x, 0);
free(zPrompt);
zPw = mprintf("%b", &x);
blob_reset(&x);
return zPw;
}
/*
** Prompt the user to enter a single line of text.
*/
void prompt_user(const char *zPrompt, Blob *pIn){
char *z;
char zLine[1000];
|
| ︙ | ︙ | |||
261 262 263 264 265 266 267 |
db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
zSecret, uid);
free(zSecret);
}
}else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
int uid;
if( g.argc!=4 && g.argc!=5 ){
| | | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
zSecret, uid);
free(zSecret);
}
}else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
int uid;
if( g.argc!=4 && g.argc!=5 ){
usage("capabilities USERNAME ?PERMISSIONS?");
}
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]);
if( uid==0 ){
fossil_fatal("no such user: %s", g.argv[3]);
}
if( g.argc==5 ){
db_multi_exec(
"UPDATE user SET cap=%Q, mtime=now() WHERE uid=%d",
g.argv[4], uid
);
}
fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid));
}else{
fossil_fatal("user subcommand should be one of: "
"capabilities default list new password");
}
}
/*
** Attempt to set the user to zLogin
*/
|
| ︙ | ︙ | |||
417 418 419 420 421 422 423 |
"(SELECT rowid FROM accesslog ORDER BY rowid DESC"
" LIMIT -1 OFFSET 200)");
cgi_redirectf("%s/access_log?y=%d&n=%d", g.zTop, y, n);
return;
}
style_header("Access Log");
blob_zero(&sql);
| | | | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
"(SELECT rowid FROM accesslog ORDER BY rowid DESC"
" LIMIT -1 OFFSET 200)");
cgi_redirectf("%s/access_log?y=%d&n=%d", g.zTop, y, n);
return;
}
style_header("Access Log");
blob_zero(&sql);
blob_appendf(&sql,
"SELECT uname, ipaddr, datetime(mtime%s), success"
" FROM accesslog", timeline_utc()
);
if( y==1 ){
blob_append(&sql, " WHERE success", -1);
}else if( y==2 ){
blob_append(&sql, " WHERE NOT success", -1);
}
blob_appendf(&sql," ORDER BY rowid DESC LIMIT %d OFFSET %d", n+1, skip);
|
| ︙ | ︙ |
Changes to src/utf8.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | */ #include "config.h" #include "utf8.h" #include <sqlite3.h> #ifdef _WIN32 # include <windows.h> #endif | < | < < < < < < | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | */ #include "config.h" #include "utf8.h" #include <sqlite3.h> #ifdef _WIN32 # include <windows.h> #endif #include "cygsup.h" #ifdef _WIN32 /* ** Translate MBCS to UTF-8. Return a pointer to the translated text. ** Call fossil_mbcs_free() to deallocate any memory used to store the ** returned pointer when done. */ |
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
** Return a pointer to the translated text.
** Call fossil_unicode_free() to deallocate any memory used to store the
** returned pointer when done.
*/
char *fossil_unicode_to_utf8(const void *zUnicode){
#if defined(_WIN32) || defined(__CYGWIN__)
int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0);
| | < < < > > > > > | > > | < < < > < < < < | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
** Return a pointer to the translated text.
** Call fossil_unicode_free() to deallocate any memory used to store the
** returned pointer when done.
*/
char *fossil_unicode_to_utf8(const void *zUnicode){
#if defined(_WIN32) || defined(__CYGWIN__)
int nByte = WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, 0, 0, 0, 0);
char *zUtf = fossil_malloc( nByte );
WideCharToMultiByte(CP_UTF8, 0, zUnicode, -1, zUtf, nByte, 0, 0);
return zUtf;
#else
static Stmt q;
char *zUtf8;
db_static_prepare(&q, "SELECT :utf8");
db_bind_text16(&q, ":utf8", zUnicode);
db_step(&q);
zUtf8 = fossil_strdup(db_column_text(&q, 0));
db_reset(&q);
return zUtf8;
#endif
}
/*
** Translate UTF-8 to unicode for use in system calls. Return a pointer to the
** translated text.. Call fossil_unicode_free() to deallocate any memory
** used to store the returned pointer when done.
*/
void *fossil_utf8_to_unicode(const char *zUtf8){
#if defined(_WIN32) || defined(__CYGWIN__)
int nByte = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, 0, 0);
wchar_t *zUnicode = fossil_malloc( nByte * 2 );
MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nByte);
return zUnicode;
#else
assert( 0 ); /* Never used in unix */
return fossil_strdup(zUtf8); /* TODO: implement for unix */
#endif
}
/*
** Deallocate any memory that was previously allocated by
** fossil_unicode_to_utf8().
*/
void fossil_unicode_free(void *pOld){
fossil_free(pOld);
}
#if defined(__APPLE__) && !defined(WITHOUT_ICONV)
# include <iconv.h>
#endif
/*
|
| ︙ | ︙ |
Changes to src/util.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
** For the fossil_timer_xxx() family of functions...
*/
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
# include <sys/resource.h>
#endif
/*
** Exit. Take care to close the database first.
*/
NORETURN void fossil_exit(int rc){
| > > > | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
** For the fossil_timer_xxx() family of functions...
*/
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
# include <sys/resource.h>
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
#endif
/*
** Exit. Take care to close the database first.
*/
NORETURN void fossil_exit(int rc){
|
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
/*
** Returns the difference in CPU times in microseconds since
** fossil_timer_start() was called and returned the given timer ID (or
** since it was last reset). Returns 0 if timerId is out of range.
*/
sqlite3_uint64 fossil_timer_fetch(int timerId){
| | < < > | < < > | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
/*
** Returns the difference in CPU times in microseconds since
** fossil_timer_start() was called and returned the given timer ID (or
** since it was last reset). Returns 0 if timerId is out of range.
*/
sqlite3_uint64 fossil_timer_fetch(int timerId){
if( timerId>0 && timerId<=FOSSIL_TIMER_COUNT ){
struct FossilTimer * start = &fossilTimerList[timerId-1];
if( !start->id ){
fossil_fatal("Invalid call to fetch a non-allocated "
"timer (#%d)", timerId);
/*NOTREACHED*/
}else{
sqlite3_uint64 eu = 0, es = 0;
fossil_cpu_times( &eu, &es );
return (eu - start->u) + (es - start->s);
}
}
return 0;
}
/*
** Resets the timer associated with the given ID, as obtained via
** fossil_timer_start(), to the current CPU time values.
*/
sqlite3_uint64 fossil_timer_reset(int timerId){
if( timerId>0 && timerId<=FOSSIL_TIMER_COUNT ){
struct FossilTimer * start = &fossilTimerList[timerId-1];
if( !start->id ){
fossil_fatal("Invalid call to reset a non-allocated "
"timer (#%d)", timerId);
/*NOTREACHED*/
}else{
sqlite3_uint64 const rc = fossil_timer_fetch(timerId);
fossil_cpu_times( &start->u, &start->s );
return rc;
}
}
return 0;
}
/**
"Deallocates" the fossil timer identified by the given timer ID.
returns the difference (in uSec) between the last time that timer
was started or reset. Returns 0 if timerId is out of range (but
note that, due to system-level precision restrictions, this
|
| ︙ | ︙ | |||
297 298 299 300 301 302 303 |
return 0;
}else{
int const rc = fossilTimerList[timerId-1].id;
assert(!rc || (rc == timerId));
return fossilTimerList[timerId-1].id;
}
}
| > > > > > > > > > > > > | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
return 0;
}else{
int const rc = fossilTimerList[timerId-1].id;
assert(!rc || (rc == timerId));
return fossilTimerList[timerId-1].id;
}
}
/*
** Return TRUE if fd is a valid open file descriptor. This only
** works on unix. The function always returns true on Windows.
*/
int is_valid_fd(int fd){
#ifdef _WIN32
return 1;
#else
return fcntl(fd, F_GETFL)!=(-1) || errno!=EBADF;
#endif
}
|
Changes to src/verify.c.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 |
Blob uuid, hash, content;
if( content_size(rid, 0)<0 ){
return; /* No way to verify phantoms */
}
blob_zero(&uuid);
db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
if( blob_size(&uuid)!=UUID_SIZE ){
| | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
Blob uuid, hash, content;
if( content_size(rid, 0)<0 ){
return; /* No way to verify phantoms */
}
blob_zero(&uuid);
db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
if( blob_size(&uuid)!=UUID_SIZE ){
fossil_fatal("not a valid rid: %d", rid);
}
if( content_get(rid, &content) ){
sha1sum_blob(&content, &hash);
blob_reset(&content);
if( blob_compare(&uuid, &hash) ){
fossil_fatal("hash of rid %d (%b) does not match its uuid (%b)",
rid, &hash, &uuid);
|
| ︙ | ︙ |
Changes to src/vfile.c.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 | /* ** Given a UUID, return the corresponding record ID. If the UUID ** does not exist, then return 0. ** ** For this routine, the UUID must be exact. For a match against ** user input with mixed case, use resolve_uuid(). ** | | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
/*
** Given a UUID, return the corresponding record ID. If the UUID
** does not exist, then return 0.
**
** For this routine, the UUID must be exact. For a match against
** user input with mixed case, use resolve_uuid().
**
** If the UUID is not found and phantomize is 1 or 2, then attempt to
** create a phantom record. A private phantom is created for 2 and
** a public phantom is created for 1.
*/
int uuid_to_rid(const char *zUuid, int phantomize){
int rid, sz;
char z[UUID_SIZE+1];
sz = strlen(zUuid);
if( sz!=UUID_SIZE || !validate16(zUuid, sz) ){
return 0;
}
memcpy(z, zUuid, UUID_SIZE+1);
canonical16(z, sz);
rid = fast_uuid_to_rid(z);
|
| ︙ | ︙ | |||
79 80 81 82 83 84 85 |
ManifestFile *pFile;
if( db_exists("SELECT 1 FROM vfile WHERE vid=%d", vid) ){
return;
}
db_begin_transaction();
| | | | > > | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
ManifestFile *pFile;
if( db_exists("SELECT 1 FROM vfile WHERE vid=%d", vid) ){
return;
}
db_begin_transaction();
p = manifest_get(vid, CFTYPE_MANIFEST, 0);
if( p==0 ) {
db_end_transaction(1);
return;
}
db_prepare(&ins,
"INSERT INTO vfile(vid,isexe,islink,rid,mrid,pathname) "
" VALUES(:vid,:isexe,:islink,:id,:id,:name)");
db_prepare(&ridq, "SELECT rid,size FROM blob WHERE uuid=:uuid");
db_bind_int(&ins, ":vid", vid);
manifest_file_rewind(p);
while( (pFile = manifest_file_next(p,0))!=0 ){
if( pFile->zUuid==0 || uuid_is_shunned(pFile->zUuid) ) continue;
db_bind_text(&ridq, ":uuid", pFile->zUuid);
if( db_step(&ridq)==SQLITE_ROW ){
rid = db_column_int(&ridq, 0);
size = db_column_int(&ridq, 1);
}else{
rid = 0;
size = 0;
}
db_reset(&ridq);
if( rid==0 || size<0 ){
fossil_warning("content missing for %s", pFile->zName);
|
| ︙ | ︙ | |||
136 137 138 139 140 141 142 | ** VFILE.CHNGED field according to whether or not ** the file has changed. 0 means no change. 1 means edited. 2 means ** the file has changed due to a merge. 3 means the file was added ** by a merge. ** ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either ** removed from configuration management via "fossil rm" or added via | | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | ** VFILE.CHNGED field according to whether or not ** the file has changed. 0 means no change. 1 means edited. 2 means ** the file has changed due to a merge. 3 means the file was added ** by a merge. ** ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either ** removed from configuration management via "fossil rm" or added via ** "fossil add", respectively, and in both cases we always know that ** the file has changed without having the check the size, mtime, ** or on-disk content. ** ** If the size of the file has changed, then we always know that the file ** changed without having to look at the mtime or on-disk content. ** ** The mtime of the file is only a factor if the mtime-changes setting |
| ︙ | ︙ | |||
211 212 213 214 215 216 217 |
db_ephemeral_blob(&q, 5, &origCksum);
if( sha1sum_file(zName, &fileCksum) ){
blob_zero(&fileCksum);
}
if( blob_compare(&fileCksum, &origCksum)==0 ) chnged = 0;
blob_reset(&origCksum);
blob_reset(&fileCksum);
| | | | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
db_ephemeral_blob(&q, 5, &origCksum);
if( sha1sum_file(zName, &fileCksum) ){
blob_zero(&fileCksum);
}
if( blob_compare(&fileCksum, &origCksum)==0 ) chnged = 0;
blob_reset(&origCksum);
blob_reset(&fileCksum);
}else if( (chnged==0 || chnged==2 || chnged==4)
&& (useMtime==0 || currentMtime!=oldMtime) ){
/* For files that were formerly believed to be unchanged or that were
** changed by merging, if their mtime changes, or unconditionally
** if --sha1sum is used, check to see if they have been edited by
** looking at their SHA1 sum */
assert( origSize==currentSize );
db_ephemeral_blob(&q, 5, &origCksum);
if( sha1sum_file(zName, &fileCksum) ){
blob_zero(&fileCksum);
}
if( blob_compare(&fileCksum, &origCksum) ){
chnged = 1;
}
blob_reset(&origCksum);
blob_reset(&fileCksum);
}
if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2 || chnged==4) ){
i64 desiredMtime;
if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
if( currentMtime!=desiredMtime ){
file_set_mtime(zName, desiredMtime);
currentMtime = file_wd_mtime(zName);
}
}
|
| ︙ | ︙ | |||
311 312 313 314 315 316 317 |
continue;
}
}
if( verbose ) fossil_print("%s\n", &zName[nRepos]);
if( file_wd_isdir(zName) == 1 ){
/*TODO(dchest): remove directories? */
fossil_fatal("%s is directory, cannot overwrite\n", zName);
| | | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
continue;
}
}
if( verbose ) fossil_print("%s\n", &zName[nRepos]);
if( file_wd_isdir(zName) == 1 ){
/*TODO(dchest): remove directories? */
fossil_fatal("%s is directory, cannot overwrite\n", zName);
}
if( file_wd_size(zName)>=0 && (isLink || file_wd_islink(zName)) ){
file_delete(zName);
}
if( isLink ){
symlink_create(blob_str(&content), zName);
}else{
blob_write_to_file(&content, zName);
|
| ︙ | ︙ | |||
388 389 390 391 392 393 394 |
static const char *const azTemp[] = {
"baseline",
"merge",
"original",
"output",
};
int i, j, n;
| | | > | > | | | < < < < | | | | | | < | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
static const char *const azTemp[] = {
"baseline",
"merge",
"original",
"output",
};
int i, j, n;
if( strglob("ci-comment-????????????.txt", zName) ) return 1;
for(; zName[0]!=0; zName++){
if( zName[0]=='/' && strglob("/ci-comment-????????????.txt", zName) ){
return 1;
}
if( zName[0]!='-' ) continue;
for(i=0; i<sizeof(azTemp)/sizeof(azTemp[0]); i++){
n = (int)strlen(azTemp[i]);
if( memcmp(azTemp[i], zName+1, n) ) continue;
if( zName[n+1]==0 ) return 1;
if( zName[n+1]=='-' ){
for(j=n+2; zName[j] && fossil_isdigit(zName[j]); j++){}
if( zName[j]==0 ) return 1;
}
}
}
return 0;
}
#if INTERFACE
/*
** Values for the scanFlags parameter to vfile_scan().
*/
#define SCAN_ALL 0x001 /* Includes files that begin with "." */
#define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
#define SCAN_NESTED 0x004 /* Scan for empty dirs in nested checkouts */
#endif /* INTERFACE */
/*
** Load into table SFILE the name of every ordinary file in
** the directory pPath. Omit the first nPrefix characters of
** of pPath when inserting into the SFILE table.
**
** Subdirectories are scanned recursively.
** Omit files named in VFILE.
**
** Files whose names begin with "." are omitted unless the SCAN_ALL
** flag is set.
**
** Any files or directories that match the glob patterns pIgnore*
** are excluded from the scan. Name matching occurs after the
** first nPrefix characters are elided from the filename.
*/
void vfile_scan(
Blob *pPath, /* Directory to be scanned */
int nPrefix, /* Number of bytes in directory name */
unsigned scanFlags, /* Zero or more SCAN_xxx flags */
Glob *pIgnore1, /* Do not add files that match this GLOB */
Glob *pIgnore2 /* Omit files matching this GLOB too */
){
DIR *d;
int origSize;
struct dirent *pEntry;
int skipAll = 0;
static Stmt ins;
static int depth = 0;
void *zNative;
origSize = blob_size(pPath);
|
| ︙ | ︙ | |||
468 469 470 471 472 473 474 |
"INSERT OR IGNORE INTO sfile(x) SELECT :file"
" WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
" pathname=:file %s)", filename_collation()
);
}
depth++;
| < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
"INSERT OR IGNORE INTO sfile(x) SELECT :file"
" WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
" pathname=:file %s)", filename_collation()
);
}
depth++;
zNative = fossil_utf8_to_filename(blob_str(pPath));
d = opendir(zNative);
if( d ){
while( (pEntry=readdir(d))!=0 ){
char *zPath;
char *zUtf8;
if( pEntry->d_name[0]=='.' ){
if( (scanFlags & SCAN_ALL)==0 ) continue;
if( pEntry->d_name[1]==0 ) continue;
if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
}
zUtf8 = fossil_filename_to_utf8(pEntry->d_name);
blob_appendf(pPath, "/%s", zUtf8);
zPath = blob_str(pPath);
if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
glob_match(pIgnore2, &zPath[nPrefix+1]) ){
/* do nothing */
}else if( file_wd_isdir(zPath)==1 ){
if( !vfile_top_of_checkout(zPath) ){
vfile_scan(pPath, nPrefix, scanFlags, pIgnore1, pIgnore2);
}
}else if( file_wd_isfile_or_link(zPath) ){
if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){
db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
db_step(&ins);
db_reset(&ins);
}
}
fossil_filename_free(zUtf8);
blob_resize(pPath, origSize);
}
closedir(d);
}
fossil_filename_free(zNative);
depth--;
if( depth==0 ){
db_finalize(&ins);
}
}
/*
** Scans the specified base directory for any directories within it, while
** keeping a count of how many files they each contains, either directly or
** indirectly.
**
** Subdirectories are scanned recursively.
** Omit files named in VFILE.
**
** Directories whose names begin with "." are omitted unless the SCAN_ALL
** flag is set.
**
** Any directories that match the glob patterns pIgnore* are excluded from
** the scan. Name matching occurs after the first nPrefix characters are
** elided from the filename.
**
** Returns the total number of files found.
*/
int vfile_dir_scan(
Blob *pPath, /* Base directory to be scanned */
int nPrefix, /* Number of bytes in base directory name */
unsigned scanFlags, /* Zero or more SCAN_xxx flags */
Glob *pIgnore1, /* Do not add directories that match this GLOB */
Glob *pIgnore2, /* Omit directories matching this GLOB too */
Glob *pIgnore3 /* Omit directories matching this GLOB too */
){
int result = 0;
DIR *d;
int origSize;
struct dirent *pEntry;
int skipAll = 0;
static Stmt ins;
static Stmt upd;
static int depth = 0;
void *zNative;
origSize = blob_size(pPath);
if( pIgnore1 || pIgnore2 || pIgnore3 ){
blob_appendf(pPath, "/");
if( glob_match(pIgnore1, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
if( glob_match(pIgnore2, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
if( glob_match(pIgnore3, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1;
blob_resize(pPath, origSize);
}
if( skipAll ) return result;
if( depth==0 ){
db_multi_exec("DROP TABLE IF EXISTS dscan_temp;"
"CREATE TEMP TABLE dscan_temp("
" x TEXT PRIMARY KEY %s, y INTEGER)",
filename_collation());
db_prepare(&ins,
"INSERT OR IGNORE INTO dscan_temp(x, y) SELECT :file, :count"
" WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE"
" pathname GLOB :file || '/*' %s)", filename_collation()
);
db_prepare(&upd,
"UPDATE OR IGNORE dscan_temp SET y = coalesce(y, 0) + 1"
" WHERE x=:file %s",
filename_collation()
);
}
depth++;
zNative = fossil_utf8_to_filename(blob_str(pPath));
d = opendir(zNative);
if( d ){
while( (pEntry=readdir(d))!=0 ){
char *zOrigPath;
char *zPath;
char *zUtf8;
if( pEntry->d_name[0]=='.' ){
if( (scanFlags & SCAN_ALL)==0 ) continue;
if( pEntry->d_name[1]==0 ) continue;
if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
}
zOrigPath = mprintf("%s", blob_str(pPath));
zUtf8 = fossil_filename_to_utf8(pEntry->d_name);
blob_appendf(pPath, "/%s", zUtf8);
zPath = blob_str(pPath);
if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
glob_match(pIgnore2, &zPath[nPrefix+1]) ||
glob_match(pIgnore3, &zPath[nPrefix+1]) ){
/* do nothing */
}else if( file_wd_isdir(zPath)==1 ){
if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
char *zSavePath = mprintf("%s", zPath);
int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
pIgnore2, pIgnore3);
db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
db_bind_int(&ins, ":count", count);
db_step(&ins);
db_reset(&ins);
fossil_free(zSavePath);
result += count; /* found X normal files? */
}
}else if( file_wd_isfile_or_link(zPath) ){
db_bind_text(&upd, ":file", zOrigPath);
db_step(&upd);
db_reset(&upd);
result++; /* found 1 normal file */
}
fossil_filename_free(zUtf8);
blob_resize(pPath, origSize);
fossil_free(zOrigPath);
}
closedir(d);
}
fossil_filename_free(zNative);
depth--;
if( depth==0 ){
db_finalize(&upd);
db_finalize(&ins);
}
return result;
}
/*
** Compute an aggregate MD5 checksum over the disk image of every
** file in vid. The file names are part of the checksum. The resulting
** checksum is the same as is expected on the R-card of a manifest.
**
** This function operates differently if the Global.aCommitFile
|
| ︙ | ︙ | |||
537 538 539 540 541 542 543 |
*/
void vfile_aggregate_checksum_disk(int vid, Blob *pOut){
FILE *in;
Stmt q;
char zBuf[4096];
db_must_be_within_tree();
| | | | 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 |
*/
void vfile_aggregate_checksum_disk(int vid, Blob *pOut){
FILE *in;
Stmt q;
char zBuf[4096];
db_must_be_within_tree();
db_prepare(&q,
"SELECT %Q || pathname, pathname, origname, is_selected(id), rid"
" FROM vfile"
" WHERE (NOT deleted OR NOT is_selected(id)) AND vid=%d"
" ORDER BY if_selected(id, pathname, origname) /*scan*/",
g.zLocalRoot, vid
);
md5sum_init();
while( db_step(&q)==SQLITE_ROW ){
const char *zFullpath = db_column_text(&q, 0);
const char *zName = db_column_text(&q, 1);
int isSelected = db_column_int(&q, 3);
if( isSelected ){
md5sum_step_text(zName, -1);
if( file_wd_islink(zFullpath) ){
/* Instead of file content, use link destination path */
Blob pathBuf;
sqlite3_snprintf(sizeof(zBuf), zBuf, " %ld\n",
blob_read_link(&pathBuf, zFullpath));
md5sum_step_text(zBuf, -1);
md5sum_step_text(blob_str(&pathBuf), -1);
blob_reset(&pathBuf);
}else{
in = fossil_fopen(zFullpath,"rb");
if( in==0 ){
|
| ︙ | ︙ | |||
626 627 628 629 630 631 632 |
** the working check-out on disk. Report any errors.
*/
void vfile_compare_repository_to_disk(int vid){
int rc;
Stmt q;
Blob disk, repo;
char *zOut;
| | | | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 |
** the working check-out on disk. Report any errors.
*/
void vfile_compare_repository_to_disk(int vid){
int rc;
Stmt q;
Blob disk, repo;
char *zOut;
db_must_be_within_tree();
db_prepare(&q,
"SELECT %Q || pathname, pathname, rid FROM vfile"
" WHERE NOT deleted AND vid=%d AND is_selected(id)"
" ORDER BY if_selected(id, pathname, origname) /*scan*/",
g.zLocalRoot, vid
);
md5sum_init();
while( db_step(&q)==SQLITE_ROW ){
|
| ︙ | ︙ | |||
692 693 694 695 696 697 698 |
*/
void vfile_aggregate_checksum_repository(int vid, Blob *pOut){
Blob file;
Stmt q;
char zBuf[100];
db_must_be_within_tree();
| | | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
*/
void vfile_aggregate_checksum_repository(int vid, Blob *pOut){
Blob file;
Stmt q;
char zBuf[100];
db_must_be_within_tree();
db_prepare(&q, "SELECT pathname, origname, rid, is_selected(id)"
" FROM vfile"
" WHERE (NOT deleted OR NOT is_selected(id))"
" AND rid>0 AND vid=%d"
" ORDER BY if_selected(id,pathname,origname) /*scan*/",
vid);
blob_zero(&file);
|
| ︙ | ︙ | |||
730 731 732 733 734 735 736 | ** ** Return the resulting checksum in blob pOut. ** ** If pManOut is not NULL then fill it with the checksum found in the ** "R" card near the end of the manifest. ** ** In a well-formed manifest, the two checksums computed here, pOut and | | > > | | > | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 |
**
** Return the resulting checksum in blob pOut.
**
** If pManOut is not NULL then fill it with the checksum found in the
** "R" card near the end of the manifest.
**
** In a well-formed manifest, the two checksums computed here, pOut and
** pManOut, should be identical.
*/
void vfile_aggregate_checksum_manifest(int vid, Blob *pOut, Blob *pManOut){
int fid;
Blob file;
Blob err;
Manifest *pManifest;
ManifestFile *pFile;
char zBuf[100];
blob_zero(pOut);
blob_zero(&err);
if( pManOut ){
blob_zero(pManOut);
}
db_must_be_within_tree();
pManifest = manifest_get(vid, CFTYPE_MANIFEST, &err);
if( pManifest==0 ){
fossil_fatal("manifest file (%d) is malformed:\n%s\n",
vid, blob_str(&err));
}
manifest_file_rewind(pManifest);
while( (pFile = manifest_file_next(pManifest,0))!=0 ){
if( pFile->zUuid==0 ) continue;
fid = uuid_to_rid(pFile->zUuid, 0);
md5sum_step_text(pFile->zName, -1);
content_get(fid, &file);
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to do formatting of wiki text. */ #include <assert.h> #include <ctype.h> | > < | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to do formatting of wiki text.
*/
#include "config.h"
#include <assert.h>
#include <ctype.h>
#include "wiki.h"
/*
** Return true if the input string is a well-formed wiki page name.
**
** Well-formed wiki page names do not begin or end with whitespace,
** and do not contain tabs or other control characters and do not
** contain more than a single space character in a row. Well-formed
** names must be between 1 and 100 characters in length, inclusive.
*/
int wiki_name_is_wellformed(const unsigned char *z){
int i;
if( z[0]<=0x20 ){
return 0;
}
for(i=1; z[i]; i++){
if( z[i]<0x20 ) return 0;
if( z[i]==0x20 && z[i-1]==0x20 ) return 0;
}
if( z[i-1]==' ' ) return 0;
if( i<1 || i>100 ) return 0;
return 1;
}
/*
** Output rules for well-formed wiki pages
*/
static void well_formed_wiki_name_rules(void){
@ <ul>
@ <li> Must not begin or end with a space.</li>
@ <li> Must not contain any control characters, including tab or
@ newline.</li>
@ <li> Must not have two or more spaces in a row internally.</li>
@ <li> Must be between 1 and 100 characters in length.</li>
@ </ul>
}
/*
** Check a wiki name. If it is not well-formed, then issue an error
** and return true. If it is well-formed, return false.
*/
|
| ︙ | ︙ | |||
94 95 96 97 98 99 100 |
}
if( !g.perm.RdWiki ){
cgi_redirectf("%s/login?g=%s/home", g.zTop, g.zTop);
}
if( zPageName ){
login_check_credentials();
g.zExtra = zPageName;
| | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
}
if( !g.perm.RdWiki ){
cgi_redirectf("%s/login?g=%s/home", g.zTop, g.zTop);
}
if( zPageName ){
login_check_credentials();
g.zExtra = zPageName;
cgi_set_parameter_nocopy("name", g.zExtra, 1);
g.isHome = 1;
wiki_page();
return;
}
style_header("Home");
@ <p>This is a stub home-page for the project.
@ To fill in this page, first go to
|
| ︙ | ︙ | |||
176 177 178 179 180 181 182 183 184 185 |
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
zPageName = P("name");
if( zPageName==0 ){
style_header("Wiki");
@ <ul>
{ char *zHomePageName = db_get("project-name",0);
if( zHomePageName ){
@ <li> %z(href("%R/wiki?name=%t",zHomePageName))
| > > > > > > | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
zPageName = P("name");
if( zPageName==0 ){
style_header("Wiki");
@ <ul>
{ char *zWikiHomePageName = db_get("index-page",0);
if( zWikiHomePageName ){
@ <li> %z(href("%R%s",zWikiHomePageName))
@ %h(zWikiHomePageName)</a> wiki home page.</li>
}
}
{ char *zHomePageName = db_get("project-name",0);
if( zHomePageName ){
@ <li> %z(href("%R/wiki?name=%t",zHomePageName))
@ %h(zHomePageName)</a> project home page.</li>
}
}
@ <li> %z(href("%R/timeline?y=w"))Recent changes</a> to wiki pages.</li>
@ <li> %z(href("%R/wiki_rules"))Formatting rules</a> for wiki.</li>
@ <li> Use the %z(href("%R/wiki?name=Sandbox"))Sandbox</a>
@ to experiment.</li>
if( g.perm.NewWiki ){
|
| ︙ | ︙ | |||
214 215 216 217 218 219 220 |
isSandbox = is_sandbox(zPageName);
if( isSandbox ){
zBody = db_get("sandbox",zBody);
zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
rid = 0;
}else{
zTag = mprintf("wiki-%s", zPageName);
| | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
isSandbox = is_sandbox(zPageName);
if( isSandbox ){
zBody = db_get("sandbox",zBody);
zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
rid = 0;
}else{
zTag = mprintf("wiki-%s", zPageName);
rid = db_int(0,
"SELECT rid FROM tagxref"
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
" ORDER BY mtime DESC", zTag
);
free(zTag);
pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
if( pWiki ){
zBody = pWiki->zWiki;
zMimetype = pWiki->zMimetype;
}
}
zMimetype = wiki_filter_mimetypes(zMimetype);
if( !g.isHome ){
|
| ︙ | ︙ | |||
252 253 254 255 256 257 258 |
}
if( rid && g.perm.ApndWiki && g.perm.Attach ){
style_submenu_element("Attach", "Add An Attachment",
"%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
g.zTop, zPageName, g.zTop, zPageName);
}
if( rid && g.perm.ApndWiki ){
| | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
}
if( rid && g.perm.ApndWiki && g.perm.Attach ){
style_submenu_element("Attach", "Add An Attachment",
"%s/attachadd?page=%T&from=%s/wiki%%3fname=%T",
g.zTop, zPageName, g.zTop, zPageName);
}
if( rid && g.perm.ApndWiki ){
style_submenu_element("Append", "Add A Comment",
"%s/wikiappend?name=%T&mimetype=%s",
g.zTop, zPageName, zMimetype);
}
if( g.perm.Hyperlink ){
style_submenu_element("History", "History", "%s/whistory?name=%T",
g.zTop, zPageName);
}
|
| ︙ | ︙ | |||
286 287 288 289 290 291 292 |
}else{
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
moderation_table_create();
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
| | | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
}else{
nrid = content_put_ex(pWiki, 0, 0, 0, 1);
moderation_table_create();
db_multi_exec("INSERT INTO modreq(objid) VALUES(%d)", nrid);
}
db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
db_multi_exec("INSERT OR IGNORE INTO unclustered VALUES(%d);", nrid);
manifest_crosslink(nrid, pWiki, MC_NONE);
}
/*
** Formal names and common names for the various wiki styles.
*/
static const char *const azStyles[] = {
"text/x-fossil-wiki", "Fossil Wiki",
"text/x-markdown", "Markdown",
"text/plain", "Plain Text"
};
/*
** Output a selection box from which the user can select the
|
| ︙ | ︙ | |||
373 374 375 376 377 378 379 |
}
if( zBody==0 ){
zBody = db_get("sandbox","");
zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
}
}else{
zTag = mprintf("wiki-%s", zPageName);
| | | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
}
if( zBody==0 ){
zBody = db_get("sandbox","");
zMimetype = db_get("sandbox-mimetype","text/x-fossil-wiki");
}
}else{
zTag = mprintf("wiki-%s", zPageName);
rid = db_int(0,
"SELECT rid FROM tagxref"
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
" ORDER BY mtime DESC", zTag
);
free(zTag);
if( (rid && !g.perm.WrWiki) || (!rid && !g.perm.NewWiki) ){
login_needed();
return;
}
if( zBody==0 && (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
zBody = pWiki->zWiki;
zMimetype = pWiki->zMimetype;
}
}
if( P("submit")!=0 && zBody!=0
&& (goodCaptcha = captcha_is_correct())
){
|
| ︙ | ︙ | |||
454 455 456 457 458 459 460 |
if( n<20 ) n = 20;
if( n>30 ) n = 30;
if( !isWysiwyg ){
/* Traditional markup-only editing */
form_begin(0, "%R/wikiedit");
@ <div>
mimetype_option_menu(zMimetype);
| | | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
if( n<20 ) n = 20;
if( n>30 ) n = 30;
if( !isWysiwyg ){
/* Traditional markup-only editing */
form_begin(0, "%R/wikiedit");
@ <div>
mimetype_option_menu(zMimetype);
@ <br /><textarea name="w" class="wikiedit" cols="80"
@ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
@ <br />
if( db_get_boolean("wysiwyg-wiki", 0) ){
@ <input type="submit" name="edit-wysiwyg" value="Wysiwyg Editor"
@ onclick='return confirm("Switching to WYSIWYG-mode\nwill erase your markup\nedits. Continue?")' />
}
@ <input type="submit" name="preview" value="Preview Your Changes" />
|
| ︙ | ︙ | |||
485 486 487 488 489 490 491 |
}
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply These Changes" />
@ <input type="hidden" name="name" value="%h(zPageName)" />
@ <input type="submit" name="cancel" value="Cancel"
@ onclick='confirm("Abandon your changes?")' />
@ </div>
| | | | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 |
}
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply These Changes" />
@ <input type="hidden" name="name" value="%h(zPageName)" />
@ <input type="submit" name="cancel" value="Cancel"
@ onclick='confirm("Abandon your changes?")' />
@ </div>
captcha_generate(0);
@ </form>
manifest_destroy(pWiki);
blob_reset(&wiki);
style_footer();
}
/*
** WEBPAGE: wikinew
** URL /wikinew
**
** Prompt the user to enter the name of a new wiki page. Then redirect
** to the wikiedit screen for that new page.
*/
void wikinew_page(void){
const char *zName;
const char *zMimetype;
login_check_credentials();
if( !g.perm.NewWiki ){
login_needed();
return;
}
zName = PD("name","");
zMimetype = wiki_filter_mimetypes(P("mimetype"));
if( zName[0] && wiki_name_is_wellformed((const unsigned char *)zName) ){
if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0
&& db_get_boolean("wysiwyg-wiki", 0)
){
cgi_redirectf("wikiedit?name=%T&wysiwyg=1", zName);
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 |
char *zId;
zDate = db_text(0, "SELECT datetime('now')");
zRemark = PD("r","");
zUser = PD("u",g.zLogin);
if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
zId = db_text(0, "SELECT lower(hex(randomblob(8)))");
| | | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 |
char *zId;
zDate = db_text(0, "SELECT datetime('now')");
zRemark = PD("r","");
zUser = PD("u",g.zLogin);
if( fossil_strcmp(zMimetype, "text/x-fossil-wiki")==0 ){
zId = db_text(0, "SELECT lower(hex(randomblob(8)))");
blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h",
zId, zDate, g.zLogin);
if( zUser[0] && fossil_strcmp(zUser,g.zLogin) ){
blob_appendf(p, " (claiming to be %h)", zUser);
}
blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId);
}else if( fossil_strcmp(zMimetype, "text/x-markdown")==0 ){
blob_appendf(p, "\n\n------\n*On %s UTC %h", zDate, g.zLogin);
|
| ︙ | ︙ | |||
593 594 595 596 597 598 599 |
login_check_credentials();
zPageName = PD("name","");
zMimetype = wiki_filter_mimetypes(P("mimetype"));
if( check_name(zPageName) ) return;
isSandbox = is_sandbox(zPageName);
if( !isSandbox ){
zTag = mprintf("wiki-%s", zPageName);
| | | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
login_check_credentials();
zPageName = PD("name","");
zMimetype = wiki_filter_mimetypes(P("mimetype"));
if( check_name(zPageName) ) return;
isSandbox = is_sandbox(zPageName);
if( !isSandbox ){
zTag = mprintf("wiki-%s", zPageName);
rid = db_int(0,
"SELECT rid FROM tagxref"
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
" ORDER BY mtime DESC", zTag
);
free(zTag);
if( !rid ){
fossil_redirect_home();
|
| ︙ | ︙ | |||
624 625 626 627 628 629 630 |
blob_zero(&body);
if( isSandbox ){
blob_appendf(&body, db_get("sandbox",""));
appendRemark(&body, zMimetype);
db_set("sandbox", blob_str(&body), 0);
}else{
login_verify_csrf_secret();
| | | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
blob_zero(&body);
if( isSandbox ){
blob_appendf(&body, db_get("sandbox",""));
appendRemark(&body, zMimetype);
db_set("sandbox", blob_str(&body), 0);
}else{
login_verify_csrf_secret();
pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
if( pWiki ){
blob_append(&body, pWiki->zWiki, -1);
manifest_destroy(pWiki);
}
blob_zero(&wiki);
db_begin_transaction();
zDate = date_in_standard_format("now");
|
| ︙ | ︙ | |||
682 683 684 685 686 687 688 | login_insert_csrf_secret(); @ <input type="hidden" name="name" value="%h(zPageName)" /> @ <input type="hidden" name="mimetype" value="%h(zMimetype)" /> @ Your Name: @ <input type="text" name="u" size="20" value="%h(zUser)" /><br /> zFormat = mimetype_common_name(zMimetype); @ Comment to append (formatted as %s(zFormat)):<br /> | | | | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
login_insert_csrf_secret();
@ <input type="hidden" name="name" value="%h(zPageName)" />
@ <input type="hidden" name="mimetype" value="%h(zMimetype)" />
@ Your Name:
@ <input type="text" name="u" size="20" value="%h(zUser)" /><br />
zFormat = mimetype_common_name(zMimetype);
@ Comment to append (formatted as %s(zFormat)):<br />
@ <textarea name="r" class="wikiedit" cols="80"
@ rows="10" wrap="virtual">%h(PD("r",""))</textarea>
@ <br />
@ <input type="submit" name="preview" value="Preview Your Comment" />
@ <input type="submit" name="submit" value="Append Your Changes" />
@ <input type="submit" name="cancel" value="Cancel" />
captcha_generate(0);
@ </form>
style_footer();
}
/*
** Name of the wiki history page being generated
*/
|
| ︙ | ︙ | |||
774 775 776 777 778 779 780 |
"SELECT objid FROM event JOIN tagxref ON objid=rid AND tagxref.tagid="
"(SELECT tagid FROM tag WHERE tagname='wiki-%q')"
" WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)"
" ORDER BY event.mtime DESC LIMIT 1",
zPageName, rid1
);
}
| | | | | | | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
"SELECT objid FROM event JOIN tagxref ON objid=rid AND tagxref.tagid="
"(SELECT tagid FROM tag WHERE tagname='wiki-%q')"
" WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)"
" ORDER BY event.mtime DESC LIMIT 1",
zPageName, rid1
);
}
pW1 = manifest_get(rid1, CFTYPE_WIKI, 0);
if( pW1==0 ) fossil_redirect_home();
blob_init(&w1, pW1->zWiki, -1);
blob_zero(&w2);
if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI, 0))!=0 ){
blob_init(&w2, pW2->zWiki, -1);
}
blob_zero(&d);
diffFlags = construct_diff_flags(1,0);
text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
@ <pre class="udiff">
@ %s(blob_str(&d))
@ <pre>
manifest_destroy(pW1);
manifest_destroy(pW2);
style_footer();
}
/*
** prepare()s pStmt with a query requesting:
**
** - wiki page name
** - tagxref (whatever that really is!)
**
** Used by wcontent_page() and the JSON wiki code.
*/
void wiki_prepare_page_list( Stmt * pStmt ){
db_prepare(pStmt,
"SELECT"
" substr(tagname, 6) as name,"
" (SELECT value FROM tagxref WHERE tagid=tag.tagid ORDER BY mtime DESC) as tagXref"
" FROM tag WHERE tagname GLOB 'wiki-*'"
" ORDER BY lower(tagname) /*sort*/"
);
}
|
| ︙ | ︙ | |||
858 859 860 861 862 863 864 |
Stmt q;
const char * zTitle;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
zTitle = PD("title","*");
style_header("Wiki Pages Found");
@ <ul>
| | | | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 |
Stmt q;
const char * zTitle;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(); return; }
zTitle = PD("title","*");
style_header("Wiki Pages Found");
@ <ul>
db_prepare(&q,
"SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname like 'wiki-%%%q%%'"
" ORDER BY lower(tagname) /*sort*/" ,
zTitle);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
@ <li>%z(href("%R/wiki?name=%T",zName))%h(zName)</a></li>
}
db_finalize(&q);
@ </ul>
style_footer();
|
| ︙ | ︙ | |||
909 910 911 912 913 914 915 | @ <li> <p><span class="wikiruleHead">Enumeration Lists</span>. @ An enumeration list item is a line that begins with a single "#" character @ surrounded on both sides by two or more spaces or by a tab. Only a single @ level of enumeration list is supported by wiki. For nested lists or for @ enumerations that count using letters or roman numerials, use HTML.</p></li> @ <li> <p><span class="wikiruleHead">Indented Paragraphs</span>. @ Any paragraph that begins with two or more spaces or a tab and | | | 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 |
@ <li> <p><span class="wikiruleHead">Enumeration Lists</span>.
@ An enumeration list item is a line that begins with a single "#" character
@ surrounded on both sides by two or more spaces or by a tab. Only a single
@ level of enumeration list is supported by wiki. For nested lists or for
@ enumerations that count using letters or roman numerials, use HTML.</p></li>
@ <li> <p><span class="wikiruleHead">Indented Paragraphs</span>.
@ Any paragraph that begins with two or more spaces or a tab and
@ which is not a bullet or enumeration list item is rendered
@ indented. Only a single level of indentation is supported by wiki; use
@ HTML for deeper indentation.</p></li>
@ <li> <p><span class="wikiruleHead">Hyperlinks</span>.
@ Text within square brackets ("[...]") becomes a hyperlink. The
@ target can be a wiki page name, the artifact ID of a check-in or ticket,
@ the name of an image, or a URL. By default, the target is displayed
@ as the text of the hyperlink. But you can specify alternative text
|
| ︙ | ︙ | |||
1054 1055 1056 1057 1058 1059 1060 |
if( (g.argc!=4) && (g.argc!=5) ){
usage("export PAGENAME ?FILE?");
}
zPageName = g.argv[3];
rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
" WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
" ORDER BY x.mtime DESC LIMIT 1",
| | | | 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 |
if( (g.argc!=4) && (g.argc!=5) ){
usage("export PAGENAME ?FILE?");
}
zPageName = g.argv[3];
rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x"
" WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'"
" ORDER BY x.mtime DESC LIMIT 1",
zPageName
);
if( (pWiki = manifest_get(rid, CFTYPE_WIKI, 0))!=0 ){
zBody = pWiki->zWiki;
}
if( zBody==0 ){
fossil_fatal("wiki page [%s] not found",zPageName);
}
for(i=strlen(zBody); i>0 && fossil_isspace(zBody[i-1]); i--){}
zBody[i] = 0;
|
| ︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 |
if( g.argc!=5 ){
usage("delete PAGENAME");
}
fossil_fatal("delete not yet implemented.");
}else
if( strncmp(g.argv[2],"list",n)==0 ){
Stmt q;
| | | 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 |
if( g.argc!=5 ){
usage("delete PAGENAME");
}
fossil_fatal("delete not yet implemented.");
}else
if( strncmp(g.argv[2],"list",n)==0 ){
Stmt q;
db_prepare(&q,
"SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'"
" ORDER BY lower(tagname) /*sort*/"
);
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
fossil_print( "%s\n",zName);
}
|
| ︙ | ︙ |
Changes to src/wikiformat.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to do formatting of wiki text. */ | < > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code to do formatting of wiki text. */ #include "config.h" #include <assert.h> #include "wikiformat.h" #if INTERFACE /* ** Allowed wiki transformation operations */ #define WIKI_HTMLONLY 0x001 /* HTML markup only. No wiki */ |
| ︙ | ︙ |
Added src/winfile.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
/*
** Copyright (c) 2006 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file implements several non-trivial file handling wrapper functions
** on Windows using the Win32 API.
*/
#include "config.h"
#ifdef _WIN32
/* This code is for win32 only */
#include <sys/stat.h>
#include <windows.h>
#include "winfile.h"
#ifndef LABEL_SECURITY_INFORMATION
# define LABEL_SECURITY_INFORMATION (0x00000010L)
#endif
/*
** Fill stat buf with information received from stat() or lstat().
** lstat() is called on Unix if isWd is TRUE and allow-symlinks setting is on.
**
*/
int win32_stat(const char *zFilename, struct fossilStat *buf, int isWd){
WIN32_FILE_ATTRIBUTE_DATA attr;
wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
int rc = GetFileAttributesExW(zMbcs, GetFileExInfoStandard, &attr);
fossil_filename_free(zMbcs);
if( rc ){
ULARGE_INTEGER ull;
ull.LowPart = attr.ftLastWriteTime.dwLowDateTime;
ull.HighPart = attr.ftLastWriteTime.dwHighDateTime;
buf->st_mode = (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
S_IFDIR : S_IFREG;
buf->st_size = (((i64)attr.nFileSizeHigh)<<32) | attr.nFileSizeLow;
buf->st_mtime = ull.QuadPart / 10000000ULL - 11644473600ULL;
}
return !rc;
}
/*
** Wrapper around the access() system call. This code was copied from Tcl
** 8.6 and then modified.
*/
int win32_access(const char *zFilename, int flags){
int rc = 0;
PSECURITY_DESCRIPTOR pSd = NULL;
unsigned long size;
PSID pSid = NULL;
BOOL sidDefaulted;
BOOL impersonated = FALSE;
SID_IDENTIFIER_AUTHORITY unmapped = {{0, 0, 0, 0, 0, 22}};
GENERIC_MAPPING genMap;
HANDLE hToken = NULL;
DWORD desiredAccess = 0, grantedAccess = 0;
BOOL accessYesNo = FALSE;
PRIVILEGE_SET privSet;
DWORD privSetSize = sizeof(PRIVILEGE_SET);
wchar_t *zMbcs = fossil_utf8_to_filename(zFilename);
DWORD attr = GetFileAttributesW(zMbcs);
if( attr==INVALID_FILE_ATTRIBUTES ){
/*
* File might not exist.
*/
if( GetLastError()!=ERROR_SHARING_VIOLATION ){
rc = -1; goto done;
}
}
if( flags==F_OK ){
/*
* File exists, nothing else to check.
*/
goto done;
}
if( (flags & W_OK)
&& (attr & FILE_ATTRIBUTE_READONLY)
&& !(attr & FILE_ATTRIBUTE_DIRECTORY) ){
/*
* The attributes say the file is not writable. If the file is a
* regular file (i.e., not a directory), then the file is not
* writable, full stop. For directories, the read-only bit is
* (mostly) ignored by Windows, so we can't ascertain anything about
* directory access from the attrib data.
*/
rc = -1; goto done;
}
/*
* It looks as if the permissions are ok, but if we are on NT, 2000 or XP,
* we have a more complex permissions structure so we try to check that.
* The code below is remarkably complex for such a simple thing as finding
* what permissions the OS has set for a file.
*/
/*
* First find out how big the buffer needs to be.
*/
size = 0;
GetFileSecurityW(zMbcs,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
0, 0, &size);
/*
* Should have failed with ERROR_INSUFFICIENT_BUFFER
*/
if( GetLastError()!=ERROR_INSUFFICIENT_BUFFER ){
/*
* Most likely case is ERROR_ACCESS_DENIED, which we will convert to
* EACCES - just what we want!
*/
rc = -1; goto done;
}
/*
* Now size contains the size of buffer needed.
*/
pSd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), 0, size);
if( pSd==NULL ){
rc = -1; goto done;
}
/*
* Call GetFileSecurity() for real.
*/
if( !GetFileSecurityW(zMbcs,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
pSd, size, &size) ){
/*
* Error getting owner SD
*/
rc = -1; goto done;
}
/*
* As of Samba 3.0.23 (10-Jul-2006), unmapped users and groups are
* assigned to SID domains S-1-22-1 and S-1-22-2, where "22" is the
* top-level authority. If the file owner and group is unmapped then
* the ACL access check below will only test against world access,
* which is likely to be more restrictive than the actual access
* restrictions. Since the ACL tests are more likely wrong than
* right, skip them. Moreover, the unix owner access permissions are
* usually mapped to the Windows attributes, so if the user is the
* file owner then the attrib checks above are correct (as far as they
* go).
*/
if( !GetSecurityDescriptorOwner(pSd, &pSid, &sidDefaulted) ||
memcmp(GetSidIdentifierAuthority(pSid), &unmapped,
sizeof(SID_IDENTIFIER_AUTHORITY))==0 ){
goto done; /* Attrib tests say access allowed. */
}
/*
* Perform security impersonation of the user and open the resulting
* thread token.
*/
if( !ImpersonateSelf(SecurityImpersonation) ){
/*
* Unable to perform security impersonation.
*/
rc = -1; goto done;
}
impersonated = TRUE;
if( !OpenThreadToken(GetCurrentThread(),
TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken) ){
/*
* Unable to get current thread's token.
*/
rc = -1; goto done;
}
/*
* Setup desiredAccess according to the access priveleges we are
* checking.
*/
if( flags & R_OK ){
desiredAccess |= FILE_GENERIC_READ;
}
if( flags & W_OK){
desiredAccess |= FILE_GENERIC_WRITE;
}
memset(&genMap, 0, sizeof(GENERIC_MAPPING));
genMap.GenericRead = FILE_GENERIC_READ;
genMap.GenericWrite = FILE_GENERIC_WRITE;
genMap.GenericExecute = FILE_GENERIC_EXECUTE;
genMap.GenericAll = FILE_ALL_ACCESS;
/*
* Perform access check using the token.
*/
if( !AccessCheck(pSd, hToken, desiredAccess, &genMap, &privSet,
&privSetSize, &grantedAccess, &accessYesNo) ){
/*
* Unable to perform access check.
*/
rc = -1; goto done;
}
if( !accessYesNo ) rc = -1;
done:
if( hToken != NULL ){
CloseHandle(hToken);
}
if( impersonated ){
RevertToSelf();
impersonated = FALSE;
}
if( pSd!=NULL ){
HeapFree(GetProcessHeap(), 0, pSd);
}
fossil_filename_free(zMbcs);
return rc;
}
/*
** Wrapper around the chdir() system call.
** If bChroot=1, do a chroot to this dir as well
** (UNIX only)
*/
int win32_chdir(const char *zChDir, int bChroot){
wchar_t *zPath = fossil_utf8_to_filename(zChDir);
int rc = (int)!SetCurrentDirectoryW(zPath);
fossil_filename_free(zPath);
return rc;
}
/*
** Get the current working directory.
**
** On windows, the name is converted from unicode to UTF8 and all '\\'
** characters are converted to '/'. No conversions are needed on
** unix.
*/
void win32_getcwd(char *zBuf, int nBuf){
int i;
char *zUtf8;
wchar_t *zWide = fossil_malloc( sizeof(wchar_t)*nBuf );
if( GetCurrentDirectoryW(nBuf, zWide)==0 ){
fossil_fatal("cannot find current working directory.");
}
zUtf8 = fossil_filename_to_utf8(zWide);
fossil_free(zWide);
for(i=0; zUtf8[i]; i++) if( zUtf8[i]=='\\' ) zUtf8[i] = '/';
strncpy(zBuf, zUtf8, nBuf);
fossil_filename_free(zUtf8);
}
#endif /* _WIN32 -- This code is for win32 only */
|
Changes to src/winhttp.c.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 | } return 0; } /* ** Process a single incoming HTTP request. */ | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
}
return 0;
}
/*
** Process a single incoming HTTP request.
*/
static void win32_http_request(void *pAppData){
HttpRequest *p = (HttpRequest*)pAppData;
FILE *in = 0, *out = 0;
int amt, got;
int wanted = 0;
char *z;
char zRequestFName[MAX_PATH];
char zReplyFName[MAX_PATH];
|
| ︙ | ︙ | |||
126 127 128 129 130 131 132 133 134 135 136 137 138 139 | if( out ) fclose(out); if( in ) fclose(in); closesocket(p->s); file_delete(zRequestFName); file_delete(zReplyFName); free(p); } /* ** Start a listening socket and process incoming HTTP requests on ** that socket. */ void win32_http_server( int mnPort, int mxPort, /* Range of allowed TCP port numbers */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
if( out ) fclose(out);
if( in ) fclose(in);
closesocket(p->s);
file_delete(zRequestFName);
file_delete(zReplyFName);
free(p);
}
/*
** Process a single incoming SCGI request.
*/
static void win32_scgi_request(void *pAppData){
HttpRequest *p = (HttpRequest*)pAppData;
FILE *in = 0, *out = 0;
int amt, got, nHdr, i;
int wanted = 0;
char zRequestFName[MAX_PATH];
char zReplyFName[MAX_PATH];
char zCmd[2000]; /* Command-line to process the request */
char zHdr[2000]; /* The SCGI request header */
sqlite3_snprintf(MAX_PATH, zRequestFName,
"%s_in%d.txt", zTempPrefix, p->id);
sqlite3_snprintf(MAX_PATH, zReplyFName,
"%s_out%d.txt", zTempPrefix, p->id);
out = fossil_fopen(zRequestFName, "wb");
if( out==0 ) goto end_request;
amt = 0;
got = recv(p->s, zHdr, sizeof(zHdr), 0);
if( got==SOCKET_ERROR ) goto end_request;
amt = fwrite(zHdr, 1, got, out);
nHdr = 0;
for(i=0; zHdr[i]>='0' && zHdr[i]<='9'; i++){
nHdr = 10*nHdr + zHdr[i] - '0';
}
wanted = nHdr + i + 1;
if( strcmp(zHdr+i+1, "CONTENT_LENGTH")==0 ){
wanted += atoi(zHdr+i+15);
}
while( wanted>amt ){
got = recv(p->s, zHdr, wanted<sizeof(zHdr) ? wanted : sizeof(zHdr), 0);
if( got<=0 ) break;
fwrite(zHdr, 1, got, out);
wanted += got;
}
fclose(out);
out = 0;
sqlite3_snprintf(sizeof(zCmd), zCmd,
"\"%s\" http \"%s\" %s %s %s --scgi --nossl%s",
g.nameOfExe, g.zRepositoryName, zRequestFName, zReplyFName,
inet_ntoa(p->addr.sin_addr), p->zOptions
);
fossil_system(zCmd);
in = fossil_fopen(zReplyFName, "rb");
if( in ){
while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
send(p->s, zHdr, got, 0);
}
}
end_request:
if( out ) fclose(out);
if( in ) fclose(in);
closesocket(p->s);
file_delete(zRequestFName);
file_delete(zReplyFName);
free(p);
}
/*
** Start a listening socket and process incoming HTTP requests on
** that socket.
*/
void win32_http_server(
int mnPort, int mxPort, /* Range of allowed TCP port numbers */
|
| ︙ | ︙ | |||
204 205 206 207 208 209 210 |
}
}
if( !GetTempPathW(MAX_PATH, zTmpPath) ){
fossil_fatal("unable to get path to the temporary directory.");
}
zTempPrefix = mprintf("%sfossil_server_P%d_",
fossil_unicode_to_utf8(zTmpPath), iPort);
| | > | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
}
}
if( !GetTempPathW(MAX_PATH, zTmpPath) ){
fossil_fatal("unable to get path to the temporary directory.");
}
zTempPrefix = mprintf("%sfossil_server_P%d_",
fossil_unicode_to_utf8(zTmpPath), iPort);
fossil_print("Listening for %s requests on TCP port %d\n",
(flags&HTTP_SERVER_SCGI)!=0?"SCGI":"HTTP", iPort);
if( zBrowser ){
zBrowser = mprintf(zBrowser, iPort);
fossil_print("Launch webbrowser: %s\n", zBrowser);
fossil_system(zBrowser);
}
fossil_print("Type Ctrl-C to stop the HTTP server\n");
/* Set the service status to running and pass the listener socket to the
|
| ︙ | ︙ | |||
242 243 244 245 246 247 248 |
break;
}
p = fossil_malloc( sizeof(*p) );
p->id = ++idCnt;
p->s = client;
p->addr = client_addr;
p->zOptions = blob_str(&options);
| > > > | > | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
break;
}
p = fossil_malloc( sizeof(*p) );
p->id = ++idCnt;
p->s = client;
p->addr = client_addr;
p->zOptions = blob_str(&options);
if( flags & HTTP_SERVER_SCGI ){
_beginthread(win32_scgi_request, 0, (void*)p);
}else{
_beginthread(win32_http_request, 0, (void*)p);
}
}
closesocket(s);
WSACleanup();
}
/*
** The HttpService structure is used to pass information to the service main
|
| ︙ | ︙ | |||
537 538 539 540 541 542 543 544 545 546 547 548 549 550 | ** ** --localauth ** ** Enables automatic login if the --localauth option is present ** and the "localauth" setting is off and the connection is from ** localhost. ** ** ** fossil winsrv delete ?SERVICE-NAME? ** ** Deletes a service. If the service is currently running, it will be ** stopped first and then deleted. ** ** | > > > > | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | ** ** --localauth ** ** Enables automatic login if the --localauth option is present ** and the "localauth" setting is off and the connection is from ** localhost. ** ** --scgi ** ** Create an SCGI server instead of an HTTP server ** ** ** fossil winsrv delete ?SERVICE-NAME? ** ** Deletes a service. If the service is currently running, it will be ** stopped first and then deleted. ** ** |
| ︙ | ︙ | |||
590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
const char *zUsername = find_option("username", "U", 1);
const char *zPassword = find_option("password", "W", 1);
const char *zPort = find_option("port", "P", 1);
const char *zNotFound = find_option("notfound", 0, 1);
const char *zFileGlob = find_option("files", 0, 1);
const char *zLocalAuth = find_option("localauth", 0, 0);
const char *zRepository = find_option("repository", "R", 1);
Blob binPath;
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
fossil_fatal("to much arguments for create method.");
| > | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 |
const char *zUsername = find_option("username", "U", 1);
const char *zPassword = find_option("password", "W", 1);
const char *zPort = find_option("port", "P", 1);
const char *zNotFound = find_option("notfound", 0, 1);
const char *zFileGlob = find_option("files", 0, 1);
const char *zLocalAuth = find_option("localauth", 0, 0);
const char *zRepository = find_option("repository", "R", 1);
int useSCGI = find_option("scgi", 0, 0)!=0;
Blob binPath;
verify_all_options();
if( g.argc==4 ){
zSvcName = g.argv[3];
}else if( g.argc>4 ){
fossil_fatal("to much arguments for create method.");
|
| ︙ | ︙ | |||
630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
db_open_repository(zRepository);
}
db_close(0);
/* Build the fully-qualified path to the service binary file. */
blob_zero(&binPath);
blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
/* Create the service. */
hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
| > | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 |
db_open_repository(zRepository);
}
db_close(0);
/* Build the fully-qualified path to the service binary file. */
blob_zero(&binPath);
blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
if( useSCGI ) blob_appendf(&binPath, " --scgi");
if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
/* Create the service. */
hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
|
| ︙ | ︙ |
Changes to src/wysiwyg.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code that generates WYSIWYG text editors on ** web pages. */ #include <assert.h> #include <ctype.h> | > < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code that generates WYSIWYG text editors on ** web pages. */ #include "config.h" #include <assert.h> #include <ctype.h> #include "wysiwyg.h" /* ** Output code for a WYSIWYG editor. The caller must have already generated ** the <form> that will contain the editor, and the call must generate the ** corresponding </form> after this routine returns. The caller must include |
| ︙ | ︙ | |||
226 227 228 229 230 231 232 | @ </div> @ <div id="wysiwygBox" @ style="resize:both; overflow:auto; width: %d(w)em; height: %d(h)em;" @ contenteditable="true">%s(zContent)</div> @ <script> @ var oDoc; | | | | | | | | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
@ </div>
@ <div id="wysiwygBox"
@ style="resize:both; overflow:auto; width: %d(w)em; height: %d(h)em;"
@ contenteditable="true">%s(zContent)</div>
@ <script>
@ var oDoc;
@
@ /* Initialize the document editor */
@ function initDoc() {
@ oDoc = document.getElementById("wysiwygBox");
@ if (!isWysiwyg()) { setDocMode(true); }
@ }
@
@ /* Return true if the document editor is in WYSIWYG mode. Return
@ ** false if it is in Markup mode */
@ function isWysiwyg() {
@ return document.getElementById("editMode").selectedIndex==0;
@ }
@
@ /* Invoke this routine prior to submitting the HTML content back
@ ** to the server */
@ function wysiwygSubmit() {
@ if(oDoc.style.whiteSpace=="pre-wrap"){setDocMode(0);}
@ document.getElementById("wysiwygValue").value=oDoc.innerHTML;
@ }
@
@ /* Run the editing command if in WYSIWYG mode */
@ function formatDoc(sCmd, sValue) {
@ if (isWysiwyg()){
@ document.execCommand("styleWithCSS", false, false);
@ document.execCommand(sCmd, false, sValue);
@ oDoc.focus();
@ }
@ }
@
@ /* Change the editing mode. Convert to markup if the argument
@ ** is true and wysiwyg if the argument is false. */
@ function setDocMode(bToMarkup) {
@ var oContent;
@ if (bToMarkup) {
@ /* WYSIWYG -> Markup */
@ var linebreak = new RegExp("</p><p>","ig");
@ oContent = document.createTextNode(
@ oDoc.innerHTML.replace(linebreak,"</p>\n\n<p>"));
|
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 | int nIGotSent; /* Number of "igot" cards sent */ int nGimmeSent; /* Number of gimme cards sent */ int nFileSent; /* Number of files sent */ int nDeltaSent; /* Number of deltas sent */ int nFileRcvd; /* Number of files received */ int nDeltaRcvd; /* Number of deltas received */ int nDanglingFile; /* Number of dangling deltas received */ | | > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | int nIGotSent; /* Number of "igot" cards sent */ int nGimmeSent; /* Number of gimme cards sent */ int nFileSent; /* Number of files sent */ int nDeltaSent; /* Number of deltas sent */ int nFileRcvd; /* Number of files received */ int nDeltaRcvd; /* Number of deltas received */ int nDanglingFile; /* Number of dangling deltas received */ int mxSend; /* Stop sending "file" when pOut reaches this size */ int resync; /* Send igot cards for all holdings */ u8 syncPrivate; /* True to enable syncing private content */ u8 nextIsPrivate; /* If true, next "file" received is a private */ time_t maxTime; /* Time when this transfer should be finished */ }; /* |
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
db_bind_int(&q, ":r", rid);
db_step(&q);
db_reset(&q);
}
}
/*
| | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
db_bind_int(&q, ":r", rid);
db_step(&q);
db_reset(&q);
}
}
/*
** The aToken[0..nToken-1] blob array is a parse of a "file" line
** message. This routine finishes parsing that message and does
** a record insert of the file.
**
** The file line is in one of the following two forms:
**
** file UUID SIZE \n CONTENT
** file UUID DELTASRC SIZE \n CONTENT
|
| ︙ | ︙ | |||
116 117 118 119 120 121 122 |
*/
static void xfer_accept_file(Xfer *pXfer, int cloneFlag){
int n;
int rid;
int srcid = 0;
Blob content, hash;
int isPriv;
| | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
*/
static void xfer_accept_file(Xfer *pXfer, int cloneFlag){
int n;
int rid;
int srcid = 0;
Blob content, hash;
int isPriv;
isPriv = pXfer->nextIsPrivate;
pXfer->nextIsPrivate = 0;
if( pXfer->nToken<3
|| pXfer->nToken>4
|| !blob_is_uuid(&pXfer->aToken[1])
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &n)
|| n<0
|| (pXfer->nToken==4 && !blob_is_uuid(&pXfer->aToken[2]))
){
blob_appendf(&pXfer->err, "malformed file line");
|
| ︙ | ︙ | |||
188 189 190 191 192 193 194 |
rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
blob_reset(&hash);
if( rid==0 ){
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
blob_reset(&content);
}else{
if( !isPriv ) content_make_public(rid);
| | | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
rid = content_put_ex(&content, blob_str(&hash), 0, 0, isPriv);
blob_reset(&hash);
if( rid==0 ){
blob_appendf(&pXfer->err, "%s", g.zErrMsg);
blob_reset(&content);
}else{
if( !isPriv ) content_make_public(rid);
manifest_crosslink(rid, &content, MC_NONE);
}
assert( blob_is_reset(&content) );
remote_has(rid);
}
/*
** The aToken[0..nToken-1] blob array is a parse of a "cfile" line
** message. This routine finishes parsing that message and does
** a record insert of the file. The difference between "file" and
** "cfile" is that with "cfile" the content is already compressed.
**
** The file line is in one of the following two forms:
**
** cfile UUID USIZE CSIZE \n CONTENT
|
| ︙ | ︙ | |||
224 225 226 227 228 229 230 |
static void xfer_accept_compressed_file(Xfer *pXfer){
int szC; /* CSIZE */
int szU; /* USIZE */
int rid;
int srcid = 0;
Blob content;
int isPriv;
| | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
static void xfer_accept_compressed_file(Xfer *pXfer){
int szC; /* CSIZE */
int szU; /* USIZE */
int rid;
int srcid = 0;
Blob content;
int isPriv;
isPriv = pXfer->nextIsPrivate;
pXfer->nextIsPrivate = 0;
if( pXfer->nToken<4
|| pXfer->nToken>5
|| !blob_is_uuid(&pXfer->aToken[1])
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-2], &szU)
|| !blob_is_int(&pXfer->aToken[pXfer->nToken-1], &szC)
|| szC<0 || szU<0
|| (pXfer->nToken==5 && !blob_is_uuid(&pXfer->aToken[2]))
){
|
| ︙ | ︙ | |||
281 282 283 284 285 286 287 |
Blob *pContent, /* The content of the file to send */
Blob *pUuid /* The UUID of the file to send */
){
static const char *const azQuery[] = {
"SELECT pid FROM plink x"
" WHERE cid=%d"
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
| | | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
Blob *pContent, /* The content of the file to send */
Blob *pUuid /* The UUID of the file to send */
){
static const char *const azQuery[] = {
"SELECT pid FROM plink x"
" WHERE cid=%d"
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)",
"SELECT pid, min(mtime) FROM mlink, event ON mlink.mid=event.objid"
" WHERE fid=%d"
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)"
};
int i;
Blob src, delta;
int size = 0;
|
| ︙ | ︙ | |||
318 319 320 321 322 323 324 |
free(zUuid);
blob_reset(&src);
}
return size;
}
/*
| | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
free(zUuid);
blob_reset(&src);
}
return size;
}
/*
** Try to send a file as a native delta.
** If successful, return the number of bytes in the delta.
** If we cannot generate an appropriate delta, then send
** nothing and return zero.
**
** Never send a delta against a private artifact.
*/
static int send_delta_native(
|
| ︙ | ︙ | |||
400 401 402 403 404 405 406 |
}else{
pUuid = &uuid;
}
if( uuid_is_shunned(blob_str(pUuid)) ){
blob_reset(&uuid);
return;
}
| | | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
}else{
pUuid = &uuid;
}
if( uuid_is_shunned(blob_str(pUuid)) ){
blob_reset(&uuid);
return;
}
if( (pXfer->maxTime != -1 && time(NULL) >= pXfer->maxTime) ||
pXfer->mxSend<=blob_size(pXfer->pOut) ){
const char *zFormat = isPriv ? "igot %b 1\n" : "igot %b\n";
blob_appendf(pXfer->pOut, zFormat, pUuid);
pXfer->nIGotSent++;
blob_reset(&uuid);
return;
}
|
| ︙ | ︙ | |||
442 443 444 445 446 447 448 |
blob_appendf(pXfer->pOut, "\n", 1);
}
#endif
}
/*
** Send the file identified by rid as a compressed artifact. Basically,
| | | 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 |
blob_appendf(pXfer->pOut, "\n", 1);
}
#endif
}
/*
** Send the file identified by rid as a compressed artifact. Basically,
** send the content exactly as it appears in the BLOB table using
** a "cfile" card.
*/
static void send_compressed_file(Xfer *pXfer, int rid){
const char *zContent;
const char *zUuid;
const char *zDelta;
int szU;
|
| ︙ | ︙ | |||
512 513 514 515 516 517 518 |
** Send a gimme message for every phantom.
**
** Except: do not request shunned artifacts. And do not request
** private artifacts if we are not doing a private transfer.
*/
static void request_phantoms(Xfer *pXfer, int maxReq){
Stmt q;
| | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
** Send a gimme message for every phantom.
**
** Except: do not request shunned artifacts. And do not request
** private artifacts if we are not doing a private transfer.
*/
static void request_phantoms(Xfer *pXfer, int maxReq){
Stmt q;
db_prepare(&q,
"SELECT uuid FROM phantom JOIN blob USING(rid)"
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s",
(pXfer->syncPrivate ? "" :
" AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)")
);
while( db_step(&q)==SQLITE_ROW && maxReq-- > 0 ){
const char *zUuid = db_column_text(&q, 0);
|
| ︙ | ︙ | |||
548 549 550 551 552 553 554 | /* ** Check the signature on an application/x-fossil payload received by ** the HTTP server. The signature is a line of the following form: ** ** login LOGIN NONCE SIGNATURE ** | | | | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
/*
** Check the signature on an application/x-fossil payload received by
** the HTTP server. The signature is a line of the following form:
**
** login LOGIN NONCE SIGNATURE
**
** The NONCE is the SHA1 hash of the remainder of the input.
** SIGNATURE is the SHA1 checksum of the NONCE concatenated
** with the users password.
**
** The parameters to this routine are ephemeral blobs holding the
** LOGIN, NONCE and SIGNATURE.
**
** This routine attempts to locate the user and verify the signature.
** If everything checks out, the USER.CAP column for the USER table
** is consulted to set privileges in the global g variable.
**
** If anything fails to check out, no changes are made to privileges.
**
** Signature generation on the client side is handled by the
** http_exchange() routine.
**
** Return non-zero for a login failure and zero for success.
*/
int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
Stmt q;
int rc = -1;
|
| ︙ | ︙ | |||
696 697 698 699 700 701 702 |
nUncl -= nRow;
nRow = 0;
blob_appendf(&deleteWhere, ",%d", rid);
}
}
db_finalize(&q);
db_multi_exec(
| | | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 |
nUncl -= nRow;
nRow = 0;
blob_appendf(&deleteWhere, ",%d", rid);
}
}
db_finalize(&q);
db_multi_exec(
"DELETE FROM unclustered WHERE rid NOT IN (0 %s)",
blob_str(&deleteWhere)
);
blob_reset(&deleteWhere);
if( nRow>0 ){
md5sum_blob(&cluster, &cksum);
blob_appendf(&cluster, "Z %b\n", &cksum);
blob_reset(&cksum);
|
| ︙ | ︙ | |||
734 735 736 737 738 739 740 |
/*
** Send an igot message for every entry in unclustered table.
** Return the number of cards sent.
*/
static int send_unclustered(Xfer *pXfer){
Stmt q;
int cnt = 0;
| > | > > > > > > > > > > | | | | | > > > | > > | | 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 |
/*
** Send an igot message for every entry in unclustered table.
** Return the number of cards sent.
*/
static int send_unclustered(Xfer *pXfer){
Stmt q;
int cnt = 0;
if( pXfer->resync ){
db_prepare(&q,
"SELECT uuid, rid FROM blob"
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
" AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
" AND blob.rid<=%d"
" ORDER BY blob.rid DESC",
pXfer->resync
);
}else{
db_prepare(&q,
"SELECT uuid FROM unclustered JOIN blob USING(rid)"
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
" AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
);
}
while( db_step(&q)==SQLITE_ROW ){
blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
cnt++;
if( pXfer->resync && pXfer->mxSend<blob_size(pXfer->pOut) ){
pXfer->resync = db_column_int(&q, 1)-1;
}
}
db_finalize(&q);
if( cnt==0 ) pXfer->resync = 0;
return cnt;
}
/*
** Send an igot message for every artifact.
*/
static void send_all(Xfer *pXfer){
Stmt q;
db_prepare(&q,
"SELECT uuid FROM blob "
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
" AND NOT EXISTS(SELECT 1 FROM private WHERE rid=blob.rid)"
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=blob.rid)"
);
while( db_step(&q)==SQLITE_ROW ){
blob_appendf(pXfer->pOut, "igot %s\n", db_column_text(&q, 0));
|
| ︙ | ︙ | |||
801 802 803 804 805 806 807 |
** from a server without authorization.
*/
static void server_private_xfer_not_authorized(void){
@ error not\sauthorized\sto\ssync\sprivate\scontent
}
/*
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | > | > > > > > | | < < | > > > | < < < < | | > > > > > > > > | | | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 |
** from a server without authorization.
*/
static void server_private_xfer_not_authorized(void){
@ error not\sauthorized\sto\ssync\sprivate\scontent
}
/*
** Return the common TH1 code to evaluate prior to evaluating any other
** TH1 transfer notification scripts.
*/
const char *xfer_common_code(void){
return db_get("xfer-common-script", 0);
}
/*
** Return the TH1 code to evaluate when a push is processed.
*/
const char *xfer_push_code(void){
return db_get("xfer-push-script", 0);
}
/*
** Return the TH1 code to evaluate when a commit is processed.
*/
const char *xfer_commit_code(void){
return db_get("xfer-commit-script", 0);
}
/*
** Return the TH1 code to evaluate when a ticket change is processed.
*/
const char *xfer_ticket_code(void){
return db_get("xfer-ticket-script", 0);
}
/*
** Run the specified TH1 script, if any, and returns 1 on error.
*/
int xfer_run_script(const char *zScript, const char *zUuid){
int rc;
if( !zScript ) return TH_OK;
Th_FossilInit(TH_INIT_DEFAULT);
if( zUuid ){
rc = Th_SetVar(g.interp, "uuid", -1, zUuid, -1);
if( rc!=TH_OK ){
fossil_error(1, "%s", Th_GetResult(g.interp, 0));
return rc;
}
}
rc = Th_Eval(g.interp, 0, zScript, -1);
if( rc!=TH_OK ){
fossil_error(1, "%s", Th_GetResult(g.interp, 0));
}
return rc;
}
/*
** Runs the pre-transfer TH1 script, if any, and returns its return code.
** This script may be run multiple times. If the script performs actions
** that cannot be redone, it should use an internal [if] guard similar to
** the following:
**
** if {![info exists common_done]} {
** # ... code here
** set common_done 1
** }
*/
int xfer_run_common_script(void){
return xfer_run_script(xfer_common_code(), 0);
}
/*
** If this variable is set, disable login checks. Used for debugging
** only.
*/
static int disableLogin = 0;
|
| ︙ | ︙ | |||
856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
Xfer xfer;
int deltaFlag = 0;
int isClone = 0;
int nGimme = 0;
int size;
int recvConfig = 0;
char *zNow;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
| > | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 |
Xfer xfer;
int deltaFlag = 0;
int isClone = 0;
int nGimme = 0;
int size;
int recvConfig = 0;
char *zNow;
int rc;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
|
| ︙ | ︙ | |||
885 886 887 888 889 890 891 |
g.xferPanic = 1;
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
);
manifest_crosslink_begin();
| | > | | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 |
g.xferPanic = 1;
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
);
manifest_crosslink_begin();
rc = xfer_run_common_script();
if( rc==TH_ERROR ){
cgi_reset_content();
@ error common\sscript\sfailed:\s%F(g.zErrMsg)
nErr++;
}
while( blob_line(xfer.pIn, &xfer.line) ){
if( blob_buffer(&xfer.line)[0]=='#' ) continue;
if( blob_size(&xfer.line)==0 ) continue;
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
|
| ︙ | ︙ | |||
973 974 975 976 977 978 979 |
}else if( g.perm.Private ){
rid_from_uuid(&xfer.aToken[1], 1, 1);
}else{
server_private_xfer_not_authorized();
}
}
}else
| | | | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 |
}else if( g.perm.Private ){
rid_from_uuid(&xfer.aToken[1], 1, 1);
}else{
server_private_xfer_not_authorized();
}
}
}else
/* pull SERVERCODE PROJECTCODE
** push SERVERCODE PROJECTCODE
**
** The client wants either send or receive. The server should
** verify that the project code matches.
*/
if( xfer.nToken==3
|
| ︙ | ︙ | |||
1082 1083 1084 1085 1086 1087 1088 |
if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
|| check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
){
cgi_reset_content();
@ error login\sfailed
nErr++;
break;
| | | | 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
|| check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
){
cgi_reset_content();
@ error login\sfailed
nErr++;
break;
}
}
}else
/* reqconfig NAME
**
** Request a configuration value
*/
if( blob_eq(&xfer.aToken[0], "reqconfig")
&& xfer.nToken==2
){
|
| ︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 |
configure_send_group(xfer.pOut, groupMask, 0);
}else if( configure_is_exportable(zName) ){
/* Old style configuration transfer */
send_legacy_config_card(&xfer, zName);
}
}
}else
| | | 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 |
configure_send_group(xfer.pOut, groupMask, 0);
}else if( configure_is_exportable(zName) ){
/* Old style configuration transfer */
send_legacy_config_card(&xfer, zName);
}
}
}else
/* config NAME SIZE \n CONTENT
**
** Receive a configuration value from the client. This is only
** permitted for high-privilege users.
*/
if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3
&& blob_is_int(&xfer.aToken[2], &size) ){
|
| ︙ | ︙ | |||
1134 1135 1136 1137 1138 1139 1140 |
recvConfig = 1;
}
configure_receive(zName, &content, CONFIGSET_ALL);
blob_reset(&content);
blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
}else
| | | 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 |
recvConfig = 1;
}
configure_receive(zName, &content, CONFIGSET_ALL);
blob_reset(&content);
blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
}else
/* cookie TEXT
**
** A cookie contains a arbitrary-length argument that is server-defined.
** The argument must be encoded so as not to contain any whitespace.
** The server can optionally send a cookie to the client. The client
** might then return the same cookie back to the server on its next
|
| ︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
login_check_credentials();
if( !g.perm.Private ){
server_private_xfer_not_authorized();
}else{
xfer.syncPrivate = 1;
}
}
}else
/* Unknown message
*/
{
cgi_reset_content();
@ error bad\scommand:\s%F(blob_str(&xfer.line))
}
blobarray_reset(xfer.aToken, xfer.nToken);
}
if( isPush ){
| > > > > > > > > > > | | | | > | 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 |
login_check_credentials();
if( !g.perm.Private ){
server_private_xfer_not_authorized();
}else{
xfer.syncPrivate = 1;
}
}
/* pragma send-catalog
**
** Send igot cards for all known artifacts.
*/
if( blob_eq(&xfer.aToken[1], "send-catalog") ){
xfer.resync = 0x7fffffff;
}
}else
/* Unknown message
*/
{
cgi_reset_content();
@ error bad\scommand:\s%F(blob_str(&xfer.line))
}
blobarray_reset(xfer.aToken, xfer.nToken);
blob_reset(&xfer.line);
}
if( isPush ){
if( rc==TH_OK ){
rc = xfer_run_script(xfer_push_code(), 0);
if( rc==TH_ERROR ){
cgi_reset_content();
@ error push\sscript\sfailed:\s%F(g.zErrMsg)
nErr++;
}
}
request_phantoms(&xfer, 500);
}
if( isClone && nGimme==0 ){
/* The initial "clone" message from client to server contains no
** "gimme" cards. On that initial message, send the client an "igot"
** card for every artifact currently in the repository. This will
|
| ︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 |
create_cluster();
send_unclustered(&xfer);
if( xfer.syncPrivate ) send_private(&xfer);
}
if( recvConfig ){
configure_finalize_receive();
}
| > | > | 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 |
create_cluster();
send_unclustered(&xfer);
if( xfer.syncPrivate ) send_private(&xfer);
}
if( recvConfig ){
configure_finalize_receive();
}
db_multi_exec("DROP TABLE onremote");
manifest_crosslink_end(MC_PERMIT_HOOKS);
/* Send the server timestamp last, in case prior processing happened
** to use up a significant fraction of our time window.
*/
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
@ # timestamp %s(zNow)
free(zNow);
db_end_transaction(0);
configure_rebuild();
}
/*
** COMMAND: test-xfer
**
** This command is used for debugging the server. There is a single
** argument which is the uncompressed content of an "xfer" message
|
| ︙ | ︙ | |||
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 | ** Flag options for controlling client_sync() */ #define SYNC_PUSH 0x0001 #define SYNC_PULL 0x0002 #define SYNC_CLONE 0x0004 #define SYNC_PRIVATE 0x0008 #define SYNC_VERBOSE 0x0010 #endif /* ** Sync to the host identified in g.urlName and g.urlPath. This ** routine is called by the client. ** ** Records are pushed to the server if pushFlag is true. Records ** are pulled if pullFlag is true. A full sync occurs if both are | > > > > > > > > | 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 |
** Flag options for controlling client_sync()
*/
#define SYNC_PUSH 0x0001
#define SYNC_PULL 0x0002
#define SYNC_CLONE 0x0004
#define SYNC_PRIVATE 0x0008
#define SYNC_VERBOSE 0x0010
#define SYNC_RESYNC 0x0020
#endif
/*
** Floating-point absolute value
*/
static double fossil_fabs(double x){
return x>0.0 ? x : -x;
}
/*
** Sync to the host identified in g.urlName and g.urlPath. This
** routine is called by the client.
**
** Records are pushed to the server if pushFlag is true. Records
** are pulled if pullFlag is true. A full sync occurs if both are
|
| ︙ | ︙ | |||
1329 1330 1331 1332 1333 1334 1335 1336 1337 |
const char *zSCode = db_get("server-code", "x");
const char *zPCode = db_get("project-code", 0);
int nErr = 0; /* Number of errors */
int nRoundtrip= 0; /* Number of HTTP requests */
int nArtifactSent = 0; /* Total artifacts sent */
int nArtifactRcvd = 0; /* Total artifacts received */
const char *zOpType = 0;/* Push, Pull, Sync, Clone */
if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
| > | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 |
const char *zSCode = db_get("server-code", "x");
const char *zPCode = db_get("project-code", 0);
int nErr = 0; /* Number of errors */
int nRoundtrip= 0; /* Number of HTTP requests */
int nArtifactSent = 0; /* Total artifacts sent */
int nArtifactRcvd = 0; /* Total artifacts received */
const char *zOpType = 0;/* Push, Pull, Sync, Clone */
double rSkew = 0.0; /* Maximum time skew */
if( db_get_boolean("dont-push", 0) ) syncFlags &= ~SYNC_PUSH;
if( (syncFlags & (SYNC_PUSH|SYNC_PULL|SYNC_CLONE))==0
&& configRcvMask==0 && configSendMask==0 ) return 0;
transport_stats(0, 0, 1);
socket_global_init();
memset(&xfer, 0, sizeof(xfer));
xfer.pIn = &recv;
xfer.pOut = &send;
|
| ︙ | ︙ | |||
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 |
/* TBD: Request all transferable configuration values */
content_enable_dephantomize(0);
zOpType = "Clone";
}else if( syncFlags & SYNC_PULL ){
blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
nCardSent++;
zOpType = (syncFlags & SYNC_PUSH)?"Sync":"Pull";
}
if( syncFlags & SYNC_PUSH ){
blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
nCardSent++;
if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
}
manifest_crosslink_begin();
| > > > > > < | | | 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 |
/* TBD: Request all transferable configuration values */
content_enable_dephantomize(0);
zOpType = "Clone";
}else if( syncFlags & SYNC_PULL ){
blob_appendf(&send, "pull %s %s\n", zSCode, zPCode);
nCardSent++;
zOpType = (syncFlags & SYNC_PUSH)?"Sync":"Pull";
if( (syncFlags & SYNC_RESYNC)!=0 && nCycle<2 ){
blob_appendf(&send, "pragma send-catalog\n");
nCardSent++;
}
}
if( syncFlags & SYNC_PUSH ){
blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
nCardSent++;
if( (syncFlags & SYNC_PULL)==0 ) zOpType = "Push";
if( (syncFlags & SYNC_RESYNC)!=0 ) xfer.resync = 0x7fffffff;
}
manifest_crosslink_begin();
if( syncFlags & SYNC_VERBOSE ){
fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
}
while( go ){
int newPhantom = 0;
char *zRandomness;
/* Send make the most recently received cookie. Let the server
** figure out if this is a cookie that it cares about.
*/
zCookie = db_get("cookie", 0);
if( zCookie ){
blob_appendf(&send, "cookie %s\n", zCookie);
}
/* Generate gimme cards for phantoms and leaf cards
** for all leaves.
*/
if( (syncFlags & SYNC_PULL)!=0
|| ((syncFlags & SYNC_CLONE)!=0 && cloneSeqno==1)
){
request_phantoms(&xfer, mxPhantomReq);
}
if( syncFlags & SYNC_PUSH ){
send_unsent(&xfer);
nCardSent += send_unclustered(&xfer);
if( syncFlags & SYNC_PRIVATE ) send_private(&xfer);
}
/* Send configuration parameter requests. On a clone, delay sending
** this until the second cycle since the login card might fail on
** the first cycle.
*/
if( configRcvMask && ((syncFlags & SYNC_CLONE)==0 || nCycle>0) ){
const char *zName;
if( zOpType==0 ) zOpType = "Pull";
zName = configure_first_name(configRcvMask);
while( zName ){
|
| ︙ | ︙ | |||
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 |
** messages unique so that that the login-card nonce will always
** be unique.
*/
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
blob_appendf(&send, "# %s\n", zRandomness);
free(zRandomness);
/* Exchange messages with the server */
if( syncFlags & SYNC_VERBOSE ){
fossil_print(zValueFormat, "Sent:",
blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
xfer.nFileSent, xfer.nDeltaSent);
}else{
nRoundtrip++;
nArtifactSent += xfer.nFileSent + xfer.nDeltaSent;
fossil_print(zBriefFormat, nRoundtrip, nArtifactSent, nArtifactRcvd);
}
nCardSent = 0;
nCardRcvd = 0;
xfer.nFileSent = 0;
xfer.nDeltaSent = 0;
xfer.nGimmeSent = 0;
xfer.nIGotSent = 0;
| > > > > > > > > > > > < < | < < < < < < | 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 |
** messages unique so that that the login-card nonce will always
** be unique.
*/
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
blob_appendf(&send, "# %s\n", zRandomness);
free(zRandomness);
if( syncFlags & SYNC_VERBOSE ){
fossil_print("waiting for server...");
}
fflush(stdout);
/* Exchange messages with the server */
if( http_exchange(&send, &recv, (syncFlags & SYNC_CLONE)==0 || nCycle>0,
MAX_REDIRECTS) ){
nErr++;
break;
}
/* Output current stats */
if( syncFlags & SYNC_VERBOSE ){
fossil_print(zValueFormat, "Sent:",
blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent,
xfer.nFileSent, xfer.nDeltaSent);
}else{
nRoundtrip++;
nArtifactSent += xfer.nFileSent + xfer.nDeltaSent;
fossil_print(zBriefFormat, nRoundtrip, nArtifactSent, nArtifactRcvd);
}
nCardSent = 0;
nCardRcvd = 0;
xfer.nFileSent = 0;
xfer.nDeltaSent = 0;
xfer.nGimmeSent = 0;
xfer.nIGotSent = 0;
lastPctDone = -1;
blob_reset(&send);
rArrivalTime = db_double(0.0, "SELECT julianday('now')");
/* Send the send-private pragma if we are trying to sync private data */
if( syncFlags & SYNC_PRIVATE ){
blob_append(&send, "pragma send-private\n", -1);
|
| ︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 |
if( memcmp(zLine, "# timestamp ", 12)==0 ){
char zTime[20];
double rDiff;
sqlite3_snprintf(sizeof(zTime), zTime, "%.19s", &zLine[12]);
rDiff = db_double(9e99, "SELECT julianday('%q') - %.17g",
zTime, rArrivalTime);
if( rDiff>9e98 || rDiff<-9e98 ) rDiff = 0.0;
| < < < < | < | < < | 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 |
if( memcmp(zLine, "# timestamp ", 12)==0 ){
char zTime[20];
double rDiff;
sqlite3_snprintf(sizeof(zTime), zTime, "%.19s", &zLine[12]);
rDiff = db_double(9e99, "SELECT julianday('%q') - %.17g",
zTime, rArrivalTime);
if( rDiff>9e98 || rDiff<-9e98 ) rDiff = 0.0;
if( rDiff*24.0*3600.0 >= -(blob_size(&recv)/5000.0 + 20) ) rDiff = 0.0;
if( fossil_fabs(rDiff)>fossil_fabs(rSkew) ) rSkew = rDiff;
}
nCardRcvd++;
continue;
}
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
nCardRcvd++;
if( (syncFlags & SYNC_VERBOSE)!=0 && recv.nUsed>0 ){
|
| ︙ | ︙ | |||
1581 1582 1583 1584 1585 1586 1587 |
&& blob_is_uuid(&xfer.aToken[1])
){
if( syncFlags & SYNC_PUSH ){
int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
}
}else
| | | | | | 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 |
&& blob_is_uuid(&xfer.aToken[1])
){
if( syncFlags & SYNC_PUSH ){
int rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
if( rid ) send_file(&xfer, rid, &xfer.aToken[1], 0);
}
}else
/* igot UUID ?PRIVATEFLAG?
**
** Server announces that it has a particular file. If this is
** not a file that we have and we are pulling, then create a
** phantom to cause this file to be requested on the next cycle.
** Always remember that the server has this file so that we do
** not transmit it by accident.
**
** If the PRIVATE argument exists and is 1, then the file is
** private. Pretend it does not exists if we are not pulling
** private files.
*/
if( xfer.nToken>=2
&& blob_eq(&xfer.aToken[0], "igot")
&& blob_is_uuid(&xfer.aToken[1])
){
int rid;
int isPriv = xfer.nToken>=3 && blob_eq(&xfer.aToken[2],"1");
rid = rid_from_uuid(&xfer.aToken[1], 0, 0);
if( rid>0 ){
if( !isPriv ) content_make_public(rid);
}else if( isPriv && !g.perm.Private ){
/* ignore private files */
}else if( (syncFlags & (SYNC_PULL|SYNC_CLONE))!=0 ){
rid = content_new(blob_str(&xfer.aToken[1]), isPriv);
if( rid ) newPhantom = 1;
}
remote_has(rid);
}else
/* push SERVERCODE PRODUCTCODE
**
** Should only happen in response to a clone. This message tells
** the client what product to use for the new database.
*/
if( blob_eq(&xfer.aToken[0],"push")
&& xfer.nToken==3
|
| ︙ | ︙ | |||
1634 1635 1636 1637 1638 1639 1640 |
if( zPCode==0 ){
zPCode = mprintf("%b", &xfer.aToken[2]);
db_set("project-code", zPCode, 0);
}
if( cloneSeqno>0 ) blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
nCardSent++;
}else
| | | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 |
if( zPCode==0 ){
zPCode = mprintf("%b", &xfer.aToken[2]);
db_set("project-code", zPCode, 0);
}
if( cloneSeqno>0 ) blob_appendf(&send, "clone 3 %d\n", cloneSeqno);
nCardSent++;
}else
/* config NAME SIZE \n CONTENT
**
** Receive a configuration value from the server.
**
** The received configuration setting is silently ignored if it was
** not requested by a prior "reqconfig" sent from client to server.
*/
|
| ︙ | ︙ | |||
1656 1657 1658 1659 1660 1661 1662 |
configure_receive(zName, &content, origConfigRcvMask);
nCardRcvd++;
nArtifactRcvd++;
blob_reset(&content);
blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
}else
| | | 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 |
configure_receive(zName, &content, origConfigRcvMask);
nCardRcvd++;
nArtifactRcvd++;
blob_reset(&content);
blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR);
}else
/* cookie TEXT
**
** The server might include a cookie in its reply. The client
** should remember this cookie and send it back to the server
** in its next query.
**
** Each cookie received overwrites the prior cookie from the
|
| ︙ | ︙ | |||
1698 1699 1700 1701 1702 1703 1704 |
/* message MESSAGE
**
** Print a message. Similar to "error" but does not stop processing.
**
** If the "login failed" message is seen, clear the sync password prior
** to the next cycle.
| | | | | | > > > > > | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 |
/* message MESSAGE
**
** Print a message. Similar to "error" but does not stop processing.
**
** If the "login failed" message is seen, clear the sync password prior
** to the next cycle.
*/
if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
char *zMsg = blob_terminate(&xfer.aToken[1]);
defossilize(zMsg);
if( (syncFlags & SYNC_PUSH) && zMsg && strglob("pull only *", zMsg) ){
syncFlags &= ~SYNC_PUSH;
zMsg = 0;
}
if( zMsg && zMsg[0] ){
fossil_force_newline();
fossil_print("Server says: %s\n", zMsg);
}
}else
/* pragma NAME VALUE...
**
** The server can send pragmas to try to convey meta-information to
** the client. These are informational only. Unknown pragmas are
** silently ignored.
*/
if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){
}else
/* error MESSAGE
**
** Report an error and abandon the sync session.
**
** Except, when cloning we will sometimes get an error on the
** first message exchange because the project-code is unknown
** and so the login card on the request was invalid. The project-code
** is returned in the reply before the error card, so second and
** subsequent messages should be OK. Nevertheless, we need to ignore
** the error card on the first message of a clone.
*/
if( blob_eq(&xfer.aToken[0],"error") && xfer.nToken==2 ){
if( (syncFlags & SYNC_CLONE)==0 || nCycle>0 ){
char *zMsg = blob_terminate(&xfer.aToken[1]);
defossilize(zMsg);
fossil_force_newline();
fossil_print("Error: %s\n", zMsg);
if( fossil_strcmp(zMsg, "login failed")==0 ){
if( nCycle<2 ){
g.urlPasswd = 0;
go = 1;
if( g.cgiOutput==0 ){
g.urlFlags |= URL_PROMPT_PW;
g.urlFlags &= ~URL_PROMPTED;
url_prompt_for_password();
url_remember();
}
}
}else{
blob_appendf(&xfer.err, "server says: %s\n", zMsg);
nErr++;
}
break;
}
|
| ︙ | ︙ | |||
1807 1808 1809 1810 1811 1812 1813 |
}
nCardRcvd = 0;
xfer.nFileRcvd = 0;
xfer.nDeltaRcvd = 0;
xfer.nDanglingFile = 0;
/* If we have one or more files queued to send, then go
| | | > > > > > > > > > > | | | | 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 |
}
nCardRcvd = 0;
xfer.nFileRcvd = 0;
xfer.nDeltaRcvd = 0;
xfer.nDanglingFile = 0;
/* If we have one or more files queued to send, then go
** another round
*/
if( xfer.nFileSent+xfer.nDeltaSent>0 ){
go = 1;
}
/* If this is a clone, the go at least two rounds */
if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;
/* Stop the cycle if the server sends a "clone_seqno 0" card and
** we have gone at least two rounds. Always go at least two rounds
** on a clone in order to be sure to retrieve the configuration
** information which is only sent on the second round.
*/
if( cloneSeqno<=0 && nCycle>1 ) go = 0;
};
transport_stats(&nSent, &nRcvd, 1);
if( (rSkew*24.0*3600.0) > 10.0 ){
fossil_warning("*** time skew *** server is fast by %s",
db_timespan_name(rSkew));
g.clockSkewSeen = 1;
}else if( rSkew*24.0*3600.0 < -10.0 ){
fossil_warning("*** time skew *** server is slow by %s",
db_timespan_name(-rSkew));
g.clockSkewSeen = 1;
}
fossil_force_newline();
fossil_print(
"%s finished with %lld bytes sent, %lld bytes received\n",
zOpType, nSent, nRcvd);
transport_close(GLOBAL_URL());
transport_global_shutdown(GLOBAL_URL());
db_multi_exec("DROP TABLE onremote");
manifest_crosslink_end(MC_PERMIT_HOOKS);
content_enable_dephantomize(1);
db_end_transaction(0);
return nErr;
}
|
Changes to src/xfersetup.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
void xfersetup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Transfer Setup");
@ <table border="0" cellspacing="20">
setup_menu_entry("Common", "xfersetup_com",
"Common TH1 code run before all transfer request processing.");
setup_menu_entry("Push", "xfersetup_push",
"Specific TH1 code to run after \"push\" transfer requests.");
@ </table>
style_footer();
}
/*
** Common implementation for the transfer setup editor pages.
*/
static void xfersetup_generic(
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
void xfersetup_page(void){
login_check_credentials();
if( !g.perm.Setup ){
login_needed();
}
style_header("Transfer Setup");
@ <table border="0" cellspacing="20">
setup_menu_entry("Common", "xfersetup_com",
"Common TH1 code run before all transfer request processing.");
setup_menu_entry("Push", "xfersetup_push",
"Specific TH1 code to run after \"push\" transfer requests.");
setup_menu_entry("Commit", "xfersetup_commit",
"Specific TH1 code to run after processing a commit.");
setup_menu_entry("Ticket", "xfersetup_ticket",
"Specific TH1 code to run after processing a ticket change.");
@ </table>
url_parse(0, 0);
if( g.urlProtocol ){
unsigned syncFlags;
const char *zButton;
char *zWarning;
if( db_get_boolean("dont-push", 0) ){
syncFlags = SYNC_PULL;
zButton = "Pull";
zWarning = 0;
}else{
syncFlags = SYNC_PUSH | SYNC_PULL;
zButton = "Synchronize";
zWarning = mprintf("WARNING: Pushing to \"%s\" is enabled.",
g.urlCanonical);
}
if( P("sync") ){
user_select();
url_enable_proxy(0);
client_sync(syncFlags, 0, 0);
}
@ <p>Press the %h(zButton) button below to synchronize with the
@ "%h(g.urlCanonical)" repository now. This may be useful when
@ testing the various transfer scripts.</p>
@ <p>You can use the "http -async" command in your scripts, but
@ make sure the "th1-uri-regexp" setting is set first.</p>
if( zWarning ){
@
@ <big><b>%h(zWarning)</b></big>
free(zWarning);
}
@
@ <blockquote>
@ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><div>
login_insert_csrf_secret();
@ <input type="submit" name="sync" value="%h(zButton)" />
@ </div></form>
@ </blockquote>
@
}
style_footer();
}
/*
** Common implementation for the transfer setup editor pages.
*/
static void xfersetup_generic(
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 147 148 |
;
xfersetup_generic(
"Transfer Push Script",
"xfer-push-script",
zDefaultXferPush,
zDesc,
0,
0,
30
);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
;
xfersetup_generic(
"Transfer Push Script",
"xfer-push-script",
zDefaultXferPush,
zDesc,
0,
0,
30
);
}
static const char *zDefaultXferCommit = 0;
/*
** WEBPAGE: xfersetup_commit
*/
void xfersetup_commit_page(void){
static const char zDesc[] =
@ Enter TH1 script that runs when a commit is processed.
;
xfersetup_generic(
"Transfer Commit Script",
"xfer-commit-script",
zDefaultXferCommit,
zDesc,
0,
0,
30
);
}
static const char *zDefaultXferTicket = 0;
/*
** WEBPAGE: xfersetup_ticket
*/
void xfersetup_ticket_page(void){
static const char zDesc[] =
@ Enter TH1 script that runs when a ticket change is processed.
;
xfersetup_generic(
"Transfer Ticket Script",
"xfer-ticket-script",
zDefaultXferTicket,
zDesc,
0,
0,
30
);
}
|
Changes to src/zip.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to generate ZIP archives. */ #include <assert.h> #include <zlib.h> | > < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to generate ZIP archives.
*/
#include "config.h"
#include <assert.h>
#include <zlib.h>
#include "zip.h"
/*
** Write a 16- or 32-bit integer as little-endian into the given buffer.
*/
static void put16(char *z, int v){
z[0] = v & 0xff;
|
| ︙ | ︙ | |||
156 157 158 159 160 161 162 | put16(&zHdr[4], 0x000a); put16(&zHdr[6], 0x0800); put16(&zHdr[8], iMethod); put16(&zHdr[10], dosTime); put16(&zHdr[12], dosDate); put16(&zHdr[26], nameLen); put16(&zHdr[28], 13); | | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | put16(&zHdr[4], 0x000a); put16(&zHdr[6], 0x0800); put16(&zHdr[8], iMethod); put16(&zHdr[10], dosTime); put16(&zHdr[12], dosDate); put16(&zHdr[26], nameLen); put16(&zHdr[28], 13); put16(&zExTime[0], 0x5455); put16(&zExTime[2], 9); zExTime[4] = 3; put32(&zExTime[5], unixTime); put32(&zExTime[9], unixTime); /* Write the header and filename. */ iStart = blob_size(&body); blob_append(&body, zHdr, 30); blob_append(&body, zName, nameLen); blob_append(&body, zExTime, 13); |
| ︙ | ︙ | |||
200 201 202 203 204 205 206 |
deflate(&stream, Z_FINISH);
toOut = sizeof(zOutBuf) - stream.avail_out;
blob_append(&body, zOutBuf, toOut);
}while( stream.avail_out==0 );
nByte = stream.total_in;
nByteCompr = stream.total_out;
deflateEnd(&stream);
| | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
deflate(&stream, Z_FINISH);
toOut = sizeof(zOutBuf) - stream.avail_out;
blob_append(&body, zOutBuf, toOut);
}while( stream.avail_out==0 );
nByte = stream.total_in;
nByteCompr = stream.total_out;
deflateEnd(&stream);
/* Go back and write the header, now that we know the compressed file size.
*/
z = &blob_buffer(&body)[iStart];
put32(&z[14], iCRC);
put32(&z[18], nByteCompr);
put32(&z[22], nByte);
}
/* Make an entry in the tables of contents
*/
memset(zBuf, 0, sizeof(zBuf));
put32(&zBuf[0], 0x02014b50);
put16(&zBuf[4], 0x0317);
put16(&zBuf[6], 0x000a);
put16(&zBuf[8], 0x0800);
|
| ︙ | ︙ | |||
320 321 322 323 324 325 326 |
*/
void zip_of_baseline(int rid, Blob *pZip, const char *zDir){
Blob mfile, hash, file;
Manifest *pManifest;
ManifestFile *pFile;
Blob filename;
int nPrefix;
| | | | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
*/
void zip_of_baseline(int rid, Blob *pZip, const char *zDir){
Blob mfile, hash, file;
Manifest *pManifest;
ManifestFile *pFile;
Blob filename;
int nPrefix;
content_get(rid, &mfile);
if( blob_size(&mfile)==0 ){
blob_zero(pZip);
return;
}
blob_zero(&hash);
blob_zero(&filename);
zip_open();
if( zDir && zDir[0] ){
blob_appendf(&filename, "%s/", zDir);
}
nPrefix = blob_size(&filename);
pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( pManifest ){
char *zName;
zip_set_timedate(pManifest->rDate);
if( db_get_boolean("manifest", 0) ){
blob_append(&filename, "manifest", -1);
zName = blob_str(&filename);
zip_add_folders(zName);
|
| ︙ | ︙ |
Changes to test/diff-test-1.wiki.
1 2 3 4 5 6 | <title>Graph Test One</title> This page contains list of URLs of interesting diffs. Click on all URLs, one by one, to verify the correct operation of the diff logic. | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<title>Graph Test One</title>
This page contains list of URLs of interesting diffs.
Click on all URLs, one by one, to verify
the correct operation of the diff logic.
* <a href="../../../info/030035345c#chunk73" target="testwindow">
Multiple edits on a single line.</a> This is an SQLite version
update diff. It is a large diff and contains many other interesting
features. Scan the whole diff.
* <a href="../../../fdiff?v1=6da016415dc52d61&v2=af6df3466e3c4a88"
target="testwindow">Tricky alignment and multiple edits per line</a>.
* <a href="../../../fdiff?v1=7108d4748b111d23&v2=2303a98525b39d19#chunk3"
target="testwindow">Add a column to a table</a>
* <a href="../../../fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113"
target="testwindow">Column alignment with multibyte characters.</a>
The edit of a line with multibyte characters is the first chunk.
* <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
target="testwindow">Large diff of sqlite3.c</a>. This diff was very
slow prior to the performance enhancement change [9e15437e97].
* <a href="../../../info/bda00cbada#chunk49" target="testwindow">
A difficult indentation change.
* <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
target="testwindow">Another tricky indentation.</a> Notice especially
lines 59398 and 59407 on the left.
* <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
target="testwindow">Inverse of the previous.</a>
* <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk24"
|
| ︙ | ︙ |
Changes to test/merge1.test.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
write_file_indented t23 {
111 - This is line ONE of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test OF THE merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
| | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
write_file_indented t23 {
111 - This is line ONE of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test OF THE merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
fossil 3-way-merge t1 t3 t2 a32
test merge1-1.1 {[same_file t23 a32]}
fossil 3-way-merge t1 t2 t3 a23
test merge1-1.2 {[same_file t23 a23]}
write_file_indented t1 {
111 - This is line one of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
|
| ︙ | ︙ | |||
94 95 96 97 98 99 100 | 111 - This is line ONE of the demo program - 1111 >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } | | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
111 - This is line ONE of the demo program - 1111
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
fossil 3-way-merge t1 t3 t2 a32
test merge1-2.1 {[same_file t32 a32]}
fossil 3-way-merge t1 t2 t3 a23
test merge1-2.2 {[same_file t23 a23]}
write_file_indented t1 {
111 - This is line one of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
|
| ︙ | ︙ | |||
127 128 129 130 131 132 133 |
write_file_indented t23 {
111 - This is line ONE of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
| | | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
write_file_indented t23 {
111 - This is line ONE of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
fossil 3-way-merge t1 t3 t2 a32
test merge1-3.1 {[same_file t23 a32]}
fossil 3-way-merge t1 t2 t3 a23
test merge1-3.2 {[same_file t23 a23]}
write_file_indented t1 {
111 - This is line one of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
|
| ︙ | ︙ | |||
179 180 181 182 183 184 185 | ======= MERGED IN content follows ================================== >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 222 - The second line program line in code - 2222 333 - This is a test of the merging algohm - 3333 444 - If all goes well, we will be pleased - 4444 555 - we think it well and other stuff too - 5555 } | | | | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
======= MERGED IN content follows ==================================
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
}
fossil 3-way-merge t1 t3 t2 a32
test merge1-4.1 {[same_file t32 a32]}
fossil 3-way-merge t1 t2 t3 a23
test merge1-4.2 {[same_file t23 a23]}
write_file_indented t1 {
111 - This is line one of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
|
| ︙ | ︙ | |||
212 213 214 215 216 217 218 |
write_file_indented t32 {
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
666 - Extra line at the end of the file wi - 6666
}
| | | | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
write_file_indented t32 {
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
555 - we think it well and other stuff too - 5555
666 - Extra line at the end of the file wi - 6666
}
fossil 3-way-merge t1 t3 t2 a32
test merge1-5.1 {[same_file t32 a32]}
fossil 3-way-merge t1 t2 t3 a23
test merge1-5.2 {[same_file t32 a23]}
write_file_indented t1 {
111 - This is line one of the demo program - 1111
222 - The second line program line in code - 2222
333 - This is a test of the merging algohm - 3333
444 - If all goes well, we will be pleased - 4444
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 |
555 - we think it well and other stuff too - 5555
}
write_file_indented t32 {
111 - This is line one of the demo program - 1111
333 - This is a test of the merging algohm - 3333
555 - we think it well and other stuff too - 5555
}
| | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
555 - we think it well and other stuff too - 5555
}
write_file_indented t32 {
111 - This is line one of the demo program - 1111
333 - This is a test of the merging algohm - 3333
555 - we think it well and other stuff too - 5555
}
fossil 3-way-merge t1 t3 t2 a32
test merge1-6.1 {[same_file t32 a32]}
fossil 3-way-merge t1 t2 t3 a23
test merge1-6.2 {[same_file t32 a23]}
write_file_indented t1 {
abcd
efgh
ijkl
mnop
|
| ︙ | ︙ | |||
326 327 328 329 330 331 332 | GHIJ >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KLMN OPQR STUV XYZ. } | | | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
GHIJ
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
KLMN
OPQR
STUV
XYZ.
}
fossil 3-way-merge t1 t2 t3 a23
test merge1-7.1 {[same_file t23 a23]}
write_file_indented t2 {
abcd
efgh 2
ijkl 2
mnop
|
| ︙ | ︙ | |||
394 395 396 397 398 399 400 | GHIJ >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KLMN OPQR STUV XYZ. } | | | 394 395 396 397 398 399 400 401 402 |
GHIJ
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
KLMN
OPQR
STUV
XYZ.
}
fossil 3-way-merge t1 t2 t3 a23
test merge1-7.2 {[same_file t23 a23]}
|
Changes to test/merge2.test.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# Tests of the delta mechanism.
#
set filelist [glob $testdir/*]
foreach f $filelist {
if {[file isdir $f]} continue
set base [file root [file tail $f]]
set f1 [read_file $f]
write_file t1 $f1
for {set i 0} {$i<100} {incr i} {
expr {srand($i*2)}
write_file t2 [set f2 [random_changes $f1 2 4 0 0.1]]
expr {srand($i*2+1)}
write_file t3 [set f3 [random_changes $f1 2 4 2 0.1]]
expr {srand($i*2+1)}
write_file t23 [random_changes $f2 2 4 2 0.1]
expr {srand($i*2)}
write_file t32 [random_changes $f3 2 4 0 0.1]
| > | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# Tests of the delta mechanism.
#
set filelist [glob $testdir/*]
foreach f $filelist {
if {[file isdir $f]} continue
set base [file root [file tail $f]]
if {[string match "utf16*" $base]} continue
set f1 [read_file $f]
write_file t1 $f1
for {set i 0} {$i<100} {incr i} {
expr {srand($i*2)}
write_file t2 [set f2 [random_changes $f1 2 4 0 0.1]]
expr {srand($i*2+1)}
write_file t3 [set f3 [random_changes $f1 2 4 2 0.1]]
expr {srand($i*2+1)}
write_file t23 [random_changes $f2 2 4 2 0.1]
expr {srand($i*2)}
write_file t32 [random_changes $f3 2 4 0 0.1]
fossil 3-way-merge t1 t2 t3 a23
test merge-$base-$i-23 {[same_file a23 t23]}
fossil 3-way-merge t1 t3 t2 a32
test merge-$base-$i-32 {[same_file a32 t32]}
}
}
|
Changes to test/merge3.test.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
# Tests of the 3-way merge
#
proc merge-test {testid basis v1 v2 result} {
write_file t1 [join [string trim $basis] \n]\n
write_file t2 [join [string trim $v1] \n]\n
write_file t3 [join [string trim $v2] \n]\n
| | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# Tests of the 3-way merge
#
proc merge-test {testid basis v1 v2 result} {
write_file t1 [join [string trim $basis] \n]\n
write_file t2 [join [string trim $v1] \n]\n
write_file t3 [join [string trim $v2] \n]\n
fossil 3-way-merge t1 t2 t3 t4
set x [read_file t4]
regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \
{MINE:} x
regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x
regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x
regsub -all {>>>>>>> END MERGE CONFLICT >+} $x {END} x
set x [split [string trim $x] \n]
|
| ︙ | ︙ |
Changes to test/merge4.test.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
# Tests of the 3-way merge
#
proc merge-test {testid basis v1 v2 result1 result2} {
write_file t1 [join [string trim $basis] \n]\n
write_file t2 [join [string trim $v1] \n]\n
write_file t3 [join [string trim $v2] \n]\n
| | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# Tests of the 3-way merge
#
proc merge-test {testid basis v1 v2 result1 result2} {
write_file t1 [join [string trim $basis] \n]\n
write_file t2 [join [string trim $v1] \n]\n
write_file t3 [join [string trim $v2] \n]\n
fossil 3-way-merge t1 t2 t3 t4
fossil 3-way-merge t1 t3 t2 t5
set x [read_file t4]
regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $x {>} x
regsub -all {=======.*=======} $x {=} x
regsub -all {>>>>>>> END MERGE CONFLICT.*>>>>} $x {<} x
set x [split [string trim $x] \n]
set y [read_file t5]
regsub -all {<<<<<<< BEGIN MERGE CONFLICT.*<<} $y {>} y
|
| ︙ | ︙ |
Changes to test/release-checklist.wiki.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 | uninitialized value that occurs within zlib). <ol type="a"> <li> <b>valgrind fossil rebuild</b> <li> <b>valgrind fossil sync</b> </ol> <li><p> | | > | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
uninitialized value that occurs within zlib).
<ol type="a">
<li> <b>valgrind fossil rebuild</b>
<li> <b>valgrind fossil sync</b>
</ol>
<li><p>
Inspect [http://www.fossil-scm.org/index.html/vdiff?from=release&to=trunk&sbs=1|all code changes since the previous release], paying particular
attention to the following details:
<ol type="a">
<li> Can a malicious HTTP request cause a buffer overrun.
<li> Can a malicious HTTP request expose privileged information to
unauthorized users.
</ol>
|
| ︙ | ︙ |
Changes to test/th1-tcl.test.
| ︙ | ︙ | |||
112 113 114 115 116 117 118 |
fossil test-th-render --th-open-config \
[file nativename [file join $dir th1-tcl8.txt]]
test th1-tcl-8 {$RESULT eq {<hr><p class="thmainError">ERROR:\
cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr><p\
class="thmainError">ERROR: tailcall can only be called from a proc or\
| | > | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
fossil test-th-render --th-open-config \
[file nativename [file join $dir th1-tcl8.txt]]
test th1-tcl-8 {$RESULT eq {<hr><p class="thmainError">ERROR:\
cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr><p\
class="thmainError">ERROR: tailcall can only be called from a proc or\
lambda</p>} || $RESULT eq {<hr><p class="thmainError">ERROR: This test\
requires Tcl 8.6 or higher.</p>}}
###############################################################################
fossil test-th-render --th-open-config \
[file nativename [file join $dir th1-tcl9.txt]]
test th1-tcl-9 {[string trim $RESULT] eq [list [file tail $fossilexe] 3 \
|
| ︙ | ︙ |
Changes to test/th1-tcl8.txt.
1 2 3 4 5 6 7 8 9 10 11 |
<th1>
#
# This is a "TH1 fragment" used to test the Tcl integration features of TH1.
# The corresponding test file executes this file using the test-th-render
# Fossil command.
#
proc doOut {msg} {puts $msg; puts \n}
if {[tclInvoke set tcl_version] >= 8.6} {
doOut [tclInvoke tailcall set x 1]
} else {
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<th1>
#
# This is a "TH1 fragment" used to test the Tcl integration features of TH1.
# The corresponding test file executes this file using the test-th-render
# Fossil command.
#
proc doOut {msg} {puts $msg; puts \n}
if {[tclInvoke set tcl_version] >= 8.6} {
doOut [tclInvoke tailcall set x 1]
} else {
error "This test requires Tcl 8.6 or higher."
}
</th1>
|
Changes to test/th1.test.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
fossil test-th-eval --th-open-config "setting -- --"
test th1-setting-9 {$RESULT eq {}}
###############################################################################
fossil test-th-eval --th-open-config "setting -strict -- --"
test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
fossil test-th-eval --th-open-config "setting -- --"
test th1-setting-9 {$RESULT eq {}}
###############################################################################
fossil test-th-eval --th-open-config "setting -strict -- --"
test th1-setting-10 {$RESULT eq {TH_ERROR: no value for setting "--"}}
###############################################################################
fossil test-th-eval "expr 42/0"
test th1-divide-by-zero-1 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
###############################################################################
fossil test-th-eval "expr 42/0.0"
test th1-divide-by-zero-2 {$RESULT eq {TH_ERROR: Divide by 0: 42}}
###############################################################################
fossil test-th-eval "expr 42.0/0"
test th1-divide-by-zero-3 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
###############################################################################
fossil test-th-eval "expr 42.0/0.0"
test th1-divide-by-zero-4 {$RESULT eq {TH_ERROR: Divide by 0: 42.0}}
###############################################################################
fossil test-th-eval "expr 42%0"
test th1-modulus-by-zero-1 {$RESULT eq {TH_ERROR: Modulo by 0: 42}}
###############################################################################
fossil test-th-eval "expr 42%0.0"
test th1-modulus-by-zero-2 {$RESULT eq {TH_ERROR: expected integer, got: "0.0"}}
###############################################################################
fossil test-th-eval "expr 42.0%0"
test th1-modulus-by-zero-3 {$RESULT eq \
{TH_ERROR: expected integer, got: "42.0"}}
###############################################################################
fossil test-th-eval "expr 42.0%0.0"
test th1-modulus-by-zero-4 {$RESULT eq \
{TH_ERROR: expected integer, got: "42.0"}}
###############################################################################
fossil test-th-eval "set var 1; info exists var"
test th1-info-exists-1 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var 1; unset var; info exists var"
test th1-info-exists-2 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "set var 1; unset var; set var 2; info exists var"
test th1-info-exists-3 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var 1; expr {\$var+0}"
test th1-info-exists-4 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var 1; unset var; expr {\$var+0}"
test th1-info-exists-5 {$RESULT eq {TH_ERROR: no such variable: var}}
###############################################################################
fossil test-th-eval "catch {bad}; info exists var; set th_stack_trace"
test th1-info-exists-6 {$RESULT eq {bad}}
###############################################################################
fossil test-th-eval "set var(1) 1; info exists var"
test th1-info-exists-7 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var(1) 1; unset var(1); info exists var"
test th1-info-exists-8 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var(1) 1; unset var; info exists var"
test th1-info-exists-9 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "set var(1) 1; info exists var(1)"
test th1-info-exists-10 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set var(1) 1; unset var(1); info exists var(1)"
test th1-info-exists-11 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "set var(1) 1; unset var; info exists var(1)"
test th1-info-exists-12 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "set var 1; unset var"
test th1-unset-1 {$RESULT eq {var}}
###############################################################################
fossil test-th-eval "unset var"
test th1-unset-2 {$RESULT eq {TH_ERROR: no such variable: var}}
###############################################################################
fossil test-th-eval "set var 1; unset var; unset var"
test th1-unset-3 {$RESULT eq {TH_ERROR: no such variable: var}}
###############################################################################
fossil test-th-eval "set gv 1; proc p {} {upvar 1 gv lv; unset lv}; p; unset gv"
test th1-unset-4 {$RESULT eq {TH_ERROR: no such variable: gv}}
###############################################################################
fossil test-th-eval "set gv 1; upvar 0 gv gv2; info exists gv2"
test th1-unset-5 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "set gv 1; upvar 0 gv gv2; unset gv; unset gv2"
test th1-unset-6 {$RESULT eq {TH_ERROR: no such variable: gv2}}
###############################################################################
fossil test-th-eval "set gv 1; upvar 0 gv gv2(1); unset gv; unset gv2(1)"
test th1-unset-7 {$RESULT eq {TH_ERROR: no such variable: gv2(1)}}
###############################################################################
fossil test-th-eval "set gv(1) 1; upvar 0 gv(1) gv2; unset gv(1); unset gv2"
test th1-unset-8 {$RESULT eq {TH_ERROR: no such variable: gv2}}
###############################################################################
fossil test-th-eval "string first {} {}"
test th1-string-first-1 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string first {} {a}"
test th1-string-first-2 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string first {a} {}"
test th1-string-first-3 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string first {a} {a}"
test th1-string-first-4 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string first {a} {aa}"
test th1-string-first-5 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string first {aa} {a}"
test th1-string-first-6 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string first {ab} {abc}"
test th1-string-first-7 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string first {bc} {abc}"
test th1-string-first-8 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "string first {AB} {abc}"
test th1-string-first-9 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {} {}"
test th1-string-last-1 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {} {a}"
test th1-string-last-2 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {a} {}"
test th1-string-last-3 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {a} {a}"
test th1-string-last-4 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string last {a} {aa}"
test th1-string-last-5 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "string last {aa} {a}"
test th1-string-last-6 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "string last {ab} {abc}"
test th1-string-last-7 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "string last {bc} {abc}"
test th1-string-last-8 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "string last {AB} {abc}"
test th1-string-last-9 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr -2147483649.0"
test th1-expr-1 {$RESULT eq {-2147483649.0}}
###############################################################################
fossil test-th-eval "expr -2147483649"
test th1-expr-2 {$RESULT eq {2147483647}}
###############################################################################
fossil test-th-eval "expr -2147483648"
test th1-expr-3 {$RESULT eq {-2147483648}}
###############################################################################
fossil test-th-eval "expr -2147483647"
test th1-expr-4 {$RESULT eq {-2147483647}}
###############################################################################
fossil test-th-eval "expr -1"
test th1-expr-5 {$RESULT eq {-1}}
###############################################################################
fossil test-th-eval "expr 0"
test th1-expr-6 {$RESULT eq {0}}
###############################################################################
fossil test-th-eval "expr 0.0"
test th1-expr-7 {$RESULT eq {0.0}}
###############################################################################
fossil test-th-eval "expr 1"
test th1-expr-8 {$RESULT eq {1}}
###############################################################################
fossil test-th-eval "expr 2147483647"
test th1-expr-9 {$RESULT eq {2147483647}}
###############################################################################
fossil test-th-eval "expr 2147483648"
test th1-expr-10 {$RESULT eq {2147483648}}
###############################################################################
fossil test-th-eval "expr 2147483649"
test th1-expr-11 {$RESULT eq {2147483649}}
###############################################################################
fossil test-th-eval "expr +2147483649"
test th1-expr-12 {$RESULT eq {-2147483647}}
###############################################################################
fossil test-th-eval "expr +2147483649.0"
test th1-expr-13 {$RESULT eq {2147483649.0}}
|
Added test/utf16be.txt.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
This file contains utf-16be text.
The purpose for including this file in the Fossil
repository is to provide the ability to test Fossil's
handling of UTF-16 using its own repository.
Browsing to this file in the web interface should display the file as
text on the screen.
When there are changes to this file those changes should show
up in the "diff" output and be properly displayed on the
screen.
Test procedures:
1. Verify that this file is correctly display using the /artifact
webpage.
2. Verify that this file is correctly displayed by the /doc webpage.
3. Verify that changes to are correctly displayed by the /fdiff webpage.
4. Verify that the "fossil diff" command correctly displays changes
in this file. Do the same with the --tk option.
|
Added test/utf16le.txt.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
This file contains utf-16le text.
The purpose for including this file in the Fossil
repository is to provide the ability to test Fossil's
handling of UTF-16 using its own repository.
Browsing to this file in the web interface should display the file as
text on the screen.
When there are changes to this file those changes should show
up in the "diff" output and be properly displayed on the
screen.
Test procedures:
1. Verify that this file is correctly display using the /artifact
webpage.
2. Verify that this file is correctly displayed by the /doc webpage.
3. Verify that changes to are correctly displayed by the /fdiff webpage.
4. Verify that the "fossil diff" command correctly displays changes
in this file. Do the same with the --tk option.
|
Changes to test/valgrind-www.tcl.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
#
# Then examine the valgrind-out.txt file for issues.
#
proc run_query {url} {
set fd [open q.txt w]
puts $fd "GET $url HTTP/1.0\r\n\r"
close $fd
| > | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#
# Then examine the valgrind-out.txt file for issues.
#
proc run_query {url} {
set fd [open q.txt w]
puts $fd "GET $url HTTP/1.0\r\n\r"
close $fd
set msg {}
catch {exec valgrind ./fossil test-http <q.txt 2>@ stderr} msg
return $msg
}
set todo {}
foreach url {
/home
/timeline
/brlist
/taglist
|
| ︙ | ︙ |
Changes to win/Makefile.PellesCGMake.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 | UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the sqlite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) | | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | UTILS_OBJ=$(UTILS:.exe=.obj) UTILS_SRC=$(foreach uf,$(UTILS),$(SRCDIR)$(uf:.exe=.c)) # define the sqlite files, which need special flags on compile SQLITESRC=sqlite3.c ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf)) SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj)) SQLITEDEFINES=-DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS # define the sqlite shell files, which need special flags on compile SQLITESHELLSRC=shell.c ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf)) SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj)) SQLITESHELLDEFINES=-Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dgetenv=fossil_getenv -Dfopen=fossil_fopen # define the th scripting files, which need special flags on compile THSRC=th.c th_lang.c ORIGTHSRC=$(foreach sf,$(THSRC),$(SRCDIR)$(sf)) THOBJ=$(foreach sf,$(THSRC),$(sf:.c=.obj)) # define the zlib files, needed by this compile |
| ︙ | ︙ |
Changes to win/Makefile.dmc.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 | SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 | > | > | | | | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | SSL = CFLAGS = -o BCC = $(DMDIR)\bin\dmc $(CFLAGS) TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32 SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dgetenv=fossil_getenv -Dfopen=fossil_fopen SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ APPNAME = $(OBJDIR)\fossil$(E) all: $(APPNAME) $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link cd $(OBJDIR) $(DMDIR)\bin\link @link $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf rebuild regexp report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ +echo. >> $@ +echo fossil >> $@ translate$E: $(SRCDIR)\translate.c $(BCC) -o$@ $** makeheaders$E: $(SRCDIR)\makeheaders.c $(BCC) -o$@ $** mkindex$E: $(SRCDIR)\mkindex.c $(BCC) -o$@ $** version$E: $B\src\mkversion.c $(BCC) -o$@ $** $(OBJDIR)\shell$O : $(SRCDIR)\shell.c $(TCC) -o$@ -c $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) $** $(OBJDIR)\sqlite3$O : $(SRCDIR)\sqlite3.c $(TCC) -o$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $** $(OBJDIR)\th$O : $(SRCDIR)\th.c $(TCC) -o$@ -c $** $(OBJDIR)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) -o$@ -c $** |
| ︙ | ︙ | |||
438 439 440 441 442 443 444 445 446 447 448 449 450 451 | +translate$E $** > $@ $(OBJDIR)\login$O : login_.c login.h $(TCC) -o$@ -c login_.c login_.c : $(SRCDIR)\login.c +translate$E $** > $@ $(OBJDIR)\main$O : main_.c main.h $(TCC) -o$@ -c main_.c main_.c : $(SRCDIR)\main.c +translate$E $** > $@ | > > > > > > | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | +translate$E $** > $@ $(OBJDIR)\login$O : login_.c login.h $(TCC) -o$@ -c login_.c login_.c : $(SRCDIR)\login.c +translate$E $** > $@ $(OBJDIR)\lookslike$O : lookslike_.c lookslike.h $(TCC) -o$@ -c lookslike_.c lookslike_.c : $(SRCDIR)\lookslike.c +translate$E $** > $@ $(OBJDIR)\main$O : main_.c main.h $(TCC) -o$@ -c main_.c main_.c : $(SRCDIR)\main.c +translate$E $** > $@ |
| ︙ | ︙ | |||
714 715 716 717 718 719 720 721 722 723 724 725 726 727 | +translate$E $** > $@ $(OBJDIR)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) -o$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c +translate$E $** > $@ $(OBJDIR)\winhttp$O : winhttp_.c winhttp.h $(TCC) -o$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c +translate$E $** > $@ | > > > > > > | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | +translate$E $** > $@ $(OBJDIR)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) -o$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c +translate$E $** > $@ $(OBJDIR)\winfile$O : winfile_.c winfile.h $(TCC) -o$@ -c winfile_.c winfile_.c : $(SRCDIR)\winfile.c +translate$E $** > $@ $(OBJDIR)\winhttp$O : winhttp_.c winhttp.h $(TCC) -o$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c +translate$E $** > $@ |
| ︙ | ︙ | |||
746 747 748 749 750 751 752 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h | | | 760 761 762 763 764 765 766 767 768 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers |
Changes to win/Makefile.mingw.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | # # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 | | > > > > | | | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | # # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # # FOSSIL_ENABLE_TCL = 1 #### Load Tcl using the stubs library mechanism # # FOSSIL_ENABLE_TCL_STUBS = 1 #### Load Tcl using the private stubs mechanism # # FOSSIL_ENABLE_TCL_PRIVATE_STUBS = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### Check if the workaround for the MinGW command line handling needs to # be enabled by default. # ifndef MINGW_IS_32BIT_ONLY ifeq (,$(findstring w64-mingw32,$(PREFIX))) MINGW_IS_32BIT_ONLY = 1 endif endif #### The directories where the zlib include and library files are located. # ZINCDIR = $(SRCDIR)/../compat/zlib ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | # TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # ifdef FOSSIL_ENABLE_TCL_STUBS LIBTCL = -ltclstub86 else LIBTCL = -ltcl86 endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. | > > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | # TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # ifdef FOSSIL_ENABLE_TCL_STUBS ifndef FOSSIL_ENABLE_TCL_PRIVATE_STUBS LIBTCL = -ltclstub86 endif TCLTARGET = libtclstub86.a else LIBTCL = -ltcl86 TCLTARGET = binaries endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. |
| ︙ | ︙ | |||
152 153 154 155 156 157 158 | else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With MinGW command line handling workaround | | > > > > | | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With MinGW command line handling workaround ifdef MINGW_IS_32BIT_ONLY TCC += -DBROKEN_MINGW_CMDLINE=1 RCC += -DBROKEN_MINGW_CMDLINE=1 endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 RCC += -DFOSSIL_ENABLE_TCL=1 # Either statically linked or via stubs ifdef FOSSIL_ENABLE_TCL_STUBS TCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS RCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS ifdef FOSSIL_ENABLE_TCL_PRIVATE_STUBS TCC += -DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 RCC += -DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 endif else TCC += -DSTATIC_BUILD RCC += -DSTATIC_BUILD endif endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 RCC += -DFOSSIL_ENABLE_JSON=1 endif #### We add the -static option here so that we can build a static # executable that will run in a chroot jail. # LIB = -static # MinGW: If available, use the Unicode capable runtime startup code. ifndef MINGW_IS_32BIT_ONLY LIB += -municode endif # OpenSSL: Add the necessary libraries required, if enabled. ifdef FOSSIL_ENABLE_SSL LIB += -lssl -lcrypto -lgdi32 endif |
| ︙ | ︙ | |||
296 297 298 299 300 301 302 303 304 305 306 307 308 309 | $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ | > | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/lookslike.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ |
| ︙ | ︙ | |||
342 343 344 345 346 347 348 349 350 351 352 353 354 355 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ |
| ︙ | ︙ | |||
404 405 406 407 408 409 410 411 412 413 414 415 416 417 | $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ | > | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/lookslike_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ |
| ︙ | ︙ | |||
450 451 452 453 454 455 456 457 458 459 460 461 462 463 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ | > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ |
| ︙ | ︙ | |||
512 513 514 515 516 517 518 519 520 521 522 523 524 525 | $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ | > | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 | $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/lookslike.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ |
| ︙ | ︙ | |||
558 559 560 561 562 563 564 565 566 567 568 569 570 571 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil.exe | > | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winfile.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil.exe |
| ︙ | ︙ | |||
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h ifdef USE_WINDOWS $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) else $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) | > > | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 | all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h ifdef USE_WINDOWS $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR)) else $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) |
| ︙ | ︙ | |||
653 654 655 656 657 658 659 660 661 662 663 664 665 666 | ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: | > > > > > > > > > > > > > > > > > | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean openssl: zlib cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) --with-zlib-lib=$(PWD)/$(ZLIBDIR) --with-zlib-include=$(PWD)/$(ZLIBDIR) zlib mingw $(MAKE) -C $(OPENSSLLIBDIR) build_libs clean-openssl: $(MAKE) -C $(OPENSSLLIBDIR) clean tcl: cd $(TCLSRCDIR)/win;./configure $(MAKE) -C $(TCLSRCDIR)/win $(TCLTARGET) clean-tcl: $(MAKE) -C $(TCLSRCDIR)/win distclean $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: |
| ︙ | ︙ | |||
733 734 735 736 737 738 739 740 741 742 743 744 745 746 | $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ $(OBJDIR)/login_.c:$(OBJDIR)/login.h \ $(OBJDIR)/main_.c:$(OBJDIR)/main.h \ $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \ $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \ $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \ | > | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ $(OBJDIR)/login_.c:$(OBJDIR)/login.h \ $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \ $(OBJDIR)/main_.c:$(OBJDIR)/main.h \ $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \ $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \ $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \ |
| ︙ | ︙ | |||
779 780 781 782 783 784 785 786 787 788 789 790 791 792 | $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \ $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \ $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \ $(SRCDIR)/sqlite3.h \ $(SRCDIR)/th.h \ | > | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 | $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \ $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \ $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \ $(SRCDIR)/sqlite3.h \ $(SRCDIR)/th.h \ |
| ︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 | $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c | > > > > > > > > | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 | $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers $(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h: $(OBJDIR)/headers $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c |
| ︙ | ︙ | |||
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c | > > > > > > > > | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winfile_.c: $(SRCDIR)/winfile.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winfile.c >$(OBJDIR)/winfile_.c $(OBJDIR)/winfile.o: $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winfile.o -c $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c |
| ︙ | ︙ | |||
1641 1642 1643 1644 1645 1646 1647 | $(TRANSLATE) $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers | > > > > > > > > > > > > > > > | | | | | | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 |
$(TRANSLATE) $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c
$(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h
$(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
$(OBJDIR)/zip.h: $(OBJDIR)/headers
SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DSQLITE_ENABLE_LOCKING_STYLE=0 \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_DEFAULT_FILE_FORMAT=4 \
-DSQLITE_OMIT_DEPRECATED \
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-D_HAVE_SQLITE_CONFIG_H \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -Dmain=sqlite3_shell \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-Dgetenv=fossil_getenv \
-Dfopen=fossil_fopen
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(SRCDIR)/../win/Makefile.mingw
$(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw
$(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
$(OBJDIR)/th.o: $(SRCDIR)/th.c
$(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
$(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
$(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
ifdef FOSSIL_ENABLE_TCL
$(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
$(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
endif
|
Changes to win/Makefile.mingw.mistachkin.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # FOSSIL_ENABLE_TCL = 1 | | > > > > | | | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | # FOSSIL_ENABLE_SSL = 1 #### Enable scripting support via Tcl/Tk # FOSSIL_ENABLE_TCL = 1 #### Load Tcl using the stubs library mechanism # FOSSIL_ENABLE_TCL_STUBS = 1 #### Load Tcl using the private stubs mechanism # FOSSIL_ENABLE_TCL_PRIVATE_STUBS = 1 #### Use the Tcl source directory instead of the install directory? # This is useful when Tcl has been compiled statically with MinGW. # FOSSIL_TCL_SOURCE = 1 #### Check if the workaround for the MinGW command line handling needs to # be enabled by default. # ifndef MINGW_IS_32BIT_ONLY ifeq (,$(findstring w64-mingw32,$(PREFIX))) MINGW_IS_32BIT_ONLY = 1 endif endif #### The directories where the zlib include and library files are located. # ZINCDIR = $(SRCDIR)/../compat/zlib ZLIBDIR = $(SRCDIR)/../compat/zlib #### The directories where the OpenSSL include and library files are located. # The recommended usage here is to use the Sysinternals junction tool # to create a hard link between an "openssl-1.x" sub-directory of the # Fossil source code directory and the target OpenSSL source directory. # OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1f/include OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1f #### Either the directory where the Tcl library is installed or the Tcl # source code directory resides (depending on the value of the macro # FOSSIL_TCL_SOURCE). If this points to the Tcl install directory, # this directory must have "include" and "lib" sub-directories. If # this points to the Tcl source code directory, this directory must # have "generic" and "win" sub-directories. The recommended usage |
| ︙ | ︙ | |||
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | # TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # ifdef FOSSIL_ENABLE_TCL_STUBS LIBTCL = -ltclstub86 else LIBTCL = -ltcl86 endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. | > > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | # TCLINCDIR = $(TCLDIR)/include TCLLIBDIR = $(TCLDIR)/lib #### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)? # ifdef FOSSIL_ENABLE_TCL_STUBS ifndef FOSSIL_ENABLE_TCL_PRIVATE_STUBS LIBTCL = -ltclstub86 endif TCLTARGET = libtclstub86.a else LIBTCL = -ltcl86 TCLTARGET = binaries endif #### C Compile and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. This C compiler builds # the finished binary for fossil. The BCC compiler above is used # for building intermediate code-generator tools. |
| ︙ | ︙ | |||
152 153 154 155 156 157 158 | else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With MinGW command line handling workaround | | > > > > | | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | else TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR) RCC += -I$(TCLINCDIR) endif endif # With MinGW command line handling workaround ifdef MINGW_IS_32BIT_ONLY TCC += -DBROKEN_MINGW_CMDLINE=1 RCC += -DBROKEN_MINGW_CMDLINE=1 endif # With HTTPS support ifdef FOSSIL_ENABLE_SSL TCC += -DFOSSIL_ENABLE_SSL=1 RCC += -DFOSSIL_ENABLE_SSL=1 endif # With Tcl support ifdef FOSSIL_ENABLE_TCL TCC += -DFOSSIL_ENABLE_TCL=1 RCC += -DFOSSIL_ENABLE_TCL=1 # Either statically linked or via stubs ifdef FOSSIL_ENABLE_TCL_STUBS TCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS RCC += -DFOSSIL_ENABLE_TCL_STUBS=1 -DUSE_TCL_STUBS ifdef FOSSIL_ENABLE_TCL_PRIVATE_STUBS TCC += -DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 RCC += -DFOSSIL_ENABLE_TCL_PRIVATE_STUBS=1 endif else TCC += -DSTATIC_BUILD RCC += -DSTATIC_BUILD endif endif # With JSON support ifdef FOSSIL_ENABLE_JSON TCC += -DFOSSIL_ENABLE_JSON=1 RCC += -DFOSSIL_ENABLE_JSON=1 endif #### We add the -static option here so that we can build a static # executable that will run in a chroot jail. # LIB = -static # MinGW: If available, use the Unicode capable runtime startup code. ifndef MINGW_IS_32BIT_ONLY LIB += -municode endif # OpenSSL: Add the necessary libraries required, if enabled. ifdef FOSSIL_ENABLE_SSL LIB += -lssl -lcrypto -lgdi32 endif |
| ︙ | ︙ | |||
296 297 298 299 300 301 302 303 304 305 306 307 308 309 | $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ | > | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | $(SRCDIR)/json_status.c \ $(SRCDIR)/json_tag.c \ $(SRCDIR)/json_timeline.c \ $(SRCDIR)/json_user.c \ $(SRCDIR)/json_wiki.c \ $(SRCDIR)/leaf.c \ $(SRCDIR)/login.c \ $(SRCDIR)/lookslike.c \ $(SRCDIR)/main.c \ $(SRCDIR)/manifest.c \ $(SRCDIR)/markdown.c \ $(SRCDIR)/markdown_html.c \ $(SRCDIR)/md5.c \ $(SRCDIR)/merge.c \ $(SRCDIR)/merge3.c \ |
| ︙ | ︙ | |||
342 343 344 345 346 347 348 349 350 351 352 353 354 355 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ | > | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | $(SRCDIR)/user.c \ $(SRCDIR)/utf8.c \ $(SRCDIR)/util.c \ $(SRCDIR)/verify.c \ $(SRCDIR)/vfile.c \ $(SRCDIR)/wiki.c \ $(SRCDIR)/wikiformat.c \ $(SRCDIR)/winfile.c \ $(SRCDIR)/winhttp.c \ $(SRCDIR)/wysiwyg.c \ $(SRCDIR)/xfer.c \ $(SRCDIR)/xfersetup.c \ $(SRCDIR)/zip.c TRANS_SRC = \ |
| ︙ | ︙ | |||
404 405 406 407 408 409 410 411 412 413 414 415 416 417 | $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ | > | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | $(OBJDIR)/json_status_.c \ $(OBJDIR)/json_tag_.c \ $(OBJDIR)/json_timeline_.c \ $(OBJDIR)/json_user_.c \ $(OBJDIR)/json_wiki_.c \ $(OBJDIR)/leaf_.c \ $(OBJDIR)/login_.c \ $(OBJDIR)/lookslike_.c \ $(OBJDIR)/main_.c \ $(OBJDIR)/manifest_.c \ $(OBJDIR)/markdown_.c \ $(OBJDIR)/markdown_html_.c \ $(OBJDIR)/md5_.c \ $(OBJDIR)/merge_.c \ $(OBJDIR)/merge3_.c \ |
| ︙ | ︙ | |||
450 451 452 453 454 455 456 457 458 459 460 461 462 463 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ | > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 | $(OBJDIR)/user_.c \ $(OBJDIR)/utf8_.c \ $(OBJDIR)/util_.c \ $(OBJDIR)/verify_.c \ $(OBJDIR)/vfile_.c \ $(OBJDIR)/wiki_.c \ $(OBJDIR)/wikiformat_.c \ $(OBJDIR)/winfile_.c \ $(OBJDIR)/winhttp_.c \ $(OBJDIR)/wysiwyg_.c \ $(OBJDIR)/xfer_.c \ $(OBJDIR)/xfersetup_.c \ $(OBJDIR)/zip_.c OBJ = \ |
| ︙ | ︙ | |||
512 513 514 515 516 517 518 519 520 521 522 523 524 525 | $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ | > | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 | $(OBJDIR)/json_status.o \ $(OBJDIR)/json_tag.o \ $(OBJDIR)/json_timeline.o \ $(OBJDIR)/json_user.o \ $(OBJDIR)/json_wiki.o \ $(OBJDIR)/leaf.o \ $(OBJDIR)/login.o \ $(OBJDIR)/lookslike.o \ $(OBJDIR)/main.o \ $(OBJDIR)/manifest.o \ $(OBJDIR)/markdown.o \ $(OBJDIR)/markdown_html.o \ $(OBJDIR)/md5.o \ $(OBJDIR)/merge.o \ $(OBJDIR)/merge3.o \ |
| ︙ | ︙ | |||
558 559 560 561 562 563 564 565 566 567 568 569 570 571 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil.exe | > | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | $(OBJDIR)/user.o \ $(OBJDIR)/utf8.o \ $(OBJDIR)/util.o \ $(OBJDIR)/verify.o \ $(OBJDIR)/vfile.o \ $(OBJDIR)/wiki.o \ $(OBJDIR)/wikiformat.o \ $(OBJDIR)/winfile.o \ $(OBJDIR)/winhttp.o \ $(OBJDIR)/wysiwyg.o \ $(OBJDIR)/xfer.o \ $(OBJDIR)/xfersetup.o \ $(OBJDIR)/zip.o APPNAME = fossil.exe |
| ︙ | ︙ | |||
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h ifdef USE_WINDOWS $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) else $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) | > > | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 | all: $(OBJDIR) $(APPNAME) $(OBJDIR)/fossil.o: $(SRCDIR)/../win/fossil.rc $(OBJDIR)/VERSION.h ifdef USE_WINDOWS $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.rc) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.ico) $(subst /,\,$(OBJDIR)) $(CP) $(subst /,\,$(SRCDIR)\..\win\fossil.exe.manifest) $(subst /,\,$(OBJDIR)) else $(CP) $(SRCDIR)/../win/fossil.rc $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.ico $(OBJDIR) $(CP) $(SRCDIR)/../win/fossil.exe.manifest $(OBJDIR) endif $(RCC) $(OBJDIR)/fossil.rc -o $(OBJDIR)/fossil.o install: $(OBJDIR) $(APPNAME) ifdef USE_WINDOWS $(MKDIR) $(subst /,\,$(INSTALLDIR)) $(MV) $(subst /,\,$(APPNAME)) $(subst /,\,$(INSTALLDIR)) |
| ︙ | ︙ | |||
653 654 655 656 657 658 659 660 661 662 663 664 665 666 | ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: | > > > > > > > > > > > > > > > > > | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | ifdef FOSSIL_ENABLE_TCL EXTRAOBJ += $(OBJDIR)/th_tcl.o endif zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc libz.a clean-zlib: $(MAKE) -C $(ZLIBDIR) PREFIX=$(PREFIX) -f win32/Makefile.gcc clean openssl: zlib cd $(OPENSSLLIBDIR);./Configure --cross-compile-prefix=$(PREFIX) --with-zlib-lib=$(PWD)/$(ZLIBDIR) --with-zlib-include=$(PWD)/$(ZLIBDIR) zlib mingw $(MAKE) -C $(OPENSSLLIBDIR) build_libs clean-openssl: $(MAKE) -C $(OPENSSLLIBDIR) clean tcl: cd $(TCLSRCDIR)/win;./configure $(MAKE) -C $(TCLSRCDIR)/win $(TCLTARGET) clean-tcl: $(MAKE) -C $(TCLSRCDIR)/win distclean $(APPNAME): $(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/fossil.o zlib $(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/fossil.o # This rule prevents make from using its default rules to try build # an executable named "manifest" out of the file named "manifest.c" # $(SRCDIR)/../manifest: |
| ︙ | ︙ | |||
733 734 735 736 737 738 739 740 741 742 743 744 745 746 | $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ $(OBJDIR)/login_.c:$(OBJDIR)/login.h \ $(OBJDIR)/main_.c:$(OBJDIR)/main.h \ $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \ $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \ $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \ | > | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | $(OBJDIR)/json_status_.c:$(OBJDIR)/json_status.h \ $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h \ $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h \ $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h \ $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h \ $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h \ $(OBJDIR)/login_.c:$(OBJDIR)/login.h \ $(OBJDIR)/lookslike_.c:$(OBJDIR)/lookslike.h \ $(OBJDIR)/main_.c:$(OBJDIR)/main.h \ $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h \ $(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \ $(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \ $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \ $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \ $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \ |
| ︙ | ︙ | |||
779 780 781 782 783 784 785 786 787 788 789 790 791 792 | $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \ $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \ $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \ $(SRCDIR)/sqlite3.h \ $(SRCDIR)/th.h \ | > | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 | $(OBJDIR)/user_.c:$(OBJDIR)/user.h \ $(OBJDIR)/utf8_.c:$(OBJDIR)/utf8.h \ $(OBJDIR)/util_.c:$(OBJDIR)/util.h \ $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h \ $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h \ $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h \ $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h \ $(OBJDIR)/winfile_.c:$(OBJDIR)/winfile.h \ $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h \ $(OBJDIR)/wysiwyg_.c:$(OBJDIR)/wysiwyg.h \ $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h \ $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h \ $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h \ $(SRCDIR)/sqlite3.h \ $(SRCDIR)/th.h \ |
| ︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 | $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c | > > > > > > > > | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 | $(OBJDIR)/login_.c: $(SRCDIR)/login.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/login.c >$(OBJDIR)/login_.c $(OBJDIR)/login.o: $(OBJDIR)/login_.c $(OBJDIR)/login.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/login.o -c $(OBJDIR)/login_.c $(OBJDIR)/login.h: $(OBJDIR)/headers $(OBJDIR)/lookslike_.c: $(SRCDIR)/lookslike.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/lookslike.c >$(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.o: $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/lookslike.o -c $(OBJDIR)/lookslike_.c $(OBJDIR)/lookslike.h: $(OBJDIR)/headers $(OBJDIR)/main_.c: $(SRCDIR)/main.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/main.c >$(OBJDIR)/main_.c $(OBJDIR)/main.o: $(OBJDIR)/main_.c $(OBJDIR)/main.h $(OBJDIR)/page_index.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/main.o -c $(OBJDIR)/main_.c |
| ︙ | ︙ | |||
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c | > > > > > > > > | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 | $(OBJDIR)/wikiformat_.c: $(SRCDIR)/wikiformat.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/wikiformat.c >$(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.o: $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/wikiformat.o -c $(OBJDIR)/wikiformat_.c $(OBJDIR)/wikiformat.h: $(OBJDIR)/headers $(OBJDIR)/winfile_.c: $(SRCDIR)/winfile.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winfile.c >$(OBJDIR)/winfile_.c $(OBJDIR)/winfile.o: $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winfile.o -c $(OBJDIR)/winfile_.c $(OBJDIR)/winfile.h: $(OBJDIR)/headers $(OBJDIR)/winhttp_.c: $(SRCDIR)/winhttp.c $(OBJDIR)/translate $(TRANSLATE) $(SRCDIR)/winhttp.c >$(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.o: $(OBJDIR)/winhttp_.c $(OBJDIR)/winhttp.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/winhttp.o -c $(OBJDIR)/winhttp_.c |
| ︙ | ︙ | |||
1641 1642 1643 1644 1645 1646 1647 | $(TRANSLATE) $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c $(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c $(OBJDIR)/zip.h: $(OBJDIR)/headers | > > > > > > > > > > > > > > > | | | | | | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 |
$(TRANSLATE) $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c
$(OBJDIR)/zip.o: $(OBJDIR)/zip_.c $(OBJDIR)/zip.h $(SRCDIR)/config.h
$(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c
$(OBJDIR)/zip.h: $(OBJDIR)/headers
SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 \
-DSQLITE_ENABLE_LOCKING_STYLE=0 \
-DSQLITE_THREADSAFE=0 \
-DSQLITE_DEFAULT_FILE_FORMAT=4 \
-DSQLITE_OMIT_DEPRECATED \
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
-D_HAVE_SQLITE_CONFIG_H \
-DSQLITE_USE_MALLOC_H \
-DSQLITE_USE_MSIZE
SHELL_OPTIONS = -Dmain=sqlite3_shell \
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
-Dgetenv=fossil_getenv \
-Dfopen=fossil_fopen
$(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c $(SRCDIR)/../win/Makefile.mingw.mistachkin
$(XTCC) $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_dir.o $(OBJDIR)/jsos_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_status.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
$(OBJDIR)/shell.o: $(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h $(SRCDIR)/../win/Makefile.mingw.mistachkin
$(XTCC) $(SHELL_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
$(OBJDIR)/th.o: $(SRCDIR)/th.c
$(XTCC) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
$(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c
$(XTCC) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
ifdef FOSSIL_ENABLE_TCL
$(OBJDIR)/th_tcl.o: $(SRCDIR)/th_tcl.c
$(XTCC) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
endif
|
Changes to win/Makefile.msc.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # B = .. SRCDIR = $B\src OBJDIR = . OX = . O = .obj E = .exe # Uncomment to enable JSON API # FOSSIL_ENABLE_JSON = 1 # Uncomment to enable SSL support # FOSSIL_ENABLE_SSL = 1 !ifdef FOSSIL_ENABLE_SSL | > > > > | | | | | | | | > > > > > > > > > | | | | | | | | | | | > > | | > | > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#
B = ..
SRCDIR = $B\src
OBJDIR = .
OX = .
O = .obj
E = .exe
P = .pdb
# Uncomment to enable debug symbols
# DEBUG = 1
# Uncomment to enable JSON API
# FOSSIL_ENABLE_JSON = 1
# Uncomment to enable SSL support
# FOSSIL_ENABLE_SSL = 1
!ifdef FOSSIL_ENABLE_SSL
SSLINCDIR = $(B)\compat\openssl-1.0.1f\include
SSLLIBDIR = $(B)\compat\openssl-1.0.1f\out32
SSLLIB = ssleay32.lib libeay32.lib user32.lib gdi32.lib
!endif
# zlib options
ZINCDIR = $(B)\compat\zlib
ZLIBDIR = $(B)\compat\zlib
ZLIB = zlib.lib
INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(ZINCDIR)
!ifdef FOSSIL_ENABLE_SSL
INCL = $(INCL) -I$(SSLINCDIR)
!endif
CFLAGS = -nologo
LDFLAGS = /NODEFAULTLIB:msvcrt /MANIFEST:NO
!ifdef DEBUG
CFLAGS = $(CFLAGS) -Zi -MTd -Od
LDFLAGS = $(LDFLAGS) /DEBUG
!else
CFLAGS = $(CFLAGS) -MT -O2
!endif
BCC = $(CC) $(CFLAGS)
TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(INCL)
RCC = rc -D_WIN32 -D_MSC_VER $(MSCDEF) $(INCL)
LIBS = $(ZLIB) ws2_32.lib advapi32.lib
LIBDIR = -LIBPATH:$(ZLIBDIR)
!ifdef FOSSIL_ENABLE_JSON
TCC = $(TCC) -DFOSSIL_ENABLE_JSON=1
RCC = $(RCC) -DFOSSIL_ENABLE_JSON=1
!endif
!ifdef FOSSIL_ENABLE_SSL
TCC = $(TCC) -DFOSSIL_ENABLE_SSL=1
RCC = $(RCC) -DFOSSIL_ENABLE_SSL=1
LIBS = $(LIBS) $(SSLLIB)
LIBDIR = $(LIBDIR) -LIBPATH:$(SSLLIBDIR)
!endif
SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 \
/DSQLITE_ENABLE_LOCKING_STYLE=0 \
/DSQLITE_THREADSAFE=0 \
/DSQLITE_DEFAULT_FILE_FORMAT=4 \
/DSQLITE_OMIT_DEPRECATED \
/DSQLITE_ENABLE_EXPLAIN_COMMENTS
SHELL_OPTIONS = /Dmain=sqlite3_shell \
/DSQLITE_OMIT_LOAD_EXTENSION=1 \
/Dgetenv=fossil_getenv \
/Dfopen=fossil_fopen
SRC = add_.c \
allrepo_.c \
attach_.c \
bag_.c \
bisect_.c \
blob_.c \
|
| ︙ | ︙ | |||
114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
json_status_.c \
json_tag_.c \
json_timeline_.c \
json_user_.c \
json_wiki_.c \
leaf_.c \
login_.c \
main_.c \
manifest_.c \
markdown_.c \
markdown_html_.c \
md5_.c \
merge_.c \
merge3_.c \
| > | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
json_status_.c \
json_tag_.c \
json_timeline_.c \
json_user_.c \
json_wiki_.c \
leaf_.c \
login_.c \
lookslike_.c \
main_.c \
manifest_.c \
markdown_.c \
markdown_html_.c \
md5_.c \
merge_.c \
merge3_.c \
|
| ︙ | ︙ | |||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
user_.c \
utf8_.c \
util_.c \
verify_.c \
vfile_.c \
wiki_.c \
wikiformat_.c \
winhttp_.c \
wysiwyg_.c \
xfer_.c \
xfersetup_.c \
zip_.c
OBJ = $(OX)\add$O \
| > | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
user_.c \
utf8_.c \
util_.c \
verify_.c \
vfile_.c \
wiki_.c \
wikiformat_.c \
winfile_.c \
winhttp_.c \
wysiwyg_.c \
xfer_.c \
xfersetup_.c \
zip_.c
OBJ = $(OX)\add$O \
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
$(OX)\json_status$O \
$(OX)\json_tag$O \
$(OX)\json_timeline$O \
$(OX)\json_user$O \
$(OX)\json_wiki$O \
$(OX)\leaf$O \
$(OX)\login$O \
$(OX)\main$O \
$(OX)\manifest$O \
$(OX)\markdown$O \
$(OX)\markdown_html$O \
$(OX)\md5$O \
$(OX)\merge$O \
$(OX)\merge3$O \
| > | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
$(OX)\json_status$O \
$(OX)\json_tag$O \
$(OX)\json_timeline$O \
$(OX)\json_user$O \
$(OX)\json_wiki$O \
$(OX)\leaf$O \
$(OX)\login$O \
$(OX)\lookslike$O \
$(OX)\main$O \
$(OX)\manifest$O \
$(OX)\markdown$O \
$(OX)\markdown_html$O \
$(OX)\md5$O \
$(OX)\merge$O \
$(OX)\merge3$O \
|
| ︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
$(OX)\user$O \
$(OX)\utf8$O \
$(OX)\util$O \
$(OX)\verify$O \
$(OX)\vfile$O \
$(OX)\wiki$O \
$(OX)\wikiformat$O \
$(OX)\winhttp$O \
$(OX)\wysiwyg$O \
$(OX)\xfer$O \
$(OX)\xfersetup$O \
$(OX)\zip$O \
$(OX)\fossil.res
APPNAME = $(OX)\fossil$(E)
all: $(OX) $(APPNAME)
zlib:
@echo Building zlib from "$(ZLIBDIR)"...
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
cd $(OX)
| > > | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
$(OX)\user$O \
$(OX)\utf8$O \
$(OX)\util$O \
$(OX)\verify$O \
$(OX)\vfile$O \
$(OX)\wiki$O \
$(OX)\wikiformat$O \
$(OX)\winfile$O \
$(OX)\winhttp$O \
$(OX)\wysiwyg$O \
$(OX)\xfer$O \
$(OX)\xfersetup$O \
$(OX)\zip$O \
$(OX)\fossil.res
APPNAME = $(OX)\fossil$(E)
PDBNAME = $(OX)\fossil$(P)
all: $(OX) $(APPNAME)
zlib:
@echo Building zlib from "$(ZLIBDIR)"...
@pushd "$(ZLIBDIR)" && nmake /f win32\Makefile.msc $(ZLIB) && popd
$(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts zlib
cd $(OX)
link $(LDFLAGS) -OUT:$@ $(LIBDIR) Wsetargv.obj fossil.res @linkopts
$(OX)\linkopts: $B\win\Makefile.msc
echo $(OX)\add.obj > $@
echo $(OX)\allrepo.obj >> $@
echo $(OX)\attach.obj >> $@
echo $(OX)\bag.obj >> $@
echo $(OX)\bisect.obj >> $@
|
| ︙ | ︙ | |||
348 349 350 351 352 353 354 355 356 357 358 359 360 361 | echo $(OX)\json_status.obj >> $@ echo $(OX)\json_tag.obj >> $@ echo $(OX)\json_timeline.obj >> $@ echo $(OX)\json_user.obj >> $@ echo $(OX)\json_wiki.obj >> $@ echo $(OX)\leaf.obj >> $@ echo $(OX)\login.obj >> $@ echo $(OX)\main.obj >> $@ echo $(OX)\manifest.obj >> $@ echo $(OX)\markdown.obj >> $@ echo $(OX)\markdown_html.obj >> $@ echo $(OX)\md5.obj >> $@ echo $(OX)\merge.obj >> $@ echo $(OX)\merge3.obj >> $@ | > | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | echo $(OX)\json_status.obj >> $@ echo $(OX)\json_tag.obj >> $@ echo $(OX)\json_timeline.obj >> $@ echo $(OX)\json_user.obj >> $@ echo $(OX)\json_wiki.obj >> $@ echo $(OX)\leaf.obj >> $@ echo $(OX)\login.obj >> $@ echo $(OX)\lookslike.obj >> $@ echo $(OX)\main.obj >> $@ echo $(OX)\manifest.obj >> $@ echo $(OX)\markdown.obj >> $@ echo $(OX)\markdown_html.obj >> $@ echo $(OX)\md5.obj >> $@ echo $(OX)\merge.obj >> $@ echo $(OX)\merge3.obj >> $@ |
| ︙ | ︙ | |||
398 399 400 401 402 403 404 405 406 407 408 409 410 411 | echo $(OX)\user.obj >> $@ echo $(OX)\utf8.obj >> $@ echo $(OX)\util.obj >> $@ echo $(OX)\verify.obj >> $@ echo $(OX)\vfile.obj >> $@ echo $(OX)\wiki.obj >> $@ echo $(OX)\wikiformat.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ echo $(LIBS) >> $@ | > | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 | echo $(OX)\user.obj >> $@ echo $(OX)\utf8.obj >> $@ echo $(OX)\util.obj >> $@ echo $(OX)\verify.obj >> $@ echo $(OX)\vfile.obj >> $@ echo $(OX)\wiki.obj >> $@ echo $(OX)\wikiformat.obj >> $@ echo $(OX)\winfile.obj >> $@ echo $(OX)\winhttp.obj >> $@ echo $(OX)\wysiwyg.obj >> $@ echo $(OX)\xfer.obj >> $@ echo $(OX)\xfersetup.obj >> $@ echo $(OX)\zip.obj >> $@ echo $(LIBS) >> $@ |
| ︙ | ︙ | |||
423 424 425 426 427 428 429 | mkindex$E: $(SRCDIR)\mkindex.c $(BCC) $** mkversion$E: $B\src\mkversion.c $(BCC) $** | | | | | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | mkindex$E: $(SRCDIR)\mkindex.c $(BCC) $** mkversion$E: $B\src\mkversion.c $(BCC) $** $(OX)\shell$O : $(SRCDIR)\shell.c $B\win\Makefile.msc $(TCC) /Fo$@ $(SHELL_OPTIONS) $(SQLITE_OPTIONS) $(SHELL_CFLAGS) -c $(SRCDIR)\shell.c $(OX)\sqlite3$O : $(SRCDIR)\sqlite3.c $B\win\Makefile.msc $(TCC) /Fo$@ -c $(SQLITE_OPTIONS) $(SQLITE_CFLAGS) $(SRCDIR)\sqlite3.c $(OX)\th$O : $(SRCDIR)\th.c $(TCC) /Fo$@ -c $** $(OX)\th_lang$O : $(SRCDIR)\th_lang.c $(TCC) /Fo$@ -c $** |
| ︙ | ︙ | |||
449 450 451 452 453 454 455 | clean: -del $(OX)\*.obj -del *.obj -del *_.c -del *.h -del *.map | | | > | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 | clean: -del $(OX)\*.obj -del *.obj -del *_.c -del *.h -del *.map -del *.res -del headers -del linkopts -del vc*.pdb realclean: clean -del $(APPNAME) -del $(PDBNAME) -del translate$E -del mkindex$E -del makeheaders$E -del mkversion$E $(OBJDIR)\json$O : $(SRCDIR)\json_detail.h $(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h |
| ︙ | ︙ | |||
807 808 809 810 811 812 813 814 815 816 817 818 819 820 | translate$E $** > $@ $(OX)\login$O : login_.c login.h $(TCC) /Fo$@ -c login_.c login_.c : $(SRCDIR)\login.c translate$E $** > $@ $(OX)\main$O : main_.c main.h $(TCC) /Fo$@ -c main_.c main_.c : $(SRCDIR)\main.c translate$E $** > $@ | > > > > > > | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | translate$E $** > $@ $(OX)\login$O : login_.c login.h $(TCC) /Fo$@ -c login_.c login_.c : $(SRCDIR)\login.c translate$E $** > $@ $(OX)\lookslike$O : lookslike_.c lookslike.h $(TCC) /Fo$@ -c lookslike_.c lookslike_.c : $(SRCDIR)\lookslike.c translate$E $** > $@ $(OX)\main$O : main_.c main.h $(TCC) /Fo$@ -c main_.c main_.c : $(SRCDIR)\main.c translate$E $** > $@ |
| ︙ | ︙ | |||
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 | translate$E $** > $@ $(OX)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) /Fo$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c translate$E $** > $@ $(OX)\winhttp$O : winhttp_.c winhttp.h $(TCC) /Fo$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c translate$E $** > $@ | > > > > > > | 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 | translate$E $** > $@ $(OX)\wikiformat$O : wikiformat_.c wikiformat.h $(TCC) /Fo$@ -c wikiformat_.c wikiformat_.c : $(SRCDIR)\wikiformat.c translate$E $** > $@ $(OX)\winfile$O : winfile_.c winfile.h $(TCC) /Fo$@ -c winfile_.c winfile_.c : $(SRCDIR)\winfile.c translate$E $** > $@ $(OX)\winhttp$O : winhttp_.c winhttp.h $(TCC) /Fo$@ -c winhttp_.c winhttp_.c : $(SRCDIR)\winhttp.c translate$E $** > $@ |
| ︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | json_status_.c:json_status.h \ json_tag_.c:json_tag.h \ json_timeline_.c:json_timeline.h \ json_user_.c:json_user.h \ json_wiki_.c:json_wiki.h \ leaf_.c:leaf.h \ login_.c:login.h \ main_.c:main.h \ manifest_.c:manifest.h \ markdown_.c:markdown.h \ markdown_html_.c:markdown_html.h \ md5_.c:md5.h \ merge_.c:merge.h \ merge3_.c:merge3.h \ | > | 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | json_status_.c:json_status.h \ json_tag_.c:json_tag.h \ json_timeline_.c:json_timeline.h \ json_user_.c:json_user.h \ json_wiki_.c:json_wiki.h \ leaf_.c:leaf.h \ login_.c:login.h \ lookslike_.c:lookslike.h \ main_.c:main.h \ manifest_.c:manifest.h \ markdown_.c:markdown.h \ markdown_html_.c:markdown_html.h \ md5_.c:md5.h \ merge_.c:merge.h \ merge3_.c:merge3.h \ |
| ︙ | ︙ | |||
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 | user_.c:user.h \ utf8_.c:utf8.h \ util_.c:util.h \ verify_.c:verify.h \ vfile_.c:vfile.h \ wiki_.c:wiki.h \ wikiformat_.c:wikiformat.h \ winhttp_.c:winhttp.h \ wysiwyg_.c:wysiwyg.h \ xfer_.c:xfer.h \ xfersetup_.c:xfersetup.h \ zip_.c:zip.h \ $(SRCDIR)\sqlite3.h \ $(SRCDIR)\th.h \ VERSION.h \ $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers | > | 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 | user_.c:user.h \ utf8_.c:utf8.h \ util_.c:util.h \ verify_.c:verify.h \ vfile_.c:vfile.h \ wiki_.c:wiki.h \ wikiformat_.c:wikiformat.h \ winfile_.c:winfile.h \ winhttp_.c:winhttp.h \ wysiwyg_.c:wysiwyg.h \ xfer_.c:xfer.h \ xfersetup_.c:xfersetup.h \ zip_.c:zip.h \ $(SRCDIR)\sqlite3.h \ $(SRCDIR)\th.h \ VERSION.h \ $(SRCDIR)\cson_amalgamation.h @copy /Y nul: headers |
Added win/buildmsvc.bat.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
@ECHO OFF
::
:: buildmsvc.bat --
::
:: This batch file attempts to build Fossil using the latest version
:: Microsoft Visual Studio installed on this machine.
::
::
SETLOCAL
REM SET __ECHO=ECHO
REM SET __ECHO2=ECHO
IF NOT DEFINED _AECHO (SET _AECHO=REM)
IF NOT DEFINED _CECHO (SET _CECHO=REM)
IF NOT DEFINED _VECHO (SET _VECHO=REM)
REM
REM Visual Studio ????
REM
IF DEFINED VSVARS32 IF EXIST "%VSVARS32%" (
%_AECHO% Build environment batch file manually overridden to "%VSVARS32%"...
GOTO skip_detectVisualStudio
)
REM
REM Visual Studio 2013
REM
IF NOT DEFINED VS120COMNTOOLS GOTO skip_detectVisualStudio2013
SET VSVARS32=%VS120COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2013...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2013
REM
REM Visual Studio 2012
REM
IF NOT DEFINED VS110COMNTOOLS GOTO skip_detectVisualStudio2012
SET VSVARS32=%VS110COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2012...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2012
REM
REM Visual Studio 2010
REM
IF NOT DEFINED VS100COMNTOOLS GOTO skip_detectVisualStudio2010
SET VSVARS32=%VS100COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2010...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2010
REM
REM Visual Studio 2008
REM
IF NOT DEFINED VS90COMNTOOLS GOTO skip_detectVisualStudio2008
SET VSVARS32=%VS90COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2008...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2008
REM
REM Visual Studio 2005
REM
IF NOT DEFINED VS80COMNTOOLS GOTO skip_detectVisualStudio2005
SET VSVARS32=%VS80COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2005...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2005
REM
REM Visual Studio 2003
REM
IF NOT DEFINED VS71COMNTOOLS GOTO skip_detectVisualStudio2003
SET VSVARS32=%VS71COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2003...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2003
REM
REM Visual Studio 2002
REM
IF NOT DEFINED VS70COMNTOOLS GOTO skip_detectVisualStudio2002
SET VSVARS32=%VS70COMNTOOLS%\vsvars32.bat
IF EXIST "%VSVARS32%" (
%_AECHO% Using Visual Studio 2002...
GOTO skip_detectVisualStudio
)
:skip_detectVisualStudio2002
REM
REM NOTE: If we get to this point, no Visual Studio build environment batch
REM files were found.
REM
ECHO No Visual Studio build environment batch files were found.
GOTO errors
REM
REM NOTE: At this point, the appropriate Visual Studio version should be
REM selected.
REM
:skip_detectVisualStudio
REM
REM NOTE: Remove any double-backslash sequences that may be present in the
REM selected Visual Studio common tools path. This is not strictly
REM necessary; however, it makes reading the output easier.
REM
SET VSVARS32=%VSVARS32:\\=\%
%_VECHO% VsVars32 = '%VSVARS32%'
REM
REM NOTE: Setup local environment variables that point to the root directory
REM of the Fossil source checkout and to the directory containing this
REM build tool.
REM
SET ROOT=%~dp0\..
SET ROOT=%ROOT:\\=\%
SET TOOLS=%~dp0
SET TOOLS=%TOOLS:~0,-1%
%_VECHO% Root = '%ROOT%'
%_VECHO% Tools = '%TOOLS%'
REM
REM NOTE: After this point, a clean ERRORLEVEL is required; therefore, make
REM sure it is reset now.
REM
CALL :fn_ResetErrorLevel
REM
REM NOTE: Attempt to call the selected batch file to setup the environment
REM variables for building with MSVC.
REM
%__ECHO3% CALL "%VSVARS32%"
IF ERRORLEVEL 1 (
ECHO Visual Studio build environment batch file "%VSVARS32%" failed.
GOTO errors
)
REM
REM NOTE: Attempt to create the build output directory, if necessary.
REM
IF NOT EXIST "%ROOT%\msvcbld" (
%__ECHO% MKDIR "%ROOT%\msvcbld"
IF ERRORLEVEL 1 (
ECHO Could not make directory "%ROOT%\msvcbld".
GOTO errors
)
)
REM
REM NOTE: Attempt to change to the created build output directory so that
REM the generated files will be placed there.
REM
%__ECHO2% PUSHD "%ROOT%\msvcbld"
IF ERRORLEVEL 1 (
ECHO Could not change to directory "%ROOT%\msvcbld".
GOTO errors
)
REM
REM NOTE: Attempt to execute NMAKE for the Fossil MSVC makefile, passing
REM anything extra from our command line along (e.g. extra options).
REM
%__ECHO% nmake /f "%TOOLS%\Makefile.msc" %*
IF ERRORLEVEL 1 (
GOTO errors
)
REM
REM NOTE: Attempt to restore the previously saved directory.
REM
%__ECHO2% POPD
IF ERRORLEVEL 1 (
ECHO Could not restore directory.
GOTO errors
)
GOTO no_errors
:fn_ResetErrorLevel
VERIFY > NUL
GOTO :EOF
:fn_SetErrorLevel
VERIFY MAYBE 2> NUL
GOTO :EOF
:usage
ECHO.
ECHO Usage: %~nx0 [...]
ECHO.
GOTO errors
:errors
CALL :fn_SetErrorLevel
ENDLOCAL
ECHO.
ECHO Build failure, errors were encountered.
GOTO end_of_file
:no_errors
CALL :fn_ResetErrorLevel
ENDLOCAL
ECHO.
ECHO Build success, no errors were encountered.
GOTO end_of_file
:end_of_file
%__ECHO% EXIT /B %ERRORLEVEL%
|
Added win/fossil.exe.manifest.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="fossil"
type="win32" />
<description>
Simple, high-reliability, distributed software configuration management system.
</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<asmv3:application>
<asmv3:windowsSettings
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls"
version="6.0.0.0" processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df" language="*" />
</dependentAssembly>
</dependency>
</assembly>
|
Changes to win/fossil.rc.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | ** This file contains resource information for the executable on Windows. */ #if !defined(_WIN32_WCE) #include "winresrc.h" #else #include "windows.h" | | > > > > | | | | | | | | | | | | | | | | | | > > > > > | > > > | > > | | | | > > > > > > > > > > > > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
** This file contains resource information for the executable on Windows.
*/
#if !defined(_WIN32_WCE)
#include "winresrc.h"
#else
#include "windows.h"
#endif /* !defined(_WIN32_WCE) */
#if !defined(VS_FF_NONE)
# define VS_FF_NONE 0x00000000L
#endif /* !defined(VS_FF_NONE) */
#include "VERSION.h"
#define _RC_COMPILE_
#include "config.h"
#include "sqlite3.h"
#include "zlib.h"
#if defined(FOSSIL_ENABLE_SSL)
#include "openssl/opensslv.h"
#endif /* defined(FOSSIL_ENABLE_SSL) */
#if defined(FOSSIL_ENABLE_TCL)
#include "tcl.h"
#endif /* defined(FOSSIL_ENABLE_TCL) */
#if defined(FOSSIL_ENABLE_JSON)
#include "json_detail.h"
#endif /* defined(FOSSIL_ENABLE_JSON) */
/*
* English (U.S.) resources
*/
#if defined(_WIN32)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif /* defined(_WIN32) */
/*
* Icon
*/
#define IDI_FOSSIL 8001
IDI_FOSSIL ICON "fossil.ico"
/*
* Version
*/
VS_VERSION_INFO VERSIONINFO
FILEVERSION RELEASE_RESOURCE_VERSION
PRODUCTVERSION RELEASE_RESOURCE_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#if defined(_DEBUG)
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS VS_FF_NONE
#endif /* defined(_DEBUG) */
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Fossil Development Team\0"
VALUE "FileDescription", "Simple, high-reliability, distributed software configuration management system.\0"
VALUE "ProductName", "Fossil\0"
VALUE "ProductVersion", "Fossil " RELEASE_VERSION " " MANIFEST_VERSION " " MANIFEST_DATE " UTC\0"
VALUE "FileVersion", "Fossil " RELEASE_VERSION " " MANIFEST_VERSION " " MANIFEST_DATE " UTC\0"
VALUE "InternalName", "fossil\0"
VALUE "LegalCopyright", "Copyright © " MANIFEST_YEAR " by D. Richard Hipp. All rights reserved.\0"
VALUE "OriginalFilename", "fossil.exe\0"
VALUE "CompilerName", COMPILER_NAME "\0"
VALUE "SQLiteVersion", "SQLite " SQLITE_VERSION " " SQLITE_SOURCE_ID "\0"
VALUE "ZlibVersion", "zlib " ZLIB_VERSION "\0"
#if defined(BROKEN_MINGW_CMDLINE)
VALUE "CommandLineIsUnicode", "No\0"
#else
VALUE "CommandLineIsUnicode", "Yes\0"
#endif /* defined(BROKEN_MINGW_CMDLINE) */
#if defined(FOSSIL_ENABLE_SSL)
VALUE "SslEnabled", "Yes, " OPENSSL_VERSION_TEXT "\0"
#endif /* defined(FOSSIL_ENABLE_SSL) */
#if defined(FOSSIL_ENABLE_TCL)
VALUE "TclEnabled", "Yes, Tcl " TCL_PATCH_LEVEL "\0"
#if defined(USE_TCL_STUBS)
VALUE "UseTclStubsEnabled", "Yes\0"
#else
VALUE "UseTclStubsEnabled", "No\0"
#endif /* defined(USE_TCL_STUBS) */
#if defined(FOSSIL_ENABLE_TCL_STUBS)
VALUE "TclStubsEnabled", "Yes\0"
#else
VALUE "TclStubsEnabled", "No\0"
#endif /* defined(FOSSIL_ENABLE_TCL_STUBS) */
#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS)
VALUE "TclPrivateStubsEnabled", "Yes\0"
#else
VALUE "TclPrivateStubsEnabled", "No\0"
#endif /* defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) */
#endif /* defined(FOSSIL_ENABLE_TCL) */
#if defined(FOSSIL_ENABLE_JSON)
VALUE "JsonEnabled", "Yes, cson " FOSSIL_JSON_API_VERSION "\0"
#endif /* defined(FOSSIL_ENABLE_JSON) */
VALUE "MarkdownEnabled", "Yes\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END
/*
* This embedded manifest is needed for Windows 8.1.
*/
#ifndef RT_MANIFEST
#define RT_MANIFEST 24
#endif
#ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#endif
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "fossil.exe.manifest"
|
Added www/adding_code.wiki.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
<title>Adding Features To Fossil</title>
<h2>1.0 Introduction</h2>
This article provides a brief overview of how to write new code that extends
or enhances Fossil.
<h2>2.0 Programming Language</h2>
Fossil is written in C-89. There are specific [./style.wiki | style guidelines]
that are required for any new code that will be accepted into the Fossil core.
But, of course, if you are writing an extension just for yourself, you can
use any programming style you want.
The source code for Fossil is not sent directly into the C compiler.
There are three separate code [./makefile.wiki#preprocessing|preprocessors]
that run over the code first.
1. The <b>mkindex</b> preprocessor scans all regular source files looking
for special comments that contain "help" text and which identify routines
that implement specific commands or which generate particular web pages.
2. The <b>makeheaders</b> preprocessor generates all the ".h" files
automatically. Fossil programmers write ".c" files only and let the
makeheaders preprocessor create the ".h" files.
3. The <b>translate</b> preprocessor converts source code lines that
begin with "@" into string literals, or into print statements that
generate web page output, depending on context.
The [./makefile.wiki|Makefile] for Fossil takes care of running these
preprocessors with all the right arguments and in the right order. So it is
not necessary to understand the details of how these preprocessors work.
(Though, the sources for all three preprocessors are included in the source
tree and are well commented, if you want to dig deeper.) It is only necessary
to know that these preprocessors exist and hence will effect the way you
write code.
<h2>3.0 Adding New Source Code Files</h2>
New source code files are added in the "src/" subdirectory of the Fossil
source tree. Suppose one wants to add a new source code file named
"xyzzy.c". The first step is to add this file to the various makefiles.
Do so by editing the file src/makemake.tcl and adding "xyzzy" (without
the final ".c") to the list of source modules at the top of that script.
Save the result and then run the makemake.tcl script using a TCL
interpreter. The command to run the makemake.tcl script is:
<b>tclsh makemake.tcl</b>
The working directory must be src/ when the command above is run.
Note that TCL is not normally required to build Fossil, but
it is required for this step. If you do not have a TCL interpreter on
your system already, they are easy to install. A popular choice is the
[http://www.activestate.com/activetcl|Active Tcl] installation from
ActiveState.
After the makefiles have been updated, create the xyzzy.c source file
from the following template:
<blockquote><verbatim>
/*
** Copyright boilerplate goes here.
*****************************************************
** High-level description of what this module goes
** here.
*/
#include "config.h"
#include "xyzzy.h"
#if INTERFACE
/* Exported object (structure) definitions or #defines
** go here */
#endif /* INTEFACE */
/* New code goes here */
</verbatim></blockquote>
Note in particular the <b>#include "xyzzy.h"</b> line near the top.
The "xyzzy.h" file is automatically generated by makeheaders. Every
normal Fossil source file must have a #include at the top that imports
its private header file. (Some source files, such as "sqlite3.c" are
exceptions to this rule. Don't worry about those exceptions. The
files you write will require this #include line.)
The "#if INTERFACE ... #endif" section is optional and is only needed
if there are structure definitions or typedefs or macros that need to
be used by other source code files. The makeheaders preprocessor
uses definitions in the INTERFACE section to help it generate header
files. See [../src/makeheaders.html | makeheaders.html] for additional
information.
After creating a template file such as shown above, and after updating
the makefiles, you should be able to recompile Fossil and have it include
your new source file, even before you source file contains any code.
It is recommended that you try this.
Be sure to [/help/add|fossil add] your new source file to the self-hosting
Fossil repository and then [/help/commit|commit] your changes!
<h2>4.0 Creating A New Command</h2>
By "commands" we mean the keywords that follow "fossil" when invoking
Fossil from the command-line. So, for example, in
<b>fossil diff xyzzy.c</b>
The "command" is "diff". Commands may optionally be followed by
arguments and/or options. To create new commands in Fossil, add code
(either to an existing source file, or to a new source file created as
described above) according to the following template:
<blockquote><verbatim>
/*
** COMMAND: xyzzy
**
** Help text goes here.
*/
void xyzzy_cmd(void){
/* Implement the command here */
fossil_print("Hello, World!\n");
}
</verbatim></blockquote>
The example above creates a new command named "xyzzy" that prints the
message "Hello, World!" on the console. This command is a normal command
that will show up in the list of command from [/help/help|fossil help].
If you add an asterisk to the end of the command name, like this:
<blockquote><verbatim>
** COMMAND: xyzzy*
</verbatim></blockquote>
Then the command will only show up if you add the "--all" option to
[/help/help|fossil help]. Or, if the command name starts with
"test" then the command will be considered experimental and will only
show up when the --test option is used with [/help/help|fossil help].
The example above is a fully functioning Fossil command. You can add
the text shown to an existing Fossil source file, recompiling then test
it out by typing:
<b>./fossil xyzzy<br>
./fossil help xyzzy<br>
./fossil xyzzy --help</b>
The name of the C function that implements the command can be anything
you like (as long as it does not collide with some other symbol in the
Fossil code) but it is traditional to name the function
"<i>commandname</i><b>_cmd</b>", as is done in the example.
You could also use "printf()" instead of "fossil_print()" to generate
the output text, if desired. But "fossil_print()" is recommended as
it has extra logic to insert \r characters at the right times on
windows systems.
Once you have the command running, you can then start adding code to
make it do useful things. There are lots of utility functions in
Fossil for parsing command-line options and for
opening and accessing and manipulating the repository and
the working check-out. Study implementations of existing commands
to get an idea of how things are done. You can easily find the implementations
of existing commands by searching for "COMMAND: <i>name</i>" in the
files of the "src/" directory.
<h2>5.0 Creating A New Web Page</h2>
As with commands, new webpages can be added simply by inserting a function
that generates the webpage together with a special header comment. A
template follows:
<blockquote><verbatim>
/*
** WEBPAGE: helloworld
*/
void helloworld_page(void){
style_header("Hello World!");
@ <p>Hello, World!</p>
style_footer();
}
</verbatim></blockquote>
Add the code above to a new or existing Fossil source code file, then
recompile fossil and run [/help/ui|fossil ui] then enter
"http://localhost:8080/helloworld" in your web browser and the routine
above will generate a web page that says "Hello World."
It really is that simple.
The special "WEBPAGE:" comment is picked up by the "mkindex" preprocessor
and used to generate a table that maps the "helloworld" webpage name
into a pointer to the "helloworld_page()" function. The function that
implements a webpage can be named anything you like (as long as it does
not collide with another name) but the traditional name is
"<i>pagename</i><b>_page</b>".
HTML pages begin with a call to style_header() and end with the call to
style_footer(). Content is generated by the "@" lines that are translated
(by the "translate" preprocessor) into printf-like code that generates the
content of the webpage. Different techniques are used to generate
non-HTML content. In the unlikely event that you need to generate
non-HTML content, look at existing webpage implementations
(ex: "logo" or "style.css") to see how that is done.
There are lots of other things that a real web-page implementation will
need to do, such verifying user credentials, parsing query parameters,
and interacting with the repository. But now that you have the general
idea of how webpages are implemented, you can look at the many other
webpage implementations already built into Fossil to see how all that
works.
<h2>6.0 See Also</h2>
* [./makefile.wiki|The Fossil Build Process]
* [./tech_overview.wiki|A Technical Overview Of Fossil]
* [./contribute.wiki|Contributing To The Fossil Project]
|
Changes to www/build.wiki.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | <h2>0.1 Executive Summary</h2> <p>Building and installing is very simple. Three steps:</p> <ol> <li> Download and unpack a source tarball or ZIP. <li> <b>./configure; make</b> | | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <h2>0.1 Executive Summary</h2> <p>Building and installing is very simple. Three steps:</p> <ol> <li> Download and unpack a source tarball or ZIP. <li> <b>./configure; make</b> <li> Move the resulting "fossil" or "fossil.exe" executable to someplace on your $PATH. </ol> <p><hr> <h2>1.0 Obtaining The Source Code</h2> <p>Fossil is self-hosting, so you can obtain a ZIP archive or tarball |
| ︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | link.</p></li> <li><p>Finally, click on one of the "Zip Archive" or "Tarball" links, according to your preference. These link will build a ZIP archive or a gzip-compressed tarball of the complete source code and download it to your browser. </ol> <h2>2.0 Compiling</h2> <ol> <li value="5"> <p>Unpack the ZIP or tarball you downloaded then <b>cd</b> into the directory created.</p></li> | > > > > > > > > > > > > > > > > > > > > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | link.</p></li> <li><p>Finally, click on one of the "Zip Archive" or "Tarball" links, according to your preference. These link will build a ZIP archive or a gzip-compressed tarball of the complete source code and download it to your browser. </ol> <h2>Aside: Is it really safe to use an unreleased development version of the Fossil source code?</h2> Yes! Any check-in on the [/timeline?t=trunk | trunk branch] of the Fossil [http://fossil-scm.org/fossil/timeline | Fossil self-hosting repository] will work fine. (Dodgy code is always on a branch.) In the unlikely event that you pick a version with a serious bug, it still won't clobber your files. Fossil uses several [./selfcheck.wiki | self-checks] prior to committing any repository change that prevent loss-of-work due to bugs. The Fossil [./selfhost.wiki | self-hosting repositories], especially the one at [http://www.fossil-scm.org/fossil], usually run a version of trunk that is less than a week or two old. Look at the bottom right-hand corner of this screen (to the right of "This page was generated in...") to see exactly which version of Fossil is rendering this page. It is always safe to use whatever version of the Fossil code you find running on the main Fossil website. <h2>2.0 Compiling</h2> <ol> <li value="5"> <p>Unpack the ZIP or tarball you downloaded then <b>cd</b> into the directory created.</p></li> |
| ︙ | ︙ | |||
90 91 92 93 94 95 96 | <li><p><i>MinGW/MinGW-w64</i> → Use the mingw makefile: "<b>make -f win/Makefile.mingw</b>". On a Windows box you will need either Cygwin or Msys as build environment. On Cygwin, Linux or Darwin you may want to make minor edits to win/Makefile.mingw to configure the cross-compile environment. | | | > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
<li><p><i>MinGW/MinGW-w64</i> → Use the mingw makefile:
"<b>make -f win/Makefile.mingw</b>". On a Windows box you will
need either Cygwin or Msys as build environment. On Cygwin, Linux
or Darwin you may want to make minor edits to win/Makefile.mingw
to configure the cross-compile environment.
<li><p><i>MSVC</i> → Use the msc makefile. First
change to the "win/" subdirectory ("<b>cd win</b>") then run
"<b>nmake /f Makefile.msc</b>". Alternatively, the batch file
"<b>win\buildmsvc.bat</b>" may be used and it will attempt to
detect and use the latest installed version of MSVC.
</ol>
</ol>
<h2>3.0 Installing</h2>
<ol>
<li value="8">
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 127 128 129 130 131 132 133 | <li><p> If the makefiles that come with Fossil do not work for you, or for some other reason you want to know how to build Fossil manually, then refer to the [./makefile.wiki | Fossil Build Process] document which describes in detail what the makefiles do behind the scenes. <li><p> To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile generated by configure to add the following lines: <blockquote><pre> TCC += -DSQLITE_WITHOUT_ZONEMALLOC TCC += -DWITHOUT_ICONV TCC += -Dsocketlen_t=int | > > > > > > > > | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | <li><p> If the makefiles that come with Fossil do not work for you, or for some other reason you want to know how to build Fossil manually, then refer to the [./makefile.wiki | Fossil Build Process] document which describes in detail what the makefiles do behind the scenes. <li><p> The fossil executable is self-contained and stand-alone and usually requires no special libraries or other software to be installed. However, the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk be installed on the local machine. You can get Tcl/Tk from [http://www.activestate.com/activetcl|ActiveState]. <li><p> To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile generated by configure to add the following lines: <blockquote><pre> TCC += -DSQLITE_WITHOUT_ZONEMALLOC TCC += -DWITHOUT_ICONV TCC += -Dsocketlen_t=int TCC += -DSQLITE_MAX_MMAP_SIZE=0 </pre></blockquote> </ul> |
Changes to www/changes.wiki.
1 2 3 4 5 6 7 8 |
<title>Change Log</title>
<h2>Changes For Version 1.26 (2013-06-18)</h2>
* The argument to the --port option for the [/help?cmd=ui | fossil ui] and
[/help?cmd=server | fossil server] commands can take an IP address in addition
to the port number, causing Fossil to bind to just that one IP address.
* After prompting for a password, also ask if that password should be
remembered.
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
<title>Change Log</title>
<h2>Changes For Version 1.29 (as yet unreleased)</h2>
* Add the ability to display content and diffs for UTF16 text files
in the web interface.
* Honor timezones in imports from git.
* The [/reports] page now requires Read ("o") permissions. The "byweek"
report now properly propagates the selected year through the event type
filter links.
* The [/help/info | info command] now shows leaf status of the checkout.
* Add support for tunneling https through a http proxy (Ticket [e854101c4f]).
<h2>Changes For Version 1.28 (2014-01-27)</h2>
* Enhance [/help?cmd=/reports | /reports] to support event type filtering.
* When cloning a repository, the user name passed via the URL (if any)
is now used as the default local admin user's name.
* Enhance the SSH transport mechanism so that it runs a single instance of
the "fossil" executable on the remote side, obviating the need for a shell
on the remote side. Some users may need to add the "?fossil=/path/to/fossil"
query parameter to "ssh:" URIs if their fossil binary is not in a standard
place.
* Add the "[/help?cmd=blame | fossil blame]" command that works just like
"fossil annotate" but uses a different output format that includes the
user who made each changes and omits line numbers.
* Add the "Tarball and ZIP-archive Prefix" configuration parameter under
Admin/Configuration.
* Fix CGI processing so that it works on web servers that do not
supply REQUEST_URI.
* Add options --dirsonly, --emptydirs, and --allckouts to the
"[/help?cmd=clean | fossil clean]" command.
* Ten-fold performance improvement in large "fossil blame" or
"fossil annotate" commands.
* Add option -W|--width and --offset to "[/help?cmd=timeline | fossil timeline]"
and "[/help?cmd=finfo | fossil finfo]" commands.
* Option -n|--limit of "[/help?cmd=timeline | fossil timeline]" now
specifies the number of entries, just like all other commands which
have the -n|--limit option. The various timeline-related functions
now output "--- ?? limit (??) reached ---" at the end whenever
appropriate. Use "-n 0" if no limit is desired.
* Fix handling of password embedded in Fossil URL.
* New <tt>--once</tt> option to [/help?cmd=clone | fossil clone] command
which does not store the URL or password when cloning.
* Modify [/help?cmd=ui | fossil ui] to respect "default user" in an open
repository.
* Fossil now hides check-ins that have the "hidden" tag in timeline webpages.
* Enhance <tt>/ci_edit</tt> page to add the "hidden" tag to check-ins.
* Advanced possibilities for commit and ticket change notifications over
http using TH1 scripting.
* Add --sha1sum and --integrate options
to the "[/help?cmd=commit | fossil commit]" command.
* Add the "clean" and "extra" subcommands to the
"[/help?cmd=all | fossil all]" command
* Add the --whatif option to "[/help?cmd=clean|fossil clean]" that works the
same as "--dry-run",
so that the name does not collide with the --dry-run option of "fossil all".
* Provide a configuration option to show dates on the web timeline
as "YYMMMDD HH:MM"
* Add an option to the "stats" webpage that allows an administrator to see
the current repository schema.
* Enhancements to the "[/help?cmd=/vdiff|/vdiff]" webpage for more difference
display options.
* Added the "[/tree?ci=trunk&expand | /tree]" webpage as an alternative
to "/dir" and make it the default way of showing file lists.
* Send gzipped HTTP responses to clients that support it.
<h2>Changes For Version 1.27 (2013-09-11)</h2>
* Enhance the [/help?cmd=changes | fossil changes],
[/help?cmd=clean | fossil clean], [/help?cmd=extras | fossil extras],
[/help?cmd=ls | fossil ls] and [/help?cmd=status | fossil status] commands
to restrict operation to files and directories named on the command-line.
* New --integrate option to [/help?cmd=merge | fossil merge], which
automatically closes the merged branch when committing.
* Renamed <tt>/stats_report</tt> page to [/reports]. Graph width is now
relative, not absolute.
* Added <tt>yw=YYYY-WW</tt> (year-week) filter to timeline to limit the results
to a specific year and calendar week number, e.g. [/timeline?yw=2013-01].
* Updates to SQLite to prevent opening a repository file using file descriptors
1 or 2 on unix. This fixes a bug under which an assertion failure could
overwrite part of a repository database file, corrupting it.
* Added support for unlimited line lengths in side-by-side diffs.
* New --close option to [/help?cmd=commit | fossil commit], which
immediately closes the branch being committed.
* Added <tt>chart</tt> option to [/help?cmd=bisect | fossil bisect].
* Improvements to the "human or bot?" determination.
* Reports errors about missing CGI-standard environment variables for HTTP
servers which do not support them.
* Minor improvements to sync support on Windows.
* Added <tt>--scgi</tt> option to [/help?cmd=server | fossil server].
* Internal improvements to the sync process.
* The internals of the JSON API are now MIT-licensed, so downstream
users/packagers are no longer affected by the "do no evil" license
clause.
<h2>Changes For Version 1.26 (2013-06-18)</h2>
* The argument to the --port option for the [/help?cmd=ui | fossil ui] and
[/help?cmd=server | fossil server] commands can take an IP address in addition
to the port number, causing Fossil to bind to just that one IP address.
* After prompting for a password, also ask if that password should be
remembered.
|
| ︙ | ︙ |
Changes to www/concepts.wiki.
| ︙ | ︙ | |||
77 78 79 80 81 82 83 | at a repository and get human-readable status, history, and tracking information about the project. <h3>2.1 Identification Of Artifacts</h3> A particular version of a particular file is called an "artifact". Each artifact has a universally unique name which is the | | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | at a repository and get human-readable status, history, and tracking information about the project. <h3>2.1 Identification Of Artifacts</h3> A particular version of a particular file is called an "artifact". Each artifact has a universally unique name which is the <a href="http://en.wikipedia.org/wiki/SHA1">SHA1</a> hash of the content of that file expressed as 40 characters of lower-case hexadecimal. Such a hash is referred to as the Artifact Identifier or Artifact ID for the artifact. The SHA1 algorithm is created with the purpose of providing a highly forgery-resistant identifier for a file. Given any file it is simple to find the artifact ID for that file. But given a artifact ID it is computationally intractable to generate a file that will have that Artifact ID. |
| ︙ | ︙ |
Changes to www/contribute.wiki.
| ︙ | ︙ | |||
76 77 78 79 80 81 82 | <h2>5.0 See Also</h2> * [./build.wiki | How To Compile And Install Fossil] * [./makefile.wiki | The Fossil Build Process] * [./tech_overview.wiki | A Technical Overview of Fossil] | > | 76 77 78 79 80 81 82 83 | <h2>5.0 See Also</h2> * [./build.wiki | How To Compile And Install Fossil] * [./makefile.wiki | The Fossil Build Process] * [./tech_overview.wiki | A Technical Overview of Fossil] * [./adding_code.wiki | Adding Features To Fossil] |
Changes to www/embeddeddoc.wiki.
| ︙ | ︙ | |||
101 102 103 104 105 106 107 | CGI mode. The "index.html" CGI script looks like this: <blockquote><pre> #!/usr/bin/fossil repository: /fossil/fossil.fossil </pre></blockquote> | | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | CGI mode. The "index.html" CGI script looks like this: <blockquote><pre> #!/usr/bin/fossil repository: /fossil/fossil.fossil </pre></blockquote> This is one of four ways to set up a <a href="./server.wiki">fossil web server</a>. The "<b>/trunk/</b>" part of the URL tells fossil to use the documentation files from the most recent trunk check-in. If you wanted to see an historical version of this document, you could substitute the name of a check-in for "<b>/trunk/</b>". For example, to see the version of this document associated with check-in [9be1b00392], simply replace the "<b>/trunk/</b>" with |
| ︙ | ︙ |
Changes to www/faq.tcl.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
faq {
How do I create a new branch?
} {
There are lots of ways:
When you are checking in a new change using the <b>[/help/commit|commit]</b>
command, you can add the option "--branch <i>BRANCH-NAME</i>" to
| | < < | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
faq {
How do I create a new branch?
} {
There are lots of ways:
When you are checking in a new change using the <b>[/help/commit|commit]</b>
command, you can add the option "--branch <i>BRANCH-NAME</i>" to
make the new check-in be the first check-in for a new branch.
If you want to create a new branch whose initial content is the
same as an existing check-in, use this command:
<blockquote>
<b>fossil [/help/branch|branch] new</b> <i>BRANCH-NAME BASIS</i>
</blockquote>
|
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
faq {
How do I tag a check-in?
} {
There are several ways:
When you are checking in a new change using the <b>[/help/commit|commit]</b>
command, you can add a tag to that check-in using the
| | > > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
faq {
How do I tag a check-in?
} {
There are several ways:
When you are checking in a new change using the <b>[/help/commit|commit]</b>
command, you can add a tag to that check-in using the
"--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag
option to give a check-in multiple tags. Tags need not be unique. So,
for example, it is common to give every released version a "release" tag.
If you want add a tag to an existing check-in, you can use the
<b>[/help/tag|tag]</b> command. For example:
<blockquote>
<b>fossil [/help/branch|tag] add</b> <i>TAGNAME</i> <i>CHECK-IN</i>
</blockquote>
|
| ︙ | ︙ |
Changes to www/faq.wiki.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 | <a name="q3"></a> <p><b>(3) How do I create a new branch?</b></p> <blockquote>There are lots of ways: When you are checking in a new change using the <b>[/help/commit|commit]</b> command, you can add the option "--branch <i>BRANCH-NAME</i>" to | | < < | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <a name="q3"></a> <p><b>(3) How do I create a new branch?</b></p> <blockquote>There are lots of ways: When you are checking in a new change using the <b>[/help/commit|commit]</b> command, you can add the option "--branch <i>BRANCH-NAME</i>" to make the new check-in be the first check-in for a new branch. If you want to create a new branch whose initial content is the same as an existing check-in, use this command: <blockquote> <b>fossil [/help/branch|branch] new</b> <i>BRANCH-NAME BASIS</i> </blockquote> |
| ︙ | ︙ | |||
71 72 73 74 75 76 77 | <a name="q4"></a> <p><b>(4) How do I tag a check-in?</b></p> <blockquote>There are several ways: When you are checking in a new change using the <b>[/help/commit|commit]</b> command, you can add a tag to that check-in using the | | > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | <a name="q4"></a> <p><b>(4) How do I tag a check-in?</b></p> <blockquote>There are several ways: When you are checking in a new change using the <b>[/help/commit|commit]</b> command, you can add a tag to that check-in using the "--tag <i>TAGNAME</i>" command-line option. You can repeat the --tag option to give a check-in multiple tags. Tags need not be unique. So, for example, it is common to give every released version a "release" tag. If you want add a tag to an existing check-in, you can use the <b>[/help/tag|tag]</b> command. For example: <blockquote> <b>fossil [/help/branch|tag] add</b> <i>TAGNAME</i> <i>CHECK-IN</i> </blockquote> |
| ︙ | ︙ |
Changes to www/fileformat.wiki.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 | <li> [#ctrl | Control Artifacts] </li> <li> [#wikichng | Wiki Pages] </li> <li> [#tktchng | Ticket Changes] </li> <li> [#attachment | Attachments] </li> <li> [#event | Events] </li> </ul> | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <li> [#ctrl | Control Artifacts] </li> <li> [#wikichng | Wiki Pages] </li> <li> [#tktchng | Ticket Changes] </li> <li> [#attachment | Attachments] </li> <li> [#event | Events] </li> </ul> These seven artifact types are described in the following sections. In the current implementation (as of 2009-01-25) the artifacts that make up a fossil repository are stored in in as delta- and zlib-compressed blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This is an implementation detail and might change in a future release. For the purpose of this article "file format" means the format of the artifacts, not how the artifacts are stored on disk. It is the artifact format that |
| ︙ | ︙ | |||
96 97 98 99 100 101 102 | Allowed cards in the manifest are as follows: <blockquote> <b>B</b> <i>baseline-manifest</i><br> <b>C</b> <i>checkin-comment</i><br> <b>D</b> <i>time-and-date-stamp</i><br> | | | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | Allowed cards in the manifest are as follows: <blockquote> <b>B</b> <i>baseline-manifest</i><br> <b>C</b> <i>checkin-comment</i><br> <b>D</b> <i>time-and-date-stamp</i><br> <b>F</b> <i>filename</i> ?<i>SHA1-hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br> <b>N</b> <i>mimetype</i><br> <b>P</b> <i>SHA1-hash</i>+<br> <b>Q</b> (<b>+</b>|<b>-</b>)<i>SHA1-hash</i> ?<i>SHA1-hash</i>?<br> <b>R</b> <i>repository-checksum</i><br> <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br> <b>U</b> <i>user-login</i><br> <b>Z</b> <i>manifest-checksum</i> </blockquote> A manifest may optionally have a single B-card. The B-card specifies another manifest that serves as the "baseline" for this manifest. A manifest that has a B-card is called a delta-manifest and a manifest |
| ︙ | ︙ | |||
209 210 211 212 213 214 215 | character (ASCII 0x0A), and the complete text of the file. Compute the MD5 checksum of the result. A manifest might contain one or more T-cards used to set [./branching.wiki#tags | tags or properties] on the check-in. The format of the T-card is the same as described in <i>Control Artifacts</i> section below, except that the | | | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | character (ASCII 0x0A), and the complete text of the file. Compute the MD5 checksum of the result. A manifest might contain one or more T-cards used to set [./branching.wiki#tags | tags or properties] on the check-in. The format of the T-card is the same as described in <i>Control Artifacts</i> section below, except that the second argument is the single character "<b>*</b>" instead of an artifact ID. The <b>*</b> in place of the artifact ID indicates that the tag or property applies to the current artifact. It is not possible to encode the current artifact ID as part of an artifact, since the act of inserting the artifact ID would change the artifact ID, hence a <b>*</b> is used to represent "self". T-cards are typically added to manifests in order to set the <b>branch</b> property and a symbolic name when the check-in is intended to start a new branch. |
| ︙ | ︙ | |||
289 290 291 292 293 294 295 | the card type and the arguments. No surplus whitespace is allowed. All cards must occur in strict lexicographical order. Allowed cards in a control artifact are as follows: <blockquote> <b>D</b> <i>time-and-date-stamp</i><br /> | | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | the card type and the arguments. No surplus whitespace is allowed. All cards must occur in strict lexicographical order. Allowed cards in a control artifact are as follows: <blockquote> <b>D</b> <i>time-and-date-stamp</i><br /> <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br /> <b>U</b> <i>user-name</i><br /> <b>Z</b> <i>checksum</i><br /> </blockquote> A control artifact must have one D card, one U card, one Z card and one or more T cards. No other cards or other text is allowed in a control artifact. Control artifacts might be PGP clearsigned. The D card and the Z card of a control artifact are the same as in a manifest. |
| ︙ | ︙ | |||
473 474 475 476 477 478 479 | <blockquote> <b>C</b> <i>comment</i><br> <b>D</b> <i>time-and-date-stamp</i><br /> <b>E</b> <i>event-time</i> <i>event-id</i><br /> <b>N</b> <i>mimetype</i><br /> <b>P</b> <i>parent-artifact-id</i>+<br /> | | | | | | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | <blockquote> <b>C</b> <i>comment</i><br> <b>D</b> <i>time-and-date-stamp</i><br /> <b>E</b> <i>event-time</i> <i>event-id</i><br /> <b>N</b> <i>mimetype</i><br /> <b>P</b> <i>parent-artifact-id</i>+<br /> <b>T</b> <b>+</b><i>tag-name</i> <b>*</b> ?<i>value</i>?<br /> <b>U</b> <i>user-name</i><br /> <b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br /> <b>Z</b> <i>checksum</i> </blockquote> The C card contains text that is displayed on the timeline for the event. The C card is optional, but there can only be one. A single D card is required to give the date and time when the event artifact was created. This is different from the time at which the event occurs. A single E card gives the time of the event (the point on the timeline where the event is displayed) and a unique identifier for the event. When there are multiple artifacts with the same event-id, the one with the most recent D card is the only one used. The event-id must be a 40-character lower-case hexadecimal string. The optional N card specifies the mimetype of the text of the event that is contained in the W card. If the N card is omitted, then the W card text mimetype is assumed to be text/x-fossil, which is the Fossil wiki format. The optional P card specifies a prior event with the same event-id from which the current event is an edit. The P card is a hint to the system that it might be space efficient to store one event as a delta of the other. An event might contain one or more T-cards used to set [./branching.wiki#tags | tags or properties] on the event. The format of the T-card is the same as described in [#ctrl | Control Artifacts] section above, except that the second argument is the single character "<b>*</b>" instead of an artifact ID and the name is always prefaced by "<b>+</b>". The <b>*</b> in place of the artifact ID indicates that the tag or property applies to the current artifact. It is not possible to encode the current artifact ID as part of an artifact, since the act of inserting the artifact ID would change the artifact ID, hence a <b>*</b> is used to represent "self". The "<b>+</b>" on the name means that tags can only be add and they can only be non-propagating |
| ︙ | ︙ | |||
529 530 531 532 533 534 535 | The Z card is the required checksum over the rest of the artifact. <a name="summary"></a> <h2>8.0 Card Summary</h2> | | | > > > > | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 |
The Z card is the required checksum over the rest of the artifact.
<a name="summary"></a>
<h2>8.0 Card Summary</h2>
The following table summarizes the various kinds of cards that appear
on Fossil artifacts. A blank entry means that combination of card and
artifact is not legal. A number or range of numbers indicates the number
of times a card may (or must) appear in the corresponding artifact type.
e.g. a value of 1 indicates a required unique card and 1+ indicates that one
or more such cards are required.
<table border=1 width="100%">
<tr>
<th rowspan=2 valign=bottom>Card Format</th>
<th colspan=7>Used By</th>
</tr>
<tr>
<th>Manifest</th>
<th>Cluster</th>
<th>Control</th>
<th>Wiki</th>
<th>Ticket</th>
<th>Attachment</th>
<th>Event</th>
</tr>
<tr>
<td><b>A</b> <i>filename</i> <i>target</i> ?<i>source</i>?</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td align=center><b>1</b></td>
<td> </td>
</tr>
<tr>
<td><b>B</b> <i>baseline</i></td>
<td align=center><b>0-1*</b></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr><td> </td><td colspan='7'>* = Required for delta manifests</td></tr>
<tr>
<td><b>C</b> <i>comment-text</i></td>
<td align=center><b>1</b></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td align=center><b>0-1</b></td>
<td align=center><b>0-1</b></td>
</tr>
<tr>
<td><b>D</b> <i>date-time-stamp</i></td>
<td align=center><b>1</b></td>
<td> </td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
</tr>
<tr>
<td><b>E</b> <i>event-time event-id</i></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td align=center><b>1</b></td>
</tr>
<tr>
<td><b>F</b> <i>filename</i> ?<i>uuid</i>? ?<i>permissions</i>? ?<i>oldname</i>?</td>
<td align=center><b>0+</b></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td><b>J</b> <i>name</i> ?<i>value</i>?</td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td align=center><b>1+</b></td>
<td> </td>
<td> </td>
</tr>
<tr>
<td><b>K</b> <i>ticket-uuid</i></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td align=center><b>1</b></td>
<td> </td>
<td> </td>
</tr>
<tr>
<td><b>L</b> <i>wiki-title</i></td>
<td> </td>
<td> </td>
<td> </td>
<td align=center><b>1</b></td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td><b>M</b> <i>uuid</i></td>
<td> </td>
<td align=center><b>1+</b></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td><b>N</b> <i>mimetype</i></td>
<td align=center><b>0-1</b></td>
<td> </td>
<td> </td>
<td align=center><b>0-1</b></td>
<td> </td>
<td align=center><b>0-1</b></td>
<td align=center><b>0-1</b></td>
</tr>
<tr>
<td><b>P</b> <i>uuid ...</i></td>
<td align=center><b>0-1</b></td>
<td> </td>
<td> </td>
<td align=center><b>0-1</b></td>
<td> </td>
<td> </td>
<td align=center><b>0-1</b></td>
</tr>
<tr>
<td><b>Q</b> (<b>+</b>|<b>-</b>)<i>uuid</i> ?<i>uuid</i>?</td>
<td align=center><b>0+</b></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td><b>R</b> <i>md5sum</i></td>
<td align=center><b>0-1</b></td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<tr>
<td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname</i> <i>uuid</i> ?<i>value</i>?</td>
<td align=center><b>0+</b></td>
<td> </td>
<td align=center><b>1+</b></td>
<td> </td>
<td> </td>
<td> </td>
<td align=center><b>0+</b></td>
</tr>
<tr>
<td><b>U</b> <i>username</i></td>
<td align=center><b>1</b></td>
<td> </td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>0-1</b></td>
<td align=center><b>0-1</b></td>
</tr>
<tr>
<td><b>W</b> <i>size</i></td>
<td> </td>
<td> </td>
<td> </td>
<td align=center><b>1</b></td>
<td> </td>
<td> </td>
<td align=center><b>1</b></td>
</tr>
<tr>
<td><b>Z</b> <i>md5sum</i></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
<td align=center><b>1</b></td>
</tr>
</table>
<a name="addenda"></a>
<h2>9.0 Addenda</h2>
This section contains additional information which may be useful when
implementing algorithms described above.
<h3>R Card Hash Calculation</h3>
Given a manifest file named <tt>MF</tt>, the following Bash shell code
demonstrates how to compute the value of the R card in that manifest.
This example uses manifest [28987096ac]. Lines starting with <tt>#</tt> are
shell input and other lines are output. This demonstration assumes that the
file versions represented by the input manifest are checked out
under the current directory.
<nowiki><pre>
# head MF
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Make\sthe\s"clearsign"\sPGP\ssigning\sdefault\sto\soff.
D 2010-02-23T15:33:14
F BUILD.txt 4f7988767e4e48b29f7eddd0e2cdea4555b9161c
F COPYRIGHT-GPL2.txt 06877624ea5c77efe3b7e39b0f909eda6e25a4ec
...
# grep '^R ' MF
R c0788982781981c96a0d81465fec7192
# for i in $(awk '/^F /{print $2}' MF); do \
echo $i $(stat -c '%s' $i); \
cat $i; \
done | md5sum
c0788982781981c96a0d81465fec7192 -
</pre></nowiki>
Minor caveats: the above demonstration will work only when none of the
filenames in the manifest are "fossilized" (encoded) because they contain
spaces. In that case the shell-generated hash would differ because the
<tt>stat</tt> calls will fail to find such files (which are output in encoded
form here). That approach also won't work for delta manifests. Calculating
the R-card for delta manifests requires traversing both the delta and its baseline in
lexical order of the files, preferring the delta's copy if both contain
a given file.
|
Changes to www/fossil-v-git.wiki.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 | <h2>3.0 Discussion</h2> <h3>3.1 Feature Set</h3> Git provides file versioning services only, whereas Fossil adds an integrated [./wikitheory.wiki | wiki], [./bugtheory.wiki | ticketing & bug tracking], | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <h2>3.0 Discussion</h2> <h3>3.1 Feature Set</h3> Git provides file versioning services only, whereas Fossil adds an integrated [./wikitheory.wiki | wiki], [./bugtheory.wiki | ticketing & bug tracking], [./embeddeddoc.wiki | embedded documentation], and [./event.wiki | News/Blog features]. These additional capabilities are available for Git as 3rd-party user-installed add-ons, but with Fossil they are integrated into the design. One way to describe Fossil is that it is "[https://github.com/ | github]-in-a-box". <h3>3.2 Sharding versus Replicating</h3> |
| ︙ | ︙ | |||
72 73 74 75 76 77 78 | at a time. Git encourages a programming model where each developer works in his or her own branch and then merges changes up the hierarchy until they reach the master branch. Fossil is designed for smaller and non-hierarchical teams where all developers are operating directly on the master branch, or at most a small number of well defined branches. | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | at a time. Git encourages a programming model where each developer works in his or her own branch and then merges changes up the hierarchy until they reach the master branch. Fossil is designed for smaller and non-hierarchical teams where all developers are operating directly on the master branch, or at most a small number of well defined branches. The [./concepts.wiki#workflow | autosync] mode of Fossil makes it easy for multiple developers to work on a single branch and maintain linear development on that branch and avoid needless forking and merging. <h3>3.3 Branches</h3> Git (and especially GitHub) encourages a workflow where each developer |
| ︙ | ︙ | |||
113 114 115 116 117 118 119 | branches in Fossil are feature-centric. The Git approach scales much better for large projects like the Linux kernel with thousands of contributors who in many cases don't even know each others names. The integrators serve a gatekeeper role to help keep undesirable code out of the official Linux source tree. On the other hand, not many projects are as big or as loosely organized as the Linux kernel. | | > > > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | branches in Fossil are feature-centric. The Git approach scales much better for large projects like the Linux kernel with thousands of contributors who in many cases don't even know each others names. The integrators serve a gatekeeper role to help keep undesirable code out of the official Linux source tree. On the other hand, not many projects are as big or as loosely organized as the Linux kernel. Most projects have a small team of developers who all know each other well and trust each other, and who enjoy working together collaboratively without the overhead and hierarchy of integrators. One consequence of the "everybody-sees-everything" focus of Fossil is that branch names are global and are part of the distributed and synchronized content of a Fossil repository, rather than being private and user-specific as they are in Git. <h3>3.4 Complexity</h3> Git is a complex system. It can be tricky to use and requires a fair amount of knowledge and experience to master. Fossil strives to be a much simpler system that can be learned and mastered much more quickly. Fossil strives to have fewer "gotchas" and quirks that can trip up a |
| ︙ | ︙ | |||
137 138 139 140 141 142 143 | the thinking about version control. Git requires the developer to maintain a more complex mental model than most other DVCSes. Git takes longer to learn. And you have to spend more time thinking about what you are doing with Git. Fossil strives for simplicity. Fossil wants to be easy to learn and to | | > | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | the thinking about version control. Git requires the developer to maintain a more complex mental model than most other DVCSes. Git takes longer to learn. And you have to spend more time thinking about what you are doing with Git. Fossil strives for simplicity. Fossil wants to be easy to learn and to require little thinking about how to operating it. [./quotes.wiki | Reports from the field] indicate that Fossil is mostly successful at this effort. <h3>3.5 Web Interface</h3> Git has a web interface, but it requires a fair amount of setup and an external web server. Fossil comes with a fully functional [./webui.wiki | built-in web-server] and a really simple mechanism (the "[/help/ui|fossil ui]" command) to automatically start the web server and bring up a web browser to navigate it. The web interface for Fossil is not only easier to set up, it is also more powerful and easier to use. The web interface to Fossil is a practical replacement to the 3rd-party "GUI Tools" that users often employ to operate Git. <h3>3.6 Implementation Strategy</h3> |
| ︙ | ︙ | |||
186 187 188 189 190 191 192 | are simply rolled back after the system reboots. <h3>3.8 Audit Trail</h3> Git features the "rebase" command which can be used to change the sequence of check-ins in the repository. Rebase can be used to "clean up" a complex sequence of check-ins to make their intent easier for others | | | < < < | > > > > > > > > | | > > | | | | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | are simply rolled back after the system reboots. <h3>3.8 Audit Trail</h3> Git features the "rebase" command which can be used to change the sequence of check-ins in the repository. Rebase can be used to "clean up" a complex sequence of check-ins to make their intent easier for others to understand. This is important if you view the history of a project as part of the documentation for the project. Fossil takes an opposing view. Fossil views history as sacrosanct and stubornly refuses to change it. Fossil allows mistakes to be corrected (for example, check-in comments can be revised, and check-ins can be moved onto new branches even after the check-in has occurred) but the correction is an addition to the respository and the original actions are preserved and displayed alongside the corrections, thus preserving an historically accurate audit trail. This is analogous to an accountant marking through an incorrect entry in a ledger and writing in a correction beside it, rather than erasing and incorrect entry. To put it another way, Git remembers what you should have done whereas Fossil remembers what you actually did. The lack of a "rebase" command and the inability to rewrite history is considered a feature of Fossil, not an omission or bug. <h3>3.9 License</h3> Both Git and Fossil are open-source. Git is under [http://www.gnu.org/licenses/gpl.html | GPL] whereas Fossil is under the [http://en.wikipedia.org/wiki/BSD_licenses | two-clause BSD license]. The difference should not be of a concern to most users. However, some corporate lawyers have objections to using GPL products and are more comfortable with a BSD-style license. |
Added www/hacker-howto.wiki.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <title>Fossil Hackers How-To</title> The following links are of interest to programmers who want to modify or enhance Fossil. Ordinary users can safely ignore this information. * [./build.wiki | How To Compile And Install Fossil] * [./makefile.wiki | The Fossil Build Process] * [./tech_overview.wiki | A Technical Overview of Fossil] * [./adding_code.wiki | Adding Features To Fossil] * [./contribute.wiki|Contributing Code Or Enhancements To The Fossil Project] * [./style.wiki | Coding Style Guidelines] * [./checkin.wiki | Pre-checkin Checklist] * [../test/release-checklist.wiki | Release Checklist] |
Changes to www/hints.wiki.
1 2 | <title>Fossil Tips And Usage Hints</title> | | | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<title>Fossil Tips And Usage Hints</title>
1. Click on nodes of any timeline graph to see diffs between the two
selected versions.
2. Add the "--tk" option to "[/help?cmd=diff | fossil diff]" commands
to get a pop-up
window containing a complete side-by-side diff. (NB: The pop-up
window is run as a separate Tcl/Tk process, so you will need to
have Tcl/Tk installed on your machine for this to work. Visit
[http://www.activestate.com/activetcl] to for a quick download of
Tcl/Tk if you do not already have it on your system.)
3. The "[/help?cmd=clean | fossil clean -f]" command makes a great
alternative to "make clean".
4. Use "[/help?cmd=all | fossil all changes]" to look for any uncommitted
edits in any of your Fossil projects. Use
"[/help?cmd=all | fossil all pull]" on your laptop
prior to going off network (for example, on a long plane ride)
to make sure you have all the latest content locally. Then run
"[/help/all|fossil all push]" when you get back online to upload
your changes.
5. Sub-menu options on Timelines lets you select either 20 or 200
records. But you can manual edit the "n=" query parameter in the
URL to get any number of records you desire. To see a complete
timeline graph, set n to some ridiculously large value like 10000000.
6. You can manually add a "c=CHECKIN" query parameter to the timeline
|
| ︙ | ︙ |
Changes to www/index.wiki.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | <ul> <li> [http://www.fossil-scm.org/download.html | Download] <li> [./quickstart.wiki | Quick Start] <li> [./build.wiki | Install] <li> [../COPYRIGHT-BSD2.txt | License] <li> [/timeline | Recent changes] <li> [./faq.wiki | FAQ] | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<ul>
<li> [http://www.fossil-scm.org/download.html | Download]
<li> [./quickstart.wiki | Quick Start]
<li> [./build.wiki | Install]
<li> [../COPYRIGHT-BSD2.txt | License]
<li> [/timeline | Recent changes]
<li> [./faq.wiki | FAQ]
<li> [./hacker-howto.wiki | Hacker How-To]
<li> [./changes.wiki | Change Log]
<li> [./hints.wiki | Tip & Hints]
<li> [./permutedindex.wiki#pindex | Documentation Index]
<li> [http://www.fossil-scm.org/schimpf-book/home | Jim Schimpf's book]
<li> Mailing list
<ul>
<li> [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | sign-up]
|
| ︙ | ︙ | |||
79 80 81 82 83 84 85 |
Fossil is a single stand-alone executable that contains everything
needed to do configuration management.
Installation is trivial: simply download a
<a href="http://www.fossil-scm.org/download.html">precompiled binary</a>
for Linux, Mac, or Windows and put it on your $PATH.
[./build.wiki | Easy-to-compile source code] is available for
users on other platforms. Fossil sources are also mostly self-contained,
| | | | | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
Fossil is a single stand-alone executable that contains everything
needed to do configuration management.
Installation is trivial: simply download a
<a href="http://www.fossil-scm.org/download.html">precompiled binary</a>
for Linux, Mac, or Windows and put it on your $PATH.
[./build.wiki | Easy-to-compile source code] is available for
users on other platforms. Fossil sources are also mostly self-contained,
requiring only the standard C library to build.
5. <b>Simple Networking</b> -
Fossil uses plain old HTTP (with
[./quickstart.wiki#proxy | proxy support])
for all network communications, meaning that it works fine from behind
restrictive firewalls. The protocol is
[./stats.wiki | bandwidth efficient] to the point that Fossil can be
used comfortably over a dial-up internet connection.
6. <b>CGI/SCGI Enabled</b> -
No server is required to use fossil. But a
server does make collaboration easier. Fossil supports four different
yet simple [./server.wiki | server configurations].
The most popular is a 2-line CGI script. This is the approach
used by the [./selfhost.wiki | self-hosting fossil repositories].
7. <b>Robust & Reliable</b> -
Fossil stores content using an [./fileformat.wiki | enduring file format]
in an SQLite database so that transactions are
atomic even if interrupted by a power loss or system crash. Furthermore,
automatic [./selfcheck.wiki | self-checks] verify that all aspects of
the repository are consistent prior to each commit. In over six years
of operation, no work has ever been lost after having been committed to
a Fossil repository.
<hr>
<h3>Links For Fossil Users:</h3>
* [./reviews.wiki | Testimonials] from satisfied fossil users and
|
| ︙ | ︙ |
Changes to www/makefile.wiki.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | want to compile the code themselves can use one of the [./build.wiki | existing makefiles]. So must people do not need to be concerned with the build complexities of Fossil. But hard-core developers who desire a deep understanding of how Fossil is put together can benefit from reviewing this article. <h1>2.0 Source Code Tour</h1> The source code for Fossil is found in the [/dir?ci=trunk&name=src | src/] subdirectory of the source tree. The src/ subdirectory contains all code, including the code for the separate preprocessor programs. | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | want to compile the code themselves can use one of the [./build.wiki | existing makefiles]. So must people do not need to be concerned with the build complexities of Fossil. But hard-core developers who desire a deep understanding of how Fossil is put together can benefit from reviewing this article. <a name="srctour"></a> <h1>2.0 Source Code Tour</h1> The source code for Fossil is found in the [/dir?ci=trunk&name=src | src/] subdirectory of the source tree. The src/ subdirectory contains all code, including the code for the separate preprocessor programs. |
| ︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 126 127 128 | The pathnames in the above command might need to be adjusted to get the directories right. The point is that the manifest.uuid, manifest, and VERSION files in the root of the source tree are the three arguments and the generated VERSION.h file appears on standard output. <h1>4.0 Preprocessing</h1> There are three preprocessors for the Fossil sources. The mkindex and translate preprocessors can be run in any order. The makeheaders preprocessor must be run after translate. <h2>4.1 The mkindex preprocessor</h2> | > | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | The pathnames in the above command might need to be adjusted to get the directories right. The point is that the manifest.uuid, manifest, and VERSION files in the root of the source tree are the three arguments and the generated VERSION.h file appears on standard output. <a name="preprocessing"></a> <h1>4.0 Preprocessing</h1> There are three preprocessors for the Fossil sources. The mkindex and translate preprocessors can be run in any order. The makeheaders preprocessor must be run after translate. <h2>4.1 The mkindex preprocessor</h2> |
| ︙ | ︙ | |||
199 200 201 202 203 204 205 | all at once, or each preprocessed source file can be compiled into a separate object code file and the resulting object code files linked together in a final step. Some files require special C-preprocessor macro definitions. When compiling sqlite.c, the following macros are recommended: | < | | < < < | | > > | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | all at once, or each preprocessed source file can be compiled into a separate object code file and the resulting object code files linked together in a final step. Some files require special C-preprocessor macro definitions. When compiling sqlite.c, the following macros are recommended: * -DSQLITE_OMIT_LOAD_EXTENSION=1 * -DSQLITE_ENABLE_LOCKING_STYLE=0 * -DSQLITE_THREADSAFE=0 * -DSQLITE_DEFAULT_FILE_FORMAT=4 * -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 The first symbol definition above is required; the others are merely recommended. Extension loading is omitted as a security measure. Fossil is single-threaded so mutexing is disabled in SQLite as a performance enhancement. The SQLITE_ENABLE_EXPLAIN_COMMENTS option makes the output of "EXPLAIN" queries in the "[/help?cmd=sqlite3|fossil sql]" command much more readable. When compiling the shell.c source file, these macros are required: * -Dmain=sqlite3_main * -DSQLITE_OMIT_LOAD_EXTENSION=1 The "main()" routine in the shell must be changed into sqlite3_main() |
| ︙ | ︙ | |||
234 235 236 237 238 239 240 | <h1>6.0 Linkage</h1> Fossil needs to be linked against [http://www.zlib.net | zlib]. If the HTTPS option is enabled, then it will also need to link against the appropriate SSL implementation. And, of course, Fossil needs to link against the standard C library. No other libraries or external dependences are used. | > > > > > | 234 235 236 237 238 239 240 241 242 243 244 245 | <h1>6.0 Linkage</h1> Fossil needs to be linked against [http://www.zlib.net | zlib]. If the HTTPS option is enabled, then it will also need to link against the appropriate SSL implementation. And, of course, Fossil needs to link against the standard C library. No other libraries or external dependences are used. <h1>7.0 See Also</h1> * [./tech_overview.wiki | A Technical Overview Of Fossil] * [./adding_code.wiki | How To Add Features To Fossil] |
Changes to www/mkdownload.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/usr/bin/tclsh
#
# Run this script to build the "download.html" page. Also generate
# the fossil_download_checksums.html page.
#
#
set out [open download.html w]
fconfigure $out -encoding utf-8 -translation lf
puts $out \
{<!DOCTYPE html><html>
<head>
<base href="http://www.fossil-scm.org/" />
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#!/usr/bin/tclsh
#
# Run this script to build the "download.html" page. Also generate
# the fossil_download_checksums.html page.
#
#
set out [open download.html w]
fconfigure $out -encoding utf-8 -translation lf
puts $out \
{<!DOCTYPE html><html>
<head>
<base href="http://www.fossil-scm.org/" />
<title>Fossil: Downloads</title>
<link rel="stylesheet" href="/fossil/style.css" type="text/css"
media="screen">
</head>
<body>
<div class="header">
<div class="logo">
<img src="/fossil/logo" alt="logo">
|
| ︙ | ︙ | |||
66 67 68 69 70 71 72 |
#
foreach datetime [lsort -decr [array names adate]] {
set dt [string range $datetime 0 3]-[string range $datetime 4 5]-
append dt "[string range $datetime 6 7] "
append dt "[string range $datetime 8 9]:[string range $datetime 10 11]:"
append dt "[string range $datetime 12 13]"
set link [string map {{ } +} $dt]
| | | | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#
foreach datetime [lsort -decr [array names adate]] {
set dt [string range $datetime 0 3]-[string range $datetime 4 5]-
append dt "[string range $datetime 6 7] "
append dt "[string range $datetime 8 9]:[string range $datetime 10 11]:"
append dt "[string range $datetime 12 13]"
set link [string map {{ } +} $dt]
set hr "http://www.fossil-scm.org/fossil/timeline?c=$link&y=ci"
puts $out "<tr><td colspan=6 align=left><hr>"
puts $out "<center><b><a href=\"$hr\">$dt</a></b></center>"
puts $out "</td></tr>"
puts $out "<tr>"
foreach {prefix suffix img desc} {
fossil-linux-x86 zip linux.gif {Linux 3.x x86}
fossil-macosx-x86 zip mac.gif {Mac 10.x x86}
fossil-openbsd-x86 zip openbsd.gif {OpenBSD 4.x x86}
fossil-w32 zip win32.gif {Windows}
fossil-src tar.gz src.gif {Source Tarball}
} {
set filename download/$prefix-$datetime.$suffix
if {[file exists $filename]} {
set size [file size $filename]
set units bytes
|
| ︙ | ︙ |
Changes to www/mkindex.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#!/bin/sh
#
# Run this TCL script to generate a WIKI page that contains a
# permuted index of the various documentation files.
#
# tclsh mkindex.tcl >permutedindex.wiki
#
set doclist {
antibot.wiki {Defense against Spiders and Bots}
bugtheory.wiki {Bug Tracking In Fossil}
branching.wiki {Branching, Forking, Merging, and Tagging}
build.wiki {Compiling and Installing Fossil}
checkin_names.wiki {Checkin And Version Names}
checkin.wiki {Check-in Checklist}
changes.wiki {Fossil Changelog}
| > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#!/bin/sh
#
# Run this TCL script to generate a WIKI page that contains a
# permuted index of the various documentation files.
#
# tclsh mkindex.tcl >permutedindex.wiki
#
set doclist {
adding_code.wiki {Adding New Features To Fossil}
adding_code.wiki {Hacking Fossil}
antibot.wiki {Defense against Spiders and Bots}
bugtheory.wiki {Bug Tracking In Fossil}
branching.wiki {Branching, Forking, Merging, and Tagging}
build.wiki {Compiling and Installing Fossil}
checkin_names.wiki {Checkin And Version Names}
checkin.wiki {Check-in Checklist}
changes.wiki {Fossil Changelog}
|
| ︙ | ︙ | |||
24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
event.wiki {Events}
faq.wiki {Frequently Asked Questions}
fileformat.wiki {Fossil File Format}
fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
foss-cklist.wiki {Checklist For Successful Open-Source Projects}
fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
fossil-v-git.wiki {Fossil Versus Git}
hints.wiki {Fossil Tips And Usage Hints}
index.wiki {Home Page}
inout.wiki {Import And Export To And From Git}
makefile.wiki {The Fossil Build Process}
newrepo.wiki {How To Create A New Fossil Repository}
password.wiki {Password Management And Authentication}
pop.wiki {Principles Of Operations}
| > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
event.wiki {Events}
faq.wiki {Frequently Asked Questions}
fileformat.wiki {Fossil File Format}
fiveminutes.wiki {Update and Running in 5 Minutes as a Single User}
foss-cklist.wiki {Checklist For Successful Open-Source Projects}
fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE}
fossil-v-git.wiki {Fossil Versus Git}
hacker-howto.wiki {Hacker How-To}
hints.wiki {Fossil Tips And Usage Hints}
index.wiki {Home Page}
inout.wiki {Import And Export To And From Git}
makefile.wiki {The Fossil Build Process}
newrepo.wiki {How To Create A New Fossil Repository}
password.wiki {Password Management And Authentication}
pop.wiki {Principles Of Operations}
|
| ︙ | ︙ |
Changes to www/permutedindex.wiki.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | </ul> <a name="pindex"></a> <h2>Permuted Index:</h2> <ul> <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Update and Running in</a></li> <li><a href="fossil-from-msvc.wiki">2010 IDE — Integrating Fossil in the Microsoft Express</a></li> <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li> <li><a href="antibot.wiki">against Spiders and Bots — Defense</a></li> <li><a href="copyright-release.html">Agreement — Contributor License</a></li> <li><a href="delta_encoder_algorithm.wiki">Algorithm — Fossil Delta Encoding</a></li> <li><a href="fiveminutes.wiki">as a Single User — Update and Running in 5 Minutes</a></li> <li><a href="faq.wiki">Asked Questions — Frequently</a></li> <li><a href="password.wiki">Authentication — Password Management And</a></li> <li><a href="antibot.wiki">Bots — Defense against Spiders and</a></li> | > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | </ul> <a name="pindex"></a> <h2>Permuted Index:</h2> <ul> <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Update and Running in</a></li> <li><a href="fossil-from-msvc.wiki">2010 IDE — Integrating Fossil in the Microsoft Express</a></li> <li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li> <li><a href="adding_code.wiki">Adding New Features To Fossil</a></li> <li><a href="antibot.wiki">against Spiders and Bots — Defense</a></li> <li><a href="copyright-release.html">Agreement — Contributor License</a></li> <li><a href="delta_encoder_algorithm.wiki">Algorithm — Fossil Delta Encoding</a></li> <li><a href="fiveminutes.wiki">as a Single User — Update and Running in 5 Minutes</a></li> <li><a href="faq.wiki">Asked Questions — Frequently</a></li> <li><a href="password.wiki">Authentication — Password Management And</a></li> <li><a href="antibot.wiki">Bots — Defense against Spiders and</a></li> |
| ︙ | ︙ | |||
59 60 61 62 63 64 65 66 67 68 69 70 71 72 | <li><a href="theory1.wiki">DVCS — Thoughts On The Design Of The Fossil</a></li> <li><a href="quotes.wiki">DVCSes in General — Quotes: What People Are Saying About Fossil, Git, and</a></li> <li><a href="embeddeddoc.wiki">Embedded Project Documentation</a></li> <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm — Fossil Delta</a></li> <li><a href="event.wiki">Events</a></li> <li><a href="inout.wiki">Export To And From Git — Import And</a></li> <li><a href="fossil-from-msvc.wiki">Express 2010 IDE — Integrating Fossil in the Microsoft</a></li> <li><a href="fileformat.wiki">File Format — Fossil</a></li> <li><a href="branching.wiki">Forking, Merging, and Tagging — Branching,</a></li> <li><a href="delta_format.wiki">Format — Fossil Delta</a></li> <li><a href="fileformat.wiki">Format — Fossil File</a></li> <li><a href="changes.wiki">Fossil Changelog</a></li> <li><a href="concepts.wiki">Fossil Core Concepts</a></li> <li><a href="delta_encoder_algorithm.wiki">Fossil Delta Encoding Algorithm</a></li> | > | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | <li><a href="theory1.wiki">DVCS — Thoughts On The Design Of The Fossil</a></li> <li><a href="quotes.wiki">DVCSes in General — Quotes: What People Are Saying About Fossil, Git, and</a></li> <li><a href="embeddeddoc.wiki">Embedded Project Documentation</a></li> <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm — Fossil Delta</a></li> <li><a href="event.wiki">Events</a></li> <li><a href="inout.wiki">Export To And From Git — Import And</a></li> <li><a href="fossil-from-msvc.wiki">Express 2010 IDE — Integrating Fossil in the Microsoft</a></li> <li><a href="adding_code.wiki">Features To Fossil — Adding New</a></li> <li><a href="fileformat.wiki">File Format — Fossil</a></li> <li><a href="branching.wiki">Forking, Merging, and Tagging — Branching,</a></li> <li><a href="delta_format.wiki">Format — Fossil Delta</a></li> <li><a href="fileformat.wiki">Format — Fossil File</a></li> <li><a href="changes.wiki">Fossil Changelog</a></li> <li><a href="concepts.wiki">Fossil Core Concepts</a></li> <li><a href="delta_encoder_algorithm.wiki">Fossil Delta Encoding Algorithm</a></li> |
| ︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | <li><a href="inout.wiki">From Git — Import And Export To And</a></li> <li><a href="quotes.wiki">General — Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li> <li><a href="fossil-v-git.wiki">Git — Fossil Versus</a></li> <li><a href="inout.wiki">Git — Import And Export To And From</a></li> <li><a href="quotes.wiki">Git, and DVCSes in General — Quotes: What People Are Saying About Fossil,</a></li> <li><a href="quickstart.wiki">Guide — Fossil Quick Start</a></li> <li><a href="style.wiki">Guidelines — Source Code Style</a></li> <li><a href="hints.wiki">Hints — Fossil Tips And Usage</a></li> <li><a href="index.wiki">Home Page</a></li> <li><a href="selfhost.wiki">Hosting Repositories — Fossil Self</a></li> <li><a href="server.wiki">How To Configure A Fossil Server</a></li> <li><a href="newrepo.wiki">How To Create A New Fossil Repository</a></li> <li><a href="fossil-from-msvc.wiki">IDE — Integrating Fossil in the Microsoft Express 2010</a></li> <li><a href="tech_overview.wiki">Implementation Of Fossil — A Technical Overview Of The Design And</a></li> <li><a href="inout.wiki">Import And Export To And From Git</a></li> <li><a href="build.wiki">Installing Fossil — Compiling and</a></li> <li><a href="fossil-from-msvc.wiki">Integrating Fossil in the Microsoft Express 2010 IDE</a></li> <li><a href="selfcheck.wiki">Integrity Self Checks — Fossil Repository</a></li> <li><a href="webui.wiki">Interface — The Fossil Web</a></li> <li><a href="copyright-release.html">License Agreement — Contributor</a></li> <li><a href="password.wiki">Management And Authentication — Password</a></li> <li><a href="branching.wiki">Merging, and Tagging — Branching, Forking,</a></li> <li><a href="fossil-from-msvc.wiki">Microsoft Express 2010 IDE — Integrating Fossil in the</a></li> <li><a href="fiveminutes.wiki">Minutes as a Single User — Update and Running in 5</a></li> <li><a href="checkin_names.wiki">Names — Checkin And Version</a></li> <li><a href="newrepo.wiki">New Fossil Repository — How To Create A</a></li> <li><a href="foss-cklist.wiki">Open-Source Projects — Checklist For Successful</a></li> <li><a href="pop.wiki">Operations — Principles Of</a></li> <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil — A Technical</a></li> <li><a href="index.wiki">Page — Home</a></li> <li><a href="password.wiki">Password Management And Authentication</a></li> <li><a href="quotes.wiki">People Are Saying About Fossil, Git, and DVCSes in General — Quotes: What</a></li> | > > > > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | <li><a href="inout.wiki">From Git — Import And Export To And</a></li> <li><a href="quotes.wiki">General — Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li> <li><a href="fossil-v-git.wiki">Git — Fossil Versus</a></li> <li><a href="inout.wiki">Git — Import And Export To And From</a></li> <li><a href="quotes.wiki">Git, and DVCSes in General — Quotes: What People Are Saying About Fossil,</a></li> <li><a href="quickstart.wiki">Guide — Fossil Quick Start</a></li> <li><a href="style.wiki">Guidelines — Source Code Style</a></li> <li><a href="hacker-howto.wiki">Hacker How-To</a></li> <li><a href="adding_code.wiki">Hacking Fossil</a></li> <li><a href="hints.wiki">Hints — Fossil Tips And Usage</a></li> <li><a href="index.wiki">Home Page</a></li> <li><a href="selfhost.wiki">Hosting Repositories — Fossil Self</a></li> <li><a href="server.wiki">How To Configure A Fossil Server</a></li> <li><a href="newrepo.wiki">How To Create A New Fossil Repository</a></li> <li><a href="hacker-howto.wiki">How-To — Hacker</a></li> <li><a href="fossil-from-msvc.wiki">IDE — Integrating Fossil in the Microsoft Express 2010</a></li> <li><a href="tech_overview.wiki">Implementation Of Fossil — A Technical Overview Of The Design And</a></li> <li><a href="inout.wiki">Import And Export To And From Git</a></li> <li><a href="build.wiki">Installing Fossil — Compiling and</a></li> <li><a href="fossil-from-msvc.wiki">Integrating Fossil in the Microsoft Express 2010 IDE</a></li> <li><a href="selfcheck.wiki">Integrity Self Checks — Fossil Repository</a></li> <li><a href="webui.wiki">Interface — The Fossil Web</a></li> <li><a href="copyright-release.html">License Agreement — Contributor</a></li> <li><a href="password.wiki">Management And Authentication — Password</a></li> <li><a href="branching.wiki">Merging, and Tagging — Branching, Forking,</a></li> <li><a href="fossil-from-msvc.wiki">Microsoft Express 2010 IDE — Integrating Fossil in the</a></li> <li><a href="fiveminutes.wiki">Minutes as a Single User — Update and Running in 5</a></li> <li><a href="checkin_names.wiki">Names — Checkin And Version</a></li> <li><a href="adding_code.wiki">New Features To Fossil — Adding</a></li> <li><a href="newrepo.wiki">New Fossil Repository — How To Create A</a></li> <li><a href="foss-cklist.wiki">Open-Source Projects — Checklist For Successful</a></li> <li><a href="pop.wiki">Operations — Principles Of</a></li> <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil — A Technical</a></li> <li><a href="index.wiki">Page — Home</a></li> <li><a href="password.wiki">Password Management And Authentication</a></li> <li><a href="quotes.wiki">People Are Saying About Fossil, Git, and DVCSes in General — Quotes: What</a></li> |
| ︙ | ︙ |
Changes to www/quickstart.wiki.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 |
<blockquote>
<b>fossil clone</b> <i>URL repository-filename</i>
</blockquote>
<p>The <i>URL</i> above is the http URL for the fossil repository
you want to clone, and it may include a "user:password" part, e.g.
| | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
<blockquote>
<b>fossil clone</b> <i>URL repository-filename</i>
</blockquote>
<p>The <i>URL</i> above is the http URL for the fossil repository
you want to clone, and it may include a "user:password" part, e.g.
<tt>http://user:password@www.fossil-scm.org/fossil</tt>. You can
call the new repository anything you want - there are no naming
restrictions. As an example, you can clone the fossil repository
this way:</p>
<blockquote>
<b>fossil clone http://www.fossil-scm.org/ myclone.fossil</b>
</blockquote>
|
| ︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 |
<blockquote>
<b>[/help/commit | fossil commit]</b>
</blockquote>
<p>You will be prompted for check-in comments using whatever editor
is specified by your VISUAL or EDITOR environment variable.</p>
<h2>Sharing Changes</h2>
| > > > > > > > > | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
<blockquote>
<b>[/help/commit | fossil commit]</b>
</blockquote>
<p>You will be prompted for check-in comments using whatever editor
is specified by your VISUAL or EDITOR environment variable.</p>
In the default configuration, the [/help/commit|commit]
command will also automatically [/help/push|push] your changes, but that
feature can be disabled. (More information about
[./concepts.wiki#workflow|autosync] and how to disable it.)
Remember that your coworkers can not see your changes until you
commit and push them.</p>
<h2>Sharing Changes</h2>
<p>When [./concepts.wiki#workflow|autosync] is turned off,
the changes you [/help/commit | commit] are only
on your local repository.
To share those changes with other repositories, do:</p>
<blockquote>
<b>[/help/push | fossil push]</b> <i>URL</i>
</blockquote>
|
| ︙ | ︙ | |||
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
abbreviation to the 40-character
artifact identifier for a particular check-in, or it can be a
date/time stamp. ([./checkin_names.wiki | more info])
If you omit
the <i>VERSION</i>, then fossil moves you to the
latest version of the branch your are currently on.</p>
<h2>Branching And Merging</h2>
<p>Use the --branch option to the [/help/commit | commit] command
to start a new branch. Note that in Fossil, branches are normally
created when you commit, not before you start editing. You can
use the [/help/branch | branch new] command to create a new branch
before you start editing, if you want, but most people just wait
until they are ready to commit.
To merge two branches back together, first
| > > > > > > > | | > > > | > > | | < < < < < < < < < | | | > | | | > > > > | > > > > > > < > | | > < < < | > | | | < < < < < < | < < < | < < < < | < < < < | | < < | < < | < | < < < < < < | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
abbreviation to the 40-character
artifact identifier for a particular check-in, or it can be a
date/time stamp. ([./checkin_names.wiki | more info])
If you omit
the <i>VERSION</i>, then fossil moves you to the
latest version of the branch your are currently on.</p>
<p>The default behavior is for [./concepts.wiki#workflow|autosync] to
be turned on. That means that a [/help/pull|pull] automatically occurs
when you run [/help/update|update] and a [/help/push|push] happens
automatically after you [/help/commit|commit]. So in normal practice,
the push, pull, and sync commands are rarely used. But it is important
to know about them, all the same.</p>
<h2>Branching And Merging</h2>
<p>Use the --branch option to the [/help/commit | commit] command
to start a new branch. Note that in Fossil, branches are normally
created when you commit, not before you start editing. You can
use the [/help/branch | branch new] command to create a new branch
before you start editing, if you want, but most people just wait
until they are ready to commit.
To merge two branches back together, first
[/help/update | update] to the branch you want to merge into.
Then do a [/help/merge|merge] another branch that you want to incorporate
the changes from. For example, to merge "featureX" changes into "trunk"
do this:</p>
<blockquote>
<b>fossil [/help/update|update] trunk</b><br>
<b>fossil [/help/merge|merge] featureX</b><br>
<i># make sure the merge didn't break anything...</i><br>
<b>fossil [/help/commit|commit]
</blockquote>
<p>The argument to the [/help/merge|merge] command can be any of the
version identifier forms that work for [/help/update|update].
([./checkin_names.wiki|more info].)
The merge command has options to cherrypick individual
changes, or to back out individual changes, if you don't want to
do a full merge.</p>
The merge command puts all changes in your working check-out.
No changes are made to the repository.
You must run [/help/commit|commit] separately
to add the merge changes into your repository to make them persistent
and so that your coworkers can see them.
But before you do that, you will normally want to run a few tests
to verify that the merge didn't cause logic breaks in your code.
The same branch can be merged multiple times without trouble. Fossil
automatically keeps up with things and avoids conflicts when doing
multiple merges. So even if you have merged the featureX branch
into trunk previously, you can do so again and Fossil will automatically
know to pull in only those changes that have occurred since the previous
merge.
<p>If a merge or update doesn't work out (perhaps something breaks or
there are many merge conflicts) then you back up using:</p>
<blockquote>
<b>[/help/undo | fossil undo]</b>
</blockquote>
<p>This will back out the changes that the merge or update made to the
working checkout. There is also a [/help/redo|redo] command if you undo by
mistake. Undo and redo only work for changes that have
not yet been checked in using commit and there is only a single
level of undo/redo.</p>
<h2>Setting Up A Server</h2>
<p>Fossil can act as a stand-alone web server using one of these
commands:</p>
<blockquote>
<b>[/help/server | fossil server]</b> <i>repository-filename</i><br>
<b>[/help/ui | fossil ui]</b> <i>repository-filename</i>
</blockquote>
<p>The <i>repository-filename</i> can be omitted when these commands
are run from within an open check-out, which a particularly useful
shortcut for the <b>fossil ui</b> command.
<p>The <b>ui</b> command is intended for accessing the web interface
from a local desktop. The <b>ui</b> command binds to the loopback IP
address only (and thus makes the web interface visible only on the
local machine) and it automatically start your web browser pointing at the
server. For cross-machine collaboration, use the <b>server</b> command,
which binds on all IP addresses and does not try to start a web browser.</p>
<p>Servers are also easily configured as:
<ul>
<li>[./server.wiki#inetd|inetd/xinetd]
<li>[./server.wiki#cgi|CGI]
<li>[./server.wiki#scgi|SCGI]
</ul>
<p>The the [./selfhost.wiki | self-hosting fossil repositories] use
CGI.
<a name="proxy"></a>
<h2>HTTP Proxies</h2>
<p>If you are behind a restrictive firewall that requires you to use
an HTTP proxy to reach the internet, then you can configure the proxy
in three different ways. You can tell fossil about your proxy using
|
| ︙ | ︙ | |||
367 368 369 370 371 372 373 |
<blockquote>
<b>fossil sync http://192.168.1.36:8080/ --proxy off</b>
</blockquote>
<h2>More Hints</h2>
| | > > > | 360 361 362 363 364 365 366 367 368 369 370 371 372 |
<blockquote>
<b>fossil sync http://192.168.1.36:8080/ --proxy off</b>
</blockquote>
<h2>More Hints</h2>
<p>A [/help | complete list of commands] is available, as is the
[./hints.wiki|helpful hints] document. See the
[./permutedindex.wiki#pindex|permuted index] for additional
documentation.
<p>Explore and have fun!</p>
|
Changes to www/quotes.wiki.
| ︙ | ︙ | |||
114 115 116 117 118 119 120 121 | the published aspect of the project, so it provides tools for rearranging that history so you can present what you "should" have done rather than what you actually did. <blockquote> <i>Mike Meyer on the Fossil mailing list, 2011-10-04</i> </blockquote> </ol> | > > > > > > | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | the published aspect of the project, so it provides tools for rearranging that history so you can present what you "should" have done rather than what you actually did. <blockquote> <i>Mike Meyer on the Fossil mailing list, 2011-10-04</i> </blockquote> <li>github is such a pale shadow of what fossil does. <blockquote> <i>dkf on the Tcl chatroom, 2013-12-06</i> </blockquote> </ol> |
Added www/scgi.wiki.
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<title>Fossil SCGI</title>
To run Fossil using SCGI, start the [/help/server|fossil server] command
with the --scgi command-line option. You will probably also want to
specific an alternative TCP/IP port using --port. For example:
<blockquote><pre>
fossil server $REPOSITORY --port 9000 --scgi
</pre></blockquote>
Then configure your SCGI-aware web-server to send SCGI requests to port
9000 on the machine where Fossil is running. A typical configuration for
this in Nginx is:
<blockquote><pre>
location ~ ^/demo_project/ {
include scgi_params;
scgi_pass localhost:9000;
scgi_param SCRIPT_NAME "/demo_project";
}
</pre></blockquote>
Note that Nginx does not normally send either the PATH_INFO or SCRIPT_NAME
variables via SCGI, but Fossil needs one or the other. So the configuration
above needs to add SCRIPT_NAME. If you do not do this, Fossil return an
error.
|
Changes to www/selfhost.wiki.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | on any of the three servers and those changes automatically propagate to the other two servers. Server (1) runs as a CGI script on a <a href="http://www.linode.com/">Linode 1024</a> located in Dallas, TX - on the same virtual machine that hosts <a href="http://www.sqlite.org/">SQLite</a> and over a | | | > | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | on any of the three servers and those changes automatically propagate to the other two servers. Server (1) runs as a CGI script on a <a href="http://www.linode.com/">Linode 1024</a> located in Dallas, TX - on the same virtual machine that hosts <a href="http://www.sqlite.org/">SQLite</a> and over a dozen other smaller projects. This demonstrates that Fossil can run on a low-power host processor. Multiple fossil-based projects can easily be hosted on the same machine, even if that machine is itself one of several dozen virtual machines on single physical box. The CGI script that runs the canonical Fossil self-hosting repository is as follows: <blockquote><pre> #!/usr/bin/fossil repository: /fossil/fossil.fossil </pre></blockquote> Server (3) runs as a CGI script on a shared hosting account at <a href="http://www.he.net/">Hurricane Electric</a> in Fremont, CA. This server demonstrates the ability of Fossil to run on an economical shared-host web account with no privileges beyond port 80 HTTP access and CGI. It is not necessary to have a dedicated computer with administrator privileges to run Fossil. As far as we are aware, Fossil is the only full-featured configuration management system that can run in such a restricted environment. The CGI script that runs on the Hurricane Electric server is the same as the CGI script shown above, except that the pathnames are modified to suit the environment: <blockquote><pre> |
| ︙ | ︙ |
Changes to www/server.wiki.
1 | <title>How To Configure A Fossil Server</title> | | > > > > > > > > | | > > > > > > > > > | < < | | | < > > | > | > > > | | | | < > > > > | | > > > > > > | | < > | < < > > > | > > > > > > > > > > > > | > > > > > > > > > | > | > > > > > > > > > > > > > > > > | | | > > > | < | < < > > > > > > | > > > > | | | > > > < < < > | | | | | > > | > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > > > | < < > > > > > > | < | > | < < > > > | > > > > > > < > > > > | > > > > | > > | > < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
<title>How To Configure A Fossil Server</title>
<h2>Introduction</h2><blockquote>
<p>A server is not necessary to use Fossil, but a server does help in collaborating with
peers. A Fossil server also works well as a complete website for a project.
For example, the complete <b>http://www.fossil-scm.org/</b> website, including the
page you are now reading (but excepting the download page),
is just a Fossil server displaying the content of the
self-hosting repository for Fossil.</p>
<p>This article is a guide for setting up your own Fossil server.</p></blockquote>
<h2>Overview</h2><blockquote>
There are basically four ways to set up a Fossil server:
<ol>
<li>A stand-alone server
<li>Using inetd or xinetd or stunnel
<li>CGI
<li>SCGI (a.k.a. SimpleCGI)
</ol>
Each of these can serve either a single repository, or a directory hierarchy
containing many repositories with names ending in ".fossil".
</blockquote>
<a name="standalone"></a>
<h2>Standalone server</h2><blockquote>
The easiest way to set up a Fossil server is to use either the
[/help/server|server] or the [/help/ui|ui] commands:
<ul>
<li><b>fossil server</b> <i>REPOSITORY</i>
<li><b>fossil ui</b> <i>REPOSITORY</i>
</ul>
<p>
The <i>REPOSITORY</i> argument is either the name of the repository file, or
a directory containing many repositories.
Both of these commands start a Fossil server, usually on TCP port 8080, though
a higher numbered port might also be used if 8080 is already occupied. You can
access these using URLs of the form <b>http://localhost:8080/</b>, or if
<i>REPOSITORY</i> is a directory, URLs of the form
<b>http://localhost:8080/</b><i>repo</i><b>/</b> where <i>repo</i> is the base
name of the repository file without the ".fossil" suffix.
The difference between "ui" and "server" is that "ui" will
also start a web browser and points it
to the URL mentioned above, and "ui" command binds to
the loopback IP address (127.0.0.1) only so that the "ui" command cannot be
used to serve content to a different machine.
</p>
<p>
If one of the commands above is run from within an open checkout,
then the <i>REPOSITORY</i> argument can be omitted and the checkout is used as
the repository.
</p>
<p>
Both commands have additional command-line options that can be used to refine
their behavior. See the [/help/server|online documentation] for an overview.
</p>
</blockquote>
<a name="inetd"></a>
<h2>Fossil as an inetd/xinetd or stunnel service</h2><blockquote>
<p>
A Fossil server can be launched on-demand by inetd or xinetd using
the [/help/http|fossil http] command. To launch Fossil from inetd, modify
your inetd configuration file (typically "/etc/inetd.conf") to contain a
line something like this:
<blockquote>
<pre>
12345 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil
</pre>
</blockquote>
In this example, you are telling "inetd" that when an incoming connection
appears on port "12345", that it should launch the binary "/usr/bin/fossil"
program with the arguments shown.
Obviously you will
need to modify the pathnames for your particular setup.
The final argument is either the name of the fossil repository to be served,
or a directory containing multiple repositories.
</p>
<p>
If you system is running xinetd, then the configuration is likely to be
in the file "/etc/xinetd.conf" or in a subfile of "/etc/xinetd.d".
An xinetd configuration file will appear like this:</p>
<blockquote>
<pre>
service http-alt
{
port = 591
socket_type = stream
wait = no
user = root
server = /usr/bin/fossil
server_args = http /home/fossil/repos/
}
</pre>
</blockquote>
<p>
The xinetd example above has Fossil configured to serve multiple
repositories, contained under the "/home/fossil/repos/" directory.
</p>
<p>
In both cases notice that Fossil was launched as root. This is not required,
but if it is done, then Fossil will automatically put itself into a chroot
jail for the user who owns the fossil repository before reading any information
off of the wire.
</p>
<p>
[http://www.stunnel.org/ | Stunnel version 4] is an inetd-like process that
accepts and decodes SSL-encrypted connections. Fossil can be run directly from
stunnel in a mannar similar to inetd and xinetd. This can be used to provide
a secure link to a Fossil project. The configuration needed to get stunnel4
to invoke Fossil is very similar to the inetd and xinetd examples shown above.
The relevant parts of an stunnel configuration might look something
like the following:
<blockquote><pre><nowiki>
[https]
accept = www.ubercool-project.org:443
TIMEOUTclose = 0
exec = /usr/bin/fossil
execargs = /usr/bin/fossil http /home/fossil/ubercool.fossil --https
</nowiki></pre></blockquote>
See the stunnel4 documentation for further details bout the /etc/stunnel/stunnel.conf
configuration file. Note that the [/help/http|fossil http] command should include
the --https option to let Fossil know to use "https" instead of "http" as the scheme
on generated hyperlinks.
<p>
Using inetd or xinetd or stunnel is a more complex setup
than the "standalone" server, but it has the
advantage of only using system resources when an actual connection is
attempted. If no-one ever connects to that port, a Fossil server will
not (automatically) run. It has the disadvantage of requiring "root" access
and therefore may not normally be available to lower-priced "shared" servers
on the internet.
</p>
</blockquote>
<a name="cgi"></a>
<h2>Fossil as CGI</h2><blockquote>
<p>
A Fossil server can also be run from an ordinary web server as a CGI program.
This feature allows Fossil to be seamlessly integrated into a larger website.
CGI is how the [./selfhost.wiki | self-hosting fossil repositories] are
implemented.
</p>
<p>
To run Fossil as CGI, create a CGI script (here called "repo") in the CGI directory
of your web server and having content like this:
<blockquote><pre>
#!/usr/bin/fossil
repository: /home/fossil/repo.fossil
</pre></blockquote>
</p>
<p>
As always, adjust your paths appropriately.
It may be necessary to set permissions properly, or to modify an ".htaccess"
file or make other server-specific changes. Consult the documentation
for your particular web server. In particular, the following permissions are
<em>normally</em> required (but, again, may be different for a particular
configuration):
<ul>
<li>The Fossil binary must be readable/executable, and ALL directories leading up to it
must be readable by the process which executes the CGI.</li>
<li>ALL directories leading to the CGI script must also be readable and the CGI
script itself must be executable for the user under which it will run (which often differs
from the one running the web server - consult your site's documentation or administrator).</li>
<li>The repository file AND the directory containing it must be writable by the same account
which executes the Fossil binary (again, this might differ from the WWW user). The directory
needs to be writable so that sqlite can write its journal files.</li>
</ul>
</p>
<p>
Once the script is set up correctly, and assuming your server is also set
correctly, you should be able to access your repository with a URL like:
<b>http://mydomain.org/cgi-bin/repo</b> (assuming the "repo" script is
accessible under "cgi-bin", which would be a typical deployment on Apache
for instance).
</p>
<p>
To serve multiple repositories from a directory using CGI, use the "directory:"
tag in the CGI script rather than "repository:". You might also want to add
a "notfound:" tag to tell where to redirect if the particular repository requested
by the URL is not found:
<blockquote><pre>
#!/usr/bin/fossil
directory: /home/fossil/repos
notfound: http://url-to-go-to-if-repo-not-found/
</pre></blockquote>
</p>
<p>
Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b>
will serve up the repository "/home/fossil/repos/XYZ.fossil" (if it exists).
</p>
</blockquote>
<a name="scgi"></a>
<h2>Fossil as SCGI</h2><blockquote>
<p>
The [/help/server|fossil server] command, described above as a way of
starting a stand-alone web server, can also be used for SCGI. Simply add
the --scgi command-line option and the stand-alone server will interpret
and respond to the SimpleCGI or SCGI protocol rather than raw HTTP. This can
be used in combination with a webserver (such as [http://nginx.org|Nginx])
that does not support CGI. A typical Nginx configuration to support SCGI
with Fossil would look something like this:
<blockquote><pre>
location ~ ^/demo_project/ {
include scgi_params;
scgi_pass localhost:9000;
scgi_param SCRIPT_NAME "/demo_project";
}
</pre></blockquote>
<p>
Note that Fossil requires the SCRIPT_NAME variable
in order to function properly, but Nginx does not provide this
variable by default.
So it is necessary to provide the SCRIPT_NAME parameter in the configuration.
Failure to do this will cause Fossil to return an error.
</p>
<p>
All of the features of the stand-alone server mode described above,
such as the ability to serve a directory full of Fossil repositories
rather than just a single repository, work the same way in SCGI mode.
</p>
</blockquote>
<h2>Securing a repository with SSL</h2><blockquote>
<p>
Using either CGI or SCGI, it is trivial to use SSL to
secure the server. Simply set up the Fossil CGI scripts etc. as above,
but modify the Apache (or IIS, etc.) server to require SSL (that is, a
URL with "https://") in order to access the CGI script directory. This
may also be accomplished (on Apache, at least) using appropriate
".htaccess" rules.
</p>
<p>
If you are using "inetd" to serve your repository, then you simply need
to add "/usr/bin/stunnel" (perhaps on a different path, depending on your
setup) before the command line to launch Fossil.
</p>
<p>
At this stage, the standalone server (e.g. "fossil server") does not
support SSL.
</p>
<p>
For more information, see <a href="./ssl.wiki">Using SSL with Fossil</a>.
</p>
</blockquote>
</blockquote>
|
Changes to www/tech_overview.wiki.
| ︙ | ︙ | |||
330 331 332 333 334 335 336 | fossil close command really isn't needed; one can accomplish the same thing simply by deleting the checkout database. Note that the stash, the undo stack, and the state of the bisect command are all contained within the checkout database. That means that the fossil close command will delete all stash content, the undo stack, and the bisect state. The close command is not undoable. Use it with care. | > > > > > > | 330 331 332 333 334 335 336 337 338 339 340 341 342 | fossil close command really isn't needed; one can accomplish the same thing simply by deleting the checkout database. Note that the stash, the undo stack, and the state of the bisect command are all contained within the checkout database. That means that the fossil close command will delete all stash content, the undo stack, and the bisect state. The close command is not undoable. Use it with care. <h2>3.0 See Also</h2> * [./makefile.wiki | The Fossil Build Process] * [./contribute.wiki | How To Contribute Code To Fossil] * [./adding_code.wiki | Adding New Features To Fossil] |
Changes to www/theory1.wiki.
| ︙ | ︙ | |||
93 94 95 96 97 98 99 | The second concern states that Fossil does not use a high-level scripting language. But that is not true. Fossil uses SQL (as implemented by SQLite) as its scripting language. This misunderstanding likely arises because people fail to appreciate that SQL is a programming language. People are taught that SQL is a "query language" as if that were somehow different from a | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | The second concern states that Fossil does not use a high-level scripting language. But that is not true. Fossil uses SQL (as implemented by SQLite) as its scripting language. This misunderstanding likely arises because people fail to appreciate that SQL is a programming language. People are taught that SQL is a "query language" as if that were somehow different from a "programming language". But they really are two different flavors of the same thing. I find that people do better with SQL if they think of SQL as a programming language and each statement of SQL is a separate program. SQL is a peculiar programming language in that one uses SQL to specify <i>what</i> to compute whereas in most other programming languages one specifies <i>how</i> to carry out the computation. This difference means that SQL |
| ︙ | ︙ |
Changes to www/webui.wiki.
| ︙ | ︙ | |||
65 66 67 68 69 70 71 | Notice that Fossil automatically finds an unused TCP port to run the server own and automatically points your web browser to the correct URL. So there is never any fumbling around trying to find an open port or to type arcane strings into your browser URL entry box. The interface just pops right up, ready to run. The Fossil web interface is also very easy to setup and run on a | | > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | Notice that Fossil automatically finds an unused TCP port to run the server own and automatically points your web browser to the correct URL. So there is never any fumbling around trying to find an open port or to type arcane strings into your browser URL entry box. The interface just pops right up, ready to run. The Fossil web interface is also very easy to setup and run on a network server, as either a CGI program or from inetd, or as an SCGI server. Details on how to do that are described further below. <h2>Things To Do Using The Web Interface</h2> You can view <b>timelines</b> of changes to the project. The default "Timeline" link on the menu bar takes you to a page that shows the 20 most recent check-ins, wiki page edits, ticket/bug-report changes, |
| ︙ | ︙ | |||
133 134 135 136 137 138 139 | "Home" page to be a wiki page or an embedded document. <h2>Installing On A Network Server</h2> When you create a new Fossil project and after you have configured it like you want it using the web interface, you can make the project available to a distributed team by simply copying the single | | > > > > | > | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | "Home" page to be a wiki page or an embedded document. <h2>Installing On A Network Server</h2> When you create a new Fossil project and after you have configured it like you want it using the web interface, you can make the project available to a distributed team by simply copying the single repository file up to a web server that supports CGI or SCGI. To run Fossil as CGI, just put the <b>sample-project.fossil</b> file in a directory where CGI scripts have both read and write permission on the file and the directory that contains the file, then add a CGI script that looks something like this: <verbatim> #!/usr/local/bin/fossil repository: /home/www/sample-project.fossil </verbatim> Adjust the script above so that the paths are correct for your system, of course, and also make sure the Fossil binary is installed on the server. But that is <u>all</u> you have to do. You now have everything you need to host a distributed software development project in less than five minutes using a two-line CGI script. Instructions for setting up an SCGI server are [./scgi.wiki | available separately]. You don't have a CGI- or SCGI-capable web server running on your server machine? Not a problem. The Fossil interface can also be launched via inetd or xinetd. An inetd configuration line sufficient to launch the Fossil web interface looks like this: <verbatim> 80 stream tcp nowait.1000 root /usr/local/bin/fossil \ /usr/local/bin/fossil http /home/www/sample-project.fossil </verbatim> As always, you'll want to adjust the pathnames to whatever is appropriate for your system. The xinetd setup uses a different syntax but follows the same idea. |